qbs-src-2.6.1/0000755000175100001660000000000014776170045012450 5ustar runnerdockerqbs-src-2.6.1/LICENSE.LGPLv30000644000175100001660000001756014776170045014474 0ustar runnerdocker GNU LESSER GENERAL PUBLIC LICENSE The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. Contact: http://www.qt.io/licensing You may use, distribute and copy the Qt GUI Toolkit under the terms of GNU Lesser General Public License version 3, which is displayed below. ------------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this licensedocument, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. “The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. qbs-src-2.6.1/docker-compose.yml0000644000175100001660000000603514776170045016111 0ustar runnerdockerversion: "3.7" x-default-service: &linux working_dir: /qbs environment: - BUILD_OPTIONS - QTEST_FUNCTION_TIMEOUT - QBS_AUTOTEST_PROFILE - QBS_TEST_SOURCE_ROOT - WITH_ARCHIVE - WITH_TESTS - CLCACHE_DIR volumes: - .:/qbs - ~/.ccache:/home/devel/.ccache - /cores:/cores network_mode: bridge cap_add: - SYS_PTRACE ulimits: core: soft: -1 hard: -1 services: noble-qt6: &noble-qt6 << : *linux hostname: noble-qt6 image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-qt6-6.5.3_2.3.2-0 build: dockerfile: docker/noble/Dockerfile context: . args: QT_VERSION: 6.5.3 QTCREATOR_VERSION: 13.0.2 noble: << : *noble-qt6 noble-qt5: << : *linux hostname: noble-qt5 image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-5.15.2_2.3.2-0 build: dockerfile: docker/noble/Dockerfile context: . args: QT_VERSION: 5.15.2 QTCREATOR_VERSION: 13.0.2 noble-android-65: << : *linux hostname: noble-android image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-android-6.5.0-0 build: dockerfile: docker/noble/test-android.Dockerfile context: . args: QT_VERSION: 6.5.0 ANDROID_NDK_VERSION: 25.1.8937393 noble-android-515: << : *linux hostname: noble-android image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-android-5.15.2-0 build: dockerfile: docker/noble/test-android.Dockerfile context: . args: QT_VERSION: 5.15.2 ANDROID_NDK_VERSION: 23.0.7599858 noble-android-ndk-r25: << : *linux hostname: noble-android image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-android-ndk-r25-0 build: dockerfile: docker/noble/test-android-no-qt.Dockerfile context: . args: ANDROID_NDK_VERSION: 25.1.8937393 noble-baremetal: << : *linux hostname: noble-baremetal image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-baremetal-0 build: dockerfile: docker/noble/test-baremetal.Dockerfile context: . noble-qt6-wasm: << : *linux hostname: noble-qt6-wasm image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-qt6-wasm-6.7.0-0 build: dockerfile: docker/noble/test-qt6-wasm.Dockerfile context: . args: QT_VERSION: 6.7.0 EMSCRIPTEN_VERSION: 3.1.50 leap: << : *linux hostname: leap image: ${DOCKER_USER:-qbsbuild}/qbsdev:leap-5.15.2_1.20.1-1 build: dockerfile: docker/leap/Dockerfile context: . args: QT_VERSION: 5.15.2 QTCREATOR_VERSION: 5.0.3 windows: image: ${DOCKER_USER:-qbsbuild}/qbsdev:windowsservercore-6.6.0_1.24.0-0 build: dockerfile: docker/windowsservercore/Dockerfile context: . args: QT_VERSION: 6.6.0 QTCREATOR_VERSION: 9.0.1 working_dir: 'C:/qbs' environment: - BUILD_OPTIONS - WITH_DOCS volumes: - type: bind source: . target: C:\qbs - type: bind source: ~/.ccache target: C:\.ccache network_mode: nat qbs-src-2.6.1/CONTRIBUTING.md0000644000175100001660000000741114776170045014704 0ustar runnerdocker# Contributing to Qbs The main source code repository is hosted at [codereview.qt-project.org](https://codereview.qt-project.org/q/project:qbs/qbs). The Qbs source code is also mirrored on [code.qt.io](https://code.qt.io/cgit/qbs/qbs.git/) and on [GitHub](https://github.com/qbs/qbs). Please note that those mirrors are read-only and we do not accept pull-requests on GitHub. However, we gladly accept contributions via [Gerrit](https://codereview.qt-project.org/q/project:qbs/qbs). This document briefly describes steps required to be able to propose changes to the Qbs project. See the [Qt Contribution Guidelines](https://wiki.qt.io/Qt_Contribution_Guidelines) page, [Setting up Gerrit](https://wiki.qt.io/Setting_up_Gerrit) and [Gerrit Introduction](https://wiki.qt.io/Gerrit_Introduction) for more details about how to upload patches to Gerrit. ## Preparations * [Set up](https://wiki.qt.io/Setting_up_Gerrit#How_to_get_started_-_Gerrit_registration) a Gerrit account * Tweak your SSH config as instructed [here](https://wiki.qt.io/Setting_up_Gerrit#Local_Setup) * Use the recommended Git settings, defined [here](https://wiki.qt.io/Setting_up_Gerrit#Configuring_Git) * Get the source code as described below ## Cloning Qbs Clone Qbs from the [code.qt.io](https://code.qt.io/cgit/qbs/qbs.git/) mirror ``` git clone git://code.qt.io/qbs/qbs.git ``` Alternatively, you can clone from the mirror on the [GitHub](https://github.com/qbs/qbs) ``` git clone https://github.com/qbs/qbs.git ``` Set up the Gerrit remote ``` git remote add gerrit ssh://@codereview.qt-project.org:29418/qbs/qbs ``` ## Setting up git hooks Install the hook generating Commit-Id files into your top level project directory: ``` gitdir=$(git rev-parse --git-dir); scp -p -P 29418 codereview.qt-project.org:hooks/commit-msg "${gitdir}/hooks/" ``` This hook automatically adds a "Change-Id: …" line to the commit message. Change-Id is used to identify new Patch Sets for existing [Changes](https://wiki.qt.io/Gerrit_Introduction#Terminology). ## Making changes Commit your changes in the usual way you do in Git. After making changes, you might want to ensure that Qbs can be built and autotests pass: ``` qbs build -p autotest-runner ``` See ["Appendix A: Building Qbs"](http://doc.qt.io/qbs/building-qbs.html) for details. In case your changes might significantly affect performance (in either way), the 'qbs_benchmarker' tool can be used (Linux only, requires Valgrind to be installed): ``` qbs_benchmarker -r -o -n -a -p ``` Use 'qbs_benchmarker --help' for details. ## Pushing your changes to Gerrit After committing your changes locally, push them to Gerrit ``` git push gerrit HEAD:refs/for/master ``` Gerrit will print a URL that can be used to access the newly created Change. ## Adding reviewers Use the "ADD REVIEWER" button on the Change's web page to ask people to do the review. To find possible reviewers, you can examine the Git history with 'git log' and/or 'git blame' or ask on the mailing list: qbs@qt-project.org ## Modifying Commits During the review process, it might be necessary to do some changes to the commit. To include you changes in the last commit, use ``` git commit --amend ``` This will edit the last commit instead of creating a new one. Make sure to preserve the Change-Id footer when amending commits. For details, see [Updating a Contribution With New Code](https://wiki.qt.io/Gerrit_Introduction#Updating_a_Contribution_With_New_Code) ## Abandoning changes Changes which are inherently flawed or became inapplicable should be abandoned. You can do that on the Change's web page with the "ABANDON" button. Make sure to remove the abandoned commit from your working copy by using '[git reset](https://git-scm.com/docs/git-reset)'. qbs-src-2.6.1/share/0000755000175100001660000000000014776170045013552 5ustar runnerdockerqbs-src-2.6.1/share/qbs/0000755000175100001660000000000014776170045014337 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/0000755000175100001660000000000014776170045016034 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/0000755000175100001660000000000014776170045016621 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/WindowsUtils/0000755000175100001660000000000014776170045021274 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/WindowsUtils/windows-utils.js0000644000175100001660000000662414776170045024472 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ function winapiFamilyDefine(name) { return { "desktop": "DESKTOP_APP", "phone": "PHONE_APP", "pc": "PC_APP", "server": "SERVER", "system": "SYSTEM" }[name]; } function winapiPartitionDefine(name) { return { "app": "APP", "desktop": "DESKTOP", "phone": "PHONE_APP", "pc": "PC_APP", "server": "SERVER", "system": "SYSTEM" }[name]; } function characterSetDefines(charset) { var defines = []; if (charset === "unicode") defines.push("UNICODE", "_UNICODE"); else if (charset === "mbcs") defines.push("_MBCS"); return defines; } function canonicalizeVersion(version) { switch (version) { case "7": return "6.1"; case "8": return "6.2"; case "8.1": return "6.3"; default: return version; } } function knownWindowsVersions() { // Add new Windows versions to this list when they are released return ['10.0', '6.3', '6.2', '6.1', '6.0', '5.2', '5.1', '5.0', '4.0']; } function isValidWindowsVersion(systemVersion) { var realVersions = knownWindowsVersions(); for (i in realVersions) if (systemVersion === realVersions[i]) return true; return false; } function getWindowsVersionInFormat(systemVersion, format) { if (!systemVersion) return undefined; var major = parseInt(systemVersion.split('.')[0], 10); var minor = parseInt(systemVersion.split('.')[1], 10); switch (format) { case "hex": // https://msdn.microsoft.com/en-us/library/6sehtctf.aspx return "0x" + ("0000" + ((major << 8) | minor).toString(16)).slice(-4); case "subsystem": // https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx return major + '.' + (minor < 10 ? '0' : '') + minor; default: throw ("Unrecognized Windows version format " + format + ". Must be in {hex, subsystem}."); } } qbs-src-2.6.1/share/qbs/imports/qbs/DarwinTools/0000755000175100001660000000000014776170045021066 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/DarwinTools/darwin-tools.js0000644000175100001660000002355214776170045024055 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var Utilities = require("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", "macos": "MacOSX", "tvos": "AppleTV", "watchos": "Watch" }; var _platformDeviceMap = { "ios": ["iphone", "ipad"], "macos": ["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) { return _deviceMap[deviceName]; } /** * Returns the list of target devices available for the given qbs target OS list. */ function targetDevices(targetOS) { for (var key in _platformDeviceMap) { if (targetOS.contains(key)) return _platformDeviceMap[key]; } } /** * Returns the TARGETED_DEVICE_FAMILY string given a list of target device names. */ function targetedDeviceFamily(deviceNames) { return deviceNames.map(function (deviceName) { return appleDeviceNumber(deviceName); }); } /** * Returns the most appropriate Apple platform name given a targetOS list. */ 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)) { // there are no MacOSXOS or MacOSXSimulator platforms var suffix = (key !== "macos") ? (suffixMap[platformType] || "") : ""; return _platformMap[key] + suffix + (version || ""); } } if (throwOnError || throwOnError === undefined) throw("No Apple platform corresponds to target OS list: " + targetOSList); } /** * Returns the localization of the resource at the given path, * or undefined if the path does not contain an {xx}.lproj path segment. */ function localizationKey(path) { return _resourceFileProperties(path)[0]; } /** * Returns the path of a localized resource at the given path, * relative to its containing {xx}.lproj directory, or '.' * if the resource is unlocalized (not contained in an lproj directory). */ function relativeResourcePath(path) { return _resourceFileProperties(path)[1]; } function _resourceFileProperties(path) { var lprojKey = ".lproj/"; var lproj = path.indexOf(lprojKey); if (lproj >= 0) { // The slash preceding XX.lproj var slashIndex = path.slice(0, lproj).lastIndexOf('/'); if (slashIndex >= 0) { var localizationKey = path.slice(slashIndex + 1, lproj); var relativeResourcePath = FileInfo.path(path.slice(lproj + lprojKey.length)); return [ localizationKey, relativeResourcePath ]; } } return [ undefined, '.' ]; } var PropertyListVariableExpander = (function () { function PropertyListVariableExpander() { } /** * Recursively perform variable replacements in an environment dictionary. */ PropertyListVariableExpander.prototype.expand = function (obj, env) { var $this = this; // Possible syntaxes for wrapping an environment variable name var syntaxes = [ {"open": "${", "close": "}"}, {"open": "$(", "close": ")"}, {"open": "@", "close": "@"} ]; /** * Finds the first index of a replacement starting with one of the supported syntaxes * This is needed so we don't do recursive substitutions */ function indexOfReplacementStart(syntaxes, str) { var syntax; var idx = -1; for (var i in syntaxes) { var j; // normal case - we search for the last occurrence to do a correct replacement // for nested variables, e.g. ${VAR1_${VAR2}}. This doesn't work in case // when start == end, e.g. @VAR@ - in that case we search from the start if (syntaxes[i].open !== syntaxes[i].close) j = str.lastIndexOf(syntaxes[i].open); else j = str.indexOf(syntaxes[i].open); if (j > idx) { syntax = syntaxes[i]; idx = j; } } return { "syntax": syntax, "index": idx }; } function expandString(key, str, env, seenVars) { if (!str) return str; var repl = indexOfReplacementStart(syntaxes, str); var i = repl.index; while (i !== -1) { var j = str.indexOf(repl.syntax.close, i + repl.syntax.open.length); if (j === -1) return str; var varParts = str.slice(i + repl.syntax.open.length, j).split(':'); var varName = varParts[0]; var varFormatter = varParts[1]; var envValue = env[varName]; // if we end up expanding the same variable again, break the recursion if (seenVars.indexOf(varName) !== -1) envValue = ""; else seenVars.push(varName); var varValue = expandString(key, envValue, env, seenVars); seenVars.pop(); if (undefined === varValue) { // skip replacement if ($this.undefinedVariableFunction) $this.undefinedVariableFunction(key, varName); varValue = ""; } varValue = String(varValue); if (varFormatter !== undefined) { // TODO: XCode supports multiple formatters separated by a comma var varFormatterLower = varFormatter.toLowerCase(); if (varFormatterLower === "rfc1034identifier" || varFormatterLower === "identifier") varValue = Utilities.rfc1034Identifier(varValue); if (varValue === "" && varFormatterLower.startsWith("default=")) varValue = varFormatter.split("=")[1]; } str = str.slice(0, i) + varValue + str.slice(j + repl.syntax.close.length); repl = indexOfReplacementStart(syntaxes, str); i = repl.index; } return str; } function expandRecursive(obj, env, checked) { checked.push(obj); for (var key in obj) { var value = obj[key]; var type = typeof(value); if (type === "object") { if (checked.indexOf(value) !== -1) continue; expandRecursive(value, env, checked); } if (type !== "string") continue; var expandedValue = expandString(key, value, env, []); if (expandedValue !== value) obj[key] = expandedValue; } } expandRecursive(obj, env, []); return obj; }; return PropertyListVariableExpander; }()); /** * JSON.stringify(expandPlistEnvironmentVariables({a:"$(x)3$$(y)",b:{t:"%$(y) $(k)"}}, * {x:"X",y:"Y"}, true)) * Warning undefined variable k in variable expansion * => {"a":"X3$Y","b":{"t":"%Y $(k)"}} */ function expandPlistEnvironmentVariables(obj, env, warn) { var expander = new PropertyListVariableExpander(); expander.undefinedVariableFunction = function (key, varName) { if (warn) console.warn("undefined variable " + varName + " in variable expansion"); }; return expander.expand(obj, env); } /** * Recursively removes any undefined, null, or empty string values from the property list. */ function cleanPropertyList(plist) { if (typeof(plist) !== "object") return; for (var key in plist) { if (plist[key] === undefined || plist[key] === null || plist[key] === "") delete plist[key]; else cleanPropertyList(plist[key]); } } qbs-src-2.6.1/share/qbs/imports/qbs/PathTools/0000755000175100001660000000000014776170045020536 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/PathTools/path-tools.js0000644000175100001660000002473114776170045023175 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); function _bundleExecutableTemporaryFilePath(product, variantSuffix) { if (variantSuffix === undefined) variantSuffix = product.cpp.variantSuffix; return ".tmp/" + FileInfo.fileName(bundleExecutableFilePath(product, variantSuffix)); } function bundleExecutableFilePath(product, variantSuffix) { if (variantSuffix === undefined) variantSuffix = product.cpp.variantSuffix; return product.moduleProperty("bundle", "executablePath") + (variantSuffix || ""); } function applicationFilePath(product, variantSuffix) { if (variantSuffix === undefined) variantSuffix = product.cpp.variantSuffix; if (product.moduleProperty("bundle", "isBundle")) return _bundleExecutableTemporaryFilePath(product, variantSuffix); return product.moduleProperty("cpp", "executablePrefix") + product.targetName + (variantSuffix || "") + product.moduleProperty("cpp", "executableSuffix"); } function loadableModuleFilePath(product, variantSuffix) { if (variantSuffix === undefined) variantSuffix = product.cpp.variantSuffix; if (product.moduleProperty("bundle", "isBundle")) return _bundleExecutableTemporaryFilePath(product, variantSuffix); return product.moduleProperty("cpp", "loadableModulePrefix") + product.targetName + (variantSuffix || "") + product.moduleProperty("cpp", "loadableModuleSuffix"); } function staticLibraryFilePath(product, variantSuffix) { if (variantSuffix === undefined) variantSuffix = product.cpp.variantSuffix; if (product.moduleProperty("bundle", "isBundle")) return _bundleExecutableTemporaryFilePath(product, variantSuffix); return product.moduleProperty("cpp", "staticLibraryPrefix") + product.targetName + (variantSuffix || "") + product.moduleProperty("cpp", "staticLibrarySuffix"); } function dynamicLibraryFilePath(product, variantSuffix, version, maxParts) { if (variantSuffix === undefined) variantSuffix = product.cpp.variantSuffix; if (product.moduleProperty("bundle", "isBundle")) return _bundleExecutableTemporaryFilePath(product, variantSuffix); // If no override version was given, use the product's version // We specifically want to differentiate between undefined and i.e. // empty string as empty string should be taken to mean "no version" // and undefined should be taken to mean "use the product's version" // (which could still end up being "no version") if (version === undefined) version = product.moduleProperty("cpp", "internalVersion"); // If we have a version number, potentially strip off some components if (maxParts === 0) version = undefined; else if (maxParts && version) version = version.split('.').slice(0, maxParts).join('.'); // Start with prefix + name (i.e. libqbs, qbs) var fileName = product.moduleProperty("cpp", "dynamicLibraryPrefix") + product.targetName + (variantSuffix || ""); // For Mach-O images, append the version number if there is one (i.e. libqbs.1.0.0) var imageFormat = product.moduleProperty("cpp", "imageFormat"); if (version && imageFormat === "macho") { fileName += "." + version; version = undefined; } fileName += product.moduleProperty("cpp", "archSuffix"); // Append the suffix (i.e. libqbs.1.0.0.dylib, libqbs.so, qbs.dll) fileName += product.moduleProperty("cpp", "dynamicLibrarySuffix"); // For ELF images, append the version number if there is one (i.e. libqbs.so.1.0.0) if (version && (imageFormat === "elf" || imageFormat === "wasm")) fileName += "." + version; return fileName; } function linkerOutputFilePath(fileTag, product, variantSuffix, version, maxParts) { switch (fileTag) { case "application": return applicationFilePath(product, variantSuffix); case "loadablemodule": return loadableModuleFilePath(product, variantSuffix); case "staticlibrary": return staticLibraryFilePath(product, variantSuffix); case "dynamiclibrary": return dynamicLibraryFilePath(product, variantSuffix, version, maxParts); default: throw new Error("Unknown linker output file tag: " + fileTag); } } function importLibraryFilePath(product) { return product.moduleProperty("cpp", "dynamicLibraryPrefix") + product.targetName + (product.cpp.variantSuffix || "") + product.moduleProperty("cpp", "dynamicLibraryImportSuffix"); } function debugInfoIsBundle(product) { if (!product.moduleProperty("qbs", "targetOS").contains("darwin")) return false; var flags = product.moduleProperty("cpp", "dsymutilFlags") || []; return !flags.contains("-f") && !flags.contains("--flat"); } function debugInfoFileName(product, variantSuffix, fileTag) { var suffix = ""; // 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.qbs.toolchain.includes("emscripten")) return product.targetName + ".wasm.debug.wasm"; if (product.moduleProperty("bundle", "isBundle")) { return FileInfo.fileName(bundleExecutableFilePath(product, variantSuffix)) + suffix; } else { switch (fileTag) { case "application": return applicationFilePath(product, variantSuffix) + suffix; case "dynamiclibrary": return dynamicLibraryFilePath(product, variantSuffix) + suffix; case "loadablemodule": return loadableModuleFilePath(product, variantSuffix) + suffix; case "staticlibrary": return staticLibraryFilePath(product, variantSuffix) + suffix; default: return product.targetName + (variantSuffix || "") + suffix; } } } function debugInfoBundlePath(product, fileTag) { if (!debugInfoIsBundle(product)) return undefined; var suffix = product.moduleProperty("cpp", "debugInfoBundleSuffix"); if (product.moduleProperty("qbs", "targetOS").contains("darwin") && product.moduleProperty("bundle", "isBundle")) return product.moduleProperty("bundle", "bundleName") + suffix; return debugInfoFileName(product, undefined, fileTag) + suffix; } function debugInfoFilePath(product, variantSuffix, fileTag) { var name = debugInfoFileName(product, variantSuffix, fileTag); if (product.moduleProperty("qbs", "targetOS").contains("darwin") && debugInfoIsBundle(product)) { return FileInfo.joinPaths(debugInfoBundlePath(product, fileTag), "Contents", "Resources", "DWARF", name); } else if (product.moduleProperty("bundle", "isBundle")) { return FileInfo.joinPaths(product.moduleProperty("bundle", "executableFolderPath"), name); } return name; } function debugInfoPlistFilePath(product, fileTag) { if (!debugInfoIsBundle(product)) return undefined; return FileInfo.joinPaths(debugInfoBundlePath(product, fileTag), "Contents", "Info.plist"); } // Returns whether the string looks like a library filename function isLibraryFileName(product, fileName, prefix, suffixes, isShared) { var suffix, i; var os = product.moduleProperty("qbs", "targetOS"); for (i = 0; i < suffixes.length; ++i) { suffix = suffixes[i]; if (isShared && os.contains("unix") && !os.contains("darwin")) suffix += "(\\.[0-9]+){0,3}"; if (fileName.match("^" + prefix + ".+?\\" + suffix + "$")) return true; } return false; } function frameworkExecutablePath(frameworkPath) { var suffix = ".framework"; var isAbsoluteFrameworkPath = frameworkPath.slice(-suffix.length) === suffix; if (isAbsoluteFrameworkPath) { var frameworkName = FileInfo.fileName(frameworkPath).slice(0, -suffix.length); return FileInfo.joinPaths(frameworkPath, frameworkName); } return undefined; } // pathList is also a string, using the respective separator function prependOrSetPath(path, pathList, separator) { if (!pathList || pathList.length === 0) return path; return path + separator + pathList; } function librarySuffixes(targetOS, types, forImport) { if (targetOS.includes("windows")) { if (forImport) { return [] .concat(types.includes("shared") ? [".lib"] : []) // mingw uses .a for static libs .concat(types.includes("static") ? [".lib", ".a"] : []); } return [].concat(types.includes("shared") ? [".dll"] : []); } if (targetOS.includes("darwin")) { return [] .concat(types.includes("shared") ? [".dylib"] : []) .concat(types.includes("static") ? [".a"] : []); } return [] .concat(types.includes("shared") ? [".so"] : []) .concat(types.includes("static") ? [".a"] : []); } function libraryNameFilter() { return function(name) { return [name, "lib" + name]; } } qbs-src-2.6.1/share/qbs/imports/qbs/ModUtils/0000755000175100001660000000000014776170045020361 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/ModUtils/utils.js0000644000175100001660000006244514776170045022072 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function mergeCFiles(inputs, outputFilePath) { var f = new TextFile(outputFilePath, TextFile.WriteOnly); try { for (var i = 0; i < inputs.length; ++i) f.writeLine('#include ' + Utilities.cStringQuote(inputs[i].filePath)); } finally { f.close(); } } function sanitizedList(list, product, fullPropertyName) { if (!(list instanceof Array)) return list; var filterFunc = function(elem) { if (typeof elem === "string" && elem.length === 0) { var msg = "Removing empty string from value of property '" + fullPropertyName + "'"; // product might actually be a module if (product.name) msg += " in product '" + product.name + "'."; console.warn(msg); return false; } return true; } return list.filter(filterFunc); } function checkCompatibilityMode(project, minimumQbsVersion, message) { if (Utilities.versionCompare(project.minimumQbsVersion || "1.3", minimumQbsVersion) < 0) { console.warn([message || "", "This message can be silenced by setting your Project's " + "minimumQbsVersion to " + minimumQbsVersion + " (and the new behavior will take effect)."].join(" ")); return true; } return false; } function artifactInstalledFilePath(artifact) { var relativeInstallDir = artifact.moduleProperty("qbs", "installDir"); var installPrefix = artifact.moduleProperty("qbs", "installPrefix"); var installSourceBase = artifact.moduleProperty("qbs", "installSourceBase"); var targetDir = FileInfo.joinPaths(artifact.moduleProperty("qbs", "installRoot"), installPrefix, relativeInstallDir); if (installSourceBase) { if (!FileInfo.isAbsolutePath(installSourceBase)) throw "installSourceBase is not an absolute path"; if (!artifact.filePath.startsWith(installSourceBase)) throw "artifact file path doesn't start with the value of qbs.installSourceBase"; return FileInfo.joinPaths(targetDir, artifact.filePath.substr(installSourceBase.length)); } return FileInfo.joinPaths(targetDir, artifact.fileName); } /** * Given a list of file tags, returns the file tag (one of [c, cpp, objc, objcpp]) * corresponding to the C-family language the file should be compiled as. * * If no such tag is found, undefined is returned. If more than one match is * found, an exception is thrown. */ function fileTagForTargetLanguage(fileTags) { var srcTags = ["c", "cpp", "objc", "objcpp", "asm", "asm_cpp", "cppm"]; var pchTags = ["c_pch", "cpp_pch", "objc_pch", "objcpp_pch"]; var canonicalTag = undefined; var foundTagCount = 0; for (var i = 0; i < fileTags.length; ++i) { var idx = srcTags.indexOf(fileTags[i]); if (idx === -1) idx = pchTags.indexOf(fileTags[i]); if (idx !== -1) { canonicalTag = srcTags[idx]; if (++foundTagCount > 1) break; } } if (foundTagCount > 1) throw ("source files cannot be identified as more than one language"); return foundTagCount == 1 ? canonicalTag : undefined; } /** * Returns the name of a language-specific property given the file tag * for that property, and the base property name. * * If \a fileTag is undefined, the language-agnostic property name is returned. */ function languagePropertyName(propertyName, fileTag) { if (!fileTag) fileTag = "common"; var asm = { "flags": "assemblerFlags", "platformFlags": "platformAssemblerFlags" }; var map = { "c": { "flags": "cFlags", "platformFlags": "platformCFlags", "usePrecompiledHeader": "useCPrecompiledHeader" }, "cpp": { "flags": "cxxFlags", "platformFlags": "platformCxxFlags", "usePrecompiledHeader": "useCxxPrecompiledHeader" }, "objc": { "flags": "objcFlags", "platformFlags": "platformObjcFlags", "usePrecompiledHeader": "useObjcPrecompiledHeader" }, "objcpp": { "flags": "objcxxFlags", "platformFlags": "platformObjcxxFlags", "usePrecompiledHeader": "useObjcxxPrecompiledHeader" }, "common": { "flags": "commonCompilerFlags", "platformFlags": "platformCommonCompilerFlags" }, "asm": asm, "asm_cpp": asm }; var lang = map[fileTag]; if (!lang) return propertyName; return lang[propertyName] || propertyName; } function modulePropertiesFromArtifacts(product, artifacts, moduleName, propertyName, langFilter) { var result = product.moduleProperty( moduleName, languagePropertyName(propertyName, langFilter)) || []; for (var i in artifacts) { var artifactProp = artifacts[i].moduleProperty( moduleName, languagePropertyName(propertyName, langFilter)); if (artifactProp) result = result.concat(artifactProp); } return sanitizedList(result, product, moduleName + "." + propertyName); } function moduleProperty(product, propertyName, langFilter) { return sanitizedModuleProperty(product, product.moduleName, propertyName, langFilter); } function sanitizedModuleProperty(obj, moduleName, propertyName, langFilter) { return sanitizedList(obj.moduleProperty(moduleName, languagePropertyName(propertyName, langFilter)), obj, moduleName + "." + propertyName); } /** * Returns roughly the same value as moduleProperty for a product, but ensures that all of the * given input artifacts share the same value of said property, as a sort of sanity check. * * This allows us to verify that users do not, for example, try to set different values on input * artifacts for which the value is input specific (not product specific), but which must be the * same for all inputs. */ function modulePropertyFromArtifacts(product, artifacts, moduleName, propertyName, langFilter) { var values = [product.moduleProperty(moduleName, languagePropertyName(propertyName, langFilter))]; for (var i in artifacts) { var value = artifacts[i].moduleProperty(moduleName, languagePropertyName(propertyName, langFilter)); if (!values.contains(value)) { values.push(value); } } if (values.length !== 1) { throw "The value of " + [moduleName, propertyName].join(".") + " must be identical for the following input artifacts: " + artifacts.map(function (artifact) { return artifact.filePath; }); } return values[0]; } function concatAll() { var result = []; for (var i = 0; i < arguments.length; ++i) { var arg = arguments[i]; if (arg === undefined) continue; else if (arg instanceof Array) result = result.concat(arg); else result.push(arg); } return result; } function allFileTags(fileTaggers) { var tags = []; for (var ext in fileTaggers) tags = tags.uniqueConcat(fileTaggers[ext]); return tags; } /** * Flattens a dictionary (string keys to strings) * into a string list containing items like \c key=value1 */ function flattenDictionary(dict, separator) { separator = separator || "="; var list = []; for (var i in dict) { var value = i; if (dict[i] !== undefined) // allow differentiation between undefined and empty string value += separator + dict[i]; list.push(value); } return list; } function ModuleError(message) { var e = new Error(message); e.fileName = ""; return e; } var EnvironmentVariable = (function () { function EnvironmentVariable(name, separator, convertPathSeparators) { if (!name) throw "EnvironmentVariable c'tor needs a name as first argument."; this.name = name; this.value = Environment.getEnv(name) || ""; this.separator = separator || ""; this.convertPathSeparators = convertPathSeparators || false; } EnvironmentVariable.prototype.prepend = function (v) { if (this.value.length > 0 && this.value.charAt(0) !== this.separator) this.value = this.separator + this.value; if (this.convertPathSeparators) v = FileInfo.toWindowsSeparators(v); this.value = v + this.value; }; EnvironmentVariable.prototype.append = function (v) { if (this.value.length > 0) this.value += this.separator; if (this.convertPathSeparators) v = FileInfo.toWindowsSeparators(v); this.value += v; }; EnvironmentVariable.prototype.set = function () { Environment.putEnv(this.name, this.value); }; EnvironmentVariable.prototype.unset = function () { Environment.unsetEnv(this.name); }; return EnvironmentVariable; })(); var PropertyValidator = (function () { function PropertyValidator(moduleName) { this.requiredProperties = {}; this.propertyValidators = []; if (!moduleName) throw "PropertyValidator c'tor needs a module name as a first argument."; this.moduleName = moduleName; } PropertyValidator.prototype.setRequiredProperty = function (propertyName, propertyValue, message) { this.requiredProperties[propertyName] = { propertyValue: propertyValue, message: message }; }; PropertyValidator.prototype.addRangeValidator = function (propertyName, propertyValue, min, max, allowFloats) { var message = []; if (min !== undefined) message.push(">= " + min); if (max !== undefined) message.push("<= " + max); this.addCustomValidator(propertyName, propertyValue, function (value) { if (typeof value !== "number") return false; if (!allowFloats && value % 1 !== 0) return false; if (min !== undefined && value < min) return false; if (max !== undefined && value > max) return false; return true; }, "must be " + (!allowFloats ? "an integer " : "") + message.join(" and ") + ", actual value: " + propertyValue); }; PropertyValidator.prototype.addVersionValidator = function (propertyName, propertyValue, minComponents, maxComponents, allowSuffixes) { if (minComponents !== undefined && (typeof minComponents !== "number" || minComponents % 1 !== 0 || minComponents < 1)) throw "minComponents must be at least 1"; if (maxComponents !== undefined && (typeof maxComponents !== "number" || maxComponents % 1 !== 0 || maxComponents < minComponents)) throw "maxComponents must be >= minComponents"; this.addCustomValidator(propertyName, propertyValue, function (value) { if (typeof value !== "string") return false; return value && value.match("^[0-9]+(\\.[0-9]+){" + ((minComponents - 1) || 0) + "," + ((maxComponents - 1) || "") + "}" + (!allowSuffixes ? "$" : "")) !== null; }, "must be a version number with " + (minComponents === maxComponents ? minComponents : (minComponents + " to " + maxComponents)) + (minComponents === maxComponents && minComponents === 1 ? " component" : " components") + ", actual value: " + propertyValue); }; PropertyValidator.prototype.addFileNameValidator = function (propertyName, propertyValue) { this.addCustomValidator(propertyName, propertyValue, function (value) { return !/[/?<>\\:*|"\u0000-\u001f\u0080-\u009f]/.test(propertyValue) && propertyValue !== "." && propertyValue !== ".."; }, "cannot contain reserved or control characters and cannot be \".\" or \"..\""); }; PropertyValidator.prototype.addCustomValidator = function (propertyName, propertyValue, validator, message) { this.propertyValidators.push({ propertyName: propertyName, propertyValue: propertyValue, validator: validator, message: message }); }; PropertyValidator.prototype.validate = function (throwOnError) { var i; var lines; // Find any missing properties var missingProperties = {}; for (i in this.requiredProperties) { var propValue = this.requiredProperties[i].propertyValue; if (propValue === undefined || propValue === null || propValue === "") { missingProperties[i] = this.requiredProperties[i]; } } // Find any properties that don't satisfy their validator function var invalidProperties = {}; for (var j = 0; j < this.propertyValidators.length; ++j) { var v = this.propertyValidators[j]; if (!v.validator(v.propertyValue)) { var messages = invalidProperties[v.propertyName] || []; messages.push(v.message); invalidProperties[v.propertyName] = messages; } } var errorMessage = ""; if (Object.keys(missingProperties).length > 0) { errorMessage += "The following properties are not set. Set them in your profile or product:\n"; lines = []; for (i in missingProperties) { var obj = missingProperties[i]; lines.push(this.moduleName + "." + i + ((obj && obj.message) ? (": " + obj.message) : "")); } errorMessage += lines.join("\n"); } if (Object.keys(invalidProperties).length > 0) { if (errorMessage) errorMessage += "\n"; errorMessage += "The following properties have invalid values:\n"; lines = []; for (i in invalidProperties) { for (j = 0; j < invalidProperties[i].length; ++j) { lines.push(this.moduleName + "." + i + ": " + invalidProperties[i][j]); } } errorMessage += lines.join("\n"); } if (throwOnError !== false && errorMessage.length > 0) throw errorMessage; return errorMessage.length == 0; }; return PropertyValidator; })(); var BlackboxOutputArtifactTracker = (function () { function BlackboxOutputArtifactTracker() { } BlackboxOutputArtifactTracker.prototype.artifacts = function (outputDirectory) { var process; var fakeOutputDirectory; try { fakeOutputDirectory = new TemporaryDir(); if (!fakeOutputDirectory.isValid()) throw "could not create temporary directory"; process = new Process(); if (this.commandEnvironmentFunction) { var env = this.commandEnvironmentFunction(fakeOutputDirectory.path()); for (var key in env) process.setEnv(key, env[key]); } process.exec(this.command, this.commandArgsFunction(fakeOutputDirectory.path()), true); var artifacts = []; if (this.fileTaggers) { var files = this.findFiles(fakeOutputDirectory.path()); for (var i = 0; i < files.length; ++i) artifacts.push(this.createArtifact(fakeOutputDirectory.path(), files[i])); } if (this.processStdOutFunction) artifacts = artifacts.concat(this.processStdOutFunction(process.readStdOut())); artifacts = this.fixArtifactPaths(artifacts, outputDirectory, fakeOutputDirectory.path()); return artifacts; } finally { if (process) process.close(); if (fakeOutputDirectory) fakeOutputDirectory.remove(); } }; BlackboxOutputArtifactTracker.prototype.createArtifact = function (root, filePath) { for (var ext in this.fileTaggers) { if (filePath.endsWith(ext)) { return { filePath: filePath, fileTags: this.fileTaggers[ext] }; } } if (!this.defaultFileTags) { var relFilePath = (filePath.startsWith(root + '/') || filePath.startsWith(root + '\\')) ? filePath.substring(root.length + 1) : filePath; throw "BlackboxOutputArtifactTracker: no matching file taggers for path '" + relFilePath + "'. Set defaultFileTags to an array of file tags to " + "apply to files not tagged by the fileTaggers map, which was:\n" + JSON.stringify(this.fileTaggers, undefined, 4); } return { filePath: filePath, fileTags: this.defaultFileTags }; }; BlackboxOutputArtifactTracker.prototype.findFiles = function (dir) { var fileList = File.directoryEntries(dir, File.Files).map(function (p) { return FileInfo.joinPaths(dir, p); }); var dirList = File.directoryEntries(dir, File.Dirs | File.NoDotAndDotDot).map(function (p) { return FileInfo.joinPaths(dir, p); }); for (var i = 0; i < dirList.length; ++i) fileList = fileList.concat(this.findFiles(dirList[i])); return fileList; }; BlackboxOutputArtifactTracker.prototype.fixArtifactPaths = function (artifacts, realBasePath, fakeBasePath) { for (var i = 0; i < artifacts.length; ++i) artifacts[i].filePath = realBasePath + artifacts[i].filePath.substr(fakeBasePath.length); return artifacts; }; return BlackboxOutputArtifactTracker; })(); function hasAnyOf(m, tokens) { for (var i = 0; i < tokens.length; ++i) { if (m[tokens[i]] !== undefined) return true; } } function guessArchitecture(m) { var architecture; if (m) { // based on the search algorithm from qprocessordetection.h in qtbase var arm64Defs = ["_M_ARM64", "__aarch64__", "__ARM64__"]; if (hasAnyOf(m, ["__arm__", "__TARGET_ARCH_ARM", "_M_ARM"].concat(arm64Defs))) { if (hasAnyOf(m, arm64Defs)) { architecture = "arm64"; } else { architecture = "arm"; var foundSubarch = false; for (var i = 8; i >= 4; --i) { var codes = ["zk", "tej", "te", "t2"].concat([].concat.apply([], new Array(26)).map(function(_, i) { return String.fromCharCode(122 - i); })); for (var j = 0; j < codes.length; ++j) { if (m["__ARM_ARCH_" + i + codes[j].toUpperCase() + "__"] !== undefined) { architecture += "v" + i + codes[j].toLowerCase(); foundSubarch = true; break; } } if (i === 7 && m["_ARM_ARCH_7"] !== undefined) { architecture += "v7"; foundSubarch = true; } if (foundSubarch) break; } } } else if (hasAnyOf(m, ["__i386", "__i386__", "__386__"])) { architecture = "x86"; } else if (hasAnyOf(m, ["_M_IX86"])) { var code = parseInt(m["_M_IX86"]); architecture = (code < 300) ? "x86_16" : "x86"; } else if (hasAnyOf(m, ["_M_I86"])) { architecture = "x86_16"; } else if (hasAnyOf(m, ["__x86_64", "__x86_64__", "__amd64", "_M_X64", "_M_AMD64"])) { architecture = "x86_64"; if (hasAnyOf(m, ["__x86_64h", "__x86_64h__"])) architecture = "x86_64h"; } else if (hasAnyOf(m, ["__ia64", "__ia64__", "_M_IA64"])) { architecture = "ia64"; } else if (hasAnyOf(m, ["__mips", "__mips__", "_M_MRX000"])) { architecture = "mips"; if (hasAnyOf(m, ["_MIPS_ARCH_MIPS64", "__mips64"])) architecture += "64"; } else if (hasAnyOf(m, ["__ppc__", "__ppc", "__powerpc__", "_ARCH_COM", "_ARCH_PWR", "_ARCH_PPC", "_M_MPPC", "_M_PPC"])) { architecture = "ppc"; if (hasAnyOf(m, ["__ppc64__", "__powerpc64__", "__64BIT__"])) architecture += "64"; } else if (hasAnyOf(m, ["__s390__"])) { if (hasAnyOf(m, ["__s390x__"])) architecture = "s390x"; } else if (hasAnyOf(m, ["__sparc__"])) { architecture = "sparc"; if (hasAnyOf(m, ["__sparc64__"])) architecture += "64"; } else if (hasAnyOf(m, ["__AVR__"])) { architecture = "avr"; } else if (hasAnyOf(m, ["__AVR32__"])) { architecture = "avr32"; } else if (hasAnyOf(m, ["__MSP430__"])) { architecture = "msp430"; } else if (hasAnyOf(m, ["__RL78__"])) { architecture = "rl78"; } else if (hasAnyOf(m, ["__RX__"])) { architecture = "rx"; } else if (hasAnyOf(m, ["__v850__"])) { architecture = "v850"; } else if (hasAnyOf(m, ["__riscv"])) { architecture = "riscv"; } else if (hasAnyOf(m, ["__xtensa__", "__XTENSA__"])) { architecture = "xtensa"; } else if (hasAnyOf(m, ["__m68k__"])) { architecture = "m68k"; } else if (hasAnyOf(m, ["__m32c__"])) { architecture = "m32c"; } else if (hasAnyOf(m, ["__m32r__", "__M32R__"])) { architecture = "m32r"; } else if (hasAnyOf(m, ["__sh__", "__SH__"])) { architecture = "sh"; } else if (hasAnyOf(m, ["__CR16__"])) { architecture = "cr16"; } else if (hasAnyOf(m, ["__mc68hc1x__", "__mc68hc1x"])) { architecture = "hcs12"; } else if (hasAnyOf(m, ["__e2k__"])) { architecture = "e2k"; } else if (hasAnyOf(m, ["__hppa__"])) { architecture = "hppa"; } } return Utilities.canonicalArchitecture(architecture); } function guessTargetPlatform(m) { if (m) { if (hasAnyOf(m, ["__ANDROID__", "ANDROID"])) return "android"; if (hasAnyOf(m, ["__QNXNTO__"])) return "qnx"; if (hasAnyOf(m, ["__INTEGRITY"])) return "integrity"; if (hasAnyOf(m, ["__vxworks"])) return "vxworks"; if (hasAnyOf(m, ["__APPLE__"])) return "darwin"; if (hasAnyOf(m, ["WIN32", "_WIN32", "__WIN32__", "__NT__", "__WINDOWS__", "_WINDOWS"])) return "windows"; if (hasAnyOf(m, ["MSDOS", "__DOS__", "DOS386"])) return "dos"; if (hasAnyOf(m, ["__OS2__"])) return "os2"; if (hasAnyOf(m, ["_AIX"])) return "aix"; if (hasAnyOf(m, ["hpux", "__hpux"])) return "hpux"; if (hasAnyOf(m, ["__sun", "sun"])) return "solaris"; if (hasAnyOf(m, ["__linux__", "__linux", "__LINUX__"])) return "linux"; if (hasAnyOf(m, ["__FreeBSD__", "__DragonFly__", "__FreeBSD_kernel__"])) return "freebsd"; if (hasAnyOf(m, ["__NetBSD__"])) return "netbsd"; if (hasAnyOf(m, ["__OpenBSD__"])) return "openbsd"; if (hasAnyOf(m, ["__GNU__"])) return "hurd"; if (hasAnyOf(m, ["__HAIKU__"])) return "haiku"; if (hasAnyOf(m, ["__wasm__"])) return "wasm-emscripten" } } function toJSLiteral(v) { if (v === undefined) return "undefined"; return JSON.stringify(v); } qbs-src-2.6.1/share/qbs/imports/qbs/BundleTools/0000755000175100001660000000000014776170045021053 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/BundleTools/bundle-tools.js0000644000175100001660000000603514776170045024024 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var DarwinTools = require("qbs.DarwinTools"); var PropertyList = require("qbs.PropertyList"); function destinationDirectoryForResource(product, input) { var path = product.destinationDirectory; var inputFilePath = FileInfo.joinPaths(input.baseDir, input.fileName); var key = DarwinTools.localizationKey(inputFilePath); if (key) { path = FileInfo.joinPaths(path, localizedResourcesFolderPath(product, key)); var subPath = DarwinTools.relativeResourcePath(inputFilePath); if (subPath && subPath !== '.') path = FileInfo.joinPaths(path, subPath); } else { path = FileInfo.joinPaths(path, product.moduleProperty("bundle", "unlocalizedResourcesFolderPath")); } return path; } function localizedResourcesFolderPath(product, key) { return FileInfo.joinPaths(product.moduleProperty("bundle", "unlocalizedResourcesFolderPath"), key + product.moduleProperty("bundle", "localizedResourcesFolderSuffix")); } function infoPlistContents(infoPlistFilePath) { if (infoPlistFilePath === undefined) return undefined; var plist = new PropertyList(); try { plist.readFromFile(infoPlistFilePath); return plist.toObject(); } finally { plist.clear(); } } function infoPlistFormat(infoPlistFilePath) { if (infoPlistFilePath === undefined) return undefined; var plist = new PropertyList(); try { plist.readFromFile(infoPlistFilePath); return plist.format(); } finally { plist.clear(); } } qbs-src-2.6.1/share/qbs/imports/qbs/base/0000755000175100001660000000000014776170045017533 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/base/LoadableModule.qbs0000644000175100001660000000305414776170045023115 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ DynamicLibrary { type: isForDarwin ? ["loadablemodule"] : base } qbs-src-2.6.1/share/qbs/imports/qbs/base/DynamicLibrary.qbs0000644000175100001660000000310614776170045023153 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Library { type: ["dynamiclibrary"].concat(isForAndroid ? ["android.nativelibrary"] : []) } qbs-src-2.6.1/share/qbs/imports/qbs/base/NetModule.qbs0000644000175100001660000000010414776170045022131 0ustar runnerdockerProduct { Depends { name: "cli" } type: ["cli.netmodule"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/StaticLibrary.qbs0000644000175100001660000000301714776170045023017 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Library { type: ["staticlibrary"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/QtGuiApplication.qbs0000644000175100001660000000303014776170045023453 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ QtApplication { Depends { name: "Qt.gui" } } qbs-src-2.6.1/share/qbs/imports/qbs/base/WindowsSetupPackage.qbs0000644000175100001660000000312314776170045024170 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "wix"; condition: qbs.targetOS.contains("windows") } type: ["wixsetup"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/JavaClassCollection.qbs0000644000175100001660000000305114776170045024124 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "java" } type: ["java.class"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/NativeBinary.qbs0000644000175100001660000000562114776170045022641 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { property bool isForAndroid: qbs.targetOS.contains("android") property bool isForDarwin: qbs.targetOS.contains("darwin") property bool isBundle: isForDarwin && bundle.isBundle property bool install: false property string installDir // Product artifacts should be installed if it's not multiplexed or aggregated, // or if it is multiplexed and it's the aggregate product readonly property bool _installable: !multiplexed || !aggregate || !multiplexConfigurationId property bool installDebugInformation: install property string debugInformationInstallDir: installDir Depends { name: "bundle"; condition: isForDarwin } aggregate: { if (!isForDarwin) return false; var multiplexProps = multiplexByQbsProperties; if (!multiplexProps) return false; if (multiplexProps.contains("architectures")) { var archs = qbs.architectures; if (archs && archs.length > 1) return true; } if (multiplexProps.contains("buildVariants")) { var variants = qbs.buildVariants; return variants && variants.length > 1; } return false; } multiplexByQbsProperties: { if (isForDarwin) return ["profiles", "architectures", "buildVariants"]; if (isForAndroid) return ["architectures"] return ["profiles"]; } } qbs-src-2.6.1/share/qbs/imports/qbs/base/JavaJarFile.qbs0000644000175100001660000000310614776170045022360 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "java" } type: ["java.jar"] property string entryPoint } qbs-src-2.6.1/share/qbs/imports/qbs/base/NSISSetup.qbs0000644000175100001660000000312514776170045022040 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "nsis"; condition: qbs.targetOS.contains("windows") } type: ["nsissetup"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/QtModule.qbs0000644000175100001660000000735514776170045022006 0ustar runnerdockerimport qbs.FileInfo Module { condition: (qbs.targetPlatform === targetPlatform || isCombinedUIKitBuild) && (!qbs.architecture || architectures.length === 0 || architectures.contains(qbs.architecture)) readonly property bool isCombinedUIKitBuild: ["ios", "tvos", "watchos"].contains(targetPlatform) && ["x86", "x86_64"].contains(qbs.architecture) && qbs.targetPlatform === targetPlatform + "-simulator" Depends { name: "cpp" } Depends { name: "Qt.core" } Depends { name: "Qt.plugin_support" } property stringList pluginTypes Qt.plugin_support.pluginTypes: pluginTypes Depends { condition: Qt.core.staticBuild && !isPlugin name: "Qt"; submodules: { // We have to pull in all plugins here, because dependency resolving happens // before module merging, and we don't know yet if someone set // Qt.pluginSupport.pluginsByType in the product. // TODO: We might be able to use Qt.pluginSupport.pluginsByType now. // The real filtering is done later by the plugin module files themselves. var list = []; var allPlugins = Qt.plugin_support.allPluginsByType; for (var i = 0; i < (pluginTypes || []).length; ++i) Array.prototype.push.apply(list, allPlugins[pluginTypes[i]]) return list; } } property string qtModuleName property path binPath: Qt.core.binPath property path incPath: Qt.core.incPath property path libPath: Qt.core.libPath property string qtLibInfix: Qt.core.libInfix property string libNameForLinkerDebug property string libNameForLinkerRelease property string libNameForLinker: Qt.core.qtBuildVariant === "debug" ? libNameForLinkerDebug : libNameForLinkerRelease property string libFilePathDebug property string libFilePathRelease property string libFilePath: Qt.core.qtBuildVariant === "debug" ? libFilePathDebug : libFilePathRelease property bool hasLibrary: true property bool isStaticLibrary: false property bool isPlugin: false property stringList architectures property string targetPlatform property stringList staticLibsDebug property stringList staticLibsRelease property stringList dynamicLibsDebug property stringList dynamicLibsRelease property stringList linkerFlagsDebug property stringList linkerFlagsRelease property stringList staticLibs: Qt.core.qtBuildVariant === "debug" ? staticLibsDebug : staticLibsRelease property stringList dynamicLibs: Qt.core.qtBuildVariant === "debug" ? dynamicLibsDebug : dynamicLibsRelease property stringList frameworksDebug property stringList frameworksRelease property stringList frameworkPathsDebug property stringList frameworkPathsRelease property stringList mFrameworks: Qt.core.qtBuildVariant === "debug" ? frameworksDebug : frameworksRelease property stringList mFrameworkPaths: Qt.core.qtBuildVariant === "debug" ? frameworkPathsDebug: frameworkPathsRelease cpp.linkerFlags: Qt.core.qtBuildVariant === "debug" ? linkerFlagsDebug : linkerFlagsRelease property bool enableLinking: qtModuleName != undefined && hasLibrary property stringList moduleConfig Properties { condition: enableLinking cpp.staticLibraries: staticLibs cpp.dynamicLibraries: dynamicLibs cpp.frameworks: mFrameworks.concat(!isStaticLibrary && Qt.core.frameworkBuild ? [libNameForLinker] : []) cpp.systemFrameworkPaths: mFrameworkPaths } } qbs-src-2.6.1/share/qbs/imports/qbs/base/AppleApplicationDiskImage.qbs0000644000175100001660000001170714776170045025253 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils AppleDiskImage { property string sourceBase: "/Applications" readonly property string absoluteSourceBase: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, sourceBase) property stringList symlinks: ["/Applications:Applications"] readonly property string stageDirectory: FileInfo.joinPaths(destinationDirectory, "Volumes", dmg.volumeName) Rule { multiplex: true outputFileTags: ["dmg.input", "dmg.input.symlink"] outputArtifacts: Array.prototype.map.call(product.symlinks, function (symlink) { var symlinkTarget = symlink.split(':')[0]; var symlinkName = symlink.split(':')[1] || symlinkTarget; if (FileInfo.isAbsolutePath(symlinkName)) throw(symlink + " is an invalid symlink; the destination must be a relative path"); return { filePath: FileInfo.joinPaths(product.stageDirectory, symlinkName), fileTags: ["dmg.input", "dmg.input.symlink"], dmg: { symlinkTarget: symlinkTarget, sourceBase: product.stageDirectory }, }; }) prepare: Array.prototype.map.call(outputs["dmg.input"], function (symlink) { var cmd = new Command("ln", ["-sfn", symlink.dmg.symlinkTarget, symlink.filePath]); cmd.workingDirectory = product.stageDirectory; cmd.description = "symlinking " + symlink.fileName + " to " + symlink.dmg.symlinkTarget; return cmd; }); } Rule { multiplex: true inputs: ["dmg.input.symlink"] inputsFromDependencies: ["installable"] outputFileTags: ["dmg.input"] outputArtifacts: { var absSourceBase = product.absoluteSourceBase; var symlinkPaths = (inputs["dmg.input.symlink"] || []).map(function (s) { return s.filePath; }); return Array.prototype.map.call(inputs["installable"], function (a) { var fp = ModUtils.artifactInstalledFilePath(a); if (fp.startsWith(absSourceBase)) { var outputFilePath = fp.replace(absSourceBase, product.stageDirectory); // Check for symlink conflicts for (var i in symlinkPaths) { if (outputFilePath.startsWith(symlinkPaths[i])) throw new Error("Cannot install '" + a.filePath + "' to '" + outputFilePath + "' because it " + "would conflict with the symlink at '" + symlinkPaths[i] + "'"); } return { filePath: outputFilePath, fileTags: ["dmg.input"], dmg: { sourceBase: product.stageDirectory } } } }).filter(function (a) { return !!a; }); } prepare: { var absSourceBase = product.absoluteSourceBase; var cmds = [], dmgs = outputs["dmg.input"]; for (var i in dmgs) { var a = dmgs[i]; var cmd = new JavaScriptCommand(); cmd.src = a.filePath.replace(product.stageDirectory, absSourceBase); cmd.dst = a.filePath; cmd.silent = true; cmd.sourceCode = function () { File.copy(src, dst); }; cmds.push(cmd); } return cmds; } } } qbs-src-2.6.1/share/qbs/imports/qbs/base/QtPlugin.qbs0000644000175100001660000000324314776170045022007 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile QtModule { isPlugin: true property string className property stringList extendsModules enableLinking: { if (!base) return false; if (!isStaticLibrary) return false; if (!Qt.plugin_support.linkPlugins) return false; if (!(Qt.plugin_support.enabledPlugins || []).contains(qtModuleName)) return false; if (!extendsModules || extendsModules.length === 0) return true; for (var i = 0; i < extendsModules.length; ++i) { var moduleName = extendsModules[i]; if (product.Qt[moduleName] && product.Qt[moduleName].present) return true; } return false; } Rule { condition: enableLinking multiplex: true Artifact { filePath: product.targetName + "_qt_plugin_import_" + product.moduleProperty(product.moduleName, "qtModuleName") + ".cpp" fileTags: ["cpp", "qt.untranslatable"] } prepare: { var cmd = new JavaScriptCommand(); var pluginName = product.moduleProperty(product.moduleName, "qtModuleName"); cmd.description = "creating static import for plugin '" + pluginName + "'"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); var className = product.moduleProperty(product.moduleName, "className"); f.writeLine("#include \n\nQ_IMPORT_PLUGIN(" + className + ")"); f.close(); }; return cmd; } } } qbs-src-2.6.1/share/qbs/imports/qbs/base/XPCService.qbs0000644000175100001660000000354414776170045022223 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Application { type: base.concat(["xpcservice"]) condition: qbs.targetOS.contains("darwin") property string xpcServiceType: "Application" bundle.infoPlist: { var infoPlist = base; if (xpcServiceType) { infoPlist["XPCService"] = { "ServiceType": xpcServiceType }; } return infoPlist; } } qbs-src-2.6.1/share/qbs/imports/qbs/base/InstallPackage.qbs0000644000175100001660000000530614776170045023130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.ModUtils import qbs.TextFile Product { type: ["archiver.archive"] builtByDefault: false Depends { name: "archiver" } archiver.type: "tar" archiver.workingDirectory: qbs.installRoot Rule { multiplex: true inputsFromDependencies: ["installable"] Artifact { filePath: product.name + ".tarlist" fileTags: ["archiver.input-list"] } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode =function() { var ofile = new TextFile(output.filePath, TextFile.WriteOnly); try { for (var i = 0; i < inputs["installable"].length; ++i) { var inp = inputs["installable"][i]; var installRoot = inp.moduleProperty("qbs", "installRoot"); var installedFilePath = ModUtils.artifactInstalledFilePath(inp); ofile.writeLine(FileInfo.relativePath(installRoot, installedFilePath)); } } finally { ofile.close(); } }; return [cmd]; } } } qbs-src-2.6.1/share/qbs/imports/qbs/base/QtApplication.qbs0000644000175100001660000000303214776170045023010 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ CppApplication { Depends { name: "Qt.core" } } qbs-src-2.6.1/share/qbs/imports/qbs/base/NodeJSApplication.qbs0000644000175100001660000000302214776170045023545 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "nodejs" } } qbs-src-2.6.1/share/qbs/imports/qbs/base/WindowsInstallerPackage.qbs0000644000175100001660000000311614776170045025027 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "wix"; condition: qbs.targetOS.contains("windows") } type: ["msi"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/CppApplication.qbs0000644000175100001660000000305514776170045023153 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Application { Depends { name: "cpp" } usesNativeCode: true } qbs-src-2.6.1/share/qbs/imports/qbs/base/AppleDiskImage.qbs0000644000175100001660000000304514776170045023063 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { Depends { name: "dmg" } type: ["dmg.dmg"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/ApplicationExtension.qbs0000644000175100001660000000550014776170045024402 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ XPCService { Depends { name: "xcode" } type: base.concat(["applicationextension"]) property bool _useLegacyExtensionLibraries: qbs.targetOS.contains("macos") && xcode.present && parseInt(xcode.sdkVersion.split(".")[1], 10) < 11 || qbs.targetOS.contains("ios") && xcode.present && parseInt(xcode.sdkVersion.split(".")[0], 10) < 9 cpp.entryPoint: "_NSExtensionMain" cpp.frameworkPaths: base.concat(_useLegacyExtensionLibraries ? qbs.sysroot + "/System/Library/PrivateFrameworks/" : []) cpp.frameworks: { var frameworks = base.concat(["Foundation"]); if (_useLegacyExtensionLibraries) frameworks.push("PlugInKit"); return frameworks; } cpp.requireAppExtensionSafeApi: true xpcServiceType: undefined property var extensionAttributes property string extensionPointIdentifier property string extensionPrincipalClass bundle.infoPlist: { var infoPlist = base; infoPlist["NSExtension"] = { "NSExtensionAttributes": extensionAttributes || {}, "NSExtensionPointIdentifier": extensionPointIdentifier, "NSExtensionPrincipalClass": extensionPrincipalClass }; return infoPlist; } } qbs-src-2.6.1/share/qbs/imports/qbs/base/InnoSetup.qbs0000644000175100001660000000326414776170045022173 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Product { condition: qbs.targetOS.contains("windows") && innosetup.present Depends { name: "innosetup"; condition: qbs.targetOS.contains("windows"); required: false } type: ["innosetup.exe"] } qbs-src-2.6.1/share/qbs/imports/qbs/base/Library.qbs0000644000175100001660000000701114776170045021645 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ NativeBinary { type: { if (qbs.targetOS.contains("ios") && parseInt(cpp.minimumIosVersion, 10) < 8) return ["staticlibrary"]; return ["dynamiclibrary"].concat(isForAndroid ? ["android.nativelibrary"] : []); } readonly property bool isDynamicLibrary: type.contains("dynamiclibrary") readonly property bool isStaticLibrary: type.contains("staticlibrary") readonly property bool isLoadableModule: type.contains("loadablemodule") installDir: { if (isBundle) return "Library/Frameworks"; if (isDynamicLibrary) return qbs.targetOS.contains("windows") ? "bin" : "lib"; if (isStaticLibrary) return "lib"; } property bool installImportLib: false property string importLibInstallDir: "lib" Group { condition: install && _installable fileTagsFilter: { if (isBundle) return ["bundle.content"]; if (isDynamicLibrary) return ["dynamiclibrary", "dynamiclibrary_symlink"]; if (isStaticLibrary) return ["staticlibrary"]; if (isLoadableModule) return ["loadablemodule"]; return []; } qbs.install: true qbs.installDir: installDir qbs.installSourceBase: isBundle ? destinationDirectory : outer } Group { condition: installImportLib && type.contains("dynamiclibrary") && _installable fileTagsFilter: "dynamiclibrary_import" qbs.install: true qbs.installDir: importLibInstallDir } Group { condition: installDebugInformation && _installable fileTagsFilter: { if (isDynamicLibrary) return ["debuginfo_dll"]; else if (isLoadableModule) return ["debuginfo_loadablemodule"]; return []; } qbs.install: true qbs.installDir: debugInformationInstallDir qbs.installSourceBase: destinationDirectory } } qbs-src-2.6.1/share/qbs/imports/qbs/base/QtLupdateRunner.qbs0000644000175100001660000001433214776170045023342 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.TextFile import qbs.Utilities Product { condition: Utilities.versionCompare(Qt.core.version, "5.13") >= 0 name: "lupdate-runner" type: "lupdate-result" builtByDefault: false property bool limitToSubProject: true property stringList extraArguments Depends { name: "Qt.core" } Depends { productTypes: "qm"; limitToSubProject: product.limitToSubProject } Rule { multiplex: true auxiliaryInputsFromDependencies: ["cpp", "objcpp", "qt.qml.qml", "qt.qml.js", "ui"] excludedInputs: "qt.untranslatable" Artifact { filePath: "lupdate.json" fileTags: "lupdate_json" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating lupdate project file"; cmd.highlight = "filegen"; cmd.sourceCode = function() { /* * From the original commit message in qttools: * Project ::= { * string projectFile // Name of the project file. * string codec // Source code codec. Valid values are * // currently "utf-16" or "utf-8" (default). * string[] translations // List of .ts files of the project. * string[] includePaths // List of include paths. * string[] sources // List of source files. * string[] excluded // List of source files, which are * // excluded for translation. * Project[] subProjects // List of sub-projects. * } */ var mainProject = { projectFile: "main", sources: [], translations: [], subProjects: [] }; var cxxArtifactsByIncludePaths = {}; function handleProduct(product) { (product.artifacts["ts"] || []).forEach(function(artifact) { mainProject.translations.push(artifact.filePath); }); ["qt.qml.qml", "qt.qml.js", "ui"].forEach(function(tag) { (product.artifacts[tag] || []).forEach(function(artifact) { mainProject.sources.push(artifact.filePath); }); }); ["cpp", "objcpp"].forEach(function(tag) { (product.artifacts[tag] || []).forEach(function(artifact) { if (!artifact.cpp || artifact.fileTags.contains("qt.untranslatable")) return; var key = (artifact.cpp.includePaths || []).join(""); var current = cxxArtifactsByIncludePaths[key] || []; current.push(artifact); cxxArtifactsByIncludePaths[key] = current; }); }); }; product.dependencies.forEach(function(dep) { if (!dep.present) handleProduct(dep); }); var cxxProductNr = 0; for (key in cxxArtifactsByIncludePaths) { var artifactList = cxxArtifactsByIncludePaths[key]; var cxxProject = { projectFile: "cxx " + ++cxxProductNr, includePaths: artifactList[0].cpp.includePaths, sources: [] }; artifactList.forEach(function(artifact) { cxxProject.sources.push(artifact.filePath); }); mainProject.subProjects.push(cxxProject); } (new TextFile(output.filePath, TextFile.WriteOnly)).write( JSON.stringify(mainProject)); } return cmd; } } // This is a pure action target that intentionally does not do any change tracking. // It is implemented this way because it writes source files and therefore needs to be able // to overwrite user edits (e.g. accidental removal of a source string). Rule { inputs: "lupdate_json" outputFileTags: "lupdate-result" prepare: { var tool = product.Qt.core.binPath + '/' + product.Qt.core.lupdateName; var args = ["-project", inputs.lupdate_json[0].filePath] .concat(product.extraArguments || []); var cmd = new Command(tool, args); cmd.description = "updating translation files"; return cmd; } } } qbs-src-2.6.1/share/qbs/imports/qbs/base/Application.qbs0000644000175100001660000000635514776170045022516 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ NativeBinary { type: isForAndroid && !consoleApplication ? ["android.package"] : ["application"] property bool usesNativeCode Depends { // Note: If we are multiplexing, then this dependency is technically only needed in // the aggregate. However, the user should not have to write the respective // condition when assigning to properties of this module, so we load it // regardless and turn off its rules for the native part of the build. name: "Android.sdk" condition: isForAndroid && !consoleApplication } Properties { condition: isForAndroid && !consoleApplication && !usesNativeCode multiplexByQbsProperties: [] aggregate: false } Properties { condition: isForAndroid && !consoleApplication && usesNativeCode && multiplexByQbsProperties && multiplexByQbsProperties.contains("architectures") && qbs.architectures && qbs.architectures.length > 1 aggregate: true multiplexedType: "android.nativelibrary" } Properties { condition: undefined multiplexByQbsProperties: base multiplexedType: base } aggregate: base installDir: isBundle ? "Applications" : "bin" Group { condition: install && _installable fileTagsFilter: isBundle ? "bundle.content" : "application" qbs.install: true qbs.installDir: installDir qbs.installSourceBase: isBundle ? destinationDirectory : outer } Group { condition: installDebugInformation && _installable fileTagsFilter: ["debuginfo_app"] qbs.install: true qbs.installDir: debugInformationInstallDir qbs.installSourceBase: destinationDirectory } } qbs-src-2.6.1/share/qbs/imports/qbs/base/AndroidApk.qbs0000644000175100001660000000317414776170045022263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo Product { type: ["android.package"] qbs.targetPlatform: "android" Depends { name: "Android.sdk" } } qbs-src-2.6.1/share/qbs/imports/qbs/base/AutotestRunner.qbs0000644000175100001660000001101014776170045023235 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils Product { name: "autotest-runner" type: ["autotest-result"] builtByDefault: false property stringList arguments: [] property stringList environment: ModUtils.flattenDictionary(qbs.commonRunEnvironment) property bool limitToSubProject: true property stringList wrapper: [] property string workingDir property stringList auxiliaryInputs property int timeout: -1 Depends { productTypes: "autotest" limitToSubProject: product.limitToSubProject } Depends { productTypes: auxiliaryInputs limitToSubProject: product.limitToSubProject } Rule { inputsFromDependencies: "application" auxiliaryInputsFromDependencies: product.auxiliaryInputs outputFileTags: "autotest-result" prepare: { // TODO: This is hacky. Possible solution: Add autotest tag to application // in autotest module and have that as inputsFromDependencies instead of application. if (!input.product.type.contains("autotest")) { var cmd = new JavaScriptCommand(); cmd.silent = true; return cmd; } var commandFilePath; var installed = input.moduleProperty("qbs", "install"); if (installed) commandFilePath = ModUtils.artifactInstalledFilePath(input); if (!commandFilePath || !File.exists(commandFilePath)) commandFilePath = input.filePath; var workingDir = product.workingDir ? product.workingDir : FileInfo.path(commandFilePath); var arguments = product.arguments; var allowFailure = false; var timeout = product.timeout; if (input.autotest) { // FIXME: We'd like to let the user override with an empty list, but // qbscore turns undefined lists into empty ones at the moment. if (input.autotest.arguments && input.autotest.arguments.length > 0) arguments = input.autotest.arguments; if (input.autotest.workingDir) workingDir = input.autotest.workingDir; allowFailure = input.autotest.allowFailure; if (input.autotest.timeout !== undefined) timeout = input.autotest.timeout; } var fullCommandLine = product.wrapper .concat([commandFilePath]) .concat(arguments); var cmd = new Command(fullCommandLine[0], fullCommandLine.slice(1)); cmd.description = "running test " + input.fileName; cmd.environment = product.environment; cmd.workingDirectory = workingDir; cmd.timeout = timeout; cmd.jobPool = "autotest-runner"; if (allowFailure) cmd.maxExitCode = 32767; return cmd; } } } qbs-src-2.6.1/share/qbs/imports/qbs/UnixUtils/0000755000175100001660000000000014776170045020565 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/UnixUtils/unix-utils.js0000644000175100001660000000533014776170045023245 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); function soname(product, outputFileName) { var soVersion = product.moduleProperty("cpp", "soVersion"); if (product.moduleProperty("qbs", "targetOS").contains("darwin")) { // If this is a bundle, ignore the parameter and use the relative path to the bundle binary // For example: qbs.framework/Versions/1/qbs if (product.moduleProperty("bundle", "isBundle")) outputFileName = product.moduleProperty("bundle", "executablePath"); } else if (soVersion) { // For non-Darwin platforms, append the shared library major version number to the soname // For example: libqbscore.so.1 var version = product.moduleProperty("cpp", "internalVersion"); if (version) { outputFileName = outputFileName.substr(0, outputFileName.length - version.length) + soVersion; } else { outputFileName += "." + soVersion; } } // Prepend the soname prefix // For example, @rpath/libqbscore.dylib or /usr/lib/libqbscore.so.1 var prefix = product.moduleProperty("cpp", "sonamePrefix"); if (prefix) outputFileName = FileInfo.joinPaths(prefix, outputFileName); return outputFileName; } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/0000755000175100001660000000000014776170045020053 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/Probes/ClangClProbe.qbs0000644000175100001660000001001414776170045023051 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Utilities import "../../../modules/cpp/gcc.js" as Gcc PathProbe { // Inputs property string compilerFilePath property string vcvarsallFilePath property stringList enableDefinesByLanguage property string preferredArchitecture property string winSdkVersion // Outputs property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property string architecture property var buildEnv property var compilerDefinesByLanguage configure: { var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; var info = languages.contains("c") ? Utilities.clangClCompilerInfo( compilerFilePath, preferredArchitecture, vcvarsallFilePath, "c", winSdkVersion) : {}; var infoCpp = languages.contains("cpp") ? Utilities.clangClCompilerInfo( compilerFilePath, preferredArchitecture, vcvarsallFilePath, "cpp", winSdkVersion) : {}; found = (!languages.contains("c") || (!!info && !!info.macros && !!info.buildEnvironment)) && (!languages.contains("cpp") || (!!infoCpp && !!infoCpp.macros && !!infoCpp.buildEnvironment)); compilerDefinesByLanguage = { "c": info.macros, "cpp": infoCpp.macros, }; var macros = info.macros || infoCpp.macros; versionMajor = parseInt(macros["__clang_major__"], 10); versionMinor = parseInt(macros["__clang_minor__"], 10); versionPatch = parseInt(macros["__clang_patchlevel__"], 10); buildEnv = info.buildEnvironment || infoCpp.buildEnvironment; // clang-cl is just a wrapper around clang.exe, so the includes *should be* the same var clangPath = FileInfo.joinPaths(FileInfo.path(compilerFilePath), "clang.exe"); var defaultPaths = Gcc.dumpDefaultPaths(buildEnv, clangPath, [], Host.nullDevice(), FileInfo.pathListSeparator(), "", ""); includePaths = defaultPaths.includePaths; architecture = ModUtils.guessArchitecture(macros); } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/MsvcProbe.qbs0000644000175100001660000000763414776170045022474 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Utilities PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage property string preferredArchitecture property string winSdkVersion // Outputs property string architecture property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var buildEnv property var compilerDefinesByLanguage configure: { var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; var info = languages.contains("c") ? Utilities.msvcCompilerInfo(compilerFilePath, "c", winSdkVersion) : {}; var infoCpp = languages.contains("cpp") ? Utilities.msvcCompilerInfo(compilerFilePath, "cpp", winSdkVersion) : {}; found = (!languages.contains("c") || (!!info && !!info.macros && !!info.buildEnvironment)) && (!languages.contains("cpp") || (!!infoCpp && !!infoCpp.macros && !!infoCpp.buildEnvironment)); compilerDefinesByLanguage = { "c": info.macros, "cpp": infoCpp.macros, }; var macros = info.macros || infoCpp.macros; architecture = ModUtils.guessArchitecture(macros); var ver = macros["_MSC_FULL_VER"]; versionMajor = parseInt(ver.substr(0, 2), 10); versionMinor = parseInt(ver.substr(2, 2), 10); versionPatch = parseInt(ver.substr(4), 10); buildEnv = info.buildEnvironment || infoCpp.buildEnvironment; var clParentDir = FileInfo.joinPaths(FileInfo.path(compilerFilePath), ".."); var inclPath = FileInfo.joinPaths(clParentDir, "INCLUDE"); if (!File.exists(inclPath)) inclPath = FileInfo.joinPaths(clParentDir, "..", "INCLUDE"); if (!File.exists(inclPath)) inclPath = FileInfo.joinPaths(clParentDir, "..", "..", "INCLUDE"); if (File.exists(inclPath)) includePaths = [inclPath]; if (preferredArchitecture && Utilities.canonicalArchitecture(preferredArchitecture) !== Utilities.canonicalArchitecture(architecture)) { throw "'" + preferredArchitecture + "' differs from the architecture produced by this compiler (" + architecture + ")"; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/IarProbe.qbs0000644000175100001660000000626114776170045022272 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import "../../../modules/cpp/iar.js" as IAR PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage // Outputs property string architecture property string endianness property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var compilerDefinesByLanguage configure: { compilerDefinesByLanguage = {}; if (!File.exists(compilerFilePath)) { found = false; return; } var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; var defaultPathsByLanguage = {}; for (var i = 0; i < languages.length; ++i) { var tag = languages[i]; compilerDefinesByLanguage[tag] = IAR.dumpMacros( compilerFilePath, tag); var paths = IAR.dumpDefaultPaths(compilerFilePath, tag); defaultPathsByLanguage[tag] = paths; } var macros = compilerDefinesByLanguage["c"] || compilerDefinesByLanguage["cpp"]; architecture = IAR.guessArchitecture(macros); endianness = IAR.guessEndianness(macros); var defaultPaths = defaultPathsByLanguage["cpp"] || defaultPathsByLanguage["c"]; includePaths = defaultPaths.includePaths; var version = IAR.guessVersion(macros, architecture); if (version) { versionMajor = version.major; versionMinor = version.minor; versionPatch = version.patch; found = !!architecture && !!endianness; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/IcoUtilsVersionProbe.qbs0000644000175100001660000000335414776170045024660 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "../../../modules/ico/ico.js" as IcoUtils Probe { // Inputs property string toolFilePath // Outputs property var version configure: { version = IcoUtils.findIcoUtilsVersion(toolFilePath); found = !!version; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/JdkProbe.qbs0000644000175100001660000000443614776170045022271 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.Host import "../../../modules/java/utils.js" as JavaUtils PathProbe { // Inputs property string architecture: !_androidCrossCompiling ? qbs.architecture : undefined property bool _androidCrossCompiling: qbs.targetOS.contains("android") && !Host.os().contains("android") environmentPaths: Environment.getEnv("JAVA_HOME") platformSearchPaths: [ "/usr/lib/jvm/default-java", // Debian/Ubuntu "/etc/alternatives/java_sdk_openjdk", // Fedora "/usr/lib/jvm/default" // Arch ] configure: { path = JavaUtils.findJdkPath(Host.os(), architecture, environmentPaths, platformSearchPaths); found = !!path; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/AndroidSdkProbe.qbs0000644000175100001660000000577014776170045023605 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import "../../../modules/Android/sdk/utils.js" as SdkUtils import "../../../modules/Android/android-utils.js" as AndroidUtils PathProbe { environmentPaths: Environment.getEnv("ANDROID_HOME") platformSearchPaths: { if (Host.os().contains("windows")) return [FileInfo.joinPaths(Environment.getEnv("LOCALAPPDATA"), "Android", "sdk")]; if (Host.os().contains("macos")) return [FileInfo.joinPaths(Environment.getEnv("HOME"), "Library", "Android", "sdk")]; if (Host.os().contains("linux")) return [FileInfo.joinPaths(Environment.getEnv("HOME"), "Android", "Sdk")]; } // Outputs property stringList candidatePaths property var buildToolsVersions property string buildToolsVersion property var platforms property string platform configure: { var i, allPaths = (environmentPaths || []).concat(platformSearchPaths || []); candidatePaths = allPaths; for (i in allPaths) { if (File.exists(FileInfo.joinPaths(allPaths[i], "build-tools"))) { path = allPaths[i]; buildToolsVersions = SdkUtils.availableBuildToolsVersions(path) buildToolsVersion = buildToolsVersions[buildToolsVersions.length - 1]; platforms = AndroidUtils.availablePlatforms(path) platform = platforms[platforms.length - 1]; found = true; return; } } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs0000644000175100001660000000603614776170045024227 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.ModUtils import qbs.Utilities import "path-probe.js" as PathProbeConfigure BinaryProbe { // output property string vcvarsallPath configure: { var _selectors; var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths); var compilerPath; if (results.found) compilerPath = results.files[0].filePath; var compilers = Utilities.installedClangCls(compilerPath); if (compilers.length >= 1) { var result = {}; result.fileName = "clang-cl.exe"; result.path = compilers[0].toolchainInstallPath; result.filePath = FileInfo.joinPaths(result.path, result.fileName); result.candidatePaths = result.filePath; result.vcvarsallPath = compilers[0].vcvarsallPath; results.found = true; results.files = [result]; } found = results.found; allResults = results.files; if (allResults.length === 1) { var result = allResults[0]; candidatePaths = result.candidatePaths; path = result.path; filePath = result.filePath; fileName = result.fileName; vcvarsallPath = result.vcvarsallPath; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs0000644000175100001660000000526114776170045023417 0ustar runnerdockerimport qbs.Environment import qbs.FileInfo import qbs.Host import "path-probe.js" as PathProbeConfigure BinaryProbe { nameSuffixes: undefined // _compilerName already contains ".exe" suffix on Windows // Inputs property string _compilerName property string _toolchainPrefix // Outputs property string tcPrefix platformSearchPaths: { var paths = base; if (qbs.targetOS.contains("windows") && Host.os().contains("windows")) paths.push(FileInfo.joinPaths( Environment.getEnv("SystemDrive"), "MinGW", "bin")); return paths; } names: { var prefixes = []; if (_toolchainPrefix) { prefixes.push(_toolchainPrefix); } else { var arch = qbs.architecture; if (qbs.targetOS.contains("windows")) { if (!arch || arch === "x86") { prefixes.push("mingw32-", "i686-w64-mingw32-", "i686-w64-mingw32.shared-", "i686-w64-mingw32.static-", "i686-mingw32-", "i586-mingw32msvc-"); } if (!arch || arch === "x86_64") { prefixes.push("x86_64-w64-mingw32-", "x86_64-w64-mingw32.shared-", "x86_64-w64-mingw32.static-", "amd64-mingw32msvc-"); } } } return prefixes.map(function(prefix) { return prefix + _compilerName; }).concat([_compilerName]); } configure: { var selectors; var results = PathProbeConfigure.configure( selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths); found = results.found; if (!found) return; var resultsMapper = function(result) { (nameSuffixes || [""]).forEach(function(suffix) { var end = _compilerName + suffix; if (result.fileName.endsWith(end)) result.tcPrefix = result.fileName.slice(0, -end.length); }); return result; }; results.files = results.files.map(resultsMapper); allResults = results.files; var result = results.files[0]; candidatePaths = result.candidatePaths; path = result.path; filePath = result.filePath; fileName = result.fileName; tcPrefix = result.tcPrefix; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs0000644000175100001660000000556314776170045023266 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.ModUtils import qbs.Utilities import "path-probe.js" as PathProbeConfigure BinaryProbe { // input property string preferredArchitecture configure: { var _selectors; var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths); if (!results.found) { var msvcs = Utilities.installedMSVCs(preferredArchitecture); if (msvcs.length >= 1) { var result = {}; result.fileName = "cl.exe"; result.path = msvcs[0].binPath; result.filePath = FileInfo.joinPaths(path, fileName); result.candidatePaths = result.filePath; results.found = true; results.files = [result]; } } found = results.found; allResults = results.files; if (allResults.length === 1) { var result = allResults[0]; candidatePaths = result.candidatePaths; path = result.path; filePath = result.filePath; fileName = result.fileName; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/QmakeProbe.qbs0000644000175100001660000000335314776170045022614 0ustar runnerdocker /**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "qmake-probe.js" as QmakeProbeConfigure Probe { property stringList qmakePaths property varList qtInfos configure: { qtInfos = QmakeProbeConfigure.configure(qmakePaths); found = qtInfos.length > 0; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/DmcProbe.qbs0000644000175100001660000000675014776170045022265 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.ModUtils import "../../../modules/cpp/dmc.js" as DMC PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage property string _targetPlatform property string _targetArchitecture property string _targetExtender // Only for DOS 16/32 bit. // Outputs property string architecture property string targetPlatform property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var compilerDefinesByLanguage configure: { compilerDefinesByLanguage = {}; if (!File.exists(compilerFilePath)) { found = false; return; } var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; var defaultPathsByLanguage = {}; for (var i = 0; i < languages.length; ++i) { var tag = languages[i]; compilerDefinesByLanguage[tag] = DMC.dumpMacros( compilerFilePath, _targetPlatform, _targetArchitecture, _targetExtender, tag); var paths = DMC.dumpDefaultPaths(compilerFilePath, tag); defaultPathsByLanguage[tag] = paths; } var macros = compilerDefinesByLanguage["c"] || compilerDefinesByLanguage["cpp"]; architecture = ModUtils.guessArchitecture(macros); targetPlatform = ModUtils.guessTargetPlatform(macros); var defaultPaths = defaultPathsByLanguage["cpp"] || defaultPathsByLanguage["c"]; includePaths = defaultPaths.includePaths; var version = DMC.guessVersion(macros); if (version) { versionMajor = version.major; versionMinor = version.minor; versionPatch = version.patch; found = !!architecture; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/IncludeProbe.qbs0000644000175100001660000000345314776170045023142 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ PathProbe { platformSearchPaths: qbs.targetOS.contains("unix") ? [ "/usr/include", "/usr/local/include", "/include", "/app/include", ] : [] platformEnvironmentPaths: { if (qbs.toolchain.contains('msvc')) return [ "INCLUDE" ]; return undefined; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs0000644000175100001660000000504614776170045023621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.Host import "../../../modules/cpp/gcc.js" as Gcc PathProbe { // Inputs property string compilerFilePath property var environment property stringList _toolchain: qbs.toolchain // Outputs property int versionMajor property int versionMinor property int versionPatch configure: { if (!File.exists(compilerFilePath)) { found = false; return; } var macros = Gcc.dumpMacros(environment, compilerFilePath, undefined, Host.nullDevice()); if (_toolchain.contains("clang")) { versionMajor = parseInt(macros["__clang_major__"], 10); versionMinor = parseInt(macros["__clang_minor__"], 10); versionPatch = parseInt(macros["__clang_patchlevel__"], 10); found = true; } else { versionMajor = parseInt(macros["__GNUC__"], 10); versionMinor = parseInt(macros["__GNUC_MINOR__"], 10); versionPatch = parseInt(macros["__GNUC_PATCHLEVEL__"], 10); found = true; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/path-probe.js0000644000175100001660000001370214776170045022455 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); function asStringList(key, value) { if (typeof(value) === "string") return [value]; if (value instanceof Array) return value; throw key + " must be a string or a stringList"; } function canonicalSelectors(selectors, nameSuffixes) { var mapper = function(selector) { if (typeof(selector) === "string") return {names : [selector]}; if (selector instanceof Array) return {names : selector}; // dict if (!selector.names) throw '"names" must be specified'; selector.names = asStringList("names", selector.names); if (selector.nameSuffixes) selector.nameSuffixes = asStringList("nameSuffixes", selector.nameSuffixes); else selector.nameSuffixes = nameSuffixes; return selector; }; return selectors.map(mapper); } function pathsFromEnvs(envs, pathListSeparator) { envs = envs || []; var result = []; for (var i = 0; i < envs.length; ++i) { var value = Environment.getEnv(envs[i]) || ''; if (value.length > 0) result = result.concat(value.split(pathListSeparator)); } return result; } function configure(selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths) { var result = { found: false, files: [] }; if (!selectors && !names) throw '"names" or "selectors" must be specified'; if (!selectors) { selectors = [ {names: names, nameSuffixes: nameSuffixes} ]; } else { selectors = canonicalSelectors(selectors, nameSuffixes); } if (nameFilter) { selectors.forEach(function(selector) { selector.names = ModUtils.concatAll.apply(undefined, selector.names.map(nameFilter)); }); } selectors.forEach(function(selector) { selector.names = ModUtils.concatAll.apply(undefined, selector.names.map(function(name) { return (selector.nameSuffixes || [""]).map(function(suffix) { return name + suffix; }); })); }); // FIXME: Suggest how to obtain paths from system var _paths = ModUtils.concatAll( pathsFromEnvs(environmentPaths, FileInfo.pathListSeparator()), searchPaths, pathsFromEnvs(platformEnvironmentPaths, FileInfo.pathListSeparator()), platformSearchPaths); var _suffixes = ModUtils.concatAll('', pathSuffixes); _paths = _paths.map(function(p) { return FileInfo.fromNativeSeparators(p); }); _suffixes = _suffixes.map(function(p) { return FileInfo.fromNativeSeparators(p); }); var findFile = function(selector) { var file = { found: false, candidatePaths: [] }; for (var i = 0; i < selector.names.length; ++i) { for (var j = 0; j < _paths.length; ++j) { for (var k = 0; k < _suffixes.length; ++k) { var _filePath = FileInfo.joinPaths(_paths[j], _suffixes[k], selector.names[i]); file.candidatePaths.push(_filePath); if (File.exists(_filePath) && (!candidateFilter || candidateFilter(_filePath))) { file.found = true; file.filePath = _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. file.fileName = selector.names[i]; file.path = FileInfo.joinPaths(_paths[j], _suffixes[k]); return file; } } } } return file; }; result.files = selectors.map(findFile); result.found = result.files.reduce(function(acc, value) { return acc && value.found }, true); return result; } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/NpmProbe.qbs0000644000175100001660000000650014776170045022305 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.Host import qbs.ModUtils import "path-probe.js" as PathProbeConfigure import "../../../modules/nodejs/nodejs.js" as NodeJs NodeJsProbe { names: ["npm"] // Inputs property string interpreterPath // Outputs property path npmBin property path npmRoot property path npmPrefix configure: { if (!interpreterPath) throw '"interpreterPath" must be specified'; var selectors; var results = PathProbeConfigure.configure( selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths); var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), Host.os().contains("windows")); v.prepend(interpreterPath); var resultsMapper = function(result) { result.npmBin = result.found ? NodeJs.findLocation(result.filePath, "bin", v.value) : undefined; result.npmRoot = result.found ? NodeJs.findLocation(result.filePath, "root", v.value) : undefined; result.npmPrefix = result.found ? NodeJs.findLocation(result.filePath, "prefix", v.value) : undefined; return result; }; results.files = results.files.map(resultsMapper); found = results.found; allResults = results.files; var result = results.files[0]; candidatePaths = result.candidatePaths; path = result.path; filePath = result.filePath; fileName = result.fileName; npmBin = result.npmBin; npmRoot = result.npmRoot; npmPrefix = result.npmPrefix; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/qmake-probe.js0000644000175100001660000016170114776170045022622 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Host = require("qbs.Host"); var Process = require("qbs.Process"); var ProviderUtils = require("qbs.ProviderUtils"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function splitNonEmpty(s, c) { return s.split(c).filter(function(e) { return e; }); } function getQmakeFilePaths(qmakeFilePaths) { if (qmakeFilePaths && qmakeFilePaths.length > 0) return qmakeFilePaths; console.info("Detecting Qt installations..."); var filePaths = []; var pathValue = Environment.getEnv("PATH"); if (pathValue) { var dirs = splitNonEmpty(pathValue, FileInfo.pathListSeparator()); for (var i = 0; i < dirs.length; ++i) { var candidate = FileInfo.joinPaths(dirs[i], "qmake" + FileInfo.executableSuffix()); var canonicalCandidate = FileInfo.canonicalPath(candidate); if (!canonicalCandidate || !File.exists(canonicalCandidate)) continue; if (FileInfo.completeBaseName(canonicalCandidate) !== "qtchooser") candidate = canonicalCandidate; if (!filePaths.contains(candidate)) { console.info("Found Qt at '" + FileInfo.toNativeSeparators(candidate) + "'."); filePaths.push(candidate); } } } if (filePaths.length === 0) { console.warn("Could not find any qmake executables in PATH. Either make sure a qmake " + "executable is present in PATH or set the moduleProviders.Qt.qmakeFilePaths property " + "to point to a qmake executable."); } return filePaths; } function queryQmake(qmakeFilePath) { var qmakeProcess = new Process; qmakeProcess.exec(qmakeFilePath, ["-query"]); if (qmakeProcess.exitCode() !== 0) { throw "The qmake executable '" + FileInfo.toNativeSeparators(qmakeFilePath) + "' failed with exit code " + qmakeProcess.exitCode() + "."; } var queryResult = {}; while (!qmakeProcess.atEnd()) { var line = qmakeProcess.readLine(); var index = (line || "").indexOf(":"); if (index !== -1) queryResult[line.slice(0, index)] = line.slice(index + 1).trim(); } return queryResult; } function pathQueryValue(queryResult, key) { var p = queryResult[key]; if (p) return FileInfo.fromNativeSeparators(p); } function readFileContent(filePath) { var f = new TextFile(filePath, TextFile.ReadOnly); var content = f.readAll(); f.close(); return content; } // TODO: Don't do the split every time... function configVariable(configContent, key) { var configContentLines = configContent.split('\n'); var regexp = new RegExp("^\\s*" + key + "\\s*\\+{0,1}=(.*)"); for (var i = 0; i < configContentLines.length; ++i) { var line = configContentLines[i]; var match = regexp.exec(line); if (match) return match[1].trim(); } } function configVariableItems(configContent, key) { var list = []; var configContentLines = configContent.split('\n'); var regexp = new RegExp("^\\s*" + key + "\\s*([+-]?=)(.*)"); for (var i = 0; i < configContentLines.length; ++i) { var line = configContentLines[i]; var match = regexp.exec(line); if (!match) continue; var op = match[1]; var lineList = splitNonEmpty(match[2], ' '); if (op === '=') { list = lineList; continue; } if (op === '+=') { list = list.concat(lineList); continue; } if (op === '-=') { for (var j = 0; j < lineList.length; ++j) { var idx = list.indexOf(lineList[j]); if (idx !== -1) list.splice(idx, 1); } } } return list; } function msvcCompilerVersionForYear(year) { var mapping = { "2005": "14", "2008": "15", "2010": "16", "2012": "17", "2013": "18", "2015": "19", "2017": "19.1", "2019": "19.2" }; return mapping[year]; } function msvcCompilerVersionFromMkspecName(mkspecName) { return msvcCompilerVersionForYear(mkspecName.slice(msvcPrefix().length)); } function addQtBuildVariant(qtProps, buildVariantName) { if (qtProps.qtConfigItems.contains(buildVariantName)) qtProps.buildVariant.push(buildVariantName); } function checkForStaticBuild(qtProps) { if (qtProps.qtMajorVersion >= 5) return qtProps.qtConfigItems.contains("static"); if (qtProps.frameworkBuild) return false; // there are no Qt4 static frameworks var isWin = qtProps.mkspecName.startsWith("win"); var libDir = isWin ? qtProps.binaryPath : qtProps.libraryPath; var coreLibFiles = File.directoryEntries(libDir, File.Files) .filter(function(fp) { return fp.contains("Core"); }); if (coreLibFiles.length === 0) throw "Could not determine whether Qt is a static build."; for (var i = 0; i < coreLibFiles.length; ++i) { if (Utilities.isSharedLibrary(coreLibFiles[i])) return false; } return true; } function guessMinimumWindowsVersion(qtProps) { if (qtProps.mkspecName.startsWith("winrt-")) return "10.0"; if (!ProviderUtils.isDesktopWindowsQt(qtProps)) return ""; if (qtProps.qtMajorVersion >= 6) return "10.0"; if (qtProps.architecture === "x86_64" || qtProps.architecture === "ia64") return "5.2" var match = qtProps.mkspecName.match(/^win32-msvc(\d+)$/); if (match) { var msvcVersion = match[1]; if (msvcVersion < 2012) return "5.0"; return "5.1"; } return qtProps.qtMajorVersion < 5 ? "5.0" : "5.1"; } function fillEntryPointLibs(qtProps, debug) { result = []; var isMinGW = ProviderUtils.isMinGwQt(qtProps); // Some Linux distributions rename the qtmain library. var qtMainCandidates = ["qtmain"]; if (isMinGW && qtProps.qtMajorVersion === 5) qtMainCandidates.push("qt5main"); if (qtProps.qtMajorVersion === 6) qtMainCandidates.push("Qt6EntryPoint"); for (var i = 0; i < qtMainCandidates.length; ++i) { var baseNameCandidate = qtMainCandidates[i]; var qtmain = qtProps.libraryPath + '/'; if (isMinGW) qtmain += "lib"; qtmain += baseNameCandidate + qtProps.qtLibInfix; if (debug && ProviderUtils.qtNeedsDSuffix(qtProps)) qtmain += 'd'; if (isMinGW) { qtmain += ".a"; } else { qtmain += ".lib"; if (Utilities.versionCompare(qtProps.qtVersion, "5.4.0") >= 0) result.push("Shell32.lib"); } if (File.exists(qtmain)) { result.push(qtmain); break; } } if (result.length === 0) { console.warn("Could not find the qtmain library at '" + FileInfo.toNativeSeparators(qtProps.libraryPath) + "'. You will not be able to link Qt applications."); } return result; } function getQtProperties(qmakeFilePath) { var queryResult = queryQmake(qmakeFilePath); var qtProps = {}; qtProps.installPrefixPath = pathQueryValue(queryResult, "QT_INSTALL_PREFIX"); qtProps.documentationPath = pathQueryValue(queryResult, "QT_INSTALL_DOCS"); qtProps.translationsPath = pathQueryValue(queryResult, "QT_INSTALL_TRANSLATIONS"); qtProps.includePath = pathQueryValue(queryResult, "QT_INSTALL_HEADERS"); qtProps.libraryPath = pathQueryValue(queryResult, "QT_INSTALL_LIBS"); qtProps.hostLibraryPath = pathQueryValue(queryResult, "QT_HOST_LIBS"); qtProps.binaryPath = pathQueryValue(queryResult, "QT_HOST_BINS") || pathQueryValue(queryResult, "QT_INSTALL_BINS"); qtProps.installPath = pathQueryValue(queryResult, "QT_INSTALL_BINS"); qtProps.pluginPath = pathQueryValue(queryResult, "QT_INSTALL_PLUGINS"); qtProps.qmlPath = pathQueryValue(queryResult, "QT_INSTALL_QML"); qtProps.qmlImportPath = pathQueryValue(queryResult, "QT_INSTALL_IMPORTS"); qtProps.qtVersion = queryResult.QT_VERSION; var mkspecsBaseSrcPath; if (Utilities.versionCompare(qtProps.qtVersion, "5") >= 0) { qtProps.mkspecBasePath = FileInfo.joinPaths(pathQueryValue(queryResult, "QT_HOST_DATA"), "mkspecs"); mkspecsBaseSrcPath = FileInfo.joinPaths(pathQueryValue(queryResult, "QT_HOST_DATA/src"), "mkspecs"); } else { qtProps.mkspecBasePath = FileInfo.joinPaths (pathQueryValue(queryResult, "QT_INSTALL_DATA"), "mkspecs"); } if (Utilities.versionCompare(qtProps.qtVersion, "6") >= 0) { qtProps.libExecPath = pathQueryValue(queryResult, "QT_HOST_LIBEXECS") || pathQueryValue(queryResult, "QT_INSTALL_LIBEXECS"); } // QML tools were only moved in Qt 6.2. qtProps.qmlLibExecPath = Utilities.versionCompare(qtProps.qtVersion, "6.2") >= 0 ? qtProps.libExecPath : qtProps.binaryPath; // qhelpgenerator was only moved in Qt 6.3. qtProps.helpGeneratorLibExecPath = Utilities.versionCompare(qtProps.qtVersion, "6.3") >= 0 ? qtProps.libExecPath : qtProps.binaryPath; if (!File.exists(qtProps.mkspecBasePath)) throw "Cannot extract the mkspecs directory."; var qconfigContent = readFileContent(FileInfo.joinPaths(qtProps.mkspecBasePath, "qconfig.pri")); qtProps.qtMajorVersion = parseInt(configVariable(qconfigContent, "QT_MAJOR_VERSION")); qtProps.qtMinorVersion = parseInt(configVariable(qconfigContent, "QT_MINOR_VERSION")); qtProps.qtPatchVersion = parseInt(configVariable(qconfigContent, "QT_PATCH_VERSION")); qtProps.qtNameSpace = configVariable(qconfigContent, "QT_NAMESPACE"); qtProps.qtLibInfix = configVariable(qconfigContent, "QT_LIBINFIX") || ""; qtProps.architecture = configVariable(qconfigContent, "QT_TARGET_ARCH") || configVariable(qconfigContent, "QT_ARCH") || "x86"; qtProps.configItems = configVariableItems(qconfigContent, "CONFIG"); qtProps.qtConfigItems = configVariableItems(qconfigContent, "QT_CONFIG"); qtProps.enabledFeatures = configVariableItems(qconfigContent, "QT.global.enabled_features"); qtProps.disabledFeatures = configVariableItems(qconfigContent, "QT.global.disabled_features"); // retrieve the mkspec if (qtProps.qtMajorVersion >= 5) { qtProps.mkspecName = queryResult.QMAKE_XSPEC; qtProps.mkspecPath = FileInfo.joinPaths(qtProps.mkspecBasePath, qtProps.mkspecName); if (mkspecsBaseSrcPath && !File.exists(qtProps.mkspecPath)) qtProps.mkspecPath = FileInfo.joinPaths(mkspecsBaseSrcPath, qtProps.mkspecName); } else { if (Host.os().contains("windows")) { var baseDirPath = FileInfo.joinPaths(qtProps.mkspecBasePath, "default"); var fileContent = readFileContent(FileInfo.joinPaths(baseDirPath, "qmake.conf")); qtProps.mkspecPath = configVariable(fileContent, "QMAKESPEC_ORIGINAL"); if (!File.exists(qtProps.mkspecPath)) { // Work around QTBUG-28792. // The value of QMAKESPEC_ORIGINAL is wrong for MinGW packages. Y u h8 me? var match = fileContent.exec(/\binclude\(([^)]+)\/qmake\.conf\)/m); if (match) { qtProps.mkspecPath = FileInfo.cleanPath(FileInfo.joinPaths( baseDirPath, match[1])); } } } else { qtProps.mkspecPath = FileInfo.canonicalPath( FileInfo.joinPaths(qtProps.mkspecBasePath, "default")); } // E.g. in qmake.conf for Qt 4.8/mingw we find this gem: // QMAKESPEC_ORIGINAL=C:\\Qt\\Qt\\4.8\\mingw482\\mkspecs\\win32-g++ qtProps.mkspecPath = FileInfo.cleanPath(qtProps.mkspecPath); qtProps.mkspecName = qtProps.mkspecPath; var idx = qtProps.mkspecName.lastIndexOf('/'); if (idx !== -1) qtProps.mkspecName = qtProps.mkspecName.slice(idx + 1); } if (!File.exists(qtProps.mkspecPath)) throw "mkspec '" + FileInfo.toNativeSeparators(qtProps.mkspecPath) + "' does not exist"; // Starting with qt 5.14, android sdk provides multi-abi if (Utilities.versionCompare(qtProps.qtVersion, "5.14.0") >= 0 && qtProps.mkspecPath.contains("android")) { var qdeviceContent = readFileContent(FileInfo.joinPaths(qtProps.mkspecBasePath, "qdevice.pri")); qtProps.androidAbis = configVariable(qdeviceContent, "DEFAULT_ANDROID_ABIS").split(' '); } // determine MSVC version if (ProviderUtils.isMsvcQt(qtProps)) { var msvcMajor = configVariable(qconfigContent, "QT_MSVC_MAJOR_VERSION"); var msvcMinor = configVariable(qconfigContent, "QT_MSVC_MINOR_VERSION"); var msvcPatch = configVariable(qconfigContent, "QT_MSVC_PATCH_VERSION"); if (msvcMajor && msvcMinor && msvcPatch) qtProps.msvcVersion = msvcMajor + "." + msvcMinor + "." + msvcPatch; else qtProps.msvcVersion = msvcCompilerVersionFromMkspecName(qtProps.mkspecName); } // determine whether we have a framework build qtProps.frameworkBuild = qtProps.mkspecPath.contains("macx") && qtProps.configItems.contains("qt_framework"); // determine whether Qt is built with debug, release or both qtProps.buildVariant = []; addQtBuildVariant(qtProps, "debug"); addQtBuildVariant(qtProps, "release"); qtProps.staticBuild = checkForStaticBuild(qtProps); qtProps.multiThreading = qtProps.enabledFeatures.contains("thread"); // determine whether user apps require C++11 if (qtProps.qtConfigItems.contains("c++11") && qtProps.staticBuild) qtProps.configItems.push("c++11"); // Set the minimum operating system versions appropriate for this Qt version qtProps.windowsVersion = guessMinimumWindowsVersion(qtProps); if (qtProps.windowsVersion) { // Is target OS Windows? if (qtProps.buildVariant.contains("debug")) qtProps.entryPointLibsDebug = fillEntryPointLibs(qtProps, true); if (qtProps.buildVariant.contains("release")) qtProps.entryPointLibsRelease = fillEntryPointLibs(qtProps, false); } else if (qtProps.mkspecPath.contains("macx")) { if (qtProps.qtMajorVersion >= 5) { // Since Qt 6.7.1, QMAKE_MACOSX|IOS_DEPLOYMENT_TARGET is no longer present in // qmake.conf. But it is also present in qconfig.pri, so first try to read it from there qtProps.macosVersion = configVariable(qconfigContent, "QMAKE_MACOSX_DEPLOYMENT_TARGET"); qtProps.iosVersion = configVariable(qconfigContent, "QMAKE_IOS_DEPLOYMENT_TARGET"); // Next, we override the value from qmake.conf, if present there // Note, that TVOS/WATCHOS variables are only present in qmake.conf (as of Qt 6.7.1) var lines = getFileContentsRecursively(FileInfo.joinPaths(qtProps.mkspecPath, "qmake.conf")); for (var i = 0; i < lines.length; ++i) { var line = lines[i].trim(); match = line.match (/^QMAKE_(MACOSX|IOS|TVOS|WATCHOS)_DEPLOYMENT_TARGET\s*=\s*(.*)\s*$/); if (match) { var platform = match[1]; var version = match[2]; if (platform === "MACOSX") qtProps.macosVersion = version; else if (platform === "IOS") qtProps.iosVersion = version; else if (platform === "TVOS") qtProps.tvosVersion = version; else if (platform === "WATCHOS") qtProps.watchosVersion = version; } } var isMac = qtProps.mkspecName !== "macx-ios-clang" && qtProps.mkspecName !== "macx-tvos-clang" && qtProps.mkspecName !== "macx-watchos-clang"; if (isMac) { // Qt 5.0.x placed the minimum version in a different file if (!qtProps.macosVersion) qtProps.macosVersion = "10.6"; // If we're using C++11 with libc++, make sure the deployment target is >= 10.7 if (Utilities.versionCompare(qtProps.macosVersion, "10, 7") < 0 && qtProps.qtConfigItems.contains("c++11")) { qtProps.macosVersion = "10.7"; } } } else if (qtProps.qtMajorVersion === 4 && qtProps.qtMinorVersion >= 6) { var qconfigDir = qtProps.frameworkBuild ? FileInfo.joinPaths(qtProps.libraryPath, "QtCore.framework", "Headers") : FileInfo.joinPaths(qtProps.includePath, "Qt"); try { var qconfig = new TextFile(FileInfo.joinPaths(qconfigDir, "qconfig.h"), TextFile.ReadOnly); var qtCocoaBuild = false; var ok = true; do { line = qconfig.readLine(); if (line.match(/\s*#define\s+QT_MAC_USE_COCOA\s+1\s*/)) { qtCocoaBuild = true; break; } } while (!qconfig.atEof()); qtProps.macosVersion = qtCocoaBuild ? "10.5" : "10.4"; } catch (e) {} finally { if (qconfig) qconfig.close(); } if (!qtProps.macosVersion) { throw "Could not determine whether Qt is using Cocoa or Carbon from '" + FileInfo.toNativeSeparators(qconfig.filePath()) + "'."; } } } else if (qtProps.mkspecPath.contains("android")) { if (qtProps.qtMajorVersion >= 5) qtProps.androidVersion = "2.3"; else if (qtProps.qtMajorVersion === 4 && qtProps.qtMinorVersion >= 8) qtProps.androidVersion = "1.6"; // Necessitas } return qtProps; } function makePluginData() { var pluginData = {}; pluginData.type = undefined; pluginData.className = undefined; pluginData.autoLoad = true; pluginData["extends"] = []; return pluginData; } function makeQtModuleInfo(name, qbsName, deps) { var moduleInfo = {}; moduleInfo.name = name; // As in the path to the headers and ".name" in the pri files. if (moduleInfo.name === undefined) moduleInfo.name = ""; moduleInfo.qbsName = qbsName; // Lower-case version without "qt" prefix. moduleInfo.dependencies = deps || []; // qbs names. if (moduleInfo.qbsName && moduleInfo.qbsName !== "core" && !moduleInfo.dependencies.contains("core")) { moduleInfo.dependencies.unshift("core"); } moduleInfo.isPrivate = qbsName && qbsName.endsWith("-private"); moduleInfo.hasLibrary = !moduleInfo.isPrivate; moduleInfo.isStaticLibrary = false; moduleInfo.isPlugin = false; moduleInfo.mustExist = true; moduleInfo.modulePrefix = ""; // empty value means "Qt". moduleInfo.version = undefined; moduleInfo.includePaths = []; moduleInfo.compilerDefines = []; moduleInfo.staticLibrariesDebug = []; moduleInfo.staticLibrariesRelease = []; moduleInfo.dynamicLibrariesDebug = []; moduleInfo.dynamicLibrariesRelease = []; moduleInfo.linkerFlagsDebug = []; moduleInfo.linkerFlagsRelease = []; moduleInfo.libFilePathDebug = undefined; moduleInfo.libFilePathRelease = undefined; moduleInfo.frameworksDebug = []; moduleInfo.frameworksRelease = []; moduleInfo.frameworkPathsDebug = []; moduleInfo.frameworkPathsRelease = []; moduleInfo.libraryPaths = []; moduleInfo.libDir = ""; moduleInfo.config = []; moduleInfo.supportedPluginTypes = []; moduleInfo.pluginData = makePluginData(); return moduleInfo; } function frameworkHeadersPath(qtModuleInfo, qtProps) { return FileInfo.joinPaths(qtProps.libraryPath, qtModuleInfo.name + ".framework", "Headers"); } function qt4ModuleIncludePaths(qtModuleInfo, qtProps) { var paths = []; if (ProviderUtils.qtIsFramework(qtModuleInfo, qtProps)) paths.push(frameworkHeadersPath(qtModuleInfo, qtProps)); else paths.push(qtProps.includePath, FileInfo.joinPaths(qtProps.includePath, qtModuleInfo.name)); return paths; } // We erroneously called the "testlib" module "test" for quite a while. Let's not punish users // for that. function addTestModule(modules) { var testModule = makeQtModuleInfo("QtTest", "test", ["testlib"]); testModule.hasLibrary = false; modules.push(testModule); } // See above. function addDesignerComponentsModule(modules) { var module = makeQtModuleInfo("QtDesignerComponents", "designercomponents", ["designercomponents-private"]); module.hasLibrary = false; modules.push(module); } function guessLibraryFilePath(prlFilePath, libDir, qtProps) { var baseName = FileInfo.baseName(prlFilePath); var prefixCandidates = ["", "lib"]; var suffixCandidates = ["so." + qtProps.qtVersion, "so", "a", "lib", "dll.a"]; for (var i = 0; i < prefixCandidates.length; ++i) { var prefix = prefixCandidates[i]; for (var j = 0; j < suffixCandidates.length; ++j) { var suffix = suffixCandidates[j]; var candidate = FileInfo.joinPaths(libDir, prefix + baseName + '.' + suffix); if (File.exists(candidate)) return candidate; } } } function doReplaceQtLibNamesWithFilePath(namePathMap, libList) { for (var i = 0; i < libList.length; ++i) { var lib = libList[i]; var path = namePathMap[lib]; if (path) libList[i] = path; } } function replaceQtLibNamesWithFilePath(modules, qtProps) { // We don't want to add the libraries for Qt modules via "-l", because of the // danger that a wrong one will be picked up, e.g. from /usr/lib. Instead, // we pull them in using the full file path. var linkerNamesToFilePathsDebug = {}; var linkerNamesToFilePathsRelease = {}; for (var i = 0; i < modules.length; ++i) { var m = modules[i]; linkerNamesToFilePathsDebug[ ProviderUtils.qtLibNameForLinker(m, qtProps, true)] = m.libFilePathDebug; linkerNamesToFilePathsRelease[ ProviderUtils.qtLibNameForLinker(m, qtProps, false)] = m.libFilePathRelease; } for (i = 0; i < modules.length; ++i) { var module = modules[i]; doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsDebug, module.dynamicLibrariesDebug); doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsDebug, module.staticLibrariesDebug); doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsRelease, module.dynamicLibrariesRelease); doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsRelease, module.staticLibrariesRelease); } } function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles, androidAbi) { if (!modInfo.hasLibrary) return; // Can happen for Qt4 convenience modules, like "widgets". if (debugBuild) { if (!qtProps.buildVariant.contains("debug")) return; var modulesNeverBuiltAsDebug = ["bootstrap", "qmldevtools"]; for (var i = 0; i < modulesNeverBuiltAsDebug.length; ++i) { var m = modulesNeverBuiltAsDebug[i]; if (modInfo.qbsName === m || modInfo.qbsName === m + "-private") return; } } else if (!qtProps.buildVariant.contains("release")) { return; } var libs = modInfo.isStaticLibrary ? (debugBuild ? modInfo.staticLibrariesDebug : modInfo.staticLibrariesRelease) : (debugBuild ? modInfo.dynamicLibrariesDebug : modInfo.dynamicLibrariesRelease); var frameworks = debugBuild ? modInfo.frameworksDebug : modInfo.frameworksRelease; var frameworkPaths = debugBuild ? modInfo.frameworkPathsDebug : modInfo.frameworkPathsRelease; var flags = debugBuild ? modInfo.linkerFlagsDebug : modInfo.linkerFlagsRelease; var libFilePath; if (qtProps.mkspecName.contains("ios") && modInfo.isStaticLibrary) { libs.push("z", "m"); if (qtProps.qtMajorVersion === 5 && qtProps.qtMinorVersion < 8) { var platformSupportModule = makeQtModuleInfo("QtPlatformSupport", "platformsupport"); libs.push(ProviderUtils.qtLibNameForLinker(platformSupportModule, qtProps, debugBuild)); } if (modInfo.name === "qios") { flags.push("-force_load", FileInfo.joinPaths( qtProps.pluginPath, "platforms", ProviderUtils.qtLibBaseName( modInfo, "libqios", debugBuild, qtProps) + ".a")); } } var prlFilePath = modInfo.isPlugin ? FileInfo.joinPaths(qtProps.pluginPath, modInfo.pluginData.type) : (modInfo.libDir ? modInfo.libDir : qtProps.libraryPath); var libDir = prlFilePath; if (ProviderUtils.qtIsFramework(modInfo, qtProps)) { prlFilePath = FileInfo.joinPaths( prlFilePath, ProviderUtils.qtLibraryBaseName(modInfo, qtProps, false) + ".framework"); libDir = prlFilePath; if (Utilities.versionCompare(qtProps.qtVersion, "5.14") >= 0) { var candidates = [ FileInfo.joinPaths(prlFilePath, "Resources"), // E.g. 5.15.9, 6.8.0/macOS FileInfo.joinPaths(prlFilePath, "Versions/A/Resources") // E.g. 6.8.0/iOS ]; for (i = 0; i < candidates.length; ++i) { if (File.exists(candidates[i])) { prlFilePath = candidates[i]; break; } } } } var baseName = ProviderUtils.qtLibraryBaseName(modInfo, qtProps, debugBuild); if (!qtProps.mkspecName.startsWith("win") && !ProviderUtils.qtIsFramework(modInfo, qtProps)) baseName = "lib" + baseName; prlFilePath = FileInfo.joinPaths(prlFilePath, baseName); var isNonStaticQt4OnWindows = qtProps.mkspecName.startsWith("win") && !modInfo.isStaticLibrary && qtProps.qtMajorVersion < 5; if (isNonStaticQt4OnWindows) prlFilePath = prlFilePath.slice(0, prlFilePath.length - 1); // The prl file base name does *not* contain the version number... // qt for android versions 6.0 and 6.1 don't have the architecture suffix in the prl file if (androidAbi.length > 0 && modInfo.name !== "QtBootstrap" && (modInfo.name !== "QtQmlDevTools" || modInfo.name === "QtQmlDevTools" && Utilities.versionCompare(qtProps.qtVersion, "6.2") >= 0) && (Utilities.versionCompare(qtProps.qtVersion, "6.0") < 0 || Utilities.versionCompare(qtProps.qtVersion, "6.2") >= 0)) { prlFilePath += "_"; prlFilePath += androidAbi; } prlFilePath += ".prl"; try { var prlFile = new TextFile(prlFilePath, TextFile.ReadOnly); while (!prlFile.atEof()) { var line = prlFile.readLine().trim(); var equalsOffset = line.indexOf('='); if (equalsOffset === -1) continue; if (line.startsWith("QMAKE_PRL_TARGET")) { var isMingw = qtProps.mkspecName.startsWith("win") && qtProps.mkspecName.contains("g++"); var isQtVersionBefore56 = qtProps.qtMajorVersion < 5 || (qtProps.qtMajorVersion === 5 && qtProps.qtMinorVersion < 6); // 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. var libFileName = ""; if (isQtVersionBefore56 && qtProps.qtMajorVersion === 5 && isMingw && !modInfo.isStaticLibrary) { libFileName += "lib"; } libFileName += line.slice(equalsOffset + 1).trim(); if (isNonStaticQt4OnWindows) libFileName += 4; // This is *not* part of QMAKE_PRL_TARGET... if (isQtVersionBefore56) { if (qtProps.mkspecName.contains("msvc")) { libFileName += ".lib"; } else if (isMingw) { libFileName += ".a"; if (!File.exists(FileInfo.joinPaths(libDir, libFileName))) libFileName = libFileName.slice(0, -2) + ".dll"; } } libFilePath = FileInfo.joinPaths(libDir, libFileName); continue; } if (line.startsWith("QMAKE_PRL_CONFIG")) { modInfo.config = splitNonEmpty(line.slice(equalsOffset + 1).trim(), ' '); continue; } if (!line.startsWith("QMAKE_PRL_LIBS =")) continue; var parts = extractPaths(line.slice(equalsOffset + 1).trim(), prlFilePath); for (i = 0; i < parts.length; ++i) { var part = parts[i]; part = part.replace("$$[QT_INSTALL_LIBS]", qtProps.libraryPath); part = part.replace("$$[QT_INSTALL_PLUGINS]", qtProps.pluginPath); part = part.replace("$$[QT_INSTALL_PREFIX]", qtProps.installPrefixPath); if (part.startsWith("-l")) { libs.push(part.slice(2)); } else if (part.startsWith("-L")) { modInfo.libraryPaths.push(part.slice(2)); } else if (part.startsWith("-F")) { frameworkPaths.push(part.slice(2)); } else if (part === "-framework") { if (++i < parts.length) frameworks.push(parts[i]); } else if (part === "-pthread") { // prl files for android have QMAKE_PRL_LIBS = -llog -pthread but the pthread // functionality is included in libc. if (androidAbi.length === 0) libs.push("pthread"); } else if (part.startsWith('-')) { // Some other option console.debug("QMAKE_PRL_LIBS contains non-library option '" + part + "' in file '" + prlFilePath + "'"); flags.push(part); } else if (part.startsWith("/LIBPATH:")) { libraryPaths.push(part.slice(9).replace(/\\/g, '/')); } else { // Assume it's a file path/name. libs.push(part.replace(/\\/g, '/')); } } } } catch (e) { // qt_ext_lib_extX.pri (usually) don't have a corresponding prl file. // So the pri file variable QMAKE_LIBS_LIBX points to the library if (modInfo.isExternal) { libFilePath = debugBuild ? modInfo.staticLibrariesDebug[0] : modInfo.staticLibrariesRelease[0]; } if (!libFilePath || !File.exists(libFilePath)) libFilePath = guessLibraryFilePath(prlFilePath, libDir, qtProps); if (nonExistingPrlFiles.contains(prlFilePath)) return; nonExistingPrlFiles.push(prlFilePath); if (modInfo.mustExist) { console.warn("Could not open prl file '" + FileInfo.toNativeSeparators(prlFilePath) + "' for module '" + modInfo.name + "' (" + e + "), and failed to deduce the library file path. " + " This module will likely not be usable by qbs."); } } finally { if (prlFile) prlFile.close(); } if (debugBuild) modInfo.libFilePathDebug = libFilePath; else modInfo.libFilePathRelease = libFilePath; } function setupLibraries(qtModuleInfo, qtProps, nonExistingPrlFiles, androidAbi) { doSetupLibraries(qtModuleInfo, qtProps, true, nonExistingPrlFiles, androidAbi); doSetupLibraries(qtModuleInfo, qtProps, false, nonExistingPrlFiles, androidAbi); } function allQt4Modules(qtProps) { // as per http://doc.qt.io/qt-4.8/modules.html + private stuff. var modules = []; var core = makeQtModuleInfo("QtCore", "core"); core.compilerDefines.push("QT_CORE_LIB"); if (qtProps.qtNameSpace) core.compilerDefines.push("QT_NAMESPACE=" + qtProps.qtNameSpace); modules.push(core, makeQtModuleInfo("QtCore", "core-private", ["core"]), makeQtModuleInfo("QtGui", "gui"), makeQtModuleInfo("QtGui", "gui-private", ["gui"]), makeQtModuleInfo("QtMultimedia", "multimedia", ["gui", "network"]), makeQtModuleInfo("QtMultimedia", "multimedia-private", ["multimedia"]), makeQtModuleInfo("QtNetwork", "network"), makeQtModuleInfo("QtNetwork", "network-private", ["network"]), makeQtModuleInfo("QtOpenGL", "opengl", ["gui"]), makeQtModuleInfo("QtOpenGL", "opengl-private", ["opengl"]), makeQtModuleInfo("QtOpenVG", "openvg", ["gui"]), makeQtModuleInfo("QtScript", "script"), makeQtModuleInfo("QtScript", "script-private", ["script"]), makeQtModuleInfo("QtScriptTools", "scripttools", ["script", "gui"]), makeQtModuleInfo("QtScriptTools", "scripttools-private", ["scripttools"]), makeQtModuleInfo("QtSql", "sql"), makeQtModuleInfo("QtSql", "sql-private", ["sql"]), makeQtModuleInfo("QtSvg", "svg", ["gui"]), makeQtModuleInfo("QtSvg", "svg-private", ["svg"]), makeQtModuleInfo("QtWebKit", "webkit", ["gui", "network"]), makeQtModuleInfo("QtWebKit", "webkit-private", ["webkit"]), makeQtModuleInfo("QtXml", "xml"), makeQtModuleInfo("QtXml", "xml-private", ["xml"]), makeQtModuleInfo("QtXmlPatterns", "xmlpatterns", ["network"]), makeQtModuleInfo("QtXmlPatterns", "xmlpatterns-private", ["xmlpatterns"]), makeQtModuleInfo("QtDeclarative", "declarative", ["gui", "script"]), makeQtModuleInfo("QtDeclarative", "declarative-private", ["declarative"]), makeQtModuleInfo("QtDesigner", "designer", ["gui", "xml"]), makeQtModuleInfo("QtDesigner", "designer-private", ["designer"]), makeQtModuleInfo("QtUiTools", "uitools"), makeQtModuleInfo("QtUiTools", "uitools-private", ["uitools"]), makeQtModuleInfo("QtHelp", "help", ["network", "sql"]), makeQtModuleInfo("QtHelp", "help-private", ["help"]), makeQtModuleInfo("QtTest", "testlib"), makeQtModuleInfo("QtTest", "testlib-private", ["testlib"])); if (qtProps.mkspecName.startsWith("win")) { var axcontainer = makeQtModuleInfo("QAxContainer", "axcontainer"); axcontainer.modulePrefix = "Q"; axcontainer.isStaticLibrary = true; axcontainer.includePaths.push(FileInfo.joinPaths(qtProps.includePath, "ActiveQt")); modules.push(axcontainer); var axserver = makeQtModuleInfo("QAxServer", "axserver"); axserver.modulePrefix = "Q"; axserver.isStaticLibrary = true; axserver.compilerDefines.push("QAXSERVER"); axserver.includePaths.push(FileInfo.joinPaths(qtProps.includePath, "ActiveQt")); modules.push(axserver); } else { modules.push(makeQtModuleInfo("QtDBus", "dbus")); modules.push(makeQtModuleInfo("QtDBus", "dbus-private", ["dbus"])); } var designerComponentsPrivate = makeQtModuleInfo( "QtDesignerComponents", "designercomponents-private", ["gui-private", "designer-private"]); designerComponentsPrivate.hasLibrary = true; modules.push(designerComponentsPrivate); var phonon = makeQtModuleInfo("Phonon", "phonon"); phonon.includePaths = qt4ModuleIncludePaths(phonon, qtProps); modules.push(phonon); // Set up include paths that haven't been set up before this point. for (i = 0; i < modules.length; ++i) { var module = modules[i]; if (module.includePaths.length > 0) continue; module.includePaths = qt4ModuleIncludePaths(module, qtProps); } // Set up compiler defines haven't been set up before this point. for (i = 0; i < modules.length; ++i) { module = modules[i]; if (module.compilerDefines.length > 0) continue; module.compilerDefines.push("QT_" + module.qbsName.toUpperCase() + "_LIB"); } // These are for the convenience of project file authors. It allows them // to add a dependency to e.g. "Qt.widgets" without a version check. var virtualModule = makeQtModuleInfo(undefined, "widgets", ["core", "gui"]); virtualModule.hasLibrary = false; modules.push(virtualModule); virtualModule = makeQtModuleInfo(undefined, "quick", ["declarative"]); virtualModule.hasLibrary = false; modules.push(virtualModule); virtualModule = makeQtModuleInfo(undefined, "concurrent"); virtualModule.hasLibrary = false; modules.push(virtualModule); virtualModule = makeQtModuleInfo(undefined, "printsupport", ["core", "gui"]); virtualModule.hasLibrary = false; modules.push(virtualModule); addTestModule(modules); addDesignerComponentsModule(modules); var modulesThatCanBeDisabled = [ "xmlpatterns", "multimedia", "phonon", "svg", "webkit", "script", "scripttools", "declarative", "gui", "dbus", "opengl", "openvg"]; var nonExistingPrlFiles = []; for (i = 0; i < modules.length; ++i) { module = modules[i]; var name = module.qbsName; var privateIndex = name.indexOf("-private"); if (privateIndex !== -1) name = name.slice(0, privateIndex); if (modulesThatCanBeDisabled.contains(name)) module.mustExist = false; if (qtProps.staticBuild) module.isStaticLibrary = true; setupLibraries(module, qtProps, nonExistingPrlFiles, ""); } replaceQtLibNamesWithFilePath(modules, qtProps); return modules; } function getFileContentsRecursively(filePath) { var file = new TextFile(filePath, TextFile.ReadOnly); var lines = splitNonEmpty(file.readAll(), '\n'); for (var i = 0; i < lines.length; ++i) { var includeString = "include("; var line = lines[i].trim(); if (!line.startsWith(includeString)) continue; var offset = includeString.length; var closingParenPos = line.indexOf(')', offset); if (closingParenPos === -1) { console.warn("Invalid include statement in '" + FileInfo.toNativeSeparators(filePath) + "'"); continue; } var includedFilePath = line.slice(offset, closingParenPos); if (!FileInfo.isAbsolutePath(includedFilePath)) includedFilePath = FileInfo.joinPaths(FileInfo.path(filePath), includedFilePath); var includedContents = getFileContentsRecursively(includedFilePath); var j = i; for (var k = 0; k < includedContents.length; ++k) lines.splice(++j, 0, includedContents[k]); lines.splice(i--, 1); } file.close(); return lines; } function extractPaths(rhs, filePath) { var paths = []; var startIndex = 0; for (;;) { while (startIndex < rhs.length && rhs.charAt(startIndex) === ' ') ++startIndex; if (startIndex >= rhs.length) break; var endIndex; if (rhs.charAt(startIndex) === '"') { ++startIndex; endIndex = rhs.indexOf('"', startIndex); if (endIndex === -1) { console.warn("Unmatched quote in file '" + FileInfo.toNativeSeparators(filePath) + "'"); break; } } else { endIndex = rhs.indexOf(' ', startIndex + 1); if (endIndex === -1) endIndex = rhs.length; } paths.push(FileInfo.cleanPath(rhs.slice(startIndex, endIndex) .replace("$$PWD", FileInfo.path(filePath)))); startIndex = endIndex + 1; } return paths; } function removeDuplicatedDependencyLibs(modules) { var revDeps = {}; var currentPath = []; var getLibraries; var getLibFilePath; function setupReverseDependencies(modules) { var moduleByName = {}; for (var i = 0; i < modules.length; ++i) moduleByName[modules[i].qbsName] = modules[i]; for (i = 0; i < modules.length; ++i) { var module = modules[i]; for (var j = 0; j < module.dependencies.length; ++j) { var depmod = moduleByName[module.dependencies[j]]; if (!depmod) continue; if (!revDeps[depmod.qbsName]) revDeps[depmod.qbsName] = []; revDeps[depmod.qbsName].push(module); } } } function roots(modules) { var result = []; for (i = 0; i < modules.length; ++i) { var module = modules[i] if (module.dependencies.length === 0) result.push(module); } return result; } function traverse(module, libs) { if (currentPath.contains(module)) return; currentPath.push(module); var moduleLibraryLists = getLibraries(module); for (var i = 0; i < moduleLibraryLists.length; ++i) { var modLibList = moduleLibraryLists[i]; for (j = modLibList.length - 1; j >= 0; --j) { if (libs.contains(modLibList[j])) modLibList.splice(j, 1); } } var libFilePath = getLibFilePath(module); if (libFilePath) libs.push(libFilePath); for (i = 0; i < moduleLibraryLists.length; ++i) libs = libs.concat(moduleLibraryLists[i]); libs.sort(); var deps = revDeps[module.qbsName]; for (i = 0; i < (deps || []).length; ++i) traverse(deps[i], libs); currentPath.pop(); } setupReverseDependencies(modules); // Traverse the debug variants of modules. getLibraries = function(module) { return [module.dynamicLibrariesDebug, module.staticLibrariesDebug]; }; getLibFilePath = function(module) { return module.libFilePathDebug; }; var rootModules = roots(modules); for (var i = 0; i < rootModules.length; ++i) traverse(rootModules[i], []); // Traverse the release variants of modules. getLibraries = function(module) { return [module.dynamicLibrariesRelease, module.staticLibrariesRelease]; }; getLibFilePath = function(module) { return module.libFilePathRelease; }; for (i = 0; i < rootModules.length; ++i) traverse(rootModules[i], []); } function allQt5Modules(qtProps, androidAbi) { var nonExistingPrlFiles = []; var modules = []; var modulesDir = FileInfo.joinPaths(qtProps.mkspecBasePath, "modules"); var modulePriFiles = File.directoryEntries(modulesDir, File.Files); for (var i = 0; i < modulePriFiles.length; ++i) { var priFileName = modulePriFiles[i]; var priFilePath = FileInfo.joinPaths(modulesDir, priFileName); var externalFileNamePrefix = "qt_ext_"; var moduleFileNamePrefix = "qt_lib_"; var pluginFileNamePrefix = "qt_plugin_"; var moduleFileNameSuffix = ".pri"; var fileHasExternalPrefix = priFileName.startsWith(externalFileNamePrefix); var fileHasModulePrefix = priFileName.startsWith(moduleFileNamePrefix); var fileHasPluginPrefix = priFileName.startsWith(pluginFileNamePrefix); if (!fileHasPluginPrefix && !fileHasModulePrefix && !fileHasExternalPrefix || !priFileName.endsWith(moduleFileNameSuffix)) { continue; } var moduleInfo = makeQtModuleInfo(); moduleInfo.isPlugin = fileHasPluginPrefix; moduleInfo.isExternal = !moduleInfo.isPlugin && !fileHasModulePrefix; var fileNamePrefix = moduleInfo.isPlugin ? pluginFileNamePrefix : moduleInfo.isExternal ? externalFileNamePrefix : moduleFileNamePrefix; moduleInfo.qbsName = priFileName.slice(fileNamePrefix.length, -moduleFileNameSuffix.length); if (moduleInfo.isPlugin) { moduleInfo.name = moduleInfo.qbsName; moduleInfo.isStaticLibrary = true; } var moduleKeyPrefix = (moduleInfo.isPlugin ? "QT_PLUGIN" : "QT") + '.' + moduleInfo.qbsName + '.'; moduleInfo.qbsName = moduleInfo.qbsName.replace("_private", "-private"); var hasV2 = false; var hasModuleEntry = false; var lines = getFileContentsRecursively(priFilePath); if (moduleInfo.isExternal) { moduleInfo.name = "qt" + moduleInfo.qbsName; moduleInfo.isStaticLibrary = true; for (var k = 0; k < lines.length; ++k) { var extLine = lines[k].trim(); var extFirstEqualsOffset = extLine.indexOf('='); if (extFirstEqualsOffset === -1) continue; var extKey = extLine.slice(0, extFirstEqualsOffset).trim(); var extValue = extLine.slice(extFirstEqualsOffset + 1).trim(); if (!extKey.startsWith("QMAKE_") || !extValue) continue; var elements = extKey.split('_'); if (elements.length >= 3) { if (elements[1] === "LIBS") { extValue = extValue.replace("/home/qt/work/qt/qtbase/lib", qtProps.libraryPath); extValue = extValue.replace("$$[QT_INSTALL_LIBS]", qtProps.libraryPath); extValue = extValue.replace("$$[QT_INSTALL_LIBS/get]", qtProps.libraryPath); if (elements.length === 4 ) { if (elements[3] === androidAbi) { moduleInfo.staticLibrariesRelease.push(extValue); moduleInfo.staticLibrariesDebug.push(extValue); } } else if (elements.length === 5 ) { // That's for "x86_64" var abi = elements[3] + '_' + elements[4]; if (abi === androidAbi) { moduleInfo.staticLibrariesRelease.push(extValue); moduleInfo.staticLibrariesDebug.push(extValue); } } else { moduleInfo.staticLibrariesRelease.push(extValue); moduleInfo.staticLibrariesDebug.push(extValue); } } else if (elements[1] === "INCDIR") { moduleInfo.includePaths.push(extValue.replace("$$[QT_INSTALL_HEADERS]", qtProps.includePath)); } } } moduleInfo.compilerDefines.push("QT_" + moduleInfo.qbsName.toUpperCase() + "_LIB"); moduleInfo.mustExist = false; } else { for (var j = 0; j < lines.length; ++j) { var line = lines[j].trim(); var firstEqualsOffset = line.indexOf('='); if (firstEqualsOffset === -1) continue; var key = line.slice(0, firstEqualsOffset).trim(); var value = line.slice(firstEqualsOffset + 1).trim(); if (!key.startsWith(moduleKeyPrefix) || !value) continue; if (key.endsWith(".name")) { moduleInfo.name = value; } else if (key.endsWith(".module")) { hasModuleEntry = true; } else if (key.endsWith(".depends")) { moduleInfo.dependencies = splitNonEmpty(value, ' '); for (var k = 0; k < moduleInfo.dependencies.length; ++k) { moduleInfo.dependencies[k] = moduleInfo.dependencies[k].replace("_private", "-private"); } } else if (key.endsWith(".module_config")) { var elems = splitNonEmpty(value, ' '); for (k = 0; k < elems.length; ++k) { var elem = elems[k]; if (elem === "no_link") moduleInfo.hasLibrary = false; else if (elem === "staticlib") moduleInfo.isStaticLibrary = true; else if (elem === "internal_module") moduleInfo.isPrivate = true; else if (elem === "v2") hasV2 = true; else if (elem === "lib_bundle") moduleInfo.isFramework = true; } } else if (key.endsWith(".includes")) { moduleInfo.includePaths = extractPaths(value, priFilePath); for (k = 0; k < moduleInfo.includePaths.length; ++k) { moduleInfo.includePaths[k] = moduleInfo.includePaths[k] .replace("$$QT_MODULE_INCLUDE_BASE", qtProps.includePath) .replace("$$QT_MODULE_HOST_LIB_BASE", qtProps.hostLibraryPath) .replace("$$QT_MODULE_LIB_BASE", qtProps.libraryPath); } } else if (key.endsWith(".libs")) { var libDirs = extractPaths(value, priFilePath); if (libDirs.length === 1) { moduleInfo.libDir = libDirs[0] .replace("$$QT_MODULE_HOST_LIB_BASE", qtProps.hostLibraryPath) .replace("$$QT_MODULE_LIB_BASE", qtProps.libraryPath); } else { moduleInfo.libDir = qtProps.libraryPath; } } else if (key.endsWith(".DEFINES")) { moduleInfo.compilerDefines = splitNonEmpty(value, ' '); } else if (key.endsWith(".VERSION")) { moduleInfo.version = value; } else if (key.endsWith(".plugin_types")) { moduleInfo.supportedPluginTypes = splitNonEmpty(value, ' '); } else if (key.endsWith(".TYPE")) { moduleInfo.pluginData.type = value; } else if (key.endsWith(".EXTENDS")) { moduleInfo.pluginData["extends"] = splitNonEmpty(value, ' '); for (k = 0; k < moduleInfo.pluginData["extends"].length; ++k) { if (moduleInfo.pluginData["extends"][k] === "-") { moduleInfo.pluginData["extends"].splice(k, 1); moduleInfo.pluginData.autoLoad = false; break; } } } else if (key.endsWith(".CLASS_NAME")) { moduleInfo.pluginData.className = value; } } } if (hasV2 && !hasModuleEntry && !moduleInfo.isStaticLibrary) moduleInfo.hasLibrary = false; // Fix include paths for Apple frameworks. // The qt_lib_XXX.pri files contain wrong values for versions < 5.6. if (!hasV2 && ProviderUtils.qtIsFramework(moduleInfo, qtProps)) { moduleInfo.includePaths = []; var baseIncDir = frameworkHeadersPath(moduleInfo, qtProps); if (moduleInfo.isPrivate) { baseIncDir = FileInfo.joinPaths(baseIncDir, moduleInfo.version); moduleInfo.includePaths.push(baseIncDir, FileInfo.joinPaths(baseIncDir, moduleInfo.name)); } else { moduleInfo.includePaths.push(baseIncDir); } } setupLibraries(moduleInfo, qtProps, nonExistingPrlFiles, androidAbi); modules.push(moduleInfo); if (moduleInfo.qbsName === "testlib") addTestModule(modules); if (moduleInfo.qbsName === "designercomponents-private") addDesignerComponentsModule(modules); } replaceQtLibNamesWithFilePath(modules, qtProps); removeDuplicatedDependencyLibs(modules); return modules; } function getQtInfo(qmakeFilePath) { if (!File.exists(qmakeFilePath)) { throw "The specified qmake file path '" + FileInfo.toNativeSeparators(qmakeFilePath) + "' does not exist."; } var qtProps = getQtProperties(qmakeFilePath); var androidAbis = []; if (qtProps.androidAbis !== undefined) { // Multiple androidAbis detected: Qt >= 5.14 androidAbis = qtProps.androidAbis; } else { // Single abi detected: Qt < 5.14 androidAbis.push(''); } if (androidAbis.length > 1) console.info("Qt with multiple abi detected: '" + androidAbis + "'"); var result = {}; result.qtProps = qtProps; result.abiInfos = []; result.qmakeFilePath = qmakeFilePath; for (a = 0; a < androidAbis.length; ++a) { var abiInfo = {}; if (androidAbis.length > 1) console.info("Found abi '" + androidAbis[a] + "'..."); abiInfo.androidAbi = androidAbis[a]; var allModules = qtProps.qtMajorVersion < 5 ? allQt4Modules(qtProps) : allQt5Modules(qtProps, androidAbis[a]);; abiInfo.modules = {}; for (var i = 0; i < allModules.length; ++i) { var module = allModules[i]; abiInfo.modules[module.qbsName] = module; } abiInfo.pluginsByType = {}; abiInfo.nonEssentialPlugins = []; for (var moduleName in abiInfo.modules) { var m = abiInfo.modules[moduleName]; if (m.isPlugin) { if (!abiInfo.pluginsByType[m.pluginData.type]) abiInfo.pluginsByType[m.pluginData.type] = []; abiInfo.pluginsByType[m.pluginData.type].push(m.name); if (!m.pluginData.autoLoad) abiInfo.nonEssentialPlugins.push(m.name); } } result.abiInfos.push(abiInfo); } return result; } function configure(qmakeFilePaths) { var result = []; qmakeFilePaths = getQmakeFilePaths(qmakeFilePaths); if (!qmakeFilePaths || qmakeFilePaths.length === 0) return result; for (var i = 0; i < qmakeFilePaths.length; ++i) { var qtInfo = {}; try { console.info("Getting info about Qt at '" + FileInfo.toNativeSeparators(qmakeFilePaths[i]) + "'..."); qtInfo = getQtInfo(qmakeFilePaths[i]); result.push(qtInfo); } catch (e) { console.warn("Error getting info about Qt for '" + FileInfo.toNativeSeparators(qmakeFilePaths[i]) + "': " + e); throw e; } } return result; } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/JdkVersionProbe.qbs0000644000175100001660000000333614776170045023635 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "../../../modules/java/utils.js" as JavaUtils Probe { // Inputs property string javac // Outputs property var version configure: { version = JavaUtils.findJdkVersion(javac); found = !!version; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/CosmicProbe.qbs0000644000175100001660000000610114776170045022765 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import "../../../modules/cpp/cosmic.js" as COSMIC PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage // Outputs property string architecture property string endianness property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var compilerDefinesByLanguage configure: { compilerDefinesByLanguage = {}; if (!File.exists(compilerFilePath)) { found = false; return; } var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; // COSMIC compiler support only the C-language. if (!languages.contains("c")) { found = false; return; } var macros = COSMIC.dumpMacros(compilerFilePath); if (!macros) { found = false; return; } compilerDefinesByLanguage["c"] = macros; architecture = COSMIC.guessArchitecture(compilerFilePath); endianness = COSMIC.guessEndianness(architecture); var defaultPaths = COSMIC.dumpDefaultPaths(compilerFilePath, architecture); includePaths = defaultPaths.includePaths; var version = COSMIC.dumpVersion(compilerFilePath); if (version) { versionMajor = version.major; versionMinor = version.minor; versionPatch = version.patch; found = !!architecture && !!endianness; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/PkgConfigProbe.qbs0000644000175100001660000001365714776170045023435 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Host import qbs.Process import qbs.FileInfo Probe { // Inputs property string sysroot: qbs.sysroot property string executable: 'pkg-config' property string name property stringList packageNames: [name] property string minVersion property string exactVersion property string maxVersion property bool forStaticBuild: false property stringList libDirs // Full, non-sysrooted paths, mirroring the environment variable // Output property stringList cflags // Unmodified --cflags output property stringList libs // Unmodified --libs output property stringList defines property stringList libraries property stringList libraryPaths property stringList includePaths property stringList compilerFlags property stringList linkerFlags property string modversion configure: { if (!packageNames || packageNames.length === 0) throw 'PkgConfigProbe.packageNames must be specified.'; var p = new Process(); var stdout; try { var libDirsToSet = libDirs; if (sysroot) { p.setEnv("PKG_CONFIG_SYSROOT_DIR", sysroot); if (!libDirsToSet) { libDirsToSet = [ sysroot + "/usr/lib/pkgconfig", sysroot + "/usr/share/pkgconfig" ]; } } if (libDirsToSet) p.setEnv("PKG_CONFIG_LIBDIR", libDirsToSet.join(FileInfo.pathListSeparator())); var versionArgs = []; if (minVersion !== undefined) versionArgs.push("--atleast-version=" + minVersion); if (exactVersion !== undefined) versionArgs.push("--exact-version=" + exactVersion); if (maxVersion !== undefined) versionArgs.push("--max-version=" + maxVersion); if (versionArgs.length !== 0 && p.exec(executable, versionArgs.concat(packageNames)) !== 0) { return; } // protobuf is reserved as qbs module name, which depends on the protobuflib module packageNames = packageNames.map(function(name) { return name === "protobuflib" ? "protobuf" : name; }); var args = packageNames; if (p.exec(executable, args.concat([ '--cflags' ])) === 0) { stdout = p.readStdOut().trim(); cflags = stdout ? stdout.split(/\s/): []; var libsArgs = args.concat("--libs"); if (forStaticBuild) libsArgs.push("--static"); if (p.exec(executable, libsArgs) === 0) { stdout = p.readStdOut().trim(); libs = stdout ? stdout.split(/\s/): []; if (p.exec(executable, [packageNames[0]].concat([ '--modversion' ])) === 0) { modversion = p.readStdOut().trim(); found = true; includePaths = []; defines = [] compilerFlags = []; for (var i = 0; i < cflags.length; ++i) { var flag = cflags[i]; if (flag.startsWith("-I")) includePaths.push(flag.slice(2)); else if (flag.startsWith("-D")) defines.push(flag.slice(2)); else compilerFlags.push(flag); } libraries = []; libraryPaths = []; linkerFlags = []; for (i = 0; i < libs.length; ++i) { flag = libs[i]; if (flag.startsWith("-l")) libraries.push(flag.slice(2)); else if (flag.startsWith("-L")) libraryPaths.push(flag.slice(2)); else linkerFlags.push(flag); } console.debug("PkgConfigProbe: found packages " + packageNames); return; } } } found = false; cflags = undefined; libs = undefined; } finally { p.close(); } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/SdccProbe.qbs0000644000175100001660000000613214776170045022430 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import "../../../modules/cpp/sdcc.js" as SDCC PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage property string preferredArchitecture // Outputs property string architecture property string endianness property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var compilerDefinesByLanguage configure: { compilerDefinesByLanguage = {}; if (!File.exists(compilerFilePath)) { found = false; return; } var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; // SDCC compiler support only the C-language. if (!languages.contains("c")) { found = false; return; } var macros = SDCC.dumpMacros(compilerFilePath, preferredArchitecture); if (!macros) { found = false; return; } compilerDefinesByLanguage["c"] = macros; architecture = SDCC.guessArchitecture(macros); endianness = SDCC.guessEndianness(macros); var defaultPaths = SDCC.dumpDefaultPaths(compilerFilePath, architecture); includePaths = defaultPaths.includePaths; var version = SDCC.guessVersion(macros); if (version) { versionMajor = version.major; versionMinor = version.minor; versionPatch = version.patch; found = !!architecture && !!endianness; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/qbs-pkg-config-probe.js0000644000175100001660000001136114776170045024327 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var PkgConfig = require("qbs.PkgConfig"); var ProviderUtils = require("qbs.ProviderUtils"); var Process = require("qbs.Process"); function getQmakePaths(pkg) { var packageName = pkg.baseFileName; if (packageName === "QtCore" || packageName === "Qt5Core" || packageName === "Qt6Core") { var binDir = pkg.variables["bindir"] || pkg.variables["host_bins"]; if (!binDir) { if (packageName === "QtCore") { // Qt4 does not have host_bins var mocLocation = pkg.variables["moc_location"]; if (!mocLocation) { console.warn("No moc_location variable in " + packageName); return; } binDir = FileInfo.path(mocLocation); } else { console.warn("No 'bindir' or 'host_bins' variable in " + packageName); return; } } var suffix = FileInfo.executableSuffix(); return [FileInfo.joinPaths(binDir, "qmake" + suffix)]; } } function configure( executableFilePath, extraPaths, libDirs, staticMode, definePrefix, sysroot) { var result = {}; result.packages = []; result.packagesByModuleName = {}; result.brokenPackages = []; result.qtInfos = []; var options = {}; options.libDirs = libDirs; options.sysroot = sysroot; options.definePrefix = definePrefix; if (options.sysroot) options.allowSystemLibraryPaths = true; options.staticMode = staticMode; options.extraPaths = extraPaths; if (options.sysroot && !options.libDirs) { options.libDirs = [ options.sysroot + "/usr/lib/pkgconfig", options.sysroot + "/usr/share/pkgconfig" ]; } if (!options.libDirs) { // if we have pkg-config/pkgconf installed, let's ask it for its search paths (since // built-in search paths can differ between platforms) if (executableFilePath) { var p = new Process() if (p.exec(executableFilePath, ['pkg-config', '--variable=pc_path']) === 0) { var stdout = p.readStdOut().trim(); options.libDirs = stdout ? stdout.split(FileInfo.pathListSeparator()): []; var installDir = FileInfo.path(executableFilePath); options.libDirs = options.libDirs.map(function(path){ if (FileInfo.isAbsolutePath(path)) return path; return FileInfo.cleanPath(FileInfo.joinPaths(installDir, path)); }); } } } var pkgConfig = new PkgConfig(options); result.packages = pkgConfig.packages(); for (var packageName in result.packages) { var pkg = result.packages[packageName]; var moduleName = ProviderUtils.pkgConfigToModuleName(packageName); result.packagesByModuleName[moduleName] = pkg; if (packageName.startsWith("Qt")) { if (!sysroot) { var qmakePaths = getQmakePaths(pkg); if (qmakePaths !== undefined) result.qmakePaths = qmakePaths; } } } return result; } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/GccProbe.qbs0000644000175100001660000001131214776170045022244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import "../../../modules/cpp/gcc.js" as Gcc PathProbe { // Inputs property var compilerFilePathByLanguage property stringList enableDefinesByLanguage property stringList flags: [] property var environment property string _sysroot: qbs.sysroot property stringList _targetOS: qbs.targetOS // Outputs property string architecture property string endianness property string targetPlatform property stringList includePaths property stringList libraryPaths property stringList frameworkPaths property var compilerDefinesByLanguage configure: { compilerDefinesByLanguage = {}; var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; for (var i = 0; i < languages.length; ++i) { var fp = compilerFilePathByLanguage[languages[i]]; if (fp && File.exists(fp)) { try { compilerDefinesByLanguage[languages[i]] = Gcc.dumpMacros(environment, fp, flags, Host.nullDevice(), languages[i]); } catch (e) { // Only throw errors when determining the compiler defines for the C language; // for other languages we presume it is an indication that the language is not // installed (as is typically the case for Objective-C/C++ on non-Apple systems) if (languages[i] === "c") throw e; } } else if (languages[i] === "c") { found = false; return; } } var macros = compilerDefinesByLanguage["c"] || compilerDefinesByLanguage["cpp"] || compilerDefinesByLanguage["objc"] || compilerDefinesByLanguage["objcpp"]; var defaultPaths = Gcc.dumpDefaultPaths(environment, compilerFilePathByLanguage["cpp"] || compilerFilePathByLanguage["c"], flags, Host.nullDevice(), FileInfo.pathListSeparator(), _sysroot, _targetOS); found = !!macros && !!defaultPaths; includePaths = defaultPaths.includePaths; libraryPaths = defaultPaths.libraryPaths; frameworkPaths = defaultPaths.frameworkPaths; // We have to dump the compiler's macros; -dumpmachine is not suitable because it is not // always complete (for example, the subarch is not included for arm architectures). architecture = ModUtils.guessArchitecture(macros); targetPlatform = ModUtils.guessTargetPlatform(macros); switch (macros["__BYTE_ORDER__"]) { case "__ORDER_BIG_ENDIAN__": endianness = "big"; break; case "__ORDER_LITTLE_ENDIAN__": endianness = "little"; break; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/BinaryProbe.qbs0000644000175100001660000000335014776170045022777 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Host PathProbe { nameSuffixes: Host.os().contains("windows") ? [".com", ".exe", ".bat", ".cmd"] : undefined platformSearchPaths: Host.os().contains("unix") ? ["/usr/bin", "/usr/local/bin"] : [] platformEnvironmentPaths: [ "PATH" ] } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/XcodeLocationProbe.qbs0000644000175100001660000000364014776170045024310 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Process Probe { property path developerPath configure: { var p = new Process(); try { p.exec("/usr/bin/xcode-select", ["--print-path"], true); developerPath = p.readStdOut().trim(); } catch (e) { developerPath = "/Applications/Xcode.app/Contents/Developer"; } finally { p.close(); found = true; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/KeilProbe.qbs0000644000175100001660000000607514776170045022446 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.Host import "../../../modules/cpp/keil.js" as KEIL PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage // Outputs property string architecture property string endianness property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var compilerDefinesByLanguage configure: { compilerDefinesByLanguage = {}; if (!File.exists(compilerFilePath)) { found = false; return; } var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; for (var i = 0; i < languages.length; ++i) { var tag = languages[i]; compilerDefinesByLanguage[tag] = KEIL.dumpMacros( compilerFilePath, tag, Host.nullDevice()); } var macros = compilerDefinesByLanguage["c"] || compilerDefinesByLanguage["cpp"]; architecture = KEIL.guessArchitecture(macros); endianness = KEIL.guessEndianness(macros); var defaultPaths = KEIL.dumpDefaultPaths( compilerFilePath, Host.nullDevice()); includePaths = defaultPaths.includePaths; var version = KEIL.guessVersion(macros); if (version) { versionMajor = version.major; versionMinor = version.minor; versionPatch = version.patch; found = !!architecture && !!endianness; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/WatcomProbe.qbs0000644000175100001660000000716414776170045023014 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.Host import qbs.ModUtils import "../../../modules/cpp/watcom.js" as WATCOM PathProbe { // Inputs property string compilerFilePath property stringList enableDefinesByLanguage property string _pathListSeparator property string _toolchainInstallPath property string _targetPlatform property string _targetArchitecture // Outputs property string architecture property string endianness property string targetPlatform property int versionMajor property int versionMinor property int versionPatch property stringList includePaths property var compilerDefinesByLanguage property var environment configure: { compilerDefinesByLanguage = {}; if (!File.exists(compilerFilePath)) { found = false; return; } var languages = enableDefinesByLanguage; if (!languages || languages.length === 0) languages = ["c"]; environment = WATCOM.guessEnvironment(Host.os(), _targetPlatform, _targetArchitecture, _toolchainInstallPath, _pathListSeparator); includePaths = environment["INCLUDE"].split(_pathListSeparator).filter(function(path) { return File.exists(path); }); for (var i = 0; i < languages.length; ++i) { var tag = languages[i]; compilerDefinesByLanguage[tag] = WATCOM.dumpMacros( environment, compilerFilePath, _targetPlatform, _targetArchitecture, tag); } var macros = compilerDefinesByLanguage["c"] || compilerDefinesByLanguage["cpp"]; endianness = macros["__BIG_ENDIAN"] ? "big" : "little"; architecture = ModUtils.guessArchitecture(macros); targetPlatform = ModUtils.guessTargetPlatform(macros); var version = WATCOM.guessVersion(macros); if (version) { versionMajor = version.major; versionMinor = version.minor; versionPatch = version.patch; found = !!architecture && !!targetPlatform; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs0000644000175100001660000000342114776170045023507 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ PathProbe { platformSearchPaths: (qbs.sysroot ? [qbs.sysroot + "/System/Library/Frameworks"] : []).concat([ "~/Library/Frameworks", "/usr/local/lib", "/Library/Frameworks", "/System/Library/Frameworks" ]) nameSuffixes: ".framework" } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs0000644000175100001660000000712214776170045023662 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import "path-probe.js" as PathProbeConfigure import "../../../modules/typescript/typescript.js" as TypeScript BinaryProbe { id: tsc names: ["tsc"] searchPaths: packageManagerBinPath ? [packageManagerBinPath] : [] // Inputs property path interpreterPath property path packageManagerBinPath property path packageManagerRootPath // Outputs property var version configure: { if (!condition) return; if (!interpreterPath) throw '"interpreterPath" must be specified'; if (!packageManagerBinPath) throw '"packageManagerBinPath" must be specified'; if (!packageManagerRootPath) throw '"packageManagerRootPath" must be specified'; var selectors; var results = PathProbeConfigure.configure( selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths); var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), Host.os().contains("windows")); v.prepend(interpreterPath); var resultsMapper = function(result) { result.version = result.found ? TypeScript.findTscVersion(result.filePath, v.value) : undefined; if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path || !File.exists( FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) { result = { found: false }; } return result; }; results.files = results.files.map(resultsMapper); found = results.found; allResults = results.files; var result = results.files[0]; candidatePaths = result.candidatePaths; path = result.path; filePath = result.filePath; fileName = result.fileName; version = result.version; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/LibraryProbe.qbs0000644000175100001660000000635714776170045023171 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.PathTools PathProbe { property string endianness nameSuffixes: PathTools.librarySuffixes(qbs.targetOS, ["shared", "static"], true) platformSearchPaths: { var result = []; if (qbs.targetOS.contains("unix")) { if (qbs.targetOS.contains("linux") && qbs.architecture) { if (qbs.architecture === "armv7") result = ["/usr/lib/arm-linux-gnueabihf"] else if (qbs.architecture === "arm64") result = ["/usr/lib/aarch64-linux-gnu"] else if (qbs.architecture === "mips" && endianness === "big") result = ["/usr/lib/mips-linux-gnu"] else if (qbs.architecture === "mips" && endianness === "little") result = ["/usr/lib/mipsel-linux-gnu"] else if (qbs.architecture === "mips64") result = ["/usr/lib/mips64el-linux-gnuabi64"] else if (qbs.architecture === "ppc") result = ["/usr/lib/powerpc-linux-gnu"] else if (qbs.architecture === "ppc64") result = ["/usr/lib/powerpc64le-linux-gnu"] else if (qbs.architecture === "x86_64") result = ["/usr/lib64", "/usr/lib/x86_64-linux-gnu"] else if (qbs.architecture === "x86") result = ["/usr/lib32", "/usr/lib/i386-linux-gnu"] } result = result.concat(["/usr/lib", "/usr/local/lib", "/lib", "/app/lib"]); } return result; } nameFilter: PathTools.libraryNameFilter() platformEnvironmentPaths: { if (qbs.targetOS.contains("windows")) return [ "PATH" ]; else return [ "LIBRARY_PATH" ]; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/PathProbe.qbs0000644000175100001660000000553614776170045022457 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "path-probe.js" as PathProbeConfigure import qbs.Host import qbs.ModUtils Probe { // Inputs property stringList names property stringList nameSuffixes property var nameFilter property var candidateFilter property varList selectors property pathList searchPaths property stringList pathSuffixes property pathList platformSearchPaths: Host.os().contains("unix") ? ['/usr', '/usr/local'] : [] property stringList environmentPaths property stringList platformEnvironmentPaths // Output property stringList candidatePaths property string path property string filePath property string fileName property varList allResults configure: { var results = PathProbeConfigure.configure(selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths, pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths); found = results.found; allResults = results.files; if (allResults.length === 1) { var result = allResults[0]; candidatePaths = result.candidatePaths; path = result.path; filePath = result.filePath; fileName = result.fileName; } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/WiXProbe.qbs0000644000175100001660000000563714776170045022274 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Utilities PathProbe { // Inputs property string registryKey: { var keys = [ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Installer XML", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows Installer XML" ]; for (var i in keys) { var groups = Utilities.nativeSettingGroups(keys[i]).filter(function (v) { return v.match(/^([0-9]+)\.([0-9]+)$/); }); groups.sort(function (a, b) { var re = /^([0-9]+)\.([0-9]+)$/; a = a.match(re); b = b.match(re); a = {major: a[1], minor: a[2]}; b = {major: b[1], minor: b[2]}; if (a.major === b.major) return b.minor - a.minor; return b.major - a.major; }); for (var j in groups) { var fullKey = keys[i] + "\\" + groups[j]; if (Utilities.getNativeSetting(fullKey, "ProductVersion")) return fullKey; } } } // Outputs property var root property var version configure: { var key = registryKey; path = Utilities.getNativeSetting(key, "InstallFolder"); root = Utilities.getNativeSetting(key, "InstallRoot"); version = Utilities.getNativeSetting(key, "ProductVersion"); found = path && root && version; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs0000644000175100001660000000412314776170045022734 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.FileInfo import qbs.Host BinaryProbe { names: ["node", "nodejs"] platformSearchPaths: { var paths = base; if (Host.os().contains("windows")) { var env32 = Environment.getEnv("PROGRAMFILES(X86)"); var env64 = Environment.getEnv("PROGRAMFILES"); if (env64 === env32 && env64.endsWith(" (x86)")) env64 = env64.slice(0, -(" (x86)".length)); // QTBUG-3845 paths.push(FileInfo.joinPaths(env64, "nodejs")); paths.push(FileInfo.joinPaths(env32, "nodejs")); } return paths; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs0000644000175100001660000001320114776170045023564 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.TextFile import "../../../modules/Android/android-utils.js" as AndroidUtils PathProbe { // Inputs property path sdkPath environmentPaths: Environment.getEnv("ANDROID_NDK_ROOT") platformSearchPaths: { var paths = []; if (sdkPath) paths.push(FileInfo.joinPaths(sdkPath, "ndk-bundle")); if (Host.os().contains("windows")) paths.push(FileInfo.joinPaths(Environment.getEnv("LOCALAPPDATA"), "Android", "sdk", "ndk-bundle")); if (Host.os().contains("macos")) paths.push(FileInfo.joinPaths(Environment.getEnv("HOME"), "Library", "Android", "sdk", "ndk-bundle")); if (Host.os().contains("linux")) paths.push(FileInfo.joinPaths(Environment.getEnv("HOME"), "Android", "Sdk", "ndk-bundle")); return paths; } // Outputs property stringList candidatePaths property string samplesDir property var hostArch property stringList toolchains: [] property string ndkVersion configure: { function readFileContent(filePath) { var result = null; if (!File.exists(filePath)) return result; try { var tf = new TextFile(filePath, TextFile.ReadOnly); result = tf.readAll(); } finally { if (tf) tf.close(); } return result; } var i, j, allPaths = (environmentPaths || []).concat(platformSearchPaths || []); candidatePaths = allPaths; for (i in allPaths) { var platforms = []; if (Host.os().contains("windows")) platforms.push("windows-x86_64", "windows"); if (Host.os().contains("darwin")) platforms.push("darwin-x86_64", "darwin-x86"); if (Host.os().contains("linux")) platforms.push("linux-x86_64", "linux-x86"); for (j in platforms) { if (File.exists(FileInfo.joinPaths(allPaths[i], "prebuilt", platforms[j]))) { path = allPaths[i]; if (File.exists(FileInfo.joinPaths(path, "samples"))) samplesDir = FileInfo.joinPaths(path, "samples"); // removed in r11 hostArch = platforms[j]; toolchains = File.directoryEntries(FileInfo.joinPaths(path, "toolchains"), File.Dirs | File.NoDotAndDotDot); // NDK r11 and above var content = readFileContent(path + "/source.properties"); if (content) { var lines = content.trim().split(/\r?\n/g).filter(function (line) { return line.length > 0; }); for (var l = 0; l < lines.length; ++l) { var m = lines[l].match(/^Pkg\.Revision\s*=\s*([0-9\.]+)$/); if (m) { ndkVersion = m[1]; found = true; return; } } } // NDK r10 and below var releaseTextFileCandidates = ["RELEASE.txt", "RELEASE.TXT"] .map(function(v) { return FileInfo.joinPaths(path, v); }) .filter(File.exists); content = releaseTextFileCandidates.length ? readFileContent(releaseTextFileCandidates[0]) : null; if (content) { var m = content.trim().match(/^r([0-9]+[a-z]?).*/); if (m) { ndkVersion = m[1]; found = true; return; } } } } } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs0000644000175100001660000001363414776170045023457 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Richard Weickelt ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Process import qbs.File import qbs.FileInfo import qbs.TextFile import qbs.Utilities Probe { // Inputs property stringList additionalArguments: [] property path conanfilePath property path packageReference property path executable: "conan" + FileInfo.executableSuffix() property stringList generators property var options property var settings property string profileAll property bool verbose: false // Output property path generatedFilesPath property var dependencies property var json // Internal // Ensure that the probe is re-run automatically whenever conanfile changes // by making a file system property part of the probe's signature. property int _conanfileLastModified: conanfilePath ? File.lastModified(conanfilePath) : 0 property path _projectBuildDirectory: project.buildDirectory configure: { if (conanfilePath && packageReference) throw("conanfilePath and packageReference must not be defined at the same time."); if (!conanfilePath && !packageReference) throw("Either conanfilePath or packageReference must be defined."); var reference = packageReference || FileInfo.cleanPath(conanfilePath); console.info("Probing '" + reference + "'. This might take a while..."); if (conanfilePath && !File.exists(reference)) throw("The conanfile '" + reference + "' does not exist."); function getConanVersion() { var p = new Process(); p.exec(executable, ["--version"], true); return p.readStdOut().trim().replace("Conan version", "").trim(); } const isConan2 = Utilities.versionCompare(getConanVersion(), "2.0.0") >= 0; var args = [ "install", reference, ]; if (options) { if (typeof options !== "object") throw("The property 'options' must be an object."); Object.keys(options).forEach(function(key,index) { args.push("-o"); args.push(key + "=" + options[key]); }); } if (settings) { if (typeof settings !== "object") throw("The property 'settings' must be an object."); Object.keys(settings).forEach(function(key,index) { args.push("-s"); args.push(key + "=" + settings[key]); }); } if (generators === undefined) { if (isConan2) generators = ["QbsDeps"]; else generators = ["json"]; } if (!isConan2 && !generators.contains("json")) generators.push("json"); for (var i = 0; i < generators.length; i++) args = args.concat(["-g", generators[i]]); for (var i = 0; i < additionalArguments.length; i++) args.push(additionalArguments[i]); generatedFilesPath = FileInfo.cleanPath(_projectBuildDirectory + "/genconan/" + Utilities.getHash(args.join())); const outputFolderOption = isConan2 ? "--output-folder" : "--install-folder"; args = args.concat([outputFolderOption, generatedFilesPath]); var p = new Process(); p.start(executable, args); while (!p.waitForFinished(500)) { const output = p.readStdOut(); if (verbose && output) { console.info(output); } } while (!p.atEnd()) { const output = p.readStdOut(); if (verbose && output) { console.info(output); } } if (p.exitCode()) { const errorOutput = p.readStdErr(); p.close(); throw errorOutput; } p.close(); if (!isConan2 && generators.contains("json")) { if (!File.exists(generatedFilesPath + "/conanbuildinfo.json")) throw("No conanbuildinfo.json has been generated."); var jsonFile = new TextFile(generatedFilesPath + "/conanbuildinfo.json", TextFile.ReadOnly); json = JSON.parse(jsonFile.readAll()); jsonFile.close(); dependencies = {}; for (var i = 0; i < json.dependencies.length; ++i) { var dep = json.dependencies[i]; dependencies[dep.name] = dep; } } found = true; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/QbsPkgConfigProbe.qbs0000644000175100001660000000455514776170045024100 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "qbs-pkg-config-probe.js" as PkgConfigProbeConfigure Probe { // Inputs property string _executableFilePath property stringList _extraPaths property stringList _libDirs property bool _staticMode: false property bool _definePrefix: false property path _sysroot // Output property var packages property var packagesByModuleName property var brokenPackages property stringList qmakePaths configure: { var result = PkgConfigProbeConfigure.configure( _executableFilePath, _extraPaths, _libDirs, _staticMode, _definePrefix, _sysroot); packages = result.packages; packagesByModuleName = result.packagesByModuleName; brokenPackages = result.brokenPackages; qmakePaths = result.qmakePaths; found = true; } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/InnoSetupProbe.qbs0000644000175100001660000000457614776170045023512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Utilities PathProbe { // Outputs property var version configure: { var keys = [ "HKEY_LOCAL_MACHINE\\SOFTWARE\\", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\" ]; var keySuffixes = [ "Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 5_is1", "Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 6_is1" ]; for (var i = 0; i < keys.length; ++i) { for (var j = 0; j < keySuffixes.length; ++j) { var key = keys[i] + keySuffixes[j]; var v = Utilities.getNativeSetting(key, "DisplayVersion"); if (v) { path = Utilities.getNativeSetting(key, "InstallLocation"); version = v; found = path && version; return; } } } } } qbs-src-2.6.1/share/qbs/imports/qbs/Probes/XcodeProbe.qbs0000644000175100001660000001034514776170045022617 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Process import qbs.PropertyList import "../../../modules/xcode/xcode.js" as Xcode Probe { // Inputs property string sdksPath property string developerPath property string xcodebuildPath property stringList targetOS: qbs.targetOS property string platformType property string platformPath property string devicePlatformPath property string _xcodeInfoPlist: FileInfo.joinPaths(developerPath, "..", "Info.plist") // Outputs property var architectureSettings property var availableSdks property var platformSettings property string xcodeVersion configure: { if (File.exists(_xcodeInfoPlist)) { // Optimized case (no forking): reads CFBundleShortVersionString from // Xcode.app/Contents/Info.plist var propertyList = new PropertyList(); try { propertyList.readFromFile(_xcodeInfoPlist); var plist = propertyList.toObject(); if (plist) xcodeVersion = plist["CFBundleShortVersionString"]; } finally { propertyList.clear(); } } else { // Fallback case: execute xcodebuild -version if Xcode.app/Contents/Info.plist is // missing; this can happen if developerPath is /, for example var process; try { process = new Process(); process.exec(xcodebuildPath, ["-version"], true); var lines = process.readStdOut().trim().split(/\r?\n/g).filter(function (line) { return line.length > 0; }); for (var l = 0; l < lines.length; ++l) { var m = lines[l].match(/^Xcode ([0-9\.]+)$/); if (m) { xcodeVersion = m[1]; break; } } } finally { process.close(); } } architectureSettings = {}; var archSpecsPath = Xcode.archsSpecsPath(xcodeVersion, targetOS, platformType, platformPath, devicePlatformPath, developerPath); var archSpecsReader = new Xcode.XcodeArchSpecsReader(archSpecsPath); archSpecsReader.getArchitectureSettings().map(function (setting) { var val = archSpecsReader.getArchitectureSettingValue(setting); if (val) architectureSettings[setting] = val; }); availableSdks = Xcode.sdkInfoList(sdksPath); var platformInfoPlist = FileInfo.joinPaths(platformPath, "Info.plist"); platformSettings = Xcode.platformInfo(platformInfoPlist); found = !!xcodeVersion; } } qbs-src-2.6.1/share/qbs/imports/qbs/ProviderUtils/0000755000175100001660000000000014776170045021434 5ustar runnerdockerqbs-src-2.6.1/share/qbs/imports/qbs/ProviderUtils/provider-utils.js0000644000175100001660000001166314776170045024771 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Utilities = require("qbs.Utilities"); function pkgConfigToModuleName(packageName) { return packageName.replace(/\./g, '-'); } function msvcPrefix() { return "win32-msvc"; } function isMsvcQt(qtProps) { return qtProps.mkspecName.startsWith(msvcPrefix()); } function isMinGwQt(qtProps) { return qtProps.mkspecName.startsWith("win32-g++") || qtProps.mkspecName.startsWith("mingw"); } function isDesktopWindowsQt(qtProps) { return qtProps.mkspecName.startsWith("win32-") || isMinGwQt(qtProps); } function qtNeedsDSuffix(qtProps) { return !isMinGwQt(qtProps) || Utilities.versionCompare(qtProps.qtVersion, "5.14.0") < 0 || qtProps.configItems.contains("debug_and_release"); } function qtIsFramework(modInfo, qtProps) { if (modInfo.isFramework) return true; if (!qtProps.frameworkBuild || modInfo.isStaticLibrary) return false; var modulesNeverBuiltAsFrameworks = [ "bootstrap", "openglextensions", "platformsupport", "qmldevtools", "harfbuzzng" ]; if (qtProps.qtMajorVersion <= 5) { modulesNeverBuiltAsFrameworks.push("uitools"); // is framework since qt6 } return !modulesNeverBuiltAsFrameworks.contains(modInfo.qbsName); } function qtLibBaseName(modInfo, libName, debugBuild, qtProps) { var name = libName; if (qtProps.mkspecName.startsWith("win")) { if (debugBuild && qtNeedsDSuffix(qtProps)) name += 'd'; if (!modInfo.isStaticLibrary && qtProps.qtMajorVersion < 5) name += qtProps.qtMajorVersion; } if (qtProps.mkspecName.contains("macx") || qtProps.mkspecName.contains("ios") || qtProps.mkspecName.contains("darwin")) { if (!qtIsFramework(modInfo, qtProps) && qtProps.buildVariant.contains("debug") && (!qtProps.buildVariant.contains("release") || debugBuild)) { name += "_debug"; } } return name; } function qtModuleNameWithoutPrefix(modInfo) { if (modInfo.name === "Phonon") return "phonon"; if (!modInfo.modulePrefix && modInfo.name.startsWith("Qt")) return modInfo.name.slice(2); // Strip off "Qt". if (modInfo.name.startsWith(modInfo.modulePrefix)) return modInfo.name.slice(modInfo.modulePrefix.length); return modInfo.name; } function qtLibraryBaseName(modInfo, qtProps, debugBuild) { if (modInfo.isPlugin) return qtLibBaseName(modInfo, modInfo.name, debugBuild, qtProps); // Some modules use a different naming scheme, so it doesn't get boring. var libNameBroken = modInfo.name === "Enginio" || modInfo.name === "DataVisualization" || modInfo.name === "Phonon"; var libName = ""; if (!modInfo.isExternal) { libName += !modInfo.modulePrefix && !libNameBroken ? "Qt" : modInfo.modulePrefix; if (qtProps.qtMajorVersion >= 5 && !qtIsFramework(modInfo, qtProps) && !libNameBroken) libName += qtProps.qtMajorVersion; } libName += qtModuleNameWithoutPrefix(modInfo); if (!modInfo.isExternal) libName += qtProps.qtLibInfix; return qtLibBaseName(modInfo, libName, debugBuild, qtProps); } function qtLibNameForLinker(modInfo, qtProps, debugBuild) { if (!modInfo.hasLibrary) return undefined; var libName = qtLibraryBaseName(modInfo, qtProps, debugBuild); if (qtProps.mkspecName.contains("msvc")) libName += ".lib"; return libName; } qbs-src-2.6.1/share/qbs/modules/0000755000175100001660000000000014776170045016007 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/qnx/0000755000175100001660000000000014776170045016615 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/qnx/qnx.qbs0000644000175100001660000001206214776170045020133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Probes import qbs.Utilities Module { Probes.PathProbe { id: qnxSdkProbe names: ["qnx700", "qnx660", "qnx650"] searchPaths: Host.os().includes("windows") ? [Environment.getEnv("USERPROFILE"), Environment.getEnv("SystemDrive")] : [Environment.getEnv("HOME"), "/opt"] } Probe { id: qnxTargetOsProbe property string qnxSdkDir: sdkDir property stringList targets: [] configure: { if (qnxSdkDir) { var validEntries = []; var entries = File.directoryEntries( FileInfo.joinPaths(qnxSdkDir, "target"), File.Dirs | File.NoDotAndDotDot); for (var i = 0; i < entries.length; ++i) { if (/^qnx[0-9]$/.test(entries[i])) validEntries.push(entries[i]); } validEntries.sort(); validEntries.reverse(); targets = validEntries; found = targets.length > 0; } else { found = false; } } } version: qnxSdkProbe.found ? qnxSdkProbe.fileName.substr(3, 3).split("").join(".") : undefined readonly property bool qnx7: version ? Utilities.versionCompare(version, "7") >= 0 : false property string sdkDir: qnxSdkProbe.filePath property string hostArch: qnx7 ? "x86_64" : "x86" property string hostOs: { if (Host.os().includes("linux")) return "linux"; if (Host.os().includes("macos")) return "darwin"; if (Host.os().includes("windows")) return qnx7 ? "win64" : "win32"; } property string targetOs: qnxTargetOsProbe.targets[0] property string compilerName: "gcc" property string configurationDir: FileInfo.joinPaths(Environment.getEnv("HOME"), ".qnx") property string hostDir: FileInfo.joinPaths(sdkDir, "host", hostOs, hostArch) property string targetDir: FileInfo.joinPaths(sdkDir, "target", targetOs) property var buildEnv: ({ "QNX_HOST": hostDir, "QNX_TARGET": targetDir, "QNX_CONFIGURATION": configurationDir }) qbs.sysroot: targetDir validate: { if (!sdkDir) { throw ModUtils.ModuleError("Could not find a QNX SDK in any of the following " + "locations:\n\t" + qnxSdkProbe.candidatePaths.join("\n\t") + "\nInstall the QNX SDK to one of the above locations, " + "or set the qnx.sdkDir property to a valid QNX SDK " + "location."); } if (!hostOs) { throw ModUtils.ModuleError("Host operating system '" + Host.os() + "' is not supported by the QNX SDK."); } else if (!File.exists(hostDir)) { throw ModUtils.ModuleError("Detected host tools operating system '" + hostOs + "' and architecture '" + hostArch + "' directory is not " + "present in the QNX SDK installed at '" + sdkDir + "' in the expected location '" + hostDir + "'; did you forget to install it?"); } if (!targetOs) throw ModUtils.ModuleError("Could not find any QNX targets in '" + targetDir + "'"); } } qbs-src-2.6.1/share/qbs/modules/cli/0000755000175100001660000000000014776170045016556 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/cli/CLIModule.qbs0000644000175100001660000001553714776170045021055 0ustar runnerdocker// base for Common Language Infrastructure modules import qbs.FileInfo import qbs.Host import qbs.ModUtils import "cli.js" as CLI Module { Group { condition: qbs.targetOS.includes("darwin") Depends { name: "bundle" } product.bundle.isBundle: false } condition: false property string warningLevel: 'all' // 'none', 'all' property bool treatWarningsAsErrors: false property string architecture: "anycpu" // for the CLI this is a much better default than qbs.architecture property string optimization: qbs.optimization property bool debugInformation: qbs.debugInformation property stringList defines property stringList platformDefines: qbs.enableDebugCode ? [] : ["NDEBUG"] property stringList compilerDefines PropertyOptions { name: "compilerDefines" description: "preprocessor macros that are defined when using this particular compiler" } property pathList libraryPaths property string csharpCompilerName property string csharpCompilerPath: FileInfo.joinPaths(toolchainInstallPath, csharpCompilerName) property string vbCompilerName property string vbCompilerPath: FileInfo.joinPaths(toolchainInstallPath, vbCompilerName) property string fsharpCompilerName property string fsharpCompilerPath: FileInfo.joinPaths(toolchainInstallPath, fsharpCompilerName) property string resgenName: "resgen" property string resgenPath: FileInfo.joinPaths(toolchainInstallPath, resgenName) property string dynamicLibrarySuffix: ".dll" property string executableSuffix: ".exe" property string netmoduleSuffix: ".netmodule" property string debugInfoSuffix property stringList dynamicLibraries // list of names, will be linked with /reference:name property stringList netmodules // list of netmodule files, will be linked with /addmodule:name property bool generateManifestFile: true property string toolchainInstallPath property stringList compilerFlags PropertyOptions { name: "compilerFlags" description: "additional compiler flags" } // Platform properties. Those are intended to be set by the toolchain setup // and are prepended to the corresponding user properties. property stringList platformCompilerFlags FileTagger { patterns: ["*.cs", "*.CS"] fileTags: ["cli.csharp"] } FileTagger { patterns: ["*.vb", "*.VB"] fileTags: ["cli.vb"] } FileTagger { patterns: ["*.fs", "*.FS"] fileTags: ["cli.fsharp"] } FileTagger { patterns: ["*.fsi", "*.FSI"] fileTags: ["cli.fsharp_signature"] } FileTagger { patterns: ["*.resx", "*.RESX"] fileTags: ["cli.resx"] } validate: { var validator = new ModUtils.PropertyValidator("cli"); validator.setRequiredProperty("toolchainInstallPath", toolchainInstallPath); validator.validate(); } setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), Host.os().includes("windows")); v.prepend(product.cli.toolchainInstallPath); v.set(); } Rule { id: cliApplication multiplex: true inputs: ["cli.csharp", "cli.vb", "cli.fsharp"] inputsFromDependencies: ["cli.netmodule", "dynamiclibrary", "cli.resources"] Artifact { fileTags: ["application"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.moduleProperty(product.moduleName, "executableSuffix")) } Artifact { fileTags: ["debuginfo_app"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.moduleProperty(product.moduleName, "debugInfoSuffix")) } prepare: CLI.prepareCompiler(product, inputs, outputs.application[0]) } Rule { id: cliDynamicLibrary multiplex: true inputs: ["cli.csharp", "cli.vb", "cli.fsharp"] inputsFromDependencies: ["cli.netmodule", "dynamiclibrary", "cli.resources"] Artifact { fileTags: ["dynamiclibrary"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.moduleProperty(product.moduleName, "dynamicLibrarySuffix")) } Artifact { fileTags: ["debuginfo_dll"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.moduleProperty(product.moduleName, "debugInfoSuffix")) } prepare: CLI.prepareCompiler(product, inputs, outputs.dynamiclibrary[0]) } Rule { id: netmodule multiplex: true inputs: ["cli.csharp", "cli.vb", "cli.fsharp"] inputsFromDependencies: ["cli.netmodule", "dynamiclibrary", "cli.resources"] Artifact { fileTags: ["cli.netmodule"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.moduleProperty(product.moduleName, "netmoduleSuffix")) } Artifact { fileTags: ["debuginfo_netmodule"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.moduleProperty(product.moduleName, "debugInfoSuffix")) } prepare: CLI.prepareCompiler(product, inputs, outputs["cli.netmodule"][0]) } Rule { inputs: ["cli.resx"] Artifact { fileTags: ["cli.resources"] filePath: FileInfo.joinPaths(product.destinationDirectory, input.completeBaseName + ".resources") } prepare: { var args = [ input.filePath, output.filePath ]; var cmd = new Command(ModUtils.moduleProperty(product, "resgenPath"), args); cmd.description = "building " + input.fileName; cmd.highlight = "compiler"; cmd.workingDirectory = FileInfo.path(output.filePath); return cmd; } } } qbs-src-2.6.1/share/qbs/modules/cli/mono.qbs0000644000175100001660000000123114776170045020232 0ustar runnerdockerimport qbs.File import qbs.Host import qbs.Probes CLIModule { condition: qbs.toolchain && qbs.toolchain.includes("mono") debugInfoSuffix: ".mdb" csharpCompilerName: "mcs" vbCompilerName: "vbnc" fsharpCompilerName: "fsharpc" Probes.PathProbe { id: monoProbe names: ["mono"] platformSearchPaths: { var paths = []; if (Host.os().includes("macos")) paths.push("/Library/Frameworks/Mono.framework/Commands"); if (Host.os().includes("unix")) paths.push("/usr/bin"); return paths; } } toolchainInstallPath: monoProbe.path } qbs-src-2.6.1/share/qbs/modules/cli/windows-dotnet.qbs0000644000175100001660000000200714776170045022251 0ustar runnerdockerimport qbs.Utilities CLIModule { condition: qbs.toolchain && qbs.toolchain.includes("dotnet") debugInfoSuffix: ".pdb" csharpCompilerName: "csc" vbCompilerName: "vbc" fsharpCompilerName: "fsc" Probe { id: dotnetProbe property string toolchainInstallPath // Output configure: { // https://msdn.microsoft.com/en-us/library/hh925568.aspx var keys = [ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\NET Framework Setup\\NDP" ]; for (var i in keys) { var key = keys[i] + "\\v4\\Full"; var value = Utilities.getNativeSetting(key, "InstallPath"); if (value) { toolchainInstallPath = value; found = true; break; } } } } toolchainInstallPath: dotnetProbe.toolchainInstallPath } qbs-src-2.6.1/share/qbs/modules/cli/cli.js0000644000175100001660000001621314776170045017666 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); function prepareCompiler(product, inputs, output) { var i; var args = ["/nologo"]; var platformDefines = product.moduleProperty("cli", "platformDefines"); var compilerDefines = product.moduleProperty("cli", "compilerDefines"); var defines = product.moduleProperty("cli", "defines"); var platformCompilerFlags = product.moduleProperty("cli", "platformCompilerFlags"); var compilerFlags = product.moduleProperty("cli", "compilerFlags") var libraryPaths = product.moduleProperty("cli", "libraryPaths"); var dynamicLibraries = product.moduleProperty("cli", "dynamicLibraries"); var netmodules = product.moduleProperty("cli", "netmodules"); var warnAsError = product.moduleProperty("cli", "treatWarningsAsErrors"); var warningLevel = product.moduleProperty("cli", "warningLevel"); var debugInformation = product.moduleProperty("cli", "debugInformation"); var optimization = product.moduleProperty("cli", "optimization"); var architecture = product.moduleProperty("cli", "architecture"); var csharpCompilerPath = product.moduleProperty("cli", "csharpCompilerPath"); var vbCompilerPath = product.moduleProperty("cli", "vbCompilerPath"); var fsharpCompilerPath = product.moduleProperty("cli", "fsharpCompilerPath"); var compilers = { "cli.csharp": csharpCompilerPath, "cli.vb": vbCompilerPath, "cli.fsharp": fsharpCompilerPath }; var pathFunction = product.moduleProperty("qbs", "hostOS").includes("windows") ? FileInfo.toWindowsSeparators : function (path) { return path; }; var outputDescription = "assembly"; if (output.fileTags.includes("application")) { args.push("/target:" + (product.consoleApplication === false ? "winexe" : "exe")); } else if (output.fileTags.includes("dynamiclibrary")) { args.push("/target:library"); } else if (output.fileTags.includes("cli.netmodule")) { args.push("/target:module"); outputDescription = "netmodule"; } // Make sure our input files are all the same language var keys = Object.keys(inputs); var language; for (i in keys) { if (Object.keys(compilers).includes(keys[i])) { if (language) throw("You cannot compile source files in more than one CLI language into a single " + outputDescription + "."); language = keys[i]; } } if (!compilers[language]) { throw("No CLI compiler available to compile " + language + " files."); } // docs state "/platform is not available in the development environment in Visual C# Express" // does this mean from the IDE or the compiler itself shipped with Express does not support it? if (architecture !== undefined) { if (architecture === "x86" || architecture === "anycpu" || architecture === "anycpu32bitpreferred") // requires .NET 4.5 ; else if (architecture === "x86_64") architecture = "x64"; else if (architecture === "ia64") architecture = "Itanium"; else if (architecture === "arm") architecture = "ARM"; else throw("Invalid CLI architecture: " + architecture); args.push("/platform:" + architecture); } if (debugInformation !== undefined) args.push("/debug" + (debugInformation ? "+" : "-")); if (optimization !== undefined) args.push("/optimize" + (optimization !== "none" ? "+" : "-")); if (warnAsError !== undefined) args.push("/warnaserror" + (warnAsError ? "+" : "-")); if (warningLevel !== undefined) { if (language === "cli.vb") { if (warningLevel === "none" || warningLevel === "0") args.push("/quiet"); } else { if (warningLevel === "all") warningLevel = "4"; else if (warningLevel === "none") warningLevel = "0"; args.push("/warn:" + warningLevel); } } // Preprocessor defines var allDefines = (platformDefines || []).concat(compilerDefines || []).concat(defines || []); if (allDefines.length > 0) args.push("/define:" + allDefines.join(";")); // Library search paths for (i in libraryPaths) args.push("/lib:" + libraryPaths.join(",")); // Dependent libraries for (i in dynamicLibraries) { args.push("/reference:" + dynamicLibraries[i] + product.moduleProperty("cli", "dynamicLibrarySuffix")); } for (i in inputs.dynamiclibrary) args.push("/reference:" + inputs.dynamiclibrary[i].filePath); // Dependent netmodules for (i in netmodules) { args.push("/addmodule:" + netmodules.map(function (f) { return f + product.moduleProperty("cli", "netmoduleSuffix"); }).join(";")); } if (inputs["cli.netmodule"]) { args.push("/addmodule:" + inputs["cli.netmodule"].map(function (f) { return f.filePath; }).join(";")); } // Dependent resources for (i in inputs["cli.resources"]) args.push("/resource:" + pathFunction(inputs["cli.resources"][i].filePath)); // Additional compiler flags args = args.concat((platformCompilerFlags || []).concat(compilerFlags || [])); args.push("/out:" + pathFunction(output.filePath)); for (i in inputs[keys[0]]) args.push(pathFunction(inputs[keys[0]][i].filePath)); var cmd = new Command(compilers[language], args); cmd.description = "linking " + output.fileName; cmd.highlight = "linker"; cmd.workingDirectory = FileInfo.path(output.filePath); return cmd; } qbs-src-2.6.1/share/qbs/modules/nodejs/0000755000175100001660000000000014776170045017271 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/nodejs/NodeJS.qbs0000644000175100001660000001416414776170045021130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Probes Module { // JavaScript files which have been "processed" - currently this simply means "copied to output // directory" but might later include minification and obfuscation processing additionalProductTypes: ["nodejs_processed_js"].concat(applicationFile ? ["application"] : []) Probes.NodeJsProbe { id: nodejs searchPaths: toolchainInstallPath ? [toolchainInstallPath] : [] } Probes.NpmProbe { id: npm searchPaths: toolchainInstallPath ? [toolchainInstallPath] : [] interpreterPath: FileInfo.path(nodejs.filePath) } property path applicationFile PropertyOptions { name: "applicationFile" 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 (" + nodejs.path + " vs " + npm.path + ")"); return nodejs.path || npm.path; } property path interpreterFileName: nodejs.fileName property path interpreterFilePath: nodejs.filePath property path packageManagerFileName: npm.fileName property path packageManagerFilePath: npm.filePath property path packageManagerBinPath: npm.npmBin property path packageManagerRootPath: npm.npmRoot property path packageManagerPrefixPath: npm.npmPrefix // private properties readonly property path compiledIntermediateDir: FileInfo.joinPaths(product.buildDirectory, "tmp", "nodejs.intermediate") setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), Host.os().includes("windows")); v.prepend(product.nodejs.toolchainInstallPath); v.set(); } setupRunEnvironment: { var v = new ModUtils.EnvironmentVariable("NODE_PATH", FileInfo.pathListSeparator(), Host.os().includes("windows")); v.prepend(FileInfo.path(Environment.getEnv("QBS_RUN_FILE_PATH"))); v.set(); } FileTagger { patterns: ["*.js"] fileTags: ["js"] } validate: { var validator = new ModUtils.PropertyValidator("nodejs"); validator.setRequiredProperty("toolchainInstallPath", toolchainInstallPath); validator.setRequiredProperty("interpreterFileName", interpreterFileName); validator.setRequiredProperty("interpreterFilePath", interpreterFilePath); validator.setRequiredProperty("packageManagerFileName", packageManagerFileName); validator.setRequiredProperty("packageManagerFilePath", packageManagerFilePath); validator.setRequiredProperty("packageManagerBinPath", packageManagerBinPath); validator.setRequiredProperty("packageManagerRootPath", packageManagerRootPath); validator.setRequiredProperty("packageManagerPrefixPath", packageManagerPrefixPath); validator.validate(); } Rule { inputs: ["js"] outputArtifacts: { var tags = ["nodejs_processed_js"]; if (input.fileTags.includes("application_js") || product.moduleProperty("nodejs", "applicationFile") === input.filePath) tags.push("application"); // Preserve directory structure of input files var intermediatePath = product.sourceDirectory; // Handle nodejs.compiledIntermediateDir (QBS-5 workaround) var compiled = product.moduleProperty("nodejs", "compiledIntermediateDir"); if (input.filePath.startsWith(compiled)) { intermediatePath = compiled; } intermediatePath = FileInfo.path(FileInfo.relativePath(intermediatePath, input.filePath)); return [{ filePath: FileInfo.joinPaths(product.destinationDirectory, intermediatePath, input.fileName), fileTags: tags }]; } outputFileTags: ["nodejs_processed_js", "application"] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "copying " + input.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } } qbs-src-2.6.1/share/qbs/modules/nodejs/nodejs.js0000644000175100001660000000360214776170045021112 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Process = require("qbs.Process"); function findLocation(packageManagerFilePath, location, nodejsPath) { var p = new Process(); try { if (nodejsPath) p.setEnv("PATH", nodejsPath); if (p.exec(packageManagerFilePath, [location, "-g"]) !== 0) console.error(p.readStdErr().trim()); return p.readStdOut().trim(); } finally { p.close(); } } qbs-src-2.6.1/share/qbs/modules/lex_yacc/0000755000175100001660000000000014776170045017576 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/lex_yacc/lexyacc.js0000644000175100001660000001173014776170045021566 0ustar runnerdockervar FileInfo = require("qbs.FileInfo"); var TextFile = require("qbs.TextFile"); function unquote(s) { return s.startsWith('"') && s.endsWith('"') ? s.substr(1, s.length - 2) : s; } function readLexOptions(filePath) { var result = {}; var f = new TextFile(filePath, TextFile.ReadOnly); var regex = /^%option\s+([^ \t=]+)(?:\s*=\s*(\S+))?/; while (!f.atEof()) { var line = f.readLine(); var m = regex.exec(line); if (!m) { if (line === "%%") break; continue; } result[m[1]] = m[2] || true; } f.close(); return result; } function lexOutputFilePath(input, posixFileName, options) { var outDir = input.lex_yacc.outputDir; var fileName; if (options.outfile) { fileName = unquote(options.outfile); } else if (options.prefix) { fileName = FileInfo.baseName(posixFileName) + '.' + unquote(options.prefix) + '.' + FileInfo.suffix(posixFileName); } else if (input.lex_yacc.uniqueSymbolPrefix) { fileName = input.baseName; fileName += posixFileName; } else { fileName = posixFileName; } return FileInfo.joinPaths(outDir, fileName); } function readYaccOptions(filePath) { var result = {}; var f = new TextFile(filePath, TextFile.ReadOnly); var regex = /^%output\s+(.+)/; while (!f.atEof()) { var line = f.readLine(); var m = regex.exec(line); if (!m) { if (line === "%%") break; continue; } result.output = m[1]; break; } f.close(); return result; } function yaccOutputFilePath(input, posixFileName, options) { var outDir = input.lex_yacc.outputDir; var fileName; if (options.output) { var outputFileName = unquote(options.output); var suffix = FileInfo.suffix(posixFileName); if (suffix === "c") { fileName = outputFileName; } else { fileName = FileInfo.completeBaseName(outputFileName) + '.' + suffix + FileInfo.suffix(outputFileName).slice(1); } } else if (input.lex_yacc.uniqueSymbolPrefix) { fileName = input.baseName + posixFileName.slice(1); } else { fileName = posixFileName; } return FileInfo.joinPaths(outDir, fileName); } function yaccOutputArtifacts(product, input) { var src = { fileTags: [product.lex_yacc.outputTag], lex_yacc: {}, }; var options = readYaccOptions(input.filePath); if (!options.output && input.lex_yacc.yaccOutputFilePath) { options.output = input.lex_yacc.yaccOutputFilePath; src.lex_yacc.useOutputFromModule = true; } var hdr = { filePath: yaccOutputFilePath(input, "y.tab.h", options), fileTags: ["hpp"], }; src.filePath = yaccOutputFilePath(input, "y.tab.c", options); src.cpp = { includePaths: [].concat(input.cpp.includePaths, input.lex_yacc.outputDir), warningLevel: input.lex_yacc.enableCompilerWarnings ? "all" : "none", }; return [hdr, src]; } function yaccCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = input.lex_yacc.yaccFlags; args.push("-d"); var impl = outputs[input.lex_yacc.outputTag][0]; if (impl.lex_yacc.useOutputFromModule) args.push("-o" + input.lex_yacc.yaccOutputFilePath); else if (input.lex_yacc.uniqueSymbolPrefix) args.push("-b", input.baseName, "-p", input.baseName); args.push(input.filePath); var cmd = new Command(input.lex_yacc.yaccBinary, args); cmd.workingDirectory = input.lex_yacc.outputDir; cmd.description = "generating " + impl.fileName + " and " + outputs["hpp"][0].fileName; return [cmd]; } function lexOutputArtifacts(product, input) { var output = { fileTags: [product.lex_yacc.outputTag], lex_yacc: {}, }; var options = readLexOptions(input.filePath); if (!options.outfile && input.lex_yacc.lexOutputFilePath) { options.outfile = input.lex_yacc.lexOutputFilePath; output.lex_yacc.useOutfileFromModule = true; } output.filePath = lexOutputFilePath(input, "lex.yy.c", options); output.cpp = { includePaths: [].concat(input.cpp.includePaths, input.lex_yacc.outputDir), warningLevel: input.lex_yacc.enableCompilerWarnings ? "all" : "none", }; return [output]; } function lexCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = input.lex_yacc.lexFlags; if (output.lex_yacc.useOutfileFromModule) args.push("-o" + input.lex_yacc.lexOutputFilePath); else if (input.lex_yacc.uniqueSymbolPrefix) args.push("-P" + input.baseName, "-o" + output.filePath); args.push(input.filePath); var cmd = new Command(input.lex_yacc.lexBinary, args); cmd.workingDirectory = input.lex_yacc.outputDir; cmd.description = "generating " + output.fileName; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/lex_yacc/lexyacc.qbs0000644000175100001660000000226014776170045021735 0ustar runnerdockerimport "lexyacc.js" as HelperFunctions Module { Depends { name: "cpp" } property bool enableCompilerWarnings: false property string lexBinary: "lex" property string yaccBinary: "yacc" property string outputTag: "c" property bool uniqueSymbolPrefix: false property string lexOutputFilePath property string yaccOutputFilePath property stringList lexFlags: [] property stringList yaccFlags: [] readonly property string outputDir: product.buildDirectory + "/lexyacc" Rule { inputs: ["lex.input"] outputFileTags: [product.lex_yacc.outputTag] outputArtifacts: HelperFunctions.lexOutputArtifacts(product, input) prepare: HelperFunctions.lexCommands.apply(HelperFunctions, arguments) } Rule { inputs: ["yacc.input"] outputFileTags: [product.lex_yacc.outputTag, "hpp"] outputArtifacts: HelperFunctions.yaccOutputArtifacts(product, input) prepare: HelperFunctions.yaccCommands.apply(HelperFunctions, arguments) } FileTagger { patterns: ["*.l"] fileTags: ["lex.input"]; } FileTagger { patterns: ["*.y"] fileTags: ["yacc.input"]; } } qbs-src-2.6.1/share/qbs/modules/ib/0000755000175100001660000000000014776170045016401 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/ib/ib.js0000644000175100001660000004041614776170045017336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var BundleTools = require("qbs.BundleTools"); var DarwinTools = require("qbs.DarwinTools"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var PropertyList = require("qbs.PropertyList"); function artifactsFromInputs(inputs) { var artifacts = []; for (var tag in inputs) { artifacts = artifacts.concat(inputs[tag]); } return artifacts; } function tiffutilScalesMap(inputs) { return artifactsFromInputs(inputs).map(function (a) { var m = a.filePath.match(/^(.+?)(@(\d+)x)?(\..+?)$/); var basePath = m[1]; var scale = m[2] || ""; var nscale = m[3]; var extension = m[4]; if (scale && scale < 1) throw new Error("Invalid scale '" + nscale + "' for image '" + a.filePath + "'"); return { basePath: basePath, extension: extension, scale: scale }; }).reduce(function (previous, current) { previous[current["basePath"]] = (previous[current["basePath"]] || []).concat([{ extension: current["extension"], scale: current["scale"] }]); return previous; }, {}); } function tiffutilOutputFilePath(product, basePath) { return FileInfo.joinPaths(product.destinationDirectory, "hidpi-images", FileInfo.relativePath(product.sourceDirectory, basePath) + product.ib.tiffSuffix); } function tiffutilArtifacts(product, inputs) { var artifacts = []; var map = tiffutilScalesMap(inputs); for (var key in map) { artifacts.push({ filePath: tiffutilOutputFilePath(product, key), fileTags: ["tiff"] }); } return artifacts; } function prepareTiffutil(project, product, inputs, outputs, input, output) { var cmds = []; var map = tiffutilScalesMap(inputs); for (var key in map) { var args = ["-cat" + (product.ib.combineHidpiImages ? "hidpicheck" : "")]; var count = 0; map[key].forEach(function (obj) { args.push(key + obj["scale"] + obj["extension"]); ++count; }); args.push("-out", tiffutilOutputFilePath(product, key)); var cmd = new Command(product.ib.tiffutilPath, args); cmd.description = "creating " + output.fileName; cmd.count = count; cmd.outputFilePath = output.filePath; cmd.stderrFilterFunction = function (output) { return output.replace(count + " images written to " + outputFilePath + ".", ""); }; cmds.push(cmd); } return cmds; } function ibtooldArguments(product, inputs, input, outputs, overrideOutput) { var i; var args = []; var allInputs = artifactsFromInputs(inputs); var outputFormat = ModUtils.moduleProperty(product, "outputFormat"); if (outputFormat) { if (!["binary1", "xml1", "human-readable-text"].includes(outputFormat)) throw("Invalid ibtoold output format: " + outputFormat + ". " + "Must be in [binary1, xml1, human-readable-text]."); args.push("--output-format", outputFormat); } var debugFlags = ["warnings", "errors", "notices"]; for (var j in debugFlags) { var flag = debugFlags[j]; if (ModUtils.modulePropertyFromArtifacts(product, allInputs, product.moduleName, flag)) { args.push("--" + flag); } } if (inputs.assetcatalog) { 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) args.push("--app-icon", appIconName); var launchImageName = ModUtils.modulePropertyFromArtifacts(product, inputs.assetcatalog, product.moduleName, "launchImageName"); if (launchImageName) args.push("--launch-image", launchImageName); // Undocumented but used by Xcode (only for iOS?), probably runs pngcrush or equivalent if (ModUtils.modulePropertyFromArtifacts(product, inputs.assetcatalog, product.moduleName, "compressPngs")) args.push("--compress-pngs"); } else { var sysroot = product.moduleProperty("qbs", "sysroot"); if (sysroot) args.push("--sdk", sysroot); args.push("--flatten", ModUtils.modulePropertyFromArtifacts(product, allInputs, product.moduleName, "flatten") ? 'YES' : 'NO'); // --module and --auto-activate-custom-fonts were introduced in Xcode 6.0 if (ModUtils.moduleProperty(product, "ibtoolVersionMajor") >= 6) { var module = ModUtils.moduleProperty(product, "module"); if (module) args.push("--module", module); if (ModUtils.modulePropertyFromArtifacts(product, allInputs, product.moduleName, "autoActivateCustomFonts")) args.push("--auto-activate-custom-fonts"); } } // --minimum-deployment-target was introduced in Xcode 5.0 var minimumDarwinVersion = product.moduleProperty("cpp", "minimumDarwinVersion"); if (minimumDarwinVersion && ModUtils.moduleProperty(product, "ibtoolVersionMajor") >= 5) args.push("--minimum-deployment-target", minimumDarwinVersion); // --target-device and -output-partial-info-plist were introduced in Xcode 6.0 for ibtool if (ModUtils.moduleProperty(product, "ibtoolVersionMajor") >= 6 || inputs.assetcatalog) { args.push("--output-partial-info-plist", (outputs && outputs.partial_infoplist) ? outputs.partial_infoplist[outputs.partial_infoplist.length - 1].filePath : "/dev/null"); // For iOS, we'd normally only output the devices specified in TARGETED_DEVICE_FAMILY // We can't get this info from Info.plist keys due to dependency order, so use the qbs prop var targetDevices = ModUtils.moduleProperty(product, "targetDevices"); for (i in targetDevices) { args.push("--target-device", targetDevices[i]); } } args = args.concat(ModUtils.modulePropertiesFromArtifacts(product, allInputs, product.moduleName, "flags")); if (overrideOutput) { args.push("--compile", overrideOutput); } else { if (outputs.compiled_assetcatalog) args.push("--compile", product.buildDirectory + "/actool.dir"); else // compiled_ibdoc args.push("--compile", product.buildDirectory + "/ibtool.dir/" + ibtoolCompiledDirSuffix(product, input)); } for (i in allInputs) args.push(allInputs[i].filePath); return args; } function ibtoolFileTaggers(fileTags) { var ext; if (fileTags.includes("nib") && !fileTags.includes("storyboard")) ext = "nib"; if (fileTags.includes("storyboard") && !fileTags.includes("nib")) ext = "storyboard"; if (!ext) throw "unknown ibtool input file tags: " + fileTags; var t = ["bundle.input", "compiled_ibdoc"]; return { ".nib": t.concat(["compiled_" + ext + (ext !== "nib" ? "_nib" : "")]), ".plist": t.concat(["compiled_" + ext + "_infoplist"]), ".storyboard": t.concat(["compiled_" + ext]) }; } function ibtoolCompiledDirSuffix(product, input) { var suffix = input.completeBaseName; if (input.fileTags.includes("nib")) suffix += ModUtils.moduleProperty(product, "compiledNibSuffix"); else if (input.fileTags.includes("storyboard")) suffix += ModUtils.moduleProperty(product, "compiledStoryboardSuffix"); return suffix; } function ibtoolOutputArtifacts(product, inputs, input) { var suffix = ibtoolCompiledDirSuffix(product, input); var tracker = new ModUtils.BlackboxOutputArtifactTracker(); tracker.hostOS = product.moduleProperty("qbs", "hostOS"); tracker.shellPath = product.moduleProperty("qbs", "shellPath"); tracker.fileTaggers = ibtoolFileTaggers(input.fileTags); tracker.command = ModUtils.moduleProperty(product, "ibtoolPath"); tracker.commandArgsFunction = function (outputDirectory) { // Last --output-format argument overrides any previous ones // Append the name of the base output since it can be either a file or a directory // in the case of XIB compilations return ibtooldArguments(product, inputs, input, undefined, FileInfo.joinPaths(outputDirectory, suffix)) .concat(["--output-format", "xml1"]); }; var ibtoolBuildDirectory = product.buildDirectory + "/ibtool.dir"; var main = BundleTools.destinationDirectoryForResource(product, input); var artifacts = tracker.artifacts(ibtoolBuildDirectory); if (product.moduleProperty("ib", "ibtoolVersionMajor") >= 6) { var prefix = input.fileTags.includes("storyboard") ? "SB" : ""; var path = FileInfo.joinPaths(product.destinationDirectory, input.completeBaseName + "-" + prefix + "PartialInfo.plist"); artifacts.push({ filePath: path, fileTags: ["partial_infoplist"] }); } // Let the output artifacts known the "main" output // This can be either a file or directory so the artifact might already exist in the output list for (var i = 0; i < artifacts.length; ++i) { if (artifacts[i].fileTags.includes("compiled_ibdoc")) artifacts[i].bundle = { _bundleFilePath: artifacts[i].filePath.replace(ibtoolBuildDirectory, main) }; } return artifacts; } function ibtoolCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new Command(ModUtils.moduleProperty(product, "ibtoolPath"), ibtooldArguments(product, inputs, input, outputs)); cmd.description = "compiling " + input.fileName; // Also display the language name of the nib/storyboard being compiled if it has one var localizationKey = DarwinTools.localizationKey(input.filePath); if (localizationKey) cmd.description += ' (' + localizationKey + ')'; cmd.highlight = 'compiler'; // May not be strictly needed, but is set by some versions of Xcode if (input.fileTags.includes("storyboard")) cmd.environment.push("IBSC_MINIMUM_COMPATIBILITY_VERSION=" + (product.moduleProperty("cpp", "minimumDarwinVersion") || "")); cmd.stdoutFilterFunction = function(output) { return ""; }; return cmd; } function actoolOutputArtifacts(product, inputs) { // actool has no --dry-run option (rdar://21786925), // so compile to a fake temporary directory in order to extract the list of output files var tracker = new ModUtils.BlackboxOutputArtifactTracker(); tracker.hostOS = product.moduleProperty("qbs", "hostOS"); tracker.shellPath = product.moduleProperty("qbs", "shellPath"); tracker.command = ModUtils.moduleProperty(product, "actoolPath"); tracker.commandArgsFunction = function (outputDirectory) { // Last --output-format argument overrides any previous ones return ibtooldArguments(product, inputs, undefined, undefined, outputDirectory).concat(["--output-format", "xml1"]); }; tracker.processStdOutFunction = parseActoolOutput; var artifacts = tracker.artifacts(product.buildDirectory + "/actool.dir"); // Newer versions of actool don't generate *anything* if there's no input; // in that case a partial Info.plist would not have been generated either if (artifacts && artifacts.length > 0) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, "assetcatalog_generated_info.plist"), fileTags: ["partial_infoplist"] }); } for (var i = 0; i < artifacts.length; ++i) { if (artifacts[i].fileTags.includes("compiled_assetcatalog")) { artifacts[i].bundle = { _bundleFilePath: artifacts[i].filePath.replace( product.buildDirectory + "/actool.dir", BundleTools.destinationDirectoryForResource(product, inputs.assetcatalog[0])) }; } } return artifacts; } function parseActoolOutput(output) { var propertyList = new PropertyList(); try { propertyList.readFromString(output); var plist = propertyList.toObject(); if (plist) plist = plist["com.apple.actool.compilation-results"]; if (plist) { var artifacts = []; files = plist["output-files"]; for (var i in files) { if (files[i] === "/dev/null") continue; var tags = files[i].endsWith(".plist") ? ["partial_infoplist"] : ["bundle.input", "compiled_assetcatalog"]; artifacts.push({ // Even though we pass in a canonical base dir, the paths in the XML File // are non-canonical. See QBS-1417. filePath: FileInfo.canonicalPath(files[i]), fileTags: tags }); } return artifacts; } } finally { propertyList.clear(); } } function ibtoolVersion(ibtool) { var process; var version; try { process = new Process(); if (process.exec(ibtool, ["--version", "--output-format", "xml1"], true) !== 0) console.error(process.readStdErr()); var propertyList = new PropertyList(); try { propertyList.readFromString(process.readStdOut()); var plist = propertyList.toObject(); if (plist) plist = plist["com.apple.ibtool.version"]; if (plist) version = plist["short-bundle-version"]; } finally { propertyList.clear(); } } finally { process.close(); } return version; } function compileAssetCatalogCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var mkdir = new JavaScriptCommand(); mkdir.silent = true; mkdir.sourceCode = function () { File.makePath(FileInfo.joinPaths(product.buildDirectory, "actool.dir")); }; var cmd = new Command(ModUtils.moduleProperty(product, "actoolPath"), ibtooldArguments(product, inputs, input, outputs)); cmd.description = inputs["assetcatalog"].map(function (input) { return "compiling " + input.fileName; }).join('\n'); cmd.highlight = "compiler"; cmd.stdoutFilterFunction = function(output) { return ""; }; return [mkdir, cmd]; } qbs-src-2.6.1/share/qbs/modules/ib/IBModule.qbs0000644000175100001660000001576714776170045020570 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.BundleTools import qbs.DarwinTools import qbs.File import qbs.Host import qbs.FileInfo import qbs.ModUtils import qbs.Process import 'ib.js' as Ib Module { Depends { name: "xcode"; required: false } Probe { id: ibProbe property string toolPath: ibtoolPath // input property string toolVersion // output configure: { toolVersion = Ib.ibtoolVersion(toolPath); found = true; } } condition: Host.os().includes("darwin") && qbs.targetOS.includes("darwin") property bool warnings: true property bool errors: true property bool notices: true property stringList flags // tiffutil specific property string tiffutilName: "tiffutil" property string tiffutilPath: FileInfo.joinPaths("/usr/bin", tiffutilName) property bool combineHidpiImages: true // iconutil specific property string iconutilName: "iconutil" property string iconutilPath: FileInfo.joinPaths("/usr/bin", iconutilName) // XIB/NIB specific property string ibtoolName: "ibtool" property string ibtoolPath: FileInfo.joinPaths(xcode.developerPath, "/usr/bin", ibtoolName) property bool flatten: true property string module property bool autoActivateCustomFonts: true // Asset catalog specific property string actoolName: xcode.present ? "actool" : "ictool" property string actoolPath: FileInfo.joinPaths(xcode.developerPath, "/usr/bin", actoolName) property string appIconName property string launchImageName property bool compressPngs: true // private properties property string outputFormat: "human-readable-text" property string tiffSuffix: ".tiff" property string appleIconSuffix: ".icns" property string compiledAssetCatalogSuffix: ".car" property string compiledNibSuffix: ".nib" property string compiledStoryboardSuffix: ".storyboardc" version: ibtoolVersion property string ibtoolVersion: ibProbe.toolVersion property var ibtoolVersionParts: ibtoolVersion ? ibtoolVersion.split('.').map(function(item) { return parseInt(item, 10); }) : [] property int ibtoolVersionMajor: ibtoolVersionParts[0] property int ibtoolVersionMinor: ibtoolVersionParts[1] property int ibtoolVersionPatch: ibtoolVersionParts[2] property stringList targetDevices: xcode.present ? xcode.targetDevices : DarwinTools.targetDevices(qbs.targetOS) validate: { var validator = new ModUtils.PropertyValidator("ib"); validator.setRequiredProperty("ibtoolVersion", ibtoolVersion); validator.setRequiredProperty("ibtoolVersionMajor", ibtoolVersionMajor); validator.setRequiredProperty("ibtoolVersionMinor", ibtoolVersionMinor); validator.addVersionValidator("ibtoolVersion", ibtoolVersion, 2, 3); validator.addRangeValidator("ibtoolVersionMajor", ibtoolVersionMajor, 1); validator.addRangeValidator("ibtoolVersionMinor", ibtoolVersionMinor, 0); if (ibtoolVersionPatch !== undefined) validator.addRangeValidator("ibtoolVersionPatch", ibtoolVersionPatch, 0); validator.validate(); } FileTagger { patterns: ["*.png"] fileTags: ["png"] } FileTagger { patterns: ["*.iconset"] // bundle fileTags: ["iconset"] } FileTagger { patterns: ["*.nib", "*.xib"] fileTags: ["nib"] } FileTagger { patterns: ["*.storyboard"] fileTags: ["storyboard"] } FileTagger { patterns: ["*.xcassets"] // bundle fileTags: ["assetcatalog"] } Rule { multiplex: true inputs: ["png"] outputFileTags: ["tiff"] outputArtifacts: Ib.tiffutilArtifacts(product, inputs) prepare: Ib.prepareTiffutil.apply(Ib, arguments) } Rule { inputs: ["iconset"] outputFileTags: ["icns", "bundle.input"] outputArtifacts: ([{ filePath: FileInfo.joinPaths(product.destinationDirectory, input.completeBaseName + ModUtils.moduleProperty(product, "appleIconSuffix")), fileTags: ["icns", "bundle.input"], bundle: { _bundleFilePath: FileInfo.joinPaths(BundleTools.destinationDirectoryForResource(product, input), input.completeBaseName + ModUtils.moduleProperty(product, "appleIconSuffix")) } }]) prepare: { var args = ["--convert", "icns", "--output", output.filePath, input.filePath]; var cmd = new Command(ModUtils.moduleProperty(product, "iconutilPath"), args); cmd.description = "compiling " + input.fileName; return cmd; } } Rule { inputs: ["nib", "storyboard"] outputFileTags: { var tags = ["partial_infoplist"]; for (var i = 0; i < inputs.length; ++i) tags = tags.uniqueConcat(ModUtils.allFileTags(Ib.ibtoolFileTaggers(inputs[i]))); return tags; } outputArtifacts: Ib.ibtoolOutputArtifacts(product, inputs, input) prepare: Ib.ibtoolCommands.apply(Ib, arguments) } Rule { inputs: ["assetcatalog"] multiplex: true outputArtifacts: Ib.actoolOutputArtifacts(product, inputs) outputFileTags: ["bundle.input", "compiled_assetcatalog", "partial_infoplist"] prepare: Ib.compileAssetCatalogCommands.apply(Ib, arguments) } } qbs-src-2.6.1/share/qbs/modules/codesign/0000755000175100001660000000000014776170045017602 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/codesign/android.qbs0000644000175100001660000001223114776170045021730 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Raphaël Cotty ** Contact: http://www.qt.io/licensing ** ** This file is part of the Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Probes import "codesign.js" as CodeSign CodeSignModule { condition: qbs.targetOS.includes("android") priority: 1 enableCodeSigning: true property bool useApksigner: true property path apksignerFilePath Probes.JdkProbe { id: jdk environmentPaths: (jdkPath ? [jdkPath] : []).concat(base) } property string jdkPath: jdk.path property string jarsignerFilePath: FileInfo.joinPaths(jdkPath, "bin", jarsignerName) property string jarsignerName: "jarsigner" property string keytoolFilePath: FileInfo.joinPaths(jdkPath, "bin", keytoolName) property string keytoolName: "keytool" property string debugKeystorePath: FileInfo.joinPaths( Environment.getEnv(Host.os().includes("windows") ? "USERPROFILE" : "HOME"), ".android", "debug.keystore") readonly property string debugKeystorePassword: "android" readonly property string debugPassword: "android" readonly property string debugKeyAlias: "androiddebugkey" property string keystorePath: debugKeystorePath property string keystorePassword: debugKeystorePassword property string keyPassword: debugPassword property string keyAlias: debugKeyAlias // Private property set by the Android.sdk module property string _packageName Rule { condition: useApksigner inputs: ["android.package_unsigned"] Artifact { filePath: product.codesign._packageName fileTags: "android.package" } prepare: CodeSign.signApkPackage.apply(this, arguments) } Rule { condition: !useApksigner inputs: ["android.package_unsigned"] Artifact { filePath: product.codesign._packageName fileTags: "android.package" } prepare: CodeSign.signAabPackage.apply(this, arguments) } validate: { // Typically there is a debug keystore in ~/.android/debug.keystore which gets created // by the native build tools the first time a build is done. However, we don't want to // create it ourselves, because writing to a location outside the qbs build directory is // both polluting and has the potential for race conditions. So we'll instruct the user what // to do. if (keystorePath === debugKeystorePath && !File.exists(debugKeystorePath)) { throw ModUtils.ModuleError("Could not find an Android debug keystore at " + codesign.debugKeystorePath + ". " + "If you are developing for Android on this machine for the first time and " + "have never built an application using the native Gradle / Android Studio " + "tooling, this is normal. You must create the debug keystore now using the " + "following command, in order to continue:\n\n" + CodeSign.createDebugKeyStoreCommandString(codesign.keytoolFilePath, codesign.debugKeystorePath, codesign.debugKeystorePassword, codesign.debugPassword, codesign.debugKeyAlias) + "\n\n" + "See the following URL for more information: " + "https://developer.android.com/studio/publish/app-signing.html#debug-mode"); } } } qbs-src-2.6.1/share/qbs/modules/codesign/noop.qbs0000644000175100001660000000313314776170045021264 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ CodeSignModule { condition: true priority: -100 } qbs-src-2.6.1/share/qbs/modules/codesign/signtool.qbs0000644000175100001660000000700414776170045022150 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.Host import qbs.ModUtils import qbs.Probes import "codesign.js" as CODESIGN CodeSignModule { condition: qbs.targetOS.includes("windows") && Host.os().includes("windows") && qbs.toolchain.includes("msvc") _canSignArtifacts: true Probes.BinaryProbe { id: signtoolProbe names: [codesignName] searchPaths: CODESIGN.findBestSignToolSearchPaths(Host.architecture()) } codesignName: "signtool" codesignPath: signtoolProbe.filePath property string subjectName PropertyOptions { name: "subjectName" description: "Name of the subject of the signing certificate." } property string rootSubjectName PropertyOptions { name: "rootSubjectName" description: "Name of the subject of the root certificate that the signing " + "certificate must chain to." } property string hashAlgorithm PropertyOptions { name: "hashAlgorithm" description: "Name of the hash algorithm used on the signing certificate." allowedValues: ["sha1", "sha256", "sha384", "sha512"] } property string timestampAlgorithm PropertyOptions { name: "timestampAlgorithm" description: "Name of the timestamp algorithm." allowedValues: ["sha1", "sha256"] } property path certificatePath PropertyOptions { name: "certificatePath" description: "Path to the signing certificate PFX file." } property string certificatePassword PropertyOptions { name: "certificatePassword" description: "Password to use when opening a certificate PFX file." } property path crossCertificatePath PropertyOptions { name: "crossCertificatePath" description: "Path to the additional certificate CER file." } validate: { if (enableCodeSigning && !File.exists(codesignPath)) { throw ModUtils.ModuleError("Could not find 'signtool' utility"); } } } qbs-src-2.6.1/share/qbs/modules/codesign/apple.qbs0000644000175100001660000002160214776170045021413 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.BundleTools import qbs.DarwinTools import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.PropertyList import qbs.Probes import qbs.Utilities import "codesign.js" as CodeSign import "../xcode/xcode.js" as XcodeUtils CodeSignModule { Depends { name: "xcode"; required: qbs.toolchain && qbs.toolchain.includes("xcode") } Probes.BinaryProbe { id: codesignProbe names: [codesignName] } condition: Host.os().includes("macos") && qbs.targetOS.includes("darwin") priority: 0 enableCodeSigning: _codeSigningRequired codesignName: "codesign" codesignPath: codesignProbe.filePath _canSignArtifacts: true property string signingType: { if (_adHocCodeSigningAllowed) return "ad-hoc"; if (_codeSigningAllowed) return "app-store"; } PropertyOptions { name: "signingType" allowedValues: ["app-store", "apple-id", "ad-hoc"] } property string signingIdentity: { if (signingType === "ad-hoc") // only useful on macOS return "-"; var isDebug = qbs.buildVariant !== "release"; if (qbs.targetOS.includes("ios") || qbs.targetOS.includes("tvos") || qbs.targetOS.includes("watchos")) { switch (signingType) { case "app-store": return isDebug ? "iPhone Developer" : "iPhone Distribution"; } } if (qbs.targetOS.includes("macos")) { switch (signingType) { case "app-store": return isDebug ? "Mac Developer" : "3rd Party Mac Developer Application"; case "apple-id": return "Developer ID Application"; } } } signingTimestamp: "none" property string provisioningProfile PropertyOptions { name: "provisioningProfile" description: "Name or UUID of the provisioning profile to embed in the application; " + "typically left blank to allow automatic provisioning" } property string teamIdentifier PropertyOptions { name: "teamIdentifier" description: "Name or identifier of the development team whose identities will be used; " + "typically left blank unless signed into multiple development teams" } property path provisioningProfilesPath: "~/Library/MobileDevice/Provisioning Profiles" readonly property var _actualSigningIdentity: { if (signingIdentity === "-") { return { SHA1: signingIdentity, subjectInfo: { CN: "ad hoc" } } } var identities = CodeSign.findSigningIdentities(signingIdentity, teamIdentifier); if (identities && Object.keys(identities).length > 1) { throw "Multiple codesigning identities (i.e. certificate and private key pairs) " + "matching '" + signingIdentity + "' were found." + CodeSign.humanReadableIdentitySummary(identities); } for (var i in identities) return identities[i]; } // Allowed for macOS readonly property bool _adHocCodeSigningAllowed: XcodeUtils.boolFromSdkOrPlatform("AD_HOC_CODE_SIGNING_ALLOWED", xcode._sdkProps, xcode._platformProps, true) // Allowed for all device platforms (not simulators) readonly property bool _codeSigningAllowed: XcodeUtils.boolFromSdkOrPlatform("CODE_SIGNING_ALLOWED", xcode._sdkProps, xcode._platformProps, true) // Required for tvOS, iOS, and watchOS (not simulators) property bool _codeSigningRequired: { // allow to override value from Xcode so tests do not require signing var envRequired = Environment.getEnv("QBS_AUTOTEST_CODE_SIGNING_REQUIRED"); if (envRequired) return envRequired === "1"; return XcodeUtils.boolFromSdkOrPlatform("CODE_SIGNING_REQUIRED", xcode._sdkProps, xcode._platformProps, false) } // Required for tvOS, iOS, and watchOS (not simulators) readonly property bool _entitlementsRequired: XcodeUtils.boolFromSdkOrPlatform("ENTITLEMENTS_REQUIRED", xcode._sdkProps, xcode._platformProps, false) readonly property bool _provisioningProfileAllowed: product.bundle && product.bundle.isBundle && product.type.includes("application") && xcode.platformType !== "simulator" // Required for tvOS, iOS, and watchOS (not simulators) // PROVISIONING_PROFILE_REQUIRED is specified only in Embedded-Device.xcspec in the // IDEiOSSupportCore IDE plugin, so we'll just write out the logic here manually readonly property bool _provisioningProfileRequired: _provisioningProfileAllowed && !qbs.targetOS.includes("macos") // Not used on simulator platforms either but provisioning profiles aren't used there anyways readonly property string _provisioningProfilePlatform: { if (qbs.targetOS.includes("macos")) return "OSX"; if (qbs.targetOS.includes("ios") || qbs.targetOS.includes("watchos")) return "iOS"; if (qbs.targetOS.includes("tvos")) return "tvOS"; } readonly property string _embeddedProfileName: (xcode._platformProps || {})["EMBEDDED_PROFILE_NAME"] || "embedded.mobileprovision" setupBuildEnvironment: { var prefixes = product.xcode ? [ product.xcode.platformPath + "/Developer", product.xcode.toolchainPath, product.xcode.developerPath ] : []; for (var i = 0; i < prefixes.length; ++i) { var codesign_allocate = prefixes[i] + "/usr/bin/codesign_allocate"; if (File.exists(codesign_allocate)) { var v = new ModUtils.EnvironmentVariable("CODESIGN_ALLOCATE"); v.value = codesign_allocate; v.set(); break; } } } Group { name: "Provisioning Profiles" prefix: provisioningProfilesPath + "/" files: ["*.mobileprovision", "*.provisionprofile"] } FileTagger { fileTags: ["codesign.entitlements"] patterns: ["*.entitlements"] } FileTagger { fileTags: ["codesign.provisioningprofile"] patterns: ["*.mobileprovision", "*.provisionprofile"] } Group { condition: enableCodeSigning Rule { multiplex: true inputs: ["codesign.entitlements", "codesign.embedded_provisioningprofile"] Artifact { filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".xcent") fileTags: ["codesign.xcent"] } prepare: CodeSign.generateAppleEntitlementsCommands.apply(CodeSign, arguments) } Rule { multiplex: true condition: module._provisioningProfileAllowed inputs: ["codesign.provisioningprofile"] outputFileTags: ["codesign.embedded_provisioningprofile"] outputArtifacts: CodeSign.generateAppleProvisioningProfileOutputs(product, inputs) prepare: CodeSign.generateAppleProvisioningProfileCommands.apply(CodeSign, arguments) } } } qbs-src-2.6.1/share/qbs/modules/codesign/CodeSignModule.qbs0000644000175100001660000000404014776170045023150 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import "codesign.js" as CodeSign Module { condition: false property bool enableCodeSigning: false property string codesignName property string codesignPath: codesignName property stringList codesignFlags property string signingTimestamp PropertyOptions { name: "signingTimestamp" description: "URL of the RFC 3161 time stamp server." } property bool _canSignArtifacts: false // whether can sign individual actifacts } qbs-src-2.6.1/share/qbs/modules/codesign/codesign.js0000644000175100001660000006505714776170045021750 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var PathTools = require("qbs.PathTools"); var Process = require("qbs.Process"); var PropertyList = require("qbs.PropertyList"); var Utilities = require("qbs.Utilities"); function findSigningIdentities(searchString, team) { if (!searchString) return {}; var identities = Utilities.signingIdentities(); var matchedIdentities = {}; for (var key in identities) { var identity = identities[key]; if (team && ![identity.subjectInfo.O, identity.subjectInfo.OU].includes(team)) continue; if (searchString === key || (identity.subjectInfo.CN && identity.subjectInfo.CN.startsWith(searchString))) { matchedIdentities[key] = identity; } } return matchedIdentities; } function humanReadableIdentitySummary(identities) { return "\n\t" + Object.keys(identities).map(function (key) { return identities[key].subjectInfo.CN + " in team " + identities[key].subjectInfo.O + " (" + identities[key].subjectInfo.OU + ")"; }).join("\n\t"); } /** * Returns the best provisioning profile for code signing a binary with the given parameters. * Ideally, this should behave identically as Xcode but the algorithm is not documented * \l{https://developer.apple.com/library/ios/qa/qa1814/_index.html}{Automatic Provisioning} */ function findBestProvisioningProfile(product, files) { var actualSigningIdentity = product.codesign._actualSigningIdentity || {}; var teamIdentifier = product.codesign.teamIdentifier; var bundleIdentifier = product.bundle.identifier; var targetOS = product.qbs.targetOS; var buildVariant = product.qbs.buildVariant; var query = product.codesign.provisioningProfile; var profilePlatform = product.codesign._provisioningProfilePlatform; // Read all provisioning profiles on disk into plist objects in memory var profiles = files.map(function(filePath) { var plist = new PropertyList(); try { plist.readFromData(Utilities.smimeMessageContent(filePath)); return { data: plist.toObject(), filePath: filePath }; } finally { plist.clear(); } }); // Do a simple search by matching UUID or Name if (query) { for (var i = 0; i < profiles.length; ++i) { var obj = profiles[i]; if (obj.data && (obj.data.UUID === query || obj.data.Name === query)) return obj; } // If we asked for a specific provisioning profile, don't select one automatically return undefined; } // Provisioning profiles are not normally used with ad-hoc code signing or non-apps // We do these checks down here only for the automatic selection but not above because // if the user explicitly selects a provisioning profile it should be used no matter what if (actualSigningIdentity.SHA1 === "-" || !product.type.includes("application")) return undefined; // Filter out any provisioning profiles we know to be unsuitable from the start profiles = profiles.filter(function (profile) { var data = profile.data; if (actualSigningIdentity.subjectInfo) { var certCommonNames = (data["DeveloperCertificates"] || []).map(function (cert) { return Utilities.certificateInfo(cert).subjectInfo.CN; }); if (!certCommonNames.includes(actualSigningIdentity.subjectInfo.CN)) { console.log("Skipping provisioning profile with no matching certificate names for '" + actualSigningIdentity.subjectInfo.CN + "' (found " + certCommonNames.join(", ") + "): " + profile.filePath); return false; } } var platforms = data["Platform"] || []; if (platforms.length > 0 && profilePlatform && !platforms.includes(profilePlatform)) { console.log("Skipping provisioning profile for platform " + platforms.join(", ") + " (current platform " + profilePlatform + ")" + ": " + profile.filePath); return false; } if (teamIdentifier && !data["TeamIdentifier"].includes(teamIdentifier) && data["TeamName"] !== teamIdentifier) { console.log("Skipping provisioning profile for team " + data["TeamIdentifier"] + " (" + data["TeamName"] + ") (current team " + teamIdentifier + ")" + ": " + profile.filePath); return false; } if (Date.parse(data["ExpirationDate"]) <= Date.now()) { console.log("Skipping expired provisioning profile: " + profile.filePath); return false; } // Filter development vs distribution profiles; // though the certificate common names check should have been sufficient var isDebug = buildVariant === "debug"; if (data["Entitlements"]["get-task-allow"] !== isDebug) { console.log("Skipping provisioning profile for wrong debug mode: " + profile.filePath); return false; } var prefix = data["ApplicationIdentifierPrefix"]; var fullAppId = data["Entitlements"]["application-identifier"]; if ([prefix, bundleIdentifier].join(".") !== fullAppId && [prefix, "*"].join(".") !== fullAppId) { console.log("Skipping provisioning profile not matching full (" + [prefix, bundleIdentifier].join(".") + ") or wildcard (" + [prefix, "*"].join(".") + ") app ID (found " + fullAppId + "): " + profile.filePath); return false; } return true; }); // Sort by expiration date - sooner expiration dates come last profiles.sort(function(profileA, profileB) { var expA = Date.parse(profileA.data["ExpirationDate"]); var expB = Date.parse(profileB.data["ExpirationDate"]); if (expA < expB) return -1; if (expA > expB) return 1; return 0; }); // Sort by application identifier - wildcard profiles come last profiles.sort(function(profileA, profileB) { var idA = profileA.data["Entitlements"]["application-identifier"]; var idB = profileB.data["Entitlements"]["application-identifier"]; if (!idA.endsWith(".*") && idB.endsWith(".*")) return -1; if (idA.endsWith(".*") && !idB.endsWith(".*")) return 1; return 0; }); if (profiles.length) { console.log("Automatic provisioning using profile " + profiles[0].data.UUID + " (" + profiles[0].data.TeamName + " - " + profiles[0].data.Name + ") in product " + product.name); return profiles[0]; } } /** * Finds out the search paths for the `signtool.exe` utility supplied with * the Windows SDK's. */ function findBestSignToolSearchPaths(arch) { var searchPaths = []; var keys = [ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Microsoft SDKs\\Windows" ]; for (var keyIndex = 0; keyIndex < keys.length; ++keyIndex) { var re = /^v([0-9]+)\.([0-9]+)$/; var groups = Utilities.nativeSettingGroups(keys[keyIndex]).filter(function(version) { return version.match(re); }); groups.sort(function(a, b) { return Utilities.versionCompare(b.substring(1), a.substring(1)); }); function addSearchPath(searchPath) { if (File.exists(searchPath) && !searchPaths.includes(searchPath)) { searchPaths.push(searchPath); return true; } return false; } for (var groupIndex = 0; groupIndex < groups.length; ++groupIndex) { var fullKey = keys[keyIndex] + "\\" + groups[groupIndex]; var fullVersion = Utilities.getNativeSetting(fullKey, "ProductVersion"); if (fullVersion) { var installRoot = FileInfo.cleanPath( Utilities.getNativeSetting(fullKey, "InstallationFolder")); if (installRoot) { // Try to add the architecture-independent path at first. var searchPath = FileInfo.joinPaths(installRoot, "App Certification Kit"); if (!addSearchPath(searchPath)) { // Try to add the architecture-dependent paths at second. var binSearchPath = FileInfo.joinPaths(installRoot, "bin/" + fullVersion); if (!File.exists(binSearchPath)) { binSearchPath += ".0"; if (!File.exists(binSearchPath)) continue; } function kitsArchitectureSubDirectory(arch) { if (arch === "x86") return "x86"; else if (arch === "x86_64") return "x64"; else if (arch.startsWith("arm64")) return "arm64"; else if (arch.startsWith("arm")) return "arm"; } var archDir = kitsArchitectureSubDirectory(arch); searchPath = FileInfo.joinPaths(binSearchPath, archDir); addSearchPath(searchPath); } } } } } return searchPaths; } function prepareSign(project, product, inputs, outputs, input, output) { var cmd, cmds = []; if (!product.codesign.enableCodeSigning) return cmds; var isBundle = "bundle.content" in outputs; var artifacts = []; if (isBundle) { artifacts = [{ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.bundleName), fileName: product.bundle.bundleName }]; } else { artifacts = outputs["codesign.signed_artifact"]; } var isProductBundle = product.bundle && product.bundle.isBundle; var shouldSignArtifact = !isProductBundle || isBundle; var enableCodeSigning = product.codesign.enableCodeSigning; if (enableCodeSigning) { var actualSigningIdentity = product.codesign._actualSigningIdentity; if (!actualSigningIdentity) { throw "No codesigning identities (i.e. certificate and private key pairs) matching “" + product.codesign.signingIdentity + "” were found."; } // If this is a framework, we need to sign its versioned directory var subpath = ""; if (isBundle) { var isFramework = product.bundle.packageType === "FMWK"; if (isFramework) { subpath = product.bundle.contentsFolderPath; subpath = subpath.substring(product.bundle.bundleName.length); } } // The codesign tool behaves weirdly. It can sign a bundle with a single artifact, but if // say debug build variant is present, it starts complaining that it is not signed. // We could always sign everything, but again, in case of a framework (but not in case of // app or loadable bundle), codesign produces a warning that artifact is already signed. // So, we skip signing the release artifact and only sign if other build variants present. if (!shouldSignArtifact && artifacts.length == 1) { artifacts = []; } for (var i = 0; i < artifacts.length; ++i) { if (!shouldSignArtifact && artifacts[i].qbs && artifacts[i].qbs.buildVariant === "release") { continue; } var outputFilePath = artifacts[i].filePath; var outputFileName = artifacts[i].fileName; var args = ["--force", "--sign", actualSigningIdentity.SHA1]; // If signingTimestamp is undefined or empty, do not specify the flag at all - // this uses the system-specific default behavior var signingTimestamp = product.codesign.signingTimestamp; if (signingTimestamp) { // If signingTimestamp is an empty string, specify the flag but do // not specify a value - this uses a default Apple-provided server var flag = "--timestamp"; if (signingTimestamp) flag += "=" + signingTimestamp; args.push(flag); } for (var j in inputs["codesign.xcent"]) { args.push("--entitlements", inputs["codesign.xcent"][j].filePath); break; // there should only be one } args = args.concat(product.codesign.codesignFlags || []); args.push(outputFilePath + subpath); cmd = new Command(product.codesign.codesignPath, args); cmd.description = "codesign " + outputFileName + " (" + actualSigningIdentity.subjectInfo.CN + ")"; cmd.outputFilePath = outputFilePath; cmd.stderrFilterFunction = function(stderr) { return stderr.replace(outputFilePath + ": replacing existing signature\n", ""); }; cmds.push(cmd); } } if (isBundle) { cmd = new Command("touch", ["-c", outputFilePath]); cmd.silent = true; cmds.push(cmd); } return cmds; } function signApkPackage(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var apkInput = inputs["android.package_unsigned"][0]; var apkOutput = outputs["android.package"][0]; var cmd; if (product.codesign.enableCodeSigning) { var args = ["sign", "--ks", product.codesign.keystorePath, "--ks-pass", "pass:" + product.codesign.keystorePassword, "--ks-key-alias", product.codesign.keyAlias, "--key-pass", "pass:" + product.codesign.keyPassword, "--out", apkOutput.filePath, apkInput.filePath]; cmd = new Command(product.codesign.apksignerFilePath, args); cmd.description = "signing " + apkOutput.fileName; } else { cmd = new JavaScriptCommand(); cmd.description = "copying without signing " + apkOutput.fileName; cmd.source = apkInput.filePath; cmd.target = apkOutput.filePath; cmd.silent = true; cmd.sourceCode = function() { // If enableCodeSigning is changed to false without any change to unsigned package then // the copy won't happen because of timestamps. So the target file needs file needs to // be removed to avoid it. File.remove(target); File.copy(source, target); } } return cmd; } function signAabPackage(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var aabInput = inputs["android.package_unsigned"][0]; var aabOutput = outputs["android.package"][0]; var cmd; if (product.codesign.enableCodeSigning) { args = ["-sigalg", "SHA1withRSA", "-digestalg", "SHA1", "-keystore", product.codesign.keystorePath, "-storepass", product.codesign.keystorePassword, "-keypass", product.codesign.keyPassword, "-signedjar", aabOutput.filePath, aabInput.filePath, product.codesign.keyAlias]; cmd = new Command(product.codesign.jarsignerFilePath, args); cmd.description = "signing " + aabOutput.fileName; } else { cmd = new JavaScriptCommand(); cmd.description = "copying without signing " + aabOutput.fileName; cmd.source = aabInput.filePath; cmd.target = aabOutput.filePath; cmd.silent = true; cmd.sourceCode = function() { // If enableCodeSigning is changed to false without any change to unsigned package then // the copy won't happen because of timestamps. So the target file needs file needs to // be removed to avoid it. File.remove(target); File.copy(source, target); } } return cmd; } function createDebugKeyStoreCommandString(keytoolFilePath, keystoreFilePath, keystorePassword, keyPassword, keyAlias) { var args = ["-genkey", "-keystore", keystoreFilePath, "-alias", keyAlias, "-storepass", keystorePassword, "-keypass", keyPassword, "-keyalg", "RSA", "-keysize", "2048", "-validity", "10000", "-dname", "CN=Android Debug,O=Android,C=US"]; return Process.shellQuote(keytoolFilePath, args); } function prepareSigntool(project, product, inputs, outputs, input, output) { var cmd, cmds = []; if (!product.codesign.enableCodeSigning) return cmds; var args = ["sign"]; var subjectName = product.codesign.subjectName; if (subjectName) args.push("/n", subjectName); var rootSubjectName = product.codesign.rootSubjectName; if (rootSubjectName) args.push("/r", rootSubjectName); var hashAlgorithm = product.codesign.hashAlgorithm; if (hashAlgorithm) args.push("/fd", hashAlgorithm); var signingTimestamp = product.codesign.signingTimestamp; if (signingTimestamp) args.push("/tr", signingTimestamp); var timestampAlgorithm = product.codesign.timestampAlgorithm; if (timestampAlgorithm) args.push("/td", timestampAlgorithm); var certificatePath = product.codesign.certificatePath; if (certificatePath) args.push("/f", certificatePath); var certificatePassword = product.codesign.certificatePassword; if (certificatePassword) args.push("/p", certificatePassword); var crossCertificatePath = product.codesign.crossCertificatePath; if (crossCertificatePath) args.push("/ac", crossCertificatePath); args = args.concat(product.codesign.codesignFlags || []); var outputArtifact = outputs["codesign.signed_artifact"][0]; args.push(outputArtifact.filePath); cmd = new Command(product.codesign.codesignPath, args); cmd.description = "signing " + outputArtifact.fileName; cmd.highlight = "linker"; cmds.push(cmd); return cmds; } function generateAppleProvisioningProfileOutputs() { var artifacts = []; var provisioningProfiles = (inputs["codesign.provisioningprofile"] || []) .map(function (a) { return a.filePath; }); var bestProfile = findBestProvisioningProfile(product, provisioningProfiles); var uuid = product.provisioningProfile; if (bestProfile) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.codesign._embeddedProfileName), fileTags: ["codesign.embedded_provisioningprofile"], codesign: { _provisioningProfileFilePath: bestProfile.filePath, _provisioningProfileData: JSON.stringify(bestProfile.data), } }); } else if (uuid) { throw "Your build settings specify a provisioning profile with the UUID '" + uuid + "', however, no such provisioning profile was found."; } else if (product._provisioningProfileRequired) { var hasProfiles = !!((inputs["codesign.provisioningprofile"] || []).length); var teamIdentifier = product.teamIdentifier; var codeSignIdentity = product.signingIdentity; if (hasProfiles) { if (codeSignIdentity) { console.warn("No provisioning profiles matching the bundle identifier '" + product.bundle.identifier + "' were found."); } else { console.warn("No provisioning profiles matching an applicable signing " + "identity were found."); } } else { if (codeSignIdentity) { if (teamIdentifier) { console.warn("No provisioning profiles with a valid signing identity " + "(i.e. certificate and private key pair) matching the " + "team ID '" + teamIdentifier + "' were found.") } else { console.warn("No provisioning profiles with a valid signing identity " + "(i.e. certificate and private key pair) were found."); } } else { console.warn("No non-expired provisioning profiles were found."); } } } return artifacts; } function generateAppleProvisioningProfileCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); var data = JSON.parse(output.codesign._provisioningProfileData); cmd.source = output.codesign._provisioningProfileFilePath; cmd.destination = output.filePath; cmd.description = "using provisioning profile " + data.Name + " (" + data.UUID + ")"; cmd.highlight = "filegen"; cmd.sourceCode = function() { File.copy(source, destination); }; return [cmd]; } function generateAppleEntitlementsCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "generating entitlements"; cmd.highlight = "codegen"; cmd.bundleIdentifier = product.bundle.identifier; cmd.signingEntitlements = (inputs["codesign.entitlements"] || []) .map(function (a) { return a.filePath; }); cmd.provisioningProfiles = (inputs["codesign.embedded_provisioningprofile"] || []) .map(function (a) { return a.filePath; }); cmd.platformPath = product.xcode ? product.xcode.platformPath : undefined; cmd.sdkPath = product.xcode ? product.xcode.sdkPath : undefined; cmd.sourceCode = function() { var i; var provData = {}; var provisionProfiles = inputs["codesign.embedded_provisioningprofile"]; for (i in provisionProfiles) { var plist = new PropertyList(); try { plist.readFromData(Utilities.smimeMessageContent( provisionProfiles[i].filePath)); provData = plist.toObject(); } finally { plist.clear(); } } var aggregateEntitlements = {}; // Start building up an aggregate entitlements plist from the files in the SDKs, // which contain placeholders in the same manner as Info.plist function entitlementsFileContents(path) { return File.exists(path) ? BundleTools.infoPlistContents(path) : undefined; } var entitlementsSources = []; if (platformPath) { entitlementsSources.push( entitlementsFileContents( FileInfo.joinPaths(platformPath, "Entitlements.plist"))); } if (sdkPath) { entitlementsSources.push( entitlementsFileContents( FileInfo.joinPaths(sdkPath, "Entitlements.plist"))); } for (i = 0; i < signingEntitlements.length; ++i) { entitlementsSources.push(entitlementsFileContents(signingEntitlements[i])); } for (i = 0; i < entitlementsSources.length; ++i) { var contents = entitlementsSources[i]; for (var key in contents) { if (contents.hasOwnProperty(key)) aggregateEntitlements[key] = contents[key]; } } contents = provData["Entitlements"]; for (key in contents) { if (contents.hasOwnProperty(key) && !aggregateEntitlements.hasOwnProperty(key)) aggregateEntitlements[key] = contents[key]; } // Expand entitlements variables with data from the provisioning profile var env = { "AppIdentifierPrefix": (provData["ApplicationIdentifierPrefix"] || "") + ".", "CFBundleIdentifier": bundleIdentifier }; DarwinTools.expandPlistEnvironmentVariables(aggregateEntitlements, env, true); // Anything with an undefined or otherwise empty value should be removed // Only JSON-formatted plists can have null values, other formats error out // This also follows Xcode behavior DarwinTools.cleanPropertyList(aggregateEntitlements); var plist = new PropertyList(); try { plist.readFromObject(aggregateEntitlements); plist.writeToFile(outputs["codesign.xcent"][0].filePath, "xml1"); } finally { plist.clear(); } }; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/dmg/0000755000175100001660000000000014776170045016556 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/dmg/dmg.js0000644000175100001660000002053114776170045017664 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var DarwinTools = require("qbs.DarwinTools"); var FileInfo = require("qbs.FileInfo"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function localizationFromArtifact(input) { var locale = input.dmg.licenseLocale || DarwinTools.localizationKey(input.filePath); if (!locale) throw("Could not determine localization for license file: " + input.filePath); return locale; } function dmgbuildSettings(product, inputs) { var backgroundImages = inputs["tiff"]; var backgroundImage; if (backgroundImages) { if (backgroundImages.length > 1) throw new Error("only one background image may be specified"); backgroundImage = backgroundImages[0].filePath; } var volumeIcons = inputs["icns"]; var volumeIcon; if (volumeIcons) { if (volumeIcons.length > 1) throw new Error("only one volume icon may be specified"); volumeIcon = volumeIcons[0].filePath; } var licenseFileObjects = Array.prototype.map.call(inputs["dmg.license"] || [], function (a) { return { "dmg": { "licenseLocale": localizationFromArtifact(a), "licenseLanguageName": a.dmg.licenseLanguageName, "licenseAgreeButtonText": a.dmg.licenseAgreeButtonText, "licenseDisagreeButtonText": a.dmg.licenseDisagreeButtonText, "licensePrintButtonText": a.dmg.licensePrintButtonText, "licenseSaveButtonText": a.dmg.licenseSaveButtonText, "licenseInstructionText": a.dmg.licenseInstructionText, }, "filePath": a.filePath }; }); function reduceLicensesForKey(licenseFileObjects, key) { return licenseFileObjects.reduce(function (accumulator, currentValue) { var locale = currentValue.dmg.licenseLocale; if (accumulator[locale]) throw new Error("Multiple license files for localization '" + locale + "'"); switch (key) { case "licenses": accumulator[locale] = currentValue.filePath; break; case "buttons": var texts = [ currentValue.dmg.licenseLanguageName, currentValue.dmg.licenseAgreeButtonText, currentValue.dmg.licenseDisagreeButtonText, currentValue.dmg.licensePrintButtonText, currentValue.dmg.licenseSaveButtonText, currentValue.dmg.licenseInstructionText ]; accumulator[locale] = texts.every(function (a) { return !!a; }) ? texts : undefined; break; } return accumulator; }, {}); } var contentsArray = Array.prototype.map.call(inputs["dmg.input"] || [], function (a) { if (a.dmg.sourceBase && !a.filePath.startsWith(a.dmg.sourceBase)) { throw new Error("Cannot install '" + a.filePath + "', " + "because it doesn't start with the value of " + "dmg.sourceBase '" + a.dmg.sourceBase + "'."); } var isSymlink = a.fileTags.includes("dmg.input.symlink"); return { "x": a.dmg.iconX, "y": a.dmg.iconY, "type": isSymlink ? "link" : "file", "path": isSymlink ? a.dmg.symlinkTarget : a.filePath, "name": FileInfo.relativePath(a.dmg.sourceBase || FileInfo.path(a.filePath), a.filePath) }; }); Array.prototype.forEach.call(product.dmg.iconPositions || [], function (obj) { var existingIndex = -1; Array.prototype.forEach.call(contentsArray, function (contentsItem, i) { if (contentsItem["name"] === obj["path"]) existingIndex = i; }); if (existingIndex >= 0) { contentsArray[existingIndex]["x"] = obj["x"]; contentsArray[existingIndex]["y"] = obj["y"]; } else { contentsArray.push({ "type": "position", "name": obj["path"], // name => path is not a typo "path": obj["path"], "x": obj["x"], "y": obj["y"] }); } }); var result = { "title": product.dmg.volumeName, "icon": !product.dmg.badgeVolumeIcon ? volumeIcon : undefined, "badge-icon": product.dmg.badgeVolumeIcon ? volumeIcon : undefined, "background": backgroundImage, "background-color": product.dmg.backgroundColor, "icon-size": product.dmg.iconSize, "window": { "position": { "x": product.dmg.windowX, "y": product.dmg.windowY }, "size": { "width": product.dmg.windowWidth, "height": product.dmg.windowHeight } }, "format": product.dmg.format, "compression-level": product.dmg.compressionLevel, "contents": contentsArray }; if (licenseFileObjects.length >= 0) { result["license"] = { "default-language": product.dmg.defaultLicenseLocale, "licenses": reduceLicensesForKey(licenseFileObjects, "licenses"), "buttons": reduceLicensesForKey(licenseFileObjects, "buttons") }; } return result; } function prepareLicense(project, product, inputs, outputs, input, output) { var cmd = new Command(product.dmg.textutilPath, [ "-convert", "rtf", "-strip", "-font", "Arial", "-output", output.filePath, "--", input.filePath ]); cmd.description = "converting " + input.fileName; return [cmd]; } function prepareDmg(project, product, inputs, outputs, input, output) { var i; var cmd; var cmds = []; var settingsJsonFilePath = FileInfo.joinPaths(product.destinationDirectory, "settings.json"); cmd = new JavaScriptCommand(); cmd.silent = true; cmd.settingsJSON = dmgbuildSettings(product, inputs); cmd.settingsJsonFilePath = settingsJsonFilePath; cmd.sourceCode = function () { var tf; try { tf = new TextFile(settingsJsonFilePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(settingsJSON, undefined, 4)); } finally { if (tf) tf.close(); } } cmds.push(cmd); // Create the actual DMG via dmgbuild cmd = new Command(product.dmg.pythonExePath, ["-m", "dmgbuild", product.dmg.volumeName, output.filePath, "--no-hidpi", // qbs handles this by itself "--settings", settingsJsonFilePath]); cmd.environment = ["PYTHONPATH=" + product.dmg.pythonPath]; cmd.description = "creating " + output.fileName; cmds.push(cmd); return cmds; } qbs-src-2.6.1/share/qbs/modules/dmg/DMGModule.qbs0000644000175100001660000001305214776170045021043 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.DarwinTools import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Process import qbs.Probes import qbs.TextFile import "dmg.js" as Dmg Module { Depends { name: "xcode"; required: false } condition: Host.os().includes("darwin") && qbs.targetOS.includes("darwin") property string volumeName: product.targetName PropertyOptions { name: "volumeName" description: "the name of the disk image (displayed in Finder when mounted)" } property bool badgeVolumeIcon: false PropertyOptions { name: "badgeVolumeIcon" description: "whether to render the user-supplied icon on top of the " + "default volume icon instead of using it directly" } property string format: "UDBZ" PropertyOptions { name: "format" description: "the format to create the disk image in" } property int compressionLevel: qbs.buildVariant === "release" ? 9 : undefined PropertyOptions { name: "compressionLevel" description: "sets the zlib or bzip2 compression level for UDZO and UDBZ disk images" } property string textutilPath: "/usr/bin/textutil" property string hdiutilPath: "/usr/bin/hdiutil" property string dmgSuffix: ".dmg" property string sourceBase Probes.BinaryProbe { id: pythonProbe names: ["python3"] } property string pythonExePath: pythonProbe.found ? pythonProbe.filePath : "python3" readonly property string pythonPath: File.canonicalFilePath(FileInfo.joinPaths(path, "..", "..", "python")) property string backgroundColor property int iconSize: 128 property int windowX: 100 property int windowY: 100 property int windowWidth: 640 property int windowHeight: 480 property var iconPositions property int iconX: windowWidth / 2 property int iconY: windowHeight / 2 property string defaultLicenseLocale property string licenseLocale property string licenseLanguageName property string licenseAgreeButtonText property string licenseDisagreeButtonText property string licensePrintButtonText property string licenseSaveButtonText property string licenseInstructionText FileTagger { patterns: [ "*.txt", "*.rtf", "*.html", "*.doc", "*.docx", "*.odt", "*.xml", "*.webarchive", "LICENSE" ] fileTags: ["dmg.license.input"] } FileTagger { patterns: ["*.icns"] fileTags: ["icns"] } FileTagger { patterns: ["*.tif", "*.tiff"] fileTags: ["tiff"] } Rule { inputs: ["dmg.license.input"] outputFileTags: ["dmg.license"] outputArtifacts: ([{ filePath: FileInfo.joinPaths(product.destinationDirectory, "licenses", FileInfo.relativePath(product.sourceDirectory, input.filePath) + ".rtf"), fileTags: ["dmg.license"], dmg: { licenseLocale: input.dmg.licenseLocale, licenseLanguageName: input.dmg.licenseLanguageName, licenseAgreeButtonText: input.dmg.licenseAgreeButtonText, licenseDisagreeButtonText: input.dmg.licenseDisagreeButtonText, licensePrintButtonText: input.dmg.licensePrintButtonText, licenseSaveButtonText: input.dmg.licenseSaveButtonText, licenseInstructionText: input.dmg.licenseInstructionText } }]) prepare: Dmg.prepareLicense.apply(Dmg, arguments) } Rule { multiplex: true inputs: ["dmg.input", "dmg.license", "icns", "tiff"] Artifact { fileTags: ["dmg.dmg"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.dmg.dmgSuffix) } prepare: Dmg.prepareDmg.apply(Dmg, arguments) } } qbs-src-2.6.1/share/qbs/modules/innosetup/0000755000175100001660000000000014776170045020033 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/innosetup/InnoSetupModule.qbs0000644000175100001660000001321114776170045023632 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.ModUtils import qbs.Probes Module { condition: qbs.targetOS.includes("windows") Probes.InnoSetupProbe { id: innoSetupProbe } property path toolchainInstallPath: innoSetupProbe.path version: innoSetupProbe.version property var versionParts: version ? version.split('.').map(function (item) { return parseInt(item, 10); }) : [] property int versionMajor: versionParts[0] property int versionMinor: versionParts[1] property int versionPatch: versionParts[2] property string compilerName: "ISCC.exe" property string compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) property bool verboseOutput: false PropertyOptions { name: "verboseOutput" description: "display verbose output from the Inno Setup compiler" } property pathList includePaths PropertyOptions { name: "includePaths" description: "directories to add to the include search path" } property stringList defines PropertyOptions { name: "defines" description: "variables that are defined when using the Inno Setup compiler" } property stringList compilerFlags PropertyOptions { name: "compilerFlags" description: "additional flags for the Inno Setup compiler" } readonly property string executableSuffix: ".exe" validate: { if (!innoSetupProbe.found) { throw ModUtils.ModuleError("Could not find InnoSetup in Windows registry. Make " + "sure InnoSetup is installed correctly."); } var validator = new ModUtils.PropertyValidator("innosetup"); validator.setRequiredProperty("toolchainInstallPath", toolchainInstallPath); validator.setRequiredProperty("version", version); validator.setRequiredProperty("versionMajor", versionMajor); validator.setRequiredProperty("versionMinor", versionMinor); validator.setRequiredProperty("versionPatch", versionPatch); validator.addVersionValidator("version", version, 3, 3); validator.addRangeValidator("versionMajor", versionMajor, 1); validator.addRangeValidator("versionMinor", versionMinor, 0); validator.addRangeValidator("versionPatch", versionPatch, 0); validator.validate(); } // Inno Setup Script FileTagger { patterns: ["*.iss"] fileTags: ["innosetup.iss"] } Rule { id: innoSetupCompiler inputs: ["innosetup.iss"] auxiliaryInputs: ["installable"] auxiliaryInputsFromDependencies: ["installable"] Artifact { fileTags: ["innosetup.exe", "application"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ModUtils.moduleProperty(product, "executableSuffix")) } prepare: { var i; var args = [ "/O" + FileInfo.toNativeSeparators(FileInfo.path(output.filePath)), "/F" + FileInfo.toNativeSeparators(FileInfo.completeBaseName(output.fileName)) ]; if (!ModUtils.moduleProperty(product, "verboseOutput")) args.push("/Q"); var includePaths = ModUtils.moduleProperty(product, "includePaths"); for (i in includePaths) args.push("/I" + FileInfo.toNativeSeparators(includePaths[i])); // User-supplied defines var defines = ModUtils.moduleProperty(product, "defines"); for (i in defines) args.push("/D" + defines[i]); // User-supplied flags var flags = ModUtils.moduleProperty(product, "compilerFlags"); for (i in flags) args.push(flags[i]); args.push(FileInfo.toNativeSeparators(input.filePath)); var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.workingDirectory = FileInfo.path(input.filePath); return cmd; } } } qbs-src-2.6.1/share/qbs/modules/xcode/0000755000175100001660000000000014776170045017111 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/xcode/xcode.qbs0000644000175100001660000002020514776170045020721 0ustar runnerdockerimport qbs.BundleTools import qbs.Environment import qbs.File import qbs.FileInfo import qbs.DarwinTools import qbs.ModUtils import qbs.Probes import qbs.PropertyList import qbs.Utilities Module { Probes.XcodeLocationProbe { id: xcodeLocationProbe condition: !developerPath } Probes.XcodeProbe { id: xcodeProbe developerPath: parent.developerPath platformType: parent.platformType platformPath: parent.platformPath devicePlatformPath: parent.devicePlatformPath xcodebuildPath: parent.xcodebuildPath sdksPath: parent.sdksPath } condition: qbs.targetOS.includes("darwin") && qbs.toolchain && qbs.toolchain.includes("xcode") version: xcodeProbe.xcodeVersion property path developerPath: xcodeLocationProbe.found ? xcodeLocationProbe.developerPath : undefined property string sdk: DarwinTools.applePlatformName(qbs.targetOS, platformType) 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"]; } } readonly property string sdkVersion: { if (_sdkSettings) { return _sdkSettings["Version"]; } } readonly property string shortSdkVersion: { var v = sdkVersion; if (v && v.split('.').length > 2) v = v.slice(0, v.lastIndexOf('.')); return v; } readonly property string latestSdkName: { if (_latestSdk) { return _latestSdk["CanonicalName"]; } } readonly property string latestSdkVersion: { if (_latestSdk) { return _latestSdk["Version"]; } } readonly property stringList availableSdkNames: { if (_availableSdks) { return _availableSdks.map(function (obj) { return obj["CanonicalName"]; }); } } readonly property stringList availableSdkVersions: { if (_availableSdks) { return _availableSdks.map(function (obj) { return obj["Version"]; }); } } readonly property path toolchainPath: FileInfo.joinPaths(toolchainsPath, "XcodeDefault" + ".xctoolchain") readonly property path platformPath: FileInfo.joinPaths(platformsPath, DarwinTools.applePlatformDirectoryName( qbs.targetOS, platformType) + ".platform") readonly property path devicePlatformPath: FileInfo.joinPaths( platformsPath, DarwinTools.applePlatformDirectoryName( qbs.targetOS, "device") + ".platform") readonly property path simulatorPlatformPath: FileInfo.joinPaths( platformsPath, DarwinTools.applePlatformDirectoryName( qbs.targetOS, "simulator") + ".platform") readonly property path sdkPath: FileInfo.joinPaths(sdksPath, DarwinTools.applePlatformDirectoryName( qbs.targetOS, platformType, shortSdkVersion) + ".sdk") // private properties readonly property path toolchainsPath: FileInfo.joinPaths(developerPath, "Toolchains") readonly property path platformsPath: FileInfo.joinPaths(developerPath, "Platforms") readonly property path sdksPath: FileInfo.joinPaths(platformPath, "Developer", "SDKs") readonly property path platformInfoPlist: FileInfo.joinPaths(platformPath, "Info.plist") readonly property path sdkSettingsPlist: FileInfo.joinPaths(sdkPath, "SDKSettings.plist") readonly property path toolchainInfoPlist: FileInfo.joinPaths(toolchainPath, "ToolchainInfo.plist") readonly property var _platformSettings: xcodeProbe.platformSettings readonly property var _platformProps: { if (_platformSettings) return _platformSettings["DefaultProperties"]; } readonly property stringList standardArchitectures: _architectureSettings["ARCHS_STANDARD"] readonly property var _architectureSettings: xcodeProbe.architectureSettings readonly property var _availableSdks: xcodeProbe.availableSdks readonly property var _latestSdk: _availableSdks[_availableSdks.length - 1] readonly property var _sdkSettings: { if (_availableSdks) { // see 'sdk' property doc to understand why this loop is needed for (var i in _availableSdks) { if (_availableSdks[i]["Version"] === sdk) return _availableSdks[i]; if (_availableSdks[i]["CanonicalName"] === sdk) return _availableSdks[i]; } // Latest SDK available for the platform (default case) if (DarwinTools.applePlatformName(qbs.targetOS, platformType) === sdk) return _latestSdk; } } readonly property var _sdkProps: { if (_sdkSettings) { return _sdkSettings["DefaultProperties"]; } } qbs.sysroot: sdkPath validate: { if (!_availableSdks) { throw "There are no SDKs available for this platform in the Xcode installation."; } if (!_sdkSettings) { throw "There is no matching SDK available for " + sdk + "."; } var validator = new ModUtils.PropertyValidator("xcode"); validator.setRequiredProperty("developerPath", developerPath); validator.setRequiredProperty("sdk", sdk); validator.setRequiredProperty("sdkName", sdkName); validator.setRequiredProperty("sdkVersion", sdkVersion); validator.setRequiredProperty("toolchainsPath", toolchainsPath); validator.setRequiredProperty("toolchainPath", toolchainPath); validator.setRequiredProperty("platformsPath", platformsPath); validator.setRequiredProperty("platformPath", platformPath); validator.setRequiredProperty("sdksPath", sdkPath); validator.setRequiredProperty("sdkPath", sdkPath); validator.addVersionValidator("sdkVersion", sdkVersion, 2, 3); validator.addCustomValidator("sdkName", sdkName, function (value) { return value === DarwinTools.applePlatformDirectoryName( qbs.targetOS, platformType, shortSdkVersion, false).toLowerCase(); }, "is '" + sdkName + "', but target OS is [" + qbs.targetOS.join(",") + "] and Xcode SDK version is '" + sdkVersion + "'"); validator.addCustomValidator("sdk", sdk, function (value) { return value === sdkName || (value + shortSdkVersion) === sdkName; }, "is '" + sdk + "', but canonical SDK name is '" + sdkName + "'"); validator.validate(); } property var buildEnv: ({ "DEVELOPER_DIR": developerPath, "SDKROOT": sdkPath }) setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), false); v.prepend(product.xcode.platformPath + "/Developer/usr/bin"); v.prepend(product.xcode.developerPath + "/usr/bin"); v.set(); for (var key in product.xcode.buildEnv) { v = new ModUtils.EnvironmentVariable(key); v.value = product.xcode.buildEnv[key]; v.set(); } } } qbs-src-2.6.1/share/qbs/modules/xcode/xcode.js0000644000175100001660000002514614776170045020561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var DarwinTools = require("qbs.DarwinTools"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); var PropertyList = require("qbs.PropertyList"); var Utilities = require("qbs.Utilities"); var XcodeArchSpecsReader = (function () { function XcodeArchSpecsReader(specsPath) { var plist = new PropertyList(); try { plist.readFromFile(specsPath); this.specsObject = plist.toObject(); } finally { plist.clear(); } } XcodeArchSpecsReader.prototype.getArchitectureSettings = function () { if (this.specsObject) { var names = []; for (var i = 0; i < this.specsObject.length; ++i) { var dict = this.specsObject[i]; var name = dict["ArchitectureSetting"]; if (name) names.push(name); } return names; } }; XcodeArchSpecsReader.prototype.getArchitectureSettingValue = function (settingName) { // settingName can be: ARCHS_STANDARD, ARCHS_STANDARD_32_BIT, ARCHS_STANDARD_64_BIT, // ARCHS_STANDARD_32_64_BIT, ARCHS_STANDARD_INCLUDING_64_BIT, or ARCHS_UNIVERSAL_IPHONE_OS. // NATIVE_ARCH_ACTUAL doesn't have a RealArchitectures property since it's determined by // Xcode programmatically. if (this.specsObject) { for (var i = 0; i < this.specsObject.length; ++i) { var dict = this.specsObject[i]; if (dict["ArchitectureSetting"] === settingName) { var realArchs = dict["RealArchitectures"]; if (realArchs) { var effectiveRealArchs = []; for (var j = 0; j < realArchs.length; ++j) { var re = /^\$\(([A-Za-z0-9_]+)\)$/; var match = realArchs[j].match(re); if (match) { var val = this.getArchitectureSettingValue(match[1]); // Don't silently omit values if missing. For example, if // ARCHS_FOO=[x86_64, $(ARCHS_BAR)], return 'undefined' instead of // simply [x86_64]. Not known to have any real world occurrences. if (!val) return undefined; Array.prototype.push.apply(effectiveRealArchs, val); } else { effectiveRealArchs.push(realArchs[j]); } } return effectiveRealArchs; } } } } }; return XcodeArchSpecsReader; }()); function platformInfo(platformInfoPlist) { var propertyList = new PropertyList(); try { propertyList.readFromFile(platformInfoPlist); return propertyList.toObject(); } finally { propertyList.clear(); } } function sdkInfoList(sdksPath) { var sdkInfo = []; var sdks = File.directoryEntries(sdksPath, File.Dirs | File.NoDotAndDotDot); for (var i in sdks) { // SDK directory name must contain a version number; // we don't want the versionless iPhoneOS.sdk directory for example if (!sdks[i].match(/[0-9]+/)) continue; if (sdks[i].startsWith("DriverKit") || sdks[i].startsWith("AssetRuntime")) continue; var settingsPlist = FileInfo.joinPaths(sdksPath, sdks[i], "SDKSettings.plist"); var propertyList = new PropertyList(); try { propertyList.readFromFile(settingsPlist); function checkPlist(plist) { if (!plist || !plist["CanonicalName"] || !plist["Version"]) return false; var re = /^[0-9]+\.[0-9]+(\.[0-9]+)?$/; return plist["Version"].match(re); } var plist = propertyList.toObject(); if (!checkPlist(plist)) { console.warn("Skipping corrupted SDK installation: " + FileInfo.joinPaths(sdksPath, sdks[i])); continue; } sdkInfo.push(plist); } finally { propertyList.clear(); } } // Sort by SDK version number sdkInfo.sort(function (a, b) { return Utilities.versionCompare(a["Version"], b["Version"]); }); return sdkInfo; } function findSigningIdentities(security, searchString) { var process; var identities; if (searchString) { try { process = new Process(); if (process.exec(security, ["find-identity", "-p", "codesigning", "-v"], true) !== 0) console.error(process.readStdErr()); var lines = process.readStdOut().split("\n"); for (var i in lines) { // e.g. 1) AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "Mac Developer: John Doe (XXXXXXXXXX) john.doe@example.org" var match = lines[i].match(/^\s*[0-9]+\)\s+([A-Fa-f0-9]{40})\s+"([^"]+)"$/); if (match !== null) { var hexId = match[1]; var displayName = match[2]; if (hexId === searchString || displayName.startsWith(searchString)) { if (!identities) identities = []; identities.push([hexId, displayName]); break; } } } } finally { process.close(); } } return identities; } function provisioningProfilePlistContents(filePath) { if (filePath === undefined || !File.exists(filePath)) return undefined; var plist = new PropertyList(); try { plist.readFromFile(filePath); return plist.toObject(); } finally { plist.clear(); } } function boolFromSdkOrPlatform(varName, sdkProps, platformProps, defaultValue) { var values = [(sdkProps || {})[varName], (platformProps || {})[varName]]; for (var i = 0; i < values.length; ++i) { if (values[i] === "YES") return true; if (values[i] === "NO") return false; } return defaultValue; } function archsSpecsPath(version, targetOS, platformType, platformPath, devicePlatformPath, developerPath) { if (Utilities.versionCompare(version, "13.3") >= 0) { var pluginsDir; if (Utilities.versionCompare(version, "15.3") >= 0) { pluginsDir = FileInfo.joinPaths(developerPath, "..", "SharedFrameworks", "XCBuild.framework", "PlugIns", "XCBBuildService.bundle", "Contents", "PlugIns"); } else if (Utilities.versionCompare(version, "14.3") >= 0) { pluginsDir = FileInfo.joinPaths(developerPath, "Library", "Xcode", "Plug-ins"); } else { pluginsDir = FileInfo.joinPaths(developerPath, "..", "PlugIns"); } var baseDir = FileInfo.joinPaths(pluginsDir, "XCBSpecifications.ideplugin", "Contents", "Resources"); var baseName = targetOS.includes("macos") ? "MacOSX Architectures" : targetOS.includes("ios-simulator") ? "iOS Simulator" : targetOS.includes("ios") ? "iOS Device" : targetOS.includes("tvos-simulator") ? "tvOS Simulator" : targetOS.includes("tvos") ? "tvOS Device" : targetOS.includes("watchos-simulator") ? "watchOS Simulator" : "watchOS Device"; return FileInfo.joinPaths(baseDir, baseName + ".xcspec"); } var _specsPluginBaseName; if (Utilities.versionCompare(version, "12") >= 0) { if (targetOS.includes("macos")) _specsPluginBaseName = "OSX"; } if (Utilities.versionCompare(version, "7") >= 0) { if (targetOS.includes("ios")) _specsPluginBaseName = "iOSPlatform"; if (targetOS.includes("tvos")) _specsPluginBaseName = "AppleTV"; if (targetOS.includes("watchos")) _specsPluginBaseName = "Watch"; } var _archSpecsDir = _specsPluginBaseName ? FileInfo.joinPaths(devicePlatformPath, "Developer", "Library", "Xcode", "PrivatePlugIns", "IDE" + _specsPluginBaseName + "SupportCore.ideplugin", "Contents", "Resources") : FileInfo.joinPaths(platformPath, "Developer", "Library", "Xcode", "Specifications"); var _archSpecsFileBaseName = targetOS.includes("ios") ? (targetOS.includes("ios-simulator") ? "iPhone Simulator " : "iPhoneOS") : DarwinTools.applePlatformDirectoryName(targetOS, platformType) + " "; if (_specsPluginBaseName) { switch (platformType) { case "device": return FileInfo.joinPaths(_archSpecsDir, "Device.xcspec"); case "simulator": return FileInfo.joinPaths(_archSpecsDir, "Simulator.xcspec"); } } return FileInfo.joinPaths(_archSpecsDir, _archSpecsFileBaseName + "Architectures.xcspec"); } qbs-src-2.6.1/share/qbs/modules/Exporter/0000755000175100001660000000000014776170045017617 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Exporter/exporter.js0000644000175100001660000000642014776170045022027 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of the Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ function getPrefixToStrip(project, product, propName, value) { function checkValuePrefix(forbiddenPrefix, prefixDescription) { if (value.startsWith(forbiddenPrefix)) { throw "Value '" + value + "' for exported property '" + propName + "' in product '" + product.name + "' points into " + prefixDescription + ".\n" + "Did you forget to set the prefixMapping property in an Export item?"; } } // Catch user oversights: Paths that point into the project source or build directories // make no sense in the module. if (!value.startsWith(product.qbs.installRoot)) { checkValuePrefix(project.buildDirectory, "project build directory"); checkValuePrefix(project.sourceDirectory, "project source directory"); } // Adapt file paths pointing into the install dir, that is, make them relative to the // module file for relocatability. We accept them with or without the install root. // The latter form will typically be a result of applying the prefixMapping property, // while the first one could be an untransformed path, for instance if the project // file is written in such a way that include paths are picked up from the installed // location rather than the source directory. var result; var fullInstallPrefix = FileInfo.joinPaths(product.qbs.installRoot, product.qbs.installPrefix); if (fullInstallPrefix.length > 1 && value.startsWith(fullInstallPrefix)) { result = fullInstallPrefix; } else { var installPrefix = FileInfo.joinPaths("/", product.qbs.installPrefix); if (installPrefix.length > 1 && value.startsWith(installPrefix)) result = installPrefix; } return result; } qbs-src-2.6.1/share/qbs/modules/Exporter/qbs/0000755000175100001660000000000014776170045020404 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Exporter/qbs/qbsexporter.js0000644000175100001660000002320314776170045023320 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var ExporterHelpers = require("../exporter.js"); function tagListToString(tagList) { return JSON.stringify(tagList); } function stringToTagList(tagListString) { return JSON.parse(tagListString); } function writeTargetArtifactGroup(output, tagList, artifactList, moduleInstallDir, moduleFile) { // Do not add our qbs module file itself. if (tagListToString(tagList) === tagListToString(output.fileTags)) return; moduleFile.writeLine(" Group {"); moduleFile.writeLine(" filesAreTargets: true"); var filteredTagList = tagList.filter(function(t) { return t !== "installable"; }); moduleFile.writeLine(" fileTags: " + JSON.stringify(filteredTagList)); moduleFile.writeLine(" files: ["); for (i = 0; i < artifactList.length; ++i) { var artifact = artifactList[i]; var installedArtifactFilePath = ModUtils.artifactInstalledFilePath(artifact); // Use relative file paths for relocatability. var relativeInstalledArtifactFilePath = FileInfo.relativePath(moduleInstallDir, installedArtifactFilePath); moduleFile.writeLine(" " + JSON.stringify(relativeInstalledArtifactFilePath) + ","); } moduleFile.writeLine(" ]"); moduleFile.writeLine(" }"); } function writeTargetArtifactGroups(product, output, moduleFile) { var relevantArtifacts = []; for (var i = 0; i < (product.Exporter.qbs._artifactTypes || []).length; ++i) { var tag = product.Exporter.qbs._artifactTypes[i]; var artifactsForTag = product.artifacts[tag] || []; for (var j = 0; j < artifactsForTag.length; ++j) { if (!relevantArtifacts.includes(artifactsForTag[j])) relevantArtifacts.push(artifactsForTag[j]); } } var artifactsByTags = {}; var artifactCount = relevantArtifacts ? relevantArtifacts.length : 0; for (i = 0; i < artifactCount; ++i) { var artifact = relevantArtifacts[i]; if (!artifact.fileTags.includes("installable")) continue; // Put all artifacts with the same set of file tags into the same group, so we don't // create more groups than necessary. var key = tagListToString(artifact.fileTags); var currentList = artifactsByTags[key]; if (currentList) currentList.push(artifact); else currentList = [artifact]; artifactsByTags[key] = currentList; } var moduleInstallDir = FileInfo.path(ModUtils.artifactInstalledFilePath(output)); for (var tagListKey in artifactsByTags) { writeTargetArtifactGroup(output, stringToTagList(tagListKey), artifactsByTags[tagListKey], moduleInstallDir, moduleFile); } } function stringifyValue(project, product, moduleInstallDir, prop, value) { if (value instanceof Array) { var repr = "["; for (var i = 0; i < value.length; ++i) { repr += stringifyValue(project, product, moduleInstallDir, prop, value[i]) + ", "; } repr += "]"; return repr; } if (typeof(value) !== "string") { var value = JSON.stringify(value); if (prop.type === "variant") value = '(' + value + ')'; return value; } var valuePrefixToStrip = ExporterHelpers.getPrefixToStrip(project, product, prop.name, value); if (valuePrefixToStrip) { var fullInstallPrefix = FileInfo.joinPaths(product.qbs.installRoot, product.qbs.installPrefix); var deployedModuleInstallDir = moduleInstallDir.slice(fullInstallPrefix.length); return "FileInfo.cleanPath(FileInfo.joinPaths(path, FileInfo.relativePath(" + JSON.stringify(deployedModuleInstallDir) + ", " + JSON.stringify(value.slice(valuePrefixToStrip.length) || "/") + ")))"; } return JSON.stringify(value); } function writeProperty(project, product, moduleInstallDir, prop, indentation, considerValue, moduleFile) { var line = indentation; var separatorIndex = prop.name.lastIndexOf("."); var isModuleProperty = separatorIndex !== -1; var needsDeclaration = !prop.isBuiltin && !isModuleProperty; if (needsDeclaration) line += "property " + prop.type + " "; var moduleName; if (isModuleProperty) { moduleName = prop.name.slice(0, separatorIndex); if ((product.Exporter.qbs.excludedDependencies || []).includes(moduleName)) return; } line += prop.name + ": "; // We emit the literal value, unless the source code clearly refers to values from inside the // original project, in which case the evaluated value is used. if (considerValue && /(project|product|exportingProduct)\./.test(prop.sourceCode)) { var value; if (isModuleProperty) { var propertyName = prop.name.slice(separatorIndex + 1); value = product.exports[moduleName][propertyName]; } else { value = product.exports[prop.name]; } line += stringifyValue(project, product, moduleInstallDir, prop, value); } else { line += prop.sourceCode.replace(/importingProduct\./g, "product."); } moduleFile.writeLine(line); } function writeProperties(project, product, moduleInstallDir, list, indentation, considerValue, moduleFile) { for (var i = 0; i < list.length; ++i) { writeProperty(project, product, moduleInstallDir, list[i], indentation, considerValue, moduleFile); } } // This writes properties set on other modules in the Export item, i.e. property assignments // like "cpp.includePaths: '...'". function writeModuleProperties(project, product, output, moduleFile) { var moduleInstallDir = FileInfo.path(ModUtils.artifactInstalledFilePath(output)); var filteredProps = product.exports.properties.filter(function(p) { return p.name !== "name"; }); // The right-hand side can refer to values from the exporting product, in which case // the evaluated value, rather than the source code, needs to go into the module file. var considerValues = true; writeProperties(project, product, moduleInstallDir, filteredProps, " ", considerValues, moduleFile); } function writeItem(product, item, indentation, moduleFile) { moduleFile.writeLine(indentation + item.name + " {"); var newIndentation = indentation + " "; // These are sub-items of the Export item, whose properties entirely live in the context // of the importing product. Therefore, they must never use pre-evaluated values. var considerValues = false; writeProperties(undefined, product, undefined, item.properties, newIndentation, considerValues, moduleFile) for (var i = 0; i < item.childItems.length; ++i) writeItem(product, item.childItems[i], newIndentation, moduleFile); moduleFile.writeLine(indentation + "}"); } function isExcludedDependency(product, childItem) { if ((product.Exporter.qbs.excludedDependencies || []).length === 0) return false; if (childItem.name !== "Depends") return false; for (var i = 0; i < childItem.properties.length; ++i) { var prop = childItem.properties[i]; var unquotedRhs = prop.sourceCode.slice(1, -1); if (prop.name === "name" && product.Exporter.qbs.excludedDependencies.includes(unquotedRhs)) return true; } return false; } function writeChildItems(product, moduleFile) { for (var i = 0; i < product.exports.childItems.length; ++i) { var item = product.exports.childItems[i]; if (!isExcludedDependency(product, item)) writeItem(product, item, " ", moduleFile); } } function writeImportStatements(product, moduleFile) { var imports = product.exports.imports; // We potentially use FileInfo ourselves when transforming paths in stringifyValue(). if (!imports.includes("import qbs.FileInfo")) imports.push("import qbs.FileInfo"); for (var i = 0; i < imports.length; ++i) moduleFile.writeLine(imports[i]); } qbs-src-2.6.1/share/qbs/modules/Exporter/qbs/qbsexporter.qbs0000644000175100001660000000612714776170045023477 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.TextFile import "qbsexporter.js" as HelperFunctions Module { property stringList artifactTypes property string fileName: product.targetName + ".qbs" property stringList excludedDependencies property string additionalContent property stringList _artifactTypes: artifactTypes ? artifactTypes : ["installable"] additionalProductTypes: ["Exporter.qbs.module"] Rule { multiplex: true requiresInputs: false // Make sure we only run when all other artifacts are already present. auxiliaryInputs: product.type.filter(function(t) { return t !== "Exporter.qbs.module"; }) Artifact { filePath: product.Exporter.qbs.fileName fileTags: ["Exporter.qbs.module"] qbs.install: true } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); HelperFunctions.writeImportStatements(product, f); f.writeLine("\nModule {"); HelperFunctions.writeModuleProperties(project, product, output, f); HelperFunctions.writeTargetArtifactGroups(product, output, f); HelperFunctions.writeChildItems(product, f); if (product.Exporter.qbs.additionalContent) f.writeLine(product.Exporter.qbs.additionalContent); f.writeLine("}"); f.close(); }; return [cmd]; } } } qbs-src-2.6.1/share/qbs/modules/Exporter/cmake/0000755000175100001660000000000014776170045020677 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Exporter/cmake/cmakeexporter.js0000644000175100001660000002417614776170045024120 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Raphaël Cotty ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of the Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var ExporterHelpers = require("../exporter.js"); function tagListToString(tagList) { return JSON.stringify(tagList); } function collectAutodetectedData(project, topLevelProduct, outputs) { var packageName = topLevelProduct.Exporter.cmake.packageName; var data = {}; data.packageName = packageName; data.installPrefixDir = "_" + packageName.toUpperCase() + "_INSTALL_PREFIX"; data.packages = []; function quote(value) { return "\"" + value + "\""; } function quoteAndPrefixify(propName) { function quoteAndPrefixifyHelper(value) { var prefixToStrip = ExporterHelpers.getPrefixToStrip(project, topLevelProduct, propName, value); if (typeof value !== "string" || !prefixToStrip || (value.length > prefixToStrip.length && value[prefixToStrip.length] !== '/')) { return quote(value); } return quote("${" + data.installPrefixDir + "}" + value.slice(prefixToStrip.length)); } return quoteAndPrefixifyHelper; } var installedOutputFilePath = ModUtils.artifactInstalledFilePath( outputs["Exporter.cmake.configFile"][0]); var installedOutputPathName = FileInfo.path(installedOutputFilePath); var installRootPath = FileInfo.joinPaths(topLevelProduct.qbs.installRoot, topLevelProduct.qbs.installPrefix); data.installPrefix = FileInfo.relativePath(installedOutputPathName, installRootPath); var libArtifacts; var libImportArtifacts; var isProduct = !topLevelProduct.present; var considerFramework = !isProduct || (topLevelProduct.type && topLevelProduct.type.includes("bundle.content")) && topLevelProduct.bundle && topLevelProduct.bundle.isBundle && topLevelProduct.qbs.targetOS.includes("darwin"); var considerDynamicLibs = !isProduct || (topLevelProduct.type && topLevelProduct.type.includes("dynamiclibrary")); var considerStaticLibs = !isProduct || (topLevelProduct.type && topLevelProduct.type.includes("staticlibrary")); if (considerFramework) { libArtifacts = topLevelProduct.artifacts["bundle.symlink.executable"]; if (considerDynamicLibs) data.type = "SHARED"; else if (considerStaticLibs) data.type = "STATIC"; else data.type = "INTERFACE"; } else if (considerDynamicLibs) { libArtifacts = topLevelProduct.artifacts.dynamiclibrary; libImportArtifacts = topLevelProduct.artifacts.dynamiclibrary_import; data.type = "SHARED"; } else if (considerStaticLibs) { libArtifacts = topLevelProduct.artifacts.staticlibrary; data.type = "STATIC"; } else { data.type = "INTERFACE"; } for (var i = 0; i < (libArtifacts || []).length; ++i) { var libArtifact = libArtifacts[i]; var libImportArtifact = (libImportArtifacts || [])[i]; if (libArtifact.qbs.install) { var installPath = ModUtils.artifactInstalledFilePath(libArtifact); data.importedLocation = quoteAndPrefixify("installRoot")(installPath); data.soName = topLevelProduct.targetName; if (libImportArtifact && libImportArtifact.qbs.install) { installPath = ModUtils.artifactInstalledFilePath(libImportArtifact); data.importedImplibLocation = quoteAndPrefixify("installRoot")(installPath); } break; } } var cpp = topLevelProduct.exports.cpp; if (cpp) { data.libraryPaths = (cpp.libraryPaths || []).map(quoteAndPrefixify("cpp.libraryPaths")); data.linkLibraries = []; data.linkLibraries = data.linkLibraries.concat(cpp.dynamicLibraries || []); data.linkLibraries = data.linkLibraries.concat(cpp.staticLibraries || []); data.linkLibraries = data.linkLibraries.map(quoteAndPrefixify("cpp.dynamicLibraries")); data.linkOptions = []; data.linkOptions = data.linkOptions.concat(cpp.driverLinkerFlags || []); if ((cpp.linkerFlags || []).length > 0) { data.linkOptions = data.linkOptions.concat("LINKER:" + (cpp.linkerFlags || []).join(",")); } data.linkOptions = data.linkOptions.map(quote); data.includeDirectories = (cpp.includePaths || []).map(quoteAndPrefixify("cpp.includePaths")); data.compileDefinitions = (cpp.defines || []).map(quote); data.compileOptions = []; data.compileOptions = data.compileOptions.concat(cpp.commonCompilerFlags || []); data.compileOptions = data.compileOptions.concat(cpp.driverFlags || []); data.compileOptions = data.compileOptions.concat(cpp.cxxFlags || []); data.compileOptions = data.compileOptions.concat(cpp.cFlags || []); data.compileOptions = data.compileOptions.map(quote); } function gatherDeps(dep) { if (dep.name === "Exporter.cmake") return; var depHasExporter = dep.Exporter && dep.Exporter.cmake; if (!depHasExporter) return; data.packages.push(dep.Exporter.cmake.packageName); } var exportedDeps = topLevelProduct.exports ? topLevelProduct.exports.dependencies : []; exportedDeps.forEach(gatherDeps); return data; } function writeConfigFile(project, product, outputs) { var autoDetectedData = collectAutodetectedData(project, product, outputs); var packageName = autoDetectedData.packageName; function writeCommand(command, lines) { if ((lines || []).length === 0) return; cmakeConfigFile.writeLine(command + "(" + packageName + " INTERFACE"); for (i = 0; i < lines.length; i++) { cmakeConfigFile.writeLine(" " + lines[i]); } cmakeConfigFile.writeLine(")"); } var cmakeConfigFile = new TextFile(outputs["Exporter.cmake.configFile"][0].filePath, TextFile.WriteOnly); cmakeConfigFile.writeLine("# Generated by Qbs"); cmakeConfigFile.writeLine("cmake_minimum_required(VERSION 3.5)"); cmakeConfigFile.writeLine("if(TARGET " + packageName + ")"); cmakeConfigFile.writeLine(" return()"); cmakeConfigFile.writeLine("endif()"); cmakeConfigFile.writeLine("set(" + autoDetectedData.installPrefixDir + " \"${CMAKE_CURRENT_LIST_DIR}/" + autoDetectedData.installPrefix + "\")"); autoDetectedData.packages.forEach(function(packageName) { cmakeConfigFile.writeLine("find_package(" + packageName + " REQUIRED SILENT)"); }); cmakeConfigFile.writeLine( "add_library(" + packageName + " " + autoDetectedData.type + " IMPORTED)"); var configuration = (product.qbs.buildVariant) ? product.qbs.buildVariant.toUpperCase() : "NONE"; cmakeConfigFile.writeLine("set_property(TARGET " + packageName + " APPEND PROPERTY IMPORTED_CONFIGURATIONS " + configuration + ")"); cmakeConfigFile.writeLine("set_target_properties(" + packageName + " PROPERTIES"); cmakeConfigFile.writeLine(" IMPORTED_LINK_INTERFACE_LANGUAGES_" + configuration + " CXX"); if (autoDetectedData.type !== "INTERFACE") { cmakeConfigFile.writeLine(" IMPORTED_LOCATION_" + configuration + " " + autoDetectedData.importedLocation); } if (autoDetectedData.importedImplibLocation) { cmakeConfigFile.writeLine(" IMPORTED_IMPLIB_" + configuration + " " + autoDetectedData.importedImplibLocation); } cmakeConfigFile.writeLine(")"); writeCommand("target_link_directories", autoDetectedData.libraryPaths); writeCommand("target_link_libraries", autoDetectedData.linkLibraries.concat(autoDetectedData.packages)); writeCommand("target_link_options", autoDetectedData.linkOptions); writeCommand("target_include_directories", autoDetectedData.includeDirectories); writeCommand("target_compile_definitions", autoDetectedData.compileDefinitions); writeCommand("target_compile_options", autoDetectedData.compileOptions); cmakeConfigFile.close(); } function writeVersionFile(product, outputs) { var cmakeVersionFile = new TextFile( outputs["Exporter.cmake.versionFile"][0].filePath, TextFile.WriteOnly); cmakeVersionFile.writeLine("# Generated by Qbs"); cmakeVersionFile.writeLine("set(PACKAGE_VERSION \"" + product.version + "\")"); cmakeVersionFile.close(); } qbs-src-2.6.1/share/qbs/modules/Exporter/cmake/cmakeexporter.qbs0000644000175100001660000000643514776170045024267 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Raphaël Cotty ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.TextFile import "cmakeexporter.js" as HelperFunctions Module { property string configFileName: packageName + "Config.cmake" property string versionFileName: packageName + "ConfigVersion.cmake" property string packageName: product.targetName additionalProductTypes: ["Exporter.cmake.package"] Rule { multiplex: true requiresInputs: false auxiliaryInputs: { if (product.type.includes("staticlibrary")) return ["staticlibrary"]; if (product.type.includes("dynamiclibrary")) return ["dynamiclibrary"]; } Artifact { filePath: product.Exporter.cmake.configFileName fileTags: ["Exporter.cmake.package", "Exporter.cmake.configFile"] } Artifact { filePath: product.Exporter.cmake.versionFileName fileTags: ["Exporter.cmake.package", "Exporter.cmake.versionFile"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generate cmake package files"; cmd.sourceCode = function() { HelperFunctions.writeConfigFile(project, product, outputs); HelperFunctions.writeVersionFile(product, outputs); } return [cmd]; } } } qbs-src-2.6.1/share/qbs/modules/Exporter/pkgconfig/0000755000175100001660000000000014776170045021566 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Exporter/pkgconfig/pkgconfig.js0000644000175100001660000002320614776170045024076 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); function quote(value) { if (value.includes(" ") || value.includes("'") || value.includes('"')) { return '"' + value.replace(/(["'\\])/g, "\\$1") + '"'; } return value; } function writeEntry(product, file, key, propertyName, required, additionalValues) { var value = product.Exporter.pkgconfig[propertyName]; if (additionalValues && additionalValues.length > 0) value = (value || []).concat(additionalValues); var valueIsNotEmpty = value && (!(value instanceof Array) || value.length > 0); if (valueIsNotEmpty) { if (value instanceof Array) value = value.join(' '); file.writeLine(key + ": " + value); } else if (required) { throw "Failure creating " + FileInfo.fileName(file.filePath()) + ": The entry '" + key + "' is required, but property Exporter.pkgconfig." + propertyName + " is not set."; } } function collectAutodetectedData(topLevelProduct) { var data = { libs: [], cflags: [], requires: [], requiresPrivate: [] }; if (!topLevelProduct.Exporter.pkgconfig.autoDetect) return data; var excludedDeps = topLevelProduct.Exporter.pkgconfig.excludedDependencies || []; var explicitRequires = topLevelProduct.Exporter.pkgconfig.requiresEntry || []; var explicitRequiresPrivate = topLevelProduct.Exporter.pkgconfig.requiresPrivateEntry || []; var transformFunc = topLevelProduct.Exporter.pkgconfig.transformFunction; // Make use of the "prefix" convenience variable if applicable. function quoteAndPrefixify(value) { var quotedValue = quote(value); var installPrefix = topLevelProduct.qbs.installPrefix || ""; if (!topLevelProduct.Exporter.pkgconfig._usePrefix || typeof value !== "string" || !value.startsWith(installPrefix) || (value.length > installPrefix.length && value[installPrefix.length] !== '/')) { return quotedValue; } return quotedValue.replace(topLevelProduct.qbs.installPrefix, "${prefix}"); } function transformedValue(product, moduleName, propertyName) { var originalValue = product.exports[moduleName][propertyName]; var value = transformFunc ? eval("(" + transformFunc + ")(product, moduleName, propertyName, originalValue)") : originalValue; if (value instanceof Array) value.forEach(function(v, i, a) { a[i] = quoteAndPrefixify(v); }); else if (value) value = quoteAndPrefixify(value); return value; } function collectLibs(productOrModule) { var libs = []; var libArtifacts; var isProduct = !productOrModule.present; var considerDynamicLibs = !isProduct || (productOrModule.type && productOrModule.type.includes("dynamiclibrary")); if (considerDynamicLibs) { libArtifacts = productOrModule.artifacts.dynamiclibrary; } else { var considerStaticLibs = !isProduct || (productOrModule.type && productOrModule.type.includes("staticlibrary")); if (considerStaticLibs) libArtifacts = productOrModule.artifacts.staticlibrary; } for (var i = 0; i < (libArtifacts || []).length; ++i) { var libArtifact = libArtifacts[i]; if (libArtifact.qbs.install) { var installDir = FileInfo.path(ModUtils.artifactInstalledFilePath(libArtifact)); installDir = installDir.slice(libArtifact.qbs.installRoot.length); libs.push("-L" + quoteAndPrefixify(FileInfo.cleanPath(installDir)), "-l" + quote(productOrModule.targetName)); } } if (!productOrModule.exports.cpp) return libs; var libPaths = transformedValue(productOrModule, "cpp", "libraryPaths"); if (libPaths) libs.push.apply(libs, libPaths.map(function(p) { return "-L" + p; })); function libNamesToLibEntries(libNames) { return libNames.map(function(libName) { return "-l" + libName; }); }; var dlls = transformedValue(productOrModule, "cpp", "dynamicLibraries"); if (dlls) libs.push.apply(libs, libNamesToLibEntries(dlls)); var staticLibs = transformedValue(productOrModule, "cpp", "staticLibraries"); if (staticLibs) libs.push.apply(libs, libNamesToLibEntries(staticLibs)); var lFlags = transformedValue(productOrModule, "cpp", "linkerFlags"); if (lFlags) libs.push.apply(libs, lFlags); lFlags = transformedValue(productOrModule, "cpp", "driverFlags"); if (lFlags) libs.push.apply(libs, lFlags); lFlags = transformedValue(productOrModule, "cpp", "driverLinkerFlags"); if (lFlags) libs.push.apply(libs, lFlags); return libs; } function collectCFlags(productOrModule) { if (!productOrModule.exports.cpp) return []; var flags = []; var defs = transformedValue(productOrModule, "cpp", "defines"); if (defs) flags.push.apply(flags, defs.map(function(d) { return "-D" + d; })); var incPaths = transformedValue(productOrModule, "cpp", "includePaths"); if (incPaths) flags.push.apply(flags, incPaths.map(function(p) { return "-I" + p; })); var cflags = transformedValue(productOrModule, "cpp", "commonCompilerFlags"); if (cflags) flags.push.apply(flags, cflags); cflags = transformedValue(productOrModule, "cpp", "driverFlags"); if (cflags) flags.push.apply(flags, cflags); cflags = transformedValue(productOrModule, "cpp", "cxxFlags") || transformedValue(productOrModule, "cpp", "cFlags"); if (cflags) flags.push.apply(flags, cflags); return flags; } function collectAutodetectedDataRecursive(productOrModule, privateContext) { if (!privateContext) { data.libs.push.apply(data.libs, collectLibs(productOrModule)); data.cflags.push.apply(data.cflags, collectCFlags(productOrModule)); } var exportedDeps = productOrModule.exports ? productOrModule.exports.dependencies : []; var exportedDepNames = []; var privateDeps = []; for (var i = 0; i < exportedDeps.length; ++i) exportedDepNames.push(exportedDeps[i].name); for (i = 0; i < (productOrModule.dependencies || []).length; ++i) { var dep = productOrModule.dependencies[i]; if (exportedDepNames.includes(dep.name)) continue; privateDeps.push(dep); } function gatherData(dep) { if (dep.name === "Exporter.pkgconfig") return; var depHasPkgConfig = dep.Exporter && dep.Exporter.pkgconfig; if (depHasPkgConfig) { var entry = FileInfo.completeBaseName(dep.Exporter.pkgconfig.fileName); if (excludedDeps.includes(entry)) return; if (isPrivateDep && !data.requiresPrivate.includes(entry) && !explicitRequiresPrivate.includes(entry)) { data.requiresPrivate.push(entry); } if (!isPrivateDep && !data.requires.includes(entry) && !explicitRequires.includes(entry)) { data.requires.push(entry); } } else { if (excludedDeps.includes(dep.name)) return; if (isPrivateDep && explicitRequiresPrivate.includes(dep.name)) return; if (!isPrivateDep && explicitRequires.includes(dep.name)) return; collectAutodetectedDataRecursive(dep, isPrivateDep); } } var isPrivateDep = privateContext; exportedDeps.forEach(gatherData); isPrivateDep = true; privateDeps.forEach(gatherData); } collectAutodetectedDataRecursive(topLevelProduct, false); return data; } qbs-src-2.6.1/share/qbs/modules/Exporter/pkgconfig/pkgconfig.qbs0000644000175100001660000000736514776170045024257 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile import "pkgconfig.js" as HelperFunctions Module { property string fileName: product.targetName + ".pc" property bool autoDetect: true property var transformFunction // function(product, moduleName, propertyName, valueElement) property stringList excludedDependencies property string nameEntry: product.name property string descriptionEntry: product.name property string versionEntry: product.version property string urlEntry property stringList cflagsEntry: [] property stringList libsEntry: [] property stringList libsPrivateEntry: [] property stringList requiresEntry: [] property stringList requiresPrivateEntry: [] property stringList conflictsEntry: [] property var customVariables property bool _usePrefix: autoDetect && qbs.installPrefix additionalProductTypes: ["Exporter.pkgconfig.pc"] Rule { multiplex: true requiresInputs: false // Make sure all relevant library artifacts have been created by the time we run. auxiliaryInputs: { if (!autoDetect) return undefined; if (product.type.includes("staticlibrary")) return ["staticlibrary"]; if (product.type.includes("dynamiclibrary")) return ["dynamiclibrary"]; } Artifact { filePath: product.Exporter.pkgconfig.fileName fileTags: ["Exporter.pkgconfig.pc"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); if (product.Exporter.pkgconfig._usePrefix) f.writeLine("prefix=" + product.qbs.installPrefix + "\n"); var customVariables = product.Exporter.pkgconfig.customVariables; if (customVariables) { for (var customVar in customVariables) f.writeLine(customVar + "=" + customVariables[customVar]); f.writeLine(""); } var autoDetectedData = HelperFunctions.collectAutodetectedData(product); HelperFunctions.writeEntry(product, f, "Name", "nameEntry", true); HelperFunctions.writeEntry(product, f, "Description", "descriptionEntry", true); HelperFunctions.writeEntry(product, f, "Version", "versionEntry", true); HelperFunctions.writeEntry(product, f, "URL", "urlEntry"); HelperFunctions.writeEntry(product, f, "Cflags", "cflagsEntry", false, autoDetectedData.cflags); HelperFunctions.writeEntry(product, f, "Libs", "libsEntry", false, autoDetectedData.libs); HelperFunctions.writeEntry(product, f, "Libs.private", "libsPrivateEntry"); HelperFunctions.writeEntry(product, f, "Requires", "requiresEntry", false, autoDetectedData.requires); HelperFunctions.writeEntry(product, f, "Requires.private", "requiresPrivateEntry", false, autoDetectedData.requiresPrivate); HelperFunctions.writeEntry(product, f, "Conflicts", "conflictsEntry"); }; return [cmd]; } } validate: { if (requiresEntry && excludedDependencies && requiresEntry.containsAny(excludedDependencies)) { throw "The contents of Export.pkgconfig.requiresEntry and " + "Export.pkgconfig.excludedDependencies must not overlap."; } } } qbs-src-2.6.1/share/qbs/modules/qbs/0000755000175100001660000000000014776170045016574 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/qbs/common.qbs0000644000175100001660000002435314776170045020602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.FileInfo import qbs.ModUtils import qbs.PathTools import qbs.Utilities Module { readonly property string configurationName: "default" property string defaultBuildVariant: { switch (configurationName.toLowerCase()) { case "release": return "release"; default: return "debug"; } } property string buildVariant: defaultBuildVariant property bool enableDebugCode: buildVariant == "debug" property bool debugInformation: (buildVariant !== "release") property string optimization: (buildVariant === "debug" ? "none" : "fast") readonly property string hostPlatform: undefined // set internally readonly property stringList hostOS: Utilities.canonicalPlatform(hostPlatform) property string hostOSVersion: { if (hostOS && hostOS.includes("macos")) { return Utilities.getNativeSetting("/System/Library/CoreServices/ServerVersion.plist", "ProductVersion") || Utilities.getNativeSetting("/System/Library/CoreServices/SystemVersion.plist", "ProductVersion"); } else if (hostOS && hostOS.includes("windows")) { var version = Utilities.getNativeSetting(windowsRegistryKey, "CurrentVersion"); return version + "." + hostOSBuildVersion; } } readonly property string hostArchitecture: undefined // set internally property string hostOSBuildVersion: { if (hostOS.includes("macos")) { return Utilities.getNativeSetting("/System/Library/CoreServices/ServerVersion.plist", "ProductBuildVersion") || Utilities.getNativeSetting("/System/Library/CoreServices/SystemVersion.plist", "ProductBuildVersion"); } else if (hostOS.includes("windows")) { return Utilities.getNativeSetting(windowsRegistryKey, "CurrentBuildNumber"); } } readonly property var hostOSVersionParts: hostOSVersion ? hostOSVersion.split('.').map(function(item) { return parseInt(item, 10); }) : [] readonly property int hostOSVersionMajor: hostOSVersionParts[0] || 0 readonly property int hostOSVersionMinor: hostOSVersionParts[1] || 0 readonly property int hostOSVersionPatch: hostOSVersionParts[2] || 0 property string targetPlatform: hostPlatform readonly property stringList targetOS: Utilities.canonicalPlatform(targetPlatform) property string pathListSeparator: hostOS.includes("windows") ? ";" : ":" property string pathSeparator: hostOS.includes("windows") ? "\\" : "/" property string nullDevice: hostOS.includes("windows") ? "NUL" : "/dev/null" property path shellPath: hostOS.includes("windows") ? windowsShellPath : "/bin/sh" property string profile: project.profile property string toolchainType: { if (targetOS.includes("windows")) return hostOS.includes("windows") ? "msvc" : "mingw"; if (targetOS.includes("darwin")) return hostOS.includes("macos") ? "xcode" : "clang"; if (targetOS.includes("freebsd")) return "clang"; if (targetOS.includes("qnx")) return "qcc"; if (targetOS.containsAny(["haiku", "vxworks", "unix"])) return "gcc"; } readonly property stringList toolchain: Utilities.canonicalToolchain(toolchainType) property string architecture property bool install: false property path installSourceBase property string installRoot: project.buildDirectory + "/install-root" property string installDir property string installPrefix: targetOS.includes("unix") ? "/usr/local" : "" property path sysroot PropertyOptions { name: "buildVariant" allowedValues: ['debug', 'release', 'profiling'] description: "name of the build variant" } PropertyOptions { name: "optimization" allowedValues: ['none', 'fast', 'small'] description: "optimization level" } validate: { var validator = new ModUtils.PropertyValidator("qbs"); validator.setRequiredProperty("hostOS", hostOS); validator.setRequiredProperty("targetOS", targetOS); validator.addCustomValidator("targetOS", targetOS, function (value) { if (!value || (value.includes("osx") && !value.includes("macos"))) return false; return true; }, "the value 'osx' has been replaced by 'macos'; use that instead and update " + "hostOS and targetOS condition checks in your project accordingly"); if (hostOS && (hostOS.includes("windows") || hostOS.includes("macos"))) { validator.setRequiredProperty("hostOSVersion", hostOSVersion, "could not detect host operating system version; " + "verify that system files and registry keys have not " + "been modified."); if (hostOSVersion) validator.addVersionValidator("hostOSVersion", hostOSVersion, 2, 4); validator.setRequiredProperty("hostOSBuildVersion", hostOSBuildVersion, "could not detect host operating system build version; " + "verify that system files or registry have not been " + "tampered with."); } validator.addCustomValidator("architecture", architecture, function (value) { return !architecture || architecture === Utilities.canonicalArchitecture(architecture); }, "'" + architecture + "' is invalid." + (architecture ? " You must use the canonical name '" + Utilities.canonicalArchitecture(architecture) : "") + "'"); validator.addCustomValidator("toolchain", toolchain, function (value) { if (toolchain === undefined) return false; // cannot have null toolchain, empty is valid... for now var canonical = Utilities.canonicalToolchain.apply(Utilities, toolchain); for (var i = 0; i < Math.max(canonical.length, toolchain.length); ++i) { if (canonical[i] !== toolchain[i]) return false; } return true; }, "'" + toolchain + "' is invalid. You must use the canonical list '" + Utilities.canonicalToolchain.apply(Utilities, toolchain) + "'"); validator.addCustomValidator("toolchain", toolchain, function (value) { // None of the pairs listed here may appear in the same toolchain list. // Note that this check is applied AFTER canonicalization, so for example // {"clang", "msvc"} need not be checked, since a toolchain containing clang is // guaranteed to also contain gcc. var pairs = [ ["gcc", "msvc"], ["llvm", "mingw"] ]; var canonical = Utilities.canonicalToolchain.apply(Utilities, value); for (var i = 0; i < pairs.length; ++i) { if (canonical.includes(pairs[i][0]) && canonical.includes(pairs[i][1])) return false; } return true; }, "'" + toolchain + "' contains one or more mutually exclusive toolchain types."); validator.validate(); } // private properties property string windowsRegistryKey: "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion" property path windowsSystemRoot: FileInfo.fromWindowsSeparators(Utilities.getNativeSetting(windowsRegistryKey, "SystemRoot")) property path windowsShellPath: FileInfo.fromWindowsSeparators(Environment.getEnv("COMSPEC")) || FileInfo.joinPaths(windowsSystemRoot, "System32", "cmd.exe") property string windowsPathVariable: hostOS.includes("windows") ? "PATH" : "WINEPATH" property var commonRunEnvironment: ({}) setupRunEnvironment: { var env = product.qbs.commonRunEnvironment; for (var i in env) { var v = new ModUtils.EnvironmentVariable(i, product.qbs.pathListSeparator, product.qbs.hostOS.includes("windows")); v.value = env[i]; v.set(); } } // Properties that can be set for multiplexing products. property stringList profiles: [] property stringList architectures: [] property stringList buildVariants: [] // internal properties readonly property string version: [versionMajor, versionMinor, versionPatch].join(".") readonly property int versionMajor: undefined // set internally readonly property int versionMinor: undefined // set internally readonly property int versionPatch: undefined // set internally readonly property var multiplexMap: ({ profiles: "profile", architectures: "architecture", buildVariants: "buildVariant" }) } qbs-src-2.6.1/share/qbs/modules/autotest/0000755000175100001660000000000014776170045017657 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/autotest/autotest.qbs0000644000175100001660000000021314776170045022232 0ustar runnerdockerModule { property stringList arguments property bool allowFailure: false property string workingDir property int timeout } qbs-src-2.6.1/share/qbs/modules/archiver/0000755000175100001660000000000014776170045017612 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/archiver/archiver.qbs0000644000175100001660000002307114776170045022127 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.Host import qbs.FileInfo import qbs.Probes Module { // jar is a suitable fallback for creating zip files as they are the same format // This will most likely end up being used on Windows Depends { name: "java"; required: false } Probes.BinaryProbe { id: tarProbe names: ["tar"] } Probes.BinaryProbe { id: zipProbe names: ["zip"] } Probes.BinaryProbe { id: sevenZipProbe names: ["7z"] platformSearchPaths: { var paths = base; if (Host.os().includes("windows")) { var env32 = Environment.getEnv("PROGRAMFILES(X86)"); var env64 = Environment.getEnv("PROGRAMFILES"); if (env64 === env32 && env64.endsWith(" (x86)")) env64 = env64.slice(0, -(" (x86)".length)); // QTBUG-3845 paths.push(FileInfo.joinPaths(env64, "7-Zip")); paths.push(FileInfo.joinPaths(env32, "7-Zip")); } return paths; } } property string type property string archiveBaseName: product.targetName property string workingDirectory property stringList flags: [] property path outputDirectory: product.destinationDirectory property string archiveExtension: { if (type === "7zip") return "7z"; if (type == "tar") { var extension = "tar"; if (compressionType !== "none") extension += "." + compressionType; return extension; } if (type === "zip") return "zip"; return undefined; } property string command: { if (type === "7zip") return sevenZipProbe.filePath; if (type === "tar") { if (tarProbe.found) return tarProbe.filePath; if (sevenZipProbe.found) return sevenZipProbe.filePath; } if (type === "zip") { // Prefer zip (probably Info-Zip) and fall back to 7z or jar when it's not available // (as is the likely case on Windows) if (zipProbe.found) return zipProbe.filePath; if (sevenZipProbe.found) return sevenZipProbe.filePath; if (java.present) return java.jarFilePath; } return undefined; } property string compressionLevel property string compressionType: { if (type === "tar") return "gz"; return undefined; } PropertyOptions { name: "type" description: "The type of archive to create." allowedValues: ["7zip", "tar", "zip"] } PropertyOptions { name: "compressionLevel" description: "How much effort to put into compression.\n" + "Higher numbers mean smaller archive files at the cost of taking more time.\n" + "This property is only used for the '7zip' and 'zip' types.\n" + "'7zip' only supports 0 and odd numbers." allowedValues: [undefined, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] } PropertyOptions { name: "compressionType" description: "The compression format to use.\n" + "For tar archives, the respective tool needs to be present.\n" + "This property is only used for the 'tar' and 'zip' types." allowedValues: ["none", "gz", "bz2", "Z", "xz", "deflate", "store"] } Rule { inputs: ["archiver.input-list"] Artifact { filePath: FileInfo.joinPaths(product.moduleProperty("archiver", "outputDirectory"), product.moduleProperty("archiver", "archiveBaseName") + '.' + product.moduleProperty("archiver", "archiveExtension")); fileTags: ["archiver.archive"] } prepare: { var binary = product.moduleProperty("archiver", "command"); var binaryName = FileInfo.baseName(binary); var args = []; var commands = []; var type = product.moduleProperty("archiver", "type"); var compression = product.moduleProperty("archiver", "compressionType"); var compressionLevel = product.moduleProperty("archiver", "compressionLevel"); if (binaryName === "7z") { var rmCommand = new JavaScriptCommand(); rmCommand.silent = true; rmCommand.sourceCode = function() { if (File.exists(output.filePath)) File.remove(output.filePath); }; commands.push(rmCommand); args.push("a", "-y", "-mmt=on"); switch (type) { case "7zip": args.push("-t7z"); break; case "zip": args.push("-tzip"); break; case "tar": if (compression === "gz") args.push("-tgzip"); else if (compression === "bz2") args.push("-tbzip2"); else args.push("-ttar"); break; default: throw "7zip: unrecognized archive type: '" + type + "'"; } if (compressionLevel) args.push("-mx" + compressionLevel); args = args.concat(product.moduleProperty("archiver", "flags")); args.push(output.filePath); args.push("@" + input.filePath); } else if (binaryName === "tar" && type === "tar") { args.push("-c"); if (compression === "gz") args.push("-z"); else if (compression === "bz2") args.push("-j"); else if (compression === "Z") args.push("-Z"); else if (compression === "xz") args.push("-J"); args.push("-f", output.filePath, "-T", input.filePath); args = args.concat(product.moduleProperty("archiver", "flags")); } else if (binaryName === "jar" && type === "zip") { if (compression === "none" || compressionLevel === "0") args.push("-0"); args.push("-cfM", output.filePath, "@" + input.filePath); args = args.concat(product.moduleProperty("archiver", "flags")); } else if (binaryName === "zip" && type === "zip") { // The "zip" program included with most Linux and Unix distributions // (including macOS) is Info-ZIP's Zip, so this should be fairly portable. if (compression === "none") { args.push("-0"); } else { compression = compression === "bz2" ? "bzip2" : compression; if (["store", "deflate", "bzip2"].includes(compression)) args.push("-Z", compression); if (compressionLevel) args.push("-" + compressionLevel); } args.push("-r", output.filePath, ".", "-i@" + input.filePath); args = args.concat(product.moduleProperty("archiver", "flags")); } else if (["tar", "zip", "jar"].includes(binaryName)) { throw binaryName + ": unrecognized archive type: '" + type + "'"; } else if (binaryName) { throw "unrecognized archive tool: '" + binaryName + "'"; } else { throw "no archive tool available to produce archive type: '" + type + "'"; } var archiverCommand = new Command(binary, args); archiverCommand.description = "creating archive file " + output.fileName; archiverCommand.highlight = "linker"; archiverCommand.workingDirectory = product.moduleProperty("archiver", "workingDirectory"); commands.push(archiverCommand); return commands; } } } qbs-src-2.6.1/share/qbs/modules/emsdk/0000755000175100001660000000000014776170045017112 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/emsdk/emsdk.js0000644000175100001660000001015314776170045020553 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Danya Patrushev ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ var Process = require("qbs.Process"); var Host = require("qbs.Host"); var FileInfo = require("qbs.FileInfo"); var File = require("qbs.File"); var Environment = require("qbs.Environment"); function getEnvironment(shellPath, emccDir) { var winOs = Host.os().includes("windows") var emsdkEnvFileName = "emsdk_env." + (winOs ? "bat" : "sh") var sep = FileInfo.pathSeparator() //if the compiler comes from emsdk its directory should be */emsdk/upstream/emscripten/ var emsdkEnvFilePath = FileInfo.cleanPath(emccDir + sep + ".." + sep + ".." + sep + emsdkEnvFileName) if (!File.exists(emsdkEnvFilePath)) { if (!winOs) { console.info("Emcc compiler found but " + emsdkEnvFilePath + " doesn't exist - assuming compiler is provided by system package") return {} } else throw emsdkEnvFilePath + " not found"; } else { var env = {} // If the environment already contains emsdk specific variables, running the script // will return a concise message about "Setting up EMSDK environment" without all // the data that we need, so we check the environment first. var dir = Environment.getEnv("EMSDK") //use it as an indication that the environment is already set if (dir) { env["EMSDK"] = dir; var python = Environment.getEnv("EMSDK_PYTHON") if (python) env["EMSDK_PYTHON"] = python; var node = Environment.getEnv("EMSDK_NODE"); if (node) env["EMSDK_NODE"] = node; } else { var process = new Process(); process.exec(shellPath, [emsdkEnvFilePath]); var equalStr = " = "; var lines = process.readStdErr().split("\n"); for (var i in lines) { var line = lines[i]; var index = line.indexOf(equalStr); if (index === -1) continue; var key = line.slice(0, index); if (key === "PATH") continue; env[key] = line.slice(index + equalStr.length); } } return env; } } qbs-src-2.6.1/share/qbs/modules/emsdk/emsdk.qbs0000644000175100001660000000135414776170045020727 0ustar runnerdockerimport qbs.Probes import "emsdk.js" as Emsdk Module { property string configuredInstallPath property string detectedInstallPath: emccPathProbe.found ? emccPathProbe.path : undefined Probes.BinaryProbe { id: emccPathProbe condition: !configuredInstallPath names: ["emcc"] } property var environment: emsdkEnvProbe.environment Probe { id: emsdkEnvProbe property string emccDir: configuredInstallPath || detectedInstallPath property string shellPath: product.qbs.shellPath property var environment condition: emccDir configure: { environment = Emsdk.getEnvironment(shellPath, emccDir); found = true; } } } qbs-src-2.6.1/share/qbs/modules/flatbuf/0000755000175100001660000000000014776170045017432 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/flatbuf/flatbuffers.js0000644000175100001660000001040114776170045022267 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); function validateCompiler(compilerName, compilerPath) { if (!File.exists(compilerPath)) { throw "Can't find '" + compilerName + "' binary. Please set the compilerPath property or " + "make sure the compiler is found in PATH"; } } function getOutputDir(module, input) { var outputDir = module._outputDir; if (!module.keepPrefix) return outputDir; var importPaths = module.importPaths; if (importPaths !== undefined && importPaths.length !== 0) { var canonicalInput = File.canonicalFilePath(FileInfo.path(input.filePath)); for (var i = 0; i < importPaths.length; ++i) { var path = File.canonicalFilePath(importPaths[i]); if (canonicalInput.startsWith(path)) { return outputDir + "/" + FileInfo.relativePath(path, canonicalInput); } } } return outputDir; } function artifactC(module, input, tag, suffix) { var outputDir = module._outputDir; return { fileTags: [tag], filePath: outputDir + "/" + FileInfo.baseName(input.fileName) + suffix, cpp: { warningLevel: "none"} }; } function doPrepareC(module, input) { var args = []; args.push("-a") // write all args.push("-o", input.flatbuf.c._outputDir) // output dir var importPaths = module.importPaths; importPaths.forEach(function(path) { args.push("-I", path); }); args.push(input.filePath); var cmd = new Command(module.compilerPath, args); cmd.workingDirectory = FileInfo.path(module._outputDir) cmd.highlight = "codegen"; cmd.description = "generating C files for " + input.fileName; return [cmd]; } function artifact(module, input, tag, suffix) { var outputDir = getOutputDir(module, input); return { fileTags: [tag], filePath: outputDir + "/" + FileInfo.baseName(input.fileName) + suffix, cpp: { warningLevel: "none" } }; } function doPrepareCpp(module, input, output) { var outputDir = FileInfo.path(output.filePath); var result = []; var args = []; args.push("--cpp") var importPaths = module.importPaths; importPaths.forEach(function(path) { args.push("-I", path); }); args.push("--filename-ext", module.filenameExtension); args.push("--filename-suffix", module.filenameSuffix); if (module.includePrefix) args.push("--include-prefix", module.includePrefix); if (module.keepPrefix) args.push("--keep-prefix"); args.push(input.filePath); var cmd = new Command(input.flatbuf.cpp.compilerPath, args); cmd.workingDirectory = outputDir; cmd.highlight = "codegen"; cmd.description = "generating C++ files for " + input.fileName; result.push(cmd); return result; } qbs-src-2.6.1/share/qbs/modules/flatbuf/flatbuffersbase.qbs0000644000175100001660000000411214776170045023275 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs import qbs.File import qbs.FileInfo import qbs.Probes import "flatbuffers.js" as HelperFunctions Module { property string compilerName: "flatc" property string compilerPath: compilerProbe.filePath property pathList importPaths: [] property string _outputDir: FileInfo.joinPaths(product.buildDirectory, "flatbuf") property stringList _searchPaths FileTagger { patterns: ["*.fbs"] fileTags: ["flatbuf.input"]; } Probes.BinaryProbe { id: compilerProbe names: [compilerName] searchPaths: _searchPaths } } qbs-src-2.6.1/share/qbs/modules/flatbuf/cpp/0000755000175100001660000000000014776170045020214 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/flatbuf/cpp/flatbuffers-cpp.qbs0000644000175100001660000000510414776170045024006 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs import qbs.FileInfo import "../flatbuffers.js" as Flatbuf import "../flatbuffersbase.qbs" as FlatbufBase FlatbufBase { Depends { name: "cpp" } Depends { name: "flatbuffers" } property string filenameExtension: "h" property string filenameSuffix: "_generated" property string includePrefix // TODO: test property bool keepPrefix: false _outputDir: FileInfo.joinPaths(product.buildDirectory, "flatbuf", "cpp") _searchPaths: flatbuffers.hostBinDirs cpp.cxxLanguageVersion: "c++11" cpp.systemIncludePaths: base.concat([_outputDir]) Rule { inputs: ["flatbuf.input"] outputFileTags: ["hpp"] outputArtifacts: { var module = input.flatbuf.cpp; var fullSuffix = module.filenameSuffix + "." + module.filenameExtension; return [ Flatbuf.artifact(module, input, "hpp", fullSuffix) ]; } prepare: { return Flatbuf.doPrepareCpp(input.flatbuf.cpp, input, output); } } validate: { Flatbuf.validateCompiler(compilerName, compilerPath); } } qbs-src-2.6.1/share/qbs/modules/flatbuf/c/0000755000175100001660000000000014776170045017654 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/flatbuf/c/flatbuffers-c.qbs0000644000175100001660000000434314776170045023112 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs import qbs.FileInfo import "../flatbuffers.js" as Flatbuf import "../flatbuffersbase.qbs" as FlatbufBase FlatbufBase { Depends { name: "cpp" } Depends { name: "flatcc" } compilerName: "flatcc" _outputDir: FileInfo.joinPaths(product.buildDirectory, "flatbuf", "c") _searchPaths: flatbuffers.hostBinDirs cpp.systemIncludePaths: base.concat([_outputDir]) Rule { inputs: ["flatbuf.input"] outputFileTags: ["hpp"] outputArtifacts: [Flatbuf.artifactC(input.flatbuf.c, input, "hpp", "_generated.h")] prepare: { return Flatbuf.doPrepareC(input.flatbuf.c, input); } } validate: { Flatbuf.validateCompiler(compilerName, compilerPath); } } qbs-src-2.6.1/share/qbs/modules/cpp/0000755000175100001660000000000014776170045016571 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/cpp/cosmic.js0000644000175100001660000003720214776170045020410 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Cpp = require("cpp.js"); var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); function toolchainDetails(qbs) { var architecture = qbs.architecture; if (architecture.startsWith("arm")) { return { "executableSuffix": ".cxm", "staticLibrarySuffix": ".cxm", "assemblerName": "cacorm", "compilerName": "cxcorm" }; } else if (architecture === "stm8") { return { "executableSuffix": ".sm8", "staticLibrarySuffix": ".sm8", "assemblerName": "castm8", "compilerName": "cxstm8" }; } else if (architecture === "hcs8") { return { "executableSuffix": ".h08", "staticLibrarySuffix": ".h08", "assemblerName": "ca6808", "compilerName": "cx6808" }; } else if (architecture === "hcs12") { return { "executableSuffix": ".h12", "staticLibrarySuffix": ".h12", "assemblerName": "ca6812", "compilerName": "cx6812" }; } else if (architecture === "m68k") { return { "executableSuffix": ".332", "staticLibrarySuffix": ".332", "assemblerName": "ca332", "compilerName": "cx332" }; } } function guessArchitecture(compilerFilePath) { var baseName = FileInfo.baseName(compilerFilePath); if (baseName === "cxcorm") return "arm"; else if (baseName === "cxstm8") return "stm8"; else if (baseName === "cx6808") return "hcs8"; else if (baseName === "cx6812") return "hcs12"; else if (baseName === "cx332") return "m68k"; } function dumpMacros(compilerFilePath) { // Note: The COSMIC compiler does not support the predefined // macros dumping. So, we do it with the following trick, where we try // to create and compile a special temporary file and to parse the console // output with the own magic pattern: (""|"key"|"value"|""). var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.fromNativeSeparators(FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c")); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); outputFile.writeLine("#define VALUE_TO_STRING(x) #x"); outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)"); outputFile.writeLine("#define VAR_NAME_VALUE(var) #var VALUE(var)"); // The COSMIC compiler defines only one pre-defined macro // (at least nothing is said about other macros in the documentation). var keys = ["__CSMC__"]; for (var i in keys) { var key = keys[i]; outputFile.writeLine("#if defined (" + key + ")"); outputFile.writeLine("#pragma message (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("#endif"); } outputFile.close(); var process = new Process(); process.exec(compilerFilePath, [outputFilePath], false); File.remove(outputFilePath); var map = {}; // COSMIC compiler use the errors output! process.readStdErr().trim().split(/\r?\n/g).map(function(line) { var match = line.match(/^#message \("(.+)" "(.+)"\)$/); if (match) map[match[1]] = match[2]; }); return map; } function dumpVersion(compilerFilePath) { var p = new Process(); p.exec(compilerFilePath, ["-vers"]); // COSMIC compiler use the errors output! var output = p.readStdErr(); var match = output.match(/^COSMIC.+V(\d+)\.?(\d+)\.?(\*|\d+)?/); if (match) { var major = match[1] ? parseInt(match[1], 10) : 0; var minor = match[2] ? parseInt(match[2], 10) : 0; var patch = match[3] ? parseInt(match[3], 10) : 0; return { major: major, minor: minor, patch: patch }; } } function guessEndianness(architecture) { // There is no mention of supported endianness in the cosmic compiler. return "big"; } function dumpDefaultPaths(compilerFilePath, architecture) { var rootPath = FileInfo.path(compilerFilePath); var includePath; var includePaths = []; if (architecture.startsWith("arm")) { includePath = FileInfo.joinPaths(rootPath, "hcorm"); if (File.exists(includePath)) includePaths.push(includePath); } else if (architecture === "stm8") { includePath = FileInfo.joinPaths(rootPath, "hstm8"); if (File.exists(includePath)) includePaths.push(includePath); } else if (architecture === "hcs8") { includePath = FileInfo.joinPaths(rootPath, "h6808"); if (File.exists(includePath)) includePaths.push(includePath); } else if (architecture === "hcs12") { includePath = FileInfo.joinPaths(rootPath, "h6812"); if (File.exists(includePath)) includePaths.push(includePath); } else if (architecture === "m68k") { includePath = FileInfo.joinPaths(rootPath, "h332"); if (File.exists(includePath)) includePaths.push(includePath); } var libraryPaths = []; var libraryPath = FileInfo.joinPaths(rootPath, "lib"); if (File.exists(libraryPath)) libraryPaths.push(libraryPath); return { "includePaths": includePaths, "libraryPaths": libraryPaths, } } function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; // Up to 128 include files. args = args.concat(Cpp.collectPreincludePathsArguments(input)); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); // Up to 128 include paths. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); // Debug information flags. if (input.cpp.debugInformation) args.push("+debug"); var architecture = input.qbs.architecture; var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); // Warning level flags. switch (input.cpp.warningLevel) { case "none": // Disabled by default. break; case "all": // Highest warning level. args.push("-pw7"); break; } // C language version flags. if (tag === "c") { var knownValues = ["c99"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownValues, "C"); switch (cLanguageVersion) { case "c99": args.push("-p", "c99"); break; default: break; } } // Objects output directory. args.push("-co", FileInfo.path(outputs.obj[0].filePath)); // Listing files generation flag. if (input.cpp.generateCompilerListingFiles) { // Enable listings. args.push("-l"); // Listings output directory. args.push("-cl", FileInfo.path(outputs.lst[0].filePath)); } // Misc flags. args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(product)); // Input. args.push(input.filePath); return args; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; // Up to 128 include paths. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); // Debug information flags. if (input.cpp.debugInformation) args.push("-xx"); // Misc flags. args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); // Listing files generation flag. if (input.cpp.generateAssemblerListingFiles) { args.push("-l"); args.push("+l", outputs.lst[0].filePath); } // Objects output file path. args.push("-o", outputs.obj[0].filePath); // Input. args.push(input.filePath); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; // Library paths. args = args.concat(Cpp.collectLibraryPaths(product).map(function(path) { // It is workaround to use the relative paths avoids a strange linking // errors. Maybe it is related to the limitations on the length of the // command arguments, or on the length of the paths. return product.cpp.libraryPathFlag + Cpp.relativePath(product.buildDirectory, path); })); // Output. args.push("-o", outputs.application[0].filePath); // Map file generation flag. if (product.cpp.generateLinkerMapFile) args.push("-m", outputs.mem_map[0].filePath); // Misc flags. args = args.concat(Cpp.collectMiscEscapableLinkerArguments(product), Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); // Linker scripts. args = args.concat(Cpp.collectLinkerScriptPathsArguments(product, inputs)); // Input objects. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); // Library dependencies (order has matters). args = args.concat(Cpp.collectLibraryDependencies(product).map(function(dep) { // It is workaround to use the relative paths avoids a strange linking // errors. Maybe it is related to the limitations on the length of the // command arguments, or on the length of the paths. return Cpp.relativePath(product.buildDirectory, dep.filePath); })); return args; } function archiverFlags(project, product, inputs, outputs) { var args = ["-cl"]; // Output. args.push(outputs.staticlibrary[0].filePath); // Input objects. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); return args; } function createPath(fullPath) { var cmd = new JavaScriptCommand(); cmd.fullPath = fullPath; cmd.silent = true; cmd.sourceCode = function() { File.makePath(fullPath); }; return cmd; } // It is a workaround to rename the generated object file to the desired name. // Reason is that the Cosmic compiler always generates the object files in the // format of 'module.o', but we expect it in flexible format, e.g. 'module.c.obj' // or 'module.c.o' depending on the cpp.objectSuffix property. function renameObjectFile(project, product, inputs, outputs, input, output) { var object = outputs.obj[0]; var cmd = new JavaScriptCommand(); cmd.newObject = object.filePath; cmd.oldObject = FileInfo.joinPaths(FileInfo.path(object.filePath), object.baseName + ".o"); cmd.silent = true; cmd.sourceCode = function() { File.move(oldObject, newObject); }; return cmd; } // It is a workaround to rename the generated listing file to the desired name. // Reason is that the Cosmic compiler always generates the listing files in the // format of 'module.ls', but we expect it in flexible format, e.g. 'module.c.lst' // or 'module.c.ls' depending on the cpp.compilerListingSuffix property. function renameListingFile(project, product, inputs, outputs, input, output) { var listing = outputs.lst[0]; var cmd = new JavaScriptCommand(); cmd.newListing = listing.filePath; cmd.oldListing = FileInfo.joinPaths(FileInfo.path(listing.filePath), listing.baseName + ".ls"); cmd.silent = true; cmd.sourceCode = function() { File.move(oldListing, newListing); }; return cmd; } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; // Create output objects path, because the Cosmic doesn't do it. var cmd = createPath(FileInfo.path(outputs.obj[0].filePath)); cmds.push(cmd); // Create output listing path, because the Cosmic doesn't do it. if (input.cpp.generateCompilerListingFiles) { cmd = createPath(FileInfo.path(outputs.lst[0].filePath)); cmds.push(cmd); } var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); cmd = new Command(input.cpp.compilerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; cmds.push(cmd); cmds.push(renameObjectFile(project, product, inputs, outputs, input, output)); if (input.cpp.generateCompilerListingFiles) cmds.push(renameListingFile(project, product, inputs, outputs, input, output)); return cmds; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; // Create output objects path, because the Cosmic doesn't do it. var cmd = createPath(FileInfo.path(outputs.obj[0].filePath)); cmds.push(cmd); // Create output listing path, because the Cosmic doesn't do it. if (input.cpp.generateCompilerListingFiles) { cmd = createPath(FileInfo.path(outputs.lst[0].filePath)); cmds.push(cmd); } var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn); cmd = new Command(input.cpp.assemblerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "assembler"; cmds.push(cmd); return cmds; } function prepareLinker(project, product, inputs, outputs, input, output) { var primaryOutput = outputs.application[0]; var args = linkerFlags(project, product, inputs, outputs); var cmd = new Command(product.cpp.linkerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; return [cmd]; } function prepareArchiver(project, product, inputs, outputs, input, output) { var args = archiverFlags(project, product, inputs, outputs); var cmd = new Command(product.cpp.archiverPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "creating " + output.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/cpp/iar.js0000644000175100001660000006277414776170045017722 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Cpp = require("cpp.js"); var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); function supportXLinker(architecture) { return architecture === "78k" || architecture === "avr" || architecture === "avr32" || architecture === "cr16" || architecture === "hcs12" || architecture === "hcs8" || architecture === "m16c" || architecture === "m32c" || architecture === "m68k" || architecture === "mcs51" || architecture === "msp430" || architecture === "r32c" || architecture === "v850"; } function supportILinker(architecture) { return architecture.startsWith("arm") || architecture === "rh850" || architecture === "riscv" || architecture === "rl78" || architecture === "rx" || architecture === "sh" || architecture === "stm8"; } function supportXArchiver(architecture) { return architecture === "78k" || architecture === "avr" || architecture === "avr32" || architecture === "cr16" || architecture === "hcs12" || architecture === "hcs8" || architecture === "m16c" || architecture === "m32c" || architecture === "m68k" || architecture === "mcs51" || architecture === "msp430" || architecture === "r32c" || architecture === "v850"; } function supportIArchiver(architecture) { return architecture.startsWith("arm") || architecture === "rh850" || architecture === "riscv" || architecture === "rl78" || architecture === "rx" || architecture === "sh" || architecture === "stm8"; } function supportXAssembler(architecture) { return architecture.startsWith("arm") || architecture === "78k" || architecture === "avr" || architecture === "hcs12" || architecture === "m16c" || architecture === "mcs51" || architecture === "msp430" || architecture === "m32c" || architecture === "v850"; } function supportIAssembler(architecture) { return architecture === "avr32" || architecture === "cr16" || architecture === "hcs8" || architecture === "r32c" || architecture === "rh850" || architecture === "riscv" || architecture === "rl78" || architecture === "rx" || architecture === "sh" || architecture === "stm8" || architecture === "m68k"; } function supportEndianness(architecture) { return architecture.startsWith("arm") || architecture === "rx"; } function supportCppExceptions(architecture) { return architecture.startsWith("arm") || architecture === "rh850" || architecture === "riscv" || architecture === "rl78" || architecture === "rx"; } function supportCppRtti(architecture) { return architecture.startsWith("arm") || architecture === "rh850" || architecture === "riscv" || architecture === "rl78" || architecture === "rx"; } function supportCppWarningAboutCStyleCast(architecture) { return architecture.startsWith("arm") || architecture === "avr" || architecture === "avr32" || architecture === "cr16" || architecture === "mcs51" || architecture === "msp430" || architecture === "rh850" || architecture === "rl78" || architecture === "rx" || architecture === "stm8" || architecture === "v850"; } function supportDeprecatedFeatureWarnings(architecture) { return architecture.startsWith("arm") || architecture === "avr" || architecture === "cr16" || architecture === "mcs51" || architecture === "msp430" || architecture === "rh850" || architecture === "rl78" || architecture === "rx" || architecture === "stm8" || architecture === "v850"; } function supportCLanguageVersion(architecture) { return architecture !== "78k"; } function supportCppLanguage(compilerFilePath) { var baseName = FileInfo.baseName(compilerFilePath); return baseName !== "iccs08"; } // It is a 'magic' IAR-specific target architecture code. function architectureCode(architecture) { switch (architecture) { case "78k": return "26"; case "avr": return "90"; case "avr32": return "82"; case "mcs51": return "51"; case "msp430": return "43"; case "v850": return "85"; case "m68k": return "68"; case "m32c": return "48"; case "r32c": return "53"; case "m16c": return "34"; case "cr16": return "45"; case "hcs12": return "12"; case "hcs8": return "78"; case "rh850": case "riscv": case "rl78": case "rx": case "sh": case "stm8": return ""; default: if (architecture.startsWith("arm")) return ""; break; } } function toolchainDetails(qbs) { var architecture = qbs.architecture; var code = architectureCode(architecture); var details = {}; if (supportXLinker(architecture)) { details.libraryPathFlag = "-I"; details.linkerScriptFlag = "-f"; details.linkerName = "xlink"; details.linkerSilentFlag = "-S"; details.linkerMapFileFlag = "-l"; details.linkerEntryPointFlag = "-s"; } else if (supportILinker(architecture)) { details.libraryPathFlag = "-L"; details.linkerScriptFlag = "--config"; details.linkerSilentFlag = "--silent"; details.linkerMapFileFlag = "--map"; details.linkerEntryPointFlag = "--entry"; details.linkerName = architecture.startsWith("arm") ? "ilinkarm" : ("ilink" + architecture); } if (supportXArchiver(architecture)) details.archiverName = "xar"; else if (supportIArchiver(architecture)) details.archiverName = "iarchive"; var hasCode = (code !== ""); details.staticLibrarySuffix = hasCode ? (".r" + code) : ".a"; details.executableSuffix = hasCode ? ((qbs.debugInformation) ? (".d" + code) : (".a" + code)) : ".out"; details.objectSuffix = hasCode ? (".r" + code) : ".o"; details.imageFormat = hasCode ? "ubrof" : "elf"; if (architecture.startsWith("arm")) { details.compilerName = "iccarm"; details.assemblerName = "iasmarm"; } else if (architecture === "78k") { details.compilerName = "icc78k"; details.assemblerName = "a78k"; } else if (architecture === "avr") { details.compilerName = "iccavr"; details.assemblerName = "aavr"; } else if (architecture === "avr32") { details.compilerName = "iccavr32"; details.assemblerName = "aavr32"; } else if (architecture === "cr16") { details.compilerName = "icccr16c"; details.assemblerName = "acr16c"; } else if (architecture === "hcs12") { details.compilerName = "icchcs12"; details.assemblerName = "ahcs12"; } else if (architecture === "hcs8") { details.compilerName = "iccs08"; details.assemblerName = "as08"; } else if (architecture === "m16c") { details.compilerName = "iccm16c"; details.assemblerName = "am16c"; } else if (architecture === "m32c") { details.compilerName = "iccm32c"; details.assemblerName = "am32c"; } else if (architecture === "m68k") { details.compilerName = "icccf"; details.assemblerName = "acf"; } else if (architecture === "mcs51") { details.compilerName = "icc8051"; details.assemblerName = "a8051"; } else if (architecture === "msp430") { details.compilerName = "icc430"; details.assemblerName = "a430"; } else if (architecture === "r32c") { details.compilerName = "iccr32c"; details.assemblerName = "ar32c"; } else if (architecture === "rh850") { details.compilerName = "iccrh850"; details.assemblerName = "iasmrh850"; } else if (architecture === "riscv") { details.compilerName = "iccriscv"; details.assemblerName = "iasmriscv"; } else if (architecture === "rl78") { details.compilerName = "iccrl78"; details.assemblerName = "iasmrl78"; } else if (architecture === "rx") { details.compilerName = "iccrx"; details.assemblerName = "iasmrx"; } else if (architecture === "sh") { details.compilerName = "iccsh"; details.assemblerName = "iasmsh"; } else if (architecture === "stm8") { details.compilerName = "iccstm8"; details.assemblerName = "iasmstm8"; } else if (architecture === "v850") { details.compilerName = "iccv850"; details.assemblerName = "av850"; } return details; } function guessArmArchitecture(core) { var arch = "arm"; if (core === "__ARM4M__") arch += "v4m"; else if (core === "__ARM4TM__") arch += "v4tm"; else if (core === "__ARM5E__") arch += "v5e"; else if (core === "__ARM5__") arch += "v5"; else if (core === "__ARM6M__") arch += "v6m"; else if (core === "__ARM6SM__") arch += "v6sm"; else if (core === "__ARM6__") arch += "v6"; else if (core === "__ARM7M__") arch += "v7m"; else if (core === "__ARM7R__") arch += "v7r"; return arch; } function guessArchitecture(macros) { if (macros["__ICC430__"] === "1") return "msp430"; else if (macros["__ICC78K__"] === "1") return "78k"; else if (macros["__ICC8051__"] === "1") return "mcs51"; else if (macros["__ICCARM__"] === "1") return guessArmArchitecture(macros["__CORE__"]); else if (macros["__ICCAVR32__"] === "1") return "avr32"; else if (macros["__ICCAVR__"] === "1") return "avr"; else if (macros["__ICCCF__"] === "1") return "m68k"; else if (macros["__ICCCR16C__"] === "1") return "cr16"; else if (macros["__ICCHCS12__"] === "1") return "hcs12"; else if (macros["__ICCM16C__"] === "1") return "m16c"; else if (macros["__ICCM32C__"] === "1") return "m32c"; else if (macros["__ICCR32C__"] === "1") return "r32c"; else if (macros["__ICCRH850__"] === "1") return "rh850"; else if (macros["__ICCRISCV__"] === "1") return "riscv"; else if (macros["__ICCRL78__"] === "1") return "rl78"; else if (macros["__ICCRX__"] === "1") return "rx"; else if (macros["__ICCS08__"] === "1") return "hcs8"; else if (macros["__ICCSH__"] === "1") return "sh"; else if (macros["__ICCSTM8__"] === "1") return "stm8"; else if (macros["__ICCV850__"] === "1") return "v850"; } function guessEndianness(macros) { if (macros["__LITTLE_ENDIAN__"] === "1") return "little"; return "big" } function guessVersion(macros, architecture) { var version = parseInt(macros["__VER__"], 10); if (architecture.startsWith("arm")) { return { major: parseInt(version / 1000000), minor: parseInt(version / 1000) % 1000, patch: parseInt(version) % 1000 } } else if (architecture === "78k" || architecture === "avr" || architecture === "avr32" || architecture === "cr16" || architecture === "hcs12" || architecture === "hcs8" || architecture === "m16c" || architecture === "m32c" || architecture === "m68k" || architecture === "mcs51" || architecture === "msp430" || architecture === "r32c" || architecture === "rh850" || architecture === "riscv" || architecture === "rl78" || architecture === "rx" || architecture === "sh" || architecture === "stm8" || architecture === "v850") { return { major: parseInt(version / 100), minor: parseInt(version % 100), patch: 0 } } } function cppLanguageOption(compilerFilePath) { var baseName = FileInfo.baseName(compilerFilePath); switch (baseName) { case "iccarm": case "iccrh850": case "iccriscv": case "iccrl78": case "iccrx": return "--c++"; case "icc430": case "icc78k": case "icc8051": case "iccavr": case "iccavr32": case "icccf": case "icccr16c": case "icchcs12": case "iccm16c": case "iccm32c": case "iccr32c": case "iccsh": case "iccstm8": case "iccv850": return "--ec++"; } } function dumpMacros(compilerFilePath, tag) { var tempDir = new TemporaryDir(); var inFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/empty-source.c"); var inFile = new TextFile(inFilePath, TextFile.WriteOnly); var outFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/iar-macros.predef"); var args = [ inFilePath, "--predef_macros", outFilePath ]; if (tag === "cpp" && supportCppLanguage(compilerFilePath)) args.push(cppLanguageOption(compilerFilePath)); var p = new Process(); p.setWorkingDirectory(tempDir.path()); p.exec(compilerFilePath, args, true); var outFile = new TextFile(outFilePath, TextFile.ReadOnly); return Cpp.extractMacros(outFile.readAll()); } function dumpCompilerIncludePaths(compilerFilePath, tag) { // We can dump the compiler include paths using the undocumented `--IDE3` flag, // e.g. which also is used in the IAR extension for the VSCode. In this case the // compiler procuces the console output in the following format: // `$$TOOL_BEGIN $$VERSION "3" $$INC_BEGIN $$FILEPATH "" $$TOOL_END` var tempDir = new TemporaryDir(); var inFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/empty-source.c"); var inFile = new TextFile(inFilePath, TextFile.WriteOnly); var args = ["--IDE3", inFilePath]; if (tag === "cpp" && supportCppLanguage(compilerFilePath)) args.push(cppLanguageOption(compilerFilePath)); var includePaths = []; var p = new Process(); p.setWorkingDirectory(tempDir.path()); // It is possible that the process can return an error code in case the // compiler does not support the `--IDE3` flag. So, don't throw an error in this case. p.exec(compilerFilePath, args, false); p.readStdOut().trim().split(/\r?\n/g).map(function(line) { var m = line.match(/\$\$INC_BEGIN\s\$\$FILEPATH\s\"([^"]*)/); if (m) { var includePath = m[1].replace(/\\\\/g, '/'); if (includePath && File.exists(includePath)) includePaths.push(includePath); } }); if (includePaths.length === 0) { // This can happen if the compiler does not support the `--IDE3` flag, // e.g. IAR for S08 architecture. In this case we use fallback to the // detection of the `inc` directory. var includePath = FileInfo.joinPaths(FileInfo.path(compilerFilePath), "../inc/"); if (File.exists(includePath)) includePaths.push(includePath); } return includePaths; } function dumpDefaultPaths(compilerFilePath, tag) { var includePaths = dumpCompilerIncludePaths(compilerFilePath, tag); return { "includePaths": includePaths }; } function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; // Input. args.push(input.filePath); // Output. args.push("-o", outputs.obj[0].filePath); // Preinclude headers. args = args.concat(Cpp.collectPreincludePathsArguments(input, true)); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); // Silent output generation flag. args.push("--silent"); // Debug information flags. if (input.cpp.debugInformation) args.push("--debug"); // Optimization flags. switch (input.cpp.optimization) { case "small": args.push("-Ohz"); break; case "fast": args.push("-Ohs"); break; case "none": args.push("-On"); break; } var architecture = input.qbs.architecture; var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); // Warning level flags. switch (input.cpp.warningLevel) { case "none": args.push("--no_warnings"); break; case "all": if (supportDeprecatedFeatureWarnings(architecture)) { args.push("--deprecated_feature_warnings=" +"+attribute_syntax," +"+preprocessor_extensions," +"+segment_pragmas"); } if (tag === "cpp" && supportCppWarningAboutCStyleCast(architecture)) args.push("--warn_about_c_style_casts"); break; } if (input.cpp.treatWarningsAsErrors) args.push("--warnings_are_errors"); // C language version flags. if (tag === "c" && supportCLanguageVersion(architecture)) { var knownValues = ["c89"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownValues, "C"); switch (cLanguageVersion) { case "c89": args.push("--c89"); break; default: // Default C language version is C18/C11/C99 that // depends on the IAR version. break; } } // C++ language version flags. var compilerFilePath = input.cpp.compilerPath; if (tag === "cpp" && supportCppLanguage(compilerFilePath)) { // C++ language flag. var cppOption = cppLanguageOption(compilerFilePath); args.push(cppOption); // Exceptions flag. var enableExceptions = input.cpp.enableExceptions; if (!enableExceptions && supportCppExceptions(architecture)) args.push("--no_exceptions"); // RTTI flag. var enableRtti = input.cpp.enableRtti; if (!enableRtti && supportCppRtti(architecture)) args.push("--no_rtti"); } // Byte order flags. var endianness = input.cpp.endianness; if (endianness && supportEndianness(architecture)) args.push("--endian=" + endianness); // Listing files generation flag. if (input.cpp.generateCompilerListingFiles) args.push("-l", outputs.lst[0].filePath); // Misc flags. args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(product)); return args; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; // Input. args.push(input.filePath); // Output. args.push("-o", outputs.obj[0].filePath); var architecture = input.qbs.architecture; // The `--preinclude` flag is only supported for a certain // set of assemblers, not for all. if (supportIAssembler(architecture)) args = args.concat(Cpp.collectPreincludePathsArguments(input)); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); // Debug information flags. if (input.cpp.debugInformation) args.push("-r"); // Architecture specific flags. if (supportIAssembler(architecture)) { // Silent output generation flag. args.push("--silent"); // Warning level flags. if (input.cpp.warningLevel === "none") args.push("--no_warnings"); if (input.cpp.treatWarningsAsErrors) args.push("--warnings_are_errors"); } else if (supportXAssembler(architecture)){ // Silent output generation flag. args.push("-S"); // Warning level flags. args.push("-w" + (input.cpp.warningLevel === "none" ? "-" : "+")); } // Byte order flags. var endianness = input.cpp.endianness; if (endianness && supportEndianness(architecture)) args.push("--endian", endianness); // Listing files generation flag. if (input.cpp.generateAssemblerListingFiles) args.push("-l", outputs.lst[0].filePath); // Misc flags. args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; // Inputs. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); // Output. args.push("-o", outputs.application[0].filePath); // Library paths. args = args.concat(Cpp.collectLibraryPathsArguments(product)); // Library dependencies. args = args.concat(Cpp.collectLibraryDependenciesArguments(product)); // Linker scripts. args = args.concat(Cpp.collectLinkerScriptPathsArguments(product, inputs, true)); // Silent output generation flag. args.push(product.cpp.linkerSilentFlag); // Map file generation flag. if (product.cpp.generateLinkerMapFile) args.push(product.cpp.linkerMapFileFlag, outputs.mem_map[0].filePath); // Entry point flag. if (product.cpp.entryPoint) args.push(product.cpp.linkerEntryPointFlag, product.cpp.entryPoint); // Debug information flag. if (supportXLinker(product.qbs.architecture)) { if (product.cpp.debugInformation) args.push("-rt"); } // Misc flags. args = args.concat(Cpp.collectMiscEscapableLinkerArguments(product), Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); return args; } function archiverFlags(project, product, inputs, outputs) { var args = []; // Inputs. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); // Output. var architecture = product.qbs.architecture; if (supportIArchiver(architecture)) args.push("--create"); args.push("-o", outputs.staticlibrary[0].filePath); return args; } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); var compilerPath = input.cpp.compilerPath; var cmd = new Command(compilerPath, args); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; return [cmd]; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn); var assemblerPath = input.cpp.assemblerPath; var cmd = new Command(assemblerPath, args); cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "assembler"; return [cmd]; } function prepareLinker(project, product, inputs, outputs, input, output) { var primaryOutput = outputs.application[0]; var args = linkerFlags(project, product, inputs, outputs); var linkerPath = product.cpp.linkerPath; var cmd = new Command(linkerPath, args); cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; return [cmd]; } function prepareArchiver(project, product, inputs, outputs, input, output) { var args = archiverFlags(project, product, inputs, outputs); var archiverPath = product.cpp.archiverPath; var cmd = new Command(archiverPath, args); cmd.description = "creating " + output.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; cmd.stdoutFilterFunction = function(output) { return ""; }; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/cpp/freebsd.js0000644000175100001660000000040714776170045020542 0ustar runnerdockervar Utilities = require("qbs.Utilities"); function stripKernelReleaseSuffix(r) { var idx = r.indexOf("-RELEASE"); return idx >= 0 ? r.substr(0, idx) : r; } function hostKernelRelease() { return stripKernelReleaseSuffix(Utilities.kernelVersion()); } qbs-src-2.6.1/share/qbs/modules/cpp/sdcc.js0000644000175100001660000005016114776170045020046 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var BinaryFile = require("qbs.BinaryFile"); var Cpp = require("cpp.js"); var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Host = require("qbs.Host"); var ModUtils = require("qbs.ModUtils"); var PathTools = require("qbs.PathTools"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); var WindowsUtils = require("qbs.WindowsUtils"); function toolchainDetails(qbs) { var architecture = qbs.architecture; if (architecture === "mcs51") { return { "assemblerName": "sdas8051", "linkerName": "sdld" } } else if (architecture === "stm8") { return { "assemblerName": "sdasstm8", "linkerName": "sdldstm8" } } else if (architecture === "hcs8") { return { "assemblerName": "sdas6808", "linkerName": "sdld6808" } } } function targetArchitectureFlag(architecture) { if (architecture === "mcs51") return "-mmcs51"; if (architecture === "stm8") return "-mstm8"; if (architecture === "hcs8") return "-mhc08"; } function guessArchitecture(macros) { if (macros["__SDCC_mcs51"] === "1") return "mcs51"; if (macros["__SDCC_stm8"] === "1") return "stm8"; if (macros["__SDCC_hc08"] === "1") return "hcs8"; } function guessEndianness(macros) { // SDCC stores numbers in little-endian format. return "little"; } function guessVersion(macros) { if ("__SDCC_VERSION_MAJOR" in macros && "__SDCC_VERSION_MINOR" in macros && "__SDCC_VERSION_PATCH" in macros) { return { major: parseInt(macros["__SDCC_VERSION_MAJOR"], 10), minor: parseInt(macros["__SDCC_VERSION_MINOR"], 10), patch: parseInt(macros["__SDCC_VERSION_PATCH"], 10) } } else if ("__SDCC" in macros) { var versions = macros["__SDCC"].split("_"); if (versions.length === 3) { return { major: parseInt(versions[0], 10), minor: parseInt(versions[1], 10), patch: parseInt(versions[2], 10) }; } } } function dumpMacros(compilerFilePath, architecture) { var tempDir = new TemporaryDir(); var fakeIn = new TextFile(tempDir.path() + "/empty-source.c", TextFile.WriteOnly); var args = [ fakeIn.filePath(), "-dM", "-E" ]; var targetFlag = targetArchitectureFlag(architecture); if (targetFlag) args.push(targetFlag); var p = new Process(); p.exec(compilerFilePath, args, true); return Cpp.extractMacros(p.readStdOut()); } function dumpDefaultPaths(compilerFilePath, architecture) { var args = [ "--print-search-dirs" ]; var targetFlag = targetArchitectureFlag(architecture); if (targetFlag) args.push(targetFlag); var p = new Process(); p.exec(compilerFilePath, args, true); var includePaths = []; var addIncludePaths = false; var lines = p.readStdOut().trim().split(/\r?\n/g); for (var i in lines) { var line = lines[i]; if (line.startsWith("includedir:")) { addIncludePaths = true; } else if (line.startsWith("programs:") || line.startsWith("datadir:") || line.startsWith("libdir:") || line.startsWith("libpath:")) { addIncludePaths = false; } else if (addIncludePaths) { if (File.exists(line)) includePaths.push(line); } } return { "includePaths": includePaths } } function effectiveLinkerPath(product) { if (product.cpp.linkerMode === "automatic") return product.cpp.compilerPath; return product.cpp.linkerPath; } function useCompilerDriverLinker(product) { var linker = effectiveLinkerPath(product); return linker === product.cpp.compilerPath; } function escapeLinkerFlags(product, linkerFlags) { if (!linkerFlags || linkerFlags.length === 0 || !useCompilerDriverLinker(product)) return linkerFlags; return ["-Wl " + linkerFlags.join(",")]; } function escapePreprocessorFlags(preprocessorFlags) { if (!preprocessorFlags || preprocessorFlags.length === 0) return preprocessorFlags; return ["-Wp " + preprocessorFlags.join(",")]; } // We need to use the asm_adb, asm_src, asm_sym and rst_data // artifacts without of any conditions. Because SDCC always generates // it (and seems, this behavior can not be disabled for SDCC). function extraCompilerOutputTags() { return ["asm_adb", "asm_src", "asm_sym", "rst_data"]; } // We need to use the lk_cmd, and mem_summary artifacts without // of any conditions. Because SDCC always generates // it (and seems, this behavior can not be disabled for SDCC). function extraApplicationLinkerOutputTags() { return ["lk_cmd", "mem_summary"]; } // We need to use the asm_adb, asm_src, asm_sym and rst_data // artifacts without of any conditions. Because SDCC always generates // it (and seems, this behavior can not be disabled for SDCC). function extraCompilerOutputArtifacts(input) { return [{ fileTags: ["asm_adb"], filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".adb" }, { fileTags: ["asm_src"], filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".asm" }, { fileTags: ["asm_sym"], filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".sym" }, { fileTags: ["rst_data"], filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".rst" }]; } // We need to use the lk_cmd, and mem_summary artifacts without // of any conditions. Because SDCC always generates // it (and seems, this behavior can not be disabled for SDCC). function extraApplicationLinkerOutputArtifacts(product) { return [{ fileTags: ["lk_cmd"], filePath: FileInfo.joinPaths( product.destinationDirectory, product.targetName + ".lk") }, { fileTags: ["mem_summary"], filePath: FileInfo.joinPaths( product.destinationDirectory, product.targetName + ".mem") }]; } function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; var escapablePreprocessorFlags = []; // Input. args.push(input.filePath); // Output. args.push("-c"); args.push("-o", outputs.obj[0].filePath); // Prefix headers. escapablePreprocessorFlags = escapablePreprocessorFlags.concat( Cpp.collectPreincludePathsArguments(input)); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); escapablePreprocessorFlags = escapablePreprocessorFlags.concat( Cpp.collectSystemIncludePathsArguments(input)); // Target MCU flag. var targetFlag = targetArchitectureFlag(input.cpp.architecture); if (targetFlag) args.push(targetFlag); // Debug information flags. if (input.cpp.debugInformation) args.push("--debug"); // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("--opt-code-size"); break; case "fast": args.push("--opt-code-speed"); break; case "none": // SDCC has not option to disable the optimization. break; } // Warning level flags. var warnings = input.cpp.warningLevel if (warnings === "none") { args.push("--less-pedantic"); escapablePreprocessorFlags.push("-w"); } else if (warnings === "all") { escapablePreprocessorFlags.push("-Wall"); } if (input.cpp.treatWarningsAsErrors) args.push("--Werror"); // Determine which C-language we"re compiling. var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); // C language version flags. if (tag === "c") { var knownValues = ["c2x", "c17", "c11", "c99", "c89"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownValues, "C"); switch (cLanguageVersion) { case "c17": cLanguageVersion = "c11"; // fall through case "c89": case "c99": case "c11": case "c2x": args.push("--std-" + cLanguageVersion); break; } } var escapedPreprocessorFlags = escapePreprocessorFlags(escapablePreprocessorFlags); if (escapedPreprocessorFlags) Array.prototype.push.apply(args, escapedPreprocessorFlags); // Misc flags. args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(input)); return args; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input, input.cpp.includeFlag)); // Misc flags. args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); args.push("-ol"); args.push(outputs.obj[0].filePath); args.push(input.filePath); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; // Target MCU flag. var targetFlag = targetArchitectureFlag(product.cpp.architecture); if (targetFlag) args.push(targetFlag); var escapableLinkerFlags = []; // Map file generation flag. if (product.cpp.generateLinkerMapFile) escapableLinkerFlags.push("-m"); escapableLinkerFlags = escapableLinkerFlags.concat(Cpp.collectMiscEscapableLinkerArguments(product)); var useCompilerDriver = useCompilerDriverLinker(product); // Output. if (useCompilerDriver) args.push("-o"); args.push(outputs.application[0].filePath); // Inputs. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); // Library paths. var libraryPathFlag = useCompilerDriver ? "-L" : "-k"; args = args.concat(Cpp.collectLibraryPathsArguments(product, libraryPathFlag)); // Linker scripts. // Note: We need to split the '-f' flag and the file path to separate // lines when we don't use the compiler driver mode. escapableLinkerFlags = escapableLinkerFlags.concat( Cpp.collectLinkerScriptPathsArguments(product, inputs, !useCompilerDriver)); // Library dependencies. args = args.concat(Cpp.collectLibraryDependenciesArguments(product)); var escapedLinkerFlags = escapeLinkerFlags(product, escapableLinkerFlags); if (escapedLinkerFlags) Array.prototype.push.apply(args, escapedLinkerFlags); // Misc flags. if (useCompilerDriver) { args = args.concat(Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); } return args; } function archiverFlags(project, product, inputs, outputs) { var args = ["-rc"]; args.push(outputs.staticlibrary[0].filePath); args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); return args; } function buildLinkerMapFilePath(target, suffix) { return FileInfo.joinPaths(FileInfo.path(target.filePath), FileInfo.completeBaseName(target.fileName) + suffix); } // This is the workaround for the SDCC bug on a Windows host: // * https://sourceforge.net/p/sdcc/bugs/2970/ // We need to replace the '\r\n\' line endings with the'\n' line // endings for each generated object file. function patchObjectFile(project, product, inputs, outputs, input, output) { var isWindows = Host.os().includes("windows"); if (isWindows && input.cpp.debugInformation) { var cmd = new JavaScriptCommand(); cmd.objectPath = outputs.obj[0].filePath; cmd.silent = true; cmd.sourceCode = function() { var file = new BinaryFile(objectPath, BinaryFile.ReadWrite); var data = file.read(file.size()); file.resize(0); for (var pos = 0; pos < data.length; ++pos) { // Find the next index of CR (\r) symbol. var index = data.indexOf(0x0d, pos); if (index < 0) index = data.length; // Write next data chunk between the previous position and the CR // symbol, exclude the CR symbol. file.write(data.slice(pos, index)); pos = index; } }; return cmd; } } // It is a workaround which removes the generated linker map file // if it is disabled by cpp.generateLinkerMapFile property. // Reason is that the SDCC compiler always generates this file, // and does not have an option to disable generation for a linker // map file. So, we can to remove a listing files only after the // linking completes. function removeLinkerMapFile(project, product, inputs, outputs, input, output) { if (!product.cpp.generateLinkerMapFile) { var target = outputs.application[0]; var cmd = new JavaScriptCommand(); cmd.mapFilePath = buildLinkerMapFilePath(target, product.cpp.linkerMapSuffix) cmd.silent = true; cmd.sourceCode = function() { File.remove(mapFilePath); }; return cmd; } } // It is a workaround to rename the extension of the output linker // map file to the specified one, since the linker generates only // files with the '.map' extension. function renameLinkerMapFile(project, product, inputs, outputs, input, output) { if (product.cpp.generateLinkerMapFile && (product.cpp.linkerMapSuffix !== ".map")) { var target = outputs.application[0]; var cmd = new JavaScriptCommand(); cmd.newMapFilePath = buildLinkerMapFilePath(target, product.cpp.linkerMapSuffix); cmd.oldMapFilePath = buildLinkerMapFilePath(target, ".map"); cmd.silent = true; cmd.sourceCode = function() { File.move(oldMapFilePath, newMapFilePath); }; return cmd; } } // It is a workaround which removes the generated listing files // if it is disabled by cpp.generateCompilerListingFiles property // or when the cpp.compilerListingSuffix differs with '.lst'. // Reason is that the SDCC compiler does not have an option to // disable generation for a listing files. Besides, the SDCC // compiler use this files and for the linking. So, we can to // remove a listing files only after the linking completes. function removeCompilerListingFiles(project, product, inputs, outputs, input, output) { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { inputs.obj.forEach(function(object) { if (!object.filePath.endsWith(".c" + object.cpp.objectSuffix)) return; // Skip the assembler generated objects. if (!object.cpp.generateCompilerListingFiles || (object.cpp.compilerListingSuffix !== ".lst")) { var listingPath = FileInfo.joinPaths(FileInfo.path(object.filePath), object.completeBaseName + ".lst"); File.remove(listingPath); } }) }; return cmd; } // It is a workaround that duplicates the generated listing files // but with desired names. The problem is that the SDCC compiler does // not support an options to specify names for the generated listing // files. At the same time, the compiler always generates the listing // files in the form of 'module.c.lst', which makes it impossible to // change the file suffix to a user-specified one. In addition, these // files are also somehow used for linking. Thus, we can not rename them // on the compiling stage. function duplicateCompilerListingFile(project, product, inputs, outputs, input, output) { if (input.cpp.generateCompilerListingFiles && (input.cpp.compilerListingSuffix !== ".lst")) { var cmd = new JavaScriptCommand(); cmd.newListing = outputs.lst[0].filePath; cmd.oldListing = FileInfo.joinPaths(FileInfo.path(outputs.lst[0].filePath), outputs.lst[0].completeBaseName + ".lst"); cmd.silent = true; cmd.sourceCode = function() { File.copy(oldListing, newListing); }; return cmd; } } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); var compilerPath = input.cpp.compilerPath; var cmd = new Command(compilerPath, args); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; cmds.push(cmd); cmd = patchObjectFile(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); cmd = duplicateCompilerListingFile(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); return cmds; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn); var assemblerPath = input.cpp.assemblerPath; var cmd = new Command(assemblerPath, args); cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "assembler"; cmds.push(cmd); cmd = patchObjectFile(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); return cmds; } function prepareLinker(project, product, inputs, outputs, input, output) { var cmds = []; var args = linkerFlags(project, product, inputs, outputs); var linkerPath = effectiveLinkerPath(product); var cmd = new Command(linkerPath, args); cmd.description = "linking " + outputs.application[0].fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; cmds.push(cmd); cmd = removeCompilerListingFiles(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); cmd = renameLinkerMapFile(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); cmd = removeLinkerMapFile(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); return cmds; } function prepareArchiver(project, product, inputs, outputs, input, output) { var args = archiverFlags(project, product, inputs, outputs); var archiverPath = product.cpp.archiverPath; var cmd = new Command(archiverPath, args); cmd.description = "creating " + output.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/cpp/windows-msvc.qbs0000644000175100001660000000570714776170045021751 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Host import qbs.Probes import "windows-msvc-base.qbs" as MsvcBaseModule MsvcBaseModule { condition: Host.os().includes('windows') && qbs.targetOS.includes('windows') && qbs.toolchain && qbs.toolchain.includes('msvc') priority: 50 Probes.ClBinaryProbe { id: compilerPathProbe preferredArchitecture: qbs.architecture condition: !toolchainInstallPath && !_skipAllChecks names: ["cl"] } Probes.MsvcProbe { id: msvcProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage preferredArchitecture: qbs.architecture winSdkVersion: windowsSdkVersion } Properties { condition: msvcProbe.found qbs.architecture: msvcProbe.architecture } compilerVersionMajor: msvcProbe.versionMajor compilerVersionMinor: msvcProbe.versionMinor compilerVersionPatch: msvcProbe.versionPatch compilerIncludePaths: msvcProbe.includePaths compilerDefinesByLanguage: msvcProbe.compilerDefinesByLanguage toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined buildEnv: msvcProbe.buildEnv enableCxxLanguageMacro: true compiledModuleSuffix: ".ifc" moduleOutputFlag: "-ifcOutput " moduleFileFlag: "-reference %module%=" } qbs-src-2.6.1/share/qbs/modules/cpp/windows-clang-cl.qbs0000644000175100001660000000741314776170045022455 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Host import qbs.ModUtils import qbs.Probes import qbs.FileInfo import 'windows-msvc-base.qbs' as MsvcBaseModule MsvcBaseModule { condition: Host.os().includes('windows') && qbs.targetOS.includes('windows') && qbs.toolchain && qbs.toolchain.includes('clang-cl') priority: 100 Probes.ClangClBinaryProbe { id: clangPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["clang-cl"] } Probes.ClangClProbe { id: clangClProbe condition: !_skipAllChecks compilerFilePath: compilerPath vcvarsallFilePath: vcvarsallPath enableDefinesByLanguage: enableCompilerDefinesByLanguage preferredArchitecture: qbs.architecture winSdkVersion: windowsSdkVersion } Properties { condition: clangClProbe.found qbs.architecture: clangClProbe.architecture } compilerVersionMajor: clangClProbe.versionMajor compilerVersionMinor: clangClProbe.versionMinor compilerVersionPatch: clangClProbe.versionPatch compilerIncludePaths: clangClProbe.includePaths compilerDefinesByLanguage: clangClProbe.compilerDefinesByLanguage toolchainInstallPath: clangPathProbe.found ? clangPathProbe.path : undefined buildEnv: clangClProbe.buildEnv property string linkerVariant PropertyOptions { name: "linkerVariant" allowedValues: ["lld", "link"] description: "Allows to specify the linker variant. Maps to clang-cl's -fuse-ld option." } Properties { condition: linkerVariant driverLinkerFlags: "-fuse-ld=" + linkerVariant } property string vcvarsallPath : clangPathProbe.found ? clangPathProbe.vcvarsallPath : undefined compilerName: "clang-cl.exe" linkerName: "lld-link.exe" linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) systemIncludeFlag: "/imsvc" validateFunc: { var baseFunc = base; return function() { if (_skipAllChecks) return; var validator = new ModUtils.PropertyValidator("cpp"); validator.setRequiredProperty("vcvarsallPath", vcvarsallPath); validator.validate(); baseFunc(); } } } qbs-src-2.6.1/share/qbs/modules/cpp/watcom.js0000644000175100001660000005470714776170045020436 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Cpp = require("cpp.js"); var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var PathTools = require("qbs.PathTools"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function toolchainDetails(qbs) { var platform = qbs.targetPlatform; var details = {}; if (platform === "dos") { details.imageFormat = "mz"; details.executableSuffix = ".exe"; } else if (platform === "os2") { details.imageFormat = "pe"; details.executableSuffix = ".exe"; details.dynamicLibrarySuffix = ".dll"; } else if (platform === "windows") { details.imageFormat = "pe"; details.executableSuffix = ".exe"; details.dynamicLibrarySuffix = ".dll"; } else if (platform === "linux") { details.imageFormat = "elf"; details.executableSuffix = ""; details.dynamicLibrarySuffix = ".so"; } return details; } function languageFlag(tag) { if (tag === "c") return "-xc"; else if (tag === "cpp") return "-xc++"; } function targetFlag(platform, architecture, type) { if (platform === "dos") { if (architecture === "x86_16") return "-bdos"; else if (architecture === "x86") return "-bdos4g"; } else if (platform === "os2") { if (architecture === "x86_16") return "-bos2"; else if (architecture === "x86") return "-bos2v2"; } else if (platform === "windows") { if (architecture === "x86_16") { if (type.includes("dynamiclibrary")) return "-bwindows_dll"; return "-bwindows"; } else if (architecture === "x86") { if (type.includes("dynamiclibrary")) return "-bnt_dll"; return "-bnt"; } } else if (platform === "linux") { return "-blinux"; } } function guessVersion(macros) { var version = parseInt(macros["__WATCOMC__"], 10) || parseInt(macros["__WATCOM_CPLUSPLUS__"], 10); if (version) { return { major: parseInt((version - 1100) / 100), minor: parseInt(version / 10) % 10, patch: ((version % 10) > 0) ? parseInt(version % 10) : 0 } } } function guessEnvironment(hostOs, platform, architecture, toolchainInstallPath, pathListSeparator) { var toolchainRootPath = FileInfo.path(toolchainInstallPath); if (!File.exists(toolchainRootPath)) { throw "Unable to deduce environment due to compiler root directory: '" + toolchainRootPath + "' does not exist"; } var env = {}; function setVariable(key, properties, path, separator) { var values = []; for (var i = 0; i < properties.length; ++i) { if (path) { var fullpath = FileInfo.joinPaths(path, properties[i]); values.push(FileInfo.toNativeSeparators(fullpath)); } else { values.push(properties[i]); } } env[key] = values.join(separator); } setVariable("WATCOM", [toolchainRootPath], undefined, pathListSeparator); setVariable("EDPATH", ["eddat"], toolchainRootPath, pathListSeparator); if (hostOs.includes("linux")) setVariable("PATH", ["binl64", "binl"], toolchainRootPath, pathListSeparator); else if (hostOs.includes("windows")) setVariable("PATH", ["binnt64", "binnt"], toolchainRootPath, pathListSeparator); if (platform === "linux") { setVariable("INCLUDE", ["lh"], toolchainRootPath, pathListSeparator); } else { // Common for DOS, Windows, OS/2. setVariable("WIPFC", ["wipfc"], toolchainRootPath, pathListSeparator); setVariable("WHTMLHELP", ["binnt/help"], toolchainRootPath, pathListSeparator); var includes = ["h"]; if (platform === "dos") { // Same includes as before. } else if (platform === "os2") { if (architecture === "x86") includes = includes.concat(["h/os2"]); else if (architecture === "x86_16") includes = includes.concat(["h/os21x"]); } else if (platform === "windows") { if (architecture === "x86") includes = includes.concat(["h/nt", "h/nt/directx", "h/nt/ddk"]); else if (architecture === "x86_16") includes = includes.concat(["h/win"]); } else { throw "Unable to deduce environment for unsupported target platform: '" + platform + "'"; } setVariable("INCLUDE", includes, toolchainRootPath, pathListSeparator); } return env; } function dumpMacros(environment, compilerPath, platform, architecture, tag) { // Note: The Open Watcom compiler does not support the predefined // macros dumping. So, we do it with the following trick, where we try // to create and compile a special temporary file and to parse the console // output with the own magic pattern: #define . var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c"); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); outputFile.writeLine("#define VALUE_TO_STRING(x) #x"); outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)"); outputFile.writeLine("#define VAR_NAME_VALUE(var) \"#define \"#var\" \"VALUE(var)"); // Declare all available pre-defined macros of Watcon compiler. var keys = [ // Prepare the DOS target macros. "__DOS__", "_DOS", "MSDOS", // Prepare the OS/2 target macros. "__OS2__", // Prepare the QNX target macros. "__QNX__", // Prepare the Netware target macros. "__NETWARE__", "__NETWARE_386__", // Prepare the Windows target macros. "__NT__", "__WINDOWS__", "_WINDOWS", "__WINDOWS_386__", // Prepare the Linux and Unix target macros. "__LINUX__", "__UNIX__", // Prepare the 16-bit target specific macros. "__I86__", "M_I86", "_M_I86", "_M_IX86", // Prepare the 32-bit target specific macros. "__386__", "M_I386", "_M_I386", "_M_IX86", // Prepare the indicated options macros. "_MT", "_DLL", "__FPI__", "__CHAR_SIGNED__", "__INLINE_FUNCTIONS__", "_CPPRTTI", "_CPPUNWIND", "NO_EXT_KEYS", // Prepare the common memory model macros. "__FLAT__", "__SMALL__", "__MEDIUM__", "__COMPACT__", "__LARGE__", "__HUGE__", // Prepare the 16-bit memory model macros. "M_I86SM", "_M_I86SM", "M_I86MM", "_M_I86MM", "M_I86CM", "_M_I86CM", "M_I86LM", "_M_I86LM", "M_I86HM", "_M_I86HM", // Prepare the 32-bit memory model macros. "M_386FM", "_M_386FM", "M_386SM", "M_386MM", "_M_386MM", "M_386CM", "_M_386CM", "M_386LM", "_M_386LM", // Prepare the compiler macros. "__X86__", "__cplusplus", "__WATCOMC__", "__WATCOM_CPLUSPLUS__", "_INTEGRAL_MAX_BITS", "_PUSHPOP_SUPPORTED", "_STDCALL_SUPPORTED", // Prepare the other macros. "__3R__", "_based", "_cdecl", "cdecl", "_export", "_far16", "_far", "far", "_fastcall", "_fortran", "fortran", "_huge", "huge", "_inline", "_interrupt", "interrupt", "_loadds", "_near", "near", "_pascal", "pascal", "_saveregs", "_segment", "_segname", "_self", "SOMDLINK", "_STDCALL_SUPPORTED", "__SW_0", "__SW_3R", "__SW_5", "__SW_FP287", "__SW_FP2", "__SW_FP387", "__SW_FP3", "__SW_FPI", "__SW_MF", "__SW_MS", "__SW_ZDP", "__SW_ZFP", "__SW_ZGF", "__SW_ZGP", "_stdcall", "_syscall", "__BIG_ENDIAN" ]; for (var i = 0; i < keys.length; ++i) { var key = keys[i]; outputFile.writeLine("#if defined(" + key + ")"); outputFile.writeLine("#pragma message (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("#endif"); } outputFile.close(); var process = new Process(); process.setWorkingDirectory(outputDirectory.path()); for (var envkey in environment) process.setEnv(envkey, environment[envkey]); var target = targetFlag(platform, architecture, ["application"]); var lang = languageFlag(tag); var args = [ target, lang, outputFilePath ]; process.exec(compilerPath, args, false); var m = Cpp.extractMacros(process.readStdOut(), /"?(#define(\s\w+){1,2})"?$/); if (tag === "cpp" && m["__cplusplus"] === "1") return m; else if (tag === "c") return m; } function effectiveLinkerPath(product) { if (product.cpp.linkerMode === "automatic") { var compilerPath = product.cpp.compilerPath; if (compilerPath) return compilerPath; console.log("Found no C-language objects, choosing system linker for " + product.name); } return product.cpp.linkerPath; } function useCompilerDriverLinker(product) { var linker = effectiveLinkerPath(product); var compiler = product.cpp.compilerPath; return linker === compiler; } function escapeLinkerFlags(useCompilerDriver, linkerFlags) { if (!linkerFlags || linkerFlags.length === 0) return []; if (useCompilerDriver) { var sep = ","; return [["-Wl"].concat(linkerFlags).join(sep)]; } return linkerFlags; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = [FileInfo.toNativeSeparators(input.filePath)]; args.push("-fo=" + FileInfo.toNativeSeparators(outputs.obj[0].filePath)); args = args.concat(Cpp.collectPreincludePaths(input).map(function(path) { return "-fi" + FileInfo.toNativeSeparators(path); })); args = args.concat(Cpp.collectDefinesArguments(input, "-d")); var includePaths = [].concat(Cpp.collectIncludePaths(input)).concat( Cpp.collectSystemIncludePaths(input)); args = args.concat(includePaths.map(function(path) { return "-i" + FileInfo.toNativeSeparators(path); })); if (input.cpp.debugInformation) args.push("-d1"); var warnings = input.cpp.warningLevel if (warnings === "none") args.push("-w0"); else if (warnings === "all") args.push("-wx"); if (input.cpp.treatWarningsAsErrors) args.push("-we"); args.push("-zq"); // Silent. args = args.concat(Cpp.collectMiscAssemblerArguments(input)); return args; } function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = ["-g" + (input.cpp.debugInformation ? "3" : "0")]; var target = targetFlag(product.qbs.targetPlatform, product.qbs.architecture, product.type); args.push(target); if (product.type.includes("application")) { if (product.qbs.targetPlatform === "windows") { var consoleApplication = product.consoleApplication; args.push(consoleApplication ? "-mconsole" : "-mwindows"); } } else if (product.type.includes("dynamiclibrary")) { args.push("-shared"); } var optimization = input.cpp.optimization if (optimization === "fast") args.push("-Ot"); else if (optimization === "small") args.push("-Os"); else if (optimization === "none") args.push("-O0"); var warnings = input.cpp.warningLevel if (warnings === "none") { args.push("-w"); } else if (warnings === "all") { args.push("-Wall"); args.push("-Wextra"); } if (input.cpp.treatWarningsAsErrors) args.push("-Werror"); var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); var langFlag = languageFlag(tag); if (langFlag) args.push(langFlag); if (tag === "cpp") { var enableExceptions = input.cpp.enableExceptions; if (enableExceptions) { var ehModel = input.cpp.exceptionHandlingModel; switch (ehModel) { case "direct": args.push("-feh-direct"); break; case "table": args.push("-feh-table"); break; default: args.push("-feh"); break; } } else { args.push("-fno-eh"); } var enableRtti = input.cpp.enableRtti; args.push(enableRtti ? "-frtti" : "-fno-rtti"); } else if (tag === "c") { var knownValues = ["c99", "c89"]; var cLanguageVersion = Cpp.languageVersion(input.cpp.cLanguageVersion, knownValues, "C"); switch (cLanguageVersion) { case "c89": args.push("-std=c89"); break; case "c99": args.push("-std=c99"); break; } } var preincludePaths = Cpp.collectPreincludePaths(input); for (var i = 0; i < preincludePaths.length; ++i) args.push(input.cpp.preincludeFlag, preincludePaths[i]); args = args.concat(Cpp.collectDefinesArguments(input)); args = args.concat(Cpp.collectIncludePaths(input).map(function(path) { return input.cpp.includeFlag + FileInfo.toNativeSeparators(path); })); args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) { return input.cpp.systemIncludeFlag + FileInfo.toNativeSeparators(path); })); args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(input)); args.push("-o", FileInfo.toNativeSeparators(outputs.obj[0].filePath)); args.push("-c", FileInfo.toNativeSeparators(input.filePath)); return args; } function resourceCompilerFlags(project, product, input, outputs) { var args = [input.filePath]; args.push("-fo=" + FileInfo.toNativeSeparators(outputs.res[0].filePath)); args = args.concat(Cpp.collectDefinesArguments(input, "-d")); args = args.concat(Cpp.collectIncludePaths(input).map(function(path) { return input.cpp.includeFlag + FileInfo.toNativeSeparators(path); })); args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) { return input.cpp.includeFlag + FileInfo.toNativeSeparators(path); })); args.push("-q", "-ad", "-r"); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; var useCompilerDriver = useCompilerDriverLinker(product); if (useCompilerDriver) { var target = targetFlag(product.qbs.targetPlatform, product.qbs.architecture, product.type); args.push(target); if (product.type.includes("application")) { args.push("-o", FileInfo.toNativeSeparators(outputs.application[0].filePath)); if (product.cpp.generateLinkerMapFile) args.push("-fm=" + FileInfo.toNativeSeparators(outputs.mem_map[0].filePath)); } else if (product.type.includes("dynamiclibrary")) { if (product.qbs.targetPlatform === "windows") { args.push("-Wl, option implib=" + FileInfo.toNativeSeparators( outputs.dynamiclibrary_import[0].filePath)); } args.push("-o", FileInfo.toNativeSeparators(outputs.dynamiclibrary[0].filePath)) } var escapableLinkerFlags = []; var targetLinkerFlags = product.cpp.targetLinkerFlags; if (targetLinkerFlags) escapableLinkerFlags = escapableLinkerFlags.concat(targetLinkerFlags); escapableLinkerFlags = escapableLinkerFlags.concat( Cpp.collectMiscEscapableLinkerArguments(product)); var escapedLinkerFlags = escapeLinkerFlags(useCompilerDriver, escapableLinkerFlags); if (escapedLinkerFlags) args = args.concat(escapedLinkerFlags); args = args.concat(Cpp.collectLibraryPaths(product).map(function(path) { return product.cpp.libraryPathFlag + FileInfo.toNativeSeparators(path); })); args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) { return FileInfo.toNativeSeparators(path); })); var libraryDependencies = Cpp.collectLibraryDependencies(product); for (var i = 0; i < libraryDependencies.length; ++i) { var lib = libraryDependencies[i].filePath; if (FileInfo.isAbsolutePath(lib) || lib.startsWith('@')) args.push(FileInfo.toNativeSeparators(lib)); else args.push("-Wl, libfile " + lib); } var resourcePaths = Cpp.collectResourceObjectPaths(inputs).map(function(path) { return FileInfo.toNativeSeparators(path); }); if (resourcePaths.length > 0) args = args.concat("-Wl, resource " + resourcePaths.join(",")); } args = args.concat(Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); return args; } function libraryManagerFlags(project, product, inputs, outputs) { var args = ["-b", "-n", "-q"]; args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) { return "+" + FileInfo.toNativeSeparators(path); })); args.push("-o", FileInfo.toNativeSeparators(outputs.staticlibrary[0].filePath)); return args; } function disassemblerFlags(project, product, inputs, outputs) { var objectPath = Cpp.relativePath(product.buildDirectory, outputs.obj[0].filePath); var listingPath = Cpp.relativePath(product.buildDirectory, outputs.lst[0].filePath); var args = []; args.push(FileInfo.toNativeSeparators(objectPath)); args.push("-l=" + FileInfo.toNativeSeparators(listingPath)); args.push("-s", "-a"); return args; } function generateCompilerListing(project, product, inputs, outputs, input, output) { var args = disassemblerFlags(project, product, input, outputs); var cmd = new Command(input.cpp.disassemblerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.silent = true; cmd.jobPool = "watcom_job_pool"; return cmd; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var args = assemblerFlags(project, product, input, outputs); var cmd = new Command(input.cpp.assemblerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "watcom_job_pool"; cmds.push(cmd); if (input.cpp.generateAssemblerListingFiles) cmds.push(generateCompilerListing(project, product, inputs, outputs, input, output)); return cmds; } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); var cmd = new Command(input.cpp.compilerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "watcom_job_pool"; cmds.push(cmd); if (input.cpp.generateCompilerListingFiles) cmds.push(generateCompilerListing(project, product, inputs, outputs, input, output)); return cmds; } function prepareResourceCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = resourceCompilerFlags(project, product, input, outputs); var cmd = new Command(input.cpp.resourceCompilerPath, args); // Set working directory to source directory as a workaround // to make the resources compilable by resource compiler (it is magic). cmd.workingDirectory = product.sourceDirectory; cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "watcom_job_pool"; return [cmd]; } function prepareLinker(project, product, inputs, outputs, input, output) { var primaryOutput = outputs.dynamiclibrary ? outputs.dynamiclibrary[0] : outputs.application[0]; var args = linkerFlags(project, product, inputs, outputs); var linkerPath = effectiveLinkerPath(product); var cmd = new Command(linkerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; cmd.jobPool = "watcom_job_pool"; return [cmd]; } function prepareLibraryManager(project, product, inputs, outputs, input, output) { var args = libraryManagerFlags(project, product, inputs, outputs); var cmd = new Command(product.cpp.libraryManagerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "linking " + outputs.staticlibrary[0].fileName; cmd.highlight = "linker"; cmd.jobPool = "watcom_job_pool"; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/cpp/cpp.js0000644000175100001660000006163114776170045017720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var BinaryFile = require("qbs.BinaryFile"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var PathTools = require("qbs.PathTools"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function languageVersion(versionArray, knownValues, lang) { if (!versionArray) return undefined; var versions = [].uniqueConcat(versionArray); if (versions.length === 1) return versions[0]; for (var i = 0; i < knownValues.length; ++i) { var candidate = knownValues[i]; if (versions.includes(candidate)) return candidate; } var version = versions[0]; console.debug("Randomly choosing '" + version + "' from list of unknown " + lang + " version strings (" + versions + ")"); return version; } function extractMacros(output, regexp) { var m = {}; output.trim().split(/\r?\n/g).map(function(line) { if (regexp) { var match = regexp.exec(line); if (!match) return; line = match[1]; } var prefix = "#define "; if (!line.startsWith(prefix)) return; var index = line.indexOf(" ", prefix.length); if (index !== -1) m[line.substr(prefix.length, index - prefix.length)] = line.substr(index + 1); }); return m; } function relativePath(baseDirectory, filePath) { if (FileInfo.isAbsolutePath(filePath)) return FileInfo.relativePath(baseDirectory, filePath); return filePath; } function assemblerOutputTags(needsListingFiles) { var tags = ["obj"]; if (needsListingFiles) tags.push("lst"); return tags; } function compilerOutputTags(withListingFiles, withCxxModules) { var tags = ["obj", "intermediate_obj"]; if (withListingFiles) tags.push("lst"); if (withCxxModules) tags = tags.concat(["compiled-module", "modulemap", "moduleinfo"]); return tags; } function applicationLinkerOutputTags(needsLinkerMapFile) { var tags = ["application"]; if (needsLinkerMapFile) tags.push("mem_map"); return tags; } function dynamicLibraryLinkerOutputTags() { return ["dynamiclibrary", "dynamiclibrary_import"]; } function staticLibraryLinkerOutputTags() { return ["staticlibrary"]; } function resourceCompilerOutputTags() { return ["res"]; } function precompiledHeaderOutputTags(lang, generateObjects) { var tags = [lang + "_pch"]; if (generateObjects) tags.push("obj"); return tags; }; function assemblerOutputArtifacts(input) { var artifacts = []; artifacts.push({ fileTags: ["obj"], filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.fileName + input.cpp.objectSuffix) }); if (input.cpp.generateAssemblerListingFiles) { artifacts.push({ fileTags: ["lst"], filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.fileName + input.cpp.assemblerListingSuffix) }); } return artifacts; } function cxxModulesArtifacts(input) { var artifacts = []; if (input.cpp.forceUseCxxModules === false) return artifacts; if (input.cpp.compiledModuleSuffix === undefined || input.cpp.moduleOutputFlag === undefined || input.cpp.moduleFileFlag === undefined) { console.warn("Skip additional artifacts for '" + input.fileName + "' since '" + input.qbs.toolchainType + "' toolchain does not support C++ Modules."); return artifacts; } var moduleInformation = CppModulesScanner.apply(input); if (moduleInformation.providesModule || moduleInformation.requiresModules.length > 0) { artifacts.push({ filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.fileName + input.cpp.moduleMapSuffix), fileTags: ["modulemap"], // we can't use maps here only strings and lists cpp: { _providesModule: moduleInformation.providesModule, _isInterfaceModule: moduleInformation.isInterfaceModule, _requiresModules : moduleInformation.requiresModules, }, }) } if (input.fileTags.includes("cppm")) { const moduleName = moduleInformation.providesModule ? moduleInformation.providesModule : undefined; if (moduleName) { const moduleFileName = moduleName.replace(':', '-'); artifacts.push({ filePath: FileInfo.joinPaths("cxx-modules", moduleFileName + product.cpp.compiledModuleSuffix), fileTags: ["compiled-module"], }) artifacts.push({ filePath: FileInfo.joinPaths("cxx-modules", moduleFileName + product.cpp.moduleInfoSuffix), fileTags: ["moduleinfo"], }) } else { console.warn("File '" + input.fileName + "' has 'cppm' tag, but does not " + "provide a module interface unit or partition"); } } return artifacts; } function compilerOutputArtifacts(input, inputs, withCxxModules) { var objTags = input.fileTags.includes("cpp_intermediate_object") ? ["intermediate_obj"] : ["obj"]; if (inputs) { if (inputs.c || inputs.objc) objTags.push("c_obj"); if (inputs.cpp || inputs.objcpp || inputs.cppm) objTags.push("cpp_obj"); } var artifacts = [{ fileTags: objTags, filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.fileName + input.cpp.objectSuffix) }]; if (input.cpp.generateCompilerListingFiles) { artifacts.push({ fileTags: ["lst"], filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.fileName + input.cpp.compilerListingSuffix) }); } if (withCxxModules) artifacts = artifacts.concat(cxxModulesArtifacts(input)); return artifacts; } function applicationLinkerOutputArtifacts(product) { var artifacts = [{ fileTags: ["application"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.applicationFilePath(product)) }]; if (product.cpp.generateLinkerMapFile) { artifacts.push({ fileTags: ["mem_map"], filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.cpp.linkerMapSuffix) }); } return artifacts; } function dynamicLibraryLinkerOutputArtifacts(product) { return [{ fileTags: ["dynamiclibrary"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.dynamicLibraryFilePath(product)) }, { fileTags: ["dynamiclibrary_import"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.importLibraryFilePath(product)), alwaysUpdated: false }]; } function staticLibraryLinkerOutputArtifacts(product) { return [{ fileTags: ["staticlibrary"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.staticLibraryFilePath(product)) }]; } function resourceCompilerOutputArtifacts(input) { return [{ fileTags: ["res"], filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.completeBaseName + input.cpp.resourceSuffix) }]; } function precompiledHeaderOutputArtifacts(input, product, lang, generateObjects) { var artifacts = [{ fileTags: [lang + "_pch"], filePath: product.name + "_" + lang + product.cpp.precompiledHeaderSuffix }]; if (generateObjects) { artifacts.push({ fileTags: ["obj"], filePath: Utilities.getHash(input.completeBaseName) + "_" + lang + input.cpp.objectSuffix }); } return artifacts; } function collectLibraryDependencies(product) { var seen = {}; var seenObjectFiles = []; var result = []; function addFilePath(filePath, wholeArchive, productName) { result.push({ filePath: filePath, wholeArchive: wholeArchive, productName: productName }); } function addArtifactFilePaths(dep, artifacts) { if (!artifacts) return; var artifactFilePaths = artifacts.map(function(a) { return a.filePath; }); var wholeArchive = dep.parameters.cpp && dep.parameters.cpp.linkWholeArchive; var artifactsAreImportLibs = artifacts.length > 0 && artifacts[0].fileTags.includes("dynamiclibrary_import"); for (var i = 0; i < artifactFilePaths.length; ++i) { addFilePath(artifactFilePaths[i], wholeArchive, artifactsAreImportLibs ? dep.name : undefined); } } function addExternalLibs(obj) { if (!obj.cpp) return; function ensureArray(a) { return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); } function handleExternalLibraries(tag, libSuffix, objSuffix) { var externalLibs = sanitizedModuleListProperty(obj, "cpp", tag) || []; externalLibs.forEach(function(libName) { var isObjectFile = objSuffix && libName.endsWith(objSuffix); if (isObjectFile) { if (seenObjectFiles.includes(libName)) return; seenObjectFiles.push(libName); } if (!libName.endsWith(libSuffix) && !isObjectFile && !libName.startsWith('@')) libName += libSuffix; addFilePath(libName, false); }); } handleExternalLibraries("staticLibraries", obj.moduleProperty("cpp", "staticLibrarySuffix"), obj.moduleProperty("cpp", "objectSuffix")); handleExternalLibraries("dynamicLibraries", obj.moduleProperty("cpp", "dynamicLibraryImportSuffix")); } function traverse(dep) { if (seen.hasOwnProperty(dep.name)) return; if (dep.parameters.cpp && dep.parameters.cpp.link === false) return; var staticLibraryArtifacts = dep.artifacts["staticlibrary"]; var dynamicLibraryArtifacts = staticLibraryArtifacts ? null : dep.artifacts["dynamiclibrary_import"]; if (staticLibraryArtifacts) { seen[dep.name] = true; dep.dependencies.forEach(traverse); addArtifactFilePaths(dep, staticLibraryArtifacts); if (product.cpp.importPrivateLibraries) addExternalLibs(dep); } else if (dynamicLibraryArtifacts) { seen[dep.name] = true; addArtifactFilePaths(dep, dynamicLibraryArtifacts); } } product.dependencies.forEach(traverse); addExternalLibs(product); return result; } function collectAbsoluteLibraryDependencyPaths(product) { var paths = collectLibraryPaths(product); var deps = collectLibraryDependencies(product); return deps.map(function(dep) { var filePath = dep.filePath; if (FileInfo.isAbsolutePath(filePath)) return filePath; for (var i = 0; i < paths.length; ++i) { var fullPath = FileInfo.joinPaths(paths[i], filePath); if (File.exists(fullPath)) return fullPath; } return filePath; }); } function collectDefines(input) { var allDefines = []; var platformDefines = input.cpp.platformDefines; if (platformDefines) allDefines = allDefines.uniqueConcat(platformDefines); var defines = input.cpp.defines; if (defines) allDefines = allDefines.uniqueConcat(defines); return allDefines; } function collectIncludePaths(input) { var allIncludePaths = []; var includePaths = input.cpp.includePaths; if (includePaths) allIncludePaths = allIncludePaths.uniqueConcat(includePaths); var builtIns = input.cpp.compilerIncludePaths; return allIncludePaths.filter(function(p) { return !builtIns.includes(p); }); } function collectSystemIncludePaths(input) { var allIncludePaths = []; var systemIncludePaths = input.cpp.systemIncludePaths; if (systemIncludePaths) allIncludePaths = allIncludePaths.uniqueConcat(systemIncludePaths); var distributionIncludePaths = input.cpp.distributionIncludePaths; if (distributionIncludePaths) allIncludePaths = allIncludePaths.uniqueConcat(distributionIncludePaths); var builtIns = input.cpp.compilerIncludePaths; return allIncludePaths.filter(function(p) { return !builtIns.includes(p); }); } function collectPreincludePaths(input) { return input.cpp.prefixHeaders; } function collectLibraryPaths(product) { var allLibraryPaths = []; var libraryPaths = product.cpp.libraryPaths; if (libraryPaths) allLibraryPaths = allLibraryPaths.uniqueConcat(libraryPaths); var distributionLibraryPaths = product.cpp.distributionLibraryPaths; if (distributionLibraryPaths) allLibraryPaths = allLibraryPaths.uniqueConcat(distributionLibraryPaths); return allLibraryPaths; } function collectLinkerScriptPaths(inputs) { return inputs.linkerscript ? inputs.linkerscript.map(function(script) { return script.filePath; }) : []; } function collectLinkerObjectPaths(inputs) { return inputs.obj ? inputs.obj.map(function(obj) { return obj.filePath; }) : []; } function collectResourceObjectPaths(inputs) { return inputs.res ? inputs.res.map(function(res) { return res.filePath; }) : []; } function collectLibraryDependenciesArguments(product) { var deps = collectLibraryDependencies(product); return deps.map(function(dep) { return product.cpp.libraryDependencyFlag + dep.filePath }) } function collectDefinesArguments(input) { var defines = collectDefines(input); return defines.map(function(define) { return input.cpp.defineFlag + define }); } function collectIncludePathsArguments(input) { var paths = collectIncludePaths(input); return paths.map(function(path) { return input.cpp.includeFlag + path }); } function collectSystemIncludePathsArguments(input, flag) { flag = (flag === undefined) ? input.cpp.systemIncludeFlag : flag; var paths = collectSystemIncludePaths(input); return paths.map(function(path) { return flag + path }); } function collectPreincludePathsArguments(input, split) { var paths = collectPreincludePaths(input); if (split) { var args = []; for (var i = 0; i < paths.length; ++i) args.push(input.cpp.preincludeFlag, paths[i]); return args; } else { return paths.map(function(path) { return input.cpp.preincludeFlag + path }); } } function collectLibraryPathsArguments(product, flag) { flag = (flag === undefined) ? product.cpp.libraryPathFlag : flag; var paths = collectLibraryPaths(product); return paths.map(function(path) { return flag + path }); } function collectLinkerScriptPathsArguments(product, inputs, split, flag) { flag = (flag === undefined) ? product.cpp.linkerScriptFlag : flag; var paths = collectLinkerScriptPaths(inputs); if (split) { var args = []; for (var i = 0; i < paths.length; ++i) args.push(flag, paths[i]); return args; } else { return paths.map(function(path) { return flag + path }); } } function collectLinkerObjectPathsArguments(product, inputs, flag) { flag = (flag === undefined) ? "" : flag; var paths = collectLinkerObjectPaths(product); return paths.map(function(path) { return flag + path }); } function collectMiscCompilerArguments(input, tag) { if (tag === "cppm") tag = "cpp"; return [].concat(ModUtils.moduleProperty(input, "platformFlags"), ModUtils.moduleProperty(input, "flags"), ModUtils.moduleProperty(input, "platformFlags", tag), ModUtils.moduleProperty(input, "flags", tag)); } function collectMiscAssemblerArguments(input, tag) { return [].concat(ModUtils.moduleProperty(input, "platformFlags", tag), ModUtils.moduleProperty(input, "flags", tag)); } function collectMiscDriverArguments(config) { return [].concat(ModUtils.moduleProperty(config, "platformDriverFlags"), ModUtils.moduleProperty(config, "driverFlags"), ModUtils.moduleProperty(config, "targetDriverFlags")); } function collectMiscLinkerArguments(product) { return [].concat(ModUtils.moduleProperty(product, "driverLinkerFlags")); } function collectMiscEscapableLinkerArguments(product) { return [].concat(ModUtils.moduleProperty(product, "platformLinkerFlags"), ModUtils.moduleProperty(product, "linkerFlags")); } function supportsArchitecture(architecture, knownArchitectures) { for (var i = 0; i < knownArchitectures.length; ++i) { if (architecture.startsWith("arm")) { if (architecture.startsWith(knownArchitectures[i])) return true; } else { if (architecture === knownArchitectures[i]) return true; } } return false; } function prepareModuleInfo(moduleInformation, input, output, product) { var command = new JavaScriptCommand() command.moduleInformation = moduleInformation command.outPath = output.filePath command.description = "generating module info for " + input.fileName command.highlight = "filegen" command.sourceCode = function() { var file = new TextFile(outPath, TextFile.WriteOnly); file.write(JSON.stringify(moduleInformation, undefined, 4)); file.close(); } return command; } function prepareModuleMap(moduleInformation, input, mm, product) { var modulesFromDeps = {}; product.dependencies.forEach(function(dep){ (dep.artifacts["compiled-module"] || []).forEach(function(a) { modulesFromDeps[a.completeBaseName.replace('-', ':')] = a.filePath; }); }); var generateModuleMap = new JavaScriptCommand() generateModuleMap.outPath = mm.filePath generateModuleMap.moduleInformation = moduleInformation; generateModuleMap.compiledModuleSuffix = product.cpp.compiledModuleSuffix; generateModuleMap.moduleInfoSuffix = product.cpp.moduleInfoSuffix; generateModuleMap.moduleOutputFlag = product.cpp.moduleOutputFlag; generateModuleMap.moduleFileFlag = product.cpp.moduleFileFlag; generateModuleMap.toolchain = product.qbs.toolchain; generateModuleMap.toolchainType = product.qbs.toolchainType; generateModuleMap.modulesFromDeps = modulesFromDeps; generateModuleMap.description = "generating module map for " + input.fileName generateModuleMap.highlight = "filegen" generateModuleMap.sourceCode = function() { function moduleFileOption(moduleName) { return moduleFileFlag.replace("%module%", moduleName); } function moduleOutputOption(moduleName) { return moduleOutputFlag.replace("%module%", moduleName); } var content = ""; if (toolchainType === "gcc" || toolchainType === "mingw") content += "$root .\n"; const isModule = input.fileTags.includes("cppm"); function modulePath(moduleName) { return FileInfo.joinPaths( product.buildDirectory, "cxx-modules", moduleName.replace(':', "-") + compiledModuleSuffix); } const providesModule = moduleInformation.providesModule if (isModule && providesModule !== undefined) { if (toolchainType === "msvc") { if (moduleInformation.isInterfaceModule) content += "-interface\n"; else content += "-internalPartition\n"; } content += moduleOutputOption(providesModule) + modulePath(providesModule) + "\n"; } function isHeaderImport(mod) { return mod.length > 2 && (mod[0] == '<' && mod[mod.length - 1] == '>' || mod[0] == '"' && mod[mod.length - 1] == '"') } function processImport(mod) { if (!isHeaderImport(mod)) { const moduleFile = modulesFromDeps[mod] || modulePath(mod); content += moduleFileOption(mod) + moduleFile + "\n"; function getModuleInfo(moduleFile) { const moduleInfoPath = FileInfo.joinPaths( FileInfo.path(moduleFile), FileInfo.completeBaseName(moduleFile) + moduleInfoSuffix); var file = new TextFile(moduleInfoPath, TextFile.ReadOnly); const moduleInfo = JSON.parse(file.readAll()); file.close(); return moduleInfo; } function processImportsRecursive(moduleFile) { // can we do better rather than pass info via a file? const moduleInfo = getModuleInfo(moduleFile); const requiresModules = moduleInfo['requiresModules'] || []; requiresModules.forEach(function(importModule) { const importModuleFile = modulesFromDeps[importModule] || modulePath(importModule); content += moduleFileOption(importModule) + importModuleFile + "\n"; processImportsRecursive(importModuleFile); }); } processImportsRecursive(moduleFile); } } moduleInformation.requiresModules.forEach(processImport); // converts UTF string to an array of bytes function encode(string) { var bytes = []; for (var i = 0; i < string.length; i++) { bytes.push(string.charCodeAt(i)); } return bytes; } // MinGW fails if file contains \r on Windows, so we use Unix line-endings on all platforms // and thus we use BinaryFile instead of TextFile here var file = new BinaryFile(outPath, TextFile.WriteOnly); file.write(encode(content)); file.close(); } return generateModuleMap; } function prepareModules(project, product, inputs, outputs, input, output) { var commands = []; // module map is present for both cppm and regular cpp files if they use modules const moduleMapOutputs = outputs["modulemap"]; if (moduleMapOutputs === undefined) return commands; const cppModuleMap = moduleMapOutputs[0]; if (cppModuleMap === undefined) return commands; const moduleInformation = { providesModule: cppModuleMap.cpp._providesModule, isInterfaceModule: cppModuleMap.cpp._isInterfaceModule, requiresModules: cppModuleMap.cpp._requiresModules, }; // module info json is present only for cppm var cppModuleInfo = outputs["moduleinfo"]; if (cppModuleInfo) commands.push(prepareModuleInfo(moduleInformation, input, cppModuleInfo[0], product)); commands.push(prepareModuleMap(moduleInformation, input, cppModuleMap, product)); return commands; }qbs-src-2.6.1/share/qbs/modules/cpp/emcc.qbs0000644000175100001660000000152114776170045020206 0ustar runnerdockerimport qbs import qbs.ModUtils GenericGCC { condition: qbs.toolchain && qbs.toolchain.includes("emscripten") priority: 100 qbs.targetPlatform: "wasm-emscripten" cCompilerName: "emcc" cxxCompilerName: "em++" archiverName: "emar" dynamicLibrarySuffix: ".so" dynamicLibraryPrefix: "lib" executableSuffix: ".js" rpathOrigin: "irrelevant"//to pass tests imageFormat: "wasm" Depends { name: "emsdk" } emsdk.configuredInstallPath: toolchainInstallPath toolchainInstallPath: emsdk.detectedInstallPath ? emsdk.detectedInstallPath : undefined probeEnv: emsdk.environment setupBuildEnvironment: { for (var key in product.cpp.probeEnv) { var v = new ModUtils.EnvironmentVariable(key); v.value = product.cpp.probeEnv[key]; v.set(); } } } qbs-src-2.6.1/share/qbs/modules/cpp/windows-msvc-base.qbs0000644000175100001660000002010314776170045022644 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.PathTools import qbs.Probes import qbs.Utilities import qbs.WindowsUtils import 'cpp.js' as Cpp import 'msvc.js' as MSVC CppModule { condition: false Depends { name: "codesign" } windowsApiCharacterSet: "unicode" platformDefines: { var defines = base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet)) .concat("WIN32"); var def = WindowsUtils.winapiFamilyDefine(windowsApiFamily); if (def) defines.push("WINAPI_FAMILY=WINAPI_FAMILY_" + def); (windowsApiAdditionalPartitions || []).map(function (name) { defines.push("WINAPI_PARTITION_" + WindowsUtils.winapiPartitionDefine(name) + "=1"); }); return defines; } platformCommonCompilerFlags: { var flags = base; if (compilerVersionMajor >= 18) // 2013 flags.push("/FS"); return flags; } warningLevel: "default" compilerName: "cl.exe" compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: { switch (qbs.architecture) { case "armv7": return "armasm.exe"; case "arm64": return "armasm64.exe"; case "ia64": return "ias.exe"; case "x86": return "ml.exe"; case "x86_64": return "ml64.exe"; } } linkerName: "link.exe" runtimeLibrary: "dynamic" separateDebugInformation: true property bool generateManifestFile: true architecture: qbs.architecture endianness: "little" staticLibrarySuffix: ".lib" dynamicLibrarySuffix: ".dll" executableSuffix: ".exe" debugInfoSuffix: ".pdb" objectSuffix: ".obj" precompiledHeaderSuffix: ".pch" imageFormat: "pe" Properties { condition: product.multiplexByQbsProperties.includes("buildVariants") && qbs.buildVariants && qbs.buildVariants.length > 1 && qbs.buildVariant !== "release" && product.type.containsAny(["staticlibrary", "dynamiclibrary"]) variantSuffix: "d" } property var buildEnv readonly property bool shouldSignArtifacts: codesign.enableCodeSigning property bool enableCxxLanguageMacro: false setupBuildEnvironment: { for (var key in product.cpp.buildEnv) { var v = new ModUtils.EnvironmentVariable(key, ';'); v.prepend(product.cpp.buildEnv[key]); v.set(); } } property string windowsSdkVersion defineFlag: "/D" includeFlag: "/I" systemIncludeFlag: "/external:I" preincludeFlag: "/FI" libraryPathFlag: "/LIBPATH:" Rule { condition: useCPrecompiledHeader inputs: ["c_pch_src"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.precompiledHeaderOutputTags("c", true) outputArtifacts: Cpp.precompiledHeaderOutputArtifacts(input, product, "c", true) prepare: MSVC.prepareCompiler.apply(MSVC, arguments) } Rule { condition: useCxxPrecompiledHeader inputs: ["cpp_pch_src"] explicitlyDependsOn: ["c_pch"] // to prevent vc--0.pdb conflict auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.precompiledHeaderOutputTags("cpp", true) outputArtifacts: Cpp.precompiledHeaderOutputArtifacts(input, product, "cpp", true) prepare: MSVC.prepareCompiler.apply(MSVC, arguments) } Rule { name: "cpp_compiler" inputs: ["cpp", "cppm", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] explicitlyDependsOn: ["c_pch", "cpp_pch"] outputFileTags: Cpp.compilerOutputTags(generateCompilerListingFiles, /*withCxxModules*/ true) outputArtifacts: Cpp.compilerOutputArtifacts(input, undefined, /*withCxxModules*/ true) prepare: MSVC.prepareCompiler.apply(MSVC, arguments) } FileTagger { patterns: ["*.manifest"] fileTags: ["native.pe.manifest"] } FileTagger { patterns: ["*.def"] fileTags: ["def"] } Rule { name: "applicationLinker" multiplex: true inputs: ['obj', 'res', 'native.pe.manifest', 'def'] inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_app"] outputFileTags: { var tags = ["application", "debuginfo_app"]; if (generateLinkerMapFile) tags.push("mem_map"); if (shouldSignArtifacts) tags.push("codesign.signed_artifact"); return tags; } outputArtifacts: MSVC.appLinkerOutputArtifacts(product) prepare: MSVC.prepareLinker.apply(MSVC, arguments) } Rule { name: "dynamicLibraryLinker" multiplex: true inputs: ['obj', 'res', 'native.pe.manifest', 'def'] inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_dll"] outputFileTags: { var tags = ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"]; if (shouldSignArtifacts) tags.push("codesign.signed_artifact"); return tags; } outputArtifacts: MSVC.dllLinkerOutputArtifacts(product) prepare: MSVC.prepareLinker.apply(MSVC, arguments) } Rule { name: "libtool" multiplex: true inputs: ["obj", "res"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: ["staticlibrary", "debuginfo_cl"] outputArtifacts: MSVC.libtoolOutputArtifacts(product) prepare: MSVC.libtoolCommands.apply(MSVC, arguments) } FileTagger { patterns: ["*.rc"] fileTags: ["rc"] } Rule { inputs: ["rc"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.resourceCompilerOutputTags() outputArtifacts: Cpp.resourceCompilerOutputArtifacts(input) prepare: { // From MSVC 2010 on, the logo can be suppressed. var logo = product.cpp.compilerVersionMajor >= 16 ? "can-suppress-logo" : "always-shows-logo"; return MSVC.createRcCommand("rc", input, output, logo); } } FileTagger { patterns: "*.asm" fileTags: ["asm"] } Rule { inputs: ["asm"] outputFileTags: Cpp.assemblerOutputTags(false) outputArtifacts: Cpp.assemblerOutputArtifacts(input) prepare: MSVC.assemblerCommands.apply(MSVC, arguments) } } qbs-src-2.6.1/share/qbs/modules/cpp/setuprunenv.js0000644000175100001660000001411114776170045021523 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var File = require("qbs.File"); var Host = require("qbs.Host"); var ModUtils = require("qbs.ModUtils"); // TODO: append/prepend functionality should go to qbs.Environment function addNewElement(list, elem) { if (!list.includes(elem)) list.push(elem); } function artifactDir(artifact) { if (!artifact.qbs.install) return FileInfo.path(artifact.filePath); return FileInfo.path(ModUtils.artifactInstalledFilePath(artifact)); } function addExternalLibPath(product, list, path) { addNewElement(list, path); if (Host.os().includes("windows") && FileInfo.fileName(path) === "lib") { var binPath = FileInfo.joinPaths(FileInfo.path(path), "bin"); if (File.exists(binPath)) addNewElement(list, binPath); } } function gatherPaths(product, libPaths, frameworkPaths, seenProducts) { if (seenProducts.includes(product.name)) return; seenProducts.push(product.name); // Gather explicitly given library paths. if (product.cpp && product.cpp.libraryPaths) product.cpp.libraryPaths.forEach(function(p) { addExternalLibPath(product, libPaths, p); }); if (product.cpp && product.cpp.frameworkPaths) product.cpp.frameworkPaths.forEach(function(p) { addNewElement(frameworkPaths, p); }); if (product.cpp && product.cpp.systemFrameworkPaths) product.cpp.systemFrameworkPaths.forEach(function(p) { addNewElement(frameworkPaths, p); }); // Extract paths from dynamic libraries, if they are given as file paths. if (product.cpp && product.cpp.dynamicLibraries) { product.cpp.dynamicLibraries.forEach(function(dll) { if (FileInfo.isAbsolutePath(dll)) addExternalLibPath(product, libPaths, FileInfo.path(dll)); }); } // Traverse library dependencies. for (var i = 0; i < product.dependencies.length; ++i) { var dep = product.dependencies[i]; var dllSymlinkArtifacts = dep.artifacts["bundle.symlink.executable"]; if (dllSymlinkArtifacts) { var addArtifact = function(artifact) { addNewElement(frameworkPaths, FileInfo.path(artifactDir(artifact))); }; dllSymlinkArtifacts.forEach(addArtifact); // TODO: Will also catch applications. Can we prevent that? } else { addArtifact = function(artifact) { addNewElement(libPaths, artifactDir(artifact)); }; var dllArtifacts = dep.artifacts["dynamiclibrary"]; if (dllArtifacts) dllArtifacts.forEach(addArtifact); var loadableModuleArtifacts = dep.artifacts["loadablemodule"]; if (loadableModuleArtifacts) loadableModuleArtifacts.forEach(addArtifact); } if (!dep.hasOwnProperty("present")) // Recurse if the dependency is a product. TODO: Provide non-heuristic way to decide whether dependency is a product. gatherPaths(dep, libPaths, frameworkPaths, seenProducts); } } function setupRunEnvironment(product, config) { if (config.includes("ignore-lib-dependencies")) return; if (Host.platform() !== product.qbs.targetPlatform) return; var libPaths = []; var frameworkPaths = []; gatherPaths(product, libPaths, frameworkPaths, []); var runPaths = product.cpp ? product.cpp.systemRunPaths : undefined; if (runPaths && runPaths.length > 0) { var canonicalRunPaths = runPaths.map(function(p) { return File.canonicalFilePath(p); }); var filterFunc = function(libPath) { return !runPaths.includes(libPath) && !canonicalRunPaths.includes(File.canonicalFilePath(libPath)); }; libPaths = libPaths.filter(filterFunc); frameworkPaths = frameworkPaths.filter(filterFunc); } if (libPaths.length > 0) { var envVarName; if (product.qbs.targetOS.includes("windows")) envVarName = "PATH"; else if (product.qbs.targetOS.includes("macos")) envVarName = "DYLD_LIBRARY_PATH"; else envVarName = "LD_LIBRARY_PATH"; var envVar = new ModUtils.EnvironmentVariable(envVarName, FileInfo.pathListSeparator(), Host.os().includes("windows")); libPaths.forEach(function(p) { envVar.prepend(p); }); envVar.set(); } if (product.qbs.targetOS.includes("macos") && frameworkPaths.length > 0) { envVar = new ModUtils.EnvironmentVariable("DYLD_FRAMEWORK_PATH", ':', false); frameworkPaths.forEach(function(p) { envVar.prepend(p); }); envVar.set(); } } qbs-src-2.6.1/share/qbs/modules/cpp/sdcc.qbs0000644000175100001660000001321014776170045020211 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Probes import "cpp.js" as Cpp import "sdcc.js" as SDCC CppModule { condition: qbs.toolchain && qbs.toolchain.includes("sdcc") Probes.BinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["sdcc"] } Probes.SdccProbe { id: sdccProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage preferredArchitecture: qbs.architecture } Properties { condition: sdccProbe.found qbs.architecture: sdccProbe.architecture } qbs.targetPlatform: "none" compilerVersionMajor: sdccProbe.versionMajor compilerVersionMinor: sdccProbe.versionMinor compilerVersionPatch: sdccProbe.versionPatch endianness: sdccProbe.endianness compilerDefinesByLanguage: sdccProbe.compilerDefinesByLanguage compilerIncludePaths: sdccProbe.includePaths toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined /* Work-around for QtCreator which expects these properties to exist. */ property string cCompilerName: compilerName property string cxxCompilerName: compilerName property string linkerMode: "automatic" compilerName: "sdcc" + compilerExtension compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: toolchainDetails.assemblerName + compilerExtension assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName) linkerName: toolchainDetails.linkerName + compilerExtension linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) property string archiverName: "sdar" + compilerExtension property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName) runtimeLibrary: "static" staticLibrarySuffix: ".lib" executableSuffix: ".ihx" objectSuffix: ".rel" imageFormat: "ihx" enableExceptions: false enableRtti: false defineFlag: "-D" includeFlag: "-I" systemIncludeFlag: "-isystem" preincludeFlag: "-include" libraryDependencyFlag: "-l" libraryPathFlag: "-L" linkerScriptFlag: "-f" toolchainDetails: SDCC.toolchainDetails(qbs) knownArchitectures: ["hcs8", "mcs51", "stm8"] Rule { id: assembler inputs: ["asm"] outputFileTags: SDCC.extraCompilerOutputTags().concat( Cpp.assemblerOutputTags(generateAssemblerListingFiles)) outputArtifacts: SDCC.extraCompilerOutputArtifacts(input).concat( Cpp.assemblerOutputArtifacts(input)) prepare: SDCC.prepareAssembler.apply(SDCC, arguments) } FileTagger { patterns: ["*.s", "*.a51", "*.asm"] fileTags: ["asm"] } Rule { id: compiler inputs: ["cpp", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: SDCC.extraCompilerOutputTags().concat( Cpp.compilerOutputTags(generateCompilerListingFiles)) outputArtifacts: SDCC.extraCompilerOutputArtifacts(input).concat( Cpp.compilerOutputArtifacts(input)) prepare: SDCC.prepareCompiler.apply(SDCC, arguments) } Rule { id: applicationLinker multiplex: true inputs: ["obj", "linkerscript"] inputsFromDependencies: ["staticlibrary"] outputFileTags: SDCC.extraApplicationLinkerOutputTags().concat( Cpp.applicationLinkerOutputTags(generateLinkerMapFile)) outputArtifacts: SDCC.extraApplicationLinkerOutputArtifacts(product).concat( Cpp.applicationLinkerOutputArtifacts(product)) prepare: SDCC.prepareLinker.apply(SDCC, arguments) } Rule { id: staticLibraryLinker multiplex: true inputs: ["obj"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.staticLibraryLinkerOutputTags() outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product) prepare: SDCC.prepareArchiver.apply(SDCC, arguments) } } qbs-src-2.6.1/share/qbs/modules/cpp/freebsd-gcc.qbs0000644000175100001660000000355514776170045021454 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "freebsd.js" as FreeBSD import qbs.Host UnixGCC { condition: qbs.targetOS.includes("freebsd") && qbs.toolchain && qbs.toolchain.includes("gcc") priority: 1 targetSystem: "freebsd" + (Host.os().includes("freebsd") ? FreeBSD.hostKernelRelease() : "") distributionIncludePaths: ["/usr/local/include"] distributionLibraryPaths: ["/usr/local/lib"] } qbs-src-2.6.1/share/qbs/modules/cpp/tvos-gcc.qbs0000644000175100001660000000416414776170045021032 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ DarwinGCC { priority: 1 condition: qbs.targetOS.includes('tvos') && qbs.toolchain && qbs.toolchain.includes('gcc') targetSystem: "tvos" + (minimumTvosVersion || "") minimumDarwinVersion: minimumTvosVersion minimumDarwinVersionCompilerFlag: qbs.targetOS.includes("tvos-simulator") ? "-mtvos-simulator-version-min" : "-mtvos-version-min" minimumDarwinVersionLinkerFlag: qbs.targetOS.includes("tvos-simulator") ? "-tvos_simulator_version_min" : "-tvos_version_min" } qbs-src-2.6.1/share/qbs/modules/cpp/dmc.qbs0000644000175100001660000001562514776170045020054 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.PathTools import qbs.Probes import qbs.Utilities import "dmc.js" as DMC import "cpp.js" as Cpp CppModule { condition: Host.os().includes("windows") && qbs.toolchain && qbs.toolchain.includes("dmc") Probes.BinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["dmc"] } Probes.DmcProbe { id: dmcProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage _targetPlatform: qbs.targetPlatform _targetArchitecture: qbs.architecture _targetExtender: extenderName } Properties { condition: dmcProbe.found qbs.architecture: dmcProbe.architecture qbs.targetPlatform: dmcProbe.targetPlatform } compilerVersionMajor: dmcProbe.versionMajor compilerVersionMinor: dmcProbe.versionMinor compilerVersionPatch: dmcProbe.versionPatch endianness: "little" compilerDefinesByLanguage: dmcProbe.compilerDefinesByLanguage compilerIncludePaths: dmcProbe.includePaths toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined /* Work-around for QtCreator which expects these properties to exist. */ property string cCompilerName: compilerName property string cxxCompilerName: compilerName compilerName: "dmc.exe" compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: "dmc.exe" assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName) linkerName: "link.exe" linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) property string archiverName: "lib.exe" property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName) property string rccCompilerName: "rcc.exe" property string rccCompilerPath: FileInfo.joinPaths(toolchainInstallPath, rccCompilerName) property string extenderName PropertyOptions { name: "extenderName" allowedValues: [undefined, "dosz", "dosr", "dosx", "dosp"] description: "Specifies the DOS memory extender to compile with:\n" + " - \"dosz\" is the ZPM 16 bit DOS Extender\n" + " - \"dosr\" is the Rational 16 bit DOS Extender\n" + " - \"dosx\" is the DOSX 32 bit DOS Extender\n" + " - \"dosp\" is the Pharlap 32 bit DOS Extender\n" ; } runtimeLibrary: "dynamic" staticLibrarySuffix: ".lib" dynamicLibrarySuffix: ".dll" executableSuffix: ".exe" objectSuffix: ".obj" imageFormat: { if (qbs.targetPlatform === "dos") return "mz"; else if (qbs.targetPlatform === "windows") return "pe"; } defineFlag: "-D" includeFlag: "-I" systemIncludeFlag: "-I" preincludeFlag: "-HI" libraryPathFlag: "-L/packcode" knownArchitectures: ["x86", "x86_16"] Rule { id: assembler inputs: ["asm"] outputFileTags: DMC.depsOutputTags().concat( Cpp.assemblerOutputTags(generateAssemblerListingFiles)) outputArtifacts: DMC.depsOutputArtifacts(input, product).concat( Cpp.assemblerOutputArtifacts(input)) prepare: DMC.prepareAssembler.apply(DMC, arguments) } FileTagger { patterns: ["*.s", "*.asm"] fileTags: ["asm"] } Rule { id: compiler inputs: ["cpp", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: DMC.depsOutputTags().concat( Cpp.compilerOutputTags(generateCompilerListingFiles)) outputArtifacts: DMC.depsOutputArtifacts(input, product).concat( Cpp.compilerOutputArtifacts(input)) prepare: DMC.prepareCompiler.apply(DMC, arguments) } Rule { id: rccCompiler inputs: ["rc"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.resourceCompilerOutputTags() outputArtifacts: Cpp.resourceCompilerOutputArtifacts(input) prepare: DMC.prepareRccCompiler.apply(DMC, arguments) } FileTagger { patterns: ["*.rc"] fileTags: ["rc"] } Rule { id: applicationLinker multiplex: true inputs: ["obj", "res", "linkerscript"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile) outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product) prepare: DMC.prepareLinker.apply(DMC, arguments) } Rule { id: dynamicLibraryLinker multiplex: true inputs: ["obj", "res"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: Cpp.dynamicLibraryLinkerOutputTags() outputArtifacts: Cpp.dynamicLibraryLinkerOutputArtifacts(product) prepare: DMC.prepareLinker.apply(DMC, arguments) } Rule { id: staticLibraryLinker multiplex: true inputs: ["obj"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: Cpp.staticLibraryLinkerOutputTags() outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product) prepare: DMC.prepareArchiver.apply(DMC, arguments) } } qbs-src-2.6.1/share/qbs/modules/cpp/CppModule.qbs0000644000175100001660000005471314776170045021202 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ // base for Cpp modules import qbs.FileInfo import qbs.ModUtils import qbs.Utilities import qbs.WindowsUtils import "cpp.js" as Cpp import "setuprunenv.js" as SetupRunEnv Module { condition: false Depends { name: "cpufeatures" } version: compilerVersion property string compilerVersion: [compilerVersionMajor, compilerVersionMinor, compilerVersionPatch].join(".") property int compilerVersionMajor property int compilerVersionMinor property int compilerVersionPatch property string warningLevel : 'all' // 'none', 'all' property bool treatWarningsAsErrors : false property bool enableSuspiciousLinkerFlagWarnings: true property string architecture: qbs.architecture property string endianness property string machineType // undocumented property string imageFormat // undocumented property string optimization: qbs.optimization property bool debugInformation: qbs.debugInformation property bool enableReproducibleBuilds: false property bool separateDebugInformation: false property pathList prefixHeaders property bool useCPrecompiledHeader: true property bool useCxxPrecompiledHeader: true property bool useObjcPrecompiledHeader: true property bool useObjcxxPrecompiledHeader: true property bool forceUseCxxModules: false property string moduleOutputFlag // undocumented property string moduleFileFlag // undocumented property bool treatSystemHeadersAsDependencies: false property stringList defines property stringList platformDefines: qbs.enableDebugCode ? [] : ["NDEBUG"] property stringList compilerDefines: compilerDefinesByLanguage ? ModUtils.flattenDictionary(compilerDefinesByLanguage["c"]) : [] property var compilerDefinesByLanguage: undefined PropertyOptions { name: "compilerDefinesByLanguage" description: "preprocessor macros that are defined when using this particular compiler" } property stringList enableCompilerDefinesByLanguage: [] property string windowsApiCharacterSet property string windowsApiFamily property stringList windowsApiAdditionalPartitions property bool requireAppContainer property string minimumWindowsVersion PropertyOptions { name: "minimumWindowsVersion" description: "A version number in the format [major].[minor] indicating the earliest \ version of Windows that the product should run on. Defines WINVER, \ _WIN32_WINNT, and _WIN32_WINDOWS, and applies a version number to the \ linker flags /SUBSYSTEM and /OSVERSION for MSVC or \ --major-subsystem-version, --minor-subsystem-version, \ --major-os-version and --minor-os-version for MinGW. \ If undefined, compiler defaults will be used." } property string minimumOsxVersion property string minimumMacosVersion: minimumOsxVersion PropertyOptions { name: "minimumMacosVersion" description: "a version number in the format [major].[minor] indicating the earliest \ version of macOS that the product should run on. passes -mmacosx-version-min= \ to the compiler. if undefined, compiler defaults will be used." } property string minimumIosVersion: qbs.architecture == "armv7a" ? "6.0" : undefined PropertyOptions { name: "minimumIosVersion" description: "a version number in the format [major].[minor] indicating the earliest \ version of iOS that the product should run on. passes -miphoneos-version-min= \ to the compiler. if undefined, compiler defaults will be used." } property string minimumWatchosVersion PropertyOptions { name: "minimumWatchosVersion" description: "a version number in the format [major].[minor] indicating the earliest \ version of watchOS that the product should run on. if undefined, compiler \ defaults will be used." } property string minimumTvosVersion: "6.0" PropertyOptions { name: "minimumTvosVersion" description: "a version number in the format [major].[minor] indicating the earliest \ version of tvOS that the product should run on. if undefined, compiler \ defaults will be used." } property string minimumAndroidVersion // not used, undocumented PropertyOptions { name: "minimumAndroidVersion" description: "a version number in the format [major].[minor] indicating the earliest \ version of Android that the product should run on. this value is converted into an SDK \ version which is then written to AndroidManifest.xml." } property string maximumAndroidVersion // not used, undocumented PropertyOptions { name: "maximumAndroidVersion" description: "a version number in the format [major].[minor] indicating the latest \ version of Android that the product should run on. this value is converted into an SDK \ version which is then written to AndroidManifest.xml. if undefined, no upper limit will \ be set." } property string toolchainInstallPath PropertyOptions { name: "toolchainInstallPath" description: "a path to the directory where the toolchain executable files are located." } property pathList includePaths property pathList systemIncludePaths property pathList distributionIncludePaths property pathList compilerIncludePaths property pathList libraryPaths property pathList distributionLibraryPaths property pathList compilerLibraryPaths property pathList frameworkPaths property pathList systemFrameworkPaths property pathList distributionFrameworkPaths property pathList compilerFrameworkPaths property stringList systemRunPaths: [] property string assemblerName property string assemblerPath: assemblerName property string compilerName property string compilerPath: compilerName property var compilerPathByLanguage property stringList compilerWrapper property string linkerName property string linkerPath: linkerName property stringList linkerWrapper property string staticLibraryPrefix: "" property string dynamicLibraryPrefix: "" property string loadableModulePrefix: "" property string executablePrefix: "" property string staticLibrarySuffix: "" property string dynamicLibrarySuffix: "" property string archSuffix: "" property string loadableModuleSuffix: "" property string executableSuffix: "" property string debugInfoSuffix: "" property string debugInfoBundleSuffix: "" property string variantSuffix: "" property string dynamicLibraryImportSuffix: ".lib" property string objectSuffix: ".o" property string linkerMapSuffix: ".map" property string compilerListingSuffix: ".lst" property string assemblerListingSuffix: ".lst" property string resourceSuffix: ".res" property string compiledModuleSuffix property string moduleMapSuffix: ".modulemap" property string moduleInfoSuffix: ".moduleinfo.json" property string precompiledHeaderSuffix property bool createSymlinks: true property stringList dynamicLibraries // list of names, will be linked with -lname property stringList staticLibraries // list of static library files property stringList frameworks // list of frameworks, will be linked with '-framework ' property stringList weakFrameworks // list of weakly-linked frameworks, will be linked with '-weak_framework ' property string rpathOrigin property stringList rpaths property string sonamePrefix: "" property bool useRPaths: true property bool useRPathLink property string rpathLinkFlag property bool discardUnusedData property bool removeDuplicateLibraries: true property string defineFlag property string includeFlag property string systemIncludeFlag property string preincludeFlag property string libraryDependencyFlag property string libraryPathFlag property string linkerScriptFlag property stringList knownArchitectures: [] property var toolchainDetails property string compilerExtension: FileInfo.executableSuffix() property string linkerMode: "automatic" PropertyOptions { name: "linkerMode" allowedValues: ["automatic", "manual"] description: "Controls whether to automatically use an appropriate compiler frontend " + "in place of the system linker when linking binaries. The default is \"automatic\", " + "which chooses either the C++ compiler, C compiler, or system linker specified by " + "the linkerName/linkerPath properties, depending on the type of object files " + "present on the linker command line. \"manual\" allows you to explicitly specify " + "the linker using the linkerName/linkerPath properties, and allows linker flags " + "passed to the linkerFlags and platformLinkerFlags properties to be escaped " + "manually (using -Wl or -Xlinker) instead of automatically based on the selected " + "linker." } property stringList assemblerFlags PropertyOptions { name: "assemblerFlags" description: "additional flags for the assembler" } property stringList cppFlags PropertyOptions { name: "cppFlags" description: "additional flags for the C preprocessor" } property stringList cFlags PropertyOptions { name: "cFlags" description: "additional flags for the C compiler" } property stringList cxxFlags PropertyOptions { name: "cxxFlags" description: "additional flags for the C++ compiler" } property stringList objcFlags PropertyOptions { name: "objcFlags" description: "additional flags for the Objective-C compiler" } property stringList objcxxFlags PropertyOptions { name: "objcxxFlags" description: "additional flags for the Objective-C++ compiler" } property stringList commonCompilerFlags PropertyOptions { name: "commonCompilerFlags" description: "flags added to all compilation independently of the language" } property stringList linkerFlags PropertyOptions { name: "linkerFlags" description: "additional linker flags" } property stringList driverFlags PropertyOptions { name: "driverFlags" description: "additional compiler driver flags" } property stringList driverLinkerFlags PropertyOptions { name: "driverLinkerFlags" description: "additional compiler driver flags used for linking only" } property bool generateLinkerMapFile: false PropertyOptions { name: "generateLinkerMapFile" description: "generate linker map file" } property bool generateCompilerListingFiles: false PropertyOptions { name: "generateCompilerListingFiles" description: "generate compiler listing files" } property bool generateAssemblerListingFiles: false PropertyOptions { name: "generateAssemblerListingFiles" description: "generate assembler listing files" } property bool positionIndependentCode: true PropertyOptions { name: "positionIndependentCode" description: "generate position independent code" } property string entryPoint PropertyOptions { name: "entryPoint" description: "entry point symbol for an executable or dynamic library" } property string runtimeLibrary PropertyOptions { name: "runtimeLibrary" description: "determine which runtime library to use" allowedValues: ['static', 'dynamic'] } property string visibility: 'default' PropertyOptions { name: "visibility" description: "export symbols visibility level" allowedValues: ['default', 'hidden', 'hiddenInlines', 'minimal'] } property stringList cLanguageVersion PropertyOptions { name: "cLanguageVersion" description: "The version of the C standard with which the code must comply." } property stringList cxxLanguageVersion PropertyOptions { name: "cxxLanguageVersion" description: "The version of the C++ standard with which the code must comply." } property bool useLanguageVersionFallback PropertyOptions { name: "useLanguageVersionFallback" description: "whether to explicitly use the language standard version fallback values in " + "compiler command line invocations" } property string cxxStandardLibrary PropertyOptions { name: "cxxStandardLibrary" allowedValues: ["libstdc++", "libc++"] description: "version of the C++ standard library to use" } property bool enableExceptions: true PropertyOptions { name: "enableExceptions" description: "enable/disable exception handling (enabled by default)" } property string exceptionHandlingModel: "default" PropertyOptions { name: "exceptionHandlingModel" description: "the kind of exception handling to be used by the compiler" } 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 property stringList platformCommonCompilerFlags property stringList platformCFlags property stringList platformCxxFlags property stringList platformObjcFlags property stringList platformObjcxxFlags property stringList platformLinkerFlags property stringList platformDriverFlags // Apple platforms properties property bool automaticReferenceCounting PropertyOptions { name: "automaticReferenceCounting" description: "whether to enable Automatic Reference Counting (ARC) for Objective-C" } property bool requireAppExtensionSafeApi PropertyOptions { name: "requireAppExtensionSafeApi" description: "whether to require app-extension-safe APIs only" } property bool allowUnresolvedSymbols property bool combineCSources: false property bool combineCxxSources: false property bool combineObjcSources: false property bool combineObjcxxSources: false // Those are set internally by different cpp module implementations property stringList targetAssemblerFlags property stringList targetDriverFlags property stringList targetLinkerFlags property bool _skipAllChecks: false // Internal property bool validateTargetTriple: true // undocumented property bool importPrivateLibraries: true // TODO: The following four rules could use a convenience base item if rule properties // were available in Artifact items and prepare scripts. Rule { multiplex: true inputs: ["c.combine"] Artifact { filePath: "amalgamated_" + product.targetName + ".c" fileTags: ["c"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { ModUtils.mergeCFiles(inputs["c.combine"], output.filePath); }; return [cmd]; } } Rule { multiplex: true inputs: ["cpp.combine"] Artifact { filePath: "amalgamated_" + product.targetName + ".cpp" fileTags: ["cpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { ModUtils.mergeCFiles(inputs["cpp.combine"], output.filePath); }; return [cmd]; } } Rule { multiplex: true inputs: ["objc.combine"] Artifact { filePath: "amalgamated_" + product.targetName + ".m" fileTags: ["objc"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { ModUtils.mergeCFiles(inputs["objc.combine"], output.filePath); }; return [cmd]; } } Rule { multiplex: true inputs: ["objcpp.combine"] Artifact { filePath: "amalgamated_" + product.targetName + ".mm" fileTags: ["objccpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { ModUtils.mergeCFiles(inputs["objcpp.combine"], output.filePath); }; return [cmd]; } } FileTagger { patterns: ["*.c"] fileTags: combineCSources ? ["c.combine"] : ["c"] } FileTagger { patterns: ["*.C", "*.cpp", "*.cxx", "*.c++", "*.cc"] fileTags: combineCxxSources ? ["cpp.combine"] : ["cpp"] } FileTagger { patterns: ["*.cppm", "*.ixx"] fileTags: ["cppm"] } FileTagger { patterns: ["*.m"] fileTags: combineObjcSources ? ["objc.combine"] : ["objc"] } FileTagger { patterns: ["*.mm"] fileTags: combineObjcxxSources ? ["objcpp.combine"] : ["objcpp"] } FileTagger { patterns: ["*.h", "*.H", "*.hpp", "*.hxx", "*.h++"] fileTags: ["hpp"] } property var validateFunc: { return function() { var validator = new ModUtils.PropertyValidator("cpp"); validator.setRequiredProperty("architecture", architecture, "you might want to re-run 'qbs-setup-toolchains'"); validator.addCustomValidator("architecture", architecture, function (value) { return !architecture || architecture === Utilities.canonicalArchitecture(architecture); }, "'" + architecture + "' is invalid. You must use the canonical name '" + Utilities.canonicalArchitecture(architecture) + "'"); validator.setRequiredProperty("endianness", endianness); validator.setRequiredProperty("compilerDefinesByLanguage", compilerDefinesByLanguage); validator.setRequiredProperty("compilerVersion", compilerVersion); validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor); validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor); validator.setRequiredProperty("compilerVersionPatch", compilerVersionPatch); validator.addVersionValidator("compilerVersion", compilerVersion, 3, 3); validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1); validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0); validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0); if (minimumWindowsVersion) { validator.addVersionValidator("minimumWindowsVersion", minimumWindowsVersion, 2, 2); validator.addCustomValidator("minimumWindowsVersion", minimumWindowsVersion, function (v) { return !v || v === WindowsUtils.canonicalizeVersion(v); }, "'" + minimumWindowsVersion + "' is invalid. Did you mean '" + WindowsUtils.canonicalizeVersion(minimumWindowsVersion) + "'?"); } validator.validate(); if (minimumWindowsVersion && !WindowsUtils.isValidWindowsVersion(minimumWindowsVersion)) { console.warn("Unknown Windows version '" + minimumWindowsVersion + "'; expected one of: " + WindowsUtils.knownWindowsVersions().map(function (a) { return '"' + a + '"'; }).join(", ") + ". See https://docs.microsoft.com/en-us/windows/desktop/SysInfo/operating-system-version"); } if (knownArchitectures && knownArchitectures.length > 0) { var isSupported = Cpp.supportsArchitecture(qbs.architecture, knownArchitectures); if (!isSupported) { throw ModUtils.ModuleError("Unsupported architecture: '" + qbs.architecture + "'"); } } } } validate: { return validateFunc(); } setupRunEnvironment: { SetupRunEnv.setupRunEnvironment(product, config); } Parameter { property bool link } Parameter { property bool linkWholeArchive } Parameter { property string symbolLinkMode } } qbs-src-2.6.1/share/qbs/modules/cpp/qnx-qcc.qbs0000644000175100001660000000710114776170045020651 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo UnixGCC { Depends { name: "qnx" } condition: qbs.targetOS.includes("qnx") && qbs.toolchain && qbs.toolchain.includes("qcc") priority: 1 distributionIncludePaths: FileInfo.joinPaths(qnx.targetDir, "usr", "include") toolchainInstallPath: FileInfo.joinPaths(qnx.hostDir, "usr", "bin") sysroot: qnx.targetDir sysrootFlags: sysroot ? [systemIncludeFlag + FileInfo.joinPaths(sysroot, "usr", "include")] : [] cCompilerName: "qcc" + compilerExtension cxxCompilerName: (qnx.qnx7 ? "q++" : "QCC") + compilerExtension targetDriverFlags: qnxTarget ? ["-V" + qnxTarget] : [] systemIncludeFlag: !qnx.qnx7 ? includeFlag : base property string qnxTarget: qbs.architecture ? qnx.compilerName + "_" + targetSystem + qnxTargetArchName : undefined property string qnxTargetArchName: { switch (qbs.architecture) { case "arm64": return "aarch64le"; case "armv7a": return "armv7le"; case "x86": case "x86_64": return qbs.architecture; } } // QNX doesn't support Objective-C or Objective-C++ and qcc/q++ don't use toolchainPrefix compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) compilerPathByLanguage: ({ "c": FileInfo.joinPaths(toolchainInstallPath, cCompilerName), "cpp": FileInfo.joinPaths(toolchainInstallPath, cxxCompilerName), "objc": undefined, "objcpp": undefined, "asm_cpp": FileInfo.joinPaths(toolchainInstallPath, cCompilerName) }) toolchainPrefix: target + "-" targetVendor: ["x86", "x86_64"].includes(qbs.architecture) ? "pc" : base targetSystem: "nto" targetAbi: "qnx" + qnx.version + (qnxTargetArchName === "armv7le" ? "eabi" : "") buildEnv: qnx.buildEnv probeEnv: buildEnv setupBuildEnvironment: { for (var key in product.cpp.buildEnv) { v = new ModUtils.EnvironmentVariable(key); v.value = product.cpp.buildEnv[key]; v.set(); } } } qbs-src-2.6.1/share/qbs/modules/cpp/iar.qbs0000644000175100001660000001332314776170045020055 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.PathTools import qbs.Probes import qbs.Utilities import "cpp.js" as Cpp import "iar.js" as IAR CppModule { condition: qbs.toolchain && qbs.toolchain.includes("iar") Probes.BinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["iccarm"] } Probes.IarProbe { id: iarProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage } Properties { condition: iarProbe.found qbs.architecture: iarProbe.architecture } qbs.targetPlatform: "none" compilerVersionMajor: iarProbe.versionMajor compilerVersionMinor: iarProbe.versionMinor compilerVersionPatch: iarProbe.versionPatch endianness: iarProbe.endianness compilerDefinesByLanguage: iarProbe.compilerDefinesByLanguage compilerIncludePaths: iarProbe.includePaths toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined /* Work-around for QtCreator which expects these properties to exist. */ property string cCompilerName: compilerName property string cxxCompilerName: compilerName compilerName: toolchainDetails.compilerName + compilerExtension compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: toolchainDetails.assemblerName + compilerExtension assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName) linkerName: toolchainDetails.linkerName + compilerExtension linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) property string archiverName: toolchainDetails.archiverName + compilerExtension property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName) runtimeLibrary: "static" staticLibrarySuffix: toolchainDetails.staticLibrarySuffix executableSuffix: toolchainDetails.executableSuffix objectSuffix: toolchainDetails.objectSuffix imageFormat: toolchainDetails.imageFormat enableExceptions: false enableRtti: false defineFlag: "-D" includeFlag: "-I" systemIncludeFlag: "-I" preincludeFlag: "--preinclude" libraryDependencyFlag: "" libraryPathFlag: toolchainDetails.libraryPathFlag linkerScriptFlag: toolchainDetails.linkerScriptFlag property string linkerSilentFlag: toolchainDetails.linkerSilentFlag property string linkerMapFileFlag: toolchainDetails.linkerMapFileFlag property string linkerEntryPointFlag: toolchainDetails.linkerEntryPointFlag toolchainDetails: IAR.toolchainDetails(qbs) knownArchitectures: ["78k", "arm", "avr", "avr32", "cr16", "hcs12", "hcs8", "m16c", "m32c", "m68k", "mcs51", "msp430", "r32c", "rh850", "riscv", "rl78", "rx", "sh", "stm8", "v850"] Rule { id: assembler inputs: ["asm"] outputFileTags: Cpp.assemblerOutputTags(generateAssemblerListingFiles) outputArtifacts: Cpp.assemblerOutputArtifacts(input) prepare: IAR.prepareAssembler.apply(IAR, arguments) } FileTagger { patterns: ["*.s", "*.s43", "*.s51", "*.s90", "*.msa", "*.asm"] fileTags: ["asm"] } Rule { id: compiler inputs: ["cpp", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.compilerOutputTags(generateCompilerListingFiles) outputArtifacts: Cpp.compilerOutputArtifacts(input) prepare: IAR.prepareCompiler.apply(IAR, arguments) } Rule { id: applicationLinker multiplex: true inputs: ["obj", "linkerscript"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile) outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product) prepare: IAR.prepareLinker.apply(IAR, arguments) } Rule { id: staticLibraryLinker multiplex: true inputs: ["obj"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.staticLibraryLinkerOutputTags() outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product) prepare: IAR.prepareArchiver.apply(IAR, arguments) } } qbs-src-2.6.1/share/qbs/modules/cpp/darwin.js0000644000175100001660000002074614776170045020424 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Codesign = require("../codesign/codesign.js"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Gcc = require("./gcc.js"); var ModUtils = require("qbs.ModUtils"); var PathTools = require("qbs.PathTools"); function lipoOutputArtifacts(product, inputs, fileTag, debugSuffix) { var buildVariants = []; for (var i = 0; i < inputs[fileTag].length; ++i) { var variant = inputs[fileTag][i].qbs.buildVariant; var suffix = inputs[fileTag][i].cpp.variantSuffix; if (!buildVariants.some(function (x) { return x.name === variant; })) buildVariants.push({ name: variant, suffix: suffix }); } var list = []; if (fileTag === "dynamiclibrary") { Array.prototype.push.apply(list, buildVariants.map(function (variant) { return { filePath: product.destinationDirectory + "/.sosymbols/" + PathTools.dynamicLibraryFilePath(product, variant.suffix), fileTags: ["dynamiclibrary_symbols"], qbs: { buildVariant: variant.name }, cpp: { variantSuffix: variant.suffix }, alwaysUpdated: false }; })); buildVariants.forEach(function (variant) { Array.prototype.push.apply(list, Gcc.librarySymlinkArtifacts(product, variant.suffix)); }); } // Bundles should have a "normal" variant. In the case of frameworks, they cannot normally be // linked to without a default variant unless a variant is specifically chosen at link time // by passing the full path to the shared library executable instead of the -framework switch. // Technically this doesn't affect qbs since qbs always uses full paths for internal // dependencies but the "normal" variant is always the one that is linked to, since the // alternative variants should only be chosen at runtime using the DYLD_IMAGE_SUFFIX variable. // So for frameworks we'll create a symlink to the "default" variant as chosen by the user // (we cannot do this automatically since the user must tell us which variant should be // preferred, if there are multiple alternative variants). Applications are fine without a // symlink but still need an explicitly chosen variant to set as the CFBundleExecutable so that // Finder/LaunchServices can launch it normally but for simplicity we'll just use the symlink // approach for all bundle types. var defaultVariant; if (!buildVariants.some(function (x) { return x.name === "release"; }) && product.multiplexByQbsProperties.includes("buildVariants") && product.qbs.buildVariants && product.qbs.buildVariants.length > 1) { var defaultBuildVariant = product.qbs.defaultBuildVariant; buildVariants.map(function (variant) { if (variant.name === defaultBuildVariant) defaultVariant = variant; }); if (!defaultVariant) { throw new Error("qbs.defaultBuildVariant is '" + defaultBuildVariant + "', but this " + "variant is not in the qbs.buildVariants list (" + product.qbs.buildVariants.join(", ") + ")"); } buildVariants.push({ name: "release", suffix: "", isSymLink: true }); } Array.prototype.push.apply(list, buildVariants.map(function (variant) { var tags = ["bundle.input"]; if (variant.isSymLink) tags.push("bundle.variant_symlink"); else tags.push(fileTag, "primary"); if (product.codesign.enableCodeSigning) tags.push("codesign.signed_artifact"); return { filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.linkerOutputFilePath(fileTag, product, variant.suffix)), fileTags: tags, qbs: { buildVariant: variant.name, _buildVariantFileName: variant.isSymLink && defaultVariant ? FileInfo.fileName(PathTools.linkerOutputFilePath( fileTag, product, defaultVariant.suffix)) : undefined }, bundle: { _bundleFilePath: product.destinationDirectory + "/" + PathTools.bundleExecutableFilePath(product, variant.suffix) }, cpp: { variantSuffix: variant.suffix } }; })); if (debugSuffix) Array.prototype.push.apply(list, Gcc.debugInfoArtifacts(product, buildVariants, debugSuffix)); return list; } function prepareLipo(project, product, inputs, outputs, input, output) { var cmd; var commands = []; for (var p in inputs) inputs[p] = inputs[p].filter(function(inp) { return inp.product.name === product.name; }); var allInputs = [].concat.apply([], Object.keys(inputs).map(function (tag) { return ["application", "dynamiclibrary", "staticlibrary", "loadablemodule"].includes(tag) ? inputs[tag] : []; })); (outputs["bundle.variant_symlink"] || []).map(function (symlink) { cmd = new Command("ln", ["-sfn", symlink.qbs._buildVariantFileName, symlink.filePath]); cmd.silent = true; commands.push(cmd); }); for (var i = 0; i < outputs.primary.length; ++i) { var vInputs = allInputs.filter(function (f) { return f.qbs.buildVariant === outputs.primary[i].qbs.buildVariant }).map(function (f) { return f.filePath }); if (vInputs.length > 1 || product.cpp.alwaysUseLipo) { cmd = new Command(ModUtils.moduleProperty(product, "lipoPath"), ["-create", "-output", outputs.primary[i].filePath].concat(vInputs)); cmd.description = "lipo " + outputs.primary[i].fileName; cmd.highlight = "linker"; } else { cmd = new JavaScriptCommand(); cmd.src = vInputs[0]; cmd.dst = outputs.primary[i].filePath; cmd.sourceCode = function () { File.copy(src, dst); }; cmd.silent = true; } Array.prototype.push.apply(commands, Gcc.librarySymlinkCommands(outputs, outputs.primary[i])); commands.push(cmd); } commands = commands.concat( Gcc.separateDebugInfoCommandsDarwin(product, outputs, outputs.primary)); if (outputs.dynamiclibrary_symbols) Array.prototype.push.apply(commands, Gcc.createSymbolCheckingCommands(product, outputs)); if (product.codesign.enableCodeSigning) { Array.prototype.push.apply( commands, Codesign.prepareSign(project, product, inputs, outputs, input, output)); } return commands; } qbs-src-2.6.1/share/qbs/modules/cpp/GenericGCC.qbs0000644000175100001660000006422614776170045021203 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.PathTools import qbs.Probes import qbs.Process import qbs.TextFile import qbs.Utilities import qbs.UnixUtils import qbs.WindowsUtils import 'cpp.js' as Cpp import 'gcc.js' as Gcc CppModule { condition: qbs.toolchain && qbs.toolchain.includes("gcc") priority: -100 Depends { name: "codesign" } Probes.GccBinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks _compilerName: compilerName _toolchainPrefix: toolchainPrefix } // Find the version as early as possible in case other things depend on it, // for example the question of whether certain flags are supported and which need to be used // in the GccProbe itself. Probes.GccVersionProbe { id: gccVersionProbe compilerFilePath: compilerPath environment: probeEnv } Probes.GccProbe { id: gccProbe condition: !_skipAllChecks compilerFilePathByLanguage: compilerPathByLanguage enableDefinesByLanguage: enableCompilerDefinesByLanguage environment: probeEnv flags: targetDriverFlags.concat(sysrootFlags) _sysroot: sysroot } property var probeEnv Probes.BinaryProbe { id: binutilsProbe condition: !File.exists(archiverPath) && !_skipAllChecks names: Gcc.toolNames([archiverName, assemblerName, linkerName, nmName, objcopyName, stripName], toolchainPrefix) } targetLinkerFlags: Gcc.targetFlags("linker", false, target, targetArch, machineType, qbs.targetOS) targetAssemblerFlags: Gcc.targetFlags("assembler", assemblerHasTargetOption, target, targetArch, machineType, qbs.targetOS) targetDriverFlags: Gcc.targetFlags("compiler", compilerHasTargetOption, target, targetArch, machineType, qbs.targetOS) Probe { id: nmProbe condition: !_skipAllChecks property string theNmPath: nmPath property bool hasDynamicOption configure: { var proc = new Process(); try { hasDynamicOption = proc.exec(theNmPath, ["-D", theNmPath], false) == 0; console.debug("nm has -D: " + hasDynamicOption); } finally { proc.close(); } } } Properties { condition: gccProbe.found qbs.architecture: gccProbe.architecture } endianness: gccProbe.endianness compilerDefinesByLanguage: gccProbe.compilerDefinesByLanguage compilerVersionMajor: gccVersionProbe.versionMajor compilerVersionMinor: gccVersionProbe.versionMinor compilerVersionPatch: gccVersionProbe.versionPatch compilerIncludePaths: gccProbe.includePaths compilerFrameworkPaths: gccProbe.frameworkPaths compilerLibraryPaths: gccProbe.libraryPaths staticLibraryPrefix: "lib" staticLibrarySuffix: ".a" precompiledHeaderSuffix: ".gch" property bool compilerHasTargetOption: qbs.toolchain.includes("clang") && Utilities.versionCompare(compilerVersion, "3.1") >= 0 property bool assemblerHasTargetOption: qbs.toolchain.includes("xcode") && Utilities.versionCompare(compilerVersion, "7") >= 0 property string target: targetArch ? [targetArch, targetVendor, targetSystem, targetAbi].join("-") : undefined property string targetArch: Utilities.canonicalTargetArchitecture( qbs.architecture, endianness, targetVendor, targetSystem, targetAbi) property string targetVendor: "unknown" property string targetSystem: "unknown" property string targetAbi: "unknown" property string toolchainPrefix: compilerPathProbe.found ? compilerPathProbe.tcPrefix : undefined toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined property string binutilsPath: binutilsProbe.found ? binutilsProbe.path : toolchainInstallPath assemblerName: 'as' + compilerExtension compilerName: cxxCompilerName linkerName: 'ld' + compilerExtension property string archiverName: 'ar' + compilerExtension property string nmName: 'nm' + compilerExtension property string objcopyName: "objcopy" + compilerExtension property string stripName: "strip" + compilerExtension property string dsymutilName: "dsymutil" + compilerExtension property string lipoName property string sysroot: qbs.sysroot property string syslibroot: sysroot property stringList sysrootFlags: sysroot ? ["--sysroot=" + sysroot] : [] property string exportedSymbolsCheckMode: "ignore-undefined" PropertyOptions { name: "exportedSymbolsCheckMode" allowedValues: ["strict", "ignore-undefined"] description: "Controls when we consider an updated dynamic library as changed with " + "regards to other binaries depending on it. The default is \"ignore-undefined\", " + "which means we do not care about undefined symbols being added or removed. " + "If you do care about that, e.g. because you link dependent products with an option " + "such as \"--no-undefined\", then you should set this property to \"strict\"." } property string linkerVariant PropertyOptions { name: "linkerVariant" allowedValues: ["bfd", "gold", "lld", "mold"] description: "Allows to specify the linker variant. Maps to gcc's and clang's -fuse-ld " + "option." } Properties { condition: linkerVariant driverLinkerFlags: "-fuse-ld=" + linkerVariant } property string toolchainPathPrefix: Gcc.pathPrefix(toolchainInstallPath, toolchainPrefix) property string binutilsPathPrefix: Gcc.pathPrefix(binutilsPath, toolchainPrefix) property string cCompilerName: (qbs.toolchain.includes("clang") ? "clang" : "gcc") + compilerExtension property string cxxCompilerName: (qbs.toolchain.includes("clang") ? "clang++" : "g++") + compilerExtension compilerPathByLanguage: ({ "c": toolchainPathPrefix + cCompilerName, "cpp": toolchainPathPrefix + cxxCompilerName, "cppm": toolchainPathPrefix + cxxCompilerName, "objc": toolchainPathPrefix + cCompilerName, "objcpp": toolchainPathPrefix + cxxCompilerName, "asm_cpp": toolchainPathPrefix + cCompilerName }) assemblerPath: binutilsPathPrefix + assemblerName compilerPath: toolchainPathPrefix + compilerName linkerPath: binutilsPathPrefix + linkerName property string archiverPath: binutilsPathPrefix + archiverName property string nmPath: binutilsPathPrefix + nmName property bool _nmHasDynamicOption: nmProbe.hasDynamicOption property string objcopyPath: binutilsPathPrefix + objcopyName property string stripPath: binutilsPathPrefix + stripName property string dsymutilPath: toolchainPathPrefix + dsymutilName property string lipoPath property stringList dsymutilFlags property bool alwaysUseLipo: false defineFlag: "-D" includeFlag: "-I" systemIncludeFlag: "-isystem" preincludeFlag: "-include" libraryPathFlag: "-L" linkerScriptFlag: "-T" readonly property bool shouldCreateSymlinks: { return createSymlinks && internalVersion && ["macho", "elf"].includes(imageFormat); } readonly property bool shouldSignArtifacts: codesign._canSignArtifacts && codesign.enableCodeSigning // codesigning is done during the lipo step && !product.multiplexed property string internalVersion: { if (product.version === undefined) return undefined; var coreVersion = product.version.match("^([0-9]+\.){0,3}[0-9]+"); if (!coreVersion) return undefined; var maxVersionParts = 3; var versionParts = coreVersion[0].split('.').slice(0, maxVersionParts); // pad if necessary for (var i = versionParts.length; i < maxVersionParts; ++i) versionParts.push("0"); return versionParts.join('.'); } property string soVersion: { if (!internalVersion) return ""; return internalVersion.split('.')[0]; } property var buildEnv: { var env = {}; if (qbs.toolchain.includes("mingw")) env.PATH = toolchainInstallPath; // For libwinpthread etc return env; } compiledModuleSuffix: qbs.toolchain.includes("clang") ? ".pcm" : ".gcm" moduleOutputFlag: qbs.toolchain.includes("clang") ? "-fmodule-output=" : "%module% " moduleFileFlag: qbs.toolchain.includes("clang") ? "-fmodule-file=%module%=" : "%module% " exceptionHandlingModel: { if (qbs.toolchain.includes("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 (!Host.os().includes("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: { if (_skipAllChecks) return; if (!File.exists(compilerPath)) { var pathMessage = FileInfo.isAbsolutePath(compilerPath) ? "at '" + compilerPath + "'" : "'" + compilerPath + "' in PATH"; throw ModUtils.ModuleError("Could not find selected C++ compiler " + pathMessage + ". " + "Ensure that the compiler is properly " + "installed, or set cpp.toolchainInstallPath to a valid " + "toolchain path, or consider whether you meant to set " + "cpp.compilerName instead."); } var isWrongTriple = false; if (gccProbe.architecture) { if (Utilities.canonicalArchitecture(architecture) !== Utilities.canonicalArchitecture(gccProbe.architecture)) isWrongTriple = true; } else if (architecture) { // This is a warning and not an error on the rare chance some new architecture comes // about which qbs does not know about the macros of. But it *might* still work. console.warn("Unknown architecture '" + architecture + "' " + "may not be supported by this compiler."); } if (gccProbe.endianness) { if (endianness !== gccProbe.endianness) isWrongTriple = true; } else if (endianness) { console.warn("Could not detect endianness ('" + endianness + "' given)"); } if (gccProbe.targetPlatform) { // Can't differentiate Darwin OSes at the compiler level alone if (gccProbe.targetPlatform === "darwin" ? !qbs.targetOS.includes("darwin") : qbs.targetPlatform !== gccProbe.targetPlatform) isWrongTriple = true; } else if (qbs.targetPlatform) { console.warn("Could not detect target platform ('" + qbs.targetPlatform + "' given)"); } if (isWrongTriple) { var realTriple = [ Utilities.canonicalArchitecture(gccProbe.architecture), gccProbe.targetPlatform, gccProbe.endianness ? gccProbe.endianness + "-endian" : undefined ].join("-"); var givenTriple = [ Utilities.canonicalArchitecture(architecture), qbs.targetPlatform, endianness ? endianness + "-endian" : undefined ].join("-"); var msg = "The selected compiler '" + compilerPath + "' produces code for '" + realTriple + "', but '" + givenTriple + "' was given, which is incompatible."; if (validateTargetTriple) { msg += " If you are absolutely certain that your configuration is correct " + "(check the values of the qbs.architecture, qbs.targetPlatform, " + "and qbs.endianness properties) and that this message has been " + "emitted in error, set the cpp.validateTargetTriple property to " + "false. However, you should consider submitting a bug report in any " + "case."; throw ModUtils.ModuleError(msg); } else { console.warn(msg); } } var validateFlagsFunction = function (value) { if (value) { for (var i = 0; i < value.length; ++i) { if (["-target", "-triple", "-arch"].includes(value[i])) return false; } } return true; } var validator = new ModUtils.PropertyValidator("cpp"); var msg = "'-target', '-triple' and '-arch' cannot appear in flags; set qbs.architecture instead"; validator.addCustomValidator("assemblerFlags", assemblerFlags, validateFlagsFunction, msg); validator.addCustomValidator("cppFlags", cppFlags, validateFlagsFunction, msg); validator.addCustomValidator("cFlags", cFlags, validateFlagsFunction, msg); validator.addCustomValidator("cxxFlags", cxxFlags, validateFlagsFunction, msg); validator.addCustomValidator("objcFlags", objcFlags, validateFlagsFunction, msg); validator.addCustomValidator("objcxxFlags", objcxxFlags, validateFlagsFunction, msg); validator.addCustomValidator("commonCompilerFlags", commonCompilerFlags, validateFlagsFunction, msg); validator.addCustomValidator("platformAssemblerFlags", platformAssemblerFlags, validateFlagsFunction, msg); //validator.addCustomValidator("platformCppFlags", platformCppFlags, validateFlagsFunction, msg); validator.addCustomValidator("platformCFlags", platformCFlags, validateFlagsFunction, msg); validator.addCustomValidator("platformCxxFlags", platformCxxFlags, validateFlagsFunction, msg); validator.addCustomValidator("platformObjcFlags", platformObjcFlags, validateFlagsFunction, msg); validator.addCustomValidator("platformObjcxxFlags", platformObjcxxFlags, validateFlagsFunction, msg); validator.addCustomValidator("platformCommonCompilerFlags", platformCommonCompilerFlags, validateFlagsFunction, msg); validator.setRequiredProperty("compilerVersion", compilerVersion); validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor); validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor); validator.setRequiredProperty("compilerVersionPatch", compilerVersionPatch); validator.addVersionValidator("compilerVersion", compilerVersion, 3, 3); validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1); validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0); validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0); validator.setRequiredProperty("compilerIncludePaths", compilerIncludePaths); validator.setRequiredProperty("compilerFrameworkPaths", compilerFrameworkPaths); validator.setRequiredProperty("compilerLibraryPaths", compilerLibraryPaths); validator.validate(); } // Product should be linked if it's not multiplexed or aggregated at all, // or if it is multiplexed, if it's not the aggregate product readonly property bool shouldLink: !(product.multiplexed || product.aggregate) || product.multiplexConfigurationId Group { condition: shouldLink Rule { name: "dynamicLibraryLinker" multiplex: true inputs: { var tags = ["obj", "res", "linkerscript", "versionscript"]; if (product.bundle && product.bundle.embedInfoPlist && product.qbs.targetOS.includes("darwin")) { tags.push("aggregate_infoplist"); } return tags; } inputsFromDependencies: ["dynamiclibrary_symbols", "staticlibrary", "dynamiclibrary_import"] outputFileTags: { var tags = ["bundle.input", "dynamiclibrary", "dynamiclibrary_symlink", "dynamiclibrary_symbols", "debuginfo_dll", "debuginfo_bundle", "dynamiclibrary_import", "debuginfo_plist"]; if (product.cpp.shouldSignArtifacts) tags.push("codesign.signed_artifact"); return tags; } outputArtifacts: Gcc.dynamicLibLinkerOutputArtifacts(product) prepare: Gcc.prepareLinker.apply(Gcc, arguments) } Rule { name: "staticLibraryLinker" multiplex: true inputs: ["obj", "res", "linkerscript"] inputsFromDependencies: ["dynamiclibrary_symbols", "dynamiclibrary_import", "staticlibrary"] outputFileTags: ["bundle.input", "staticlibrary", "c_staticlibrary", "cpp_staticlibrary"] outputArtifacts: Gcc.staticLibLinkerOutputArtifacts(product, inputs) prepare: Gcc.staticLibLinkerCommands.apply(Gcc, arguments) } Rule { name: "loadableModuleLinker" multiplex: true inputs: { var tags = ["obj", "res", "linkerscript"]; if (product.bundle && product.bundle.embedInfoPlist && product.qbs.targetOS.includes("darwin")) { tags.push("aggregate_infoplist"); } return tags; } inputsFromDependencies: ["dynamiclibrary_symbols", "dynamiclibrary_import", "staticlibrary"] outputFileTags: { var tags = ["bundle.input", "loadablemodule", "debuginfo_loadablemodule", "debuginfo_bundle", "debuginfo_plist"]; if (product.cpp.shouldSignArtifacts) tags.push("codesign.signed_artifact"); return tags; } outputArtifacts: Gcc.moduleLinkerOutputArtifacts(product) prepare: Gcc.prepareLinker.apply(Gcc, arguments) } Rule { name: "applicationLinker" multiplex: true inputs: { var tags = ["obj", "res", "linkerscript"]; if (product.bundle && product.bundle.embedInfoPlist && product.qbs.targetOS.includes("darwin")) { tags.push("aggregate_infoplist"); } return tags; } inputsFromDependencies: ["dynamiclibrary_symbols", "dynamiclibrary_import", "staticlibrary"] outputFileTags: { var tags = ["bundle.input", "application", "debuginfo_app", "debuginfo_bundle", "debuginfo_plist"]; if (product.cpp.shouldSignArtifacts) tags.push("codesign.signed_artifact"); if (product.cpp.generateLinkerMapFile) tags.push("mem_map"); if(product.qbs.toolchain.includes("emscripten")) tags.push("wasm") return tags; } outputArtifacts: Gcc.appLinkerOutputArtifacts(product) prepare: Gcc.prepareLinker.apply(Gcc, arguments) } } Rule { name: "cpp_compiler" inputs: ["cpp", "cppm", "c", "objcpp", "objc", "asm_cpp"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] explicitlyDependsOn: ["c_pch", "cpp_pch", "objc_pch", "objcpp_pch"] outputFileTags: Cpp.compilerOutputTags(/*withListingFiles*/ false, /*withCxxModules*/ true) .concat(["c_obj", "cpp_obj"]) outputArtifacts: Cpp.compilerOutputArtifacts(input, inputs, /*withCxxModules*/ true) prepare: Gcc.prepareCompiler.apply(Gcc, arguments) } Rule { name: "assembler" inputs: ["asm"] outputFileTags: Cpp.assemblerOutputTags(false) outputArtifacts: Cpp.assemblerOutputArtifacts(input) prepare: Gcc.prepareAssembler.apply(Gcc, arguments) } Rule { condition: useCPrecompiledHeader inputs: ["c_pch_src"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.precompiledHeaderOutputTags("c", false) outputArtifacts: Cpp.precompiledHeaderOutputArtifacts(input, product, "c", false) prepare: Gcc.prepareCompiler.apply(Gcc, arguments) } Rule { condition: useCxxPrecompiledHeader inputs: ["cpp_pch_src"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.precompiledHeaderOutputTags("cpp", false) outputArtifacts: Cpp.precompiledHeaderOutputArtifacts(input, product, "cpp", false) prepare: Gcc.prepareCompiler.apply(Gcc, arguments) } Rule { condition: useObjcPrecompiledHeader inputs: ["objc_pch_src"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.precompiledHeaderOutputTags("objc", false) outputArtifacts: Cpp.precompiledHeaderOutputArtifacts(input, product, "objc", false) prepare: Gcc.prepareCompiler.apply(Gcc, arguments) } Rule { condition: useObjcxxPrecompiledHeader inputs: ["objcpp_pch_src"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.precompiledHeaderOutputTags("objcpp", false) outputArtifacts: Cpp.precompiledHeaderOutputArtifacts(input, product, "objcpp", false) prepare: Gcc.prepareCompiler.apply(Gcc, arguments) } FileTagger { patterns: "*.s" fileTags: ["asm"] } FileTagger { patterns: "*.S" fileTags: ["asm_cpp"] } FileTagger { patterns: "*.sx" fileTags: ["asm_cpp"] } Scanner { inputs: ["linkerscript"] recursive: true scan: { console.debug("scanning linkerscript " + filePath + " for dependencies"); var retval = []; var linkerScript = new TextFile(filePath, TextFile.ReadOnly); var regexp = /[\s]*INCLUDE[\s]+(\S+).*/ // "INCLUDE filename" var match; while (!linkerScript.atEof()) { match = regexp.exec(linkerScript.readLine()); if (match) { var dependencyFileName = match[1]; retval.push(dependencyFileName); console.debug("linkerscript " + filePath + " depends on " + dependencyFileName); } } linkerScript.close(); return retval; } searchPaths: { var retval = []; for (var i = 0; i < (product.cpp.libraryPaths || []).length; i++) retval.push(product.cpp.libraryPaths[i]); var regexp = /[\s]*SEARCH_DIR\((\S+)\).*/ // "SEARCH_DIR(path)" var match; var linkerScript = new TextFile(input.filePath, TextFile.ReadOnly); while (!linkerScript.atEof()) { match = regexp.exec(linkerScript.readLine()); if(match) { var additionalPath = match[1]; // path can be quoted to use non-latin letters, remove quotes if present if (additionalPath.startsWith("\"") && additionalPath.endsWith("\"")) additionalPath = additionalPath.slice(1, additionalPath.length - 1); retval.push(additionalPath); } } linkerScript.close(); return retval; } } } qbs-src-2.6.1/share/qbs/modules/cpp/android-gcc.qbs0000644000175100001660000001713514776170045021461 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.TextFile import qbs.Utilities import "../../modules/Android/ndk/utils.js" as NdkUtils import 'gcc.js' as Gcc LinuxGCC { Depends { name: "Android.ndk" } condition: qbs.targetOS.includes("android") && qbs.toolchain && qbs.toolchain.includes("llvm") priority: 2 rpaths: [] // toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android cxxLanguageVersion: "c++14" property string archLibsDir: { switch (qbs.architecture) { case "arm64": return "aarch64"; case "armv7a": return "arm"; case "x86_64": return qbs.architecture; case "x86": return "i686"; } } property string targetDir: "android" + (["armeabi", "armeabi-v7a"].includes(Android.ndk.abi) ? "eabi" : "") property string triple: [archLibsDir, targetSystem, targetDir].join("-") property string libsDir: FileInfo.joinPaths(sysroot, "usr", "lib", triple); property string sharedStlFilePath: (libsDir && Android.ndk.appStl.endsWith("_shared")) ? FileInfo.joinPaths(libsDir, dynamicLibraryPrefix + Android.ndk.appStl + dynamicLibrarySuffix) : undefined property string staticStlFilePath: (libsDir && Android.ndk.appStl.endsWith("_static")) ? FileInfo.joinPaths(libsDir, Android.ndk.platformVersion, NdkUtils.stlFileName(staticLibraryPrefix, Android.ndk, staticLibrarySuffix)) : undefined toolchainInstallPath: FileInfo.joinPaths(Android.ndk.ndkDir, "toolchains", "llvm", "prebuilt", Android.ndk.hostArch, "bin") property string toolchainTriple: [targetAbi === "androideabi" ? "arm" : targetArch, targetSystem, targetAbi].join("-") internalVersion: undefined toolchainPrefix: undefined machineType: { if (Android.ndk.abi === "armeabi-v7a") return "armv7-a"; } qbs.optimization: targetAbi === "androideabi" ? "small" : base enableExceptions: Android.ndk.appStl !== "system" enableRtti: Android.ndk.appStl !== "system" commonCompilerFlags: NdkUtils.commonCompilerFlags(qbs.toolchain, qbs.buildVariant, Android.ndk) linkerFlags: NdkUtils.commonLinkerFlags(Android.ndk); driverLinkerFlags: { var flags = ["-fuse-ld=lld", "-Wl,--exclude-libs,libgcc.a", "-nostdlib++"]; // See https://android.googlesource.com/platform/ndk/+/ndk-release-r21/docs/BuildSystemMaintainers.md#Unwinding if (Android.ndk.abi === "armeabi-v7a") { flags = flags.concat(["-Wl,--exclude-libs,libgcc_real.a"]); if (Android.ndk.appStl.startsWith("c++")) flags = flags.concat(["-Wl,--exclude-libs,libunwind.a"]); } return flags; } platformDriverFlags: ["-fdata-sections", "-ffunction-sections", "-funwind-tables", "-fstack-protector-strong", "-no-canonical-prefixes"] dynamicLibraries: { var libs = ["c", "m"]; if (sharedStlFilePath) libs.push(FileInfo.joinPaths(libsDir, Android.ndk.platformVersion, NdkUtils.stlFileName(dynamicLibraryPrefix, Android.ndk, dynamicLibrarySuffix))); return libs; } staticLibraries: staticStlFilePath // When using ndk r19c, llvm doesn't add sysroot/usr/include/c++/v1 to the path // But it works starting with ndk r20b systemIncludePaths: (Utilities.versionCompare(Android.ndk.version, "20") < 0) ? FileInfo.joinPaths(sysroot, "usr", "include", "c++", "v1") : [] defines: ["ANDROID", "__ANDROID__"] binutilsPath: FileInfo.joinPaths(Android.ndk.ndkDir, "toolchains", "llvm", "prebuilt", Android.ndk.hostArch, "bin"); binutilsPathPrefix: FileInfo.joinPaths(binutilsPath, "llvm-") sysroot: FileInfo.joinPaths(Android.ndk.ndkDir, "toolchains", "llvm", "prebuilt", Android.ndk.hostArch, "sysroot") targetArch: { switch (qbs.architecture) { case "arm64": return "aarch64"; case "armv5": case "armv5te": return "armv5te"; case "armv7a": case "x86_64": return qbs.architecture; case "x86": return "i686"; } } target: [targetArch, targetSystem, targetAbi].join("-") targetSystem: "linux" targetAbi: "android" + (["armeabi", "armeabi-v7a"].includes(Android.ndk.abi) ? "eabi" : "") + Android.ndk.platformVersion endianness: "little" Group { condition: shouldLink Group { name: "Android STL" condition: module.sharedStlFilePath files: module.sharedStlFilePath ? [module.sharedStlFilePath] : [] fileTags: "android.stl" } Rule { inputs: "dynamiclibrary" Artifact { filePath: FileInfo.joinPaths("stripped-libs", input.fileName) fileTags: "android.nativelibrary" } prepare: { var stripArgs = ["--strip-all", "-o", output.filePath, input.filePath]; var stripCmd = new Command(product.cpp.stripPath, stripArgs); stripCmd.description = "stripping unneeded symbols from " + input.fileName; return stripCmd; } } } _skipAllChecks: !shouldLink validate: { if (_skipAllChecks) return; var baseValidator = new ModUtils.PropertyValidator("qbs"); baseValidator.addCustomValidator("architecture", targetArch, function (value) { return value !== undefined; }, "unknown Android architecture '" + qbs.architecture + "'."); var validator = new ModUtils.PropertyValidator("cpp"); validator.setRequiredProperty("targetArch", targetArch); return baseValidator.validate() && validator.validate(); } } qbs-src-2.6.1/share/qbs/modules/cpp/watcom.qbs0000644000175100001660000001623014776170045020574 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs 1.0 import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Probes import "cpp.js" as Cpp import "watcom.js" as WATCOM CppModule { condition: qbs.toolchain && qbs.toolchain.includes("watcom") Probes.BinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["owcc"] } Probes.WatcomProbe { id: watcomProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage _pathListSeparator: qbs.pathListSeparator _toolchainInstallPath: toolchainInstallPath _targetPlatform: qbs.targetPlatform _targetArchitecture: qbs.architecture } Properties { condition: watcomProbe.found qbs.architecture: watcomProbe.architecture qbs.targetPlatform: watcomProbe.targetPlatform } compilerVersionMajor: watcomProbe.versionMajor compilerVersionMinor: watcomProbe.versionMinor compilerVersionPatch: watcomProbe.versionPatch endianness: watcomProbe.endianness compilerDefinesByLanguage: watcomProbe.compilerDefinesByLanguage compilerIncludePaths: watcomProbe.includePaths toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined /* Work-around for QtCreator which expects these properties to exist. */ property string cCompilerName: compilerName property string cxxCompilerName: compilerName compilerName: "owcc" + compilerExtension compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: "wasm" + compilerExtension assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName) linkerName: "wlink" + compilerExtension linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) property string disassemblerName: "wdis" + compilerExtension property string disassemblerPath: FileInfo.joinPaths(toolchainInstallPath, disassemblerName) property string resourceCompilerName: "wrc" + compilerExtension property string resourceCompilerPath: FileInfo.joinPaths(toolchainInstallPath, resourceCompilerName) property string libraryManagerName: "wlib" + compilerExtension property string libraryManagerPath: FileInfo.joinPaths(toolchainInstallPath, libraryManagerName) runtimeLibrary: "dynamic" staticLibrarySuffix: ".lib" dynamicLibrarySuffix: toolchainDetails.dynamicLibrarySuffix executableSuffix: toolchainDetails.executableSuffix objectSuffix: ".obj" imageFormat: toolchainDetails.imageFormat defineFlag: "-D" includeFlag: "-I" systemIncludeFlag: "-I" preincludeFlag: "-include" libraryDependencyFlag: "-l" libraryPathFlag: "-L" linkerScriptFlag: "" toolchainDetails: WATCOM.toolchainDetails(qbs) knownArchitectures: ["x86", "x86_16"] property var buildEnv: watcomProbe.environment setupBuildEnvironment: { for (var key in product.cpp.buildEnv) { var v = new ModUtils.EnvironmentVariable(key, product.qbs.pathListSeparator); v.prepend(product.cpp.buildEnv[key]); v.set(); } } Rule { id: assembler inputs: ["asm"] outputFileTags: Cpp.assemblerOutputTags(generateAssemblerListingFiles) outputArtifacts: Cpp.assemblerOutputArtifacts(input) prepare: WATCOM.prepareAssembler.apply(WATCOM, arguments) } FileTagger { patterns: ["*.asm"] fileTags: ["asm"] } Rule { id: compiler inputs: ["cpp", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.compilerOutputTags(generateCompilerListingFiles) outputArtifacts: Cpp.compilerOutputArtifacts(input) prepare: WATCOM.prepareCompiler.apply(WATCOM, arguments) } Rule { id: rccCompiler inputs: ["rc"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.resourceCompilerOutputTags() outputArtifacts: Cpp.resourceCompilerOutputArtifacts(input) prepare: WATCOM.prepareResourceCompiler.apply(WATCOM, arguments) } FileTagger { patterns: ["*.rc"] fileTags: ["rc"] } Rule { id: applicationLinker multiplex: true inputs: ["obj", "res", "linkerscript"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile) outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product) prepare: WATCOM.prepareLinker.apply(WATCOM, arguments) } Rule { id: dynamicLibraryLinker condition: qbs.targetOS.includes("windows") multiplex: true inputs: ["obj", "res"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: Cpp.dynamicLibraryLinkerOutputTags(); outputArtifacts: Cpp.dynamicLibraryLinkerOutputArtifacts(product) prepare: WATCOM.prepareLinker.apply(WATCOM, arguments) } Rule { id: libraryManager multiplex: true inputs: ["obj"] inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"] outputFileTags: Cpp.staticLibraryLinkerOutputTags() outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product) prepare: WATCOM.prepareLibraryManager.apply(WATCOM, arguments) } JobLimit { jobPool: "watcom_job_pool" jobCount: 1 } } qbs-src-2.6.1/share/qbs/modules/cpp/gcc.js0000644000175100001660000021022114776170045017661 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Codesign = require("../codesign/codesign.js"); var Cpp = require("cpp.js"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Host = require("qbs.Host"); var DarwinTools = require("qbs.DarwinTools"); var ModUtils = require("qbs.ModUtils"); var PathTools = require("qbs.PathTools"); var Process = require("qbs.Process"); var TextFile = require("qbs.TextFile"); var UnixUtils = require("qbs.UnixUtils"); var Utilities = require("qbs.Utilities"); var WindowsUtils = require("qbs.WindowsUtils"); function effectiveLinkerPath(product, inputs) { if (product.cpp.linkerMode === "automatic") { var compilers = product.cpp.compilerPathByLanguage; if (compilers) { if (inputs.cpp_obj || inputs.cpp_staticlibrary) { console.log("Found C++ or Objective-C++ objects, choosing C++ linker for " + product.name); return compilers["cpp"]; } if (inputs.c_obj || inputs.c_staticlibrary) { console.log("Found C or Objective-C objects, choosing C linker for " + product.name); return compilers["c"]; } } console.log("Found no C-language objects, choosing system linker for " + product.name); } return product.cpp.linkerPath; } function useCompilerDriverLinker(product, inputs) { var linker = effectiveLinkerPath(product, inputs); var compilers = product.cpp.compilerPathByLanguage; if (compilers) { return linker === compilers["cpp"] || linker === compilers["c"]; } return linker === product.cpp.compilerPath; } function collectLibraryDependencies(product, isDarwin) { var publicDeps = {}; var privateDeps = {}; var objects = []; var objectByFilePath = {}; var tagForLinkingAgainstSharedLib = product.cpp.imageFormat === "pe" ? "dynamiclibrary_import" : "dynamiclibrary"; var removeDuplicateLibraries = product.cpp.removeDuplicateLibraries function addObject(obj, addFunc) { /* If the object is already known, remove its previous usage and insert * it again in the new desired position. This preserves the order of * the other objects, and is analogous to what qmake does (see the * mergeLflags parameter in UnixMakefileGenerator::findLibraries()). */ if (removeDuplicateLibraries && (obj.filePath in objectByFilePath)) { var oldObj = objectByFilePath[obj.filePath]; var i = objects.indexOf(oldObj); if (i >= 0) objects.splice(i, 1); } addFunc.call(objects, obj); objectByFilePath[obj.filePath] = obj; } function addPublicFilePath(filePath, dep) { var existing = objectByFilePath[filePath]; var wholeArchive = dep.parameters.cpp && dep.parameters.cpp.linkWholeArchive; var symbolLinkMode = dep.parameters.cpp && dep.parameters.cpp.symbolLinkMode; if (existing) { existing.direct = true; existing.wholeArchive = wholeArchive; existing.symbolLinkMode = symbolLinkMode; } else { addObject({ direct: true, filePath: filePath, wholeArchive: wholeArchive, symbolLinkMode: symbolLinkMode }, Array.prototype.unshift); } } function addPrivateFilePath(filePath) { var existing = objectByFilePath[filePath]; if (!existing) addObject({ direct: false, filePath: filePath }, Array.prototype.unshift); } function addArtifactFilePaths(dep, tag, addFunction) { var artifacts = dep.artifacts[tag]; if (!artifacts) return; var artifactFilePaths = artifacts.map(function(a) { return a.filePath; }); for (var i = 0; i < artifactFilePaths.length; ++i) addFunction(artifactFilePaths[i], dep); } function addExternalLibs(obj) { if (!obj.cpp) return; function ensureArray(a) { return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); } var externalLibs = [].concat( ensureArray(sanitizedModuleListProperty(obj, "cpp", "staticLibraries")), ensureArray(sanitizedModuleListProperty(obj, "cpp", "dynamicLibraries"))); for (var i = 0, len = externalLibs.length; i < len; ++i) addObject({ direct: true, filePath: externalLibs[i] }, Array.prototype.push); if (isDarwin) { externalLibs = [].concat( ensureArray(sanitizedModuleListProperty(obj, "cpp", "frameworks"))); for (var i = 0, len = externalLibs.length; i < len; ++i) addObject({ direct: true, filePath: externalLibs[i], framework: true }, Array.prototype.push); externalLibs = [].concat( ensureArray(sanitizedModuleListProperty(obj, "cpp", "weakFrameworks"))); for (var i = 0, len = externalLibs.length; i < len; ++i) addObject({ direct: true, filePath: externalLibs[i], framework: true, symbolLinkMode: "weak" }, Array.prototype.push); } } function traverse(dep, isBelowIndirectDynamicLib) { if (publicDeps[dep.name]) return; if (dep.parameters.cpp && dep.parameters.cpp.link === false) return; var isStaticLibrary = typeof dep.artifacts["staticlibrary"] !== "undefined"; var isDynamicLibrary = !isStaticLibrary && typeof dep.artifacts[tagForLinkingAgainstSharedLib] !== "undefined"; if (!isStaticLibrary && !isDynamicLibrary) return; if (isBelowIndirectDynamicLib && privateDeps[dep.name]) return; var nextIsBelowIndirectDynamicLib = isBelowIndirectDynamicLib || isDynamicLibrary; dep.dependencies.forEach(function(depdep) { // If "dep" is an aggregate product, and "depdep" is one of the multiplexed variants // of the same product, we don't want to depend on the multiplexed variants, because // that could mean linking more than one time against the same library. Instead skip // the multiplexed dependency, and depend only on the aggregate one. if (depdep.name === dep.name) return; traverse(depdep, nextIsBelowIndirectDynamicLib); }); if (isStaticLibrary) { if (!isBelowIndirectDynamicLib) { addArtifactFilePaths(dep, "staticlibrary", addPublicFilePath); if (product.cpp.importPrivateLibraries) addExternalLibs(dep); publicDeps[dep.name] = true; } } else if (isDynamicLibrary) { if (!isBelowIndirectDynamicLib) { addArtifactFilePaths(dep, tagForLinkingAgainstSharedLib, addPublicFilePath); publicDeps[dep.name] = true; } else { addArtifactFilePaths(dep, tagForLinkingAgainstSharedLib, addPrivateFilePath); privateDeps[dep.name] = true; } } } function traverseDirectDependency(dep) { traverse(dep, false); } product.dependencies.forEach(traverseDirectDependency); addExternalLibs(product); var result = { libraries: [], rpath_link: [] }; objects.forEach( function (obj) { if (obj.direct) { result.libraries.push({ filePath: obj.filePath, wholeArchive: obj.wholeArchive, symbolLinkMode: obj.symbolLinkMode, framework: obj.framework }); } else { var dirPath = FileInfo.path(obj.filePath); result.rpath_link.push(dirPath); } }); return result; } function escapeLinkerFlags(product, inputs, linkerFlags) { if (!linkerFlags || linkerFlags.length === 0) return []; if (useCompilerDriverLinker(product, inputs)) { var sep = ","; var useXlinker = linkerFlags.some(function (f) { return f.includes(sep); }); if (useXlinker) { // One or more linker arguments contain the separator character itself // Use -Xlinker to handle these var xlinkerFlags = []; linkerFlags.map(function (linkerFlag) { if (product.cpp.enableSuspiciousLinkerFlagWarnings && linkerFlag.startsWith("-Wl,")) { console.warn("Encountered escaped linker flag '" + linkerFlag + "'. This may " + "cause the target to fail to link. Please do not escape these " + "flags manually; qbs does that for you."); } xlinkerFlags.push("-Xlinker", linkerFlag); }); return xlinkerFlags; } if (product.cpp.enableSuspiciousLinkerFlagWarnings && linkerFlags.includes("-Xlinker")) { console.warn("Encountered -Xlinker linker flag escape sequence. This may cause the " + "target to fail to link. Please do not escape these flags manually; " + "qbs does that for you."); } // If no linker arguments contain the separator character we can just use -Wl, // which is more compact and easier to read in logs return [["-Wl"].concat(linkerFlags).join(sep)]; } return linkerFlags; } function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPath) { var isDarwin = product.qbs.targetOS.includes("darwin"); var libraryDependencies = collectLibraryDependencies(product, isDarwin); var rpaths = (product.cpp.useRPaths !== false) ? product.cpp.rpaths : undefined; var systemRunPaths = product.cpp.systemRunPaths || []; var canonicalSystemRunPaths = systemRunPaths.map(function(p) { return File.canonicalFilePath(p); }); var i, args = additionalCompilerAndLinkerFlags(product); var escapableLinkerFlags = []; if (primaryOutput.fileTags.includes("dynamiclibrary")) { if (isDarwin) { args.push((function () { var tags = ["c", "cpp", "cppm", "objc", "objcpp", "asm_cpp"]; for (var i = 0; i < tags.length; ++i) { if (linkerPath === product.cpp.compilerPathByLanguage[tags[i]]) return "-dynamiclib"; } return "-dylib"; // for ld64 })()); } else { args.push("-shared"); } if (isDarwin) { if (product.cpp.internalVersion) args.push("-current_version", product.cpp.internalVersion); escapableLinkerFlags.push("-install_name", UnixUtils.soname(product, primaryOutput.fileName)); } else if (product.cpp.imageFormat === "elf") { escapableLinkerFlags.push("-soname=" + UnixUtils.soname(product, primaryOutput.fileName)); } } if (primaryOutput.fileTags.includes("loadablemodule")) args.push(isDarwin ? "-bundle" : "-shared"); if (primaryOutput.fileTags.containsAny(["dynamiclibrary", "loadablemodule"])) { if (isDarwin) escapableLinkerFlags.push("-headerpad_max_install_names"); else if (product.cpp.imageFormat === "elf") escapableLinkerFlags.push("--as-needed"); } if (isLegacyQnxSdk(product)) { ["c", "cpp"].map(function (tag) { if (linkerPath === product.cpp.compilerPathByLanguage[tag]) args = args.concat(qnxLangArgs(product, tag)); }); } var targetLinkerFlags = product.cpp.targetLinkerFlags; if (targetLinkerFlags) Array.prototype.push.apply(escapableLinkerFlags, targetLinkerFlags); var sysroot = product.cpp.syslibroot; if (sysroot) { if (product.qbs.toolchain.includes("qcc")) escapableLinkerFlags.push("--sysroot=" + sysroot); else if (isDarwin) escapableLinkerFlags.push("-syslibroot", sysroot); else args.push("--sysroot=" + sysroot); // do not escape, compiler-as-linker also needs it } if (product.cpp.allowUnresolvedSymbols) { if (isDarwin) escapableLinkerFlags.push("-undefined", "suppress"); else escapableLinkerFlags.push("--unresolved-symbols=ignore-all"); } function fixupRPath(rpath) { // iOS, tvOS, watchOS, and others, are fine if (!product.qbs.targetOS.includes("macos")) return rpath; // ...as are newer versions of macOS var min = product.cpp.minimumMacosVersion; if (min && Utilities.versionCompare(min, "10.10") >= 0) return rpath; // In older versions of dyld, a trailing slash is required if (!rpath.endsWith("/")) return rpath + "/"; return rpath; } function isNotSystemRunPath(p) { return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.includes(p) && !canonicalSystemRunPaths.includes(File.canonicalFilePath(p))); }; if (!product.qbs.targetOS.includes("windows")) { for (i in rpaths) { if (isNotSystemRunPath(rpaths[i])) escapableLinkerFlags.push("-rpath", fixupRPath(rpaths[i])); } } if (product.cpp.entryPoint) escapableLinkerFlags.push("-e", product.cpp.entryPoint); if (product.qbs.toolchain.includes("mingw")) { if (product.consoleApplication !== undefined) escapableLinkerFlags.push("-subsystem", product.consoleApplication ? "console" : "windows"); var minimumWindowsVersion = product.cpp.minimumWindowsVersion; if (minimumWindowsVersion) { // workaround for QBS-1724, mingw seems to be broken if (Utilities.versionCompare(minimumWindowsVersion, "6.2") > 0) minimumWindowsVersion = "6.2"; var subsystemVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion, 'subsystem'); if (subsystemVersion) { var major = subsystemVersion.split('.')[0]; var minor = subsystemVersion.split('.')[1]; // http://sourceware.org/binutils/docs/ld/Options.html escapableLinkerFlags.push("--major-subsystem-version", major, "--minor-subsystem-version", minor, "--major-os-version", major, "--minor-os-version", minor); } } } if (inputs.aggregate_infoplist) args.push("-sectcreate", "__TEXT", "__info_plist", inputs.aggregate_infoplist[0].filePath); var isLinkingCppObjects = !!(inputs.cpp_obj || inputs.cpp_staticlibrary); var stdlib = isLinkingCppObjects ? product.cpp.cxxStandardLibrary : undefined; if (stdlib && product.qbs.toolchain.includes("clang")) args.push("-stdlib=" + stdlib); // Flags for library search paths var allLibraryPaths = Cpp.collectLibraryPaths(product); var builtIns = product.cpp.compilerLibraryPaths allLibraryPaths = allLibraryPaths.filter(function(p) { return !builtIns.includes(p); }); args = args.concat(allLibraryPaths.map(function(path) { return product.cpp.libraryPathFlag + path })); escapableLinkerFlags = escapableLinkerFlags.concat(Cpp.collectLinkerScriptPathsArguments(product, inputs)); var versionScripts = inputs.versionscript ? inputs.versionscript.map(function(a) { return a.filePath; }) : []; Array.prototype.push.apply(escapableLinkerFlags, [].uniqueConcat(versionScripts) .map(function(path) { return '--version-script=' + path })); if (isDarwin && product.cpp.warningLevel === "none") args.push('-w'); var useCompilerDriver = useCompilerDriverLinker(product, inputs); args = args.concat(configFlags(product, useCompilerDriver)); escapableLinkerFlags = escapableLinkerFlags.concat(Cpp.collectMiscEscapableLinkerArguments(product)); // Note: due to the QCC response files hack in prepareLinker(), at least one object file or // library file must follow the output file path so that QCC has something to process before // sending the rest of the arguments through the response file. args.push("-o", primaryOutput.filePath); args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); args = args.concat(Cpp.collectResourceObjectPaths(inputs)); var wholeArchiveActive = false; var prevLib; for (i = 0; i < libraryDependencies.libraries.length; ++i) { var dep = libraryDependencies.libraries[i]; var lib = dep.filePath; if (lib === prevLib) continue; prevLib = lib; if (dep.wholeArchive && !wholeArchiveActive) { var wholeArchiveFlag; if (isDarwin) { wholeArchiveFlag = "-force_load"; } else { wholeArchiveFlag = "--whole-archive"; wholeArchiveActive = true; } Array.prototype.push.apply(args, escapeLinkerFlags(product, inputs, [wholeArchiveFlag])); } if (!dep.wholeArchive && wholeArchiveActive) { Array.prototype.push.apply(args, escapeLinkerFlags(product, inputs, ["--no-whole-archive"])); wholeArchiveActive = false; } var symbolLinkMode = dep.symbolLinkMode; if (isDarwin && symbolLinkMode) { if (!["lazy", "reexport", "upward", "weak"].includes(symbolLinkMode)) throw new Error("unknown value '" + symbolLinkMode + "' for cpp.symbolLinkMode"); } var supportsLazyMode = Utilities.versionCompare(product.cpp.compilerVersion, "15.0.0") < 0; if (isDarwin && symbolLinkMode && (symbolLinkMode !== "lazy" || supportsLazyMode)) { if (FileInfo.isAbsolutePath(lib) || lib.startsWith('@')) escapableLinkerFlags.push("-" + symbolLinkMode + "_library", lib); else if (dep.framework) escapableLinkerFlags.push("-" + symbolLinkMode + "_framework", lib); else escapableLinkerFlags.push("-" + symbolLinkMode + "-l" + lib); } else if (FileInfo.isAbsolutePath(lib) || lib.startsWith('@')) { args.push(dep.framework ? PathTools.frameworkExecutablePath(lib) : lib); } else if (dep.framework) { args.push("-framework", lib); } else { args.push('-l' + lib); } } if (wholeArchiveActive) { Array.prototype.push.apply(args, escapeLinkerFlags(product, inputs, ["--no-whole-archive"])); } var discardUnusedData = product.cpp.discardUnusedData; if (discardUnusedData !== undefined) { var flags = []; if (discardUnusedData === true) { if (isDarwin) escapableLinkerFlags.push("-dead_strip"); else escapableLinkerFlags.push("--gc-sections"); } else if (!isDarwin) { escapableLinkerFlags.push("--no-gc-sections"); } } if (product.cpp.useRPathLink) { if (!product.cpp.rpathLinkFlag) throw new Error("Using rpath-link but cpp.rpathLinkFlag is not defined"); Array.prototype.push.apply(escapableLinkerFlags, libraryDependencies.rpath_link.map( function(dir) { return product.cpp.rpathLinkFlag + dir; })); } var importLibs = outputs.dynamiclibrary_import; if (importLibs) escapableLinkerFlags.push("--out-implib", importLibs[0].filePath); if (outputs.application && product.cpp.generateLinkerMapFile) { if (isDarwin) escapableLinkerFlags.push("-map", outputs.mem_map[0].filePath); else escapableLinkerFlags.push("-Map=" + outputs.mem_map[0].filePath); } var escapedLinkerFlags = escapeLinkerFlags(product, inputs, escapableLinkerFlags); Array.prototype.push.apply(escapedLinkerFlags, args); if (useCompilerDriver) escapedLinkerFlags = escapedLinkerFlags.concat(Cpp.collectMiscLinkerArguments(product)); if (product.qbs.toolchain.includes("mingw") && product.cpp.runtimeLibrary === "static") escapedLinkerFlags = ['-static-libgcc', '-static-libstdc++'].concat(escapedLinkerFlags); return escapedLinkerFlags; } // for compiler AND linker function configFlags(config, isDriver) { var args = []; if (isDriver !== false) args = args.concat(Cpp.collectMiscDriverArguments(config)); var frameworkPaths = config.cpp.frameworkPaths; if (frameworkPaths) args = args.uniqueConcat(frameworkPaths.map(function(path) { return '-F' + path })); var allSystemFrameworkPaths = []; var systemFrameworkPaths = config.cpp.systemFrameworkPaths; if (systemFrameworkPaths) allSystemFrameworkPaths = allSystemFrameworkPaths.uniqueConcat(systemFrameworkPaths); var distributionFrameworkPaths = config.cpp.distributionFrameworkPaths; if (distributionFrameworkPaths) allSystemFrameworkPaths = allSystemFrameworkPaths.uniqueConcat(distributionFrameworkPaths); args = args.concat(allSystemFrameworkPaths.map(function(path) { return '-iframework' + path })); return args; } function languageTagFromFileExtension(toolchain, fileName) { var i = fileName.lastIndexOf('.'); if (i === -1) return; var m = { "c" : "c", "C" : "cpp", "cpp" : "cpp", "cxx" : "cpp", "c++" : "cpp", "cc" : "cpp", "m" : "objc", "mm" : "objcpp", "s" : "asm", "S" : "asm_cpp" }; if (!toolchain.includes("clang")) m["sx"] = "asm_cpp"; // clang does NOT recognize .sx else m["cppm"] = "cppm"; return m[fileName.substring(i + 1)]; } // Older versions of the QNX SDK have C and C++ compilers whose filenames differ only by case, // which won't work in case insensitive environments like Win32+NTFS, HFS+ and APFS function isLegacyQnxSdk(config) { return config.qbs.toolchain.includes("qcc") && config.qnx && !config.qnx.qnx7; } function effectiveCompilerInfo(toolchain, input, output) { var compilerPath, language; var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags)); // Whether we're compiling a precompiled header or normal source file var pchOutput = output.fileTags.includes(tag + "_pch"); var compilerPathByLanguage = input.cpp.compilerPathByLanguage; if (compilerPathByLanguage) compilerPath = compilerPathByLanguage[tag]; if (!compilerPath || tag !== languageTagFromFileExtension(toolchain, input.fileName) || isLegacyQnxSdk(input)) { if (input.qbs.toolchain.includes("qcc")) language = qnxLangArgs(input, tag); else language = ["-x", languageName(tag) + (pchOutput ? '-header' : '')]; } if (!compilerPath) // fall back to main compiler compilerPath = input.cpp.compilerPath; return { path: compilerPath, language: language, tag: tag }; } function qnxLangArgs(config, tag) { switch (tag) { case "c": return ["-lang-c"]; case "cpp": return ["-lang-c++"]; default: return []; } } function handleCpuFeatures(input, flags) { function potentiallyAddFlagForFeature(propName, flagName) { var propValue = input.cpufeatures[propName]; if (propValue === true) flags.push("-m" + flagName); else if (propValue === false) flags.push("-mno-" + flagName); } if (!input.qbs.architecture) return; if (input.qbs.architecture.startsWith("x86")) { potentiallyAddFlagForFeature("x86_avx", "avx"); potentiallyAddFlagForFeature("x86_avx2", "avx2"); potentiallyAddFlagForFeature("x86_avx512bw", "avx512bw"); potentiallyAddFlagForFeature("x86_avx512cd", "avx512cd"); potentiallyAddFlagForFeature("x86_avx512dq", "avx512dq"); potentiallyAddFlagForFeature("x86_avx512er", "avx512er"); potentiallyAddFlagForFeature("x86_avx512f", "avx512f"); potentiallyAddFlagForFeature("x86_avx512ifma", "avx512ifma"); potentiallyAddFlagForFeature("x86_avx512pf", "avx512pf"); potentiallyAddFlagForFeature("x86_avx512vbmi", "avx512vbmi"); potentiallyAddFlagForFeature("x86_avx512vl", "avx512vl"); potentiallyAddFlagForFeature("x86_f16c", "f16c"); potentiallyAddFlagForFeature("x86_sse2", "sse2"); potentiallyAddFlagForFeature("x86_sse3", "sse3"); potentiallyAddFlagForFeature("x86_sse4_1", "sse4.1"); potentiallyAddFlagForFeature("x86_sse4_2", "sse4.2"); potentiallyAddFlagForFeature("x86_ssse3", "ssse3"); } else if (input.qbs.architecture.startsWith("arm")) { if (input.cpufeatures.arm_neon === true) flags.push("-mfpu=neon"); if (input.cpufeatures.arm_vfpv4 === true) flags.push("-mfpu=vfpv4"); } else if (input.qbs.architecture.startsWith("mips")) { potentiallyAddFlagForFeature("mips_dsp", "dsp"); potentiallyAddFlagForFeature("mips_dspr2", "dspr2"); } } function standardFallbackValueOrDefault(toolchain, compilerVersion, languageVersion, useLanguageVersionFallback) { // NEVER use the fallback values (safety brake for users in case our version map is ever wrong) if (useLanguageVersionFallback === false) return languageVersion; // Deprecated, but compatible with older compiler versions. // Note that these versions are the first to support the *value* to the -std= command line // option, not necessarily the first versions where support for that language standard was // considered fully implemented. Tested manually. var languageVersionsMap = { "c++11": { "fallback": "c++0x", "toolchains": [ {"name": "xcode", "version": "4.3"}, {"name": "clang", "version": "3.0"}, {"name": "gcc", "version": "4.7"} ] }, "c11": { "fallback": "c1x", "toolchains": [ {"name": "xcode", "version": "5.0"}, {"name": "clang", "version": "3.1"}, {"name": "gcc", "version": "4.7"} ] }, "c17": { "fallback": "c11", "toolchains": [ {"name": "xcode", "version": "10.2"}, {"name": "clang", "version": "7.0"}, {"name": "gcc", "version": "8.1"} ] }, "c2x": { "fallback": "c17", "toolchains": [ {"name": "xcode", "version": "11.4"}, {"name": "clang", "version": "9.0"}, {"name": "gcc", "version": "9.0"} ] }, "c++14": { "fallback": "c++1y", "toolchains": [ {"name": "xcode", "version": "6.3"}, {"name": "clang", "version": "3.5"}, {"name": "gcc", "version": "4.9"} ] }, "c++17": { "fallback": "c++1z", "toolchains": [ {"name": "xcode", "version": "9.3"}, {"name": "clang", "version": "5.0"}, {"name": "gcc", "version": "5.1"} ] }, "c++20": { "fallback": "c++2a", "toolchains": [ {"name": "xcode", "version": "12.5"}, {"name": "clang", "version": "11.0"}, {"name": "gcc", "version": "10.1"} ] }, "c++23": { "fallback": "c++2b", "toolchains": [ {"name": "xcode"}, {"name": "clang"}, {"name": "gcc"} ] } }; var m = languageVersionsMap[languageVersion]; if (m) { for (var idx = 0; idx < m.toolchains.length; ++idx) { var tc = m.toolchains[idx]; if (toolchain.includes(tc.name)) { // If we found our toolchain and it doesn't yet support the language standard // we're requesting, or we're using an older version that only supports the // preliminary flag, use that. if (useLanguageVersionFallback || !tc.version || Utilities.versionCompare(compilerVersion, tc.version) < 0) return m.fallback; break; } } } // If we didn't find our toolchain at all, simply use the standard value. return languageVersion; } function compilerFlags(project, product, outputs, input, output, explicitlyDependsOn) { var i; // Determine which C-language we're compiling var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(output.fileTags)); if (!["c", "cpp", "cppm", "objc", "objcpp", "asm_cpp"].includes(tag)) throw ("unsupported source language: " + tag); var compilerInfo = effectiveCompilerInfo(product.qbs.toolchain, input, output); var args = additionalCompilerAndLinkerFlags(product); Array.prototype.push.apply(args, product.cpp.sysrootFlags); handleCpuFeatures(input, args); if (input.cpp.debugInformation) args.push('-g'); var opt = input.cpp.optimization if (opt === 'fast') args.push('-O2'); if (opt === 'small') args.push('-Os'); if (opt === 'none') args.push('-O0'); if (input.cpp.forceUseCxxModules) { if (!product.qbs.toolchain.includes("clang")) args.push('-fmodules-ts') } var warnings = input.cpp.warningLevel if (warnings === 'none') args.push('-w'); if (warnings === 'all') { args.push('-Wall'); args.push('-Wextra'); } if (input.cpp.treatWarningsAsErrors) args.push('-Werror'); var moduleMap = (outputs["modulemap"] || [])[0]; if (moduleMap) { const moduleMapperFlag = product.qbs.toolchain.includes("clang") ? "@" // clang uses response file with the list of flags : "-fmodule-mapper="; // gcc uses file with special syntax args.push(moduleMapperFlag + moduleMap.filePath); } args = args.concat(configFlags(input)); if (!input.qbs.toolchain.includes("qcc")) args.push('-pipe'); if (input.cpp.enableReproducibleBuilds) { var toolchain = product.qbs.toolchain; if (!toolchain.includes("clang")) { var hashString = FileInfo.relativePath(project.sourceDirectory, input.filePath); var hash = Utilities.getHash(hashString); args.push("-frandom-seed=0x" + hash.substring(0, 8)); } var major = product.cpp.compilerVersionMajor; var minor = product.cpp.compilerVersionMinor; if ((toolchain.includes("clang") && (major > 3 || (major === 3 && minor >= 5))) || (toolchain.includes("gcc") && (major > 4 || (major === 4 && minor >= 9)))) { args.push("-Wdate-time"); } } var useArc = input.cpp.automaticReferenceCounting; if (useArc !== undefined && (tag === "objc" || tag === "objcpp")) { args.push(useArc ? "-fobjc-arc" : "-fno-objc-arc"); } var enableExceptions = input.cpp.enableExceptions; if (enableExceptions !== undefined) { if (tag === "cpp" || tag === "objcpp" || tag === "cppm") 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 = input.cpp.enableRtti; if (enableRtti !== undefined && (tag === "cpp" || tag === "objcpp" || tag === "cppm")) { args.push(enableRtti ? "-frtti" : "-fno-rtti"); } var visibility = input.cpp.visibility; if (!product.qbs.toolchain.includes("mingw")) { if (visibility === 'hidden' || visibility === 'minimal') args.push('-fvisibility=hidden'); if ((visibility === 'hiddenInlines' || visibility === 'minimal') && tag === 'cpp') args.push('-fvisibility-inlines-hidden'); if (visibility === 'default') args.push('-fvisibility=default') } if (compilerInfo.language) // Only push language arguments if we have to. Array.prototype.push.apply(args, compilerInfo.language); args = args.concat(Cpp.collectMiscCompilerArguments(input, tag)); var pchTag = compilerInfo.tag + "_pch"; var pchOutput = output.fileTags.includes(pchTag); var pchInputs = explicitlyDependsOn[pchTag]; if (!pchOutput && pchInputs && pchInputs.length === 1 && ModUtils.moduleProperty(input, 'usePrecompiledHeader', tag)) { var pchInput = pchInputs[0]; var pchFilePath = FileInfo.joinPaths(FileInfo.path(pchInput.filePath), pchInput.completeBaseName); args.push(input.cpp.preincludeFlag, pchFilePath); } args = args.concat(Cpp.collectPreincludePathsArguments(input)); var positionIndependentCode = input.cpp.positionIndependentCode; if (positionIndependentCode && !product.qbs.targetOS.includes("windows")) args.push('-fPIC'); var cppFlags = input.cpp.cppFlags; for (i in cppFlags) args.push('-Wp,' + cppFlags[i]) args = args.concat(Cpp.collectDefinesArguments(input)); args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); var minimumWindowsVersion = input.cpp.minimumWindowsVersion; if (minimumWindowsVersion && product.qbs.targetOS.includes("windows")) { var hexVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion, 'hex'); if (hexVersion) { var versionDefs = [ 'WINVER', '_WIN32_WINNT', '_WIN32_WINDOWS' ]; for (i in versionDefs) args.push(input.cpp.defineFlag + versionDefs[i] + '=' + hexVersion); } } function currentLanguageVersion(tag) { switch (tag) { case "c": case "objc": var knownValues = ["c2x", "c17", "c11", "c99", "c90", "c89"]; return Cpp.languageVersion(input.cpp.cLanguageVersion, knownValues, "C"); case "cpp": case "cppm": case "objcpp": knownValues = ["c++23", "c++2b", "c++20", "c++2a", "c++17", "c++1z", "c++14", "c++1y", "c++11", "c++0x", "c++03", "c++98"]; return Cpp.languageVersion(input.cpp.cxxLanguageVersion, knownValues, "C++"); } } var langVersion = currentLanguageVersion(tag); if (langVersion) { args.push("-std=" + standardFallbackValueOrDefault(product.qbs.toolchain, product.cpp.compilerVersion, langVersion, product.cpp.useLanguageVersionFallback)); } if (tag === "cpp" || tag === "objcpp" || tag === "cppm") { var cxxStandardLibrary = product.cpp.cxxStandardLibrary; if (cxxStandardLibrary && product.qbs.toolchain.includes("clang")) { args.push("-stdlib=" + cxxStandardLibrary); } } args.push("-o", output.filePath); args.push("-c", input.filePath); return args; } function additionalCompilerAndLinkerFlags(product) { var args = [] var requireAppExtensionSafeApi = product.cpp.requireAppExtensionSafeApi; if (requireAppExtensionSafeApi !== undefined && product.qbs.targetOS.includes("darwin")) { args.push(requireAppExtensionSafeApi ? "-fapplication-extension" : "-fno-application-extension"); } return args } // Returns the GCC language name equivalent to fileTag, accepted by the -x argument function languageName(fileTag) { if (fileTag === 'c') return 'c'; else if (fileTag === 'cpp') return 'c++'; else if (fileTag === 'cppm') return 'c++'; else if (fileTag === 'objc') return 'objective-c'; else if (fileTag === 'objcpp') return 'objective-c++'; else if (fileTag === 'asm') return 'assembler'; else if (fileTag === 'asm_cpp') return 'assembler-with-cpp'; } function prepareAssembler(project, product, inputs, outputs, input, output) { var assemblerPath = product.cpp.assemblerPath; var args = product.cpp.targetAssemblerFlags; if (input.cpp.debugInformation) args.push('-g'); var warnings = input.cpp.warningLevel if (warnings === 'none') args.push('-W'); args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input, input.cpp.includeFlag)); args.push("-o", output.filePath); args.push(input.filePath); var cmd = new Command(assemblerPath, args); cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "assembler"; return cmd; } function compilerEnvVars(config, compilerInfo) { if (config.qbs.toolchain.includes("qcc")) return ["QCC_CONF_PATH"]; var list = ["CPATH", "TMPDIR"]; if (compilerInfo.tag === "c") list.push("C_INCLUDE_PATH"); else if (compilerInfo.tag === "cpp") list.push("CPLUS_INCLUDE_PATH"); else if (compilerInfo.tag === "cppm") list.push("CPLUS_INCLUDE_PATH"); else if (compilerInfo.tag === "objc") list.push("OBJC_INCLUDE_PATH"); else if (compilerInfo.tag === "objccpp") list.push("OBJCPLUS_INCLUDE_PATH"); if (config.qbs.targetOS.includes("macos")) list.push("MACOSX_DEPLOYMENT_TARGET"); else if (config.qbs.targetOS.includes("ios")) list.push("IPHONEOS_DEPLOYMENT_TARGET"); else if (config.qbs.targetOS.includes("tvos")) list.push("TVOS_DEPLOYMENT_TARGET"); else if (config.qbs.targetOS.includes("watchos")) list.push("WATCHOS_DEPLOYMENT_TARGET"); if (config.qbs.toolchain.includes("clang")) { list.push("TEMP", "TMP"); } else { list.push("LANG", "LC_CTYPE", "LC_MESSAGES", "LC_ALL", "GCC_COMPARE_DEBUG", "GCC_EXEC_PREFIX", "COMPILER_PATH", "SOURCE_DATE_EPOCH"); } return list; } function linkerEnvVars(config, inputs) { if (config.qbs.toolchain.includes("clang") || config.qbs.toolchain.includes("qcc")) return []; var list = ["GNUTARGET", "LDEMULATION", "COLLECT_NO_DEMANGLE"]; if (useCompilerDriverLinker(config, inputs)) list.push("LIBRARY_PATH"); return list; } function setResponseFileThreshold(command, product) { if (Host.os().includes("windows")) command.responseFileThreshold = 8000; } function prepareCompilerInternal(project, product, inputs, outputs, input, output_, explicitlyDependsOn) { var output = output_ || outputs["obj"][0]; var compilerInfo = effectiveCompilerInfo(product.qbs.toolchain, input, output); var compilerPath = compilerInfo.path; var pchOutput = output.fileTags.includes(compilerInfo.tag + "_pch"); var args = compilerFlags(project, product, outputs, input, output, explicitlyDependsOn); var wrapperArgsLength = 0; var wrapperArgs = product.cpp.compilerWrapper; var extraEnv; if (wrapperArgs && wrapperArgs.length > 0) { // distcc cannot deal with absolute compiler paths (QBS-1336). for (var i = 0; i < wrapperArgs.length; ++i) { if (FileInfo.baseName(wrapperArgs[i]) !== "distcc") continue; if (i === wrapperArgs.length - 1) { if (FileInfo.isAbsolutePath(compilerPath)) { extraEnv = ["PATH=" + FileInfo.path(compilerPath)]; compilerPath = FileInfo.fileName(compilerPath); } } else if (FileInfo.isAbsolutePath(wrapperArgs[i + 1])) { extraEnv = ["PATH=" + FileInfo.path(FileInfo.path(wrapperArgs[i + 1]))]; wrapperArgs[i + 1] = FileInfo.fileName(wrapperArgs[i + 1]); } break; } wrapperArgsLength = wrapperArgs.length; args.unshift(compilerPath); compilerPath = wrapperArgs.shift(); args = wrapperArgs.concat(args); } var cmd = new Command(compilerPath, args); cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + input.fileName; if (pchOutput) cmd.description += ' (' + compilerInfo.tag + ')'; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; cmd.relevantEnvironmentVariables = compilerEnvVars(input, compilerInfo); if (extraEnv) cmd.environment = extraEnv; cmd.responseFileArgumentIndex = wrapperArgsLength; cmd.responseFileUsagePrefix = '@'; setResponseFileThreshold(cmd, product); return cmd; } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var result = Cpp.prepareModules(project, product, inputs, outputs, input, output); result = result.concat(prepareCompilerInternal( project, product, inputs, outputs, input, output, explicitlyDependsOn)); return result; } // Concatenates two arrays of library names and preserves the dependency order that ld needs. function concatLibs(libs, deplibs) { var r = []; var s = {}; function addLibs(lst) { for (var i = lst.length; --i >= 0;) { var lib = lst[i]; if (!s[lib]) { s[lib] = true; r.unshift(lib); } } } addLibs(deplibs); addLibs(libs); return r; } function collectStdoutLines(command, args) { var p = new Process(); try { p.exec(command, args); return p.readStdOut().split(/\r?\n/g).filter(function (e) { return e; }); } finally { p.close(); } } function getSymbolInfo(product, inputFile) { var result = { }; var command = product.cpp.nmPath; var args = ["-g", "-P"]; if (product.cpp._nmHasDynamicOption) args.push("-D"); try { result.allGlobalSymbols = collectStdoutLines(command, args.concat(inputFile)); // GNU nm has the "--defined" option but POSIX nm does not, so we have to manually // construct the list of defined symbols by subtracting. var undefinedGlobalSymbols = collectStdoutLines(command, args.concat(["-u", inputFile])); result.definedGlobalSymbols = result.allGlobalSymbols.filter(function(line) { return !undefinedGlobalSymbols.includes(line); }); result.success = true; } catch (e) { console.debug("Failed to collect symbols for shared library: nm command '" + command + "' failed (" + e.toString() + ")"); result.success = false; } return result; } function createSymbolFile(filePath, allSymbols, definedSymbols) { var file; try { file = new TextFile(filePath, TextFile.WriteOnly); for (var lineNr in allSymbols) file.writeLine(allSymbols[lineNr]); file.writeLine("==="); for (lineNr in definedSymbols) file.writeLine(definedSymbols[lineNr]); } finally { if (file) file.close(); } } function readSymbolFile(filePath) { var result = { success: true, allGlobalSymbols: [], definedGlobalSymbols: [] }; var file; try { file = new TextFile(filePath, TextFile.ReadOnly); var prop = "allGlobalSymbols"; while (true) { var line = file.readLine(); if (!line) break; if (line === "===") { prop = "definedGlobalSymbols"; continue; } result[prop].push(line); } } catch (e) { console.debug("Failed to read symbols from '" + filePath + "'"); result.success = false; } finally { if (file) file.close(); } return result; } function createSymbolCheckingCommands(product, outputs) { var commands = []; if (!outputs.dynamiclibrary || !outputs.dynamiclibrary_symbols) return commands; if (outputs.dynamiclibrary.length !== outputs.dynamiclibrary_symbols.length) throw new Error("The number of outputs tagged dynamiclibrary (" + outputs.dynamiclibrary.length + ") must be equal to the number of " + "outputs tagged dynamiclibrary_symbols (" + outputs.dynamiclibrary_symbols.length + ")"); for (var d = 0; d < outputs.dynamiclibrary_symbols.length; ++d) { // Update the symbols file if the list of relevant symbols has changed. var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.d = d; cmd.sourceCode = function() { if (outputs.dynamiclibrary[d].qbs.buildVariant !== outputs.dynamiclibrary_symbols[d].qbs.buildVariant) throw new Error("Build variant of output tagged dynamiclibrary (" + outputs.dynamiclibrary[d].qbs.buildVariant + ") is not equal to " + "build variant of output tagged dynamiclibrary_symbols (" + outputs.dynamiclibrary_symbols[d].qbs.buildVariant + ") at index " + d); var libFilePath = outputs.dynamiclibrary[d].filePath; var symbolFilePath = outputs.dynamiclibrary_symbols[d].filePath; var newNmResult = getSymbolInfo(product, libFilePath); if (!newNmResult.success) return; if (!File.exists(symbolFilePath)) { console.debug("Symbol file '" + symbolFilePath + "' does not yet exist."); createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols, newNmResult.definedGlobalSymbols); return; } var oldNmResult = readSymbolFile(symbolFilePath); var checkMode = product.cpp.exportedSymbolsCheckMode; var oldSymbols; var newSymbols; if (checkMode === "strict") { oldSymbols = oldNmResult.allGlobalSymbols; newSymbols = newNmResult.allGlobalSymbols; } else { var weakFilter = function(line) { var symbolType = line.split(/\s+/)[1]; return symbolType != "v" && symbolType != "V" && symbolType != "w" && symbolType != "W"; }; oldSymbols = oldNmResult.definedGlobalSymbols.filter(weakFilter); newSymbols = newNmResult.definedGlobalSymbols.filter(weakFilter); } if (oldSymbols.length !== newSymbols.length) { console.debug("List of relevant symbols differs for '" + libFilePath + "'."); createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols, newNmResult.definedGlobalSymbols); return; } for (var i = 0; i < oldSymbols.length; ++i) { var oldLine = oldSymbols[i]; var newLine = newSymbols[i]; var oldLineElems = oldLine.split(/\s+/); var newLineElems = newLine.split(/\s+/); if (oldLineElems[0] !== newLineElems[0] // Object name. || oldLineElems[1] !== newLineElems[1]) { // Object type console.debug("List of relevant symbols differs for '" + libFilePath + "'."); createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols, newNmResult.definedGlobalSymbols); return; } } } commands.push(cmd); } return commands; } function separateDebugInfoCommands(product, outputs, primaryOutput) { var commands = []; var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll || outputs.debuginfo_loadablemodule; if (debugInfo && !product.qbs.toolchain.includes("emscripten")) { var objcopy = product.cpp.objcopyPath; var cmd = new Command(objcopy, ["--only-keep-debug", primaryOutput.filePath, debugInfo[0].filePath]); cmd.silent = true; commands.push(cmd); cmd = new Command(objcopy, ["--strip-debug", primaryOutput.filePath]); cmd.silent = true; commands.push(cmd); cmd = new Command(objcopy, ["--add-gnu-debuglink=" + debugInfo[0].filePath, primaryOutput.filePath]); cmd.silent = true; commands.push(cmd); } return commands; } function separateDebugInfoCommandsDarwin(product, outputs, primaryOutputs) { var commands = []; var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll || outputs.debuginfo_loadablemodule; if (debugInfo) { var dsymPath = debugInfo[0].filePath; if (outputs.debuginfo_bundle && outputs.debuginfo_bundle[0]) dsymPath = outputs.debuginfo_bundle[0].filePath; var flags = product.cpp.dsymutilFlags || []; var files = primaryOutputs.map(function (f) { return f.filePath; }); var cmd = new Command(product.cpp.dsymutilPath, flags.concat(["-o", dsymPath].concat(files))); cmd.description = "generating dSYM for " + product.name; commands.push(cmd); // strip debug info cmd = new Command(product.cpp.stripPath, ["-S"].concat(files)); cmd.silent = true; commands.push(cmd); } return commands; } function librarySymlinkArtifacts(product, buildVariantSuffix) { var artifacts = []; if (product.cpp.shouldCreateSymlinks && (!product.bundle || !product.bundle.isBundle)) { var maxVersionParts = product.cpp.internalVersion ? 3 : 1; var primaryFileName = PathTools.dynamicLibraryFilePath(product, buildVariantSuffix, undefined); for (var i = 0; i < maxVersionParts; ++i) { var symlink = { filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.dynamicLibraryFilePath( product, buildVariantSuffix, undefined, i)), fileTags: ["dynamiclibrary_symlink"], cpp: { primaryFileName: primaryFileName } }; if (i > 0 && artifacts[i-1].filePath == symlink.filePath) break; // Version number has less than three components. artifacts.push(symlink); } } return artifacts; } function librarySymlinkCommands(outputs, primaryOutput) { var commands = []; // Create symlinks from {libfoo, libfoo.1, libfoo.1.0} to libfoo.1.0.0 var links = outputs["dynamiclibrary_symlink"]; var symlinkCount = links ? links.length : 0; for (i = 0; i < symlinkCount; ++i) { var cmd = new Command("ln", ["-sf", links[i].cpp.primaryFileName, links[i].filePath]); cmd.highlight = "filegen"; cmd.description = "creating symbolic link '" + links[i].fileName + "'"; cmd.workingDirectory = FileInfo.path(primaryOutput.filePath); commands.push(cmd); } return commands; } function prepareLinker(project, product, inputs, outputs, input, output) { var i, primaryOutput, cmd, commands = []; if (outputs.application) { primaryOutput = outputs.application[0]; } else if (outputs.dynamiclibrary) { primaryOutput = outputs.dynamiclibrary[0]; } else if (outputs.loadablemodule) { primaryOutput = outputs.loadablemodule[0]; } var linkerPath = effectiveLinkerPath(product, inputs) var args = linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPath); var wrapperArgsLength = 0; var wrapperArgs = product.cpp.linkerWrapper; if (wrapperArgs && wrapperArgs.length > 0) { wrapperArgsLength = wrapperArgs.length; args.unshift(linkerPath); linkerPath = wrapperArgs.shift(); args = wrapperArgs.concat(args); } var responseFileArgumentIndex = wrapperArgsLength; // qcc doesn't properly handle response files, so we have to do it manually var useQnxResponseFileHack = product.qbs.toolchain.includes("qcc") && useCompilerDriverLinker(product, inputs); if (useQnxResponseFileHack) { // qcc needs to see at least one object/library file to think it has something to do, // so start the response file at the second object file (so, 3 after the last -o option) var idx = args.lastIndexOf("-o"); if (idx !== -1 && idx + 3 < args.length) responseFileArgumentIndex += idx + 3; } cmd = new Command(linkerPath, args); cmd.description = 'linking ' + primaryOutput.fileName; cmd.highlight = 'linker'; cmd.jobPool = "linker"; cmd.relevantEnvironmentVariables = linkerEnvVars(product, inputs); cmd.responseFileArgumentIndex = responseFileArgumentIndex; cmd.responseFileUsagePrefix = useQnxResponseFileHack ? "-Wl,@" : "@"; setResponseFileThreshold(cmd, product); commands.push(cmd); if (product.qbs.toolchain.includes("emscripten") && outputs.application && product.cpp.separateDebugInformation) { args.push("-gseparate-dwarf"); } else if (product.qbs.targetOS.includes("darwin")) { if (!product.aggregate) { commands = commands.concat(separateDebugInfoCommandsDarwin( product, outputs, [primaryOutput])); } } else { commands = commands.concat(separateDebugInfoCommands(product, outputs, primaryOutput)); } if (outputs.dynamiclibrary) { Array.prototype.push.apply(commands, createSymbolCheckingCommands(product, outputs)); Array.prototype.push.apply(commands, librarySymlinkCommands(outputs, primaryOutput)); } if (product.cpp.shouldSignArtifacts) { Array.prototype.push.apply( commands, Codesign.prepareSign(project, product, inputs, outputs, input, output)); } return commands; } function debugInfoArtifacts(product, variants, debugInfoTagSuffix) { var fileTag; switch (debugInfoTagSuffix) { case "app": fileTag = "application"; break; case "dll": fileTag = "dynamiclibrary"; break; default: fileTag = debugInfoTagSuffix; break; } variants = variants || [{}]; var artifacts = []; var separateDebugInfo = product.cpp.separateDebugInformation; if (separateDebugInfo && product.qbs.toolchain.includes("emscripten")) separateDebugInfo = fileTag === "application"; if (separateDebugInfo) { variants.map(function (variant) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoFilePath(product, variant.suffix, fileTag)), fileTags: ["debuginfo_" + debugInfoTagSuffix] }); }); if (PathTools.debugInfoIsBundle(product)) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoBundlePath(product, fileTag)), fileTags: ["debuginfo_bundle"] }); artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoPlistFilePath(product, fileTag)), fileTags: ["debuginfo_plist"] }); } } return artifacts; } function dumpMacros(env, compilerFilePath, args, nullDevice, tag) { var p = new Process(); try { p.setEnv("LC_ALL", "C"); for (var key in env) p.setEnv(key, env[key]); // qcc NEEDS the explicit -Wp, prefix to -dM; clang and gcc do not but all three accept it p.exec(compilerFilePath, (args || []).concat(["-Wp,-dM", "-E", "-x", languageName(tag || "c") , nullDevice]), true); return Cpp.extractMacros(p.readStdOut()); } finally { p.close(); } } function dumpDefaultPaths(env, compilerFilePath, args, nullDevice, pathListSeparator, sysroot, targetOS) { var p = new Process(); try { p.setEnv("LC_ALL", "C"); for (var key in env) p.setEnv(key, env[key]); args = args || []; p.exec(compilerFilePath, args.concat(["-v", "-E", "-x", "c++", nullDevice]), true); var suffix = " (framework directory)"; var includePaths = []; var libraryPaths = []; var frameworkPaths = []; var addIncludes = false; var lines = p.readStdErr().trim().split(/\r?\n/g).map(function (line) { return line.trim(); }); for (var i = 0; i < lines.length; ++i) { var line = lines[i]; var prefix = "LIBRARY_PATH="; if (line.startsWith(prefix)) { libraryPaths = libraryPaths.concat(line.substr(prefix.length) .split(pathListSeparator)); } else if (line === "#include <...> search starts here:") { addIncludes = true; } else if (line === "End of search list.") { addIncludes = false; } else if (addIncludes) { if (line.endsWith(suffix)) frameworkPaths.push(line.substr(0, line.length - suffix.length)); else includePaths.push(line); } } sysroot = sysroot || ""; if (includePaths.length === 0) includePaths.push(sysroot + "/usr/include", sysroot + "/usr/local/include"); if (libraryPaths.length === 0) libraryPaths.push(sysroot + "/lib", sysroot + "/usr/lib"); if (frameworkPaths.length === 0 && targetOS.includes("darwin")) frameworkPaths.push(sysroot + "/System/Library/Frameworks"); return { "includePaths": includePaths, "libraryPaths": libraryPaths, "frameworkPaths": frameworkPaths }; } finally { p.close(); } } function targetLinkerFlags(targetArch, targetOS) { var linkerFlags = { "windows": { "i386": "i386pe", "x86_64": "i386pep", }, "freebsd": { "i386": "elf_i386_fbsd", "x86_64": "elf_x86_64_fbsd", }, "other": { "i386": "elf_i386", "x86_64": "elf_x86_64", } }; if (targetOS.includes("windows")) return linkerFlags["windows"][targetArch]; else if (targetOS.includes("freebsd")) return linkerFlags["freebsd"][targetArch]; return linkerFlags["other"][targetArch]; } function targetFlags(tool, hasTargetOption, target, targetArch, machineType, targetOS) { var args = []; if (hasTargetOption) { if (target) args.push("-target", target); } else { var archArgs = { "compiler": { "i386": ["-m32"], "x86_64": ["-m64"], }, "linker": { "i386": ["-m", targetLinkerFlags("i386", targetOS)], "x86_64": ["-m", targetLinkerFlags("x86_64", targetOS)], }, "assembler": { "i386": ["--32"], "x86_64": ["--64"], }, }; var flags = archArgs[tool] ? archArgs[tool][targetArch] : undefined; if (flags) args = args.concat(flags); if (machineType && tool !== "linker") args.push("-march=" + machineType); } return args; } function toolNames(rawToolNames, toolchainPrefix) { return toolchainPrefix ? rawToolNames.map(function(rawName) { return toolchainPrefix + rawName; }) : rawToolNames; } function pathPrefix(baseDir, prefix) { var path = ''; if (baseDir) { path += baseDir; if (path.substr(-1) !== '/') path += '/'; } if (prefix) path += prefix; return path; } function appLinkerOutputArtifacts(product) { var app = { filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.applicationFilePath(product)), fileTags: ["bundle.input", "application"].concat( product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []), bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.bundleExecutableFilePath(product)) } } var artifacts = [app]; if (!product.aggregate) artifacts = artifacts.concat(debugInfoArtifacts(product, undefined, "app")); if (product.cpp.generateLinkerMapFile) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + product.cpp.linkerMapSuffix), fileTags: ["mem_map"] }); } if (product.qbs.toolchain.includes("emscripten")) artifacts = artifacts.concat(wasmArtifacts(product)); return artifacts; } function moduleLinkerOutputArtifacts(product, inputs) { var app = { filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.loadableModuleFilePath(product)), fileTags: ["bundle.input", "loadablemodule"] .concat(product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []), bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.bundleExecutableFilePath(product)) } } var artifacts = [app]; if (!product.aggregate) artifacts = artifacts.concat(debugInfoArtifacts(product, undefined, "loadablemodule")); return artifacts; } function staticLibLinkerOutputArtifacts(product) { var tags = ["bundle.input", "staticlibrary"]; var objs = inputs["obj"]; var objCount = objs ? objs.length : 0; for (var i = 0; i < objCount; ++i) { var ft = objs[i].fileTags; if (ft.includes("c_obj")) tags.push("c_staticlibrary"); if (ft.includes("cpp_obj")) tags.push("cpp_staticlibrary"); } return [{ filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.staticLibraryFilePath(product)), fileTags: tags, bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.bundleExecutableFilePath(product)) } }]; } function staticLibLinkerCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = ['rcs', output.filePath]; for (var i in inputs.obj) args.push(inputs.obj[i].filePath); for (var i in inputs.res) args.push(inputs.res[i].filePath); var cmd = new Command(product.cpp.archiverPath, args); cmd.description = 'creating ' + output.fileName; cmd.highlight = 'linker' cmd.jobPool = "linker"; cmd.responseFileUsagePrefix = '@'; setResponseFileThreshold(cmd, product); return cmd; } function dynamicLibLinkerOutputArtifacts(product) { var artifacts = [{ filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.dynamicLibraryFilePath(product)), fileTags: ["bundle.input", "dynamiclibrary"] .concat(product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []), bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.bundleExecutableFilePath(product)) } }]; if (product.cpp.imageFormat === "pe") { artifacts.push({ fileTags: ["dynamiclibrary_import"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.importLibraryFilePath(product)), alwaysUpdated: false }); } else { // List of libfoo's public symbols for smart re-linking. artifacts.push({ filePath: product.destinationDirectory + "/.sosymbols/" + PathTools.dynamicLibraryFilePath(product), fileTags: ["dynamiclibrary_symbols"], alwaysUpdated: false, }); } artifacts = artifacts.concat(librarySymlinkArtifacts(product)); if (!product.aggregate) artifacts = artifacts.concat(debugInfoArtifacts(product, undefined, "dll")); return artifacts; } function wasmArtifacts(product) { var flags = product.cpp.driverLinkerFlags; var wasmoption = 1; var pthread = false; for (var index in flags) { var option = flags[index]; if (option.indexOf("WASM") !== -1) { option = option.trim(); wasmoption = option.substring(option.length - 1); } else if (option.indexOf("-pthread") !== -1) { pthread = true; } } var artifacts = []; var createAppArtifact = function(fileName) { return { filePath: FileInfo.joinPaths(product.destinationDirectory, fileName), fileTags: ["wasm"] }; }; var suffix = product.cpp.executableSuffix; if (suffix !== ".wasm") { if (suffix === ".html") artifacts.push(createAppArtifact(product.targetName + ".js")); if (pthread) artifacts.push(createAppArtifact(product.targetName + ".worker.js")); } if (wasmoption !== 0 && suffix !== ".wasm") //suffix .wasm will already result in "application".wasm artifacts.push(createAppArtifact(product.targetName + ".wasm")); if (wasmoption == 2) artifacts.push(createAppArtifact(product.targetName + ".wasm.js")); return artifacts; } qbs-src-2.6.1/share/qbs/modules/cpp/macos-gcc.qbs0000644000175100001660000000403214776170045021133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.ModUtils import qbs.Utilities DarwinGCC { priority: 1 condition: qbs.targetOS.includes('macos') && qbs.toolchain && qbs.toolchain.includes('gcc') targetSystem: "macosx" + (minimumMacosVersion || "") minimumDarwinVersion: minimumMacosVersion minimumDarwinVersionCompilerFlag: "-mmacosx-version-min" minimumDarwinVersionLinkerFlag: "-macosx_version_min" libcxxAvailable: base && minimumDarwinVersion && Utilities.versionCompare(minimumDarwinVersion, "10.7") >= 0 } qbs-src-2.6.1/share/qbs/modules/cpp/dmc.js0000644000175100001660000004707614776170045017710 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Cpp = require("cpp.js"); var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function targetFlags(platform, architecture, extender, consoleApp, type) { if (platform === "dos") { if (architecture === "x86_16") { if (extender === "dosz") return ["-mz"]; else if (extender === "dosr") return ["-mr"]; return ["-mc"]; } else if (architecture === "x86") { if (extender === "dosx") return ["-mx"]; else if (extender === "dosp") return ["-mp"]; } } else if (platform === "windows") { var flags = []; if (architecture === "x86_16") { flags.push("-ml"); if (type.includes("application") && !consoleApp) flags.push("-WA"); else if (type.includes("dynamiclibrary")) flags.push("-WD"); } else if (architecture === "x86") { flags.push("-mn"); if (type.includes("application")) flags.push("-WA"); else if (type.includes("dynamiclibrary")) flags.push("-WD"); } return flags; } return []; } function languageFlags(tag) { if (tag === "cpp") return ["-cpp"]; return []; } function dumpMacros(compilerPath, platform, architecture, extender, tag) { // Note: The DMC compiler does not support the predefined/ macros dumping. So, we do it // with the following trick, where we try to create and compile a special temporary file // and to parse the console output with the own magic pattern: #define . var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c"); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); outputFile.writeLine("#define VALUE_TO_STRING(x) #x"); outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)"); outputFile.writeLine("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)"); // Declare all available pre-defined macros of DMC compiler. var keys = [ // Prepare the DOS target macros. "_MSDOS", "MSDOS", // Prepare the OS/2 target macros. "__OS2__", // Prepare the Windows target macros. "WIN32", "_WIN32", "__NT__", // Prepare extended the 32 and 16 bit DOS target macros. "DOS386", "DOS16RM", // Prepare the memory model macros. "M_I86", "_M_I86", "_M_I86TM", "M_I86TM", "_M_I86SM", "M_I86SM", "_M_I86MM", "M_I86MM", "_M_I86CM", "M_I86CM", "_M_I86LM", "M_I86LM", "_M_I86VM", "M_I86VM", // Prepare 8086 macros. "_M_I8086", "M_I8086", // Prepare 286 macros. "_M_I286", "M_I286", // Prepare 32 bit macros. "_M_IX86", // Prepare compiler identification macros. "__DMC__", "__DMC_VERSION_STRING__", // Prepare common compiler macros. "_CHAR_UNSIGNED", "_CHAR_EQ_UCHAR", "_DEBUG_TRACE", "_DLL", "_ENABLE_ARRAYNEW", "_BOOL_DEFINED", "_WCHAR_T_DEFINED", "_CPPRTTI", "_CPPUNWIND", "_MD", "_PUSHPOP_SUPPORTED", "_STDCALL_SUPPORTED", "__INTSIZE", "__DEFALIGN", "_INTEGRAL_MAX_BITS", "_WINDOWS", "_WINDLL", "__INLINE_8087", "__I86__", "__SMALL__", "__MEDIUM__", "__COMPACT__", "__LARGE__", "__VCM__", "__FPCE__", "__FPCE__IEEE__", "DEBUG", // Prepare C99 and C++98 macros. "__STDC__", "__STDC_HOSTED__", "__STDC_VERSION__", "__STDC_IEC_559__", "__STDC_IEC_559_COMPLEX__", "__STDC_ISO_10646__", "__cplusplus" ]; for (var i = 0; i < keys.length; ++i) { var key = keys[i]; outputFile.writeLine("#if defined (" + key + ")"); outputFile.writeLine("#pragma message (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("#endif"); } outputFile.close(); var process = new Process(); process.setWorkingDirectory(outputDirectory.path()); var lang = languageFlags(tag); var target = targetFlags(platform, architecture, extender, false, ["application"]); var args = ["-c"].concat(lang, target, FileInfo.toWindowsSeparators(outputFilePath)); process.exec(compilerPath, args, false); File.remove(outputFilePath); var out = process.readStdOut(); return Cpp.extractMacros(out); } function dumpDefaultPaths(compilerFilePath, tag) { var binPath = FileInfo.path(compilerFilePath); var rootPath = FileInfo.path(binPath); var includePaths = []; var cppIncludePath = FileInfo.joinPaths(rootPath, "stlport/stlport"); if (File.exists(cppIncludePath)) includePaths.push(cppIncludePath); var cIncludePath = FileInfo.joinPaths(rootPath, "include"); if (File.exists(cIncludePath)) includePaths.push(cIncludePath); var libraryPaths = []; var libraryPath = FileInfo.joinPaths(rootPath, "lib"); if (File.exists(libraryPath)) libraryPaths.push(libraryPath); return { "includePaths": includePaths, "libraryPaths": libraryPaths, } } function guessVersion(macros) { var version = macros["__DMC__"]; return { major: parseInt(version / 100), minor: parseInt(version % 100), patch: 0 }; } function effectiveLinkerPath(product) { if (product.cpp.linkerMode === "automatic") { var compilerPath = product.cpp.compilerPath; if (compilerPath) return compilerPath; console.log("Found no C-language objects, choosing system linker for " + product.name); } return product.cpp.linkerPath; } function useCompilerDriverLinker(product) { var linker = effectiveLinkerPath(product); var compilers = product.cpp.compilerPathByLanguage; if (compilers) return linker === compilers["cpp"] || linker === compilers["c"]; return linker === product.cpp.compilerPath; } function depsOutputTags() { return ["dep"]; } function depsOutputArtifacts(input, product) { return [{ fileTags: depsOutputTags(), filePath: FileInfo.joinPaths(product.destinationDirectory, input.baseName + ".dep") }]; } function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = ["-c"]; var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); args = args.concat(languageFlags(tag)); args = args.concat(targetFlags(product.qbs.targetPlatform, product.qbs.architecture, product.cpp.extenderName, product.consoleApplication, product.type)); // Input. args.push(FileInfo.toWindowsSeparators(input.filePath)); // Output. args.push("-o" + FileInfo.toWindowsSeparators(outputs.obj[0].filePath)); // Preinclude headers. args = args.concat(Cpp.collectPreincludePaths(input).map(function(path) { return input.cpp.preincludeFlag + FileInfo.toWindowsSeparators(path); })); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); if (tag === "cpp") { // We need to add the paths to the STL includes, because the DMC compiler does // not handle it by default (because the STL libraries is a separate port). var compilerIncludePaths = input.cpp.compilerIncludePaths || []; args = args.concat(compilerIncludePaths.map(function(path) { return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path); })); } // Other includes. args = args.concat(Cpp.collectIncludePaths(input).map(function(path) { return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path); })); args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) { return input.cpp.systemIncludeFlag + FileInfo.toWindowsSeparators(path); })); // Debug information flags. if (input.cpp.debugInformation) args.push("-d"); // Optimization flags. switch (input.cpp.optimization) { case "small": args.push("-o+space"); break; case "fast": args.push("-o+speed"); break; case "none": args.push("-o+none"); break; } // Warning level flags. switch (input.cpp.warningLevel) { case "none": args.push("-w"); break; case "all": args.push("-w-"); break; } if (input.cpp.treatWarningsAsErrors) args.push("-wx"); if (tag === "cpp") { // Exceptions flag. if (input.cpp.enableExceptions) args.push("-Ae"); // RTTI flag. var enableRtti = input.cpp.enableRtti; if (input.cpp.enableRtti) args.push("-Ar"); } // Listing files generation flag. if (input.cpp.generateCompilerListingFiles) { // We need to use the relative path here, because the DMC compiler does not handle // a long file path for this option. var listingPath = Cpp.relativePath(product.buildDirectory, outputs.lst[0].filePath); args.push("-l" + FileInfo.toWindowsSeparators(listingPath)); } // Misc flags. args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(product)); return args; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = ["-c"]; // Input. args.push(FileInfo.toWindowsSeparators(input.filePath)); // Output. args.push("-o" + FileInfo.toWindowsSeparators(outputs.obj[0].filePath)); // Preinclude headers. args = args.concat(Cpp.collectPreincludePaths(input).map(function(path) { return input.cpp.preincludeFlag + FileInfo.toWindowsSeparators(path); })); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); // Other includes. args = args.concat(Cpp.collectIncludePaths(input).map(function(path) { return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path); })); args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) { return input.cpp.systemIncludeFlag + FileInfo.toWindowsSeparators(path); })); // Misc flags. args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; var useCompilerDriver = useCompilerDriverLinker(product); if (useCompilerDriver) { args = args.concat(targetFlags(product.qbs.targetPlatform, product.qbs.architecture, product.cpp.extenderName, product.consoleApplication, product.type)); // Input objects. args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) { return FileInfo.toWindowsSeparators(path); })); // Input resources. args = args.concat(Cpp.collectResourceObjectPaths(inputs).map(function(path) { return FileInfo.toWindowsSeparators(path); })); // Input libraries. args = args.concat(Cpp.collectAbsoluteLibraryDependencyPaths(product).map(function(path) { return FileInfo.toWindowsSeparators(path); })); // Output. if (product.type.includes("application")) { args.push("-o" + FileInfo.toWindowsSeparators(outputs.application[0].filePath)); args.push("-L/" + (product.cpp.generateLinkerMapFile ? "MAP" : "NOMAP")); if (product.qbs.targetPlatform === "windows" && product.qbs.architecture === "x86") args.push("-L/SUBSYSTEM:" + (product.consoleApplication ? "CONSOLE" : "WINDOWS")); } else if (product.type.includes("dynamiclibrary")) { args.push("-o" + FileInfo.toWindowsSeparators(outputs.dynamiclibrary[0].filePath)); if (product.qbs.targetPlatform === "windows" && product.qbs.architecture === "x86") { args.push("kernel32.lib"); args.push("-L/IMPLIB:" + FileInfo.toWindowsSeparators( outputs.dynamiclibrary_import[0].filePath)); } } if (product.cpp.debugInformation) args.push("-L/DEBUG"); args.push("-L/NOLOGO", "-L/SILENT"); } // Misc flags. args = args.concat(Cpp.collectMiscEscapableLinkerArguments(product), Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); return args; } function archiverFlags(project, product, inputs, outputs) { var args = ["-c"]; // Output. args.push(FileInfo.toWindowsSeparators(outputs.staticlibrary[0].filePath)); // Input objects. args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) { return FileInfo.toWindowsSeparators(path); })); return args; } function rccCompilerFlags(project, product, input, outputs) { // Input. var args = [FileInfo.toWindowsSeparators(input.filePath)]; // Output. args.push("-o" + FileInfo.toWindowsSeparators(outputs.res[0].filePath)); // Bitness. args.push("-32"); // Defines args = args.concat(Cpp.collectDefinesArguments(input)); // Other includes. args = args.concat(Cpp.collectIncludePaths(input).map(function(path) { return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path); })); args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) { return input.cpp.systemIncludeFlag + FileInfo.toWindowsSeparators(path); })); return args; } function buildLinkerMapFilePath(target, suffix) { return FileInfo.joinPaths(FileInfo.path(target.filePath), FileInfo.completeBaseName(target.fileName) + suffix); } // It is a workaround which removes the generated linker map file if it is disabled // by cpp.generateLinkerMapFile property. Reason is that the DMC compiler always // generates this file, and does not have an option to disable generation for a linker // map file. So, we can to remove a listing files only after the linking completes. function removeLinkerMapFile(project, product, inputs, outputs, input, output) { var target = outputs.dynamiclibrary ? outputs.dynamiclibrary[0] : outputs.application[0]; var cmd = new JavaScriptCommand(); cmd.mapFilePath = buildLinkerMapFilePath(target, ".map") cmd.silent = true; cmd.sourceCode = function() { File.remove(mapFilePath); }; return cmd; } // It is a workaround to rename the extension of the output linker map file to the // specified one, since the linker generates only files with the '.map' extension. function renameLinkerMapFile(project, product, inputs, outputs, input, output) { var target = outputs.dynamiclibrary ? outputs.dynamiclibrary[0] : outputs.application[0]; var cmd = new JavaScriptCommand(); cmd.newMapFilePath = buildLinkerMapFilePath(target, product.cpp.linkerMapSuffix); cmd.oldMapFilePath = buildLinkerMapFilePath(target, ".map"); cmd.silent = true; cmd.sourceCode = function() { if (oldMapFilePath !== newMapFilePath) File.move(oldMapFilePath, newMapFilePath); }; return cmd; } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); var cmd = new Command(input.cpp.compilerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; return [cmd]; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn); var cmd = new Command(input.cpp.assemblerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "assembler"; return [cmd]; } function prepareLinker(project, product, inputs, outputs, input, output) { var cmds = []; var primaryOutput = outputs.dynamiclibrary ? outputs.dynamiclibrary[0] : outputs.application[0]; var args = linkerFlags(project, product, inputs, outputs); var linkerPath = effectiveLinkerPath(product); var cmd = new Command(linkerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; cmds.push(cmd); if (product.cpp.generateLinkerMapFile) cmds.push(renameLinkerMapFile(project, product, inputs, outputs, input, output)); else cmds.push(removeLinkerMapFile(project, product, inputs, outputs, input, output)); return cmds; } function prepareArchiver(project, product, inputs, outputs, input, output) { var args = archiverFlags(project, product, inputs, outputs); var cmd = new Command(product.cpp.archiverPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "creating " + output.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; return [cmd]; } function prepareRccCompiler(project, product, inputs, outputs, input, output) { var args = rccCompilerFlags(project, product, input, outputs); var cmd = new Command(input.cpp.rccCompilerPath, args); cmd.workingDirectory = product.buildDirectory; cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/cpp/watchos-gcc.qbs0000644000175100001660000000427014776170045021505 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ DarwinGCC { priority: 1 condition: qbs.targetOS.includes('watchos') && qbs.toolchain && qbs.toolchain.includes('gcc') targetSystem: "watchos" + (minimumWatchosVersion || "") minimumDarwinVersion: minimumWatchosVersion minimumDarwinVersionCompilerFlag: qbs.targetOS.includes("watchos-simulator") ? "-mwatchos-simulator-version-min" : "-mwatchos-version-min" minimumDarwinVersionLinkerFlag: qbs.targetOS.includes("watchos-simulator") ? "-watchos_simulator_version_min" : "-watchos_version_min" } qbs-src-2.6.1/share/qbs/modules/cpp/UnixGCC.qbs0000644000175100001660000000371214776170045020543 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File GenericGCC { condition: qbs.toolchain && qbs.toolchain.includes("gcc") && qbs.targetOS.includes("unix") priority: -50 dynamicLibraryPrefix: "lib" loadableModulePrefix: "lib" dynamicLibrarySuffix: ".so" debugInfoSuffix: ".debug" imageFormat: "elf" systemRunPaths: ["/lib", "/usr/lib"].filter(function(p) { return File.exists(p); }) rpathOrigin: "$ORIGIN" useRPathLink: true rpathLinkFlag: "-rpath-link=" } qbs-src-2.6.1/share/qbs/modules/cpp/msvc.js0000644000175100001660000007474714776170045020122 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Codesign = require("../codesign/codesign.js"); var Cpp = require("cpp.js"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Utilities = require("qbs.Utilities"); var WindowsUtils = require("qbs.WindowsUtils"); function effectiveLinkerPath(product, inputs) { if (product.cpp.linkerMode === "automatic") { var compiler = product.cpp.compilerPath; if (compiler) { if (inputs.obj || inputs.staticlibrary) { console.log("Found C/C++ objects, using compiler as a linker for " + product.name); return compiler; } } console.log("Found no C-language objects, choosing system linker for " + product.name); } return product.cpp.linkerPath; } function handleCpuFeatures(input, flags) { if (!input.qbs.architecture) return; if (input.qbs.architecture.startsWith("x86")) { if (input.qbs.architecture === "x86") { var sse2 = input.cpufeatures.x86_sse2; if (sse2 === true) flags.push("/arch:SSE2"); if (sse2 === false) flags.push("/arch:IA32"); } if (input.cpufeatures.x86_avx === true) flags.push("/arch:AVX"); if (input.cpufeatures.x86_avx2 === true) flags.push("/arch:AVX2"); } else if (input.qbs.architecture.startsWith("arm")) { if (input.cpufeatures.arm_vfpv4 === true) flags.push("/arch:VFPv4"); if (input.cpp.machineType === "armv7ve") flags.push("/arch:ARMv7VE"); } } function hasCxx17Option(input) { // Probably this is not the earliest version to support the flag, but we have tested this one // and it's a pain to find out the exact minimum. return (input.qbs.toolchain.includes("clang-cl") && input.cpp.compilerVersionMajor >= 7) || Utilities.versionCompare(input.cpp.compilerVersion, "19.12.25831") >= 0; } function hasZCplusPlusOption(input) { // /Zc:__cplusplus is supported starting from Visual Studio 15.7 // Looks like closest MSVC version is 14.14.26428 (cl ver 19.14.26433) // At least, this version is tested // https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus // clang-cl supports this option starting around-ish versions 8/9, but it // ignores this option, so this doesn't really matter // https://reviews.llvm.org/D45877 return (input.qbs.toolchain.includes("clang-cl") && input.cpp.compilerVersionMajor >= 9) || Utilities.versionCompare(input.cpp.compilerVersion, "19.14.26433") >= 0; } function hasCxx20Option(input) { return (input.qbs.toolchain.includes("clang-cl") && input.cpp.compilerVersionMajor >= 13) || Utilities.versionCompare(input.cpp.compilerVersion, "19.29.30133.0") >= 0; } function hasCVerOption(input) { return (input.qbs.toolchain.includes("clang-cl") && input.cpp.compilerVersionMajor >= 13) || Utilities.versionCompare(input.cpp.compilerVersion, "19.29.30138.0") >= 0; } function supportsExternalIncludesOption(input) { if (input.qbs.toolchain.includes("clang-cl")) return false; // Exclude clang-cl. // This option was introcuded since MSVC 2017 v15.6 (aka _MSC_VER 19.13). // But due to some MSVC bugs: // * https://developercommunity.visualstudio.com/content/problem/181006/externali-include-paths-not-working.html // this option has been fixed since MSVC 2017 update 9, v15.9 (aka _MSC_VER 19.16). return Utilities.versionCompare(input.cpp.compilerVersion, "19.16") >= 0; } function addCxxLanguageVersionFlag(input, args) { var cxxVersion = Cpp.languageVersion(input.cpp.cxxLanguageVersion, ["c++23", "c++20", "c++17", "c++14", "c++11", "c++98"], "C++"); if (!cxxVersion) return; // Visual C++ 2013, Update 3 or clang-cl var hasStdOption = input.qbs.toolchain.includes("clang-cl") || Utilities.versionCompare(input.cpp.compilerVersion, "18.00.30723") >= 0; if (!hasStdOption) return; var flag; if (cxxVersion === "c++14") flag = "/std:c++14"; else if (cxxVersion === "c++17" && hasCxx17Option(input)) flag = "/std:c++17"; else if (cxxVersion === "c++20" && hasCxx20Option(input)) flag = "/std:c++20"; else if (cxxVersion !== "c++11" && cxxVersion !== "c++98") flag = "/std:c++latest"; if (flag) args.push(flag); } function addCLanguageVersionFlag(input, args) { var cVersion = Cpp.languageVersion(input.cpp.cLanguageVersion, ["c17", "c11"], "C"); if (!cVersion) return; var hasStdOption = hasCVerOption(input); if (!hasStdOption) return; var flag; if (cVersion === "c17") flag = "/std:c17"; else if (cVersion === "c11") flag = "/std:c11"; if (flag) args.push(flag); } function handleClangClArchitectureFlags(product, architecture, flags) { if (product.qbs.toolchain.includes("clang-cl")) { if (architecture === "x86") flags.push("-m32"); else if (architecture === "x86_64") flags.push("-m64"); } } function prepareCompilerInternal(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var i; var debugInformation = input.cpp.debugInformation; var args = ['/nologo', '/c'] handleCpuFeatures(input, args); // Determine which C-language we're compiling var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(Object.keys(outputs))); if (!["c", "cpp", "cppm"].includes(tag)) throw ("unsupported source language"); var enableExceptions = input.cpp.enableExceptions; if (enableExceptions) { var ehModel = input.cpp.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 = input.cpp.enableRtti; if (enableRtti !== undefined) { args.push(enableRtti ? "/GR" : "/GR-"); } switch (input.cpp.optimization) { case "small": args.push('/Os') break; case "fast": args.push('/O2') break; case "none": args.push("/Od"); break; } handleClangClArchitectureFlags(product, input.cpp.architecture, args); if (debugInformation) { if (product.cpp.separateDebugInformation) args.push('/Zi'); else args.push('/Z7'); } var rtl = product.cpp.runtimeLibrary; if (rtl) { rtl = (rtl === "static" ? "/MT" : "/MD"); if (product.qbs.enableDebugCode) rtl += "d"; args.push(rtl); } args = args.concat(Cpp.collectMiscDriverArguments(product)); // warnings: var warningLevel = input.cpp.warningLevel; if (warningLevel === 'none') args.push('/w') if (warningLevel === 'all') args.push('/Wall') if (input.cpp.treatWarningsAsErrors) args.push('/WX') var includePaths = Cpp.collectIncludePaths(input); args = args.concat([].uniqueConcat(includePaths).map(function(path) { return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path); })); var includeFlag = input.qbs.toolchain.includes("clang-cl") ? input.cpp.systemIncludeFlag : input.cpp.includeFlag; if (!input.qbs.toolchain.includes("clang-cl")) { if (supportsExternalIncludesOption(input)) { args.push("/experimental:external"); var enforcesSlashW = Utilities.versionCompare(input.cpp.compilerVersion, "19.29.30037") >= 0 if (enforcesSlashW) args.push("/external:W0") includeFlag = input.cpp.systemIncludeFlag; } } var systemIncludePaths = Cpp.collectSystemIncludePaths(input); args = args.concat([].uniqueConcat(systemIncludePaths).map(function(path) { return includeFlag + FileInfo.toWindowsSeparators(path); })); var defines = Cpp.collectDefines(input); args = args.concat([].uniqueConcat(defines).map(function(define) { return input.cpp.defineFlag + define.replace(/%/g, "%%"); })); var minimumWindowsVersion = product.cpp.minimumWindowsVersion; if (minimumWindowsVersion) { var hexVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion, 'hex'); if (hexVersion) { var versionDefs = [ 'WINVER', '_WIN32_WINNT', '_WIN32_WINDOWS' ]; for (i in versionDefs) { args.push(input.cpp.defineFlag + versionDefs[i] + '=' + hexVersion); } } } if (product.cpp.debugInformation && product.cpp.separateDebugInformation) args.push("/Fd" + product.targetName + ".cl" + product.cpp.debugInfoSuffix); if (input.cpp.generateCompilerListingFiles) args.push("/Fa" + FileInfo.toWindowsSeparators(outputs.lst[0].filePath)); if (input.cpp.enableCxxLanguageMacro && hasZCplusPlusOption(input)) args.push("/Zc:__cplusplus"); var objectMap = outputs.obj || outputs.intermediate_obj var objOutput = objectMap ? objectMap[0] : undefined args.push('/Fo' + FileInfo.toWindowsSeparators(objOutput.filePath)) args.push(FileInfo.toWindowsSeparators(input.filePath)) var preincludePaths = Cpp.collectPreincludePaths(input); args = args.concat([].uniqueConcat(preincludePaths).map(function(path) { return input.cpp.preincludeFlag + FileInfo.toWindowsSeparators(path); })); // Language if (tag === "cpp" || tag === "cppm") { args.push("/TP"); addCxxLanguageVersionFlag(input, args); } else if (tag === "c") { args.push("/TC"); addCLanguageVersionFlag(input, args); } var moduleMap = (outputs["modulemap"] || [])[0]; if (moduleMap) { args.push("@" + moduleMap.filePath); } // Whether we're compiling a precompiled header or normal source file var pchOutput = outputs[tag + "_pch"] ? outputs[tag + "_pch"][0] : undefined; var pchInputs = explicitlyDependsOn[tag + "_pch"]; if (pchOutput) { // create PCH if (input.qbs.toolchain.includes("clang-cl")) { // clang-cl does not support /Yc flag without filename args.push("/Yc" + FileInfo.toWindowsSeparators(input.filePath)); // clang-cl complains when pch file is not included args.push("/FI" + FileInfo.toWindowsSeparators(input.filePath)); args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath)); args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath)); } else { // real msvc args.push("/Yc"); args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath)); args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath)); args.push(FileInfo.toWindowsSeparators(input.filePath)); } } else if (pchInputs && pchInputs.length === 1 && ModUtils.moduleProperty(input, "usePrecompiledHeader", tag)) { // use PCH var pchSourceArtifacts = product.artifacts[tag + "_pch_src"]; if (pchSourceArtifacts && pchSourceArtifacts.length > 0) { var pchSourceFilePath = pchSourceArtifacts[0].filePath; var pchFilePath = FileInfo.toWindowsSeparators(pchInputs[0].filePath); args.push("/FI" + pchSourceFilePath); args.push("/Yu" + pchSourceFilePath); args.push("/Fp" + pchFilePath); } else { console.warning("products." + product.name + ".usePrecompiledHeader is true, " + "but there is no " + tag + "_pch_src artifact."); } } args = args.concat(Cpp.collectMiscCompilerArguments(input, tag)); var compilerPath = product.cpp.compilerPath; var wrapperArgs = product.cpp.compilerWrapper; if (wrapperArgs && wrapperArgs.length > 0) { args.unshift(compilerPath); compilerPath = wrapperArgs.shift(); args = wrapperArgs.concat(args); } var cmd = new Command(compilerPath, args) cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + input.fileName; if (pchOutput) cmd.description += ' (' + tag + ')'; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; cmd.workingDirectory = product.buildDirectory; cmd.responseFileUsagePrefix = '@'; // cl.exe outputs the cpp file name. We filter that out. cmd.inputFileName = input.fileName; cmd.relevantEnvironmentVariables = ["CL", "_CL_", "INCLUDE"]; cmd.stdoutFilterFunction = function(output) { return output.split(inputFileName + "\r\n").join(""); }; return [cmd]; } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var result = Cpp.prepareModules(project, product, inputs, outputs, input, output); result = result.concat(prepareCompilerInternal( project, product, inputs, outputs, input, output, explicitlyDependsOn)); return result; } function linkerSupportsWholeArchive(product) { return product.qbs.toolchainType.includes("clang-cl") || Utilities.versionCompare(product.cpp.compilerVersion, "19.0.24215.1") >= 0 } function handleDiscardProperty(product, flags) { var discardUnusedData = product.cpp.discardUnusedData; if (discardUnusedData === true) flags.push("/OPT:REF"); else if (discardUnusedData === false) flags.push("/OPT:NOREF"); } function prepareLinker(project, product, inputs, outputs, input, output) { var i; var linkDLL = (outputs.dynamiclibrary ? true : false) var primaryOutput = (linkDLL ? outputs.dynamiclibrary[0] : outputs.application[0]) var debugInformation = product.cpp.debugInformation; var additionalManifestInputs = Array.prototype.map.call(inputs["native.pe.manifest"] || [], function (a) { return a.filePath; }); var moduleDefinitionInputs = Array.prototype.map.call(inputs["def"] || [], function (a) { return a.filePath; }); var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile; var useClangCl = product.qbs.toolchain.includes("clang-cl"); var canEmbedManifest = useClangCl || product.cpp.compilerVersionMajor >= 17 // VS 2012 var linkerPath = effectiveLinkerPath(product, inputs); var useCompilerDriver = linkerPath === product.cpp.compilerPath; // args variable is built as follows: // [linkerWrapper] linkerPath /nologo [driverFlags driverLinkerFlags] // allInputs libDeps [/link] linkerArgs var args = [] if (useCompilerDriver) { args.push('/nologo'); args = args.concat(Cpp.collectMiscDriverArguments(product), Cpp.collectMiscLinkerArguments(product)); } var allInputs = [].concat(Cpp.collectLinkerObjectPaths(inputs), Cpp.collectResourceObjectPaths(inputs)); args = args.concat([].uniqueConcat(allInputs).map(function(path) { return FileInfo.toWindowsSeparators(path); })); var linkerArgs = ['/nologo'] if (linkDLL) { linkerArgs.push('/DLL'); linkerArgs.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath)); } if (debugInformation) { linkerArgs.push("/DEBUG"); var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll; if (debugInfo) linkerArgs.push("/PDB:" + debugInfo[0].fileName); } else { linkerArgs.push('/INCREMENTAL:NO') } switch (product.qbs.architecture) { case "x86": linkerArgs.push("/MACHINE:X86"); break; case "x86_64": linkerArgs.push("/MACHINE:X64"); break; case "ia64": linkerArgs.push("/MACHINE:IA64"); break; case "armv7": linkerArgs.push("/MACHINE:ARM"); break; case "arm64": linkerArgs.push("/MACHINE:ARM64"); break; } if (useCompilerDriver) handleClangClArchitectureFlags(product, product.qbs.architecture, args); var requireAppContainer = product.cpp.requireAppContainer; if (requireAppContainer !== undefined) linkerArgs.push("/APPCONTAINER" + (requireAppContainer ? "" : ":NO")); var minimumWindowsVersion = product.cpp.minimumWindowsVersion; var subsystemSwitch = undefined; if (minimumWindowsVersion || product.consoleApplication !== undefined) { // Ensure that we default to console if product.consoleApplication is undefined // since that could still be the case if only minimumWindowsVersion had been defined subsystemSwitch = product.consoleApplication === false ? '/SUBSYSTEM:WINDOWS' : '/SUBSYSTEM:CONSOLE'; } var useLldLink = useCompilerDriver && product.cpp.linkerVariant === "lld" || !useCompilerDriver && product.cpp.linkerName === "lld-link.exe"; if (minimumWindowsVersion) { var subsystemVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion, 'subsystem'); if (subsystemVersion) { subsystemSwitch += ',' + subsystemVersion; // llvm linker does not support /OSVERSION if (!useLldLink) linkerArgs.push('/OSVERSION:' + subsystemVersion); } } if (subsystemSwitch) linkerArgs.push(subsystemSwitch); var linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath); var manifestFileNames = []; if (generateManifestFiles) { if (canEmbedManifest) { linkerArgs.push("/MANIFEST:embed"); additionalManifestInputs.forEach(function (manifestFileName) { linkerArgs.push("/MANIFESTINPUT:" + manifestFileName); }); } else { linkerOutputNativeFilePath = FileInfo.toWindowsSeparators( FileInfo.path(primaryOutput.filePath) + "/intermediate." + primaryOutput.fileName); var manifestFileName = linkerOutputNativeFilePath + ".manifest"; linkerArgs.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName); manifestFileNames = [manifestFileName].concat(additionalManifestInputs); } } if (moduleDefinitionInputs.length === 1) linkerArgs.push("/DEF:" + moduleDefinitionInputs[0]); else if (moduleDefinitionInputs.length > 1) throw new Error("Only one '.def' file can be specified for linking"); var wholeArchiveSupported = linkerSupportsWholeArchive(product); var wholeArchiveRequested = false; var libDeps = Cpp.collectLibraryDependencies(product); var prevLib; for (i = 0; i < libDeps.length; ++i) { var dep = libDeps[i]; var lib = dep.filePath; if (lib === prevLib) continue; prevLib = lib; if (wholeArchiveSupported && dep.wholeArchive) { // need to pass libraries to the driver to avoid "no input files" error if no object // files are specified; thus libraries are duplicated when using "WHOLEARCHIVE" if (useCompilerDriver && allInputs.length === 0) args.push(FileInfo.toWindowsSeparators(lib)); linkerArgs.push("/WHOLEARCHIVE:" + FileInfo.toWindowsSeparators(lib)); } else { args.push(FileInfo.toWindowsSeparators(lib)); } if (dep.wholeArchive) wholeArchiveRequested = true; } if (wholeArchiveRequested && !wholeArchiveSupported) { console.warn("Product '" + product.name + "' sets cpp.linkWholeArchive on a dependency, " + "but your linker does not support the /WHOLEARCHIVE option. " + "Please upgrade to Visual Studio 2015 Update 2 or higher."); } if (product.cpp.entryPoint) linkerArgs.push("/ENTRY:" + product.cpp.entryPoint); if (outputs.application && product.cpp.generateLinkerMapFile) { if (useLldLink) linkerArgs.push("/lldmap:" + outputs.mem_map[0].filePath); else linkerArgs.push("/MAP:" + outputs.mem_map[0].filePath); } if (useCompilerDriver) args.push('/Fe' + linkerOutputNativeFilePath); else linkerArgs.push('/OUT:' + linkerOutputNativeFilePath); var libraryPaths = Cpp.collectLibraryPaths(product); linkerArgs = linkerArgs.concat([].uniqueConcat(libraryPaths).map(function(path) { return product.cpp.libraryPathFlag + FileInfo.toWindowsSeparators(path); })); handleDiscardProperty(product, linkerArgs); var linkerFlags = product.cpp.platformLinkerFlags.concat(product.cpp.linkerFlags); linkerArgs = linkerArgs.concat(linkerFlags); if (product.cpp.allowUnresolvedSymbols) linkerArgs.push("/FORCE:UNRESOLVED"); var wrapperArgs = product.cpp.linkerWrapper; if (wrapperArgs && wrapperArgs.length > 0) { args.unshift(linkerPath); linkerPath = wrapperArgs.shift(); args = wrapperArgs.concat(args); } var commands = []; var warningCmd = new JavaScriptCommand(); warningCmd.silent = true; warningCmd.libDeps = libDeps; warningCmd.sourceCode = function() { for (var i = 0; i < libDeps.length; ++i) { if (!libDeps[i].productName || File.exists(libDeps[i].filePath)) continue; console.warn("Import library '" + FileInfo.toNativeSeparators(libDeps[i].filePath) + "' does not exist. This typically happens when a DLL does not " + "export any symbols. Please make sure the '" + libDeps[i].productName + "' library exports symbols, or, if you do not intend to actually " + "link against it, specify \"cpp.link: false\" in the Depends item."); } }; commands.push(warningCmd); if (linkerArgs.length !== 0) args = args.concat(useCompilerDriver ? ['/link'] : []).concat(linkerArgs); var cmd = new Command(linkerPath, args) cmd.description = 'linking ' + primaryOutput.fileName; cmd.highlight = 'linker'; cmd.jobPool = "linker"; cmd.relevantEnvironmentVariables = ["LINK", "_LINK_", "LIB", "TMP"]; cmd.workingDirectory = FileInfo.path(primaryOutput.filePath) cmd.responseFileUsagePrefix = '@'; cmd.responseFileSeparator = useCompilerDriver ? ' ' : '\n'; cmd.stdoutFilterFunction = function(output) { res = output.replace(/^.*performing full link.*\s*/, ""); res = res.replace(/^ *Creating library.*\s*/, ""); res = res.replace(/^\s*Generating code\s*/, ""); res = res.replace(/^\s*Finished generating code\s*/, ""); return res; }; commands.push(cmd); if (generateManifestFiles && !canEmbedManifest) { var outputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath); cmd = new JavaScriptCommand(); cmd.src = linkerOutputNativeFilePath; cmd.dst = outputNativeFilePath; cmd.sourceCode = function() { File.copy(src, dst); } cmd.silent = true commands.push(cmd); args = ['/nologo', '/manifest'].concat(manifestFileNames); args.push("/outputresource:" + outputNativeFilePath + ";#" + (linkDLL ? "2" : "1")); cmd = new Command("mt.exe", args) cmd.description = 'embedding manifest into ' + primaryOutput.fileName; cmd.highlight = 'linker'; cmd.workingDirectory = FileInfo.path(primaryOutput.filePath) commands.push(cmd); } if (product.cpp.shouldSignArtifacts) { Array.prototype.push.apply( commands, Codesign.prepareSigntool( project, product, inputs, outputs, input, output)); } return commands; } function createRcCommand(binary, input, output, logo) { var platformDefines = input.cpp.platformDefines; var defines = input.cpp.defines; var includePaths = input.cpp.includePaths; var systemIncludePaths = input.cpp.systemIncludePaths; var args = []; if (logo === "can-suppress-logo") args.push("/nologo"); for (i in platformDefines) { args.push("/d"); args.push(platformDefines[i]); } for (i in defines) { args.push("/d"); args.push(defines[i]); } for (i in includePaths) { args.push("/I"); args.push(includePaths[i]); } for (i in systemIncludePaths) { args.push("/I"); args.push(systemIncludePaths[i]); } args = args.concat(["/FO", output.filePath, input.filePath]); var cmd = new Command(binary, args); cmd.description = 'compiling ' + input.fileName; cmd.highlight = 'compiler'; cmd.jobPool = "compiler"; if (logo === "always-shows-logo") { // Remove the first two lines of stdout. That's the logo. cmd.stdoutFilterFunction = function(output) { var idx = 0; for (var i = 0; i < 3; ++i) idx = output.indexOf('\n', idx + 1); return output.substr(idx + 1); } } return cmd; } function assemblerCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = ["/nologo", "/c", "/Fo" + FileInfo.toWindowsSeparators(output.filePath)]; if (product.cpp.debugInformation) args.push("/Zi"); args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); args.push(FileInfo.toWindowsSeparators(input.filePath)); var cmd = new Command(product.cpp.assemblerPath, args); cmd.description = "assembling " + input.fileName; cmd.jobPool = "assembler"; cmd.inputFileName = input.fileName; cmd.stdoutFilterFunction = function(output) { var lines = output.split("\r\n").filter(function (s) { return !s.endsWith(inputFileName); }); return lines.join("\r\n"); }; return cmd; } function libtoolOutputArtifacts(product) { var artifacts = [ { fileTags: ["staticlibrary"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.staticLibraryFilePath(product)) } ]; if (product.cpp.debugInformation && product.cpp.separateDebugInformation) { artifacts.push({ fileTags: ["debuginfo_cl"], filePath: product.targetName + ".cl" + product.cpp.debugInfoSuffix }); } return artifacts; } function libtoolCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = ['/nologo'] var lib = outputs["staticlibrary"][0]; var nativeOutputFileName = FileInfo.toWindowsSeparators(lib.filePath) args.push('/OUT:' + nativeOutputFileName) for (var i in inputs.obj) { var fileName = FileInfo.toWindowsSeparators(inputs.obj[i].filePath) args.push(fileName) } for (var i in inputs.res) { var fileName = FileInfo.toWindowsSeparators(inputs.res[i].filePath) args.push(fileName) } var cmd = new Command("lib.exe", args); cmd.description = 'creating ' + lib.fileName; cmd.highlight = 'linker'; cmd.jobPool = "linker"; cmd.workingDirectory = FileInfo.path(lib.filePath) cmd.responseFileUsagePrefix = '@'; return cmd; } function dllLinkerOutputArtifacts(product) { var artifacts = [ { fileTags: ["dynamiclibrary"].concat( product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []), filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.dynamicLibraryFilePath(product)) }, { fileTags: ["dynamiclibrary_import"], filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.importLibraryFilePath(product)), alwaysUpdated: false } ]; if (product.cpp.debugInformation && product.cpp.separateDebugInformation) { var lib = artifacts[0]; artifacts.push({ fileTags: ["debuginfo_dll"], filePath: lib.filePath.substr(0, lib.filePath.length - 4) + product.cpp.debugInfoSuffix }); } return artifacts; } function appLinkerOutputArtifacts(product) { var app = { fileTags: ["application"].concat( product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []), filePath: FileInfo.joinPaths( product.destinationDirectory, PathTools.applicationFilePath(product)) }; var artifacts = [app]; if (product.cpp.debugInformation && product.cpp.separateDebugInformation) { artifacts.push({ fileTags: ["debuginfo_app"], filePath: app.filePath.substr(0, app.filePath.length - 4) + product.cpp.debugInfoSuffix }); } if (product.cpp.generateLinkerMapFile) { artifacts.push({ fileTags: ["mem_map"], filePath: FileInfo.joinPaths( product.destinationDirectory, product.targetName + product.cpp.linkerMapSuffix) }); } return artifacts; } qbs-src-2.6.1/share/qbs/modules/cpp/MingwBaseModule.qbs0000644000175100001660000001023414776170045022322 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.TextFile import qbs.Utilities import qbs.WindowsUtils import "setuprunenv.js" as SetupRunEnv GenericGCC { condition: false dynamicLibrarySuffix: ".dll" executableSuffix: ".exe" debugInfoSuffix: ".debug" imageFormat: "pe" windowsApiCharacterSet: "unicode" platformDefines: base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet)) .concat("WIN32") runtimeLibrary: "dynamic" Properties { condition: product.multiplexByQbsProperties.includes("buildVariants") && qbs.buildVariants && qbs.buildVariants.length > 1 && qbs.buildVariant !== "release" && product.type.containsAny(["staticlibrary", "dynamiclibrary"]) variantSuffix: "d" } FileTagger { patterns: ["*.manifest"] fileTags: ["native.pe.manifest"] } FileTagger { patterns: ["*.rc"] fileTags: ["rc"] } Rule { inputs: ["native.pe.manifest"] multiplex: true outputFileTags: ["rc"] outputArtifacts: { if (product.type.containsAny(["application", "dynamiclibrary"])) { return [{ filePath: input.completeBaseName + ".rc", fileTags: ["rc"] }]; } return []; } prepare: { var inputList = inputs["native.pe.manifest"]; // TODO: Emulate manifest merging like Microsoft's mt.exe tool does if (inputList.length !== 1) { throw("The MinGW toolchain does not support manifest merging; " + "you may only specify a single manifest file to embed into your assembly."); } var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.productType = product.type; cmd.inputFilePath = inputList[0].filePath; cmd.outputFilePath = output.filePath; cmd.sourceCode = function() { var tf; try { tf = new TextFile(outputFilePath, TextFile.WriteOnly); if (productType.includes("application")) tf.write("1 "); // CREATEPROCESS_MANIFEST_RESOURCE_ID else if (productType.includes("dynamiclibrary")) tf.write("2 "); // ISOLATIONAWARE_MANIFEST_RESOURCE_ID tf.write("24 "); // RT_MANIFEST tf.writeLine(Utilities.cStringQuote(inputFilePath)); } finally { if (tf) tf.close(); } }; return [cmd]; } } } qbs-src-2.6.1/share/qbs/modules/cpp/LinuxGCC.qbs0000644000175100001660000000540514776170045020720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Host import qbs.Process UnixGCC { condition: qbs.targetOS.includes('linux') && qbs.toolchain && qbs.toolchain.includes('gcc') priority: 1 targetVendor: "pc" targetSystem: "linux" targetAbi: "gnu" Probe { id: runPathsProbe condition: !_skipAllChecks && qbs.targetPlatform === Host.platform() property stringList systemRunPaths: [] configure: { var paths = []; var ldconfig = new Process(); try { var success = ldconfig.exec("ldconfig", ["-vNX"]); if (success === -1) return; var line; do { line = ldconfig.readLine(); if (line.charAt(0) === '/') { var colonIndex = line.indexOf(':'); if (colonIndex == -1) continue; paths.push(line.slice(0, colonIndex)); } } while (line && line.length > 0) found = true; systemRunPaths = paths; } finally { ldconfig.close(); } } } systemRunPaths: runPathsProbe.found ? runPathsProbe.systemRunPaths : base } qbs-src-2.6.1/share/qbs/modules/cpp/DarwinGCC.qbs0000644000175100001660000002671514776170045021054 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.DarwinTools import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.PathTools import qbs.Probes import qbs.PropertyList import qbs.TextFile import qbs.Utilities import "darwin.js" as Darwin import "gcc.js" as Gcc UnixGCC { condition: false Depends { name: "xcode"; required: qbs.toolchain && qbs.toolchain.includes("xcode") } Probes.BinaryProbe { id: lipoProbe condition: !_skipAllChecks names: [lipoName] platformSearchPaths: { var paths = (xcode.present && xcode.devicePlatformPath) ? [xcode.devicePlatformPath + "/Developer/usr/bin"] : []; return paths.concat([toolchainInstallPath, "/usr/bin"]); } } property string lipoPathPrefix: Gcc.pathPrefix(lipoProbe.found ? lipoProbe.path : toolchainInstallPath, toolchainPrefix) lipoName: "lipo" lipoPath: lipoPathPrefix + lipoName property bool enableAggregationRules: product.aggregate && !product.multiplexConfigurationId targetVendor: "apple" targetSystem: "darwin" targetAbi: "macho" imageFormat: "macho" cxxStandardLibrary: libcxxAvailable ? "libc++" : base loadableModulePrefix: "" loadableModuleSuffix: ".bundle" dynamicLibrarySuffix: ".dylib" Properties { condition: product.multiplexByQbsProperties.includes("buildVariants") && qbs.buildVariants && qbs.buildVariants.length > 1 && (!product.aggregate || !!product.multiplexConfigurationId) && qbs.buildVariant !== "release" variantSuffix: "_" + qbs.buildVariant } separateDebugInformation: true debugInfoBundleSuffix: ".dSYM" debugInfoSuffix: ".dwarf" rpathOrigin: "@loader_path" useRPathLink: !minimumDarwinVersion || Utilities.versionCompare(minimumDarwinVersion, "10.5") < 0 rpathLinkFlag: "-L" toolchainInstallPath: xcode.present ? FileInfo.joinPaths(xcode.toolchainPath, "usr", "bin") : base sysroot: xcode.present ? xcode.sdkPath : base sysrootFlags: sysroot ? ["-isysroot", sysroot] : [] setupBuildEnvironment: { for (var key in product.cpp.buildEnv) { var v = new ModUtils.EnvironmentVariable(key); v.value = product.cpp.buildEnv[key]; v.set(); } } property var defaultInfoPlist: { var dict = {}; if (qbs.targetOS.includes("macos")) { dict["NSPrincipalClass"] = "NSApplication"; // needed for Retina display support // QBS-1670: set this flag by default to avoid extensive GPU usage dict["NSSupportsAutomaticGraphicsSwitching"] = true; if (minimumMacosVersion) dict["LSMinimumSystemVersion"] = minimumMacosVersion; } if (qbs.targetOS.includes("ios") && minimumIosVersion) dict["MinimumOSVersion"] = minimumIosVersion; else if (qbs.targetOS.includes("tvos") && minimumTvosVersion) dict["MinimumOSVersion"] = minimumTvosVersion; else if (qbs.targetOS.includes("watchos") && minimumWatchosVersion) dict["MinimumOSVersion"] = minimumWatchosVersion; if (qbs.targetOS.containsAny(["ios", "tvos"])) { dict["LSRequiresIPhoneOS"] = true; if (xcode.platformType === "device") { if (qbs.targetOS.includes("ios")) { if (qbs.architecture === "arm64") dict["UIRequiredDeviceCapabilities"] = ["arm64"]; else dict["UIRequiredDeviceCapabilities"] = ["armv7"]; } if (qbs.targetOS.includes("tvos")) dict["UIRequiredDeviceCapabilities"] = ["arm64"]; } } if (xcode.present) { var targetDevices = DarwinTools.targetedDeviceFamily(xcode.targetDevices); if (qbs.targetOS.includes("ios")) dict["UIDeviceFamily"] = targetDevices; if (qbs.targetOS.containsAny(["ios", "watchos"])) { var orientations = [ "UIInterfaceOrientationPortrait", "UIInterfaceOrientationPortraitUpsideDown", "UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeRight" ]; if (targetDevices.includes("ipad")) dict["UISupportedInterfaceOrientations~ipad"] = orientations; if (targetDevices.includes("watch")) dict["UISupportedInterfaceOrientations"] = orientations.slice(0, 2); if (targetDevices.includes("iphone")) { orientations.splice(1, 1); dict["UISupportedInterfaceOrientations"] = orientations; } } } return dict; } targetLinkerFlags: darwinArchFlags.concat(minimumDarwinVersionLinkerFlags) targetAssemblerFlags: !assemblerHasTargetOption ? darwinArchFlags : base; targetDriverFlags: !compilerHasTargetOption ? legacyTargetDriverFlags : base property stringList legacyTargetDriverFlags: base.concat(darwinArchFlags).concat(minimumDarwinVersionCompilerFlags) // private properties readonly property stringList darwinArchFlags: targetArch ? ["-arch", targetArch] : [] readonly property stringList minimumDarwinVersionCompilerFlags: (minimumDarwinVersionCompilerFlag && minimumDarwinVersion) ? [minimumDarwinVersionCompilerFlag + "=" + minimumDarwinVersion] : [] readonly property stringList minimumDarwinVersionLinkerFlags: (minimumDarwinVersionLinkerFlag && minimumDarwinVersion && compilerVersionMajor < 11) ? [minimumDarwinVersionLinkerFlag, minimumDarwinVersion] : [] readonly property var buildEnv: { var env = { "ARCHS_STANDARD": xcode.standardArchitectures, "EXECUTABLE_NAME": product.targetName, "LANG": "en_US.US-ASCII", "PRODUCT_NAME": product.name } // Set the corresponding environment variable even if the minimum OS version is undefined, // because this indicates the default deployment target for that OS if (qbs.targetOS.includes("ios") && minimumIosVersion) env["IPHONEOS_DEPLOYMENT_TARGET"] = minimumIosVersion; if (qbs.targetOS.includes("macos") && minimumMacosVersion) env["MACOSX_DEPLOYMENT_TARGET"] = minimumMacosVersion; if (qbs.targetOS.includes("watchos") && minimumWatchosVersion) env["WATCHOS_DEPLOYMENT_TARGET"] = minimumWatchosVersion; if (qbs.targetOS.includes("tvos") && minimumTvosVersion) env["TVOS_DEPLOYMENT_TARGET"] = minimumTvosVersion; if (xcode.present) env["TARGETED_DEVICE_FAMILY"] = DarwinTools.targetedDeviceFamily(xcode.targetDevices).join(","); return env; } property string minimumDarwinVersion property string minimumDarwinVersionCompilerFlag property string minimumDarwinVersionLinkerFlag property bool libcxxAvailable: qbs.toolchain.includes("clang") && cxxLanguageVersion !== "c++98" Group { condition: enableAggregationRules Rule { inputsFromDependencies: ["application"] multiplex: true outputFileTags: ["bundle.input", "application", "primary", "debuginfo_app", "debuginfo_bundle", "bundle.variant_symlink", "debuginfo_plist", "codesign.signed_artifact"] outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "application", "app") prepare: Darwin.prepareLipo.apply(Darwin, arguments) } Rule { inputsFromDependencies: ["loadablemodule"] multiplex: true outputFileTags: ["bundle.input", "loadablemodule", "primary", "debuginfo_loadablemodule", "debuginfo_bundle", "debuginfo_plist", "codesign.signed_artifact"] outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "loadablemodule", "loadablemodule") prepare: Darwin.prepareLipo.apply(Darwin, arguments) } Rule { inputsFromDependencies: ["dynamiclibrary"] multiplex: true outputFileTags: ["bundle.input", "dynamiclibrary", "dynamiclibrary_symbols", "primary", "debuginfo_dll","debuginfo_bundle","bundle.variant_symlink", "debuginfo_plist", "codesign.signed_artifact", "dynamiclibrary_symlink"] outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "dynamiclibrary", "dll") prepare: Darwin.prepareLipo.apply(Darwin, arguments) } Rule { inputsFromDependencies: ["staticlibrary"] multiplex: true outputFileTags: ["bundle.input", "staticlibrary", "primary", "codesign.signed_artifact"] outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "staticlibrary") prepare: Darwin.prepareLipo.apply(Darwin, arguments) } } Rule { condition: qbs.targetOS.includes("darwin") multiplex: true Artifact { filePath: product.name + "-cpp-Info.plist" fileTags: ["partial_infoplist"] } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.inputData = product.cpp.defaultInfoPlist; cmd.outputFilePath = output.filePath; cmd.sourceCode = function() { var plist = new PropertyList(); try { plist.readFromObject(inputData); plist.writeToFile(outputFilePath, "xml1"); } finally { plist.clear(); } }; return [cmd]; } } } qbs-src-2.6.1/share/qbs/modules/cpp/windows-mingw.qbs0000644000175100001660000000763614776170045022125 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Utilities import 'cpp.js' as Cpp import "setuprunenv.js" as SetupRunEnv MingwBaseModule { condition: qbs.targetOS.includes("windows") && qbs.toolchain && qbs.toolchain.includes("mingw") priority: 0 probeEnv: buildEnv property string windresName: "windres" + compilerExtension property path windresPath: { var filePath = toolchainPathPrefix + windresName; if (!File.exists(filePath)) filePath = FileInfo.joinPaths(toolchainInstallPath, windresName); return filePath; } setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), true); v.prepend(product.cpp.toolchainInstallPath); v.set(); } setupRunEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), true); v.prepend(product.cpp.toolchainInstallPath); v.set(); SetupRunEnv.setupRunEnvironment(product, config); } Rule { inputs: ["rc"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.resourceCompilerOutputTags() outputArtifacts: Cpp.resourceCompilerOutputArtifacts(input) prepare: { var platformDefines = input.cpp.platformDefines; var defines = input.cpp.defines; var includePaths = input.cpp.includePaths; var systemIncludePaths = input.cpp.systemIncludePaths; var args = []; var i; for (i in platformDefines) { args.push('-D'); args.push(platformDefines[i]); } for (i in defines) { args.push('-D'); args.push(defines[i]); } for (i in includePaths) { args.push('-I'); args.push(includePaths[i]); } for (i in systemIncludePaths) { args.push('-I'); args.push(systemIncludePaths[i]); } args.push("-O", "coff"); // Set COFF format explicitly. args = args.concat(['-i', input.filePath, '-o', output.filePath]); var cmd = new Command(product.cpp.windresPath, args); cmd.description = 'compiling ' + input.fileName; cmd.highlight = 'compiler'; return cmd; } } } qbs-src-2.6.1/share/qbs/modules/cpp/ios-gcc.qbs0000644000175100001660000000735614776170045020637 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.DarwinTools import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Utilities DarwinGCC { priority: 1 condition: qbs.targetOS.includes('ios') && qbs.toolchain && qbs.toolchain.includes('gcc') minimumIosVersion: { if (Host.architecture() == "armv7a") return "6.0"; // XCode 12 requres version (at least 8.0) to be present in the -target triplet // when compiling for ios-simulator if (xcode.present && Utilities.versionCompare(xcode.version, "12.0") >= 0) return "8.0"; } targetSystem: "ios" + (minimumIosVersion || "") minimumDarwinVersion: minimumIosVersion minimumDarwinVersionCompilerFlag: qbs.targetOS.includes("ios-simulator") ? "-mios-simulator-version-min" : "-miphoneos-version-min" minimumDarwinVersionLinkerFlag: qbs.targetOS.includes("ios-simulator") ? "-ios_simulator_version_min" : "-iphoneos_version_min" libcxxAvailable: base && (!minimumDarwinVersion || Utilities.versionCompare(minimumDarwinVersion, "5") >= 0) platformObjcFlags: base.concat(simulatorObjcFlags) platformObjcxxFlags: base.concat(simulatorObjcFlags) // Private properties readonly property stringList simulatorObjcFlags: { // default in Xcode and also required for building 32-bit Simulator binaries with ARC // since the default ABI version is 0 for 32-bit targets return qbs.targetOS.includes("ios-simulator") ? ["-fobjc-abi-version=2", "-fobjc-legacy-dispatch"] : []; } Rule { condition: !product.qbs.targetOS.includes("ios-simulator") inputsFromDependencies: ["bundle.content"] Artifact { filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".ipa") fileTags: ["ipa"] } prepare: { var cmd = new Command("PackageApplication", [input.filePath, "-o", output.filePath]); cmd.description = "creating ipa"; cmd.highlight = "codegen"; return cmd; } } } qbs-src-2.6.1/share/qbs/modules/cpp/cosmic.qbs0000644000175100001660000001231114776170045020553 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.PathTools import qbs.Probes import qbs.Utilities import "cosmic.js" as COSMIC import "cpp.js" as Cpp CppModule { condition: qbs.toolchain && qbs.toolchain.includes("cosmic") Probes.BinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["cxcorm"] } Probes.CosmicProbe { id: cosmicProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage } Properties { condition: cosmicProbe.found qbs.architecture: cosmicProbe.architecture } qbs.targetPlatform: "none" compilerVersionMajor: cosmicProbe.versionMajor compilerVersionMinor: cosmicProbe.versionMinor compilerVersionPatch: cosmicProbe.versionPatch endianness: cosmicProbe.endianness compilerDefinesByLanguage: cosmicProbe.compilerDefinesByLanguage compilerIncludePaths: cosmicProbe.includePaths toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined /* Work-around for QtCreator which expects these properties to exist. */ property string cCompilerName: compilerName property string cxxCompilerName: compilerName compilerName: toolchainDetails.compilerName + compilerExtension compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: toolchainDetails.assemblerName + compilerExtension assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName) linkerName: "clnk" + compilerExtension linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) property string archiverName: "clib" + compilerExtension property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName) runtimeLibrary: "static" staticLibrarySuffix: toolchainDetails.staticLibrarySuffix executableSuffix: toolchainDetails.executableSuffix imageFormat: "cosmic" enableExceptions: false enableRtti: false defineFlag: "-d" includeFlag: "-i" systemIncludeFlag: "-i" preincludeFlag: "-ph" libraryDependencyFlag: "" libraryPathFlag: "-l" linkerScriptFlag: "" toolchainDetails: COSMIC.toolchainDetails(qbs) knownArchitectures: ["arm", "hcs12", "hcs8", "m68k", "stm8"] Rule { id: assembler inputs: ["asm"] outputFileTags: Cpp.assemblerOutputTags(generateAssemblerListingFiles) outputArtifacts: Cpp.assemblerOutputArtifacts(input) prepare: COSMIC.prepareAssembler.apply(COSMIC, arguments) } FileTagger { patterns: ["*.s"] fileTags: ["asm"] } Rule { id: compiler inputs: ["cpp", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.compilerOutputTags(generateCompilerListingFiles) outputArtifacts: Cpp.compilerOutputArtifacts(input) prepare: COSMIC.prepareCompiler.apply(COSMIC, arguments) } Rule { id: applicationLinker multiplex: true inputs: ["obj", "linkerscript"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile) outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product) prepare: COSMIC.prepareLinker.apply(COSMIC, arguments) } Rule { id: staticLibraryLinker multiplex: true inputs: ["obj"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.staticLibraryLinkerOutputTags() outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product) prepare: COSMIC.prepareArchiver.apply(COSMIC, arguments) } } qbs-src-2.6.1/share/qbs/modules/cpp/keil.js0000644000175100001660000011075214776170045020061 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Cpp = require("cpp.js"); var Environment = require("qbs.Environment"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var PathTools = require("qbs.PathTools"); var Process = require("qbs.Process"); var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function isMcs51Architecture(architecture) { return architecture === "mcs51"; } function isMcs251Architecture(architecture) { return architecture === "mcs251"; } function isMcsArchitecture(architecture) { return isMcs51Architecture(architecture) || isMcs251Architecture(architecture); } function isC166Architecture(architecture) { return architecture === "c166"; } function isArmArchitecture(architecture) { return architecture.startsWith("arm"); } function isMcsCompiler(compilerPath) { var base = FileInfo.baseName(compilerPath).toLowerCase(); return base === "c51" || base === "cx51" || base === "c251"; } function isC166Compiler(compilerPath) { return FileInfo.baseName(compilerPath).toLowerCase() === "c166"; } function isArmCCCompiler(compilerPath) { return FileInfo.baseName(compilerPath).toLowerCase() === "armcc"; } function isArmClangCompiler(compilerPath) { return FileInfo.baseName(compilerPath).toLowerCase() === "armclang"; } function preincludeFlag(compilerPath) { if (isArmCCCompiler(compilerPath)) return "--preinclude"; else if (isArmClangCompiler(compilerPath)) return "-include"; } function toolchainDetails(qbs) { var architecture = qbs.architecture; if (isMcs51Architecture(architecture)) { return { "imageFormat": "omf", "linkerMapSuffix":".m51", "objectSuffix": ".obj", "executableSuffix": ".abs", "compilerName": "c51", "assemblerName": "a51", "linkerName": "bl51", "archiverName": "lib51" }; } else if (isMcs251Architecture(architecture)) { return { "imageFormat": "omf", "linkerMapSuffix":".m51", "objectSuffix": ".obj", "executableSuffix": ".abs", "compilerName": "c251", "assemblerName": "a251", "linkerName": "l251", "archiverName": "lib251" }; } else if (isC166Architecture(architecture)) { return { "imageFormat": "omf", "linkerMapSuffix":".m66", "objectSuffix": ".obj", "executableSuffix": ".abs", "compilerName": "c166", "assemblerName": "a166", "linkerName": "l166", "archiverName": "lib166" }; } else if (isArmArchitecture(architecture)) { return { "imageFormat": "elf", "linkerMapSuffix":".map", "objectSuffix": ".o", "executableSuffix": ".axf", "disassemblerName": "fromelf", "compilerName": "armcc", "assemblerName": "armasm", "linkerName": "armlink", "archiverName": "armar" }; } } function guessArmCCArchitecture(targetArchArm, targetArchThumb) { var arch = "arm"; if (targetArchArm === "4" && targetArchThumb === "0") arch += "v4"; else if (targetArchArm === "4" && targetArchThumb === "1") arch += "v4t"; else if (targetArchArm === "5" && targetArchThumb === "2") arch += "v5t"; else if (targetArchArm === "6" && targetArchThumb === "3") arch += "v6"; else if (targetArchArm === "6" && targetArchThumb === "4") arch += "v6t2"; else if (targetArchArm === "0" && targetArchThumb === "3") arch += "v6m"; else if (targetArchArm === "7" && targetArchThumb === "4") arch += "v7r"; else if (targetArchArm === "0" && targetArchThumb === "4") arch += "v7m"; return arch; } function guessArmClangArchitecture(targetArchArm, targetArchProfile) { targetArchProfile = targetArchProfile.replace(/'/g, ""); var arch = "arm"; if (targetArchArm !== "" && targetArchProfile !== "") arch += "v" + targetArchArm + targetArchProfile.toLowerCase(); return arch; } function guessArchitecture(macros) { if (macros["__C51__"]) return "mcs51"; else if (macros["__C251__"]) return "mcs251"; else if (macros["__C166__"]) return "c166"; else if (macros["__CC_ARM"] === "1") return guessArmCCArchitecture(macros["__TARGET_ARCH_ARM"], macros["__TARGET_ARCH_THUMB"]); else if (macros["__clang__"] === "1" && macros["__arm__"] === "1") return guessArmClangArchitecture(macros["__ARM_ARCH"], macros["__ARM_ARCH_PROFILE"]); } function guessEndianness(macros) { if (macros["__C51__"] || macros["__C251__"]) { // The 8051 processors are 8-bit. So, the data with an integer type // represented by more than one byte is stored as big endian in the // Keil toolchain. See for more info: // * http://www.keil.com/support/man/docs/c51/c51_ap_2bytescalar.htm // * http://www.keil.com/support/man/docs/c51/c51_ap_4bytescalar.htm // * http://www.keil.com/support/man/docs/c251/c251_ap_2bytescalar.htm // * http://www.keil.com/support/man/docs/c251/c251_ap_4bytescalar.htm return "big"; } else if (macros["__C166__"]) { // The C166 processors are 16-bit. So, the data with an integer type // represented by more than one byte is stored as little endian in the // Keil toolchain. See for more info: // * http://www.keil.com/support/man/docs/c166/c166_ap_ints.htm // * http://www.keil.com/support/man/docs/c166/c166_ap_longs.htm return "little"; } else if (macros["__CC_ARM"]) { return macros["__BIG_ENDIAN"] ? "big" : "little"; } else if (macros["__clang__"] && macros["__arm__"]) { switch (macros["__BYTE_ORDER__"]) { case "__ORDER_BIG_ENDIAN__": return "big"; case "__ORDER_LITTLE_ENDIAN__": return "little"; } } } function guessVersion(macros) { if (macros["__C51__"] || macros["__C251__"]) { var mcsVersion = macros["__C51__"] || macros["__C251__"]; return { major: parseInt(mcsVersion / 100), minor: parseInt(mcsVersion % 100), patch: 0 } } else if (macros["__C166__"]) { var xcVersion = macros["__C166__"]; return { major: parseInt(xcVersion / 100), minor: parseInt(xcVersion % 100), patch: 0 } } else if (macros["__CC_ARM"] || macros["__clang__"]) { var armVersion = macros["__ARMCC_VERSION"]; return { major: parseInt(armVersion / 1000000), minor: parseInt(armVersion / 10000) % 100, patch: parseInt(armVersion) % 10000 } } } function dumpMcsCompilerMacros(compilerFilePath, tag) { // C51 or C251 compiler support only C language. if (tag === "cpp") return {}; // Note: The C51 or C251 compiler does not support the predefined // macros dumping. So, we do it with the following trick, where we try // to create and compile a special temporary file and to parse the console // output with the own magic pattern: (""|"key"|"value"|""). var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.fromNativeSeparators(FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c")); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); outputFile.writeLine("#define VALUE_TO_STRING(x) #x"); outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)"); // Predefined keys for C51 and C251 compilers, see details: // * https://www.keil.com/support/man/docs/c51/c51_pp_predefmacroconst.htm // * https://www.keil.com/support/man/docs/c251/c251_pp_predefmacroconst.htm var keys = ["__C51__", "__CX51__", "__C251__", "__MODEL__", "__STDC__", "__FLOAT64__", "__MODSRC__"]; // For C51 compiler. outputFile.writeLine("#if defined(__C51__) || defined(__CX51__)"); outputFile.writeLine("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\""); for (var i in keys) { var key = keys[i]; outputFile.writeLine("# if defined (" + key + ")"); outputFile.writeLine("# pragma message (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("# endif"); } outputFile.writeLine("#endif"); // For C251 compiler. outputFile.writeLine("#if defined(__C251__)"); outputFile.writeLine("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\""); for (var i in keys) { var key = keys[i]; outputFile.writeLine("# if defined (" + key + ")"); outputFile.writeLine("# warning (VAR_NAME_VALUE(" + key + "))"); outputFile.writeLine("# endif"); } outputFile.writeLine("#endif"); outputFile.close(); var process = new Process(); process.exec(compilerFilePath, [outputFilePath], false); File.remove(outputFilePath); var map = {}; process.readStdOut().trim().split(/\r?\n/g).map(function(line) { var parts = line.split("\"|\"", 4); if (parts.length === 4) map[parts[1]] = parts[2]; }); return map; } function dumpC166CompilerMacros(compilerFilePath, tag) { // C166 compiler support only C language. if (tag === "cpp") return {}; // Note: The C166 compiler does not support the predefined // macros dumping. Also, it does not support the '#pragma' and // '#message|warning|error' directives properly (it is impossible // to print to console the value of macro). // So, we do it with the following trick, where we try // to create and compile a special temporary file and to parse the console // output with the own magic pattern, e.g: // // *** WARNING C320 IN LINE 41 OF c51.c: __C166__ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored // // where the '__C166__' is a key, and the '757' is a value. var outputDirectory = new TemporaryDir(); var outputFilePath = FileInfo.fromNativeSeparators(outputDirectory.path() + "/dump-macros.c"); var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly); // Predefined keys for C166 compiler, see details: // * https://www.keil.com/support/man/docs/c166/c166_pp_predefmacroconst.htm var keys = ["__C166__", "__DUS__", "__MAC__", "__MOD167__", "__MODEL__", "__MODV2__", "__SAVEMAC__", "__STDC__"]; // For C166 compiler. outputFile.writeLine("#if defined(__C166__)"); for (var i in keys) { var key = keys[i]; outputFile.writeLine("# if defined (" + key + ")"); outputFile.writeLine("# warning " + key); outputFile.writeLine("# pragma " + key); outputFile.writeLine("# endif"); } outputFile.writeLine("#endif"); outputFile.close(); function extractKey(line, knownKeys) { for (var i in keys) { var key = knownKeys[i]; var regexp = new RegExp("^\\*\\*\\* WARNING C320 IN LINE .+: (" + key + ")$"); var match = regexp.exec(line); if (match) return key; } }; function extractValue(line) { var regexp = new RegExp("^\\*\\*\\* WARNING C2 IN LINE .+'(.+)':.+$"); var match = regexp.exec(line); if (match) return match[1]; }; var process = new Process(); process.exec(compilerFilePath, [outputFilePath], false); File.remove(outputFilePath); var lines = process.readStdOut().trim().split(/\r?\n/g); var map = {}; for (var i = 0; i < lines.length; ++i) { // First line should contains the macro key. var keyLine = lines[i]; var key = extractKey(keyLine, keys); if (!key) continue; i += 1; if (i >= lines.length) break; // Second line should contains the macro value. var valueLine = lines[i]; var value = extractValue(valueLine); if (!value) continue; map[key] = value; } return map; } function dumpArmCCCompilerMacros(compilerFilePath, tag, nullDevice) { var args = [ "-E", "--list-macros", "--cpu=cortex-m0", nullDevice ]; if (tag === "cpp") args.push("--cpp"); var p = new Process(); p.exec(compilerFilePath, args, false); return Cpp.extractMacros(p.readStdOut()); } function dumpArmClangCompilerMacros(compilerFilePath, tag, nullDevice) { var args = [ "--target=arm-arm-none-eabi", "-mcpu=cortex-m0", "-dM", "-E", "-x", ((tag === "cpp") ? "c++" : "c"), nullDevice ]; var p = new Process(); p.exec(compilerFilePath, args, false); return Cpp.extractMacros(p.readStdOut()); } function dumpMacros(compilerFilePath, tag, nullDevice) { if (isMcsCompiler(compilerFilePath)) return dumpMcsCompilerMacros(compilerFilePath, tag, nullDevice); else if (isC166Compiler(compilerFilePath)) return dumpC166CompilerMacros(compilerFilePath, tag, nullDevice); else if (isArmCCCompiler(compilerFilePath)) return dumpArmCCCompilerMacros(compilerFilePath, tag, nullDevice); else if (isArmClangCompiler(compilerFilePath)) return dumpArmClangCompilerMacros(compilerFilePath, tag, nullDevice); return {}; } function dumpMcsCompilerIncludePaths(compilerFilePath) { var includePath = compilerFilePath.replace(/bin[\\\/](.*)$/i, "inc"); return [includePath]; } function dumpC166CompilerIncludePaths(compilerFilePath) { // Same as for MCS compiler. return dumpMcsCompilerIncludePaths(compilerFilePath); } function dumpArmCCCompilerIncludePaths(compilerFilePath) { var includePath = compilerFilePath.replace(/bin[\\\/](.*)$/i, "include"); return [includePath]; } function dumpArmClangCompilerIncludePaths(compilerFilePath, nullDevice) { var args = [ "--target=arm-arm-none-eabi", "-mcpu=cortex-m0", "-v", "-E", "-x", "c++", nullDevice ]; var p = new Process(); p.exec(compilerFilePath, args, false); var lines = p.readStdErr().trim().split(/\r?\n/g).map(function (line) { return line.trim(); }); var addIncludes = false; var includePaths = []; for (var i = 0; i < lines.length; ++i) { var line = lines[i]; if (line === "#include <...> search starts here:") addIncludes = true; else if (line === "End of search list.") addIncludes = false; else if (addIncludes) includePaths.push(line); } return includePaths; } function dumpDefaultPaths(compilerFilePath, nullDevice) { var includePaths = []; if (isMcsCompiler(compilerFilePath)) includePaths = dumpMcsCompilerIncludePaths(compilerFilePath); else if (isC166Compiler(compilerFilePath)) includePaths = dumpC166CompilerIncludePaths(compilerFilePath); else if (isArmCCCompiler(compilerFilePath)) includePaths = dumpArmCCCompilerIncludePaths(compilerFilePath); else if (isArmClangCompiler(compilerFilePath)) includePaths = dumpArmClangCompilerIncludePaths(compilerFilePath, nullDevice); return { "includePaths": includePaths }; } function filterMcsOutput(output) { var filteredLines = []; output.split(/\r\n|\r|\n/).forEach(function(line) { var regexp = /^\s*\*{3}\s|^\s{29}|^\s{4}\S|^\s{2}[0-9A-F]{4}|^\s{21,25}\d+|^[0-9A-F]{4}\s\d+/; if (regexp.exec(line)) filteredLines.push(line); }); return filteredLines.join('\n'); }; function filterC166Output(output) { var filteredLines = []; output.split(/\r\n|\r|\n/).forEach(function(line) { var regexp = /^\s*\*{3}\s|^\s{29}|^\s{27,28}\d+|^\s{21}\d+|^\s{4}\S|^\s{2}[0-9A-F]{4}|^[0-9A-F]{4}\s\d+/; if (regexp.exec(line)) filteredLines.push(line); }); return filteredLines.join('\n'); }; function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { // Determine which C-language we're compiling. var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); var args = []; var architecture = input.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Input. args.push(input.filePath); // Output. args.push("OBJECT(" + FileInfo.toWindowsSeparators(outputs.obj[0].filePath) + ")"); // Defines. var defines = Cpp.collectDefines(input); if (defines.length > 0) args = args.concat("DEFINE (" + defines.join(",") + ")"); // Includes. var allIncludePaths = [].concat(Cpp.collectIncludePaths(input), Cpp.collectSystemIncludePaths(input)); if (allIncludePaths.length > 0) args = args.concat("INCDIR(" + allIncludePaths.map(function(path) { return FileInfo.toWindowsSeparators(path); }).join(";") + ")"); // Debug information flags. if (input.cpp.debugInformation) args.push("DEBUG"); // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("OPTIMIZE (SIZE)"); break; case "fast": args.push("OPTIMIZE (SPEED)"); break; case "none": args.push("OPTIMIZE (0)"); break; } // Warning level flags. switch (input.cpp.warningLevel) { case "none": args.push("WARNINGLEVEL (0)"); break; case "all": args.push("WARNINGLEVEL (2)"); if (isMcs51Architecture(architecture)) args.push("FARWARNING"); break; } // Listing files generation flag. if (!input.cpp.generateCompilerListingFiles) args.push("NOPRINT"); else args.push("PRINT(" + FileInfo.toWindowsSeparators(outputs.lst[0].filePath) + ")"); } else if (isArmArchitecture(architecture)) { // Input. args.push("-c", input.filePath); // Output. args.push("-o", outputs.obj[0].filePath); // Preinclude headers. args = args.concat(Cpp.collectPreincludePathsArguments(input, true)); // Defines. args = args.concat(Cpp.collectDefinesArguments(input)); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); var compilerPath = input.cpp.compilerPath; if (isArmCCCompiler(compilerPath)) { // Debug information flags. if (input.cpp.debugInformation) { args.push("--debug"); args.push("-g"); } // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("-Ospace") break; case "fast": args.push("-Otime") break; case "none": args.push("-O0") break; } // Warning level flags. switch (input.cpp.warningLevel) { case "none": args.push("-W"); break; default: // By default all warnings are enabled. break; } if (tag === "c") { // C language version flags. var knownCLanguageValues = ["c99", "c90"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownCLanguageValues, "C"); switch (cLanguageVersion) { case "c99": args.push("--c99"); break; case "c90": args.push("--c90"); break; } } else if (tag === "cpp") { // C++ language version flags. var knownCppLanguageValues = ["c++11", "c++03"]; var cppLanguageVersion = Cpp.languageVersion( input.cpp.cxxLanguageVersion, knownCppLanguageValues, "C++"); switch (cppLanguageVersion) { case "c++11": args.push("--cpp11"); break; default: // Default C++ language is C++03. args.push("--cpp"); break; } // Exceptions flags. var enableExceptions = input.cpp.enableExceptions; if (enableExceptions !== undefined) args.push(enableExceptions ? "--exceptions" : "--no_exceptions"); // RTTI flags. var enableRtti = input.cpp.enableRtti; if (enableRtti !== undefined) args.push(enableRtti ? "--rtti" : "--no_rtti"); } // Listing files generation flag. if (input.cpp.generateCompilerListingFiles) { args.push("--list"); args.push("--list_dir", FileInfo.path(outputs.lst[0].filePath)); } } else if (isArmClangCompiler(compilerPath)) { // Debug information flags. if (input.cpp.debugInformation) args.push("-g"); // Optimization level flags. switch (input.cpp.optimization) { case "small": args.push("-Oz") break; case "fast": args.push("-Ofast") break; case "none": args.push("-O0") break; } // Warning level flags. switch (input.cpp.warningLevel) { case "all": args.push("-Wall"); break; default: break; } if (input.cpp.treatWarningsAsErrors) args.push("-Werror"); if (tag === "c") { // C language version flags. var knownCLanguageValues = ["c11", "c99", "c90", "c89"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownCLanguageValues, "C"); if (cLanguageVersion) args.push("-std=" + cLanguageVersion); } else if (tag === "cpp") { // C++ language version flags. var knownCppLanguageValues = ["c++17", "c++14", "c++11", "c++03", "c++98"]; var cppLanguageVersion = Cpp.languageVersion( input.cpp.cxxLanguageVersion, knownCppLanguageValues, "C++"); if (cppLanguageVersion) args.push("-std=" + cppLanguageVersion); // Exceptions flags. var enableExceptions = input.cpp.enableExceptions; if (enableExceptions !== undefined) args.push(enableExceptions ? "-fexceptions" : "-fno-exceptions"); // RTTI flags. var enableRtti = input.cpp.enableRtti; if (enableRtti !== undefined) args.push(enableRtti ? "-frtti" : "-fno-rtti"); } // Listing files generation does not supported! // There are only a workaround: http://www.keil.com/support/docs/4152.htm } } // Misc flags. args = args.concat(Cpp.collectMiscCompilerArguments(input, tag), Cpp.collectMiscDriverArguments(input)); return args; } function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = []; var architecture = input.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Input. args.push(input.filePath); // Output. args.push("OBJECT(" + FileInfo.toWindowsSeparators(outputs.obj[0].filePath) + ")"); // Includes. var allIncludePaths = [].concat(Cpp.collectIncludePaths(input), Cpp.collectSystemIncludePaths(input)); if (allIncludePaths.length > 0) args = args.concat("INCDIR(" + allIncludePaths.map(function(path) { return FileInfo.toWindowsSeparators(path); }).join(";") + ")"); // Debug information flags. if (input.cpp.debugInformation) args.push("DEBUG"); // Enable errors printing. args.push("EP"); // Listing files generation flag. if (!input.cpp.generateAssemblerListingFiles) args.push("NOPRINT"); else args.push("PRINT(" + FileInfo.toWindowsSeparators(outputs.lst[0].filePath) + ")"); } else if (isArmArchitecture(architecture)) { // Input. args.push(input.filePath); // Output. args.push("-o", outputs.obj[0].filePath); // Includes. args = args.concat(Cpp.collectIncludePathsArguments(input)); args = args.concat(Cpp.collectSystemIncludePathsArguments(input)); // Debug information flags. if (input.cpp.debugInformation) { args.push("--debug"); args.push("-g"); } // Warning level flags. if (input.cpp.warningLevel === "none") args.push("--no_warn"); // Byte order flags. var endianness = input.cpp.endianness; if (endianness) args.push((endianness === "little") ? "--littleend" : "--bigend"); // Listing files generation flag. if (input.cpp.generateAssemblerListingFiles) args.push("--list", outputs.lst[0].filePath); } // Misc flags. args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm")); return args; } function disassemblerFlags(project, product, input, outputs, explicitlyDependsOn) { var args = ["--disassemble", "--interleave=source"]; args.push(outputs.obj[0].filePath); args.push("--output=" + outputs.lst[0].filePath); return args; } function linkerFlags(project, product, inputs, outputs) { var args = []; var libraryPaths = Cpp.collectLibraryPaths(product); var architecture = product.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Semi-intelligent handling the library paths. // We need to add the full path prefix to the library file if this // file is not absolute or not relative. Reason is that the C51, C251, // and C166 linkers does not support the library paths. function collectLibraryObjectPaths(product) { var libraryObjects = Cpp.collectLibraryDependencies(product); return libraryObjects.map(function(dep) { var filePath = dep.filePath; if (FileInfo.isAbsolutePath(filePath)) return filePath; for (var i = 0; i < libraryPaths.length; ++i) { var fullPath = FileInfo.joinPaths(libraryPaths[i], filePath); if (File.exists(fullPath)) return fullPath; } return filePath; }); } // Note: The C51, C251, or C166 linker does not distinguish an object files and // a libraries, it interpret all this stuff as an input objects, // so, we need to pass it together in one string. function collectAllObjectPathsArguments(product, inputs) { return [].concat(Cpp.collectLinkerObjectPaths(inputs), collectLibraryObjectPaths(product)); } // Add all input objects as arguments (application and library object files). var allObjectPaths = collectAllObjectPathsArguments(product, inputs); if (allObjectPaths.length > 0) args = args.concat(allObjectPaths.map(function(path) { return FileInfo.toWindowsSeparators(path); }).join(",")); // Output. args.push("TO", FileInfo.toWindowsSeparators(outputs.application[0].filePath)); // Map file generation flag. if (!product.cpp.generateLinkerMapFile) args.push("NOPRINT"); else args.push("PRINT(" + FileInfo.toWindowsSeparators(outputs.mem_map[0].filePath) + ")"); } else if (isArmArchitecture(architecture)) { // Inputs. args = args.concat(Cpp.collectLinkerObjectPaths(inputs)); // Output. args.push("--output", outputs.application[0].filePath); // Library paths. if (libraryPaths.length > 0) args.push(product.cpp.libraryPathFlag + libraryPaths.join(",")); // Library dependencies. args = args.concat(Cpp.collectLibraryDependenciesArguments(product)); // Linker scripts. args = args.concat(Cpp.collectLinkerScriptPathsArguments(product, inputs, true)); // Map file generation flag. if (product.cpp.generateLinkerMapFile) args.push("--list", outputs.mem_map[0].filePath); // Entry point flag. if (product.cpp.entryPoint) args.push("--entry", product.cpp.entryPoint); // Debug information flag. var debugInformation = product.cpp.debugInformation; if (debugInformation !== undefined) args.push(debugInformation ? "--debug" : "--no_debug"); } // Misc flags. args = args.concat(Cpp.collectMiscEscapableLinkerArguments(product), Cpp.collectMiscLinkerArguments(product), Cpp.collectMiscDriverArguments(product)); return args; } function archiverFlags(project, product, inputs, outputs) { var args = []; // Inputs. var objectPaths = Cpp.collectLinkerObjectPaths(inputs); var architecture = product.qbs.architecture; if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) { // Library creation command. args.push("TRANSFER"); // Inputs. if (objectPaths.length > 0) args = args.concat(objectPaths.map(function(path) { return FileInfo.toWindowsSeparators(path); }).join(",")); // Output. args.push("TO", FileInfo.toWindowsSeparators(outputs.staticlibrary[0].filePath)); } else if (isArmArchitecture(architecture)) { // Note: The ARM archiver command line expect the output file // first, and then a set of input objects. // Output. args.push("--create", outputs.staticlibrary[0].filePath); // Inputs. args = args.concat(objectPaths); // Debug information flag. if (product.cpp.debugInformation) args.push("--debug_symbols"); } return args; } // The ARMCLANG compiler does not support generation // for the listing files: // * https://www.keil.com/support/docs/4152.htm // So, we generate the listing files from the object files // using the disassembler. function generateClangCompilerListing(project, product, inputs, outputs, input, output) { if (isArmClangCompiler(input.cpp.compilerPath) && input.cpp.generateCompilerListingFiles) { var args = disassemblerFlags(project, product, input, outputs, explicitlyDependsOn); var disassemblerPath = input.cpp.disassemblerPath; var cmd = new Command(disassemblerPath, args); cmd.silent = true; return cmd; } } // The ARMCC compiler generates the listing files only in a short form, // e.g. to 'module.lst' instead of 'module.{c|cpp}.lst', that complicates // the auto-tests. Therefore we need to rename generated listing files // with correct unified names. function generateArmccCompilerListing(project, product, inputs, outputs, input, output) { if (isArmCCCompiler(input.cpp.compilerPath) && input.cpp.generateCompilerListingFiles) { var listingPath = FileInfo.path(outputs.lst[0].filePath); var cmd = new JavaScriptCommand(); cmd.oldListing = FileInfo.joinPaths(listingPath, input.baseName + ".lst"); cmd.newListing = FileInfo.joinPaths( listingPath, input.fileName + input.cpp.compilerListingSuffix); cmd.silent = true; cmd.sourceCode = function() { File.move(oldListing, newListing); }; return cmd; } } function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn); var compilerPath = input.cpp.compilerPath; var architecture = input.cpp.architecture; var cmd = new Command(compilerPath, args); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "compiler"; if (isMcsArchitecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterC166Output; } cmds.push(cmd); cmd = generateClangCompilerListing(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); cmd = generateArmccCompilerListing(project, product, inputs, outputs, input, output); if (cmd) cmds.push(cmd); return cmds; } function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn); var assemblerPath = input.cpp.assemblerPath; var architecture = input.cpp.architecture; var cmd = new Command(assemblerPath, args); cmd.description = "assembling " + input.fileName; cmd.highlight = "compiler"; cmd.jobPool = "assembler"; if (isMcsArchitecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterC166Output; } return [cmd]; } function prepareLinker(project, product, inputs, outputs, input, output) { var primaryOutput = outputs.application[0]; var args = linkerFlags(project, product, inputs, outputs); var linkerPath = product.cpp.linkerPath; var architecture = product.cpp.architecture; var cmd = new Command(linkerPath, args); cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; if (isMcsArchitecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.maxExitCode = 1; cmd.stdoutFilterFunction = filterC166Output; } return [cmd]; } function prepareArchiver(project, product, inputs, outputs, input, output) { var args = archiverFlags(project, product, inputs, outputs); var archiverPath = product.cpp.archiverPath; var architecture = product.cpp.architecture; var cmd = new Command(archiverPath, args); cmd.description = "creating " + output.fileName; cmd.highlight = "linker"; cmd.jobPool = "linker"; if (isMcsArchitecture(architecture)) { cmd.stdoutFilterFunction = filterMcsOutput; } else if (isC166Architecture(architecture)) { cmd.stdoutFilterFunction = filterC166Output; } return [cmd]; } qbs-src-2.6.1/share/qbs/modules/cpp/windows-clang-mingw.qbs0000644000175100001660000000742514776170045023203 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Utilities import "msvc.js" as MSVC import "setuprunenv.js" as SetupRunEnv MingwBaseModule { condition: qbs.targetOS.includes("windows") && qbs.toolchain && qbs.toolchain.includes("clang") priority: 0 // llvm-as and llvm-objopy are not shipped with the official binaries on Windows at the // moment (8.0). We fall back to using the mingw versions in that case. assemblerName: "llvm-as" + compilerExtension assemblerPath: { if (File.exists(base)) return base; if (qbs.sysroot) return FileInfo.joinPaths(qbs.sysroot, "bin", "as" + compilerExtension); } objcopyName: "llvm-objcopy" + compilerExtension objcopyPath: { if (File.exists(base)) return base; if (qbs.sysroot) return FileInfo.joinPaths(qbs.sysroot, "bin", "objcopy" + compilerExtension); } archiverName: "llvm-ar" + compilerExtension linkerVariant: "lld" targetVendor: "pc" targetSystem: "windows" targetAbi: "gnu" property string rcFilePath: FileInfo.joinPaths(toolchainInstallPath, "llvm-rc" + compilerExtension) setupBuildEnvironment: { if (Host.os().includes("windows") && product.qbs.sysroot) { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), true); v.prepend(FileInfo.joinPaths(product.qbs.sysroot, "bin")); v.set(); } } setupRunEnvironment: { if (Host.os().includes("windows") && product.qbs.sysroot) { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), true); v.prepend(FileInfo.joinPaths(product.qbs.sysroot, "bin")); v.set(); SetupRunEnv.setupRunEnvironment(product, config); } } Rule { inputs: ["rc"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] Artifact { filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), input.completeBaseName + ".res") fileTags: ["obj"] } prepare: MSVC.createRcCommand(product.cpp.rcFilePath, input, output) } } qbs-src-2.6.1/share/qbs/modules/cpp/keil.qbs0000644000175100001660000001304314776170045020225 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.Probes import "cpp.js" as Cpp import "keil.js" as KEIL CppModule { condition: Host.os().includes("windows") && qbs.toolchain && qbs.toolchain.includes("keil") Probes.BinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["c51"] } Probes.KeilProbe { id: keilProbe condition: !_skipAllChecks compilerFilePath: compilerPath enableDefinesByLanguage: enableCompilerDefinesByLanguage } Properties { condition: keilProbe.found qbs.architecture: keilProbe.architecture } qbs.targetPlatform: "none" compilerVersionMajor: keilProbe.versionMajor compilerVersionMinor: keilProbe.versionMinor compilerVersionPatch: keilProbe.versionPatch endianness: keilProbe.endianness compilerDefinesByLanguage: keilProbe.compilerDefinesByLanguage compilerIncludePaths: keilProbe.includePaths toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined /* Work-around for QtCreator which expects these properties to exist. */ property string cCompilerName: compilerName property string cxxCompilerName: compilerName compilerName: toolchainDetails.compilerName + compilerExtension compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName) assemblerName: toolchainDetails.assemblerName + compilerExtension assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName) linkerName: toolchainDetails.linkerName + compilerExtension linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName) property string archiverName: toolchainDetails.archiverName + compilerExtension property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName) property string disassemblerName: toolchainDetails.disassemblerName + compilerExtension property string disassemblerPath: FileInfo.joinPaths(toolchainInstallPath, disassemblerName) runtimeLibrary: "static" staticLibrarySuffix: ".lib" executableSuffix: toolchainDetails.executableSuffix objectSuffix: toolchainDetails.objectSuffix linkerMapSuffix: toolchainDetails.linkerMapSuffix imageFormat: toolchainDetails.imageFormat enableExceptions: false enableRtti: false defineFlag: "-D" includeFlag: "-I" systemIncludeFlag: "-I" preincludeFlag: KEIL.preincludeFlag(compilerPath) libraryDependencyFlag: "" libraryPathFlag: "--userlibpath=" linkerScriptFlag: "--scatter" toolchainDetails: KEIL.toolchainDetails(qbs) knownArchitectures: ["arm", "c166", "mcs251", "mcs51"] Rule { id: assembler inputs: ["asm"] outputFileTags: Cpp.assemblerOutputTags(generateAssemblerListingFiles) outputArtifacts: Cpp.assemblerOutputArtifacts(input) prepare: KEIL.prepareAssembler.apply(KEIL, arguments) } FileTagger { patterns: ["*.s", "*.a51", ".asm"] fileTags: ["asm"] } Rule { id: compiler inputs: ["cpp", "c"] auxiliaryInputs: ["hpp"] auxiliaryInputsFromDependencies: ["hpp"] outputFileTags: Cpp.compilerOutputTags(generateCompilerListingFiles) outputArtifacts: Cpp.compilerOutputArtifacts(input) prepare: KEIL.prepareCompiler.apply(KEIL, arguments) } Rule { id: applicationLinker multiplex: true inputs: ["obj", "linkerscript"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile) outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product) prepare: KEIL.prepareLinker.apply(KEIL, arguments) } Rule { id: staticLibraryLinker multiplex: true inputs: ["obj"] inputsFromDependencies: ["staticlibrary"] outputFileTags: Cpp.staticLibraryLinkerOutputTags() outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product) prepare: KEIL.prepareArchiver.apply(KEIL, arguments) } } qbs-src-2.6.1/share/qbs/modules/protobuf/0000755000175100001660000000000014776170045017647 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/protobuf/objc/0000755000175100001660000000000014776170045020564 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/protobuf/objc/protobufobjc.qbs0000644000175100001660000000436114776170045023775 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Probes import "../protobufbase.qbs" as ProtobufBase import "../protobuf.js" as HelperFunctions ProtobufBase { property string includePath: includeProbe.path property string libraryPath: libraryProbe.path property string frameworkPath: frameworkProbe.path Depends { name: "cpp" } cpp.includePaths: [outputDir].concat(!frameworkPath && includePath ? [includePath] : []) cpp.libraryPaths: !frameworkPath && libraryPath ? [libraryPath] : [] cpp.dynamicLibraries: !frameworkPath && libraryPath ? ["ProtocolBuffers"] : [] cpp.frameworkPaths: frameworkPath ? [frameworkPath] : [] cpp.frameworks: ["Foundation"].concat(frameworkPath ? ["Protobuf"] : []) cpp.defines: frameworkPath ? ["GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS"] : [] Rule { inputs: ["protobuf.input"] outputFileTags: ["hpp", "protobuf.hpp", "objc"] outputArtifacts: { var outputDir = HelperFunctions.getOutputDir(input.protobuf.objc, input); return [ HelperFunctions.objcArtifact(outputDir, input, ["hpp", "protobuf.hpp"], ".pbobjc.h"), HelperFunctions.objcArtifact(outputDir, input, ["objc"], ".pbobjc.m") ]; } prepare: HelperFunctions.doPrepare(input.protobuf.objc, product, input, outputs, "objc") } Probes.IncludeProbe { id: includeProbe names: "GPBMessage.h" } Probes.LibraryProbe { id: libraryProbe names: "ProtocolBuffers" } Probes.FrameworkProbe { id: frameworkProbe names: ["Protobuf"] } validate: { HelperFunctions.validateCompiler(compilerName, compilerPath); if (!HelperFunctions.checkPath(frameworkPath)) { if (!HelperFunctions.checkPath(includePath)) { throw "Can't find objective-c protobuf include files. Please set the includePath " + "or frameworkPath property."; } if (!HelperFunctions.checkPath(libraryPath)) { throw "Can't find objective-c protobuf library. Please set the libraryPath or " + "frameworkPath property."; } } } } qbs-src-2.6.1/share/qbs/modules/protobuf/nanopb/0000755000175100001660000000000014776170045021124 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/protobuf/nanopb/nanopb.qbs0000644000175100001660000000654714776170045023124 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Probes import qbs.ModUtils import "../protobufbase.qbs" as ProtobufBase import "../protobuf.js" as HelperFunctions ProtobufBase { property string includePath: includeProbe.found ? includeProbe.path : undefined property string libraryPath: libraryProbe.found ? libraryProbe.path : undefined property string pluginPath: pluginProbe.filePath property string pluginName: "protoc-gen-nanopb" readonly property string _plugin: "protoc-gen-nanopb=" + pluginPath readonly property string _libraryName: { var libraryName; if (libraryProbe.found) { libraryName = FileInfo.baseName(libraryProbe.fileName); if (libraryName.startsWith("lib")) libraryName = libraryName.substring(3); } return libraryName; } Depends { name: "cpp" } cpp.libraryPaths: { var result = []; if (libraryProbe.found) result.push(libraryProbe.path); return result; } cpp.dynamicLibraries: { var result = []; if (_libraryName) result.push(_libraryName); return result; } cpp.includePaths: { var result = [outputDir]; if (includeProbe.found) result.push(includePath); return result; } cpp.cxxLanguageVersion: qbs.targetOS.contains("darwin") ? ["c++17"] : ["c++11"] Rule { inputs: ["protobuf.input"] outputFileTags: ["hpp", "protobuf.hpp", "cpp"] outputArtifacts: { var outputDir = HelperFunctions.getOutputDir(input.protobuf.nanopb, input); var result = [ HelperFunctions.cppArtifact(outputDir, input, ["hpp", "protobuf.hpp"], ".pb.h"), HelperFunctions.cppArtifact(outputDir, input, ["cpp"], ".pb.c") ]; return result; } prepare: { var options = input.protobuf.nanopb.importPaths.map(function (path) { return "-I" + path; }) var result = HelperFunctions.doPrepare( input.protobuf.nanopb, product, input, outputs, "nanopb", input.protobuf.nanopb._plugin, options); return result; } } Probes.IncludeProbe { id: includeProbe names: ["pb.h", "pb_encode.h", "pb_decode.h", "pb_common.h"] platformSearchPaths: includePath ? [] : base searchPaths: includePath ? [includePath] : [] } Probes.LibraryProbe { id: libraryProbe names: [ "protobuf-nanopb", "protobuf-nanopbd", ] platformSearchPaths: libraryPath ? [] : base searchPaths: libraryPath ? [libraryPath] : [] } Probes.BinaryProbe { id: pluginProbe names: pluginName } validate: { HelperFunctions.validateCompiler(compilerName, compilerPath); if (!includeProbe.found) throw "Can't find nanopb protobuf include files. Please set the includePath property."; if (!libraryProbe.found) throw "Can't find nanopb protobuf library. Please set the libraryPath property."; if (!HelperFunctions.checkPath(pluginPath)) throw "Can't find nanopb protobuf plugin. Please set the pluginPath property."; } } qbs-src-2.6.1/share/qbs/modules/protobuf/protobuf.js0000644000175100001660000001106014776170045022043 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); function validateCompiler(compilerName, compilerPath) { if (!File.exists(compilerPath)) { throw "Can't find '" + compilerName + "' binary. Please set the compilerPath property or " + "make sure the compiler is found in PATH"; } } function checkPath(path) { return path && File.exists(path); }; function toCamelCase(str){ return str.split('_').map(function(word, index) { // If it is the first word make sure to lowercase all the chars. if (index === 0) { return word.toLowerCase(); } // If it is not the first word only upper case the first char and lowercase the rest. return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); }).join(''); } function getOutputDir(module, input) { var outputDir = module.outputDir; var importPaths = module.importPaths; if (importPaths.length !== 0) { var canonicalInput = File.canonicalFilePath(FileInfo.path(input.filePath)); for (var i = 0; i < importPaths.length; ++i) { var path = File.canonicalFilePath(importPaths[i]); if (canonicalInput.startsWith(path)) { return outputDir + "/" + FileInfo.relativePath(path, canonicalInput); } } } return outputDir; } function cppArtifact(outputDir, input, tags, suffix) { return { fileTags: tags, filePath: FileInfo.joinPaths(outputDir, FileInfo.baseName(input.fileName) + suffix), cpp: { includePaths: [].concat(input.cpp.includePaths, outputDir), defines: ["NDEBUG"], warningLevel: "none", } }; } function objcArtifact(outputDir, input, tags, suffix) { return { fileTags: tags, filePath: FileInfo.joinPaths( outputDir, toCamelCase(FileInfo.baseName(input.fileName)) + suffix), cpp: { automaticReferenceCounting: false, includePaths: [].concat(input.cpp.includePaths, outputDir), warningLevel: "none", } } } function doPrepare(module, product, input, outputs, generator, plugin, generatorOptions) { var outputDir = module.outputDir; var args = []; if (!!plugin) args.push("--plugin=" + plugin) args.push("--" + generator + "_out", outputDir); if (!!generatorOptions) { for (var i = 0; i < generatorOptions.length; ++i) args.push("--" + generator + "_opt=" + generatorOptions[i]) } var importPaths = module.importPaths; if (importPaths.length === 0) importPaths = [FileInfo.path(input.filePath)]; importPaths.forEach(function(path) { if (!FileInfo.isAbsolutePath(path)) path = FileInfo.joinPaths(product.sourceDirectory, path); args.push("--proto_path", path); }); args.push(input.filePath); var cmd = new Command(module.compilerPath, args); cmd.highlight = "codegen"; cmd.description = "generating " + generator + " files for " + input.fileName; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/protobuf/cpp/0000755000175100001660000000000014776170045020431 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/protobuf/cpp/protobufcpp.qbs0000644000175100001660000000566114776170045023513 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Probes import qbs.ModUtils import "../protobufbase.qbs" as ProtobufBase import "../protobuf.js" as HelperFunctions ProtobufBase { property bool useGrpc: false property bool _linkLibraries: true readonly property bool _hasModules: protobuflib.present && (!useGrpc || grpcpp.present) property string _cxxLanguageVersion: "c++17" _searchPaths: protobuflib.present ? protobuflib.hostBinDirs : undefined property stringList _grpcSearchPaths: grpcpp.present ? grpcpp.hostBinDirs : undefined cpp.includePaths: outputDir Depends { name: "cpp" } Depends { name: "protobuflib"; condition: _linkLibraries; required: false } Depends { name: "grpc++"; id: grpcpp condition: _linkLibraries && useGrpc; required: false } property path grpcPluginPath: grpcPluginProbe.filePath Probes.BinaryProbe { condition: useGrpc id: grpcPluginProbe names: "grpc_cpp_plugin" searchPaths: _grpcSearchPaths } cpp.cxxLanguageVersion: _cxxLanguageVersion Rule { inputs: ["protobuf.input", "protobuf.grpc"] outputFileTags: ["hpp", "protobuf.hpp", "cpp"] outputArtifacts: { var outputDir = HelperFunctions.getOutputDir(input.protobuf.cpp, input); var result = [ HelperFunctions.cppArtifact(outputDir, input, ["hpp", "protobuf.hpp"], ".pb.h"), HelperFunctions.cppArtifact(outputDir, input, "cpp", ".pb.cc") ]; if (input.fileTags.includes("protobuf.grpc")) { result.push( HelperFunctions.cppArtifact(outputDir, input, ["hpp", "protobuf.hpp"], ".grpc.pb.h"), HelperFunctions.cppArtifact(outputDir, input, ["cpp"], ".grpc.pb.cc")); } return result; } prepare: { var result = HelperFunctions.doPrepare( input.protobuf.cpp, product, input, outputs, "cpp"); if (input.fileTags.includes("protobuf.grpc")) { result = ModUtils.concatAll(result, HelperFunctions.doPrepare( input.protobuf.cpp, product, input, outputs, "grpc", "protoc-gen-grpc=" + input.protobuf.cpp.grpcPluginPath)); } return result; } } validate: { HelperFunctions.validateCompiler(compilerName, compilerPath); if (_linkLibraries && ! _hasModules) { throw "Can't find cpp protobuf runtime. Make sure .pc files are present"; } if (useGrpc) { if (!File.exists(grpcPluginPath)) throw "Can't find grpc_cpp_plugin plugin. Please set the grpcPluginPath property."; } } } qbs-src-2.6.1/share/qbs/modules/protobuf/protobufbase.qbs0000644000175100001660000000106614776170045023054 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Probes import "protobuf.js" as HelperFunctions Module { property string compilerName: "protoc" property string compilerPath: compilerProbe.filePath property var _searchPaths property pathList importPaths: [] readonly property string outputDir: product.buildDirectory + "/protobuf" FileTagger { patterns: ["*.proto"] fileTags: ["protobuf.input"] } Probes.BinaryProbe { id: compilerProbe names: [compilerName] searchPaths: _searchPaths } } qbs-src-2.6.1/share/qbs/modules/Sanitizers/0000755000175100001660000000000014776170045020142 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Sanitizers/address/0000755000175100001660000000000014776170045021567 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Sanitizers/address/asan.qbs0000644000175100001660000000632314776170045023224 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Utilities Module { Depends { name: "cpp" } property bool enabled: true readonly property bool _supported: qbs.toolchain.includes("gcc") || qbs.toolchain.includes("clang-cl") || (qbs.toolchain.includes("msvc") && Utilities.versionCompare(cpp.compilerVersion, "19.28.29500.0") >= 0) readonly property bool _enabled: enabled && _supported property string detectUseAfterReturn: "always" PropertyOptions { name: "detectUseAfterReturn" description: "Whether to detect problems with stack use after return from a function" allowedValues: ["never", "runtime", "always"] } property bool detectUseAfterScope: true cpp.driverFlags: { var flags = []; if (!_enabled) return flags; if (qbs.toolchain.includes("msvc") && !qbs.toolchain.includes("clang-cl")) { flags.push("/fsanitize=address"); if (detectUseAfterReturn !== "never") flags.push("/fsanitize-address-use-after-return"); return flags; } flags.push("-fsanitize=address", "-fno-omit-frame-pointer"); if (detectUseAfterScope) flags.push("-fsanitize-address-use-after-scope"); if (detectUseAfterReturn) { if (qbs.toolchain.includes("llvm")) { var minVersion = qbs.toolchain.contains("xcode") ? "14" : "13"; if (Utilities.versionCompare(cpp.compilerVersion, minVersion) >= 0) flags.push("-fsanitize-address-use-after-return=" + detectUseAfterReturn); } else if (detectUseAfterReturn === "never") { flags.push("--param", "asan-use-after-return=0"); } } return flags; } } qbs-src-2.6.1/share/qbs/modules/texttemplate/0000755000175100001660000000000014776170045020527 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/texttemplate/texttemplate.qbs0000644000175100001660000000473114776170045023763 0ustar runnerdockerimport qbs.TextFile Module { property var dict: ({}) property string outputTag: "text" property string outputFileName FileTagger { patterns: ["*.in"] fileTags: ["texttemplate.input"] } Rule { inputs: ["texttemplate.input"] outputFileTags: [product.texttemplate.outputTag] outputArtifacts: [ { fileTags: [product.texttemplate.outputTag], filePath: input.texttemplate.outputFileName || input.completeBaseName } ] prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { try { var src = new TextFile(input.filePath, TextFile.ReadOnly); var dst = new TextFile(output.filePath, TextFile.WriteOnly); var rex = /\${(\$|\w+)}/g; var match; while (!src.atEof()) { rex.lastIndex = 0; var line = src.readLine(); var matches = []; while (match = rex.exec(line)) matches.push(match); for (var i = matches.length; --i >= 0;) { match = matches[i]; var replacement; if (match[1] === "$") { replacement = "$"; } else { replacement = input.texttemplate.dict[match[1]]; if (typeof replacement === "undefined") { throw new Error("Placeholder '" + match[1] + "' is not defined in textemplate.dict for '" + input.fileName + "'."); } } line = line.substr(0, match.index) + replacement + line.substr(match.index + match[0].length); } dst.writeLine(line); } } finally { if (src) src.close(); if (dst) dst.close(); } }; return [cmd]; } } } qbs-src-2.6.1/share/qbs/modules/cpufeatures/0000755000175100001660000000000014776170045020335 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/cpufeatures/cpufeatures.qbs0000644000175100001660000000116014776170045023370 0ustar runnerdockerModule { property bool arm_neon property bool arm_vfpv4 property bool mips_dsp property bool mips_dspr2 property bool x86_avx property bool x86_avx2 property bool x86_avx512bw property bool x86_avx512cd property bool x86_avx512dq property bool x86_avx512er property bool x86_avx512f property bool x86_avx512ifma property bool x86_avx512pf property bool x86_avx512vbmi property bool x86_avx512vl property bool x86_f16c property bool x86_sse2 property bool x86_sse3 property bool x86_sse4_1 property bool x86_sse4_2 property bool x86_ssse3 } qbs-src-2.6.1/share/qbs/modules/vcs/0000755000175100001660000000000014776170045016602 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/vcs/vcs-module.qbs0000644000175100001660000001323014776170045021366 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Process import qbs.TextFile import qbs.Utilities Module { property string type: typeProbe.type property string repoDir: project.sourceDirectory property string toolFilePath: { if (type === "git") return "git"; if (type === "svn") return "svn"; } property string headerFileName: "vcs-repo-state.h" readonly property string repoState: gitProbe.repoState || subversionProbe.repoState // Internal readonly property string includeDir: FileInfo.joinPaths(product.buildDirectory, "vcs-include") readonly property string metaDataBaseDir: typeProbe.metaDataBaseDir PropertyOptions { name: "type" allowedValues: ["git", "svn"] description: "the version control system your project is using" } Group { condition: headerFileName Depends { name: "cpp" } product.cpp.includePaths: [includeDir] Rule { multiplex: true Artifact { filePath: FileInfo.joinPaths(product.vcs.includeDir, product.vcs.headerFileName) fileTags: ["hpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "codegen"; cmd.repoState = product.vcs.repoState; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); try { f.writeLine("#ifndef VCS_REPO_STATE_H"); f.writeLine("#define VCS_REPO_STATE_H"); f.writeLine('#define VCS_REPO_STATE "' + (repoState ? repoState : "none") + '"') f.writeLine("#endif"); } finally { f.close(); } }; return [cmd]; } } } Probe { id: typeProbe property string tool: toolFilePath property string theRepoDir: repoDir property string type property string metaDataBaseDir configure: { var detector = new Process(); try { detector.setWorkingDirectory(theRepoDir); if (detector.exec(tool || "git", ["rev-parse", "--git-dir"]) === 0) { found = true; type = "git"; metaDataBaseDir = detector.readStdOut().trim(); if (!FileInfo.isAbsolutePath(metaDataBaseDir)) metaDataBaseDir = FileInfo.joinPaths(theRepoDir, metaDataBaseDir); return; } if (detector.exec(tool || "svn", ["info", "--show-item", "wc-root", "--no-newline"]) === 0) { found = true type = "svn"; metaDataBaseDir = FileInfo.joinPaths(detector.readStdOut(), ".svn"); return; } else if (detector.exec(tool || "svn", ["info"]) === 0) { if (detector.exec(tool || "svn", ["--version", "--quiet"]) === 0 && Utilities.versionCompare(detector.readStdOut().trim(), "1.9") < 0) { throw "svn too old, version >= 1.9 required"; } } } finally { detector.close(); } } } Probe { id: gitProbe condition: type === "git" property string tool: toolFilePath property string theRepoDir: repoDir property string filePath: FileInfo.joinPaths(metaDataBaseDir, "logs/HEAD") property var timestamp: File.lastModified(filePath) property string repoState configure: { if (!File.exists(filePath)) { // it is possible that the HEAD file is not present in CI environments, in this // case we can use the commit count to determine the repo state // see https://bugreports.qt.io/projects/QBS/issues/QBS-1814 try { var proc = new Process(); proc.setWorkingDirectory(theRepoDir); proc.exec(tool, ["rev-list", "HEAD", "--count"], true); } catch (e) { return; // No commits yet. } finally { proc.close(); } } try { var proc = new Process(); proc.setWorkingDirectory(theRepoDir); proc.exec(tool, ["describe", "--always", "HEAD"], true); repoState = proc.readStdOut().trim(); if (repoState) found = true; } finally { proc.close(); } } } Probe { id: subversionProbe condition: type === "svn" property string tool: toolFilePath property string theRepoDir: repoDir property string filePath: FileInfo.joinPaths(metaDataBaseDir, "wc.db") property var timestamp: File.lastModified(filePath) property string repoState configure: { var proc = new Process(); try { proc.setWorkingDirectory(theRepoDir); proc.exec(tool, ["info", "-r", "HEAD", "--show-item", "revision", "--no-newline"], true); repoState = proc.readStdOut().trim(); if (repoState) found = true; } finally { proc.close(); } } } } qbs-src-2.6.1/share/qbs/modules/bundle/0000755000175100001660000000000014776170045017260 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/bundle/MacOSX-Package-Types.xcspec0000644000175100001660000005047114776170045024223 0ustar runnerdocker/** MacOSX Package Types.xcspec Copyright (c) 1999-2015 Apple Inc. All rights reserved. Package type specifications in the Mac OS X platform. */ ( // Mach-O executable { Type = PackageType; Identifier = com.apple.package-type.mach-o-executable; Name = "Mach-O Executable"; Description = "Mach-O executable"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ""; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; }; ProductReference = { FileType = compiled.mach-o.executable; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = YES; }; }, // Mach-O object file { Type = PackageType; Identifier = com.apple.package-type.mach-o-objfile; Name = "Mach-O Object File"; Description = "Mach-O Object File"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ""; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; }; ProductReference = { FileType = compiled.mach-o.objfile; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, // Mach-O dynamic library { Type = PackageType; Identifier = com.apple.package-type.mach-o-dylib; Name = "Mach-O Dynamic Library"; Description = "Mach-O dynamic library"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ""; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; }; ProductReference = { FileType = compiled.mach-o.dylib; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, // Static library ('ar' archive containing .o files) { Type = PackageType; Identifier = com.apple.package-type.static-library; Name = "Mach-O Static Library"; Description = "Mach-O static library"; DefaultBuildSettings = { EXECUTABLE_PREFIX = "lib"; EXECUTABLE_SUFFIX = ".a"; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; }; ProductReference = { FileType = archive.ar; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, // Mach-O bundle (not related to a CFBundle) { Type = PackageType; Identifier = com.apple.package-type.mach-o-bundle; Name = "Mach-O Loadable"; Description = "Mach-O loadable"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ".dylib"; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; }; ProductReference = { FileType = compiled.mach-o.bundle; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, // CFBundle wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper; Name = "Wrapper"; Description = "Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "BNDL"; WRAPPER_PREFIX = ""; WRAPPER_SUFFIX = ".bundle"; WRAPPER_NAME = "$(WRAPPER_PREFIX)$(PRODUCT_NAME)$(WRAPPER_SUFFIX)"; CONTENTS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH_SHALLOW_BUNDLE_$(SHALLOW_BUNDLE))"; EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ""; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_FOLDER_PATH = "$(EXECUTABLE_FOLDER_PATH_SHALLOW_BUNDLE_$(SHALLOW_BUNDLE))"; EXECUTABLE_PATH = "$(EXECUTABLE_FOLDER_PATH)/$(EXECUTABLE_NAME)"; INFOPLIST_PATH = "$(CONTENTS_FOLDER_PATH)/Info.plist"; INFOSTRINGS_PATH = "$(LOCALIZED_RESOURCES_FOLDER_PATH)/InfoPlist.strings"; PKGINFO_PATH = "$(CONTENTS_FOLDER_PATH)/PkgInfo"; PBDEVELOPMENTPLIST_PATH = "$(CONTENTS_FOLDER_PATH)/pbdevelopment.plist"; VERSIONPLIST_PATH = "$(CONTENTS_FOLDER_PATH)/version.plist"; PUBLIC_HEADERS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Headers"; PRIVATE_HEADERS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/PrivateHeaders"; EXECUTABLES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Executables"; // Not the same as EXECUTABLE_FOLDER_PATH FRAMEWORKS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Frameworks"; SHARED_FRAMEWORKS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/SharedFrameworks"; SHARED_SUPPORT_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/SharedSupport"; UNLOCALIZED_RESOURCES_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH_SHALLOW_BUNDLE_$(SHALLOW_BUNDLE))"; LOCALIZED_RESOURCES_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/$(DEVELOPMENT_LANGUAGE).lproj"; DOCUMENTATION_FOLDER_PATH = "$(LOCALIZED_RESOURCES_FOLDER_PATH)/Documentation"; MODULES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Modules"; PLUGINS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/PlugIns"; SCRIPTS_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Scripts"; JAVA_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Java"; SYSTEM_EXTENSIONS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)/Library/SystemExtensions"; // Settings specific to deep bundles (macOS) CONTENTS_FOLDER_PATH_SHALLOW_BUNDLE_NO = "$(WRAPPER_NAME)/Contents"; EXECUTABLE_FOLDER_PATH_SHALLOW_BUNDLE_NO = "$(CONTENTS_FOLDER_PATH)/MacOS"; UNLOCALIZED_RESOURCES_FOLDER_PATH_SHALLOW_BUNDLE_NO = "$(CONTENTS_FOLDER_PATH)/Resources"; // Settings specific to shallow bundles (iOS, DriverKit on any OS) CONTENTS_FOLDER_PATH_SHALLOW_BUNDLE_YES = "$(WRAPPER_NAME)"; EXECUTABLE_FOLDER_PATH_SHALLOW_BUNDLE_YES = "$(CONTENTS_FOLDER_PATH)"; UNLOCALIZED_RESOURCES_FOLDER_PATH_SHALLOW_BUNDLE_YES = "$(CONTENTS_FOLDER_PATH)"; // DriverKit should always use shallow bundles SHALLOW_BUNDLE = "$(SHALLOW_BUNDLE_$(SWIFT_PLATFORM_TARGET_PREFIX))"; SHALLOW_BUNDLE_ = YES; SHALLOW_BUNDLE_macos = NO; SHALLOW_BUNDLE_ios = NO; // for macCatalyst SHALLOW_BUNDLE_driverkit = YES; }; ProductReference = { FileType = wrapper.cfbundle; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Shallow CFBundle wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.shallow; BasedOn = com.apple.package-type.wrapper; Name = "Wrapper (Shallow)"; Description = "Shallow Wrapper"; DefaultBuildSettings = { SHALLOW_BUNDLE = YES; }; ProductReference = { FileType = wrapper.cfbundle; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Application wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.application; BasedOn = com.apple.package-type.wrapper; Name = "Application Wrapper"; Description = "Application Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "APPL"; GENERATE_PKGINFO_FILE = YES; }; ProductReference = { FileType = wrapper.application; Name = "$(WRAPPER_NAME)"; IsLaunchable = YES; }; }, // Shallow Application wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.application.shallow; BasedOn = com.apple.package-type.wrapper.shallow; Name = "Application Wrapper (Shallow)"; Description = "Shallow Application Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "APPL"; GENERATE_PKGINFO_FILE = YES; SHALLOW_BUNDLE = YES; }; ProductReference = { FileType = wrapper.application; Name = "$(WRAPPER_NAME)"; IsLaunchable = YES; }; }, // System extension wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.system-extension; BasedOn = com.apple.package-type.wrapper; Name = "System Extension Wrapper"; Description = "System Extension Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "SYSX"; }; ProductReference = { FileType = wrapper.system-extension; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Driver extension wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.driver-extension; BasedOn = com.apple.package-type.wrapper.system-extension; Name = "Driver Extension Wrapper"; Description = "Driver Extension Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "DEXT"; }; ProductReference = { FileType = wrapper.driver-extension; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Kernel extension wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.kernel-extension; BasedOn = com.apple.package-type.wrapper; Name = "Kernel Extension Wrapper"; Description = "Kernel Extension Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "KEXT"; PUBLIC_HEADERS_FOLDER_PATH = "$(KEXT_FRAMEWORK)/Contents/Headers/$(KEXT_FAMILY_NAME)"; PRIVATE_HEADERS_FOLDER_PATH = "$(KEXT_FRAMEWORK)/Contents/PrivateHeaders/$(KEXT_FAMILY_NAME)"; }; ProductReference = { FileType = wrapper.cfbundle; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Shallow Kernel extension wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.kernel-extension.shallow; BasedOn = com.apple.package-type.wrapper.shallow; Name = "Kernel Extension Wrapper (Shallow)"; Description = "Shallow Kernel Extension Wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "KEXT"; PUBLIC_HEADERS_FOLDER_PATH = "$(KEXT_FRAMEWORK)/Contents/Headers/$(KEXT_FAMILY_NAME)"; PRIVATE_HEADERS_FOLDER_PATH = "$(KEXT_FRAMEWORK)/Contents/PrivateHeaders/$(KEXT_FAMILY_NAME)"; SHALLOW_BUNDLE = YES; }; ProductReference = { FileType = wrapper.cfbundle; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Framework wrapper { Type = PackageType; Identifier = com.apple.package-type.wrapper.framework; BasedOn = com.apple.package-type.wrapper; Name = "Framework Wrapper"; Description = "Framework wrapper"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "FMWK"; WRAPPER_SUFFIX = ".framework"; VERSIONS_FOLDER_PATH = "$(VERSIONS_FOLDER_PATH_SHALLOW_BUNDLE_$(SHALLOW_BUNDLE))"; CURRENT_VERSION = "Current"; INFOPLIST_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Info.plist"; PKGINFO_PATH = "$(WRAPPER_NAME)/PkgInfo"; VERSIONPLIST_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/version.plist"; EXECUTABLES_FOLDER_PATH = "$(LOCALIZED_RESOURCES_FOLDER_PATH)"; // Not the same as EXECUTABLE_FOLDER_PATH SHARED_SUPPORT_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)"; CODESIGNING_FOLDER_PATH = "$(TARGET_BUILD_DIR)/$(CONTENTS_FOLDER_PATH)"; // Settings specific to deep bundles (macOS) VERSIONS_FOLDER_PATH_SHALLOW_BUNDLE_NO = "$(WRAPPER_NAME)/Versions"; CONTENTS_FOLDER_PATH_SHALLOW_BUNDLE_NO = "$(VERSIONS_FOLDER_PATH)/$(FRAMEWORK_VERSION)"; EXECUTABLE_FOLDER_PATH_SHALLOW_BUNDLE_NO = "$(CONTENTS_FOLDER_PATH)"; // Settings specific to shallow bundles (iOS, DriverKit on any OS) VERSIONS_FOLDER_PATH_SHALLOW_BUNDLE_YES = "$(WRAPPER_NAME)"; }; ProductReference = { FileType = wrapper.framework; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Static framework wrapper (like a framework, except that it contains a libX.a instead of a dylib) { Type = PackageType; Identifier = com.apple.package-type.wrapper.framework.static; Name = "Mach-O Static Framework"; Description = "Mach-O static framework"; BasedOn = com.apple.package-type.wrapper.framework; DefaultBuildSettings = { }; ProductReference = { FileType = wrapper.framework.static; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Shallow Framework Package { Type = PackageType; Identifier = com.apple.package-type.wrapper.framework.shallow; Name = "Shallow Framework Wrapper"; Description = "Shallow framework wrapper"; BasedOn = com.apple.package-type.wrapper.framework; DefaultBuildSettings = { SHALLOW_BUNDLE = YES; }; ProductReference = { FileType = wrapper.framework; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Unit Test Bundle wrapper { Type = PackageType; Identifier = com.apple.package-type.bundle.unit-test; BasedOn = com.apple.package-type.wrapper; Name = "Unit Test Bundle"; Description = "Unit Test Bundle"; DefaultBuildSettings = { WRAPPER_SUFFIX = "xctest"; }; ProductReference = { FileType = wrapper.cfbundle; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Legacy OCUnit Test Bundle wrapper { Type = PackageType; Identifier = com.apple.package-type.bundle.ocunit-test; BasedOn = com.apple.package-type.wrapper; Name = "OCUnit Test Bundle"; Description = "OCUnit Test Bundle"; DefaultBuildSettings = { WRAPPER_SUFFIX = "octest"; }; ProductReference = { FileType = wrapper.cfbundle; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // In-app Purchase Content wrapper { Type = PackageType; Identifier = com.apple.package-type.in-app-purchase-content; BasedOn = com.apple.package-type.wrapper; Name = "In-App Purchase Content"; Description = "In-App Purchase Content"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = ""; WRAPPER_SUFFIX = ""; EXECUTABLE_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; INFOPLIST_PATH = "$(WRAPPER_NAME)/ContentInfo.plist"; INFOSTRINGS_PATH = "$(LOCALIZED_RESOURCES_FOLDER_PATH)/ContentInfo.strings"; PUBLIC_HEADERS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; PRIVATE_HEADERS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; EXECUTABLES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; FRAMEWORKS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; SHARED_FRAMEWORKS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; SHARED_SUPPORT_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; UNLOCALIZED_RESOURCES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; LOCALIZED_RESOURCES_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/$(DEVELOPMENT_LANGUAGE).lproj"; DOCUMENTATION_FOLDER_PATH = "$(LOCALIZED_RESOURCES_FOLDER_PATH)"; MODULES_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; PLUGINS_FOLDER_PATH = "$(CONTENTS_FOLDER_PATH)"; SCRIPTS_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)"; JAVA_FOLDER_PATH = "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)"; }; ProductReference = { FileType = folder; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // XPC Service wrapper { Type = PackageType; Identifier = com.apple.package-type.xpc-service; BasedOn = com.apple.package-type.wrapper; Name = "XPC Service"; Description = "XPC Service"; DefaultBuildSettings = { PRODUCT_BUNDLE_PACKAGE_TYPE = "XPC!"; WRAPPER_SUFFIX = ".xpc"; }; ProductReference = { FileType = wrapper.xpc-service; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // PlugInKit PlugIn wrapper { Type = PackageType; Identifier = com.apple.package-type.pluginkit-plugin; BasedOn = com.apple.package-type.xpc-service; Name = "PlugInKit PlugIn"; Description = "PlugInKit PlugIn"; DefaultBuildSettings = { WRAPPER_SUFFIX = ".pluginkit"; }; ProductReference = { FileType = wrapper.app-extension; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // App Extension wrapper { Type = PackageType; Identifier = com.apple.package-type.app-extension; BasedOn = com.apple.package-type.pluginkit-plugin; Name = "App Extension"; Description = "App Extension"; DefaultBuildSettings = { WRAPPER_SUFFIX = ".appex"; }; ProductReference = { FileType = wrapper.app-extension; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Spotlight Importer wrapper { Type = PackageType; Identifier = com.apple.package-type.spotlight-importer; BasedOn = com.apple.package-type.wrapper; Name = "Spotlight Importer"; Description = "Spotlight Importer"; DefaultBuildSettings = { }; ProductReference = { FileType = wrapper.spotlight-importer; Name = "$(WRAPPER_NAME)"; IsLaunchable = NO; }; }, // Jar file { Type = PackageType; Identifier = com.apple.package-type.jarfile; Name = "Jar File"; Description = "Jar file"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ".jar"; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; JAVA_ARCHIVE_CLASSES = YES; JAVA_MAKE_ZIPFILE = NO; }; ProductReference = { FileType = archive.jar; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, // Zip file { Type = PackageType; Identifier = com.apple.package-type.zipfile; Name = "Zip File"; Description = "Zip file"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ".zip"; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; JAVA_ARCHIVE_CLASSES = YES; JAVA_MAKE_ZIPFILE = YES; }; ProductReference = { FileType = archive.zip; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, // Java class folder { Type = PackageType; Identifier = com.apple.package-type.javaclassfolder; Name = "Class Folder"; Description = "Class folder"; DefaultBuildSettings = { EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ""; EXECUTABLE_NAME = "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_SUFFIX)"; EXECUTABLE_PATH = "$(EXECUTABLE_NAME)"; JAVA_ARCHIVE_CLASSES = NO; }; ProductReference = { FileType = wrapper.java-classfolder; Name = "$(EXECUTABLE_NAME)"; IsLaunchable = NO; }; }, ) qbs-src-2.6.1/share/qbs/modules/bundle/BundleModule.qbs0000644000175100001660000004003414776170045022347 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.BundleTools import qbs.DarwinTools import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.PropertyList import qbs.TextFile import qbs.Utilities import "bundle.js" as Bundle import "../codesign/codesign.js" as Codesign Module { Depends { name: "xcode"; required: false; } Depends { name: "codesign"; required: false; } Probe { id: bundleSettingsProbe condition: qbs.targetOS.includes("darwin") property string xcodeDeveloperPath: xcode.developerPath property var xcodeArchSettings: xcode._architectureSettings property string productTypeIdentifier: _productTypeIdentifier property bool useXcodeBuildSpecs: !useBuiltinXcodeBuildSpecs property bool isMacOs: qbs.targetOS.includes("macos") property bool xcodePresent: xcode.present property string xcodeVersion: xcode.version // 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, "IS_MACCATALYST": "NO", "LD_RUNPATH_SEARCH_PATHS_NO": [], "PRODUCT_NAME": product.targetName, "LOCAL_APPS_DIR": Environment.getEnv("HOME") + "/Applications", "LOCAL_LIBRARY_DIR": Environment.getEnv("HOME") + "/Library", // actually, this is cpp.targetAbi, but XCode does not set it for non-simulator builds // while Qbs set it to "macho". "LLVM_TARGET_TRIPLE_SUFFIX": qbs.targetOS.includes("simulator") ? "-simulator" : "", "SWIFT_PLATFORM_TARGET_PREFIX": isMacOs ? "macos" : qbs.targetOS.includes("ios") ? "ios" : "", "TARGET_BUILD_DIR": product.buildDirectory, "WRAPPER_NAME": bundleName, "WRAPPER_EXTENSION": extension }) // Outputs property var xcodeSettings: ({}) property var productTypeIdentifierChain: [] configure: { var specsPaths = [path]; var specsSeparator = "-"; if (xcodeDeveloperPath && useXcodeBuildSpecs) { specsPaths = Bundle.macOSSpecsPaths(xcodeVersion, xcodeDeveloperPath); specsSeparator = " "; } var reader = new Bundle.XcodeBuildSpecsReader(specsPaths, specsSeparator, additionalSettings, !isMacOs); var settings = reader.expandedSettings(productTypeIdentifier, xcodePresent ? xcodeArchSettings : {}); var chain = reader.productTypeIdentifierChain(productTypeIdentifier); if (settings && chain) { xcodeSettings = settings; productTypeIdentifierChain = chain; found = true; } else { xcodeSettings = {}; productTypeIdentifierChain = []; found = false; } } } additionalProductTypes: !(product.multiplexed || product.aggregate) || !product.multiplexConfigurationId ? ["bundle.content"] : [] property bool isBundle: !product.consoleApplication && qbs.targetOS.includes("darwin") 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: bundleSettingsProbe.xcodeSettings["WRAPPER_EXTENSION"] property string packageType: Bundle.packageType(_productTypeIdentifier) property string signature: "????" // legacy creator code in Mac OS Classic (CFBundleSignature), can be ignored property string bundleName: bundleSettingsProbe.xcodeSettings["WRAPPER_NAME"] property string frameworkVersion: { 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 property pathList privateHeaders property pathList resources property var infoPlist property bool processInfoPlist: true property bool embedInfoPlist: product.consoleApplication && !isBundle property string infoPlistFormat: qbs.targetOS.includes("macos") ? "same-as-input" : "binary1" property string localizedResourcesFolderSuffix: ".lproj" property string lsregisterName: "lsregister" property string lsregisterPath: FileInfo.joinPaths( "/System/Library/Frameworks/CoreServices.framework" + "/Versions/A/Frameworks/LaunchServices.framework" + "/Versions/A/Support", lsregisterName); // all paths are relative to the directory containing the bundle 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"] property bool useBuiltinXcodeBuildSpecs: !_useXcodeBuildSpecs // true to use ONLY the qbs build specs // private properties property string _productTypeIdentifier: Bundle.productTypeIdentifier(product.type) property stringList _productTypeIdentifierChain: bundleSettingsProbe.productTypeIdentifierChain readonly property path _developerPath: xcode.developerPath readonly property path _platformInfoPlist: xcode.platformInfoPlist readonly property path _sdkSettingsPlist: xcode.sdkSettingsPlist readonly property path _toolchainInfoPlist: xcode.toolchainInfoPlist property bool _useXcodeBuildSpecs: true // TODO: remove in 1.25 property var extraEnv: ({ "PRODUCT_BUNDLE_IDENTIFIER": identifier }) readonly property var qmakeEnv: { return { "BUNDLEIDENTIFIER": identifier, "EXECUTABLE": product.targetName, "FULL_VERSION": product.version || "1.0", // CFBundleVersion "ICON": product.targetName, // ### QBS-73 "LIBRARY": product.targetName, "SHORT_VERSION": product.version || "1.0", // CFBundleShortVersionString "TYPEINFO": signature // CFBundleSignature }; } readonly property var defaultInfoPlist: { return { CFBundleDevelopmentRegion: "en", // default localization CFBundleDisplayName: product.targetName, // localizable CFBundleExecutable: product.targetName, CFBundleIdentifier: identifier, CFBundleInfoDictionaryVersion: "6.0", CFBundleName: product.targetName, // short display name of the bundle, localizable CFBundlePackageType: packageType, CFBundleShortVersionString: product.version || "1.0", // "release" version number, localizable CFBundleSignature: signature, // legacy creator code in Mac OS Classic, can be ignored CFBundleVersion: product.version || "1.0.0" // build version number, must be 3 octets }; } validate: { if (!qbs.targetOS.includes("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"] } Rule { condition: qbs.targetOS.includes("darwin") multiplex: true requiresInputs: false // TODO: The resources property should probably be a tag instead. inputs: ["infoplist", "partial_infoplist"] outputFileTags: ["bundle.input", "aggregate_infoplist"] outputArtifacts: Bundle.aggregateInfoPlistOutputs(product) prepare: Bundle.aggregateInfoPlistCommands.apply(Bundle, arguments) } Rule { condition: qbs.targetOS.includes("darwin") multiplex: true inputs: ["aggregate_infoplist"] outputFileTags: ["bundle.input", "pkginfo"] outputArtifacts: Bundle.generatePkgInfoOutputs(product) prepare: Bundle.generatePkgInfoCommands.apply(Bundle, arguments) } Rule { condition: qbs.targetOS.includes("darwin") multiplex: true inputs: ["bundle.input", "aggregate_infoplist", "pkginfo", "hpp", "icns", "codesign.xcent", "compiled_ibdoc", "compiled_assetcatalog", "codesign.embedded_provisioningprofile", "bundle.input.privacymanifest"] // Make sure the inputs of this rule are only those rules which produce outputs compatible // with the type of the bundle being produced. excludedInputs: Bundle.excludedAuxiliaryInputs(project, product) outputFileTags: [ "bundle.content", "bundle.symlink.headers", "bundle.symlink.private-headers", "bundle.symlink.resources", "bundle.symlink.executable", "bundle.symlink.version", "bundle.hpp", "bundle.resource", "bundle.provisioningprofile", "bundle.content.copied", "bundle.application-executable", "bundle.code-signature", "bundle.privacymanifest"] outputArtifacts: Bundle.generateBundleOutputs(product, inputs) prepare: Bundle.generateBundleCommands.apply(Bundle, arguments) } } qbs-src-2.6.1/share/qbs/modules/bundle/bundle.js0000644000175100001660000010530714776170045021075 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Codesign = require("../codesign/codesign.js"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var DarwinTools = require("qbs.DarwinTools"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var Utilities = require("qbs.Utilities"); // HACK: Workaround until the PropertyList extension is supported cross-platform var TextFile = require("qbs.TextFile"); 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.includes(k)) return _productTypeIdentifiers[k]; } return "com.apple.package-type.wrapper"; } function excludedAuxiliaryInputs(project, product) { var chain = product.bundle._productTypeIdentifierChain; var bestPossibleType; for (var i = chain.length - 1; i >= 0; --i) { switch (chain[i]) { case "com.apple.product-type.bundle": bestPossibleType = "loadablemodule"; break; case "com.apple.product-type.framework": bestPossibleType = "dynamiclibrary"; break; case "com.apple.product-type.framework.static": bestPossibleType = "staticlibrary"; break; case "com.apple.product-type.application": case "com.apple.product-type.xpc-service": bestPossibleType = "application"; break; } } var excluded = []; var possibleTypes = ["application", "dynamiclibrary", "staticlibrary", "loadablemodule"]; for (i = 0; i < possibleTypes.length; ++i) { if (possibleTypes[i] !== bestPossibleType) excluded.push(possibleTypes[i]); } return excluded; } function packageType(productTypeIdentifier) { switch (productTypeIdentifier) { case "com.apple.product-type.in-app-purchase-content": return undefined; case "com.apple.product-type.app-extension": case "com.apple.product-type.xpc-service": return "XPC!"; case "com.apple.product-type.application": return "APPL"; case "com.apple.product-type.framework": case "com.apple.product-type.framework.static": return "FMWK"; case "com.apple.product-type.kernel-extension": case "com.apple.product-type.kernel-extension.iokit": return "KEXT"; default: return "BNDL"; } } function _assign(target, source) { if (source) { for (var k in source) { if (source.hasOwnProperty(k)) target[k] = source[k]; } return target; } } function macOSSpecsPaths(version, developerPath) { var result = []; if (Utilities.versionCompare(version, "15.3") >= 0) { result.push(FileInfo.joinPaths( developerPath, "..", "SharedFrameworks", "XCBuild.framework", "PlugIns", "XCBBuildService.bundle", "Contents", "PlugIns", "XCBSpecifications.ideplugin", "Contents", "Resources")); } if (Utilities.versionCompare(version, "14.3") >= 0) { result.push(FileInfo.joinPaths( developerPath, "Library", "Xcode", "Plug-ins", "XCBSpecifications.ideplugin", "Contents", "Resources")); } else if (Utilities.versionCompare(version, "12.5") >= 0) { result.push(FileInfo.joinPaths( developerPath, "..", "PlugIns", "XCBSpecifications.ideplugin", "Contents", "Resources")); } else if (Utilities.versionCompare(version, "12") >= 0) { result.push(FileInfo.joinPaths( developerPath, "Platforms", "MacOSX.platform", "Developer", "Library", "Xcode", "PrivatePlugIns", "IDEOSXSupportCore.ideplugin", "Contents", "Resources")); } else { result.push(FileInfo.joinPaths( developerPath, "Platforms", "MacOSX.platform", "Developer", "Library", "Xcode", "Specifications")); } return result; } var XcodeBuildSpecsReader = (function () { function XcodeBuildSpecsReader(specsPaths, separator, additionalSettings, useShallowBundles) { this._additionalSettings = additionalSettings; this._useShallowBundles = useShallowBundles; this._packageTypes = []; this._productTypes = []; var i, j; for (i = 0; i < specsPaths.length; ++i) { var specsPath = specsPaths[i]; var names = ["", "Darwin", "MacOSX"]; for (j = 0; j < names.length; ++j) { var name = names[j]; var plist = new PropertyList2(); var plist2 = new PropertyList2(); try { var plistName = [name, "Package", "Types.xcspec"].join(name ? separator : ""); var plistName2 = [name, "Product", "Types.xcspec"].join(name ? separator : ""); var plistPath = FileInfo.joinPaths(specsPath, plistName); var plistPath2 = FileInfo.joinPaths(specsPath, plistName2); if (File.exists(plistPath)) { plist.readFromFile(plistPath); this._packageTypes = this._packageTypes.concat(plist.toObject()); } if (File.exists(plistPath2)) { plist2.readFromFile(plistPath2); this._productTypes = this._productTypes.concat(plist2.toObject()); } } finally { plist.clear(); plist2.clear(); } } } 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]; } XcodeBuildSpecsReader.prototype.productTypeIdentifierChain = function (typeIdentifier) { var ids = [typeIdentifier]; var obj = this._types[typeIdentifier]; var parentId = obj && obj["BasedOn"]; if (parentId) return ids.concat(this.productTypeIdentifierChain(parentId)); return ids; }; 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 // macOS 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, baseSettings) { var obj = this.settings(typeIdentifier, true); if (obj) { for (var k in obj) obj[k] = this.expandedSetting(typeIdentifier, baseSettings, k); return obj; } }; XcodeBuildSpecsReader.prototype.expandedSetting = function (typeIdentifier, baseSettings, settingName) { var obj = {}; _assign(obj, baseSettings); // todo: copy recursively obj = _assign(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, false)["key"]; } return setting; } }; return XcodeBuildSpecsReader; }()); function generateBundleOutputs(product, inputs) { var i, artifacts = []; if (product.bundle.isBundle) { for (i in inputs["bundle.input"]) { var fp = inputs["bundle.input"][i].bundle._bundleFilePath; if (!fp) throw("Artifact " + inputs["bundle.input"][i].filePath + " has no associated bundle file path"); var extraTags = inputs["bundle.input"][i].fileTags.includes("application") ? ["bundle.application-executable"] : []; artifacts.push({ filePath: fp, fileTags: ["bundle.content", "bundle.content.copied"].concat(extraTags) }); } var provprofiles = inputs["codesign.embedded_provisioningprofile"]; for (i in provprofiles) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.contentsFolderPath, provprofiles[i].fileName), fileTags: ["bundle.provisioningprofile", "bundle.content"] }); } var privacymanifests = inputs["bundle.input.privacymanifest"] || []; for (var i = 0; i < privacymanifests.length; ++i) { var filePath; if (product.qbs.targetOS.includes("macos")) { filePath = FileInfo.joinPaths(product.destinationDirectory, product.bundle.contentsFolderPath, "Resources", privacymanifests[i].fileName); } else if (product.qbs.targetOS.includes("ios")) { filePath = FileInfo.joinPaths(product.destinationDirectory, product.bundle.contentsFolderPath, privacymanifests[i].fileName); } if (filePath) { artifacts.push({ filePath: filePath, fileTags: ["bundle.content", "bundle.privacymanifest"] }); } } var packageType = product.bundle.packageType; var isShallow = product.bundle.isShallow; if (packageType === "FMWK" && !isShallow) { var publicHeaders = product.bundle.publicHeaders; if (publicHeaders && publicHeaders.length) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.bundleName, "Headers"), fileTags: ["bundle.symlink.headers", "bundle.content"] }); } var privateHeaders = ModUtils.moduleProperty(product, "privateHeaders"); if (privateHeaders && privateHeaders.length) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.bundleName, "PrivateHeaders"), fileTags: ["bundle.symlink.private-headers", "bundle.content"] }); } artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.bundleName, "Resources"), fileTags: ["bundle.symlink.resources", "bundle.content"] }); artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.bundleName, product.targetName), fileTags: ["bundle.symlink.executable", "bundle.content"] }); artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.versionsFolderPath, "Current"), fileTags: ["bundle.symlink.version", "bundle.content"] }); } var headerTypes = ["public", "private"]; for (var h in headerTypes) { var sources = ModUtils.moduleProperty(product, headerTypes[h] + "Headers"); var destination = FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, headerTypes[h] + "HeadersFolderPath")); for (i in sources) { artifacts.push({ filePath: FileInfo.joinPaths(destination, FileInfo.fileName(sources[i])), fileTags: ["bundle.hpp", "bundle.content"] }); } } sources = product.bundle.resources; for (i in sources) { destination = BundleTools.destinationDirectoryForResource(product, {baseDir: FileInfo.path(sources[i]), fileName: FileInfo.fileName(sources[i])}); artifacts.push({ filePath: FileInfo.joinPaths(destination, FileInfo.fileName(sources[i])), fileTags: ["bundle.resource", "bundle.content"] }); } var wrapperPath = FileInfo.joinPaths( product.destinationDirectory, product.bundle.bundleName); for (var i = 0; i < artifacts.length; ++i) artifacts[i].bundle = { wrapperPath: wrapperPath }; if (Host.os().includes("darwin") && product.codesign && product.codesign.enableCodeSigning) { artifacts.push({ filePath: FileInfo.joinPaths(product.bundle.contentsFolderPath, "_CodeSignature/CodeResources"), fileTags: ["bundle.code-signature", "bundle.content"] }); } } return artifacts; } function generateBundleCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var i, cmd, commands = []; var packageType = product.bundle.packageType; var bundleType = "bundle"; if (packageType === "APPL") bundleType = "application"; if (packageType === "FMWK") bundleType = "framework"; // Product is unbundled if (!product.bundle.isBundle) { cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function () { }; commands.push(cmd); } var symlinks = outputs["bundle.symlink.version"]; for (i in symlinks) { cmd = new Command("ln", ["-sfn", product.bundle.frameworkVersion, symlinks[i].filePath]); cmd.silent = true; commands.push(cmd); } var publicHeaders = outputs["bundle.symlink.headers"]; for (i in publicHeaders) { cmd = new Command("ln", ["-sfn", "Versions/Current/Headers", publicHeaders[i].filePath]); cmd.silent = true; commands.push(cmd); } var privateHeaders = outputs["bundle.symlink.private-headers"]; for (i in privateHeaders) { cmd = new Command("ln", ["-sfn", "Versions/Current/PrivateHeaders", privateHeaders[i].filePath]); cmd.silent = true; commands.push(cmd); } var resources = outputs["bundle.symlink.resources"]; for (i in resources) { cmd = new Command("ln", ["-sfn", "Versions/Current/Resources", resources[i].filePath]); cmd.silent = true; commands.push(cmd); } var executables = outputs["bundle.symlink.executable"]; for (i in executables) { cmd = new Command("ln", ["-sfn", FileInfo.joinPaths("Versions", "Current", product.targetName), executables[i].filePath]); cmd.silent = true; commands.push(cmd); } function sortedArtifactList(list, func) { if (list) { return list.sort(func || (function (a, b) { return a.filePath.localeCompare(b.filePath); })); } } var bundleInputs = sortedArtifactList(inputs["bundle.input"], function (a, b) { return a.bundle._bundleFilePath.localeCompare( b.bundle._bundleFilePath); }); var bundleContents = sortedArtifactList(outputs["bundle.content.copied"]); for (i in bundleContents) { cmd = new JavaScriptCommand(); cmd.silent = true; cmd.source = bundleInputs[i].filePath; cmd.destination = bundleContents[i].filePath; cmd.sourceCode = function() { File.copy(source, destination); }; commands.push(cmd); } cmd = new JavaScriptCommand(); cmd.description = "copying provisioning profile"; cmd.highlight = "filegen"; cmd.sources = (inputs["codesign.embedded_provisioningprofile"] || []) .map(function(artifact) { return artifact.filePath; }); cmd.destination = (outputs["bundle.provisioningprofile"] || []) .map(function(artifact) { return artifact.filePath; }); cmd.sourceCode = function() { var i; for (var i in sources) { File.copy(sources[i], destination[i]); } }; if (cmd.sources && cmd.sources.length) commands.push(cmd); cmd = new JavaScriptCommand(); cmd.description = "copying privacy manifest"; cmd.highlight = "filegen"; cmd.sources = (inputs["bundle.input.privacymanifest"] || []) .map(function(artifact) { return artifact.filePath; }); cmd.destination = (outputs["bundle.privacymanifest"] || []) .map(function(artifact) { return artifact.filePath; }); cmd.sourceCode = function() { var i; for (var i = 0; i < sources.length; ++i) File.copy(sources[i], destination[i]); }; if (cmd.sources && cmd.sources.length) commands.push(cmd); cmd = new JavaScriptCommand(); cmd.description = "copying public headers"; cmd.highlight = "filegen"; cmd.sources = product.bundle.publicHeaders; cmd.destination = FileInfo.joinPaths(product.destinationDirectory, product.bundle.publicHeadersFolderPath); cmd.sourceCode = function() { var i; for (var i in sources) { File.copy(sources[i], FileInfo.joinPaths(destination, FileInfo.fileName(sources[i]))); } }; if (cmd.sources && cmd.sources.length) commands.push(cmd); cmd = new JavaScriptCommand(); cmd.description = "copying private headers"; cmd.highlight = "filegen"; cmd.sources = product.bundle.privateHeaders; cmd.destination = FileInfo.joinPaths(product.destinationDirectory, product.bundle.privateHeadersFolderPath); cmd.sourceCode = function() { var i; for (var i in sources) { File.copy(sources[i], FileInfo.joinPaths(destination, FileInfo.fileName(sources[i]))); } }; if (cmd.sources && cmd.sources.length) commands.push(cmd); cmd = new JavaScriptCommand(); cmd.description = "copying resources"; cmd.highlight = "filegen"; cmd.sources = product.bundle.resources; cmd.sourceCode = function() { var i; for (var i in sources) { var destination = BundleTools.destinationDirectoryForResource(product, {baseDir: FileInfo.path(sources[i]), fileName: FileInfo.fileName(sources[i])}); File.copy(sources[i], FileInfo.joinPaths(destination, FileInfo.fileName(sources[i]))); } }; if (cmd.sources && cmd.sources.length) commands.push(cmd); if (product.qbs.hostOS.includes("darwin")) { Array.prototype.push.apply(commands, Codesign.prepareSign( project, product, inputs, outputs, input, output)); if (bundleType === "application" && product.qbs.targetOS.includes("macos")) { var bundlePath = FileInfo.joinPaths( product.destinationDirectory, product.bundle.bundleName); cmd = new Command(product.bundle.lsregisterPath, ["-f", bundlePath]); cmd.description = "registering " + product.bundle.bundleName; commands.push(cmd); } } return commands; } function generatePkgInfoOutputs(product) { var artifacts = []; if (product.bundle.isBundle && product.bundle.generatePackageInfo) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, "PkgInfo"), fileTags: ["bundle.input", "pkginfo"], bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, product.bundle.pkgInfoPath) } }); } return artifacts; } function generatePkgInfoCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "generating PkgInfo for " + product.name; cmd.highlight = "codegen"; cmd.sourceCode = function() { var infoPlist = BundleTools.infoPlistContents(inputs.aggregate_infoplist[0].filePath); var pkgType = infoPlist['CFBundlePackageType']; if (!pkgType) throw("CFBundlePackageType not found in Info.plist; this should not happen"); var pkgSign = infoPlist['CFBundleSignature']; if (!pkgSign) throw("CFBundleSignature not found in Info.plist; this should not happen"); var pkginfo = new TextFile(outputs.pkginfo[0].filePath, TextFile.WriteOnly); pkginfo.write(pkgType + pkgSign); pkginfo.close(); } return cmd; } function aggregateInfoPlistOutputs(product) { var artifacts = []; var embed = product.bundle.embedInfoPlist; if (product.bundle.isBundle || embed) { artifacts.push({ filePath: FileInfo.joinPaths( product.destinationDirectory, product.name + "-Info.plist"), fileTags: ["aggregate_infoplist"].concat(!embed ? ["bundle.input"] : []), bundle: { _bundleFilePath: FileInfo.joinPaths( product.destinationDirectory, product.bundle.infoPlistPath), } }); } return artifacts; } function aggregateInfoPlistCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "generating Info.plist for " + product.name; cmd.highlight = "codegen"; cmd.infoPlist = product.bundle.infoPlist || {}; cmd.processInfoPlist = product.bundle.processInfoPlist; cmd.infoPlistFormat = product.bundle.infoPlistFormat; cmd.extraEnv = product.bundle.extraEnv; cmd.qmakeEnv = product.bundle.qmakeEnv; // TODO: bundle module should know nothing about cpp module cmd.buildEnv = product.moduleProperty("cpp", "buildEnv"); cmd.developerPath = product.bundle._developerPath; cmd.platformInfoPlist = product.bundle._platformInfoPlist; cmd.sdkSettingsPlist = product.bundle._sdkSettingsPlist; cmd.toolchainInfoPlist = product.bundle._toolchainInfoPlist; cmd.osBuildVersion = product.qbs.hostOSBuildVersion; cmd.sourceCode = function() { var plist, process, key, i; // Contains the combination of default, file, and in-source keys and values // Start out with the contents of this file as the "base", if given var aggregatePlist = {}; for (i = 0; i < (inputs.infoplist || []).length; ++i) { aggregatePlist = BundleTools.infoPlistContents(inputs.infoplist[i].filePath); infoPlistFormat = (infoPlistFormat === "same-as-input") ? BundleTools.infoPlistFormat(inputs.infoplist[i].filePath) : "xml1"; break; } // Add local key-value pairs (overrides equivalent keys specified in the file if // one was given) for (key in infoPlist) { if (infoPlist.hasOwnProperty(key)) aggregatePlist[key] = infoPlist[key]; } // Do some postprocessing if desired if (processInfoPlist) { // Add default values to the aggregate plist if the corresponding keys // for those values are not already present var defaultValues = product.bundle.defaultInfoPlist; for (key in defaultValues) { if (defaultValues.hasOwnProperty(key) && !(key in aggregatePlist)) aggregatePlist[key] = defaultValues[key]; } // Add keys from platform's Info.plist if not already present var platformInfo = {}; var sdkSettings = {}; var toolchainInfo = {}; if (developerPath) { plist = new PropertyList(); try { plist.readFromFile(platformInfoPlist); platformInfo = plist.toObject(); } finally { plist.clear(); } var additionalProps = platformInfo["AdditionalInfo"]; for (key in additionalProps) { // override infoPlist? if (additionalProps.hasOwnProperty(key) && !(key in aggregatePlist)) aggregatePlist[key] = defaultValues[key]; } props = platformInfo['OverrideProperties']; for (key in props) { aggregatePlist[key] = props[key]; } plist = new PropertyList(); try { plist.readFromFile(sdkSettingsPlist); sdkSettings = plist.toObject(); } finally { plist.clear(); } plist = new PropertyList(); try { plist.readFromFile(toolchainInfoPlist); toolchainInfo = plist.toObject(); } finally { plist.clear(); } } aggregatePlist["BuildMachineOSBuild"] = osBuildVersion; // setup env env = { "SDK_NAME": sdkSettings["CanonicalName"], "XCODE_VERSION_ACTUAL": toolchainInfo["DTXcode"], "SDK_PRODUCT_BUILD_VERSION": toolchainInfo["DTPlatformBuild"], "GCC_VERSION": platformInfo["DTCompiler"], "XCODE_PRODUCT_BUILD_VERSION": platformInfo["DTPlatformBuild"], "PLATFORM_PRODUCT_BUILD_VERSION": platformInfo["ProductBuildVersion"], } env["MAC_OS_X_PRODUCT_BUILD_VERSION"] = osBuildVersion; for (key in extraEnv) env[key] = extraEnv[key]; for (key in buildEnv) env[key] = buildEnv[key]; for (key in qmakeEnv) env[key] = qmakeEnv[key]; var expander = new DarwinTools.PropertyListVariableExpander(); expander.undefinedVariableFunction = function (key, varName) { var msg = "Info.plist variable expansion encountered undefined variable '" + varName + "' when expanding value for key '" + key + "', defined in one of the following files:\n\t"; var allFilePaths = []; for (i = 0; i < (inputs.infoplist || []).length; ++i) allFilePaths.push(inputs.infoplist[i].filePath); if (platformInfoPlist) allFilePaths.push(platformInfoPlist); msg += allFilePaths.join("\n\t") + "\n"; msg += "or in the bundle.infoPlist property of product '" + product.name + "'"; console.warn(msg); }; aggregatePlist = expander.expand(aggregatePlist, env); // Add keys from partial Info.plists from asset catalogs, XIBs, and storyboards. for (var j = 0; j < (inputs.partial_infoplist || []).length; ++j) { var partialInfoPlist = BundleTools.infoPlistContents( inputs.partial_infoplist[j].filePath) || {}; for (key in partialInfoPlist) { if (partialInfoPlist.hasOwnProperty(key) && aggregatePlist[key] === undefined) aggregatePlist[key] = partialInfoPlist[key]; } } } // Anything with an undefined or otherwise empty value should be removed // Only JSON-formatted plists can have null values, other formats error out // This also follows Xcode behavior DarwinTools.cleanPropertyList(aggregatePlist); if (infoPlistFormat === "same-as-input") infoPlistFormat = "xml1"; var validFormats = [ "xml1", "binary1", "json" ]; if (!validFormats.includes(infoPlistFormat)) throw("Invalid Info.plist format " + infoPlistFormat + ". " + "Must be in [xml1, binary1, json]."); // Write the plist contents in the format appropriate for the current platform plist = new PropertyList(); try { plist.readFromObject(aggregatePlist); plist.writeToFile(outputs.aggregate_infoplist[0].filePath, infoPlistFormat); } finally { plist.clear(); } } return cmd; } qbs-src-2.6.1/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec0000644000175100001660000007550014776170045024310 0ustar runnerdocker// // MacOSX Product Types.xcspec // // Copyright © 1999-2020 Apple Inc. All rights reserved. // // Product type specifications in the macOS platform. // ( // // Single-file product types // // Tool (normal Unix command-line executable) { Type = ProductType; Identifier = com.apple.product-type.tool; Class = PBXToolProductType; Name = "Command-line Tool"; Description = "Standalone command-line tool"; IconNamePrefix = "TargetExecutable"; DefaultTargetName = "Command-line Tool"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; MACH_O_TYPE = "mh_execute"; EXECUTABLE_PREFIX = ""; EXECUTABLE_SUFFIX = ""; REZ_EXECUTABLE = YES; INSTALL_PATH = "/usr/local/bin"; FRAMEWORK_FLAG_PREFIX = "-framework"; LIBRARY_FLAG_PREFIX = "-l"; LIBRARY_FLAG_NOSPACE = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; STRIP_STYLE = "all"; CODE_SIGNING_ALLOWED = YES; }; PackageTypes = ( com.apple.package-type.mach-o-executable // default ); WantsSigningEditing = YES; WantsBundleIdentifierEditing = YES; }, // Java tool { Type = ProductType; Identifier = com.apple.product-type.tool.java; Name = "Java Command-line Tool"; Description = "Java Command-line tool"; IconNamePrefix = "TargetExecutable"; DefaultTargetName = "Java Command-line Tool"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; REZ_EXECUTABLE = YES; INSTALL_PATH = "/usr/local/bin"; }; IsJava = YES; PackageTypes = ( com.apple.package-type.jarfile, // default com.apple.package-type.zipfile, com.apple.package-type.javaclassfolder ); }, // Object file { Type = ProductType; Identifier = com.apple.product-type.objfile; Class = XCStandaloneExecutableProductType; Name = "Object File"; Description = "Object File"; IconNamePrefix = "TargetPlugin"; DefaultTargetName = "Object File"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; MACH_O_TYPE = "mh_object"; LINK_WITH_STANDARD_LIBRARIES = NO; REZ_EXECUTABLE = YES; EXECUTABLE_SUFFIX = ".$(EXECUTABLE_EXTENSION)"; EXECUTABLE_EXTENSION = "o"; PUBLIC_HEADERS_FOLDER_PATH = "/usr/local/include"; PRIVATE_HEADERS_FOLDER_PATH = "/usr/local/include"; INSTALL_PATH = "$(HOME)/Objects"; FRAMEWORK_FLAG_PREFIX = "-framework"; LIBRARY_FLAG_PREFIX = "-l"; LIBRARY_FLAG_NOSPACE = YES; SKIP_INSTALL = YES; STRIP_STYLE = "debugging"; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; KEEP_PRIVATE_EXTERNS = YES; DEAD_CODE_STRIPPING = NO; }; PackageTypes = ( com.apple.package-type.mach-o-objfile // default ); }, // Dynamic library { Type = ProductType; Identifier = com.apple.product-type.library.dynamic; Class = PBXDynamicLibraryProductType; Name = "Dynamic Library"; Description = "Dynamic library"; IconNamePrefix = "TargetLibrary"; DefaultTargetName = "Dynamic Library"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; MACH_O_TYPE = "mh_dylib"; REZ_EXECUTABLE = YES; EXECUTABLE_SUFFIX = ".$(EXECUTABLE_EXTENSION)"; EXECUTABLE_EXTENSION = "dylib"; PUBLIC_HEADERS_FOLDER_PATH = "/usr/local/include"; PRIVATE_HEADERS_FOLDER_PATH = "/usr/local/include"; INSTALL_PATH = "/usr/local/lib"; DYLIB_INSTALL_NAME_BASE = "$(INSTALL_PATH)"; LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)"; DYLIB_COMPATIBILITY_VERSION = "1"; DYLIB_CURRENT_VERSION = "1"; FRAMEWORK_FLAG_PREFIX = "-framework"; LIBRARY_FLAG_PREFIX = "-l"; LIBRARY_FLAG_NOSPACE = YES; STRIP_STYLE = "debugging"; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; CODE_SIGNING_ALLOWED = YES; CODE_SIGNING_REQUIRED = NO; }; PackageTypes = ( com.apple.package-type.mach-o-dylib // default ); }, // Static library { Type = ProductType; Identifier = com.apple.product-type.library.static; Class = PBXStaticLibraryProductType; Name = "Static Library"; Description = "Static library"; IconNamePrefix = "TargetLibrary"; DefaultTargetName = "Static Library"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; MACH_O_TYPE = "staticlib"; REZ_EXECUTABLE = YES; EXECUTABLE_PREFIX = "lib"; EXECUTABLE_SUFFIX = ".$(EXECUTABLE_EXTENSION)"; EXECUTABLE_EXTENSION = "a"; PUBLIC_HEADERS_FOLDER_PATH = "/usr/local/include"; PRIVATE_HEADERS_FOLDER_PATH = "/usr/local/include"; INSTALL_PATH = "/usr/local/lib"; FRAMEWORK_FLAG_PREFIX = "-framework"; LIBRARY_FLAG_PREFIX = "-l"; LIBRARY_FLAG_NOSPACE = YES; STRIP_STYLE = "debugging"; CLANG_ENABLE_MODULE_DEBUGGING = NO; CODE_SIGNING_ALLOWED = NO; }; AlwaysPerformSeparateStrip = YES; PackageTypes = ( com.apple.package-type.static-library // default ); }, // Java library (jar or zip file) { Type = ProductType; Identifier = com.apple.product-type.library.java.archive; Name = "Java Library"; Description = "Java library packaged as a Jar file, Zip file, or class folder"; IconNamePrefix = "TargetPlugin"; DefaultTargetName = "Java Library"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(PRODUCT_NAME)"; INSTALL_PATH = "/usr/local/lib"; }; IsJava = YES; PackageTypes = ( com.apple.package-type.jarfile, // default com.apple.package-type.zipfile, com.apple.package-type.javaclassfolder ); }, // // Wrapper product types // // Bundle { Type = ProductType; Identifier = com.apple.product-type.bundle; Class = PBXBundleProductType; Name = "Bundle"; Description = "Generic bundle"; IconNamePrefix = "TargetPlugin"; DefaultTargetName = "Bundle"; DefaultBuildProperties = { FULL_PRODUCT_NAME = "$(WRAPPER_NAME)"; MACH_O_TYPE = "mh_bundle"; WRAPPER_PREFIX = ""; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "bundle"; WRAPPER_NAME = "$(WRAPPER_PREFIX)$(PRODUCT_NAME)$(WRAPPER_SUFFIX)"; FRAMEWORK_FLAG_PREFIX = "-framework"; LIBRARY_FLAG_PREFIX = "-l"; LIBRARY_FLAG_NOSPACE = YES; STRIP_STYLE = "non-global"; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; CODE_SIGNING_ALLOWED = YES; }; PackageTypes = ( com.apple.package-type.wrapper, // default com.apple.package-type.wrapper.shallow // Not clear if this is needed in the presence of the Shallow Bundle product type below. ); IsWrapper = YES; HasInfoPlist = YES; HasInfoPlistStrings = YES; WantsBundleIdentifierEditing = YES; WantsSigningEditing = YES; }, // Shallow Bundle Product { Type = ProductType; Identifier = com.apple.product-type.bundle.shallow; BasedOn = com.apple.product-type.bundle; Class = PBXBundleProductType; Name = "Bundle (Shallow)"; Description = "Bundle (Shallow)"; PackageTypes = ( com.apple.package-type.wrapper.shallow ); }, // Application { Type = ProductType; Identifier = com.apple.product-type.application; BasedOn = com.apple.product-type.bundle; Class = PBXApplicationProductType; Name = "Application"; Description = "Application"; IconNamePrefix = "TargetApp"; DefaultTargetName = "Application"; DefaultBuildProperties = { MACH_O_TYPE = "mh_execute"; GCC_DYNAMIC_NO_PIC = NO; GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "app"; INSTALL_PATH = "$(LOCAL_APPS_DIR)"; STRIP_STYLE = "all"; CODE_SIGNING_ALLOWED = YES; LD_RUNPATH_SEARCH_PATHS = "$(LD_RUNPATH_SEARCH_PATHS_$(IS_MACCATALYST))"; LD_RUNPATH_SEARCH_PATHS_YES = ( "@loader_path/../Frameworks", ); }; PackageTypes = ( com.apple.package-type.wrapper.application // default ); /** Product type validation hooks */ Validation = { // Checks - a dictionary of checks that are perform just prior to building the product // Each dictionary key is the "XCPropertyMacroExpression" to evaluate // The dictionary value contains the error message to display if the condition evaluates to false. Checks = { // This is intentially empty as currently all of the checks are done in-code for this particular application type. However, we enable the plubmbing for the validation tool spec infrastructure to be called to avoid any further hacks in pbxbuild or xcbuild. This is to enable rdar://problem/45590882. }; // Determines if the legacy build system has support for this validation hook. This is a workaround for enabling additional validation in xcbuild (specifically for rdar://problem/45590882), which does not have the same plugin restriction that is imposed on pbxbuild's implementation of the validation hooks. EnabledForLegacyBuildSystem = NO; // ValidationToolSpec - the identifier of the tool (script) to run after a target is constructed. ValidationToolSpec = "com.apple.build-tools.platform.validate"; }; CanEmbedCompilerSanitizerLibraries = YES; RunpathSearchPathForEmbeddedFrameworks = "@executable_path/../Frameworks"; ValidateEmbeddedBinaries = YES; ProvisioningProfileSupported = YES; ProvisioningProfileRequired = NO; WantsBundleIdentifierEditing = YES; WantsSigningEditing = YES; }, // Shallow Application Product { Type = ProductType; Identifier = com.apple.product-type.application.shallow; BasedOn = com.apple.product-type.application; Class = PBXApplicationProductType; // see radar 5604879, this shouldn't be necesary Name = "Application (Shallow Bundle)"; Description = "Application (Shallow Bundle)"; PackageTypes = ( com.apple.package-type.wrapper.application.shallow ); }, // Java Application { Type = ProductType; Identifier = com.apple.product-type.application.java; BasedOn = com.apple.product-type.application; Name = "Java Application"; Description = "Java Application"; DefaultTargetName = "Java Application"; DefaultBuildProperties = { INFOPLIST_PATH = ""; PKGINFO_PATH = ""; }; IsJava = YES; }, // Framework { Type = ProductType; Identifier = com.apple.product-type.framework; BasedOn = com.apple.product-type.bundle; Class = PBXFrameworkProductType; Name = "Framework"; Description = "Framework"; IconNamePrefix = "TargetFramework"; DefaultTargetName = "Framework"; DefaultBuildProperties = { MACH_O_TYPE = "mh_dylib"; FRAMEWORK_VERSION = "A"; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "framework"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; DYLIB_INSTALL_NAME_BASE = "$(INSTALL_PATH)"; LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)"; STRIP_STYLE = "debugging"; CODE_SIGNING_ALLOWED = YES; CODE_SIGNING_REQUIRED = NO; ENTITLEMENTS_REQUIRED = NO; CODE_SIGNING_REQUIRES_TEAM = YES; }; PackageTypes = ( com.apple.package-type.wrapper.framework // default ); }, // Shallow Framework Product { Type = ProductType; Identifier = com.apple.product-type.framework.shallow; BasedOn = com.apple.product-type.framework; Class = PBXFrameworkProductType; Name = "Framework (Shallow Bundle)"; Description = "Framework (Shallow Bundle)"; PackageTypes = ( com.apple.package-type.wrapper.framework.shallow ); }, // Static framework { Type = ProductType; Identifier = com.apple.product-type.framework.static; BasedOn = com.apple.product-type.framework; Class = XCStaticFrameworkProductType; Name = "Static Framework"; Description = "Static Framework"; IconNamePrefix = "TargetFramework"; DefaultTargetName = "Static Framework"; DefaultBuildProperties = { MACH_O_TYPE = "staticlib"; FRAMEWORK_VERSION = "A"; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "framework"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; DYLIB_INSTALL_NAME_BASE = ""; LD_DYLIB_INSTALL_NAME = ""; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; CODE_SIGNING_ALLOWED = NO; }; AlwaysPerformSeparateStrip = YES; PackageTypes = ( com.apple.package-type.wrapper.framework.static // default ); }, // System extension { Type = ProductType; Identifier = com.apple.product-type.system-extension; BasedOn = com.apple.product-type.bundle; Name = "DriverKit Driver"; Description = "DriverKit driver"; DefaultTargetName = "DriverKit Driver"; DefaultBuildProperties = { MACH_O_TYPE = "mh_execute"; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "systemextension"; PRODUCT_NAME = "$(PRODUCT_BUNDLE_IDENTIFIER)"; }; PackageTypes = ( com.apple.package-type.wrapper.system-extension, ); ProvisioningProfileSupported = YES; ProvisioningProfileRequired = NO; }, // DriverKit driver { Type = ProductType; Identifier = com.apple.product-type.driver-extension; BasedOn = com.apple.product-type.system-extension; Name = "DriverKit Driver"; Description = "DriverKit driver"; DefaultTargetName = "DriverKit Driver"; DefaultBuildProperties = { SDKROOT = "driverkit"; MACH_O_TYPE = "mh_execute"; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "dext"; INSTALL_PATH = "$(DEFAULT_DEXT_INSTALL_PATH)"; STRIP_STYLE = "debugging"; DEXT_FRAMEWORK_NAME = "DriverKit"; DEXT_FRAMEWORK = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(DEXT_FRAMEWORK_NAME).framework"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; PRODUCT_NAME = "$(PRODUCT_BUNDLE_IDENTIFIER)"; PRODUCT_TYPE_HEADER_SEARCH_PATHS = "$(inherited) $(IIG_HEADERS_DIR)"; }; DefaultEntitlements = { "com.apple.developer.driverkit" = YES; }; PackageTypes = ( com.apple.package-type.wrapper.driver-extension, ); }, // Kernel Extension { Type = ProductType; Identifier = com.apple.product-type.kernel-extension; BasedOn = com.apple.product-type.bundle; Class = XCKernelExtensionProductType; Name = "Kernel Extension"; Description = "Kernel extension"; DefaultTargetName = "Kernel Extension"; DefaultBuildProperties = { MACH_O_TYPE = "mh_execute"; WRAPPER_SUFFIX = ".$(WRAPPER_EXTENSION)"; WRAPPER_EXTENSION = "kext"; INSTALL_PATH = "$(DEFAULT_KEXT_INSTALL_PATH)"; STRIP_STYLE = "debugging"; KEXT_FRAMEWORK_NAME = "Kernel"; KEXT_FRAMEWORK = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(KEXT_FRAMEWORK_NAME).framework"; KEXT_FAMILY_NAME = "family"; PUBLIC_HEADERS_FOLDER_PATH = "$(KEXT_FRAMEWORK)/Contents/Headers/$(KEXT_FAMILY_NAME)"; PRIVATE_HEADERS_FOLDER_PATH = "$(KEXT_FRAMEWORK)/Contents/PrivateHeaders/$(KEXT_FAMILY_NAME)"; MODULE_NAME = "com.company.driver.modulename"; MODULE_VERSION = "1.0"; MODULE_START = "0"; MODULE_STOP = "0"; ENABLE_APPLE_KEXT_CODE_GENERATION = YES; // -fapple-kext GCC_ENABLE_KERNEL_DEVELOPMENT = YES; // -mkernel GCC_USE_STANDARD_INCLUDE_SEARCHING = NO; // -nostdinc GCC_ENABLE_PASCAL_STRINGS = NO; // Disables -fpascal-strings GCC_FORCE_CPU_SUBTYPE_ALL = YES; // -force_cpusubtype_ALL GCC_CHECK_RETURN_VALUE_OF_OPERATOR_NEW = YES; // -fcheck-new GCC_INLINES_ARE_PRIVATE_EXTERN = NO; // -fvisibility-inlines-hidden GCC_ENABLE_BUILTIN_FUNCTIONS = NO; // -fno-builtin GCC_NO_COMMON_BLOCKS = YES; // -fno-common GCC_ENABLE_CPP_EXCEPTIONS = NO; // -fno-exceptions GCC_ENABLE_CPP_RTTI = NO; // -fno-rtti // Supposedly these two flags are the default in GCC, but they're provided here for compatibility with older Xcode versions. GCC_ENABLE_FUNCTION_INLINING = YES; // -finline GCC_DISABLE_STATIC_FUNCTION_INLINING = YES; // -fno-keep-inline-functions // Per-product-type settings. // The KERNEL_*** settings are defined differently for some SDKs, so we continue to use them for compatibility reasons. KERNEL_FRAMEWORK = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework"; KERNEL_FRAMEWORK_HEADERS = "$(KERNEL_FRAMEWORK)/Headers"; KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(KERNEL_FRAMEWORK)/PrivateHeaders $(KERNEL_FRAMEWORK_HEADERS)"; // These settings are reserved for use by product types. GCC_PRODUCT_TYPE_PREPROCESSOR_DEFINITIONS = "$(inherited) KERNEL KERNEL_PRIVATE DRIVER_PRIVATE APPLE NeXT"; PRODUCT_TYPE_CFLAGS = "$(inherited) $(KEXT_CFLAGS)"; PRODUCT_TYPE_CPLUSPLUSFLAGS = "$(inherited) $(KEXT_CPLUSPLUSFLAGS)"; PRODUCT_SPECIFIC_LDFLAGS = "$(inherited) $(KEXT_LDFLAGS)"; PRODUCT_TYPE_HEADER_SEARCH_PATHS = "$(inherited) $(KERNEL_EXTENSION_HEADER_SEARCH_PATHS)"; CODE_SIGNING_ALLOWED = YES; ARCHS_STANDARD = "arm64e x86_64"; ARCHS_STANDARD_64_BIT = "$(ARCHS_STANDARD)"; ARCHS_STANDARD_INCLUDING_64_BIT = "$(ARCHS_STANDARD)"; }; PackageTypes = ( com.apple.package-type.wrapper.kernel-extension, // Default com.apple.package-type.wrapper.kernel-extension.shallow, ); }, // Shallow Kernel Extension { Type = ProductType; Identifier = com.apple.product-type.kernel-extension.shallow; BasedOn = com.apple.product-type.kernel-extension; Class = XCKernelExtensionProductType; Name = "Kernel Extension (Shallow)"; Description = "Kernel extension (shallow)"; DefaultBuildProperties = { // None yet }; PackageTypes = ( com.apple.package-type.wrapper.kernel-extension.shallow, ); }, // IOKit Kernel Extension { Type = ProductType; Identifier = com.apple.product-type.kernel-extension.iokit; BasedOn = com.apple.product-type.kernel-extension; Class = XCKernelExtensionProductType; Name = "IOKit Kernel Extension"; Description = "IOKit Kernel extension"; DefaultTargetName = "IOKit Kernel Extension"; DefaultBuildProperties = { CODE_SIGNING_ALLOWED = YES; }; PackageTypes = ( com.apple.package-type.wrapper.kernel-extension, // Default com.apple.package-type.wrapper.kernel-extension.shallow, ); }, // Shallow IOKit Kernel Extension { Type = ProductType; Identifier = com.apple.product-type.kernel-extension.iokit.shallow; BasedOn = com.apple.product-type.kernel-extension; Class = XCKernelExtensionProductType; Name = "IOKit Kernel Extension (Shallow)"; Description = "IOKit Kernel extension (Shallow)"; DefaultTargetName = "IOKit Kernel Extension (Shallow)"; DefaultBuildProperties = { // None yet }; PackageTypes = ( com.apple.package-type.wrapper.kernel-extension.shallow, ); }, // Unit Test Bundle { Type = ProductType; Identifier = com.apple.product-type.bundle.unit-test; BasedOn = com.apple.product-type.bundle; Class = PBXXCTestBundleProductType; Name = "Unit Test Bundle"; Description = "Unit Test Bundle"; DefaultBuildProperties = { WRAPPER_EXTENSION = "xctest"; ENABLE_TESTING_SEARCH_PATHS = YES; PRODUCT_SPECIFIC_LDFLAGS = "-framework XCTest"; XCTRUNNER_PATH = "$(XCTRUNNER_PATH$(TEST_BUILD_STYLE))"; LD_RUNPATH_SEARCH_PATHS = "$(LD_RUNPATH_SEARCH_PATHS_$(IS_MACCATALYST))"; LD_RUNPATH_SEARCH_PATHS_YES = ( "@loader_path/../Frameworks", "@executable_path/../Frameworks", ); }; PackageTypes = ( com.apple.package-type.bundle.unit-test ); CanEmbedCompilerSanitizerLibraries = YES; IsUnitTest = YES; WantsBundleIdentifierEditing = NO; }, // UI Testing Bundle { Type = ProductType; Identifier = com.apple.product-type.bundle.ui-testing; BasedOn = com.apple.product-type.bundle.unit-test; Class = PBXXCTestBundleProductType; Name = "UI Testing Bundle"; Description = "UI Testing Bundle"; DefaultBuildProperties = { USES_XCTRUNNER = "YES"; }; PackageTypes = ( com.apple.package-type.bundle.unit-test ); ProvisioningProfileSupported = YES; IsUITest = YES; InfoPlistAdditions = { XCTContainsUITests = YES; }; WantsBundleIdentifierEditing = NO; }, // Legacy OCUnit Test Bundle { Type = ProductType; Identifier = com.apple.product-type.bundle.ocunit-test; BasedOn = com.apple.product-type.bundle; Class = PBXBundleProductType; Name = "OCUnit Test Bundle"; Description = "OCUnit Test Bundle"; DefaultBuildProperties = { WRAPPER_EXTENSION = "octest"; }; PackageTypes = ( com.apple.package-type.bundle.ocunit-test ); IsUnitTest = YES; }, // In-App Purchase Content { Type = ProductType; Identifier = com.apple.product-type.in-app-purchase-content; Class = PBXBundleProductType; Name = "In-App Purchase Content"; Description = "In-App Purchase Content"; DefaultBuildProperties = { CODE_SIGNING_ALLOWED = NO; FULL_PRODUCT_NAME = "$(WRAPPER_NAME)"; }; PackageTypes = ( com.apple.package-type.in-app-purchase-content, // default ); IsWrapper = YES; HasInfoPlist = YES; HasInfoPlistStrings = NO; }, // XPC Service { Type = ProductType; Identifier = "com.apple.product-type.xpc-service"; BasedOn = "com.apple.product-type.bundle"; Class = PBXBundleProductType; Name = "XPC Service"; Description = "XPC Service"; IconNamePrefix = XPCService; DefaultTargetName = "XPC Service"; CanEmbedCompilerSanitizerLibraries = YES; "DefaultBuildProperties" = { "MACH_O_TYPE" = "mh_execute"; WRAPPER_EXTENSION = "xpc"; LD_RUNPATH_SEARCH_PATHS = "$(LD_RUNPATH_SEARCH_PATHS_$(IS_MACCATALYST)_$(_BOOL_$(SKIP_INSTALL)))"; LD_RUNPATH_SEARCH_PATHS_YES_YES = ( "@loader_path/../Frameworks", "@loader_path/../../../../Frameworks", ); LD_RUNPATH_SEARCH_PATHS_YES_NO = ( "@loader_path/../Frameworks", ); }; PackageTypes = ( "com.apple.package-type.xpc-service", ); ProvisioningProfileSupported = YES; ProvisioningProfileRequired = NO; WantsBundleIdentifierEditing = YES; WantsSigningEditing = YES; }, // PlugIn-Kit PlugIn { Type = ProductType; Identifier = "com.apple.product-type.pluginkit-plugin"; BasedOn = "com.apple.product-type.xpc-service"; Class = PBXBundleProductType; Name = "PlugInKit PlugIn"; Description = "PlugInKit PlugIn"; IconNamePrefix = XPCService; DefaultTargetName = "PlugInKit PlugIn"; "DefaultBuildProperties" = { "PRODUCT_SPECIFIC_LDFLAGS" = "$(SDKROOT)/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit"; WRAPPER_EXTENSION = "pluginkit"; }; PackageTypes = ( "com.apple.package-type.pluginkit-plugin", ); }, // App Extension { Type = ProductType; Identifier = "com.apple.product-type.app-extension"; BasedOn = "com.apple.product-type.pluginkit-plugin"; Class = PBXBundleProductType; Name = "App Extension"; Description = "App Extension"; IconNamePrefix = AppExtension; DefaultTargetName = "App Extension"; "DefaultBuildProperties" = { "CODE_SIGNING_ALLOWED" = YES; "APPLICATION_EXTENSION_API_ONLY" = YES; "PRODUCT_SPECIFIC_LDFLAGS" = "-e _NSExtensionMain"; WRAPPER_EXTENSION = "appex"; }; PackageTypes = ( "com.apple.package-type.app-extension", ); ProvisioningProfileSupported = YES; ProvisioningProfileRequired = NO; WantsBundleIdentifierEditing = YES; WantsSigningEditing = YES; }, // Xcode Extension { Type = ProductType; Identifier = "com.apple.product-type.xcode-extension"; BasedOn = "com.apple.product-type.app-extension"; Name = "Xcode Extension"; Description = "Xcode Extension"; IconNamePrefix = XcodeExtension; DefaultTargetName = "Xcode Extension"; "DefaultBuildProperties" = { "CODE_SIGNING_ALLOWED" = YES; "APPLICATION_EXTENSION_API_ONLY" = YES; "PRODUCT_SPECIFIC_LDFLAGS" = "-e _XCExtensionMain -lXcodeExtension"; "PRODUCT_TYPE_FRAMEWORK_SEARCH_PATHS" = ( "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", ); "PRODUCT_TYPE_LIBRARY_SEARCH_PATHS" = ( "$(inherited)", "$(DEVELOPER_USR_DIR)/lib", ); LD_RUNPATH_SEARCH_PATHS = ( "@loader_path/../Frameworks", ); WRAPPER_EXTENSION = "appex"; }; PackageTypes = ( "com.apple.package-type.app-extension", ); ProvisioningProfileSupported = YES; ProvisioningProfileRequired = NO; WantsBundleIdentifierEditing = YES; WantsSigningEditing = YES; }, // Spotlight Importer { Type = ProductType; Identifier = "com.apple.product-type.spotlight-importer"; BasedOn = "com.apple.product-type.bundle"; Class = PBXBundleProductType; Name = "Spotlight Importer"; Description = "Spotlight Importer"; DefaultTargetName = "Spotlight"; "DefaultBuildProperties" = { "CODE_SIGNING_ALLOWED" = YES; }; PackageTypes = ( "com.apple.package-type.spotlight-importer", ); }, // Copied from iOS specs to aid in build system diagnostic support. // Later, we should put these in some central place. { Type = ProductType; Identifier = "com.apple.product-type.app-extension.messages"; BasedOn = "com.apple.product-type.app-extension"; }, { Type = ProductType; Identifier = "com.apple.product-type.app-extension.messages-sticker-pack"; BasedOn = "com.apple.product-type.app-extension"; IsCapabilitiesUnsupported = YES; WantsSimpleTargetEditing = YES; DefaultBuildProperties = { MESSAGES_APPLICATION_EXTENSION_PRODUCT_BINARY_SOURCE_PATH = "$(PLATFORM_DIR)/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub"; ASSETCATALOG_COMPILER_INCLUDE_STICKER_CONTENT = YES; ASSETCATALOG_COMPILER_TARGET_STICKERS_ICON_ROLE = "extension"; ASSETCATALOG_COMPILER_STICKER_PACK_IDENTIFIER_PREFIX = "$(PRODUCT_BUNDLE_IDENTIFIER).sticker-pack."; }; AllowedBuildPhases = ( "com.apple.buildphase.resources", "com.apple.buildphase.shell-script", ); InfoPlistAdditions = { LSApplicationIsStickerProvider = YES; }; }, { Type = ProductType; Identifier = "com.apple.product-type.application.on-demand-install-capable"; BasedOn = "com.apple.product-type.application"; Name = "App Clip"; Description = "App Clip"; DefaultBuildProperties = { ENABLE_ON_DEMAND_RESOURCES = NO; ASSETCATALOG_COMPILER_STANDALONE_ICON_BEHAVIOR = none; // Don't include standalone icons to keep size down PRODUCT_SPECIFIC_LDFLAGS = "$(inherited) -framework AppClip"; SKIP_INSTALL = YES; }; DefaultEntitlements = { "com.apple.developer.on-demand-install-capable" = YES; }; SupportsOnDemandResources = NO; IsEmbeddable = YES; BuildPhaseInjectionsWhenEmbedding = ( { BuildPhase = "CopyFiles"; Name = "Embed App Clips"; RunOnlyForDeploymentPostprocessing = NO; DstSubFolderSpec = 16; DstPath = "$(CONTENTS_FOLDER_PATH)/AppClips"; } ); }, ) qbs-src-2.6.1/share/qbs/modules/nsis/0000755000175100001660000000000014776170045016763 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/nsis/NSISModule.qbs0000644000175100001660000002257014776170045021422 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Utilities Module { condition: qbs.targetOS.includes("windows") property path toolchainInstallPath: Utilities.getNativeSetting(registryKey) version: (versionMajor !== undefined && versionMinor !== undefined) ? (versionMajor + "." + versionMinor) : undefined property var versionParts: [ versionMajor, versionMinor, versionPatch, versionBuild ] property int versionMajor: Utilities.getNativeSetting(registryKey, "VersionMajor") property int versionMinor: Utilities.getNativeSetting(registryKey, "VersionMinor") property int versionPatch: Utilities.getNativeSetting(registryKey, "VersionBuild") property int versionBuild: Utilities.getNativeSetting(registryKey, "VersionRevision") property string compilerName: "makensis" property string compilerPath: compilerName property string warningLevel: "normal" PropertyOptions { name: "warningLevel" allowedValues: ["none", "normal", "errors", "warnings", "info", "all"] } property bool disableConfig: false PropertyOptions { name: "disableConfig" description: "disable inclusion of nsisconf.nsh" } property bool enableQbsDefines: true PropertyOptions { name: "enableQbsDefines" description: "built-in variables that are defined when using the NSIS compiler" } property stringList defines PropertyOptions { name: "defines" description: "variables that are defined when using the NSIS compiler" } property stringList compilerFlags PropertyOptions { name: "compilerFlags" description: "additional flags for the NSIS compiler" } property string compressor: "default" PropertyOptions { name: "compressor" description: "the compression algorithm used to compress files/data in the installer" allowedValues: ["default", "zlib", "zlib-solid", "bzip2", "bzip2-solid", "lzma", "lzma-solid"] } property string executableSuffix: ".exe" // Private properties property string registryKey: { if (!Host.os().includes("windows")) return undefined; var keys = [ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS" ]; for (var i in keys) { if (Utilities.getNativeSetting(keys[i])) return keys[i]; } } validate: { var validator = new ModUtils.PropertyValidator("nsis"); // Only *require* the toolchain install path on Windows // On other (Unix-like) operating systems it'll probably be in the PATH if (qbs.targetOS.includes("windows")) validator.setRequiredProperty("toolchainInstallPath", toolchainInstallPath); validator.setRequiredProperty("versionMajor", versionMajor); validator.setRequiredProperty("versionMinor", versionMinor); validator.setRequiredProperty("versionPatch", versionPatch); validator.setRequiredProperty("versionBuild", versionBuild); validator.addVersionValidator("version", version, 2, 4); validator.addRangeValidator("versionMajor", versionMajor, 1); validator.addRangeValidator("versionMinor", versionMinor, 0); validator.addRangeValidator("versionPatch", versionPatch, 0); validator.addRangeValidator("versionBuild", versionBuild, 0); validator.validate(); } setupBuildEnvironment: { if (product.nsis.toolchainInstallPath) { var v = new ModUtils.EnvironmentVariable("PATH", ";", true); v.prepend(product.nsis.toolchainInstallPath); v.prepend(FileInfo.joinPaths(product.nsis.toolchainInstallPath, "bin")); v.set(); } } // NSIS Script File FileTagger { patterns: ["*.nsi"] fileTags: ["nsi"] } // NSIS Header File FileTagger { patterns: ["*.nsh"] fileTags: ["nsh"] } Rule { id: nsisCompiler multiplex: true inputs: ["nsi"] auxiliaryInputs: ["installable"] auxiliaryInputsFromDependencies: ["installable"] Artifact { fileTags: ["nsissetup", "application"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ModUtils.moduleProperty( product, "executableSuffix")) } prepare: { var i; var args = []; // Prefix character for makensis options var opt = product.moduleProperty("qbs", "hostOS").includes("windows") ? "/" : "-"; if (ModUtils.moduleProperty(product, "disableConfig")) { args.push(opt + "NOCONFIG"); } var warningLevel = ModUtils.moduleProperty(product, "warningLevel"); var warningLevels = ["none", "errors", "warnings", "info", "all"]; if (warningLevel !== "normal") { var level = warningLevels.indexOf(warningLevel); if (level < 0) { throw("Unexpected warning level '" + warningLevel + "'."); } else { args.push(opt + "V" + level); } } var enableQbsDefines = ModUtils.moduleProperty(product, "enableQbsDefines") if (enableQbsDefines) { var map = { "project.": project, "product.": product }; for (var prefix in map) { var obj = map[prefix]; for (var prop in obj) { var val = obj[prop]; if (typeof val !== 'function' && typeof val !== 'object' && !prop.startsWith("_")) { args.push(opt + "D" + prefix + prop + "=" + val); } } } // Users are likely to need this var arch = product.moduleProperty("qbs", "architecture"); args.push(opt + "Dqbs.architecture=" + arch); // Helper define for alternating between 32-bit and 64-bit logic if (arch === "x86_64" || arch === "ia64") { args.push(opt + "DWin64"); } } // User-supplied defines var defines = ModUtils.moduleProperty(product, "defines"); for (i in defines) { args.push(opt + "D" + defines[i]); } // User-supplied flags var flags = ModUtils.moduleProperty(product, "compilerFlags"); for (i in flags) { args.push(flags[i]); } // Override the compression algorithm if needed var compressor = ModUtils.moduleProperty(product, "compressor"); if (compressor !== "default") { var compressorFlag = opt + "XSetCompressor /FINAL "; if (compressor.endsWith("-solid")) { compressorFlag += "/SOLID "; } args.push(compressorFlag + compressor.split('-')[0]); } var inputFileNames = []; for (i in inputs.nsi) { inputFileNames.push(inputs.nsi[i].fileName); args.push(FileInfo.toNativeSeparators(inputs.nsi[i].filePath, product.moduleProperty("qbs", "hostOS"))); } // Output file name - this goes last to override any OutFile command in the script args.push(opt + "XOutFile " + output.filePath); var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); cmd.description = "compiling " + inputFileNames.join(", "); cmd.highlight = "compiler"; cmd.workingDirectory = FileInfo.path(output.filePath); return cmd; } } } qbs-src-2.6.1/share/qbs/modules/freedesktop/0000755000175100001660000000000014776170045020322 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/freedesktop/freedesktop.js0000644000175100001660000000731014776170045023174 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Alberto Mardegan ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var TextFile = require("qbs.TextFile"); function parseDesktopFile(filePath) { var file = new TextFile(filePath); var fileValues = {}; var currentSection = {}; var sectionRex = /^\[(.+)\]$/g; while (!file.atEof()) { var line = file.readLine().trim(); if (line.length == 0) continue; if (line[0] == '#') continue; var match = sectionRex.exec(line); if (match) { var currentSectionName = match[1]; fileValues[currentSectionName] = {}; currentSection = fileValues[currentSectionName]; continue; } var parts = line.split('=', 2); currentSection[parts[0]] = parts[1] } file.close(); return fileValues } function dumpDesktopFile(filePath, keys) { var file = new TextFile(filePath, TextFile.WriteOnly); for (var sectionName in keys) { file.writeLine('[' + sectionName + ']'); var section = keys[sectionName]; for (var key in section) { var line = key + '=' + section[key]; file.writeLine(line); } // Write an empty line between sections (and before EOF) file.writeLine(''); } file.close(); } function generateDesktopFileCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName + " from " + input.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var aggregateDesktopKeys = parseDesktopFile(input.filePath); var desktopKeys = ModUtils.moduleProperty(product, "desktopKeys") || {} var mainSection = aggregateDesktopKeys['Desktop Entry']; for (key in desktopKeys) { if (desktopKeys.hasOwnProperty(key)) { mainSection[key] = desktopKeys[key]; } } var defaultValues = product.freedesktop.defaultDesktopKeys for (key in defaultValues) { if (!(key in mainSection)) { mainSection[key] = defaultValues[key]; } } dumpDesktopFile(output.filePath, aggregateDesktopKeys); } return [cmd]; } qbs-src-2.6.1/share/qbs/modules/freedesktop/FreeDesktop.qbs0000644000175100001660000000647414776170045023257 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Alberto Mardegan ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.ModUtils import qbs.TextFile import "freedesktop.js" as Fdo Module { property string name: product.name property string appName: name property string hicolorRoot: undefined property var desktopKeys readonly property var defaultDesktopKeys: { return { 'Type': 'Application', 'Name': product.freedesktop.appName, 'Exec': product.targetName, 'Terminal': 'false', 'Version': '1.1', } } property bool _fdoSupported: qbs.targetOS.includes("unix") && !qbs.targetOS.includes("darwin") additionalProductTypes: "freedesktop.desktopfile" FileTagger { patterns: [ "*.desktop" ] fileTags: [ "freedesktop.desktopfile_source" ] } Group { condition: _fdoSupported qbs.install: true Group { fileTagsFilter: [ "freedesktop.desktopfile" ] qbs.installDir: "share/applications" } Group { condition: product.freedesktop.hicolorRoot !== undefined fileTagsFilter: [ "freedesktop.appIcon" ] qbs.installDir: "share/icons/hicolor" qbs.installSourceBase: product.freedesktop.hicolorRoot } Group { fileTagsFilter: [ "freedesktop.appstream" ] qbs.installDir: "share/metainfo" } Rule { inputs: [ "freedesktop.desktopfile_source" ] outputFileTags: [ "freedesktop.desktopfile" ] Artifact { fileTags: [ "freedesktop.desktopfile" ] filePath: input.fileName } prepare: Fdo.generateDesktopFileCommands.apply(Fdo, arguments) } } FileTagger { patterns: [ "*.metainfo.xml", "*.appdata.xml" ] fileTags: [ "freedesktop.appstream" ] } } qbs-src-2.6.1/share/qbs/modules/java/0000755000175100001660000000000014776170045016730 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/java/io/0000755000175100001660000000000014776170045017337 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/java/io/qt/0000755000175100001660000000000014776170045017763 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/0000755000175100001660000000000014776170045020550 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/tools/0000755000175100001660000000000014776170045021710 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/tools/utils/0000755000175100001660000000000014776170045023050 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/tools/utils/NullFileObject.java0000644000175100001660000001040214776170045026551 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs.tools.utils; import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; import javax.tools.FileObject; import javax.tools.JavaFileObject; import java.io.*; import java.net.URI; /** * Represents a FileObject that discards its output when written. */ public class NullFileObject implements FileObject, JavaFileObject { FileObject obj; public NullFileObject(FileObject obj) { this.obj = obj; } @Override public URI toUri() { return obj.toUri(); } @Override public String getName() { return obj.getName(); } @Override public InputStream openInputStream() throws IOException { return obj.openInputStream(); } @Override public OutputStream openOutputStream() throws IOException { return new OutputStream() { @Override public void write(int b) throws IOException { } }; } @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { return obj.openReader(ignoreEncodingErrors); } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return obj.getCharContent(ignoreEncodingErrors); } @Override public Writer openWriter() throws IOException { return new Writer() { @Override public void write(char[] cbuf, int off, int len) throws IOException { } @Override public void flush() throws IOException { } @Override public void close() throws IOException { } }; } @Override public long getLastModified() { return obj.getLastModified(); } @Override public boolean delete() { return true; } @Override public Kind getKind() { if (obj instanceof JavaFileObject) { return ((JavaFileObject) obj).getKind(); } throw new UnsupportedOperationException(); } @Override public boolean isNameCompatible(String simpleName, Kind kind) { if (obj instanceof JavaFileObject) { return ((JavaFileObject) obj).isNameCompatible(simpleName, kind); } throw new UnsupportedOperationException(); } @Override public NestingKind getNestingKind() { if (obj instanceof JavaFileObject) { return ((JavaFileObject) obj).getNestingKind(); } throw new UnsupportedOperationException(); } @Override public Modifier getAccessLevel() { if (obj instanceof JavaFileObject) { return ((JavaFileObject) obj).getAccessLevel(); } throw new UnsupportedOperationException(); } } qbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerScanner.java0000644000175100001660000001102314776170045027576 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs.tools.utils; import io.qt.qbs.*; import javax.tools.*; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.*; public class JavaCompilerScanner { private List artifacts = new ArrayList(); private ArtifactListWriter writer = new ArtifactListJsonWriter(); public List getArtifacts() { return this.artifacts; } public int run(List compilerArguments) { artifacts.clear(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager standardFileManager = compiler .getStandardFileManager(null, null, null); final JavaFileManager fileManager = new ForwardingJavaFileManager( standardFileManager) { @Override public JavaFileObject getJavaFileForOutput( JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { JavaFileObject o = super.getJavaFileForOutput(location, className, kind, sibling); Artifact artifact = new Artifact(new File(o.toUri() .getSchemeSpecificPart()).toString()); if (kind.equals(JavaFileObject.Kind.CLASS)) { artifact.addFileTag("java.class"); } else if (kind.equals(JavaFileObject.Kind.SOURCE)) { artifact.addFileTag("java.java"); } artifacts.add(artifact); return new NullFileObject(o); } @Override public FileObject getFileForOutput( JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { FileObject o = super.getFileForOutput(location, packageName, relativeName, sibling); Artifact artifact = new Artifact(new File(o.toUri() .getSchemeSpecificPart()).toString()); if (o.getName().endsWith(".h")) { artifact.addFileTag("hpp"); } artifacts.add(artifact); return new NullFileObject(o); } }; final JavaCompilerOptions options = JavaCompilerOptions .parse(compiler, standardFileManager, compilerArguments .toArray(new String[compilerArguments.size()])); return compiler.getTask( null, fileManager, null, options.getRecognizedOptions(), options.getClassNames(), standardFileManager.getJavaFileObjectsFromFiles(options .getFiles())).call() ? 0 : 1; } public void write(OutputStream outputStream) throws IOException { writer.write(getArtifacts(), outputStream); } } qbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerOptions.java0000644000175100001660000000771014776170045027650 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs.tools.utils; import javax.lang.model.SourceVersion; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class JavaCompilerOptions { private final List recognizedOptions; private final List classNames; private final List files; private JavaCompilerOptions(List recognizedOptions, List classNames, List files) { this.recognizedOptions = recognizedOptions; this.classNames = classNames; this.files = files; } public static JavaCompilerOptions parse(JavaCompiler compiler, JavaFileManager fileManager, String... arguments) { List recognizedOptions = new ArrayList(); List classNames = new ArrayList(); List files = new ArrayList(); for (int i = 0; i < arguments.length; ++i) { int argumentCount = compiler.isSupportedOption(arguments[i]); if (argumentCount < 0) argumentCount = fileManager.isSupportedOption(arguments[i]); if (argumentCount >= 0) { // isSupportedOption() returns 1 for -Xlint* in Java 9. Bug? if (arguments[i].startsWith("-Xlint")) argumentCount = 0; for (int j = 0; j < argumentCount + 1; ++j) { if (i + j >= arguments.length) { throw new IllegalArgumentException(arguments[i]); } recognizedOptions.add(arguments[i + j]); } i += argumentCount; } else { File file = new File(arguments[i]); if (file.exists()) files.add(file); else if (SourceVersion.isName(arguments[i])) classNames.add(arguments[i]); else throw new IllegalArgumentException(arguments[i]); } } return new JavaCompilerOptions(recognizedOptions, classNames, files); } public List getRecognizedOptions() { return Collections.unmodifiableList(recognizedOptions); } public List getFiles() { return Collections.unmodifiableList(files); } public List getClassNames() { return Collections.unmodifiableList(classNames); } } qbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/tools/JavaCompilerScannerTool.java0000644000175100001660000000412014776170045027274 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs.tools; import io.qt.qbs.tools.utils.JavaCompilerScanner; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; public class JavaCompilerScannerTool { public static void main(String[] args) { try { JavaCompilerScanner scanner = new JavaCompilerScanner(); int result = scanner.run(new ArrayList(Arrays.asList(args))); scanner.write(System.out); System.exit(result); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } } qbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/ArtifactListJsonWriter.java0000644000175100001660000001302714776170045026036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.List; /** * This uses a custom JSON implementation because the Java Standard Library does * not yet have native support for JSON, and only minimal support is required * here. */ public class ArtifactListJsonWriter implements ArtifactListWriter { private static final int TAB_WIDTH = 4; // based on escapeString from qtbase/qjsonwriter.cpp private static String escapeString(String s) { String out = ""; for (int i = 0; i < s.length();) { int u = s.codePointAt(i); // unpaired surrogate if (u >= Character.MIN_SURROGATE && u <= Character.MAX_SURROGATE) { out += "\ufffd"; i += Character.charCount(u); continue; } if (u < 0x80) { if (u < 0x20 || u == 0x22 || u == 0x5c) { out += "\\"; switch (u) { case 0x22: out += "\""; break; case 0x5c: out += "\\"; break; case 0x8: out += "b"; break; case 0xc: out += "f"; break; case 0xa: out += "n"; break; case 0xd: out += "r"; break; case 0x9: out += "t"; break; default: out += "u"; out += "0"; out += "0"; String hex = Integer.toHexString(u); if (hex.length() == 1) out += "0"; out += hex; break; } } else { out += s.substring(i, i + Character.charCount(u)); } } else { out += s.substring(i, i + Character.charCount(u)); } i += Character.charCount(u); } return out; } private static void writeString(PrintStream printWriter, String s) { printWriter.print("\""); printWriter.print(escapeString(s)); printWriter.print("\""); } private static void writeIndent(PrintStream printWriter, int level) { for (int i = 0; i < level * TAB_WIDTH; ++i) { printWriter.print(" "); } } private static void writeArtifact(Artifact artifact, PrintStream printWriter, int indentLevel, Boolean comma) { writeIndent(printWriter, indentLevel++); printWriter.print("{\n"); writeIndent(printWriter, indentLevel); writeString(printWriter, "filePath"); printWriter.print(": "); writeString(printWriter, artifact.getFilePath()); printWriter.println(","); writeIndent(printWriter, indentLevel); writeString(printWriter, "fileTags"); printWriter.print(": ["); for (int i = 0; i < artifact.getFileTags().size(); ++i) { writeString(printWriter, artifact.getFileTags().get(i)); if (i != artifact.getFileTags().size() - 1) printWriter.print(", "); } printWriter.println("]"); writeIndent(printWriter, --indentLevel); printWriter.println("}" + (comma ? "," : "")); } @Override public void write(List artifacts, OutputStream outputStream) throws IOException { PrintStream printWriter = new PrintStream(outputStream); printWriter.print("[\n"); for (int i = 0; i < artifacts.size(); ++i) { writeArtifact(artifacts.get(i), printWriter, 1, i != artifacts.size() - 1); } printWriter.println("]"); } } qbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/ArtifactListWriter.java0000644000175100001660000000334414776170045025205 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs; import java.io.IOException; import java.io.OutputStream; import java.util.List; public interface ArtifactListWriter { void write(List artifacts, OutputStream outputStream) throws IOException; } qbs-src-2.6.1/share/qbs/modules/java/io/qt/qbs/Artifact.java0000644000175100001660000000501614776170045023152 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ package io.qt.qbs; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Artifact { private String filePath; private List fileTags; public Artifact(String filePath) { if (filePath == null) throw new IllegalArgumentException("filePath"); this.filePath = filePath; this.fileTags = new ArrayList(); } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public List getFileTags() { return Collections.unmodifiableList(fileTags); } public void setFileTags(List fileTags) { this.fileTags = new ArrayList(fileTags); } public void addFileTag(String fileTag) { this.fileTags.add(fileTag); } public void removeFileTag(String fileTag) { this.fileTags.remove(fileTag); } public void clearFileTags() { this.fileTags.clear(); } } qbs-src-2.6.1/share/qbs/modules/java/JavaModule.qbs0000644000175100001660000003364314776170045021477 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Probes import qbs.Process import qbs.TextFile import qbs.Utilities import "utils.js" as JavaUtils Module { Probes.JdkProbe { id: jdk environmentPaths: (jdkPath ? [jdkPath] : []).concat(base) } Probes.JdkVersionProbe { id: jdkVersionProbe javac: compilerFilePath } property stringList additionalClassPaths property stringList additionalCompilerFlags property stringList additionalJarFlags property stringList bootClassPaths property string compilerFilePath: FileInfo.joinPaths(jdkPath, "bin", compilerName) property string compilerName: "javac" property bool enableWarnings: true property string interpreterFilePath : FileInfo.joinPaths(jdkPath, "bin", interpreterName) property string interpreterName: "java" property string jarFilePath: FileInfo.joinPaths(jdkPath, "bin", jarName) property string jarName: "jar" property string jarsignerFilePath: FileInfo.joinPaths(jdkPath, "bin", jarsignerName) property string jarsignerName: "jarsigner" property string keytoolFilePath: FileInfo.joinPaths(jdkPath, "bin", keytoolName) property string keytoolName: "keytool" property bool _tagJniHeaders: true property string jdkPath: jdk.path version: [compilerVersionMajor, compilerVersionMinor, compilerVersionPatch].join(".") property string compilerVersion: jdkVersionProbe.version ? jdkVersionProbe.version[1] : undefined property var compilerVersionParts: JavaUtils.splitVersionString(compilerVersion) property int compilerVersionMajor: compilerVersionParts[0] property int compilerVersionMinor: compilerVersionParts[1] property int compilerVersionPatch: compilerVersionParts[2] property int compilerVersionUpdate: compilerVersionParts[3] property string languageVersion PropertyOptions { name: "languageVersion" description: "Java language version to interpret source code as" } property string runtimeVersion PropertyOptions { name: "runtimeVersion" description: "version of the Java runtime to generate compatible bytecode for" } property var manifest: { return { "Manifest-Version": "1.0", "Class-Path": manifestClassPath ? manifestClassPath.join(" ") : undefined }; } PropertyOptions { name: "manifest" description: "properties to add to the manifest file when building a JAR" } PropertyOptions { name: "manifestFile" description: "Use files tagged \"java.manifest\" instead." removalVersion: "1.9" } property stringList manifestClassPath PropertyOptions { name: "manifestClassPath" description: "entries to add to the manifest's Class-Path when building a JAR" } property bool warningsAsErrors: false property pathList jdkIncludePaths: { var paths = []; if (isAppleJava) { paths.push(FileInfo.joinPaths(qbs.sysroot, "/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers")); } else { paths.push(FileInfo.joinPaths(jdkPath, "include")); var hostOS = Host.os().includes("windows") ? Host.os().concat(["win32"]) : Host.os(); var platforms = ["win32", "darwin", "linux", "bsd", "solaris"]; for (var i = 0; i < platforms.length; ++i) { if (hostOS.includes(platforms[i])) { // Corresponds to JDK_INCLUDE_SUBDIR in the JDK Makefiles paths.push(FileInfo.joinPaths(jdkPath, "include", platforms[i])); break; } } } return paths; } // Internal properties property path classFilesDir: FileInfo.joinPaths(product.buildDirectory, "classes") property path internalClassFilesDir: FileInfo.joinPaths(product.buildDirectory, ".classes") property bool isAppleJava: Host.os().includes("darwin") && (compilerVersionMajor < 1 || (compilerVersionMajor === 1 && compilerVersionMinor < 7)) // https://developer.apple.com/library/content/documentation/Java/Conceptual/Java14Development/02-JavaDevTools/JavaDevTools.html // tools.jar does not exist. Classes usually located here are instead included in classes.jar. // The same is true for rt.jar, although not mentioned in the documentation property path classesJarPath: { if (isAppleJava) return FileInfo.joinPaths(jdkPath, "bundle", "Classes", "classes.jar"); } property path runtimeJarPath: { if (compilerVersionMajor >= 9) return undefined; if (classesJarPath) return classesJarPath; return FileInfo.joinPaths(jdkPath, "jre", "lib", "rt.jar"); } property path toolsJarPath: { if (compilerVersionMajor >= 9) return undefined; if (classesJarPath) return classesJarPath; return FileInfo.joinPaths(jdkPath, "lib", "tools.jar"); } validate: { var validator = new ModUtils.PropertyValidator("java"); validator.setRequiredProperty("jdkPath", jdkPath); validator.setRequiredProperty("compilerVersion", compilerVersion); validator.setRequiredProperty("compilerVersionParts", compilerVersionParts); validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor); validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor); if (Utilities.versionCompare(version, "9") < 0) validator.setRequiredProperty("compilerVersionUpdate", compilerVersionUpdate); validator.addVersionValidator("compilerVersion", compilerVersion ? compilerVersion.replace("_", ".") : undefined, 1, 4); validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1); validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0); validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0); if (Utilities.versionCompare(version, "9") < 0) validator.addRangeValidator("compilerVersionUpdate", compilerVersionUpdate, 0); validator.validate(); } FileTagger { patterns: "*.java" fileTags: ["java.java"] } FileTagger { patterns: ["*.mf"] fileTags: ["java.manifest"] } Group { name: "io.qt.qbs.internal.java-helper" files: { return JavaUtils.helperFullyQualifiedNames("java").map(function(name) { return FileInfo.joinPaths(path, name + ".java"); }); } fileTags: ["java.java-internal"] } Rule { multiplex: true inputs: ["java.java-internal"] outputFileTags: ["java.class-internal"] outputArtifacts: { return JavaUtils.helperOutputArtifacts(product); } prepare: { var cmd = new Command(ModUtils.moduleProperty(product, "compilerFilePath"), JavaUtils.javacArguments(product, inputs, JavaUtils.helperOverrideArgs(product, "javac"))); cmd.ignoreDryRun = true; cmd.silent = true; return [cmd]; } } Rule { multiplex: true inputs: ["java.java"] inputsFromDependencies: ["java.jar"] explicitlyDependsOn: ["java.class-internal"] outputFileTags: ["java.class"].concat(_tagJniHeaders ? ["hpp"] : ["java.jni-hpp"]) // Annotations can produce additional java source files. Ignored for now. outputArtifacts: { var artifacts = JavaUtils.outputArtifacts(product, inputs); if (!product.java._tagJniHeaders) { for (var i = 0; i < artifacts.length; ++i) { var a = artifacts[i]; if (a.fileTags instanceof Array) a.fileTags = a.fileTags.map(function(tag) { if (tag === "hpp") return "java.jni-hpp"; return tag; }); } } return artifacts; } prepare: { var cmd = new Command(ModUtils.moduleProperty(product, "compilerFilePath"), JavaUtils.javacArguments(product, inputs)); cmd.description = "compiling Java sources"; cmd.highlight = "compiler"; return [cmd]; } } Rule { inputs: ["java.class", "java.manifest"] multiplex: true Artifact { fileTags: ["java.jar"] filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".jar") } prepare: { var i, key; var flags = "cf"; var args = [output.filePath]; var aggregateManifest = {}; var manifestFiles = (inputs["java.manifest"] || []).map(function (a) { return a.filePath; }); manifestFiles.forEach(function (manifestFile) { var mf = JavaUtils.manifestContents(manifestFile); for (key in mf) { if (mf.hasOwnProperty(key)) { var oldValue = aggregateManifest[key]; var newValue = mf[key]; if (oldValue !== undefined && oldValue !== newValue) { throw new Error("Conflicting values '" + oldValue + "' and '" + newValue + "' for manifest file key '" + key + "'"); } aggregateManifest[key] = newValue; } } }); // Add local key-value pairs (overrides equivalent keys specified in the file if // one was given) var manifest = product.java.manifest; for (key in manifest) { if (manifest.hasOwnProperty(key)) aggregateManifest[key] = manifest[key]; } for (key in aggregateManifest) { if (aggregateManifest.hasOwnProperty(key) && aggregateManifest[key] === undefined) delete aggregateManifest[key]; } // Use default manifest unless we actually have properties to set var needsManifestFile = manifestFiles.length > 0 || aggregateManifest !== {"Manifest-Version": "1.0"}; var manifestFile = FileInfo.joinPaths(product.buildDirectory, "manifest.mf"); var mf; try { mf = new TextFile(manifestFile, TextFile.WriteOnly); // Ensure that manifest version comes first mf.write("Manifest-Version: " + (aggregateManifest["Manifest-Version"] || "1.0") + "\n"); delete aggregateManifest["Manifest-Version"]; for (key in aggregateManifest) mf.write(key + ": " + aggregateManifest[key] + "\n"); mf.write("\n"); } finally { if (mf) { mf.close(); } } if (needsManifestFile) { flags += "m"; args.push(manifestFile); } var entryPoint = ModUtils.moduleProperty(product, "entryPoint"); var entryPoint = product.entryPoint; if (entryPoint) { flags += "e"; args.push(entryPoint); } args.unshift(flags); var otherFlags = ModUtils.moduleProperty(product, "additionalJarFlags"); if (otherFlags) args = args.concat(otherFlags); for (i in inputs["java.class"]) args.push(FileInfo.relativePath(ModUtils.moduleProperty(product, "classFilesDir"), inputs["java.class"][i].filePath)); var cmd = new Command(ModUtils.moduleProperty(product, "jarFilePath"), args); cmd.workingDirectory = ModUtils.moduleProperty(product, "classFilesDir"); cmd.description = "building " + FileInfo.fileName(output.fileName); cmd.highlight = "linker"; return cmd; } } } qbs-src-2.6.1/share/qbs/modules/java/utils.js0000644000175100001660000003576714776170045020450 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); var WindowsUtils = require("qbs.WindowsUtils"); function is64bitProcess() { var y = jdkRootRegistryKey(true); var n = jdkRootRegistryKey(false); y = Utilities.getNativeSetting(y + "\\" + Utilities.getNativeSetting(y, "CurrentVersion"), "JavaHome"); n = Utilities.getNativeSetting(n + "\\" + Utilities.getNativeSetting(n, "CurrentVersion"), "JavaHome"); return y !== n; } function useWow64Key(arch) { var wow64 = false; switch (arch) { case "x86_64": case "ia64": // QTBUG-3845 if (!is64bitProcess()) return undefined; break; case "x86": case "armv7": wow64 = is64bitProcess(); break; } return wow64; } function jdkRootRegistryKey(wow64) { // If an architecture is specified, search the appropriate key for that architecture, // on this version of Windows (i.e. WOW64 or not) if compatible, // otherwise get both keys since any JDK will be usable if (wow64 === undefined) return undefined; return FileInfo.toWindowsSeparators(FileInfo.joinPaths("HKEY_LOCAL_MACHINE", "SOFTWARE", (wow64 ? "Wow6432Node" : undefined), "JavaSoft", "Java Development Kit")); } function findJdkPath(hostOS, arch, environmentPaths, searchPaths) { var i; for (i = 0; i < environmentPaths.length; ++i) { if (environmentPaths[i]) return environmentPaths[i]; } if (hostOS.includes("windows")) { var rootKey = jdkRootRegistryKey(useWow64Key(arch)); if (rootKey) { var current = Utilities.getNativeSetting(rootKey, "CurrentVersion"); // 1.8 etc. if (current) { var home = Utilities.getNativeSetting([rootKey, current].join("\\"), "JavaHome"); if (home) { return home; } } } return undefined; } if (hostOS.includes("macos")) { var p = new Process(); try { // We filter by architecture here so that we'll get a compatible JVM for JNI use. var args = []; var canonicalArch; if (arch) { // Hardcoding apple/macosx/macho here is fine because we know we're on macOS canonicalArch = Utilities.canonicalTargetArchitecture(arch, undefined, "apple", "macosx", "macho"); args.push("--arch", canonicalArch); } // --failfast doesn't print the default JVM if nothing matches the filter(s). var status = p.exec("/usr/libexec/java_home", args.concat(["--failfast"])); if (status === 0) return p.readStdOut().trim(); // It has been obvserved that java_home fails for any architecture that is passed, // so try without the filter and look up the JDK architecture manually. if (!canonicalArch) return undefined; if (p.exec("/usr/libexec/java_home", ["--failfast"]) !== 0) return undefined; var jdkPath = p.readStdOut().trim(); var releaseFile = new TextFile(jdkPath + "/release", TextFile.ReadOnly); var line; while ((line = releaseFile.readLine())) { if (!line.startsWith("OS_ARCH=")) continue; var firstQuote = line.indexOf('"'); if (firstQuote === -1) break; var secondQuote = line.indexOf('"', firstQuote + 1); if (secondQuote === -1) break; var archFromFile = line.substring(firstQuote + 1, secondQuote); if (archFromFile !== canonicalArch) break; return jdkPath; } return undefined; } finally { p.close(); } } if (hostOS.includes("unix")) { var requiredTools = ["javac", "java", "jar"]; for (i = 0; i < searchPaths.length; ++i) { function fullToolPath(tool) { return FileInfo.joinPaths(searchPaths[i], "bin", tool); } if (requiredTools.map(function(p) { return fullToolPath(p); }) .every(function(p) { return File.exists(p); })) { return searchPaths[i]; } } return undefined; } } function findJdkVersion(compilerFilePath) { var p = new Process(); try { p.exec(compilerFilePath, ["-version"]); var re = /^javac (([0-9]+(?:\.[0-9]+){0,2})(_([0-9]+))?)(.*)?$/m; var match = p.readStdErr().trim().match(re); if (!match) match = p.readStdOut().trim().match(re); if (match !== null) return match; } finally { p.close(); } } function splitVersionString(compilerVersion) { if (!compilerVersion) return []; var result = compilerVersion.split(/[\._]/).map(function(item) { return parseInt(item, 10); }); // special case, if javac -version returned "12" instead of "12.0.0" if (result.length === 1) result.push(0, 0); return result; } function supportsGeneratedNativeHeaderFiles(product) { var compilerVersionMajor = ModUtils.moduleProperty(product, "compilerVersionMajor"); if (compilerVersionMajor === 1) { if (ModUtils.moduleProperty(product, "compilerVersionMinor") >= 8) { return true; } } return compilerVersionMajor > 1; } function javacArguments(product, inputs, overrides) { function getModuleProperty(product, propertyName, overrides) { if (overrides && overrides[propertyName]) return overrides[propertyName]; return ModUtils.moduleProperty(product, propertyName); } function getModuleProperties(product, propertyName, overrides) { if (overrides && overrides[propertyName]) return overrides[propertyName]; return ModUtils.moduleProperty(product, propertyName); } var i; var outputDir = getModuleProperty(product, "classFilesDir", overrides); var classPaths = [outputDir]; var additionalClassPaths = getModuleProperties(product, "additionalClassPaths", overrides); if (additionalClassPaths) classPaths = classPaths.concat(additionalClassPaths); for (i in inputs["java.jar"]) classPaths.push(inputs["java.jar"][i].filePath); var debugArg = product.moduleProperty("qbs", "buildVariant") === "debug" ? "-g" : "-g:none"; var pathListSeparator = FileInfo.pathListSeparator(); var args = [ "-classpath", classPaths.join(pathListSeparator), "-s", product.buildDirectory, debugArg, "-d", outputDir ]; if (supportsGeneratedNativeHeaderFiles(product)) args.push("-h", product.buildDirectory); var runtimeVersion = getModuleProperty(product, "runtimeVersion", overrides); if (runtimeVersion) args.push("-target", runtimeVersion); var languageVersion = getModuleProperty(product, "languageVersion", overrides); if (languageVersion) args.push("-source", languageVersion); var bootClassPaths = getModuleProperties(product, "bootClassPaths", overrides); if (bootClassPaths && bootClassPaths.length > 0 && (!runtimeVersion || Utilities.versionCompare(runtimeVersion, "9") < 0)) { args.push("-bootclasspath", bootClassPaths.join(pathListSeparator)); } if (!getModuleProperty(product, "enableWarnings", overrides)) args.push("-nowarn"); if (getModuleProperty(product, "warningsAsErrors", overrides)) args.push("-Werror"); var otherFlags = getModuleProperties(product, "additionalCompilerFlags", overrides); if (otherFlags) args = args.concat(otherFlags); for (i in inputs["java.java"]) args.push(inputs["java.java"][i].filePath); for (i in inputs["java.java-internal"]) args.push(inputs["java.java-internal"][i].filePath); return args; } /** * Returns a list of fully qualified Java class names for the compiler helper tool. * * @param type @c java to return names of sources, @c to return names of compiled classes */ function helperFullyQualifiedNames(type) { var names = [ "io/qt/qbs/Artifact", "io/qt/qbs/ArtifactListJsonWriter", "io/qt/qbs/ArtifactListWriter", "io/qt/qbs/tools/JavaCompilerScannerTool", "io/qt/qbs/tools/utils/JavaCompilerOptions", "io/qt/qbs/tools/utils/JavaCompilerScanner", "io/qt/qbs/tools/utils/JavaCompilerScanner$1", "io/qt/qbs/tools/utils/NullFileObject", "io/qt/qbs/tools/utils/NullFileObject$1", "io/qt/qbs/tools/utils/NullFileObject$2", ]; if (type === "java") { return names.filter(function (name) { return !name.includes("$"); }); } else if (type === "class") { return names; } } function helperOutputArtifacts(product) { File.makePath(ModUtils.moduleProperty(product, "internalClassFilesDir")); return helperFullyQualifiedNames("class").map(function (name) { return { filePath: FileInfo.joinPaths(ModUtils.moduleProperty(product, "internalClassFilesDir"), name + ".class"), fileTags: ["java.class-internal"] }; }); } function helperOverrideArgs(product, tool) { var overrides = {}; if (tool === "javac") { // Build the helper tool with the same source and target version as the JDK it's being // compiled with. Both are irrelevant here since the resulting tool will only be run // with the same JDK as it was built with, and we know in advance the source is // compatible with all Java language versions from 1.6 and above. var jdkVersionArray = [product.java.compilerVersionMajor]; if (product.java.compilerVersionMajor < 9) jdkVersionArray.push(product.java.compilerVersionMinor); var jdkVersion = jdkVersionArray.join("."); overrides["languageVersion"] = jdkVersion; overrides["runtimeVersion"] = jdkVersion; // Build the helper tool's class files separately from the actual product's class files overrides["classFilesDir"] = ModUtils.moduleProperty(product, "internalClassFilesDir"); // Add tools.jar to the classpath as required for the tree scanner API var toolsJarPath = ModUtils.moduleProperty(product, "toolsJarPath"); if (toolsJarPath) overrides["additionalClassPaths"] = [toolsJarPath].concat( ModUtils.moduleProperty(product, "additionalClassPaths")); } // Inject the current JDK's runtime classes into the boot class path when building/running the // dependency scanner. This is normally not necessary but is important for Android platforms // where android.jar is the only JAR on the boot classpath and JSR 199 is unavailable. var rtJarPath = product.java.runtimeJarPath; overrides["bootClassPaths"] = (rtJarPath ? [rtJarPath] : []).concat( ModUtils.moduleProperty(product, "bootClassPaths")); return overrides; } function outputArtifacts(product, inputs) { // Handle the case where a product depends on Java but has no Java sources if (!inputs["java.java"] || inputs["java.java"].length === 0) return []; // We need to ensure that the output directory is created first, because the Java compiler // internally checks that it is present before performing any actions File.makePath(ModUtils.moduleProperty(product, "classFilesDir")); var process; try { process = new Process(); process.setWorkingDirectory( FileInfo.joinPaths(ModUtils.moduleProperty(product, "internalClassFilesDir"))); var sep = FileInfo.pathListSeparator(); var toolsJarPath = ModUtils.moduleProperty(product, "toolsJarPath"); var javaArgs = [ "-classpath", process.workingDirectory() + (toolsJarPath ? (sep + toolsJarPath) : ""), "io/qt/qbs/tools/JavaCompilerScannerTool", ]; process.exec(ModUtils.moduleProperty(product, "interpreterFilePath"), javaArgs .concat(javacArguments(product, inputs, helperOverrideArgs(product))), true); var out = JSON.parse(process.readStdOut()); console.error(process.readStdErr()); return out; } finally { if (process) process.close(); } } function manifestContents(filePath) { if (filePath === undefined) return undefined; var contents, file; try { file = new TextFile(filePath); contents = file.readAll(); } finally { if (file) { file.close(); } } if (contents) { var dict = {}; var lines = contents.split(/\r?\n/g).filter(function (line) { return line.length > 0; }); for (var i = 0; i < lines.length; ++i) { var kv = lines[i].split(":"); if (kv.length !== 2) throw new Error("Syntax error in manifest file '" + filePath + "'; found \"" + lines[i] + "\" on line " + parseInt(i, 10) + "; expected format \"Key: Value\""); dict[kv[0].trim()] = kv[1].trim(); } return dict; } } qbs-src-2.6.1/share/qbs/modules/capnproto/0000755000175100001660000000000014776170045020014 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/capnproto/capnprotobase.qbs0000644000175100001660000000464514776170045023374 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.Probes import "capnproto.js" as HelperFunctions Module { property string compilerName: "capnpc" property string compilerPath: compilerProbe.filePath property string pluginName property string pluginPath: pluginProbe.filePath property pathList importPaths: [] property string outputDir: product.buildDirectory + "/capnp" property var _searchPaths Probes.BinaryProbe { id: compilerProbe names: compilerName ? [compilerName] : [] searchPaths: _searchPaths } Probes.BinaryProbe { id: pluginProbe names: pluginName ? [pluginName] : [] searchPaths: _searchPaths } FileTagger { patterns: ["*.capnp"] fileTags: ["capnproto.input"]; } validate: { HelperFunctions.validateCompiler(compilerName, compilerPath); HelperFunctions.validatePlugin(pluginName, pluginPath); } } qbs-src-2.6.1/share/qbs/modules/capnproto/cpp/0000755000175100001660000000000014776170045020576 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/capnproto/cpp/capnprotocpp.qbs0000644000175100001660000000502614776170045024020 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import "../capnprotobase.qbs" as CapnProtoBase import "../capnproto.js" as HelperFunctions CapnProtoBase { property bool useRpc: false Depends { name: "cpp" } Depends { name: "capnp" } Depends { name: "capnp-rpc"; condition: useRpc } pluginName: "capnpc-c++" version: capnp.version _searchPaths: capnp.hostBinDirs cpp.systemIncludePaths: outputDir cpp.cxxLanguageVersion: "c++14" Rule { inputs: ["capnproto.input"] outputFileTags: ["hpp", "cpp"] outputArtifacts: { var outputDir = HelperFunctions.getOutputDir(input.capnproto.cpp, input); var result = [ HelperFunctions.artifact(outputDir, input, "hpp", ".capnp.h"), HelperFunctions.artifact(outputDir, input, "cpp", ".capnp.c++") ]; return result; } prepare: { var result = HelperFunctions.doPrepare( input.capnproto.cpp, product, input, outputs, "cpp"); return result; } } } qbs-src-2.6.1/share/qbs/modules/capnproto/capnproto.js0000644000175100001660000000725214776170045022365 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Utilities = require("qbs.Utilities"); function validateCompiler(name, path) { if (!File.exists(path)) throw "Cannot find executable '" + name + "'. Please set the compilerPath " + "property or make sure the compiler is found in PATH"; } function validatePlugin(name, path) { if (!name) throw "pluginName is not set"; if (!File.exists(path)) throw "Cannot find plugin '" + name + "'. Please set the pluginPath " + "property or make sure the plugin is found in PATH"; } function getOutputDir(module, input) { var outputDir = module.outputDir; var importPaths = module.importPaths; if (importPaths.length !== 0) { var canonicalInput = File.canonicalFilePath(FileInfo.path(input.filePath)); for (var i = 0; i < importPaths.length; ++i) { var path = File.canonicalFilePath(importPaths[i]); if (canonicalInput.startsWith(path)) { return outputDir + "/" + FileInfo.relativePath(path, canonicalInput); } } } return outputDir; } function artifact(outputDir, input, tag, suffix) { return { fileTags: [tag], filePath: FileInfo.joinPaths(outputDir, FileInfo.baseName(input.fileName) + suffix), cpp: { includePaths: [].concat(input.cpp.includePaths, outputDir), warningLevel: "none", } }; } function doPrepare(module, product, input, outputs, lang) { var outputDir = FileInfo.path(outputs["cpp"][0].filePath); var args = []; args.push("--output=" + module.pluginPath + ":" + outputDir); args.push("--src-prefix=" + FileInfo.path(input.filePath)); var importPaths = module.importPaths; importPaths.forEach(function(path) { if (!FileInfo.isAbsolutePath(path)) path = FileInfo.joinPaths(product.sourceDirectory, path); args.push("--import-path", path); }); args.push(input.filePath); var cmd = new Command(module.compilerPath, args); cmd.highlight = "codegen"; cmd.description = "generating " + lang + " files for " + input.fileName; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/ico/0000755000175100001660000000000014776170045016561 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/ico/ico.js0000644000175100001660000000773714776170045017707 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); function prepareIconset(project, product, inputs, outputs, input, output) { inputs = File.directoryEntries(input.filePath, File.Files).map(function (p) { return { filePath: FileInfo.joinPaths(input.filePath, p), fileTags: p.endsWith(".png") ? ["png"] : [], ico: {} }; }); inputs = {"png": inputs.filter(function (a) { return a.fileTags.includes("png"); })}; input = undefined; return prepare(project, product, inputs, outputs, input, output); } function prepare(project, product, inputs, outputs, input, output) { var args = ["--create", "--output=" + output.filePath]; if (output.fileTags.includes("ico")) { args.push("--icon"); if (product.ico.alphaThreshold !== undefined) args.push("--alpha-threshold=" + product.ico.alphaThreshold); } var isCursor = output.fileTags.includes("cur"); if (isCursor) args.push("--cursor"); var hasMultipleImages = inputs["png"].length > 1; inputs["png"].map(function(inp) { if (isCursor) { var hasX = inp.ico.cursorHotspotX !== undefined; var hasY = inp.ico.cursorHotspotY !== undefined; if (hasX || hasY) { if (hasMultipleImages && product.ico.hasCursorHotspotBug) { console.warn("icotool " + product.ico.version + " does not support setting " + "the hotspot for cursor files with multiple images. Install " + "icoutils 0.32.0 or newer to use this feature."); } else { if (hasX) args.push("--hotspot-x=" + inp.ico.cursorHotspotX); if (hasY) args.push("--hotspot-y=" + inp.ico.cursorHotspotY); } } } if (inp.ico.raw) args.push("-r"); args.push(inp.filePath); }); var cmd = new Command(product.ico.icotoolFilePath, args); cmd.description = "creating " + output.fileName; return [cmd]; } function findIcoUtilsVersion(toolFilePath) { var p = new Process(); try { p.exec(toolFilePath, ["--version"]); var re = /^[a-z]+ \(icoutils\) ([0-9]+(?:\.[0-9]+){1,2})$/m; var match = p.readStdOut().trim().match(re); if (match !== null) return match[1]; } finally { p.close(); } } qbs-src-2.6.1/share/qbs/modules/ico/IcoModule.qbs0000644000175100001660000000462614776170045021160 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Probes import qbs.Process import qbs.Utilities import "ico.js" as IcoUtils Module { Probes.BinaryProbe { id: icotoolProbe names: ["icotool"] } Probes.IcoUtilsVersionProbe { id: icotoolVersionProbe toolFilePath: icotoolFilePath } version: icotoolVersionProbe.version property int alphaThreshold property int cursorHotspotX property int cursorHotspotY property bool raw // private properties property string icotoolFilePath: icotoolProbe.filePath readonly property bool hasCursorHotspotBug: Utilities.versionCompare(version, "0.32") < 0 FileTagger { patterns: ["*.png"] fileTags: ["png"] } FileTagger { patterns: ["*.iconset"] // bundle fileTags: ["iconset"] } Rule { inputs: ["iconset"] Artifact { filePath: input.baseName + ".ico" fileTags: ["ico"] } prepare: IcoUtils.prepareIconset.apply(IcoUtils, arguments) } Rule { multiplex: true inputs: ["png"] Artifact { filePath: product.targetName + ".ico" fileTags: ["ico"] } prepare: IcoUtils.prepare.apply(IcoUtils, arguments) } Rule { inputs: ["iconset"] Artifact { filePath: input.baseName + ".cur" fileTags: ["cur"] } prepare: IcoUtils.prepareIconset.apply(IcoUtils, arguments) } Rule { multiplex: true inputs: ["png"] Artifact { filePath: product.targetName + ".cur" fileTags: ["cur"] } prepare: IcoUtils.prepare.apply(IcoUtils, arguments) } validate: { if (!icotoolFilePath) throw ModUtils.ModuleError("Could not find icotool in any of the following " + "locations:\n\t" + icotoolProbe.candidatePaths.join("\n\t") + "\nInstall the icoutils package on your platform."); if (!version) throw ModUtils.ModuleError("Could not determine icoutils package version."); var validator = new ModUtils.PropertyValidator("ico"); validator.setRequiredProperty("version", version); validator.addVersionValidator("version", version, 2, 3); return validator.validate() } } qbs-src-2.6.1/share/qbs/modules/Android/0000755000175100001660000000000014776170045017367 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Android/sdk/0000755000175100001660000000000014776170045020150 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Android/sdk/sdk.qbs0000644000175100001660000004061014776170045021441 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Probes import qbs.TextFile import qbs.Utilities import qbs.Xml import "utils.js" as SdkUtils Module { Probes.AndroidSdkProbe { id: sdkProbe environmentPaths: (sdkDir ? [sdkDir] : []).concat(base) } Probes.AndroidNdkProbe { id: ndkProbe sdkPath: sdkProbe.path environmentPaths: (ndkDir ? [ndkDir] : []).concat(base) } Probes.PathProbe { id: bundletoolProbe platformSearchPaths: [sdkDir] names: ["bundletool-all"] nameSuffixes: ["-0.11.0.jar", "-0.12.0.jar", "-0.13.0.jar", "-0.13.3.jar", "-0.13.4.jar", "-0.14.0.jar", "-0.15.0.jar", "-1.0.0.jar", "-1.1.0.jar", "-1.2.0.jar", "-1.3.0.jar", "-1.4.0.jar", "-1.5.0.jar", "-1.6.0.jar", "-1.6.1.jar", "-1.7.0.jar", "-1.7.1.jar", "-1.8.0.jar"] } property path sdkDir: sdkProbe.path property path ndkDir: ndkProbe.path property path ndkSamplesDir: ndkProbe.samplesDir property string buildToolsVersion: sdkProbe.buildToolsVersion property var buildToolsVersionParts: buildToolsVersion ? buildToolsVersion.split('.').map(function(item) { return parseInt(item, 10); }) : [] property int buildToolsVersionMajor: buildToolsVersionParts[0] property int buildToolsVersionMinor: buildToolsVersionParts[1] property int buildToolsVersionPatch: buildToolsVersionParts[2] property string platform: sdkProbe.platform property string minimumVersion: "21" property string targetVersion: platformVersion.toString() property path bundletoolFilePath: bundletoolProbe.filePath // Product-specific properties and files property string packageName: { var idx = product.name.indexOf(".") if (idx > 0 && idx < product.name.length) return product.name; return "com.example." + product.name; } property int versionCode property string versionName property string apkBaseName: packageName property bool automaticSources: true property bool legacyLayout: false property path sourceSetDir: legacyLayout ? product.sourceDirectory : FileInfo.joinPaths(product.sourceDirectory, "src/main") property path resourcesDir: FileInfo.joinPaths(sourceSetDir, "res") property path assetsDir: FileInfo.joinPaths(sourceSetDir, "assets") property path sourcesDir: FileInfo.joinPaths(sourceSetDir, legacyLayout ? "src" : "java") property string manifestFile: defaultManifestFile readonly property string defaultManifestFile: FileInfo.joinPaths(sourceSetDir, "AndroidManifest.xml") property bool customManifestProcessing: false property bool _enableRules: !product.multiplexConfigurationId && !!packageName property bool _bundledInAssets: true // Internal properties. property int platformVersion: { if (platform) { var match = platform.match(/^android-([0-9]+)$/); if (match !== null) { return parseInt(match[1], 10); } } } property string platformJavaVersion: { if (platformVersion >= 21) return "1.7"; return "1.5"; } property path buildToolsDir: FileInfo.joinPaths(sdkDir, "build-tools", buildToolsVersion) property string aaptName: "aapt2" PropertyOptions { name: "aaptName" allowedValues: ["aapt", "aapt2"] } property path aaptFilePath: FileInfo.joinPaths(buildToolsDir, aaptName) readonly property bool _enableAapt2: aaptName === "aapt2" property string packageType: "apk" PropertyOptions { name: "packageType" allowedValues: ["apk", "aab"] } readonly property bool _generateAab: packageType == "aab" property stringList extraResourcePackages PropertyOptions { name: "extraResourcePackages" description: "extra resource packages to compile resources for" } property path apksignerFilePath: FileInfo.joinPaths(buildToolsDir, "apksigner") property path aidlFilePath: FileInfo.joinPaths(buildToolsDir, "aidl") property path dxFilePath: FileInfo.joinPaths(buildToolsDir, "dx") property path d8FilePath: FileInfo.joinPaths(buildToolsDir, "d8") property string dexCompilerName: "d8" PropertyOptions { name: "dexCompilerName" allowedValues: ["dx", "d8"] } readonly property bool _useD8: dexCompilerName === "d8" property bool d8Desugaring: false PropertyOptions { name: "d8Desugaring" description: "enable desugaring in d8 dex compiler" } property path zipalignFilePath: FileInfo.joinPaths(buildToolsDir, "zipalign") property path androidJarFilePath: FileInfo.joinPaths(sdkDir, "platforms", platform, "android.jar") property path frameworkAidlFilePath: FileInfo.joinPaths(sdkDir, "platforms", platform, "framework.aidl") property path generatedJavaFilesBaseDir: FileInfo.joinPaths(product.buildDirectory, "gen") property path generatedJavaFilesDir: FileInfo.joinPaths(generatedJavaFilesBaseDir, (packageName || "").split('.').join('/')) property path compiledResourcesDir: FileInfo.joinPaths(product.buildDirectory, "compiled_resources") property string packageContentsDir: FileInfo.joinPaths(product.buildDirectory, packageType) property stringList aidlSearchPaths Group { condition: automaticSources Group { name: "java sources" prefix: FileInfo.resolvePath(product.sourceDirectory, module.sourcesDir + '/') files: "**/*.java" } Group { name: "android resources" fileTags: ["android.resources"] prefix: FileInfo.resolvePath(product.sourceDirectory, module.resourcesDir + '/') files: "**/*" } Group { name: "android assets" fileTags: ["android.assets"] prefix: FileInfo.resolvePath(product.sourceDirectory, module.assetsDir + '/') files: "**/*" } Group { name: "manifest" fileTags: ["android.manifest"] files: module.manifestFile && module.manifestFile !== module.defaultManifestFile ? [module.manifestFile] : (File.exists(module.defaultManifestFile) ? [module.defaultManifestFile] : []) } } Group { condition: !customManifestProcessing fileTagsFilter: "android.manifest_processed" fileTags: "android.manifest_final" } Group { condition: _enableRules Depends { name: "java" } Depends { name: "codesign" } product.java.languageVersion: platformJavaVersion product.java.runtimeVersion: platformJavaVersion product.java.bootClassPaths: androidJarFilePath product.codesign.apksignerFilePath: apksignerFilePath product.codesign._packageName: apkBaseName + (_generateAab ? ".aab" : ".apk") product.codesign.useApksigner: !_generateAab Rule { inputs: ["android.aidl"] Artifact { filePath: FileInfo.joinPaths(Utilities.getHash(input.filePath), input.completeBaseName + ".java") fileTags: ["java.java"] } prepare: SdkUtils.processAidlCommands.apply(SdkUtils, arguments) } Rule { inputs: "android.manifest" Artifact { filePath: FileInfo.joinPaths("processed_manifest", input.fileName) fileTags: "android.manifest_processed" } prepare: SdkUtils.generateProcessedManifestCommands.apply(SdkUtils, arguments) } Rule { multiplex: true Artifact { filePath: FileInfo.joinPaths(product.Android.sdk.generatedJavaFilesDir, "BuildConfig.java") fileTags: ["java.java"] } prepare: SdkUtils.generateBuildConfigJavaCommands(product, output) } Rule { multiplex: true inputs: ["java.class"] inputsFromDependencies: ["java.jar", "bundled_jar"] Artifact { filePath: product.Android.sdk._generateAab ? FileInfo.joinPaths(product.Android.sdk.packageContentsDir, "dex", "classes.dex") : FileInfo.joinPaths(product.Android.sdk.packageContentsDir, "classes.dex") fileTags: ["android.dex"] } prepare: SdkUtils.prepareDex.apply(SdkUtils, arguments) } Rule { property stringList inputTags: "android.nativelibrary" inputsFromDependencies: inputTags inputs: product.aggregate ? [] : inputTags Artifact { filePath: FileInfo.joinPaths(product.Android.sdk.packageContentsDir, "lib", input.Android.ndk.abi, product.Android.sdk._archInName ? input.baseName + "_" + input.Android.ndk.abi + ".so" : input.fileName) fileTags: "android.nativelibrary_deployed" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "copying " + input.fileName + " for packaging"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } Rule { multiplex: true property stringList inputTags: "android.stl" inputsFromDependencies: inputTags inputs: product.aggregate ? [] : inputTags outputFileTags: "android.stl_deployed" outputArtifacts: SdkUtils.deployStlOutputs(product, inputs) prepare: SdkUtils.deployStlCommands(product, inputs) } Group { condition: module._enableAapt2 Rule { inputs: ["android.resources"] outputFileTags: ["android.resources_compiled"] outputArtifacts: SdkUtils.aapt2CompileResourceOutputs(product, inputs) prepare: SdkUtils.prepareAapt2CompileResource.apply(SdkUtils, arguments) } Rule { multiplex: true inputs: ["android.resources_compiled", "android.assets", "android.manifest_final"] outputFileTags: ["java.java", "android.apk_resources"] outputArtifacts: SdkUtils.aaptLinkOutputs(product, inputs) prepare: SdkUtils.prepareAapt2Link.apply(SdkUtils, arguments) } Rule { condition: module._generateAab multiplex: true inputs: [ "android.apk_resources", "android.manifest_final", "android.dex", "android.stl_deployed", "android.nativelibrary_deployed" ] Artifact { filePath: product.Android.sdk.apkBaseName + ".aab_unsigned" fileTags: "android.package_unsigned" } prepare: SdkUtils.prepareBundletoolPackage.apply(SdkUtils, arguments) } Rule { condition: !module._generateAab multiplex: true inputs: [ "android.apk_resources", "android.manifest_final", "android.dex", "android.stl_deployed", "android.nativelibrary_deployed" ] Artifact { filePath: product.Android.sdk.apkBaseName + ".apk_unsigned" fileTags: "android.package_unsigned" } prepare: SdkUtils.prepareApkPackage.apply(SdkUtils, arguments) } } Group { condition: !module._enableAapt2 Rule { multiplex: true inputs: ["android.resources", "android.assets", "android.manifest_final"] outputFileTags: ["java.java"] outputArtifacts: SdkUtils.aaptGenerateOutputs(product, inputs) prepare: SdkUtils.prepareAaptGenerate.apply(SdkUtils, arguments) } Rule { condition: !module._generateAab multiplex: true inputs: [ "android.resources", "android.assets", "android.manifest_final", "android.dex", "android.stl_deployed", "android.nativelibrary_deployed" ] Artifact { filePath: product.Android.sdk.apkBaseName + ".apk_unsigned" fileTags: "android.package_unsigned" } prepare: SdkUtils.prepareAaptPackage.apply(SdkUtils, arguments) } } } validate: { if (!sdkDir) { throw ModUtils.ModuleError("Could not find an Android SDK at any of the following " + "locations:\n\t" + sdkProbe.candidatePaths.join("\n\t") + "\nInstall the Android SDK to one of the above locations, " + "or set the Android.sdk.sdkDir property or " + "ANDROID_HOME environment variable to a valid " + "Android SDK location."); } if (!bundletoolFilePath && _generateAab) { throw ModUtils.ModuleError("Could not find Android bundletool at the following " + "location:\n\t" + Android.sdk.sdkDir + "\nInstall the Android bundletool to the above location, " + "or set the Android.sdk.bundletoolFilePath property.\n" + "Android bundletool can be downloaded from " + "https://github.com/google/bundletool"); } if (Utilities.versionCompare(buildToolsVersion, "24.0.3") < 0) { throw ModUtils.ModuleError("Version of Android SDK build tools too old. This version " + "is " + buildToolsVersion + " and minimum version is " + "24.0.3. Please update the Android SDK.") } } FileTagger { patterns: ["AndroidManifest.xml"] fileTags: ["android.manifest"] } FileTagger { patterns: ["*.aidl"] fileTags: ["android.aidl"] } Parameter { property bool embedJar: true } } qbs-src-2.6.1/share/qbs/modules/Android/sdk/utils.js0000644000175100001660000006403014776170045021651 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); var Xml = require("qbs.Xml"); function availableBuildToolsVersions(sdkDir) { var re = /^([0-9]+)\.([0-9]+)\.([0-9]+)$/; var buildTools = File.directoryEntries(FileInfo.joinPaths(sdkDir, "build-tools"), File.Dirs | File.NoDotAndDotDot); var versions = []; for (var i = 0; i < buildTools.length; ++i) { var match = buildTools[i].match(re); if (match !== null) { versions.push(buildTools[i]); } } // Sort by version number versions.sort(function (a, b) { return Utilities.versionCompare(a, b); }); return versions; } function prepareDex(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var dexCompilerFilePath = product.Android.sdk._useD8 ? product.Android.sdk.d8FilePath : product.Android.sdk.dxFilePath; var args = ["--output", FileInfo.path(output.filePath)]; if (product.Android.sdk._useD8) { if (!product.Android.sdk.d8Desugaring) args.push("--no-desugaring"); if (product.Android.sdk.minimumVersion) { args.push("--min-api", product.Android.sdk.minimumVersion); } args.push("--release"); var classes = inputs["java.class"]; if (classes) { args = args.concat(classes.map(function(javaClass) { return FileInfo.relativePath(product.java.classFilesDir, javaClass.filePath) })); } } else { args.unshift("--dex"); args.push(product.java.classFilesDir); } var jarFiles = []; function traverseJarDeps(dep) { if (dep.parameters.Android && dep.parameters.Android.sdk && dep.parameters.Android.sdk.embedJar === false) return; var isJar = typeof dep.artifacts["java.jar"] !== "undefined"; if (!isJar) return; dep.artifacts["java.jar"].forEach(function(artifact) { if (!jarFiles.includes(artifact.filePath)) jarFiles.push(artifact.filePath); }); dep.dependencies.forEach(traverseJarDeps); } product.dependencies.forEach(traverseJarDeps); if (typeof product.artifacts["java.jar"] !== "undefined") { product.artifacts["java.jar"].forEach(function(artifact) { if (!jarFiles.includes(artifact.filePath)) jarFiles.push(artifact.filePath); }); } args = args.concat(jarFiles); var cmd; if (product.Android.sdk._useD8) { cmd = new JavaScriptCommand(); cmd.args = args; cmd.dexCompilerFilePath = dexCompilerFilePath; cmd.description = "creating " + output.fileName; cmd.workingDirectory = product.java.classFilesDir; cmd.extendedDescription = dexCompilerFilePath + " " + args.join(' '); cmd.highlight = "compiler"; cmd.sourceCode = function() { // androiddeployqt copied jar files in product.java.classFilesDir // but the rule only tags one jar file ("QtAndroid.jar"/"Qt6Android.jar") // So to pass all files to d8, Qbs needs to read the directory var bundledJarFilesDir = product.java.classFilesDir; var bundledJarFiles = File.directoryEntries(bundledJarFilesDir, File.Files | File.NoDotAndDotDot); args = args.concat(bundledJarFiles.map(function(jarFile) { return FileInfo.joinPaths(bundledJarFilesDir, jarFile) })); var process = new Process(); var exitCode; process.setWorkingDirectory(workingDirectory); process.exec(dexCompilerFilePath, args, true); try { process.exec(dexCompilerFilePath, args, true); } catch (e) { throw new Error("Error while running dex compiler command: '" + Process.shellQuote(dexCompilerFilePath, args) + "': " + e.toString()); } finally { process.close(); } } } else { cmd = new Command(dexCompilerFilePath, args); cmd.description = "creating " + output.fileName; cmd.workingDirectory = product.java.classFilesDir; } return [cmd]; } function findParentDir(filePath, parentDirName) { var lastDir; var currentDir = FileInfo.path(filePath); while (lastDir !== currentDir) { if (FileInfo.fileName(currentDir) === parentDirName) return currentDir; lastDir = currentDir; currentDir = FileInfo.path(currentDir); } } function commonAaptPackageArgs(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var manifestFilePath = inputs["android.manifest_final"][0].filePath; var args = ["package", "--auto-add-overlay", "-f", "-M", manifestFilePath, "-I", product.Android.sdk.androidJarFilePath]; var resources = inputs["android.resources"]; var resourceDirs = []; if (resources) { for (var i = 0; i < resources.length; ++i) { var resDir = findParentDir(resources[i].filePath, "res"); if (!resDir) { throw "File '" + resources[i].filePath + "' is tagged as an Android resource, " + "but is not located under a directory called 'res'."; } if (!resourceDirs.includes(resDir)) resourceDirs.push(resDir); } } for (i = 0; i < resourceDirs.length; ++i) args.push("-S", resourceDirs[i]); var assets = inputs["android.assets"]; var assetDirs = []; if (assets) { for (i = 0; i < assets.length; ++i) { var assetDir = findParentDir(assets[i].filePath, "assets"); if (!assetDir) { throw "File '" + assets[i].filePath + "' is tagged as an Android asset, " + "but is not located under a directory called 'assets'."; } if (!assetDirs.includes(assetDir)) assetDirs.push(assetDir); } } for (i = 0; i < assetDirs.length; ++i) args.push("-A", assetDirs[i]); if (product.qbs.buildVariant === "debug") args.push("--debug-mode"); return args; } // Rules: from https://developer.android.com/studio/command-line/aapt2 // Input Output // XML resource files, such as Resource table with *.arsc.flat as its extension. // String and Style, which are // located in the res/values/ // directory. // All other resource files. All files other than the files under res/values/ directory are // converted to binary XML files with *.flat extensions. // Additionally all PNG files are crunched by default and adopt // *.png.flat extensions. function generateAapt2ResourceFileName(filePath) { var suffix = FileInfo.suffix(filePath); if (suffix === "xml") { var data = new Xml.DomDocument(); data.load(filePath); var rootElem = data.documentElement(); if (rootElem && rootElem.isElement() && rootElem.tagName() === "resources") // This is a valid XML resource file suffix = "arsc"; // If the xml file is not a "resources" one then it's treated like any other resource file. } var dir = FileInfo.path(filePath); var baseName = FileInfo.completeBaseName(filePath) return FileInfo.fileName(dir) + "_" + baseName + "." + suffix + ".flat"; } function aapt2CompileResourceOutputs(product, inputs) { var outputs = []; var resources = inputs["android.resources"]; for (var i = 0; i < resources.length; ++i) { var filePath = resources[i].filePath; var resourceFileName = generateAapt2ResourceFileName(filePath); var compiledName = FileInfo.joinPaths(product.Android.sdk.compiledResourcesDir, resourceFileName); outputs.push({filePath: compiledName, fileTags: "android.resources_compiled"}); } return outputs; } function prepareAapt2CompileResource(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var resources = inputs["android.resources"]; var compilesResourcesDir = product.Android.sdk.compiledResourcesDir; if (!File.makePath(compilesResourcesDir)) { throw "Cannot create directory '" + FileInfo.toNativeSeparators(compilesResourcesDir) + "'."; } var args = ["compile", FileInfo.toNativeSeparators(input.filePath), "-o", FileInfo.toNativeSeparators(compilesResourcesDir)]; var cmd = new Command(product.Android.sdk.aaptFilePath, args); var outputFileName = generateAapt2ResourceFileName(input.filePath); cmd.description = "compiling resource " + input.fileName + " into " + outputFileName; cmds.push(cmd); return cmds; } function aaptLinkOutputs(product, inputs) { var artifacts = []; artifacts.push({ filePath: product.Android.sdk.apkBaseName + (product.Android.sdk._generateAab ? ".apk_aab" : ".apk_apk"), fileTags: ["android.apk_resources"] }); var resources = inputs["android.resources_compiled"]; if (resources && resources.length) { artifacts.push({ filePath: FileInfo.joinPaths(product.Android.sdk.generatedJavaFilesDir, "R.java"), fileTags: ["java.java"] }); } for (var rp in product.Android.sdk.extraResourcePackages) { var resourcePackageName = product.Android.sdk.extraResourcePackages[rp]; artifacts.push({ filePath: FileInfo.joinPaths(product.Android.sdk.generatedJavaFilesBaseDir, resourcePackageName.split('.').join('/'), "R.java"), fileTags: ["java.java"] }); } return artifacts; } function prepareAapt2Link(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var baseOutputFilePath = outputs["android.apk_resources"][0].filePath; var manifestFilePath = inputs["android.manifest_final"][0].filePath; var compilesResourcesDir = product.Android.sdk.compiledResourcesDir; var compiledResources = inputs["android.resources_compiled"]; var args = ["link", "-o", baseOutputFilePath, "-I", product.Android.sdk.androidJarFilePath]; var i = 0; if (compiledResources) { for (i = 0; i < compiledResources.length; ++i) args.push(compiledResources[i].filePath); } args.push("--no-auto-version"); args.push("--auto-add-overlay"); args.push("--manifest", manifestFilePath); args.push("--java", product.Android.sdk.generatedJavaFilesBaseDir); var assets = inputs["android.assets"]; var assetDirs = []; if (assets) { for (i = 0; i < assets.length; ++i) { var assetDir = findParentDir(assets[i].filePath, "assets"); if (!assetDir) { throw "File '" + assets[i].filePath + "' is tagged as an Android asset, " + "but is not located under a directory called 'assets'."; } if (!assetDirs.includes(assetDir)) assetDirs.push(assetDir); } } for (i = 0; i < assetDirs.length; ++i) args.push("-A", assetDirs[i]); if (product.qbs.buildVariant === "debug") args.push("-v"); if (product.Android.sdk._generateAab) args.push("--proto-format"); if (product.Android.sdk.extraResourcePackages) { args.push("--extra-packages"); args.push(product.Android.sdk.extraResourcePackages.join(":")); } var cmd = new Command(product.Android.sdk.aaptFilePath, args); cmd.description = "linking resources"; cmd.workingDirectory = product.buildDirectory; cmds.push(cmd); return cmds; } function aaptGenerateOutputs(product, inputs) { var artifacts = []; var resources = inputs["android.resources"]; if (resources && resources.length) { artifacts.push({ filePath: FileInfo.joinPaths(product.Android.sdk.generatedJavaFilesDir, "R.java"), fileTags: ["java.java"] }); } return artifacts; } function prepareAaptGenerate(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var args = commonAaptPackageArgs.apply(this, arguments); args.push("--no-crunch", "-m"); var resources = inputs["android.resources"]; if (resources && resources.length) args.push("-J", ModUtils.moduleProperty(product, "generatedJavaFilesBaseDir")); var cmd = new Command(product.Android.sdk.aaptFilePath, args); cmd.description = "processing resources"; return [cmd]; } function prepareAaptPackage(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var apkOutput = outputs["android.package_unsigned"][0]; var args = commonAaptPackageArgs.apply(this, arguments); args.push("-F", apkOutput.filePath + ".unaligned"); args.push(product.Android.sdk.packageContentsDir); var cmd = new Command(product.Android.sdk.aaptFilePath, args); cmd.description = "generating " + apkOutput.fileName; cmds.push(cmd); cmd = new Command(product.Android.sdk.zipalignFilePath, ["-f", "4", apkOutput.filePath + ".unaligned", apkOutput.filePath]); cmd.silent = true; cmds.push(cmd); cmd = new JavaScriptCommand(); cmd.silent = true; cmd.unalignedApk = apkOutput.filePath + ".unaligned"; cmd.sourceCode = function() { File.remove(unalignedApk); }; cmds.push(cmd); return cmds; } function prepareApkPackage(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var apkInputFilePath = inputs["android.apk_resources"][0].filePath; var apkOutput = outputs["android.package_unsigned"][0]; var apkOutputFilePathUnaligned = apkOutput.filePath + ".unaligned"; var dexFilePath = inputs["android.dex"][0].filePath; var copyCmd = new JavaScriptCommand(); copyCmd.description = "copying apk"; copyCmd.source = apkInputFilePath; copyCmd.target = apkOutputFilePathUnaligned; copyCmd.sourceCode = function() { File.copy(source, target); } cmds.push(copyCmd); var jarArgs = ["-uvf", apkOutputFilePathUnaligned, "."]; var libPath = FileInfo.joinPaths(product.Android.sdk.packageContentsDir); var jarCmd = new Command(product.java.jarFilePath, jarArgs); jarCmd.description = "packaging files"; jarCmd.workingDirectory = libPath; cmds.push(jarCmd); cmd = new Command(product.Android.sdk.zipalignFilePath, ["-f", "4", apkOutputFilePathUnaligned, apkOutput.filePath]); cmd.silent = true; cmds.push(cmd); cmd = new JavaScriptCommand(); cmd.silent = true; cmd.unalignedApk = apkOutputFilePathUnaligned; cmd.sourceCode = function() { File.remove(unalignedApk); }; cmds.push(cmd); return cmds; } function prepareBundletoolPackage(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var baseModuleDir = product.Android.sdk.packageContentsDir; var manifestDirName = FileInfo.joinPaths(baseModuleDir, "manifest"); var pkgBaseFileName = inputs["android.apk_resources"][0].filePath; var jarResourcesArgs = ["xf", pkgBaseFileName]; var jarResourcesCmd = new Command(product.java.jarFilePath, jarResourcesArgs); jarResourcesCmd.description = "extracting resources apk"; jarResourcesCmd.workingDirectory = baseModuleDir; cmds.push(jarResourcesCmd); var moveManifestCmd = new JavaScriptCommand(); moveManifestCmd.description = "moving manifest in manifest directory"; moveManifestCmd.path = manifestDirName; moveManifestCmd.manifestFilePath = baseModuleDir + "/AndroidManifest.xml"; moveManifestCmd.sourceCode = function() { if (!File.exists(path)) File.makePath(path); if (File.exists(manifestFilePath)) File.move(manifestFilePath, path + "/AndroidManifest.xml"); } cmds.push(moveManifestCmd); var baseFilePath = FileInfo.joinPaths(product.buildDirectory, "base.zip"); var jarBaseArgs = ["cfM", baseFilePath, "."]; var jarBaseCmd = new Command(product.java.jarFilePath, jarBaseArgs); jarBaseCmd.description = "compressing base module"; jarBaseCmd.workingDirectory = baseModuleDir; cmds.push(jarBaseCmd); var aabFilePath = outputs["android.package_unsigned"][0].filePath; var removeCmd = new JavaScriptCommand(); removeCmd.description = "removing previous aab"; removeCmd.filePath = aabFilePath; removeCmd.sourceCode = function() { if (File.exists(filePath)) File.remove(filePath); } cmds.push(removeCmd); var bundleConfigFilePath = FileInfo.joinPaths(product.buildDirectory, "BundleConfig.json"); var createBundleConfigCmd = new JavaScriptCommand(); createBundleConfigCmd.description = "create BundleConfig.json"; createBundleConfigCmd.filePath = bundleConfigFilePath; createBundleConfigCmd.sourceCode = function() { var bc = new TextFile(filePath, TextFile.WriteOnly); bc.writeLine('{"optimizations": {'); bc.writeLine('"uncompress_native_libraries": {'); bc.writeLine('"enabled": false'); bc.writeLine('}}}'); } cmds.push(createBundleConfigCmd); var args = ["-jar", product.Android.sdk.bundletoolFilePath, "build-bundle"]; args.push("--modules=" + baseFilePath); args.push("--output=" + aabFilePath); args.push("--config=" + bundleConfigFilePath); var cmd = new Command(product.java.interpreterFilePath, args); cmd.description = "generating " + aabFilePath.fileName; cmds.push(cmd); return cmds; } function stlDeploymentData(product, inputs, type) { var data = { uniqueInputs: [], outputFilePaths: []}; var uniqueFilePaths = []; var theInputs = inputs["android.stl"]; if (!theInputs) return data; for (var i = 0; i < theInputs.length; ++i) { var currentInput = theInputs[i]; if (uniqueFilePaths.includes(currentInput.filePath)) continue; uniqueFilePaths.push(currentInput.filePath); data.uniqueInputs.push(currentInput); var outputFileName = currentInput.fileName; data.outputFilePaths.push(FileInfo.joinPaths(product.Android.sdk.packageContentsDir, "lib", currentInput.Android.ndk.abi, outputFileName)); } return data; } function elementHasBundledAttributes(element) { return element.hasAttribute("android:name") && (element.attribute("android:name") === "android.app.bundled_in_assets_resource_id") || (element.attribute("android:name") === "android.app.bundled_in_lib_resource_id"); } function deployStlOutputs(product, inputs) { var deploymentData = stlDeploymentData(product, inputs, "stl"); var outputs = []; for (var i = 0; i < deploymentData.outputFilePaths.length; ++i) { outputs.push({filePath: deploymentData.outputFilePaths[i], fileTags: "android.stl_deployed"}); } return outputs; } function deployStlCommands(product, inputs) { var cmds = []; var deploymentData = stlDeploymentData(product, inputs); for (var i = 0; i < deploymentData.uniqueInputs.length; ++i) { var input = deploymentData.uniqueInputs[i]; var stripArgs = ["--strip-all", "-o", deploymentData.outputFilePaths[i], input.filePath]; var cmd = new Command(input.cpp.stripPath, stripArgs); cmd.description = "deploying " + input.fileName; cmds.push(cmd); } return cmds; } function generateBuildConfigJavaCommands(product, output) { var cmd = new JavaScriptCommand(); cmd.description = "generating BuildConfig.java"; cmd.sourceCode = function() { var debugValue = product.qbs.buildVariant === "debug" ? "true" : "false"; var ofile = new TextFile(output.filePath, TextFile.WriteOnly); ofile.writeLine("package " + product.Android.sdk.packageName + ";") ofile.writeLine("public final class BuildConfig {"); ofile.writeLine(" public final static boolean DEBUG = " + debugValue + ";"); ofile.writeLine("}"); ofile.close(); }; return [cmd]; } function generateProcessedManifestCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "ensuring correct package name in Android manifest file"; cmd.sourceCode = function() { var manifestData = new Xml.DomDocument(); manifestData.load(input.filePath); var rootElem = manifestData.documentElement(); if (!rootElem || !rootElem.isElement() || rootElem.tagName() !== "manifest") throw "No manifest tag found in '" + input.filePath + "'."; // Quick sanity check. Don't try to be fancy; let's not risk rejecting valid names. var packageName = product.Android.sdk.packageName; if (!packageName.match(/^[^.]+(?:\.[^.]+)+$/)) { throw "Package name '" + packageName + "' is not valid. Please set " + "Android.sdk.packageName to a name following the " + "'com.mycompany.myproduct' pattern." } rootElem.setAttribute("package", packageName); if (product.Android.sdk.versionCode !== undefined) rootElem.setAttribute("android:versionCode", product.Android.sdk.versionCode); if (product.Android.sdk.versionName !== undefined) rootElem.setAttribute("android:versionName", product.Android.sdk.versionName); if (product.Android.sdk._bundledInAssets) { // Remove // custom AndroidManifest.xml because assets are in rcc files for qt >= 5.14 var appElem = rootElem.firstChild("application"); if (!appElem || !appElem.isElement() || appElem.tagName() !== "application") throw "No application tag found in '" + input.filePath + "'."; var activityElem = appElem.firstChild("activity"); if (!activityElem || !activityElem.isElement() || activityElem.tagName() !== "activity") throw "No activity tag found in '" + input.filePath + "'."; var metaDataElem = activityElem.firstChild("meta-data"); while (metaDataElem && metaDataElem.isElement()) { if (elementHasBundledAttributes(metaDataElem)) { var elemToRemove = metaDataElem; metaDataElem = metaDataElem.nextSibling("meta-data"); activityElem.removeChild(elemToRemove); } else { metaDataElem = metaDataElem.nextSibling("meta-data"); } } } var usedSdkElem = rootElem.firstChild("uses-sdk"); if (!usedSdkElem || !usedSdkElem.isElement()) { usedSdkElem = manifestData.createElement("uses-sdk"); rootElem.appendChild(usedSdkElem); } else { if (!usedSdkElem.isElement()) throw "Tag uses-sdk is not an element in '" + input.filePath + "'."; } usedSdkElem.setAttribute("android:minSdkVersion", product.Android.sdk.minimumVersion); usedSdkElem.setAttribute("android:targetSdkVersion", product.Android.sdk.targetVersion); rootElem.appendChild(usedSdkElem); manifestData.save(output.filePath, 4); } return cmd; } function processAidlCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var aidl = product.Android.sdk.aidlFilePath; var args = ["-p" + product.Android.sdk.frameworkAidlFilePath]; var aidlSearchPaths = input.Android.sdk.aidlSearchPaths; for (var i = 0; i < (aidlSearchPaths ? aidlSearchPaths.length : 0); ++i) args.push("-I" + aidlSearchPaths[i]); args.push(input.filePath, output.filePath); var cmd = new Command(aidl, args); cmd.description = "processing " + input.fileName; return [cmd]; } qbs-src-2.6.1/share/qbs/modules/Android/ndk/0000755000175100001660000000000014776170045020143 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/Android/ndk/ndk.qbs0000644000175100001660000001322014776170045021424 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Probes import qbs.Utilities import "utils.js" as NdkUtils Module { Probes.AndroidNdkProbe { id: ndkProbe environmentPaths: (ndkDir ? [ndkDir] : []).concat(base) } version: ndkProbe.ndkVersion readonly property string abi: NdkUtils.androidAbi(qbs.architecture) PropertyOptions { name: "abi" description: "Supported Android ABIs" allowedValues: ["arm64-v8a", "armeabi-v7a", "x86", "x86_64"] } // From https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md // Android Studio‘s LLDB debugger uses a binary’s build ID to locate debug information. To // ensure that LLDB works with a binary, pass an option like -Wl,--build-id=sha1 to Clang when // linking. Other --build-id= modes are OK, but avoid a plain --build-id argument when using // LLD, because Android Studio‘s version of LLDB doesn’t recognize LLD's default 8-byte build // ID. See Issue 885. // Plain --build-id option is nevertheless implemented when buildId property is empty. // Possible values (from man page of ld.lld — ELF linker from the LLVM project): // one of fast, md5, sha1, tree, uuid, 0xhex-string, and none. tree is an alias for sha1. // Build-IDs of type fast, md5, sha1, and tree are calculated from the object contents. fast is // not intended to be cryptographically secure. property string buildId: "sha1" // See https://developer.android.com/ndk/guides/cpp-support.html property string appStl: "c++_shared" PropertyOptions { name: "appStl" description: "C++ Runtime Libraries." allowedValues: ["c++_static", "c++_shared"] } property string hostArch: ndkProbe.hostArch property string ndkDir: ndkProbe.path property string ndkSamplesDir: ndkProbe.samplesDir property string platform: { switch (abi) { case "armeabi-v7a": // case "x86": // x86 has broken wstring support return "android-19"; default: return "android-21"; } } property int platformVersion: { if (platform) { var match = platform.match(/^android-([0-9]+)$/); if (match !== null) { return parseInt(match[1], 10); } } } property stringList abis: { var list = ["armeabi-v7a"]; if (platformVersion >= 16) list.push("x86"); if (platformVersion >= 21) list.push("arm64-v8a", "x86_64"); return list; } property string armMode: abi && abi.startsWith("armeabi") ? (qbs.buildVariant === "debug" ? "arm" : "thumb") : undefined; PropertyOptions { name: "armMode" description: "Determines the instruction set for armeabi configurations." allowedValues: ["arm", "thumb"] } validate: { if (!ndkDir) { throw ModUtils.ModuleError("Could not find an Android NDK at any of the following " + "locations:\n\t" + ndkProbe.candidatePaths.join("\n\t") + "\nInstall the Android NDK to one of the above locations, " + "or set the Android.ndk.ndkDir property or " + "ANDROID_NDK_ROOT environment variable to a valid " + "Android NDK location."); } if (Utilities.versionCompare(version, "19") < 0) throw ModUtils.ModuleError("Unsupported NDK version " + Android.ndk.version + ", please upgrade your NDK to r19+"); if (product.aggregate && !product.multiplexConfigurationId) return; var validator = new ModUtils.PropertyValidator("Android.ndk"); validator.setRequiredProperty("abi", abi); validator.setRequiredProperty("appStl", appStl); validator.setRequiredProperty("hostArch", hostArch); validator.setRequiredProperty("platform", platform); return validator.validate(); } } qbs-src-2.6.1/share/qbs/modules/Android/ndk/utils.js0000644000175100001660000000646314776170045021652 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Utilities = require("qbs.Utilities") function abiNameToDirName(abiName) { switch (abiName) { case "armeabi": case "armeabi-v7a": return "arm"; case "arm64-v8a": return "arm64"; default: return abiName; } } function androidAbi(arch) { switch (arch) { case "arm64": return "arm64-v8a"; case "armv5": case "armv5te": return "armeabi"; case "armv7": case "armv7a": return "armeabi-v7a"; default: return arch; } } function commonCompilerFlags(toolchain, buildVariant, ndk) { var flags = ["-Werror=format-security"]; var abi = ndk.abi; var armMode = ndk.armMode; if (abi === "arm64-v8a") flags.push("-fpic"); if (abi === "armeabi" || abi === "armeabi-v7a") { flags.push("-fpic"); if (abi === "armeabi") flags.push("-mtune=xscale", "-msoft-float"); if (abi === "armeabi-v7a") { flags.push("-mfpu=vfpv3-d16"); flags.push("-mfloat-abi=softfp"); } } if (abi === "x86" || abi === "x86_64") flags.push("-fPIC"); flags.push("-fno-limit-debug-info"); if (armMode) flags.push("-m" + armMode); // https://github.com/android-ndk/ndk/issues/884 is fixed in r21 if (ndk.version < 21) flags.push("-fno-addrsig"); // https://github.com/android/ndk/issues/635 is fixed in api 24 if (abi === "x86" && ndk.platformVersion < 24) flags.push("-mstackrealign"); return flags; } function commonLinkerFlags(ndk) { var buildId = (ndk.buildId) ? "--build-id=" + ndk.buildId : "--build-id"; return ["-z", "noexecstack", "-z", "relro", "-z", "now", buildId, "--gc-sections"]; } function stlFileName(prefix, ndk, suffix) { return prefix + ndk.appStl.slice(0, ndk.appStl.indexOf('_')) + suffix; } qbs-src-2.6.1/share/qbs/modules/Android/android-utils.js0000644000175100001660000000416514776170045022511 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); function availablePlatforms(baseDir) { var re = /^android-([0-9]+)$/; var platforms = File.directoryEntries(FileInfo.joinPaths(baseDir, "platforms"), File.Dirs | File.NoDotAndDotDot); var versions = []; for (var i = 0; i < platforms.length; ++i) { var match = platforms[i].match(re); if (match !== null) { versions.push(platforms[i]); } } versions.sort(function (a, b) { return parseInt(a.match(re)[1], 10) - parseInt(b.match(re)[1], 10); }); return versions; } qbs-src-2.6.1/share/qbs/modules/wix/0000755000175100001660000000000014776170045016616 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/wix/WiXModule.qbs0000644000175100001660000004205614776170045021211 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.Probes import qbs.Utilities Module { condition: qbs.targetOS.includes("windows") Probes.WiXProbe { id: wixProbe } property path toolchainInstallPath: wixProbe.path property path toolchainInstallRoot: wixProbe.root version: wixProbe.version property var versionParts: version ? version.split('.').map(function(item) { return parseInt(item, 10); }) : [] property int versionMajor: versionParts[0] property int versionMinor: versionParts[1] property int versionPatch: versionParts[2] property int versionBuild: versionParts[3] property string compilerName: "candle.exe" property string compilerPath: FileInfo.joinPaths(toolchainInstallRoot, compilerName) property string linkerName: "light.exe" property string linkerPath: FileInfo.joinPaths(toolchainInstallRoot, linkerName) property string warningLevel: "normal" PropertyOptions { name: "warningLevel" allowedValues: ["none", "normal", "pedantic"] } property bool debugInformation: qbs.debugInformation property bool treatWarningsAsErrors: false property bool verboseOutput: false PropertyOptions { name: "verboseOutput" description: "display verbose output from the compiler and linker" } property bool visualStudioCompatibility: true PropertyOptions { name: "visualStudioCompatibility" description: "whether to define most of the same variables as " + "Visual Studio when using the Candle compiler" } property bool enableQbsDefines: true PropertyOptions { name: "enableQbsDefines" description: "built-in variables that are defined when using the Candle compiler" } property pathList includePaths PropertyOptions { name: "includePaths" description: "directories to add to the include search path" } property stringList defines PropertyOptions { name: "defines" description: "variables that are defined when using the Candle compiler" } property stringList compilerFlags PropertyOptions { name: "compilerFlags" description: "additional flags for the Candle compiler" } property stringList linkerFlags PropertyOptions { name: "linkerFlags" description: "additional flags for the Light linker" } property stringList cultures PropertyOptions { name: "cultures" description: "the list of localizations to build the MSI for; leave undefined to build all localizations" } property stringList extensions: product.type.includes("wixsetup") ? ["WixBalExtension"] : [] // default to WiX Standard Bootstrapper extension // private properties property string targetSuffix: { if (product.type.includes("msi")) { return windowsInstallerSuffix; } else if (product.type.includes("wixsetup")) { return executableSuffix; } } // MSI/MSM package validation only works natively on Windows property bool enablePackageValidation: Host.os().includes("windows") property string executableSuffix: ".exe" property string windowsInstallerSuffix: ".msi" validate: { var validator = new ModUtils.PropertyValidator("wix"); validator.setRequiredProperty("toolchainInstallPath", toolchainInstallPath); validator.setRequiredProperty("toolchainInstallRoot", toolchainInstallRoot); validator.setRequiredProperty("version", version); validator.setRequiredProperty("versionMajor", versionMajor); validator.setRequiredProperty("versionMinor", versionMinor); validator.setRequiredProperty("versionPatch", versionPatch); validator.addVersionValidator("version", version, 3, 4); validator.addRangeValidator("versionMajor", versionMajor, 1); validator.addRangeValidator("versionMinor", versionMinor, 0); validator.addRangeValidator("versionPatch", versionPatch, 0); if (versionParts && versionParts.length >= 4) { validator.setRequiredProperty("versionBuild", versionBuild); validator.addRangeValidator("versionBuild", versionBuild, 0); } validator.validate(); } setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(), true); v.prepend(product.wix.toolchainInstallPath); v.prepend(product.wix.toolchainInstallRoot); v.set(); } // WiX Include Files FileTagger { patterns: ["*.wxi"] fileTags: ["wxi"] } // WiX Localization Files FileTagger { patterns: ["*.wxl"] fileTags: ["wxl"] } // WiX Source Files FileTagger { patterns: ["*.wxs"] fileTags: ["wxs"] } Rule { id: candleCompiler inputs: ["wxs"] auxiliaryInputs: ["wxi", "installable"] auxiliaryInputsFromDependencies: ["wxi", "installable"] Artifact { fileTags: ["wixobj"] filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), FileInfo.baseName(input.fileName) + ".wixobj") } prepare: { var i; var args = ["-nologo"]; if (ModUtils.moduleProperty(input, "warningLevel") === "none") { args.push("-sw"); } else { if (ModUtils.moduleProperty(input, "warningLevel") === "pedantic") { args.push("-pedantic"); } if (ModUtils.moduleProperty(input, "treatWarningsAsErrors")) { args.push("-wx"); } } if (ModUtils.moduleProperty(input, "verboseOutput")) { args.push("-v"); } var arch = product.moduleProperty("qbs", "architecture"); // http://wixtoolset.org/documentation/manual/v3/xsd/wix/package.html switch (arch) { case "x86_64": arch = "x64"; break; case "armv7": case "armv7a": arch = "arm"; break; } // Visual Studio defines these variables along with various solution and project names and paths; // we'll pass most of them to ease compatibility between QBS and WiX projects originally created // using Visual Studio. The only definitions we don't pass are the ones which make no sense at all // in QBS, like the solution and project directories since they do not exist. if (ModUtils.moduleProperty(input, "visualStudioCompatibility")) { var toolchain = product.moduleProperty("qbs", "toolchain"); var toolchainInstallPath = product.moduleProperty("cpp", "toolchainInstallPath"); if (toolchain && toolchain.includes("msvc") && toolchainInstallPath) { var vcDir = toolchainInstallPath.replace(/[\\/]bin$/i, ""); var vcRootDir = vcDir.replace(/[\\/]VC$/i, ""); args.push("-dDevEnvDir=" + FileInfo.toWindowsSeparators(FileInfo.joinPaths(vcRootDir, 'Common7', 'IDE'))); } var buildVariant = product.moduleProperty("qbs", "buildVariant"); if (buildVariant === "debug") { args.push("-dDebug"); args.push("-dConfiguration=Debug"); } else if (buildVariant === "release") { // VS doesn't define "Release" args.push("-dConfiguration=Release"); } var productTargetExt = ModUtils.moduleProperty(input, "targetSuffix"); if (!productTargetExt) { throw("WiX: Unsupported product type '" + product.type + "'"); } var builtBinaryFilePath = FileInfo.joinPaths(product.destinationDirectory, product.targetName + productTargetExt); args.push("-dOutDir=" + FileInfo.toWindowsSeparators(FileInfo.path(builtBinaryFilePath))); // in VS, relative to the project file by default args.push("-dPlatform=" + (arch || "x86")); args.push("-dProjectName=" + project.name); args.push("-dTargetDir=" + FileInfo.toWindowsSeparators(FileInfo.path(builtBinaryFilePath))); // in VS, an absolute path args.push("-dTargetExt=" + productTargetExt); args.push("-dTargetFileName=" + product.targetName + productTargetExt); args.push("-dTargetName=" + product.targetName); args.push("-dTargetPath=" + FileInfo.toWindowsSeparators(builtBinaryFilePath)); } var includePaths = ModUtils.moduleProperty(input, "includePaths"); for (i in includePaths) { args.push("-I" + includePaths[i]); } var enableQbsDefines = ModUtils.moduleProperty(input, "enableQbsDefines") if (enableQbsDefines) { var map = { "project.": project, "product.": product }; for (var prefix in map) { var obj = map[prefix]; for (var prop in obj) { var val = obj[prop]; if (typeof val !== 'function' && typeof val !== 'object' && !prop.startsWith("_")) { args.push("-d" + prefix + prop + "=" + val); } } } // Helper define for alternating between 32-bit and 64-bit logic if (arch === "x64" || arch === "ia64") { args.push("-dWin64"); } } // User-supplied defines var defines = ModUtils.moduleProperty(input, "defines"); for (i in defines) { args.push("-d" + defines[i]); } // User-supplied flags var flags = ModUtils.moduleProperty(input, "compilerFlags"); for (i in flags) { args.push(flags[i]); } args.push("-out"); args.push(FileInfo.toWindowsSeparators(output.filePath)); if (arch) { args.push("-arch"); args.push(arch); } var extensions = ModUtils.moduleProperty(input, "extensions"); for (i in extensions) { args.push("-ext"); args.push(extensions[i]); } args.push(FileInfo.toWindowsSeparators(input.filePath)); var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; cmd.workingDirectory = FileInfo.path(output.filePath); // candle.exe outputs the file name. We filter that out. cmd.inputFileName = input.fileName; cmd.stdoutFilterFunction = function(output) { return output.split(inputFileName + "\r\n").join(""); }; return cmd; } } Rule { id: lightLinker multiplex: true inputs: ["wixobj", "wxl"] auxiliaryInputs: ["installable"] auxiliaryInputsFromDependencies: ["installable"] inputsFromDependencies: product.type.includes("wixsetup") ? ["msi"] : [] outputArtifacts: { var artifacts = []; if (product.type.includes("wixsetup")) { artifacts.push({ fileTags: ["wixsetup", "application"], filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ModUtils.moduleProperty(product, "executableSuffix")) }); } if (product.type.includes("msi")) { artifacts.push({ fileTags: ["msi"], filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ModUtils.moduleProperty(product, "windowsInstallerSuffix")) }); } if (ModUtils.moduleProperty(product, "debugInformation")) { artifacts.push({ fileTags: ["wixpdb"], filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".wixpdb") }); } return artifacts; } outputFileTags: ["application", "msi", "wixpdb", "wixsetup"] prepare: { var i; var primaryOutput; if (product.type.includes("wixsetup")) { primaryOutput = outputs.wixsetup[0]; } else if (product.type.includes("msi")) { primaryOutput = outputs.msi[0]; } else { throw("WiX: Unsupported product type '" + product.type + "'"); } var args = ["-nologo"]; if (!ModUtils.moduleProperty(product, "enablePackageValidation")) { args.push("-sval"); } if (ModUtils.moduleProperty(product, "warningLevel") === "none") { args.push("-sw"); } else { if (ModUtils.moduleProperty(product, "warningLevel") === "pedantic") { args.push("-pedantic"); } if (ModUtils.moduleProperty(product, "treatWarningsAsErrors")) { args.push("-wx"); } } if (ModUtils.moduleProperty(product, "verboseOutput")) { args.push("-v"); } args.push("-out"); args.push(FileInfo.toWindowsSeparators(primaryOutput.filePath)); if (ModUtils.moduleProperty(product, "debugInformation")) { args.push("-pdbout"); args.push(FileInfo.toWindowsSeparators(outputs.wixpdb[0].filePath)); } else { args.push("-spdb"); } var extensions = ModUtils.moduleProperty(product, "extensions"); for (i in extensions) { args.push("-ext"); args.push(extensions[i]); } for (i in inputs.wxl) { args.push("-loc"); args.push(FileInfo.toWindowsSeparators(inputs.wxl[i].filePath)); } if (product.type.includes("msi")) { var cultures = ModUtils.moduleProperty(product, "cultures"); args.push("-cultures:" + (cultures && cultures.length > 0 ? cultures.join(";") : "null")); } // User-supplied flags var flags = ModUtils.moduleProperty(product, "linkerFlags"); for (i in flags) { args.push(flags[i]); } for (i in inputs.wixobj) { args.push(FileInfo.toWindowsSeparators(inputs.wixobj[i].filePath)); } var cmd = new Command(ModUtils.moduleProperty(product, "linkerPath"), args); cmd.description = "linking " + primaryOutput.fileName; cmd.highlight = "linker"; cmd.workingDirectory = FileInfo.path(primaryOutput.filePath); return cmd; } } } qbs-src-2.6.1/share/qbs/modules/pkgconfig/0000755000175100001660000000000014776170045017756 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/pkgconfig/pkgconfig.qbs0000644000175100001660000000507114776170045022437 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.File import qbs.Probes Module { Probes.BinaryProbe { id: pkgconfigProbe names: "pkg-config" } property path sysroot: { if (qbs.targetOS.includes("macos")) return ""; return qbs.sysroot; } property string executableFilePath: pkgconfigProbe.filePath property stringList libDirs property bool staticMode: false validate: { if (!executableFilePath) { throw "No pkg-config executable found. " + "Please set modules.pkgconfig.executableFilePath."; } if (!File.exists(executableFilePath)) throw "The pkg-config executable '" + executableFilePath + "' does not exist."; } } qbs-src-2.6.1/share/qbs/modules/typescript/0000755000175100001660000000000014776170045020215 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/typescript/typescript.js0000644000175100001660000002465014776170045022770 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); function findTscVersion(compilerFilePath, nodejsPath) { var p = new Process(); try { if (nodejsPath) p.setEnv("PATH", nodejsPath); p.exec(compilerFilePath, ["--version"]); var re = /^(?:message TS6029: )?Version (([0-9]+(?:\.[0-9]+){1,3})(?:-(.+?))?)$/m; var match = p.readStdOut().trim().match(re); if (match !== null) return match; } finally { p.close(); } } function tscArguments(product, inputs) { var i; var args = []; if (ModUtils.moduleProperty(product, "warningLevel") === "pedantic") { args.push("--noImplicitAny"); } var targetVersion = ModUtils.moduleProperty(product, "targetVersion"); if (targetVersion) { args.push("--target"); args.push(targetVersion); } var moduleLoader = ModUtils.moduleProperty(product, "moduleLoader"); if (moduleLoader) { args.push("--module"); args.push(moduleLoader); } if (ModUtils.moduleProperty(product, "stripComments")) { args.push("--removeComments"); } if (ModUtils.moduleProperty(product, "generateDeclarations")) { args.push("--declaration"); } if (ModUtils.moduleProperty(product, "generateSourceMaps")) { args.push("--sourcemap"); } // User-supplied flags var flags = ModUtils.moduleProperty(product, "compilerFlags"); for (i in flags) { args.push(flags[i]); } if (supportsModernFeatures(product)) { args.push("--rootDir", product.sourceDirectory); } args.push("--outDir", product.buildDirectory); if (ModUtils.moduleProperty(product, "singleFile")) { args.push(outOption(product), FileInfo.joinPaths(product.destinationDirectory, product.targetName) + ".js"); } if (inputs.typescript_declaration) { for (i = 0; i < inputs.typescript_declaration.length; ++i) { args.push(inputs.typescript_declaration[i].filePath); } } if (inputs.typescript) { for (i = 0; i < inputs.typescript.length; ++i) { args.push(inputs.typescript[i].filePath); } } if (inputs["typescript.typescript-internal"]) { for (i = 0; i < inputs["typescript.typescript-internal"].length; ++i) { args.push(inputs["typescript.typescript-internal"][i].filePath); } } return args; } function outputArtifacts(product, inputs) { if (!supportsModernFeatures(product)) { console.warn("Qbs does not properly support TypeScript versions prior to 1.5 due to " + "severe limitations in dependency tracking. This is TypeScript version " + ModUtils.moduleProperty(product, "version") + ". It is strongly recommended " + "that you upgrade TypeScript, or continue at your own risk."); return legacyOutputArtifacts(product, inputs); } var process; try { process = new Process(); process.setEnv("NODE_PATH", [ ModUtils.moduleProperty(product, "toolchainInstallPath"), product.moduleProperty("nodejs", "packageManagerRootPath") ].join(FileInfo.pathListSeparator())); process.exec(product.moduleProperty("nodejs", "interpreterFilePath"), [FileInfo.joinPaths(product.buildDirectory, ".io.qt.qbs.internal.typescript", "qbs-tsc-scan.js")] .concat(tscArguments(product, inputs)), true); var artifacts = JSON.parse(process.readStdOut()); // Find and tag the "main" output file var applicationFile = product.moduleProperty("nodejs", "applicationFile"); if (applicationFile) { var i, appIndex = -1; if (product.moduleProperty("typescript", "singleFile")) { for (i = 0; i < artifacts.length; ++i) { if (artifacts[i].fileTags.includes("compiled_typescript")) { appIndex = i; break; } } } else { var expected = FileInfo.relativePath(product.sourceDirectory, applicationFile); if (!expected.endsWith(".ts")) // tsc doesn't allow this anyways, so it's a perfectly reasonable restriction throw "TypeScript source file name '" + applicationFile + "' does not end with .ts"; expected = expected.slice(0, -2) + "js"; for (i = 0; i < artifacts.length; ++i) { if (expected === FileInfo.relativePath(product.buildDirectory, artifacts[i].filePath)) { appIndex = i; break; } } } if (appIndex === -1 || !artifacts[appIndex].fileTags.includes("compiled_typescript")) throw "nodejs.applicationFile was set, but Qbs couldn't find the compiled " + "JavaScript file corresponding to '" + applicationFile + "'"; artifacts[appIndex].fileTags = artifacts[appIndex].fileTags.concat(["application_js"]); } return artifacts; } finally { if (process) process.close(); } } function legacyOutputArtifacts(product, inputs) { var artifacts = []; if (!inputs.typescript) { return artifacts; } var jsTags = ["js", "compiled_typescript"]; var filePath = FileInfo.joinPaths(product.destinationDirectory, product.targetName); if (product.moduleProperty("typescript", "singleFile")) { // We could check // if (product.moduleProperty("nodejs", "applicationFile") === inputs.typescript[i].filePath) // but since we're compiling to a single file there's no need to state it explicitly jsTags.push("application_js"); artifacts.push({fileTags: jsTags, filePath: FileInfo.joinPaths( product.moduleProperty("nodejs", "compiledIntermediateDir"), product.targetName + ".js")}); if (product.moduleProperty("typescript", "generateDeclarations")) { artifacts.push({fileTags: ["typescript_declaration"], filePath: filePath + ".d.ts"}); } if (product.moduleProperty("typescript", "generateSourceMaps")) { artifacts.push({fileTags: ["source_map"], filePath: filePath + ".js.map"}); } } else { for (var i = 0; i < inputs.typescript.length; ++i) { jsTags = ["js", "compiled_typescript"]; if (product.moduleProperty("nodejs", "applicationFile") === inputs.typescript[i].filePath) jsTags.push("application_js"); var intermediatePath = FileInfo.path(FileInfo.relativePath( product.sourceDirectory, inputs.typescript[i].filePath)); var baseName = FileInfo.baseName(inputs.typescript[i].fileName); filePath = FileInfo.joinPaths(product.destinationDirectory, intermediatePath, baseName); artifacts.push({fileTags: jsTags, filePath: FileInfo.joinPaths( product.moduleProperty("nodejs", "compiledIntermediateDir"), intermediatePath, baseName + ".js")}); if (product.moduleProperty("typescript", "generateDeclarations")) { artifacts.push({fileTags: ["typescript_declaration"], filePath: filePath + ".d.ts"}); } if (product.moduleProperty("typescript", "generateSourceMaps")) { artifacts.push({fileTags: ["source_map"], filePath: filePath + ".js.map"}); } } } 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) { if (ModUtils.moduleProperty(product, "versionMinor") >= 5) { return true; } } return compilerVersionMajor > 1; } qbs-src-2.6.1/share/qbs/modules/typescript/qbs-tsc-scan/0000755000175100001660000000000014776170045022513 5ustar runnerdockerqbs-src-2.6.1/share/qbs/modules/typescript/qbs-tsc-scan/qbs-tsc-scan.ts0000644000175100001660000000516714776170045025372 0ustar runnerdockerimport ts = require("typescript"); declare var process: any; export namespace io.qt.qbs { export class Artifact { filePath: string; fileTags: string[]; } export namespace tools { export namespace utils { function stringEndsWith(s: string, e: string) { return s.slice(-e.length) === e; } export function artifactFromFilePath(filePath: string): Artifact { var fileTags: string[] = []; if (stringEndsWith(filePath, ".js.map")) { fileTags.push("source_map"); } else if (stringEndsWith(filePath, ".js")) { fileTags.push("js", "compiled_typescript"); } else if (stringEndsWith(filePath, ".d.ts")) { fileTags.push("typescript_declaration"); } return { filePath: filePath, fileTags: fileTags }; } } function compileInternal(fileNames: string[], options: ts.CompilerOptions): qbs.Artifact[] { var outputArtifacts: qbs.Artifact[] = []; var program = ts.createProgram(fileNames, options); var emitResult = program.emit(undefined, filePath => { outputArtifacts.push(utils.artifactFromFilePath(filePath)); }); var allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); allDiagnostics.forEach(diagnostic => { var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); if (diagnostic.file) { var { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); console.error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); } else { console.error(message); } }); return emitResult.emitSkipped ? undefined : outputArtifacts; } export function compile(commandLineArguments: string[]): qbs.Artifact[] { var parsedCommandLine = ts.parseCommandLine(commandLineArguments); return compileInternal(parsedCommandLine.fileNames, parsedCommandLine.options); } export function TypeScriptCompilerScannerToolMain(): void { var outputArtifacts = compile(process.argv.slice(2)); if (outputArtifacts !== undefined) { console.log(JSON.stringify(outputArtifacts)); } else { process.exit(1); } } } } io.qt.qbs.tools.TypeScriptCompilerScannerToolMain(); qbs-src-2.6.1/share/qbs/modules/typescript/qbs-tsc-scan/.gitignore0000644000175100001660000000016114776170045024501 0ustar runnerdocker# Visual Studio Code IDE tsconfig.json qbs-tsc-scan.js typings/node/node.d.ts typings/typescript/typescript.d.ts qbs-src-2.6.1/share/qbs/modules/typescript/TypeScriptModule.qbs0000644000175100001660000003055314776170045024206 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Probes import qbs.Process import "typescript.js" as TypeScript Module { // Qbs does NOT support standalone TypeScript installations // (for example, %PROGRAMFILES%\Microsoft SDKs\TypeScript and some Debian and RPM packages), // because they do not include typescript.d.ts, which is necessary for building internal tools. // Only npm-based installations of TypeScript are supported (this is also the most common). Depends { name: "nodejs" } additionalProductTypes: ["compiled_typescript"] Probes.TypeScriptProbe { id: tsc interpreterPath: FileInfo.path(nodejs.interpreterFilePath) packageManagerBinPath: nodejs.packageManagerBinPath packageManagerRootPath: nodejs.packageManagerRootPath } property path toolchainInstallPath: tsc.path property path toolchainLibDirName: (versionMajor > 1 || (versionMajor === 1 && versionMinor >= 6)) ? "lib" : "bin" property path toolchainLibInstallPath: FileInfo.joinPaths(nodejs.packageManagerRootPath, "typescript", toolchainLibDirName) version: tsc.version ? tsc.version[2] : undefined property var versionParts: version ? version.split('.').map(function(item) { return parseInt(item, 10); }) : [] property int versionMajor: versionParts[0] property int versionMinor: versionParts[1] property int versionPatch: versionParts[2] property int versionBuild: versionParts[3] property string versionSuffix: tsc.version ? tsc.version[3] : undefined property string compilerName: tsc.fileName property string compilerPath: tsc.filePath property string warningLevel: "normal" PropertyOptions { name: "warningLevel" description: "pedantic to warn on expressions and declarations with an implied 'any' type" allowedValues: ["normal", "pedantic"] } property string targetVersion PropertyOptions { name: "targetVersion" description: "ECMAScript target version" allowedValues: ["ES3", "ES5", "ES2015"] } property string moduleLoader PropertyOptions { name: "moduleLoader" allowedValues: ["commonjs", "amd"] } property bool stripComments: !qbs.debugInformation PropertyOptions { name: "stripComments" description: "whether to remove comments from the generated output" } property bool generateDeclarations: false PropertyOptions { name: "generateDeclarations" description: "whether to generate corresponding .d.ts files during compilation" } // In release mode, nodejs can/should default-enable minification and obfuscation, // making the source maps useless, so these default settings work out fine property bool generateSourceMaps: qbs.debugInformation PropertyOptions { name: "generateSourceMaps" description: "whether to generate corresponding .map files during compilation" } property stringList compilerFlags PropertyOptions { name: "compilerFlags" description: "additional flags for the TypeScript compiler" } property bool singleFile: false PropertyOptions { name: "singleFile" description: "whether to compile all source files to a single output file" } 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" + FileInfo.executableSuffix(); }, 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); validator.setRequiredProperty("compilerPath", compilerPath); validator.setRequiredProperty("version", version); validator.setRequiredProperty("versionParts", versionParts); validator.setRequiredProperty("versionMajor", versionMajor); validator.setRequiredProperty("versionMinor", versionMinor); validator.setRequiredProperty("versionPatch", versionPatch); validator.addVersionValidator("version", version, 3, 4); validator.addRangeValidator("versionMajor", versionMajor, 1); validator.addRangeValidator("versionMinor", versionMinor, 0); validator.addRangeValidator("versionPatch", versionPatch, 0); if (versionParts && versionParts.length >= 4) { validator.setRequiredProperty("versionBuild", versionBuild); validator.addRangeValidator("versionBuild", versionBuild, 0); } validator.validate(); } // TypeScript declaration files FileTagger { patterns: ["*.d.ts"] fileTags: ["typescript_declaration"] } // TypeScript source files FileTagger { patterns: ["*.ts"] fileTags: ["typescript"] } Group { 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, "..", "package.json") ] fileTags: ["typescript.typescript-internal"] } Rule { multiplex: true inputs: ["typescript.typescript-internal"] outputFileTags: ["typescript.compiled_typescript-internal"] outputArtifacts: { if (!TypeScript.supportsModernFeatures(product)) 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"] }]; } prepare: { var inputPaths = inputs["typescript.typescript-internal"].map(function (input) { 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.ignoreDryRun = true; 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", outDir].concat(outputPaths.filter(function (f) { return !f.endsWith(".json"); })); var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); cmd.ignoreDryRun = true; cmd.silent = true; return [jcmd, cmd]; } } Rule { id: typescriptCompiler multiplex: true inputs: ["typescript"] inputsFromDependencies: ["typescript_declaration"] explicitlyDependsOn: ["typescript.compiled_typescript-internal"] outputArtifacts: TypeScript.outputArtifacts(product, inputs) outputFileTags: ["application_js", "compiled_typescript", "js", "source_map", "typescript_declaration"] prepare: { var cmd, cmds = []; cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), TypeScript.tscArguments(product, inputs)); cmd.description = "compiling " + (ModUtils.moduleProperty(product, "singleFile") ? outputs.compiled_typescript[0].fileName : inputs.typescript.map(function(obj) { return obj.fileName; }).join(", ")); cmd.highlight = "compiler"; cmds.push(cmd); // QBS-5 // Move the compiled JavaScript files compiled by TypeScript to an intermediate // directory so that the nodejs module can perform any necessary postprocessing // on the result. The nodejs module will move the files back to their original // locations after postprocessing. cmd = new JavaScriptCommand(); cmd.silent = true; cmd.outDir = product.buildDirectory; cmd.sourceCode = function() { for (var i = 0; i < outputs.compiled_typescript.length; ++i) { var output = outputs.compiled_typescript[i]; var intermediatePath = FileInfo.path(FileInfo.relativePath(product.moduleProperty("nodejs", "compiledIntermediateDir"), output.filePath)); var originalFilePath = FileInfo.joinPaths(outDir, intermediatePath, output.fileName); File.copy(originalFilePath, output.filePath); File.remove(originalFilePath); } }; cmds.push(cmd); return cmds; } } } qbs-src-2.6.1/share/qbs/module-providers/0000755000175100001660000000000014776170045017637 5ustar runnerdockerqbs-src-2.6.1/share/qbs/module-providers/conan.js0000644000175100001660000002220614776170045021275 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Kai Dohmen ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var PathProbe = require("../imports/qbs/Probes/path-probe.js") var PathTools = require("qbs.PathTools"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); const architectureMap = { 'x86': 'x86', 'x86_64': 'x86_64', 'ppc32be': 'ppc', 'ppc32': 'ppc', 'ppc64le': 'ppc64', 'ppc64': 'ppc64', 'armv4': 'arm', 'armv4i': 'arm', 'armv5el': 'arm', 'armv5hf': 'arm', 'armv6': 'arm', 'armv7': 'arm', 'armv7hf': 'arm', 'armv7s': 'arm', 'armv7k': 'arm', 'armv8': 'arm64', 'armv8_32': 'arm64', 'armv8.3': 'arm64', 'sparc': 'sparc', 'sparcv9': 'sparc64', 'mips': 'mips', 'mips64': 'mips64', 'avr': 'avr', 's390': 's390x', 's390x': 's390x', 'sh4le': 'sh' } const platformMap = { 'Windows': 'windows', 'WindowsStore': 'windows', 'WindowsCE': 'windows', 'Linux': 'linux', 'Macos': 'macos', 'Android': 'android', 'iOS': 'ios', 'watchOS': 'watchos', 'tvOS': 'tvos', 'FreeBSD': 'freebsd', 'SunOS': 'solaris', 'AIX': 'aix', 'Emscripten': undefined, 'Arduino': 'none', 'Neutrino': 'qnx', 'VxWorks': 'vxworks', } function findLibs(libnames, libdirs, libtypes, targetOS, forImport) { var result = []; if (libnames === null || libdirs === null) return result; libnames.forEach(function(libraryName) { const suffixes = PathTools.librarySuffixes(targetOS, libtypes, forImport); const lib = PathProbe.configure( undefined, // selectors [libraryName], suffixes, PathTools.libraryNameFilter(), undefined, // candidateFilter libdirs, // searchPaths undefined, // pathSuffixes [], // platformSearchPaths undefined, // environmentPaths undefined // platformEnvironmentPaths ); if (lib.found) result.push(lib.files[0].filePath); }); return result; } function getLibraryTypes(options) { if (options !== undefined && options !== null) { if (options.shared === undefined) return ["shared", "static"]; else if (options.shared === "True") return ["shared"]; else if (options.shared === "False") return ["static"]; } return ["shared", "static"]; } function configure(installDirectory, moduleName, outputBaseDir, jsonProbe) { const moduleMapping = {"protobuflib": "protobuf"} const realModuleName = moduleMapping[moduleName] || moduleName; const moduleFilePath = FileInfo.joinPaths(installDirectory, "conan-qbs-deps", realModuleName + ".json") if (!File.exists(moduleFilePath)) return []; var reverseMapping = {} for (var key in moduleMapping) reverseMapping[moduleMapping[key]] = key console.info("Setting up Conan module '" + moduleName + "'"); var moduleFile = new TextFile(moduleFilePath, TextFile.ReadOnly); const moduleInfo = JSON.parse(moduleFile.readAll()); const outputDir = FileInfo.joinPaths(outputBaseDir, "modules", moduleName.replace(".", "/")); File.makePath(outputDir); const outputFilePath = FileInfo.joinPaths(outputDir, "module.qbs"); const cppInfo = moduleInfo.cpp_info; var moduleContent = ""; // function write(data) { moduleContent = moduleContent + data } function writeLine(data) { moduleContent = moduleContent + data + "\n"; } function writeProperty(propertyName, propertyValue) { if (propertyValue === undefined || propertyValue === null) propertyValue = []; writeLine(" readonly property stringList " + propertyName + ": " + ModUtils.toJSLiteral(propertyValue)); } function writeCppProperty(propertyName, propertyValue) { writeProperty(propertyName, propertyValue); // skip empty props for simplicity of the module file if (propertyValue !== undefined && propertyValue != null && propertyValue.length !== 0) { writeLine(" cpp." + propertyName + ": " + propertyName); } } writeLine("Module {"); writeLine(" version: " + ModUtils.toJSLiteral(moduleInfo.version)); const architecture = architectureMap[moduleInfo.settings.arch]; const platform = platformMap[moduleInfo.settings.os]; const targetOS = Utilities.canonicalPlatform(platform); writeLine(" readonly property string architecture: " + ModUtils.toJSLiteral(architecture)); if (platform !== undefined) writeLine(" readonly property string platform: " + ModUtils.toJSLiteral(platform)); writeLine(" condition: true"); if (architecture !== undefined) { writeLine(" && (!qbs.architecture || qbs.architecture === architecture)"); } if (platform !== undefined) { if (["ios", "tvos", "watchos"].includes(platform)) { writeLine(" && (qbs.targetPlatform === platform || qbs.targetPlatform === platform + \"-simulator\")"); } else { writeLine(" && qbs.targetPlatform === platform"); } } writeLine(" Depends { name: 'cpp' }"); moduleInfo.dependencies.forEach(function(dep) { const realDepName = reverseMapping[dep.name] || dep.name; writeLine(" Depends { name: " + ModUtils.toJSLiteral(realDepName) + "; version: " + ModUtils.toJSLiteral(dep.version) + "}"); }); const buildBindirs = FileInfo.fromNativeSeparators(moduleInfo.build_bindirs); writeLine(" readonly property stringList hostBinDirs: (" + ModUtils.toJSLiteral(buildBindirs) + ")"); const targetBindirs = FileInfo.fromNativeSeparators(cppInfo.bindirs); writeLine(" readonly property stringList binDirs: (" + ModUtils.toJSLiteral(targetBindirs) + ")"); // TODO: there's a weird issue with system include dirs with xcode-less clang - incorrect include order? writeCppProperty("includePaths", FileInfo.fromNativeSeparators(cppInfo.includedirs)); writeCppProperty("frameworkPaths", FileInfo.fromNativeSeparators(cppInfo.frameworkdirs)); writeCppProperty("frameworks", cppInfo.frameworks); writeCppProperty("defines", cppInfo.defines); writeCppProperty("cFlags", cppInfo.cflags); writeCppProperty("cxxFlags", cppInfo.cxxflags); writeCppProperty("linkerFlags", (cppInfo.sharedlinkflags || []).concat(cppInfo.exelinkflags || [])); writeProperty("resources", FileInfo.fromNativeSeparators(cppInfo.resdirs)); const isForImport = targetOS.includes("windows") const libraryTypes = getLibraryTypes(moduleInfo.options); libraryTypes.forEach(function(libraryType){ const cppInfoLibs = cppInfo.libs === null ? [] : cppInfo.libs; const libdirs = FileInfo.fromNativeSeparators(cppInfo.libdirs); const libs = findLibs(cppInfoLibs, libdirs, libraryType, targetOS, isForImport) .concat(cppInfo.system_libs === null ? [] : cppInfo.system_libs); const property = libraryType === "shared" ? "dynamicLibraries" : "staticLibraries"; writeCppProperty(property, libs); }); writeLine("}"); var moduleFile = new TextFile(outputFilePath, TextFile.WriteOnly); moduleFile.write(moduleContent); moduleFile.close(); return ""; } qbs-src-2.6.1/share/qbs/module-providers/qbspkgconfig.qbs0000644000175100001660000002123614776170045023027 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.Environment import qbs.File import qbs.FileInfo import qbs.Host import qbs.ModUtils import qbs.PkgConfig import qbs.ProviderUtils import qbs.Probes import qbs.Process import qbs.TextFile import "Qt/setup-qt.js" as SetupQt ModuleProvider { property stringList executableNames: ["pkgconf", "pkg-config"] property string executableFilePath: pkgConfigProbe.filePath property stringList extraPaths property stringList libDirs property bool staticMode: false property bool definePrefix: Host.os().includes("windows") // We take the sysroot default from qbs.sysroot, except for Xcode toolchains, where // the sysroot points into the Xcode installation and does not contain .pc files. property path sysroot: qbs.toolchain && qbs.toolchain.includes("xcode") ? undefined : qbs.sysroot Probes.BinaryProbe { id: pkgConfigProbe condition: !executableFilePath names: executableNames } Probes.QbsPkgConfigProbe { id: theProbe _executableFilePath: executableFilePath _extraPaths: extraPaths _sysroot: sysroot _libDirs: libDirs _staticMode: staticMode _definePrefix: definePrefix } Probes.QmakeProbe { id: qmakeProbe condition: moduleName.startsWith("Qt") && theProbe.qmakePaths qmakePaths: theProbe.qmakePaths } isEager: false relativeSearchPaths: { function getModuleInfo(pkg, staticMode) { var result = {}; var mapper = function(flag) { return flag.value; } var typeFilter = function(type) { return function(flag) { return flag.type === type; } } function getLibsInfo(libs) { var result = {}; result.dynamicLibraries = libs.filter(typeFilter(PkgConfig.LibraryName)).map(mapper); result.staticLibraries = libs.filter(typeFilter(PkgConfig.StaticLibraryName)).map(mapper); result.libraryPaths = libs.filter(typeFilter(PkgConfig.LibraryPath)).map(mapper); result.frameworks = libs.filter(typeFilter(PkgConfig.Framework)).map(mapper); result.frameworkPaths = libs.filter(typeFilter(PkgConfig.FrameworkPath)).map(mapper); result.driverLinkerFlags = libs.filter(typeFilter(PkgConfig.LinkerFlag)).map(mapper); return result; } result.version = pkg.version; result.includePaths = pkg.cflags.filter(typeFilter(PkgConfig.IncludePath)).map(mapper); result.systemIncludePaths = pkg.cflags.filter(typeFilter(PkgConfig.SystemIncludePath)).map(mapper); result.defines = pkg.cflags.filter(typeFilter(PkgConfig.Define)).map(mapper); result.commonCompilerFlags = pkg.cflags.filter(typeFilter(PkgConfig.CompilerFlag)).map(mapper); var allLibs = pkg.libs; if (staticMode) allLibs = allLibs.concat(pkg.libsPrivate); var libsInfo = getLibsInfo(allLibs); for (var key in libsInfo) { result[key] = libsInfo[key]; } return result; } function getModuleDependencies(pkg, staticMode) { var mapper = function(p) { var result = {}; for (var key in p) result[key] = p[key]; result.name = ProviderUtils.pkgConfigToModuleName(result.name); return result; } var result = pkg.requires.map(mapper); if (staticMode) result = result.concat(pkg.requiresPrivate.map(mapper)); return result; } console.debug("Running pkgconfig provider for " + moduleName + "."); var outputDir = FileInfo.joinPaths(outputBaseDir, "modules"); File.makePath(outputDir); var moduleMapping = { "protobuf": "protobuflib" } var reverseMapping = {} for (var key in moduleMapping) reverseMapping[moduleMapping[key]] = key if (moduleName.startsWith("Qt")) { function setupQt(packageName, qtInfos) { if (qtInfos === undefined || qtInfos.length === 0) return []; var qtProviderDir = FileInfo.joinPaths(path, "Qt"); return SetupQt.doSetup(packageName, qtInfos, outputBaseDir, qtProviderDir); } if (!sysroot) { return setupQt(moduleName, qmakeProbe.qtInfos); } return []; } var pkg; pkg = theProbe.packages[reverseMapping[moduleName]]; if (pkg === undefined) pkg = theProbe.packagesByModuleName[moduleName]; if (pkg === undefined) return []; if (pkg.isBroken) { console.warn("Failed to load " + moduleName + " as it's pkg-config package is broken"); return []; } var moduleInfo = getModuleInfo(pkg, staticMode); var deps = getModuleDependencies(pkg, staticMode); var moduleDir = FileInfo.joinPaths(outputDir, moduleName); File.makePath(moduleDir); var module = new TextFile(FileInfo.joinPaths(moduleDir, "module.qbs"), TextFile.WriteOnly); module.writeLine("Module {"); module.writeLine(" version: " + ModUtils.toJSLiteral(moduleInfo.version)); module.writeLine(" Depends { name: 'cpp' }"); deps.forEach(function(dep) { var depName = ProviderUtils.pkgConfigToModuleName( moduleMapping[dep.name] ? moduleMapping[dep.name] : dep.name); module.write(" Depends { name: '" + depName + "'"); for (var k in dep) { if (k === "name") continue; module.write("; " + k + ": " + ModUtils.toJSLiteral(dep[k])); } module.writeLine(" }"); }) function writeProperty(propertyName) { var value = moduleInfo[propertyName]; if (value.length !== 0) { // skip empty props for simplicity of the module file module.writeLine( " cpp." + propertyName + ":" + ModUtils.toJSLiteral(value)); } } writeProperty("includePaths"); writeProperty("systemIncludePaths"); writeProperty("defines"); writeProperty("commonCompilerFlags"); writeProperty("dynamicLibraries"); writeProperty("staticLibraries"); writeProperty("libraryPaths"); writeProperty("frameworks"); writeProperty("frameworkPaths"); writeProperty("driverLinkerFlags"); module.writeLine("}"); module.close(); return ""; } } qbs-src-2.6.1/share/qbs/module-providers/conan.qbs0000644000175100001660000000036114776170045021444 0ustar runnerdockerimport "conan.js" as ConanHelper ModuleProvider { /* input */ property path installDirectory isEager: false relativeSearchPaths: { return ConanHelper.configure(installDirectory, moduleName, outputBaseDir); } } qbs-src-2.6.1/share/qbs/module-providers/__fallback/0000755000175100001660000000000014776170045021674 5ustar runnerdockerqbs-src-2.6.1/share/qbs/module-providers/__fallback/provider.qbs0000644000175100001660000000453714776170045024246 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.File import qbs.FileInfo ModuleProvider { relativeSearchPaths: { console.debug("Running fallback provider for module '" + name + "'."); var inputFilePath = FileInfo.joinPaths(path, "fallback.qbs"); var outputDir = FileInfo.joinPaths(outputBaseDir, "modules", name.replace(".", "/")); File.makePath(outputDir); var outputFilePath = FileInfo.joinPaths(outputDir, name + ".qbs"); File.copy(inputFilePath, outputFilePath); return ""; } } qbs-src-2.6.1/share/qbs/module-providers/__fallback/fallback.qbs0000644000175100001660000000606514776170045024151 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.FileInfo import qbs.Probes Module { Depends { name: "cpp" } Depends { name: "pkgconfig"; required: false } property string theName: FileInfo.completeBaseName(filePath) readonly property bool __fallback: true // Hack, please look away Probes.PkgConfigProbe { id: pkgConfigProbe condition: pkgconfig.present sysroot: pkgconfig.sysroot name: theName executable: pkgconfig.executableFilePath libDirs: pkgconfig.libDirs forStaticBuild: pkgconfig.staticMode } Properties { condition: pkgConfigProbe.found version: pkgConfigProbe.modversion cpp.dynamicLibraries: pkgConfigProbe.libraries cpp.libraryPaths: pkgConfigProbe.libraryPaths cpp.includePaths: pkgConfigProbe.includePaths cpp.defines: pkgConfigProbe.defines cpp.driverLinkerFlags: pkgConfigProbe.linkerFlags cpp.commonCompilerFlags: pkgConfigProbe.compilerFlags } validate: { if (!pkgConfigProbe.found) { throw "Dependency '" + theName + "' not found for product '" + product.name + "'. " + "Locating a package of this name via pkg-config also failed."; } } } qbs-src-2.6.1/share/qbs/module-providers/Qt/0000755000175100001660000000000014776170045020223 5ustar runnerdockerqbs-src-2.6.1/share/qbs/module-providers/Qt/provider.qbs0000644000175100001660000000065014776170045022565 0ustar runnerdockerimport "setup-qt.js" as SetupQt import qbs.Probes ModuleProvider { Probes.QmakeProbe { condition: moduleName.startsWith("Qt.") id: probe qmakePaths: qmakeFilePaths } property stringList qmakeFilePaths readonly property varList _qtInfos: probe.qtInfos condition: probe.found isEager: false relativeSearchPaths: SetupQt.doSetup(moduleName, _qtInfos, outputBaseDir, path) } qbs-src-2.6.1/share/qbs/module-providers/Qt/setup-qt.js0000644000175100001660000005562614776170045022361 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); var ProviderUtils = require("qbs.ProviderUtils"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function extractQbsArchs(module, qtProps) { if (qtProps.mkspecName.startsWith("macx-")) { var archs = []; if (module.libFilePathRelease) archs = Utilities.getArchitecturesFromBinary(module.libFilePathRelease); return archs; } var qbsArch = Utilities.canonicalArchitecture(qtProps.architecture); if (qbsArch === "arm" && qtProps.mkspecPath.contains("android")) qbsArch = "armv7a"; // Qt4 has "QT_ARCH = windows" in qconfig.pri for both MSVC and mingw. if (qbsArch === "windows") return [] return [qbsArch]; } function qbsTargetPlatformFromQtMkspec(qtProps) { var mkspec = qtProps.mkspecName; var idx = mkspec.lastIndexOf('/'); if (idx !== -1) mkspec = mkspec.slice(idx + 1); if (mkspec.startsWith("aix-")) return "aix"; if (mkspec.startsWith("android-")) return "android"; if (mkspec.startsWith("cygwin-")) return "windows"; if (mkspec.startsWith("darwin-")) return "macos"; if (mkspec.startsWith("freebsd-")) return "freebsd"; if (mkspec.startsWith("haiku-")) return "haiku"; if (mkspec.startsWith(("hpux-")) || mkspec.startsWith(("hpuxi-"))) return "hpux"; if (mkspec.startsWith("hurd-")) return "hurd"; if (mkspec.startsWith("integrity-")) return "integrity"; if (mkspec.startsWith("linux-")) return "linux"; if (mkspec.startsWith("macx-")) { if (mkspec.startsWith("macx-ios-")) return "ios"; if (mkspec.startsWith("macx-tvos-")) return "tvos"; if (mkspec.startsWith("macx-watchos-")) return "watchos"; return "macos"; } if (mkspec.startsWith("netbsd-")) return "netbsd"; if (mkspec.startsWith("openbsd-")) return "openbsd"; if (mkspec.startsWith("qnx-")) return "qnx"; if (mkspec.startsWith("solaris-")) return "solaris"; if (mkspec.startsWith("vxworks-")) return "vxworks"; if (ProviderUtils.isDesktopWindowsQt(qtProps) || mkspec.startsWith("winrt-")) return "windows"; if (mkspec.startsWith("wasm-")) return "wasm-emscripten"; } function pathToJSLiteral(path) { return JSON.stringify(FileInfo.fromNativeSeparators(path)); } function defaultQpaPlugin(module, qtProps) { if (qtProps.qtMajorVersion < 5) return undefined; function findInPriFile(filePath) { var priFile = new TextFile(filePath); var magicString = "QT_DEFAULT_QPA_PLUGIN ="; while (!priFile.atEof()) { var line = priFile.readLine().trim(); if (line.startsWith(magicString)) return line.slice(magicString.length).trim(); } }; if (qtProps.qtMajorVersion === 5 && qtProps.qtMinorVersion < 8) { var pluginName = findInPriFile(FileInfo.joinPaths(qtProps.mkspecBasePath, "qconfig.pri")); if (pluginName) return pluginName; } else { pluginName = findInPriFile(FileInfo.joinPaths(qtProps.mkspecBasePath, "modules", "qt_lib_gui.pri")); if (pluginName) return pluginName; var gtGuiHeadersPath = qtProps.frameworkBuild ? FileInfo.joinPaths(qtProps.libraryPath, "QtGui.framework", "Headers") : FileInfo.joinPaths(qtProps.includePath, "QtGui"); var qtGuiConfigHeader = FileInfo.joinPaths(gtGuiHeadersPath, "qtgui-config.h"); var headerFiles = []; headerFiles.push(qtGuiConfigHeader); while (headerFiles.length > 0) { var filePath = headerFiles.shift(); var headerFile = new TextFile(filePath, TextFile.ReadOnly); var regexp = /^#define QT_QPA_DEFAULT_PLATFORM_NAME "(.+)".*$/; var includeRegexp = /^#include "(.+)".*$/; while (!headerFile.atEof()) { var line = headerFile.readLine().trim(); var match = line.match(regexp); if (match) return 'q' + match[1]; match = line.match(includeRegexp); if (match) { var includedFile = match[1]; if (!FileInfo.isAbsolutePath(includedFile)) { includedFile = FileInfo.cleanPath( FileInfo.joinPaths(FileInfo.path(filePath), includedFile)); } headerFiles.push(includedFile); } } headerFile.close(); } } if (module.isStaticLibrary) console.warn("Could not determine default QPA plugin for static Qt."); } function libraryFileTag(module, qtProps) { if (module.isStaticLibrary) return "staticlibrary"; return ProviderUtils.isMsvcQt(qtProps) || qtProps.mkspecName.startsWith("win32-g++") ? "dynamiclibrary_import" : "dynamiclibrary"; } function findVariable(content, start) { var result = [-1, -1]; result[0] = content.indexOf('@', start); if (result[0] === -1) return result; result[1] = content.indexOf('@', result[0] + 1); if (result[1] === -1) { result[0] = -1; return result; } var forbiddenChars = [' ', '\n']; for (var i = 0; i < forbiddenChars.length; ++i) { var forbidden = forbiddenChars[i]; var k = content.indexOf(forbidden, result[0] + 1); if (k !== -1 && k < result[1]) return findVariable(content, result[0] + 1); } return result; } function minVersionJsString(minVersion) { return !minVersion ? "" : ModUtils.toJSLiteral(minVersion); } function abiToArchitecture(abi) { switch (abi) { case "armeabi-v7a": return "armv7a"; case "arm64-v8a": return "arm64"; case "x86": case "x86_64": default: return abi; } } function replaceSpecialValues(content, module, qtProps, abi) { var architectures = []; if (abi.length > 0) architectures.push(abiToArchitecture(abi)); else architectures = extractQbsArchs(module, qtProps); var dict = { archs: ModUtils.toJSLiteral(architectures), targetPlatform: ModUtils.toJSLiteral(qbsTargetPlatformFromQtMkspec(qtProps)), config: ModUtils.toJSLiteral(qtProps.configItems), qtConfig: ModUtils.toJSLiteral(qtProps.qtConfigItems), enabledFeatures: ModUtils.toJSLiteral(qtProps.enabledFeatures), disabledFeatures: ModUtils.toJSLiteral(qtProps.disabledFeatures), binPath: ModUtils.toJSLiteral(qtProps.binaryPath), installPath: ModUtils.toJSLiteral(qtProps.installPath), installPrefixPath: ModUtils.toJSLiteral(qtProps.installPrefixPath), libPath: ModUtils.toJSLiteral(qtProps.libraryPath), libExecPath: ModUtils.toJSLiteral(qtProps.libExecPath), qmlLibExecPath: ModUtils.toJSLiteral(qtProps.qmlLibExecPath), pluginPath: ModUtils.toJSLiteral(qtProps.pluginPath), incPath: ModUtils.toJSLiteral(qtProps.includePath), docPath: ModUtils.toJSLiteral(qtProps.documentationPath), translationsPath: ModUtils.toJSLiteral(qtProps.translationsPath), helpGeneratorLibExecPath: ModUtils.toJSLiteral(qtProps.helpGeneratorLibExecPath), mkspecName: ModUtils.toJSLiteral(qtProps.mkspecName), mkspecPath: ModUtils.toJSLiteral(qtProps.mkspecPath), version: ModUtils.toJSLiteral(qtProps.qtVersion), libInfix: ModUtils.toJSLiteral(qtProps.qtLibInfix), availableBuildVariants: ModUtils.toJSLiteral(qtProps.buildVariant), staticBuild: ModUtils.toJSLiteral(qtProps.staticBuild), multiThreading: ModUtils.toJSLiteral(qtProps.multiThreading), frameworkBuild: ModUtils.toJSLiteral(qtProps.frameworkBuild), name: ModUtils.toJSLiteral(ProviderUtils.qtModuleNameWithoutPrefix(module)), has_library: ModUtils.toJSLiteral(module.hasLibrary), dependencies: ModUtils.toJSLiteral(module.dependencies), includes: ModUtils.toJSLiteral(module.includePaths), staticLibsDebug: ModUtils.toJSLiteral(module.staticLibrariesDebug), staticLibsRelease: ModUtils.toJSLiteral(module.staticLibrariesRelease), dynamicLibsDebug: ModUtils.toJSLiteral(module.dynamicLibrariesDebug), dynamicLibsRelease: ModUtils.toJSLiteral(module.dynamicLibrariesRelease), linkerFlagsDebug: ModUtils.toJSLiteral(module.linkerFlagsDebug), linkerFlagsRelease: ModUtils.toJSLiteral(module.linkerFlagsRelease), libraryPaths: ModUtils.toJSLiteral(module.libraryPaths), frameworkPathsDebug: ModUtils.toJSLiteral(module.frameworkPathsDebug), frameworkPathsRelease: ModUtils.toJSLiteral(module.frameworkPathsRelease), frameworksDebug: ModUtils.toJSLiteral(module.frameworksDebug), frameworksRelease: ModUtils.toJSLiteral(module.frameworksRelease), libFilePathDebug: ModUtils.toJSLiteral(module.libFilePathDebug), libFilePathRelease: ModUtils.toJSLiteral(module.libFilePathRelease), libNameForLinkerDebug: ModUtils.toJSLiteral(ProviderUtils.qtLibNameForLinker(module, qtProps, true)), pluginTypes: ModUtils.toJSLiteral(module.supportedPluginTypes), moduleConfig: ModUtils.toJSLiteral(module.config), libNameForLinkerRelease: ModUtils.toJSLiteral(ProviderUtils.qtLibNameForLinker(module, qtProps, false)), entryPointLibsDebug: ModUtils.toJSLiteral(qtProps.entryPointLibsDebug), entryPointLibsRelease: ModUtils.toJSLiteral(qtProps.entryPointLibsRelease), minWinVersion_optional: minVersionJsString(qtProps.windowsVersion), minMacVersion_optional: minVersionJsString(qtProps.macosVersion), minIosVersion_optional: minVersionJsString(qtProps.iosVersion), minTvosVersion_optional: minVersionJsString(qtProps.tvosVersion), minWatchosVersion_optional: minVersionJsString(qtProps.watchosVersion), minAndroidVersion_optional: minVersionJsString(qtProps.androidVersion), }; var additionalContent = ""; var compilerDefines = ModUtils.toJSLiteral(module.compilerDefines); if (module.qbsName === "declarative" || module.qbsName === "quick") { var debugMacro = module.qbsName === "declarative" || qtProps.qtMajorVersion < 5 ? "QT_DECLARATIVE_DEBUG" : "QT_QML_DEBUG"; var indent = " "; additionalContent = "property bool qmlDebugging: false\n" + indent + "property string qmlPath"; if (qtProps.qmlPath) additionalContent += ": " + pathToJSLiteral(qtProps.qmlPath) + '\n'; else additionalContent += '\n'; additionalContent += indent + "property string qmlImportsPath: " + pathToJSLiteral(qtProps.qmlImportPath); compilerDefines = "{\n" + indent + indent + "var result = " + compilerDefines + ";\n" + indent + indent + "if (qmlDebugging)\n" + indent + indent + indent + "result.push(\"" + debugMacro + "\");\n" + indent + indent + "return result;\n" + indent + "}"; } dict.defines = compilerDefines; if (module.qbsName === "gui") dict.defaultQpaPlugin = ModUtils.toJSLiteral(defaultQpaPlugin(module, qtProps)); if (module.qbsName === "qml") dict.qmlPath = pathToJSLiteral(qtProps.qmlPath); if (module.isStaticLibrary && module.qbsName !== "core") { if (additionalContent) additionalContent += "\n "; additionalContent += "isStaticLibrary: true"; } if (module.isPlugin) { dict.className = ModUtils.toJSLiteral(module.pluginData.className); dict["extends"] = ModUtils.toJSLiteral(module.pluginData["extends"]); } indent = " "; var metaTypesFile = qtProps.libraryPath + "/metatypes/qt" + qtProps.qtMajorVersion + module.qbsName + "_metatypes.json"; if (File.exists(metaTypesFile)) { if (additionalContent) additionalContent += "\n" + indent; additionalContent += "Group {\n"; additionalContent += indent + indent + "files: " + JSON.stringify(metaTypesFile) + "\n" + indent + indent + "filesAreTargets: true\n" + indent + indent + "fileTags: [\"qt.core.metatypes\"]\n" + indent + "}"; } if (module.hasLibrary && !ProviderUtils.qtIsFramework(module, qtProps)) { if (additionalContent) additionalContent += "\n" + indent; additionalContent += "Group {\n"; if (module.isPlugin) { additionalContent += indent + indent + "condition: enableLinking\n"; } additionalContent += indent + indent + "files: libFilePath\n" + indent + indent + "filesAreTargets: true\n" + indent + indent + "fileTags: [\"" + libraryFileTag(module, qtProps) + "\"]\n" + indent + "}"; } dict.additionalContent = additionalContent; for (var pos = findVariable(content, 0); pos[0] !== -1; pos = findVariable(content, pos[0])) { var varName = content.slice(pos[0] + 1, pos[1]); var replacement = dict[varName] || ""; if (!replacement && varName.endsWith("_optional")) { var prevNewline = content.lastIndexOf('\n', pos[0]); if (prevNewline === -1) prevNewline = 0; var nextNewline = content.indexOf('\n', pos[0]); if (nextNewline === -1) prevNewline = content.length; content = content.slice(0, prevNewline) + content.slice(nextNewline); pos[0] = prevNewline; } else { content = content.slice(0, pos[0]) + replacement + content.slice(pos[1] + 1); pos[0] += replacement.length; } } return content; } function copyTemplateFile(fileName, targetDirectory, qtProps, abi, location, allFiles, module, pluginMap, nonEssentialPlugins) { if (!File.makePath(targetDirectory)) { throw "Cannot create directory '" + FileInfo.toNativeSeparators(targetDirectory) + "'."; } var sourceFile = new TextFile(FileInfo.joinPaths(location, "templates", fileName), TextFile.ReadOnly); var newContent = sourceFile.readAll(); if (module) { newContent = replaceSpecialValues(newContent, module, qtProps, abi); } else { newContent = newContent.replace("@allPluginsByType@", '(' + ModUtils.toJSLiteral(pluginMap) + ')'); newContent = newContent.replace("@nonEssentialPlugins@", ModUtils.toJSLiteral(nonEssentialPlugins)); newContent = newContent.replace("@version@", ModUtils.toJSLiteral(qtProps.qtVersion)); } sourceFile.close(); var targetPath = FileInfo.joinPaths(targetDirectory, fileName); allFiles.push(targetPath); var targetFile = new TextFile(targetPath, TextFile.WriteOnly); targetFile.write(newContent); targetFile.close(); } function setupOneQt(moduleName, qtInfo, outputBaseDir, uniquify, location) { var qtProps = qtInfo.qtProps; var relativeSearchPaths = []; for (a = 0; a < qtInfo.abiInfos.length; ++a) { var abiInfo = qtInfo.abiInfos[a]; var androidAbi = abiInfo.androidAbi; if (qtInfo.abiInfos.length > 1) console.info("Configuring abi '" + androidAbi + "'..."); var relativeSearchPath = uniquify ? Utilities.getHash(qtInfo.qmakeFilePath) : ""; relativeSearchPath = FileInfo.joinPaths(relativeSearchPath, androidAbi); var qbsQtModuleBaseDir = FileInfo.joinPaths(outputBaseDir, relativeSearchPath, "modules", "Qt"); // TODO: // if (File.exists(qbsQtModuleBaseDir)) // File.remove(qbsQtModuleBaseDir); var allFiles = []; if (moduleName === "plugin_support") { copyTemplateFile("plugin_support.qbs", FileInfo.joinPaths(qbsQtModuleBaseDir, "plugin_support"), qtProps, androidAbi, location, allFiles, undefined, abiInfo.pluginsByType, abiInfo.nonEssentialPlugins); relativeSearchPaths.push(relativeSearchPath); return relativeSearchPaths; } else if (moduleName === "android_support") { // Note that it's not strictly necessary to copy this one, as it has no variable content. // But we do it anyway for consistency. copyTemplateFile("android_support.qbs", FileInfo.joinPaths(qbsQtModuleBaseDir, "android_support"), qtProps, androidAbi, location, allFiles); copyTemplateFile("android_support.js", FileInfo.joinPaths(qbsQtModuleBaseDir, "android_support"), qtProps, androidAbi, location, allFiles); relativeSearchPaths.push(relativeSearchPath); return relativeSearchPaths; } else if (moduleName === "qmlcache") { var qmlcacheStr = "qmlcache"; if (File.exists(FileInfo.joinPaths(qtProps.qmlLibExecPath, "qmlcachegen" + FileInfo.executableSuffix()))) { copyTemplateFile(qmlcacheStr + ".qbs", FileInfo.joinPaths(qbsQtModuleBaseDir, qmlcacheStr), qtProps, androidAbi, location, allFiles); } relativeSearchPaths.push(relativeSearchPath); return relativeSearchPaths; } if (abiInfo.modules[moduleName] !== undefined) { var module = abiInfo.modules[moduleName]; var qbsQtModuleDir = FileInfo.joinPaths(qbsQtModuleBaseDir, module.qbsName); var moduleTemplateFileName; if (module.qbsName === "core") { moduleTemplateFileName = "core.qbs"; copyTemplateFile("core.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); copyTemplateFile("moc.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); copyTemplateFile("qdoc.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); copyTemplateFile("rcc.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); } else if (module.qbsName === "gui") { moduleTemplateFileName = "gui.qbs"; } else if (module.qbsName === "scxml") { moduleTemplateFileName = "scxml.qbs"; } else if (module.qbsName === "dbus") { moduleTemplateFileName = "dbus.qbs"; copyTemplateFile("dbus.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); } else if (module.qbsName === "qml") { moduleTemplateFileName = "qml.qbs"; copyTemplateFile("qml.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); } else if (module.qbsName === "quick") { moduleTemplateFileName = "quick.qbs"; copyTemplateFile("quick.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); copyTemplateFile("rcc.js", qbsQtModuleDir, qtProps, androidAbi, location, allFiles); } else if (module.isPlugin) { moduleTemplateFileName = "plugin.qbs"; } else { moduleTemplateFileName = "module.qbs"; } copyTemplateFile(moduleTemplateFileName, qbsQtModuleDir, qtProps, androidAbi, location, allFiles, module); relativeSearchPaths.push(relativeSearchPath); } } return relativeSearchPaths; } function doSetup(moduleName, qtInfos, outputBaseDir, location) { if (!qtInfos || qtInfos.length === 0) return []; var uniquifySearchPath = qtInfos.length > 1; var allSearchPaths = []; moduleName = moduleName.substring(3); for (var i = 0; i < qtInfos.length; ++i) { try { console.info("Setting up Qt module '" + moduleName + "' for Qt located at '" + FileInfo.toNativeSeparators(qtInfos[i].qmakeFilePath) + "'."); var searchPaths = setupOneQt(moduleName, qtInfos[i], outputBaseDir, uniquifySearchPath, location); if (searchPaths.length > 0) { for (var j = 0; j < searchPaths.length; ++j ) allSearchPaths.push(searchPaths[j]); } } catch (e) { console.warn("Error setting up Qt module '" + moduleName + "' for '" + FileInfo.toNativeSeparators(qtInfos[i].qmakeFilePath) + "': " + e); throw e; } } return allSearchPaths; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/0000755000175100001660000000000014776170045022221 5ustar runnerdockerqbs-src-2.6.1/share/qbs/module-providers/Qt/templates/plugin.qbs0000644000175100001660000000163414776170045024232 0ustar runnerdockerQtPlugin { qtModuleName: @name@ Depends { name: "Qt"; submodules: @dependencies@} version: @version@ className: @className@ architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ cpp.libraryPaths: @libraryPaths@ extendsModules: @extends@ @additionalContent@ } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/qmlcache.qbs0000644000175100001660000000563014776170045024511 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Process import qbs.Utilities Module { additionalProductTypes: ["qt.qml.qmlc", "qt.qml.jsc"] validate: { if (!qmlcachegenProbe.found) throw "qmlcachegen unsupported for this target"; } property string qmlCacheGenPath: FileInfo.joinPaths(Qt.core.qmlLibExecPath, "qmlcachegen") + FileInfo.executableSuffix() property bool supportsAllArchitectures: Utilities.versionCompare(Qt.core.version, "5.11") >= 0 property string installDir readonly property stringList _targetArgs: { if (supportsAllArchitectures) return []; function translateArch(arch) { if (arch === "x86") return "i386"; if (arch.startsWith("armv")) return "arm"; return arch; } var args = ["--target-architecture", translateArch(qbs.architecture)]; return args; } Depends { name: "Qt.core" } Probe { id: qmlcachegenProbe property string arch: qbs.architecture property string _qmlCacheGenPath: qmlCacheGenPath property stringList targetArgs: _targetArgs property bool _supportsAllArchitectures: supportsAllArchitectures configure: { if (_supportsAllArchitectures) { found = File.exists(_qmlCacheGenPath); return; } var process = new Process(); found = false; try { found = process.exec(_qmlCacheGenPath, targetArgs.concat("--check-if-supported")) == 0; if (!found) { var msg = "QML cache generation was requested but is unsupported on " + "architecture '" + arch + "'."; console.warn(msg); } } finally { process.close(); } } } Rule { condition: qmlcachegenProbe.found inputs: ["qt.qml.qml", "qt.qml.js"] outputArtifacts: [{ filePath: input.fileName + 'c', fileTags: input.fileTags.filter(function(tag) { return tag === "qt.qml.qml" || tag === "qt.qml.js"; })[0] + 'c' }] outputFileTags: ["qt.qml.qmlc", "qt.qml.jsc"] prepare: { var args = input.Qt.qmlcache._targetArgs.concat(input.filePath, "-o", output.filePath); var cmd = new Command(input.Qt.qmlcache.qmlCacheGenPath, args); cmd.description = "precompiling " + input.fileName; cmd.highlight = "compiler"; return cmd; } } Group { condition: product.Qt.qmlcache.installDir !== undefined fileTagsFilter: product.Qt.qmlcache.additionalProductTypes qbs.install: true qbs.installDir: product.Qt.qmlcache.installDir } } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/dbus.js0000644000175100001660000000600414776170045023514 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); function outputFileName(input, suffix) { var parts = input.fileName.split('.').filter(function(s) { return s.length > 0; }); if (parts.length === 0) throw "Cannot run qdbusxml2cpp on '" + input.filePath + "': Unsuitable file name."; var outputBaseName = parts.length === 1 ? parts[0] : parts[parts.length - 2]; return outputBaseName.toLowerCase() + suffix; } function createCommands(product, input, outputs, option) { var exe = ModUtils.moduleProperty(product, "binPath") + '/' + ModUtils.moduleProperty(product, "xml2cppName"); var hppOutput = outputs["hpp"][0]; var hppArgs = ModUtils.moduleProperty(product, "xml2CppHeaderFlags"); hppArgs.push(option, hppOutput.fileName + ':', input.filePath); // Can't use filePath on Windows var hppCmd = new Command(exe, hppArgs) hppCmd.description = "qdbusxml2cpp " + input.fileName + " -> " + hppOutput.fileName; hppCmd.highlight = "codegen"; hppCmd.workingDirectory = FileInfo.path(hppOutput.filePath); var cppOutput = outputs["cpp"][0]; var cppArgs = ModUtils.moduleProperty(product, "xml2CppSourceFlags"); cppArgs.push("-i", hppOutput.filePath, option, ':' + cppOutput.fileName, input.filePath); var cppCmd = new Command(exe, cppArgs) cppCmd.description = "qdbusxml2cpp " + input.fileName + " -> " + cppOutput.fileName; cppCmd.highlight = "codegen"; cppCmd.workingDirectory = FileInfo.path(cppOutput.filePath); return [hppCmd, cppCmd]; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/rcc.js0000644000175100001660000001005214776170045023324 0ustar runnerdockervar FileInfo = require("qbs.FileInfo"); var Utilities = require("qbs.Utilities"); var Xml = require("qbs.Xml"); function fullPath(product) { if (Utilities.versionCompare(product.Qt.core.version, "6.1") < 0) return product.Qt.core.binPath + '/' + product.Qt.core.rccName; return product.Qt.core.libExecPath + '/' + product.Qt.core.rccName; } function generateQrcFileCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var doc = new Xml.DomDocument("RCC"); var rccNode = doc.createElement("RCC"); rccNode.setAttribute("version", "1.0"); doc.appendChild(rccNode); var inputsByPrefix = {} for (var i = 0; i < inputs["qt.core.resource_data"].length; ++i) { var inp = inputs["qt.core.resource_data"][i]; var prefix = inp.Qt.core.resourcePrefix; var inputsList = inputsByPrefix[prefix] || []; inputsList.push(inp); inputsByPrefix[prefix] = inputsList; } for (var prefix in inputsByPrefix) { var qresourceNode = doc.createElement("qresource"); qresourceNode.setAttribute("prefix", prefix); rccNode.appendChild(qresourceNode); for (var i = 0; i < inputsByPrefix[prefix].length; ++i) { var inp = inputsByPrefix[prefix][i]; var fullResPath = inp.filePath; var baseDir = inp.Qt.core.resourceSourceBase; var resAlias = baseDir ? FileInfo.relativePath(baseDir, fullResPath) : inp.fileName; var fileNode = doc.createElement("file"); fileNode.setAttribute("alias", resAlias); qresourceNode.appendChild(fileNode); var fileTextNode = doc.createTextNode(fullResPath); fileNode.appendChild(fileTextNode); } } doc.save(output.filePath, 4); }; return [cmd]; } function rccOutputArtifacts(input) { var artifact = { filePath: "qrc_" + input.completeBaseName + ".cpp", fileTags: ["cpp"] }; if (input.Qt.core.enableBigResources) artifact.fileTags.push("cpp_intermediate_object"); return [artifact]; } function rccCommands(product, input, output) { var args = [input.filePath, "-name", FileInfo.completeBaseName(input.filePath), "-o", output.filePath]; if (input.Qt.core.enableBigResources) args.push("-pass", "1"); if (product.Qt.core.disabledFeatures.contains("zstd") && Utilities.versionCompare(product.Qt.core.version, "5.13") >= 0) { args.push("--no-zstd"); } var cmd = new Command(fullPath(product), args); cmd.description = "rcc " + (input.Qt.core.enableBigResources ? "(pass 1) " : "") + input.fileName; cmd.highlight = 'codegen'; return cmd; } function rccPass2Commands(product, input, output) { function findChild(artifact, predicate) { var children = artifact.children; var len = children.length; for (var i = 0; i < len; ++i) { var child = children[i]; if (predicate(child)) return child; child = findChild(child, predicate); if (child) return child; } return undefined; } var qrcArtifact = findChild(input, function(c) { return c.fileTags.contains("qrc"); }); var cppArtifact = findChild(input, function(c) { return c.fileTags.contains("cpp"); }); var cmd = new Command(fullPath(product), [qrcArtifact.filePath, "-temp", input.filePath, "-name", FileInfo.completeBaseName(input.filePath), "-o", output.filePath, "-pass", "2"]); cmd.description = "rcc (pass 2) " + qrcArtifact.fileName; cmd.highlight = 'codegen'; return cmd; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/qml.js0000644000175100001660000002170314776170045023353 0ustar runnerdockervar File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); var TextFile = require("qbs.TextFile"); function scannerData(scannerFilePath, qmlFiles, qmlPath, hostOS) { var p; try { p = new Process(); if (!hostOS.contains("windows")) { p.exec(scannerFilePath, ["-qmlFiles"].concat(qmlFiles).concat(["-importPath", qmlPath]), true); return JSON.parse(p.readStdOut()); } var data = []; var nextFileIndex = 0; while (nextFileIndex < qmlFiles.length) { var currentFileList = []; var currentFileListStringLength = 0; while (nextFileIndex < qmlFiles.length && currentFileListStringLength < 30000) { var currentFile = qmlFiles[nextFileIndex++]; currentFileList.push(currentFile); currentFileListStringLength += currentFile.length; } p.exec(scannerFilePath, ["-qmlFiles"].concat(currentFileList) .concat(["-importPath", qmlPath]), true); data = data.concat(JSON.parse(p.readStdOut())); } return data; } finally { if (p) p.close(); } } function getPrlRhs(line) { return line.split('=')[1].trim(); } function getLibsForPlugin(pluginData, product) { var targetOS = product.qbs.targetOS; var toolchain = product.qbs.toolchain; var buildVariant = product.Qt.core.qtBuildVariant; var qtLibDir = product.Qt.core.libPath; var qtPluginDir = product.Qt.core.pluginPath; var qtDir = product.Qt.core.installPrefixPath; var qtQmlPath = product.Qt.qml.qmlPath; if (!pluginData.path) return ""; var prlFileName = ""; if (!targetOS.contains("windows")) prlFileName += "lib"; prlFileName += pluginData.plugin; if (buildVariant === "debug") { if (targetOS.contains("windows")) { prlFileName += "d"; } else if (product.Qt.core.versionMajor >= 6 && (targetOS.contains("ios") || targetOS.contains("tvos") || targetOS.contains("watchos"))) { prlFileName += "_debug"; } } prlFileName += ".prl"; var prlFilePath = FileInfo.joinPaths(pluginData.path, prlFileName); if (!File.exists(prlFilePath)) { console.warn("prl file for QML plugin '" + pluginData.plugin + "' not present at '" + prlFilePath + "'. Linking may fail."); return ""; } var prlFile = new TextFile(prlFilePath, TextFile.ReadOnly); try { var pluginLib; var otherLibs = []; var line; while (!prlFile.atEof()) { line = prlFile.readLine().trim(); if (!line) continue; if (line.startsWith("QMAKE_PRL_TARGET")) pluginLib = FileInfo.joinPaths(pluginData.path, getPrlRhs(line)); if (line.startsWith("QMAKE_PRL_LIBS = ")) { var otherLibsLine = ' ' + getPrlRhs(line); if (toolchain.contains("msvc")) { otherLibsLine = otherLibsLine.replace(/ -L/g, " /LIBPATH:"); otherLibsLine = otherLibsLine.replace(/-l([^ ]+)/g, "$1" + ".lib"); } otherLibsLine = otherLibsLine.replace(/\$\$\[QT_INSTALL_LIBS\]/g, qtLibDir); otherLibsLine = otherLibsLine.replace(/\$\$\[QT_INSTALL_PLUGINS\]/g, qtPluginDir); otherLibsLine = otherLibsLine.replace(/\$\$\[QT_INSTALL_PREFIX\]/g, qtDir); otherLibsLine = otherLibsLine.replace(/\$\$\[QT_INSTALL_QML\]/g, qtQmlPath); otherLibs = otherLibs.concat(otherLibsLine.split(' ').map(FileInfo.cleanPath)); } } if (!pluginLib) throw "Malformed prl file '" + prlFilePath + "'."; return [pluginLib].concat(otherLibs); } finally { prlFile.close(); } } function typeRegistrarCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var versionParts = product.Qt.qml._importVersionParts; var args = [ "--generate-qmltypes=" + outputs["qt.qml.types"][0].filePath, "--import-name=" + product.Qt.qml.importName, "--major-version=" + versionParts[0], "--minor-version=" + (versionParts.length > 1 ? versionParts[1] : "0") ]; var foreignTypes = product.Qt.qml.extraMetaTypesFiles || []; var metaTypeArtifactsFromDeps = explicitlyDependsOn["qt.core.metatypes"] || []; var filePathFromArtifact = function(a) { return a.filePath; }; foreignTypes = foreignTypes.concat(metaTypeArtifactsFromDeps.map(filePathFromArtifact)); if (foreignTypes.length > 0) args.push("--foreign-types=" + foreignTypes.join(",")); args.push("-o", outputs.cpp[0].filePath); args = args.concat(inputs["qt.core.metatypes"].map(filePathFromArtifact)); var cmd = new Command(product.Qt.core.qmlLibExecPath + "/qmltyperegistrar", args); cmd.description = "running qmltyperegistrar"; cmd.highlight = "codegen"; return cmd; } function generatePluginImportOutputArtifacts(product, inputs) { var list = []; if (inputs["qt.qml.qml"]) list.push({ filePath: "qml_plugin_import.cpp", fileTags: ["cpp"] }); list.push({ filePath: product.Qt.core.qtBuildVariant === "debug" ? product.Qt.qml.pluginListFilePathDebug : product.Qt.qml.pluginListFilePathRelease, fileTags: ["qt.qml.pluginlist"] }); return list; } function getCppLibsAndFrameworks(cpp) { var libs = {"frameworks": {}, "libraries": {}}; for (var i = 0; i < cpp.frameworks.length; ++i) libs.frameworks[cpp.frameworks[i]] = true; for (var i = 0; i < cpp.staticLibraries.length; ++i) libs.libraries[cpp.staticLibraries[i]] = true; for (var i = 0; i < cpp.dynamicLibraries.length; ++i) libs.libraries[cpp.dynamicLibraries[i]] = true; return libs; } function getUniqueLibs(libs, seen) { var uniqueLibs = []; for (var i = 0; i < libs.length; ++i) { if (libs[i] == "-framework") { var frameworkName = libs[i + 1]; if (frameworkName && !seen.frameworks[frameworkName]) { seen.frameworks[frameworkName] = true; uniqueLibs.push("-framework", frameworkName); } ++i; // Skip framework name } else { var libName; if (libs[i].startsWith("-l")) libName = libs[i].substr(2); else libName = libs[i]; if (!seen.libraries[libName]) { seen.libraries[libName] = true; uniqueLibs.push(libs[i]); } } } return uniqueLibs; } function generatePluginImportCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); if (inputs["qt.qml.qml"]) cmd.description = "creating " + outputs["cpp"][0].fileName; else cmd.silent = true; cmd.sourceCode = function() { var qmlInputs = inputs["qt.qml.qml"]; if (!qmlInputs) qmlInputs = []; var scannerData = Qml.scannerData(product.Qt.qml.qmlImportScannerFilePath, qmlInputs.map(function(inp) { return inp.filePath; }), product.Qt.qml.qmlPath, Host.os()); var cppFile; var listFile; try { if (qmlInputs.length > 0) cppFile = new TextFile(outputs["cpp"][0].filePath, TextFile.WriteOnly); listFile = new TextFile(outputs["qt.qml.pluginlist"][0].filePath, TextFile.WriteOnly); if (cppFile) cppFile.writeLine("#include "); var plugins = { }; var seen = Qml.getCppLibsAndFrameworks(product.cpp); var libsWithUniqueObjects = []; for (var p in scannerData) { var plugin = scannerData[p].plugin; if (!plugin || plugins[plugin]) continue; plugins[plugin] = true; var className = scannerData[p].classname; if (!className) { throw "QML plugin '" + plugin + "' is missing a classname entry. " + "Please add one to the qmldir file."; } if (cppFile) cppFile.writeLine("Q_IMPORT_PLUGIN(" + className + ")"); var libs = Qml.getLibsForPlugin(scannerData[p], product); var uniqueLibs = Qml.getUniqueLibs(libs, seen); libsWithUniqueObjects = libsWithUniqueObjects.concat(uniqueLibs); } listFile.write(libsWithUniqueObjects.join("\n")); } finally { if (cppFile) cppFile.close(); if (listFile) listFile.close(); }; }; return [cmd]; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/quick.qbs0000644000175100001660000001116414776170045024047 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.File import qbs.FileInfo import qbs.Utilities import 'quick.js' as QC QtModule { qtModuleName: @name@ Depends { name: "Qt"; submodules: @dependencies@ } version: @version@ hasLibrary: @has_library@ architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ pluginTypes: @pluginTypes@ moduleConfig: @moduleConfig@ cpp.defines: @defines@ cpp.systemIncludePaths: @includes@ cpp.libraryPaths: @libraryPaths@ @additionalContent@ readonly property bool _compilerIsQmlCacheGen: Utilities.versionCompare(Qt.core.version, "5.11") >= 0 readonly property bool _supportsQmlJsFiltering: Utilities.versionCompare(Qt.core.version, "5.15") < 0 readonly property string _generatedLoaderFileName: _compilerIsQmlCacheGen ? "qmlcache_loader.cpp" : "qtquickcompiler_loader.cpp" property string _compilerBaseDir: _compilerIsQmlCacheGen ? Qt.core.qmlLibExecPath : Qt.core.binPath property string compilerBaseName: (_compilerIsQmlCacheGen ? "qmlcachegen" : "qtquickcompiler") property string compilerFilePath: FileInfo.joinPaths(_compilerBaseDir, compilerBaseName + FileInfo.executableSuffix()) property bool compilerAvailable: File.exists(compilerFilePath); property bool useCompiler: compilerAvailable && !_compilerIsQmlCacheGen Group { condition: useCompiler FileTagger { patterns: "*.qrc" fileTags: ["qt.quick.qrc"] priority: 100 } Scanner { inputs: 'qt.quick.qrc' searchPaths: [FileInfo.path(input.filePath)] scan: QC.scanQrc(product, input.filePath) } Rule { inputs: ["qt.quick.qrc"] Artifact { filePath: input.fileName + ".json" fileTags: ["qt.quick.qrcinfo"] } prepare: QC.generateCompilerInputCommands(product, input, output) } Rule { inputs: ["qt.quick.qrcinfo"] outputFileTags: ["cpp", "qrc", "qt.untranslatable"] multiplex: true outputArtifacts: QC.compilerOutputArtifacts(product, inputs) prepare: QC.compilerCommands.apply(QC, arguments) } } } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/qml.qbs0000644000175100001660000001074014776170045023523 0ustar runnerdockerimport qbs.FileInfo import qbs.Host import qbs.TextFile import "qml.js" as Qml QtModule { qtModuleName: "Qml" Depends { name: "Qt"; submodules: @dependencies@} property string qmlImportScannerName: Qt.core.qmlImportScannerName property string qmlImportScannerFilePath: Qt.core.qmlImportScannerFilePath property string qmlPath: @qmlPath@ property bool generateCacheFiles: false Depends { name: "Qt.qmlcache"; condition: generateCacheFiles; required: false } readonly property bool cachingEnabled: generateCacheFiles && Qt.qmlcache.present property string qmlCacheGenPath Properties { condition: cachingEnabled Qt.qmlcache.qmlCacheGenPath: qmlCacheGenPath || original Qt.qmlcache.installDir: cacheFilesInstallDir || original } property string cacheFilesInstallDir readonly property string pluginListFilePathDebug: product.buildDirectory + "/plugins.list.d" readonly property string pluginListFilePathRelease: product.buildDirectory + "/plugins.list" property bool linkPlugins: isStaticLibrary && Qt.plugin_support.linkPlugins version: @version@ hasLibrary: @has_library@ architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: (linkPlugins ? ['@' + pluginListFilePathDebug] : []).concat(@staticLibsDebug@) staticLibsRelease: (linkPlugins ? ['@' + pluginListFilePathRelease] : []).concat(@staticLibsRelease@) dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ pluginTypes: @pluginTypes@ moduleConfig: @moduleConfig@ cpp.defines: @defines@ cpp.systemIncludePaths: @includes@ cpp.libraryPaths: @libraryPaths@ @additionalContent@ FileTagger { patterns: ["*.qml"] fileTags: ["qt.qml.qml"] } FileTagger { patterns: ["*.js"] fileTags: ["qt.qml.js"] } // Type registration property string importName property string importVersion: product.version readonly property stringList _importVersionParts: (importVersion || "").split(".") property string typesFileName: { if (product.type && product.type.contains("application")) return product.targetName + ".qmltypes"; return "plugins.qmltypes"; } property string typesInstallDir property stringList extraMetaTypesFiles Group { condition: importName product.Qt.core.generateMetaTypesFile: true Rule { inputs: "qt.core.metatypes" multiplex: true explicitlyDependsOnFromDependencies: "qt.core.metatypes" Artifact { filePath: product.targetName.toLowerCase() + "_qmltyperegistrations.cpp" fileTags: ["cpp", "unmocable", "qt.untranslatable"] } Artifact { filePath: product.Qt.qml.typesFileName fileTags: "qt.qml.types" qbs.install: product.Qt.qml.typesInstallDir qbs.installDir: product.Qt.qml.typesInstallDir } prepare: Qml.typeRegistrarCommands.apply(Qml, arguments) } } Rule { condition: linkPlugins multiplex: true requiresInputs: false inputs: ["qt.qml.qml"] outputFileTags: ["cpp", "qt.qml.pluginlist", "qt.untranslatable"] outputArtifacts: Qml.generatePluginImportOutputArtifacts(product, inputs) prepare: Qml.generatePluginImportCommands.apply(Qml, arguments) } validate: { if (importName) { if (!importVersion) throw "Qt.qml.importVersion must be set if Qt.qml.importName is set."; var isInt = function(value) { return !isNaN(value) && parseInt(Number(value)) == value && !isNaN(parseInt(value, 10)); } if (!isInt(_importVersionParts[0]) || (_importVersionParts.length > 1 && !isInt(_importVersionParts[1]))) { throw "Qt.qml.importVersion must be of the form x.y, where x and y are integers."; } } } } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/plugin_support.qbs0000644000175100001660000000544214776170045026027 0ustar runnerdockerModule { // Set by user. property varList pluginsByType property bool linkPlugins: product.type && (product.type.contains("application") || product.type.contains("sharedlibrary")) // Set by Qt modules. property stringList pluginTypes // Set by setup-qt. readonly property var allPluginsByType: @allPluginsByType@ readonly property stringList nonEssentialPlugins: @nonEssentialPlugins@ // Derived. readonly property var defaultPluginsByType: { var map = {}; for (var i = 0; i < (pluginTypes || []).length; ++i) { var pType = pluginTypes[i]; map[pType] = (allPluginsByType[pType] || []).filter(function(p) { return !nonEssentialPlugins.contains(p); }); } return map; } readonly property var effectivePluginsByType: { var ppt = pluginsByType || []; var eppt = {}; for (var i = 0; i < ppt.length; ++i) { var listEntry = ppt[i]; for (var pluginType in listEntry) { var newValue = listEntry[pluginType]; if (!newValue) newValue = []; else if (typeof newValue == "string") newValue = [newValue]; if (!newValue instanceof Array) throw "Invalid value '" + newValue + "' in Qt.plugin_support.pluginsByType"; eppt[pluginType] = (eppt[pluginType] || []).uniqueConcat(newValue); } } var dppt = defaultPluginsByType; for (var pluginType in dppt) { if (!eppt[pluginType]) eppt[pluginType] = dppt[pluginType]; } return eppt; } readonly property stringList enabledPlugins: { var list = []; var eppt = effectivePluginsByType; for (var t in eppt) Array.prototype.push.apply(list, eppt[t]); return list; } validate: { var ppt = pluginsByType; if (!ppt) return; var appt = allPluginsByType; for (var i = 0; i < ppt.length; ++i) { for (var pluginType in ppt[i]) { var requestedPlugins = ppt[i][pluginType]; if (!requestedPlugins) continue; var availablePlugins = appt[pluginType] || []; if (typeof requestedPlugins === "string") requestedPlugins = [requestedPlugins]; for (var j = 0; j < requestedPlugins.length; ++j) { if (!availablePlugins.contains(requestedPlugins[j])) { throw "Plugin '" + requestedPlugins[j] + "' of type '" + pluginType + "' was requested, but is not available."; } } } } } } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/gui.qbs0000644000175100001660000000466314776170045023525 0ustar runnerdockerimport qbs.FileInfo import qbs.ModUtils import qbs.Utilities QtModule { qtModuleName: "Gui" property string uicName: "uic" FileTagger { patterns: ["*.ui"] fileTags: ["ui"] } Rule { inputs: ["ui"] Artifact { filePath: FileInfo.joinPaths(input.moduleProperty("Qt.core", "generatedHeadersDir"), 'ui_' + input.completeBaseName + '.h') fileTags: ["hpp", "qt.untranslatable"] } prepare: { var uicPath = Utilities.versionCompare(product.Qt.gui.version, "6.1") < 0 ? product.Qt.core.binPath + '/' + product.Qt.gui.uicName : product.Qt.core.libExecPath + '/' + product.Qt.gui.uicName; var cmd = new Command(uicPath, [input.filePath, '-o', output.filePath]); cmd.description = 'generating ' + output.fileName; cmd.highlight = 'codegen'; return cmd; } } property string defaultQpaPlugin: @defaultQpaPlugin@ version: @version@ architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ pluginTypes: @pluginTypes@ cpp.entryPoint: qbs.targetOS.containsAny(["ios", "tvos"]) && Utilities.versionCompare(version, "5.6.0") >= 0 ? "_qt_main_wrapper" : undefined cpp.defines: @defines@ cpp.systemIncludePaths: @includes@ cpp.libraryPaths: @libraryPaths@ Properties { condition: Qt.core.staticBuild && qbs.targetOS.contains("ios") cpp.frameworks: base.concat(["UIKit", "QuartzCore", "CoreText", "CoreGraphics", "Foundation", "CoreFoundation", "AudioToolbox"]) } Properties { condition: undefined cpp.frameworks: base } @additionalContent@ } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/module.qbs0000644000175100001660000000200314776170045024210 0ustar runnerdockerQtModule { qtModuleName: @name@ Depends { name: "Qt"; submodules: @dependencies@} version: @version@ architectures: @archs@ targetPlatform: @targetPlatform@ hasLibrary: @has_library@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ pluginTypes: @pluginTypes@ moduleConfig: @moduleConfig@ cpp.defines: @defines@ cpp.systemIncludePaths: @includes@ cpp.libraryPaths: @libraryPaths@ @additionalContent@ } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/android_support.qbs0000644000175100001660000001306214776170045026146 0ustar runnerdockerimport qbs.FileInfo import qbs.ModUtils import qbs.Utilities import qbs.Xml import "android_support.js" as Impl Module { version: @version@ property string qmlRootDir: product.sourceDirectory property stringList extraPrefixDirs property stringList qmlImportPaths property stringList deploymentDependencies // qmake: ANDROID_DEPLOYMENT_DEPENDENCIES property stringList extraPlugins // qmake: ANDROID_EXTRA_PLUGINS property stringList extraLibs // qmake: ANDROID_EXTRA_LIBS property bool verboseAndroidDeployQt: false property string _androidDeployQtFilePath: FileInfo.joinPaths(_qtBinaryDir, "bin", "androiddeployqt") property string rccFilePath property string _qtBinaryDir property string _qtInstallDir property bool _enableSdkSupport: product.type && product.type.contains("android.package") && !product.consoleApplication property bool _enableNdkSupport: !product.aggregate || product.multiplexConfigurationId property string _templatesBaseDir: FileInfo.joinPaths(_qtInstallDir, "src", "android") property string _deployQtOutDir: FileInfo.joinPaths(product.buildDirectory, "deployqt_out") property bool _multiAbi: Utilities.versionCompare(version, "5.14") >= 0 // QTBUG-87288: correct QtNetwork jar dependencies for 5.15.0 < Qt < 5.15.3 property bool _correctQtNetworkDependencies: Utilities.versionCompare(version, "5.15.0") > 0 && Utilities.versionCompare(version, "5.15.3") < 0 readonly property string _qtAndroidJarFileName: Utilities.versionCompare(version, "6.0") >= 0 ? "Qt6Android.jar" : "QtAndroid.jar" Group { condition: _enableSdkSupport name: "helper sources from qt" Depends { name: "Android.sdk" } Depends { name: "java" } product.Android.sdk.customManifestProcessing: true product.Android.sdk._bundledInAssets: _multiAbi product.java._tagJniHeaders: false // prevent rule cycle Properties { condition: Utilities.versionCompare(version, "5.15") >= 0 && Utilities.versionCompare(version, "6.0") < 0 java.additionalClassPaths: [FileInfo.joinPaths(_qtInstallDir, "jar", "QtAndroid.jar")] } Properties { condition: Utilities.versionCompare(version, "6.0") >= 0 java.additionalClassPaths: [FileInfo.joinPaths(_qtInstallDir, "jar", "Qt6Android.jar")] Android.sdk.minimumVersion: "23" } Properties { condition: Utilities.versionCompare(version, "6.0") < 0 Android.sdk.minimumVersion: "21" } prefix: Qt.android_support._templatesBaseDir + "/java/" Android.sdk.aidlSearchPaths: prefix + "src" files: [ "**/*.java", "**/*.aidl", ] Rule { multiplex: true property stringList inputTags: ["android.nativelibrary", "qrc"] inputsFromDependencies: inputTags inputs: product.aggregate ? [] : inputTags Artifact { filePath: "androiddeployqt.json" fileTags: "qt_androiddeployqt_input" } prepare: Impl.prepareDeployQtCommands.apply(Impl, arguments) } // We use the manifest template from the Qt installation if and only if the project // does not provide a manifest file. Rule { multiplex: true requiresInputs: false inputs: "android.manifest" excludedInputs: "qt.android_manifest" outputFileTags: ["android.manifest", "qt.android_manifest"] outputArtifacts: Impl.qtManifestOutputArtifacts(inputs) prepare: Impl.qtManifestCommands(product, output) } Rule { multiplex: true property stringList defaultInputs: ["qt_androiddeployqt_input", "android.manifest_processed"] property stringList allInputs: ["qt_androiddeployqt_input", "android.manifest_processed", "android.nativelibrary"] inputsFromDependencies: "android.nativelibrary" inputs: product.aggregate ? defaultInputs : allInputs outputFileTags: [ "android.manifest_final", "android.resources", "android.assets", "bundled_jar", "android.deployqt_list", ] outputArtifacts: Impl.deployQtOutputArtifacts(product) prepare: Impl.deployQtCommands.apply(Impl, arguments) } } Group { condition: _enableNdkSupport Depends { name: "cpp" } Depends { name: "Android.ndk" } product.Android.ndk.appStl: qbs.toolchain.contains("clang") ? "c++_shared" : "gnustl_shared" Properties { condition: _multiAbi cpp.archSuffix: "_" + Android.ndk.abi } // "ANDROID_HAS_WSTRING" was removed from qtcore qstring.h in Qt 5.14.0 Properties { condition: Utilities.versionCompare(version, "5.14.0") < 0 && (Android.ndk.abi === "armeabi-v7a" || Android.ndk.abi === "x86") cpp.defines: "ANDROID_HAS_WSTRING" } } validate: { if (Utilities.versionCompare(version, "5.12") < 0) throw ModUtils.ModuleError("Cannot use Qt " + version + " with Android. " + "Version 5.12 or later is required."); } } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/qdoc.js0000644000175100001660000000754014776170045023513 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var ModUtils = require("qbs.ModUtils"); function qdocArgs(product, input, outputDir) { var args = [input.filePath]; var qtVersion = ModUtils.moduleProperty(product, "versionMajor"); if (qtVersion >= 5) { args.push("-outputdir"); args.push(outputDir); } return args; } var _qdocDefaultFileTag = "qdoc-output"; function qdocFileTaggers() { var t = _qdocDefaultFileTag; return { ".qhp": [t, "qhp"], ".qhp.sha1": [t, "qhp-sha1"], ".css": [t, "qdoc-css"], ".html": [t, "qdoc-html"], ".index": [t, "qdoc-index"], ".png": [t, "qdoc-png"] }; } function outputArtifacts(product, input) { var tracker = new ModUtils.BlackboxOutputArtifactTracker(); tracker.hostOS = product.moduleProperty("qbs", "hostOS"); tracker.shellPath = product.moduleProperty("qbs", "shellPath"); tracker.defaultFileTags = [_qdocDefaultFileTag]; tracker.fileTaggers = qdocFileTaggers(); tracker.command = FileInfo.joinPaths(ModUtils.moduleProperty(product, "binPath"), ModUtils.moduleProperty(product, "qdocName")); tracker.commandArgsFunction = function (outputDirectory) { return qdocArgs(product, input, outputDirectory); }; tracker.commandEnvironmentFunction = function (outputDirectory) { var env = {}; var qdocEnv = ModUtils.moduleProperty(product, "qdocEnvironment"); for (var j = 0; j < qdocEnv.length; ++j) { var e = qdocEnv[j]; var idx = e.indexOf("="); var name = e.slice(0, idx); var value = e.slice(idx + 1, e.length); env[name] = value; } env["OUTDIR"] = outputDirectory; // Qt 4 replacement for -outputdir return env; }; return tracker.artifacts(ModUtils.moduleProperty(product, "qdocOutputDir")); } function commands(product, input) { var outputDir = product.Qt.core.qdocOutputDir; var args = qdocArgs(product, input, outputDir); var cmd = new Command(product.Qt.core.binPath + '/' + product.Qt.core.qdocName, args); cmd.description = 'qdoc ' + input.fileName; cmd.highlight = 'filegen'; cmd.environment = product.Qt.core.qdocEnvironment; cmd.environment.push("OUTDIR=" + outputDir); // Qt 4 replacement for -outputdir return cmd; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/quick.js0000644000175100001660000001571014776170045023677 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); var Rcc = require("rcc.js"); var TextFile = require("qbs.TextFile"); function scanQrc(product, qrcFilePath) { var absInputDir = FileInfo.path(qrcFilePath); var result = []; var process = new Process(); try { var rcc = FileInfo.joinPaths(Rcc.fullPath(product) + FileInfo.executableSuffix()); var exitCode = process.exec(rcc, ["--list", qrcFilePath], true); for (;;) { var line = process.readLine(); if (!line) break; line = line.trim(); line = FileInfo.relativePath(absInputDir, line); result.push(line); } } finally { process.close(); } return result; } function qtQuickCompilerOutputName(filePath) { var str = filePath.replace(/\//g, '_'); var i = str.lastIndexOf('.'); if (i != -1) str = str.substr(0, i) + '_' + str.substr(i + 1); str += ".cpp"; return str; } function qtQuickResourceFileOutputName(fileName) { return fileName.replace(/\.qrc$/, "_qtquickcompiler.qrc"); } function contentFromQrc(product, qrcFilePath) { var supportsFiltering = product.Qt.quick._supportsQmlJsFiltering; var filesInQrc = scanQrc(product, qrcFilePath); var qmlJsFiles = filesInQrc.filter(function (filePath) { return (/\.(mjs|js|qml)$/).test(filePath); } ); var content = {}; if (!supportsFiltering || filesInQrc.length - qmlJsFiles.length > 0) { content.newQrcFileName = qtQuickResourceFileOutputName(input.fileName); } content.qmlJsFiles = qmlJsFiles.map(function (filePath) { return { input: filePath, output: qtQuickCompilerOutputName(filePath) }; }); return content; } function generateCompilerInputCommands(product, input, output) { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var content = contentFromQrc(product, input.filePath); content.qrcFilePath = input.filePath; var tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.write(JSON.stringify(content)); tf.close(); } return cmd; } function compilerOutputArtifacts(product, inputs) { var infos = []; inputs["qt.quick.qrcinfo"].forEach(function (input) { var tf = new TextFile(input.filePath, TextFile.ReadOnly); infos.push(JSON.parse(tf.readAll())); tf.close(); }); var result = []; infos.forEach(function (info) { if (info.newQrcFileName) { result.push({ filePath: info.newQrcFileName, fileTags: ["qrc"] }); } info.qmlJsFiles.forEach(function (qmlJsFile) { result.push({ filePath: qmlJsFile.output, fileTags: ["cpp"] }); }); }); result.push({ filePath: product.Qt.quick._generatedLoaderFileName, fileTags: ["cpp"] }); return result; } function compilerCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var infos = []; inputs["qt.quick.qrcinfo"].forEach(function (input) { var tf = new TextFile(input.filePath, TextFile.ReadOnly); infos.push(JSON.parse(tf.readAll())); tf.close(); }); var cmds = []; var qmlCompiler = product.Qt.quick.compilerFilePath; var useCacheGen = product.Qt.quick._compilerIsQmlCacheGen; var cmd; var loaderFlags = []; function findOutput(fileName) { for (var k in outputs) { for (var i in outputs[k]) { if (outputs[k][i].fileName === fileName) return outputs[k][i]; } } throw new Error("Qt Quick compiler rule: Cannot find output artifact " + fileName + "."); } infos.forEach(function (info) { if (info.newQrcFileName) { loaderFlags.push("--resource-file-mapping=" + FileInfo.fileName(info.qrcFilePath) + '=' + info.newQrcFileName); // Qt 5.15 doesn't really filter anyting but merely copies the qrc // content to the new location var args = ["--filter-resource-file", info.qrcFilePath]; if (useCacheGen) args.push("-o"); args.push(findOutput(info.newQrcFileName).filePath); cmd = new Command(qmlCompiler, args); cmd.description = "generating " + info.newQrcFileName; cmds.push(cmd); } else { loaderFlags.push("--resource-file-mapping=" + info.qrcFilePath); } info.qmlJsFiles.forEach(function (qmlJsFile) { var args = ["--resource=" + info.qrcFilePath, qmlJsFile.input]; if (useCacheGen) args.push("-o"); args.push(findOutput(qmlJsFile.output).filePath); cmd = new Command(qmlCompiler, args); cmd.description = "generating " + qmlJsFile.output; cmd.workingDirectory = FileInfo.path(info.qrcFilePath); cmds.push(cmd); }); }); var args = loaderFlags.concat(infos.map(function (info) { return info.qrcFilePath; })); if (useCacheGen) args.push("-o"); args.push(findOutput(product.Qt.quick._generatedLoaderFileName).filePath); cmd = new Command(qmlCompiler, args); cmd.description = "generating loader source"; cmds.push(cmd); return cmds; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/dbus.qbs0000644000175100001660000000420114776170045023662 0ustar runnerdockerimport qbs.FileInfo import qbs.ModUtils import "dbus.js" as DBus QtModule { qtModuleName: "DBus" property string xml2cppName: "qdbusxml2cpp" property stringList xml2CppHeaderFlags: [] property stringList xml2CppSourceFlags: [] Rule { inputs: ["qt.dbus.adaptor"] Artifact { filePath: FileInfo.joinPaths(input.moduleProperty("Qt.core", "generatedHeadersDir"), DBus.outputFileName(input, "_adaptor.h")) fileTags: ["hpp"] } Artifact { filePath: DBus.outputFileName(input, "_adaptor.cpp") fileTags: ["cpp", "qt.untranslatable"] } prepare: DBus.createCommands(product, input, outputs, "-a") } Rule { inputs: ["qt.dbus.interface"] Artifact { filePath: FileInfo.joinPaths(input.moduleProperty("Qt.core", "generatedHeadersDir"), DBus.outputFileName(input, "_interface.h")) fileTags: ["hpp"] } Artifact { filePath: DBus.outputFileName(input, "_interface.cpp") fileTags: ["cpp", "qt.untranslatable"] } prepare: DBus.createCommands(product, input, outputs, "-p") } version: @version@ architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ pluginTypes: @pluginTypes@ moduleConfig: @moduleConfig@ cpp.defines: @defines@ cpp.systemIncludePaths: @includes@ cpp.libraryPaths: @libraryPaths@ @additionalContent@ } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/android_support.js0000644000175100001660000004664314776170045026010 0ustar runnerdockervar File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); function prepareDeployQtCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var theBinary; var nativeLibs = inputs["android.nativelibrary"]; var architectures = []; var triples = []; var qtInstallDirectories = []; var hostArch; var targetArchitecture; if (nativeLibs.length === 1) { theBinary = nativeLibs[0]; hostArch = theBinary.Android.ndk.hostArch; targetArchitecture = theBinary.Android.ndk.abi; if (product.Qt.android_support._multiAbi) { architectures.push(theBinary.Android.ndk.abi); triples.push(theBinary.cpp.toolchainTriple); qtInstallDirectories.push(theBinary.Qt.android_support._qtInstallDir); } } else { for (i = 0; i < nativeLibs.length; ++i) { var candidate = nativeLibs[i]; if (product.Qt.android_support._multiAbi) { if (candidate.product.name === product.name) { architectures.push(candidate.Android.ndk.abi); triples.push(candidate.cpp.toolchainTriple); qtInstallDirectories.push( candidate.Qt.android_support._qtInstallDir); hostArch = candidate.Android.ndk.hostArch; targetArchitecture = candidate.Android.ndk.abi; theBinary = candidate; } } else { if (!candidate.fileName.contains(candidate.product.targetName)) continue; if (!theBinary) { theBinary = candidate; hostArch = theBinary.Android.ndk.hostArch; targetArchitecture = theBinary.Android.ndk.abi; continue; } if (candidate.product.name !== product.name) { continue; // This is not going to be a match } if (candidate.product.name === product.name && theBinary.product.name !== product.name) { theBinary = candidate; // The new candidate is a better match. hostArch = theBinary.Android.ndk.hostArch; targetArchitecture = theBinary.Android.ndk.abi; continue; } throw "Qt applications for Android support only one native binary " + "per package.\n" + "In particular, you cannot build a Qt app for more than " + "one architecture at the same time."; } } } var f = new TextFile(output.filePath, TextFile.WriteOnly); f.writeLine("{"); f.writeLine('"description": "This file was generated by qbs to be read by ' + 'androiddeployqt and should not be modified by hand.",'); if (Utilities.versionCompare(product.Qt.core.version, "6.3.0") >= 0) { var line = '"qt": {'; for (var i = 0; i < qtInstallDirectories.length && i < architectures.length; ++i) { line = line + '"' + architectures[i] + '":"' + qtInstallDirectories[i] + '"'; if (i < qtInstallDirectories.length-1 || i < architectures.length-1) line = line + ','; } line = line + "},"; f.writeLine(line); } else { f.writeLine('"qt": "' + product.Qt.android_support._qtInstallDir + '",'); } f.writeLine('"sdk": "' + product.Android.sdk.sdkDir + '",'); f.writeLine('"sdkBuildToolsRevision": "' + product.Android.sdk.buildToolsVersion + '",'); f.writeLine('"ndk": "' + product.Android.sdk.ndkDir + '",'); f.writeLine('"toolchain-prefix": "llvm",'); f.writeLine('"tool-prefix": "llvm",'); f.writeLine('"useLLVM": true,'); f.writeLine('"ndk-host": "' + hostArch + '",'); if (!product.Qt.android_support._multiAbi) { f.writeLine('"target-architecture": "' + targetArchitecture + '",'); } else { var line = '"architectures": {'; for (var i in architectures) { line = line + '"' + architectures[i] + '":"' + triples[i] + '"'; if (i < architectures.length-1) line = line + ','; } line = line + "},"; f.writeLine(line); } f.writeLine('"qml-root-path": "' + product.Qt.android_support.qmlRootDir + '",'); var deploymentDeps = product.Qt.android_support.deploymentDependencies; if (deploymentDeps && deploymentDeps.length > 0) f.writeLine('"deployment-dependencies": "' + deploymentDeps.join() + '",'); var extraPlugins = product.Qt.android_support.extraPlugins; if (extraPlugins && extraPlugins.length > 0) f.writeLine('"android-extra-plugins": "' + extraPlugins.join() + '",'); var extraLibs = product.Qt.android_support.extraLibs; if (extraLibs && extraLibs.length > 0) { for (var i = 0; i < extraLibs.length; ++i) { if (!FileInfo.isAbsolutePath(extraLibs[i])) { extraLibs[i] = FileInfo.joinPaths(product.sourceDirectory, extraLibs[i]); } } f.writeLine('"android-extra-libs": "' + extraLibs.join() + '",'); } var prefixDirs = product.Qt.android_support.extraPrefixDirs; if (prefixDirs && prefixDirs.length > 0) f.writeLine('"extraPrefixDirs": ' + JSON.stringify(prefixDirs) + ','); var qmlImportPaths = product.Qt.android_support.qmlImportPaths; if (qmlImportPaths && qmlImportPaths.length > 0) f.writeLine('"qml-import-paths": "' + qmlImportPaths.join(',') + '",'); else if ((product.qmlImportPaths instanceof Array) && product.qmlImportPaths.length > 0) f.writeLine('"qml-import-paths": "' + product.qmlImportPaths.join(',') + '",'); if (Utilities.versionCompare(product.Qt.android_support.version, "6.0") >= 0) { f.writeLine('"qml-importscanner-binary": "' + product.Qt.core.qmlImportScannerFilePath + FileInfo.executableSuffix() + '",'); f.writeLine('"rcc-binary": "' + product.Qt.android_support.rccFilePath + FileInfo.executableSuffix() + '",'); if (inputs["qrc"] && inputs["qrc"].length > 0) { var qrcFiles = []; var qrcInputs = inputs["qrc"]; for (i = 0; i < qrcInputs.length; ++i) { qrcFiles.push(qrcInputs[i].filePath); } f.writeLine('"qrcFiles": "' + qrcFiles.join(',') + '",'); } } // QBS-1429 if (!product.Qt.android_support._multiAbi) { f.writeLine('"stdcpp-path": "' + (product.cpp.sharedStlFilePath ? product.cpp.sharedStlFilePath : product.cpp.staticStlFilePath) + '",'); f.writeLine('"application-binary": "' + theBinary.filePath + '"'); } else { f.writeLine('"stdcpp-path": "' + product.Android.sdk.ndkDir + '/toolchains/llvm/prebuilt/' + hostArch + '/sysroot/usr/lib/",'); f.writeLine('"application-binary": "' + theBinary.product.targetName + '"'); } f.writeLine("}"); f.close(); }; return cmd; } function qtManifestOutputArtifacts(inputs) { if (inputs["android.manifest"]) return []; return [{ filePath: "qt_manifest/AndroidManifest.xml", fileTags: ["android.manifest", "qt.android_manifest"] }]; } function qtManifestCommands(product, output) { var cmd = new JavaScriptCommand(); cmd.description = "copying Qt Android manifest template"; cmd.sourceCode = function() { File.copy(FileInfo.joinPaths(product.Qt.android_support._templatesBaseDir, "templates", "AndroidManifest.xml"), output.filePath); }; return cmd; } function deployQtOutputArtifacts(product) { return [ { filePath: "AndroidManifest.xml", fileTags: "android.manifest_final" }, { filePath: product.Qt.android_support._deployQtOutDir + "/res/values/libs.xml", fileTags: "android.resources" }, { filePath: product.Qt.android_support._deployQtOutDir + "/res/values/strings.xml", fileTags: "android.resources" }, { filePath: product.Qt.android_support._deployQtOutDir + "/assets/.dummy", fileTags: "android.assets" }, { filePath: "deployqt.list", fileTags: "android.deployqt_list" }, // androiddeployqt potentially copies more jar files but this one will always be there // since it comes with Qt.core { filePath: FileInfo.joinPaths(product.java.classFilesDir, product.Qt.android_support._qtAndroidJarFileName), fileTags: "bundled_jar" } ]; } function deployQtCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var cmds = []; var copyCmd = new JavaScriptCommand(); copyCmd.description = "copying Qt resource templates"; copyCmd.sourceCode = function() { File.copy(inputs["android.manifest_processed"][0].filePath, product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml"); File.copy(product.Qt.android_support._templatesBaseDir + "/java/res", product.Qt.android_support._deployQtOutDir + "/res"); File.copy(product.Qt.android_support._templatesBaseDir + "/templates/res/values/libs.xml", product.Qt.android_support._deployQtOutDir + "/res/values/libs.xml"); if (!product.Qt.android_support._multiAbi) { try { File.remove(FileInfo.path(outputs["android.assets"][0].filePath)); } catch (e) { } } else { for (var i in inputs["android.nativelibrary"]) { var input = inputs["android.nativelibrary"][i]; File.copy(input.filePath, FileInfo.joinPaths(product.Qt.android_support._deployQtOutDir, "libs", input.Android.ndk.abi, input.fileName)); } } }; cmds.push(copyCmd); var androidDeployQtArgs = [ "--output", product.Qt.android_support._deployQtOutDir, "--input", inputs["qt_androiddeployqt_input"][0].filePath, "--aux-mode", "--deployment", "bundled", "--android-platform", product.Android.sdk.platform, ]; if (product.Qt.android_support.verboseAndroidDeployQt) androidDeployQtArgs.push("--verbose"); var androidDeployQtCmd = new Command( product.Qt.android_support._androidDeployQtFilePath, androidDeployQtArgs); androidDeployQtCmd.description = "running androiddeployqt"; cmds.push(androidDeployQtCmd); // We do not want androiddeployqt to write directly into our APK base dir, so // we ran it on an isolated directory and now we move stuff over. // We remember the files for which we do that, so if the next invocation // of androiddeployqt creates fewer files, the other ones are removed from // the APK base dir. var moveCmd = new JavaScriptCommand(); moveCmd.description = "processing androiddeployqt output"; moveCmd.sourceCode = function() { File.makePath(product.java.classFilesDir); var libsDir = product.Qt.android_support._deployQtOutDir + "/libs"; var libDir = product.Android.sdk.packageContentsDir + "/lib"; var listFilePath = outputs["android.deployqt_list"][0].filePath; var oldLibs = []; try { var listFile = new TextFile(listFilePath, TextFile.ReadOnly); var listFileLine = listFile.readLine(); while (listFileLine) { oldLibs.push(listFileLine); listFileLine = listFile.readLine(); } listFile.close(); } catch (e) { } listFile = new TextFile(listFilePath, TextFile.WriteOnly); var newLibs = []; var moveLibFiles = function(prefix) { var fullSrcPrefix = FileInfo.joinPaths(libsDir, prefix); var files = File.directoryEntries(fullSrcPrefix, File.Files); for (var i = 0; i < files.length; ++i) { var file = files[i]; var srcFilePath = FileInfo.joinPaths(fullSrcPrefix, file); var targetFilePath; if (file.endsWith(".jar")) targetFilePath = FileInfo.joinPaths(product.java.classFilesDir, file); else targetFilePath = FileInfo.joinPaths(libDir, prefix, file); File.move(srcFilePath, targetFilePath); listFile.writeLine(targetFilePath); newLibs.push(targetFilePath); } var dirs = File.directoryEntries(fullSrcPrefix, File.Dirs | File.NoDotAndDotDot); for (i = 0; i < dirs.length; ++i) moveLibFiles(FileInfo.joinPaths(prefix, dirs[i])); }; moveLibFiles(""); listFile.close(); for (i = 0; i < oldLibs.length; ++i) { if (!newLibs.contains(oldLibs[i])) File.remove(oldLibs[i]); } }; cmds.push(moveCmd); // androiddeployqt doesn't strip the deployed libraries anymore so it has to done here // but only for release build if (product.qbs.buildVariant == "release") { var stripLibsCmd = new JavaScriptCommand(); stripLibsCmd.description = "stripping unneeded symbols from deployed qt libraries"; stripLibsCmd.sourceCode = function() { var stripArgs = ["--strip-all"]; var architectures = []; for (var i in inputs["android.nativelibrary"]) architectures.push(inputs["android.nativelibrary"][i].Android.ndk.abi); for (var i in architectures) { var abiDirPath = FileInfo.joinPaths(product.Android.sdk.packageContentsDir, "lib", architectures[i]); var files = File.directoryEntries(abiDirPath, File.Files); for (var i = 0; i < files.length; ++i) { var filePath = FileInfo.joinPaths(abiDirPath, files[i]); if (FileInfo.suffix(filePath) == "so") { stripArgs.push(filePath); } } } var process = new Process(); process.exec(product.cpp.stripPath, stripArgs, false); } cmds.push(stripLibsCmd); } var correctingCmd = new JavaScriptCommand(); if (product.Qt.android_support._correctQtNetworkDependencies) { correctingCmd.description = "correcting network jar dependency"; correctingCmd.sourceCode = function() { var findNetworkLib = function() { var libsDir = product.Android.sdk.packageContentsDir + "/lib"; var dirList = File.directoryEntries(libsDir, File.Dirs | File.NoDotAndDotDot); for (var i = 0; i < dirList.length; ++i) { var archDir = FileInfo.joinPaths(libsDir, dirList[i]); var fileList = File.directoryEntries(archDir, File.Files); if (fileList) { for (var j = 0; j < fileList.length; ++j) { if (fileList[j].contains("libQt5Network")) { return true; } } } } return false; } if (findNetworkLib()) { var manifestData = new Xml.DomDocument(); var manifestFilePath = product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml" manifestData.load(manifestFilePath); var rootElem = manifestData.documentElement(); if (!rootElem || !rootElem.isElement() || rootElem.tagName() != "manifest") throw "No manifest tag found in '" + manifestFilePath + "'."; var appElem = rootElem.firstChild("application"); if (!appElem || !appElem.isElement() || appElem.tagName() != "application") throw "No application tag found in '" + manifestFilePath + "'."; var activityElem = appElem.firstChild("activity"); if (!activityElem || !activityElem.isElement() || activityElem.tagName() != "activity") throw "No activity tag found in '" + manifestFilePath + "'."; var metaDataElem = activityElem.firstChild("meta-data"); while (metaDataElem && metaDataElem.isElement()) { if (metaDataElem.attribute("android:name") == "android.app.load_local_jars" ) { var value = metaDataElem.attribute("android:value"); var fileName = "QtAndroidNetwork.jar"; metaDataElem.setAttribute("android:value", value + ":jar/" + fileName); var jarFilePath = FileInfo.joinPaths( product.Qt.android_support._qtInstallDir, "jar", fileName); var targetFilePath = FileInfo.joinPaths(product.java.classFilesDir, fileName); File.copy(jarFilePath, targetFilePath); break; } metaDataElem = metaDataElem.nextSibling("meta-data"); } manifestData.save(outputs["android.manifest_final"][0].filePath, 4); } else { File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml", outputs["android.manifest_final"][0].filePath); } }; } else { correctingCmd.description = "copying manifest"; correctingCmd.sourceCode = function() { File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml", outputs["android.manifest_final"][0].filePath); } } cmds.push(correctingCmd); return cmds; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/core.js0000644000175100001660000000364214776170045023514 0ustar runnerdockervar TextFile = require("qbs.TextFile"); function lreleaseCommands(project, product, inputs, outputs, input, output, explicitlyDependsOn) { var inputFilePaths; if (product.Qt.core.lreleaseMultiplexMode) inputFilePaths = inputs["ts"].map(function(artifact) { return artifact.filePath; }); else inputFilePaths = [input.filePath]; var args = ['-silent', '-qm', output.filePath].concat(inputFilePaths); var cmd = new Command(product.Qt.core.binPath + '/' + product.Qt.core.lreleaseName, args); cmd.description = 'creating ' + output.fileName; cmd.highlight = 'filegen'; return cmd; } function qhelpGeneratorCommands(product, input, output) { var args = [input.filePath]; args = args.concat(product.Qt.core.helpGeneratorArgs); args.push("-o"); args.push(output.filePath); var cmd = new Command( product.Qt.core.helpGeneratorLibExecPath + "/qhelpgenerator", args); cmd.description = 'qhelpgenerator ' + input.fileName; cmd.highlight = 'filegen'; cmd.stdoutFilterFunction = function(output) { return ""; }; return cmd; } function wasmQtHtmlCommands(product, output) { var cmd = new JavaScriptCommand(); cmd.description = "Generating Qt html for " + product.targetName; cmd.highlight = "filegen"; cmd.sourceCode = function() { var platformsPath = product.Qt.core.pluginPath + "/platforms"; var wasmShellFile = new TextFile(platformsPath + "/wasm_shell.html"); var content = wasmShellFile.readAll(); var appNameTemplate = "@APPNAME@"; var finalContent = content.replaceAll(appNameTemplate, product.name); var preload = "@PRELOAD@";//TODO: figure out what it's for finalContent = finalContent.replace(preload, ""); var finalHtmlFile = new TextFile(output.filePath, OpenMode = TextFile.WriteOnly); finalHtmlFile.write(finalContent); } return cmd; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/moc.js0000644000175100001660000001307014776170045023336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var ModUtils = require("qbs.ModUtils"); var Utilities = require("qbs.Utilities"); function args(product, input, outputs) { var defines = product.cpp.compilerDefinesByLanguage; if (input.fileTags.contains("objcpp")) defines = ModUtils.flattenDictionary(defines["objcpp"]) || []; else if (input.fileTags.contains("cpp") || input.fileTags.contains("hpp")) defines = ModUtils.flattenDictionary(defines["cpp"]) || []; else defines = []; defines = defines.uniqueConcat(product.cpp.platformDefines); defines = defines.uniqueConcat(input.cpp.defines); var includePaths = input.cpp.includePaths; includePaths = includePaths.uniqueConcat(input.cpp.systemIncludePaths); var useCompilerPaths = product.Qt.core.versionMajor >= 5; if (useCompilerPaths) { includePaths = includePaths.uniqueConcat(input.cpp.compilerIncludePaths); } var frameworkPaths = product.cpp.frameworkPaths; frameworkPaths = frameworkPaths.uniqueConcat( product.cpp.systemFrameworkPaths); if (useCompilerPaths) { frameworkPaths = frameworkPaths.uniqueConcat( product.cpp.compilerFrameworkPaths); } var pluginMetaData = product.Qt.core.pluginMetaData; var args = []; if (product.Qt.core._generateMetaTypesFile) args.push("--output-json"); var outputFileName; for (tag in outputs) { if (tag !== "qt.core.metatypes.in") { outputFileName = outputs[tag][0].filePath; break; } } args = args.concat( defines.map(function(item) { return '-D' + item; }), includePaths.map(function(item) { return '-I' + item; }), frameworkPaths.map(function(item) { return '-F' + item; }), pluginMetaData.map(function(item) { return '-M' + item; }), product.Qt.core.mocFlags, '-o', outputFileName, input.filePath); return args; } function fullPath(product) { if (Utilities.versionCompare(product.Qt.core.version, "6.1") < 0) return product.Qt.core.binPath + '/' + product.Qt.core.mocName; return product.Qt.core.libExecPath + '/' + product.Qt.core.mocName; } function outputArtifacts(project, product, inputs, input) { var mocInfo = QtMocScanner.apply(input); if (!mocInfo.hasQObjectMacro) return []; var artifact = { fileTags: ["unmocable"] }; if (mocInfo.hasPluginMetaDataMacro) artifact.explicitlyDependsOn = ["qt_plugin_metadata"]; if (input.fileTags.contains("hpp")) { artifact.filePath = input.Qt.core.generatedHeadersDir + "/moc_" + input.completeBaseName + ".cpp"; var amalgamate = input.Qt.core.combineMocOutput; artifact.fileTags.push(mocInfo.mustCompile ? (amalgamate ? "moc_cpp" : "cpp") : "hpp"); } else { artifact.filePath = input.Qt.core.generatedHeadersDir + '/' + input.completeBaseName + ".moc"; artifact.fileTags.push("hpp"); } var artifacts = [artifact]; if (product.Qt.core._generateMetaTypesFile) artifacts.push({filePath: artifact.filePath + ".json", fileTags: "qt.core.metatypes.in"}); return artifacts; } function commands(project, product, inputs, outputs, input, output) { var cmd = new Command(fullPath(product), args(product, input, outputs)); cmd.description = 'moc ' + input.fileName; cmd.highlight = 'codegen'; return cmd; } function generateMocCppCommands(inputs, output) { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { ModUtils.mergeCFiles(inputs["moc_cpp"], output.filePath); }; return [cmd]; } function generateMetaTypesCommands(inputs, output) { var inputFilePaths = inputs["qt.core.metatypes.in"].map(function(a) { return a.filePath; }); var cmd = new Command(fullPath(product), ["--collect-json", "-o", output.filePath].concat(inputFilePaths)); cmd.description = "generating " + output.fileName; cmd.highlight = "codegen"; return cmd; } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/scxml.qbs0000644000175100001660000000605214776170045024061 0ustar runnerdockerimport qbs.FileInfo import qbs.Utilities QtModule { qtModuleName: "Scxml" property string _qscxmlcDir: Utilities.versionCompare(Qt.core.version, "6.3") >= 0 ? Qt.core.libExecPath : Qt.core.binPath property string qscxmlcName: "qscxmlc" property string className property string namespace property bool generateStateMethods property stringList additionalCompilerFlags Rule { inputs: ["qt.scxml.compilable"] Artifact { filePath: FileInfo.joinPaths(input.moduleProperty("Qt.core", "generatedHeadersDir"), input.baseName + ".h") fileTags: ["hpp", "unmocable"] } Artifact { filePath: input.baseName + ".cpp" fileTags: ["cpp", "unmocable", "qt.untranslatable"] } prepare: { var compilerName = product.moduleProperty("Qt.scxml", "qscxmlcName"); var compilerPath = FileInfo.joinPaths(input.Qt.scxml._qscxmlcDir, compilerName); var args = ["--header", outputs["hpp"][0].filePath, "--impl", outputs["cpp"][0].filePath]; var cxx98 = input.moduleProperty("cpp", "cxxLanguageVersion") === "c++98"; if (cxx98) args.push("-no-c++11"); var className = input.moduleProperty("Qt.scxml", "className"); if (className) args.push("--classname", className); var namespace = input.moduleProperty("Qt.scxml", "namespace"); if (namespace) args.push("--namespace", namespace); if (input.Qt.scxml.generateStateMethods && Utilities.versionCompare(product.Qt.scxml.version, "5.9") >= 0) { args.push("--statemethods"); } if (input.Qt.scxml.additionalCompilerFlags) args = args.concat(input.Qt.scxml.additionalCompilerFlags); args.push(input.filePath); var cmd = new Command(compilerPath, args); cmd.description = "compiling " + input.fileName; cmd.highlight = "codegen"; return [cmd]; } } version: @version@ architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ dynamicLibsDebug: @dynamicLibsDebug@ dynamicLibsRelease: @dynamicLibsRelease@ linkerFlagsDebug: @linkerFlagsDebug@ linkerFlagsRelease: @linkerFlagsRelease@ frameworksDebug: @frameworksDebug@ frameworksRelease: @frameworksRelease@ frameworkPathsDebug: @frameworkPathsDebug@ frameworkPathsRelease: @frameworkPathsRelease@ libNameForLinkerDebug: @libNameForLinkerDebug@ libNameForLinkerRelease: @libNameForLinkerRelease@ libFilePathDebug: @libFilePathDebug@ libFilePathRelease: @libFilePathRelease@ pluginTypes: @pluginTypes@ moduleConfig: @moduleConfig@ cpp.defines: @defines@ cpp.systemIncludePaths: @includes@ cpp.libraryPaths: @libraryPaths@ @additionalContent@ } qbs-src-2.6.1/share/qbs/module-providers/Qt/templates/core.qbs0000644000175100001660000004606314776170045023671 0ustar runnerdockerimport qbs.FileInfo import qbs.ModUtils import qbs.TextFile import qbs.Utilities import "core.js" as Core import "moc.js" as Moc import "qdoc.js" as Qdoc import "rcc.js" as Rcc Module { condition: (qbs.targetPlatform === targetPlatform || isCombinedUIKitBuild) && (!qbs.architecture || architectures.length === 0 || architectures.contains(qbs.architecture)) readonly property bool isCombinedUIKitBuild: ["ios", "tvos", "watchos"].contains(targetPlatform) && (!qbs.architecture || ["x86", "x86_64"].contains(qbs.architecture)) && qbs.targetPlatform === targetPlatform + "-simulator" Depends { name: "cpp" } Depends { name: "Sanitizers.address"; condition: config.contains("sanitize_address") } Group { condition: qbs.targetOS.contains("android") Depends { name: "Qt.android_support" } product.Qt.android_support._qtBinaryDir: FileInfo.path(binPath) product.Qt.android_support._qtInstallDir: FileInfo.path(installPath) product.Qt.android_support.version: version product.Qt.android_support.rccFilePath: Rcc.fullPath(product) } // qmlImportScanner is required by androiddeployqt even if the project doesn't // depend on qml. That's why the scannerName must be defined here and not in the // qml module property string qmlImportScannerName: "qmlimportscanner" property string qmlImportScannerFilePath: qmlLibExecPath + '/' + qmlImportScannerName version: @version@ property stringList architectures: @archs@ property string targetPlatform: @targetPlatform@ property string libInfix: @libInfix@ property stringList config: @config@ property stringList qtConfig: @qtConfig@ readonly property stringList enabledFeatures: @enabledFeatures@ readonly property stringList disabledFeatures: @disabledFeatures@ property path binPath: @binPath@ property path installPath: @installPath@ property path incPath: @incPath@ property path libPath: @libPath@ property path installPrefixPath: @installPrefixPath@ property path libExecPath: @libExecPath@ property path qmlLibExecPath: @qmlLibExecPath@ property path pluginPath: @pluginPath@ property string mkspecName: @mkspecName@ property path mkspecPath: @mkspecPath@ property string mocName: "moc" property stringList mocFlags: [] property string lreleaseName: "lrelease" property string lupdateName: "lupdate" property string rccName: "rcc" property string qdocName: versionMajor >= 5 ? "qdoc" : "qdoc3" property stringList qdocEnvironment property path docPath: @docPath@ property path translationsPath: @translationsPath@ property string helpGeneratorLibExecPath: @helpGeneratorLibExecPath@ property stringList helpGeneratorArgs: versionMajor >= 5 ? ["-platform", "minimal"] : [] property var versionParts: version ? version.split('.').map(function(item) { return parseInt(item, 10); }) : [] property int versionMajor: versionParts[0] property int versionMinor: versionParts[1] property int versionPatch: versionParts[2] property bool frameworkBuild: @frameworkBuild@ property bool staticBuild: @staticBuild@ property bool multiThreading: @multiThreading@ property stringList pluginMetaData: [] property bool enableKeywords: true property bool generateMetaTypesFile readonly property bool _generateMetaTypesFile: generateMetaTypesFile && Utilities.versionCompare(version, "5.15") >= 0 property string metaTypesInstallDir property stringList availableBuildVariants: @availableBuildVariants@ property string qtBuildVariant: { if (availableBuildVariants.contains(qbs.buildVariant)) return qbs.buildVariant; if (qbs.buildVariant === "profiling" && availableBuildVariants.contains("release")) return "release"; return availableBuildVariants.length > 0 ? availableBuildVariants[0] : ""; } property stringList staticLibsDebug: @staticLibsDebug@ property stringList staticLibsRelease: @staticLibsRelease@ property stringList dynamicLibsDebug: @dynamicLibsDebug@ property stringList dynamicLibsRelease: @dynamicLibsRelease@ property stringList staticLibs: qtBuildVariant === "debug" ? staticLibsDebug : staticLibsRelease property stringList dynamicLibs: qtBuildVariant === "debug" ? dynamicLibsDebug : dynamicLibsRelease property stringList linkerFlagsDebug: @linkerFlagsDebug@ property stringList linkerFlagsRelease: @linkerFlagsRelease@ property stringList coreLinkerFlags: qtBuildVariant === "debug" ? linkerFlagsDebug : linkerFlagsRelease property stringList frameworksDebug: @frameworksDebug@ property stringList frameworksRelease: @frameworksRelease@ property stringList coreFrameworks: qtBuildVariant === "debug" ? frameworksDebug : frameworksRelease property stringList frameworkPathsDebug: @frameworkPathsDebug@ property stringList frameworkPathsRelease: @frameworkPathsRelease@ property stringList coreFrameworkPaths: qtBuildVariant === "debug" ? frameworkPathsDebug : frameworkPathsRelease property string libNameForLinkerDebug: @libNameForLinkerDebug@ property string libNameForLinkerRelease: @libNameForLinkerRelease@ property string libNameForLinker: qtBuildVariant === "debug" ? libNameForLinkerDebug : libNameForLinkerRelease property string libFilePathDebug: @libFilePathDebug@ property string libFilePathRelease: @libFilePathRelease@ property string libFilePath: qtBuildVariant === "debug" ? libFilePathDebug : libFilePathRelease property bool useRPaths: qbs.targetOS.contains("linux") && !qbs.targetOS.contains("android") property stringList coreLibPaths: @libraryPaths@ property bool hasLibrary: true // These are deliberately not path types // We don't want to resolve them against the source directory property string generatedHeadersDir: product.buildDirectory + "/qt.headers" property string qdocOutputDir: product.buildDirectory + "/qdoc_html" property string qmDir: product.destinationDirectory property string qmBaseName: product.targetName property bool lreleaseMultiplexMode: false property stringList moduleConfig: @moduleConfig@ Properties { condition: moduleConfig.contains("use_gold_linker") cpp.linkerVariant: "gold" } Properties { condition: Utilities.versionCompare(version, "6") >= 0 cpp.cxxLanguageVersion: "c++17" } Properties { condition: Utilities.versionCompare(version, "6") < 0 && Utilities.versionCompare(version, "5.7.0") >= 0 cpp.cxxLanguageVersion: "c++11" } cpp.enableCompilerDefinesByLanguage: ["cpp"].concat( qbs.targetOS.contains("darwin") ? ["objcpp"] : []) cpp.defines: { var defines = @defines@; // ### QT_NO_DEBUG must be added if the current build variant is not derived // from the build variant "debug" if (!qbs.enableDebugCode) defines.push("QT_NO_DEBUG"); if (!enableKeywords) defines.push("QT_NO_KEYWORDS"); if (qbs.targetOS.containsAny(["ios", "tvos"])) { defines = defines.concat(["DARWIN_NO_CARBON", "QT_NO_CORESERVICES", "QT_NO_PRINTER", "QT_NO_PRINTDIALOG"]); if (Utilities.versionCompare(version, "5.6.0") < 0) defines.push("main=qtmn"); } if (qbs.toolchain.contains("msvc")) defines.push("_ENABLE_EXTENDED_ALIGNED_STORAGE"); return defines; } cpp.driverFlags: { var flags = []; if (qbs.toolchain.contains("gcc")) { if (config.contains("sanitize_undefined")) flags.push("-fsanitize=undefined"); if (config.contains("sanitize_thread")) flags.push("-fsanitize=thread"); if (config.contains("sanitize_memory")) flags.push("-fsanitize=memory"); } return flags; } cpp.includePaths: generatedHeadersDir cpp.systemIncludePaths: @includes@.concat(mkspecPath) cpp.libraryPaths: { var libPaths = [libPath]; if (staticBuild && pluginPath) libPaths.push(pluginPath + "/platforms"); libPaths = libPaths.concat(coreLibPaths); return libPaths; } cpp.staticLibraries: { var libs = []; if (qbs.targetOS.contains('windows') && !product.consoleApplication) { libs = libs.concat(qtBuildVariant === "debug" ? @entryPointLibsDebug@ : @entryPointLibsRelease@); } libs = libs.concat(staticLibs); return libs; } cpp.dynamicLibraries: dynamicLibs cpp.linkerFlags: coreLinkerFlags cpp.systemFrameworkPaths: coreFrameworkPaths.concat(frameworkBuild ? [libPath] : []) cpp.frameworks: { var frameworks = coreFrameworks if (frameworkBuild) frameworks.push(libNameForLinker); if (qbs.targetOS.contains('ios') && staticBuild) frameworks = frameworks.concat(["Foundation", "CoreFoundation"]); if (frameworks.length === 0) return undefined; return frameworks; } cpp.rpaths: useRPaths ? libPath : undefined Properties { condition: qbs.toolchain.contains("msvc") && config.contains("static_runtime") cpp.runtimeLibrary: "static" } Properties { condition: qbs.toolchain.contains("msvc") && !config.contains("static_runtime") cpp.runtimeLibrary: "dynamic" } Properties { condition: versionMajor >= 5 cpp.positionIndependentCode: true } cpp.cxxFlags: { var flags = []; if (qbs.toolchain.contains('msvc')) { if (versionMajor < 5) flags.push('/Zc:wchar_t-'); if (Utilities.versionCompare(version, "6.3") >= 0 && Utilities.versionCompare(cpp.compilerVersion, "19.10") >= 0) { flags.push("/permissive-"); } } if (qbs.toolchain.includes("emscripten") && multiThreading) flags.push("-pthread"); return flags; } Properties { condition: qbs.targetOS.contains('darwin') && qbs.toolchain.contains('clang') && config.contains('c++11') cpp.cxxStandardLibrary: "libc++" } Properties { condition: qbs.toolchain.includes("emscripten") cpp.driverLinkerFlags: { var flags = [ "-sMAX_WEBGL_VERSION=2", "-sFETCH=1", "-sWASM_BIGINT=1", "-sMODULARIZE", "-sEXPORT_NAME=createQtAppInstance", "-sALLOW_MEMORY_GROWTH", '-sASYNCIFY_IMPORTS=["qt_asyncify_suspend_js", "qt_asyncify_resume_js"]', '-sEXPORTED_RUNTIME_METHODS=["UTF16ToString", "stringToUTF16", "JSEvents", "specialHTMLTargets", "FS"]', "-lembind" ]; if (multiThreading) flags.push("-pthread") return flags; } } cpp.minimumWindowsVersion: @minWinVersion_optional@ cpp.minimumMacosVersion: @minMacVersion_optional@ cpp.minimumIosVersion: @minIosVersion_optional@ cpp.minimumTvosVersion: @minTvosVersion_optional@ cpp.minimumWatchosVersion: @minWatchosVersion_optional@ cpp.minimumAndroidVersion: @minAndroidVersion_optional@ // Universal Windows Platform support cpp.windowsApiFamily: mkspecName.startsWith("winrt-") ? "pc" : undefined cpp.windowsApiAdditionalPartitions: mkspecPath.startsWith("winrt-") ? ["phone"] : undefined cpp.requireAppContainer: mkspecName.startsWith("winrt-") additionalProductTypes: ["qm", "qt.core.metatypes"] validate: { var validator = new ModUtils.PropertyValidator("Qt.core"); validator.setRequiredProperty("binPath", binPath); validator.setRequiredProperty("incPath", incPath); validator.setRequiredProperty("libPath", libPath); validator.setRequiredProperty("mkspecPath", mkspecPath); validator.setRequiredProperty("version", version); validator.setRequiredProperty("config", config); validator.setRequiredProperty("qtConfig", qtConfig); validator.setRequiredProperty("versionMajor", versionMajor); validator.setRequiredProperty("versionMinor", versionMinor); validator.setRequiredProperty("versionPatch", versionPatch); if (!staticBuild) validator.setRequiredProperty("pluginPath", pluginPath); // Allow custom version suffix since some distributions might want to do this, // but otherwise the version must start with a valid 3-component string validator.addVersionValidator("version", version, 3, 3, true); validator.addRangeValidator("versionMajor", versionMajor, 1); validator.addRangeValidator("versionMinor", versionMinor, 0); validator.addRangeValidator("versionPatch", versionPatch, 0); validator.addCustomValidator("availableBuildVariants", availableBuildVariants, function (v) { return v.length > 0; }, "the Qt installation supports no build variants"); validator.addCustomValidator("qtBuildVariant", qtBuildVariant, function (variant) { return availableBuildVariants.contains(variant); }, "'" + qtBuildVariant + "' is not supported by this Qt installation"); validator.addCustomValidator("qtBuildVariant", qtBuildVariant, function (variant) { return variant === qbs.buildVariant || !qbs.toolchain.contains("msvc"); }, " is '" + qtBuildVariant + "', but qbs.buildVariant is '" + qbs.buildVariant + "', which is not allowed when using MSVC"); validator.addFileNameValidator("resourceFileBaseName", resourceFileBaseName); validator.validate(); } FileTagger { patterns: ["*.qrc"] fileTags: ["qrc"] } FileTagger { patterns: ["*.ts"] fileTags: ["ts"] } FileTagger { patterns: ["*.qdoc", "*.qdocinc"] fileTags: ["qdoc"] } FileTagger { patterns: ["*.qdocconf"] fileTags: ["qdocconf"] } FileTagger { patterns: ["*.qhp"] fileTags: ["qhp"] } property bool combineMocOutput: cpp.combineCxxSources property bool enableBigResources: false // Product should not moc in the aggregate when multiplexing. property bool enableMoc: !(product.multiplexed || product.aggregate) || product.multiplexConfigurationId Group { condition: enableMoc Rule { name: "QtCoreMocRuleCpp" property string cppInput: cpp.combineCxxSources ? "cpp.combine" : "cpp" property string objcppInput: cpp.combineObjcxxSources ? "objcpp.combine" : "objcpp" inputs: [objcppInput, cppInput] auxiliaryInputs: "qt_plugin_metadata" excludedInputs: "unmocable" outputFileTags: ["hpp", "unmocable", "qt.core.metatypes.in", "qt.untranslatable"] outputArtifacts: Moc.outputArtifacts.apply(Moc, arguments) prepare: Moc.commands.apply(Moc, arguments) } Rule { name: "QtCoreMocRuleHpp" inputs: "hpp" auxiliaryInputs: ["qt_plugin_metadata", "cpp", "objcpp"] excludedInputs: "unmocable" outputFileTags: ["hpp", "cpp", "moc_cpp", "unmocable", "qt.core.metatypes.in", "qt.untranslatable"] outputArtifacts: Moc.outputArtifacts.apply(Moc, arguments) prepare: Moc.commands.apply(Moc, arguments) } } Rule { multiplex: true inputs: ["moc_cpp"] Artifact { filePath: "amalgamated_moc_" + product.targetName + ".cpp" fileTags: ["cpp", "unmocable", "qt.untranslatable"] } prepare: Moc.generateMocCppCommands(inputs, output) } Rule { multiplex: true inputs: "qt.core.metatypes.in" Artifact { filePath: product.targetName.toLowerCase() + "_metatypes.json" fileTags: "qt.core.metatypes" qbs.install: product.Qt.core.metaTypesInstallDir qbs.installDir: product.Qt.core.metaTypesInstallDir } prepare: Moc.generateMetaTypesCommands(inputs, output) } property path resourceSourceBase property string resourcePrefix: "/" property string resourceFileBaseName: product.targetName Rule { multiplex: true inputs: ["qt.core.resource_data"] Artifact { filePath: product.Qt.core.resourceFileBaseName + ".qrc" fileTags: ["qrc"] } prepare: Rcc.generateQrcFileCommands.apply(Rcc, arguments) } Rule { inputs: ["qrc"] outputFileTags: ["cpp", "cpp_intermediate_object", "qt.untranslatable"] outputArtifacts: Rcc.rccOutputArtifacts(input) prepare: Rcc.rccCommands(product, input, output) } Rule { inputs: ["intermediate_obj"] Artifact { filePath: input.completeBaseName + ".2" + input.cpp.objectSuffix fileTags: ["obj"] } prepare: Rcc.rccPass2Commands(product, input, output) } Rule { inputs: ["ts"] multiplex: lreleaseMultiplexMode Artifact { filePath: FileInfo.joinPaths(product.Qt.core.qmDir, (product.Qt.core.lreleaseMultiplexMode ? product.Qt.core.qmBaseName : input.baseName) + ".qm") fileTags: ["qm"] } prepare: Core.lreleaseCommands.apply(Core, arguments) } Rule { inputs: "qdocconf-main" explicitlyDependsOn: ["qdoc", "qdocconf"] outputFileTags: ModUtils.allFileTags(Qdoc.qdocFileTaggers()) outputArtifacts: Qdoc.outputArtifacts(product, input) prepare: Qdoc.commands(product, input) } Rule { inputs: "qhp" auxiliaryInputs: ModUtils.allFileTags(Qdoc.qdocFileTaggers()) .filter(function(tag) { return tag !== "qhp"; }) Artifact { filePath: input.completeBaseName + ".qch" fileTags: ["qch"] } prepare: Core.qhelpGeneratorCommands(product, input, output) } Group { condition: qbs.toolchain.includes("emscripten") && (product.type.includes("application") && product.type.includes("qthtml")) Rule { inputs: ["application"] multiplex: true Artifact { filePath : FileInfo.joinPaths(product.buildDirectory, product.targetName + ".html") fileTags : ["qthtml"] } prepare: Core.wasmQtHtmlCommands(product, output) } Group { fileTags: ["qthtml"] files: [ module.pluginPath + "/platforms/qtloader.js", module.pluginPath + "/platforms/qtlogo.svg" ] } } @additionalContent@ } qbs-src-2.6.1/share/share.qbs0000644000175100001660000001103114776170045015357 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.TextFile import qbs.Utilities Product { name: "qbs resources" type: ["qbs qml type descriptions", "qbs qml type bundle"] Depends { name: "qbsbuildconfig" } Group { name: "Incredibuild" prefix: "../bin/" files: ["ibmsvc.xml", "ibqbs.bat"] fileTags: [] qbs.install: qbs.targetOS.contains("windows") qbs.installDir: qbsbuildconfig.appInstallDir } Group { name: "CMake" files: "CMakeLists.txt" } Group { name: "Python packages" prefix: "../src/3rdparty/python/**/" files: ["*.py"] fileTags: ["qbs resources"] qbs.install: true qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share/qbs/python" qbs.installSourceBase: "../src/3rdparty/python/lib/python3.9/site-packages" } Group { name: "Imports" files: ["qbs/imports/qbs/**/*"] fileTags: ["qbs resources"] qbs.install: true qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share" qbs.installSourceBase: "." } Group { name: "Modules" files: ["qbs/modules/**/*"] fileTags: ["qbs resources"] qbs.install: true qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share" qbs.installSourceBase: "." } Group { name: "Module providers" files: ["qbs/module-providers/*", "qbs/module-providers/**/*"] fileTags: ["qbs resources"] qbs.install: true qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share" qbs.installSourceBase: "." } Group { name: "Examples as resources" files: ["../examples/**/*"] fileTags: [] qbs.install: true qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share/qbs" qbs.installSourceBase: ".." } Rule { condition: Utilities.versionCompare(product.qbs.version, "1.9.1") >= 0 multiplex: true Artifact { filePath: "qbs.qmltypes" fileTags: ["qbs qml type descriptions"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(Utilities.qmlTypeInfo()); } finally { if (tf) tf.close(); } }; return cmd; } } Rule { condition: Utilities.versionCompare(product.qbs.version, "1.9.1") >= 0 multiplex: true Artifact { filePath: "qbs-bundle.json" fileTags: ["qbs qml type bundle"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var tf; try { var imports = File.directoryEntries(FileInfo.joinPaths(product.sourceDirectory, "qbs", "imports", "qbs"), File.Dirs | File.NoDotAndDotDot).filter( function(i) { return i !== "base"; }).concat( Utilities.builtinExtensionNames()).map( function(i) { return "qbs." + i; }); imports.sort(); var obj = { "name": "qbs", "searchPaths": ["$(QBS_IMPORT_PATH)"], "installPaths": ["$(QBS_IMPORT_PATH)"], "implicitImports": ["__javascriptQt5__"], "supportedImports": ["qbs"].concat(imports) }; tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(obj, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } Group { name: "QML Type Info" fileTagsFilter: ["qbs qml type descriptions", "qbs qml type bundle"] qbs.install: true qbs.installDir: qbsbuildconfig.qmlTypeDescriptionsInstallDir } } qbs-src-2.6.1/share/CMakeLists.txt0000644000175100001660000000712614776170045016320 0ustar runnerdockerif(WIN32) install( FILES ../bin/ibmsvc.xml ../bin/ibqbs.bat DESTINATION "${QBS_APP_INSTALL_DIR}" ) endif() # below we copy some files that are required to run qbs from the build directory # emulating the same layout we will have after the installation # copy & install python packages set(_SITE_PACKAGES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/3rdparty/python/lib/python3.9/site-packages/) file(GLOB_RECURSE _SITE_PACKAGES_RELATIVE RELATIVE "${_SITE_PACKAGES_DIR}" "${_SITE_PACKAGES_DIR}/*.py") set(_SITE_PACKAGES_SRC ${_SITE_PACKAGES_RELATIVE}) list_transform_prepend(_SITE_PACKAGES_SRC "${_SITE_PACKAGES_DIR}/") set(_SITE_PACKAGES_DST ${_SITE_PACKAGES_RELATIVE}) list_transform_prepend(_SITE_PACKAGES_DST "${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_RESOURCES_INSTALL_DIR}/qbs/python/") add_custom_command( OUTPUT ${_SITE_PACKAGES_DST} DEPENDS ${_SITE_PACKAGES_SRC} COMMAND ${CMAKE_COMMAND} -E copy_directory "${_SITE_PACKAGES_DIR}" ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_RESOURCES_INSTALL_DIR}/qbs/python COMMENT "Copying Python packages" ) install( # trailing slash avoid copying the 'site-packages' dir and only copies its content DIRECTORY "${_SITE_PACKAGES_DIR}" DESTINATION "${QBS_RESOURCES_INSTALL_DIR}/qbs/python" FILES_MATCHING PATTERN "*.py" ) # copy & install the "share/qbs" dir file(GLOB_RECURSE _QBS_RESOURCES_RELATIVE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/qbs/*") set(_QBS_RESOURCES_SRC ${_QBS_RESOURCES_RELATIVE}) list_transform_prepend(_QBS_RESOURCES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/") set(_QBS_RESOURCES_DST ${_QBS_RESOURCES_RELATIVE}) list_transform_prepend(_QBS_RESOURCES_DST "${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_RESOURCES_INSTALL_DIR}/") add_custom_command( OUTPUT ${_QBS_RESOURCES_DST} DEPENDS ${_QBS_RESOURCES_SRC} COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/qbs ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_RESOURCES_INSTALL_DIR}/qbs COMMENT "Copying QBS resources" ) install( DIRECTORY qbs DESTINATION "${QBS_RESOURCES_INSTALL_DIR}" PATTERN ".gitignore" EXCLUDE ) # install examples dir install( DIRECTORY ../examples DESTINATION "${QBS_RESOURCES_INSTALL_DIR}/qbs" ) set(_QMLTYPES_INSTALL_PATH "${PROJECT_BINARY_DIR}/resources-build/install-root/share/qbs/qml-type-descriptions/qbs.qmltypes") get_update_path_command(UPDATE_PATH_COMMAND) get_target_property(_QBS_OUTPUT_DIR qbs RUNTIME_OUTPUT_DIRECTORY) add_custom_command( OUTPUT "${_QMLTYPES_INSTALL_PATH}" COMMAND ${CMAKE_COMMAND} -E env "${UPDATE_PATH_COMMAND}" ${_QBS_OUTPUT_DIR}/qbs resolve --settings-dir ${PROJECT_BINARY_DIR}/settings -f ${PROJECT_SOURCE_DIR}/qbs.qbs -d ${PROJECT_BINARY_DIR}/ config:resources-build qbs.installPrefix:"" project.withCode:false project.withDocumentation:false profile:none COMMAND ${CMAKE_COMMAND} -E env "${UPDATE_PATH_COMMAND}" ${_QBS_OUTPUT_DIR}/qbs build --settings-dir ${PROJECT_BINARY_DIR}/settings -f ${PROJECT_SOURCE_DIR}/qbs.qbs -d ${PROJECT_BINARY_DIR}/ config:resources-build -p "qbs resources" DEPENDS qbs "${_QBS_RESOURCES_DST}" qbs_processlauncher ) add_custom_target( BuildQbsResources ALL DEPENDS ${_SITE_PACKAGES_DST} ${_QBS_RESOURCES_DST} "${_QMLTYPES_INSTALL_PATH}" ) install( DIRECTORY ${PROJECT_BINARY_DIR}/resources-build/install-root/share/qbs/qml-type-descriptions DESTINATION "${QBS_RESOURCES_INSTALL_DIR}/qbs" ) qbs-src-2.6.1/release/0000755000175100001660000000000014776170045014070 5ustar runnerdockerqbs-src-2.6.1/tests/0000755000175100001660000000000014776170045013612 5ustar runnerdockerqbs-src-2.6.1/tests/auto/0000755000175100001660000000000014776170045014562 5ustar runnerdockerqbs-src-2.6.1/tests/auto/tools/0000755000175100001660000000000014776170045015722 5ustar runnerdockerqbs-src-2.6.1/tests/auto/tools/tools.qbs0000644000175100001660000000045514776170045017575 0ustar runnerdockerimport qbs.Utilities QbsUnittest { Depends { name: "qbsversion" } testName: "tools" condition: qbsbuildconfig.enableUnitTests files: [ "tst_tools.cpp", "tst_tools.h" ] cpp.defines: base.concat(["QBS_VERSION=" + Utilities.cStringQuote(qbsversion.version)]) } qbs-src-2.6.1/tests/auto/tools/tst_tools.h0000644000175100001660000000663514776170045020137 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include QT_BEGIN_NAMESPACE class QTemporaryDir; QT_END_NAMESPACE namespace qbs { class Settings; } class TestTools : public QObject { Q_OBJECT public: TestTools(qbs::Settings *settings); ~TestTools(); public slots: virtual void initTestCase(); private slots: void fileSaver(); void fileCaseCheck(); void testBuildConfigMerging(); void testFileInfo(); void testProcessNameByPid(); void testProfiles(); void testSettingsMigration(); void testSettingsMigration_data(); void set_operator_eq(); void set_swap(); void set_size(); void set_capacity(); void set_reserve(); void set_clear(); void set_remove(); void set_contains(); void set_containsSet(); void set_find(); void set_begin(); void set_end(); void set_insert(); void set_reverseIterators(); void set_stlIterator(); void set_stlMutableIterator(); void set_setOperations(); void set_makeSureTheComfortFunctionsCompile(); void set_initializerList(); void set_intersects(); void stringutils_join(); void stringutils_join_data(); void stringutils_join_empty(); void stringutils_join_char(); void stringutils_join_char_data(); void stringutils_trimmed(); void hash_tuple(); void hash_range(); void span(); private: QString setupSettingsDir1(); QString setupSettingsDir2(); QString setupSettingsDir3(); qbs::Settings * const m_settings; QList m_tmpDirs; const QString testDataDir; }; qbs-src-2.6.1/tests/auto/tools/tst_tools.cpp0000644000175100001660000010745714776170045020476 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack. #include "tst_tools.h" #include "../shared.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using namespace qbs::Internal; namespace std { template struct hash> { std::size_t operator()(const std::vector &v) const noexcept { return hashRange(v); } }; } // namespace std TestTools::TestTools(Settings *settings) : m_settings(settings), testDataDir(testWorkDir("tools")) { } TestTools::~TestTools() { qDeleteAll(m_tmpDirs); } void TestTools::initTestCase() { QDir().mkpath(testDataDir); } void TestTools::fileSaver() { QVERIFY(QDir::setCurrent(testDataDir)); static const char *fn = "foo.txt"; const auto run = [](const std::function &func) { if (QFile::exists(fn)) QVERIFY(QFile::remove(fn)); func(); if (QFile::exists(fn)) QVERIFY(QFile::remove(fn)); }; // failing to open the file means nothing works run([] { Internal::FileSaver fs(fn); QVERIFY(!fs.device()); QVERIFY(!fs.write("hello")); QVERIFY(!fs.commit()); QVERIFY(!QFile::exists(fn)); }); // verify that correct usage creates a file with the right contents run([] { Internal::FileSaver fs(fn); QVERIFY(fs.open()); QVERIFY(fs.device()); QVERIFY(fs.write("hello")); QVERIFY(fs.commit()); QVERIFY(QFile::exists(fn)); QFile f(fn); QVERIFY(f.open(QIODevice::ReadOnly)); QCOMPARE(f.readAll(), QByteArrayLiteral("hello")); }); // failing to commit writes nothing run([] { Internal::FileSaver fs(fn); QVERIFY(fs.open()); QVERIFY(fs.device()); QVERIFY(fs.write("hello")); QVERIFY(!QFile::exists(fn)); }); // verify that correct usage creates a file with the right contents and does not overwrite run([] { { Internal::FileSaver fs(fn); QVERIFY(fs.open()); QVERIFY(fs.device()); QVERIFY(fs.write("hello")); QVERIFY(fs.commit()); QVERIFY(QFile::exists(fn)); QFile f(fn); QVERIFY(f.open(QIODevice::ReadOnly)); QCOMPARE(f.readAll(), QByteArrayLiteral("hello")); } const auto lm = QFileInfo(fn).lastModified(); QVERIFY(lm.isValid()); waitForNewTimestamp("."); { Internal::FileSaver fs(fn); QVERIFY(fs.open()); QVERIFY(fs.device()); QVERIFY(fs.write("hello")); QVERIFY(fs.commit()); QVERIFY(QFile::exists(fn)); } const auto lm2 = QFileInfo(fn).lastModified(); QVERIFY(lm2.isValid()); QCOMPARE(lm, lm2); // timestamps should be the same since content did not change waitForNewTimestamp("."); { Internal::FileSaver fs(fn); QVERIFY(fs.open()); QVERIFY(fs.device()); QVERIFY(fs.write("hello2")); QVERIFY(fs.commit()); QVERIFY(QFile::exists(fn)); QFile f(fn); QVERIFY(f.open(QIODevice::ReadOnly)); QCOMPARE(f.readAll(), QByteArrayLiteral("hello2")); } const auto lm3 = QFileInfo(fn).lastModified(); QVERIFY(lm3.isValid()); QVERIFY(lm != lm3); // timestamps should differ since the content changed waitForNewTimestamp("."); { // Test overwriteIfUnchanged Internal::FileSaver fs(fn, true); QVERIFY(fs.open()); QVERIFY(fs.device()); QVERIFY(fs.write("hello2")); QVERIFY(fs.commit()); QVERIFY(QFile::exists(fn)); QFile f(fn); QVERIFY(f.open(QIODevice::ReadOnly)); QCOMPARE(f.readAll(), QByteArrayLiteral("hello2")); } const auto lm4 = QFileInfo(fn).lastModified(); QVERIFY(lm4.isValid()); QVERIFY(lm3 != lm4); // timestamps should differ since we always overwrite }); } void TestTools::testFileInfo() { QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe")); QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter")); QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe")); QCOMPARE(FileInfo::suffix("C:/waffl/copter.exe.lib"), QString("lib")); QCOMPARE(FileInfo::completeSuffix("C:/waffl/copter.exe.lib"), QString("exe.lib")); QCOMPARE(FileInfo::path("abc"), QString(".")); QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc")); QCOMPARE(FileInfo::path("/fileInRoot"), QString(QLatin1Char('/'))); if (HostOsInfo::isWindowsHost()) QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/")); QVERIFY(!FileInfo::isAbsolute("bla/lol")); QVERIFY(FileInfo::isAbsolute("/bla/lol")); if (HostOsInfo::isWindowsHost()) { QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol")); QVERIFY(FileInfo::isAbsolute("C:\\")); QVERIFY(FileInfo::isAbsolute("C:/")); QVERIFY(!FileInfo::isAbsolute("C:")); } QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl")); QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar")); QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar")); QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar")); if (HostOsInfo::isWindowsHost()) { QCOMPARE(FileInfo::resolvePath("C:/share", ".."), QString("C:/")); QCOMPARE(FileInfo::resolvePath("C:/share", "D:/"), QString("D:/")); QCOMPARE(FileInfo::resolvePath("C:/share", "D:"), QString()); // should soft-assert } QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime()); } void TestTools::fileCaseCheck() { QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/CamelCase")); QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString())); QFileInfo tempFileInfo(tempFile.fileName()); const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/') + tempFileInfo.fileName().toLower(); const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/') + tempFileInfo.fileName().toUpper(); QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath())); if (QFile::exists(lowerFilePath)) QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath)); if (QFile::exists(upperFilePath)) QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath)); } void TestTools::testProfiles() { TemporaryProfile tpp("parent", m_settings); Profile parentProfile = tpp.p; TemporaryProfile tpc("child", m_settings); Profile childProfile = tpc.p; parentProfile.removeBaseProfile(); parentProfile.remove("testKey"); QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none")); parentProfile.setValue("testKey", "testValue"); QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue")); childProfile.remove("testKey"); childProfile.removeBaseProfile(); QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none")); childProfile.setBaseProfile("parent"); QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue")); // Change base profile and check if the inherited value also changes. TemporaryProfile tpf("foo", m_settings); Profile fooProfile = tpf.p; fooProfile.setValue("testKey", "gnampf"); childProfile.setBaseProfile("foo"); QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf")); ErrorInfo errorInfo; childProfile.setBaseProfile("SmurfAlongWithMe"); childProfile.value("blubb", QString(), &errorInfo); QVERIFY(errorInfo.hasError()); errorInfo.clear(); childProfile.setBaseProfile("parent"); parentProfile.setBaseProfile("child"); QVERIFY(!childProfile.value("blubb", QString(), &errorInfo).isValid()); QVERIFY(errorInfo.hasError()); QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).empty()); errorInfo.clear(); QVERIFY(childProfile.allKeys(Profile::KeySelectionRecursive, &errorInfo).empty()); QVERIFY(errorInfo.hasError()); } void TestTools::testSettingsMigration() { QFETCH(QString, baseDir); QFETCH(bool, hasOldSettings); Settings settings(baseDir); if (hasOldSettings) { // checks that we do not copy old "profiles/" dir anymore QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt") .exists()); QVERIFY(!settings.value("key", Settings::UserScope).toString().isEmpty()); } else { QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists()); QVERIFY(settings.allKeys(Settings::UserScope).empty()); } } void TestTools::testSettingsMigration_data() { QTest::addColumn("baseDir"); QTest::addColumn("hasOldSettings"); QTest::newRow("settings dir with lots of versions") << setupSettingsDir1() << true; QTest::newRow("settings dir with only a fallback") << setupSettingsDir2() << true; QTest::newRow("no previous settings") << setupSettingsDir3() << false; } QString TestTools::setupSettingsDir1() { const auto baseDir = new QTemporaryDir; m_tmpDirs.push_back(baseDir); const Version thisVersion = Version::fromString(QBS_VERSION); Version predecessor; if (thisVersion.patchLevel() > 0) { predecessor.setMajorVersion(thisVersion.majorVersion()); predecessor.setMinorVersion(thisVersion.minorVersion()); predecessor.setPatchLevel(thisVersion.patchLevel() - 1); } else if (thisVersion.minorVersion() > 0) { predecessor.setMajorVersion(thisVersion.majorVersion()); predecessor.setMinorVersion(thisVersion.minorVersion() - 1); predecessor.setPatchLevel(99); } else { predecessor.setMajorVersion(thisVersion.majorVersion() - 1); predecessor.setMajorVersion(99); predecessor.setPatchLevel(99); } const auto versions = QList() << Version(0, 1, 0) << Version(1, 0, 5) << predecessor << Version(thisVersion.majorVersion() + 1, thisVersion.minorVersion(), thisVersion.patchLevel()) << Version(thisVersion.majorVersion(), thisVersion.minorVersion() + 1, thisVersion.patchLevel()) << Version(thisVersion.majorVersion(), thisVersion.minorVersion(), thisVersion.patchLevel() + 1) << Version(99, 99, 99); for (const Version &v : versions) { const QString settingsDir = baseDir->path() + "/qbs/" + v.toString(); QSettings s(settingsDir + "/qbs.conf", HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat); const QString profilesDir = settingsDir + "/profiles"; QDir::root().mkpath(profilesDir); const QString magicString = v == predecessor ? "right" : "wrong"; QFile f(profilesDir + '/' + magicString + ".txt"); f.open(QIODevice::WriteOnly); s.setValue("org/qt-project/qbs/key", profilesDir + magicString); } return baseDir->path(); } QString TestTools::setupSettingsDir2() { const auto baseDir = new QTemporaryDir; m_tmpDirs.push_back(baseDir); const QString settingsDir = baseDir->path(); QSettings s(settingsDir + QLatin1String("/qbs.conf"), HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat); const QString profilesDir = settingsDir + QLatin1String("/qbs/profiles"); QDir::root().mkpath(profilesDir); QFile f(profilesDir + "/right.txt"); f.open(QIODevice::WriteOnly); s.setValue("org/qt-project/qbs/key", profilesDir + "right"); return baseDir->path(); } QString TestTools::setupSettingsDir3() { const auto baseDir = new QTemporaryDir; m_tmpDirs.push_back(baseDir); return baseDir->path(); } void TestTools::testBuildConfigMerging() { TemporaryProfile tp(QLatin1String("tst_tools_profile"), m_settings); Profile profile = tp.p; profile.setValue(QStringLiteral("topLevelKey"), QStringLiteral("topLevelValue")); profile.setValue(QStringLiteral("qbs.toolchain"), QStringLiteral("gcc")); profile.setValue(QStringLiteral("qbs.architecture"), QStringLiteral("Jean-Claude Pillemann")); profile.setValue(QStringLiteral("cpp.treatWarningsAsErrors"), true); QVariantMap overrideMap; overrideMap.insert(QStringLiteral("qbs.toolchain"), QStringLiteral("clang")); overrideMap.insert(QStringLiteral("qbs.installRoot"), QStringLiteral("/blubb")); SetupProjectParameters params; params.setSettingsDirectory(m_settings->baseDirectory()); params.setTopLevelProfile(profile.name()); params.setConfigurationName(QStringLiteral("debug")); params.setOverriddenValues(overrideMap); const ErrorInfo error = params.expandBuildConfiguration(); QVERIFY2(!error.hasError(), qPrintable(error.toString())); const QVariantMap finalMap = params.finalBuildConfigurationTree(); QCOMPARE(finalMap.size(), 3); QCOMPARE(finalMap.value(QStringLiteral("topLevelKey")).toString(), QStringLiteral("topLevelValue")); const QVariantMap finalQbsMap = finalMap.value(QStringLiteral("qbs")).toMap(); QCOMPARE(finalQbsMap.size(), 4); QCOMPARE(finalQbsMap.value(QStringLiteral("toolchain")).toString(), QStringLiteral("clang")); QCOMPARE(finalQbsMap.value(QStringLiteral("configurationName")).toString(), QStringLiteral("debug")); QCOMPARE(finalQbsMap.value(QStringLiteral("architecture")).toString(), QStringLiteral("Jean-Claude Pillemann")); QCOMPARE(finalQbsMap.value(QStringLiteral("installRoot")).toString(), QLatin1String("/blubb")); const QVariantMap finalCppMap = finalMap.value(QStringLiteral("cpp")).toMap(); QCOMPARE(finalCppMap.size(), 1); QCOMPARE(finalCppMap.value(QStringLiteral("treatWarningsAsErrors")).toBool(), true); } void TestTools::testProcessNameByPid() { QCOMPARE(qAppName(), processNameByPid(QCoreApplication::applicationPid())); } int toNumber(const QString &str) { int res = 0; for (const QChar &c : str) res = (res * 10) + c.digitValue(); return res; } void TestTools::set_operator_eq() { { Set set1, set2; QVERIFY(set1 == set2); QVERIFY(!(set1 != set2)); set1.insert(1); QVERIFY(set1 != set2); QVERIFY(!(set1 == set2)); set2.insert(1); QVERIFY(set1 == set2); QVERIFY(!(set1 != set2)); set2.insert(1); QVERIFY(set1 == set2); QVERIFY(!(set1 != set2)); set1.insert(2); QVERIFY(set1 != set2); QVERIFY(!(set1 == set2)); } { Set set1, set2; QVERIFY(set1 == set2); QVERIFY(!(set1 != set2)); set1.insert("one"); QVERIFY(set1 != set2); QVERIFY(!(set1 == set2)); set2.insert("one"); QVERIFY(set1 == set2); QVERIFY(!(set1 != set2)); set2.insert("one"); QVERIFY(set1 == set2); QVERIFY(!(set1 != set2)); set1.insert("two"); QVERIFY(set1 != set2); QVERIFY(!(set1 == set2)); } { Set a; Set b; a += "otto"; b += "willy"; QVERIFY(a != b); QVERIFY(!(a == b)); } { Set s1, s2; s1.reserve(100); s2.reserve(4); QVERIFY(s1 == s2); s1 << 100 << 200 << 300 << 400; s2 << 400 << 300 << 200 << 100; QVERIFY(s1 == s2); } } void TestTools::set_swap() { Set s1, s2; s1.insert(1); s2.insert(2); s1.swap(s2); QCOMPARE(*s1.begin(),2); QCOMPARE(*s2.begin(),1); } void TestTools::set_size() { Set set; QVERIFY(set.size() == 0); QVERIFY(set.empty()); QVERIFY(set.size() == set.size()); set.insert(1); QVERIFY(set.size() == 1); QVERIFY(!set.empty()); QVERIFY(set.size() == set.size()); set.insert(1); QVERIFY(set.size() == 1); QVERIFY(!set.empty()); QVERIFY(set.size() == set.size()); set.insert(2); QVERIFY(set.size() == 2); QVERIFY(!set.empty()); QVERIFY(set.size() == set.size()); set.remove(1); QVERIFY(set.size() == 1); QVERIFY(!set.empty()); QVERIFY(set.size() == set.size()); set.remove(1); QVERIFY(set.size() == 1); QVERIFY(!set.empty()); QVERIFY(set.size() == set.size()); set.remove(2); QVERIFY(set.size() == 0); QVERIFY(set.empty()); QVERIFY(set.size() == set.size()); } void TestTools::set_capacity() { Set set; size_t n = set.capacity(); QVERIFY(n == 0); for (int i = 0; i < 1000; ++i) { set.insert(i); QVERIFY(set.capacity() >= set.size()); } } void TestTools::set_reserve() { Set set; set.reserve(1000); QVERIFY(set.capacity() >= 1000); for (int i = 0; i < 500; ++i) set.insert(i); QVERIFY(set.capacity() >= 1000); for (int j = 0; j < 500; ++j) set.remove(j); QVERIFY(set.capacity() >= 1000); } void TestTools::set_clear() { Set set1, set2; QVERIFY(set1.size() == 0); set1.clear(); QVERIFY(set1.size() == 0); set1.insert("foo"); QVERIFY(set1.size() != 0); set2 = set1; set1.clear(); QVERIFY(set1.size() == 0); QVERIFY(set2.size() != 0); set2.clear(); QVERIFY(set1.size() == 0); QVERIFY(set2.size() == 0); } void TestTools::set_remove() { Set set1; const size_t max = 500; for (size_t i = 0; i < max; ++i) set1.insert(QString::number(i)); QCOMPARE(set1.size(), max); for (size_t j = 0; j < max; ++j) { set1.remove(QString::number((j * 17) % max)); QCOMPARE(set1.size(), max - j - 1); } } void TestTools::set_contains() { Set set1; for (int i = 0; i < 500; ++i) { QVERIFY(!set1.contains(QString::number(i))); set1.insert(QString::number(i)); QVERIFY(set1.contains(QString::number(i))); } QCOMPARE(set1.size(), size_t { 500 }); for (int j = 0; j < 500; ++j) { int i = (j * 17) % 500; QVERIFY(set1.contains(QString::number(i))); set1.remove(QString::number(i)); QVERIFY(!set1.contains(QString::number(i))); } } void TestTools::set_containsSet() { Set set1; Set set2; // empty set contains the empty set QVERIFY(set1.contains(set2)); for (int i = 0; i < 500; ++i) { set1.insert(QString::number(i)); set2.insert(QString::number(i)); } QVERIFY(set1.contains(set2)); set2.remove(QString::number(19)); set2.remove(QString::number(82)); set2.remove(QString::number(7)); QVERIFY(set1.contains(set2)); set1.remove(QString::number(23)); QVERIFY(!set1.contains(set2)); // filled set contains the empty set as well Set set3; QVERIFY(set1.contains(set3)); // the empty set doesn't contain a filled set QVERIFY(!set3.contains(set1)); // verify const signature const Set set4; QVERIFY(set3.contains(set4)); } void TestTools::set_find() { Set set1; for (int i = 0; i < 500; ++i) { QVERIFY(set1.find(QString::number(i)) == set1.end()); set1.insert(QString::number(i)); const auto it = set1.find(QString::number(i)); QVERIFY(it != set1.end()); QVERIFY(*it == QString::number(i)); } QCOMPARE(set1.size(), size_t { 500 }); for (int j = 0; j < 500; ++j) { int i = (j * 17) % 500; const auto it = set1.find(QString::number(i)); QVERIFY(it != set1.end()); QVERIFY(*it == QString::number(i)); set1.remove(QString::number(i)); QVERIFY(set1.find(QString::number(i)) == set1.end()); } } void TestTools::set_begin() { Set set1; Set set2 = set1; { const auto i = set1.constBegin(); const auto j = set1.cbegin(); const auto k = set2.constBegin(); const auto ell = set2.cbegin(); QVERIFY(i == j); QVERIFY(k == ell); } set1.insert(44); { const auto i = set1.constBegin(); const auto j = set1.cbegin(); const auto k = set2.constBegin(); const auto ell = set2.cbegin(); QVERIFY(i == j); QVERIFY(k == ell); } set2 = set1; { const auto i = set1.constBegin(); const auto j = set1.cbegin(); const auto k = set2.constBegin(); const auto ell = set2.cbegin(); QVERIFY(i == j); QVERIFY(k == ell); } } void TestTools::set_end() { Set set1; Set set2 = set1; { const auto i = set1.constEnd(); const auto j = set1.cend(); const auto k = set2.constEnd(); const auto ell = set2.cend(); QVERIFY(i == j); QVERIFY(k == ell); QVERIFY(set1.constBegin() == set1.constEnd()); QVERIFY(set2.constBegin() == set2.constEnd()); } set1.insert(44); { const auto i = set1.constEnd(); const auto j = set1.cend(); const auto k = set2.constEnd(); const auto ell = set2.cend(); QVERIFY(i == j); QVERIFY(k == ell); QVERIFY(set1.constBegin() != set1.constEnd()); QVERIFY(set2.constBegin() == set2.constEnd()); } set2 = set1; { const auto i = set1.constEnd(); const auto j = set1.cend(); const auto k = set2.constEnd(); const auto ell = set2.cend(); QVERIFY(i == j); QVERIFY(k == ell); QVERIFY(set1.constBegin() != set1.constEnd()); QVERIFY(set2.constBegin() != set2.constEnd()); } set1.clear(); set2.clear(); QVERIFY(set1.constBegin() == set1.constEnd()); QVERIFY(set2.constBegin() == set2.constEnd()); } struct IdentityTracker { int value, id; }; inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; } inline bool operator<(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value < rhs.value; } void TestTools::set_insert() { { Set set1; QVERIFY(set1.size() == 0); set1.insert(1); QVERIFY(set1.size() == 1); set1.insert(2); QVERIFY(set1.size() == 2); set1.insert(2); QVERIFY(set1.size() == 2); QVERIFY(set1.contains(2)); set1.remove(2); QVERIFY(set1.size() == 1); QVERIFY(!set1.contains(2)); set1.insert(2); QVERIFY(set1.size() == 2); QVERIFY(set1.contains(2)); } { Set set1; QVERIFY(set1.size() == 0); set1 << 1; QVERIFY(set1.size() == 1); set1 << 2; QVERIFY(set1.size() == 2); set1 << 2; QVERIFY(set1.size() == 2); QVERIFY(set1.contains(2)); set1.remove(2); QVERIFY(set1.size() == 1); QVERIFY(!set1.contains(2)); set1 << 2; QVERIFY(set1.size() == 2); QVERIFY(set1.contains(2)); } { Set set; QCOMPARE(set.size(), size_t { 0 }); const int dummy = -1; IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy}; QCOMPARE(set.insert(id00).first->id, id00.id); QCOMPARE(set.size(), size_t { 1 }); QCOMPARE(set.insert(id01).first->id, id00.id); // first inserted is kept QCOMPARE(set.size(), size_t { 1 }); QCOMPARE(set.find(searchKey)->id, id00.id); } } void TestTools::set_reverseIterators() { Set s; s << 1 << 17 << 61 << 127 << 911; std::vector v(s.begin(), s.end()); std::reverse(v.begin(), v.end()); const Set &cs = s; QVERIFY(std::equal(v.begin(), v.end(), s.rbegin())); QVERIFY(std::equal(v.begin(), v.end(), s.crbegin())); QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin())); QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin())); QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin())); QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin())); } void TestTools::set_stlIterator() { Set set1; for (int i = 0; i < 25000; ++i) set1.insert(QString::number(i)); { int sum = 0; auto i = set1.cbegin(); while (i != set1.end()) { sum += toNumber(*i); ++i; } QVERIFY(sum == 24999 * 25000 / 2); } { int sum = 0; auto i = set1.cend(); while (i != set1.begin()) { --i; sum += toNumber(*i); } QVERIFY(sum == 24999 * 25000 / 2); } } void TestTools::set_stlMutableIterator() { Set set1; for (int i = 0; i < 25000; ++i) set1.insert(QString::number(i)); { int sum = 0; auto i = set1.begin(); while (i != set1.end()) { sum += toNumber(*i); ++i; } QVERIFY(sum == 24999 * 25000 / 2); } { int sum = 0; auto i = set1.end(); while (i != set1.begin()) { --i; sum += toNumber(*i); } QVERIFY(sum == 24999 * 25000 / 2); } { Set set2 = set1; Set set3 = set2; auto i = set2.begin(); auto j = set3.begin(); while (i != set2.end()) { i = set2.erase(i); } QVERIFY(set2.empty()); QVERIFY(!set3.empty()); j = set3.end(); while (j != set3.begin()) { j--; if (j + 1 != set3.end()) set3.erase(j + 1); } if (set3.begin() != set3.end()) set3.erase(set3.begin()); QVERIFY(set2.empty()); QVERIFY(set3.empty()); i = set2.insert("foo").first; QCOMPARE(*i, QLatin1String("foo")); } } void TestTools::set_setOperations() { Set set1, set2; set1 << "alpha" << "beta" << "gamma" << "delta" << "zeta" << "omega"; set2 << "beta" << "gamma" << "delta" << "epsilon" << "iota" << "omega"; Set set3 = set1; set3.unite(set2); QVERIFY(set3.size() == 8); QVERIFY(set3.contains("alpha")); QVERIFY(set3.contains("beta")); QVERIFY(set3.contains("gamma")); QVERIFY(set3.contains("delta")); QVERIFY(set3.contains("epsilon")); QVERIFY(set3.contains("zeta")); QVERIFY(set3.contains("iota")); QVERIFY(set3.contains("omega")); Set set4 = set2; set4.unite(set1); QVERIFY(set4.size() == 8); QVERIFY(set4.contains("alpha")); QVERIFY(set4.contains("beta")); QVERIFY(set4.contains("gamma")); QVERIFY(set4.contains("delta")); QVERIFY(set4.contains("epsilon")); QVERIFY(set4.contains("zeta")); QVERIFY(set4.contains("iota")); QVERIFY(set4.contains("omega")); QVERIFY(set3 == set4); Set set5 = set1; set5.intersect(set2); QVERIFY(set5.size() == 4); QVERIFY(set5.contains("beta")); QVERIFY(set5.contains("gamma")); QVERIFY(set5.contains("delta")); QVERIFY(set5.contains("omega")); Set set6 = set2; set6.intersect(set1); QVERIFY(set6.size() == 4); QVERIFY(set6.contains("beta")); QVERIFY(set6.contains("gamma")); QVERIFY(set6.contains("delta")); QVERIFY(set6.contains("omega")); QVERIFY(set5 == set6); Set set7 = set1; set7.subtract(set2); QVERIFY(set7.size() == 2); QVERIFY(set7.contains("alpha")); QVERIFY(set7.contains("zeta")); Set set8 = set2; set8.subtract(set1); QVERIFY(set8.size() == 2); QVERIFY(set8.contains("epsilon")); QVERIFY(set8.contains("iota")); Set set9 = set1 | set2; QVERIFY(set9 == set3); Set set10 = set1 & set2; QVERIFY(set10 == set5); Set set11 = set1 + set2; QVERIFY(set11 == set3); Set set12 = set1 - set2; QVERIFY(set12 == set7); Set set13 = set2 - set1; QVERIFY(set13 == set8); Set set14 = set1; set14 |= set2; QVERIFY(set14 == set3); Set set15 = set1; set15 &= set2; QVERIFY(set15 == set5); Set set16 = set1; set16 += set2; QVERIFY(set16 == set3); Set set17 = set1; set17 -= set2; QVERIFY(set17 == set7); Set set18 = set2; set18 -= set1; QVERIFY(set18 == set8); } void TestTools::set_makeSureTheComfortFunctionsCompile() { Set set1, set2, set3; set1 << 5; set1 |= set2; set1 |= 5; set1 &= set2; set1 &= 5; set1 += set2; set1 += 5; set1 -= set2; set1 -= 5; set1 = set2 | set3; set1 = set2 & set3; set1 = set2 + set3; set1 = set2 - set3; } void TestTools::set_initializerList() { Set set = {1, 1, 2, 3, 4, 5}; QCOMPARE(set.size(), size_t { 5 }); QVERIFY(set.contains(1)); QVERIFY(set.contains(2)); QVERIFY(set.contains(3)); QVERIFY(set.contains(4)); QVERIFY(set.contains(5)); // check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last): const Set set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; QCOMPARE(set2.size(), size_t { 5 }); const int dummy = -1; const IdentityTracker searchKey = {1, dummy}; QCOMPARE(set2.find(searchKey)->id, 0); Set emptySet{}; QVERIFY(emptySet.empty()); Set set3{{}, {}, {}}; QVERIFY(!set3.empty()); } void TestTools::set_intersects() { Set s1; Set s2; QVERIFY(!s1.intersects(s1)); QVERIFY(!s1.intersects(s2)); s1 << 100; QVERIFY(s1.intersects(s1)); QVERIFY(!s1.intersects(s2)); s2 << 200; QVERIFY(!s1.intersects(s2)); s1 << 200; QVERIFY(s1.intersects(s2)); Set s3; s3 << 500; QVERIFY(!s1.intersects(s3)); s3 << 200; QVERIFY(s1.intersects(s3)); } void TestTools::stringutils_join() { QFETCH(std::vector, input); QFETCH(std::string, separator); QFETCH(std::string, expectedResult); QCOMPARE(join(input, separator), expectedResult); } void TestTools::stringutils_join_data() { QTest::addColumn>("input"); QTest::addColumn("separator"); QTest::addColumn("expectedResult"); QTest::newRow("data1") << std::vector() << std::string() << std::string(); QTest::newRow("data2") << std::vector() << std::string("separator") << std::string(); QTest::newRow("data3") << std::vector({"one"}) << std::string("separator") << std::string("one"); QTest::newRow("data4") << std::vector({"one"}) << std::string("separator") << std::string("one"); QTest::newRow("data5") << std::vector({"a", "b"}) << std::string(" ") << std::string("a b"); QTest::newRow("data6") << std::vector({"a", "b", "c"}) << std::string(" ") << std::string("a b c"); } void TestTools::stringutils_join_empty() { std::vector list; std::string string = join(list, std::string()); QVERIFY(string.empty()); } void TestTools::stringutils_join_char() { QFETCH(std::vector, input); QFETCH(char, separator); QFETCH(std::string, expectedResult); QCOMPARE(join(input, separator), expectedResult); } void TestTools::stringutils_join_char_data() { QTest::addColumn>("input"); QTest::addColumn("separator"); QTest::addColumn("expectedResult"); QTest::newRow("data1") << std::vector() << ' ' << std::string(); QTest::newRow("data5") << std::vector({"a", "b"}) << ' ' << std::string("a b"); QTest::newRow("data6") << std::vector({"a", "b", "c"}) << ' ' << std::string("a b c"); } void TestTools::stringutils_trimmed() { std::string a; a = "Text"; QCOMPARE(a, std::string("Text")); QCOMPARE(trimmed(a), std::string("Text")); QCOMPARE(a, std::string("Text")); a = " "; QCOMPARE(trimmed(a), std::string("")); QCOMPARE(a, std::string(" ")); a = " a "; QCOMPARE(trimmed(a), std::string("a")); a = "Text"; QCOMPARE(trimmed(std::move(a)), std::string("Text")); a = " "; QCOMPARE(trimmed(std::move(a)), std::string("")); a = " a "; QCOMPARE(trimmed(std::move(a)), std::string("a")); } void TestTools::hash_tuple() { using Key = std::tuple; Key key0{0, 5}; Key key1{10, 20}; Key key2{30, 40}; std::unordered_map map; map.insert({key1, 1}); map.insert({key2, 2}); QCOMPARE(map[key0], 0); QCOMPARE(map[key1], 1); QCOMPARE(map[key2], 2); } void TestTools::hash_range() { using Key = std::vector; Key key0; Key key1{1}; Key key2{1, 2}; std::unordered_map map; map.insert({key1, 1}); map.insert({key2, 2}); QCOMPARE(map[key0], 0); QCOMPARE(map[key1], 1); QCOMPARE(map[key2], 2); } void TestTools::span() { std::vector vec; qbs::Internal::span span(vec); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); const SettingsPtr s = settings(); TestTools tt(s.get()); return QTest::qExec(&tt, argc, argv); } qbs-src-2.6.1/tests/auto/tools/CMakeLists.txt0000644000175100001660000000020414776170045020456 0ustar runnerdockeradd_qbs_test(tools DEFINES "QBS_VERSION=\"${QBS_VERSION}\"" SOURCES tst_tools.cpp tst_tools.h ) qbs-src-2.6.1/tests/auto/language/0000755000175100001660000000000014776170045016345 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/tst_language.h0000644000175100001660000001656114776170045021204 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_LANGUAGE_H #define TST_LANGUAGE_H #include #include #include #include #include #include #include #include class TestLanguage : public QObject { Q_OBJECT public: TestLanguage(qbs::ILogSink *logSink, qbs::Settings *settings); ~TestLanguage(); private slots: void init(); void initTestCase(); void additionalProductTypes(); void baseProperty(); void baseValidation(); void brokenDependencyCycle(); void brokenDependencyCycle_data(); void buildConfigStringListSyntax(); void builtinFunctionInSearchPathsProperty(); void chainedProbes(); void canonicalArchitecture(); void conditionalDepends(); void convertStringList(); void correctDeclInParentLookup(); void delayedError(); void delayedError_data(); void dependencyOnAllProfiles(); void dependsItemInGroup_data(); void dependsItemInGroup(); void derivedSubProject(); void disabledPropertiesItem_data(); void disabledPropertiesItem(); void disabledSubProject(); void dottedNames_data(); void dottedNames(); void duplicateMultiplexValues_data(); void duplicateMultiplexValues(); void emptyJsFile(); void enumerateProjectProperties(); void evalErrorInNonPresentModule_data(); void evalErrorInNonPresentModule(); void environmentVariable(); void errorInDisabledProduct(); void erroneousFiles_data(); void erroneousFiles(); void exports(); void fileContextProperties(); void fileInProductAndModule_data(); void fileInProductAndModule(); void fileTags_data(); void fileTags(); void groupConditions_data(); void groupConditions(); void groupName(); void getNativeSetting(); void homeDirectory(); void identifierSearch_data(); void identifierSearch(); void idUsage(); void idUniqueness(); void importCollection(); void inheritedPropertiesItems_data(); void inheritedPropertiesItems(); void invalidBindingInDisabledItem(); void invalidOverrides(); void invalidOverrides_data(); void invalidPropOnNonRequiredModule_data(); void invalidPropOnNonRequiredModule(); void itemPrototype(); void itemScope(); void jsExtensions(); void jsImportUsedInMultipleScopes_data(); void jsImportUsedInMultipleScopes(); void keepLoadingDependencies(); void localProfileAsTopLevelProfile(); void moduleMergingVariantValues(); void moduleNameCollisions_data(); void moduleNameCollisions(); void moduleParameters_data(); void moduleParameters(); void modulePrioritizationBySearchPath_data(); void modulePrioritizationBySearchPath(); void moduleProperties_data(); void moduleProperties(); void modulePropertiesInGroups(); void modulePropertyOverridesPerProduct(); void moduleScope(); void moduleWithProductDependency(); void modules_data(); void modules(); void multiplexedExports(); void multiplexingByProfile(); void multiplexingByProfile_data(); void nonApplicableModulePropertyInProfile(); void nonApplicableModulePropertyInProfile_data(); void nonRequiredProducts(); void nonRequiredProducts_data(); void outerInGroup(); void overriddenPropertiesAndPrototypes(); void overriddenPropertiesAndPrototypes_data(); void overriddenVariantProperty(); void parameterTypes(); void pathProperties(); void probesAndMultiplexing(); void productConditions(); void productDirectories(); void profileValuesAndOverriddenValues(); void projectFileLookup(); void projectFileLookup_data(); void propertiesBlocks_data(); void propertiesBlocks(); void propertiesBlockInGroup_data(); void propertiesBlockInGroup(); void propertiesItemInModule(); void propertyAssignmentInExportedGroup(); void qbs1275(); void qbsPropertiesInProjectCondition(); void qbsPropertyConvenienceOverride(); void relaxedErrorMode(); void relaxedErrorMode_data(); void requiredAndNonRequiredDependencies(); void requiredAndNonRequiredDependencies_data(); void suppressedAndNonSuppressedErrors(); void throwingProbe(); void throwingProbe_data(); void defaultValue(); void defaultValue_data(); void qualifiedId(); void recursiveProductDependencies(); void rfc1034Identifier(); void throwThings_data(); void throwThings(); void useInternalProfile(); void versionCompare(); void wildcards_data(); void wildcards(); private: QHash productsFromProject( qbs::Internal::ResolvedProjectPtr project); qbs::Internal::ResolvedModuleConstPtr findModuleByName( qbs::Internal::ResolvedProductPtr product, const QString &name); QVariant productPropertyValue(qbs::Internal::ResolvedProductPtr product, QString propertyName); void handleInitCleanupDataTags(const char *projectFileName, bool *handled); qbs::Internal::TopLevelProjectPtr resolveProject(const char *relProjectFilePath = nullptr); qbs::ILogSink * const m_logSink; qbs::Settings * const m_settings; qbs::Internal::Logger m_logger; std::unique_ptr m_engine; qbs::Internal::TopLevelProjectPtr project; qbs::SetupProjectParameters defaultParameters; const QString m_wildcardsTestDirPath; QTemporaryDir m_tempDir; QRandomGenerator m_rand; }; #endif // TST_LANGUAGE_H qbs-src-2.6.1/tests/auto/language/language.qbs0000644000175100001660000000102414776170045020634 0ustar runnerdockerimport qbs.Utilities QbsUnittest { Depends { name: "qbsversion" } Depends { name: "qbsconsolelogger" } testName: "language" condition: qbsbuildconfig.enableUnitTests files: [ "tst_language.cpp", "tst_language.h" ] cpp.defines: base.concat([ "QBS_VERSION=" + Utilities.cStringQuote(qbsversion.version), "SRCDIR=" + Utilities.cStringQuote(path) ]) Group { name: "testdata" prefix: "testdata/" files: ["**/*"] fileTags: [] } } qbs-src-2.6.1/tests/auto/language/testdata/0000755000175100001660000000000014776170045020156 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/0000755000175100001660000000000014776170045025053 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/disabled-properties-item.qbs0000644000175100001660000000102414776170045032454 0ustar runnerdockerProduct { name: "p" Depends { name: "higher1" } Depends { name: "higher2" } property bool setProp property string value: "fromProduct" property stringList productProp: "default" lower.n: 10 Group { condition: setProp product.lower.prop: value product.lower.listProp: "WITH_PRODUCT_PROP" product.productProp: "condition1" } Group { condition: lower.n > 7 product.lower.listProp: "N_GREATER_7" product.productProp: "condition2" } } qbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/0000755000175100001660000000000014776170045026523 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/higher1/0000755000175100001660000000000014776170045030052 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/higher1/higher1.qbs0000644000175100001660000000076614776170045032121 0ustar runnerdockerModule { Depends { name: "lower" } property bool setProp property string value: "fromHigher1" Properties { condition: setProp lower.prop: value lower.listProp: "WITH_HIGHER1_PROP" } Properties { condition: lower.n > 5 lower.listProp: "N_GREATER_5" } Properties { condition: lower.n < 10 lower.listProp: "N_LESS_10" } Properties { condition: lower.n < 20 lower.listProp: "N_LESS_20" } } qbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/higher2/0000755000175100001660000000000014776170045030053 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/higher2/higher2.qbs0000644000175100001660000000043314776170045032112 0ustar runnerdockerModule { Depends { name: "lower" } property bool setProp Properties { condition: setProp lower.prop: undefined lower.listProp: "WITH_HIGHER2_PROP" } Properties { condition: lower.n > 6 lower.listProp: "N_GREATER_6" } } qbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/lower/0000755000175100001660000000000014776170045027653 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/disabled-properties-item/modules/lower/lower.qbs0000644000175100001660000000056714776170045031522 0ustar runnerdockerModule { property bool setProp property string value: "fromLower" property string prop: "default" property stringList listProp property int n: 0 Group { condition: setProp module.prop: outer + "_" + value module.listProp: "WITH_LOWER_PROP" } Group { condition: n module.listProp: ["N_NON_ZERO"] } } qbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/0000755000175100001660000000000014776170045025442 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items.qbs0000644000175100001660000000015114776170045033432 0ustar runnerdockerProject { qbsSearchPaths: sourceDirectory references: "inherited-properties-items-product.qbs" } qbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/imports/0000755000175100001660000000000014776170045027137 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/imports/DebugName.qbs0000644000175100001660000000012514776170045031473 0ustar runnerdockerProperties { condition: qbs.buildVariant === "debug" name: "product_debug" } qbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/imports/ReleaseName.qbs0000644000175100001660000000013114776170045032022 0ustar runnerdockerProperties { condition: qbs.buildVariant === "release" name: "product_release" } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items-product.qbsqbs-src-2.6.1/tests/auto/language/testdata/inherited-properties-items/inherited-properties-items-pro0000644000175100001660000000011414776170045033443 0ustar runnerdockerProduct { name: "product_default" DebugName {} ReleaseName {} } qbs-src-2.6.1/tests/auto/language/testdata/suppressed-and-non-suppressed-errors.qbs0000644000175100001660000000033414776170045030117 0ustar runnerdockerProject { Product { name: "mysterious creature" files: ["easter bunny"] } Product { name: "tasty food" condition: false Depends { name: "TheBeautifulSausage" } } } qbs-src-2.6.1/tests/auto/language/testdata/invalidBindingInDisabledItem.qbs0000644000175100001660000000051514776170045026345 0ustar runnerdockerProject { Product { name: "product1" condition: false someNonsense: "Bitte stellen Sie die Tassen auf den Tisch." } Product { name: "product2" Group { condition: false moreNonsense: "Follen. Follen. Hünuntergefollen. Auf dön Töppüch." } } } qbs-src-2.6.1/tests/auto/language/testdata/qbs-properties-in-project-condition.qbs0000644000175100001660000000016014776170045027675 0ustar runnerdockerProject { condition: qbs.targetOS.includes("whatever") Product { name: "never reached" } } qbs-src-2.6.1/tests/auto/language/testdata/versionCompare.qbs0000644000175100001660000000113514776170045023661 0ustar runnerdockerimport qbs.Utilities Product { name: { var e = "unexpected comparison result"; if (Utilities.versionCompare("1.5", "1.5") !== 0) throw e; if (Utilities.versionCompare("1.5", "1.5.0") !== 0) throw e; if (Utilities.versionCompare("1.5", "1.6") >= 0) throw e; if (Utilities.versionCompare("1.6", "1.5") <= 0) throw e; if (Utilities.versionCompare("2.5", "1.6") <= 0) throw e; if (Utilities.versionCompare("1.6", "2.5") >= 0) throw e; return "versionCompare"; } } qbs-src-2.6.1/tests/auto/language/testdata/overridden-properties-and-prototypes.qbs0000644000175100001660000000010414776170045030201 0ustar runnerdockerProduct { name: "p" Depends { name: "multiple_backends" } } qbs-src-2.6.1/tests/auto/language/testdata/error-in-disabled-product.qbs0000644000175100001660000000161714776170045025652 0ustar runnerdockerProject { Product { name: "a" condition: false property stringList l: [undefined] } Product { name: "b" condition: false Group { name: { throw "boo!" } } } Product { name: "c" Group { condition: false name: { throw "boo!" } } } Project { condition: false Project { condition: true Product { name: "d" condition: { throw "ouch!" } } } } Product { condition: false Rule { inputs: [5] } } Project { condition: false minimumQbsVersion: false } Product { name: "e" condition: dummy.falseProperty Depends { name: "does.not.exist" } Depends { name: "dummy" } } } qbs-src-2.6.1/tests/auto/language/testdata/non-required-products.qbs0000644000175100001660000000134114776170045025135 0ustar runnerdockerProject { Product { name: "depender" Depends { name: "dummy" } Depends { name: "dependee"; required: false } Properties { condition: dependee.present dummy.defines: ["WITH_DEPENDEE"] } } Project { name: "subproject" Product { name: "dependee" } } Product { name: "p1" condition: p2.present Depends { name: "p2"; required: false } } Product { name: "p2" condition: p3.present Depends { name: "p3"; required: false } } Product { name: "p3" condition: nosuchmodule.present Depends { name: "nosuchmodule"; required: false } } } qbs-src-2.6.1/tests/auto/language/testdata/productconditions.qbs0000644000175100001660000000143014776170045024435 0ustar runnerdockerimport qbs.Probes Project { Product { name: "product_no_condition" } Product { name: "product_true_condition" condition: 1 === 1 } Product { name: "product_false_condition" condition: 1 === 2 } Product { name: "product_condition_dependent_of_module" condition: qbs.architecture !== (qbs.architecture + "foo") } Product { name: "product_probe_condition_true" condition: trueProbe.found Probe { id: trueProbe configure: { found = true; } } } Product { name: "product_probe_condition_false" condition: falseProbe.found Probe { id: falseProbe configure: { found = false; } } } } qbs-src-2.6.1/tests/auto/language/testdata/id-uniqueness.qbs0000644000175100001660000000040614776170045023456 0ustar runnerdockerimport "idusagebase.qbs" as DerivedProduct Project { id: theProject DerivedProduct { id: baseProduct // OK - even though 'baseProduct' is used in the base item. } DerivedProduct { id: baseProduct // ERROR } } qbs-src-2.6.1/tests/auto/language/testdata/modules.qbs0000644000175100001660000000256614776170045022346 0ustar runnerdockerProject { Product { name: "no_modules" property var foo } Product { name: "qt_core" dummyqt.core.version: "1.2.3" property var foo: dummyqt.core.coreVersion Depends { name: "dummyqt.core" } } Product { name: "qt_gui" property var foo: dummyqt.gui.guiProperty Depends { name: "dummyqt.gui" } } Product { name: "qt_gui_network" property var foo: dummyqt.gui.guiProperty + ',' + dummyqt.network.networkProperty Depends { name: "dummyqt" submodules: ["gui", "network"] } } Product { name: "deep_module_name" property var foo: deepdummy.deep.moat.depth Depends { name: "deepdummy.deep.moat" } } Product { name: "deep_module_name_submodule_syntax1" property var foo: deepdummy.deep.moat.depth Depends { name: "deepdummy.deep" submodules: ["moat"] } } Product { name: "deep_module_name_submodule_syntax2" property var foo: deepdummy.deep.moat.depth Depends { name: "deepdummy" submodules: ["deep.moat"] } } Product { name: "dummy_twice" Depends { name: "dummy" } Depends { name: "dummy" } } } qbs-src-2.6.1/tests/auto/language/testdata/properties-block-in-group.qbs0000644000175100001660000000075314776170045025714 0ustar runnerdockerProduct { name: "in-group" property bool featureEnabled: true Depends { name: "dummy" } Depends { name: "module_with_group" } dummy.defines: ["BASEDEF"] Group { condition: featureEnabled name: "the group" files: ["dummy.txt" ] Properties { condition: name === "the group" dummy.defines: outer.concat("FEATURE_ENABLED", name.toUpperCase().replace(' ', '_')) } dummy.defines: "GROUP_ONLY" } } qbs-src-2.6.1/tests/auto/language/testdata/module-parameters/0000755000175100001660000000000014776170045023604 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-parameters/module-parameters.qbs0000644000175100001660000000175014776170045027744 0ustar runnerdockerProject { property bool overrideFromModule property bool overrideFromExport property bool overrideFromProduct Product { name: "dep" Export { Depends { name: "higher"; condition: project.overrideFromExport lower.param: "fromExportDepends" } Parameters { lower.param: "fromParameters" } } } Product { name: "main" Depends { name: "dep" condition: project.overrideFromProduct lower.param: "fromProductDepends" } Depends { name: "higher" condition: project.overrideFromProduct lower.param: "fromProductDepends" } Depends { name: "dep"; condition: !project.overrideFromProduct } Depends { name: "higher"; condition: !project.overrideFromProduct } Depends { name: "highest" } Depends { name: "broken"; required: false } } } qbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/0000755000175100001660000000000014776170045025254 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/broken/0000755000175100001660000000000014776170045026534 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/broken/broken.qbs0000644000175100001660000000022514776170045030522 0ustar runnerdockerModule { Depends { name: "higher"; lower.param: "shouldNeverAppear" } validate: { throw "As the name indicates, this module is broken."; } } qbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/lower/0000755000175100001660000000000014776170045026404 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/lower/lower.qbs0000644000175100001660000000007514776170045030245 0ustar runnerdockerModule { Parameter { property string param: "origin" } } qbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/highest/0000755000175100001660000000000014776170045026707 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/highest/highest.qbs0000644000175100001660000000021514776170045031047 0ustar runnerdockerModule { Depends { name: "higher" condition: project.overrideFromModule lower.param: "fromModuleDepends" } } qbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/higher/0000755000175100001660000000000014776170045026522 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-parameters/modules/higher/higher.qbs0000644000175100001660000000013214776170045030473 0ustar runnerdockerModule { Depends { name: "lower" } Parameters { lower.param: "fromParameters" } } qbs-src-2.6.1/tests/auto/language/testdata/rfc1034identifier.qbs0000644000175100001660000000046414776170045024016 0ustar runnerdockerimport qbs.Utilities CppApplication { name: Utilities.rfc1034Identifier("this!has@special#characters$uh-oh,Undersc0r3s_Are.Bad") Properties { condition: qbs.targetOS.includes("darwin") bundle.infoPlist: { return {"CFBundleIdentifier": "$(PRODUCT_NAME:rfc1034identifier)"}; } } } qbs-src-2.6.1/tests/auto/language/testdata/getNativeSetting.qbs0000644000175100001660000000163414776170045024155 0ustar runnerdockerimport qbs.FileInfo import qbs.Utilities import qbs.Host Project { Product { name: "p1" targetName: { if (Host.os().includes("macos")) { return Utilities.getNativeSetting("/System/Library/CoreServices/SystemVersion.plist", "ProductName"); } else if (Host.os().includes("windows")) { var productName = Utilities.getNativeSetting("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName"); if (productName.includes("Windows")) { return "Windows"; } return undefined; } else { return Utilities.getNativeSetting(FileInfo.joinPaths(path, "nativesettings.ini"), "osname"); } } } Product { name: "p2" targetName: Utilities.getNativeSetting("/dev/null", undefined, "fallback"); } } qbs-src-2.6.1/tests/auto/language/testdata/zort0000644000175100001660000000000014776170045021065 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/canonicalArchitecture.qbs0000644000175100001660000000012414776170045025154 0ustar runnerdockerimport qbs.Utilities Product { name: Utilities.canonicalArchitecture("i386") } qbs-src-2.6.1/tests/auto/language/testdata/conditionaldepends_base.qbs0000644000175100001660000000023014776170045025520 0ustar runnerdockerProduct { name: 'conditionaldepends_base' property bool someProp: false Depends { condition: someProp name: 'dummy' } } qbs-src-2.6.1/tests/auto/language/testdata/parameter-types.qbs0000644000175100001660000000073414776170045024013 0ustar runnerdockerProject { Product { name: "foo" qbsSearchPaths: "./erroneous" Depends { name: "module_with_parameters" } Depends { name: "bar" module_with_parameters.boolParameter: true module_with_parameters.intParameter: 156 module_with_parameters.stringParameter: "hello" module_with_parameters.stringListParameter: ["la", "le", "lu"] } } Product { name: "bar" } } qbs-src-2.6.1/tests/auto/language/testdata/baseproperty_base.qbs0000644000175100001660000000010114776170045024366 0ustar runnerdockerProduct { property var narf property var zort: ["bar"] } qbs-src-2.6.1/tests/auto/language/testdata/buildconfigstringlistsyntax.qbs0000644000175100001660000000006014776170045026540 0ustar runnerdockerProject { property stringList someStrings } qbs-src-2.6.1/tests/auto/language/testdata/exports.qbs0000644000175100001660000000735014776170045022376 0ustar runnerdockerimport "exports_product.qbs" as ProductWithInheritedExportItem Project { Product { type: "app" name: "myapp" Depends { name: "mylib" } Depends { name: "dummy" } Depends { name: "qbs" } dummy.defines: ["BUILD_" + product.name.toUpperCase()] dummy.includePaths: ["./app"] } references: [ "subdir/exports-mylib.qbs", "subdir2/exports-mylib2.qbs" ] Product { type: "app" name: "A" Depends { name: "qbs" } Depends { name: "B" } } Product { type: "lib" name: "B" Export { Depends { name: "C" } Depends { name: "qbs" } } } Product { type: "lib" name: "C" Export { Depends { name: "D" } Depends { name: "qbs" } } } Product { type: "lib" name: "D" } Product { type: "app" name: "myapp2" Depends { name: "productWithInheritedExportItem" } Depends { name: "qbs" } } ProductWithInheritedExportItem { name: "productWithInheritedExportItem" Export { dummy.cFlags: base.concat("PRODUCT_" + exportingProduct.name.toUpperCase()) dummy.cxxFlags: ["-bar"] Properties { dummy.defines: base.concat(["DEF"]) } } } Product { type: "app" name: "myapp3" Depends { name: "productWithInheritedExportItem"; versionAtLeast: "2.0" } } Project { name: "sub1" Product { name: "sub p1" Export { Depends { name: "dummy" } dummy.someString: project.name } } } Project { name: "sub2" Product { name: "sub p2" Depends { name: "sub p1" } } } ParentWithExport { name: "libA" Export { Depends { name: "libB" } } } ParentWithExport { name: "libB" } ParentWithExport { name: "libC" Export { Depends { name: "libA" } } } ParentWithExport { name: "libD" Export { Depends { name: "libA" } } } Product { name: "libE" Depends { name: "libD" } Depends { name: "libC" } Group { qbs.install: false } } Product { name: "dependency" Probe { id: configProbe property var config configure: { var obj = {}; obj.featureX = true; obj.featureY = false; obj.featureZ = true; config = obj; found = true; } } property var config: configProbe.config Export { property bool depend: false property var config: exportingProduct.config Group { condition: depend Depends { name: "cpp" } Properties { cpp.includePaths: ["."] } } } } Product { name: "depender" Depends { name: "dependency" } property bool featureX: dependency.config.featureX property bool featureY: dependency.config.featureY property bool featureZ: dependency.config.featureZ } Product { name: "broken_cycle1" Export { property bool depend: true Depends { name: "broken_cycle3"; condition: depend } } } Product { name: "broken_cycle2" Export { Depends { name: "broken_cycle1" } broken_cycle1.depend: false } } Product { name: "broken_cycle3" Depends { name: "broken_cycle2" } } } qbs-src-2.6.1/tests/auto/language/testdata/empty-js-file.qbs0000644000175100001660000000006014776170045023346 0ustar runnerdockerimport "empty-js-file.js" as Empty Product { } qbs-src-2.6.1/tests/auto/language/testdata/property-assignment-in-exported-group.qbs0000644000175100001660000000047314776170045030311 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "dummy" } Group { name: "exported_group" dummy.someString: "test" files: ["narf"] } } } Product { Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/language/testdata/aboutdialog.cpp0000644000175100001660000000000014776170045023142 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/idusage_group.qbs0000644000175100001660000000011014776170045023512 0ustar runnerdockerGroup { id: baseGroup name: "base" prefix: baseGroup.name } qbs-src-2.6.1/tests/auto/language/testdata/environmentvariable.qbs0000644000175100001660000000012114776170045024731 0ustar runnerdockerimport qbs.Environment Product { name: Environment.getEnv("PRODUCT_NAME") } qbs-src-2.6.1/tests/auto/language/testdata/modulepropertiesingroups.qbs0000644000175100001660000000450714776170045026064 0ustar runnerdockerProject { Product { name: "grouptest" Depends { name: "gmod.gmod1" } Depends { name: "gmod3" } Depends { name: "gmod4" } gmod.gmod1.gmod1_list2: base.concat([name, gmod.gmod1.gmod1_string]) gmod.gmod1.gmod1_list3: ["product"] gmod.gmod1.p1: 1 Group { name: "g1" files: ["Banana"] gmod.gmod1.gmod1_string: name gmod.gmod1.gmod1_list2: outer.concat([name]) gmod.gmod1.p2: 2 gmod2.prop: 1 gmod2.commonName: "g1" gmod3.gmod3_string: "g1_gmod3" gmod4.gmod4_string: "g1_gmod4" Group { name: "g1.1" gmod.gmod1.gmod1_string: name gmod.gmod1.gmod1_list2: outer.concat([name]) gmod.gmod1.p2: 4 gmod2.prop: 2 gmod2.commonName: name gmod3.gmod3_string: "g1.1_gmod3" gmod4.gmod4_string: "g1.1_gmod4" } Group { name: "g1.2" gmod.gmod1.gmod1_string: name gmod.gmod1.gmod1_list2: outer.concat([name]) gmod.gmod1.p2: 8 gmod2.commonName: name gmod3.gmod3_string: "g1.2_gmod3" } } Group { name: "g2" files: ["zort"] gmod.gmod1.gmod1_string: name gmod.gmod1.p1: 2 gmod.gmod1.p2: 4 gmod2.prop: 2 gmod3.gmod3_string: name + "_gmod3" gmod4.gmod4_string: name + "_gmod4" Group { name: "g2.1" Group { name: "g2.1.1" gmod.gmod1.gmod1_list2: [name] gmod.gmod1.p2: 15 } } } } Product { name: "grouptest2" Depends { name: "gmod.gmod1" } Group { name: "g1" gmod.gmod1.gmod1_list2: ["G1"] Group { name: "g1.1" gmod.gmod1.gmod1_string: "G1.1" } } } Product { name: "module-property-in-group-condition" Depends { name: "cpp" } Group { condition: qbs.architecture === "x86_64" cpp.includePaths: "." } } } qbs-src-2.6.1/tests/auto/language/testdata/subdir/0000755000175100001660000000000014776170045021446 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/subdir/pathproperties_base.qbs0000644000175100001660000000016614776170045026223 0ustar runnerdockerProduct { property path base_fileInProductDir: "foo" property path base_fileInBaseProductDir: path + "/bar" } qbs-src-2.6.1/tests/auto/language/testdata/subdir/exports-mylib.qbs0000644000175100001660000000074714776170045025003 0ustar runnerdockerStaticLibrary { name: "mylib" Depends { name: "dummy" } dummy.defines: ["BUILD_" + product.name.toUpperCase()] property string definePrefix: "USE_" property path aPath: "." dummy.somePath: aPath Export { Depends { name: "dummy" } Depends { name: "mylib2" } dummy.defines: [exportingProduct.definePrefix + exportingProduct.name.toUpperCase()] dummy.includePaths: ["./lib"] dummy.somePath: exportingProduct.aPath } } qbs-src-2.6.1/tests/auto/language/testdata/delayed-error/0000755000175100001660000000000014776170045022714 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/delayed-error/validation.qbs0000644000175100001660000000025014776170045025552 0ustar runnerdockerProject { property bool enableProduct: true Product { name: "theProduct" condition: project.enableProduct Depends { name: "m" } } } qbs-src-2.6.1/tests/auto/language/testdata/delayed-error/nonexisting.qbs0000644000175100001660000000026314776170045025771 0ustar runnerdockerProject { property bool enableProduct: true Product { name: "theProduct" condition: project.enableProduct Depends { name: "nosuchmodule" } } } qbs-src-2.6.1/tests/auto/language/testdata/delayed-error/modules/0000755000175100001660000000000014776170045024364 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/delayed-error/modules/m/0000755000175100001660000000000014776170045024620 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/delayed-error/modules/m/m.qbs0000644000175100001660000000007014776170045025560 0ustar runnerdockerModule { validate: { throw "Validation error!"; } } qbs-src-2.6.1/tests/auto/language/testdata/dirwithoneproject/0000755000175100001660000000000014776170045023721 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dirwithoneproject/project.qbs0000644000175100001660000000000014776170045026064 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/ParentWithExport.qbs0000644000175100001660000000017614776170045024160 0ustar runnerdockerProduct { Export { Depends { name: "dummy" } dummy.defines: [exportingProduct.name.toUpperCase()] } } qbs-src-2.6.1/tests/auto/language/testdata/nativesettings.ini0000644000175100001660000000001614776170045023723 0ustar runnerdockerosname = Unix qbs-src-2.6.1/tests/auto/language/testdata/use-internal-profile.qbs0000644000175100001660000000030014776170045024722 0ustar runnerdockerProject { name: "theproject" Profile { name: "theprofile" dummy.defines: name } Product { name: "theproduct" Depends { name: "dummy" } } }qbs-src-2.6.1/tests/auto/language/testdata/modulescope.qbs0000644000175100001660000000040014776170045023176 0ustar runnerdockerimport "modulescope_base.qbs" as MyProduct Project { MyProduct { name: "product1" property int e: 12 property int f: 13 scopemod.a: 2 scopemod.f: 2 scopemod.g: e * f scopemod.h: base + 2 } } qbs-src-2.6.1/tests/auto/language/testdata/throw.qbs0000644000175100001660000000070314776170045022030 0ustar runnerdockerProject { property string throwType property bool dummy: { if (throwType === "bool") throw true; if (throwType === "int") throw 43; if (throwType === "string") throw "an error"; if (throwType === "list") throw ["an", "error"]; if (throwType === "object") throw { result: "crash", reason: "overheating" }; throw "type missing"; } } qbs-src-2.6.1/tests/auto/language/testdata/qbs-property-convenience-override.qbs0000644000175100001660000000007614776170045027446 0ustar runnerdockerProduct { name: "p" qbs.installPrefix: "/usr/local" } qbs-src-2.6.1/tests/auto/language/testdata/propertiesblocks.qbs0000644000175100001660000001367614776170045024274 0ustar runnerdockerimport "propertiesblocks_base.qbs" as ProductBase Project { Product { name: "property_overwrite" Depends { name: "dummy" } dummy.defines: ["SOMETHING"] Properties { dummy.defines: ["OVERWRITTEN"] } } Product { name: "property_set_indirect" Depends { name: "dummyqt.core" } Properties { dummyqt.core.zort: "VAL" } } Product { name: "property_overwrite_no_outer" Depends { name: "dummy" } Properties { dummy.defines: ["OVERWRITTEN"] } } Product { name: "property_append_to_outer" Depends { name: "dummy" } dummy.defines: ["ONE"] Properties { dummy.defines: outer.concat(["TWO"]) } } Product { name: "property_append_to_indirect_outer" Depends { name: "dummy" } property stringList myDefines: ["ONE"] dummy.defines: myDefines Properties { dummy.defines: outer.concat(["TWO"]) } } ProductBase { name: "property_append_to_indirect_derived_outer1" Properties { dummy.cFlags: outer.concat("PROPS") } } ProductBase { name: "property_append_to_indirect_derived_outer2" Properties { dummy.cFlags: outer.concat("PROPS") } dummy.cFlags: ["PRODUCT"] } ProductBase { name: "property_append_to_indirect_derived_outer3" Properties { dummy.cFlags: outer.concat("PROPS") } dummy.cFlags: base.concat("PRODUCT") } Product { name: "property_append_to_indirect_merged_outer" Depends { name: "dummy" } property string justOne: "ONE" dummy.rpaths: [justOne] Properties { dummy.rpaths: outer.concat(["TWO"]) } } Product { name: "multiple_exclusive_properties" Depends { name: "dummy" } Properties { dummy.defines: ["OVERWRITTEN"] } Properties { condition: false dummy.defines: ["IMPOSSIBLE"] } Properties { condition: undefined dummy.defines: ["SOMETHING"] } } Product { name: "multiple_exclusive_properties_no_outer" Depends { name: "dummy" } Properties { condition: undefined dummy.defines: ["OVERWRITTEN"] } Properties { condition: false dummy.defines: ["IMPOSSIBLE"] } } Product { name: "multiple_exclusive_properties_append_to_outer" Depends { name: "dummy" } dummy.defines: ["ONE"] Properties { dummy.defines: outer.concat(["TWO"]) } Properties { condition: false dummy.defines: ["IMPOSSIBLE"] } } Product { name: "ambiguous_properties" Depends { name: "dummy" } dummy.defines: ["ONE"] Properties { dummy.defines: outer.concat(["TWO"]) } Properties { condition: false dummy.defines: outer.concat(["IMPOSSIBLE"]) } Properties { dummy.defines: outer.concat(["THREE"]) } } Product { name: "condition_refers_to_product_property" property bool narf: true property string someString: "SOMETHING" Depends { name: "dummy" } Properties { condition: narf dummy.defines: ["OVERWRITTEN"] someString: "OVERWRITTEN" } } property bool zort: true Product { name: "condition_refers_to_project_property" property string someString: "SOMETHING" Depends { name: "dummy" } Properties { condition: project.zort dummy.defines: ["OVERWRITTEN"] someString: "OVERWRITTEN" } } ProductBase { name: "inheritance_overwrite_in_subitem" dummy.defines: ["OVERWRITTEN_IN_SUBITEM"] } ProductBase { name: "inheritance_retain_base1" dummy.defines: base.concat("SUB") } ProductBase { name: "inheritance_retain_base2" Properties { condition: true dummy.defines: base.concat("SUB") } Properties { condition: undefined dummy.defines: ["GNAMPF"] } } ProductBase { name: "inheritance_retain_base3" Properties { condition: true dummy.defines: base.concat("SUB") } // no dummy.defines binding } ProductBase { name: "inheritance_retain_base4" Properties { condition: false dummy.defines: ["NEVERMORE"] } // no "else case" for dummy.defines. The value is derived from ProductBase. } ProductBase { name: "inheritance_condition_in_subitem1" defineBase: false dummy.defines: base.concat("SUB") } ProductBase { name: "inheritance_condition_in_subitem2" defineBase: false // no dummy.defines binding } Product { id: knolf name: "gnampf" } Product { name: "condition_references_id" Depends { name: "dummy" } Properties { condition: knolf.name === "gnampf" dummy.defines: ["OVERWRITTEN"] } } Product { name: "using_derived_Properties_item" Depends { name: "dummy" } MyProperties { condition: true dummy.defines: ["string from MyProperties"] } } Product { name: "conditional-depends" Depends { name: "dummy" condition: false } Properties { condition: false dummy.defines: ["a string"] } } Product { name: "use-module-with-properties-item" Depends { name: "module-with-properties-item" } } } qbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/0000755000175100001660000000000014776170045027065 5ustar runnerdocker././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/invalid-prop-on-non-required-module.qbsqbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/invalid-prop-on-non-r0000644000175100001660000000066614776170045033065 0ustar runnerdockerProject { property bool useExistingModule Product { name: "a" condition: project.useExistingModule Depends { name: "deploader" } Depends { name: "dep" } dep.nosuchprop: true } Product { name: "b" condition: !project.useExistingModule Depends { name: "deploader" } Depends { name: "random"; required: false } random.nosuchprop: true } } qbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/0000755000175100001660000000000014776170045030535 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/deploader/0000755000175100001660000000000014776170045032474 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/deploader/deploader.qbsqbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/deploader/dep0000644000175100001660000000050114776170045033163 0ustar runnerdockerModule { // This indirection exists to properly model QBS-1776. // "deploader" corresponds to "bundle", and "dep" corresponds to "codesign" Depends { condition: project.useExistingModule; name: "dep"; required: false } Depends { condition: !project.useExistingModule; name: "random"; required: false } } qbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/dep/0000755000175100001660000000000014776170045031305 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/invalid-prop-on-non-required-module/modules/dep/dep.qbs0000644000175100001660000000001214776170045032555 0ustar runnerdockerModule {} qbs-src-2.6.1/tests/auto/language/testdata/moduleproperties.qbs0000644000175100001660000000370514776170045024274 0ustar runnerdockerProject { name: "MyProject" property string projectName: name Product { name: "merge_lists" Depends { name: "dummyqt"; submodules: ["gui", "network"] } Depends { name: "dummy" } dummy.defines: ["THE_PRODUCT"] } Product { name: "merge_lists_and_values" Depends { name: "dummyqt"; submodules: ["network", "gui"] } Depends { name: "dummy" } dummy.defines: "THE_PRODUCT" } Product { name: "merge_lists_with_duplicates" Depends { name: "dummy" } dummy.cxxFlags: ["-foo", "BAR", "-foo", "BAZ"] } Product { name: "merge_lists_with_prototype_values" Depends { name: "dummyqt"; submodules: ["gui", "network"] } Depends { name: "dummy" } } Product { name: "list_property_that_references_product" type: ["blubb"] Depends { name: "dummy" } dummy.listProp: ["x"] } Product { name: "list_property_depending_on_overridden_property" Depends { name: "dummy" } dummy.listProp2: ["PRODUCT_STUFF"] dummy.controllingProp: true } Product { name: "overridden_list_property" Depends { name: "dummy" } Properties { overrideListProperties: true dummy.listProp: ["PRODUCT_STUFF"] } } Product { name: "shadowed-list-property" property string productName: name Depends { name: "dummy" } dummy.defines: [projectName, productName] } Product { name: "shadowed-scalar-property" property string productName: name Depends { name: "dummy" } dummy.someString: projectName + "_" + productName } Product { name: "merged-varlist" property string productName: name Depends { name: "dummy" } Depends { name: "dummyqt.core" } dummy.controllingProp: true dummy.varListProp: ({d: "product"}) } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/0000755000175100001660000000000014776170045024535 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/simple-collision1.qbs0000644000175100001660000000006314776170045030606 0ustar runnerdockerProduct { Depends { name: "prefix1.suffix" } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/no-collision2.qbs0000644000175100001660000000014314776170045027731 0ustar runnerdockerProduct { Depends { name: "prefix1.middle1" } Depends { name: "prefix1.middle2.suffix" } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/simple-collision2.qbs0000644000175100001660000000005414776170045030607 0ustar runnerdockerProduct { Depends { name: "prefix2" } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/complex-collision.qbs0000644000175100001660000000014414776170045030703 0ustar runnerdockerProduct { Depends { name: "prefix1.middle1" } Depends { name: "prefix1.middle1.suffix1" } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/no-collision1.qbs0000644000175100001660000000015414776170045027732 0ustar runnerdockerProduct { Depends { name: "prefix1.middle1.suffix1" } Depends { name: "prefix1.middle1.suffix2" } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/0000755000175100001660000000000014776170045026205 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/0000755000175100001660000000000014776170045027563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/suffix/0000755000175100001660000000000014776170045031067 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/suffix/suffix.qbs0000644000175100001660000000005314776170045033100 0ustar runnerdockerModule { Depends { name: "prefix1" } } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/prefix1.qbs0000644000175100001660000000001314776170045031642 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/0000755000175100001660000000000014776170045031102 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix1/0000755000175100001660000000000014776170045032467 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix1/suffix1.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix1/su0000644000175100001660000000001214776170045033032 0ustar runnerdockerModule {} qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix2/0000755000175100001660000000000014776170045032470 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix2/suffix2.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/suffix2/su0000644000175100001660000000001214776170045033033 0ustar runnerdockerModule {} ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/middle1.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle1/middle1.qb0000644000175100001660000000001214776170045032736 0ustar runnerdockerModule {} qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/0000755000175100001660000000000014776170045031103 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/suffix/0000755000175100001660000000000014776170045032407 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/suffix/suffix.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix1/middle2/suffix/suf0000644000175100001660000000001214776170045033120 0ustar runnerdockerModule {} qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix2/0000755000175100001660000000000014776170045027564 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix2/suffix/0000755000175100001660000000000014776170045031070 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix2/suffix/suffix.qbs0000644000175100001660000000001314776170045033075 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/language/testdata/module-name-collisions/modules/prefix2/prefix2.qbs0000644000175100001660000000006214776170045031650 0ustar runnerdockerModule { Depends { name: "prefix2.suffix" } } qbs-src-2.6.1/tests/auto/language/testdata/chained-probes/0000755000175100001660000000000014776170045023041 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/chained-probes/chained-probes.qbs0000644000175100001660000000004614776170045026433 0ustar runnerdockerProduct { Depends { name: "m" } } qbs-src-2.6.1/tests/auto/language/testdata/chained-probes/modules/0000755000175100001660000000000014776170045024511 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/chained-probes/modules/m/0000755000175100001660000000000014776170045024745 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/chained-probes/modules/m/m.qbs0000644000175100001660000000064614776170045025716 0ustar runnerdockerModule { Probe { id: probe1 property string probe1Prop configure: { probe1Prop = "probe1Val"; found = true } } Probe { id: probe2 property string inputProp: prop1 property string probe2Prop configure: { probe2Prop = inputProp + "probe2Val"; found = true } } property string prop1: probe1.probe1Prop property string prop2: probe2.probe2Prop } qbs-src-2.6.1/tests/auto/language/testdata/import-collection/0000755000175100001660000000000014776170045023621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/import-collection/product.qbs0000644000175100001660000000030214776170045026003 0ustar runnerdockerimport Collection as Collection1 import "collection" as Collection2 Product { name: "da product" targetName: Collection1.f1() + Collection1.f2() + Collection2.f1() + Collection2.f2() } qbs-src-2.6.1/tests/auto/language/testdata/import-collection/project.qbs0000644000175100001660000000005514776170045025776 0ustar runnerdockerProject { references: ["product.qbs"] } qbs-src-2.6.1/tests/auto/language/testdata/import-collection/imports/0000755000175100001660000000000014776170045025316 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/import-collection/imports/Collection/0000755000175100001660000000000014776170045027411 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/import-collection/imports/Collection/file2.js0000644000175100001660000000004114776170045030743 0ustar runnerdockerfunction f2() { return "C1f2"; } qbs-src-2.6.1/tests/auto/language/testdata/import-collection/imports/Collection/file1.js0000644000175100001660000000004114776170045030742 0ustar runnerdockerfunction f1() { return "C1f1"; } qbs-src-2.6.1/tests/auto/language/testdata/import-collection/collection/0000755000175100001660000000000014776170045025754 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/import-collection/collection/file2.js0000644000175100001660000000004114776170045027306 0ustar runnerdockerfunction f2() { return "C2f2"; } qbs-src-2.6.1/tests/auto/language/testdata/import-collection/collection/file1.js0000644000175100001660000000004114776170045027305 0ustar runnerdockerfunction f1() { return "C2f1"; } qbs-src-2.6.1/tests/auto/language/testdata/duplicate-multiplex-value2.qbs0000644000175100001660000000024714776170045026057 0ustar runnerdockerProduct { name: "p" multiplexByQbsProperties: ["architectures", "buildVariants", "architectures"] aggregate: false qbs.architectures: ["x86", "arm"] } qbs-src-2.6.1/tests/auto/language/testdata/empty-js-file.js0000644000175100001660000000000014776170045023167 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/idusagebase.qbs0000644000175100001660000000063314776170045023143 0ustar runnerdockerimport "idusagebasebase.qbs" as DeriveMeCrazy import "idusage_group.qbs" as MyGroup import "idusage_group2.qbs" as MyGroup2 DeriveMeCrazy { id: baseProduct property int nr: theProject.initialNr + 1 name: "product1_" + nr property string productName: baseProduct.name MyGroup { name: "group in base product" } MyGroup2 { name: "another group in base product" } } qbs-src-2.6.1/tests/auto/language/testdata/idusage.qbs0000644000175100001660000000135414776170045022311 0ustar runnerdockerimport "idusagebase.qbs" as DerivedProduct Project { id: theProject property int initialNr: 0 DerivedProduct { id: product1 } Product { id: product2 property int nr: theProject.initialNr + product1.nr + 1 name: "product2_" + nr } Product { id: product3 property int nr: product2.nr + 1 name: "product3_" + nr } DerivedProduct { id: product4 nr: product3.nr + 1 name: "product4_" + nr } Product { name: "product5" Depends { name: "deepdummy.deep.moat"; id: moat } Group { Group { condition: moat.present files: "dummy.txt" } } } } qbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/0000755000175100001660000000000014776170045026030 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/module-merging-variant-values.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/module-merging-variant-valu0000644000175100001660000000017314776170045033276 0ustar runnerdockerProduct { multiplexByQbsProperties: ["architectures"] qbs.architectures: ["a1", "a2"] Depends { name: "m2" } } qbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/modules/0000755000175100001660000000000014776170045027500 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/modules/m2/0000755000175100001660000000000014776170045030016 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/modules/m2/m2.qbs0000644000175100001660000000071714776170045031050 0ustar runnerdockerModule { Depends { name: "m1" } m1.arch: qbs.architecture property string arch: qbs.architecture validate: { if (qbs.architecture !== "a1" && qbs.architecture !== "a2") throw "Unexpected arch " + qbs.architecture; if (arch !== qbs.architecture) throw "Oops: " + arch + "/" + qbs.architecture; if (m1.arch !== qbs.architecture) throw "Oops: " + m1.arch + "/" + qbs.architecture; } } qbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/modules/m1/0000755000175100001660000000000014776170045030015 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-merging-variant-values/modules/m1/m1.qbs0000644000175100001660000000027214776170045031042 0ustar runnerdockerModule { condition: qbs.architecture === "a1" || qbs.architecture === "a2" property string arch qbs.architecture: undefined // We do something like this in GenericGCC.qbs } qbs-src-2.6.1/tests/auto/language/testdata/correct-decl-in-parent-lookup.qbs0000644000175100001660000000013714776170045026436 0ustar runnerdockerProduct { name: "p" Depends { name: "dummy" } dummy.cxxFlags: base.concat(["x"]) } qbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/0000755000175100001660000000000014776170045027334 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/product.qbs0000644000175100001660000000007214776170045031522 0ustar runnerdockerProduct { Depends { name: "conflicting-instances" } } qbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/project.qbs0000644000175100001660000000005414776170045031510 0ustar runnerdockerProject { references: ["product.qbs"] } qbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/bar/0000755000175100001660000000000014776170045030100 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/bar/modules/0000755000175100001660000000000014776170045031550 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/bar/modules/conflicting-instances/qbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/bar/modules/conflict0000755000175100001660000000000014776170045033272 5ustar runnerdocker././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/bar/modules/conflicting-instances/bar.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/bar/modules/conflict0000644000175100001660000000006414776170045033274 0ustar runnerdockerModule { property string moduleVariant: "bar" } qbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/foo/0000755000175100001660000000000014776170045030117 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/foo/modules/0000755000175100001660000000000014776170045031567 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/foo/modules/conflicting-instances/qbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/foo/modules/conflict0000755000175100001660000000000014776170045033311 5ustar runnerdocker././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/foo/modules/conflicting-instances/foo.qbsqbs-src-2.6.1/tests/auto/language/testdata/module-prioritization-by-search-path/foo/modules/conflict0000644000175100001660000000006414776170045033313 0ustar runnerdockerModule { property string moduleVariant: "foo" } qbs-src-2.6.1/tests/auto/language/testdata/dirwithnoprojects/0000755000175100001660000000000014776170045023737 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dirwithnoprojects/.gitignore0000644000175100001660000000001614776170045025724 0ustar runnerdocker* !.gitignore qbs-src-2.6.1/tests/auto/language/testdata/baseproperty.qbs0000644000175100001660000000022214776170045023400 0ustar runnerdockerimport "baseproperty_base.qbs" as BaseProduct BaseProduct { name: "product1" narf: base.concat(["boo"]) zort: base.concat(["boo"]) } qbs-src-2.6.1/tests/auto/language/testdata/local-profile-as-top-level-profile.qbs0000644000175100001660000000020114776170045027352 0ustar runnerdockerProduct { Profile { name: "test-profile" qbs.architecture: "arm" qbs.targetPlatform: "macos" } } qbs-src-2.6.1/tests/auto/language/testdata/propertiesblocks_base.qbs0000644000175100001660000000041114776170045025245 0ustar runnerdockerProduct { property bool defineBase: true Depends { name: "dummy" } Properties { condition: defineBase dummy.defines: ["BASE"] } dummy.defines: ["SOMETHING"] property stringList myCFlags: ["BASE"] dummy.cFlags: myCFlags } qbs-src-2.6.1/tests/auto/language/testdata/base-validate/0000755000175100001660000000000014776170045022657 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/base-validate/base-validate.qbs0000644000175100001660000000004614776170045026067 0ustar runnerdockerProduct { Depends { name: "m" } } qbs-src-2.6.1/tests/auto/language/testdata/base-validate/modules/0000755000175100001660000000000014776170045024327 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/base-validate/modules/m/0000755000175100001660000000000014776170045024563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/base-validate/modules/m/MParent.qbs0000644000175100001660000000006314776170045026637 0ustar runnerdockerModule { condition: false validate: true } qbs-src-2.6.1/tests/auto/language/testdata/base-validate/modules/m/m.qbs0000644000175100001660000000030614776170045025525 0ustar runnerdockerMParent { condition: true validate: { var parentResult = base; if (!parentResult) throw "Parent failed"; throw "Parent succeeded, child failed."; } } qbs-src-2.6.1/tests/auto/language/testdata/dotted-names/0000755000175100001660000000000014776170045022542 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dotted-names/dotted-names.qbs0000644000175100001660000000077414776170045025645 0ustar runnerdockerProject { name: "theProject" property bool includeDottedProduct property bool includeDottedModule Project { condition: project.includeDottedProduct Product { name: "a.b" Export { property string c: "default" } } } Product { name: "p" Depends { name: "a.b"; condition: project.includeDottedProduct } Depends { name: "x.y"; condition: project.includeDottedModule } a.b.c: "p" x.y.z: "p" } } qbs-src-2.6.1/tests/auto/language/testdata/dotted-names/modules/0000755000175100001660000000000014776170045024212 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dotted-names/modules/x/0000755000175100001660000000000014776170045024461 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dotted-names/modules/x/y/0000755000175100001660000000000014776170045024731 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dotted-names/modules/x/y/xy.qbs0000644000175100001660000000005414776170045026077 0ustar runnerdockerModule { property string z: "default" } qbs-src-2.6.1/tests/auto/language/testdata/overridden-variant-property.qbs0000644000175100001660000000006414776170045026352 0ustar runnerdockerProduct { name: "p" property var myObject } qbs-src-2.6.1/tests/auto/language/testdata/module-depends-on-product.qbs0000644000175100001660000000022514776170045025661 0ustar runnerdockerProject { Product { name: "p1" Depends { name: "module-with-product-dependency" } } Product { name: "p2" } } qbs-src-2.6.1/tests/auto/language/testdata/module-property-overrides-per-product.qbs0000644000175100001660000000056714776170045030306 0ustar runnerdockerProject { Product { Depends { name: "dummy" } name: "a" property stringList rpaths: dummy.rpaths } Product { Depends { name: "dummy" } name: "b" property stringList rpaths: dummy.rpaths } Product { Depends { name: "dummy" } name: "c" property stringList rpaths: dummy.rpaths } } qbs-src-2.6.1/tests/auto/language/testdata/invalid-overrides.qbs0000644000175100001660000000032214776170045024310 0ustar runnerdockerProject { name: "My.Project" property bool x Product { name: "MyProduct" property bool x } Product { name: "MyOtherProduct" Depends { name: "cpp" } } } qbs-src-2.6.1/tests/auto/language/testdata/multiplexed-exports.qbs0000644000175100001660000000101214776170045024715 0ustar runnerdockerProject { Product { name: "dep" multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] property string includeDir: qbs.buildVariant === "debug" ? "/d" : "/r" Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.includeDir } } Product { name: "p" Depends { name: "dep" } multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] } } qbs-src-2.6.1/tests/auto/language/testdata/dependencyOnAllProfiles.qbs0000644000175100001660000000041014776170045025430 0ustar runnerdockerProject { property string profile1 property string profile2 Product { name: "dep" qbs.profiles: [project.profile1, project.profile2] } Product { name: "main" Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/language/testdata/builtinFunctionInSearchPathsProperty.qbs0000644000175100001660000000024614776170045030225 0ustar runnerdockerimport qbs.Environment Project { qbsSearchPaths: { if (!Environment.getEnv("PATH")) throw "Environment.getEnv doesn't seem to work"; } } qbs-src-2.6.1/tests/auto/language/testdata/keep-loading-dependencies.qbs0000644000175100001660000000011114776170045025641 0ustar runnerdockerProduct { Depends { name: "none"; submodules: ["m1", "m2", "m3"] } } qbs-src-2.6.1/tests/auto/language/testdata/disabled-subproject.qbs0000644000175100001660000000076114776170045024616 0ustar runnerdockerProject { SubProject { condition: false filePath: "nosuchfile.qbs" } SubProject { Properties { condition: false } filePath: "nosuchfile.qbs" } SubProject { condition: true Properties { condition: false } filePath: "nosuchfile.qbs" } SubProject { condition: false Properties { condition: true } filePath: "nosuchfile.qbs" } } qbs-src-2.6.1/tests/auto/language/testdata/dummy.txt0000644000175100001660000000000014776170045022040 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs0000644000175100001660000000142214776170045027531 0ustar runnerdockerProject { Product { name: "product1" property bool dummyProp: { if (!(dummy.cFlags instanceof Array)) throw new Error("dummy.cFlags: Array type expected."); if (!(dummy.cxxFlags instanceof Array)) throw new Error("dummy.cxxFlags: Array type expected."); if (!(dummy.defines instanceof Array)) throw new Error("dummy.defines: Array type expected."); return true; } consoleApplication: true Depends { name: "dummy" } // dummy.cxxFlags is set via profile and is not overridden dummy.defines: ["IN_FILE"] // set in profile, overridden in file dummy.cFlags: ["IN_FILE"] // set in profile, overridden on command line } } qbs-src-2.6.1/tests/auto/language/testdata/MyProperties.qbs0000644000175100001660000000001714776170045023325 0ustar runnerdockerProperties { } qbs-src-2.6.1/tests/auto/language/testdata/exports_product.qbs0000644000175100001660000000033614776170045024133 0ustar runnerdockerProduct { Export { version: "2.0" Depends { name: "dummy" } dummy.cFlags: ["BASE_" + exportingProduct.name.toUpperCase()] dummy.cxxFlags: ["-foo"] dummy.defines: ["ABC"] } } qbs-src-2.6.1/tests/auto/language/testdata/enum-project-props.qbs0000644000175100001660000000041214776170045024433 0ustar runnerdockerProject { property string anExistingFile: "dummy.txt" Product { files: { for (var k in project) { if (k === "anExistingFile") return [project[k]]; } return []; } } } qbs-src-2.6.1/tests/auto/language/testdata/properties-item-in-module.qbs0000644000175100001660000000020414776170045025700 0ustar runnerdockerProject { Product { name: "a"; Depends { name: "dummyqt.core" } } Product { name: "b"; Depends { name: "dummyqt.core" } } } qbs-src-2.6.1/tests/auto/language/testdata/idusagebasebase.qbs0000644000175100001660000000017614776170045024000 0ustar runnerdockerProduct { id: baseBaseProduct name: "ace of base" property string productNameInBaseOfBase: baseBaseProduct.name } qbs-src-2.6.1/tests/auto/language/testdata/narf0000644000175100001660000000000014776170045021015 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/filecontextproperties.qbs0000644000175100001660000000014314776170045025324 0ustar runnerdockerProduct { name: "product1" property string narf: filePath property string zort: path } qbs-src-2.6.1/tests/auto/language/testdata/narf.zort0000644000175100001660000000000014776170045022012 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/file-in-product-and-module.qbs0000644000175100001660000000026214776170045025711 0ustar runnerdockerProduct { name: "p" Depends { name: "module_with_file" } property bool addFileToProduct Group { files: "zort" condition: addFileToProduct } } qbs-src-2.6.1/tests/auto/language/testdata/broken-dependency-cycle1.qbs0000644000175100001660000000050114776170045025433 0ustar runnerdockerProject { Product { name: "p1" Export { property bool c: true Depends { name: "p2"; condition: c } } } Product { name: "p2" Depends { name: "p1" } p1.c: false } Product { name: "p3" Depends { name: "p1" } } } qbs-src-2.6.1/tests/auto/language/testdata/non-applicable-module-property-in-profile.qbs0000644000175100001660000000067214776170045030765 0ustar runnerdockerProject { property string targetOS property string toolchain Product { name: "p" multiplexByQbsProperties: ["profiles"] qbs.profiles: ["theProfile"] Depends { name: "multiple_backends" } Profile { name: "theProfile" qbs.targetOS: [project.targetOS] qbs.toolchain: [project.toolchain] multiple_backends.backend3Prop: "value" } } } qbs-src-2.6.1/tests/auto/language/testdata/groupname.qbs0000644000175100001660000000054114776170045022662 0ustar runnerdockerProject { Product { name: "MyProduct" Group { name: product.name + ".MyGroup" files: "*" } } Product { name: "My2ndProduct" Group { name: product.name + ".MyGroup" files: ["narf"] } Group { files: ["zort"] } } } qbs-src-2.6.1/tests/auto/language/testdata/homeDirectory.qbs0000644000175100001660000000066114776170045023505 0ustar runnerdockerProject { Product { name: "home" // These should resolve property path home: "~" property path homeSlash: "~/" property path homeUp: "~/.." property path homeFile: "~/a" // These are sanity checks and should not property path bogus1: "a~b" property path bogus2: "a/~/bb" property path user: "~foo/bar" // we don't resolve other-user paths } } qbs-src-2.6.1/tests/auto/language/testdata/groupconditions.qbs0000644000175100001660000000214014776170045024110 0ustar runnerdockerProject { property bool someTrueProperty: true Product { name: "no_condition_no_group" files: ["main.cpp"] } Product { name: "no_condition" Group { files: ["main.cpp"] } } Product { name: "true_condition" Group { condition: true files: ["main.cpp"] } } Product { name: "false_condition" Group { condition: false files: ["main.cpp"] } } Product { name: "true_condition_from_product" property bool anotherTrueProperty: true Group { condition: anotherTrueProperty files: ["main.cpp"] } } Product { name: "true_condition_from_project" Group { condition: project.someTrueProperty files: ["main.cpp"] } } Product { name: "condition_accessing_module_property" Group { condition: qbs.targetOS.includes("narf") files: ["main.cpp"] qbs.install: false } } } qbs-src-2.6.1/tests/auto/language/testdata/broken-dependency-cycle2.qbs0000644000175100001660000000050114776170045025434 0ustar runnerdockerProject { Product { name: "p1" Export { property bool c: true Depends { name: "p2"; condition: c } } } Product { name: "p3" Depends { name: "p1" } } Product { name: "p2" Depends { name: "p1" } p1.c: false } } qbs-src-2.6.1/tests/auto/language/testdata/modulescope_base.qbs0000644000175100001660000000010314776170045024170 0ustar runnerdockerProduct { Depends { name: "scopemod" } scopemod.h: e * f } qbs-src-2.6.1/tests/auto/language/testdata/derived-sub-project/0000755000175100001660000000000014776170045024033 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/derived-sub-project/subproject.qbs0000644000175100001660000000001414776170045026715 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/language/testdata/derived-sub-project/project.qbs0000644000175100001660000000021214776170045026203 0ustar runnerdockerProject { DerivedSubProject { filePath: "subproject.qbs" Properties { name: "something" } } } qbs-src-2.6.1/tests/auto/language/testdata/derived-sub-project/DerivedSubProject.qbs0000644000175100001660000000001714776170045030123 0ustar runnerdockerSubProject { } qbs-src-2.6.1/tests/auto/language/testdata/relaxed-error-mode/0000755000175100001660000000000014776170045023653 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/relaxed-error-mode/file1.txt0000644000175100001660000000000014776170045025402 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/relaxed-error-mode/relaxed-error-mode.qbs0000644000175100001660000000121014776170045030051 0ustar runnerdockerProject { Product { name: "recursive depender" Depends { name: "depender required" } files: "file1.txt" } Product { name: "broken" Depends { name: "nosuchmodule" } } Product { name: "depender required" Depends { name: "broken" } files: "file1.txt" } Product { name: "depender nonrequired" Depends { name: "broken"; required: false } files: "file1.txt" } Product { name: "missing file" files: ["file1.txt", "file3.txt", "file2.txt"] } Product { name: "fine" files: "file2.txt" } } qbs-src-2.6.1/tests/auto/language/testdata/relaxed-error-mode/file2.txt0000644000175100001660000000000014776170045025403 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/main.cpp0000644000175100001660000000000014776170045021574 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/duplicate-multiplex-value.qbs0000644000175100001660000000021214776170045025765 0ustar runnerdockerProduct { name: "p" multiplexByQbsProperties: "architectures" aggregate: false qbs.architectures: ["x86", "arm", "x86"] } qbs-src-2.6.1/tests/auto/language/testdata/jsimportsinmultiplescopes.js0000644000175100001660000000030114776170045026060 0ustar runnerdockerfunction getName(qbsModule) { if (qbsModule.debugInformation) return "MyProduct_debug"; else return "MyProduct"; } function getInstallDir() { return "somewhere"; } qbs-src-2.6.1/tests/auto/language/testdata/recursive-dependencies/0000755000175100001660000000000014776170045024611 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/recursive-dependencies/recursive-dependencies.qbs0000644000175100001660000000043014776170045031750 0ustar runnerdockerProject { Product { name: "p1" Depends { name: "p3" } } Product { name: "p2" Depends { name: "p3" } } Product { name: "p3" Export { Depends { name: "p4" } } } Product { name: "p4" } } qbs-src-2.6.1/tests/auto/language/testdata/drawline.asm0000644000175100001660000000000014776170045022453 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/additional-product-types.qbs0000644000175100001660000000046014776170045025615 0ustar runnerdockerProduct { name: "p" type: ["tag1"] Depends { name: "dummy" } Depends { name: "dummy2" } property bool hasTag1: type.includes("tag1") property bool hasTag2: type.includes("tag2") property bool hasTag3: type.includes("tag3") property bool hasTag4: type.includes("tag4") } qbs-src-2.6.1/tests/auto/language/testdata/jsextensions.js0000644000175100001660000000420714776170045023253 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ (function() { // Function wrapper to keep the environment clean. /* * poor man's JS test suite */ var testctx = {}; function initTestContext(name) { testctx.nr = 1; testctx.name = name; } function verify(c) { if (!c) throw testctx.name + ": verification #" + testctx.nr + " failed."; testctx.nr++; } /* * Tests for extensions of JavaScript builtin types. */ var a = ["one", "two", "three"]; initTestContext("Array.prototype.contains"); for (var k in a) verify(k !== "contains"); verify(a.includes("one")); verify(a.includes("two")); verify(a.includes("three")); verify(!a.includes("four")); })() // END function wrapper qbs-src-2.6.1/tests/auto/language/testdata/idusage_group2.qbs0000644000175100001660000000014014776170045023577 0ustar runnerdockerimport "idusage_group.qbs" as MyGroup MyGroup { name: "between the hammer and the anvil" } qbs-src-2.6.1/tests/auto/language/testdata/dirwithmultipleprojects/0000755000175100001660000000000014776170045025156 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dirwithmultipleprojects/project.qbs0000644000175100001660000000000014776170045027321 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/dirwithmultipleprojects/project2.qbs0000644000175100001660000000000014776170045027403 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/0000755000175100001660000000000014776170045022637 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/test.txt0000644000175100001660000000000014776170045024345 0ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/egon.qbs0000644000175100001660000000031114776170045024271 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "higher" } } } Product { name: "egon" Depends { name: "dep" } lower.prop1: "blubb" } } qbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/modules/0000755000175100001660000000000014776170045024307 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/modules/lower/0000755000175100001660000000000014776170045025437 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/modules/lower/lower.qbs0000644000175100001660000000030614776170045027275 0ustar runnerdockerModule { property string prop1 property string prop2: prop1 === "blubb" ? "withBlubb" : "withoutBlubb" property stringList listProp: prop1 === "blubb" ? ["blubb", "other"] : ["other"] } qbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/modules/higher/0000755000175100001660000000000014776170045025555 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/defaultvalue/modules/higher/higher.qbs0000644000175100001660000000025214776170045027531 0ustar runnerdockerModule { Depends { name: "lower" } lower.prop2: lower.prop1 === "egon" ? "withEgon" : original lower.listProp: lower.prop1 === "egon" ? ["egon"] : original } qbs-src-2.6.1/tests/auto/language/testdata/outerInGroup.qbs0000644000175100001660000000075514776170045023336 0ustar runnerdockerProject { Product { name: "OuterInGroup" Depends { name: "dummy" } qbs.installDir: "/somewhere" dummy.someString: "s1" Properties { dummy.someString: outer.concat("s2") } files: ["main.cpp"] Group { Group { name: "Special Group" files: ["aboutdialog.cpp"] qbs.installDir: outer + "/else" dummy.someString: outer.concat("s3") } } } } qbs-src-2.6.1/tests/auto/language/testdata/productdirectories.qbs0000644000175100001660000000003614776170045024601 0ustar runnerdockerProduct { name: "MyApp" } qbs-src-2.6.1/tests/auto/language/testdata/pathproperties.qbs0000644000175100001660000000042314776170045023735 0ustar runnerdockerimport "subdir/pathproperties_base.qbs" as ProductBase ProductBase { name: "product1" property path projectFileDir: "." property pathList filesInProjectFileDir: ["./aboutdialog.h", "aboutdialog.cpp"] Depends { name: "dummy" } dummy.includePaths: ["."] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/0000755000175100001660000000000014776170045022177 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_property_wrapper.qbs0000644000175100001660000000011714776170045030517 0ustar runnerdockerProject { SubProject { filePath: "undeclared_property.qbs" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/conflicting_fileTagsFilter.qbs0000644000175100001660000000026214776170045030171 0ustar runnerdockerProduct { type: "app" Group { fileTagsFilter: "app" qbs.install: true } Group { fileTagsFilter: "app" qbs.install: false } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs0000644000175100001660000000056314776170045031042 0ustar runnerdockerProject { Product { name: "a" multiplexByQbsProperties: ["architectures", "buildVariants"] qbs.architectures: ["x86", "arm"] qbs.buildVariants: ["debug", "release"] } Product { name: "b" Depends { name: "a" } multiplexByQbsProperties: ["architectures"] qbs.architectures: ["x86", "arm"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/wrongQbsVersionFormat.qbs0000644000175100001660000000006214776170045027225 0ustar runnerdockerProject { minimumQbsVersion: "hfyh1234wat?" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency_cycle.qbs0000644000175100001660000000045414776170045026206 0ustar runnerdockerProject { Product { name: "A" Depends { name: "B" } files: ["main.cpp"] } Product { name: "B" Depends { name: "C" } files: ["main.cpp"] } Product { name: "C" Depends { name: "A" } files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_module_property_in_module.qbs0000644000175100001660000000010314776170045032352 0ustar runnerdockerProduct { name: "p" Depends { name: "no_such_property" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/module-property-binding-in-project.qbs0000644000175100001660000000004114776170045031530 0ustar runnerdockerProject { qbs.sysroot: "/" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/wrong-toplevel-item.qbs0000644000175100001660000000001514776170045026622 0ustar runnerdockerArtifact { } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/importloop2.qbs0000644000175100001660000000004514776170045025173 0ustar runnerdockerimport "importloop1.qbs" as X X {} qbs-src-2.6.1/tests/auto/language/testdata/erroneous/module-var-in-product.qbs0000644000175100001660000000011114776170045027034 0ustar runnerdockerProduct { property bool p Group { module.p: true } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid-property-option.qbs0000644000175100001660000000010614776170045027521 0ustar runnerdockerProduct { Depends { name: "module-with-wrong-property-option" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undefined_stringlist_element.qbs0000644000175100001660000000010714776170045030640 0ustar runnerdockerProduct { property string blubb files: ["foo", blubb, "bar"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/subproject_cycle.qbs0000644000175100001660000000011614776170045026243 0ustar runnerdockerProject { SubProject { filePath: "subproject_cycle2.qbs" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/references_cycle2.qbs0000644000175100001660000000006714776170045026273 0ustar runnerdockerProject { references: ["references_cycle3.qbs"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/module-with-id.qbs0000644000175100001660000000010114776170045025526 0ustar runnerdockerProduct { name: "p" Depends { name: "module-with-id" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_property_in_export_item.qbs0000644000175100001660000000030014776170045032056 0ustar runnerdockerProject { Product { name: "p1" Export { Depends { name: "cpp" } cpp.blubb: "x" } } Product { Depends { name: "p1" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency_cycle3a.qbs0000644000175100001660000000026214776170045026427 0ustar runnerdockerProject { Product { name: "B" Depends { productTypes: ["a"] } } Product { type: ["a"] name: "A" Depends { name: "B" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/references_cycle3.qbs0000644000175100001660000000006614776170045026273 0ustar runnerdockerProject { references: ["references_cycle.qbs"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_property_in_export_item2.qbs0000644000175100001660000000024214776170045032145 0ustar runnerdockerProject { Product { name: "p1" Export { something.other: "x" } } Product { Depends { name: "p1" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/overwrite-inherited-readonly-property.qbs0000644000175100001660000000007714776170045032406 0ustar runnerdockerParentItem { readOnlyString: "changing the unchangeable" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/ParentWithExport.qbs0000644000175100001660000000007514776170045026177 0ustar runnerdockerProduct { Export { property bool theProp } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/unknown_item_type.qbs0000644000175100001660000000014314776170045026462 0ustar runnerdockerNarf { zort: 1 // This invalid binding should not hide the "Unexpected item type" error. } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid-parameter-type.qbs0000644000175100001660000000034214776170045027270 0ustar runnerdockerProduct { Depends { name: "module_with_parameters" } Depends { name: "readonly" module_with_parameters.boolParameter: "This is not an error." module_with_parameters.stringParameter: 123 } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared-parameter2.qbs0000644000175100001660000000012414776170045027051 0ustar runnerdockerProduct { name: "myproduct" Depends { name: "readonly"; foo.bar: "bla" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/frozen-object-list.qbs0000644000175100001660000000044614776170045026432 0ustar runnerdocker Product { Probe { id: probe property varList output configure: { output = [{"key": "value"}]; found = true; } } property var test: { var result = probe.output; result.push({}); return result; } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/original-in-export-item3.qbs0000644000175100001660000000033014776170045027450 0ustar runnerdockerProject { Product { name: "a" Export { Properties { x.y.z: original } } } Product { name: "b" Depends { name: "a" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/syntax-error-in-probe.qbs0000644000175100001660000000012514776170045027072 0ustar runnerdockerProduct { Probe { id: hurz configure: { fngkgsdjfgklkf } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/multiple_properties_in_subproject.qbs0000644000175100001660000000016014776170045031740 0ustar runnerdockerProject { SubProject { Properties { condition: false } Properties { name: "blubb" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_property.qbs0000644000175100001660000000004214776170045026754 0ustar runnerdockerProduct { doesntexist: 123 } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_property_in_export_item3.qbs0000644000175100001660000000017214776170045032150 0ustar runnerdockerProject { Product { name: "p1" Export { blubb: false } } Product { Depends { name: "p1" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/ParentItem.qbs0000644000175100001660000000014614776170045024757 0ustar runnerdockerProduct { property bool cpp readonly property string readOnlyString: "I cannot be changed!" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_item.qbs0000644000175100001660000000005514776170045026032 0ustar runnerdockerProduct { cpp.defines: ["SUPERCRAZY"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid-references.qbs0000644000175100001660000000006014776170045026447 0ustar runnerdockerProject { references: "nosuchproject.qbs" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/missing-js-file.qbs0000644000175100001660000000007314776170045025706 0ustar runnerdockerProduct { Depends { name: "missing-js-file-module" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency_cycle3.qbs0000644000175100001660000000026214776170045026266 0ustar runnerdockerProject { Product { type: ["a"] name: "A" Depends { name: "B" } } Product { name: "B" Depends { productTypes: ["a"] } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/throw_in_property_binding.qbs0000644000175100001660000000010214776170045030166 0ustar runnerdockerProduct { name: { throw "something is wrong"; } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/original-in-module-prototype.qbs0000644000175100001660000000010114776170045030434 0ustar runnerdockerProduct { Depends { name: "module-with-invalid-original" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/original-in-export-item.qbs0000644000175100001660000000027114776170045027371 0ustar runnerdockerProject { Product { name: "a" Export { property string p: original } } Product { name: "b" Depends { name: "a" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/references_cycle.qbs0000644000175100001660000000006714776170045026211 0ustar runnerdockerProject { references: ["references_cycle2.qbs"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/duplicate_sources_wildcards.qbs0000644000175100001660000000014614776170045030460 0ustar runnerdockerProduct { files: ["*.qbs"] Group { files: ["duplicate_sources_wildcards.qbs"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/unknown_module.qbs0000644000175100001660000000007414776170045025753 0ustar runnerdockerProduct { Depends { name: "neitherModuleNorProduct" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid_file.qbs0000644000175100001660000000005714776170045025335 0ustar runnerdockerProduct { files: ["main.cpp", "other.h"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/subproject_cycle2.qbs0000644000175100001660000000011614776170045026325 0ustar runnerdockerProject { SubProject { filePath: "subproject_cycle3.qbs" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undefined_stringlist_element_in_probe.qbs0000644000175100001660000000022314776170045032514 0ustar runnerdockerProduct { Probe { id: dummy property stringList l configure: { l = ["a", undefined, "b"] } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid-parameter-rhs.qbs0000644000175100001660000000017414776170045027106 0ustar runnerdockerProduct { Depends { name: "prefix2.suffix" } Depends { name: "readonly"; prefix2.suffix.nope: access.will.fail } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency_cycle2.qbs0000644000175100001660000000055614776170045026273 0ustar runnerdockerProject { Product { name: "A" Depends { name: "B" } files: ["main.cpp"] } Product { name: "B" Depends { name: "C" } files: ["main.cpp"] } Product { name: "C" Depends { name: "A" } files: ["main.cpp"] } Product { name: "D" files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/original-in-product-property.qbs0000644000175100001660000000005114776170045030452 0ustar runnerdockerProduct { property int n: original } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/reserved_name_in_import.qbs0000644000175100001660000000006514776170045027606 0ustar runnerdockerimport "../idusagebase.qbs" as TextFile Product { } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/original-in-export-item2.qbs0000644000175100001660000000025514776170045027455 0ustar runnerdockerProject { Product { name: "a" Export { x.y.z: original } } Product { name: "b" Depends { name: "a" } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/conflicting-properties-in-export-items.qbs0000644000175100001660000000011014776170045032431 0ustar runnerdockerParentWithExport { Export { property string theProp } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/oldQbsVersion.qbs0000644000175100001660000000013714776170045025501 0ustar runnerdockerProject { minimumQbsVersion: "999.5.4" Product { qbs.enableSound: true } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/subproject_cycle3.qbs0000644000175100001660000000011514776170045026325 0ustar runnerdockerProject { SubProject { filePath: "subproject_cycle.qbs" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/frozen-object.qbs0000644000175100001660000000047314776170045025461 0ustar runnerdocker Product { Probe { id: probe property var output configure: { output = {"key": "value"} found = true } } property var test: { "use strict" var result = probe.output; result.key = "newValue"; return result; } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/no-configure-in-probe.qbs0000644000175100001660000000005714776170045027014 0ustar runnerdockerProduct { Probe { id: hurz } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/nonexistentouter.qbs0000644000175100001660000000006414776170045026343 0ustar runnerdockerProject { Product { name: outer } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/mismatching-multiplex-dependency.qbs0000644000175100001660000000046314776170045031351 0ustar runnerdockerProject { Product { name: "a" multiplexByQbsProperties: ["architectures"] qbs.architectures: ["x86", "arm"] } Product { name: "b" Depends { name: "a" } multiplexByQbsProperties: ["architectures"] qbs.architectures: ["mips", "ppc"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/overwrite-readonly-module-property.qbs0000644000175100001660000000014614776170045031715 0ustar runnerdockerProduct { Depends { name: "readonly" } readonly.readOnlyString: "changing the unchangeable" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/multiple_exports.qbs0000644000175100001660000000005014776170045026320 0ustar runnerdockerProduct { Export {} Export {} } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared-parameter1.qbs0000644000175100001660000000016214776170045027052 0ustar runnerdockerProduct { Depends { name: "prefix2.suffix" } Depends { name: "readonly"; prefix2.suffix.nope: "nope" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid_child_item_type.qbs0000644000175100001660000000005114776170045027552 0ustar runnerdockerProject { Depends { name: "foo" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/undeclared_property_in_Properties_item.qbs0000644000175100001660000000007214776170045032677 0ustar runnerdockerProduct { Properties { blubb.bla: "x" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/misused-inherited-property.qbs0000644000175100001660000000005514776170045030212 0ustar runnerdockerParentItem { cpp.compilerName: "blubb" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/conflicting-module-instances.qbs0000644000175100001660000000007214776170045030454 0ustar runnerdockerProduct { Depends { name: "conflicting-instances" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/rule-without-output-tags.qbs0000644000175100001660000000034614776170045027653 0ustar runnerdockerProduct { Rule { inputs: "input-tag" prepare: { var cmd = new JavaScriptCommand; cmd.silent = true; cmd.sourceCode = function() {}; return cmd; } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/main.cpp0000644000175100001660000000356014776170045023633 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/missing-colon.qbs0000644000175100001660000000013214776170045025463 0ustar runnerdockerProduct { Depends { name: "dummy" } qbsSearchPaths: ".." dummy.cxxFlags { } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid_property_type.qbs0000644000175100001660000000005314776170045027337 0ustar runnerdockerProduct { property nonsense esnesnon } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/importloop1.qbs0000644000175100001660000000004514776170045025172 0ustar runnerdockerimport "importloop2.qbs" as X X {} qbs-src-2.6.1/tests/auto/language/testdata/erroneous/invalid_stringlist_element.qbs0000644000175100001660000000005714776170045030331 0ustar runnerdockerProduct { files: ["foo", ["zoo"], "bar"] } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/properties-item-with-invalid-condition.qbs0000644000175100001660000000023414776170045032416 0ustar runnerdockerProduct { Depends { name: "cpp" } Properties { condition: cpp.nonexistingproperty.includes("somevalue") cpp.defines: ["ABC"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/duplicate_sources.qbs0000644000175100001660000000012214776170045026416 0ustar runnerdockerProduct { files: ["main.cpp"] Group { files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency_cycle4.qbs0000644000175100001660000000005514776170045026267 0ustar runnerdockerProduct { Depends { name: "module-a" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/0000755000175100001660000000000014776170045023647 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-wrong-property-option/0000755000175100001660000000000014776170045032427 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-wrong-property-option/m.qbs0000644000175100001660000000023014776170045033365 0ustar runnerdockerModule { property string someProp PropertyOptions { name: "s0meProp" description: "Oops, spelt the property name wrong" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/conflicting-instances/0000755000175100001660000000000014776170045030133 5ustar runnerdocker././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/conflicting-instances/conflicting-instance1.qbsqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/conflicting-instances/conflicting-insta0000644000175100001660000000001314776170045033463 0ustar runnerdockerModule { } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/conflicting-instances/conflicting-instance2.qbsqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/conflicting-instances/conflicting-insta0000644000175100001660000000001314776170045033463 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/prefix2/0000755000175100001660000000000014776170045025226 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/prefix2/suffix/0000755000175100001660000000000014776170045026532 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/prefix2/suffix/suffix.qbs0000644000175100001660000000001314776170045030537 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/prefix2/prefix2.qbs0000644000175100001660000000006214776170045027312 0ustar runnerdockerModule { Depends { name: "prefix2.suffix" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module_with_parameters/0000755000175100001660000000000014776170045030412 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module_with_parameters/module_with_parameters.qbsqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module_with_parameters/module_with_para0000644000175100001660000000032114776170045033654 0ustar runnerdockerModule { Parameter { property bool boolParameter } Parameter { property int intParameter } Parameter { property stringList stringListParameter } Parameter { property string stringParameter } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/0000755000175100001660000000000014776170045030132 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file.jsqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file.0000644000175100001660000000005414776170045033132 0ustar runnerdockervar userfile = require("javascriptfile.js") ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file-module.qbsqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/missing-js-file-module/missing-js-file-0000644000175100001660000000007114776170045033130 0ustar runnerdockerimport "missing-js-file.js" as MissingJsFile Module { } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/readonly/0000755000175100001660000000000014776170045025464 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/readonly/readonly.qbs0000644000175100001660000000011714776170045030007 0ustar runnerdockerModule { readonly property string readOnlyString: "I cannot be changed!" } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/no_such_property/0000755000175100001660000000000014776170045027251 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/no_such_property/no-such-property.qbs0000644000175100001660000000015214776170045033214 0ustar runnerdockerModule { Depends { name: "module_with_parameters" } module_with_parameters.noSuchProperty: true } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-a/0000755000175100001660000000000014776170045025352 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-a/module-a.qbs0000644000175100001660000000005414776170045027563 0ustar runnerdockerModule { Depends { name: "module-b" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-id/0000755000175100001660000000000014776170045026477 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithIdParent.qbs0000644000175100001660000000001214776170045032707 0ustar runnerdockerModule {} qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-id/ModuleWithId.qbs0000644000175100001660000000003714776170045031544 0ustar runnerdockerModuleWithIdParent { id: foo } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-b/0000755000175100001660000000000014776170045025353 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-b/module-b.qbs0000644000175100001660000000005414776170045027565 0ustar runnerdockerModule { Depends { name: "module-a" } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-invalid-original/0000755000175100001660000000000014776170045031333 5ustar runnerdocker././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-invalid-original/module-with-invalid-original.qbsqbs-src-2.6.1/tests/auto/language/testdata/erroneous/modules/module-with-invalid-original/module-wit0000644000175100001660000000005314776170045033342 0ustar runnerdockerModule { property string p: original } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs0000644000175100001660000000044114776170045030423 0ustar runnerdockerProject { Profile { name: "profile1" } Profile { name: "profile2" } Product { name: "dep" qbs.profiles: ["profile1", "profile2"] } Product { name: "main" Depends { name: "dep"; profiles: ["profile47"]; } } } qbs-src-2.6.1/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs0000644000175100001660000000035014776170045030263 0ustar runnerdockerProject { Profile { name: "profile1" } Product { name: "dep" qbs.profiles: ["profile1"] } Product { name: "main" Depends { name: "dep"; profiles: ["profile47"]; } } } qbs-src-2.6.1/tests/auto/language/testdata/jsimportsinmultiplescopes.qbs0000644000175100001660000000025314776170045026237 0ustar runnerdockerimport "jsimportsinmultiplescopes.js" as MyFunctions Product { name: MyFunctions.getName(qbs) qbs.installDir: MyFunctions.getInstallDir() files: "main.cpp" } qbs-src-2.6.1/tests/auto/language/testdata/qbs1275.qbs0000644000175100001660000000111114776170045021763 0ustar runnerdockerProject { Product { name: "v-bug" Export { Depends { name: "cpp"} cpp.defines: "" } } Product { name: "e-bug" Export { Depends { name: "v-bug" } } } Product { name: "u-bug" Export { Depends { name: "c-bug" } } } Product { name: "c-bug" Export { Depends { name: "e-bug" } } } Product { name: "H-bug" Depends { name: "e-bug" } Depends { name: "u-bug" } Group { qbs.install: true } } } qbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/0000755000175100001660000000000014776170045027513 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/dependency-via-module.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/dependency-via-modu0000644000175100001660000000017414776170045033275 0ustar runnerdockerProduct { Depends { name: "failing-validation"; required: false } Depends { name: "failing-validation-indirect" } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/required-chain-module.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/required-chain-modu0000644000175100001660000000021514776170045033276 0ustar runnerdockerProduct { Depends { name: "failing-validation"; required: false } Depends { name: "failing-validation-indirect"; required: false } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/required-chain-export.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/required-chain-expo0000644000175100001660000000041014776170045033302 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "failing-validation" } } } Product { Depends { name: "failing-validation"; required: false } Depends { name: "dep"; required: false } } } ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/required-chain-export-indirect.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/required-chain-expo0000644000175100001660000000057514776170045033316 0ustar runnerdockerProject { Product { name: "dep2" Export { Depends { name: "dep1" } } } Product { name: "dep1" Export { Depends { name: "failing-validation-indirect" } } } Product { Depends { name: "failing-validation"; required: false } Depends { name: "dep2"; required: false } } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/dependency-via-export.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/dependency-via-expo0000644000175100001660000000036714776170045033310 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "failing-validation" } } } Product { Depends { name: "failing-validation"; required: false } Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/complicated.qbs0000644000175100001660000000030114776170045032500 0ustar runnerdockerProduct { Depends { name: "failing-validation"; required: false } Depends { name: "failing-validation-indirect" } Depends { name: "failing-validation-indirect"; required: false } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/direct-dependencies.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/direct-dependencies0000644000175100001660000000016314776170045033334 0ustar runnerdockerProduct { Depends { name: "failing-validation"; required: false } Depends { name: "failing-validation" } } qbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/0000755000175100001660000000000014776170045031163 5ustar runnerdocker././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-validation-indirect/qbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-val0000755000175100001660000000000014776170045033275 5ustar runnerdocker././@LongLink0000644000000000000000000000022500000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-validation-indirect/failing-validation-indirect.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-val0000644000175100001660000000006614776170045033301 0ustar runnerdockerModule { Depends { name: "failing-validation" } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-validation/qbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-val0000755000175100001660000000000014776170045033275 5ustar runnerdocker././@LongLink0000644000000000000000000000020300000000000011576 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-validation/failing-validation.qbsqbs-src-2.6.1/tests/auto/language/testdata/required-and-nonrequired-dependencies/modules/failing-val0000644000175100001660000000007014776170045033274 0ustar runnerdockerModule { validate: { throw "validation error!"; } } qbs-src-2.6.1/tests/auto/language/testdata/depends-item-in-group.qbs0000644000175100001660000000070714776170045025005 0ustar runnerdockerProject { Product { name: "dep" } Product { name: "main" property bool enableGroup1 property bool enableGroup2 property bool enableDepends Group { condition: enableGroup1 Group { condition: product.enableGroup2 property bool forwarded: product.enableDepends Depends { name: "dep"; condition: forwarded } } } } } qbs-src-2.6.1/tests/auto/language/testdata/throwing-probe.qbs0000644000175100001660000000030214776170045023626 0ustar runnerdockerProduct { name: "theProduct" property bool enableProbe Probe { id: whatever condition: enableProbe configure: { throw "Error!"; } } } qbs-src-2.6.1/tests/auto/language/testdata/modules/0000755000175100001660000000000014776170045021626 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/broken/0000755000175100001660000000000014776170045023106 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/broken/broken.qbs0000644000175100001660000000056514776170045025103 0ustar runnerdockerModule { Probe { id: theProbe property stringList broken property stringList fine configure: { broken = [["x"]]; fine = ["x"] found = true; } } property stringList broken: theProbe.broken property stringList fine: theProbe.fine.filter(function(incl) { return incl != "y"; }); } qbs-src-2.6.1/tests/auto/language/testdata/modules/multiple_backends/0000755000175100001660000000000014776170045025313 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/multiple_backends/backend3.qbs0000644000175100001660000000021014776170045027465 0ustar runnerdockerModule { condition: qbs.targetOS.includes("os2") && qbs.toolchain.includes("tc") priority: 1 property string backend3Prop } qbs-src-2.6.1/tests/auto/language/testdata/modules/multiple_backends/backend2.qbs0000644000175100001660000000017614776170045027477 0ustar runnerdockerModule { condition: qbs.targetOS.includes("os2") property string prop: "backend 2" property string backend2Prop } qbs-src-2.6.1/tests/auto/language/testdata/modules/multiple_backends/backend1.qbs0000644000175100001660000000013514776170045027471 0ustar runnerdockerModule { condition: qbs.targetOS.includes("os1") property string prop: "backend 1" } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/0000755000175100001660000000000014776170045023326 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/gui/0000755000175100001660000000000014776170045024112 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/gui/dummygui.qbs0000644000175100001660000000041614776170045026462 0ustar runnerdockerModule { Depends { name: "dummyqt.core" } property string guiProperty: "guiProperty" property string someString: "ene mene muh" Depends { name: "dummy" } dummy.defines: ["QT_GUI"] dummy.someString: someString dummy.zort: dummyqt.core.zort } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/core/0000755000175100001660000000000014776170045024256 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/core/dummycore.qbs0000644000175100001660000000111614776170045026770 0ustar runnerdockerModule { property int versionMajor: 5 property int versionMinor: 0 property int versionPatch: 0 property string version: versionMajor.toString() + "." + versionMinor.toString() + "." + versionPatch.toString() property string coreProperty: "coreProperty" property string coreVersion: version property string zort: "zort in dummyqt.core" Depends { name: "dummy" } dummy.defines: ["QT_CORE"] dummy.rpaths: ["/opt/qt/lib"] dummy.cFlags: [zort] dummy.varListProp: [{c: "qtcore"}] Properties { dummy.productName: product.name } } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/network/0000755000175100001660000000000014776170045025017 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummyqt/network/dummynetwork.qbs0000644000175100001660000000027114776170045030273 0ustar runnerdockerModule { Depends { name: "dummyqt"; submodules: ["core"] } property string networkProperty: "networkProperty" Depends { name: "dummy" } dummy.defines: ["QT_NETWORK"] } qbs-src-2.6.1/tests/auto/language/testdata/modules/gmod2/0000755000175100001660000000000014776170045022636 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/gmod2/gmod2.qbs0000644000175100001660000000031214776170045024351 0ustar runnerdockerModule { property int prop: 0 property string gmod2_string: "gmod2_string_proto" property string commonName: "commonName_in_gmod2" property stringList gmod2_list: ["gmod2_list_proto"] } qbs-src-2.6.1/tests/auto/language/testdata/modules/module_with_group/0000755000175100001660000000000014776170045025362 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/module_with_group/module_with_group.qbs0000644000175100001660000000072414776170045031630 0ustar runnerdockerModule { Depends { name: "dummy" } property string moduleDefine: "module_define" property string group Group { name: "module_group" condition: group == name Properties { dummy.defines: [moduleDefine.toUpperCase(), name.toUpperCase()] } } Group { name: "module_group_alt" condition: group == name product.dummy.defines: [moduleDefine.toUpperCase(), name.toUpperCase()] } } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummy3_loader/0000755000175100001660000000000014776170045024372 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummy3_loader/dummy3_loader.qbs0000644000175100001660000000010514776170045027641 0ustar runnerdockerModule { Depends { name: "dummy3" } dummy3.loadDummy: true } qbs-src-2.6.1/tests/auto/language/testdata/modules/scopemod/0000755000175100001660000000000014776170045023437 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/scopemod/scopemod.qbs0000644000175100001660000000030314776170045025753 0ustar runnerdockerModule { property int a: 1 property int b: 1 property int c: a + 1 property int d: b + 1 property int e: 1 property int f: 1 property int g: 1 property int h: 1 } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummy/0000755000175100001660000000000014776170045022761 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummy/dummy_base.qbs0000644000175100001660000000010314776170045025607 0ustar runnerdockerModule { condition: false property pathList includePaths } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummy/dummy.qbs0000644000175100001660000000173114776170045024625 0ustar runnerdockerimport "dummy_base.qbs" as DummyBase DummyBase { condition: true additionalProductTypes: ["tag2"] property bool falseProperty: false property stringList defines property stringList cFlags property stringList cxxFlags property stringList rpaths: ["$ORIGIN"] property string someString property string productName: product.name property string upperCaseProductName: productName.toUpperCase() property string zort: "zort in dummy" property pathList includePaths property path somePath property stringList listProp: product.type.includes("blubb") ? ["123"] : ["456"] property bool controllingProp: false property stringList listProp2: controllingProp ? ["DEFAULT_STUFF", "EXTRA_STUFF"] : ["DEFAULT_STUFF"] property varList varListProp: [{a: controllingProp, b: someString}] Probe { id: QBS_1821 property stringList Flags: cxxFlags configure: {} } } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummy2/0000755000175100001660000000000014776170045023043 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummy2/dummy2.qbs0000644000175100001660000000022414776170045024765 0ustar runnerdockerModule { additionalProductTypes: ["tag3"] property var defines property var someTrueProp: true property var someFalseProp: false } qbs-src-2.6.1/tests/auto/language/testdata/modules/module-with-properties-item/0000755000175100001660000000000014776170045027212 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/modules/module-with-properties-item/module-with-properties-item.qbsqbs-src-2.6.1/tests/auto/language/testdata/modules/module-with-properties-item/module-with-propertie0000644000175100001660000000033014776170045033376 0ustar runnerdockerModule { property bool boolProperty: true property string stringProperty: "set in Module item" Properties { condition: boolProperty stringProperty: "overridden in Properties item" } } qbs-src-2.6.1/tests/auto/language/testdata/modules/gmod/0000755000175100001660000000000014776170045022554 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/gmod/gmod1/0000755000175100001660000000000014776170045023563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/gmod/gmod1/gmod1.qbs0000644000175100001660000000106314776170045025301 0ustar runnerdockerModule { Depends { name: "gmod2" } Depends { name: "gmod4" } property stringList gmod1_list1: ["gmod1_list1_proto", gmod1_string] property stringList gmod1_list2: ["gmod1_list2_proto"] property stringList gmod1_list3: [gmod1_string] property string gmod1_string: "gmod1_string_proto" property string commonName: "commonName_in_gmod1" property int depProp: gmod2.prop property int p0: p1 + p2 property int p1: 0 property int p2: 0 gmod2.gmod2_string: gmod1_string gmod2.gmod2_list: [gmod1_string, commonName] } qbs-src-2.6.1/tests/auto/language/testdata/modules/module-with-product-dependency/0000755000175100001660000000000014776170045027656 5ustar runnerdocker././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/language/testdata/modules/module-with-product-dependency/module-with-product-dependency.qbsqbs-src-2.6.1/tests/auto/language/testdata/modules/module-with-product-dependency/module-with-produc0000644000175100001660000000004614776170045033331 0ustar runnerdockerModule { Depends { name: "p2" } } qbs-src-2.6.1/tests/auto/language/testdata/modules/gmod4/0000755000175100001660000000000014776170045022640 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/gmod4/gmod4.qbs0000644000175100001660000000027614776170045024366 0ustar runnerdockerModule { Depends { name: "gmod2" } Depends { name: "gmod3" } property string gmod4_string: "gmod4_string_proto" gmod2.gmod2_list: [gmod4_string + "_" + gmod3.gmod3_string] } qbs-src-2.6.1/tests/auto/language/testdata/modules/dummy3/0000755000175100001660000000000014776170045023044 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/dummy3/dummy3.qbs0000644000175100001660000000014214776170045024766 0ustar runnerdockerModule { property bool loadDummy: false Depends { name: "dummy"; condition: loadDummy } } qbs-src-2.6.1/tests/auto/language/testdata/modules/deepdummy/0000755000175100001660000000000014776170045023617 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/deepdummy/deep/0000755000175100001660000000000014776170045024534 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/deepdummy/deep/moat/0000755000175100001660000000000014776170045025474 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/deepdummy/deep/moat/dummydeepmoat.qbs0000644000175100001660000000020214776170045031047 0ustar runnerdockerModule { property string depth: "abysmal" Depends { name: "dummy"; id: dummyId } property string zort: dummyId.zort } qbs-src-2.6.1/tests/auto/language/testdata/modules/gmod3/0000755000175100001660000000000014776170045022637 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/gmod3/qmod3.qbs0000644000175100001660000000020514776170045024366 0ustar runnerdockerModule { Depends { name: "gmod2" } property string gmod3_string: "gmod3_string_proto" gmod2.gmod2_list: [gmod3_string] } qbs-src-2.6.1/tests/auto/language/testdata/modules/module_with_file/0000755000175100001660000000000014776170045025145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/modules/module_with_file/module-with-file.qbs0000644000175100001660000000056714776170045031037 0ustar runnerdockerModule { property bool file1IsTarget property bool file2IsTarget Group { prefix: product.sourceDirectory + '/' files: "zort" filesAreTargets: product.module_with_file.file1IsTarget } Group { prefix: product.sourceDirectory + '/' files: "zort" filesAreTargets: product.module_with_file.file2IsTarget } } qbs-src-2.6.1/tests/auto/language/testdata/Banana0000644000175100001660000000003214776170045021254 0ustar runnerdockerPeanut butter jelly time! qbs-src-2.6.1/tests/auto/language/testdata/eval-error-in-non-present-module.qbs0000644000175100001660000000016414776170045027101 0ustar runnerdockerProduct { name: "p" property bool moduleRequired Depends { name: "broken"; required: moduleRequired } } qbs-src-2.6.1/tests/auto/language/testdata/probes-and-multiplexing.qbs0000644000175100001660000000062614776170045025442 0ustar runnerdockerProduct { multiplexByQbsProperties: "architectures" qbs.architectures: ["x86", "x86_64", "arm"] property string archFromProbe: theProbe.archOut Probe { id: theProbe property string archIn: qbs.architecture property string archOut configure: { archOut = archIn; } } Group { name: "theGroup" qbs.sysroot: "/" + theProbe.archOut } } qbs-src-2.6.1/tests/auto/language/testdata/filetags.qbs0000644000175100001660000000307314776170045022466 0ustar runnerdockerProject { FileTagger { patterns: "*.cpp" fileTags: ["cpp"] } Product { name: "filetagger_project_scope" files: ["main.cpp"] } Product { name: "filetagger_product_scope" files: ["drawline.asm"] FileTagger { patterns: "*.asm" fileTags: ["asm"] } } Product { name: "filetagger_static_pattern" files: "Banana" FileTagger { patterns: "Banana" fileTags: ["yellow"] } } Product { name: "unknown_file_tag" files: "narf.zort" } Product { name: "set_file_tag_via_group" Group { files: ["main.cpp"] fileTags: ["c++"] } } Product { name: "override_file_tag_via_group" Group { files: "main.cpp" // gets file tag "cpp" through the FileTagger fileTags: ["c++"] } } Product { name: "add_file_tag_via_group" Group { overrideTags: false files: "main.cpp" fileTags: ["zzz"] } } Product { name: "prioritized_filetagger" files: ["main.cpp"] FileTagger { patterns: ["*.cpp"] fileTags: ["cpp1"] priority: 3 } FileTagger { patterns: ["*.cpp"] fileTags: ["cpp2"] priority: 3 } FileTagger { patterns: ["*.cpp"] fileTags: ["ignored"] priority: 2 } } } qbs-src-2.6.1/tests/auto/language/testdata/subdir2/0000755000175100001660000000000014776170045021530 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/subdir2/exports-mylib2.qbs0000644000175100001660000000053714776170045025144 0ustar runnerdockerStaticLibrary { name: "mylib2" Depends { name: "dummy" } dummy.defines: ["BUILD_" + product.name.toUpperCase()] property string definePrefix: "USE_" Export { Depends { name: "dummy" } dummy.defines: [exportingProduct.definePrefix + exportingProduct.name.toUpperCase()] dummy.includePaths: ["./lib"] } } qbs-src-2.6.1/tests/auto/language/testdata/multiplexing-by-profile/0000755000175100001660000000000014776170045024745 5ustar runnerdockerqbs-src-2.6.1/tests/auto/language/testdata/multiplexing-by-profile/p2.qbs0000644000175100001660000000055114776170045025776 0ustar runnerdockerProject { Profile { name: "profile1" qbs.architecture: "dummy" } Profile { name: "profile2" qbs.architecture: "blubb" } Product { name: "p1" qbs.profiles: ["profile1"] } Product { name: "p2" qbs.profiles: ["profile1", "profile2"] Depends { name: "p1" } } } qbs-src-2.6.1/tests/auto/language/testdata/multiplexing-by-profile/p1.qbs0000644000175100001660000000042414776170045025774 0ustar runnerdockerProject { Profile { name: "theProfile" qbs.architecture: "dummy" } Product { name: "p1" qbs.profiles: ["theProfile"] } Product { name: "p2" qbs.profiles: ["theProfile"] Depends { name: "p1" } } } qbs-src-2.6.1/tests/auto/language/testdata/multiplexing-by-profile/p3.qbs0000644000175100001660000000102114776170045025770 0ustar runnerdockerProject { Profile { name: "profile1" qbs.architecture: "dummy" } Profile { name: "profile2" qbs.architecture: "blubb" } Profile { name: "profile3" qbs.architecture: "hurz" } Profile { name: "profile4" qbs.architecture: "zonk" } Product { name: "p1" qbs.profiles: ["profile1", "profile2"] Depends { name: "p2" } } Product { name: "p2" qbs.profiles: ["profile3", "profile4"] } } qbs-src-2.6.1/tests/auto/language/testdata/multiplexing-by-profile/p4.qbs0000644000175100001660000000060114776170045025774 0ustar runnerdockerProject { Profile { name: "profile1" qbs.architecture: "dummy" } Profile { name: "profile2" qbs.architecture: "blubb" } Product { name: "p1" qbs.profiles: ["profile1"] Depends { name: "p2"; profiles: ["profile1"] } } Product { name: "p2" qbs.profiles: ["profile1", "profile2"] } } qbs-src-2.6.1/tests/auto/language/testdata/conditionaldepends.qbs0000644000175100001660000000421614776170045024536 0ustar runnerdockerimport "conditionaldepends_base.qbs" as CondBase Project { CondBase { name: 'conditionaldepends_derived' someProp: true } CondBase { name: 'conditionaldepends_derived_false' someProp: "knolf" === "narf" } Product { name: "product_props_true" property bool someTrueProp: true Depends { condition: someTrueProp; name: "dummy" } } Product { name: "product_props_false" property bool someFalseProp: false Depends { condition: someFalseProp; name: "dummy" } } property bool someTruePrjProp: true Product { name: "project_props_true" Depends { condition: project.someTruePrjProp; name: "dummy" } } property bool someFalsePrjProp: false Product { name: "project_props_false" Depends { condition: project.someFalsePrjProp; name: "dummy" } } Product { name: "module_props_true" Depends { name: "dummy2" } Depends { condition: dummy2.someTrueProp; name: "dummy" } } Product { name: "module_props_false" Depends { name: "dummy2" } Depends { condition: dummy2.someFalseProp; name: "dummy" } } Product { name: "multilevel_module_props_true" Depends { name: "dummy3" } dummy3.loadDummy: true } Product { name: "multilevel_module_props_false" Depends { name: "dummy3" } } Product { name: "multilevel_module_props_overridden" Depends { name: "dummy3" } } Product { name: "multilevel2_module_props_true" Depends { name: "dummy3_loader" } } Product { name: "contradictory_conditions1" Depends { condition: false; name: "dummy" } Depends { condition: true; name: "dummy" } // this one wins } Product { name: "contradictory_conditions2" Depends { condition: true; name: "dummy" } // this one wins Depends { condition: false; name: "dummy" } } Product { name: "unknown_dependency_condition_false" Depends { condition: false; name: "doesonlyexistifhellfreezesover" } } } qbs-src-2.6.1/tests/auto/language/tst_language.cpp0000644000175100001660000047121514776170045021540 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack. #include "tst_language.h" #include "../shared.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QList) using namespace qbs; using namespace qbs::Internal; static QString testDataDir() { return testDataSourceDir(SRCDIR "/testdata"); } static QString testProject(const char *fileName) { return testDataDir() + QLatin1Char('/') + QLatin1String(fileName); } class JSSourceValueCreator { FileContextPtr m_fileContext; std::vector> m_strings; public: JSSourceValueCreator(const FileContextPtr &fileContext) : m_fileContext(fileContext) { } JSSourceValuePtr create(const QString &sourceCode) { JSSourceValuePtr value = JSSourceValue::create(); value->setFile(m_fileContext); auto str = std::make_unique(sourceCode); value->setSourceCode(*str.get()); m_strings.push_back(std::move(str)); return value; } }; TestLanguage::TestLanguage(ILogSink *logSink, Settings *settings) : m_logSink(logSink) , m_settings(settings) , m_wildcardsTestDirPath(QDir::tempPath() + QLatin1String("/_wildcards_test_dir_")) { m_rand.seed(QTime::currentTime().msec()); qRegisterMetaType >("QList"); } TestLanguage::~TestLanguage() = default; QHash TestLanguage::productsFromProject(ResolvedProjectPtr project) { QHash result; const auto products = project->allProducts(); for (const ResolvedProductPtr &product : products) result.insert(product->name, product); return result; } template typename C::value_type findByName(const C &container, const QString &name) { auto endIt = std::end(container); auto it = std::find_if(std::begin(container), endIt, [&name] (const typename C::value_type &thing) { return thing->name == name; }); if (it != endIt) return *it; return typename C::value_type(); } ResolvedModuleConstPtr TestLanguage::findModuleByName(ResolvedProductPtr product, const QString &name) { return findByName(product->modules, name); } QVariant TestLanguage::productPropertyValue(ResolvedProductPtr product, QString propertyName) { QStringList propertyNameComponents = propertyName.split(QLatin1Char('.')); if (propertyNameComponents.size() > 1) return product->moduleProperties->property(propertyNameComponents); return getConfigProperty(product->productProperties, propertyNameComponents); } void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool *handled) { const QByteArray dataTag = QTest::currentDataTag(); if (dataTag == "init") { *handled = true; bool exceptionCaught = false; try { resolveProject(projectFileName); QVERIFY(!!project); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } else if (dataTag == "cleanup") { *handled = true; project.reset(); } else { *handled = false; } } TopLevelProjectPtr TestLanguage::resolveProject(const char *relProjectFilePath) { if (relProjectFilePath) defaultParameters.setProjectFilePath(testProject(relProjectFilePath)); defaultParameters.expandBuildConfiguration(); ProjectResolver resolver(defaultParameters, m_engine.get(), m_logger); return project = resolver.resolve(); } void TestLanguage::init() { // clear caches, otherwise StoredVariantValues may end up being at the same address // as the destroyed value m_engine->reset(); m_logSink->setLogLevel(LoggerInfo); defaultParameters = {}; defaultParameters.setBuildRoot(m_tempDir.path() + "/buildroot"); defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict); defaultParameters.setSettingsDirectory(m_settings->baseDirectory()); defaultParameters.setTopLevelProfile(profileName()); defaultParameters.setMaxJobCount(1); defaultParameters.setConfigurationName("default"); defaultParameters.setEnvironment(QProcessEnvironment::systemEnvironment()); defaultParameters.setSearchPaths({SRCDIR "/../../../share/qbs"}); QVERIFY(m_tempDir.isValid()); } #define HANDLE_INIT_CLEANUP_DATATAGS(fn) {\ bool handled;\ handleInitCleanupDataTags(fn, &handled);\ if (handled)\ return;\ QVERIFY(!!project);\ } void TestLanguage::initTestCase() { m_logger = Logger(m_logSink); m_engine = ScriptEngine::create(m_logger, EvalContext::PropertyEvaluation); QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute()); } void TestLanguage::additionalProductTypes() { bool exceptionCaught = false; try { resolveProject("additional-product-types.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); const ResolvedProductConstPtr product = products.value("p"); QVERIFY(!!product); const QVariantMap cfg = product->productProperties; QVERIFY(cfg.value("hasTag1").toBool()); QVERIFY(cfg.value("hasTag2").toBool()); QVERIFY(cfg.value("hasTag3").toBool()); QVERIFY(!cfg.value("hasTag4").toBool()); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::baseProperty() { bool exceptionCaught = false; try { resolveProject("baseproperty.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); QVERIFY(!!product); QVariantMap cfg = product->productProperties; QCOMPARE(cfg.value("narf").toStringList(), QStringList() << "boo"); QCOMPARE(cfg.value("zort").toStringList(), QStringList() << "bar" << "boo"); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::baseValidation() { try { resolveProject("base-validate/base-validate.qbs"); QVERIFY2(false, "exception expected"); } catch (const qbs::ErrorInfo &e) { QVERIFY2(e.toString().contains("Parent succeeded, child failed."), qPrintable(e.toString())); } } void TestLanguage::brokenDependencyCycle() { QFETCH(QString, projectFileName); try { resolveProject(qPrintable(projectFileName)); } catch (const qbs::ErrorInfo &e) { QVERIFY2(false, qPrintable(e.toString())); } } void TestLanguage::brokenDependencyCycle_data() { QTest::addColumn("projectFileName"); QTest::newRow("one order of products") << "broken-dependency-cycle1.qbs"; QTest::newRow("another order of products") << "broken-dependency-cycle2.qbs"; } void TestLanguage::buildConfigStringListSyntax() { bool exceptionCaught = false; try { QVariantMap overriddenValues; overriddenValues.insert("project.someStrings", "foo,bar,baz"); defaultParameters.setOverriddenValues(overriddenValues); resolveProject("buildconfigstringlistsyntax.qbs"); QVERIFY(!!project); QCOMPARE(project->projectProperties().value("someStrings").toStringList(), QStringList() << "foo" << "bar" << "baz"); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::builtinFunctionInSearchPathsProperty() { bool exceptionCaught = false; try { QVERIFY(resolveProject("builtinFunctionInSearchPathsProperty.qbs")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::chainedProbes() { bool exceptionCaught = false; try { resolveProject("chained-probes/chained-probes.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); const QString prop1Val = project->products.front()->moduleProperties ->moduleProperty("m", "prop1").toString(); QCOMPARE(prop1Val, QLatin1String("probe1Val")); const QString prop2Val = project->products.front()->moduleProperties ->moduleProperty("m", "prop2").toString(); QCOMPARE(prop2Val, QLatin1String("probe1Valprobe2Val")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::versionCompare() { bool exceptionCaught = false; try { QVERIFY(resolveProject("versionCompare.qbs")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::canonicalArchitecture() { bool exceptionCaught = false; try { resolveProject("canonicalArchitecture.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value(QStringLiteral("x86")); QVERIFY(!!product); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::rfc1034Identifier() { bool exceptionCaught = false; try { resolveProject("rfc1034identifier.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value(QStringLiteral("this-has-special-characters-" "uh-oh-Undersc0r3s-Are.Bad")); QVERIFY(!!product); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::throwThings_data() { QTest::addColumn("type"); QTest::addColumn("result"); QTest::addRow("bool") << "bool" << "true"; QTest::addRow("int") << "int" << "43"; QTest::addRow("string") << "string" << "an error"; QTest::addRow("list") << "list" << R"([ "an", "error" ])"; QTest::addRow("object") << "object" << R"({ "reason": "overheating", "result": "crash" })"; } void TestLanguage::throwThings() { QFETCH(QString, type); QFETCH(QString, result); bool exceptionCaught = false; try { defaultParameters.setOverriddenValues({{"project.throwType", type}}); resolveProject("throw.qbs"); } catch (const ErrorInfo &e) { exceptionCaught = true; QVERIFY2(e.toString().contains(result), qPrintable(e.toString())); } QVERIFY(exceptionCaught); } void TestLanguage::conditionalDepends() { bool exceptionCaught = false; ResolvedProductPtr product; ResolvedModuleConstPtr dependency; try { defaultParameters.setOverriddenValues({std::make_pair(QString("products." "multilevel_module_props_overridden.dummy3.loadDummy"), true)}); resolveProject("conditionaldepends.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); product = products.value("conditionaldepends_derived"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("conditionaldepends_derived_false"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QCOMPARE(dependency, ResolvedModuleConstPtr()); product = products.value("product_props_true"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("product_props_false"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QCOMPARE(dependency, ResolvedModuleConstPtr()); product = products.value("project_props_true"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("project_props_false"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QCOMPARE(dependency, ResolvedModuleConstPtr()); product = products.value("module_props_true"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy2"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("module_props_false"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy2"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy"); QCOMPARE(dependency, ResolvedModuleConstPtr()); product = products.value("multilevel_module_props_true"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy3"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("multilevel_module_props_false"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy3"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy"); QCOMPARE(dependency, ResolvedModuleConstPtr()); product = products.value("multilevel_module_props_overridden"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy3"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("multilevel2_module_props_true"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy3_loader"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy3"); QVERIFY(!!dependency); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("contradictory_conditions1"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("contradictory_conditions2"); QVERIFY(!!product); dependency = findModuleByName(product, "dummy"); QVERIFY(!!dependency); product = products.value("unknown_dependency_condition_false"); QVERIFY(!!product); dependency = findModuleByName(product, "doesonlyexistifhellfreezesover"); QVERIFY(!dependency); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::convertStringList() { FileContextPtr fileContext = FileContext::create(); fileContext->setFilePath("/dev/null"); JSSourceValueCreator sourceValueCreator(fileContext); ItemPool pool; Item *scope = Item::create(&pool, ItemType::Scope); scope->setProperty("x", sourceValueCreator.create("[\"a\", \"b\"]")); Evaluator evaluator(m_engine.get()); auto variantValue = evaluator.variantValue(scope, "x"); // despite we have a stringList prop, we evaluate it as a QVariantList QCOMPARE(variantValue.userType(), QMetaType::Type::QVariantList); // and we have to convert it explicitly #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) variantValue.convert(QMetaType(QMetaType::QStringList)); #else variantValue.convert(QMetaType::QStringList); #endif QCOMPARE(variantValue.userType(), QMetaType::Type::QStringList); QCOMPARE(variantValue, QStringList({"a", "b"})); } void TestLanguage::correctDeclInParentLookup() { ErrorInfo exception; try { resolveProject("correct-decl-in-parent-lookup.qbs"); QVERIFY(project); QCOMPARE(project->products.size(), size_t(1)); const ResolvedProductConstPtr theProduct = productsFromProject(project).value("p"); QVERIFY(theProduct); QCOMPARE( theProduct->moduleProperties->moduleProperty("dummy", "cxxFlags").toStringList(), QStringList("x")); } catch (const ErrorInfo &e) { exception = e; } QVERIFY2(!exception.hasError(), qPrintable(exception.toString())); } void TestLanguage::delayedError() { QFETCH(bool, productEnabled); try { QFETCH(QString, projectFileName); QVariantMap overriddenValues; overriddenValues.insert("project.enableProduct", productEnabled); defaultParameters.setOverriddenValues(overriddenValues); resolveProject(projectFileName.toLatin1()); QCOMPARE(productEnabled, false); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); const ResolvedProductConstPtr theProduct = productsFromProject(project).value("theProduct"); QVERIFY(!!theProduct); QCOMPARE(theProduct->enabled, false); } catch (const ErrorInfo &e) { if (!productEnabled) qDebug() << e.toString(); QCOMPARE(productEnabled, true); } } void TestLanguage::delayedError_data() { QTest::addColumn("projectFileName"); QTest::addColumn("productEnabled"); QTest::newRow("product enabled, module validation error") << "delayed-error/validation.qbs" << true; QTest::newRow("product disabled, module validation error") << "delayed-error/validation.qbs" << false; QTest::newRow("product enabled, module not found") << "delayed-error/nonexisting.qbs" << true; QTest::newRow("product disabled, module not found") << "delayed-error/nonexisting.qbs" << false; } void TestLanguage::dependencyOnAllProfiles() { bool exceptionCaught = false; try { TemporaryProfile p1("p1", m_settings); p1.p.setValue("qbs.architecture", "arch1"); TemporaryProfile p2("p2", m_settings); p2.p.setValue("qbs.architecture", "arch2"); QVariantMap overriddenValues; overriddenValues.insert("project.profile1", "p1"); overriddenValues.insert("project.profile2", "p2"); defaultParameters.setOverriddenValues(overriddenValues); resolveProject("dependencyOnAllProfiles.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(3)); const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main"); QVERIFY(!!mainProduct); QCOMPARE(mainProduct->dependencies.size(), size_t { 2 }); for (const ResolvedProductPtr &p : mainProduct->dependencies) { QCOMPARE(p->name, QLatin1String("dep")); QVERIFY(p->profile() == "p1" || p->profile() == "p2"); } } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::dependsItemInGroup_data() { QTest::addColumn("enableGroup1"); QTest::addColumn("enableGroup2"); QTest::addColumn("enableDepends"); QTest::addColumn("dependencyExpected"); QTest::newRow("all disabled") << false << false << false << false; QTest::newRow("only Depends enabled") << false << false << true << false; QTest::newRow("only inner Group enabled") << false << true << false << false; QTest::newRow("inner Group and Depends enabled") << false << true << true << false; QTest::newRow("only outer Group enabled") << true << false << false << false; QTest::newRow("only outer Group and Depends enabled") << true << false << true << false; QTest::newRow("only Groups enabled") << true << true << false << false; QTest::newRow("everything enabled") << true << true << true << true; } void TestLanguage::dependsItemInGroup() { QFETCH(bool, enableGroup1); QFETCH(bool, enableGroup2); QFETCH(bool, enableDepends); QFETCH(bool, dependencyExpected); bool exceptionCaught = false; try { const QVariantMap overriddenValues{ std::make_pair("products.main.enableGroup1", enableGroup1), std::make_pair("products.main.enableGroup2", enableGroup2), std::make_pair("products.main.enableDepends", enableDepends)}; defaultParameters.setOverriddenValues(overriddenValues); resolveProject("depends-item-in-group.qbs"); QVERIFY(project); const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main"); QVERIFY(mainProduct); QCOMPARE(mainProduct->dependencies.empty(), !dependencyExpected); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::derivedSubProject() { bool exceptionCaught = false; try { resolveProject("derived-sub-project/project.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::disabledPropertiesItem_data() { QTest::addColumn("setInProduct"); QTest::addColumn("setInHigher1"); QTest::addColumn("setInHigher2"); QTest::addColumn("setInLower"); QTest::addColumn("expectedValue"); QTest::addColumn("expectedListValue"); QTest::addColumn("expectedProductValue"); QTest::newRow("default") << false << false << false << false << QString("default") << QStringList{"N_GREATER_7", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition2"}; QTest::newRow("lower only") << false << false << false << true << QString("default_fromLower") << QStringList{"N_GREATER_7", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "WITH_LOWER_PROP", "N_NON_ZERO"} << QStringList{"condition2"}; QTest::newRow("higher2 only") << false << false << true << false << QString() << QStringList{"N_GREATER_7", "WITH_HIGHER2_PROP", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition2"}; QTest::newRow("lower and higher2") << false << false << true << true << QString() << QStringList{"N_GREATER_7", "WITH_HIGHER2_PROP", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "WITH_LOWER_PROP", "N_NON_ZERO"} << QStringList{"condition2"}; QTest::newRow("higher1 only") << false << true << false << false << QString("fromHigher1") << QStringList{"N_GREATER_7", "N_GREATER_6", "WITH_HIGHER1_PROP", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition2"}; QTest::newRow("lower and higher1") << false << true << false << true << QString("fromHigher1") << QStringList{"N_GREATER_7", "N_GREATER_6", "WITH_HIGHER1_PROP", "N_GREATER_5", "N_LESS_20", "WITH_LOWER_PROP", "N_NON_ZERO"} << QStringList{"condition2"}; QTest::newRow("product only") << true << false << false << false << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; QTest::newRow("product and lower") << true << false << false << true << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "WITH_LOWER_PROP", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; QTest::newRow("product and higher2") << true << false << true << false << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "WITH_HIGHER2_PROP", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; QTest::newRow("product, higher2 and lower") << true << false << true << true << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "WITH_HIGHER2_PROP", "N_GREATER_6", "N_GREATER_5", "N_LESS_20", "WITH_LOWER_PROP", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; QTest::newRow("product and higher1") << true << true << false << false << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "N_GREATER_6", "WITH_HIGHER1_PROP", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; QTest::newRow("product, higher1 and higher2") << true << true << true << false << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "WITH_HIGHER2_PROP", "N_GREATER_6", "WITH_HIGHER1_PROP", "N_GREATER_5", "N_LESS_20", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; QTest::newRow("all") << true << true << true << true << QString("fromProduct") << QStringList{"WITH_PRODUCT_PROP", "N_GREATER_7", "WITH_HIGHER2_PROP", "N_GREATER_6", "WITH_HIGHER1_PROP", "N_GREATER_5", "N_LESS_20", "WITH_LOWER_PROP", "N_NON_ZERO"} << QStringList{"condition1", "condition2"}; } void TestLanguage::disabledPropertiesItem() { QFETCH(bool, setInLower); QFETCH(bool, setInHigher1); QFETCH(bool, setInHigher2); QFETCH(bool, setInProduct); QFETCH(QString, expectedValue); QFETCH(QStringList, expectedListValue); QFETCH(QStringList, expectedProductValue); QVariantMap overriddenValues; overriddenValues.insert("modules.lower.setProp", setInLower); overriddenValues.insert("modules.higher1.setProp", setInHigher1); overriddenValues.insert("modules.higher2.setProp", setInHigher2); overriddenValues.insert("products.p.setProp", setInProduct); defaultParameters.setOverriddenValues(overriddenValues); bool exceptionCaught = false; try { resolveProject("disabled-properties-item/disabled-properties-item.qbs"); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); const ResolvedProductConstPtr &p = *products.constBegin(); QCOMPARE(p->moduleProperties->moduleProperty("lower", "prop").toString(), expectedValue); QCOMPARE( p->moduleProperties->moduleProperty("lower", "listProp").toStringList(), expectedListValue); QCOMPARE(p->productProperties.value("productProp").toStringList(), expectedProductValue); } void TestLanguage::disabledSubProject() { bool exceptionCaught = false; try { resolveProject("disabled-subproject.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 0); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::dottedNames_data() { QTest::addColumn("useProduct"); QTest::addColumn("useModule"); QTest::addColumn("expectSuccess"); QTest::addColumn("expectedErrorMessage"); QTest::newRow("missing product dependency") << false << true << false << QString("Item 'a.b' is not declared. Did you forget to add a Depends item"); QTest::newRow("missing module dependency") << true << false << false << QString("Item 'x.y' is not declared. Did you forget to add a Depends item"); QTest::newRow("missing both dependencies") << false << false << false << QString(); QTest::newRow("ok") << true << true << true << QString(); } void TestLanguage::dottedNames() { QFETCH(bool, expectSuccess); try { QFETCH(bool, useProduct); QFETCH(bool, useModule); const QVariantMap overridden{ std::make_pair("projects.theProject.includeDottedProduct", useProduct), std::make_pair("projects.theProject.includeDottedModule", useModule) }; defaultParameters.setOverriddenValues(overridden); resolveProject("dotted-names/dotted-names.qbs"); QVERIFY(expectSuccess); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), useProduct ? 2 : 1); const ResolvedProductPtr product = products.value("p"); QVERIFY(!!product); QCOMPARE(product->moduleProperties->moduleProperty("a.b", "c").toString(), QString("p")); QCOMPARE(product->moduleProperties->moduleProperty("x.y", "z").toString(), QString("p")); } catch (const ErrorInfo &e) { QVERIFY(!expectSuccess); QFETCH(QString, expectedErrorMessage); if (!expectedErrorMessage.isEmpty()) QVERIFY2(e.toString().contains(expectedErrorMessage), qPrintable(e.toString())); } } void TestLanguage::duplicateMultiplexValues_data() { QTest::addColumn("dummy"); QTest::newRow("duplicate-multiplex-value") << true; QTest::newRow("duplicate-multiplex-value2") << true; } void TestLanguage::duplicateMultiplexValues() { bool exceptionCaught = false; try { resolveProject(qPrintable(QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs"))); QVERIFY(project); const std::vector products = project->allProducts(); QCOMPARE(products.size(), 2); bool x86 = false; bool arm = false; for (const ResolvedProductPtr &p : products) { if (p->moduleProperties->moduleProperty("qbs", "architecture").toString() == "x86") x86 = true; else if (p->moduleProperties->moduleProperty("qbs", "architecture").toString() == "arm") arm = true; } QVERIFY(x86); QVERIFY(arm); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::emptyJsFile() { bool exceptionCaught = false; try { resolveProject("empty-js-file.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::enumerateProjectProperties() { bool exceptionCaught = false; try { resolveProject("enum-project-props.qbs"); QVERIFY(!!project); auto products = productsFromProject(project); QCOMPARE(products.size(), 1); auto product = products.values().front(); auto files = product->groups.front()->files; QCOMPARE(product->groups.size(), size_t(1)); QVERIFY(files); QCOMPARE(files->size(), size_t(1)); auto fileName = FileInfo::fileName(files->front()->absoluteFilePath); QCOMPARE(fileName, QString("dummy.txt")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::evalErrorInNonPresentModule_data() { QTest::addColumn("moduleRequired"); QTest::addColumn("errorMessage"); QTest::newRow("module required") << true << "broken.qbs:2:5 Element at index 0 of list property 'broken' " "does not have string type"; QTest::newRow("module not required") << false << QString(); } void TestLanguage::evalErrorInNonPresentModule() { QFETCH(bool, moduleRequired); QFETCH(QString, errorMessage); try { QVariantMap overridden{std::make_pair("products.p.moduleRequired", moduleRequired)}; defaultParameters.setOverriddenValues(overridden); resolveProject("eval-error-in-non-present-module.qbs"); QVERIFY(errorMessage.isEmpty()); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); const ResolvedProductPtr product = products.value("p"); QVERIFY(!!product); } catch (const ErrorInfo &e) { QVERIFY(!errorMessage.isEmpty()); QVERIFY2(e.toString().contains(errorMessage), qPrintable(e.toString())); } } void TestLanguage::defaultValue() { bool exceptionCaught = false; try { QFETCH(QString, prop1Value); QVariantMap overridden; if (!prop1Value.isEmpty()) overridden.insert("modules.lower.prop1", prop1Value); defaultParameters.setOverriddenValues(overridden); resolveProject("defaultvalue/egon.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 2); const ResolvedProductPtr product = products.value("egon"); QVERIFY(!!product); QStringList propertyName = QStringList() << "lower" << "prop2"; QVariant propertyValue = product->moduleProperties->property(propertyName); QFETCH(QVariant, expectedProp2Value); QCOMPARE(propertyValue, expectedProp2Value); propertyName = QStringList() << "lower" << "listProp"; propertyValue = product->moduleProperties->property(propertyName); QFETCH(QVariant, expectedListPropValue); QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList()); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::defaultValue_data() { QTest::addColumn("prop1Value"); QTest::addColumn("expectedProp2Value"); QTest::addColumn("expectedListPropValue"); QTest::newRow("controlling property with random value") << "random" << QVariant("withoutBlubb") << QVariant(QStringList({"other"})); QTest::newRow("controlling property with blubb value") << "blubb" << QVariant("withBlubb") << QVariant(QStringList({"blubb", "other"})); QTest::newRow("controlling property with egon value") << "egon" << QVariant("withEgon") << QVariant(QStringList({"egon", "other"})); QTest::newRow("controlling property not overwritten") << "" << QVariant("withBlubb") << QVariant(QStringList({"blubb", "other"})); } void TestLanguage::environmentVariable() { bool exceptionCaught = false; try { // Create new environment: const QString varName = QStringLiteral("PRODUCT_NAME"); const QString productName = QLatin1String("MyApp") + QString::number(m_rand.generate()); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(varName, productName); QProcessEnvironment origEnv = defaultParameters.environment(); // store orig environment defaultParameters.setEnvironment(env); resolveProject("environmentvariable.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value(productName); QVERIFY(!!product); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::errorInDisabledProduct() { bool exceptionCaught = false; try { resolveProject("error-in-disabled-product.qbs"); QVERIFY(!!project); auto products = productsFromProject(project); QCOMPARE(products.size(), 5); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::erroneousFiles_data() { QTest::addColumn("errorMessage"); QTest::newRow("unknown_module") << "Dependency 'neitherModuleNorProduct' not found"; QTest::newRow("multiple_exports") << "Multiple Export items in one product are prohibited."; QTest::newRow("multiple_properties_in_subproject") << "Multiple instances of item 'Properties' found where at most one " "is allowed."; QTest::newRow("importloop1") << "Loop detected when importing"; QTest::newRow("nonexistentouter") << "'outer' is not defined"; QTest::newRow("invalid_file") << "does not exist"; QTest::newRow("invalid-parameter-rhs") << "'access' is not defined"; QTest::newRow("invalid-parameter-type") << "Value assigned to property 'stringParameter' does not have type 'string'."; QTest::newRow("invalid_property_type") << "Unknown type 'nonsense' in property declaration."; QTest::newRow("reserved_name_in_import") << "Cannot reuse the name of built-in extension 'TextFile'."; QTest::newRow("throw_in_property_binding") << "something is wrong"; QTest::newRow("no-configure-in-probe") << "no-configure-in-probe.qbs:2:5.*Probe.configure must be set"; QTest::newRow("dependency_cycle") << "Cyclic dependencies detected."; QTest::newRow("dependency_cycle2") << "Cyclic dependencies detected."; QTest::newRow("dependency_cycle3") << "Cyclic dependencies detected."; QTest::newRow("dependency_cycle3a") << "Cyclic dependencies detected."; QTest::newRow("dependency_cycle4") << "Cyclic dependencies detected."; QTest::newRow("references_cycle") << "Cycle detected while referencing file '.*references_cycle.qbs'."; QTest::newRow("subproject_cycle") << "Cycle detected while loading subproject file 'subproject_cycle.qbs'."; QTest::newRow("invalid_stringlist_element") << "Element at index 1 of list property 'files' does not have string type."; QTest::newRow("undefined_stringlist_element") << "Element at index 1 of list property 'files' is undefined. String expected."; QTest::newRow("undefined_stringlist_element_in_probe") << "Element at index 1 of list property 'l' is undefined. String expected."; QTest::newRow("undeclared_item") << "Item 'cpp' is not declared."; QTest::newRow("undeclared-parameter1") << "Parameter 'prefix2.suffix.nope' is not declared."; QTest::newRow("undeclared-parameter2") << "Cannot set parameter 'foo.bar', " "because 'myproduct' does not have a dependency on 'foo'."; QTest::newRow("undeclared_property_wrapper") << "Property 'doesntexist' is not declared."; QTest::newRow("undeclared_property_in_export_item") << "Property 'blubb' is not declared."; QTest::newRow("undeclared_property_in_export_item2") << "Item 'something' is not declared."; QTest::newRow("undeclared_property_in_export_item3") << "Property 'blubb' is not declared."; QTest::newRow("undeclared_module_property_in_module") << "Property 'noSuchProperty' is not declared."; QTest::newRow("unknown_item_type") << "Unexpected item type 'Narf'"; QTest::newRow("invalid_child_item_type") << "Items of type 'Project' cannot contain items of type 'Depends'."; QTest::newRow("conflicting_fileTagsFilter") << "Conflicting fileTagsFilter in Group items"; QTest::newRow("duplicate_sources") << "Duplicate source file '.*main.cpp'" ".*duplicate_sources.qbs:2:12.*duplicate_sources.qbs:4:16."; QTest::newRow("duplicate_sources_wildcards") << "Duplicate source file '.*duplicate_sources_wildcards.qbs'" ".*duplicate_sources_wildcards.qbs:2:12" ".*duplicate_sources_wildcards.qbs:4:16."; QTest::newRow("oldQbsVersion") << "The project requires at least qbs version \\d+\\.\\d+.\\d+, " "but this is qbs version " QBS_VERSION "."; QTest::newRow("wrongQbsVersionFormat") << "The value '.*' of Project.minimumQbsVersion is not a valid version string."; QTest::newRow("properties-item-with-invalid-condition") << "properties-item-with-invalid-condition.qbs:4:19.*" "cannot read property 'includes' of undefined"; QTest::newRow("misused-inherited-property") << "Binding to non-item property"; QTest::newRow("undeclared_property_in_Properties_item") << "Item 'blubb' is not declared"; QTest::newRow("conflicting-properties-in-export-items") << "Export item in inherited item redeclares property 'theProp' with different type."; QTest::newRow("invalid-property-option") << "PropertyOptions item refers to non-existing property 's0meProp'"; QTest::newRow("missing-colon") << "Invalid item 'dummy.cxxFlags'. Did you mean to set a module property?"; QTest::newRow("syntax-error-in-probe") << "syntax-error-in-probe.qbs:4:20.*'fngkgsdjfgklkf' is not defined"; QTest::newRow("wrong-toplevel-item") << "wrong-toplevel-item.qbs:1:1.*The top-level item must be of type 'Project' or " "'Product', but it is of type 'Artifact'."; QTest::newRow("conflicting-module-instances") << "There is more than one equally prioritized candidate for module " "'conflicting-instances'."; QTest::newRow("overwrite-inherited-readonly-property") << "overwrite-inherited-readonly-property.qbs" ":2:21.*Cannot set read-only property 'readOnlyString'."; QTest::newRow("overwrite-readonly-module-property") << "overwrite-readonly-module-property.qbs" ":3:30.*Cannot set read-only property 'readOnlyString'."; QTest::newRow("original-in-product-property") << "original-in-product-property.qbs" ":2:21.*The special value 'original' can only be used with module properties."; QTest::newRow("rule-without-output-tags") << "rule-without-output-tags.qbs:2:5.*A rule needs to have Artifact items or " "a non-empty outputFileTags property."; QTest::newRow("original-in-module-prototype") << "module-with-invalid-original.qbs:2:24.*The special value 'original' cannot be used " "on the right-hand side of a property declaration."; QTest::newRow("original-in-export-item") << "original-in-export-item.qbs:5:32.*The special value 'original' cannot be used " "on the right-hand side of a property declaration."; QTest::newRow("original-in-export-item2") << "original-in-export-item2.qbs:4:9.*Item 'x.y' is not declared. Did you forget " "to add a Depends item"; QTest::newRow("original-in-export-item3") << "original-in-export-item3.qbs:6:9.*Item 'x.y' is not declared. Did you forget " "to add a Depends item"; QTest::newRow("mismatching-multiplex-dependency") << "mismatching-multiplex-dependency.qbs:9:9.*Dependency from product " "'b \\{\"architecture\":\"mips\"\\}' to product 'a'" " not fulfilled. There are no eligible multiplex candidates."; QTest::newRow("ambiguous-multiplex-dependency") << "ambiguous-multiplex-dependency.qbs:10:9.*Dependency from product 'b " "\\{\"architecture\":\"x86\"\\}' to product 'a' is ambiguous. Eligible multiplex " "candidates: a \\{\"architecture\":\"x86\",\"buildVariant\":\"debug\"\\}, " "a \\{\"architecture\":\"x86\",\"buildVariant\":\"release\"\\}."; QTest::newRow("dependency-profile-mismatch") << "dependency-profile-mismatch.qbs:10:5.*Product 'main' depends on 'dep', " "which does not exist for the requested profile 'profile47'."; QTest::newRow("dependency-profile-mismatch-2") << "dependency-profile-mismatch-2.qbs:15:9 Dependency from product 'main' to " "product 'dep' not fulfilled. There are no eligible multiplex candidates."; QTest::newRow("invalid-references") << "invalid-references.qbs:2:17.*Cannot open '.*nosuchproject.qbs'"; QTest::newRow("missing-js-file") << "missing-js-file-module.qbs.*Cannot open '.*javascriptfile.js'"; QTest::newRow("frozen-object") << "'key' is read-only"; QTest::newRow("frozen-object-list") << "object is not extensible"; QTest::newRow("module-property-binding-in-project") << "Module properties cannot be set in Project items"; QTest::newRow("module-with-id") << "Module items cannot have an id property"; QTest::newRow("module-var-in-product") << "module-var-in-product.qbs:4:19 Use of 'module' is only allowed in Module items"; } void TestLanguage::erroneousFiles() { QFETCH(QString, errorMessage); QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs"); try { resolveProject(qPrintable("/erroneous/" + fileName)); } catch (const ErrorInfo &e) { const QRegularExpression reg(errorMessage, QRegularExpression::DotMatchesEverythingOption); if (!e.toString().contains(reg)) { qDebug() << "Message: " << e.toString(); qDebug() << "Expected: " << errorMessage; QFAIL("Unexpected error message."); } return; } QEXPECT_FAIL("undeclared_property_in_Properties_item", "Too expensive to check", Continue); QEXPECT_FAIL("original-in-export-item3", "Too expensive to check", Continue); QVERIFY(!"No error thrown on invalid input."); } void TestLanguage::exports() { bool exceptionCaught = false; try { defaultParameters.setDeprecationWarningMode(DeprecationWarningMode::On); resolveProject("exports.qbs"); QVERIFY(!!project); Set warningLocations; for (const ErrorInfo &e : std::as_const(project->warningsEncountered)) { const QString errStr = e.toString(); QVERIFY2( errStr.contains("Resolving path properties relative to the exporting " "product's location is deprecated"), qPrintable(errStr)); for (const ErrorItem &ei : e.items()) warningLocations << ei.codeLocation(); } QCOMPARE(int(warningLocations.size()), 2); for (const CodeLocation &loc : warningLocations) QVERIFY(loc.line() == 12 || loc.line() == 9); QHash products = productsFromProject(project); QCOMPARE(products.size(), 22); ResolvedProductPtr product; product = products.value("myapp"); QVERIFY(!!product); QStringList propertyName = QStringList() << "dummy" << "defines"; QVariant propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYAPP" << "USE_MYLIB" << "USE_MYLIB2"); propertyName = QStringList() << "dummy" << "includePaths"; QVariantList propertyValues = product->moduleProperties->property(propertyName).toList(); QCOMPARE(propertyValues.size(), 3); QVERIFY(propertyValues.at(0).toString().endsWith("/app")); QVERIFY(propertyValues.at(1).toString().endsWith("/subdir/lib")); QVERIFY(propertyValues.at(2).toString().endsWith("/subdir2/lib")); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(), QString("myapp")); QVERIFY(product->moduleProperties->moduleProperty("dummy", "somePath").toString() .endsWith("/subdir")); product = products.value("mylib"); QVERIFY(!!product); propertyName = QStringList() << "dummy" << "defines"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB"); QVERIFY(product->moduleProperties->moduleProperty("dummy", "somePath").toString() .endsWith("/subdir")); product = products.value("mylib2"); QVERIFY(!!product); propertyName = QStringList() << "dummy" << "defines"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB2"); product = products.value("A"); QVERIFY(!!product); QVERIFY(contains(product->dependencies, products.value("B"))); QVERIFY(contains(product->dependencies, products.value("C"))); QVERIFY(contains(product->dependencies, products.value("D"))); product = products.value("B"); QVERIFY(!!product); QVERIFY(product->dependencies.empty()); QCOMPARE(product->exportedModule.productDependencies, std::vector{"C"}); product = products.value("C"); QVERIFY(!!product); QVERIFY(product->dependencies.empty()); product = products.value("D"); QVERIFY(!!product); QVERIFY(product->dependencies.empty()); product = products.value("myapp2"); QVERIFY(!!product); propertyName = QStringList() << "dummy" << "cFlags"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList() << "BASE_PRODUCTWITHINHERITEDEXPORTITEM" << "PRODUCT_PRODUCTWITHINHERITEDEXPORTITEM"); propertyName = QStringList() << "dummy" << "cxxFlags"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList() << "-bar"); propertyName = QStringList() << "dummy" << "defines"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList({"ABC", "DEF"})); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(), QString("myapp2")); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "upperCaseProductName").toString(), QString("MYAPP2")); // Check whether we're returning incorrect cached values. product = products.value("myapp3"); QVERIFY(!!product); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(), QString("myapp3")); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "upperCaseProductName").toString(), QString("MYAPP3")); // Verify we refer to the right "project" variable. product = products.value("sub p2"); QVERIFY(!!product); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "someString").toString(), QString("sub1")); product = products.value("libE"); QVERIFY(!!product); propertyName = QStringList() << "dummy" << "defines"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toStringList(), QStringList() << "LIBD" << "LIBC" << "LIBA" << "LIBB"); propertyName = QStringList() << "dummy" << "productName"; propertyValue = product->moduleProperties->property(propertyName); QCOMPARE(propertyValue.toString(), QString("libE")); product = products.value("depender"); QVERIFY(!!product); QCOMPARE(product->modules.size(), size_t(2)); for (const ResolvedModulePtr &m : product->modules) { QVERIFY2(m->name == QString("qbs") || m->name == QString("dependency"), qPrintable(m->name)); } QCOMPARE(product->productProperties.value("featureX").toBool(), true); QCOMPARE(product->productProperties.value("featureY").toBool(), false); QCOMPARE(product->productProperties.value("featureZ").toBool(), true); product = products.value("broken_cycle3"); QVERIFY(!!product); QCOMPARE(product->modules.size(), size_t(3)); for (const ResolvedModulePtr &m : product->modules) { QVERIFY2(m->name == QString("qbs") || m->name == QString("broken_cycle1") || m->name == QString("broken_cycle2"), qPrintable(m->name)); } } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::fileContextProperties() { bool exceptionCaught = false; try { resolveProject("filecontextproperties.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); QVERIFY(!!product); QVariantMap cfg = product->productProperties; QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath()); QString dirPath = QFileInfo(defaultParameters.projectFilePath()).absolutePath(); QCOMPARE(cfg.value("zort").toString(), dirPath); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::fileInProductAndModule_data() { QTest::addColumn("file1IsTarget"); QTest::addColumn("file2IsTarget"); QTest::addColumn("addFileToProduct"); QTest::addColumn("successExpected"); QTest::newRow("file occurs twice in module as non-target") << false << false << false << false; QTest::newRow("file occurs twice in module as non-target, and in product as well") << false << false << true << false; QTest::newRow("file occurs in module as non-target and target") << false << true << false << true; QTest::newRow("file occurs in module as non-target and target, and in product as well") << false << true << true << false; QTest::newRow("file occurs in module as target and non-target") << true << false << false << true; QTest::newRow("file occurs in module as target and non-target, and in product as well") << true << false << true << false; QTest::newRow("file occurs twice in module as target") << true << true << false << false; QTest::newRow("file occurs twice in module as target, and in product as well") << true << true << true << false; } void TestLanguage::fileInProductAndModule() { bool exceptionCaught = false; QFETCH(bool, file1IsTarget); QFETCH(bool, file2IsTarget); QFETCH(bool, addFileToProduct); QFETCH(bool, successExpected); try { defaultParameters.setOverriddenValues(QVariantMap{ std::make_pair("modules.module_with_file.file1IsTarget", file1IsTarget), std::make_pair("modules.module_with_file.file2IsTarget", file2IsTarget), std::make_pair("products.p.addFileToProduct", addFileToProduct), }); resolveProject("file-in-product-and-module.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); } catch (const ErrorInfo &e) { exceptionCaught = true; QVERIFY2(e.toString().contains("Duplicate"), qPrintable(e.toString())); } QCOMPARE(exceptionCaught, !successExpected); } void TestLanguage::getNativeSetting() { bool exceptionCaught = false; try { resolveProject("getNativeSetting.qbs"); QString expectedTargetName; if (HostOsInfo::isMacosHost()) { if (HostOsInfo::hostOsVersion() >= qbs::Version(11)) expectedTargetName = QStringLiteral("macOS"); else expectedTargetName = QStringLiteral("Mac OS X"); } else if (HostOsInfo::isWindowsHost()) { expectedTargetName = QStringLiteral("Windows"); } else { expectedTargetName = QStringLiteral("Unix"); } QVERIFY(!!project); QHash products; for (const ResolvedProductPtr &product : project->allProducts()) products.insert(product->targetName, product); ResolvedProductPtr product = products.value(expectedTargetName); QVERIFY(!!product); ResolvedProductPtr product2 = products.value(QStringLiteral("fallback")); QVERIFY(!!product2); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::groupConditions_data() { QTest::addColumn("groupCount"); QTest::addColumn>("groupEnabled"); QTest::newRow("init") << size_t(0) << std::vector(); QTest::newRow("no_condition_no_group") << size_t(1) << std::vector{ true }; QTest::newRow("no_condition") << size_t(2) << std::vector{ true, true }; QTest::newRow("true_condition") << size_t(2) << std::vector{ true, true }; QTest::newRow("false_condition") << size_t(2) << std::vector{ true, false }; QTest::newRow("true_condition_from_product") << size_t(2) << std::vector{ true, true }; QTest::newRow("true_condition_from_project") << size_t(2) << std::vector{ true, true }; QTest::newRow("condition_accessing_module_property") << size_t(2) << std::vector{ true, false }; QTest::newRow("cleanup") << size_t(0) << std::vector(); } void TestLanguage::groupConditions() { HANDLE_INIT_CLEANUP_DATATAGS("groupconditions.qbs"); QFETCH(size_t, groupCount); QFETCH(std::vector, groupEnabled); QCOMPARE(groupCount, groupEnabled.size()); const QHash products = productsFromProject(project); const QString productName = QString::fromLocal8Bit(QTest::currentDataTag()); ResolvedProductPtr product = products.value(productName); QVERIFY(!!product); QCOMPARE(product->name, productName); QCOMPARE(product->groups.size(), groupCount); for (size_t i = 0; i < groupCount; ++i) { if (product->groups.at(i)->enabled != groupEnabled.at(i)) { QFAIL(qPrintable( QString("groups.at(%1)->enabled != %2").arg(i).arg(groupEnabled.at(i)))); } } } void TestLanguage::groupName() { bool exceptionCaught = false; try { resolveProject("groupname.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 2); ResolvedProductPtr product = products.value("MyProduct"); QVERIFY(!!product); QCOMPARE(product->groups.size(), size_t(2)); GroupConstPtr group = product->groups.at(0); QVERIFY(!!group); QCOMPARE(group->name, QString("MyProduct")); group = product->groups.at(1); QVERIFY(!!group); QCOMPARE(group->name, QString("MyProduct.MyGroup")); product = products.value("My2ndProduct"); QVERIFY(!!product); QCOMPARE(product->groups.size(), size_t(3)); group = product->groups.at(0); QVERIFY(!!group); QCOMPARE(group->name, QString("My2ndProduct")); group = product->groups.at(1); QVERIFY(!!group); QCOMPARE(group->name, QString("My2ndProduct.MyGroup")); group = product->groups.at(2); QVERIFY(!!group); QCOMPARE(group->name, QString("Group 2")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::homeDirectory() { try { resolveProject("homeDirectory.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product = products.value("home"); QVERIFY(!!product); QDir dir = QDir::home(); QCOMPARE(product->productProperties.value("home").toString(), dir.path()); QCOMPARE(product->productProperties.value("homeSlash").toString(), dir.path()); dir.cdUp(); QCOMPARE(product->productProperties.value("homeUp").toString(), dir.path()); dir = QDir::home(); QCOMPARE(product->productProperties.value("homeFile").toString(), dir.filePath("a")); QCOMPARE(product->productProperties.value("bogus1").toString(), FileInfo::resolvePath(product->sourceDirectory, QStringLiteral("a~b"))); QCOMPARE(product->productProperties.value("bogus2").toString(), FileInfo::resolvePath(product->sourceDirectory, QStringLiteral("a/~/bb"))); QCOMPARE(product->productProperties.value("user").toString(), FileInfo::resolvePath(product->sourceDirectory, QStringLiteral("~foo/bar"))); } catch (const ErrorInfo &e) { qDebug() << e.toString(); } } void TestLanguage::identifierSearch_data() { QTest::addColumn("expectedHasNarf"); QTest::addColumn("expectedHasZort"); QTest::addColumn("sourceCode"); QTest::newRow("no narf, no zort") << false << false << QString( "Product {\n" " name: {\n" " var foo = 'bar';\n" " console.info(foo);\n" " return foo;\n" " }\n" "}\n"); QTest::newRow("narf, no zort") << true << false << QString( "Product {\n" " name: {\n" " var foo = 'zort';\n" " console.info(narf + foo);\n" " return foo;\n" " }\n" "}\n"); QTest::newRow("no narf, zort") << false << true << QString( "Product {\n" " name: {\n" " var foo = 'narf';\n" " console.info(zort + foo);\n" " return foo;\n" " }\n" "}\n"); QTest::newRow("narf, zort") << true << true << QString( "Product {\n" " name: {\n" " var foo = narf;\n" " foo = foo + zort;\n" " return foo;\n" " }\n" "}\n"); QTest::newRow("2 narfs, 1 zort") << true << true << QString( "Product {\n" " name: {\n" " var foo = narf;\n" " foo = narf + foo + zort;\n" " return foo;\n" " }\n" "}\n"); } void TestLanguage::identifierSearch() { QFETCH(bool, expectedHasNarf); QFETCH(bool, expectedHasZort); QFETCH(QString, sourceCode); bool hasNarf = !expectedHasNarf; bool hasZort = !expectedHasZort; IdentifierSearch isearch; isearch.add("narf", &hasNarf); isearch.add("zort", &hasZort); QbsQmlJS::Engine engine; QbsQmlJS::Lexer lexer(&engine); lexer.setCode(sourceCode, 1); QbsQmlJS::Parser parser(&engine); QVERIFY(parser.parse()); QVERIFY(parser.ast()); isearch.start(parser.ast()); QCOMPARE(hasNarf, expectedHasNarf); QCOMPARE(hasZort, expectedHasZort); } void TestLanguage::idUsage() { bool exceptionCaught = false; try { resolveProject("idusage.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 5); QVERIFY(products.contains("product1_1")); QVERIFY(products.contains("product2_2")); QVERIFY(products.contains("product3_3")); ResolvedProductPtr product4 = products.value("product4_4"); QVERIFY(!!product4); auto product4Property = [&product4] (const char *name) { return product4->productProperties.value(QString::fromUtf8(name)).toString(); }; QCOMPARE(product4Property("productName"), product4->name); QCOMPARE(product4Property("productNameInBaseOfBase"), product4->name); GroupPtr group = findByName(product4->groups, "group in base product"); QVERIFY(!!group); QCOMPARE(qPrintable(group->prefix), "group in base product"); group = findByName(product4->groups, "another group in base product"); QVERIFY(!!group); QCOMPARE(qPrintable(group->prefix), "another group in base product"); ResolvedProductPtr product5 = products.value("product5"); QVERIFY(!!product5); QCOMPARE(product5->moduleProperties->moduleProperty("deepdummy.deep.moat", "zort") .toString(), QString("zort in dummy")); QCOMPARE(int(product5->allEnabledFiles().size()), 1); QVERIFY(product5->allEnabledFiles().at(0)->absoluteFilePath.endsWith("dummy.txt")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::idUniqueness() { bool exceptionCaught = false; try { resolveProject("id-uniqueness.qbs"); } catch (const ErrorInfo &e) { exceptionCaught = true; const QList items = e.items(); QCOMPARE(items.size(), 3); QCOMPARE(items.at(0).toString(), QString::fromUtf8("The id 'baseProduct' is not unique.")); QVERIFY(items.at(1).toString().contains("id-uniqueness.qbs:5:5 First occurrence is here.")); QVERIFY(items.at(2).toString().contains("id-uniqueness.qbs:8:5 Next occurrence is here.")); } QVERIFY(exceptionCaught); } void TestLanguage::importCollection() { bool exceptionCaught = false; try { resolveProject("import-collection/project.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); const ResolvedProductConstPtr product = products.value("da product"); QCOMPARE(product->productProperties.value("targetName").toString(), QLatin1String("C1f1C1f2C2f1C2f2")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::inheritedPropertiesItems_data() { QTest::addColumn("buildVariant"); QTest::addColumn("productName"); QTest::newRow("debug build") << "debug" << "product_debug"; QTest::newRow("release build") << "release" << "product_release"; } void TestLanguage::inheritedPropertiesItems() { bool exceptionCaught = false; try { QFETCH(QString, buildVariant); QFETCH(QString, productName); defaultParameters.setOverriddenValues(QVariantMap{std::make_pair("qbs.buildVariant", buildVariant)}); resolveProject("inherited-properties-items/inherited-properties-items.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); QVERIFY(!!products.value(productName)); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::invalidBindingInDisabledItem() { bool exceptionCaught = false; try { resolveProject("invalidBindingInDisabledItem.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 2); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::invalidOverrides() { QFETCH(QString, key); QFETCH(QString, expectedErrorMessage); const bool successExpected = expectedErrorMessage.isEmpty(); bool exceptionCaught = false; try { defaultParameters.setOverriddenValues(QVariantMap{std::make_pair(key, true)}); resolveProject("invalid-overrides.qbs"); QVERIFY(!!project); } catch (const ErrorInfo &e) { exceptionCaught = true; if (successExpected) qDebug() << e.toString(); else QVERIFY2(e.toString().contains(expectedErrorMessage), qPrintable(e.toString())); } QEXPECT_FAIL("no such module in product", "not easily checkable", Continue); QCOMPARE(!exceptionCaught, successExpected); } void TestLanguage::invalidOverrides_data() { QTest::addColumn("key"); QTest::addColumn("expectedErrorMessage"); QTest::newRow("no such project") << "projects.myproject.x" << QString("Unknown project 'myproject' in property override."); QTest::newRow("no such project property") << "projects.My.Project.y" << QString("Unknown property: projects.My.Project.y"); QTest::newRow("valid project property override") << "projects.My.Project.x" << QString(); QTest::newRow("no such product") << "products.myproduct.x" << QString("Unknown product 'myproduct' in property override."); QTest::newRow("no such product (with module)") << "products.myproduct.cpp.useRPaths" << QString("Unknown product 'myproduct' in property override."); QTest::newRow("no such product property") << "products.MyProduct.y" << QString("Unknown property: products.MyProduct.y"); QTest::newRow("valid product property override") << "products.MyProduct.x" << QString(); // This cannot be an error, because the semantics are "if some product in the project has // such a module, then set that property", and the code that does the property overrides // does not have a global view. QTest::newRow("no such module") << "modules.blubb.x" << QString(); QTest::newRow("no such module in product") << "products.MyProduct.cpp.useRPaths" << QString("Invalid module 'cpp' in property override."); QTest::newRow("no such module property") << "modules.cpp.blubb" << QString("Unknown property: modules.cpp.blubb"); QTest::newRow("no such module property (per product)") << "products.MyOtherProduct.cpp.blubb" << QString("Unknown property: products.MyOtherProduct.cpp.blubb"); QTest::newRow("valid per-product module property override") << "products.MyOtherProduct.cpp.useRPaths" << QString(); } void TestLanguage::invalidPropOnNonRequiredModule_data() { QTest::addColumn("useExistingModule"); QTest::addColumn("errorExpected"); QTest::newRow("existing module") << true << true; QTest::newRow("non-existing module") << false << false; } void TestLanguage::invalidPropOnNonRequiredModule() { QFETCH(bool, useExistingModule); QFETCH(bool, errorExpected); try { defaultParameters.setOverriddenValues( {std::make_pair("project.useExistingModule", useExistingModule)}); resolveProject("invalid-prop-on-non-required-module"); QVERIFY(!errorExpected); } catch (const ErrorInfo &e) { const QString errorString = e.toString(); QVERIFY2(errorExpected, qPrintable(errorString)); QVERIFY2(errorString.contains("Property 'nosuchprop' is not declared"), qPrintable(errorString)); } } void TestLanguage::itemPrototype() { FileContextPtr fileContext = FileContext::create(); fileContext->setFilePath("/dev/null"); JSSourceValueCreator sourceValueCreator(fileContext); ItemPool pool; Item *proto = Item::create(&pool, ItemType::Product); proto->setProperty("x", sourceValueCreator.create("1")); proto->setProperty("y", sourceValueCreator.create("1")); Item *item = Item::create(&pool, ItemType::Product); item->setPrototype(proto); item->setProperty("y", sourceValueCreator.create("x + 1")); item->setProperty("z", sourceValueCreator.create("2")); Evaluator evaluator(m_engine.get()); JSContext * const ctx = m_engine->context(); QCOMPARE(getJsVariant(ctx, evaluator.property(proto, "x")).toInt(), 1); QCOMPARE(getJsVariant(ctx, evaluator.property(proto, "y")).toInt(), 1); QVERIFY(JS_IsUndefined(evaluator.property(proto, "z"))); QCOMPARE(getJsVariant(ctx, evaluator.property(item, "x")).toInt(), 1); QCOMPARE(getJsVariant(ctx, evaluator.property(item, "y")).toInt(), 2); QCOMPARE(getJsVariant(ctx, evaluator.property(item, "z")).toInt(), 2); } void TestLanguage::itemScope() { FileContextPtr fileContext = FileContext::create(); fileContext->setFilePath("/dev/null"); JSSourceValueCreator sourceValueCreator(fileContext); ItemPool pool; Item *scope1 = Item::create(&pool, ItemType::Scope); scope1->setProperty("x", sourceValueCreator.create("1")); Item *scope2 = Item::create(&pool, ItemType::Scope); scope2->setScope(scope1); scope2->setProperty("y", sourceValueCreator.create("x + 1")); Item *item = Item::create(&pool, ItemType::Scope); item->setScope(scope2); item->setProperty("z", sourceValueCreator.create("x + y")); Evaluator evaluator(m_engine.get()); JSContext * const ctx = m_engine->context(); QCOMPARE(getJsVariant(ctx, evaluator.property(scope1, "x")).toInt(), 1); QCOMPARE(getJsVariant(ctx, evaluator.property(scope2, "y")).toInt(), 2); QVERIFY(JS_IsUndefined(evaluator.property(scope2, "x"))); QCOMPARE(getJsVariant(ctx, evaluator.property(item, "z")).toInt(), 3); } void TestLanguage::jsExtensions() { QFile file(testProject("jsextensions.js")); QVERIFY(file.open(QFile::ReadOnly)); QTextStream ts(&file); QString code = ts.readAll(); QVERIFY(!code.isEmpty()); m_engine->evaluate(JsValueOwner::Caller, code, file.fileName(), 1); if (JsException ex = m_engine->checkAndClearException({})) { qDebug() << ex.stackTrace(); QFAIL(qPrintable(ex.message())); } } void TestLanguage::jsImportUsedInMultipleScopes_data() { QTest::addColumn("buildVariant"); QTest::addColumn("expectedProductName"); QTest::newRow("debug") << QString("debug") << QString("MyProduct_debug"); QTest::newRow("release") << QString("release") << QString("MyProduct"); } void TestLanguage::jsImportUsedInMultipleScopes() { QFETCH(QString, buildVariant); QFETCH(QString, expectedProductName); bool exceptionCaught = false; try { defaultParameters.setOverriddenValues({std::make_pair(QStringLiteral("qbs.buildVariant"), buildVariant)}); resolveProject("jsimportsinmultiplescopes.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product = products.values().front(); QVERIFY(!!product); QCOMPARE(product->name, expectedProductName); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::keepLoadingDependencies() { QString error; try { resolveProject("keep-loading-dependencies.qbs"); QFAIL("Should not get here!"); } catch (const ErrorInfo &e) { error = e.toString(); } QVERIFY2(error.contains("Dependency 'none.m1' not found"), qPrintable(error)); QVERIFY2(error.contains("Dependency 'none.m2' not found"), qPrintable(error)); QVERIFY2(error.contains("Dependency 'none.m3' not found"), qPrintable(error)); QVERIFY2(!error.contains("QBS_CHECK"), qPrintable(error)); } void TestLanguage::localProfileAsTopLevelProfile() { bool exceptionCaught = false; try { defaultParameters.setTopLevelProfile("test-profile"); resolveProject("local-profile-as-top-level-profile.qbs"); QVERIFY(!!project); QCOMPARE(int(project->products.size()), 1); const PropertyMapConstPtr &props = project->products.front()->moduleProperties; QCOMPARE(props->qbsPropertyValue("architecture"), "arm"); QCOMPARE(props->qbsPropertyValue("targetPlatform"), "macos"); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::moduleMergingVariantValues() { bool exceptionCaught = false; try { resolveProject("module-merging-variant-values/module-merging-variant-values.qbs"); QVERIFY(!!project); QCOMPARE(int(project->products.size()), 2); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::moduleNameCollisions_data() { QTest::addColumn("projectFile"); QTest::addColumn("collisionExpected"); QTest::newRow("simple collision (one order)") << "simple-collision1.qbs" << true; QTest::newRow("simple collision (other order)") << "simple-collision2.qbs" << true; QTest::newRow("collision with more components") << "complex-collision.qbs" << true; QTest::newRow("no collision (same length)") << "no-collision1.qbs" << false; QTest::newRow("no collision (different length)") << "no-collision2.qbs" << false; } void TestLanguage::moduleNameCollisions() { QFETCH(QString, projectFile); QFETCH(bool, collisionExpected); try { const QString compositeProjectFilePath = QString("module-name-collisions/") + projectFile; QVERIFY(resolveProject(qPrintable(compositeProjectFilePath))); QVERIFY(!collisionExpected); } catch (const ErrorInfo &e) { const QString errorString = e.toString(); QVERIFY2(collisionExpected, qPrintable(errorString)); QVERIFY2(errorString.contains("not allowed"), qPrintable(errorString)); } } void TestLanguage::moduleParameters_data() { QTest::addColumn("inputProperties"); QTest::addColumn("expectedModuleParameters"); QTest::addColumn("errorExpected"); QTest::newRow("no overrides") << QVariantMap{ std::make_pair("project.overrideFromModule", "false"), std::make_pair("project.overrideFromExport", "false"), std::make_pair("project.overrideFromProduct", "false")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromParameters")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromParameters")})})} << false; QTest::newRow("override from product") << QVariantMap{ std::make_pair("project.overrideFromModule", "false"), std::make_pair("project.overrideFromExport", "false"), std::make_pair("project.overrideFromProduct", "true")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})})} << false; QTest::newRow("override from export") << QVariantMap{ std::make_pair("project.overrideFromModule", "false"), std::make_pair("project.overrideFromExport", "true"), std::make_pair("project.overrideFromProduct", "false")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromExportDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromParameters")})})} << false; QTest::newRow("override from export and product") << QVariantMap{ std::make_pair("project.overrideFromModule", "false"), std::make_pair("project.overrideFromExport", "true"), std::make_pair("project.overrideFromProduct", "true")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})})} << false; QTest::newRow("override from module") << QVariantMap{ std::make_pair("project.overrideFromModule", "true"), std::make_pair("project.overrideFromExport", "false"), std::make_pair("project.overrideFromProduct", "false")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromModuleDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromParameters")})})} << false; QTest::newRow("override from module and product") << QVariantMap{ std::make_pair("project.overrideFromModule", "true"), std::make_pair("project.overrideFromExport", "false"), std::make_pair("project.overrideFromProduct", "true")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})})} << false; QTest::newRow("override from module and export") << QVariantMap{ std::make_pair("project.overrideFromModule", "true"), std::make_pair("project.overrideFromExport", "true"), std::make_pair("project.overrideFromProduct", "false")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromExportDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromParameters")})})} << true; QTest::newRow("override from module, export and product") << QVariantMap{ std::make_pair("project.overrideFromModule", "true"), std::make_pair("project.overrideFromExport", "true"), std::make_pair("project.overrideFromProduct", "true")} << QVariantMap{ std::make_pair("higher", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})}), std::make_pair("dep", QVariantMap{std::make_pair("lower", QVariantMap{std::make_pair("param", "fromProductDepends")})})} << false; } void TestLanguage::moduleParameters() { QFETCH(QVariantMap, inputProperties); QFETCH(QVariantMap, expectedModuleParameters); QFETCH(bool, errorExpected); try { defaultParameters.setOverriddenValues(inputProperties); resolveProject("module-parameters/module-parameters.qbs"); QVERIFY(!errorExpected); QVERIFY(project); QCOMPARE(int(project->products.size()), 2); const ResolvedProductPtr mainProduct = productsFromProject(project).value("main"); QVERIFY(mainProduct); QCOMPARE(int(mainProduct->moduleParameters.size()), 2); for (auto it = expectedModuleParameters.cbegin(); it != expectedModuleParameters.cend(); ++it) { const auto findInProduct = [&](const QString &moduleName) { for (auto it = mainProduct->moduleParameters.cbegin(); it != mainProduct->moduleParameters.cend(); ++it) { if (it.key()->name == moduleName) return it.value(); } return QVariantMap(); }; const QVariantMap actual = findInProduct(it.key()); const QVariantMap expected = it.value().toMap(); const bool same = qVariantMapsEqual(actual, expected); if (!same) { qDebug().noquote() << "---" << expected; qDebug().noquote() << "+++" << actual; } QVERIFY(same); } } catch (const ErrorInfo &e) { QVERIFY2(errorExpected, qPrintable(e.toString())); } } void TestLanguage::modulePrioritizationBySearchPath_data() { QTest::addColumn("searchPaths"); QTest::addColumn("expectedVariant"); QTest::newRow("foo has priority") << QStringList{"./foo", "./bar"} << "foo"; QTest::newRow("bar has priority") << QStringList{"./bar", "./foo"} << "bar"; } void TestLanguage::modulePrioritizationBySearchPath() { QFETCH(QStringList, searchPaths); QFETCH(QString, expectedVariant); bool exceptionCaught = false; try { defaultParameters.setOverriddenValues( {std::make_pair(QStringLiteral("project.qbsSearchPaths"), searchPaths)}); resolveProject("module-prioritization-by-search-path/project.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product = products.values().front(); QVERIFY(!!product); const QString actualVariant = product->moduleProperties->moduleProperty ("conflicting-instances", "moduleVariant").toString(); QCOMPARE(actualVariant, expectedVariant); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QVERIFY(!exceptionCaught); } void TestLanguage::moduleProperties_data() { QTest::addColumn("propertyName"); QTest::addColumn("expectedValue"); QTest::newRow("init") << QString() << QVariant(); QTest::newRow("merge_lists") << "defines" << QVariant(QStringList() << "THE_PRODUCT" << "QT_NETWORK" << "QT_GUI" << "QT_CORE"); QTest::newRow("merge_lists_and_values") << "defines" << QVariant(QStringList() << "THE_PRODUCT" << "QT_NETWORK" << "QT_GUI" << "QT_CORE"); QTest::newRow("merge_lists_with_duplicates") << "cxxFlags" << QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ"); QTest::newRow("merge_lists_with_prototype_values") << "rpaths" << QVariant(QStringList() << "/opt/qt/lib" << "$ORIGIN"); QTest::newRow("list_property_that_references_product") << "listProp" << QVariant(QStringList() << "x" << "123"); QTest::newRow("list_property_depending_on_overridden_property") << "listProp2" << QVariant(QStringList() << "PRODUCT_STUFF" << "DEFAULT_STUFF" << "EXTRA_STUFF"); QTest::newRow("overridden_list_property") << "listProp" << QVariant(QStringList() << "PRODUCT_STUFF"); QTest::newRow("shadowed-list-property") << "defines" << QVariant(QStringList() << "MyProject" << "shadowed-list-property"); QTest::newRow("shadowed-scalar-property") << "someString" << QVariant(QString("MyProject_shadowed-scalar-property")); QTest::newRow("merged-varlist") << "varListProp" << QVariant(QVariantList() << QVariantMap({std::make_pair("d", "product")}) << QVariantMap({std::make_pair("c", "qtcore")}) << QVariantMap({std::make_pair("a", true), std::make_pair("b", QVariant())})); QTest::newRow("cleanup") << QString() << QVariant(); } void TestLanguage::moduleProperties() { HANDLE_INIT_CLEANUP_DATATAGS("moduleproperties.qbs"); QFETCH(QString, propertyName); QFETCH(QVariant, expectedValue); QHash products = productsFromProject(project); const QString productName = QString::fromLocal8Bit(QTest::currentDataTag()); ResolvedProductPtr product = products.value(productName); QVERIFY(!!product); const QVariant value = product->moduleProperties->moduleProperty("dummy", propertyName); QCOMPARE(value, expectedValue); } void TestLanguage::modulePropertiesInGroups() { defaultParameters.setProjectFilePath(testProject("modulepropertiesingroups.qbs")); bool exceptionCaught = false; try { resolveProject(); QVERIFY(!!project); const QHash products = productsFromProject(project); ResolvedProductPtr product = products.value("grouptest"); QVERIFY(!!product); GroupConstPtr g1; GroupConstPtr g11; GroupConstPtr g12; GroupConstPtr g2; GroupConstPtr g21; GroupConstPtr g211; for (const GroupPtr &g : product->groups) { if (g->name == "g1") g1= g; else if (g->name == "g2") g2 = g; else if (g->name == "g1.1") g11 = g; else if (g->name == "g1.2") g12 = g; else if (g->name == "g2.1") g21 = g; else if (g->name == "g2.1.1") g211 = g; } QVERIFY(!!g1); QVERIFY(!!g2); QVERIFY(!!g11); QVERIFY(!!g12); QVERIFY(!!g21); QVERIFY(!!g211); const QVariantMap productProps = product->moduleProperties->value(); const auto &productGmod1List1 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(productGmod1List1, QStringList() << "gmod1_list1_proto" << "gmod1_string_proto"); const auto &productGmod1List2 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list2") .toStringList(); QCOMPARE(productGmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" << "gmod1_list2_proto"); const auto &productGmod1List3 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list3") .toStringList(); QCOMPARE(productGmod1List3, QStringList() << "product" << "gmod1_string_proto"); const int productP0 = moduleProperty(productProps, "gmod.gmod1", "p0").toInt(); QCOMPARE(productP0, 1); const int productDepProp = moduleProperty(productProps, "gmod.gmod1", "depProp").toInt(); QCOMPARE(productDepProp, 0); const auto &productGmod2String = moduleProperty(productProps, "gmod2", "gmod2_string") .toString(); QCOMPARE(productGmod2String, QString("gmod1_string_proto")); const auto &productGmod2List = moduleProperty(productProps, "gmod2", "gmod2_list") .toStringList(); QCOMPARE(productGmod2List, QStringList() << "gmod1_string_proto" << "commonName_in_gmod1" << "gmod4_string_proto_gmod3_string_proto" << "gmod3_string_proto" << "gmod2_list_proto"); const QVariantMap g1Props = g1->properties->value(); const auto &g1Gmod1List1 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(g1Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1"); const auto &g1Gmod1List2 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list2") .toStringList(); QCOMPARE(g1Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" << "gmod1_list2_proto" << "g1"); const auto &g1Gmod1List3 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list3") .toStringList(); QCOMPARE(g1Gmod1List3, QStringList() << "product" << "g1"); const int g1P0 = moduleProperty(g1Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g1P0, 3); const int g1DepProp = moduleProperty(g1Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g1DepProp, 1); const auto &g1Gmod2String = moduleProperty(g1Props, "gmod2", "gmod2_string").toString(); QCOMPARE(g1Gmod2String, QString("g1")); const auto &g1Gmod2List = moduleProperty(g1Props, "gmod2", "gmod2_list") .toStringList(); QCOMPARE(g1Gmod2List, QStringList() << "g1" << "commonName_in_gmod1" << "g1_gmod4_g1_gmod3" << "g1_gmod3" << "gmod2_list_proto"); const QVariantMap g11Props = g11->properties->value(); const auto &g11Gmod1List1 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(g11Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.1"); const auto &g11Gmod1List2 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list2") .toStringList(); QCOMPARE(g11Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" << "gmod1_list2_proto" << "g1" << "g1.1"); const auto &g11Gmod1List3 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list3") .toStringList(); QCOMPARE(g11Gmod1List3, QStringList() << "product" << "g1.1"); const int g11P0 = moduleProperty(g11Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g11P0, 5); const int g11DepProp = moduleProperty(g11Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g11DepProp, 2); const auto &g11Gmod2String = moduleProperty(g11Props, "gmod2", "gmod2_string").toString(); QCOMPARE(g11Gmod2String, QString("g1.1")); const auto &g11Gmod2List = moduleProperty(g11Props, "gmod2", "gmod2_list") .toStringList(); QCOMPARE(g11Gmod2List, QStringList() << "g1.1" << "commonName_in_gmod1" << "g1.1_gmod4_g1.1_gmod3" << "g1.1_gmod3" << "gmod2_list_proto"); const QVariantMap g12Props = g12->properties->value(); const auto &g12Gmod1List1 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(g12Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.2"); const auto &g12Gmod1List2 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list2") .toStringList(); QCOMPARE(g12Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" << "gmod1_list2_proto" << "g1" << "g1.2"); const auto &g12Gmod1List3 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list3") .toStringList(); QCOMPARE(g12Gmod1List3, QStringList() << "product" << "g1.2"); const int g12P0 = moduleProperty(g12Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g12P0, 9); const int g12DepProp = moduleProperty(g12Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g12DepProp, 1); const auto &g12Gmod2String = moduleProperty(g12Props, "gmod2", "gmod2_string").toString(); QCOMPARE(g12Gmod2String, QString("g1.2")); const auto &g12Gmod2List = moduleProperty(g12Props, "gmod2", "gmod2_list") .toStringList(); QCOMPARE(g12Gmod2List, QStringList() << "g1.2" << "commonName_in_gmod1" << "g1_gmod4_g1.2_gmod3" << "g1.2_gmod3" << "gmod2_list_proto"); const QVariantMap g2Props = g2->properties->value(); const auto &g2Gmod1List1 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2"); const auto &g2Gmod1List2 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list2") .toStringList(); QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" << "gmod1_list2_proto"); const int g2P0 = moduleProperty(g2Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g2P0, 6); const int g2DepProp = moduleProperty(g2Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g2DepProp, 2); const auto &g2Gmod2String = moduleProperty(g2Props, "gmod2", "gmod2_string").toString(); QCOMPARE(g2Gmod2String, QString("g2")); const auto &g2Gmod2List = moduleProperty(g2Props, "gmod2", "gmod2_list") .toStringList(); QCOMPARE(g2Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2_gmod4_g2_gmod3" << "g2_gmod3" << "gmod2_list_proto"); const QVariantMap g21Props = g21->properties->value(); const auto &g21Gmod1List1 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(g21Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2"); const auto &g21Gmod1List2 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list2") .toStringList(); QEXPECT_FAIL(nullptr, "no re-eval when no module props set", Continue); QCOMPARE(g21Gmod1List2, QStringList() << "grouptest" << "g2.1" << "gmod1_list2_proto"); const int g21P0 = moduleProperty(g21Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g21P0, 6); const int g21DepProp = moduleProperty(g21Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g21DepProp, 2); const auto &g21Gmod2String = moduleProperty(g21Props, "gmod2", "gmod2_string").toString(); QCOMPARE(g21Gmod2String, QString("g2")); const auto &g21Gmod2List = moduleProperty(g21Props, "gmod2", "gmod2_list") .toStringList(); QEXPECT_FAIL(nullptr, "no re-eval when no module props set", Continue); QCOMPARE(g21Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2.1_gmod4_g2.1_gmod3" << "g2.1_gmod3" << "gmod2_list_proto"); const QVariantMap g211Props = g211->properties->value(); const auto &g211Gmod1List1 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list1") .toStringList(); QCOMPARE(g211Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2"); const auto &g211Gmod1List2 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list2") .toStringList(); QCOMPARE(g211Gmod1List2, QStringList() << "g2.1.1"); const int g211P0 = moduleProperty(g211Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g211P0, 17); const int g211DepProp = moduleProperty(g211Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g211DepProp, 2); const auto &g211Gmod2String = moduleProperty(g211Props, "gmod2", "gmod2_string").toString(); QEXPECT_FAIL(nullptr, "re-eval not triggered", Continue); QCOMPARE(g211Gmod2String, QString("g2.1.1")); const auto &g211Gmod2List = moduleProperty(g211Props, "gmod2", "gmod2_list") .toStringList(); QEXPECT_FAIL(nullptr, "re-eval not triggered", Continue); QCOMPARE(g211Gmod2List, QStringList() << "g2.1.1" << "commonName_in_gmod1" << "g2.1.1_gmod4_g2.1.1_gmod3" << "g2.1.1_gmod3" << "gmod2_list_proto"); product = products.value("grouptest2"); QVERIFY(!!product); g1.reset(); g11.reset(); for (const GroupPtr &g : product->groups) { if (g->name == "g1") g1= g; else if (g->name == "g1.1") g11 = g; } QVERIFY(!!g1); QVERIFY(!!g11); QCOMPARE(moduleProperty(g1->properties->value(), "gmod.gmod1", "gmod1_list2") .toStringList(), QStringList({"G1"})); QCOMPARE(moduleProperty(g11->properties->value(), "gmod.gmod1", "gmod1_list2") .toStringList(), moduleProperty(g1->properties->value(), "gmod.gmod1", "gmod1_list2") .toStringList()); QCOMPARE(moduleProperty(g11->properties->value(), "gmod.gmod1", "gmod1_string").toString(), QString("G1.1")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::modulePropertyOverridesPerProduct() { bool exceptionCaught = false; try { defaultParameters.setOverriddenValues({ std::make_pair("modules.dummy.rpaths", QStringList({"/usr/lib"})), std::make_pair("modules.dummy.someString", "m"), std::make_pair("products.b.dummy.someString", "b"), std::make_pair("products.c.dummy.someString", "c"), std::make_pair("products.c.dummy.rpaths", QStringList({"/home", "/tmp"})) }); resolveProject("module-property-overrides-per-product.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 3); const ResolvedProductConstPtr a = products.value("a"); QVERIFY(!!a); const ResolvedProductConstPtr b = products.value("b"); QVERIFY(!!b); const ResolvedProductConstPtr c = products.value("c"); QVERIFY(!!c); const auto stringPropertyValue = [](const ResolvedProductConstPtr &p) -> QString { return p->moduleProperties->moduleProperty("dummy", "someString").toString(); }; const auto listPropertyValue = [](const ResolvedProductConstPtr &p) -> QStringList { return p->moduleProperties->moduleProperty("dummy", "rpaths").toStringList(); }; const auto productPropertyValue = [](const ResolvedProductConstPtr &p) -> QStringList { return p->productProperties.value("rpaths").toStringList(); }; QCOMPARE(stringPropertyValue(a), QString("m")); QCOMPARE(stringPropertyValue(b), QString("b")); QCOMPARE(stringPropertyValue(c), QString("c")); QCOMPARE(listPropertyValue(a), QStringList({"/usr/lib"})); QCOMPARE(listPropertyValue(b), QStringList({"/usr/lib"})); QCOMPARE(listPropertyValue(c), QStringList({"/home", "/tmp"})); QCOMPARE(listPropertyValue(a), productPropertyValue(a)); QCOMPARE(listPropertyValue(b), productPropertyValue(b)); QCOMPARE(listPropertyValue(c), productPropertyValue(c)); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::moduleScope() { bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("modulescope.qbs")); resolveProject(); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product = products.value("product1"); QVERIFY(!!product); auto intModuleValue = [product] (const QString &name) -> int { return product->moduleProperties->moduleProperty("scopemod", name).toInt(); }; QCOMPARE(intModuleValue("a"), 2); // overridden in module instance QCOMPARE(intModuleValue("b"), 1); // genuine QCOMPARE(intModuleValue("c"), 3); // genuine, dependent on overridden value QCOMPARE(intModuleValue("d"), 2); // genuine, dependent on genuine value QCOMPARE(intModuleValue("e"), 1); // genuine QCOMPARE(intModuleValue("f"), 2); // overridden QCOMPARE(intModuleValue("g"), 156); // overridden, dependent on product properties QCOMPARE(intModuleValue("h"), 158); // overridden, base dependent on product properties } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::moduleWithProductDependency() { bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("module-depends-on-product.qbs")); resolveProject(); QVERIFY(project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 2); ResolvedProductPtr product = products.value("p1"); QVERIFY(product); QCOMPARE(int(product->dependencies.size()), 1); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::modules_data() { QTest::addColumn("expectedModulesInProduct"); QTest::addColumn("expectedProductProperty"); QTest::newRow("init") << QStringList(); QTest::newRow("no_modules") << (QStringList() << "qbs") << QString(); QTest::newRow("qt_core") << (QStringList() << "qbs" << "dummy" << "dummyqt.core") << QString("1.2.3"); QTest::newRow("qt_gui") << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui") << QString("guiProperty"); QTest::newRow("qt_gui_network") << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui" << "dummyqt.network") << QString("guiProperty,networkProperty"); QTest::newRow("deep_module_name") << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy") << QString("abysmal"); QTest::newRow("deep_module_name_submodule_syntax1") << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy") << QString("abysmal"); QTest::newRow("deep_module_name_submodule_syntax2") << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy") << QString("abysmal"); QTest::newRow("dummy_twice") << (QStringList() << "qbs" << "dummy") << QString(); QTest::newRow("cleanup") << QStringList(); } void TestLanguage::modules() { HANDLE_INIT_CLEANUP_DATATAGS("modules.qbs"); QFETCH(QStringList, expectedModulesInProduct); QFETCH(QString, expectedProductProperty); QHash products = productsFromProject(project); const QString productName = QString::fromLocal8Bit(QTest::currentDataTag()); const ResolvedProductPtr product = products.value(productName); QVERIFY(!!product); QCOMPARE(product->name, productName); QStringList modulesInProduct; for (ResolvedModuleConstPtr m : product->modules) modulesInProduct += m->name; modulesInProduct.sort(); expectedModulesInProduct.sort(); QCOMPARE(modulesInProduct, expectedModulesInProduct); QCOMPARE(product->productProperties.value("foo").toString(), expectedProductProperty); } void TestLanguage::multiplexedExports() { bool exceptionCaught = false; try { resolveProject("multiplexed-exports.qbs"); QVERIFY(!!project); const auto products = project->allProducts(); QCOMPARE(products.size(), size_t(4)); std::set pVariants; for (const auto &product : products) { if (product->name != "p") continue; static const auto buildVariant = [](const ResolvedProductConstPtr &p) { return p->moduleProperties->qbsPropertyValue("buildVariant").toString(); }; static const auto cppIncludePaths = [](const ResolvedProductConstPtr &p) { return p->moduleProperties->moduleProperty("cpp", "includePaths").toStringList(); }; if (buildVariant(product) == "debug") { pVariants.insert(product); QCOMPARE(cppIncludePaths(product), QStringList("/d")); } else if (buildVariant(product) == "release") { pVariants.insert(product); QCOMPARE(cppIncludePaths(product), QStringList("/r")); } } QCOMPARE(int(pVariants.size()), 2); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::multiplexingByProfile() { QFETCH(QString, projectFileName); QFETCH(bool, successExpected); try { defaultParameters.setDryRun(true); resolveProject(qPrintable("/multiplexing-by-profile/" + projectFileName)); QVERIFY(successExpected); QVERIFY(!!project); } catch (const ErrorInfo &e) { QVERIFY2(!successExpected, qPrintable(e.toString())); } } void TestLanguage::multiplexingByProfile_data() { QTest::addColumn("projectFileName"); QTest::addColumn("successExpected"); QTest::newRow("same profile") << "p1.qbs" << true; QTest::newRow("dependency on non-multiplexed") << "p2.qbs" << true; QTest::newRow("dependency by non-multiplexed") << "p3.qbs" << false; QTest::newRow("dependency by non-multiplexed with Depends.profile") << "p4.qbs" << true; } void TestLanguage::nonApplicableModulePropertyInProfile() { QFETCH(QString, targetOS); QFETCH(QString, toolchain); QFETCH(bool, successExpected); try { defaultParameters.setOverriddenValues({std::make_pair("project.targetOS", targetOS), std::make_pair("project.toolchain", toolchain)}); resolveProject("non-applicable-module-property-in-profile.qbs"); QVERIFY(!!project); QVERIFY(successExpected); } catch (const ErrorInfo &e) { QVERIFY2(!successExpected, qPrintable(e.toString())); QVERIFY2(e.toString().contains("Loading module 'multiple_backends' for product 'p' failed " "due to invalid values in profile 'theProfile'"), qPrintable(e.toString())); QVERIFY2(e.toString().contains("backend3Prop"), qPrintable(e.toString())); } } void TestLanguage::nonApplicableModulePropertyInProfile_data() { QTest::addColumn("targetOS"); QTest::addColumn("toolchain"); QTest::addColumn("successExpected"); QTest::newRow("no matching property (1)") << "os1" << QString() << false; QTest::newRow("no matching property (2)") << "os2" << QString() << false; // The point here is that there's a second, lower-prioritized candidate with a matching // condition that doesn't have the property. This candidate must not throw an error. QTest::newRow("matching property") << "os2" << "tc" << true; } void TestLanguage::nonRequiredProducts() { bool exceptionCaught = false; try { QFETCH(bool, subProjectEnabled); QFETCH(bool, dependeeEnabled); QVariantMap overriddenValues; if (!subProjectEnabled) overriddenValues.insert("projects.subproject.condition", false); else if (!dependeeEnabled) overriddenValues.insert("products.dependee.condition", false); defaultParameters.setOverriddenValues(overriddenValues); resolveProject("non-required-products.qbs"); QVERIFY(!!project); const auto products = productsFromProject(project); QCOMPARE(products.size(), 4 + !!subProjectEnabled); const ResolvedProductConstPtr dependee = products.value("dependee"); QCOMPARE(subProjectEnabled, !!dependee); if (dependee) QCOMPARE(dependeeEnabled, dependee->enabled); const ResolvedProductConstPtr depender = products.value("depender"); QVERIFY(!!depender); const QStringList defines = depender->moduleProperties->moduleProperty("dummy", "defines") .toStringList(); QCOMPARE(subProjectEnabled && dependeeEnabled, defines.contains("WITH_DEPENDEE")); for (const auto &name : std::vector({ "p3", "p2", "p1"})) { const ResolvedProductConstPtr &product = products.value(name); QVERIFY2(product, name); QVERIFY2(!product->enabled, name); } } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::nonRequiredProducts_data() { QTest::addColumn("subProjectEnabled"); QTest::addColumn("dependeeEnabled"); QTest::newRow("dependee enabled") << true << true; QTest::newRow("dependee disabled") << true << false; QTest::newRow("sub project disabled") << false << true; } void TestLanguage::outerInGroup() { bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs")); resolveProject(); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product = products.value("OuterInGroup"); QVERIFY(!!product); QCOMPARE(product->groups.size(), size_t(3)); GroupPtr group = product->groups.at(0); QVERIFY(!!group); QCOMPARE(group->name, product->name); QVERIFY(group->files); QCOMPARE(group->files->size(), size_t(1)); SourceArtifactConstPtr artifact = group->files->front(); QVariant installDir = artifact->properties->qbsPropertyValue("installDir"); QCOMPARE(installDir.toString(), QString("/somewhere")); group = product->groups.at(2); QVERIFY(!!group); QCOMPARE(group->name, QString("Special Group")); QVERIFY(group->files); QCOMPARE(group->files->size(), size_t(1)); artifact = group->files->front(); installDir = artifact->properties->qbsPropertyValue("installDir"); QCOMPARE(installDir.toString(), QString("/somewhere/else")); const QVariant stringProp = artifact->properties->moduleProperty("dummy", "someString"); QCOMPARE(stringProp.toString(), "s1s2s3"); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::overriddenPropertiesAndPrototypes() { bool exceptionCaught = false; try { QFETCH(QString, osName); QFETCH(QString, backendName); defaultParameters.setOverriddenValues({std::make_pair("modules.qbs.targetPlatform", osName)}); resolveProject("overridden-properties-and-prototypes.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); QCOMPARE(project->products.front()->moduleProperties->moduleProperty( "multiple_backends", "prop").toString(), backendName); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::overriddenPropertiesAndPrototypes_data() { QTest::addColumn("osName"); QTest::addColumn("backendName"); QTest::newRow("first backend") << "os1" << "backend 1"; QTest::newRow("second backend") << "os2" << "backend 2"; } void TestLanguage::overriddenVariantProperty() { bool exceptionCaught = false; try { const QVariantMap objectValue{std::make_pair("x", 1), std::make_pair("y", 2)}; defaultParameters.setOverriddenValues({std::make_pair("products.p.myObject", objectValue)}); resolveProject("overridden-variant-property.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); QCOMPARE(project->products.front()->productProperties.value("myObject").toMap(), objectValue); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::parameterTypes() { bool exceptionCaught = false; try { defaultParameters.setProjectFilePath(testProject("parameter-types.qbs")); resolveProject(); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::pathProperties() { bool exceptionCaught = false; try { resolveProject("pathproperties.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); QVERIFY(!!product); QString projectFileDir = QFileInfo(defaultParameters.projectFilePath()).absolutePath(); const QVariantMap productProps = product->productProperties; QCOMPARE(productProps.value("projectFileDir").toString(), projectFileDir); QStringList filesInProjectFileDir = QStringList() << FileInfo::resolvePath(projectFileDir, "aboutdialog.h") << FileInfo::resolvePath(projectFileDir, "aboutdialog.cpp"); QCOMPARE(productProps.value("filesInProjectFileDir").toStringList(), filesInProjectFileDir); QStringList includePaths = product->moduleProperties->property( QStringList() << "dummy" << "includePaths").toStringList(); QCOMPARE(includePaths, QStringList() << projectFileDir); QCOMPARE(productProps.value("base_fileInProductDir").toString(), FileInfo::resolvePath(projectFileDir, QStringLiteral("foo"))); QCOMPARE(productProps.value("base_fileInBaseProductDir").toString(), FileInfo::resolvePath(projectFileDir, QStringLiteral("subdir/bar"))); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::probesAndMultiplexing() { bool exceptionCaught = false; try { resolveProject("probes-and-multiplexing.qbs"); QVERIFY(project); QCOMPARE(int(project->products.size()), 3); QStringList architectures{"x86", "x86_64", "arm"}; for (const ResolvedProductPtr &product : project->products) { const QString arch = product->moduleProperties->moduleProperty("qbs", "architecture") .toString(); QVERIFY2(architectures.removeOne(arch), qPrintable(arch)); QCOMPARE(product->productProperties.value("archFromProbe").toString(), arch); bool foundGroup = false; for (const GroupPtr &group : product->groups) { if (group->name == "theGroup") { foundGroup = true; QCOMPARE(group->properties->moduleProperty("qbs", "sysroot"), "/" + arch); } } QVERIFY(foundGroup); } } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::profileValuesAndOverriddenValues() { bool exceptionCaught = false; try { TemporaryProfile tp(QStringLiteral("tst_lang_profile"), m_settings); Profile profile = tp.p; profile.setValue("dummy.defines", "IN_PROFILE"); profile.setValue("dummy.cFlags", "IN_PROFILE"); profile.setValue("dummy.cxxFlags", "IN_PROFILE"); profile.setValue("qbs.architecture", "x86"); defaultParameters.setTopLevelProfile(profile.name()); QVariantMap overriddenValues; overriddenValues.insert("modules.dummy.cFlags", "OVERRIDDEN"); defaultParameters.setOverriddenValues(overriddenValues); resolveProject("profilevaluesandoverriddenvalues.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); QVERIFY(!!product); QVariantList values; values = product->moduleProperties->moduleProperty("dummy", "cxxFlags").toList(); QCOMPARE(values.length(), 1); QCOMPARE(values.front().toString(), QString("IN_PROFILE")); values = product->moduleProperties->moduleProperty("dummy", "defines").toList(); QCOMPARE(values, QVariantList() << QStringLiteral("IN_FILE") << QStringLiteral("IN_PROFILE")); values = product->moduleProperties->moduleProperty("dummy", "cFlags").toList(); QCOMPARE(values.length(), 1); QCOMPARE(values.front().toString(), QString("OVERRIDDEN")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::projectFileLookup() { QFETCH(QString, projectFileInput); QFETCH(QString, projectFileOutput); QFETCH(bool, failureExpected); try { SetupProjectParameters params; params.setProjectFilePath(projectFileInput); params.finalizeProjectFilePath(); QVERIFY(!failureExpected); QCOMPARE(params.projectFilePath(), projectFileOutput); } catch (const ErrorInfo &) { QVERIFY(failureExpected); } } void TestLanguage::projectFileLookup_data() { QTest::addColumn("projectFileInput"); QTest::addColumn("projectFileOutput"); QTest::addColumn("failureExpected"); const QString baseDir = testDataDir(); const QString multiProjectsDir = baseDir + "/dirwithmultipleprojects"; const QString noProjectsDir = baseDir + "/dirwithnoprojects"; const QString oneProjectDir = baseDir + "/dirwithoneproject"; QVERIFY(QDir(noProjectsDir).exists() && QDir(oneProjectDir).exists() && QDir(multiProjectsDir).exists()); const QString fullFilePath = multiProjectsDir + "/project.qbs"; QTest::newRow("full file path") << fullFilePath << fullFilePath << false; QTest::newRow("base dir ") << oneProjectDir << (oneProjectDir + "/project.qbs") << false; QTest::newRow("empty dir") << noProjectsDir << QString() << true; QTest::newRow("ambiguous dir") << multiProjectsDir << QString() << true; } void TestLanguage::productConditions() { bool exceptionCaught = false; try { resolveProject("productconditions.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 6); ResolvedProductPtr product; product = products.value("product_no_condition"); QVERIFY(!!product); QVERIFY(product->enabled); product = products.value("product_true_condition"); QVERIFY(!!product); QVERIFY(product->enabled); product = products.value("product_condition_dependent_of_module"); QVERIFY(!!product); QVERIFY(product->enabled); product = products.value("product_false_condition"); QVERIFY(!!product); QVERIFY(!product->enabled); product = products.value("product_probe_condition_false"); QVERIFY(!!product); QVERIFY(!product->enabled); product = products.value("product_probe_condition_true"); QVERIFY(!!product); QVERIFY(product->enabled); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::productDirectories() { bool exceptionCaught = false; try { resolveProject("productdirectories.qbs"); QVERIFY(!!project); QHash products = productsFromProject(project); QCOMPARE(products.size(), 1); ResolvedProductPtr product; product = products.value("MyApp"); QVERIFY(!!product); const QVariantMap config = product->productProperties; QCOMPARE(config.value(QStringLiteral("buildDirectory")).toString(), product->buildDirectory()); QCOMPARE(config.value(QStringLiteral("sourceDirectory")).toString(), testDataDir()); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::propertiesBlocks_data() { QTest::addColumn("propertyName"); QTest::addColumn("expectedValue"); QTest::addColumn("expectedStringValue"); QTest::newRow("init") << QString() << QVariant() << QString(); QTest::newRow("property_overwrite") << QString("dummy.defines") << QVariant(QStringList("OVERWRITTEN")) << QString(); QTest::newRow("property_set_indirect") << QString("dummy.cFlags") << QVariant(QStringList("VAL")) << QString(); QTest::newRow("property_overwrite_no_outer") << QString("dummy.defines") << QVariant(QStringList("OVERWRITTEN")) << QString(); QTest::newRow("property_append_to_outer") << QString("dummy.defines") << QVariant(QStringList() << QString("ONE") << QString("TWO")) << QString(); QTest::newRow("property_append_to_indirect_outer") << QString("dummy.defines") << QVariant(QStringList() << QString("ONE") << QString("TWO")) << QString(); QTest::newRow("property_append_to_indirect_derived_outer1") << QString("dummy.cFlags") << QVariant(QStringList() << QString("BASE") << QString("PROPS")) << QString(); QTest::newRow("property_append_to_indirect_derived_outer2") << QString("dummy.cFlags") << QVariant(QStringList() << QString("PRODUCT") << QString("PROPS")) << QString(); QTest::newRow("property_append_to_indirect_derived_outer3") << QString("dummy.cFlags") << QVariant(QStringList() << QString("BASE") << QString("PRODUCT") << QString("PROPS")) << QString(); QTest::newRow("property_append_to_indirect_merged_outer") << QString("dummy.rpaths") << QVariant(QStringList() << QString("ONE") << QString("TWO") << QString("$ORIGIN")) << QString(); QTest::newRow("multiple_exclusive_properties") << QString("dummy.defines") << QVariant(QStringList("OVERWRITTEN")) << QString(); QTest::newRow("multiple_exclusive_properties_no_outer") << QString("dummy.defines") << QVariant(QStringList("OVERWRITTEN")) << QString(); QTest::newRow("multiple_exclusive_properties_append_to_outer") << QString("dummy.defines") << QVariant(QStringList() << QString("ONE") << QString("TWO")) << QString(); QTest::newRow("condition_refers_to_product_property") << QString("dummy.defines") << QVariant(QStringList("OVERWRITTEN")) << QString("OVERWRITTEN"); QTest::newRow("condition_refers_to_project_property") << QString("dummy.defines") << QVariant(QStringList("OVERWRITTEN")) << QString("OVERWRITTEN"); QTest::newRow("ambiguous_properties") << QString("dummy.defines") << QVariant(QStringList{"ONE", "TWO", "ONE", "THREE"}) << QString(); QTest::newRow("inheritance_overwrite_in_subitem") << QString("dummy.defines") << QVariant(QStringList() << QString("OVERWRITTEN_IN_SUBITEM")) << QString(); QTest::newRow("inheritance_retain_base1") << QString("dummy.defines") << QVariant(QStringList() << QString("BASE") << QString("SUB")) << QString(); QTest::newRow("inheritance_retain_base2") << QString("dummy.defines") << QVariant(QStringList() << QString("BASE") << QString("SUB")) << QString(); QTest::newRow("inheritance_retain_base3") << QString("dummy.defines") << QVariant(QStringList() << QString("BASE") << QString("SUB")) << QString(); QTest::newRow("inheritance_retain_base4") << QString("dummy.defines") << QVariant(QStringList() << QString("BASE")) << QString(); QTest::newRow("inheritance_condition_in_subitem1") << QString("dummy.defines") << QVariant(QStringList() << QString("SOMETHING") << QString("SUB")) << QString(); QTest::newRow("inheritance_condition_in_subitem2") << QString("dummy.defines") << QVariant(QStringList() << QString("SOMETHING")) << QString(); QTest::newRow("condition_references_id") << QString("dummy.defines") << QVariant(QStringList() << QString("OVERWRITTEN")) << QString(); QTest::newRow("using_derived_Properties_item") << "dummy.defines" << QVariant(QStringList() << "string from MyProperties") << QString(); QTest::newRow("conditional-depends") << QString("dummy.defines") << QVariant() << QString(); QTest::newRow("use-module-with-properties-item") << QString("module-with-properties-item.stringProperty") << QVariant(QString("overridden in Properties item")) << QString(); QTest::newRow("cleanup") << QString() << QVariant() << QString(); } void TestLanguage::propertiesBlocks() { defaultParameters.setDeprecationWarningMode(DeprecationWarningMode::On); HANDLE_INIT_CLEANUP_DATATAGS("propertiesblocks.qbs"); QFETCH(QString, propertyName); QFETCH(QVariant, expectedValue); QFETCH(QString, expectedStringValue); QVERIFY(!!project); Set warningLocations; for (const ErrorInfo &e : std::as_const(project->warningsEncountered)) { const QString errStr = e.toString(); QVERIFY2( errStr.contains("Using list properties as fallback values is deprecated"), qPrintable(errStr)); for (const ErrorItem &ei : e.items()) warningLocations << ei.codeLocation(); } const QList lines{7, 8, 29, 38, 54, 61, 67, 102, 114}; QCOMPARE(int(warningLocations.size()), int(lines.size())); for (const CodeLocation &loc : warningLocations) QVERIFY2(lines.contains(loc.line()), qPrintable(QString::number(loc.line()))); QHash products = productsFromProject(project); const QString productName = QString::fromLocal8Bit(QTest::currentDataTag()); ResolvedProductPtr product = products.value(productName); QVERIFY(!!product); QCOMPARE(product->name, productName); QVariant v = productPropertyValue(product, propertyName); QCOMPARE(v, expectedValue); if (!expectedStringValue.isEmpty()) { v = productPropertyValue(product, "someString"); QCOMPARE(v.toString(), expectedStringValue); } } void TestLanguage::propertiesBlockInGroup_data() { QTest::addColumn("withGroup"); QTest::addColumn("moduleGroup"); QTest::addColumn("expectedValue"); QTest::newRow("with group, use primary module group") << true << "module_group" << QStringList{"BASEDEF", "FEATURE_ENABLED", "THE_GROUP", "MODULE_DEFINE", "MODULE_GROUP"}; QTest::newRow("with group, use alternative module group") << true << "module_group_alt" << QStringList{ "BASEDEF", "FEATURE_ENABLED", "THE_GROUP", "MODULE_DEFINE", "MODULE_GROUP_ALT"}; QTest::newRow("without group, use primary module group") << false << "module_group" << QStringList{"BASEDEF", "MODULE_DEFINE", "MODULE_GROUP"}; QTest::newRow("without group, use alternative module group") << false << "module_group_alt" << QStringList{"BASEDEF", "MODULE_DEFINE", "MODULE_GROUP_ALT"}; } void TestLanguage::propertiesBlockInGroup() { QFETCH(bool, withGroup); QFETCH(QString, moduleGroup); QFETCH(QStringList, expectedValue); bool exceptionCaught = false; try { defaultParameters.setOverriddenValues( {std::make_pair(QString("products.in-group.featureEnabled"), withGroup), std::make_pair(QString("modules.module_with_group.group"), moduleGroup)}); resolveProject("properties-block-in-group.qbs"); QVERIFY(!!project); QCOMPARE(project->allProducts().size(), size_t(1)); const ResolvedProductConstPtr product = project->allProducts().front(); const QStringList productValue = moduleProperty(product->moduleProperties->value(), "dummy", "defines").toStringList(); QCOMPARE(productValue, expectedValue); const auto groupIt = std::find_if(product->groups.cbegin(), product->groups.cend(), [](const GroupConstPtr &g) { return g->name == "the group"; }); QVERIFY(groupIt != product->groups.cend()); const QStringList groupValue = moduleProperty((*groupIt)->properties->value(), "dummy", "defines").toStringList(); QCOMPARE(groupValue, QStringList{"GROUP_ONLY"}); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::propertiesItemInModule() { bool exceptionCaught = false; try { resolveProject("properties-item-in-module.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 2); for (const ResolvedProductPtr &p : products) { QCOMPARE(p->moduleProperties->moduleProperty("dummy", "productName").toString(), p->name); } } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::propertyAssignmentInExportedGroup() { bool exceptionCaught = false; try { resolveProject("property-assignment-in-exported-group.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 2); for (const ResolvedProductPtr &p : products) { QCOMPARE(p->moduleProperties->moduleProperty("dummy", "someString").toString(), QString()); for (const GroupPtr &g : p->groups) { const QString propValue = g->properties->moduleProperty("dummy", "someString").toString(); if (g->name == "exported_group") QCOMPARE(propValue, QString("test")); else QCOMPARE(propValue, QString()); } } } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::qbs1275() { bool exceptionCaught = false; try { resolveProject("qbs1275.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.count(), 5); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::qbsPropertiesInProjectCondition() { bool exceptionCaught = false; try { resolveProject("qbs-properties-in-project-condition.qbs"); QVERIFY(!!project); QVERIFY(!project->enabled); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 0); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::qbsPropertyConvenienceOverride() { bool exceptionCaught = false; try { defaultParameters.setOverriddenValues({std::make_pair("qbs.installPrefix", "/opt")}); resolveProject("qbs-property-convenience-override.qbs"); QVERIFY(!!project); QCOMPARE(project->products.size(), size_t(1)); QCOMPARE(project->products.front()->moduleProperties->qbsPropertyValue("installPrefix") .toString(), QString("/opt")); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::relaxedErrorMode() { m_logSink->setLogLevel(LoggerMinLevel); QFETCH(bool, strictMode); try { defaultParameters.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict : ErrorHandlingMode::Relaxed); resolveProject("relaxed-error-mode/relaxed-error-mode.qbs"); QVERIFY(!strictMode); const auto productMap = productsFromProject(project); const ResolvedProductConstPtr brokenProduct = productMap.value("broken"); QVERIFY(!brokenProduct->enabled); QVERIFY(brokenProduct->location.isValid()); QCOMPARE(brokenProduct->allFiles().size(), size_t(0)); const ResolvedProductConstPtr dependerRequired = productMap.value("depender required"); QVERIFY(!dependerRequired->enabled); QVERIFY(dependerRequired->location.isValid()); QCOMPARE(dependerRequired->allFiles().size(), size_t(1)); const ResolvedProductConstPtr dependerNonRequired = productMap.value("depender nonrequired"); QVERIFY(dependerNonRequired->enabled); QCOMPARE(dependerNonRequired->allFiles().size(), size_t(1)); const ResolvedProductConstPtr recursiveDepender = productMap.value("recursive depender"); QVERIFY(!recursiveDepender->enabled); QVERIFY(recursiveDepender->location.isValid()); QCOMPARE(recursiveDepender->allFiles().size(), size_t(1)); const ResolvedProductConstPtr missingFile = productMap.value("missing file"); QVERIFY(missingFile->enabled); QCOMPARE(missingFile->groups.size(), size_t(1)); QVERIFY(missingFile->groups.front()->enabled); QVERIFY(missingFile->groups.front()->files); QCOMPARE(missingFile->groups.front()->files->size(), size_t(2)); const ResolvedProductConstPtr fine = productMap.value("fine"); QVERIFY(fine->enabled); QCOMPARE(fine->allFiles().size(), size_t(1)); } catch (const ErrorInfo &e) { QVERIFY2(strictMode, qPrintable(e.toString())); } } void TestLanguage::relaxedErrorMode_data() { QTest::addColumn("strictMode"); QTest::newRow("strict mode") << true; QTest::newRow("relaxed mode") << false; } void TestLanguage::requiredAndNonRequiredDependencies() { QFETCH(QString, projectFile); QFETCH(bool, exceptionExpected); try { resolveProject(qPrintable("required-and-nonrequired-dependencies/" + projectFile)); QVERIFY(!!project); QVERIFY(!exceptionExpected); } catch (const ErrorInfo &e) { QVERIFY(exceptionExpected); QVERIFY2(e.toString().contains("validation error!"), qPrintable(e.toString())); } } void TestLanguage::requiredAndNonRequiredDependencies_data() { QTest::addColumn("projectFile"); QTest::addColumn("exceptionExpected"); QTest::newRow("same file") << "direct-dependencies.qbs" << true; QTest::newRow("dependency via module") << "dependency-via-module.qbs" << true; QTest::newRow("dependency via export") << "dependency-via-export.qbs" << true; QTest::newRow("more indirection") << "complicated.qbs" << true; QTest::newRow("required chain (module)") << "required-chain-module.qbs" << false; QTest::newRow("required chain (export)") << "required-chain-export.qbs" << false; QTest::newRow("required chain (export indirect)") << "required-chain-export-indirect.qbs" << false; } void TestLanguage::suppressedAndNonSuppressedErrors() { try { resolveProject("suppressed-and-non-suppressed-errors.qbs"); QFAIL("failure expected"); } catch (const ErrorInfo &e) { QVERIFY2(e.toString().contains("easter bunny"), qPrintable(e.toString())); QVERIFY2(!e.toString().contains("TheBeautifulSausage"), qPrintable(e.toString())); } } void TestLanguage::throwingProbe() { QFETCH(bool, enableProbe); try { QVariantMap properties; properties.insert(QStringLiteral("products.theProduct.enableProbe"), enableProbe); defaultParameters.setOverriddenValues(properties); resolveProject("throwing-probe.qbs"); QVERIFY(!!project); QVERIFY(!enableProbe); } catch (const ErrorInfo &e) { QVERIFY2(enableProbe, qPrintable(e.toString())); } } void TestLanguage::throwingProbe_data() { QTest::addColumn("enableProbe"); QTest::newRow("enabled probe") << true; QTest::newRow("disabled probe") << false; } void TestLanguage::qualifiedId() { QString str = "foo.bar.baz"; QualifiedId id = QualifiedId::fromString(str); QCOMPARE(id.size(), 3); QCOMPARE(id.toString(), str); id = QualifiedId("blubb.di.blubb"); // c'tor does not split QCOMPARE(id.size(), 1); QList ids; ids << QualifiedId::fromString("a") << QualifiedId::fromString("a.a") << QualifiedId::fromString("b") << QualifiedId::fromString("c.a") << QualifiedId::fromString("c.b.a") << QualifiedId::fromString("c.c"); QList sorted = ids; std::sort(sorted.begin(), sorted.end()); QCOMPARE(ids, sorted); } void TestLanguage::recursiveProductDependencies() { bool exceptionCaught = false; try { resolveProject("recursive-dependencies/recursive-dependencies.qbs"); QVERIFY(!!project); const QHash products = productsFromProject(project); QCOMPARE(products.size(), 4); const ResolvedProductConstPtr p1 = products.value("p1"); QVERIFY(!!p1); const ResolvedProductConstPtr p2 = products.value("p2"); QVERIFY(!!p2); const ResolvedProductPtr p3 = products.value("p3"); QVERIFY(!!p3); const ResolvedProductPtr p4 = products.value("p4"); QVERIFY(!!p4); QVERIFY(p1->dependencies == std::vector({p3, p4})); QVERIFY(p2->dependencies == std::vector({p3, p4})); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } void TestLanguage::fileTags_data() { QTest::addColumn("numberOfGroups"); QTest::addColumn("expectedFileTags"); QTest::newRow("init") << size_t(0) << QStringList(); QTest::newRow("filetagger_project_scope") << size_t(1) << (QStringList() << "cpp"); QTest::newRow("filetagger_product_scope") << size_t(1) << (QStringList() << "asm"); QTest::newRow("filetagger_static_pattern") << size_t(1) << (QStringList() << "yellow"); QTest::newRow("unknown_file_tag") << size_t(1) << (QStringList() << "unknown-file-tag"); QTest::newRow("set_file_tag_via_group") << size_t(2) << (QStringList() << "c++"); QTest::newRow("override_file_tag_via_group") << size_t(2) << (QStringList() << "c++"); QTest::newRow("add_file_tag_via_group") << size_t(2) << (QStringList() << "cpp" << "zzz"); QTest::newRow("prioritized_filetagger") << size_t(1) << (QStringList() << "cpp1" << "cpp2"); QTest::newRow("cleanup") << size_t(0) << QStringList(); } void TestLanguage::fileTags() { HANDLE_INIT_CLEANUP_DATATAGS("filetags.qbs"); QFETCH(size_t, numberOfGroups); QFETCH(QStringList, expectedFileTags); QHash products = productsFromProject(project); ResolvedProductPtr product; const QString productName = QString::fromLocal8Bit(QTest::currentDataTag()); QVERIFY(!!(product = products.value(productName))); QCOMPARE(product->groups.size(), numberOfGroups); GroupPtr group = *(product->groups.end() - 1); QVERIFY(!!group); QVERIFY(group->files); QCOMPARE(group->files->size(), size_t(1)); SourceArtifactConstPtr sourceFile = group->files->front(); QStringList fileTags = sourceFile->fileTags.toStringList(); fileTags.sort(); QCOMPARE(fileTags, expectedFileTags); } void TestLanguage::useInternalProfile() { const QString profile(QStringLiteral("theprofile")); defaultParameters.setTopLevelProfile(profile); resolveProject("use-internal-profile.qbs"); QVERIFY(!!project); QCOMPARE(project->profile(), profile); QCOMPARE(project->products.size(), size_t(1)); const ResolvedProductConstPtr product = project->products[0]; QCOMPARE(product->profile(), profile); QCOMPARE(product->moduleProperties->moduleProperty("dummy", "defines").toString(), profile); } void TestLanguage::wildcards_data() { QTest::addColumn("useGroup"); QTest::addColumn("filesToCreate"); QTest::addColumn("projectFileSubDir"); QTest::addColumn("prefix"); QTest::addColumn("patterns"); QTest::addColumn("excludePatterns"); QTest::addColumn("expected"); const bool useGroup = true; for (int i = 0; i <= 1; ++i) { const bool useGroup = i; const QByteArray dataTagSuffix = useGroup ? " group" : " nogroup"; QTest::newRow(QByteArray("simple 1") + dataTagSuffix) << useGroup << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp") << QString() << QString() << (QStringList() << "*.h") << QStringList() << (QStringList() << "foo.h" << "bar.h"); QTest::newRow(QByteArray("simple 2") + dataTagSuffix) << useGroup << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp") << QString() << QString() << (QStringList() << "foo.*") << QStringList() << (QStringList() << "foo.h" << "foo.cpp"); QTest::newRow(QByteArray("simple 3") + dataTagSuffix) << useGroup << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp") << QString() << QString() << (QStringList() << "*.h" << "*.cpp") << QStringList() << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp"); QTest::newRow(QByteArray("exclude 1") + dataTagSuffix) << useGroup << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp") << QString() << QString() << (QStringList() << "*.h" << "*.cpp") << (QStringList() << "bar*") << (QStringList() << "foo.h" << "foo.cpp"); QTest::newRow(QByteArray("exclude 2") + dataTagSuffix) << useGroup << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp") << QString() << QString() << (QStringList() << "*") << (QStringList() << "*.qbs") << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp"); QTest::newRow(QByteArray("non-recursive") + dataTagSuffix) << useGroup << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp") << QString() << QString() << (QStringList() << "a/*") << QStringList() << (QStringList() << "a/foo.h" << "a/foo.cpp"); QTest::newRow(QByteArray("absolute paths") + dataTagSuffix) << useGroup << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp") << QString() << QString() << (QStringList() << m_wildcardsTestDirPath + "/?oo.*") << QStringList() << (QStringList() << "foo.h" << "foo.cpp"); QTest::newRow(QByteArray("relative paths with dotdot") + dataTagSuffix) << useGroup << (QStringList() << "bar.h" << "bar.cpp") << QString("TheLaughingLlama") << QString() << (QStringList() << "../bar.*") << QStringList() << (QStringList() << "bar.h" << "bar.cpp"); } QTest::newRow(QByteArray("recursive 1")) << useGroup << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp") << QString() << QString() << (QStringList() << "a/**") << QStringList() << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp"); QTest::newRow(QByteArray("recursive 2")) << useGroup << (QStringList() << "d/1.h" << "b/d/1.h" << "b/c/d/1.h" << "d/e/1.h" << "b/d/e/1.h" << "b/c/d/e/1.h" << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h" << "a/d/e/1.h" << "a/b/d/e/1.h" << "a/b/c/d/e/1.h" << "a/d/1.cpp" << "a/b/d/1.cpp" << "a/b/c/d/1.h" << "a/d/e/1.cpp" << "a/b/d/e/1.cpp" << "a/b/c/d/e/1.cpp") << QString() << QString() << (QStringList() << "a/**/d/*.h") << QStringList() << (QStringList() << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h"); QTest::newRow(QByteArray("recursive 3")) << useGroup << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp") << QString() << QString() << (QStringList() << "a/**/**/**") << QStringList() << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp"); QTest::newRow(QByteArray("prefix")) << useGroup << (QStringList() << "subdir/foo.h" << "subdir/foo.cpp" << "subdir/bar.h" << "subdir/bar.cpp") << QString() << QString("subdir/") << (QStringList() << "*.h") << QStringList() << (QStringList() << "subdir/foo.h" << "subdir/bar.h"); QTest::newRow(QByteArray("non-existing absolute path")) << useGroup << QStringList() << QString() << QString("/dir") << (QStringList() << "*.whatever") << QStringList() << QStringList(); } void TestLanguage::wildcards() { QFETCH(bool, useGroup); QFETCH(QStringList, filesToCreate); QFETCH(QString, projectFileSubDir); QFETCH(QString, prefix); QFETCH(QStringList, patterns); QFETCH(QStringList, excludePatterns); QFETCH(QStringList, expected); // create test directory QDir::setCurrent(QDir::tempPath()); { QString errorMessage; if (QFile::exists(m_wildcardsTestDirPath)) { if (!removeDirectoryWithContents(m_wildcardsTestDirPath, &errorMessage)) { qDebug() << errorMessage; QVERIFY2(false, "removeDirectoryWithContents failed"); } } QVERIFY(QDir().mkdir(m_wildcardsTestDirPath)); } // create project file const QString groupName = "Keks"; QString dataTag = QString::fromLocal8Bit(QTest::currentDataTag()); dataTag.replace(' ', '_'); if (!projectFileSubDir.isEmpty()) { if (!projectFileSubDir.startsWith('/')) projectFileSubDir.prepend('/'); if (projectFileSubDir.endsWith('/')) projectFileSubDir.chop(1); QVERIFY(QDir().mkpath(m_wildcardsTestDirPath + projectFileSubDir)); } const QString projectFilePath = m_wildcardsTestDirPath + projectFileSubDir + "/test_" + dataTag + ".qbs"; { QFile projectFile(projectFilePath); QVERIFY(projectFile.open(QIODevice::WriteOnly)); QTextStream s(&projectFile); using Qt::endl; s << "Application {" << endl << " name: \"MyProduct\"" << endl; if (useGroup) { s << " Group {" << endl << " name: " << toJSLiteral(groupName) << endl; } if (!prefix.isEmpty()) s << " prefix: " << toJSLiteral(prefix) << endl; if (!patterns.empty()) s << " files: " << toJSLiteral(patterns) << endl; if (!excludePatterns.empty()) s << " excludeFiles: " << toJSLiteral(excludePatterns) << endl; if (useGroup) s << " }" << endl; s << "}" << endl << endl; } // create files for (QString filePath : std::as_const(filesToCreate)) { filePath.prepend(m_wildcardsTestDirPath + '/'); QFileInfo fi(filePath); if (!QDir(fi.path()).exists()) QVERIFY(QDir().mkpath(fi.path())); QFile file(filePath); QVERIFY(file.open(QIODevice::WriteOnly)); } // read the project bool exceptionCaught = false; ResolvedProductPtr product; try { defaultParameters.setProjectFilePath(projectFilePath); resolveProject(); QVERIFY(!!project); const QHash products = productsFromProject(project); product = products.value("MyProduct"); QVERIFY(!!product); GroupPtr group; if (useGroup) { QCOMPARE(product->groups.size(), size_t(HostOsInfo::isMacosHost() ? 4 : 2)); for (const GroupPtr &rg : product->groups) { if (rg->name == groupName) { group = rg; break; } } } else { QCOMPARE(product->groups.size(), size_t(HostOsInfo::isMacosHost() ? 3 : 1)); group = product->groups.front(); } QVERIFY(!!group); QVERIFY(group->files); QCOMPARE(group->files->size(), expected.size()); // we assume all files are wildcards QVERIFY(!!group->wildcards); QStringList actualFilePaths; for (const SourceArtifactPtr &artifact : *group->files) { QString str = artifact->absoluteFilePath; int idx = str.indexOf(m_wildcardsTestDirPath); if (idx != -1) str.remove(0, idx + m_wildcardsTestDirPath.size() + 1); actualFilePaths << str; } actualFilePaths.sort(); expected.sort(); QCOMPARE(actualFilePaths, expected); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); } QCOMPARE(exceptionCaught, false); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); const SettingsPtr s = settings(); TestLanguage tl(ConsoleLogger::instance().logSink(), s.get()); return QTest::qExec(&tl, argc, argv); } qbs-src-2.6.1/tests/auto/language/CMakeLists.txt0000644000175100001660000000031214776170045021101 0ustar runnerdockeradd_qbs_test(language DEFINES "QBS_VERSION=\"${QBS_VERSION}\"" DEPENDS qbsquickjsheaders Qt6Core5Compat SOURCES tst_language.cpp tst_language.h ) qbs-src-2.6.1/tests/auto/dllexport.h0000644000175100001660000000304714776170045016754 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef DLLEXPORT_H #define DLLEXPORT_H #if defined(_WIN32) || defined(WIN32) # define DLL_EXPORT __declspec(dllexport) # define DLL_IMPORT __declspec(dllimport) #else # define DLL_EXPORT __attribute__((visibility("default"))) # define DLL_IMPORT __attribute__((visibility("default"))) # endif #endif // include guard qbs-src-2.6.1/tests/auto/api/0000755000175100001660000000000014776170045015333 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/tst_api.h0000644000175100001660000001277014776170045017156 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TST_API_H #define QBS_TST_API_H #include #include #include namespace qbs { class ErrorInfo; class SetupProjectParameters; } class BuildDescriptionReceiver; class LogSink; class ProcessResultReceiver; class TaskReceiver; class TestApi : public QObject { Q_OBJECT public: TestApi(); ~TestApi() override; private slots: void initTestCase(); void init(); void addQObjectMacroToCppFile(); void addedFilePersistent(); void baseProperties(); void buildErrorCodeLocation(); void buildGraphInfo(); void buildGraphLocking(); void buildProject(); void buildProject_data(); void buildProjectDryRun(); void buildProjectDryRun_data(); void buildSingleFile(); void canonicalToolchainList(); void changeContent(); void changeDependentLib(); void checkOutputs(); void checkOutputs_data(); void commandExtraction(); void dependencyOnMultiplexedType(); void disabledInstallGroup(); void disabledProduct(); void disabledProject(); void disappearedWildcardFile(); void duplicateProductNames(); void duplicateProductNames_data(); void emptyFileTagList(); void emptySubmodulesList(); void enableAndDisableProduct(); void errorInSetupRunEnvironment(); void excludedInputs(); void explicitlyDependsOn(); void exportSimple(); void exportWithRecursiveDepends(); void fallbackGcc(); void fileTagger(); void fileTagsFilterOverride(); void generatedFilesList(); void groupVisibility(); void infiniteLoopBuilding(); void infiniteLoopBuilding_data(); void infiniteLoopResolving(); void inheritQbsSearchPaths(); void installableFiles(); void isRunnable(); void linkDynamicLibs(); void linkDynamicAndStaticLibs(); void linkStaticAndDynamicLibs(); void listBuildSystemFiles(); void localProfiles(); void localProfiles_data(); void missingSourceFile(); void mocCppIncluded(); void multiArch(); void multiplexing(); void newOutputArtifactInDependency(); void newPatternMatch(); void noAssertsInRelaxedMode(); void nonexistingProjectPropertyFromCommandLine(); void nonexistingProjectPropertyFromProduct(); void objC(); void projectDataAfterProductInvalidation(); void processResult(); void processResult_data(); void projectInvalidation(); void projectLocking(); void projectPropertiesByName(); void projectWithPropertiesItem(); void projectWithProbeAndProfileItem(); void propertiesBlocks(); void rc(); void referencedFileErrors(); void referencedFileErrors_data(); void references(); void relaxedModeRecovery(); void removeFileDependency(); void renameProduct(); void renameTargetArtifact(); void renamedQbsSource(); void resolveProject(); void resolveProject_data(); void resolveProjectDryRun(); void resolveProjectDryRun_data(); void restoredWarnings(); void restoreAndResolve(); void ruleConflict(); void runEnvForDisabledProduct(); void softDependency(); void sourceFileInBuildDir(); void subProjects(); void targetArtifactStatus_data(); void targetArtifactStatus(); void timeout(); void timeout_data(); void toolInModule(); void trackAddQObjectHeader(); void trackRemoveQObjectHeader(); void transformerData(); void transformers(); void typeChange(); void uic(); private: qbs::SetupProjectParameters defaultSetupParameters(const QString &projectFileOrDir) const; qbs::ErrorInfo doBuildProject(const QString &projectFilePath, BuildDescriptionReceiver *buildDescriptionReceiver = 0, ProcessResultReceiver *procResultReceiver = 0, TaskReceiver *taskReceiver = 0, const qbs::BuildOptions &options = qbs::BuildOptions(), const QVariantMap &overriddenValues = QVariantMap()); QString getProductFilePath(const QString &productNameOrFilePath); LogSink * const m_logSink; const QString m_sourceDataDir; const QString m_workingDataDir; }; #endif // Include guard. qbs-src-2.6.1/tests/auto/api/testdata/0000755000175100001660000000000014776170045017144 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/transformers/0000755000175100001660000000000014776170045021671 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/transformers/transformers.qbs0000644000175100001660000000561014776170045025127 0ustar runnerdockerimport qbs.File import qbs.TextFile import qbs.Xml import qbs.FileInfo Project { Product { name: "HelloWorld" type: "application" consoleApplication: true Group { files: ["main.cpp"] fileTags: ["main"] } Depends { name: "cpp" } Rule { // no inputs -> just a generator multiplex: true Artifact { filePath: "foo.txt" fileTags: "text" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating foo.txt"; cmd.highlight = "linker"; cmd.sourceCode = function () { File.remove(output.filePath); var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("Dear Sir/Madam,\n\n"); f.write("this is a generated file.\n\n\n"); f.write("Best Regards and Mellow Greetings,\nYour Build Tool.\n"); f.close(); } return cmd; } } Rule { multiplex: true // no inputs -> just a generator Artifact { filePath: "foo.xml" fileTags: "xml" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating foo.xml"; cmd.highlight = "linker"; cmd.sourceCode = function () { File.remove(output.filePath); var doc = new Xml.DomDocument(); var root = doc.createElement("root"); doc.appendChild(root); var tag = doc.createElement("Greeting"); root.appendChild(tag); tag.appendChild(doc.createTextNode("text node")); doc.save(output.filePath); } return cmd; } } Rule { inputs: ["main"] Artifact { filePath: "bar.txt" fileTags: "text" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating bar.txt"; cmd.highlight = "linker"; cmd.inputFileName = input.filePath; cmd.sourceCode = function() { File.remove(output.filePath); var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("Dear Sir/Madam,\n\n"); f.write("this file was generated from " + inputFileName + ".\n\n\n"); f.write("Best Regards and Mellow Greetings,\nYour Build Tool.\n"); f.close(); } return cmd; } } } } qbs-src-2.6.1/tests/auto/api/testdata/transformers/main.cpp0000644000175100001660000000437314776170045023330 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include using namespace std; bool displayTextFile(const string &dirPath, const string &fileName) { string fullPath = dirPath + fileName; ifstream istream(fullPath.c_str()); if (!istream.is_open()) { cout << "Cannot open " << fileName << endl; return false; } cout << "---" << fileName << "---" << endl; char buf[256]; unsigned int i = 1; while (istream.good()) { istream.getline(buf, sizeof(buf)); cout << i++ << ": " << buf << endl; } return true; } int main(int, char **argv) { string appPath(argv[0]); size_t i = appPath.find_last_of('/'); if (i == string::npos) i = appPath.find_last_of('\\'); if (i == string::npos) // No path, plain executable was called appPath.clear(); else appPath.resize(i + 1); if (!displayTextFile(appPath, "foo.txt")) return 1; if (!displayTextFile(appPath, "bar.txt")) return 2; cout << "-------------" << endl; return 0; } qbs-src-2.6.1/tests/auto/api/testdata/export-item-with-group/0000755000175100001660000000000014776170045023524 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-item-with-group/export-item-with-group.qbs0000644000175100001660000000055014776170045030613 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "cpp" } Group { files: ["main.cpp"] } } } Application { name: "app" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/api/testdata/export-item-with-group/main.cpp0000644000175100001660000000235214776170045025156 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/api/testdata/objc/0000755000175100001660000000000014776170045020061 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/objc/main.mm0000644000175100001660000000072014776170045021337 0ustar runnerdocker#import #include int main(int argc, char **argv) { // We support both C++ std::cout << "Hello from C++" << std::endl; // And Objective-C NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; NSString *productVersion = [version objectForKey:@"ProductVersion"]; NSLog(@"Hello, macOS %@!", productVersion); // So it's Objective-C++ } qbs-src-2.6.1/tests/auto/api/testdata/objc/objc.qbs0000644000175100001660000000023314776170045021503 0ustar runnerdockerProject { CppApplication { condition: qbs.targetOS.includes("macos") files: "main.mm" cpp.frameworks: [ "Foundation" ] } } qbs-src-2.6.1/tests/auto/api/testdata/filetagsfilter_override/0000755000175100001660000000000014776170045024047 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/filetagsfilter_override/filetagsfilter_override.qbs0000644000175100001660000000030514776170045031457 0ustar runnerdockerimport "InstalledApp.qbs" as InstalledApp InstalledApp { files: "main.cpp" Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "habicht" } } qbs-src-2.6.1/tests/auto/api/testdata/filetagsfilter_override/InstalledApp.qbs0000644000175100001660000000027014776170045027135 0ustar runnerdockerCppApplication { type: "application" consoleApplication: true Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "hurz" } } qbs-src-2.6.1/tests/auto/api/testdata/filetagsfilter_override/main.cpp0000644000175100001660000000235114776170045025500 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/is-runnable/0000755000175100001660000000000014776170045021363 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/is-runnable/is-runnable.qbs0000644000175100001660000000034314776170045024311 0ustar runnerdockerProject { CppApplication { name: "app" } DynamicLibrary { name: "lib" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/0000755000175100001660000000000014776170045024556 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/test.txt0000644000175100001660000000000014776170045026264 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/two-default-property-values.qbs0000644000175100001660000000036514776170045032703 0ustar runnerdockerProduct { name: "two-default-property-values" type: "mymodule" Depends { name: "mymodule" } Depends { name: "myothermodule" } mymodule.direct: "dummy" Group { files: ["test.txt"] fileTags: ["txt"] } } qbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/modules/0000755000175100001660000000000014776170045026226 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/modules/myothermodule/0000755000175100001660000000000014776170045031123 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/modules/myothermodule/myothermodule.qbsqbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/modules/myothermodule/myothermodul0000644000175100001660000000005414776170045033575 0ustar runnerdockerModule { Depends { name: "mymodule" } } qbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/modules/mymodule/0000755000175100001660000000000014776170045030061 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/two-default-property-values/modules/mymodule/mymodule.qbs0000644000175100001660000000114314776170045032422 0ustar runnerdockerimport qbs.TextFile Module { property string direct property string indirect: direct ? "set" : "unset" Rule { inputs: ["txt"] Artifact { filePath: product.moduleProperty("mymodule", "indirect") fileTags: ["mymodule"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/api/testdata/project-with-properties-item/0000755000175100001660000000000014776170045024711 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-with-properties-item/project-with-properties-item.qbs0000644000175100001660000000034614776170045033170 0ustar runnerdockerProject { property string binPath: "/usr/bin" property string libPath: "/usr/lib" Properties { condition: qbs.targetOS.includes("macos") binPath: "/Users/boo" libPath: "/Libraries/foo" } } qbs-src-2.6.1/tests/auto/api/testdata/timeout-process/0000755000175100001660000000000014776170045022306 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/timeout-process/timeout.qbs0000644000175100001660000000245414776170045024510 0ustar runnerdockerimport qbs.Host Project { CppApplication { type: "application" consoleApplication: true // suppress bundle generation files: "main.cpp" name: "infinite-loop" cpp.cxxLanguageVersion: "c++11" cpp.minimumOsxVersion: "10.8" // For Properties { condition: qbs.toolchain.includes("gcc") cpp.driverFlags: "-pthread" } } Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } type: "product-under-test" name: "caller" Depends { name: "infinite-loop" } Depends { name: "cpp" // Make sure build environment is set up properly. condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } Rule { inputsFromDependencies: "application" outputFileTags: "product-under-test" prepare: { var cmd = new Command(inputs["application"][0].filePath); cmd.description = "calling application that runs forever"; cmd.timeout = 3; return cmd; } } } } qbs-src-2.6.1/tests/auto/api/testdata/timeout-process/main.cpp0000644000175100001660000000255714776170045023747 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main() { std::this_thread::sleep_for(std::chrono::seconds(700)); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-scan/0000755000175100001660000000000014776170045024440 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-scan/file.in0000644000175100001660000000000014776170045025675 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-scan/infinite-loop.qbs0000644000175100001660000000063614776170045027730 0ustar runnerdockerProduct { type: "t" Depends { name: "m" } Group { files: "file.in" fileTags: "i" } Rule { inputs: "i" Artifact { filePath: "dummy" fileTags: "t" } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() {}; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-scan/modules/0000755000175100001660000000000014776170045026110 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-scan/modules/m/0000755000175100001660000000000014776170045026344 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-scan/modules/m/m.qbs0000644000175100001660000000012214776170045027302 0ustar runnerdockerModule { Scanner { inputs: "i" scan: { while (true); } } }qbs-src-2.6.1/tests/auto/api/testdata/rule-conflict/0000755000175100001660000000000014776170045021712 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rule-conflict/rule-conflict.qbs0000644000175100001660000000023114776170045025163 0ustar runnerdockerCppApplication { files: "main.cpp" Group { name: "pch files" files: ["pch1.h", "pch2.h"] fileTags: "cpp_pch_src" } } qbs-src-2.6.1/tests/auto/api/testdata/rule-conflict/main.cpp0000644000175100001660000000235114776170045023343 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/rule-conflict/pch1.h0000644000175100001660000000233214776170045022716 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/api/testdata/rule-conflict/pch2.h0000644000175100001660000000233214776170045022717 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/api/testdata/lib-same-source/0000755000175100001660000000000014776170045022133 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/lib-same-source/lib-same-source.qbs0000644000175100001660000000074614776170045025640 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name : "HelloWorldApp" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: 'cpp' } Group { files : [ "main.cpp" ] } } Product { type: "staticlibrary" name : "HelloWorldLib" Depends { name: 'cpp' } Group { files : [ "main.cpp" ] } } } qbs-src-2.6.1/tests/auto/api/testdata/lib-same-source/main.cpp0000644000175100001660000000243414776170045023566 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::puts("Hello WOrld!"); } qbs-src-2.6.1/tests/auto/api/testdata/base-properties/0000755000175100001660000000000014776170045022250 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/base-properties/prj.qbs0000644000175100001660000000021014776170045023543 0ustar runnerdockerimport "imports/Foo.qbs" as Foo Project { Foo { cpp.defines: base.concat(["FROM_PRJ"]); files: "main.cpp" } } qbs-src-2.6.1/tests/auto/api/testdata/base-properties/imports/0000755000175100001660000000000014776170045023745 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/base-properties/imports/Foo.qbs0000644000175100001660000000015114776170045025174 0ustar runnerdockerBar { type: "application" consoleApplication: true cpp.defines: base.concat(["FROM_FOO"]) } qbs-src-2.6.1/tests/auto/api/testdata/base-properties/imports/Bar.qbs0000644000175100001660000000010614776170045025155 0ustar runnerdockerProduct { Depends { name: "cpp" } cpp.defines: ["FROM_BAR"] } qbs-src-2.6.1/tests/auto/api/testdata/base-properties/main.cpp0000644000175100001660000000261414776170045023703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FROM_FOO #error FROM_FOO missing! #endif #ifndef FROM_BAR #error FROM_BAR missing! #endif #ifndef FROM_PRJ #error FROM_PRJ missing! #endif int main() { return 0; } qbs-src-2.6.1/tests/auto/api/testdata/change-dependent-lib/0000755000175100001660000000000014776170045023101 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/change-dependent-lib/mylib.cpp0000644000175100001660000000253414776170045024725 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_EXPORT int mylib_hello() { std::puts("mylib says hello!"); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/change-dependent-lib/change-dependent-lib.qbs0000644000175100001660000000100214776170045027536 0ustar runnerdockerProject { Application { name : "HelloWorld" Group { files : [ "main.cpp" ] } Depends { name: "cpp" } Depends { name: "mylib" } } DynamicLibrary { name : "mylib" version: "1.2.3" Group { files : [ "mylib.cpp" ] } Depends { name: "cpp" } cpp.defines: ["XXXX"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/api/testdata/change-dependent-lib/main.cpp0000644000175100001660000000257314776170045024540 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_IMPORT int mylib_hello(); int main() { std::puts("application says hello!"); return mylib_hello(); } qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-dynamic/0000755000175100001660000000000014776170045024317 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-dynamic/autogen.h.in0000644000175100001660000000012714776170045026537 0ustar runnerdocker#ifndef AUTOGEN_IN_H #define AUTOGEN_IN_H inline void f() { } #endif // AUTOGEN_IN_H qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-dynamic/precompiled-header-dynamic.qbs0000644000175100001660000000142514776170045032203 0ustar runnerdockerimport qbs.File CppApplication { name: "MyApp" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } cpp.includePaths: [product.buildDirectory] Group { files: ["pch.h"] fileTags: ["cpp_pch_src"] } Group { files: ["autogen.h.in"] fileTags: ["hpp.in"] } files: ["main.cpp"] Rule { inputs: ["hpp.in"] Artifact { filePath: "autogen.h" fileTags: ["hpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-dynamic/pch.h0000644000175100001660000000236014776170045025243 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "autogen.h" qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-dynamic/main.cpp0000644000175100001660000000236314776170045025753 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { f(); } qbs-src-2.6.1/tests/auto/api/testdata/empty-filetag-list/0000755000175100001660000000000014776170045022664 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/empty-filetag-list/dontcompilethis.cpp0000644000175100001660000000002114776170045026566 0ustar runnerdockerThis is not C++. qbs-src-2.6.1/tests/auto/api/testdata/empty-filetag-list/empty-filetag-list.qbs0000644000175100001660000000013714776170045027114 0ustar runnerdockerCppApplication { Group { files: "dontcompilethis.cpp" fileTags: [] } } qbs-src-2.6.1/tests/auto/api/testdata/command-extraction/0000755000175100001660000000000014776170045022740 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/command-extraction/command-extraction.qbs0000644000175100001660000000005114776170045027237 0ustar runnerdockerCppApplication { files: "main.cpp" } qbs-src-2.6.1/tests/auto/api/testdata/command-extraction/main.cpp0000644000175100001660000000235114776170045024371 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/restored-warnings/0000755000175100001660000000000014776170045022621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/restored-warnings/file.cpp0000644000175100001660000000001414776170045024237 0ustar runnerdockervoid f() {} qbs-src-2.6.1/tests/auto/api/testdata/restored-warnings/main.cpp0000644000175100001660000000001614776170045024246 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/api/testdata/restored-warnings/restored-warnings.qbs0000644000175100001660000000071614776170045027011 0ustar runnerdockerimport qbs.Process 1.5 Project { CppApplication { name: "theProduct" cpp.blubb: true files: ["file.cpp", "main.cpp"] } Product { name: "theOtherProduct" property bool dummy: { throw "this one comes from a thread"; } } Product { name: "aThirdProduct" property bool moreFiles: false Group { condition: moreFiles files: ["blubb.txt"] } } } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/0000755000175100001660000000000014776170045024534 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static2.cpp0000644000175100001660000000015514776170045026612 0ustar runnerdocker#include "static2.h" #include void TestMe::hello() const { std::puts("static2 says hello!"); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic2.cpp0000644000175100001660000000025514776170045026750 0ustar runnerdocker#include "../dllexport.h" #include "static2.h" #include DLL_EXPORT void dynamic2_hello() { TestMe tm; tm.hello(); std::puts("dynamic2 says hello!"); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static2.h0000644000175100001660000000015414776170045026256 0ustar runnerdocker#ifndef STATIC2_H #define STATIC2_H class TestMe { public: void hello() const; }; #endif // STATIC2_H qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/dynamic1.cpp0000644000175100001660000000026314776170045026746 0ustar runnerdocker#include #include "../dllexport.h" void static1_hello(); DLL_EXPORT int dynamic1_hello() { static1_hello(); std::puts("dynamic1 says hello!"); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/static1.cpp0000644000175100001660000000024514776170045026611 0ustar runnerdocker#include "../dllexport.h" #include DLL_IMPORT void dynamic2_hello(); void static1_hello() { dynamic2_hello(); std::puts("static1 says hello!"); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/main.cpp0000644000175100001660000000027614776170045026171 0ustar runnerdocker#include "../dllexport.h" #include DLL_IMPORT int dynamic1_hello(); int main() { int result = dynamic1_hello(); std::puts("application says hello!"); return result; } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs-staticlibs/link-dynamiclibs-staticlibs.qbs0000644000175100001660000000254314776170045032637 0ustar runnerdockerProject { Application { name : "HelloWorld" files : [ "main.cpp" ] Depends { name: "cpp" } Depends { name: "dynamic1" } } DynamicLibrary { name : "dynamic1" files : [ "dynamic1.cpp" ] Depends { name: "cpp" } Depends { name: "static1" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } StaticLibrary { name: "static1" files: [ "static1.cpp" ] Depends { name: "cpp" } Depends { name: "dynamic2" } } DynamicLibrary { name: "dynamic2" files: [ "dynamic2.cpp" ] Depends { name: "cpp" } Depends { name: "static2" } cpp.visibility: 'hidden' Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } StaticLibrary { name: "static2" files: [ "static2.cpp", "static2.h" ] Depends { name: "cpp" } Probe { id: tcPrinter property bool isGcc: qbs.toolchain.contains("gcc") property bool isEmscripten: qbs.toolchain.contains("emscripten") configure: { console.info("is gcc: " + isGcc); console.info("is emscripten: " + isEmscripten); } } } } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlib-dynamiclib/0000755000175100001660000000000014776170045024166 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-staticlib-dynamiclib/link-staticlib-dynamiclib.qbs0000644000175100001660000000103314776170045031714 0ustar runnerdockerProject { CppApplication { Depends { name: "mystaticlib" } name: "app" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: ["main.cpp"] } StaticLibrary { Depends { name: "cpp" } Depends { name: "mydynamiclib" } name: "mystaticlib" files: ["mystaticlib.cpp"] } DynamicLibrary { name: "mydynamiclib" Depends { name: "cpp" } files: ["mydynamiclib.cpp"] } } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlib-dynamiclib/mydynamiclib.cpp0000644000175100001660000000010714776170045027351 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT int dynamic_foo() { return 12; } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlib-dynamiclib/main.cpp0000644000175100001660000000010214776170045025607 0ustar runnerdockerint static_foo(); int main() { return static_foo() - 156; } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlib-dynamiclib/mystaticlib.cpp0000644000175100001660000000015214776170045027214 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT int dynamic_foo(); int static_foo() { return dynamic_foo() * 13; } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-resolving/0000755000175100001660000000000014776170045023726 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-resolving/infinite-loop-resolving.qbs0000644000175100001660000000007014776170045031214 0ustar runnerdockerProduct { type: { while (true); return "Haha!"; } } qbs-src-2.6.1/tests/auto/api/testdata/added-file-persistent/0000755000175100001660000000000014776170045023320 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/added-file-persistent/added-file-persistent.qbs0000644000175100001660000000012314776170045030177 0ustar runnerdockerCppApplication { files: [ 'main.cpp', /* 'file.cpp' */ ] } qbs-src-2.6.1/tests/auto/api/testdata/added-file-persistent/file.cpp0000644000175100001660000000235014776170045024743 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f() { } qbs-src-2.6.1/tests/auto/api/testdata/added-file-persistent/main.cpp0000644000175100001660000000237214776170045024754 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f(); int main() { f(); } qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-new/0000755000175100001660000000000014776170045023464 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-new/myobject.h0000644000175100001660000000251014776170045025447 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MYOBJECT_H #define MYOBJECT_H class MyObject { public: MyObject(); ~MyObject(); }; #endif qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-new/myobject.cpp0000644000175100001660000000263514776170045026012 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "myobject.h" MyObject::MyObject() { std::cout << "MyObject::MyObject()\n"; } MyObject::~MyObject() { std::cout << "MyObject::~MyObject()" << std::endl; } qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-new/main.cpp0000644000175100001660000000334214776170045025116 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "myobject.h" #include #include #include using namespace std; int main() { MyObject obj; list lst; lst.push_back(1); lst.push_back(2); lst.push_back(3); lst.push_back(4); lst.push_back(5); lst.push_back(6); lst.push_back(7); lst.push_back(8); lst.push_back(9); reverse(lst.begin(), lst.end()); for (list::iterator it=lst.begin(); it != lst.end(); ++it) cout << *it << ", "; cout << endl; return 0; } qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-new/stable.h0000644000175100001660000000253614776170045025115 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /* Add C includes here */ #if defined __cplusplus /* Add C++ includes here */ # include # include #endif qbs-src-2.6.1/tests/auto/api/testdata/precompiled-header-new/precompiled-header-new.qbs0000644000175100001660000000050514776170045030513 0ustar runnerdockerCppApplication { name: "MyApp" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Group { name: "precompiled headers" files: ["stable.h"] fileTags: ["cpp_pch_src"] } files: ["myobject.h", "main.cpp", "myobject.cpp"] } qbs-src-2.6.1/tests/auto/api/testdata/project-editing/0000755000175100001660000000000014776170045022233 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/existingfile1.txt0000644000175100001660000000000014776170045025535 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/file.cpp0000644000175100001660000000233214776170045023656 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/api/testdata/project-editing/project-with-no-files.qbs0000644000175100001660000000007714776170045027077 0ustar runnerdockerCppApplication { Group { files: "file.cpp" } } qbs-src-2.6.1/tests/auto/api/testdata/project-editing/subdir/0000755000175100001660000000000014776170045023523 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/subdir/file.txt0000644000175100001660000000000014776170045025171 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/existingfile2.txt0000644000175100001660000000000014776170045025536 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/file.h0000644000175100001660000000233214776170045023323 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/api/testdata/project-editing/newfile4.txt0000644000175100001660000000000014776170045024477 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/newfile2.txt0000644000175100001660000000000014776170045024475 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/test.wildcard0000644000175100001660000000000014776170045024713 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/newfile3.txt0000644000175100001660000000000014776170045024476 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/main.cpp0000644000175100001660000000233214776170045023663 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/api/testdata/project-editing/existingfile3.txt0000644000175100001660000000000014776170045025537 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-editing/project-editing.qbs0000644000175100001660000000137014776170045026032 0ustar runnerdockerCppApplication { Group { name: "Existing Group 1" files: ["existingfile1.txt"] } property string aFile: "existingfile2.txt" Group { name: "Existing Group 2" files: product.aFile } Group { name: "Existing Group 3" files: { var file = "existingfile3.txt"; return file; } } Group { name: "Existing Group 4" prefix: "subdir/" files: [] } Group { name: "Existing Group 5" prefix: "blubb" files: [] } Group { name: "Group with wildcards" files: "*.klaus" } Group { name: "Other group with wildcards" files: "*.wildcard" } files: "main.cpp" } qbs-src-2.6.1/tests/auto/api/testdata/project-editing/newfile1.txt0000644000175100001660000000000014776170045024474 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/multi-arch/0000755000175100001660000000000014776170045021211 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/multi-arch/host+target.input0000644000175100001660000000000014776170045024517 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/multi-arch/multi-arch.qbs0000644000175100001660000000273614776170045023775 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Project { property string hostProfile property string targetProfile Product { property stringList myProfiles name: "p1" type: "output" qbs.profiles: myProfiles ? myProfiles : [project.targetProfile, project.hostProfile] Group { files: "host+target.input" fileTags: "input" } qbs.installPrefix: "" Group { fileTagsFilter: "output" qbs.install: true qbs.installDir: qbs.profile } } Product { name: "p2" type: "output" qbs.profiles: [project.hostProfile] Group { files: "host-tool.input" fileTags: "input" } qbs.installPrefix: "" Group { fileTagsFilter: "output" qbs.install: true qbs.installDir: qbs.profile } } Rule { inputs: "input" Artifact { filePath: FileInfo.baseName(input.fileName) + ".output" fileTags: "output" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); file.write(product.moduleProperty("qbs", "architecture")); file.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/multi-arch/host-tool.input0000644000175100001660000000000014776170045024210 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/0000755000175100001660000000000014776170045025063 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/main1.cpp0000644000175100001660000000235114776170045026575 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/main2.cpp0000644000175100001660000000241614776170045026600 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { #ifndef HAS_FOO blubb(); #endif } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/export-with-recursive-depends.qbsqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/export-with-recursive-depends.qb0000644000175100001660000000036314776170045033330 0ustar runnerdockerProject { CppApplication { name: "app1" files: "main1.cpp" Export { Depends { name: "module1" } } } CppApplication { name: "app2" Depends { name: "app1" } files: "main2.cpp" } } qbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/modules/0000755000175100001660000000000014776170045026533 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/modules/module2/0000755000175100001660000000000014776170045030102 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/modules/module2/module2.qbs0000644000175100001660000000010414776170045032153 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.defines: ["HAS_FOO"] } qbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/modules/module1/0000755000175100001660000000000014776170045030101 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-with-recursive-depends/modules/module1/module1.qbs0000644000175100001660000000005314776170045032154 0ustar runnerdockerModule { Depends { name: "module2" } } qbs-src-2.6.1/tests/auto/api/testdata/buildgraph-locking/0000755000175100001660000000000014776170045022711 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/buildgraph-locking/buildgraph-locking.qbs0000644000175100001660000000001414776170045027160 0ustar runnerdockerProject { } qbs-src-2.6.1/tests/auto/api/testdata/explicitly-depends-on/0000755000175100001660000000000014776170045023364 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/explicitly-depends-on/c.in0000644000175100001660000000000014776170045024124 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/explicitly-depends-on/b.in0000644000175100001660000000000014776170045024123 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs0000644000175100001660000000410014776170045030306 0ustar runnerdockerimport qbs.FileInfo import qbs.Host import qbs.TextFile Project { CppApplication { name: "compiler" files: ["compiler.cpp"] Group { fileTagsFilter: ["application"] fileTags: ["compiler"] } } Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "p" type: ["mytype"] Depends { name: "compiler" } Depends { name: "cpp" } Rule { inputs: ["mytype.in"] explicitlyDependsOnFromDependencies: ["compiler"] Artifact { filePath: input.fileName + ".out" fileTags: product.type } prepare: { var compiler = explicitlyDependsOn["compiler"][0].filePath; var cmd = new Command(compiler, [input.filePath, output.filePath]); cmd.description = "compiling " + input.fileName; cmd.highlight = "compiler"; return [cmd]; } } Rule { multiplex: true explicitlyDependsOnFromDependencies: ["compiler"] Artifact { filePath: "compiler-name.txt" fileTags: product.type } prepare: { var nameCmd = new JavaScriptCommand(); nameCmd.description = "writing compiler name"; nameCmd.sourceCode = function() { var compiler = explicitlyDependsOn["compiler"][0].filePath; var file = new TextFile(output.filePath, TextFile.WriteOnly); file.write("compiler file name: " + FileInfo.baseName(compiler)); file.close(); } return [nameCmd]; } } FileTagger { patterns: "*.in" fileTags: ["mytype.in"] } files: ["a.in", "b.in", "c.in"] } } qbs-src-2.6.1/tests/auto/api/testdata/explicitly-depends-on/a.in0000644000175100001660000000000014776170045024122 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/explicitly-depends-on/compiler.cpp0000644000175100001660000000026214776170045025702 0ustar runnerdocker#include #include int main(int argc, char *argv[]) { assert(argc == 3); std::ofstream target(argv[2]); assert(target); target << argv[1]; } qbs-src-2.6.1/tests/auto/api/testdata/empty-submodules-list/0000755000175100001660000000000014776170045023433 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/empty-submodules-list/empty-submodules-list.qbs0000644000175100001660000000012414776170045030426 0ustar runnerdockerCppApplication { Depends { name: "dummy" submodules: [] } } qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp-included/0000755000175100001660000000000014776170045022274 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/moc-hpp-included/object.cpp0000644000175100001660000000263114776170045024250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.h" Object::Object(QObject *parent) : QObject(parent) {} #include "moc_object.cpp" #include int main() { Object obj; std::printf("Hello World\n"); } qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp-included/object.h0000644000175100001660000000257114776170045023720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECT_H #define OBJECT_H #include class Object : public QObject { Q_OBJECT public: Object(QObject *parent = nullptr); }; #endif qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp-included/object2.mm0000644000175100001660000000031514776170045024156 0ustar runnerdocker#include "object2.h" Object2::Object2(QObject *parent) : QObject(parent) {} #include "moc_object2.cpp" #include int main2() { Object2 obj; printf("Hello World\n"); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp-included/moc-hpp-included.qbs0000644000175100001660000000072714776170045026141 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "moc_hpp_included" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "Qt.core" } cpp.cxxLanguageVersion: "c++11" files: ["object.cpp", "object.h"] Group { condition: qbs.targetOS.includes("darwin") files: ["object2.mm", "object2.h"] } } } qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp-included/object2.h0000644000175100001660000000257514776170045024006 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECT2_H #define OBJECT2_H #include class Object2 : public QObject { Q_OBJECT public: Object2(QObject *parent = nullptr); }; #endif qbs-src-2.6.1/tests/auto/api/testdata/installed-artifact/0000755000175100001660000000000014776170045022716 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/installed-artifact/main.cpp0000644000175100001660000000235114776170045024347 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/installed-artifact/installed-artifact.qbs0000644000175100001660000000131014776170045027172 0ustar runnerdocker Project { CppApplication { name: "other app" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: ["main.cpp"] } CppApplication { name: "installedApp" type: "application" consoleApplication: true Depends { name: "other app" } Group { files: "main.cpp" qbs.install: true qbs.installDir: "src" } qbs.installPrefix: "/usr" install: true installDebugInformation: false installDir: "bin" Group { fileTagsFilter: "obj" qbs.install: true qbs.installDir: "objects" } } } qbs-src-2.6.1/tests/auto/api/testdata/build-properties-source/0000755000175100001660000000000014776170045023733 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/build-properties-source/main.cpp0000644000175100001660000000252514776170045025367 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #ifndef WORLD # error WORLD is not defined #endif int main() { std::puts("Hello " WORLD "!"); } qbs-src-2.6.1/tests/auto/api/testdata/build-properties-source/build-properties-source.qbs0000644000175100001660000000054214776170045031232 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "HelloWorld" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: 'cpp' } Group { cpp.defines: ['WORLD="BANANA"'] files : [ "main.cpp" ] } } } qbs-src-2.6.1/tests/auto/api/testdata/timeout-js/0000755000175100001660000000000014776170045021244 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/timeout-js/timeout.qbs0000644000175100001660000000074214776170045023444 0ustar runnerdockerProduct { type: "product-under-test" Rule { multiplex: true Artifact { filePath: "output.txt" fileTags: "product-under-test" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "running infinite loop"; cmd.sourceCode = function() { while (true) ; } cmd.timeout = 3; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/disappeared-wildcard-file/0000755000175100001660000000000014776170045024131 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/disappeared-wildcard-file/file1.txt0000644000175100001660000000000014776170045025660 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/disappeared-wildcard-file/disappeared-wildcard-file.qbs0000644000175100001660000000006114776170045031622 0ustar runnerdockerProduct { name: "dummy" files: "*.txt" } qbs-src-2.6.1/tests/auto/api/testdata/disappeared-wildcard-file/file2.txt0000644000175100001660000000000014776170045025661 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/add-qobject-macro-to-cpp-file/0000755000175100001660000000000014776170045024535 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/add-qobject-macro-to-cpp-file/object.cpp0000644000175100001660000000256714776170045026521 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.h" #include // class InternalClass : public QObject // { // Q_OBJECT // }; void Object::f() { } // #include "object.moc" qbs-src-2.6.1/tests/auto/api/testdata/add-qobject-macro-to-cpp-file/object.h0000644000175100001660000000240314776170045026153 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ class Object { public: void f(); }; ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/add-qobject-macro-to-cpp-file/add-qobject-macro-to-cpp-file.qbsqbs-src-2.6.1/tests/auto/api/testdata/add-qobject-macro-to-cpp-file/add-qobject-macro-to-cpp-file.qb0000644000175100001660000000010514776170045032446 0ustar runnerdockerQtApplication { files: ["main.cpp", "object.h", "object.cpp"] } qbs-src-2.6.1/tests/auto/api/testdata/add-qobject-macro-to-cpp-file/main.cpp0000644000175100001660000000243014776170045026164 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.h" int main() { Object o; o.f(); } qbs-src-2.6.1/tests/auto/api/testdata/local-profiles/0000755000175100001660000000000014776170045022057 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/local-profiles/local-profiles.qbs0000644000175100001660000000233714776170045025506 0ustar runnerdockerProject { property string windowsProfile: "windowsProfile" property bool enableProfiles property string mingwToolchain: "mingw" property string mingwProfile: "mingwProfile" Profile { name: windowsProfile qbs.targetPlatform: "windows" } Profile { name: project.mingwProfile condition: enableProfiles baseProfile: project.windowsProfile qbs.toolchainType: project.mingwToolchain } Application { name: "app" Depends { name: "cpp"; required: false } aggregate: false multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] qbs.profile: project.mingwProfile } DynamicLibrary { name: "lib" Depends { name: "cpp"; required: false } property string clangToolchain: "clang" property string clangProfileName: "clangProfile" Profile { name: product.clangProfileName condition: project.enableProfiles qbs.targetPlatform: "linux" qbs.toolchainType: product.clangToolchain } multiplexByQbsProperties: ["profiles"] qbs.profiles: [project.mingwProfile, "clangProfile"] } } qbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/0000755000175100001660000000000014776170045023751 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/prj.qbs0000644000175100001660000000026714776170045025260 0ustar runnerdockerimport "imports/Foo.qbs" as Foo Project { qbsSearchPaths: "subdir" Project { qbsSearchPaths: "subdir2" Foo { files: "main.cpp" } } } qbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir/0000755000175100001660000000000014776170045025241 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir/modules/0000755000175100001660000000000014776170045026711 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir/modules/bli/0000755000175100001660000000000014776170045027457 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir/modules/bli/m.qbs0000644000175100001660000000010614776170045030417 0ustar runnerdockerModule { Depends {name : "cpp" } cpp.defines: ["HAVE_BLI"] } qbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/imports/0000755000175100001660000000000014776170045025446 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/imports/Foo.qbs0000644000175100001660000000013614776170045026700 0ustar runnerdockerProduct { type: "application" consoleApplication: true Depends { name: 'bli' } } qbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/main.cpp0000644000175100001660000000245314776170045025405 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HAVE_BLI #error HAVE_BLI missing! #endif int main() { return 0; } qbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir2/0000755000175100001660000000000014776170045025323 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir2/modules/0000755000175100001660000000000014776170045026773 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir2/modules/bla/0000755000175100001660000000000014776170045027531 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/inherit-qbs-search-paths/subdir2/modules/bla/m.qbs0000644000175100001660000000010614776170045030471 0ustar runnerdockerModule { Depends {name : "cpp" } cpp.defines: ["HAVE_BLA"] } qbs-src-2.6.1/tests/auto/api/testdata/references/0000755000175100001660000000000014776170045021265 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/invalid1.qbs0000644000175100001660000000006414776170045023503 0ustar runnerdockerProject { references: "subdir-with-no-project" }qbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-multiple-projects/0000755000175100001660000000000014776170045027206 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject1.qbs0000644000175100001660000000000014776170045032144 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject3.qbs0000644000175100001660000000000014776170045032146 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-multiple-projects/subproject2.qbs0000644000175100001660000000000014776170045032145 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/valid.qbs0000644000175100001660000000006614776170045023075 0ustar runnerdockerProject { references: "subdir-with-one-project" } qbs-src-2.6.1/tests/auto/api/testdata/references/invalid2.qbs0000644000175100001660000000007314776170045023504 0ustar runnerdockerProject { references: "subdir-with-multiple-projects" }qbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-no-project/0000755000175100001660000000000014776170045025604 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-no-project/test.txt0000644000175100001660000000000014776170045027312 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-one-project/0000755000175100001660000000000014776170045025751 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-one-project/test.txt0000644000175100001660000000000014776170045027457 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/references/subdir-with-one-project/p.qbs0000644000175100001660000000001414776170045026712 0ustar runnerdockerProject { } qbs-src-2.6.1/tests/auto/api/testdata/group-visibility/0000755000175100001660000000000014776170045022465 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/group-visibility/group-visibility.qbs0000644000175100001660000000027014776170045026514 0ustar runnerdockerProduct { Depends { name: "m" } Group { name: "should be visible (product)" files: [] } Group { name: "should not be visible (product)" } } qbs-src-2.6.1/tests/auto/api/testdata/group-visibility/modules/0000755000175100001660000000000014776170045024135 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/group-visibility/modules/m/0000755000175100001660000000000014776170045024371 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/group-visibility/modules/m/m.qbs0000644000175100001660000000041114776170045025330 0ustar runnerdockerModule { Group { name: "should not be visible (module)" Group { name: "should be visible (module)" files: [] Group { name: "should also not be visible (module)" } } } } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/0000755000175100001660000000000014776170045021507 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject1/0000755000175100001660000000000014776170045023750 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject1/main.cpp0000644000175100001660000000237614776170045025410 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f(); int main() { f(); } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject2/0000755000175100001660000000000014776170045023751 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject2/subproject2.qbs0000644000175100001660000000051014776170045026716 0ustar runnerdockerProject { name: "subproject2" property string libNamePrefix: "test" SubProject { filePath: "subproject3/subproject3.qbs" inheritProperties: true Properties { name: "overridden name" condition: qbs.targetOS.length > 0 libNameSuffix: "Lib" } } } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject2/subproject3/0000755000175100001660000000000014776170045026214 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject2/subproject3/subproject3.qbs0000644000175100001660000000063114776170045031166 0ustar runnerdockerimport LibraryType Project { condition: false property string libNameSuffix: "blubb" Product { name: project.libNamePrefix + project.libNameSuffix type: LibraryType.type() Depends { name: "cpp" } Depends { name: "QtCoreDepender" } cpp.defines: "MY_EXPORT=Q_DECL_EXPORT" files: "testlib.cpp" Export { Depends { name: "cute.core" } } } } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/subproject2/subproject3/testlib.cpp0000644000175100001660000000245214776170045030371 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "../../../dllexport.h" MY_EXPORT void f() {} qbs-src-2.6.1/tests/auto/api/testdata/subprojects/toplevelproject.qbs0000644000175100001660000000055114776170045025440 0ustar runnerdockerProject { name: "top level project" references: ["subproject2"] Project { condition: true name: "app-project" CppApplication { name: "app" Depends { name: "testLib" } cpp.defines: "MY_EXPORT=" files: "subproject1/main.cpp" } } qbsSearchPaths: ["resources"] } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/0000755000175100001660000000000014776170045023521 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/imports/0000755000175100001660000000000014776170045025216 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/imports/LibraryType/0000755000175100001660000000000014776170045027464 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/imports/LibraryType/type.js0000644000175100001660000000005514776170045031003 0ustar runnerdockerfunction type() { return "dynamiclibrary"; } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/0000755000175100001660000000000014776170045025171 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/QtCoreDepender/0000755000175100001660000000000014776170045030035 5ustar runnerdocker././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/QtCoreDepender/qtcoredepender.qbsqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/QtCoreDepender/qtcoredepender.qb0000644000175100001660000000005514776170045033365 0ustar runnerdockerModule { Depends { name: "cute.core" } } qbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/cute/0000755000175100001660000000000014776170045026131 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/cute/core/0000755000175100001660000000000014776170045027061 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/cute/core/cuteglobal.h0000644000175100001660000000004114776170045031346 0ustar runnerdocker#define Q_DECL_EXPORT DLL_EXPORT qbs-src-2.6.1/tests/auto/api/testdata/subprojects/resources/modules/cute/core/core.qbs0000644000175100001660000000010414776170045030513 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.includePaths: [path] } qbs-src-2.6.1/tests/auto/api/testdata/no-asserts-in-relaxed-mode/0000755000175100001660000000000014776170045024212 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/no-asserts-in-relaxed-mode/no-asserts-in-relaxed-mode.qbs0000644000175100001660000000024514776170045031770 0ustar runnerdockerProject { Product { name: "p" Depends { name: "dep" } } Product { name: "dep" property bool p: { throw "oops"; } } } qbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/0000755000175100001660000000000014776170045023475 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/okay.qbs0000644000175100001660000000002714776170045025146 0ustar runnerdockerProduct { name: "p2" } qbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/emptydir/0000755000175100001660000000000014776170045025332 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/emptydir/.gitignore0000644000175100001660000000000014776170045027310 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/ambiguousdir/0000755000175100001660000000000014776170045026167 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/ambiguousdir/p2.qbs0000644000175100001660000000000014776170045027205 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/ambiguousdir/p1.qbs0000644000175100001660000000000014776170045027204 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/cycle.qbs0000644000175100001660000000021314776170045025277 0ustar runnerdockerProject { property string productName: "p1" Product { name: project.productName } references: ["referenced-file-errors.qbs"] } qbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/referenced-file-errors.qbs0000644000175100001660000000074114776170045030537 0ustar runnerdockerProject { references: [ "ambiguousdir", "cycle.qbs", "emptydir", "nosuchfile.qbs", "okay.qbs", "wrongtype.qbs", ] SubProject { filePath: "cycle.qbs" Properties { productName: "p3" } } SubProject { filePath: "nosuchfile.qbs" } SubProject { filePath: "okay2.qbs" } Product { name: "p5" Depends { name: "brokenmodule" } } } qbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/wrongtype.qbs0000644000175100001660000000001314776170045026234 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/modules/0000755000175100001660000000000014776170045025145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/modules/brokenmodule/0000755000175100001660000000000014776170045027633 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/modules/brokenmodule/brokenmodule.qbs0000644000175100001660000000003414776170045033025 0ustar runnerdockerModule { syntax error } qbs-src-2.6.1/tests/auto/api/testdata/referenced-file-errors/okay2.qbs0000644000175100001660000000002714776170045025230 0ustar runnerdockerProduct { name: "p4" } qbs-src-2.6.1/tests/auto/api/testdata/fallback-gcc/0000755000175100001660000000000014776170045021435 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/fallback-gcc/fallback-gcc.qbs0000644000175100001660000000106314776170045024435 0ustar runnerdockerCppApplication { name: "app" cpp._skipAllChecks: true Profile { name: "unixProfile" qbs.targetOS: ["unix"] qbs.toolchain: ["gcc"] // qbs.targetPlatform: "unix" // qbs.toolchainType: "gcc" } Profile { name: "gccProfile" qbs.targetOS: [] qbs.toolchain: ["gcc"] // qbs.targetPlatform: undefined // qbs.toolchainType: "gcc" } multiplexByQbsProperties: ["profiles"] qbs.profiles: ["unixProfile", "gccProfile"] } qbs-src-2.6.1/tests/auto/api/testdata/recursive-wildcards/0000755000175100001660000000000014776170045023125 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/recursive-wildcards/dir/0000755000175100001660000000000014776170045023703 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/recursive-wildcards/dir/file1.txt0000644000175100001660000000000014776170045025432 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/recursive-wildcards/dir/subdir/0000755000175100001660000000000014776170045025173 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/recursive-wildcards/dir/subdir/file2.txt0000644000175100001660000000000014776170045026723 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/recursive-wildcards/recursive-wildcards.qbs0000644000175100001660000000021014776170045027606 0ustar runnerdockerProduct { qbs.installPrefix: "" Group { files: "dir/**" qbs.install: true qbs.installDir: "dir" } } qbs-src-2.6.1/tests/auto/api/testdata/transformer-data/0000755000175100001660000000000014776170045022415 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/transformer-data/transformer-data.qbs0000644000175100001660000000163114776170045026376 0ustar runnerdockerimport qbs.File import qbs.TextFile Product { type: ["theType"] Rule { multiplex: true Artifact { filePath: "artifact1" fileTags: ["type1"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return [cmd]; } } Rule { inputs: ["type1"] Artifact { filePath: "artifact2" fileTags: ["theType"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/api/testdata/check-outputs/0000755000175100001660000000000014776170045021742 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/check-outputs/check-outputs.qbs0000644000175100001660000000152614776170045025253 0ustar runnerdockerimport qbs.File Project { Product { type: 'application' consoleApplication: true Group { files: 'foo.txt' fileTags: ['text'] } Depends { name: 'cpp' } } Rule { inputs: ['text'] Artifact { fileTags: ['cpp'] filePath: input.baseName + '.cpp' } Artifact { fileTags: ['ghost'] filePath: input.baseName + '.ghost' } prepare: { var cmd = new JavaScriptCommand(); cmd.inp = inputs["text"][0].filePath; cmd.out = outputs["cpp"][0].filePath; cmd.description = "generating " + outputs["cpp"][0].fileName; cmd.sourceCode = function() { File.copy(inp, out); }; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/check-outputs/foo.txt0000644000175100001660000000003114776170045023260 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/api/testdata/process-result/0000755000175100001660000000000014776170045022136 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/process-result/process-result.qbs0000644000175100001660000000223314776170045025637 0ustar runnerdockerimport qbs.Host Project { CppApplication { name: "app" consoleApplication: true files: ["main.cpp"] } Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "app-caller" type: "mytype" Depends { name: "app" } Depends { name: "cpp" } property bool redirectStdout property bool redirectStderr property int argument Rule { inputsFromDependencies: ["application"] outputFileTags: "mytype" prepare: { var cmd = new Command(inputs["application"][0].filePath, [product.argument]); if (product.redirectStdout) cmd.stdoutFilePath = product.buildDirectory + "/stdout.txt"; if (product.redirectStderr) cmd.stderrFilePath = product.buildDirectory + "/stderr.txt"; cmd.description = "building app-caller"; return [cmd]; } } } } qbs-src-2.6.1/tests/auto/api/testdata/process-result/main.cpp0000644000175100001660000000257014776170045023572 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main(int argc, char *argv[]) { std::cout << "stdout"; std::cerr << "stderr"; return atoi(argv[1]); } qbs-src-2.6.1/tests/auto/api/testdata/moc-cpp/0000755000175100001660000000000014776170045020502 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/moc-cpp/bla.cpp0000644000175100001660000000254614776170045021753 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class MyObject : public QObject { Q_OBJECT }; int main() { MyObject obj; return 0; } #include "bla.moc" qbs-src-2.6.1/tests/auto/api/testdata/moc-cpp/moc-cpp.qbs0000644000175100001660000000044714776170045022554 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "moc_cpp" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "Qt.core" } files: ["bla.cpp"] } } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-process/0000755000175100001660000000000014776170045023374 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs0000644000175100001660000000173714776170045026667 0ustar runnerdockerimport qbs.Host Project { CppApplication { type: "application" consoleApplication: true // suppress bundle generation files: "main.cpp" name: "infinite-loop" cpp.cxxLanguageVersion: "c++11" Properties { condition: qbs.toolchain.includes("gcc") cpp.driverFlags: "-pthread" } } Product { type: "mytype" name: "caller" Depends { name: "infinite-loop" } Depends { name: "cpp" // Make sure build environment is set up properly. condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } Rule { inputsFromDependencies: "application" outputFileTags: "mytype" prepare: { var cmd = new Command(inputs["application"][0].filePath); cmd.description = "calling application that runs forever"; return cmd; } } } } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-process/main.cpp0000644000175100001660000000251314776170045025025 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main() { std::this_thread::sleep_for(std::chrono::seconds(700)); } qbs-src-2.6.1/tests/auto/api/testdata/remove-file-dependency/0000755000175100001660000000000014776170045023472 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/remove-file-dependency/someheader.h0000644000175100001660000000240314776170045025756 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ inline int magicValue() { return 156; } qbs-src-2.6.1/tests/auto/api/testdata/remove-file-dependency/removeFileDependency.qbs0000644000175100001660000000020214776170045030267 0ustar runnerdockerCppApplication { files: ["main.cpp"] // Do not reference header files here to force them to be FileDependency objects. } qbs-src-2.6.1/tests/auto/api/testdata/remove-file-dependency/main.cpp0000644000175100001660000000253714776170045025131 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "someheader.h" #include int main() { std::printf("The magic value is %d.\n", magicValue()); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/export-simple/0000755000175100001660000000000014776170045021754 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/export-simple/export-simple.qbs0000644000175100001660000000203714776170045025275 0ustar runnerdockerProject { Application { name : "HelloWorld" destinationDirectory: "bin" Group { files : [ "main.cpp" ] } Depends { name: "cpp" } Depends { name: 'dummy' } } Product { name: 'dummy' Group { files: 'main.cpp' qbs.install: true } Export { Depends { name: 'dummy2' } Properties { // QBS-550 condition: false qbs.optimization: "ludicrous speed" } } } Product { name: 'dummy2' Group { files: 'lib1.cpp' qbs.install: true } Export { Depends { name: 'lib1' } } } DynamicLibrary { name : "lib1" destinationDirectory: "bin" Group { files : [ "lib1.cpp" ] } Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/api/testdata/export-simple/lib1.cpp0000644000175100001660000000253114776170045023310 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_EXPORT int lib1_hello() { std::puts("lib1 says hello!"); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/export-simple/main.cpp0000644000175100001660000000257014776170045023410 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_IMPORT int lib1_hello(); int main() { std::puts("application says hello!"); return lib1_hello(); } qbs-src-2.6.1/tests/auto/api/testdata/enable-and-disable-product/0000755000175100001660000000000014776170045024211 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/enable-and-disable-product/enable-and-disable-product.qbs0000644000175100001660000000027514776170045031771 0ustar runnerdockerCppApplication { property string prop: undefined // Influences source artifact properties and the product condition condition: prop cpp.visibility: prop files: "main.cpp" } qbs-src-2.6.1/tests/auto/api/testdata/enable-and-disable-product/main.cpp0000644000175100001660000000235114776170045025642 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/restore-and-resolve/0000755000175100001660000000000014776170045023044 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/restore-and-resolve/restore-and-resolve.qbs0000644000175100001660000000006114776170045027450 0ustar runnerdockerProject { references: "broken-product.qbs" } qbs-src-2.6.1/tests/auto/api/testdata/restore-and-resolve/broken-product.qbs0000644000175100001660000000067014776170045026514 0ustar runnerdockerimport qbs.TextFile syntax error Product { type: "t" Rule { multiplex: true Artifact { filePath: "dummy.txt"; fileTags: "t" } prepare: { var cmd = JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { new TextFile(output.filePath, TextFile.WriteOnly); }; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/error-in-setup-run-environment/0000755000175100001660000000000014776170045025203 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/error-in-setup-run-environment/modules/0000755000175100001660000000000014776170045026653 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/error-in-setup-run-environment/modules/mymodule/0000755000175100001660000000000014776170045030506 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/error-in-setup-run-environment/modules/mymodule/mymodule.qbs0000644000175100001660000000007514776170045033052 0ustar runnerdockerModule { setupRunEnvironment: { trallala } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/error-in-setup-run-environment/error-in-setup-run-environment.qbsqbs-src-2.6.1/tests/auto/api/testdata/error-in-setup-run-environment/error-in-setup-run-environment.0000644000175100001660000000006414776170045033243 0ustar runnerdockerCppApplication { Depends { name: "mymodule" } } qbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/0000755000175100001660000000000014776170045023675 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/subdir1/0000755000175100001660000000000014776170045025246 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/subdir1/subproject.qbs0000644000175100001660000000001414776170045030130 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/explicit.qbs0000644000175100001660000000014614776170045026226 0ustar runnerdockerProject { Product { name: "blubb" } Product { name: "blubb" } Product { name: "blubb" } } qbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/implicit-indirect.qbs0000644000175100001660000000012114776170045030007 0ustar runnerdockerProject { references: ["subdir1/subproject.qbs", "subdir2/subproject.qbs"] } qbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/implicit.qbs0000644000175100001660000000007414776170045026217 0ustar runnerdockerProject { Product { } Product { } Product { } } qbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/subdir2/0000755000175100001660000000000014776170045025247 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/duplicate-product-names/subdir2/subproject.qbs0000644000175100001660000000001414776170045030131 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/api/testdata/project-locking/0000755000175100001660000000000014776170045022236 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-locking/project-locking.qbs0000644000175100001660000000001414776170045026032 0ustar runnerdockerProject { } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-js/0000755000175100001660000000000014776170045022332 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs0000644000175100001660000000065514776170045025623 0ustar runnerdockerProduct { type: "mytype" Rule { multiplex: true Artifact { filePath: "output.txt" fileTags: "mytype" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "running infinite loop"; cmd.sourceCode = function() { while (true) ; } return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/build-single-file/0000755000175100001660000000000014776170045022437 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/build-single-file/build-single-file.qbs0000644000175100001660000000136314776170045026444 0ustar runnerdockerimport qbs.TextFile CppApplication { consoleApplication: true files: ["ignored1.cpp", "ignored2.cpp", "compiled.cpp"] cpp.includePaths: [buildDirectory] Group { files: ["pch.h"] fileTags: ["cpp_pch_src"] } install: true installDir: "" Rule { multiplex: true Artifact { filePath: "generated.h" fileTags: ["hpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var header = new TextFile(output.filePath, TextFile.WriteOnly); header.close(); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/api/testdata/build-single-file/compiled.cpp0000644000175100001660000000243114776170045024737 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include void f() { std::cout << "test"; } qbs-src-2.6.1/tests/auto/api/testdata/build-single-file/ignored1.cpp0000644000175100001660000000000014776170045024641 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/build-single-file/ignored2.cpp0000644000175100001660000000000014776170045024642 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/build-single-file/pch.h0000644000175100001660000000002414776170045023356 0ustar runnerdocker#include qbs-src-2.6.1/tests/auto/api/testdata/generated-files-list/0000755000175100001660000000000014776170045023153 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/generated-files-list/generated-files-list.qbs0000644000175100001660000000062614776170045027675 0ustar runnerdockerCppApplication { Depends { name: "Qt.widgets" } consoleApplication: true property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } cpp.cxxLanguageVersion: "c++11" cpp.debugInformation: false cpp.separateDebugInformation: false files: [ "main.cpp", "mainwindow.cpp", "mainwindow.h", "mainwindow.ui" ] } qbs-src-2.6.1/tests/auto/api/testdata/generated-files-list/mainwindow.ui0000644000175100001660000000116614776170045025672 0ustar runnerdocker MainWindow 0 0 400 300 MainWindow qbs-src-2.6.1/tests/auto/api/testdata/generated-files-list/mainwindow.cpp0000644000175100001660000000266614776170045026045 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } qbs-src-2.6.1/tests/auto/api/testdata/generated-files-list/mainwindow.h0000644000175100001660000000305014776170045025476 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H qbs-src-2.6.1/tests/auto/api/testdata/generated-files-list/main.cpp0000644000175100001660000000260714776170045024610 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mainwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } qbs-src-2.6.1/tests/auto/api/testdata/dependency-on-multiplexed-type/0000755000175100001660000000000014776170045025205 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/dependency-on-multiplexed-type/dependency-on-multiplexed-type.qbsqbs-src-2.6.1/tests/auto/api/testdata/dependency-on-multiplexed-type/dependency-on-multiplexed-type.0000644000175100001660000000053314776170045033250 0ustar runnerdockerProject { Product { name: "dep"; type: "x" } Product { name: "p1" multiplexByQbsProperties: "architectures" qbs.architectures: ["a", "b"] aggregate: true Depends { productTypes: "x" } multiplexedType: "x" } Product { name: "p2" Depends { productTypes: "x" } } } qbs-src-2.6.1/tests/auto/api/testdata/build-error-code-location/0000755000175100001660000000000014776170045024110 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/build-error-code-location/build-error-code-location.qbs0000644000175100001660000000025214776170045031562 0ustar runnerdockerProduct { name: "p" type: ["p.out"] Rule { multiplex: true outputFileTags: ["p.out"] outputArtifacts: { } prepare: {} } } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/0000755000175100001660000000000014776170045024534 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static2.cpp0000644000175100001660000000030014776170045026602 0ustar runnerdocker#include "../dllexport.h" #include "static2.h" #include DLL_IMPORT void dynamic2_hello(); void TestMe::hello() const { dynamic2_hello(); std::puts("static2 says hello!"); } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic2.cpp0000644000175100001660000000017114776170045026745 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void dynamic2_hello() { std::puts("dynamic2 says hello!"); } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/link-staticlibs-dynamiclibs.qbs0000644000175100001660000000310614776170045032633 0ustar runnerdockerProject { Application { name : "HelloWorld" files : [ "main.cpp" ] Depends { name: "cpp" } Depends { name: "static1" } } StaticLibrary { name: "static1" files: [ "static1.cpp" ] Depends { name: "cpp" } Depends { name: "dynamic1" } Probe { id: osCheck property bool isNormalUnix: qbs.targetOS.includes("unix") && !qbs.targetOS.includes("darwin") property bool isGcc: qbs.toolchain.contains("gcc") property bool isEmscripten: qbs.toolchain.contains("emscripten") configure: { console.info("is normal unix: " + (isNormalUnix ? "yes" : "no")); console.info("is gcc: " + isGcc); console.info("is emscripten: " + isEmscripten); } } } DynamicLibrary { name : "dynamic1" files : [ "dynamic1.cpp" ] Depends { name: "cpp" } Depends { name: "static2" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } StaticLibrary { name: "static2" files: [ "static2.cpp", "static2.h" ] Depends { name: "cpp" } Depends { name: "dynamic2" } } DynamicLibrary { name: "dynamic2" files: [ "dynamic2.cpp" ] Depends { name: "cpp" } cpp.visibility: 'hidden' Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static2.h0000644000175100001660000000015414776170045026256 0ustar runnerdocker#ifndef STATIC2_H #define STATIC2_H class TestMe { public: void hello() const; }; #endif // STATIC2_H qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/dynamic1.cpp0000644000175100001660000000027214776170045026746 0ustar runnerdocker#include "../dllexport.h" #include "static2.h" #include DLL_EXPORT int dynamic1_hello() { TestMe tm; tm.hello(); std::puts("dynamic1 says hello!"); return 1; } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/static1.cpp0000644000175100001660000000026514776170045026613 0ustar runnerdocker#include "../dllexport.h" #include DLL_IMPORT int dynamic1_hello(); void static1_hello() { int n = dynamic1_hello(); std::printf("static%d says hello!\n", n); } qbs-src-2.6.1/tests/auto/api/testdata/link-staticlibs-dynamiclibs/main.cpp0000644000175100001660000000020614776170045026162 0ustar runnerdocker#include void static1_hello(); int main() { static1_hello(); std::puts("application says hello!"); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/projectd0000644000175100001660000000000014776170045020667 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-data-after-product-invalidation/0000755000175100001660000000000014776170045026755 5ustar runnerdocker././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/project-data-after-product-invalidation/project-data-after-product-invalidation.qbsqbs-src-2.6.1/tests/auto/api/testdata/project-data-after-product-invalidation/project-data-after-pro0000644000175100001660000000014514776170045033152 0ustar runnerdockerCppApplication { name: "theProduct" files: [ "file.cpp", "main.cpp", ] } qbs-src-2.6.1/tests/auto/api/testdata/project-data-after-product-invalidation/file.cpp0000644000175100001660000000235014776170045030400 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f() { } qbs-src-2.6.1/tests/auto/api/testdata/project-data-after-product-invalidation/main.cpp0000644000175100001660000000235114776170045030406 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/0000755000175100001660000000000014776170045021476 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/object.narf.h0000644000175100001660000000260114776170045024041 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECT_H #define OBJECT_H #include class ObjectNarf : public QObject { Q_OBJECT public: ObjectNarf(QObject *parent = nullptr); }; #endif qbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/lots-of-dots.qbs0000644000175100001660000000067014776170045024542 0ustar runnerdockerProject { QtGuiApplication { type: "application" consoleApplication: true name: "lots.of.dots" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } cpp.cxxLanguageVersion: "c++11" files : [ "m.a.i.n.cpp", "object.narf.h", "object.narf.cpp", "polka.dots.qrc", "dotty.matrix.ui" ] } } qbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/object.narf.cpp0000644000175100001660000000251114776170045024374 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.narf.h" #include ObjectNarf::ObjectNarf(QObject *parent) : QObject(parent) {} qbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/dotty.matrix.ui0000644000175100001660000000065414776170045024510 0ustar runnerdocker Form 0 0 400 300 Form qbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/polka.dots.qrc0000644000175100001660000000014414776170045024262 0ustar runnerdocker m.a.i.n.cpp qbs-src-2.6.1/tests/auto/api/testdata/lots-of-dots/m.a.i.n.cpp0000644000175100001660000000253614776170045023346 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.narf.h" #include #include int main() { ObjectNarf obj; std::puts("..."); } qbs-src-2.6.1/tests/auto/api/testdata/multiplexing/0000755000175100001660000000000014776170045021665 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/multiplexing/multiplexing.qbs0000644000175100001660000000645114776170045025123 0ustar runnerdockerimport qbs.TextFile Project { Project { name: "subproject 1" Product { name: "multiplex-using-export" multiplexByQbsProperties: ["architectures"] qbs.architectures: ["TRS-80", "C64"] Depends { name: "multiplex-with-export" } } Product { name: "multiplex-without-aggregator-2-depend-on-non-multiplexed" multiplexByQbsProperties: ["architectures"] qbs.architectures: ["TRS-80", "C64"] Depends { name: "no-multiplexing" } } Product { name: "multiplex-with-aggregator-2" aggregate: true multiplexByQbsProperties: ["architectures"] qbs.architectures: ["TRS-80", "C64"] qbs.architecture: "Atari ST" } Product { name: "multiplex-with-aggregator-2-dependent" Depends { name: "multiplex-with-aggregator-2" } } Product { name: "non-multiplexed-with-dependencies-on-multiplexed" Depends { name: "multiplex-without-aggregator-2" } } Product { name: "non-multiplexed-with-dependencies-on-multiplexed-via-export1" Depends { name: "multiplex-with-export" } } Product { name: "non-multiplexed-with-dependencies-on-multiplexed-via-export2" Depends { name: "nonmultiplex-with-export" } } Product { name: "non-multiplexed-with-dependencies-on-aggregation-via-export" Depends { name: "nonmultiplex-exporting-aggregation" } } } Project { name: "subproject 2" Product { name: "no-multiplexing" } Product { name: "multiplex-without-aggregator-2" multiplexByQbsProperties: ["architectures"] qbs.architectures: ["TRS-80", "C64"] } Product { name: "multiplex-with-export" multiplexByQbsProperties: ["architectures"] qbs.architectures: ["TRS-80", "C64"] Export { Depends { name: "multiplex-without-aggregator-2" } } } Product { name: "nonmultiplex-with-export" Export { Depends { name: "multiplex-without-aggregator-2" } } } Product { name: "nonmultiplex-exporting-aggregation" Export { Depends { name: "multiplex-with-aggregator-2" } } } Product { name: "multiplex-without-aggregator-4" multiplexByQbsProperties: ["architectures", "buildVariants"] qbs.architectures: ["TRS-80", "C64"] qbs.buildVariants: ["debug", "release"] } Product { name: "multiplex-without-aggregator-4-depends-2" multiplexByQbsProperties: ["architectures", "buildVariants"] qbs.architectures: ["TRS-80", "C64"] qbs.buildVariants: ["debug", "release"] Depends { name: "multiplex-without-aggregator-2" } } } Product { name: "aggregate-with-dependencies-on-aggregation-via-export" Depends { name: "nonmultiplex-exporting-aggregation" } aggregate: true multiplexByQbsProperties: ["architectures"] qbs.architectures: ["TRS-80", "C64"] qbs.architecture: "Atari ST" } } qbs-src-2.6.1/tests/auto/api/testdata/missing-qobject-header/0000755000175100001660000000000014776170045023470 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/missing-qobject-header/myobject.h0000644000175100001660000000247414776170045025464 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class MyObject : public QObject { Q_OBJECT public: void func(); }; qbs-src-2.6.1/tests/auto/api/testdata/missing-qobject-header/myobject.cpp0000644000175100001660000000241414776170045026011 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "myobject.h" void MyObject::func() { } qbs-src-2.6.1/tests/auto/api/testdata/missing-qobject-header/main.cpp0000644000175100001660000000243014776170045025117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "myobject.h" int main() { MyObject().func(); } qbs-src-2.6.1/tests/auto/api/testdata/project-properties-by-name/0000755000175100001660000000000014776170045024332 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-properties-by-name/main1.cpp0000644000175100001660000000250514776170045026045 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SUB1 #error "Missing define" #endif #ifdef SUB2 #error "Extraneous define" #endif int main() { } qbs-src-2.6.1/tests/auto/api/testdata/project-properties-by-name/project-properties-by-name.qbs0000644000175100001660000000071014776170045032225 0ustar runnerdockerProject { name: "toplevel" property stringList theDefines: [] Project { name: "subproject1" CppApplication { name: "subproduct1" files: ["main1.cpp"] cpp.defines: project.theDefines } } Project { name: "subproject2" CppApplication { name: "subproduct2" files: ["main2.cpp"] cpp.defines: project.theDefines } } } qbs-src-2.6.1/tests/auto/api/testdata/project-properties-by-name/main2.cpp0000644000175100001660000000250514776170045026046 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SUB2 #error "Missing define" #endif #ifdef SUB1 #error "Extraneous define" #endif int main() { } qbs-src-2.6.1/tests/auto/api/testdata/relaxed-mode-recovery/0000755000175100001660000000000014776170045023346 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/relaxed-mode-recovery/relaxed-mode-recovery.qbs0000644000175100001660000000031114776170045030252 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "blubb" } } } Product { name: "p1"; Depends { name: "dep" } } Product { name: "p2"; Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/api/testdata/soft-dependency/0000755000175100001660000000000014776170045022233 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/soft-dependency/main.cpp0000644000175100001660000000240314776170045023662 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { thisShouldNotLink(); } qbs-src-2.6.1/tests/auto/api/testdata/soft-dependency/soft-dependency.qbs0000644000175100001660000000026514776170045026034 0ustar runnerdockerCppApplication { Depends { name: "nosuchmodule" required: false } Properties { condition: nosuchmodule.present files: "main.cpp" } } qbs-src-2.6.1/tests/auto/api/testdata/excluded-inputs/0000755000175100001660000000000014776170045022261 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/excluded-inputs/excluded-inputs.qbs0000644000175100001660000000720214776170045026106 0ustar runnerdockerimport qbs.File import qbs.TextFile Project { Product { name: "dep" type: "the_tag" Rule { multiplex: true Artifact { filePath: "file1.txt" fileTags: "the_tag" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.writeLine("the_content"); f.close(); }; return cmd; } } Rule { inputs: "the_tag" excludedInputs: "the_other_tag" Artifact { filePath: "file2.txt" fileTags: "the_other_tag" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); var f = new TextFile(output.filePath, TextFile.Append); f.writeLine("the_other_content"); f.close(); }; return cmd; } } Group { fileTagsFilter: "the_other_tag" fileTags: "the_tag" } } Product { name: "p" type: "p_type" Depends { name: "dep" } Rule { multiplex: true inputsFromDependencies: "the_tag" Artifact { filePath: "dummy1.txt" fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName;; if (!inputs["the_tag"] || inputs["the_tag"].length != 2) throw "Huch?"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } Rule { multiplex: true inputsFromDependencies: "the_tag" excludedInputs: "the_other_tag" Artifact { filePath: "dummy2.txt" fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName;; if (!inputs["the_tag"] || inputs["the_tag"].length != 1) throw "Huch?"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } Rule { multiplex: true explicitlyDependsOnFromDependencies: "the_tag" excludedInputs: "the_other_tag" Artifact { filePath: "dummy3.txt" fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; if (!explicitlyDependsOn["the_tag"] || explicitlyDependsOn["the_tag"].length != 1) throw "Huch?"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } } } qbs-src-2.6.1/tests/auto/api/testdata/new-output-artifact-in-dependency/0000755000175100001660000000000014776170045025606 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbsqbs-src-2.6.1/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-depen0000644000175100001660000000053114776170045033147 0ustar runnerdockerProject { DynamicLibrary { //Depends { name: "cpp" } name: "lib" files: "lib.cpp" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } CppApplication { name: "app" files: "main.cpp" Depends { name: "lib" } } } qbs-src-2.6.1/tests/auto/api/testdata/new-output-artifact-in-dependency/lib.cpp0000644000175100001660000000241514776170045027062 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" DLL_EXPORT void f() {} qbs-src-2.6.1/tests/auto/api/testdata/new-output-artifact-in-dependency/main.cpp0000644000175100001660000000240214776170045027234 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ //void f(); int main() { // f(); } qbs-src-2.6.1/tests/auto/api/testdata/uic/0000755000175100001660000000000014776170045017724 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/uic/bla.cpp0000644000175100001660000000246614776170045021176 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "bla.h" int main() { Ui::MainWindow mainWindow; Q_UNUSED(mainWindow); } qbs-src-2.6.1/tests/auto/api/testdata/uic/uic.qbs0000644000175100001660000000035114776170045021212 0ustar runnerdockerProject { QtGuiApplication { type: "application" consoleApplication: true name: "ui" files: [ "bla.cpp", "bla.h", "ui.ui", "ui.h" ] } } qbs-src-2.6.1/tests/auto/api/testdata/uic/ui.h0000644000175100001660000000235614776170045020520 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "ui_ui.h" qbs-src-2.6.1/tests/auto/api/testdata/uic/bla.h0000644000175100001660000000235314776170045020636 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "ui.h" qbs-src-2.6.1/tests/auto/api/testdata/uic/ui.ui0000644000175100001660000000126414776170045020703 0ustar runnerdocker MainWindow 0 0 800 600 MainWindow 0 0 800 25 qbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/0000755000175100001660000000000014776170045021151 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/echoplugin.cpp0000644000175100001660000000247514776170045024022 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "echoplugin.h" QString EchoPlugin::echo(const QString &message) { return message; } qbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/echoplugin_dummy.cpp0000644000175100001660000000235714776170045025234 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void dummyFunc() {} qbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/echoplugin.h0000644000175100001660000000310314776170045023454 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef ECHOPLUGIN_H #define ECHOPLUGIN_H #include #include #include "echointerface.h" class EchoPlugin : public QObject, EchoInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.EchoInterface" FILE "echoplugin.json") Q_INTERFACES(EchoInterface) public: QString echo(const QString &message); }; #endif qbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/echoplugin.json.source0000644000175100001660000000000314776170045025471 0ustar runnerdocker{} qbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/echointerface.h0000644000175100001660000000312214776170045024117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef ECHOINTERFACE_H #define ECHOINTERFACE_H #include //! [0] class EchoInterface { public: virtual ~EchoInterface() {} virtual QString echo(const QString &message) = 0; }; QT_BEGIN_NAMESPACE #define EchoInterface_iid "org.qt-project.Qt.Examples.EchoInterface" Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid) QT_END_NAMESPACE //! [0] #endif qbs-src-2.6.1/tests/auto/api/testdata/qt5-plugin/qt5-plugin.qbs0000644000175100001660000000222314776170045023664 0ustar runnerdockerimport qbs.File import qbs.FileInfo DynamicLibrary { name: "echoplugin" Depends { name: "Qt.core" } Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Group { condition: Qt.core.versionMajor >= 5 files: [ "echoplugin.h", "echoplugin.cpp", ] } Group { condition: Qt.core.versionMajor >= 5 files: ["echoplugin.json.source"] fileTags: ["json_in"] } Group { condition: Qt.core.versionMajor < 5 files: "echoplugin_dummy.cpp" } cpp.includePaths: buildDirectory Rule { condition: Qt.core.versionMajor >= 5 inputs: ["json_in"] Artifact { filePath: "echoplugin.json" fileTags: ["qt_plugin_metadata"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + FileInfo.fileName(output.filePath); cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/0000755000175100001660000000000014776170045022132 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/link-static-lib.qbs0000644000175100001660000000220314776170045025624 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "HelloWorld" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files : [ "main.cpp" ] Depends { name: "cpp" } Depends { name: "mystaticlib" } } StaticLibrary { name : "mystaticlib" files : [ "mystaticlib.cpp" ] Depends { name: "cpp" } Depends { name: "helper1" } } StaticLibrary { name : "helper1" files : [ "helper1/helper1.h", "helper1/helper1.cpp" ] Depends { name: "cpp" } Depends { name: "helper2" } Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory + '/helper1'] } } StaticLibrary { name : "helper2" files : [ "helper2/helper2.h", "helper2/helper2.cpp" ] Depends { name: "cpp" } Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory + '/helper2'] } } } qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/mystaticlibhelper.cpp0000644000175100001660000000240614776170045026364 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int helper_function() { return 156; } qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/helper2/0000755000175100001660000000000014776170045023473 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/helper2/helper2.cpp0000644000175100001660000000242714776170045025545 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "helper2.h" int getOddNumber() { return 13; } qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/helper2/helper2.h0000644000175100001660000000244314776170045025210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HELPER2_H #define HELPER2_H extern int getOddNumber(); #endif qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/helper1/0000755000175100001660000000000014776170045023472 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/helper1/helper1.h0000644000175100001660000000244414776170045025207 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HELPER1_H #define HELPER1_H extern int getSomeNumber(); #endif qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/helper1/helper1.cpp0000644000175100001660000000247614776170045025547 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "helper1.h" #include int getSomeNumber() { return 12 * getOddNumber(); } qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/main.cpp0000644000175100001660000000243414776170045023565 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int bla(); int main() { return bla(); } qbs-src-2.6.1/tests/auto/api/testdata/link-static-lib/mystaticlib.cpp0000644000175100001660000000257114776170045025167 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int bla() { int n = getSomeNumber(); std::printf("Hello World! The magic number is %d.", n); return n; } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/0000755000175100001660000000000014776170045026021 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/file.in0000644000175100001660000000000014776170045027256 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/infinite-loop.qbs0000644000175100001660000000063614776170045031311 0ustar runnerdockerProduct { type: "t" Depends { name: "m" } Group { files: "file.in" fileTags: "i" } Rule { inputs: "i" Artifact { filePath: "dummy" fileTags: "t" } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() {}; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/modules/0000755000175100001660000000000014776170045027471 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/modules/m/0000755000175100001660000000000014776170045027725 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/infinite-loop-scanning-searchpaths/modules/m/m.qbs0000644000175100001660000000015314776170045030667 0ustar runnerdockerModule { Scanner { inputs: "i" searchPaths: { while (true); } scan: [] } } qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp/0000755000175100001660000000000014776170045020507 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/moc-hpp/object.cpp0000644000175100001660000000257614776170045022473 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.h" #include Object::Object(QObject *parent) : QObject(parent) {} int main() { Object obj; std::printf("Hello World\n"); } qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp/object.h0000644000175100001660000000257114776170045022133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECT_H #define OBJECT_H #include class Object : public QObject { Q_OBJECT public: Object(QObject *parent = nullptr); }; #endif qbs-src-2.6.1/tests/auto/api/testdata/moc-hpp/moc-hpp.qbs0000644000175100001660000000056014776170045022562 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "moc_hpp" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "Qt.core" } cpp.cxxLanguageVersion: "c++11" files : [ "object.h", "object.cpp" ] } } qbs-src-2.6.1/tests/auto/api/testdata/target-artifact-status/0000755000175100001660000000000014776170045023546 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/target-artifact-status/target-artifact-status.qbs0000644000175100001660000000141214776170045030655 0ustar runnerdockerimport qbs.TextFile Product { name: "p" type: "p_type" property bool enableTagging Rule { multiplex: true Artifact { filePath: "a1"; fileTags: "p_type" } Artifact { filePath: "a2"; fileTags: "x" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating outputs"; cmd.sourceCode = function() { var f = new TextFile(outputs.p_type[0].filePath, TextFile.WriteOnly); f.close(); f = new TextFile(outputs.x[0].filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } Group { condition: enableTagging fileTagsFilter: "x" fileTags: "p_type" } } qbs-src-2.6.1/tests/auto/api/testdata/project-invalidation/0000755000175100001660000000000014776170045023271 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/project-invalidation/project.no-error.qbs0000644000175100001660000000003714776170045027210 0ustar runnerdockerProduct { type: "mytype" } qbs-src-2.6.1/tests/auto/api/testdata/project-invalidation/project.early-error.qbs0000644000175100001660000000007314776170045027710 0ustar runnerdockerProduct { type: "mytype" files: "nosuchfile.txt" } qbs-src-2.6.1/tests/auto/api/testdata/project-invalidation/project.late-error.qbs0000644000175100001660000000027214776170045027522 0ustar runnerdockerProduct { type: "mytype" Rule { inputs: ["mytype"] Artifact { filePath: "blubb" fileTags: "mytype" } prepare: [] } } qbs-src-2.6.1/tests/auto/api/testdata/file-tagger/0000755000175100001660000000000014776170045021332 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/file-tagger/bla.txt0000644000175100001660000000021314776170045022625 0ustar runnerdocker#include class MyObject : public QObject { Q_OBJECT }; int main() { MyObject obj; return 0; } #include "bla.moc" qbs-src-2.6.1/tests/auto/api/testdata/file-tagger/moc_cpp.qbs0000644000175100001660000000203014776170045023454 0ustar runnerdockerimport qbs.TextFile import qbs.FileInfo Project { Product { type: "application" consoleApplication: true name: "moc_cpp" Depends { name: "Qt.core" } Group { files: 'bla.txt' fileTags: ['text'] } } Rule { inputs: ['text'] Artifact { fileTags: ['cpp'] filePath: input.baseName + '.cpp' } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = function () { var file = new TextFile(input.filePath, TextFile.ReadOnly); var text = file.readAll(); file.close(); file = new TextFile(output.filePath, TextFile.WriteOnly); file.truncate(); file.write(text); file.close(); } cmd.description = 'generating ' + FileInfo.fileName(output.filePath); cmd.highlight = 'codegen'; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/disabled-project/0000755000175100001660000000000014776170045022357 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/disabled-project/disabled-project.qbs0000644000175100001660000000015114776170045026276 0ustar runnerdockerimport qbs.File Project { condition: File.exists("blubb"); references: "blubb/nosuchfile.qbs" } qbs-src-2.6.1/tests/auto/api/testdata/renamed-qbs-source-file/0000755000175100001660000000000014776170045023555 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/renamed-qbs-source-file/renamed-qbs-source-file.qbs0000644000175100001660000000025114776170045030673 0ustar runnerdockerProject { references: "the-product/the-prodduct.qbs" Product { Group { files: "the-product/*.qbs" fileTags: [] } } } qbs-src-2.6.1/tests/auto/api/testdata/renamed-qbs-source-file/the-product/0000755000175100001660000000000014776170045026013 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/renamed-qbs-source-file/the-product/the-prodduct.qbs0000644000175100001660000000001414776170045031117 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/api/testdata/app-without-sources/0000755000175100001660000000000014776170045023106 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs0000644000175100001660000000146314776170045027563 0ustar runnerdockerProject { StaticLibrary { name: "a" Depends { name: "cpp" } files: [ "a.c", ] } StaticLibrary { name: "b" Depends { name: "a" } Depends { name: "cpp" } files: [ "b.c", ] } CppApplication { name: "appWithoutSources" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } // HACK: cpp.entryPoint currently not working 100% with gcc Properties { condition: qbs.toolchain.includes("msvc") cpp.entryPoint: "main" cpp.dynamicLibraries: ["ucrt", "kernel32"] } cpp.entryPoint: undefined Depends { name: "a" } Depends { name: "b" } } } qbs-src-2.6.1/tests/auto/api/testdata/app-without-sources/b.c0000644000175100001660000000246214776170045023477 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int foo(); // defined in a.cpp int main() { return foo(); } qbs-src-2.6.1/tests/auto/api/testdata/app-without-sources/a.c0000644000175100001660000000236414776170045023477 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int foo() { return 42; } qbs-src-2.6.1/tests/auto/api/testdata/disabled_install_group/0000755000175100001660000000000014776170045023655 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/disabled_install_group/disabled_install_group.qbs0000644000175100001660000000026014776170045031073 0ustar runnerdockerCppApplication { consoleApplication: true files: "main.cpp" Group { condition: false qbs.install: true fileTagsFilter: product.type } } qbs-src-2.6.1/tests/auto/api/testdata/disabled_install_group/main.cpp0000644000175100001660000000235214776170045025307 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/api/testdata/disabled-product/0000755000175100001660000000000014776170045022371 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/disabled-product/main.cpp0000644000175100001660000000002314776170045024014 0ustar runnerdockerthiswillnotcompile qbs-src-2.6.1/tests/auto/api/testdata/disabled-product/disabled-product.qbs0000644000175100001660000000023514776170045026325 0ustar runnerdockerCppApplication { condition: false files: "main.cpp" Group { condition: qbs.targetOS.includes("stuff") qbs.install: false } } qbs-src-2.6.1/tests/auto/api/testdata/buildgraph-info/0000755000175100001660000000000014776170045022216 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/buildgraph-info/buildgraph-info.qbs0000644000175100001660000000005314776170045025775 0ustar runnerdockerProduct { qbs.shellPath: "/bin/bash" } qbs-src-2.6.1/tests/auto/api/testdata/source-file-in-build-dir/0000755000175100001660000000000014776170045023636 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/source-file-in-build-dir/file.cpp0000644000175100001660000000235214776170045025263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/api/testdata/source-file-in-build-dir/source-file-in-build-dir.qbs0000644000175100001660000000112714776170045031040 0ustar runnerdockerimport qbs.TextFile CppApplication { name: "theProduct" type: base.concat(["dummy"]) Rule { multiplex: true Artifact { filePath: "generated.cpp" fileTags: ["dummy"] } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return [cmd]; } } Group { name: "the group" files: "**/*.cpp" } } qbs-src-2.6.1/tests/auto/api/testdata/simple-probe/0000755000175100001660000000000014776170045021542 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/simple-probe/simple-probe.qbs0000644000175100001660000000135114776170045024647 0ustar runnerdockerimport qbs.Probes CppApplication { Probe { id: probe1 property string someString configure: { someString = "one"; found = true; } } Probe { id: probe2 configure: { found = false; } } type: ["application"] name: "MyApp" 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 true } property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/api/testdata/simple-probe/main.cpp0000644000175100001660000000236414776170045023177 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/0000755000175100001660000000000014776170045022010 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-within-project/0000755000175100001660000000000014776170045025550 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs0000644000175100001660000000241114776170045032015 0ustar runnerdockerimport qbs.Host Project { CppApplication { name: "thetool" consoleApplication: true files: "main.cpp" property bool skip: { var result = qbs.targetPlatform !== Host.platform(); if (result) console.info("Skip this test"); return result; } install: true installDir: "" qbs.installPrefix: "" Group { fileTagsFilter: ["application"] fileTags: ["thetool.thetool"] } Export { Depends { name: "cpp" } Rule { multiplex: true explicitlyDependsOnFromDependencies: ["thetool.thetool"] Artifact { filePath: "tool-output.txt" fileTags: ["thetool.output"] } prepare: { var cmd = new Command(explicitlyDependsOn["thetool.thetool"][0].filePath, output.filePath); cmd.description = "running the tool"; return [cmd]; } } } } Product { name: "user-in-project" type: ["thetool.output"] Depends { name: "thetool" } } } qbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-within-project/tool-input.txt0000644000175100001660000000000014776170045030411 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-within-project/main.cpp0000644000175100001660000000026714776170045027205 0ustar runnerdocker#include #include int main(int argc, char *argv[]) { assert(argc == 2); std::ofstream file(argv[1]); assert(file.is_open()); file << "content"; } qbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-outside-project/0000755000175100001660000000000014776170045025722 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-outside-project/use-outside-project.qbs0000644000175100001660000000015214776170045032341 0ustar runnerdockerProduct { name: "user-outside-project" type: ["thetool.output"] Depends { name: "thetool" } } qbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/0000755000175100001660000000000014776170045027372 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/0000755000175100001660000000000014776170045031050 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs0000644000175100001660000000144414776170045033240 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Module { Depends { name: "cpp" } Group { name: "thetool binary" files: FileInfo.cleanPath(FileInfo.joinPaths(path, "..", "..", "thetool" + (Host.os().includes("windows") ? ".exe" : ""))); fileTags: ["thetool.thetool"] filesAreTargets: true } Rule { multiplex: true explicitlyDependsOnFromDependencies: ["thetool.thetool"] Artifact { filePath: "tool-output.txt" fileTags: ["thetool.output"] } prepare: { var cmd = new Command(explicitlyDependsOn["thetool.thetool"][0].filePath, output.filePath); cmd.description = "running the tool"; return [cmd]; } } } qbs-src-2.6.1/tests/auto/api/testdata/run-disabled-product/0000755000175100001660000000000014776170045023173 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/run-disabled-product/run-disabled-product.qbs0000644000175100001660000000007014776170045027726 0ustar runnerdockerCppApplication { name: "app" condition: false } qbs-src-2.6.1/tests/auto/api/testdata/missing-source-file/0000755000175100001660000000000014776170045023030 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/missing-source-file/file1.txt0000644000175100001660000000000014776170045024557 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/missing-source-file/missing-source-file.qbs0000644000175100001660000000013614776170045027423 0ustar runnerdockerProduct { files: [ "file1.txt", "file2.txt", "file3.txt", ] } qbs-src-2.6.1/tests/auto/api/testdata/missing-source-file/file3.txt0000644000175100001660000000000014776170045024561 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/missing-source-file/file2.txt.missing0000644000175100001660000000000014776170045026230 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rc/0000755000175100001660000000000014776170045017550 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rc/subdir/0000755000175100001660000000000014776170045021040 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rc/subdir/rc-include.h0000644000175100001660000000000014776170045023224 0ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rc/rc.qbs0000644000175100001660000000032014776170045020656 0ustar runnerdockerApplication { type: "application" consoleApplication: true name: "rctest" Depends { name: 'cpp' } cpp.includePaths: "subdir" files: [ "main.cpp", "test.rc" ] } qbs-src-2.6.1/tests/auto/api/testdata/rc/main.cpp0000644000175100001660000000237014776170045021202 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/api/testdata/rc/test.rc0000644000175100001660000000062114776170045021054 0ustar runnerdocker#define IDR_VERSION1 1 #include IDR_VERSION1 VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEOS 0x00000004 FILETYPE 0x00000000 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "FFFF0000" BEGIN VALUE "FileVersion", "1.0.0.0\0" VALUE "ProductVersion", "1.0.0.0\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0xFFFF, 0x0000 END END qbs-src-2.6.1/tests/auto/api/testdata/same-base-name/0000755000175100001660000000000014776170045021717 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/same-base-name/same-base-name.qbs0000644000175100001660000000136514776170045025206 0ustar runnerdockerProject { CppApplication { type: "application" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "basenamelib" } name: "basename" files: "main.c" } StaticLibrary { Depends { name: "cpp" } name: "basenamelib" files: [ "lib.c", "lib.cpp" ] Group { condition: qbs.targetOS.includes("darwin") files: [ "lib.m", "lib.mm" ] } Export { Depends { name: "cpp" } cpp.frameworks: qbs.targetOS.includes("darwin") ? "Foundation" : undefined } } } qbs-src-2.6.1/tests/auto/api/testdata/same-base-name/lib.c0000644000175100001660000000247314776170045022637 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include extern void printHelloC() { printf("Hello from C in " __FILE__ "\n"); } qbs-src-2.6.1/tests/auto/api/testdata/same-base-name/lib.m0000644000175100001660000000016714776170045022647 0ustar runnerdocker#import extern void printHelloObjc() { NSLog(@"Hello from Objective-C in " __FILE__); } qbs-src-2.6.1/tests/auto/api/testdata/same-base-name/lib.mm0000644000175100001660000000027214776170045023021 0ustar runnerdocker#include #import extern "C" void printHelloObjcpp() { NSLog(@"Hello from Objective-C++..."); std::cout << "...in " __FILE__ << std::endl; } qbs-src-2.6.1/tests/auto/api/testdata/same-base-name/main.c0000644000175100001660000000276614776170045023022 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ extern void printHelloC(); extern void printHelloCpp(); #ifdef __APPLE__ extern void printHelloObjc(); extern void printHelloObjcpp(); #endif int main() { printHelloC(); printHelloCpp(); #ifdef __APPLE__ printHelloObjc(); printHelloObjcpp(); #endif return 0; } qbs-src-2.6.1/tests/auto/api/testdata/same-base-name/lib.cpp0000644000175100001660000000252414776170045023174 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include extern "C" void printHelloCpp() { std::cout << "Hello from C++ in " << __FILE__ << std::endl; } qbs-src-2.6.1/tests/auto/api/testdata/nonexistingprojectproperties/0000755000175100001660000000000014776170045025215 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/nonexistingprojectproperties/nonexistingprojectproperties.qbs0000644000175100001660000000001414776170045033770 0ustar runnerdockerProject { } qbs-src-2.6.1/tests/auto/api/testdata/nonexistingprojectproperties/invalidaccessfromproduct.qbs0000644000175100001660000000005414776170045033020 0ustar runnerdockerProject { Product { type: project.blubb } } qbs-src-2.6.1/tests/auto/api/testdata/codegen/0000755000175100001660000000000014776170045020550 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/codegen/codegen.qbs0000644000175100001660000000537414776170045022674 0ustar runnerdockerimport qbs.FileInfo Project { property string name: 'codegen' property string osSpecificName: name.toUpperCase() + '_' + qbs.targetPlatform.toUpperCase() Product { type: 'application' consoleApplication: true name: project.name property var replacements: ({ NUMBERTYPE: "int", STRINGTYPE: "char **", FUNCTIONNAME: "main" }) property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Group { files: 'foo.txt' fileTags: ['text'] } Depends { name: 'cpp' } Depends { name: 'Qt.core' } } Rule { inputs: ['text'] Artifact { fileTags: ['cpp'] filePath: input.baseName + '.cpp' } prepare: { function expandMacros(str, table) { var rex = /\$\w+/; var m = rex.exec(str); while (m != null) { str = str.substr(0, m.index) + table[m[0].substr(1)] + str.substr(m.index + m[0].length); m = rex.exec(str); } return str; } // check whether multipart module name translation is working var actual = product.moduleProperty("Qt.core", "mocName"); if (!actual || !actual.includes("moc")) throw "multipart module name translation is broken"; // check whether we can access project properties here var expected = "CODEGEN_" + product.moduleProperty("qbs", "targetPlatform").toUpperCase(); if (project.osSpecificName !== expected) throw "Wrong project property value: " + project.osSpecificName + "\nexpected: " + expected; var code = '$NUMBERTYPE $FUNCTIONNAME($NUMBERTYPE, $STRINGTYPE) { return 0; }'; code = expandMacros(code, product.replacements); var args = ['echo ' + code + '>' + output.filePath] var cmd if (product.moduleProperty("qbs", "hostOS").includes('windows')) { cmd = new Command(product.qbs.windowsShellPath, ['/C'].concat(args)); } else { args[0] = args[0].replace(/\(/g, '\\(') args[0] = args[0].replace(/\)/g, '\\)') args[0] = args[0].replace(/;/g, '\\;') cmd = new Command(product.qbs.shellPath, ['-c'].concat(args)) } cmd.description = 'generating ' + FileInfo.fileName(output.filePath); cmd.highlight = 'codegen'; return cmd; } } } qbs-src-2.6.1/tests/auto/api/testdata/codegen/foo.txt0000644000175100001660000000001414776170045022067 0ustar runnerdockerHello World qbs-src-2.6.1/tests/auto/api/testdata/productNameWithDots/0000755000175100001660000000000014776170045023113 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/productNameWithDots/productNameWithDots.qbs0000644000175100001660000000055714776170045027600 0ustar runnerdockerProject { CppApplication { name: "myapp" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "foo.bar.bla" } files: ["app.cpp"] } StaticLibrary { Depends { name: "cpp" } name: "foo.bar.bla" files: ["lib.cpp"] } } qbs-src-2.6.1/tests/auto/api/testdata/productNameWithDots/app.cpp0000644000175100001660000000236414776170045024404 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/api/testdata/productNameWithDots/lib.cpp0000644000175100001660000000235114776170045024366 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void foo() {} qbs-src-2.6.1/tests/auto/api/testdata/new-pattern-match/0000755000175100001660000000000014776170045022502 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/new-pattern-match/new-pattern-match.qbs0000644000175100001660000000003714776170045026547 0ustar runnerdockerProduct { files: "*.txt" } qbs-src-2.6.1/tests/auto/api/testdata/rename-target-artifact/0000755000175100001660000000000014776170045023472 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rename-target-artifact/rename.qbs0000644000175100001660000000077514776170045025461 0ustar runnerdockerProject { CppApplication { Depends { name: "TheLib" } cpp.defines: "MY_EXPORT=" qbs.buildVariant: "release" files: "main.cpp" } DynamicLibrary { name: "TheLib" targetName: "the_lib" Depends { name: "cpp" } cpp.defines: "MY_EXPORT=DLL_EXPORT" qbs.buildVariant: "release" files: "lib.cpp" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/api/testdata/rename-target-artifact/lib.cpp0000644000175100001660000000241514776170045024746 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" MY_EXPORT void f() { } qbs-src-2.6.1/tests/auto/api/testdata/rename-target-artifact/main.cpp0000644000175100001660000000237614776170045025132 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f(); int main() { f(); } qbs-src-2.6.1/tests/auto/api/testdata/properties-blocks/0000755000175100001660000000000014776170045022613 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/properties-blocks/properties-blocks.qbs0000644000175100001660000000100514776170045026765 0ustar runnerdockerProduct { Depends { name: 'cpp' } Properties { type: 'application' consoleApplication: true name: 'HelloWorld' } Properties { condition: name == 'HelloWorld' cpp.defines: ['DEFINE_IN_PROPERTIES'] } Properties { condition: qbs.targetOS.includes("weird") cpp.staticLibraries: "abc" } Group { cpp.defines: outer.concat(['HAVE_MAIN_CPP', cpp.debugInformation ? '_DEBUG' : '_RELEASE']) files: ['main.cpp'] } } qbs-src-2.6.1/tests/auto/api/testdata/properties-blocks/main.cpp0000644000175100001660000000301714776170045024244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #ifndef HAVE_MAIN_CPP # error missing define HAVE_MAIN_CPP #endif #ifndef DEFINE_IN_PROPERTIES # error missing define DEFINE_IN_PROPERTIES #endif int main() { #ifdef _DEBUG std::puts("Hello World! (debug version)"); #else std::puts("Hello World! (release version)"); #endif } qbs-src-2.6.1/tests/auto/api/testdata/project-with-probe-and-profile-item/0000755000175100001660000000000014776170045026022 5ustar runnerdocker././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/api/testdata/project-with-probe-and-profile-item/project-with-probe-and-profile-item.qbsqbs-src-2.6.1/tests/auto/api/testdata/project-with-probe-and-profile-item/project-with-probe-and-pro0000644000175100001660000000051714776170045033032 0ustar runnerdockerProject { property bool probesEvaluated: probe.found Probe { id: probe configure: { found = true; } } Profile { name: "the-profile" cpp.includePaths: { if (!probesEvaluated) throw "project-level probes not evaluated"; } } } qbs-src-2.6.1/tests/auto/api/testdata/type-change/0000755000175100001660000000000014776170045021350 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/type-change/type-change.qbs0000644000175100001660000000013114776170045024256 0ustar runnerdockerProduct { files: "main.cpp" Depends { name: "cpp" } // type: "application" } qbs-src-2.6.1/tests/auto/api/testdata/type-change/main.cpp0000644000175100001660000000235114776170045023001 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/api/testdata/rename-product/0000755000175100001660000000000014776170045022071 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/rename-product/rename.qbs0000644000175100001660000000062714776170045024054 0ustar runnerdockerProject { CppApplication { Depends { name: "TheLib" } cpp.defines: "MY_EXPORT=" files: "main.cpp" } DynamicLibrary { name: "TheLib" Depends { name: "cpp" } cpp.defines: "MY_EXPORT=DLL_EXPORT" files: "lib.cpp" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/api/testdata/rename-product/lib.cpp0000644000175100001660000000241514776170045023345 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" MY_EXPORT void f() { } qbs-src-2.6.1/tests/auto/api/testdata/rename-product/main.cpp0000644000175100001660000000237614776170045023531 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f(); int main() { f(); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/0000755000175100001660000000000014776170045022375 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/lib4.cpp0000644000175100001660000000262614776170045023741 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib4.h" TestMe::TestMe() { } void TestMe::hello1() const { std::puts("lib4 says hello!"); } void TestMe::hello2Impl() const { std::puts("lib4 says hello inline!"); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/lib4.h0000644000175100001660000000307414776170045023404 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LIB4_H #define LIB4_H #include "../dllexport.h" #include #ifdef TEST_LIB # define LIB_EXPORT DLL_EXPORT #else # define LIB_EXPORT DLL_IMPORT #endif class LIB_EXPORT TestMe { public: TestMe(); void hello1() const; inline void hello2() const { hello2Impl(); } private: void hello2Impl() const; }; #endif // LIB4_H qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/link-dynamiclibs.qbs0000644000175100001660000000332514776170045026340 0ustar runnerdockerProject { Application { name : "HelloWorld" property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } Group { files : [ "main.cpp" ] } Depends { name: "cpp" } Depends { name: "lib1" } Depends { name: "lib4" } } DynamicLibrary { name : "lib1" Group { files : [ "lib1.cpp" ] } Depends { name: "cpp" } Depends { name: "lib2" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } DynamicLibrary { name : "lib2" cpp.visibility: 'default' Group { files : [ "lib2.cpp" ] } Depends { name: "cpp" } Depends { name: "lib3" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } DynamicLibrary { name : "lib3" cpp.visibility: 'hidden' Group { files : [ "lib3.cpp" ] } Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } DynamicLibrary { name : "lib4" cpp.visibility: 'hiddenInlines' cpp.defines: "TEST_LIB" Group { files : [ "lib4.h", "lib4.cpp" ] } Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } } } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/lib1.cpp0000644000175100001660000000261214776170045023731 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_IMPORT void lib2_hello(); DLL_EXPORT int lib1_hello() { std::puts("lib1 says hello!"); lib2_hello(); return 0; } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/lib2.cpp0000644000175100001660000000257614776170045023743 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_IMPORT void lib3_hello(); DLL_EXPORT void lib2_hello() { std::puts("lib2 says hello!"); lib3_hello(); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/main.cpp0000644000175100001660000000265014776170045024030 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include DLL_IMPORT int lib1_hello(); int main() { std::puts("application says hello!"); TestMe test; test.hello1(); test.hello2(); return lib1_hello(); } qbs-src-2.6.1/tests/auto/api/testdata/link-dynamiclibs/lib3.cpp0000644000175100001660000000265614776170045023743 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #include DLL_EXPORT void lib3_hello() { std::puts("lib3 says hello!"); } DLL_EXPORT char* lib3_greeting() { static char greeting[] = "hello"; return greeting; } qbs-src-2.6.1/tests/auto/api/testdata/QBS-728/0000755000175100001660000000000014776170045020107 5ustar runnerdockerqbs-src-2.6.1/tests/auto/api/testdata/QBS-728/QBS-728.qbs0000644000175100001660000000026214776170045021561 0ustar runnerdockerProduct { property bool isBlubbOS: qbs.targetOS.includes("blubb-OS") qbs.profiles: isBlubbOS ? ["blubb-profile"] : [project.profile] qbs.architecture: "blubb-arch" } qbs-src-2.6.1/tests/auto/api/CMakeLists.txt0000644000175100001660000000044214776170045020073 0ustar runnerdockeradd_qbs_test(api DEFINES "QBS_RELATIVE_LIBEXEC_PATH=\"${QBS_RELATIVE_LIBEXEC_PATH}\"" "QBS_RELATIVE_SEARCH_PATH=\"${QBS_RELATIVE_SEARCH_PATH}\"" "QBS_RELATIVE_PLUGINS_PATH=\"${QBS_RELATIVE_PLUGINS_PATH}\"" SOURCES tst_api.cpp tst_api.h ) qbs-src-2.6.1/tests/auto/api/tst_api.cpp0000644000175100001660000043626014776170045017515 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_api.h" #include "../shared.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERIFY_NO_ERROR(errorInfo) \ QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())) #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(m_workingDataDir) class LogSink: public qbs::ILogSink { public: QString output; void doPrintWarning(const qbs::ErrorInfo &error) override { qDebug("%s", qPrintable(error.toString())); warnings.push_back(error); } void doPrintError(const qbs::ErrorInfo &error) override { qDebug("%s", qPrintable(error.toString())); errors.push_back(error); } void doPrintMessage(qbs::LoggerLevel, const QString &message, const QString &) override { output += '\n' + message; } QList warnings; QList errors; }; class BuildDescriptionReceiver : public QObject { Q_OBJECT public: QString descriptions; QStringList descriptionLines; void handleDescription(const QString &, const QString &description) { descriptions += description; descriptionLines << description; } }; class ProcessResultReceiver : public QObject { Q_OBJECT public: QString output; std::vector results; void handleProcessResult(const qbs::ProcessResult &result) { results.push_back(result); output += result.stdErr().join(QLatin1Char('\n')); output += result.stdOut().join(QLatin1Char('\n')); } }; class TaskReceiver : public QObject { Q_OBJECT public: QString taskDescriptions; void handleTaskStart(const QString &task) { taskDescriptions += task; } }; static void removeBuildDir(const qbs::SetupProjectParameters ¶ms) { QString message; const QString dir = params.buildRoot() + '/' + params.configurationName(); if (!qbs::Internal::removeDirectoryWithContents(dir, &message)) qFatal("Could not remove build dir: %s", qPrintable(message)); } static bool waitForFinished(qbs::AbstractJob *job, int timeout = 0) { if (job->state() == qbs::AbstractJob::StateFinished) return true; QEventLoop loop; QObject::connect(job, &qbs::AbstractJob::finished, &loop, &QEventLoop::quit); if (timeout > 0) { QTimer timer; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); timer.setSingleShot(true); timer.start(timeout); loop.exec(); return timer.isActive(); // Timer ended the loop <=> job did not finish. } loop.exec(); return true; } TestApi::TestApi() : m_logSink(new LogSink) , m_sourceDataDir(testDataSourceDir(SRCDIR "/testdata")) , m_workingDataDir(testWorkDir(QStringLiteral("api"))) { } TestApi::~TestApi() { delete m_logSink; } void TestApi::initTestCase() { QString errorMessage; qbs::Internal::removeDirectoryWithContents(m_workingDataDir, &errorMessage); QVERIFY2(qbs::Internal::copyFileRecursion(m_sourceDataDir, m_workingDataDir, false, true, &errorMessage), qPrintable(errorMessage)); QVERIFY(copyDllExportHeader(m_sourceDataDir, m_workingDataDir)); } void TestApi::init() { m_logSink->warnings.clear(); m_logSink->errors.clear(); m_logSink->setLogLevel(qbs::LoggerInfo); } void TestApi::addQObjectMacroToCppFile() { BuildDescriptionReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("add-qobject-macro-to-cpp-file", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(!receiver.descriptions.contains("moc"), qPrintable(receiver.descriptions)); receiver.descriptions.clear(); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("object.cpp", "// ", ""); errorInfo = doBuildProject("add-qobject-macro-to-cpp-file", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.descriptions.contains("moc"), qPrintable(receiver.descriptions)); } static bool isAboutUndefinedSymbols(const QString &_message) { const QString message = _message.toLower(); return message.contains("undefined") || message.contains("unresolved"); } void TestApi::addedFilePersistent() { // On the initial run, linking will fail. const QString relProjectFilePath = "added-file-persistent"; ProcessResultReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject(relProjectFilePath, nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable((receiver.output))); receiver.output.clear(); // Add a file. qbs must schedule it for rule application on the next build. WAIT_FOR_NEW_TIMESTAMP(); const qbs::SetupProjectParameters params = defaultSetupParameters(relProjectFilePath); REPLACE_IN_FILE(params.projectFilePath(), "/* 'file.cpp' */", "'file.cpp'"); std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); setupJob.reset(nullptr); // Remove the file again. qbs must unschedule the rule application again. // Consequently, the linking step must fail as in the initial run. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(params.projectFilePath(), "'file.cpp'", "/* 'file.cpp' */"); errorInfo = doBuildProject(relProjectFilePath, nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable((receiver.output))); // Add the file again. qbs must schedule it for rule application on the next build. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(params.projectFilePath(), "/* 'file.cpp' */", "'file.cpp'"); setupJob.reset(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); setupJob.reset(nullptr); // qbs must remember that a file was scheduled for rule application. The build must then // succeed, as now all necessary symbols are linked in. errorInfo = doBuildProject(relProjectFilePath); VERIFY_NO_ERROR(errorInfo); } void TestApi::baseProperties() { const qbs::ErrorInfo errorInfo = doBuildProject("base-properties/prj.qbs"); VERIFY_NO_ERROR(errorInfo); } void TestApi::buildGraphInfo() { SettingsPtr s = settings(); qbs::Internal::TemporaryProfile p("bgInfoProfile", s.get()); p.p.setValue("qbs.targetPlatform", "xenix"); qbs::SetupProjectParameters setupParams = defaultSetupParameters("buildgraph-info"); setupParams.setTopLevelProfile(p.p.name()); setupParams.setOverriddenValues({std::make_pair("qbs.architecture", "arm")}); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const QString bgFilePath = setupParams.buildRoot() + QLatin1Char('/') + relativeBuildGraphFilePath(); QVERIFY2(QFileInfo::exists(bgFilePath), qPrintable(bgFilePath)); qbs::Project::BuildGraphInfo bgInfo = qbs::Project::getBuildGraphInfo(bgFilePath, QStringList()); QVERIFY(bgInfo.error.hasError()); // Build graph is still locked. setupJob.reset(nullptr); const QStringList requestedProperties({"qbs.architecture", "qbs.shellPath", "qbs.targetPlatform"}); bgInfo = qbs::Project::getBuildGraphInfo(bgFilePath, requestedProperties); QVERIFY2(!bgInfo.error.hasError(), qPrintable(bgInfo.error.toString())); QCOMPARE(bgFilePath, bgInfo.bgFilePath); QCOMPARE(bgInfo.profileData.size(), 1); QCOMPARE(bgInfo.profileData.value(p.p.name()).toMap().size(), 1); QCOMPARE(bgInfo.profileData.value(p.p.name()).toMap().value("qbs").toMap().value( "targetPlatform"), p.p.value("qbs.targetPlatform")); QCOMPARE(bgInfo.overriddenProperties, setupParams.overriddenValues()); QCOMPARE(bgInfo.requestedProperties.size(), requestedProperties.size()); QCOMPARE(bgInfo.requestedProperties.value("qbs.architecture").toString(), QString("arm")); QCOMPARE(bgInfo.requestedProperties.value("qbs.shellPath").toString(), QString("/bin/bash")); QCOMPARE(bgInfo.requestedProperties.value("qbs.targetPlatform").toString(), QString("xenix")); } void TestApi::buildErrorCodeLocation() { const qbs::ErrorInfo errorInfo = doBuildProject("build-error-code-location/build-error-code-location.qbs"); QVERIFY(errorInfo.hasError()); const qbs::ErrorItem errorItem = errorInfo.items().front(); QCOMPARE(errorItem.description(), QString("Rule.outputArtifacts must return an array of objects.")); const qbs::CodeLocation errorLoc = errorItem.codeLocation(); QCOMPARE(QFileInfo(errorLoc.filePath()).fileName(), QString("build-error-code-location.qbs")); QCOMPARE(errorLoc.line(), 7); QCOMPARE(errorLoc.column(), 26); } void TestApi::buildGraphLocking() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("buildgraph-locking"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const qbs::Project project = setupJob->project(); Q_UNUSED(project); // Case 1: Setting up a competing project from scratch. setupJob.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY2(setupJob->error().toString().contains("lock"), qPrintable(setupJob->error().toString())); // Case 2: Setting up a non-competing project and then making it competing. qbs::SetupProjectParameters setupParams2 = setupParams; setupParams2.setBuildRoot(setupParams.buildRoot() + "/2"); setupJob.reset(qbs::Project().setupProject(setupParams2, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const QString buildDirName = relativeBuildDir(setupParams2.configurationName()); const QString lockFile = setupParams2.buildRoot() + '/' + buildDirName + '/' + buildDirName + ".bg.lock"; QVERIFY2(QFileInfo(lockFile).isFile(), qPrintable(lockFile)); qbs::Project project2 = setupJob->project(); QVERIFY(project2.isValid()); setupJob.reset(project2.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY2(setupJob->error().toString().contains("lock"), qPrintable(setupJob->error().toString())); QVERIFY2(QFileInfo(lockFile).isFile(), qPrintable(lockFile)); // Case 3: Changing the build directory of an existing project to something non-competing. qbs::SetupProjectParameters setupParams3 = setupParams2; setupParams3.setBuildRoot(setupParams.buildRoot() + "/3"); setupJob.reset(qbs::Project().setupProject(setupParams3, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); project2 = qbs::Project(); QVERIFY2(!QFileInfo(lockFile).exists(), qPrintable(lockFile)); const QString newLockFile = setupParams3.buildRoot() + '/' + buildDirName + '/' + buildDirName + ".bg.lock"; QVERIFY2(QFileInfo(newLockFile).isFile(), qPrintable(newLockFile)); qbs::Project project3 = setupJob->project(); QVERIFY(project3.isValid()); // Case 4: Changing the build directory again, but cancelling the job. setupJob.reset(project3.setupProject(setupParams2, m_logSink, nullptr)); QThread::sleep(1); setupJob->cancel(); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY2(!QFileInfo(lockFile).exists(), qPrintable(lockFile)); QVERIFY2(QFileInfo(newLockFile).isFile(), qPrintable(newLockFile)); setupJob.reset(nullptr); project3 = qbs::Project(); QVERIFY2(!QFileInfo(newLockFile).exists(), qPrintable(newLockFile)); } void TestApi::buildProject() { QFETCH(QString, projectSubDir); QFETCH(QString, productNameOrFilePath); const QString projectFilePath = projectSubDir + QLatin1Char('/') + projectSubDir + QLatin1String(".qbs"); qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath); removeBuildDir(params); ProcessResultReceiver resultReceiver; qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath, nullptr, &resultReceiver); if (resultReceiver.output.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); VERIFY_NO_ERROR(errorInfo); QVERIFY(regularFileExists(relativeBuildGraphFilePath())); const QString productFilePath = getProductFilePath(productNameOrFilePath); if (!productFilePath.isEmpty()) { QVERIFY2(regularFileExists(productFilePath), qPrintable(productFilePath)); QVERIFY2(QFile::remove(productFilePath), qPrintable(productFilePath)); } WAIT_FOR_NEW_TIMESTAMP(); qbs::BuildOptions options; options.setForceTimestampCheck(true); errorInfo = doBuildProject(projectFilePath, nullptr, nullptr, nullptr, options); VERIFY_NO_ERROR(errorInfo); if (!productFilePath.isEmpty()) QVERIFY2(regularFileExists(productFilePath), qPrintable(productFilePath)); QVERIFY(regularFileExists(relativeBuildGraphFilePath())); } void TestApi::buildProject_data() { QTest::addColumn("projectSubDir"); QTest::addColumn("productNameOrFilePath"); QTest::newRow("BPs in Sources") << QString("build-properties-source") << QString("HelloWorld"); QTest::newRow("code generator") << QString("codegen") << QString("codegen"); QTest::newRow("link static libs") << QString("link-static-lib") << QString("HelloWorld"); QTest::newRow("link staticlib dynamiclib") << QString("link-staticlib-dynamiclib") << QString("app"); QTest::newRow("precompiled header new") << QString("precompiled-header-new") << QString("MyApp"); QTest::newRow("precompiled header dynamic") << QString("precompiled-header-dynamic") << QString("MyApp"); QTest::newRow("lots of dots") << QString("lots-of-dots") << QString("lots.of.dots"); QTest::newRow("Qt5 plugin") << QString("qt5-plugin") << relativeProductBuildDir("echoplugin") + '/' + qbs::Internal::HostOsInfo::dynamicLibraryName("echoplugin"); QTest::newRow("Q_OBJECT in source") << QString("moc-cpp") << QString("moc_cpp"); QTest::newRow("Q_OBJECT in header") << QString("moc-hpp") << QString("moc_hpp"); QTest::newRow("Q_OBJECT in header, moc_XXX.cpp included") << QString("moc-hpp-included") << QString("moc_hpp_included"); QTest::newRow("app and lib with same source file") << QString("lib-same-source") << QString("HelloWorldApp"); QTest::newRow("source files with the same base name but different extensions") << QString("same-base-name") << QString("basename"); QTest::newRow("simple probes") << QString("simple-probe") << QString("MyApp"); QTest::newRow("application without sources") << QString("app-without-sources") << QString("appWithoutSources"); QTest::newRow("productNameWithDots") << QString("productNameWithDots") << QString("myapp"); QTest::newRow("only default properties") << QString("two-default-property-values") << relativeProductBuildDir("two-default-property-values") + "/set"; QTest::newRow("Export item with Group") << QString("export-item-with-group") << QString("app"); QTest::newRow("QBS-728") << QString("QBS-728") << QString(); } void TestApi::buildProjectDryRun() { QFETCH(QString, projectSubDir); QFETCH(QString, productNameOrFilePath); const QString projectFilePath = projectSubDir + QLatin1Char('/') + projectSubDir + QLatin1String(".qbs"); qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath); removeBuildDir(params); qbs::BuildOptions options; options.setDryRun(true); const qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath, nullptr, nullptr, nullptr, options); VERIFY_NO_ERROR(errorInfo); QVERIFY2(!QFileInfo::exists(relativeBuildDir()), qPrintable(QDir(relativeBuildDir()) .entryList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::System).join(", "))); } void TestApi::buildProjectDryRun_data() { return buildProject_data(); } void TestApi::buildSingleFile() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("build-single-file"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); qbs::BuildOptions options; options.setFilesToConsider(QStringList(setupParams.buildRoot() + "/compiled.cpp")); options.setActiveFileTags(QStringList("obj")); m_logSink->setLogLevel(qbs::LoggerMaxLevel); std::unique_ptr buildJob(project.buildAllProducts(options)); BuildDescriptionReceiver receiver; ProcessResultReceiver resultReceiver; connect(buildJob.get(), &qbs::BuildJob::reportProcessResult, &resultReceiver, &ProcessResultReceiver::handleProcessResult); connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, &receiver, &BuildDescriptionReceiver::handleDescription); waitForFinished(buildJob.get()); if (resultReceiver.output.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QCOMPARE(receiver.descriptions.count("compiling"), 2); QCOMPARE(receiver.descriptions.count("precompiling"), 1); QVERIFY2(receiver.descriptions.contains("generating generated.h"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling compiled.cpp"), qPrintable(receiver.descriptions)); } void TestApi::canonicalToolchainList() { // All the known toolchain lists should be equal QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "clang", "llvm", "gcc"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "llvm", "gcc"})), QStringList({"clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang-cl", "msvc"})), QStringList({"clang-cl", "msvc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "gcc"})), QStringList({"llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw", "gcc"})), QStringList({"mingw", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc"})), QStringList({"gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"msvc"})), QStringList({"msvc"})); // Single names should canonicalize to the known lists QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang"})), QStringList({"clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang-cl"})), QStringList({"clang-cl", "msvc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm"})), QStringList({"llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw"})), QStringList({"mingw", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc"})), QStringList({"gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"msvc"})), QStringList({"msvc"})); // Missing some in the middle QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "llvm", "gcc"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "clang", "gcc"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "gcc"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "llvm"})), QStringList({"clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "gcc"})), QStringList({"clang", "llvm", "gcc"})); // Sorted wrong, missing some in the middle QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm", "clang", "xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "gcc", "llvm", "xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "clang", "xcode", "gcc"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm", "clang"})), QStringList({"clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "clang", "xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm"})), QStringList({"llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "mingw"})), QStringList({"mingw", "gcc"})); // Duplicates QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm", "clang", "xcode", "xcode", "xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "gcc", "llvm", "clang", "xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "clang", "clang", "xcode", "xcode", "gcc"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "clang", "gcc", "llvm", "clang"})), QStringList({"clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "gcc", "clang", "gcc", "clang", "xcode"})), QStringList({"xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "gcc", "llvm", "llvm"})), QStringList({"llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "gcc", "gcc", "mingw"})), QStringList({"mingw", "gcc"})); // Custom insanity QCOMPARE(qbs::canonicalToolchain( QStringList({"crazy", "gcc", "llvm", "clang", "xcode", "insane"})), QStringList({"crazy", "insane", "xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain( QStringList({"crazy", "gcc", "llvm", "clang", "xcode", "insane", "crazy"})), QStringList({"crazy", "insane", "xcode", "clang", "llvm", "gcc"})); QCOMPARE(qbs::canonicalToolchain( QStringList({"crazy", "insane", "gcc", "trade", "llvm", "clang", "xcode", "insane", "mark", "crazy"})), QStringList({"crazy", "insane", "trade", "mark", "xcode", "clang", "llvm", "gcc"})); } void TestApi::checkOutputs() { QFETCH(bool, check); qbs::SetupProjectParameters params = defaultSetupParameters("/check-outputs"); qbs::BuildOptions options; options.setForceOutputCheck(check); removeBuildDir(params); qbs::ErrorInfo errorInfo = doBuildProject("/check-outputs", nullptr, nullptr, nullptr, options); if (check) QVERIFY(errorInfo.hasError()); else VERIFY_NO_ERROR(errorInfo); } void TestApi::checkOutputs_data() { QTest::addColumn("check"); QTest::newRow("checked outputs") << true; QTest::newRow("unchecked outputs") << false; } qbs::GroupData findGroup(const qbs::ProductData &product, const QString &name) { const auto groups = product.groups(); for (const qbs::GroupData &g : groups) { if (g.name() == name) return g; } return qbs::GroupData(); } static qbs::Project::ProductSelection defaultProducts() { return qbs::Project::ProductSelectionDefaultOnly; } void TestApi::changeContent() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-editing"); std::unique_ptr job; qbs::Project project; qbs::ProjectData projectData; qbs::ProductData product; const auto resolve = [&] { job.reset(project.setupProject(setupParams, m_logSink, 0)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project(); projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 1); product = projectData.allProducts().front(); }; resolve(); QVERIFY(product.groups().size() >= 5); // Error handling: Invalid product. qbs::ErrorInfo errorInfo = project.addGroup(qbs::ProductData(), "blubb"); QVERIFY(errorInfo.hasError()); QVERIFY(errorInfo.toString().contains("invalid")); // Error handling: Empty group name. errorInfo = project.addGroup(product, QString()); QVERIFY(errorInfo.hasError()); QVERIFY(errorInfo.toString().contains("empty")); WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.addGroup(product, "New Group 1"); VERIFY_NO_ERROR(errorInfo); errorInfo = project.addGroup(product, "New Group 2"); VERIFY_NO_ERROR(errorInfo); resolve(); QVERIFY(product.groups().size() >= 10); // Error handling: Group already inserted. errorInfo = project.addGroup(product, "New Group 1"); QVERIFY(errorInfo.hasError()); QVERIFY(errorInfo.toString().contains("already")); // Error handling: Add list of files with double entries. errorInfo = project.addFiles(product, qbs::GroupData(), QStringList() << "file.cpp" << "file.cpp"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("more than once"), qPrintable(errorInfo.toString())); // Add files to empty array literal. WAIT_FOR_NEW_TIMESTAMP(); qbs::GroupData group = findGroup(product, "New Group 1"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "file.h" << "file.cpp"); VERIFY_NO_ERROR(errorInfo); // Error handling: Add the same file again. resolve(); group = findGroup(product, "New Group 1"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "file.cpp"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("already"), qPrintable(errorInfo.toString())); // Remove one of the newly added files again. WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.removeFiles(product, group, QStringList("file.h")); VERIFY_NO_ERROR(errorInfo); // Error handling: Try to remove the same file again. resolve(); group = findGroup(product, "New Group 1"); QVERIFY(group.isValid()); errorInfo = project.removeFiles(product, group, QStringList() << "file.h"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("not known"), qPrintable(errorInfo.toString())); // Error handling: Try to remove a file from a complex list. group = findGroup(product, "Existing Group 2"); QVERIFY(group.isValid()); errorInfo = project.removeFiles(product, group, QStringList() << "existingfile2.txt"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString())); // Remove file from product's 'files' binding. WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.removeFiles(product, qbs::GroupData(), QStringList("main.cpp")); VERIFY_NO_ERROR(errorInfo); resolve(); // Add file to non-empty array literal. WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 1"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt"); VERIFY_NO_ERROR(errorInfo); resolve(); // Add files to list represented as a single string. WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.addFiles(product, qbs::GroupData(), QStringList() << "newfile2.txt"); VERIFY_NO_ERROR(errorInfo); resolve(); // Add files to list represented as an identifier. WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 2"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile3.txt"); VERIFY_NO_ERROR(errorInfo); resolve(); // Add files to list represented as a block of code (not yet implemented). group = findGroup(product, "Existing Group 3"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile4.txt"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString())); // Add file to group with directory prefix. WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 4"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "file.txt"); VERIFY_NO_ERROR(errorInfo); resolve(); // Error handling: Add file to group with non-directory prefix. group = findGroup(product, "Existing Group 5"); QVERIFY(group.isValid()); errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("prefix"), qPrintable(errorInfo.toString())); // Remove group. WAIT_FOR_NEW_TIMESTAMP(); group = findGroup(product, "Existing Group 5"); QVERIFY(group.isValid()); errorInfo = project.removeGroup(product, group); VERIFY_NO_ERROR(errorInfo); resolve(); // Error handling: Try to remove the same group again. errorInfo = project.removeGroup(product, group); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("does not exist"), qPrintable(errorInfo.toString())); // Add a file to a group where the file name is already matched by a wildcard. projectData = project.projectData(); QVERIFY(projectData.products().size() == 1); product = projectData.products().front(); group = findGroup(product, "Group with wildcards"); QVERIFY(group.isValid()); QFile newFile("koerper.klaus"); QVERIFY2(newFile.open(QIODevice::WriteOnly), qPrintable(newFile.errorString())); newFile.close(); errorInfo = project.addFiles(product, group, QStringList() << newFile.fileName()); VERIFY_NO_ERROR(errorInfo); resolve(); group = findGroup(product, "Group with wildcards"); QVERIFY(group.isValid()); QCOMPARE(group.sourceArtifactsFromWildcards().size(), 1); QCOMPARE(group.sourceArtifactsFromWildcards().front().filePath(), QFileInfo(newFile).absoluteFilePath()); // Error checking: Try to remove a file that originates from a wildcard pattern. projectData = project.projectData(); QVERIFY(projectData.products().size() == 1); product = projectData.products().front(); group = findGroup(product, "Other group with wildcards"); QVERIFY(group.isValid()); errorInfo = project.removeFiles(product, group, QStringList() << "test.wildcard"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("pattern"), qPrintable(errorInfo.toString())); // Check whether building will take the added and removed cpp files into account. // This must not be moved below the re-resolving test!!! qbs::BuildOptions buildOptions; buildOptions.setDryRun(true); BuildDescriptionReceiver rcvr; std::unique_ptr buildJob(project.buildAllProducts(buildOptions, defaultProducts(), this)); connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, &rcvr, &BuildDescriptionReceiver::handleDescription); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QVERIFY(rcvr.descriptions.contains("compiling file.cpp")); QVERIFY(!rcvr.descriptions.contains("compiling main.cpp")); // Error handling: Try to change the project during a build. buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this)); errorInfo = project.addGroup(projectData.products().front(), "blubb"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("in progress"), qPrintable(errorInfo.toString())); waitForFinished(buildJob.get()); errorInfo = project.addGroup(projectData.products().front(), "blubb"); VERIFY_NO_ERROR(errorInfo); project = qbs::Project(); job.reset(nullptr); buildJob.reset(nullptr); removeBuildDir(setupParams); // Add a file to the top level of a product that does not have a "files" binding yet. setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir + "/project-editing/project-with-no-files.qbs")); resolve(); WAIT_FOR_NEW_TIMESTAMP(); errorInfo = project.addFiles(product, qbs::GroupData(), QStringList("main.cpp")); VERIFY_NO_ERROR(errorInfo); resolve(); rcvr.descriptions.clear(); buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this)); connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, &rcvr, &BuildDescriptionReceiver::handleDescription); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QVERIFY(rcvr.descriptions.contains("compiling main.cpp")); job.reset(project.setupProject(setupParams, m_logSink, 0)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); } void TestApi::commandExtraction() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("/command-extraction"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); qbs::ProjectData projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 1); qbs::ProductData productData = projectData.allProducts().front(); qbs::ErrorInfo errorInfo; const QString projectDirPath = QDir::cleanPath(QFileInfo(setupParams.projectFilePath()).path()); const QString sourceFilePath = projectDirPath + "/main.cpp"; // Before the first build, no rules exist. qbs::RuleCommandList commands = project.ruleCommands(productData, sourceFilePath, "obj", &errorInfo); QCOMPARE(commands.size(), 0); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("No rule"), qPrintable(errorInfo.toString())); qbs::BuildOptions options; options.setDryRun(true); std::unique_ptr buildJob(project.buildAllProducts(options)); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 1); productData = projectData.allProducts().front(); errorInfo = qbs::ErrorInfo(); // After the build, the compile command must be found. commands = project.ruleCommands(productData, sourceFilePath, "obj", &errorInfo); QCOMPARE(commands.size(), 1); QVERIFY2(!errorInfo.hasError(), qPrintable(errorInfo.toString())); const qbs::RuleCommand command = commands.front(); QCOMPARE(command.type(), qbs::RuleCommand::ProcessCommandType); QVERIFY(!command.executable().isEmpty()); QVERIFY(!command.arguments().empty()); } void TestApi::dependencyOnMultiplexedType() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("/dependency-on-multiplexed-type"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); qbs::ProjectData projectData = project.projectData(); const QList allProducts = projectData.allProducts(); QCOMPARE(allProducts.size(), 5); int depCount = 0; int p1Count = 0; int p2Count = 0; for (const qbs::ProductData &p : allProducts) { if (p.name() == "dep") { ++depCount; QCOMPARE(p.dependencies().size(), 0); } else if (p.name() == "p1") { ++p1Count; if (p.multiplexConfigurationId().isEmpty()) // aggregate QCOMPARE(p.dependencies().size(), 3); else QCOMPARE(p.dependencies().size(), 1); } else { QVERIFY(p.name() == "p2"); ++p2Count; QVERIFY(p.dependencies().contains("dep")); } } QCOMPARE(depCount, 1); QCOMPARE(p1Count, 3); QCOMPARE(p2Count, 1); std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); } void TestApi::changeDependentLib() { qbs::ErrorInfo errorInfo = doBuildProject("change-dependent-lib"); VERIFY_NO_ERROR(errorInfo); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("change-dependent-lib.qbs", "cpp.defines: [\"XXXX\"]", "cpp.defines: [\"ABCD\"]"); errorInfo = doBuildProject("change-dependent-lib"); VERIFY_NO_ERROR(errorInfo); } void TestApi::enableAndDisableProduct() { BuildDescriptionReceiver bdr; qbs::ErrorInfo errorInfo = doBuildProject("enable-and-disable-product", &bdr); VERIFY_NO_ERROR(errorInfo); QVERIFY(!bdr.descriptions.contains("compiling")); WAIT_FOR_NEW_TIMESTAMP(); QFile projectFile("enable-and-disable-product.qbs"); QVERIFY(projectFile.open(QIODevice::ReadWrite)); QByteArray content = projectFile.readAll(); content.replace("undefined", "'hidden'"); projectFile.resize(0); projectFile.write(content); projectFile.close(); bdr.descriptions.clear(); errorInfo = doBuildProject("enable-and-disable-product", &bdr); VERIFY_NO_ERROR(errorInfo); QVERIFY(bdr.descriptions.contains("linking")); WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QVERIFY(projectFile.open(QIODevice::ReadWrite)); content = projectFile.readAll(); content.replace("'hidden'", "undefined"); projectFile.resize(0); projectFile.write(content); projectFile.close(); bdr.descriptions.clear(); errorInfo = doBuildProject("enable-and-disable-product", &bdr); VERIFY_NO_ERROR(errorInfo); QVERIFY(!bdr.descriptions.contains("compiling")); } void TestApi::errorInSetupRunEnvironment() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("error-in-setup-run-environment"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::Project project = job->project(); QVERIFY(project.isValid()); QCOMPARE(project.projectData().products().size(), 1); const qbs::ProductData product = project.projectData().products().front(); bool exceptionCaught = false; try { const SettingsPtr s = settings(); qbs::RunEnvironment runEnv = project.getRunEnvironment(product, qbs::InstallOptions(), QProcessEnvironment(), QStringList(), s.get()); qbs::ErrorInfo error; const QProcessEnvironment env = runEnv.runEnvironment(&error); QVERIFY(error.hasError()); QVERIFY2(error.toString().contains("trallala"), qPrintable(error.toString())); } catch (const qbs::ErrorInfo &) { exceptionCaught = true; } QVERIFY(!exceptionCaught); } void TestApi::excludedInputs() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("excluded-inputs"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::Project project = job->project(); std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(job->error().toString())); QVERIFY(project.isValid()); const qbs::ProjectData projectData = project.projectData(); QCOMPARE(projectData.products().size(), 2); qbs::ProductData depProduct; qbs::ProductData pProduct; for (const qbs::ProductData &p : projectData.products()) { if (p.name() == "dep") depProduct = p; else if (p.name() == "p") pProduct = p; } QVERIFY(depProduct.isValid()); QVERIFY(pProduct.isValid()); int theTagCount = 0; for (const qbs::ArtifactData &artifact : depProduct.targetArtifacts()) { if (!artifact.fileTags().contains("the_tag")) continue; ++theTagCount; QFile f(artifact.filePath()); QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(f.errorString())); const QByteArray content = f.readAll(); QVERIFY2(content.contains("the_content"), content.constData()); QCOMPARE(artifact.fileTags().contains("the_other_tag"), content.contains("the_other_content")); } QCOMPARE(theTagCount, 2); int dummyCount = 0; for (const qbs::ArtifactData &artifact : pProduct.targetArtifacts()) { QFileInfo fi(artifact.filePath()); QVERIFY2(fi.exists(), qPrintable(fi.filePath())); if (fi.fileName().startsWith("dummy")) ++dummyCount; } QCOMPARE(dummyCount, 3); } static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project &project) { qbs::BuildOptions buildOptions; buildOptions.setDryRun(true); std::unique_ptr buildJob(project.buildAllProducts(buildOptions)); waitForFinished(buildJob.get()); return buildJob->error(); } void TestApi::disabledInstallGroup() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("disabled_install_group"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::Project project = job->project(); const qbs::ErrorInfo errorInfo = forceRuleEvaluation(project); VERIFY_NO_ERROR(errorInfo); qbs::ProjectData projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 1); qbs::ProductData product = projectData.allProducts().front(); const QList targets = product.targetArtifacts(); QCOMPARE(targets.size(), 1); QVERIFY(targets.front().isGenerated()); QVERIFY(targets.front().isExecutable()); QVERIFY(targets.front().isTargetArtifact()); QCOMPARE(projectData.installableArtifacts().size(), 0); QCOMPARE(product.targetExecutable(), targets.front().filePath()); } void TestApi::disabledProduct() { const qbs::ErrorInfo errorInfo = doBuildProject("disabled-product"); VERIFY_NO_ERROR(errorInfo); } void TestApi::disabledProject() { const qbs::ErrorInfo errorInfo = doBuildProject("disabled-project"); VERIFY_NO_ERROR(errorInfo); } void TestApi::disappearedWildcardFile() { const qbs::SetupProjectParameters setupParams = defaultSetupParameters("disappeared-wildcard-file/disappeared-wildcard-file.qbs"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); VERIFY_NO_ERROR(setupJob->error()); qbs::Project project = setupJob->project(); qbs::ProjectData projectData = project.projectData(); QVERIFY(projectData.isValid()); QList products = projectData.allProducts(); QCOMPARE(products.size(), 1); QCOMPARE(products.first().groups().size(), 1); QCOMPARE(products.first().groups().first().allFilePaths().size(), 2); std::unique_ptr buildJob(project.buildAllProducts({})); QVERIFY(waitForFinished(buildJob.get())); VERIFY_NO_ERROR(buildJob->error()); WAIT_FOR_NEW_TIMESTAMP(); const QString fileToRemove = QFileInfo(setupParams.projectFilePath()).path() + "/file2.txt"; QVERIFY(QFile::remove(fileToRemove)); buildJob.reset(project.buildAllProducts({})); QVERIFY(waitForFinished(buildJob.get())); QVERIFY(buildJob->error().hasError()); QVERIFY2(buildJob->error().toString().contains( tr("Source file '%1' has disappeared.") .arg(fileToRemove)), qPrintable(buildJob->error().toString())); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); VERIFY_NO_ERROR(setupJob->error()); project = setupJob->project(); projectData = project.projectData(); QVERIFY(projectData.isValid()); products = projectData.allProducts(); QCOMPARE(products.size(), 1); QCOMPARE(products.first().groups().size(), 1); QCOMPARE(products.first().groups().first().allFilePaths().size(), 1); buildJob.reset(project.buildAllProducts({})); QVERIFY(waitForFinished(buildJob.get())); VERIFY_NO_ERROR(buildJob->error()); } void TestApi::renamedQbsSource() { const qbs::SetupProjectParameters setupParams = defaultSetupParameters("renamed-qbs-source-file/renamed-qbs-source-file.qbs"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); VERIFY_NO_ERROR(setupJob->error()); qbs::Project project = setupJob->project(); QCOMPARE(project.projectData().allProducts().size(), 2); std::unique_ptr buildJob(project.buildAllProducts({})); QVERIFY(waitForFinished(buildJob.get())); VERIFY_NO_ERROR(buildJob->error()); WAIT_FOR_NEW_TIMESTAMP(); const QString oldFilePath = QFileInfo(setupParams.projectFilePath()).path() + "/the-product/the-prodduct.qbs"; const QString newFilePath = QFileInfo(setupParams.projectFilePath()).path() + "/the-product/the-product.qbs"; QVERIFY(QFile::rename(oldFilePath, newFilePath)); REPLACE_IN_FILE(setupParams.projectFilePath(), "prodduct", "product"); buildJob.reset(project.buildAllProducts({})); QVERIFY(waitForFinished(buildJob.get())); QVERIFY(buildJob->error().hasError()); QVERIFY2(buildJob->error().toString().contains( tr("Source file '%1' has disappeared.") .arg(oldFilePath)), qPrintable(buildJob->error().toString())); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); VERIFY_NO_ERROR(setupJob->error()); project = setupJob->project(); QCOMPARE(project.projectData().allProducts().size(), 2); buildJob.reset(project.buildAllProducts({})); QVERIFY(waitForFinished(buildJob.get())); VERIFY_NO_ERROR(buildJob->error()); } void TestApi::duplicateProductNames() { QFETCH(QString, projectFileName); const qbs::ErrorInfo errorInfo = doBuildProject("duplicate-product-names/" + projectFileName); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("Duplicate product name"), qPrintable(errorInfo.toString())); } void TestApi::duplicateProductNames_data() { QTest::addColumn("projectFileName"); QTest::newRow("Names explicitly set") << QString("explicit.qbs"); QTest::newRow("Unnamed products in same file") << QString("implicit.qbs"); QTest::newRow("Unnamed products in files of the same name") << QString("implicit-indirect.qbs"); } void TestApi::emptyFileTagList() { const qbs::ErrorInfo errorInfo = doBuildProject("empty-filetag-list"); VERIFY_NO_ERROR(errorInfo); } void TestApi::emptySubmodulesList() { const qbs::ErrorInfo errorInfo = doBuildProject("empty-submodules-list"); VERIFY_NO_ERROR(errorInfo); } void TestApi::explicitlyDependsOn() { BuildDescriptionReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("explicitly-depends-on", &receiver); VERIFY_NO_ERROR(errorInfo); if (m_logSink->output.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QVERIFY2(receiver.descriptions.contains("compiling compiler.cpp"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling a.in"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling b.in"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling c.in"), qPrintable(receiver.descriptions)); QFile txtFile(relativeProductBuildDir("p") + "/compiler-name.txt"); QVERIFY2(txtFile.open(QIODevice::ReadOnly), qPrintable(txtFile.errorString())); const QByteArray content = txtFile.readAll(); QCOMPARE(content, QByteArray("compiler file name: compiler")); receiver.descriptions.clear(); errorInfo = doBuildProject("explicitly-depends-on", &receiver); QVERIFY2(!receiver.descriptions.contains("compiling compiler.cpp"), qPrintable(receiver.descriptions)); QVERIFY2(!receiver.descriptions.contains("compiling a.in"), qPrintable(receiver.descriptions)); QVERIFY2(!receiver.descriptions.contains("compiling b.in"), qPrintable(receiver.descriptions)); QVERIFY2(!receiver.descriptions.contains("compiling c.in"), qPrintable(receiver.descriptions)); VERIFY_NO_ERROR(errorInfo); WAIT_FOR_NEW_TIMESTAMP(); touch("compiler.cpp"); waitForFileUnlock(); errorInfo = doBuildProject("explicitly-depends-on", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.descriptions.contains("compiling compiler.cpp"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling a.in"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling b.in"), qPrintable(receiver.descriptions)); QVERIFY2(receiver.descriptions.contains("compiling c.in"), qPrintable(receiver.descriptions)); } void TestApi::exportSimple() { const qbs::ErrorInfo errorInfo = doBuildProject("export-simple"); VERIFY_NO_ERROR(errorInfo); } void TestApi::exportWithRecursiveDepends() { const qbs::ErrorInfo errorInfo = doBuildProject("export-with-recursive-depends"); VERIFY_NO_ERROR(errorInfo); } void TestApi::fallbackGcc() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("fallback-gcc/fallback-gcc.qbs"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); VERIFY_NO_ERROR(job->error()); qbs::ProjectData project = job->project().projectData(); QVERIFY(project.isValid()); QList products = project.allProducts(); QCOMPARE(products.size(), 2); for (const qbs::ProductData &p : std::as_const(products)) { if (p.profile() == "unixProfile") { qbs::PropertyMap moduleProps = p.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), QStringList({"unix"})); QCOMPARE(moduleProps.getModuleProperty("qbs", "toolchain").toStringList(), QStringList({"gcc"})); QCOMPARE(QFileInfo(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString()) .completeBaseName(), QString("g++")); QCOMPARE(moduleProps.getModuleProperty("cpp", "dynamicLibrarySuffix").toString(), QString(".so")); } else { QCOMPARE(p.profile(), QString("gccProfile")); qbs::PropertyMap moduleProps = p.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), QStringList()); QCOMPARE(moduleProps.getModuleProperty("qbs", "toolchain").toStringList(), QStringList({"gcc"})); QCOMPARE(QFileInfo(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString()) .completeBaseName(), QString("g++")); QCOMPARE(moduleProps.getModuleProperty("cpp", "dynamicLibrarySuffix").toString(), QString()); } } } void TestApi::fileTagger() { BuildDescriptionReceiver receiver; const qbs::ErrorInfo errorInfo = doBuildProject("file-tagger/moc_cpp.qbs", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.descriptions.contains("moc bla.cpp"), qPrintable(receiver.descriptions)); } void TestApi::fileTagsFilterOverride() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("filetagsfilter_override"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::Project project = job->project(); const qbs::ErrorInfo errorInfo = forceRuleEvaluation(project); VERIFY_NO_ERROR(errorInfo); qbs::ProjectData projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 1); const qbs::ProductData product = projectData.allProducts().front(); QList installableFiles = product.installableArtifacts(); QCOMPARE(installableFiles.size(), 1); QVERIFY(installableFiles.front().installData().installFilePath().contains("habicht")); } void TestApi::generatedFilesList() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("generated-files-list"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const bool isEmscripten = m_logSink->output.contains("is emscripten: true"); const bool isNotEmscripten = m_logSink->output.contains("is emscripten: false"); QCOMPARE(isEmscripten, !isNotEmscripten); qbs::Project project = setupJob->project(); qbs::BuildOptions options; options.setExecuteRulesOnly(true); const std::unique_ptr buildJob(project.buildAllProducts(options)); QVERIFY(waitForFinished(buildJob.get())); VERIFY_NO_ERROR(buildJob->error()); const qbs::ProjectData projectData = project.projectData(); QCOMPARE(projectData.products().size(), 1); const qbs::ProductData product = projectData.products().front(); QString uiFilePath; QVERIFY(product.generatedArtifacts().size() >= 6); const auto &artifacts = product.generatedArtifacts(); for (const qbs::ArtifactData &a : artifacts) { QVERIFY(a.isGenerated()); QFileInfo fi(a.filePath()); using qbs::Internal::HostOsInfo; const QStringList possibleFileNames = QStringList() << "main.cpp.o" << "main.cpp.obj" << "mainwindow.cpp.o" << "mainwindow.cpp.obj" << "moc_mainwindow.cpp" << "moc_mainwindow.cpp.o" << "moc_mainwindow.cpp.obj" << "ui_mainwindow.h" << "generated-files-list.wasm" << "generated-files-list.worker.js" << "generated-files-list.js" << "generated-files-list.html" << qbs::Internal::HostOsInfo::appendExecutableSuffix( "generated-files-list"); QVERIFY2(possibleFileNames.contains(fi.fileName()) || fi.fileName().endsWith(".plist") || fi.fileName().contains("qt_plugin_import"), qPrintable(fi.fileName())); } const auto groups = product.groups(); for (const qbs::GroupData &group : groups) { const auto artifacts = group.sourceArtifacts(); for (const qbs::ArtifactData &a : artifacts) { QVERIFY(!a.isGenerated()); QVERIFY(!a.isTargetArtifact()); if (a.fileTags().contains(QLatin1String("ui"))) { uiFilePath = a.filePath(); break; } } if (!uiFilePath.isEmpty()) break; } QVERIFY(!uiFilePath.isEmpty()); const QStringList directParents = project.generatedFiles(product, uiFilePath, false); QCOMPARE(directParents.size(), 1); const QFileInfo uiHeaderFileInfo(directParents.front()); QCOMPARE(uiHeaderFileInfo.fileName(), QStringLiteral("ui_mainwindow.h")); QVERIFY(!uiHeaderFileInfo.exists()); const QStringList allParents = project.generatedFiles(product, uiFilePath, true); if (isEmscripten) QCOMPARE(allParents.size(), 5); //built with "-pthread" support else QCOMPARE(allParents.size(), 3); } void TestApi::groupVisibility() { qbs::SetupProjectParameters setupParams = defaultSetupParameters( "group-visibility/group-visibility.qbs"); std::unique_ptr job( qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::ProjectData project = job->project().projectData(); QCOMPARE(project.allProducts().size(), 1); qbs::ProductData product = project.allProducts().front(); const QList groups = product.groups(); QCOMPARE(groups.size(), 3); for (const qbs::GroupData &g : groups) { QVERIFY2( g.name().contains("should be visible") || g.name() == "group-visibility", qPrintable(g.name())); } } void TestApi::infiniteLoopBuilding() { QFETCH(QString, projectDirName); qbs::SetupProjectParameters setupParams = defaultSetupParameters(projectDirName + "/infinite-loop.qbs"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); const std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); QTimer::singleShot(1000, buildJob.get(), &qbs::AbstractJob::cancel); QVERIFY(waitForFinished(buildJob.get(), testTimeoutInMsecs())); QVERIFY(buildJob->error().hasError()); } void TestApi::infiniteLoopBuilding_data() { QTest::addColumn("projectDirName"); QTest::newRow("JS Command") << QString("infinite-loop-js"); QTest::newRow("Process Command") << QString("infinite-loop-process"); QTest::newRow("Scanner (scan property)") << QString("infinite-loop-scanning-scan"); QTest::newRow("Scanner (searchPaths property)") << QString("infinite-loop-scanning-searchpaths"); } void TestApi::infiniteLoopResolving() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("infinite-loop-resolving"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); QTimer::singleShot(1000, setupJob.get(), &qbs::AbstractJob::cancel); QVERIFY(waitForFinished(setupJob.get(), testTimeoutInMsecs())); QVERIFY2(setupJob->error().toString().toLower().contains("cancel"), qPrintable(setupJob->error().toString())); } void TestApi::inheritQbsSearchPaths() { const QString projectFilePath = "inherit-qbs-search-paths/prj.qbs"; qbs::ErrorInfo errorInfo = doBuildProject(projectFilePath); VERIFY_NO_ERROR(errorInfo); WAIT_FOR_NEW_TIMESTAMP(); QFile projectFile(m_workingDataDir + '/' + projectFilePath); QVERIFY(projectFile.open(QIODevice::ReadWrite)); QByteArray content = projectFile.readAll(); content.replace("qbsSearchPaths: \"subdir\"", "//qbsSearchPaths: \"subdir\""); projectFile.resize(0); projectFile.write(content); projectFile.close(); errorInfo = doBuildProject(projectFilePath); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("Dependency 'bli' not found"), qPrintable(errorInfo.toString())); QVariantMap overriddenValues; overriddenValues.insert("project.qbsSearchPaths", QStringList() << m_workingDataDir + "/inherit-qbs-search-paths/subdir"); errorInfo = doBuildProject(projectFilePath, nullptr, nullptr, nullptr, qbs::BuildOptions(), overriddenValues); VERIFY_NO_ERROR(errorInfo); } template typename T::value_type findElem(const T &list, Pred p) { const auto it = std::find_if(list.cbegin(), list.cend(), p); return it == list.cend() ? typename T::value_type() : *it; } void TestApi::installableFiles() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("installed-artifact"); QVariantMap overriddenValues; overriddenValues.insert(QStringLiteral("qbs.installRoot"), QStringLiteral("/tmp")); setupParams.setOverriddenValues(overriddenValues); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::Project project = job->project(); const qbs::ErrorInfo errorInfo = forceRuleEvaluation(project); VERIFY_NO_ERROR(errorInfo); qbs::ProjectData projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 2); qbs::ProductData product = findElem(projectData.allProducts(), [](const qbs::ProductData &p) { return p.name() == QLatin1String("installedApp"); }); QVERIFY(product.isValid()); const QList beforeInstallableFiles = product.installableArtifacts(); QCOMPARE(beforeInstallableFiles.size(), 3); for (const qbs::ArtifactData &f : beforeInstallableFiles) { if (!QFileInfo(f.filePath()).fileName().startsWith("main")) { QVERIFY(f.isExecutable()); const auto expectedTargetFilePath = appendExecSuffix( QStringLiteral("/tmp/usr/bin/installedApp"), m_logSink->output.toLocal8Bit()); QCOMPARE(f.installData().localInstallFilePath(), expectedTargetFilePath); QCOMPARE(product.targetExecutable(), expectedTargetFilePath); break; } } setupParams = defaultSetupParameters("recursive-wildcards"); setupParams.setOverriddenValues(overriddenValues); job.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project(); projectData = project.projectData(); QCOMPARE(projectData.allProducts().size(), 1); product = projectData.allProducts().front(); const QList afterInstallableFiles = product.installableArtifacts(); QCOMPARE(afterInstallableFiles.size(), 2); for (const qbs::ArtifactData &f : afterInstallableFiles) QVERIFY(!f.isExecutable()); QCOMPARE(afterInstallableFiles.front().installData().localInstallFilePath(), QLatin1String("/tmp/dir/file1.txt")); QCOMPARE(afterInstallableFiles.last().installData().localInstallFilePath(), QLatin1String("/tmp/dir/file2.txt")); } void TestApi::isRunnable() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("is-runnable"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::Project project = job->project(); const QList products = project.projectData().products(); QCOMPARE(products.size(), 2); for (const qbs::ProductData &p : products) { QVERIFY2(p.name() == "app" || p.name() == "lib", qPrintable(p.name())); if (p.name() == "app") QVERIFY(p.isRunnable()); else QVERIFY(!p.isRunnable()); } } void TestApi::linkDynamicLibs() { const qbs::ErrorInfo errorInfo = doBuildProject("link-dynamiclibs"); const bool isEmscripten = m_logSink->output.contains("is emscripten: true"); const bool isNotEmscripten = m_logSink->output.contains("is emscripten: false"); if (isEmscripten) QEXPECT_FAIL(nullptr, "Emscripten does not support dynamic linking", Abort); QVERIFY(isNotEmscripten); VERIFY_NO_ERROR(errorInfo); } void TestApi::linkDynamicAndStaticLibs() { BuildDescriptionReceiver bdr; qbs::BuildOptions options; options.setEchoMode(qbs::CommandEchoModeCommandLine); m_logSink->output.clear(); const qbs::ErrorInfo errorInfo = doBuildProject("link-dynamiclibs-staticlibs", &bdr, nullptr, nullptr, options); const bool isEmscripten = m_logSink->output.contains("is emscripten: true"); const bool isNotEmscripten = m_logSink->output.contains("is emscripten: false"); if (isEmscripten) QEXPECT_FAIL(nullptr, "Emscripten does not support dynamic linking", Abort); VERIFY_NO_ERROR(errorInfo); QVERIFY(isNotEmscripten); const bool isGcc = m_logSink->output.contains("is gcc: true"); const bool isNotGcc = m_logSink->output.contains("is gcc: false"); if (isNotGcc) QSKIP("The remainder of this test applies only to GCC"); QVERIFY(isGcc); // The dependent static libs should not appear in the link command for the executable. static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); QString appLinkCmd; for (const QString &line : std::as_const(bdr.descriptionLines)) { const auto ln = line.toStdString(); if (std::regex_search(ln, appLinkCmdRex)) { appLinkCmd = line; break; } } QVERIFY(!appLinkCmd.isEmpty()); QVERIFY(!appLinkCmd.contains("static1")); QVERIFY(!appLinkCmd.contains("static2")); } void TestApi::linkStaticAndDynamicLibs() { BuildDescriptionReceiver bdr; qbs::BuildOptions options; options.setEchoMode(qbs::CommandEchoModeCommandLine); m_logSink->output.clear(); const qbs::ErrorInfo errorInfo = doBuildProject( "link-staticlibs-dynamiclibs", &bdr, nullptr, nullptr, options); const bool isNormalUnix = m_logSink->output.contains("is normal unix: yes"); const bool isNotNormalUnix = m_logSink->output.contains("is normal unix: no"); QVERIFY2(isNormalUnix != isNotNormalUnix, qPrintable(m_logSink->output)); const bool isGcc = m_logSink->output.contains("is gcc: true"); const bool isNotGcc = m_logSink->output.contains("is gcc: false"); const bool isEmscripten = m_logSink->output.contains("is emscripten: true"); const bool isNotEmscripten = m_logSink->output.contains("is emscripten: false"); if (isEmscripten) QEXPECT_FAIL(nullptr, "Emscripten does not support dynamic linking", Abort); VERIFY_NO_ERROR(errorInfo); QVERIFY(isNotEmscripten); if (isNotGcc) QSKIP("The remainder of this test applies only to GCC"); QVERIFY(isGcc); // The dependencies libdynamic1.so and libstatic2.a must not appear in the link command for the // executable. The -rpath-link line for libdynamic1.so must be there. static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " "); QString appLinkCmd; for (const QString &line : std::as_const(bdr.descriptionLines)) { const auto ln = line.toStdString(); if (std::regex_search(ln, appLinkCmdRex)) { appLinkCmd = line; break; } } QVERIFY(!appLinkCmd.isEmpty()); if (isNormalUnix) { const std::regex rpathLinkRex("-rpath-link=\\S*/" + relativeProductBuildDir("dynamic2").toStdString()); const auto ln = appLinkCmd.toStdString(); QVERIFY(std::regex_search(ln, rpathLinkRex)); } QVERIFY(!appLinkCmd.contains("libstatic2.a")); QVERIFY(!appLinkCmd.contains("libdynamic2.so")); } void TestApi::listBuildSystemFiles() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("subprojects/toplevelproject.qbs"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const auto buildSystemFiles = job->project().buildSystemFiles(); QVERIFY(buildSystemFiles.count(setupParams.projectFilePath())); QVERIFY(buildSystemFiles.count(setupParams.buildRoot() + "/subproject2/subproject2.qbs")); QVERIFY(buildSystemFiles.count(setupParams.buildRoot() + "/subproject2/subproject3/subproject3.qbs")); } void TestApi::localProfiles() { QFETCH(bool, enableProfiles); qbs::SetupProjectParameters setupParams = defaultSetupParameters("local-profiles/local-profiles.qbs"); setupParams.setOverriddenValues( {std::make_pair(QString("project.enableProfiles"), enableProfiles)}); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); QString taskDescriptions; const auto taskDescHandler = [&taskDescriptions](const QString &desc, int, qbs::AbstractJob *) { taskDescriptions += '\n' + desc; }; connect(job.get(), &qbs::AbstractJob::taskStarted, taskDescHandler); waitForFinished(job.get()); const QString error = job->error().toString(); QVERIFY2(job->error().hasError() == !enableProfiles, qPrintable(error)); if (!enableProfiles) { QVERIFY2(error.contains("does not exist"), qPrintable(error)); return; } QVERIFY2(taskDescriptions.contains("Resolving"), qPrintable(taskDescriptions)); qbs::ProjectData project = job->project().projectData(); QList products = project.allProducts(); QCOMPARE(products.size(), 4); qbs::ProductData libMingw; qbs::ProductData libClang; qbs::ProductData appDebug; qbs::ProductData appRelease; for (const qbs::ProductData &p : std::as_const(products)) { if (p.name() == "lib") { if (p.profile() == "mingwProfile") libMingw = p; else if (p.profile() == "clangProfile") libClang = p; } else if (p.name() == "app") { const QString buildVariant = p.moduleProperties().getModuleProperty("qbs", "buildVariant").toString(); if (buildVariant == "debug") appDebug = p; else if (buildVariant == "release") appRelease = p; } } QVERIFY(libMingw.isValid()); QVERIFY((libClang.isValid())); QVERIFY(appDebug.isValid()); QVERIFY(appRelease.isValid()); QCOMPARE(appDebug.profile(), QLatin1String("mingwProfile")); QCOMPARE(appRelease.profile(), QLatin1String("mingwProfile")); qbs::PropertyMap moduleProps = libMingw.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), QStringList({"windows"})); QCOMPARE(moduleProps.getModuleProperty("qbs", "toolchain").toStringList(), QStringList({"mingw", "gcc"})); if (moduleProps.getModuleProperty("cpp", "present").toBool()) { QCOMPARE(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString(), qbs::Internal::HostOsInfo::appendExecutableSuffix(QString("g++"))); } moduleProps = libClang.moduleProperties(); QCOMPARE(moduleProps.getModuleProperty("qbs", "targetOS").toStringList(), QStringList({"linux", "unix"})); QCOMPARE(moduleProps.getModuleProperty("qbs", "toolchain").toStringList(), QStringList({"clang", "llvm", "gcc"})); if (moduleProps.getModuleProperty("cpp", "present").toBool()) { QCOMPARE(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString(), qbs::Internal::HostOsInfo::appendExecutableSuffix(QString("clang++"))); } moduleProps = appDebug.moduleProperties(); if (moduleProps.getModuleProperty("cpp", "present").toBool()) QCOMPARE(moduleProps.getModuleProperty("cpp", "optimization").toString(), QString("none")); moduleProps = appRelease.moduleProperties(); if (moduleProps.getModuleProperty("cpp", "present").toBool()) QCOMPARE(moduleProps.getModuleProperty("cpp", "optimization").toString(), QString("fast")); taskDescriptions.clear(); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); connect(job.get(), &qbs::AbstractJob::taskStarted, taskDescHandler); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); QVERIFY2(!taskDescriptions.contains("Resolving"), qPrintable(taskDescriptions)); WAIT_FOR_NEW_TIMESTAMP(); QFile projectFile(setupParams.projectFilePath()); QVERIFY2(projectFile.open(QIODevice::ReadWrite), qPrintable(projectFile.errorString())); QByteArray content = projectFile.readAll(); content.replace("\"clang\"", "\"gcc\""); projectFile.resize(0); projectFile.write(content); projectFile.close(); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project().projectData(); products = project.allProducts(); QCOMPARE(products.size(), 4); int clangProfiles = 0; for (const qbs::ProductData &p : std::as_const(products)) { if (p.profile() == "clangProfile") { ++clangProfiles; moduleProps = p.moduleProperties(); if (moduleProps.getModuleProperty("cpp", "present").toBool()) { QCOMPARE(moduleProps.getModuleProperty("cpp", "cxxCompilerName").toString(), qbs::Internal::HostOsInfo::appendExecutableSuffix(QString("g++"))); } } } QCOMPARE(clangProfiles, 1); } void TestApi::localProfiles_data() { QTest::addColumn("enableProfiles"); QTest::newRow("profiles enabled") << true; QTest::newRow("profiles disabled") << false; } void TestApi::missingSourceFile() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("missing-source-file/missing-source-file.qbs"); setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); m_logSink->setLogLevel(qbs::LoggerMinLevel); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); qbs::ProjectData project = job->project().projectData(); QCOMPARE(project.allProducts().size(), 1); qbs::ProductData product = project.allProducts().front(); QCOMPARE(product.groups().size(), 1); qbs::GroupData group = product.groups().front(); QCOMPARE(group.allSourceArtifacts().size(), 2); QFile::rename("file2.txt.missing", "file2.txt"); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); project = job->project().projectData(); QCOMPARE(project.allProducts().size(), 1); product = project.allProducts().front(); QCOMPARE(product.groups().size(), 1); group = product.groups().front(); QCOMPARE(group.allSourceArtifacts().size(), 3); } void TestApi::mocCppIncluded() { // Initial build. qbs::ErrorInfo errorInfo = doBuildProject("moc-hpp-included"); VERIFY_NO_ERROR(errorInfo); // Touch header and try again. WAIT_FOR_NEW_TIMESTAMP(); QFile headerFile("object.h"); QVERIFY2(headerFile.open(QIODevice::WriteOnly | QIODevice::Append), qPrintable(headerFile.errorString())); headerFile.write("\n"); headerFile.close(); errorInfo = doBuildProject("moc-hpp-included"); VERIFY_NO_ERROR(errorInfo); // Touch cpp file and try again. WAIT_FOR_NEW_TIMESTAMP(); QFile cppFile("object.cpp"); QVERIFY2(cppFile.open(QIODevice::WriteOnly | QIODevice::Append), qPrintable(cppFile.errorString())); cppFile.write("\n"); cppFile.close(); errorInfo = doBuildProject("moc-hpp-included"); VERIFY_NO_ERROR(errorInfo); } void TestApi::multiArch() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("multi-arch"); const SettingsPtr s = settings(); qbs::Internal::TemporaryProfile tph("host", s.get()); qbs::Profile hostProfile = tph.p; hostProfile.setValue("qbs.architecture", "host-arch"); qbs::Internal::TemporaryProfile tpt("target", s.get()); qbs::Profile targetProfile = tpt.p; targetProfile.setValue("qbs.architecture", "target-arch"); QVariantMap overriddenValues; overriddenValues.insert("project.hostProfile", hostProfile.name()); overriddenValues.insert("project.targetProfile", targetProfile.name()); setupParams.setOverriddenValues(overriddenValues); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QCOMPARE(project.profile(), profileName()); const qbs::ProjectData projectData = project.projectData(); const QList &products = projectData.products(); QCOMPARE(products.size(), 3); QList hostProducts; QList targetProducts; for (const qbs::ProductData &p : products) { QVERIFY2(p.profile() == hostProfile.name() || p.profile() == targetProfile.name(), qPrintable(p.profile())); if (p.profile() == hostProfile.name()) hostProducts.push_back(p); else targetProducts.push_back(p); } QCOMPARE(hostProducts.size(), 2); QCOMPARE(targetProducts.size(), 1); QCOMPARE(targetProducts.front().name(), QLatin1String("p1")); QStringList hostProductNames = QStringList() << hostProducts.front().name() << hostProducts.last().name(); QCOMPARE(hostProductNames.count("p1"), 1); QCOMPARE(hostProductNames.count("p2"), 1); const QString p1HostMultiplexCfgId = hostProducts.at(0).multiplexConfigurationId(); const QString p2HostMultiplexCfgId = hostProducts.at(1).multiplexConfigurationId(); const QString p1TargetMultiplexCfgId = targetProducts.at(0).multiplexConfigurationId(); std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); const QString outputBaseDir = setupParams.buildRoot() + '/'; QFile p1HostArtifact(outputBaseDir + relativeProductBuildDir("p1", QString(), p1HostMultiplexCfgId) + "/host+target.output"); QVERIFY2(p1HostArtifact.exists(), qPrintable(p1HostArtifact.fileName())); QVERIFY2(p1HostArtifact.open(QIODevice::ReadOnly), qPrintable(p1HostArtifact.errorString())); QCOMPARE(p1HostArtifact.readAll().constData(), "host-arch"); QFile p1TargetArtifact(outputBaseDir + relativeProductBuildDir("p1", QString(), p1TargetMultiplexCfgId) + "/host+target.output"); QVERIFY2(p1TargetArtifact.exists(), qPrintable(p1TargetArtifact.fileName())); QVERIFY2(p1TargetArtifact.open(QIODevice::ReadOnly), qPrintable(p1TargetArtifact.errorString())); QCOMPARE(p1TargetArtifact.readAll().constData(), "target-arch"); QFile p2Artifact(outputBaseDir + relativeProductBuildDir("p2", QString(), p2HostMultiplexCfgId) + "/host-tool.output"); QVERIFY2(p2Artifact.exists(), qPrintable(p2Artifact.fileName())); QVERIFY2(p2Artifact.open(QIODevice::ReadOnly), qPrintable(p2Artifact.errorString())); QCOMPARE(p2Artifact.readAll().constData(), "host-arch"); const QString installRoot = outputBaseDir + relativeBuildDir() + '/' + qbs::InstallOptions::defaultInstallRoot(); std::unique_ptr installJob(project.installAllProducts(qbs::InstallOptions())); waitForFinished(installJob.get()); QVERIFY2(!installJob->error().hasError(), qPrintable(installJob->error().toString())); QFile p1HostArtifactInstalled(installRoot + "/host/host+target.output"); QVERIFY2(p1HostArtifactInstalled.exists(), qPrintable(p1HostArtifactInstalled.fileName())); QFile p1TargetArtifactInstalled(installRoot + "/target/host+target.output"); QVERIFY2(p1TargetArtifactInstalled.exists(), qPrintable(p1TargetArtifactInstalled.fileName())); QFile p2ArtifactInstalled(installRoot + "/host/host-tool.output"); QVERIFY2(p2ArtifactInstalled.exists(), qPrintable(p2ArtifactInstalled.fileName())); // Specifying the same profile twice should not result in an attempt to multiplex. overriddenValues.insert("project.targetProfile", hostProfile.name()); setupParams.setOverriddenValues(overriddenValues); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(!setupJob->error().hasError()); QCOMPARE(int(setupJob->project().projectData().products().size()), 2); // The same, but this time attaching the properties via the product name. overriddenValues.remove(QStringLiteral("project.targetProfile")); overriddenValues.insert("products.p1.myProfiles", targetProfile.name() + ',' + targetProfile.name()); setupParams.setOverriddenValues(overriddenValues); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(!setupJob->error().hasError()); QCOMPARE(int(setupJob->project().projectData().products().size()), 2); } struct ProductDataSelector { void clear() { name.clear(); qbsProperties.clear(); } bool matches(const qbs::ProductData &p) const { return name == p.name() && qbsPropertiesMatch(p); } bool qbsPropertiesMatch(const qbs::ProductData &p) const { for (auto it = qbsProperties.begin(); it != qbsProperties.end(); ++it) { if (!qbs::qVariantsEqual( it.value(), p.moduleProperties().getModuleProperty("qbs", it.key()))) return false; } return true; } QString name; QVariantMap qbsProperties; }; static qbs::ProductData takeMatchingProduct(QList &products, const ProductDataSelector &s) { qbs::ProductData result; auto it = std::find_if(products.begin(), products.end(), [&s] (const qbs::ProductData &pd) { return s.matches(pd); }); if (it != products.end()) { result = *it; products.erase(it); } return result; } void TestApi::multiplexing() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("multiplexing"); std::unique_ptr setupJob( qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QList products = project.projectData().allProducts(); qbs::ProductData product; ProductDataSelector selector; selector.name = "no-multiplexing"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.clear(); selector.name = "multiplex-without-aggregator-2"; selector.qbsProperties["architecture"] = "TRS-80"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.clear(); selector.name = "multiplex-with-export"; selector.qbsProperties["architecture"] = "TRS-80"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.clear(); selector.name = "nonmultiplex-with-export"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.clear(); selector.name = "nonmultiplex-exporting-aggregation"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.clear(); selector.name = "multiplex-using-export"; selector.qbsProperties["architecture"] = "TRS-80"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.clear(); selector.name = "multiplex-without-aggregator-2-depend-on-non-multiplexed"; selector.qbsProperties["architecture"] = "TRS-80"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.clear(); selector.name = "multiplex-without-aggregator-4"; selector.qbsProperties["architecture"] = "C64"; selector.qbsProperties["buildVariant"] = "debug"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.qbsProperties["buildVariant"] = "release"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.qbsProperties["architecture"] = "TRS-80"; selector.qbsProperties["buildVariant"] = "debug"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.qbsProperties["buildVariant"] = "release"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QVERIFY(product.dependencies().empty()); selector.clear(); selector.name = "multiplex-without-aggregator-4-depends-2"; selector.qbsProperties["architecture"] = "C64"; selector.qbsProperties["buildVariant"] = "debug"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.qbsProperties["buildVariant"] = "release"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.qbsProperties["architecture"] = "TRS-80"; selector.qbsProperties["buildVariant"] = "debug"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.qbsProperties["buildVariant"] = "release"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.clear(); selector.name = "multiplex-with-aggregator-2"; selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 0); selector.qbsProperties["architecture"] = "TRS-80"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 0); selector.qbsProperties["architecture"] = "Atari ST"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.clear(); selector.name = "multiplex-with-aggregator-2-dependent"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 1); selector.clear(); selector.name = "non-multiplexed-with-dependencies-on-multiplexed"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.clear(); selector.name = "non-multiplexed-with-dependencies-on-multiplexed-via-export1"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 4); selector.clear(); selector.name = "non-multiplexed-with-dependencies-on-multiplexed-via-export2"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 3); selector.clear(); selector.name = "non-multiplexed-with-dependencies-on-aggregation-via-export"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(!product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.clear(); selector.name = "aggregate-with-dependencies-on-aggregation-via-export"; selector.qbsProperties["architecture"] = "C64"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.qbsProperties["architecture"] = "TRS-80"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 2); selector.qbsProperties["architecture"] = "Atari ST"; product = takeMatchingProduct(products, selector); QVERIFY(product.isValid()); QVERIFY(product.isMultiplexed()); QCOMPARE(product.dependencies().size(), 4); QVERIFY(products.empty()); } void TestApi::newOutputArtifactInDependency() { BuildDescriptionReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("new-output-artifact-in-dependency", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(receiver.descriptions.contains("linking app")); const QByteArray linkingLibString = QByteArray("linking ") + qbs::Internal::HostOsInfo::dynamicLibraryName("lib").toLatin1(); QVERIFY(!receiver.descriptions.contains(linkingLibString)); receiver.descriptions.clear(); WAIT_FOR_NEW_TIMESTAMP(); QFile projectFile("new-output-artifact-in-dependency.qbs"); QVERIFY2(projectFile.open(QIODevice::ReadWrite), qPrintable(projectFile.errorString())); QByteArray contents = projectFile.readAll(); contents.replace("//Depends", "Depends"); projectFile.resize(0); projectFile.write(contents); projectFile.close(); errorInfo = doBuildProject("new-output-artifact-in-dependency", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(receiver.descriptions.contains("linking app")); QVERIFY(receiver.descriptions.contains(linkingLibString)); } void TestApi::newPatternMatch() { TaskReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.taskDescriptions.contains("Resolving"), qPrintable(m_logSink->output)); receiver.taskDescriptions.clear(); errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(!receiver.taskDescriptions.contains("Resolving")); WAIT_FOR_NEW_TIMESTAMP(); QFile f("test.txt"); QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); f.close(); errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(receiver.taskDescriptions.contains("Resolving")); receiver.taskDescriptions.clear(); errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(!receiver.taskDescriptions.contains("Resolving")); WAIT_FOR_NEW_TIMESTAMP(); f.remove(); errorInfo = doBuildProject("new-pattern-match", nullptr, nullptr, &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY(receiver.taskDescriptions.contains("Resolving")); } void TestApi::noAssertsInRelaxedMode() { qbs::SetupProjectParameters setupParams = defaultSetupParameters( "no-asserts-in-relaxed-mode/no-asserts-in-relaxed-mode.qbs"); setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Relaxed); const std::unique_ptr job( qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); } void TestApi::nonexistingProjectPropertyFromProduct() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("nonexistingprojectproperties/invalidaccessfromproduct.qbs"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QEXPECT_FAIL("", "QBS-432", Abort); QVERIFY(job->error().hasError()); QVERIFY2(job->error().toString().contains(QLatin1String("blubb")), qPrintable(job->error().toString())); } void TestApi::nonexistingProjectPropertyFromCommandLine() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("nonexistingprojectproperties"); removeBuildDir(setupParams); QVariantMap projectProperties; projectProperties.insert(QStringLiteral("project.blubb"), QStringLiteral("true")); setupParams.setOverriddenValues(projectProperties); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY(job->error().hasError()); QVERIFY2(job->error().toString().contains(QLatin1String("blubb")), qPrintable(job->error().toString())); } void TestApi::objC() { const qbs::ErrorInfo errorInfo = doBuildProject("objc"); VERIFY_NO_ERROR(errorInfo); } void TestApi::projectDataAfterProductInvalidation() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-data-after-" "product-invalidation/project-data-after-product-invalidation.qbs"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QVERIFY(project.isValid()); QCOMPARE(project.projectData().products().size(), 1); QVERIFY(project.projectData().products().front().generatedArtifacts().empty()); std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QCOMPARE(project.projectData().products().size(), 1); const qbs::ProductData productAfterBulding = project.projectData().products().front(); QVERIFY(!productAfterBulding.generatedArtifacts().empty()); QFile projectFile(setupParams.projectFilePath()); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY2(projectFile.open(QIODevice::ReadWrite), qPrintable(projectFile.errorString())); QByteArray content = projectFile.readAll(); QVERIFY(!content.isEmpty()); content.replace("\"file.cpp", "// \"file.cpp"); projectFile.resize(0); projectFile.write(content); projectFile.flush(); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); QVERIFY(!project.isValid()); project = setupJob->project(); QVERIFY(project.isValid()); QCOMPARE(project.projectData().products().size(), 1); QVERIFY(project.projectData().products().front().generatedArtifacts() == productAfterBulding.generatedArtifacts()); buildJob.reset(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.get()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QCOMPARE(project.projectData().products().size(), 1); QVERIFY(project.projectData().products().front().generatedArtifacts() != productAfterBulding.generatedArtifacts()); } void TestApi::processResult() { waitForFileUnlock(); removeBuildDir(defaultSetupParameters("process-result")); QFETCH(int, expectedExitCode); QFETCH(bool, redirectStdout); QFETCH(bool, redirectStderr); QVariantMap overridden; overridden.insert("products.app-caller.argument", expectedExitCode); overridden.insert("products.app-caller.redirectStdout", redirectStdout); overridden.insert("products.app-caller.redirectStderr", redirectStderr); ProcessResultReceiver resultReceiver; const qbs::ErrorInfo errorInfo = doBuildProject("process-result", nullptr, &resultReceiver, nullptr, qbs::BuildOptions(), overridden); if (m_logSink->output.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(expectedExitCode != 0, errorInfo.hasError()); QVERIFY(resultReceiver.results.size() > 1); const qbs::ProcessResult &result = resultReceiver.results.back(); QVERIFY2(result.executableFilePath().contains("app"), qPrintable(result.executableFilePath())); QCOMPARE(expectedExitCode, result.exitCode()); QCOMPARE(expectedExitCode == 0, result.success()); QCOMPARE(result.error(), QProcess::UnknownError); struct CheckParams { CheckParams(bool r, QString f, QByteArray c, QStringList co) : redirect(r) , fileName(std::move(f)) , expectedContent(std::move(c)) , consoleOutput(std::move(co)) {} bool redirect; QString fileName; QByteArray expectedContent; const QStringList consoleOutput; }; const std::vector checkParams({ CheckParams(redirectStdout, "stdout.txt", "stdout", result.stdOut()), CheckParams(redirectStderr, "stderr.txt", "stderr", result.stdErr()) }); for (const CheckParams &p : checkParams) { QFile f(relativeProductBuildDir("app-caller") + '/' + p.fileName); QCOMPARE(f.exists(), p.redirect); if (p.redirect) { QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(f.errorString())); QCOMPARE(f.readAll(), p.expectedContent); QCOMPARE(p.consoleOutput, QStringList()); } else { QCOMPARE(p.consoleOutput.join("").toLocal8Bit(), p.expectedContent); } } } void TestApi::processResult_data() { QTest::addColumn("expectedExitCode"); QTest::addColumn("redirectStdout"); QTest::addColumn("redirectStderr"); QTest::newRow("success, no redirection") << 0 << false << false; QTest::newRow("success, stdout redirection") << 0 << true << false; QTest::newRow("failure, stderr redirection") << 1 << false << true; } void TestApi::projectInvalidation() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-invalidation"); QVERIFY(QFile::copy("project.no-error.qbs", "project-invalidation.qbs")); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); QVERIFY(project.isValid()); WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("project.early-error.qbs", "project-invalidation.qbs"); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY(project.isValid()); // Error in Loader, old project still valid. WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("project.late-error.qbs", "project-invalidation.qbs"); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY(setupJob->error().hasError()); QVERIFY(!project.isValid()); // Error in build data re-resolving, old project not valid anymore. } void TestApi::projectLocking() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-locking"); std::unique_ptr setupJob(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); qbs::Project project = setupJob->project(); setupJob.reset(project.setupProject(setupParams, m_logSink, nullptr)); std::unique_ptr setupJob2(project.setupProject(setupParams, m_logSink, nullptr)); waitForFinished(setupJob2.get()); QVERIFY(setupJob2->error().hasError()); QVERIFY2(setupJob2->error().toString() .contains("Cannot start a job while another one is in progress."), qPrintable(setupJob2->error().toString())); waitForFinished(setupJob.get()); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); } void TestApi::projectPropertiesByName() { const QString projectFile = "project-properties-by-name/project-properties-by-name.qbs"; qbs::ErrorInfo errorInfo = doBuildProject(projectFile); QVERIFY(errorInfo.hasError()); QVariantMap overridden; overridden.insert("project.theDefines", QStringList() << "SUB1" << "SUB2"); errorInfo = doBuildProject(projectFile, nullptr, nullptr, nullptr, qbs::BuildOptions(), overridden); QVERIFY(errorInfo.hasError()); overridden.clear(); overridden.insert("projects.subproject1.theDefines", QStringList() << "SUB1"); errorInfo = doBuildProject(projectFile, nullptr, nullptr, nullptr, qbs::BuildOptions(), overridden); QVERIFY(errorInfo.hasError()); overridden.insert("projects.subproject2.theDefines", QStringList() << "SUB2"); errorInfo = doBuildProject(projectFile, nullptr, nullptr, nullptr, qbs::BuildOptions(), overridden); VERIFY_NO_ERROR(errorInfo); } void TestApi::projectWithPropertiesItem() { const qbs::ErrorInfo errorInfo = doBuildProject("project-with-properties-item"); VERIFY_NO_ERROR(errorInfo); } void TestApi::projectWithProbeAndProfileItem() { const qbs::ErrorInfo errorInfo = doBuildProject("project-with-probe-and-profile-item"); VERIFY_NO_ERROR(errorInfo); } void TestApi::propertiesBlocks() { const qbs::ErrorInfo errorInfo = doBuildProject("properties-blocks"); VERIFY_NO_ERROR(errorInfo); } void TestApi::rc() { BuildDescriptionReceiver bdr; ProcessResultReceiver prr; const auto buildRc = [this, &bdr, &prr]() { bdr.descriptions.clear(); bdr.descriptionLines.clear(); prr.output.clear(); prr.results.clear(); const qbs::ErrorInfo errorInfo = doBuildProject("rc", &bdr, &prr); if (errorInfo.hasError()) qDebug() << prr.output; return errorInfo; }; const auto rcFileWasCompiled = [&bdr]() { return bdr.descriptions.contains("compiling test.rc"); }; qbs::ErrorInfo error = buildRc(); VERIFY_NO_ERROR(error); QCOMPARE(rcFileWasCompiled(), qbs::Internal::HostOsInfo::isWindowsHost()); WAIT_FOR_NEW_TIMESTAMP(); error = buildRc(); VERIFY_NO_ERROR(error); QVERIFY(!rcFileWasCompiled()); touch("subdir/rc-include.h"); error = buildRc(); VERIFY_NO_ERROR(error); QCOMPARE(rcFileWasCompiled(), qbs::Internal::HostOsInfo::isWindowsHost()); } void TestApi::referencedFileErrors() { QFETCH(bool, relaxedMode); qbs::SetupProjectParameters params = defaultSetupParameters("referenced-file-errors"); params.setDryRun(true); params.setProductErrorMode(relaxedMode ? qbs::ErrorHandlingMode::Relaxed : qbs::ErrorHandlingMode::Strict); m_logSink->setLogLevel(qbs::LoggerMinLevel); std::unique_ptr job(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(job->error().hasError() != relaxedMode, qPrintable(job->error().toString())); const qbs::Project project = job->project(); QCOMPARE(project.isValid(), relaxedMode); if (!relaxedMode) return; const QList products = project.projectData().allProducts(); QCOMPARE(products.size(), 5); for (const qbs::ProductData &p : products) QCOMPARE(p.isEnabled(), p.name() != "p5"); } void TestApi::referencedFileErrors_data() { QTest::addColumn("relaxedMode"); QTest::newRow("strict mode") << false; QTest::newRow("relaxed mode") << true; } qbs::SetupProjectParameters TestApi::defaultSetupParameters(const QString &projectFileOrDir) const { QFileInfo fi(m_workingDataDir + QLatin1Char('/') + projectFileOrDir); QString projectDirPath; QString projectFilePath; if (fi.isDir()) { projectDirPath = fi.absoluteFilePath(); projectFilePath = projectDirPath + QLatin1Char('/') + projectFileOrDir + QStringLiteral(".qbs"); } else { projectDirPath = fi.absolutePath(); projectFilePath = fi.absoluteFilePath(); } qbs::SetupProjectParameters setupParams; auto environment = QProcessEnvironment::systemEnvironment(); environment.insert("QBS_AUTOTEST_CODE_SIGNING_REQUIRED", "0"); setupParams.setEnvironment(environment); setupParams.setProjectFilePath(projectFilePath); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Strict); setupParams.setOverrideBuildGraphData(true); QDir::setCurrent(projectDirPath); setupParams.setBuildRoot(projectDirPath); const SettingsPtr s = settings(); const qbs::Preferences prefs(s.get(), profileName()); setupParams.setSearchPaths(prefs.searchPaths(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_SEARCH_PATH)))); setupParams.setPluginPaths(prefs.pluginPaths(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_PLUGINS_PATH)))); setupParams.setLibexecPath(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH))); setupParams.setTopLevelProfile(profileName()); setupParams.setMaxJobCount(2); setupParams.setConfigurationName(QStringLiteral("default")); setupParams.setSettingsDirectory(settings()->baseDirectory()); return setupParams; } void TestApi::references() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("references/invalid1.qbs"); const QString projectDir = QDir::cleanPath(m_workingDataDir + "/references"); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY(job->error().hasError()); QString errorString = job->error().toString(); QVERIFY2(errorString.contains("does not contain"), qPrintable(errorString)); setupParams.setProjectFilePath(projectDir + QLatin1String("/invalid2.qbs")); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY(job->error().hasError()); errorString = job->error().toString(); QVERIFY2(errorString.contains("contains more than one"), qPrintable(errorString)); setupParams.setProjectFilePath(projectDir + QLatin1String("/valid.qbs")); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::ProjectData topLevelProject = job->project().projectData(); QCOMPARE(topLevelProject.subProjects().size(), 1); const QString subProjectFileName = QFileInfo(topLevelProject.subProjects().front().location().filePath()).fileName(); QCOMPARE(subProjectFileName, QString("p.qbs")); } void TestApi::relaxedModeRecovery() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("relaxed-mode-recovery"); setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Relaxed); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); if (m_logSink->errors.size() != 4) { for (const qbs::ErrorInfo &error : std::as_const(m_logSink->errors)) qDebug() << error.toString(); } QCOMPARE(m_logSink->errors.size(), 4); for (const qbs::ErrorInfo &error : std::as_const(m_logSink->errors)) { QVERIFY2(!error.toString().contains("ASSERT") && (error.toString().contains("Dependency 'blubb' not found") || error.toString().contains("Product 'p1' had errors and was disabled") || error.toString().contains("Product 'p2' had errors and was disabled")), qPrintable(error.toString())); } } void TestApi::renameProduct() { // Initial run. qbs::ErrorInfo errorInfo = doBuildProject("rename-product/rename.qbs"); VERIFY_NO_ERROR(errorInfo); // Rename lib and adapt Depends item. WAIT_FOR_NEW_TIMESTAMP(); QFile f("rename.qbs"); QVERIFY(f.open(QIODevice::ReadWrite)); QByteArray contents = f.readAll(); contents.replace("TheLib", "thelib"); f.resize(0); f.write(contents); f.close(); errorInfo = doBuildProject("rename-product/rename.qbs"); VERIFY_NO_ERROR(errorInfo); // Rename lib and don't adapt Depends item. WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(f.open(QIODevice::ReadWrite)); contents = f.readAll(); const int libNameIndex = contents.lastIndexOf("thelib"); QVERIFY(libNameIndex != -1); contents.replace(libNameIndex, 6, "TheLib"); f.resize(0); f.write(contents); f.close(); errorInfo = doBuildProject("rename-product/rename.qbs"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("Dependency 'thelib' not found"), qPrintable(errorInfo.toString())); } void TestApi::renameTargetArtifact() { // Initial run. BuildDescriptionReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("rename-target-artifact/rename.qbs", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.descriptions.contains("compiling"), qPrintable(receiver.descriptions)); QCOMPARE(receiver.descriptions.count("linking"), 2); receiver.descriptions.clear(); // Rename library file name. WAIT_FOR_NEW_TIMESTAMP(); QFile f("rename.qbs"); QVERIFY(f.open(QIODevice::ReadWrite)); QByteArray contents = f.readAll(); contents.replace("the_lib", "TheLib"); f.resize(0); f.write(contents); f.close(); errorInfo = doBuildProject("rename-target-artifact/rename.qbs", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(!receiver.descriptions.contains("compiling"), qPrintable(receiver.descriptions)); QCOMPARE(receiver.descriptions.count("linking"), 2); } void TestApi::removeFileDependency() { qbs::ErrorInfo errorInfo = doBuildProject("remove-file-dependency/removeFileDependency.qbs"); VERIFY_NO_ERROR(errorInfo); QFile::remove("someheader.h"); ProcessResultReceiver receiver; errorInfo = doBuildProject("remove-file-dependency/removeFileDependency.qbs", nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(receiver.output.contains("someheader.h"), qPrintable(receiver.output)); } void TestApi::resolveProject() { QFETCH(QString, projectSubDir); QFETCH(QString, productNameOrFilePath); const qbs::SetupProjectParameters params = defaultSetupParameters(projectSubDir); removeBuildDir(params); const std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(setupJob.get()); VERIFY_NO_ERROR(setupJob->error()); const QString productFilePath = getProductFilePath(productNameOrFilePath); QVERIFY2(!QFile::exists(productFilePath), qPrintable(productFilePath)); QVERIFY(regularFileExists(relativeBuildGraphFilePath())); } void TestApi::resolveProject_data() { return buildProject_data(); } void TestApi::resolveProjectDryRun() { QFETCH(QString, projectSubDir); QFETCH(QString, productNameOrFilePath); qbs::SetupProjectParameters params = defaultSetupParameters(projectSubDir); params.setDryRun(true); removeBuildDir(params); const std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(setupJob.get()); VERIFY_NO_ERROR(setupJob->error()); const QString productFilePath = getProductFilePath(productNameOrFilePath); QVERIFY2(!QFile::exists(productFilePath), qPrintable(productFilePath)); QVERIFY(!regularFileExists(relativeBuildGraphFilePath())); } void TestApi::resolveProjectDryRun_data() { return resolveProject_data(); } void TestApi::restoredWarnings() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("restored-warnings"); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Relaxed); setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); // Initial resolving: Errors are new. std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); QCOMPARE(toSet(m_logSink->warnings).size(), 1); QVERIFY2( m_logSink->warnings.first().toString().contains("Superfluous version"), qPrintable(m_logSink->warnings.first().toString())); QCOMPARE(toSet(m_logSink->errors).size(), 4); for (const qbs::ErrorInfo &e : std::as_const(m_logSink->errors)) { const QString msg = e.toString(); QVERIFY2( msg.contains("Property 'blubb' is not declared") || msg.contains("this one comes from a thread") || msg.contains("Product 'theOtherProduct' had errors and was disabled") || msg.contains("Product 'theProduct' had errors and was disabled"), qPrintable(msg)); } m_logSink->warnings.clear(); m_logSink->errors.clear(); // Re-resolving with no changes: Errors come from the stored build graph. job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); QCOMPARE(toSet(m_logSink->warnings).size(), 1); QCOMPARE(toSet(m_logSink->errors).size(), 4); m_logSink->warnings.clear(); m_logSink->errors.clear(); // Re-resolving with changes: Errors come from the re-resolving, stored ones must be suppressed. QVariantMap overridenValues; overridenValues.insert("products.aThirdProduct.moreFiles", true); setupParams.setOverriddenValues(overridenValues); job.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); job.reset(nullptr); QCOMPARE(toSet(m_logSink->warnings).size(), 1); QVERIFY2( m_logSink->warnings.first().toString().contains("Superfluous version"), qPrintable(m_logSink->warnings.first().toString())); QCOMPARE(toSet(m_logSink->errors).size(), 5); // One more for the additional group for (const qbs::ErrorInfo &e : std::as_const(m_logSink->errors)) { const QString msg = e.toString(); QVERIFY2( msg.contains("Property 'blubb' is not declared") || msg.contains("blubb.txt' does not exist") || msg.contains("this one comes from a thread") || msg.contains("Product 'theOtherProduct' had errors and was disabled") || msg.contains("Product 'theThirdProduct' had errors and was disabled") || msg.contains("Product 'theProduct' had errors and was disabled"), qPrintable(msg)); } m_logSink->warnings.clear(); m_logSink->errors.clear(); } void TestApi::restoreAndResolve() { qbs::SetupProjectParameters setupParams = defaultSetupParameters("restore-and-resolve"); setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Relaxed); setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed); // Initial resolving finishes with warnings due to syntax error. std::unique_ptr resolveJob( qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(resolveJob.get()); QVERIFY2(!resolveJob->error().hasError(), qPrintable(resolveJob->error().toString())); QVERIFY(!m_logSink->errors.isEmpty()); QVERIFY(resolveJob->project().projectData().products().isEmpty()); // Fix syntax error. Next attempt at resolving still fails, because the failed file is not // in the list of build system files and therefore the default RestoreAndTrackChanges mode // cannot detect any changes. m_logSink->errors.clear(); REPLACE_IN_FILE("broken-product.qbs", "syntax error", ""); WAIT_FOR_NEW_TIMESTAMP(); resolveJob.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(resolveJob.get()); QVERIFY2(!resolveJob->error().hasError(), qPrintable(resolveJob->error().toString())); QVERIFY(!m_logSink->errors.isEmpty()); QVERIFY(resolveJob->project().projectData().products().isEmpty()); // Now force a new resolve, which should succeed. m_logSink->errors.clear(); setupParams.setRestoreBehavior(qbs::SetupProjectParameters::RestoreAndResolve); resolveJob.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(resolveJob.get()); QVERIFY2(!resolveJob->error().hasError(), qPrintable(resolveJob->error().toString())); QVERIFY(m_logSink->errors.isEmpty()); QCOMPARE(int(resolveJob->project().projectData().products().size()), 1); // Build the product. BuildDescriptionReceiver bdr; std::unique_ptr buildJob( resolveJob->project().buildAllProducts(qbs::BuildOptions())); connect( buildJob.get(), &qbs::BuildJob::reportCommandDescription, &bdr, &BuildDescriptionReceiver::handleDescription); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QVERIFY2(bdr.descriptions.contains("creating dummy.txt"), qPrintable(bdr.descriptions)); buildJob.reset(nullptr); // Now force a new resolve again and verify that nothing gets rebuilt. m_logSink->errors.clear(); bdr.descriptions.clear(); resolveJob.reset(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(resolveJob.get()); QVERIFY2(!resolveJob->error().hasError(), qPrintable(resolveJob->error().toString())); QVERIFY(m_logSink->errors.isEmpty()); QCOMPARE(int(resolveJob->project().projectData().products().size()), 1); buildJob.reset(resolveJob->project().buildAllProducts(qbs::BuildOptions())); connect( buildJob.get(), &qbs::BuildJob::reportCommandDescription, &bdr, &BuildDescriptionReceiver::handleDescription); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); QVERIFY2(bdr.descriptions.isEmpty(), qPrintable(bdr.descriptions)); } void TestApi::ruleConflict() { const qbs::ErrorInfo errorInfo = doBuildProject("rule-conflict"); QVERIFY(errorInfo.hasError()); const QString errorString = errorInfo.toString(); QVERIFY2(errorString.contains("conflict") && errorString.contains("pch1.h") && errorString.contains("pch2.h"), qPrintable(errorString)); } void TestApi::runEnvForDisabledProduct() { const qbs::SetupProjectParameters params = defaultSetupParameters("run-disabled-product/run-disabled-product.qbs"); const std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const qbs::Project project = setupJob->project(); const std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); const qbs::ProjectData projectData = project.projectData(); const QList products = projectData.products(); QCOMPARE(products.size(), 1); const qbs::ProductData product = products.front(); qbs::RunEnvironment runEnv = project.getRunEnvironment( product, qbs::InstallOptions(), QProcessEnvironment(), QStringList(), settings().get()); qbs::ErrorInfo runError; const QProcessEnvironment env = runEnv.runEnvironment(&runError); QVERIFY2(runError.toString().contains("Cannot run disabled product 'app'"), qPrintable(runError.toString())); runError.clear(); runEnv.runTarget(QString(), QStringList(), true, &runError); QVERIFY2(runError.toString().contains("Cannot run disabled product 'app'"), qPrintable(runError.toString())); } void TestApi::softDependency() { const qbs::ErrorInfo errorInfo = doBuildProject("soft-dependency"); VERIFY_NO_ERROR(errorInfo); } void TestApi::sourceFileInBuildDir() { VERIFY_NO_ERROR(doBuildProject("source-file-in-build-dir")); qbs::SetupProjectParameters setupParams = defaultSetupParameters("source-file-in-build-dir"); const QString generatedFile = relativeProductBuildDir("theProduct") + "/generated.cpp"; QVERIFY2(regularFileExists(generatedFile), qPrintable(generatedFile)); std::unique_ptr job(qbs::Project().setupProject(setupParams, m_logSink, nullptr)); waitForFinished(job.get()); QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); const qbs::ProjectData projectData = job->project().projectData(); QCOMPARE(projectData.allProducts().size(), 1); const qbs::ProductData product = projectData.allProducts().front(); QCOMPARE(product.profile(), profileName()); const qbs::GroupData group = findGroup(product, "the group"); QVERIFY(group.isValid()); QCOMPARE(group.allFilePaths().size(), 1); } void TestApi::subProjects() { const qbs::SetupProjectParameters params = defaultSetupParameters("subprojects/toplevelproject.qbs"); removeBuildDir(params); // Check all three types of subproject creation, plus property overrides. qbs::ErrorInfo errorInfo = doBuildProject("subprojects/toplevelproject.qbs"); VERIFY_NO_ERROR(errorInfo); // Disabling both the project with the dependency and the one with the dependent // should not cause an error. WAIT_FOR_NEW_TIMESTAMP(); QFile f(params.projectFilePath()); QVERIFY(f.open(QIODevice::ReadWrite)); QByteArray contents = f.readAll(); contents.replace("condition: true", "condition: false"); f.resize(0); f.write(contents); f.close(); f.setFileName(params.buildRoot() + "/subproject2/subproject2.qbs"); QVERIFY(f.open(QIODevice::ReadWrite)); contents = f.readAll(); contents.replace("condition: qbs.targetOS.length > 0", "condition: false"); f.resize(0); f.write(contents); f.close(); errorInfo = doBuildProject("subprojects/toplevelproject.qbs"); VERIFY_NO_ERROR(errorInfo); // Disabling the project with the dependency only is an error. // This tests also whether changes in sub-projects are detected. WAIT_FOR_NEW_TIMESTAMP(); f.setFileName(params.projectFilePath()); QVERIFY(f.open(QIODevice::ReadWrite)); contents = f.readAll(); contents.replace("condition: false", "condition: true"); f.resize(0); f.write(contents); f.close(); errorInfo = doBuildProject("subprojects/toplevelproject.qbs"); QVERIFY(errorInfo.hasError()); QVERIFY2(errorInfo.toString().contains("Dependency 'testLib' not found"), qPrintable(errorInfo.toString())); } void TestApi::targetArtifactStatus_data() { QTest::addColumn("enableTagging"); QTest::newRow("tagging off") << false; QTest::newRow("tagging on") << true; QTest::newRow("tagging off again") << false; } void TestApi::targetArtifactStatus() { QFETCH(bool, enableTagging); qbs::SetupProjectParameters params = defaultSetupParameters("target-artifact-status/target-artifact-status.qbs"); params.setOverriddenValues({std::make_pair("products.p.enableTagging", enableTagging)}); const std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); waitForFinished(setupJob.get()); VERIFY_NO_ERROR(setupJob->error()); const qbs::Project project = setupJob->project(); QVERIFY(project.isValid()); const std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get())); VERIFY_NO_ERROR(buildJob->error()); const qbs::ProjectData projectData = project.projectData(); const QList products = projectData.products(); QCOMPARE(products.size(), 1); const qbs::ProductData product = products.front(); QCOMPARE(product.targetArtifacts().size(), enableTagging ? 2 : 1); } void TestApi::timeout() { QFETCH(QString, projectDirName); QFETCH(QString, cancelOutput); const auto setupParams = defaultSetupParameters(projectDirName + "/timeout.qbs"); std::unique_ptr setupJob{ qbs::Project().setupProject(setupParams, m_logSink, nullptr)}; waitForFinished(setupJob.get()); if (m_logSink->output.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); auto project = setupJob->project(); const auto products = project.projectData().products(); QList helperProducts; qbs::ProductData productUnderTest; for (const auto &product : products) { if (!product.type().contains(QLatin1String("product-under-test"))) helperProducts.append(product); else productUnderTest = product; } const std::unique_ptr buildHelpersJob{ project.buildSomeProducts(helperProducts, qbs::BuildOptions())}; QVERIFY(waitForFinished(buildHelpersJob.get(), testTimeoutInMsecs())); if (buildHelpersJob->error().hasError()) { qDebug().noquote() << buildHelpersJob->error().toString(); QFAIL("Could not build helper products"); } const std::unique_ptr buildJob(project.buildOneProduct(productUnderTest, qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get(), testTimeoutInMsecs())); QVERIFY(buildJob->error().hasError()); const auto errorString = buildJob->error().toString(); QVERIFY2(errorString.contains("cancel"), qPrintable(errorString)); QVERIFY(errorString.contains("timeout")); QVERIFY(errorString.contains(cancelOutput)); } void TestApi::timeout_data() { QTest::addColumn("projectDirName"); QTest::addColumn("cancelOutput"); QTest::newRow("JS Command") << QString("timeout-js") << QString("infinite loop"); QTest::newRow("Process Command") << QString("timeout-process") << QString("infinite-loop"); } void TestApi::toolInModule() { QVariantMap overrides({std::make_pair("qbs.installRoot", m_workingDataDir + "/tool-in-module/use-outside-project")}); qbs::SetupProjectParameters params = defaultSetupParameters("tool-in-module/use-within-project/use-within-project.qbs"); params.setOverriddenValues(overrides); std::unique_ptr setupJob( qbs::Project().setupProject(params, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); if (m_logSink->output.contains("Skip this test")) QSKIP("Skip this test"); std::unique_ptr buildJob(setupJob->project() .buildAllProducts(qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); const QString toolOutput = relativeProductBuildDir("user-in-project") + "/tool-output.txt"; QVERIFY2(QFile::exists(toolOutput), qPrintable(toolOutput)); params = defaultSetupParameters("tool-in-module/use-outside-project/use-outside-project.qbs"); setupJob.reset(qbs::Project().setupProject(params, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const auto project = setupJob->project(); const auto projectData = project.projectData(); const auto products = projectData.products(); QCOMPARE(products.size(), 1); const qbs::ProductData product = products.front(); const auto groups = product.groups(); for (const qbs::GroupData &group : groups) QVERIFY(group.name() != "thetool binary"); buildJob.reset(setupJob->project().buildAllProducts(qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); const QString toolOutput2 = relativeProductBuildDir("user-outside-project") + "/tool-output.txt"; QVERIFY2(QFile::exists(toolOutput2), qPrintable(toolOutput2)); } void TestApi::trackAddQObjectHeader() { const qbs::SetupProjectParameters params = defaultSetupParameters("missing-qobject-header/missingheader.qbs"); QFile qbsFile(params.projectFilePath()); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp']\n}"); qbsFile.close(); ProcessResultReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs", nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable(receiver.output)); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp','myobject.h']\n}"); qbsFile.close(); errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs"); VERIFY_NO_ERROR(errorInfo); } void TestApi::trackRemoveQObjectHeader() { const qbs::SetupProjectParameters params = defaultSetupParameters("missing-qobject-header/missingheader.qbs"); removeBuildDir(params); QFile qbsFile(params.projectFilePath()); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp','myobject.h']\n}"); qbsFile.close(); qbs::ErrorInfo errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs"); VERIFY_NO_ERROR(errorInfo); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(qbsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); qbsFile.write("CppApplication {\n Depends { name: 'Qt.core' }\n" " files: ['main.cpp', 'myobject.cpp']\n}"); qbsFile.close(); ProcessResultReceiver receiver; errorInfo = doBuildProject("missing-qobject-header/missingheader.qbs", nullptr, &receiver); QVERIFY(errorInfo.hasError()); QVERIFY2(isAboutUndefinedSymbols(receiver.output), qPrintable(receiver.output)); } void TestApi::transformerData() { const qbs::SetupProjectParameters params = defaultSetupParameters("transformer-data/transformer-data.qbs"); const std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); QVERIFY(waitForFinished(setupJob.get())); QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString())); const qbs::Project project = setupJob->project(); const std::unique_ptr buildJob(project.buildAllProducts(qbs::BuildOptions())); QVERIFY(waitForFinished(buildJob.get())); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); qbs::ErrorInfo error; const qbs::ProjectTransformerData projectTData = project.transformerData(&error); QVERIFY2(!error.hasError(), qPrintable(error.toString())); QCOMPARE(projectTData.size(), 1); const qbs::ProductTransformerData productTData = projectTData.first().second; QCOMPARE(productTData.size(), 2); bool firstTransformerFound = false; bool secondTransformerFound = false; for (const qbs::TransformerData &tData : productTData) { if (tData.inputs().empty()) { firstTransformerFound = true; QCOMPARE(tData.outputs().size(), 1); QCOMPARE(QFileInfo(tData.outputs().first().filePath()).fileName(), QString("artifact1")); QCOMPARE(tData.commands().size(), 1); QCOMPARE(tData.commands().first().type(), qbs::RuleCommand::JavaScriptCommandType); } else { secondTransformerFound = true; QCOMPARE(tData.inputs().size(), 1); QCOMPARE(QFileInfo(tData.inputs().first().filePath()).fileName(), QString("artifact1")); QCOMPARE(tData.outputs().size(), 1); QCOMPARE(QFileInfo(tData.outputs().first().filePath()).fileName(), QString("artifact2")); QCOMPARE(tData.commands().size(), 1); QCOMPARE(tData.commands().first().type(), qbs::RuleCommand::JavaScriptCommandType); } } QVERIFY(firstTransformerFound); QVERIFY(secondTransformerFound); } void TestApi::transformers() { const qbs::ErrorInfo errorInfo = doBuildProject("transformers/transformers.qbs"); VERIFY_NO_ERROR(errorInfo); } void TestApi::typeChange() { BuildDescriptionReceiver receiver; qbs::ErrorInfo errorInfo = doBuildProject("type-change", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(!receiver.descriptions.contains("compiling"), qPrintable(receiver.descriptions)); WAIT_FOR_NEW_TIMESTAMP(); QFile projectFile("type-change.qbs"); QVERIFY2(projectFile.open(QIODevice::ReadWrite), qPrintable(projectFile.errorString())); QByteArray content = projectFile.readAll(); content.replace("//", ""); projectFile.resize(0); projectFile.write(content); projectFile.close(); errorInfo = doBuildProject("type-change", &receiver); VERIFY_NO_ERROR(errorInfo); QVERIFY2(receiver.descriptions.contains("compiling"), qPrintable(receiver.descriptions)); } void TestApi::uic() { const qbs::ErrorInfo errorInfo = doBuildProject("uic"); VERIFY_NO_ERROR(errorInfo); } qbs::ErrorInfo TestApi::doBuildProject( const QString &projectFilePath, BuildDescriptionReceiver *buildDescriptionReceiver, ProcessResultReceiver *procResultReceiver, TaskReceiver *taskReceiver, const qbs::BuildOptions &options, const QVariantMap &overriddenValues) { qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath); params.setOverriddenValues(overriddenValues); params.setDryRun(options.dryRun()); const std::unique_ptr setupJob(qbs::Project().setupProject(params, m_logSink, nullptr)); if (taskReceiver) { connect(setupJob.get(), &qbs::AbstractJob::taskStarted, taskReceiver, &TaskReceiver::handleTaskStart); } waitForFinished(setupJob.get()); if (setupJob->error().hasError()) return setupJob->error(); const std::unique_ptr buildJob(setupJob->project().buildAllProducts(options)); if (buildDescriptionReceiver) { connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription, buildDescriptionReceiver, &BuildDescriptionReceiver::handleDescription); } if (procResultReceiver) { connect(buildJob.get(), &qbs::BuildJob::reportProcessResult, procResultReceiver, &ProcessResultReceiver::handleProcessResult); } waitForFinished(buildJob.get()); return buildJob->error(); } QString TestApi::getProductFilePath(const QString &productNameOrFilePath) { if (productNameOrFilePath.isEmpty()) return {}; return productNameOrFilePath.contains('/') ? productNameOrFilePath : relativeExecutableFilePath(productNameOrFilePath, m_logSink->output.toLocal8Bit()); } QTEST_MAIN(TestApi) #include "tst_api.moc" qbs-src-2.6.1/tests/auto/api/api.qbs0000644000175100001660000000114414776170045016613 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "api" files: ["../shared.h", "tst_api.h", "tst_api.cpp"] cpp.defines: base.concat([ "SRCDIR=" + Utilities.cStringQuote(path), "QBS_RELATIVE_LIBEXEC_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeLibexecPath), "QBS_RELATIVE_SEARCH_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeSearchPath), "QBS_RELATIVE_PLUGINS_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativePluginsPath) ]) Group { name: "testdata" prefix: "testdata/" files: ["**/*"] fileTags: [] } } qbs-src-2.6.1/tests/auto/cmdlineparser/0000755000175100001660000000000014776170045017412 5ustar runnerdockerqbs-src-2.6.1/tests/auto/cmdlineparser/cmdlineparser.qbs0000644000175100001660000000161414776170045022753 0ustar runnerdockerimport qbs.Utilities QbsAutotest { Depends { name: "qbsversion" } Depends { name: "qbsconsolelogger" } testName: "cmdlineparser" files: ["tst_cmdlineparser.cpp", "../../../src/app/qbs/qbstool.cpp"] cpp.defines: base.concat([ "SRCDIR=" + Utilities.cStringQuote(path), "QBS_VERSION=" +Utilities.cStringQuote(qbsversion.version) ]) // TODO: Make parser a static library? Group { name: "parser" prefix: "../../../src/app/qbs/parser/" files: [ "commandlineoption.cpp", "commandlineoption.h", "commandlineoptionpool.cpp", "commandlineoptionpool.h", "commandlineparser.cpp", "commandlineparser.h", "commandpool.cpp", "commandpool.h", "commandtype.h", "parsercommand.cpp", "parsercommand.h", ] } } qbs-src-2.6.1/tests/auto/cmdlineparser/tst_cmdlineparser.cpp0000644000175100001660000002622314776170045023645 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../shared.h" #include #include #include #include #include #include #include #include using namespace qbs; class TestCmdLineParser : public QObject { Q_OBJECT public: TestCmdLineParser() { ConsoleLogger::instance().logSink()->setEnabled(false); } private slots: void initTestCase() { QVERIFY(m_projectFile.open()); m_fileArgs = QStringList() << "-f" << m_projectFile.fileName(); } void testResolve_data() { QTest::addColumn("args"); QTest::addColumn("expectedJobCount"); QTest::newRow("default job count") << QStringList() << BuildOptions::defaultMaxJobCount(); QTest::newRow("explicit job count") << QStringList("-j5") << 5; } void testResolve() { QFETCH(QStringList, args); QFETCH(int, expectedJobCount); CommandLineParser parser; QVERIFY(parser.parseCommandLine(QStringList("resolve") << args << m_fileArgs)); QCOMPARE(parser.command(), ResolveCommandType); QCOMPARE(parser.jobCount(profileName()), expectedJobCount); } void testValidCommandLine() { QStringList args; args.push_back("-vvk"); args.push_back("-v"); args << "--products" << "blubb"; args << "--changed-files" << "foo,bar" << m_fileArgs; args << "--check-timestamps"; args << "--check-outputs"; CommandLineParser parser; QVERIFY(parser.parseCommandLine(args)); QCOMPARE(ConsoleLogger::instance().logSink()->logLevel(), LoggerTrace); QCOMPARE(parser.command(), BuildCommandType); QCOMPARE(parser.products(), QStringList() << "blubb"); QCOMPARE(parser.buildOptions(QString()).changedFiles().size(), 2); QVERIFY(parser.buildOptions(QString()).keepGoing()); QVERIFY(parser.forceTimestampCheck()); QVERIFY(parser.forceOutputCheck()); QVERIFY(!parser.logTime()); QCOMPARE(parser.buildConfigurations().size(), 1); QVERIFY(parser.parseCommandLine(QStringList() << "-vvvqqq" << m_fileArgs)); QCOMPARE(ConsoleLogger::instance().logSink()->logLevel(), defaultLogLevel()); QVERIFY(parser.parseCommandLine(QStringList() << "-t" << m_fileArgs)); QVERIFY(parser.logTime()); // Note: We cannot just check for !parser.logTime() here, because if the test is not // run in a terminal, "--show-progress" is ignored, in which case "--log-time" // takes effect. QVERIFY(parser.parseCommandLine(QStringList() << "-t" << "--show-progress" << m_fileArgs)); QVERIFY(parser.showProgress() != parser.logTime()); QVERIFY(parser.parseCommandLine(QStringList() << "-vvqqq" << m_fileArgs)); QCOMPARE(ConsoleLogger::instance().logSink()->logLevel(), LoggerWarning); QVERIFY(parser.parseCommandLine(QStringList() << "-vvvqq" << m_fileArgs)); QCOMPARE(ConsoleLogger::instance().logSink()->logLevel(), LoggerDebug); QVERIFY(parser.parseCommandLine(QStringList() << "--log-level" << "trace" << m_fileArgs)); QCOMPARE(ConsoleLogger::instance().logSink()->logLevel(), LoggerTrace); // Second "global" profile overwrites first. QVERIFY(parser.parseCommandLine(QStringList() << "profile:a" << m_fileArgs << "profile:b")); QCOMPARE(parser.buildConfigurations().size(), 1); QCOMPARE(parser.buildConfigurations().front().value("qbs.profile").toString(), QLatin1String("b")); // Second build configuration-specific profile overwrites first. QVERIFY(parser.parseCommandLine(QStringList(m_fileArgs) << "config:debug" << "profile:a" << "profile:b")); QCOMPARE(parser.buildConfigurations().size(), 1); QCOMPARE(parser.buildConfigurations().front().value("qbs.profile").toString(), QLatin1String("b")); QVERIFY(parser.parseCommandLine(QStringList(m_fileArgs) << "config:a-debug" << "profile:a" << "config:b-debug" << "profile:b")); QCOMPARE(parser.buildConfigurations().size(), 2); QCOMPARE(parser.buildConfigurations().front().value("qbs.configurationName").toString(), QLatin1String("a-debug")); QCOMPARE(parser.buildConfigurations().front().value("qbs.profile").toString(), QLatin1String("a")); QCOMPARE(parser.buildConfigurations().at(1).value("qbs.configurationName").toString(), QLatin1String("b-debug")); QCOMPARE(parser.buildConfigurations().at(1).value("qbs.profile").toString(), QLatin1String("b")); // Redundant build request QVERIFY(parser.parseCommandLine(QStringList(m_fileArgs) << "config:debug" << "profile:a" << "config:debug" << "profile:a")); QCOMPARE(parser.buildConfigurations().size(), 1); QVERIFY(parser.parseCommandLine(QStringList() << "config:debug" << "profile:a" << "config:release" << "profile:b" << m_fileArgs)); QCOMPARE(parser.buildConfigurations().size(), 2); QCOMPARE(parser.buildConfigurations().front().value("qbs.configurationName").toString(), QLatin1String("debug")); QCOMPARE(parser.buildConfigurations().front().value("qbs.profile").toString(), QLatin1String("a")); QCOMPARE(parser.buildConfigurations().at(1).value("qbs.configurationName").toString(), QLatin1String("release")); QCOMPARE(parser.buildConfigurations().at(1).value("qbs.profile").toString(), QLatin1String("b")); // Non-global property takes precedence. QVERIFY(parser.parseCommandLine(QStringList(m_fileArgs) << "profile:a" << "config:debug" << "profile:b")); QCOMPARE(parser.buildConfigurations().size(), 1); QCOMPARE(parser.buildConfigurations().front().value("qbs.configurationName").toString(), QLatin1String("debug")); QCOMPARE(parser.buildConfigurations().front().value("qbs.profile").toString(), QLatin1String("b")); // Digits are always handled as option parameters. QVERIFY(parser.parseCommandLine(QStringList(m_fileArgs) << "-j" << "123")); QCOMPARE(parser.buildOptions(QString()).maxJobCount(), 123); QVERIFY(parser.parseCommandLine(QStringList(m_fileArgs) << "-j123")); QCOMPARE(parser.buildOptions(QString()).maxJobCount(), 123); // Argument list separation for the "run" command. QVERIFY(parser.parseCommandLine(QStringList("run") << m_fileArgs << "config:custom" << "-j123")); QCOMPARE(parser.command(), RunCommandType); QCOMPARE(parser.buildOptions(QString()).maxJobCount(), 123); QCOMPARE(parser.buildConfigurations().front().value("qbs.configurationName").toString(), QLatin1String("custom")); QVERIFY(parser.runArgs().empty()); QVERIFY(parser.parseCommandLine(QStringList("run") << m_fileArgs << "-j" << "123" << "--" << "config:custom")); QCOMPARE(parser.command(), RunCommandType); QCOMPARE(parser.buildOptions(QString()).maxJobCount(), 123); QCOMPARE(parser.buildConfigurations().front().value("qbs.configurationName").toString(), QLatin1String("default")); QCOMPARE(parser.runArgs(), QStringList({"config:custom"})); // show-version QVERIFY(parser.parseCommandLine(QStringList("show-version"))); QVERIFY(parser.showVersion()); QVERIFY(parser.parseCommandLine(QStringList("--version"))); QVERIFY(parser.showVersion()); QVERIFY(parser.parseCommandLine(QStringList("-V"))); QVERIFY(parser.showVersion()); QVERIFY(parser.parseCommandLine(QStringList{"run", "--setup-run-env-config", "x,y,z"})); QCOMPARE(parser.runEnvConfig(), QStringList({"x", "y", "z"})); } void testInvalidCommandLine() { QFETCH(QStringList, commandLine); CommandLineParser parser; QVERIFY(!parser.parseCommandLine(commandLine)); } void testInvalidCommandLine_data() { QTest::addColumn("commandLine"); QTest::newRow("Unknown short option") << (QStringList() << m_fileArgs << "-x"); QTest::newRow("Unknown long option") << (QStringList() << m_fileArgs << "--xyz"); QTest::newRow("Invalid position") << (QStringList() << m_fileArgs << "-vjv"); QTest::newRow("Missing jobs argument") << (QStringList() << m_fileArgs << "-j"); QTest::newRow("Missing products argument") << (QStringList() << m_fileArgs << "--products"); QTest::newRow("Wrong argument") << (QStringList() << "-j" << "0" << m_fileArgs); QTest::newRow("Invalid list argument") << (QStringList() << "--changed-files" << "," << m_fileArgs); QTest::newRow("Invalid log level") << (QStringList() << "--log-level" << "blubb" << m_fileArgs); QTest::newRow("Unknown numeric argument") << (QStringList() << m_fileArgs << "-123"); QTest::newRow("Unknown parameter") << (QStringList() << m_fileArgs << "debug"); QTest::newRow("Too many arguments") << (QStringList("help") << "build" << "clean"); QTest::newRow("Property assignment for clean") << (QStringList("clean") << "profile:x"); QTest::newRow("Property assignment for dump-nodes-tree") << (QStringList("dump-nodes-tree") << "profile:x"); QTest::newRow("Property assignment for status") << (QStringList("status") << "profile:x"); QTest::newRow("Property assignment for update-timestamps") << (QStringList("update-timestamps") << "profile:x"); QTest::newRow("Argument for show-version") << (QStringList("show-version") << "config:debug"); } private: QTemporaryFile m_projectFile; QStringList m_fileArgs; }; QTEST_MAIN(TestCmdLineParser) #include "tst_cmdlineparser.moc" qbs-src-2.6.1/tests/auto/cmdlineparser/CMakeLists.txt0000644000175100001660000000115714776170045022156 0ustar runnerdockerset(PARSER_SOURCES commandlineoption.cpp commandlineoption.h commandlineoptionpool.cpp commandlineoptionpool.h commandlineparser.cpp commandlineparser.h commandpool.cpp commandpool.h commandtype.h parsercommand.cpp parsercommand.h ) list_transform_prepend(PARSER_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../../../src/app/qbs/parser/") add_qbs_test(cmdlineparser DEFINES "QBS_VERSION=\"${QBS_VERSION}\"" INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/../../../src" SOURCES tst_cmdlineparser.cpp ../../../src/app/qbs/qbstool.cpp ${PARSER_SOURCES} ) qbs-src-2.6.1/tests/auto/CMakeLists.txt0000644000175100001660000000035214776170045017322 0ustar runnerdockeradd_subdirectory(api) add_subdirectory(cmdlineparser) add_subdirectory(blackbox) if(WITH_UNIT_TESTS) add_subdirectory(buildgraph) add_subdirectory(language) add_subdirectory(pkgconfig) add_subdirectory(tools) endif() qbs-src-2.6.1/tests/auto/blackbox/0000755000175100001660000000000014776170045016347 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/blackbox-joblimits.qbs0000644000175100001660000000075214776170045022641 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-joblimits" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-joblimits/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxjoblimits.cpp", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/blackbox.qbs0000644000175100001660000000136114776170045020644 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "find" prefix: "find/" files: ["**/*"] fileTags: [] } Group { name: "testdata" prefix: "testdata/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackbox.cpp", "tst_blackbox.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) .concat(qbsbuildconfig.enableUnitTests ? ["QBS_ENABLE_UNIT_TESTS"] : []) .concat("QBS_VERSION=" + Utilities.cStringQuote(qbsversion.version)) } qbs-src-2.6.1/tests/auto/blackbox/blackbox-apple.qbs0000644000175100001660000000103414776170045021740 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-apple" Depends { name: "Qt.xml" } Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-apple/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxapple.cpp", "tst_blackboxapple.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxapple.h0000644000175100001660000000463614776170045022232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BLACKBOXAPPLE_H #define TST_BLACKBOXAPPLE_H #include "tst_blackboxbase.h" #include namespace qbs { class Version; } // namespace qbs class TestBlackboxApple : public TestBlackboxBase { Q_OBJECT public: TestBlackboxApple(); public slots: void initTestCase() override; private slots: void appleMultiConfig(); void aggregateDependencyLinking(); void appiconset(); void assetCatalog(); void assetCatalog_data(); void assetCatalogsEmpty(); void assetCatalogsMultiple(); void bundleStructure(); void bundleStructure_data(); void byteArrayInfoPlist(); void codesign(); void codesign_data(); void deploymentTarget(); void deploymentTarget_data(); void dmg(); void embedInfoPlist(); void frameworkStructure(); void iconset(); void iconsetApp(); void infoPlist(); void privacymanifest(); void infoPlistVariables(); void lipoSymlinks(); void lipoSymlinks_data(); void objcArc(); void overrideInfoPlist(); void xcode(); private: std::optional findXcode(int *status = nullptr); std::optional findXcodeVersion(); }; #endif // TST_BLACKBOXAPPLE_H qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxqt.cpp0000644000175100001660000011643514776170045022111 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackboxqt.h" #include "../shared.h" #include #include #include #include #include #include #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) using qbs::Internal::HostOsInfo; TestBlackboxQt::TestBlackboxQt() : TestBlackboxBase (SRCDIR "/testdata-qt", "blackbox-qt") { setNeedsQt(); } void TestBlackboxQt::addQObjectMacroToGeneratedCppFile() { QDir::setCurrent(testDataDir + "/add-qobject-macro-to-generated-cpp-file"); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("moc"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("object.cpp.in", "// ", ""); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("moc"), m_qbsStdout.constData()); } void TestBlackboxQt::autoQrc() { QDir::setCurrent(testDataDir + "/auto-qrc"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app"})), 0); QVERIFY2(m_qbsStdout.simplified().contains("resource data: resource1 resource2"), m_qbsStdout.constData()); } void TestBlackboxQt::cachedQml() { QDir::setCurrent(testDataDir + "/cached-qml"); if ((runQbs() != 0) && m_qbsStderr.contains("Dependency 'Qt.qml' not found for product 'app'")) QSKIP("Qt version too old"); QString dataDir = relativeBuildDir() + "/install-root/data"; QVERIFY2(m_qbsStdout.contains("qmlcachegen must work: true") || m_qbsStdout.contains("qmlcachegen must work: false"), m_qbsStdout.constData()); if (m_qbsStdout.contains("qmlcachegen must work: false") && QFile::exists(dataDir + "/main.cpp")) { // If C++ source files were installed then Qt.qmlcache is not available. See project file. QSKIP("No QML cache files generated."); } QVERIFY(QFile::exists(dataDir + "/main.qmlc")); QVERIFY(QFile::exists(dataDir + "/MainForm.ui.qmlc")); QVERIFY(QFile::exists(dataDir + "/stuff.jsc")); } void TestBlackboxQt::combinedMoc() { QDir::setCurrent(testDataDir + "/combined-moc"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling moc_theobject.cpp")); QVERIFY(!m_qbsStdout.contains("creating amalgamated_moc_theapp.cpp")); QVERIFY(!m_qbsStdout.contains("compiling amalgamated_moc_theapp.cpp")); QbsRunParameters params(QStringList("modules.Qt.core.combineMocOutput:true")); params.command = "resolve"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling moc_theobject.cpp")); QVERIFY(m_qbsStdout.contains("creating amalgamated_moc_theapp.cpp")); QVERIFY(m_qbsStdout.contains("compiling amalgamated_moc_theapp.cpp")); } void TestBlackboxQt::createProject() { QDir::setCurrent(testDataDir + "/create-project"); QVERIFY(QFile::copy(testSourceDir + "/../../../../examples/helloworld-qt/main.cpp", QDir::currentPath() + "/main.cpp")); QbsRunParameters createParams("create-project"); createParams.profile.clear(); QCOMPARE(runQbs(createParams), 0); createParams.expectFailure = true; QVERIFY(runQbs(createParams) != 0); QVERIFY2(m_qbsStderr.contains("already contains qbs files"), m_qbsStderr.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling"), m_qbsStdout.constData()); } void TestBlackboxQt::dbusAdaptors() { QDir::setCurrent(testDataDir + "/dbus-adaptors"); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::dbusInterfaces() { QDir::setCurrent(testDataDir + "/dbus-interfaces"); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::emscriptenHtml() { QDir::setCurrent(testDataDir + "/emscripten-html"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("is emscripten: false")) QSKIP("Skipping emscripten test"); QVERIFY(m_qbsStdout.contains("is emscripten: true")); const auto relativeInstallRoot = relativeBuildDir() + QStringLiteral("/install-root/"); QVERIFY(!regularFileExists(relativeInstallRoot + QStringLiteral("qtloader.js"))); QVERIFY(!regularFileExists(relativeInstallRoot + QStringLiteral("qtlogo.svg"))); QVERIFY(!regularFileExists(relativeInstallRoot + QStringLiteral("app.html"))); const QStringList params = {QStringLiteral("products.app.generateHtml:true")}; QCOMPARE(runQbs(QbsRunParameters("resolve", params)), 0); QCOMPARE(runQbs(QbsRunParameters("build", params)), 0); QVERIFY(regularFileExists(relativeInstallRoot + QStringLiteral("qtloader.js"))); QVERIFY(regularFileExists(relativeInstallRoot + QStringLiteral("qtlogo.svg"))); QVERIFY(regularFileExists(relativeInstallRoot + QStringLiteral("app.html"))); } void TestBlackboxQt::forcedMoc() { QDir::setCurrent(testDataDir + "/forced-moc"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("using qt4")) QSKIP("Qt version too old"); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStderr.contains("Hello from slot"), m_qbsStderr.constData()); } void TestBlackboxQt::includedMocCpp() { QDir::setCurrent(testDataDir + "/included-moc-cpp"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("using qt4")) QSKIP("Qt version too old"); QVERIFY2(!m_qbsStdout.contains("compiling moc_myobject.cpp"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("myobject.cpp", "#include ("generate"); QTest::addColumn("installDir"); QTest::newRow("don't generate") << false << QString(); QTest::newRow("don't generate with install info") << false << QString("blubb"); QTest::newRow("generate only") << true << QString(); QTest::newRow("generate and install") << true << QString("blubb"); } void TestBlackboxQt::metaTypes() { QDir::setCurrent(testDataDir + "/metatypes"); QFETCH(bool, generate); QFETCH(QString, installDir); const QStringList args{"modules.Qt.core.generateMetaTypesFile:" + QString(generate ? "true" : "false"), "modules.Qt.core.metaTypesInstallDir:" + installDir, "-v", "--force-probe-execution"}; QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0); const bool canGenerate = m_qbsStdout.contains("can generate"); const bool cannotGenerate = m_qbsStdout.contains("cannot generate"); QVERIFY(canGenerate != cannotGenerate); const bool expectFiles = generate && canGenerate; const bool expectInstalledFiles = expectFiles && !installDir.isEmpty(); QCOMPARE(runQbs(QStringList("--clean-install-root")), 0); const QString productDir = relativeProductBuildDir("mylib"); const QString outputDir = productDir + "/qt.headers"; QVERIFY(!regularFileExists(outputDir + "/moc_unmocableclass.cpp.json")); QCOMPARE(regularFileExists(outputDir + "/moc_mocableclass1.cpp.json"), expectFiles); QCOMPARE(regularFileExists(outputDir + "/mocableclass2.moc.json"), expectFiles); QCOMPARE(regularFileExists(productDir + "/mylib_metatypes.json"), expectFiles); QCOMPARE(regularFileExists(relativeBuildDir() + "/install-root/some-prefix/" + installDir + "/mylib_metatypes.json"), expectInstalledFiles); } void TestBlackboxQt::mixedBuildVariants() { QDir::setCurrent(testDataDir + "/mixed-build-variants"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); const bool isMsvc = m_qbsStdout.contains("is msvc: true"); const bool isNotMsvc = m_qbsStdout.contains("is msvc: false"); if (isMsvc) { QVERIFY2(m_qbsStderr.contains("not allowed"), m_qbsStderr.constData()); } else { QVERIFY(isNotMsvc); QVERIFY2(m_qbsStderr.contains("not supported"), m_qbsStderr.constData()); } } void TestBlackboxQt::mocAndCppCombining() { QDir::setCurrent(testDataDir + "/moc-and-cxx-combining"); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::mocFlags() { QDir::setCurrent(testDataDir + "/moc-flags"); QCOMPARE(runQbs(), 0); WAIT_FOR_NEW_TIMESTAMP(); QbsRunParameters params; params.expectFailure = true; params.arguments << "Qt.core.mocFlags:-E"; QVERIFY(runQbs(params) != 0); } void TestBlackboxQt::mocCompilerDefines() { QDir::setCurrent(testDataDir + "/moc-compiler-defines"); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::mocSameFileName() { QDir::setCurrent(testDataDir + "/moc-same-file-name"); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("compiling moc_someclass.cpp"), 2); } void TestBlackboxQt::noMocRunAfterTouchingOtherCppFile() { QDir::setCurrent(testDataDir + "/no-moc-run-after-touching-other-cpp-file"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("moc header1.h")); QVERIFY(m_qbsStdout.contains("moc header2.h")); QVERIFY(m_qbsStdout.contains("compiling moc_header1.cpp")); QVERIFY(m_qbsStdout.contains("compiling moc_header2.cpp")); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); QVERIFY(m_qbsStdout.contains("linking")); WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("moc header1.h")); QVERIFY(!m_qbsStdout.contains("moc header2.h")); QVERIFY(!m_qbsStdout.contains("compiling moc_header1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling moc_header2.cpp")); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); QVERIFY(m_qbsStdout.contains("linking")); } void TestBlackboxQt::noRelinkOnQDebug() { QFETCH(QString, checkMode); QFETCH(bool, expectRelink); QVERIFY(QDir::setCurrent(testDataDir + "/no-relink-on-qdebug")); rmDirR("default"); // Target check. QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("is emscripten: true")) QSKIP("Irrelevant for emscripten"); QVERIFY(m_qbsStdout.contains("is emscripten: false")); QVERIFY2(m_qbsStdout.contains("is GCC: "), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("is MinGW: "), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("is Darwin: "), m_qbsStdout.constData()); const bool isGCCLike = m_qbsStdout.contains("is GCC: true"); const bool isMingw = m_qbsStdout.contains("is MinGW: true"); const bool isDarwin = m_qbsStdout.contains("is Darwin: true"); if (!isGCCLike) expectRelink = false; else if (isMingw || isDarwin) expectRelink = true; // Initial build. QbsRunParameters params("resolve"); if (isGCCLike && !checkMode.isEmpty()) params.arguments << ("modules.cpp.exportedSymbolsCheckMode:" + checkMode); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("linking"), 2); // Inserting the qDebug() statement will pull in weak symbols. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("lib.cpp", "// qDebug", "qDebug"); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("linking"), expectRelink ? 2 : 1); // Also check the opposite case. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("lib.cpp", "qDebug", "// qDebug"); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("linking"), expectRelink ? 2 : 1); } void TestBlackboxQt::noRelinkOnQDebug_data() { QTest::addColumn("checkMode"); QTest::addColumn("expectRelink"); QTest::newRow("default") << QString() << false; QTest::newRow("relaxed") << QString("ignore-undefined") << false; QTest::newRow("strict") << QString("strict") << true; } void TestBlackboxQt::pkgconfig() { QDir::setCurrent(testDataDir + "/pkgconfig"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); } void TestBlackboxQt::pkgconfigQt() { QFETCH(QStringList, arguments); QFETCH(bool, success); QDir::setCurrent(testDataDir + "/pkgconfig-qt"); rmDirR(relativeBuildDir()); QbsRunParameters dumpParams("resolve", {"-f", "dump-libpath.qbs"}); QCOMPARE(runQbs(dumpParams), 0); auto lines = QString::fromUtf8(m_qbsStdout).split('\n'); const QString needle = "libPath="; qbs::Internal::removeIf( lines, [&needle](const auto &line) { return !line.startsWith(needle); }); QCOMPARE(lines.size(), 1); const auto libPath = lines[0].mid(needle.size()); auto prefix = QFileInfo(libPath).path(); if (prefix.endsWith("/lib") && !prefix.startsWith("/lib")) prefix = QFileInfo(prefix).path(); const auto pkgConfigPath = libPath + "/pkgconfig/"; if (!QFileInfo(pkgConfigPath).exists()) QSKIP("No *.pc files found"); rmDirR(relativeBuildDir()); QbsRunParameters params("build", {"-f", "pkgconfig-qt.qbs"}); // need to override prefix for the downloaded Qt params.environment.insert("PKG_CONFIG_QT5CORE_PREFIX", prefix); params.environment.insert("PKG_CONFIG_QT6CORE_PREFIX", prefix); params.arguments << "moduleProviders.qbspkgconfig.extraPaths:" + pkgConfigPath; params.arguments << arguments; QCOMPARE(runQbs(params) == 0, success); if (!success) QVERIFY(m_qbsStderr.contains("Dependency 'Qt.core' not found for product 'p'")); } void TestBlackboxQt::pkgconfigQt_data() { QTest::addColumn("arguments"); QTest::addColumn("success"); QTest::newRow("pkgconfig") << QStringList() << true; QTest::newRow("dummy") << QStringList({"products.p.qbsModuleProviders:dummyProvider"}) << false; QTest::newRow("cross-compiling") << QStringList({"moduleProviders.qbspkgconfig.sysroot:/some/fake/sysroot"}) << false; } void TestBlackboxQt::pkgconfigNoQt() { QDir::setCurrent(testDataDir + "/pkgconfig-qt"); rmDirR(relativeBuildDir()); QbsRunParameters params("build", {"-f", "pkgconfig-qt.qbs"}); params.arguments << "moduleProviders.qbspkgconfig.libDirs:nonexistent"; params.expectFailure = true; QCOMPARE(runQbs(params) == 0, false); QVERIFY2(m_qbsStderr.contains("Dependency 'Qt.core' not found for product 'p'"), m_qbsStderr); // QBS-1777: basic check for JS exceptions in case of missing Qt QVERIFY2(!m_qbsStderr.contains("Error executing provider for module 'Qt.core'"), m_qbsStderr); } void TestBlackboxQt::pluginMetaData() { QDir::setCurrent(testDataDir + "/plugin-meta-data"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("using qt4")) QSKIP("Qt version too old"); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QVERIFY2(runQbs(QbsRunParameters("run", QStringList{"-p", "app"})) == 0, m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("all ok!"), m_qbsStderr.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("metadata.json"); waitForFileUnlock(); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("moc"), m_qbsStdout.constData()); } void TestBlackboxQt::pluginSupport_data() { QTest::addColumn("invalidPlugin"); QTest::newRow("request valid plugins") << false; QTest::newRow("request invalid plugin") << true; } void TestBlackboxQt::pluginSupport() { QDir::setCurrent(testDataDir + "/plugin-support"); QFETCH(bool, invalidPlugin); QbsRunParameters resolveParams("resolve"); if (invalidPlugin) { resolveParams.arguments << "modules.m1.useDummy:true"; resolveParams.expectFailure = true; } bool resolveResult = runQbs(resolveParams) == 0; if (m_qbsStdout.contains("using qt4")) QSKIP("Qt version too old"); QCOMPARE(resolveResult, !invalidPlugin); if (invalidPlugin) { QVERIFY2(m_qbsStderr.contains("Plugin 'dummy' of type 'imageformats' was requested, " "but is not available"), m_qbsStderr.constData()); return; } const bool isStaticQt = m_qbsStdout.contains("static Qt: true"); const bool isDynamicQt = m_qbsStdout.contains("static Qt: false"); QVERIFY(isStaticQt != isDynamicQt); if (isStaticQt) QVERIFY2(m_qbsStdout.contains("platform plugin count: 1"), m_qbsStdout.constData()); else QVERIFY2(m_qbsStdout.contains("platform plugin count: 0"), m_qbsStdout.constData()); const auto extractList = [this](const char sep) { const int listStartIndex = m_qbsStdout.indexOf(sep); const int listEndIndex = m_qbsStdout.indexOf(sep, listStartIndex + 1); const QByteArray listString = m_qbsStdout.mid(listStartIndex + 1, listEndIndex - listStartIndex - 1); return listString.isEmpty() ? QByteArrayList() : listString.split(','); }; const QByteArrayList enabledPlugins = extractList('%'); if (isStaticQt) QCOMPARE(enabledPlugins.size(), 2); else QVERIFY(enabledPlugins.empty()); const QByteArrayList allPlugins = extractList('#'); QVERIFY(allPlugins.size() >= enabledPlugins.size()); QCOMPARE(runQbs(), 0); for (const QByteArray &plugin : allPlugins) { QCOMPARE(m_qbsStdout.contains("qt_plugin_import_" + plugin + ".cpp"), enabledPlugins.contains(plugin)); } } void TestBlackboxQt::qdoc() { QDir::setCurrent(testDataDir + "/qdoc"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); if (m_qbsStdout.contains("Qt is too old")) QSKIP("Skip test since qdoc3 does not work properly"); QCOMPARE(runQbs(), 0); QVERIFY(QFileInfo(relativeProductBuildDir("QDoc Test") + "/qdoctest.qch").exists()); } void TestBlackboxQt::qmlDebugging() { QDir::setCurrent(testDataDir + "/qml-debugging"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const bool isGcc = m_qbsStdout.contains("is gcc: true"); const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); if (isNotGcc) QSKIP("The remainder of this test only applies to gcc"); QVERIFY(isGcc); QProcess nm; nm.start("nm", QStringList(relativeExecutableFilePath("debuggable-app", m_qbsStdout))); if (!nm.waitForStarted()) QSKIP("The remainder of this test requires nm"); QVERIFY2(nm.waitForFinished(), qPrintable(nm.errorString())); QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData()); const QByteArray output = nm.readAllStandardOutput(); QVERIFY2(output.toLower().contains("debugginghelper"), output.constData()); } void TestBlackboxQt::qobjectInObjectiveCpp() { if (!HostOsInfo::isMacosHost()) QSKIP("only applies on macOS"); const QString testDir = testDataDir + "/qobject-in-mm"; QDir::setCurrent(testDir); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::qmlTypeRegistrar_data() { QTest::addColumn("importName"); QTest::addColumn("installDir"); QTest::newRow("don't generate") << QString() << QString(); QTest::newRow("don't generate with install info") << QString() << QString("blubb"); QTest::newRow("generate only") << QString("People") << QString(); QTest::newRow("generate and install") << QString("People") << QString("blubb"); } void TestBlackboxQt::qmlTypeRegistrar() { QDir::setCurrent(testDataDir + "/qmltyperegistrar"); QFETCH(QString, importName); QFETCH(QString, installDir); rmDirR(relativeBuildDir()); const QStringList args{"modules.Qt.qml.importName:" + importName, "modules.Qt.qml.typesInstallDir:" + installDir}; if ((runQbs(QbsRunParameters("resolve", args)) != 0) && m_qbsStderr.contains("Dependency 'Qt.qml' not found for product 'myapp'")) QSKIP("Qt version too old"); const bool hasRegistrar = m_qbsStdout.contains("has registrar"); const bool doesNotHaveRegistrar = m_qbsStdout.contains("does not have registrar"); QVERIFY(hasRegistrar != doesNotHaveRegistrar); if (doesNotHaveRegistrar) QSKIP("Qt version too old"); QCOMPARE(runQbs(), 0); const bool enabled = !importName.isEmpty(); QCOMPARE(m_qbsStdout.contains("running qmltyperegistrar"), enabled); QCOMPARE(m_qbsStdout.contains("compiling myapp_qmltyperegistrations.cpp"), enabled); const QString buildDir = relativeProductBuildDir("myapp"); QCOMPARE(regularFileExists(buildDir + "/myapp.qmltypes"), enabled); QCOMPARE(regularFileExists(relativeBuildDir() + "/install-root/" + installDir + "/myapp.qmltypes"), enabled && !installDir.isEmpty()); } void TestBlackboxQt::qtKeywords() { QDir::setCurrent(testDataDir + "/qt-keywords"); QbsRunParameters params(QStringList("modules.Qt.core.enableKeywords:false")); params.expectFailure = true; QVERIFY(runQbs(params) != 0); params.arguments.clear(); QVERIFY(runQbs(params) != 0); params.command = "resolve"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); } void TestBlackboxQt::quickCompiler() { QDir::setCurrent(testDataDir + "/quick-compiler"); if ((runQbs() != 0) && m_qbsStderr.contains("'Qt.quick' has version 4.8.7, but it needs to be at least 5.0.0.")) QSKIP("Qt version too old"); const bool hasCompiler = m_qbsStdout.contains("compiler available"); const bool doesNotHaveCompiler = m_qbsStdout.contains("compiler not available"); QVERIFY2(hasCompiler || doesNotHaveCompiler, m_qbsStdout.constData()); QCOMPARE(m_qbsStdout.contains("compiling qml_subdir_test_qml.cpp"), hasCompiler); if (doesNotHaveCompiler) QSKIP("qtquickcompiler not available"); QVERIFY2(m_qbsStdout.contains("generating loader source"), m_qbsStdout.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("generating loader source"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("qml/subdir/test.qml"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating loader source"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters(QStringList{"config:off", "modules.Qt.quick.useCompiler:false"})), 0); QVERIFY2(m_qbsStdout.contains("compiling"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling qml_subdir_test_qml.cpp"), m_qbsStdout.constData()); } void TestBlackboxQt::qtScxml() { QDir::setCurrent(testDataDir + "/qtscxml"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("QtScxml not present")) QSKIP("QtScxml module not present"); QVERIFY2(m_qbsStdout.contains("state machine name: qbs_test_machine"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.Qt.scxml.additionalCompilerFlags:--blubb"))), 0); QbsRunParameters params; params.expectFailure = true; QVERIFY2(runQbs(params) != 0, m_qbsStdout.constData()); } void TestBlackboxQt::removeMocHeaderFromFileList() { QDir::setCurrent(testDataDir + "/remove-moc-header-from-file-list"); QCOMPARE(runQbs(), 0); QString projectFile("remove-moc-header-from-file-list.qbs"); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "\"file.h\"", "// \"file.h\""); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "// \"file.h\"", "\"file.h\""); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::staticQtPluginLinking() { QDir::setCurrent(testDataDir + "/static-qt-plugin-linking"); QCOMPARE(runQbs(QStringList("products.p.type:application")), 0); const bool isStaticQt = m_qbsStdout.contains("Qt is static"); QVERIFY2(m_qbsStdout.contains("creating static import") == isStaticQt, m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.p.type:staticlibrary"))), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("creating static import"), m_qbsStdout.constData()); } void TestBlackboxQt::trackAddMocInclude() { QDir::setCurrent(testDataDir + "/trackAddMocInclude"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/trackAddMocInclude/work"); // The build must fail because the main.moc include is missing. QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); WAIT_FOR_NEW_TIMESTAMP(); ccp("../after", "."); touch("main.cpp"); QCOMPARE(runQbs(), 0); } void TestBlackboxQt::track_qobject_change() { QDir::setCurrent(testDataDir + "/trackQObjChange"); copyFileAndUpdateTimestamp("bla_qobject.h", "bla.h"); QCOMPARE(runQbs(), 0); const QString objectSuffix = parsedObjectSuffix(m_qbsStdout); const QString productFilePath = relativeExecutableFilePath("i", m_qbsStdout); QVERIFY2(regularFileExists(productFilePath), qPrintable(productFilePath)); QString moc_bla_objectFileName = relativeProductBuildDir("i") + '/' + inputDirHash("qt.headers") + "/moc_bla.cpp" + objectSuffix; QVERIFY2(regularFileExists(moc_bla_objectFileName), qPrintable(moc_bla_objectFileName)); WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("bla_noqobject.h", "bla.h"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(productFilePath)); QVERIFY(!QFile(moc_bla_objectFileName).exists()); } void TestBlackboxQt::track_qrc() { QDir::setCurrent(testDataDir + "/qrc"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("using qt4")) QSKIP("Qt version too old"); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QString fileName = relativeExecutableFilePath("i", m_qbsStdout); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("rcc"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling test.cpp"), m_qbsStdout.constData()); QVERIFY2(regularFileExists(fileName), qPrintable(fileName)); QDateTime dt = QFileInfo(fileName).lastModified(); WAIT_FOR_NEW_TIMESTAMP(); { QFile f("stuff.txt"); f.remove(); QVERIFY(f.open(QFile::WriteOnly)); f.write("bla"); f.close(); } REPLACE_IN_FILE("i.qbs", "//\"test.cpp\"", "\"test.cpp\""); waitForFileUnlock(); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("rcc bla.qrc"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("compiling test.cpp"), m_qbsStdout.constData()); QVERIFY(regularFileExists(fileName)); QVERIFY(dt < QFileInfo(fileName).lastModified()); WAIT_FOR_NEW_TIMESTAMP(); touch("i.qbs"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("rcc"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling test.cpp"), m_qbsStdout.constData()); // Turn on big resources. WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(QbsRunParameters("resolve", {"modules.Qt.core.enableBigResources:true"})), 0); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("rcc (pass 1) bla.qrc"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("rcc (pass 2) bla.qrc"), m_qbsStdout.constData()); // Check null build. WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Building"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("rcc"), m_qbsStdout.constData()); // Turn off big resources. WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(QbsRunParameters("resolve", {"modules.Qt.core.enableBigResources:false"})), 0); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("rcc bla.qrc"), m_qbsStdout.constData()); // Check null build. WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Building"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("rcc"), m_qbsStdout.constData()); } void TestBlackboxQt::unmocable() { QDir::setCurrent(testDataDir + "/unmocable"); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStderr.contains("No relevant classes found. No output generated.")); } QTEST_MAIN(TestBlackboxQt) qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxproviders.h0000644000175100001660000000500514776170045023135 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef TST_BLACKBOXPROVIDERS_H #define TST_BLACKBOXPROVIDERS_H #include "tst_blackboxbase.h" class TestBlackboxProviders : public TestBlackboxBase { Q_OBJECT public: TestBlackboxProviders(); private slots: void allowedValues(); void allowedValues_data(); void brokenProvider(); void conanProvider(); void conanProvider_data(); void conanFileProbe(); void moduleProviders(); void moduleProvidersCache(); void nonEagerModuleProvider(); void probeInModuleProvider(); void providersCondition(); void providersConditionProbes(); void providersProperties(); void qbsModulePropertiesInProviders(); void qbsModuleProviders_data(); void qbsModuleProviders(); void qbsModuleProvidersCliOverride(); void qbsModuleProvidersCliOverride_data(); void qbsModuleProvidersCompatibility(); void qbsModuleProvidersCompatibility_data(); void qbspkgconfigModuleProvider(); void qtBug51237(); void removalVersion(); }; #endif // TST_BLACKBOXPROVIDERS_H qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/0000755000175100001660000000000014776170045020602 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/0000755000175100001660000000000014776170045023612 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/plugin-support-main.cpp0000644000175100001660000000001614776170045030245 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/plugin-support.qbs0000644000175100001660000000165114776170045027334 0ustar runnerdockerimport qbs.Utilities QtGuiApplication { condition: { // pluginTypes empty for Qt4 if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { console.info("using qt4"); return false; } return true; } Probe { id: staticProbe property bool isStaticQt: Qt.gui.isStaticLibrary property var plugins: Qt.plugin_support.effectivePluginsByType property var allPlugins: Qt.plugin_support.allPluginsByType configure: { console.info("static Qt: " + isStaticQt); console.info("requested image plugins: %" + plugins.imageformats + "%"); console.info("all image plugins: #" + allPlugins.imageformats + "#"); console.info("platform plugin count: " + (plugins.platforms || []).length); } } Depends { name: "m1" } Depends { name: "m2" } files: "plugin-support-main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/modules/0000755000175100001660000000000014776170045025262 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/modules/m2/0000755000175100001660000000000014776170045025600 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/modules/m2/m2.qbs0000644000175100001660000000044314776170045026626 0ustar runnerdockerModule { Depends { name: "Qt.plugin_support" } Properties { condition: Qt.plugin_support.allPluginsByType && Qt.plugin_support.allPluginsByType.imageformats Qt.plugin_support.pluginsByType: ({imageformats: Qt.plugin_support.allPluginsByType.imageformats[1]}) } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/modules/m1/0000755000175100001660000000000014776170045025577 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-support/modules/m1/m1.qbs0000644000175100001660000000066414776170045026631 0ustar runnerdockerModule { property bool useDummy Depends { name: "Qt.plugin_support" } Properties { condition: useDummy Qt.plugin_support.pluginsByType: ({imageformats: "dummy"}) } Properties { condition: Qt.plugin_support.allPluginsByType && Qt.plugin_support.allPluginsByType.imageformats Qt.plugin_support.pluginsByType: ({imageformats: Qt.plugin_support.allPluginsByType.imageformats[0]}) } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/emscripten-html/0000755000175100001660000000000014776170045023715 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/emscripten-html/emscripten-html.qbs0000644000175100001660000000056414776170045027544 0ustar runnerdockerProduct { name: "app" type: generateHtml ? ["application", "qthtml"] : ["application"] Depends { name: "Qt.core" } files: "main.cpp" property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } property bool generateHtml: false Group { fileTagsFilter: ["qthtml"] qbs.install: true } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/emscripten-html/main.cpp0000644000175100001660000000235114776170045025346 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/0000755000175100001660000000000014776170045022240 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/lupdate_de_DE.ts0000644000175100001660000000013714776170045025267 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/input2.txt0000644000175100001660000000020414776170045024216 0ustar runnerdocker#include class C : public QObject { Q_OBJECT public: C() { auto s = tr("ignored message"); } }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt1-test.cpp0000644000175100001660000000010414776170045024421 0ustar runnerdocker#include H::H() { const auto s = tr("H message"); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/mainwindow.ui0000644000175100001660000000120214776170045024746 0ustar runnerdocker MainWindow 0 0 800 600 The title 0 0 800 19 qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/subdir/0000755000175100001660000000000014776170045023530 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/subdir/header.h0000644000175100001660000000012114776170045025123 0ustar runnerdocker#include class H : public QObject { Q_OBJECT public: H(); }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt2-main.cpp0000644000175100001660000000026514776170045024377 0ustar runnerdocker#include class M : public QObject { Q_OBJECT public: M() { auto s = tr("M message"); // auto s2 = tr("M message 2"); } }; int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt1-main.cpp0000644000175100001660000000001614776170045024370 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt1-dummy2.cpp0000644000175100001660000000002314776170045024657 0ustar runnerdockerstatic void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/noqt-main.cpp0000644000175100001660000000001614776170045024644 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt2-dummy.cpp0000644000175100001660000000002314776170045024576 0ustar runnerdockerstatic void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/input.txt0000644000175100001660000000017614776170045024144 0ustar runnerdocker#include class C : public QObject { Q_OBJECT public: C() { auto s = tr("C message"); } }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt2-dummy2.cpp0000644000175100001660000000002314776170045024660 0ustar runnerdockerstatic void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt2-new.cpp0000644000175100001660000000015614776170045024243 0ustar runnerdocker#include class N : public QObject { Q_OBJECT public: N() { auto s = tr("N message"); } }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/qt1-dummy.cpp0000644000175100001660000000002314776170045024575 0ustar runnerdockerstatic void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lupdate/lupdate.qbs0000644000175100001660000000446514776170045024416 0ustar runnerdockerimport qbs.File Project { QtApplication { name: "qt1" Depends { name: "Qt.widgets" } /*cpp.includePaths: "subdir"*/ // cpp.cxxLanguageVersion: "c++17" Group { name: "ignored" files: "qt1-main.cpp" fileTags: ["cpp", "qt.untranslatable"] } Group { name: "with extra include path" cpp.includePaths: outer.concat("subdir") files: "qt1-test.cpp" } Group { name: "translatable generator input" files: "input.txt" fileTags: "cpp.in" } Group { name: "non-translatable generator input" files: "input2.txt" fileTags: "cpp.in.nontranslatable" } files: [ "mainwindow.ui", "qt1-dummy.cpp", "qt1-dummy2.cpp", "subdir/header.h", ] Rule { inputs: "cpp.in" Artifact { filePath: "generated_" + input.baseName + ".cpp"; fileTags: "cpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "filegen"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } Rule { inputs: "cpp.in.nontranslatable" Artifact { filePath: "generated_" + input.baseName + ".cpp"; fileTags: ["cpp", "qt.untranslatable"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "filegen"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } } QtApplication { name: "qt2" files: [ "qt2-dummy.cpp", "qt2-dummy2.cpp", "qt2-main.cpp", /*"qt2-new.cpp"*/ ] } CppApplication { name: "noqt" files: "noqt-main.cpp" } Product { name: "translations" Depends { name: "Qt.core" } files: "lupdate_de_DE.ts" } QtLupdateRunner {} } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qml-debugging/0000755000175100001660000000000014776170045023324 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qml-debugging/main.cpp0000644000175100001660000000345614776170045024764 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #include using Application = QGuiApplication; #define AH_SO_THIS_IS_QT5 #else #include #include #define AH_SO_THIS_IS_QT4 using Application = QApplication; #endif int main(int argc, char *argv[]) { Application app(argc, argv); #ifdef AH_SO_THIS_IS_QT5 QQmlApplicationEngine engine; engine.load(QUrl("blubb")); #else QDeclarativeView view; view.setSource(QUrl("blubb")); #endif return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs0000644000175100001660000000077314776170045026564 0ustar runnerdockerQtApplication { name: "debuggable-app" consoleApplication: true Depends { name: "Qt.quick" } Qt.quick.qmlDebugging: true files: "main.cpp" Probe { id: checker property bool isGcc: qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("emscripten") property string executableSuffix: cpp.executableSuffix configure: { console.info("is gcc: " + isGcc); console.info("executable suffix: " + executableSuffix); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/0000755000175100001660000000000014776170045022600 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/MainForm.ui.qml0000644000175100001660000000116014776170045025435 0ustar runnerdockerimport QtQuick 2.6 Rectangle { property alias mouseArea: mouseArea property alias textEdit: textEdit width: 360 height: 360 MouseArea { id: mouseArea anchors.fill: parent } TextEdit { id: textEdit text: qsTr("Enter some text...") verticalAlignment: Text.AlignVCenter anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 20 Rectangle { anchors.fill: parent anchors.margins: -10 color: "transparent" border.width: 1 } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/cached-qml.qbs0000644000175100001660000000163714776170045025314 0ustar runnerdockerimport qbs.Utilities CppApplication { name: "app" consoleApplication: true Depends { name: "Qt.core" } Depends { name: "Qt.quick" } Depends { name: "Qt.qml" } install: true installDir: "" qbs.installPrefix: "" Qt.qml.generateCacheFiles: true Qt.qml.cacheFilesInstallDir: "data" files: [ "main.cpp", "MainForm.ui.qml", "main.qml", "stuff.js" ] // Install the C++ sources to tell the blackbox test that Qt.qmlcache is not available. Group { condition: !Qt.qml.cachingEnabled fileTagsFilter: ["cpp"] qbs.install: true qbs.installDir: "data" } Probe { id: qtVersionProbe property string qtVersion: Qt.core.version configure: { console.info("qmlcachegen must work: " + (Utilities.versionCompare(qtVersion, "5.11") >= 0)) } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/main.qml0000644000175100001660000000052014776170045024234 0ustar runnerdockerimport QtQuick 2.6 import QtQuick.Window 2.2 import "stuff.js" as Stuff Window { visible: true width: 640 height: 480 title: Stuff.title() MainForm { anchors.fill: parent mouseArea.onClicked: { console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"')) } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/qml.qrc0000644000175100001660000000023114776170045024074 0ustar runnerdocker main.qml MainForm.ui.qml qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/main.cpp0000644000175100001660000000052314776170045024230 0ustar runnerdocker#include #include int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(qApp->applicationDirPath() + QStringLiteral("/data/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/cached-qml/stuff.js0000644000175100001660000000005414776170045024264 0ustar runnerdockerfunction title() { return "Wello Horld!"; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lrelease/0000755000175100001660000000000014776170045022376 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lrelease/hu.ts0000644000175100001660000000074114776170045023364 0ustar runnerdocker Application My hovercraft is full of eels A légpárnásom tele van angolnákkal I will not buy this record; it is scratched Nem fogok vásárolni ezt a rekordot; ez karcos qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lrelease/lrelease.qbs0000644000175100001660000000051514776170045024702 0ustar runnerdockerimport qbs.Host Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "lrelease-test" type: ["ts"] Depends { name: "Qt.core" } files: ["de.ts", "hu.ts"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/lrelease/de.ts0000644000175100001660000000124414776170045023337 0ustar runnerdocker Application I am hunry Ich bin Ungar I am thirsty Ich bin Donnerstag Please press Control Bitte drücken Sie den Kontrolleur No keyboard detected. Please press F1 to continue Sehr witzig qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qmltyperegistrar/0000755000175100001660000000000014776170045024220 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs0000644000175100001660000000126414776170045030350 0ustar runnerdockerimport qbs.Utilities CppApplication { name: "myapp" Depends { name: "Qt.qml" } Qt.qml.importVersion: "1" cpp.includePaths: sourceDirectory qbs.installPrefix: "" files: [ "main.cpp", "person.cpp", "person.h", ] Group { files: "example.qml" fileTags: "qt.core.resource_data" } Probe { id: versionProbe property string version: Qt.core.version configure: { if (Utilities.versionCompare(version, "5.15") >= 0) console.info("has registrar"); else console.info("does not have registrar"); found = true; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml0000644000175100001660000000475414776170045026400 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // ![0] import People 1.0 Person { name: "Bob Jones" shoeSize: 12 } // ![0] qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp0000644000175100001660000000534414776170045026240 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "person.h" // ![0] Person::Person(QObject *parent) : QObject(parent), m_shoeSize(0) { } QString Person::name() const { return m_name; } void Person::setName(const QString &n) { m_name = n; } int Person::shoeSize() const { return m_shoeSize; } void Person::setShoeSize(int s) { m_shoeSize = s; } // ![0] qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h0000644000175100001660000000561614776170045025707 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PERSON_H #define PERSON_H #include #include //![0] class Person : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) QML_ELEMENT public: Person(QObject *parent = nullptr); QString name() const; void setName(const QString &); int shoeSize() const; void setShoeSize(int); private: QString m_name; int m_shoeSize; }; //![0] #endif // PERSON_H qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp0000644000175100001660000000573514776170045025662 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include "person.h" int main(int argc, char ** argv) { QCoreApplication app(argc, argv); QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); auto *person = qobject_cast(component.create()); if (person) { qWarning() << "The person's name is" << person->name(); qWarning() << "They wear a" << person->shoeSize() << "sized shoe"; } else { qWarning() << component.errors(); } return EXIT_SUCCESS; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/0000755000175100001660000000000014776170045023660 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.ui0000644000175100001660000000276214776170045026411 0ustar runnerdocker Controller 0 0 255 111 Controller 9 6 Controller Qt::AlignCenter Decelerate Accelerate Right Left qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp0000644000175100001660000000625714776170045026561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include "controller.h" #include "car_interface.h" Controller::Controller(QWidget *parent) : QWidget(parent) { ui.setupUi(this); car = new org::example::Examples::CarInterface("org.example.CarExample", "/Car", QDBusConnection::sessionBus(), this); startTimer(1000); } void Controller::timerEvent(QTimerEvent *event) { Q_UNUSED(event); if (car->isValid()) ui.label->setText("connected"); else ui.label->setText("disconnected"); } void Controller::on_accelerate_clicked() { car->accelerate(); } void Controller::on_decelerate_clicked() { car->decelerate(); } void Controller::on_left_clicked() { car->turnLeft(); } void Controller::on_right_clicked() { car->turnRight(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.qbs0000644000175100001660000000065014776170045026553 0ustar runnerdockerCppApplication { name: "controller" condition: Qt.dbus.present Depends { name: "Qt.dbus"; required: false } Depends { name: "Qt.widgets" } cpp.cxxLanguageVersion: "c++11" files: [ "controller.cpp", "controller.h", "controller.ui", "main.cpp", ] Group { name: "DBUS Interface" files: ["car.xml"] fileTags: ["qt.dbus.interface"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/car.xml0000644000175100001660000000062414776170045025151 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp0000644000175100001660000000531014776170045025307 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #else #include > #endif #include #include "controller.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Controller controller; controller.show(); return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.h0000644000175100001660000000330014776170045026210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CONTROLLER_H #define CONTROLLER_H #include "ui_controller.h" #include "car_interface.h" class Controller : public QWidget { Q_OBJECT public: Controller(QWidget *parent = nullptr); protected: void timerEvent(QTimerEvent *event); private slots: void on_accelerate_clicked(); void on_decelerate_clicked(); void on_left_clicked(); void on_right_clicked(); private: Ui::Controller ui; org::example::Examples::CarInterface *car; }; #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/forced-moc/0000755000175100001660000000000014776170045022620 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/forced-moc/createqtclass.h0000644000175100001660000000032414776170045025626 0ustar runnerdocker#ifndef CREATEQTCLASS_H #define CREATEQTCLASS_H #include #define CREATE_QT_CLASS(className) \ class className : public QObject \ { \ Q_OBJECT \ public: \ Q_SIGNAL void mySignal(); \ } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/forced-moc/main.cpp0000644000175100001660000000054614776170045024255 0ustar runnerdocker#include "myqtclass.h" #include #include #include int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); MyQtClass c; QObject::connect(&c, &MyQtClass::mySignal, [] { qDebug() << "Hello from slot"; qApp->quit(); }); QTimer::singleShot(0, &c, &MyQtClass::mySignal); return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/forced-moc/forced-moc.qbs0000644000175100001660000000123714776170045025350 0ustar runnerdockerimport qbs.Host import qbs.Utilities QtApplication { condition: { if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { console.info("using qt4"); return false; } var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } files: "main.cpp" Group { name: "QObject service provider" files: "createqtclass.h" fileTags: ["hpp", "unmocable"] } Group { name: "QObject service user" files: "myqtclass.h" fileTags: ["hpp", "mocable"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/forced-moc/myqtclass.h0000644000175100001660000000015114776170045025006 0ustar runnerdocker#ifndef MYQTCLASS_H #define MYQTCLASS_H #include "createqtclass.h" CREATE_QT_CLASS(MyQtClass); #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/0000755000175100001660000000000014776170045023526 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/qml.qrc0000644000175100001660000000014214776170045025023 0ustar runnerdocker qml/subdir/test.qml qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/qml/0000755000175100001660000000000014776170045024317 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/qml/subdir/0000755000175100001660000000000014776170045025607 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/qml/subdir/test.qml0000644000175100001660000000003614776170045027300 0ustar runnerdockerimport QtQuick 2.0 Item { } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/main.cpp0000644000175100001660000000063714776170045025164 0ustar runnerdocker#include #include int main(int argc, char *argv[]) { #if defined(Q_OS_WIN) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/qml/subdir/test.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/quick-compiler/quick-compiler.qbs0000644000175100001660000000110014776170045027151 0ustar runnerdockerCppApplication { Depends { name: "Qt.quick" // Must fail when using Qt4 versionAtLeast: "5" } Qt.quick.useCompiler: Qt.quick.compilerAvailable cpp.cxxLanguageVersion: "c++11" Probe { id: qtQuickCompilerProbe property bool hasCompiler: Qt.quick.compilerAvailable configure: { if (hasCompiler) console.info("compiler available"); else console.info("compiler not available"); } } files: [ "main.cpp", "qml.qrc", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/create-project/0000755000175100001660000000000014776170045023511 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/create-project/dummy.txt0000644000175100001660000000000014776170045025373 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-compiler-defines/0000755000175100001660000000000014776170045024603 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.cpp0000644000175100001660000000011414776170045026551 0ustar runnerdocker#include "object.h" Object::Object(QObject *parent) : QObject(parent) { } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-compiler-defines/moc-compiler-defines.qbs0000644000175100001660000000010414776170045031306 0ustar runnerdockerQtApplication { files: ["main.cpp", "object.h", "object.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-compiler-defines/object.h0000644000175100001660000000450014776170045026221 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECT_H #define OBJECT_H #include // These were not defined during the moc run (QBS-1592). // Do not use Q_OS_UNIX here as it is a fallback value which is defined when nothing else is. #if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(Q_OS_HURD) \ || defined(Q_OS_WASM) class Object : public QObject { Q_OBJECT public: explicit Object(QObject *parent = nullptr); }; #endif #endif // OBJECT_H qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-compiler-defines/main.cpp0000644000175100001660000000010114776170045026223 0ustar runnerdocker#include "object.h" int main() { QObject o; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/0000755000175100001660000000000014776170045021367 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/test.cpp0000644000175100001660000000001714776170045023050 0ustar runnerdockervoid test() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/bla.cpp0000644000175100001660000000273114776170045022634 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { QFileInfo f(":/stuff.txt"); if (!f.exists()) return 1; if (!f.isFile()) return 2; QFileInfo d(":/subdir"); if (!d.exists()) return 3; if (!d.isDir()) return 4; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/i.qbs0000644000175100001660000000137014776170045022327 0ustar runnerdockerimport qbs.Host import qbs.Utilities Project { Product { condition: { if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { console.info("using qt4"); return false; } var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); console.info("executable suffix: " + cpp.executableSuffix); return result; } consoleApplication: true type: "application" name: "i" Depends { name: "Qt.core" } files: [ "bla.cpp", "bla.qrc", //"test.cpp", ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/subdir/0000755000175100001660000000000014776170045022657 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/subdir/dummy.txt0000644000175100001660000000000014776170045024541 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/bla.qrc0000644000175100001660000000016514776170045022636 0ustar runnerdocker stuff.txt subdir/ qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qrc/stuff.txt0000644000175100001660000000002014776170045023247 0ustar runnerdockera resource file qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/metatypes/0000755000175100001660000000000014776170045022615 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp0000644000175100001660000000025114776170045026031 0ustar runnerdocker#include class MocableClass2 : public QObject { Q_OBJECT public: MocableClass2(QObject *parent) : QObject(parent) {} }; #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp0000644000175100001660000000020014776170045026304 0ustar runnerdocker#include class UnmocableClass : public QObject { public: UnmocableClass(QObject *parent) : QObject(parent) {} }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs0000644000175100001660000000112514776170045025336 0ustar runnerdockerimport qbs.Utilities StaticLibrary { name: "mylib" Depends { name: "Qt.core" } qbs.installPrefix: "some-prefix" Probe { id: capabilitiesChecker property string version: Qt.core.version configure: { if (Utilities.versionCompare(version, "5.15") >= 0) console.info("can generate"); else console.info("cannot generate"); found = true; } } files: [ "mocableclass1.cpp", "mocableclass1.h", "mocableclass2.cpp", "unmocableclass.cpp", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h0000644000175100001660000000020114776170045025470 0ustar runnerdocker#include class MocableClass1 : public QObject { Q_OBJECT public: MocableClass1(QObject *parent = nullptr); }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp0000644000175100001660000000013714776170045026033 0ustar runnerdocker#include "mocableclass1.h" MocableClass1::MocableClass1(QObject *parent) : QObject(parent) {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qdoc/0000755000175100001660000000000014776170045021530 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdoc0000644000175100001660000000012414776170045023323 0ustar runnerdocker/*! \page index.html \title QDoc Test QDoc Test is a test for QDoc. */qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qdocconf0000644000175100001660000000043014776170045024171 0ustar runnerdockerproject = QDoc Test description = QDoc Test headerdirs = . sourcedirs = . exampledirs = . outputdir = doc/html qhp.projects = QDocTest qhp.QDocTest.file = qdoctest.qhp qhp.QDocTest.namespace = org.qt-project.QDocTest qhp.QDocTest.virtualFolder = doc qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qdoc/qdoc.qbs0000644000175100001660000000117214776170045023166 0ustar runnerdockerimport qbs.Host import qbs.Utilities Product { condition: { if (Utilities.versionCompare(Qt.core.version, "5.0.0") < 0) { console.info("Qt is too old"); return false; } if (qbs.targetPlatform !== Host.platform()) { console.info("targetPlatform differs from hostPlatform"); return false; } return true; } name: "QDoc Test" type: ["qdoc-html", "qch"] Depends { name: "Qt.core" } files: ["qdoc.qdoc"] Group { name: "main qdocconf file" files: "qdoc.qdocconf" fileTags: "qdocconf-main" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/0000755000175100001660000000000014776170045022335 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs0000644000175100001660000000167214776170045024605 0ustar runnerdockerimport qbs.Host Project { QtApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "app" files: ["main.cpp"] Group { prefix: "qrc-base/" Qt.core.resourcePrefix: "/thePrefix" Qt.core.resourceSourceBase: "qrc-base" files: ["resource1.txt"] fileTags: ["qt.core.resource_data"] Group { prefix: "qrc-base/subdir/" Qt.core.resourceSourceBase: "qrc-base/subdir" files: ["resource2.txt"] Group { prefix: "qrc-base/subdir/" Qt.core.resourcePrefix: "/theOtherPrefix" files: ["resource3.txt"] } } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/0000755000175100001660000000000014776170045024032 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/0000755000175100001660000000000014776170045025322 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource3.txt0000644000175100001660000000001214776170045027766 0ustar runnerdockerresource3 qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource2.txt0000644000175100001660000000001214776170045027765 0ustar runnerdockerresource2 qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/resource1.txt0000644000175100001660000000001214776170045026474 0ustar runnerdockerresource1 qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/auto-qrc/main.cpp0000644000175100001660000000107114776170045023764 0ustar runnerdocker#include #include int main() { QFile resource1(":/thePrefix/resource1.txt"); if (!resource1.open(QIODevice::ReadOnly)) return 1; QFile resource2(":/thePrefix/resource2.txt"); if (!resource2.open(QIODevice::ReadOnly)) return 2; QFile resource3(":/theOtherPrefix/resource3.txt"); if (!resource3.open(QIODevice::ReadOnly)) return 3; std::cout << "resource data: " << resource1.readAll().constData() << resource2.readAll().constData() << resource3.readAll().constData() << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/combined-moc/0000755000175100001660000000000014776170045023136 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/combined-moc/combined-moc.qbs0000644000175100001660000000014314776170045026177 0ustar runnerdockerQtApplication { name: "theapp" files: [ "main.cpp", "theobject.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/combined-moc/theobject.h0000644000175100001660000000010714776170045025254 0ustar runnerdocker#include class TheObject : public QObject { Q_OBJECT }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/combined-moc/main.cpp0000644000175100001660000000007514776170045024570 0ustar runnerdocker#include "theobject.h" int main() { TheObject object; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/0000755000175100001660000000000014776170045024357 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.h0000644000175100001660000000045714776170045025304 0ustar runnerdocker#ifndef SYMBOLSTEST_H #define SYMBOLSTEST_H #include #if defined(SYMBOLSTEST_LIBRARY) # define SYMBOLSTEST_EXPORT Q_DECL_EXPORT #else # define SYMBOLSTEST_EXPORT Q_DECL_IMPORT #endif class SYMBOLSTEST_EXPORT SymbolsTest { public: SymbolsTest(); }; #endif // SYMBOLSTEST_H qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/symbols-test.qbs0000644000175100001660000000146414776170045027540 0ustar runnerdockerProject { CppApplication { name: "app" Depends { name: "lib" } property bool dummy: { var isGCC = qbs.toolchain.includes("gcc") && !qbs.toolchain.includes("emscripten") console.info("is GCC: " + isGCC); console.info("is MinGW: " + qbs.toolchain.includes("mingw")); console.info("is Darwin: " + qbs.targetOS.includes("darwin")); console.info("is emscripten: " + qbs.toolchain.contains("emscripten")); } files: "main.cpp" } DynamicLibrary { name: "lib" Depends { name: "Qt.core" } cpp.cxxLanguageVersion: "c++11" cpp.defines: "SYMBOLSTEST_LIBRARY" files: [ "lib.cpp", "lib.h", ] Export { Depends { name: "Qt.core" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/lib.cpp0000644000175100001660000000014114776170045025625 0ustar runnerdocker#include #include "lib.h" SymbolsTest::SymbolsTest() { // qDebug() << "hallo"; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-relink-on-qdebug/main.cpp0000644000175100001660000000001714776170045026005 0ustar runnerdockerint main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/0000755000175100001660000000000014776170045024136 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src2/0000755000175100001660000000000014776170045025007 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src2/somefile.cpp0000644000175100001660000000020414776170045027312 0ustar runnerdocker#include class MyClass2 : public QObject { Q_OBJECT }; static void f() { MyClass2 m; } #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src2/someclass.cpp0000644000175100001660000000015114776170045027501 0ustar runnerdocker#include "someclass.h" namespace Src2 { SomeClass::SomeClass(QObject *parent) : QObject(parent) { } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src2/someclass.h0000644000175100001660000000030114776170045027143 0ustar runnerdocker#ifndef SOMECLASS2_H #define SOMECLASS2_H #include namespace Src2 { class SomeClass : public QObject { Q_OBJECT public: SomeClass(QObject *parent = nullptr); }; } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src1/0000755000175100001660000000000014776170045025006 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src1/somefile.cpp0000644000175100001660000000020414776170045027311 0ustar runnerdocker#include class MyClass1 : public QObject { Q_OBJECT }; static void f() { MyClass1 m; } #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src1/someclass.cpp0000644000175100001660000000015114776170045027500 0ustar runnerdocker#include "someclass.h" namespace Src1 { SomeClass::SomeClass(QObject *parent) : QObject(parent) { } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/src1/someclass.h0000644000175100001660000000030114776170045027142 0ustar runnerdocker#ifndef SOMECLASS1_H #define SOMECLASS1_H #include namespace Src1 { class SomeClass : public QObject { Q_OBJECT public: SomeClass(QObject *parent = nullptr); }; } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/main.cpp0000644000175100001660000000017214776170045025566 0ustar runnerdocker#include "src1/someclass.h" #include "src2/someclass.h" int main() { Src1::SomeClass sc1; Src2::SomeClass sc2; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-same-file-name/moc-same-file-name.qbs0000644000175100001660000000114014776170045030175 0ustar runnerdockerQtApplication { name: "app" cpp.cxxLanguageVersion: "c++11" files: "main.cpp" Group { name: "src1" Qt.core.generatedHeadersDir: product.buildDirectory + "/qt.headers_src1" prefix: name + '/' files: [ "someclass.cpp", "someclass.h", "somefile.cpp", ] } Group { name: "src2" prefix: name + '/' Qt.core.generatedHeadersDir: product.buildDirectory + "/qt.headers_src2" files: [ "someclass.cpp", "someclass.h", "somefile.cpp", ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-meta-data/0000755000175100001660000000000014776170045023733 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-meta-data/app.cpp0000644000175100001660000000523114776170045025220 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #ifdef QT_STATIC Q_IMPORT_PLUGIN(ThePlugin) #endif int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QJsonObject metaData; for (const QStaticPlugin &p : QPluginLoader::staticPlugins()) { const QJsonObject &md = p.metaData(); if (md.value("className") == "ThePlugin") { metaData = md; break; } } #ifdef QT_STATIC if (metaData.isEmpty()) { qDebug() << "no static metadata"; return 1; } #else if (!metaData.isEmpty()) { qDebug() << "static metadata"; return 1; } #endif if (metaData.isEmpty()) metaData = QPluginLoader("thePlugin").metaData(); const QJsonValue v = metaData.value(QStringLiteral("theKey")); if (!v.isArray()) { qDebug() << "value is" << v; return 1; } const QJsonArray a = v.toArray(); if (a.size() != 1 || a.first() != QLatin1String("theValue")) { qDebug() << "value is" << v; return 1; } const QJsonValue v2 = metaData.value(QStringLiteral("MetaData")).toObject() .value(QStringLiteral("theOtherKey")); if (v2.toString() != QLatin1String("theOtherValue")) { qDebug() << "metadata:" << metaData; return 1; } qDebug() << "all ok!"; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs0000644000175100001660000000331114776170045027571 0ustar runnerdockerimport qbs.Host import qbs.Utilities Project { QtApplication { condition: { if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { // qt4 moc can't be used with pluginMetaData console.info("using qt4"); return false; } var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "app" consoleApplication: true Depends { name: "thePlugin" } cpp.cxxLanguageVersion: "c++11" Properties { condition: qbs.targetOS.includes("unix") cpp.rpaths: [cpp.rpathOrigin] } Group { fileTagsFilter: product.type qbs.install: true } files: ["app.cpp"] } Library { type: Qt.core.staticBuild ? "staticlibrary" : "dynamiclibrary" name: "thePlugin" Depends { name: "cpp" } Depends { name: "Qt.core" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.defines: [Qt.core.staticBuild ? "QT_STATICPLUGIN" : "QT_PLUGIN"] cpp.cxxLanguageVersion: "c++11" cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.includePaths: ["."] Qt.core.pluginMetaData: ["theKey=theValue"] Group { fileTagsFilter: product.type qbs.install: true } files: ["theplugin.cpp"] Group { files: ["metadata.json"] fileTags: ["qt_plugin_metadata"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-meta-data/metadata.json0000644000175100001660000000005014776170045026401 0ustar runnerdocker{ "theOtherKey" : "theOtherValue" } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/plugin-meta-data/theplugin.cpp0000644000175100001660000000263714776170045026446 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include class ThePlugin : public QObject { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.qbs.ThePlugin" FILE "metadata.json") }; #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-moc-run-after-touching-other-cpp-file/0000755000175100001660000000000014776170045030325 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-moc-run-after-touching-other-cpp-file/header2.h0000644000175100001660000000010314776170045032002 0ustar runnerdocker#include class Test2 : public QObject { Q_OBJECT }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-moc-run-after-touching-other-cpp-file/main.cpp0000644000175100001660000000007514776170045031757 0ustar runnerdocker int main(int /*argc*/, char * /*argv*/[]) { return 0; } ././@LongLink0000644000000000000000000000020400000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-moc-run-after-touching-other-cpp-file/no-moc-run-after-touching-other-cpp-file.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-moc-run-after-touching-other-cpp-file/no-moc-run-af0000644000175100001660000000016214776170045032625 0ustar runnerdockerQtApplication { name: "app" files: [ "header1.h", "header2.h", "main.cpp" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/no-moc-run-after-touching-other-cpp-file/header1.h0000644000175100001660000000010314776170045032001 0ustar runnerdocker#include class Test1 : public QObject { Q_OBJECT }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/mixed-build-variants/0000755000175100001660000000000014776170045024632 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs0000644000175100001660000000066114776170045031374 0ustar runnerdockerProject { Probe { id: tcProbe property bool isMsvc: qbs.toolchain.contains("msvc") configure: { console.info("is msvc: " + isMsvc); } } QtApplication { Properties { condition: qbs.toolchain.includes("msvc") Qt.core.qtBuildVariant: "release" qbs.buildVariant: "debug" } Qt.core.qtBuildVariant: "dummy" files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/mixed-build-variants/main.cpp0000644000175100001660000000242314776170045026263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { qDebug("Tach."); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackAddMocInclude/0000755000175100001660000000000014776170045024262 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackAddMocInclude/after/0000755000175100001660000000000014776170045025363 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackAddMocInclude/after/main.cpp0000644000175100001660000000304114776170045027011 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class MyObject : public QObject { Q_OBJECT public: MyObject(QObject *parent = nullptr) : QObject(parent) { } }; int main(int argc, char **argv) { QCoreApplication app(argc, argv); const auto obj = new MyObject(&app); return app.exec(); } #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/0000755000175100001660000000000014776170045025524 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/test.qbs0000644000175100001660000000015514776170045027213 0ustar runnerdockerApplication { Depends { name: "Qt.core" } cpp.cxxLanguageVersion: "c++11" files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/main.cpp0000644000175100001660000000301414776170045027152 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class MyObject : public QObject { Q_OBJECT public: MyObject(QObject *parent = nullptr) : QObject(parent) { } }; int main(int argc, char **argv) { QCoreApplication app(argc, argv); const auto obj = new MyObject(&app); return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/unmocable/0000755000175100001660000000000014776170045022547 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/unmocable/unmocable.qbs0000644000175100001660000000025714776170045025227 0ustar runnerdockerApplication { Depends { name: "Qt.core" } files: ["main.cpp"] Group { files: ["foo.h"] fileTags: ["unmocable"] overrideTags: false } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/unmocable/main.cpp0000644000175100001660000000010014776170045024166 0ustar runnerdocker#include "foo.h" int main() { return someNumber() - 156; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/unmocable/foo.h0000644000175100001660000000007314776170045023503 0ustar runnerdocker#define Q_OBJECT 156 int someNumber() { return Q_OBJECT; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/add-qobject-macro-to-generated-cpp-file/0000755000175100001660000000000014776170045030127 5ustar runnerdocker././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/add-qobject-macro-to-generated-cpp-file/add-qobject-macro-to-generated-cpp-file.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/add-qobject-macro-to-generated-cpp-file/add-qobject-ma0000644000175100001660000000111214776170045032615 0ustar runnerdockerimport qbs.File QtApplication { name: "p" files: ["main.cpp", "object.h"] Group { files: "object.cpp.in" fileTags: "cpp.in" } Rule { inputs: "cpp.in" Artifact { filePath: input.completeBaseName fileTags: "cpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generatating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } cpp.includePaths: path } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/add-qobject-macro-to-generated-cpp-file/object.cpp.in0000644000175100001660000000256714776170045032520 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include // class InternalClass : public QObject // { // Q_OBJECT // }; void Object::f() { } // #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/add-qobject-macro-to-generated-cpp-file/object.h0000644000175100001660000000240314776170045031545 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ class Object { public: void f(); }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/add-qobject-macro-to-generated-cpp-file/main.cpp0000644000175100001660000000243014776170045031556 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "object.h" int main() { Object o; o.f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-and-cxx-combining/0000755000175100001660000000000014776170045024663 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-and-cxx-combining/moc-and-cxx-combining.qbs0000644000175100001660000000015014776170045031447 0ustar runnerdockerQtApplication { cpp.combineCxxSources: true files: ["main.cpp", "myobject.h", "myobject.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-and-cxx-combining/myobject.h0000644000175100001660000000010314776170045026642 0ustar runnerdocker#ifndef MYOBJECT_H #define MYOBJECT_H void useMyObject(); #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-and-cxx-combining/myobject.cpp0000644000175100001660000000027214776170045027204 0ustar runnerdocker#include "myobject.h" #include class MyObject : public QObject { Q_OBJECT public: void use() {} }; void useMyObject() { MyObject().use(); } #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-and-cxx-combining/main.cpp0000644000175100001660000000007114776170045026311 0ustar runnerdocker#include "myobject.h" int main() { useMyObject(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/remove-moc-header-from-file-list/0000755000175100001660000000000014776170045026730 5ustar runnerdocker././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/remove-moc-header-from-file-list/remove-moc-header-from-file-list.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/remove-moc-header-from-file-list/remove-moc-header-fro0000644000175100001660000000013014776170045032730 0ustar runnerdockerQtApplication { name: "p" files: [ "file.h", "file.cpp" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/remove-moc-header-from-file-list/file.cpp0000644000175100001660000000014514776170045030353 0ustar runnerdocker#include "file.h" MyObject::MyObject() {} int main() { MyObject o1; } #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/remove-moc-header-from-file-list/file.h0000644000175100001660000000022114776170045030013 0ustar runnerdocker#pragma once #include class MyObject : public QObject { Q_OBJECT public: MyObject(); signals: void someSignal(); }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackQObjChange/0000755000175100001660000000000014776170045023570 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackQObjChange/bla.cpp0000644000175100001660000000247114776170045025036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "bla.h" int main() { MyObject obj; obj.setObjectName("I am the object!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackQObjChange/i.qbs0000644000175100001660000000064214776170045024531 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "i" property bool dummy: { console.info("object suffix: " + cpp.objectSuffix); console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "Qt.core" } files: [ "bla.cpp", "bla.h" ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackQObjChange/bla_qobject.h0000644000175100001660000000244214776170045026210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class MyObject : public QObject { Q_OBJECT }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/trackQObjChange/bla_noqobject.h0000644000175100001660000000242514776170045026546 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class MyObject : public QObject { }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/included-moc-cpp/0000755000175100001660000000000014776170045023725 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/included-moc-cpp/myobject.h0000644000175100001660000000016514776170045025714 0ustar runnerdocker#ifndef MYOBJECT_H #define MYOBJECT_H #include class MyObject : public QObject { Q_OBJECT }; #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/included-moc-cpp/myobject.cpp0000644000175100001660000000006314776170045026244 0ustar runnerdocker#include "myobject.h" #include qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/included-moc-cpp/included-moc-cpp.qbs0000644000175100001660000000047014776170045027560 0ustar runnerdockerimport qbs.Utilities QtApplication { condition: { if (Utilities.versionCompare(Qt.core.version, "5.0") < 0) { console.info("using qt4"); return false; } return true; } files: [ "main.cpp", "myobject.cpp", "myobject.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/included-moc-cpp/main.cpp0000644000175100001660000000015514776170045025356 0ustar runnerdocker#include "myobject.h" int main() { MyObject o; QObject::connect(&o, &QObject::destroyed, [] { }); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/linker-variant/0000755000175100001660000000000014776170045023530 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/linker-variant/qt-linker-variant.qbs0000644000175100001660000000041514776170045027607 0ustar runnerdockerQtApplication { Probe { id: qtConfigProbe property stringList moduleConfig: Qt.core.moduleConfig configure: { console.info("Qt requires gold: " + moduleConfig.includes("use_gold_linker")); } } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/linker-variant/main.cpp0000644000175100001660000000007414776170045025161 0ustar runnerdocker#include int main() { qDebug() << "Tach."; } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qobject-in-mm/0000755000175100001660000000000014776170045023244 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qobject-in-mm/main.mm0000644000175100001660000000017414776170045024525 0ustar runnerdocker#include class Foo : public QObject { Q_OBJECT }; int main() { Foo foo; return 0; } #include "main.moc" qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qobject-in-mm/qobject-in-mm.qbs0000644000175100001660000000011214776170045026407 0ustar runnerdockerCppApplication { Depends { name: "Qt.core" } files: ["main.mm"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/0000755000175100001660000000000014776170045025440 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/lib.cpp0000644000175100001660000000002314776170045026705 0ustar runnerdockervoid function() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/main.cpp0000644000175100001660000000017714776170045027075 0ustar runnerdocker#include int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs0000644000175100001660000000117214776170045033006 0ustar runnerdockerProduct { name: "p" Probe { id: staticQtChecker property bool staticQt: Qt.core.staticBuild configure: { found = staticQt; if (found) console.info("Qt is static"); } } Group { condition: type.includes("application") files: "main.cpp" } Group { condition: type.includes("staticlibrary") files: "lib.cpp" } Depends { name: "Qt.core" } Depends { name: "Qt.gui" } Depends { name: "Qt.qminimal"; condition: Qt.core.staticBuild && !qbs.toolchain.includes("emscripten") } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qtscxml/0000755000175100001660000000000014776170045022275 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qtscxml/dummystatemachine.scxml0000644000175100001660000000016614776170045027071 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs0000644000175100001660000000404014776170045024475 0ustar runnerdockerimport qbs.Environment import qbs.FileInfo import qbs.Host import qbs.Utilities Project { QtApplication { name: "app" Depends { name: "Qt.scxml"; required: false } Properties { condition: Qt.scxml.present && Utilities.versionCompare(Qt.core.version, "5.13.0") != 0 cpp.defines: ["HAS_QTSCXML"] } Qt.scxml.className: "QbsStateMachine" Qt.scxml.namespace: "QbsTest" Qt.scxml.generateStateMethods: true files: ["main.cpp"] Group { files: ["dummystatemachine.scxml"] fileTags: ["qt.scxml.compilable"] } } Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "runner" type: ["runner"] Depends { name: "app" } Rule { inputsFromDependencies: ["application"] outputFileTags: ["runner"] prepare: { var cmd = new Command(input.filePath); cmd.description = "running " + input.filePath; var envVars = {}; if (Host.os().includes("windows")) { envVars["PATH"] = FileInfo.toWindowsSeparators(input["Qt.core"].binPath); } else if (Host.os().includes("macos")) { envVars["DYLD_LIBRARY_PATH"] = input["Qt.core"].libPath; envVars["DYLD_FRAMEWORK_PATH"] = input["Qt.core"].libPath; } else { envVars["LD_LIBRARY_PATH"] = input["Qt.core"].libPath; } for (var varName in envVars) { var oldValue = Environment.getEnv(varName) || ""; var newValue = envVars[varName] + FileInfo.pathListSeparator() + oldValue; cmd.environment.push(varName + '=' + newValue); } return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qtscxml/main.cpp0000644000175100001660000000045514776170045023731 0ustar runnerdocker#ifdef HAS_QTSCXML #include #endif #include int main() { #ifdef HAS_QTSCXML QbsTest::QbsStateMachine machine; std::cout << "state machine name: " << qPrintable(machine.name()) << std::endl; #else std::cout << "QtScxml not present" << std::endl; #endif } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig-qt/0000755000175100001660000000000014776170045023173 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig-qt/dump-libpath.qbs0000644000175100001660000000017014776170045026266 0ustar runnerdockerQtApplication { files: "main.cpp" property bool test: { console.info("libPath="+Qt.core.libPath) } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig-qt/main.cpp0000644000175100001660000000001614776170045024620 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig-qt/pkgconfig-qt.qbs0000644000175100001660000000016514776170045026275 0ustar runnerdockerQtApplication { name: "p" files: "main.cpp" qbsSearchPaths: "." qbsModuleProviders: "qbspkgconfig" } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig-qt/module-providers/0000755000175100001660000000000014776170045026473 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig-qt/module-providers/dummyProvider.qbs0000644000175100001660000000005714776170045032052 0ustar runnerdockerModuleProvider { relativeSearchPaths: "" } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-adaptors/0000755000175100001660000000000014776170045023352 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.qbs0000644000175100001660000000062114776170045024625 0ustar runnerdockerCppApplication { name: "car" condition: Qt.dbus.present cpp.cxxLanguageVersion: "c++11" Depends { name: "Qt.dbus"; required: false } Depends { name: "Qt.widgets" } files: [ "car.cpp", "car.h", "main.cpp", ] Group { name: "DBUS Adaptor" files: ["THIS.IS.A.STRANGE.FILENAME.CAR.XML"] fileTags: ["qt.dbus.adaptor"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML0000644000175100001660000000062414776170045030063 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp0000644000175100001660000001135514776170045024630 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "car.h" #include #include static const double Pi = 3.14159265358979323846264338327950288419717; QRectF Car::boundingRect() const { return {-35, -81, 70, 115}; } Car::Car() : color(Qt::green), wheelsAngle(0), speed(0) { startTimer(1000 / 33); setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsItem::ItemIsFocusable, true); } void Car::accelerate() { if (speed < 10) ++speed; } void Car::decelerate() { if (speed > -10) --speed; } void Car::turnLeft() { if (wheelsAngle > -30) wheelsAngle -= 5; } void Car::turnRight() { if (wheelsAngle < 30) wheelsAngle += 5; } void Car::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); painter->setBrush(Qt::gray); painter->drawRect(-20, -58, 40, 2); // front axel painter->drawRect(-20, 7, 40, 2); // rear axel painter->setBrush(color); painter->drawRect(-25, -79, 50, 10); // front wing painter->drawEllipse(-25, -48, 50, 20); // side pods painter->drawRect(-25, -38, 50, 35); // side pods painter->drawRect(-5, 9, 10, 10); // back pod painter->drawEllipse(-10, -81, 20, 100); // main body painter->drawRect(-17, 19, 34, 15); // rear wing painter->setBrush(Qt::black); painter->drawPie(-5, -51, 10, 15, 0, 180 * 16); painter->drawRect(-5, -44, 10, 10); // cocpit painter->save(); painter->translate(-20, -58); painter->rotate(wheelsAngle); painter->drawRect(-10, -7, 10, 15); // front left painter->restore(); painter->save(); painter->translate(20, -58); painter->rotate(wheelsAngle); painter->drawRect(0, -7, 10, 15); // front left painter->restore(); painter->drawRect(-30, 0, 12, 17); // rear left painter->drawRect(19, 0, 12, 17); // rear right } void Car::timerEvent(QTimerEvent *event) { Q_UNUSED(event); const qreal axelDistance = 54; qreal wheelsAngleRads = (wheelsAngle * Pi) / 180; qreal turnDistance = ::cos(wheelsAngleRads) * axelDistance * 2; qreal turnRateRads = wheelsAngleRads / turnDistance; // rough estimate qreal turnRate = (turnRateRads * 180) / Pi; qreal rotation = speed * turnRate; setTransform(QTransform().rotate(rotation), true); setTransform(QTransform::fromTranslate(0, -speed), true); update(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.h0000644000175100001660000000351014776170045024267 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CAR_H #define CAR_H #include #include class Car : public QGraphicsObject { Q_OBJECT public: Car(); QRectF boundingRect() const; public Q_SLOTS: void accelerate(); void decelerate(); void turnLeft(); void turnRight(); Q_SIGNALS: void crashed(); protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); void timerEvent(QTimerEvent *event); private: QBrush color; qreal wheelsAngle; // used when applying rotation qreal speed; // delta movement along the body axis }; #endif // CAR_H qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp0000644000175100001660000000663014776170045025007 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "car.h" #include "car_adaptor.h" #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #include #include #else #include #include #include #endif #include int main(int argc, char *argv[]) { QApplication app(argc, argv); QGraphicsScene scene; scene.setSceneRect(-500, -500, 1000, 1000); scene.setItemIndexMethod(QGraphicsScene::NoIndex); const auto car = new Car(); scene.addItem(car); QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); view.setBackgroundBrush(Qt::darkGray); view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Qt DBus Controlled Car")); view.resize(400, 300); view.show(); new CarInterfaceAdaptor(car); QDBusConnection connection = QDBusConnection::sessionBus(); connection.registerObject("/Car", car); connection.registerService("org.example.CarExample"); return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-flags/0000755000175100001660000000000014776170045022452 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-flags/blubb.h0000644000175100001660000000251714776170045023716 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class Blubb : public QObject { Q_OBJECT public: Blubb() { } void makeBlubb() { } }; qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-flags/main.cpp0000644000175100001660000000242714776170045024107 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "blubb.h" int main() { Blubb().makeBlubb(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/moc-flags/moc-flags.qbs0000644000175100001660000000006514776170045025032 0ustar runnerdockerQtApplication { files: ["main.cpp", "blubb.h"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig/0000755000175100001660000000000014776170045022551 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig/main.cpp0000644000175100001660000000303014776170045024175 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef QT_CORE_LIB #include #include #else #include #endif int main(int argc, char **argv) { #ifdef QT_CORE_LIB QCoreApplication app(argc, argv); qDebug() << "Hello world!"; #else (void)argc; (void)argv; std::cout << "Skip this test" << std::endl; #endif } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/pkgconfig/pkgconfig.qbs0000644000175100001660000000116314776170045025230 0ustar runnerdockerimport qbs.Host import qbs.Probes Project { property string name: 'pkgconfig' CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: project.name Probes.PkgConfigProbe { id: pkgConfig name: "QtCore" minVersion: '4.0.0' maxVersion: '5.99.99' } files: 'main.cpp' cpp.cxxFlags: pkgConfig.cflags cpp.linkerFlags: pkgConfig.libs } } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qt-keywords/0000755000175100001660000000000014776170045023073 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qt-keywords/qt-keywords.qbs0000644000175100001660000000005214776170045026070 0ustar runnerdockerQtApplication { files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-qt/qt-keywords/main.cpp0000644000175100001660000000021314776170045024517 0ustar runnerdocker#include class AnObject : public QObject { Q_OBJECT signals: void someSignal(); }; int main() { } #include qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxexamples.h0000644000175100001660000000363014776170045022740 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef TST_BLACKBOXEXAMPLES_H #define TST_BLACKBOXEXAMPLES_H #include "tst_blackboxbase.h" class TestBlackboxExamples : public TestBlackboxBase { Q_OBJECT private: QStringList collectExamples(const QString &dirPath); public: TestBlackboxExamples(); private slots: void baremetal_data(); void baremetal(); void examples_data(); void examples(); }; #endif // TST_BLACKBOXEXAMPLES_H qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxjava.cpp0000644000175100001660000002447214776170045022405 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackboxjava.h" #include "../shared.h" #include #include #include #include #include using qbs::Internal::HostOsInfo; using qbs::Profile; TestBlackboxJava::TestBlackboxJava() : TestBlackboxBase (SRCDIR "/testdata-java", "blackbox-java"), m_blacklistedJdks(qgetenv("QBS_AUTOTEST_JDK_BLACKLIST")) { } static QProcessEnvironment processEnvironmentWithCurrentDirectoryInLibraryPath() { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(HostOsInfo::libraryPathEnvironmentVariable(), (QStringList() << env.value(HostOsInfo::libraryPathEnvironmentVariable()) << ".") .join(HostOsInfo::pathListSeparator())); return env; } void TestBlackboxJava::java() { #if defined(Q_OS_WIN32) && !defined(Q_OS_WIN64) QSKIP("QTBUG-3845"); #endif const SettingsPtr s = settings(); Profile p(profileName(), s.get()); int status; const auto jdkTools = findJdkTools(&status); QCOMPARE(status, 0); QDir::setCurrent(testDataDir + "/java"); status = runQbs(); if (p.value("java.jdkPath").toString().isEmpty() && status != 0 && m_qbsStderr.contains("jdkPath")) { QSKIP("java.jdkPath not set and automatic detection failed"); } if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Skip test in cross-compiled build"); QCOMPARE(status, 0); const QStringList classFiles = QStringList() << "Jet" << "Ship" << "Vehicles"; QStringList classFiles1 = QStringList(classFiles) << "io/qt/qbs/HelloWorld" << "NoPackage"; for (QString &classFile : classFiles1) { classFile = relativeProductBuildDir("cc") + "/classes/" + classFile + ".class"; QVERIFY2(regularFileExists(classFile), qPrintable(classFile)); } for (const QString &classFile : classFiles) { const QString filePath = relativeProductBuildDir("jar_file") + "/classes/" + classFile + ".class"; QVERIFY2(regularFileExists(filePath), qPrintable(filePath)); } const QString jarFilePath = relativeProductBuildDir("jar_file") + '/' + "jar_file.jar"; QVERIFY2(regularFileExists(jarFilePath), qPrintable(jarFilePath)); // Now check whether we correctly predicted the class file output paths. QCOMPARE(runQbs(QbsRunParameters("clean")), 0); for (const QString &classFile : std::as_const(classFiles1)) { QVERIFY2(!regularFileExists(classFile), qPrintable(classFile)); } // This tests various things: java.manifestClassPath, JNI, etc. QDir::setCurrent(relativeBuildDir() + "/install-root"); QProcess process; process.setProcessEnvironment(processEnvironmentWithCurrentDirectoryInLibraryPath()); process.start(HostOsInfo::appendExecutableSuffix(jdkTools["java"]), QStringList() << "-jar" << "jar_file.jar"); if (process.waitForStarted()) { QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); QVERIFY2(process.exitCode() == 0, process.readAllStandardError().constData()); const QByteArray stdOut = process.readAllStandardOutput(); QVERIFY2(stdOut.contains("Driving!"), stdOut.constData()); QVERIFY2(stdOut.contains("Flying!"), stdOut.constData()); QVERIFY2(stdOut.contains("Flying (this is a space ship)!"), stdOut.constData()); QVERIFY2(stdOut.contains("Sailing!"), stdOut.constData()); QVERIFY2(stdOut.contains("Native code performing complex internal combustion process ("), stdOut.constData()); } process.start("unzip", QStringList() << "-p" << "jar_file.jar"); if (process.waitForStarted()) { QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); const QByteArray stdOut = process.readAllStandardOutput(); QVERIFY2(stdOut.contains("Class-Path: random_stuff.jar car_jar.jar"), stdOut.constData()); QVERIFY2(stdOut.contains("Main-Class: Vehicles"), stdOut.constData()); QVERIFY2(stdOut.contains("Some-Property: Some-Value"), stdOut.constData()); QVERIFY2(stdOut.contains("Additional-Property: Additional-Value"), stdOut.constData()); QVERIFY2(stdOut.contains("Extra-Property: Crazy-Value"), stdOut.constData()); } } static QString dpkgArch(const QString &prefix = QString()) { QProcess dpkg; dpkg.start("/usr/bin/dpkg", QStringList() << "--print-architecture"); dpkg.waitForFinished(); if (dpkg.exitStatus() == QProcess::NormalExit && dpkg.exitCode() == 0) return prefix + QString::fromLocal8Bit(dpkg.readAllStandardOutput().trimmed()); return {}; } void TestBlackboxJava::javaDependencyTracking() { QFETCH(QString, jdkPath); QFETCH(QString, javaVersion); QDir::setCurrent(testDataDir + "/java"); QbsRunParameters rp; rp.arguments.push_back("--check-outputs"); if (!jdkPath.isEmpty()) { if (m_blacklistedJdks.contains(jdkPath)) QSKIP("skipping blacklisted JDK"); rp.arguments << ("modules.java.jdkPath:" + jdkPath); } if (!javaVersion.isEmpty()) rp.arguments << ("modules.java.languageVersion:'" + javaVersion + "'"); rmDirR(relativeBuildDir()); const bool defaultJdkPossiblyTooOld = jdkPath.isEmpty() && !javaVersion.isEmpty(); rp.expectFailure = defaultJdkPossiblyTooOld; QVERIFY(runQbs(rp) == 0 || (defaultJdkPossiblyTooOld && m_qbsStderr.contains("invalid source release"))); } void TestBlackboxJava::javaDependencyTracking_data() { QTest::addColumn("jdkPath"); QTest::addColumn("javaVersion"); const SettingsPtr s = settings(); Profile p(profileName(), s.get()); auto getSpecificJdkVersion = [](const QString &jdkVersion) -> QString { if (HostOsInfo::isMacosHost()) { QProcess java_home; java_home.start("/usr/libexec/java_home", {"--version", jdkVersion, "--failfast"}); java_home.waitForFinished(); if (java_home.exitStatus() == QProcess::NormalExit && java_home.exitCode() == 0) return QString::fromLocal8Bit(java_home.readAllStandardOutput().trimmed()); } else if (HostOsInfo::isWindowsHost()) { QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\" + jdkVersion, QSettings::NativeFormat); return settings.value("JavaHome").toString(); } else { QString minorVersion = jdkVersion; if (minorVersion.startsWith("1.")) minorVersion.remove(0, 2); const QStringList searchPaths = { "/usr/lib/jvm/java-" + minorVersion + "-openjdk" + dpkgArch("-"), // Debian "/usr/lib/jvm/java-" + minorVersion + "-openjdk", // Arch "/usr/lib/jvm/jre-1." + minorVersion + ".0-openjdk", // Fedora "/usr/lib64/jvm/java-1." + minorVersion + ".0-openjdk", // OpenSuSE }; for (const QString &searchPath : searchPaths) { if (QFile::exists(searchPath + "/bin/javac")) return searchPath; } } return {}; }; static const auto knownJdkVersions = QStringList() << "1.7" << "1.8" << "1.9" << QString(); // default JDK; QStringList seenJdkVersions; for (const auto &jdkVersion : knownJdkVersions) { QString specificJdkPath = getSpecificJdkVersion(jdkVersion); if (jdkVersion.isEmpty() || !specificJdkPath.isEmpty()) { const auto jdkPath = jdkVersion.isEmpty() ? jdkVersion : specificJdkPath; if (!jdkVersion.isEmpty()) seenJdkVersions << jdkVersion; if (!seenJdkVersions.empty()) { const auto javaVersions = QStringList() << knownJdkVersions.mid(0, knownJdkVersions.indexOf(seenJdkVersions.last()) + 1) << QString(); // also test with no explicitly specified source version for (const auto ¤tJavaVersion : javaVersions) { const QString rowName = (!jdkPath.isEmpty() ? jdkPath : "default JDK") + QStringLiteral(", ") + (!currentJavaVersion.isEmpty() ? ("Java " + currentJavaVersion) : "default Java version"); QTest::newRow(rowName.toLatin1().constData()) << jdkPath << currentJavaVersion; } } } } if (seenJdkVersions.empty()) QSKIP("No JDKs installed"); } void TestBlackboxJava::javaDependencyTrackingInnerClass() { const SettingsPtr s = settings(); Profile p(profileName(), s.get()); QDir::setCurrent(testDataDir + "/java/inner-class"); QbsRunParameters params; int status = runQbs(params); if (p.value("java.jdkPath").toString().isEmpty() && status != 0 && m_qbsStderr.contains("jdkPath")) { QSKIP("java.jdkPath not set and automatic detection failed"); } QCOMPARE(status, 0); } QTEST_MAIN(TestBlackboxJava) qbs-src-2.6.1/tests/auto/blackbox/testdata-android/0000755000175100001660000000000014776170045021576 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/0000755000175100001660000000000014776170045023145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/src/0000755000175100001660000000000014776170045023734 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/src/main/0000755000175100001660000000000014776170045024660 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/src/main/assets/0000755000175100001660000000000014776170045026162 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/src/main/assets/dummyasset.txt0000644000175100001660000000000014776170045031104 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml0000644000175100001660000001167714776170045030465 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/main.qml0000644000175100001660000000021114776170045024576 0ustar runnerdockerimport QtQuick 2.6 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/qml.qrc0000644000175100001660000000012714776170045024445 0ustar runnerdocker main.qml qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/qml-app.qbs0000644000175100001660000000063614776170045025230 0ustar runnerdockerQtApplication { name: "qmlapp" Depends { name: "Qt.quick" } Depends { name: "Qt.android_support" } Properties { condition: qbs.targetOS.includes("android") Qt.android_support.extraPrefixDirs: path } Android.sdk.packageName: "my.qmlapp" Android.sdk.apkBaseName: name Qt.android_support.qmlImportPaths: path files: [ "main.cpp", "qml.qrc", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qml-app/main.cpp0000644000175100001660000000111014776170045024566 0ustar runnerdocker#include #include int main(int argc, char *argv[]) { if (qEnvironmentVariableIsEmpty("QTGLESSTREAM_DISPLAY")) { qputenv("QT_QPA_EGLFS_PHYSICAL_WIDTH", QByteArray("213")); qputenv("QT_QPA_EGLFS_PHYSICAL_HEIGHT", QByteArray("120")); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); } QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/0000755000175100001660000000000014776170045023000 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/TestQt6.java0000644000175100001660000000260414776170045025157 0ustar runnerdockerpackage org.qbs.example; import org.qtproject.qt.android.bindings.QtActivity; import android.os.*; import android.content.*; import android.app.*; import android.util.Log; import java.lang.String; import android.content.Intent; import org.qbs.example.*; public class TestQt6 extends QtActivity { public static native void testFunc(String test); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("qbs", "onCreate Test"); Intent theIntent = getIntent(); if (theIntent != null) { String theAction = theIntent.getAction(); if (theAction != null) { Log.d("qbs onCreate ", theAction); } } } @Override public void onDestroy() { Log.d("qbs", "onDestroy"); System.exit(0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("qbs onActivityResult", "requestCode: "+requestCode); if (resultCode == RESULT_OK) { Log.d("qbs onActivityResult - resultCode: ", "SUCCESS"); } else { Log.d("qbs onActivityResult - resultCode: ", "CANCEL"); } } @Override public void onNewIntent(Intent intent) { Log.d("qbs", "onNewIntent"); super.onNewIntent(intent); setIntent(intent); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/test.keystore0000644000175100001660000000240414776170045025546 0ustar runnerdockerqbstestwg00 +*ոR9C!Y5!CJ<"_'ҲS__^eszIegƒgL*<z6N wBav Y&vgêe,˷u`?-2Z 5 ]J3y:LJ!Eh@w׶7,DL,mf &ݙ، ojX+N_s6Ȍ\ΆQZC0*=цkip<؛XLe_@ ^N7(Sě"+*^kdp58U{sx5`+yzi:'"$uB0y~Mҝۈ"{ 'D%3;ӱWc7[Bd$ȴRIB,yuUl0I6X.50900gw20  *H  021 0 UUS10U Android10Uqbs test0 210118213023Z 480605213023Z021 0 UUS10U Android10Uqbs test00  *H 0>_\e_r'1[ޤ%RP cK vи..UPmNL#@-w:!ƙ U;)VCF/ׂ@ՋVmc6+&G@$7!00U>r!i&y~`(Z 0  *H  wGg5Vk0O)S>hE5ȕ+5$~T]IyTr.B,4R$Y:rjV}S-e.?ead1z/bJguW)0Uؼ@;柋k>iT:%QevRqbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/MainWindow.h0000644000175100001660000000033214776170045025223 0ustar runnerdocker#ifndef MAINWINDOW_H #define MAINWINDOW_H #include class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); }; #endif // MAINWINDOW_H qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/MainWindow.cpp0000644000175100001660000000017714776170045025565 0ustar runnerdocker#include "MainWindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { } MainWindow::~MainWindow() { } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/main.cpp0000644000175100001660000000025414776170045024431 0ustar runnerdocker#include "MainWindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/qt-app.qbs0000644000175100001660000000122014776170045024704 0ustar runnerdockerProject { QtGuiApplication { Depends { name: "Lib" } files: ["main.cpp", "MainWindow.cpp", "MainWindow.h" ] Group { condition: Qt.core.versionMajor == 5 files: ["Test.java"] } Group { condition: Qt.core.versionMajor == 6 files: ["TestQt6.java"] } Android.sdk.packageName: "my.qtapp" Android.sdk.apkBaseName: name Depends { name: "Qt"; submodules: ["core", "widgets"] } } StaticLibrary { name: "Lib" Export { Depends { name: "Qt.android_support"; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/qt-app/Test.java0000644000175100001660000000260214776170045024562 0ustar runnerdockerpackage org.qbs.example; import org.qtproject.qt5.android.bindings.QtActivity; import android.os.*; import android.content.*; import android.app.*; import android.util.Log; import java.lang.String; import android.content.Intent; import org.qbs.example.*; public class Test extends QtActivity { public static native void testFunc(String test); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("qbs", "onCreate Test"); Intent theIntent = getIntent(); if (theIntent != null) { String theAction = theIntent.getAction(); if (theAction != null) { Log.d("qbs onCreate ", theAction); } } } @Override public void onDestroy() { Log.d("qbs", "onDestroy"); System.exit(0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("qbs onActivityResult", "requestCode: "+requestCode); if (resultCode == RESULT_OK) { Log.d("qbs onActivityResult - resultCode: ", "SUCCESS"); } else { Log.d("qbs onActivityResult - resultCode: ", "CANCEL"); } } @Override public void onNewIntent(Intent intent) { Log.d("qbs", "onNewIntent"); super.onNewIntent(intent); setIntent(intent); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/0000755000175100001660000000000014776170045026615 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/multiple-apks-per-project.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/multiple-apks-per-proje0000644000175100001660000000011414776170045033224 0ustar runnerdockerProject { references: [ "product1", "product2", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/0000755000175100001660000000000014776170045030356 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/0000755000175100001660000000000014776170045031145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/0000755000175100001660000000000014776170045032071 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/res/0000755000175100001660000000000014776170045032662 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/res/values/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/res/v0000755000175100001660000000000014776170045033050 5ustar runnerdocker././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/res/values/strings.xmlqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/res/v0000644000175100001660000000010514776170045033046 0ustar runnerdocker dummy1 ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xmlqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/Andro0000644000175100001660000000145114776170045033060 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/0000755000175100001660000000000014776170045033012 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/io/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/0000755000175100001660000000000014776170045033012 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/io/qt/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/0000755000175100001660000000000014776170045033012 5ustar runnerdocker././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/io/qt/dummy1/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/0000755000175100001660000000000014776170045033012 5ustar runnerdocker././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/io/qt/dummy1/Dummy.javaqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/java/0000644000175100001660000000070714776170045033020 0ustar runnerdockerpackage io.qt.dummy1; import android.app.Activity; import android.os.Build; import java.util.Arrays; import java.util.List; public class Dummy extends Activity { static { List abis = Arrays.asList(Build.SUPPORTED_ABIS); if (abis.contains("x86") || abis.contains("mips")) { System.loadLibrary("p1lib1"); } if (abis.contains("armeabi")) { System.loadLibrary("p1lib2"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/jni/0000755000175100001660000000000014776170045032651 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/jni/lib1.cppqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/jni/l0000644000175100001660000000234714776170045033035 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f() {} ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/jni/lib2.cppqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/jni/l0000644000175100001660000000234714776170045033035 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void g() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/product1.qbs0000644000175100001660000000222014776170045032622 0ustar runnerdockerProject { DynamicLibrary { Depends { name: "Android.ndk" } Depends { name: "cpp" } name: "p1lib1" files: ["src/main/jni/lib1.cpp"] qbs.targetPlatform: "android" Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" Properties { qbs.architectures: !qbs.architecture ? ["armv7a", "x86"] : undefined overrideListProperties: true } cpp.useRPaths: false } DynamicLibrary { Depends { name: "Android.ndk" } Depends { name: "cpp" } name: "p1lib2" files: ["src/main/jni/lib2.cpp"] qbs.targetPlatform: "android" Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" cpp.useRPaths: false } Application { name: "twolibs1" Android.sdk.apkBaseName: name Android.sdk.packageName: "io.qt.dummy1" Depends { productTypes: ["android.nativelibrary"] limitToSubProject: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/0000755000175100001660000000000014776170045030357 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/0000755000175100001660000000000014776170045031146 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/0000755000175100001660000000000014776170045032072 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xmlqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/Andro0000644000175100001660000000145114776170045033061 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/0000755000175100001660000000000014776170045033013 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/io/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/0000755000175100001660000000000014776170045033013 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/io/qt/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/0000755000175100001660000000000014776170045033013 5ustar runnerdocker././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/io/qt/dummy2/qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/0000755000175100001660000000000014776170045033013 5ustar runnerdocker././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/io/qt/dummy2/Dummy.javaqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/java/0000644000175100001660000000060014776170045033011 0ustar runnerdockerpackage io.qt.dummy2; import android.app.Activity; import android.os.Build; import java.util.Arrays; import java.util.List; public class Dummy extends Activity { static { List abis = Arrays.asList(Build.SUPPORTED_ABIS); if (abis.contains("armeabi")) { System.loadLibrary("p2lib1"); System.loadLibrary("p2lib2"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/jni/0000755000175100001660000000000014776170045032652 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/jni/lib1.cppqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/jni/l0000644000175100001660000000234714776170045033036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f() {} ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/jni/lib2.cppqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/jni/l0000644000175100001660000000234714776170045033036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void g() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/product2.qbs0000644000175100001660000000144114776170045032630 0ustar runnerdockerProject { DynamicLibrary { Depends { name: "cpp" } name: "p2lib1" files: ["src/main/jni/lib1.cpp"] qbs.targetPlatform: "android" cpp.useRPaths: false } DynamicLibrary { Depends { name: "Android.ndk" } Depends { name: "cpp" } name: "p2lib2" files: ["src/main/jni/lib2.cpp"] qbs.targetPlatform: "android" Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" } Application { name: "twolibs2" Android.sdk.apkBaseName: name Android.sdk.packageName: "io.qt.dummy2" Depends { productTypes: ["android.nativelibrary"] limitToSubProject: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/0000755000175100001660000000000014776170045024510 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs0000644000175100001660000000065414776170045030136 0ustar runnerdockerCppApplication { name: "minimalnative" qbs.buildVariant: "release" Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.sdk.packageName: "my.minimalnative" Android.sdk.apkBaseName: name Android.ndk.appStl: "stlport_shared" files: "src/main/native/native.c" Group { files: "libdependency.so" fileTags: "android.nativelibrary" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/0000755000175100001660000000000014776170045025277 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/0000755000175100001660000000000014776170045026223 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml0000644000175100001660000000103214776170045032010 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/0000755000175100001660000000000014776170045027511 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c0000644000175100001660000000033514776170045031144 0ustar runnerdocker#include #include jstring Java_minimalnative_MinimalNative_stringFromNative(JNIEnv* env, jobject thiz) { (void)thiz; return (*env)->NewStringUTF(env, "This message comes from native code."); } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/0000755000175100001660000000000014776170045027144 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/my/0000755000175100001660000000000014776170045027571 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/my/minimal/0000755000175100001660000000000014776170045031217 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/my/minimal/MinimalNative.javaqbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/my/minimal/MinimalNa0000644000175100001660000000070614776170045033012 0ustar runnerdockerpackage minimalnative; import android.app.Activity; import android.widget.TextView; import android.os.Bundle; public class MinimalNative extends Activity { @Override public void onCreate(Bundle savedInstanceState) { TextView tv = new TextView(this); tv.setText(stringFromNative()); setContentView(tv); } public native String stringFromNative(); static { System.loadLibrary("minimal"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/minimal-native/libdependency.so0000644000175100001660000000000014776170045027646 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/no-native/0000755000175100001660000000000014776170045023476 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/no-native/no-native.qbs0000644000175100001660000000044014776170045026103 0ustar runnerdockerApplication { qbs.targetPlatform: "android" name: "com.example.android.basicmediadecoder" Android.sdk.sourceSetDir: Android.sdk.sdkDir + "/samples/android-BasicMediaDecoder/Application/src/main" Android.sdk.versionCode: 5 Android.sdk.versionName: "5.0" } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/0000755000175100001660000000000014776170045025715 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/lib4.java0000644000175100001660000000002614776170045027410 0ustar runnerdockerpublic class lib4 { } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/multiple-libs-per-apk.qbs0000644000175100001660000000463514776170045032553 0ustar runnerdockerProject { DynamicLibrary { Depends { name: "Android.ndk" } Depends { name: "cpp" } name: "lib1" files: ["src/main/jni/lib1.cpp"] qbs.targetPlatform: "android" Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" cpp.useRPaths: false } DynamicLibrary { Depends { name: "Android.ndk" } Depends { name: "cpp" } name: "lib2" files: ["src/main/jni/lib2.cpp"] qbs.targetPlatform: "android" Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "stlport_shared" cpp.useRPaths: false } JavaJarFile { Depends { name: "Android.sdk" } Android.sdk.packageName: undefined Android.sdk.automaticSources: false Depends { name: "lib6" } Depends { name: "lib8" } name: "lib3" files: ["io/qbs/lib3/lib3.java"] } JavaJarFile { Depends { name: "Android.sdk" } Android.sdk.packageName: undefined Android.sdk.automaticSources: false name: "lib4" files: ["lib4.java"] } JavaJarFile { Depends { name: "Android.sdk" } Android.sdk.packageName: undefined Android.sdk.automaticSources: false name: "lib5" files: ["lib5.java"] } JavaJarFile { Depends { name: "Android.sdk" } Android.sdk.packageName: undefined Android.sdk.automaticSources: false name: "lib6" files: ["lib6.java"] } JavaJarFile { Depends { name: "Android.sdk" } Android.sdk.packageName: undefined Android.sdk.automaticSources: false name: "lib7" files: ["lib7.java"] } JavaJarFile { Depends { name: "Android.sdk" } Android.sdk.packageName: undefined Android.sdk.automaticSources: false Depends { name: "lib7"; Android.sdk.embedJar: false } name: "lib8" files: ["lib8.java"] } Application { name: "twolibs" Android.sdk.apkBaseName: name Android.sdk.packageName: "io.qt.dummy" Depends { productTypes: ["android.nativelibrary"] } Depends { name: "lib3"; Android.sdk.embedJar: true } Depends { name: "lib4"; Android.sdk.embedJar: false } Depends { name: "lib5" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/lib8.java0000644000175100001660000000002614776170045027414 0ustar runnerdockerpublic class lib8 { } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/lib7.java0000644000175100001660000000002614776170045027413 0ustar runnerdockerpublic class lib7 { } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/io/0000755000175100001660000000000014776170045026324 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/io/qbs/0000755000175100001660000000000014776170045027111 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/io/qbs/lib3/0000755000175100001660000000000014776170045027742 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/io/qbs/lib3/lib3.java0000644000175100001660000000012114776170045031430 0ustar runnerdockerpackage io.qbs.lib3; public class lib3 { public static void foo() { } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/0000755000175100001660000000000014776170045026504 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/0000755000175100001660000000000014776170045027430 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/res/0000755000175100001660000000000014776170045030221 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/res/values/0000755000175100001660000000000014776170045031520 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/res/values/strings.xmlqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/res/values/strings0000644000175100001660000000010414776170045033127 0ustar runnerdocker dummy ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xmlqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xm0000644000175100001660000000145014776170045033045 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/java/0000755000175100001660000000000014776170045030351 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/java/io/0000755000175100001660000000000014776170045030760 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/java/io/qt/0000755000175100001660000000000014776170045031404 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/java/io/qt/dummy/0000755000175100001660000000000014776170045032537 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/java/io/qt/dummy/Dummy.javaqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/java/io/qt/dummy/D0000644000175100001660000000065014776170045032646 0ustar runnerdockerpackage io.qt.dummy; import android.app.Activity; import android.os.Build; import io.qbs.lib3.lib3; import java.util.Arrays; import java.util.List; public class Dummy extends Activity { static { List abis = Arrays.asList(Build.SUPPORTED_ABIS); if (abis.contains("armeabi")) { System.loadLibrary("lib1"); System.loadLibrary("lib2"); } lib3.foo(); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/jni/0000755000175100001660000000000014776170045030210 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/jni/lib1.cpp0000644000175100001660000000234714776170045031551 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/jni/lib2.cpp0000644000175100001660000000234714776170045031552 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void g() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/lib6.java0000644000175100001660000000002614776170045027412 0ustar runnerdockerpublic class lib6 { } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/lib5.java0000644000175100001660000000002614776170045027411 0ustar runnerdockerpublic class lib5 { } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/teapot/0000755000175100001660000000000014776170045023072 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/teapot/teapot.qbs0000644000175100001660000001145514776170045025103 0ustar runnerdockerimport qbs.File Project { minimumQbsVersion: qbs.version StaticLibrary { name: "native-glue" qbs.targetPlatform: "android" cpp.warningLevel: "none" Depends { name: "cpp" } Group { id: glue_sources prefix: Android.ndk.ndkDir + "/sources/android/native_app_glue/" files: ["*.c", "*.h"] } Export { Depends { name: "cpp" } cpp.includePaths: [glue_sources.prefix] cpp.dynamicLibraries: ["log"] } } StaticLibrary { name: "ndk-helper" qbs.targetPlatform: "android" cpp.warningLevel: "none" Depends { name: "Android.ndk" } Depends { name: "cpp" } Depends { name: "native-glue" } Probe { id: ndkHelperProbe property string ndkDir: Android.ndk.ndkDir property string samplesDir: Android.ndk.ndkSamplesDir property string dir configure: { var paths = [samplesDir + "/teapots/common/ndk_helper/", ndkDir + "/sources/android/ndk_helper/"]; for (var i = 0; i < paths.length; ++i) { if (File.exists(paths[i])) { dir = paths[i]; break; } } } } property string ndkDir: ndkHelperProbe.dir Group { id: ndkhelper_sources prefix: ndkHelperProbe.dir files: ["*.cpp", "*.h"].concat( !File.exists(ndkHelperProbe.dir + "/gl3stub.cpp") ? ["gl3stub.c"] : []) } Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "gnustl_shared" cpp.cxxLanguageVersion: "c++11" Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.ndkDir] cpp.dynamicLibraries: ["log", "android", "EGL", "GLESv2"] } } StaticLibrary { name: "android_cpufeatures" qbs.targetPlatform: "android" Depends { name: "cpp" } Group { id: cpufeatures_sources prefix: Android.ndk.ndkDir + "/sources/android/cpufeatures/" files: ["*.c", "*.h"] } Export { Depends { name: "cpp" } cpp.includePaths: [cpufeatures_sources.prefix] cpp.dynamicLibraries: ["dl"] } } CppApplication { name: "TeapotNativeActivity" qbs.targetPlatform: "android" Depends { name: "Android.ndk" } Depends { name: "cpp" } Depends { name: "android_cpufeatures" } Depends { name: "native-glue" } Depends { name: "ndk-helper" } Probe { id: teapotProbe property string samplesDir: Android.sdk.ndkSamplesDir property string dir configure: { var paths = ["/teapots/classic-teapot/src/main", "/Teapot/app/src/main", "/Teapot"]; for (var i = 0; i < paths.length; ++i) { if (File.exists(samplesDir + paths[i])) { dir = samplesDir + paths[i]; break; } } } } Probe { id: teapotProbeJni property string samplesDir: Android.ndk.ndkSamplesDir property string jniDir configure: { var paths = ["/teapots/classic-teapot/src/main/cpp/", "/Teapot/app/src/main/jni/", "/Teapot/jni/"]; for (var i = 0; i < paths.length; ++i) { if (File.exists(samplesDir + paths[i])) { jniDir = samplesDir + paths[i]; break; } } } } Group { name: "C++ sources" prefix: teapotProbeJni.jniDir files: [ "TeapotNativeActivity.cpp", "TeapotRenderer.cpp", "TeapotRenderer.h", "teapot.inl", ] } FileTagger { patterns: ["*.inl"]; fileTags: ["hpp"] } version: "2.0" Android.sdk.apkBaseName: name Android.sdk.packageName: "com.sample.teapot" Android.sdk.sourceSetDir: teapotProbe.dir Properties { condition: qbs.toolchain.includes("clang"); Android.ndk.appStl: "c++_shared" } Android.ndk.appStl: "gnustl_shared" cpp.cxxLanguageVersion: "c++11" cpp.dynamicLibraries: ["log", "android", "EGL", "GLESv2"] cpp.useRPaths: false // Export ANativeActivity_onCreate(), // Refer to: https://github.com/android-ndk/ndk/issues/381 cpp.linkerFlags: ["-u", "ANativeActivity_onCreate"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/0000755000175100001660000000000014776170045022507 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/AndroidManifest.xml0000644000175100001660000000103114776170045026273 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/io/0000755000175100001660000000000014776170045023116 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/io/qbs/0000755000175100001660000000000014776170045023703 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/io/qbs/aidltest/0000755000175100001660000000000014776170045025514 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/io/qbs/aidltest/Interface1.aidl0000644000175100001660000000022514776170045030327 0ustar runnerdockerpackage io.qbs.aidltest; import io.qbs.aidltest.Interface2; interface Interface1 { void doSomething(in Interface2 param1, in Bundle param2); } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/io/qbs/aidltest/MainActivity.java0000644000175100001660000000061414776170045030761 0ustar runnerdockerpackage io.qbs.aidltest; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView label = new TextView(this); label.setText("Hello world!"); setContentView(label); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/io/qbs/aidltest/Interface2.aidl0000644000175100001660000000013014776170045030323 0ustar runnerdockerpackage io.qbs.aidltest; interface Interface2 { void someFunc(in Bundle params); } qbs-src-2.6.1/tests/auto/blackbox/testdata-android/aidl/aidl.qbs0000644000175100001660000000024114776170045024124 0ustar runnerdockerApplication { name: "io.qbs.aidltest" Android.sdk.aidlSearchPaths: path files: [ "AndroidManifest.xml", "io/qbs/aidltest/*", ] } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxwindows.h0000644000175100001660000000371614776170045022621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef TST_BLACKBOXWINDOWS_H #define TST_BLACKBOXWINDOWS_H #include "tst_blackboxbase.h" class TestBlackboxWindows : public TestBlackboxBase { Q_OBJECT public: TestBlackboxWindows(); public slots: void initTestCase() override; private slots: void innoSetup(); void innoSetupDependencies(); void standaloneCodesign(); void standaloneCodesign_data(); void wix(); void wixDependencies(); }; #endif // TST_BLACKBOXWINDOWS_H qbs-src-2.6.1/tests/auto/blackbox/blackbox-providers.qbs0000644000175100001660000000101514776170045022653 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-providers" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-providers/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxproviders.cpp", "tst_blackboxproviders.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxtutorial.h0000644000175100001660000000344414776170045022770 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef TST_BLACKBOXTUTORIAL_H #define TST_BLACKBOXTUTORIAL_H #include "tst_blackboxbase.h" class TestBlackboxTutorial : public TestBlackboxBase { Q_OBJECT public: TestBlackboxTutorial(); private slots: void tutorial_data(); void tutorial(); }; #endif // TST_BLACKBOXTUTORIAL_H qbs-src-2.6.1/tests/auto/blackbox/find/0000755000175100001660000000000014776170045017267 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/find/find-nodejs.qbs0000644000175100001660000000167514776170045022207 0ustar runnerdockerimport qbs.TextFile Product { Depends { name: "nodejs"; required: false } type: ["json"] Rule { multiplex: true Artifact { filePath: ["nodejs.json"] fileTags: ["json"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; if (product.moduleProperty("nodejs", "present")) { tools["node"] = product.moduleProperty("nodejs", "interpreterFilePath"); } var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/find/find-typescript.qbs0000644000175100001660000000176514776170045023133 0ustar runnerdockerimport qbs.TextFile Product { Depends { name: "nodejs"; required: false } Depends { name: "typescript"; required: false } type: ["json"] Rule { multiplex: true Artifact { filePath: ["typescript.json"] fileTags: ["json"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; if (product.moduleProperty("typescript", "present")) { tools["tsc"] = product.moduleProperty("typescript", "compilerPath"); } var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/find/find-jdk.qbs0000644000175100001660000000213714776170045021467 0ustar runnerdockerimport qbs.TextFile Product { Depends { name: "java"; required: false } type: ["json"] Rule { multiplex: true Artifact { filePath: ["jdk.json"] fileTags: ["json"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; if (product.moduleProperty("java", "present")) { tools["javac"] = product.moduleProperty("java", "compilerFilePath"); tools["java"] = product.moduleProperty("java", "interpreterFilePath"); tools["jar"] = product.moduleProperty("java", "jarFilePath"); } var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/find/find-xcode.qbs0000644000175100001660000000235314776170045022021 0ustar runnerdockerimport qbs.TextFile Product { Depends { name: "xcode"; required: false } type: ["json"] Rule { multiplex: true Artifact { filePath: ["xcode.json"] fileTags: ["json"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; var present = product.moduleProperty("xcode", "present"); tools["present"] = !!present; if (present) { var keys = [ "developerPath", "version" ]; for (var i = 0; i < keys.length; ++i) { var key = keys[i]; tools[key] = product.xcode[key]; } } var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/find/find-android.qbs0000644000175100001660000000572214776170045022342 0ustar runnerdockerimport qbs.TextFile Product { property string packageName: "" qbs.targetPlatform: "android" multiplexByQbsProperties: ["architectures"] Properties { condition: qbs.architectures && qbs.architectures.length > 1 aggregate: true multiplexedType: "json_arch" } Depends { name: "Android.sdk"; required: false } Depends { name: "Android.ndk"; required: false } type: ["json"] Rule { multiplex: true property stringList inputTags: "json_arch" inputsFromDependencies: inputTags inputs: product.aggregate ? [] : inputTags Artifact { filePath: ["android.json"] fileTags: ["json"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; for (var i in inputs["json_arch"]) { var tf = new TextFile(inputs["json_arch"][i].filePath, TextFile.ReadOnly); var json = JSON.parse(tf.readAll()); tools["ndk"] = json["ndk"]; tools["ndk-samples"] = json["ndk-samples"]; tf.close(); } if (product.moduleProperty("Android.sdk", "present")) { tools["sdk"] = product.moduleProperty("Android.sdk", "sdkDir"); tools["sdk-build-tools-dx"] = product.Android.sdk.dxFilePath; tools["sdk-build-tools-d8"] = product.Android.sdk.d8FilePath; } if (product.java && product.java.present) tools["jar"] = product.java.jarFilePath; var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } Rule { multiplex: true Artifact { filePath: ["android_arch.json"] fileTags: ["json_arch"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; if (product.moduleProperty("Android.ndk", "present")) { tools["ndk"] = product.moduleProperty("Android.ndk", "ndkDir"); tools["ndk-samples"] = product.Android.ndk.ndkSamplesDir; } var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/tst_clangdb.h0000644000175100001660000000411614776170045021006 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TST_CLANGDB_H #define QBS_TST_CLANGDB_H #include "tst_blackbox.h" #include class TestClangDb : public TestBlackboxBase { Q_OBJECT public: TestClangDb(); private slots: void initTestCase() override; void ensureBuildTreeCreated(); void checkCanGenerateDb(); void checkDbIsValidJson(); void checkDbIsConsistentWithProject(); void checkClangDetectsSourceCodeProblems(); private: int runProcess(const QString &exec, const QStringList &args, QByteArray &stdErr, QByteArray &stdOut); qbs::Version clangVersion(); const QString projectDir; const QString projectFileName; const QString buildDir; const QString sourceFilePath; const QString dbFilePath; bool isMsvc = false; bool isMingw = false; QProcessEnvironment processEnvironment; }; #endif // Include guard. qbs-src-2.6.1/tests/auto/blackbox/blackbox-tutorial.qbs0000644000175100001660000000101114776170045022475 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-tutorial" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "../../../tutorial/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxtutorial.cpp", "tst_blackboxtutorial.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/blackbox-windows.qbs0000644000175100001660000000100514776170045022327 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-windows" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-windows/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxwindows.cpp", "tst_blackboxwindows.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/blackbox-qt.qbs0000644000175100001660000000076114776170045021271 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-qt" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-qt/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxqt.cpp", "tst_blackboxqt.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/0000755000175100001660000000000014776170045022112 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-listing/0000755000175100001660000000000014776170045025373 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs0000644000175100001660000000070614776170045031366 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { condition: { if (!qbs.toolchain.includes("gcc")) { console.info("compiler listing suffix: %%" + cpp.compilerListingSuffix + "%%"); return true; } console.info("unsupported toolset: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); return false; } files: ["main.c", "fun.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c0000644000175100001660000000003614776170045026326 0ustar runnerdockerint f(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c0000644000175100001660000000007014776170045026460 0ustar runnerdockerextern int f(void); int main(void) { return f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/0000755000175100001660000000000014776170045027367 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/bar/0000755000175100001660000000000014776170045030133 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/bar/bar.h0000644000175100001660000000010214776170045031041 0ustar runnerdocker#ifndef BAR_H #define BAR_H #define BAR_VALUE 1 #endif // BAR_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/main.c0000644000175100001660000000013014776170045030451 0ustar runnerdocker#include #include int main(void) { return FOO_VALUE - BAR_VALUE; } ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/distribution-include-paths.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/distribution-include0000644000175100001660000000023614776170045033453 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { files: ["main.c"] cpp.distributionIncludePaths: ["foo", "bar"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/foo/0000755000175100001660000000000014776170045030152 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/distribution-include-paths/foo/foo.h0000644000175100001660000000010214776170045031077 0ustar runnerdocker#ifndef FOO_H #define FOO_H #define FOO_VALUE 1 #endif // FOO_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/0000755000175100001660000000000014776170045026462 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/compiler-include-paths.q0000644000175100001660000000036714776170045033222 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { files: ["main.c"] property bool dummy: { console.info("compilerIncludePaths: %%" + cpp.compilerIncludePaths + "%%"); return true; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-include-paths/main.c0000644000175100001660000000004114776170045027545 0ustar runnerdockerint main(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/defines/0000755000175100001660000000000014776170045023527 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/defines/defines.qbs0000644000175100001660000000021514776170045025651 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { cpp.defines: ["FOO", "BAR"] files: ["main.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/defines/main.c0000644000175100001660000000016014776170045024614 0ustar runnerdocker#ifndef FOO #error FOO missing! #endif #ifndef BAR #error BAR missing! #endif int main(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/0000755000175100001660000000000014776170045027216 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-gcc.s0000644000175100001660000000011714776170045030677 0ustar runnerdocker .global _main .type _main, @function _main: mov.w #0, r0 rts qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-iar.s0000644000175100001660000000015614776170045031105 0ustar runnerdocker PUBLIC main RSEG NEAR_CODE:CODE:NOROOT(0) main: MOV R2, #0x0 MOV R3, #0x0 RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m16c-iar.s0000644000175100001660000000013614776170045030721 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:REORDER:NOROOT(0) main: MOV.W #0x0, R0 RTS END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32r-gcc.s0000644000175100001660000000020014776170045030707 0ustar runnerdocker .global main .type main, @function main: push fp mv fp, sp ldi r4, #0 mv r0, r4 pop fp jmp lr qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-gcc.s0000644000175100001660000000027014776170045030635 0ustar runnerdocker .global _main .type _main, @function _main: add -4, sp st.w r29, 0[sp] mov sp, r29 mov 0, r10 mov r29, sp ld.w 0[sp], r29 add 4, sp jmp [r31] qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-gcc.s0000644000175100001660000000023714776170045030732 0ustar runnerdockerr8 = 0xffef0 .text .global _main .type _main, @function _main: subw sp, #2 clrw ax movw [sp], ax movw r8, ax addw sp, #2 ret qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-cosmic.s0000644000175100001660000000010114776170045031565 0ustar runnerdocker_main: .dcall "2,0,_main" rts xdef _main end qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-gcc.s0000644000175100001660000000021614776170045030564 0ustar runnerdocker .global _main .type _main, @function _main: push.l r10 mov.L r0, r10 mov.L #0, r5 mov.L r5, r1 rtsd #4, r10-r10 qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-iar.s0000644000175100001660000000015114776170045030727 0ustar runnerdocker PUBLIC main SECTION `.text`:CODE:NOROOT(1) THUMB main: MOVS R0, #+0 BX LR END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-keil.s0000644000175100001660000000024714776170045031257 0ustar runnerdockerPUBLIC main MAIN_SEG SEGMENT CODE RSEG MAIN_SEG main: MOV R6, #0x0 MOV R7, #0x0 RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-gcc.s0000644000175100001660000000011514776170045030710 0ustar runnerdocker .global main .type main, %function main: mov r0, #0 bx lr qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/cr16-iar.s0000644000175100001660000000013114776170045030721 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:NOROOT(0) main: MOVW $0, R0 JUMP (RA) END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs251-keil.s0000644000175100001660000000024114776170045031333 0ustar runnerdockerPUBLIC main MAIN_SEG SEGMENT CODE RSEG MAIN_SEG main PROC XRL WR6,WR6 RET ENDP END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-cosmic.s0000644000175100001660000000010314776170045031426 0ustar runnerdocker_main: movs r0, #0 bx lr xdef _main end qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-iar.s0000644000175100001660000000015314776170045031107 0ustar runnerdocker PUBLIC main RSEG CODE32:CODE:REORDER:NOROOT(2) CODE main: MOV R12, 0x0 RET R12 END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/c166-keil.s0000644000175100001660000000023414776170045031002 0ustar runnerdockerMAIN_SEG SECTION CODE WORD 'NCODE' main PROC NEAR MOV R4, #0 RET main ENDP MAIN_SEG ENDS END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-gcc.s0000644000175100001660000000015114776170045030716 0ustar runnerdocker .global main .type main, @function main: link.w %fp, #0 clr.l %d0 unlk %fp rts qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rl78-iar.s0000644000175100001660000000014014776170045030742 0ustar runnerdocker PUBLIC _main SECTION `.text`:CODE:NOROOT(0) CODE _main: CLRW AX RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-sdcc.s0000644000175100001660000000012514776170045031157 0ustar runnerdocker .globl main .area DSEG (PAG) .area HOME (CODE) main: clra tax qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/mcs51-sdcc.s0000644000175100001660000000020214776170045031236 0ustar runnerdocker .globl main .area PSEG (PAG,XDATA) .area XSEG (XDATA) .area HOME (CODE) main: mov dptr, #0x0000 ret qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-iar.s0000644000175100001660000000015714776170045031051 0ustar runnerdocker PUBLIC main SECTION `.near_func.text`:CODE:REORDER:NOROOT(0) CODE main: CLRW X RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-gcc.s0000644000175100001660000000026414776170045031264 0ustar runnerdocker .globl main .type main, @function main: add sp, sp, -16 sd s0, 8(sp) add s0, sp, 16 li a5, 0 mv a0, a5 ld s0, 8(sp) add sp, sp, 16 jr ra qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/78k-iar.s0000644000175100001660000000012314776170045030560 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:NOROOT(0) main: MOVW AX, #0 RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rh850-iar.s0000644000175100001660000000015114776170045031016 0ustar runnerdocker PUBLIC _main SECTION `.text`:CODE:NOROOT(2) CODE _main: MOV r0, r10 JMP [lp] END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-cosmic.s0000644000175100001660000000014314776170045031546 0ustar runnerdocker scross off _main: .dcall "2,0,_main" ret .scheck _main xdef _main end qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-iar.s0000644000175100001660000000014114776170045031175 0ustar runnerdocker PUBLIC main RSEG `CODE`:CODE:REORDER:NOROOT(1) main: MOV.W #0x0, R12 RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/msp430-gcc.s0000644000175100001660000000011714776170045031161 0ustar runnerdocker .global main .type main, %function main: mov #0, r15 .LIRD0: qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/riscv-iar.s0000644000175100001660000000015314776170045031300 0ustar runnerdocker PUBLIC main SECTION `.text`:CODE:REORDER:NOROOT(2) CODE main: MV A0, ZERO RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-iar.s0000644000175100001660000000012114776170045030732 0ustar runnerdocker PUBLIC main RSEG FCODE:CODE:NOROOT(1) main: CLR.L D0 RTS END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-gcc.s0000644000175100001660000000013114776170045030717 0ustar runnerdocker .global main .type main, %function main: ldi r24, 0 ldi r25, 0 ret qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/xtensa-gcc.s0000644000175100001660000000031714776170045031437 0ustar runnerdocker .global main .type main, @function main: addi sp, sp, -16 s32i.n a15, sp, 12 mov.n a15, sp movi.n a2, 0 mov.n sp, a15 l32i.n a15, sp, 12 addi sp, sp, 16 ret.n qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/sh-iar.s0000644000175100001660000000015414776170045030565 0ustar runnerdocker PUBLIC _main SECTION `.code32.text`:CODE:NOROOT(2) _main: CODE MOV #0, R0 RTS/N END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr-iar.s0000644000175100001660000000014114776170045030737 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:NOROOT(1) main: LDI R16, 0 LDI R17, 0 RET END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/arm-keil.s0000644000175100001660000000016514776170045031105 0ustar runnerdocker THUMB AREA ||.text||, CODE, READONLY, ALIGN = 1 main PROC MOVS r0, #0 BX lr ENDP END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-iar.s0000644000175100001660000000014014776170045031013 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:REORDER:NOROOT(0) main: LDHX #0x0000 RTS END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs8-cosmic.s0000644000175100001660000000010114776170045031512 0ustar runnerdocker_main: .dcall "2,0,_main" rts xdef _main end qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/rx-iar.s0000644000175100001660000000011414776170045030600 0ustar runnerdocker PUBLIC _main SECTION CODE:CODE:ROOT(2) _main: BRA _main END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/v850-iar.s0000644000175100001660000000014614776170045030656 0ustar runnerdocker PUBLIC _main RSEG `CODE`:CODE:NOROOT(2) CODE _main: MOV zero, r1 JMP [lp] END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/stm8-sdcc.s0000644000175100001660000000012714776170045031207 0ustar runnerdocker .globl main .area DATA .area SSEG .area HOME main: clrw x ret qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/avr32-gcc.s0000644000175100001660000000021214776170045031064 0ustar runnerdocker .global main .type main, @function main: stm --sp, r7, lr mov r7, sp mov r8, 0 mov r12, r8 ldm sp++, r7, pc qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/r32c-iar.s0000644000175100001660000000020214776170045030716 0ustar runnerdocker PUBLIC main RSEG CODE24:CODE:REORDER:NOROOT(0) main: MOV.L:Z #0x0, R2R0 RTS RSEG SBREF:DATA:NOROOT(0) END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/hcs12-iar.s0000644000175100001660000000014114776170045031067 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:REORDER:NOROOT(0) main: CLRB CLRA RTS END ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/one-object-asm-application.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/one-object-asm-appli0000644000175100001660000001037114776170045033051 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { condition: { if (qbs.toolchainType === "cosmic") { if (qbs.architecture.startsWith("arm")) return true; if (qbs.architecture === "stm8") return true; if (qbs.architecture === "hcs8") return true; if (qbs.architecture === "hcs12") return true; if (qbs.architecture === "m68k") return true; } else if (qbs.toolchainType === "keil") { if (qbs.architecture.startsWith("arm")) return true; if (qbs.architecture === "mcs51") return true; if (qbs.architecture === "mcs251") return true; if (qbs.architecture === "c166") return true; } else if (qbs.toolchainType === "iar") { if (qbs.architecture.startsWith("arm")) return true; if (qbs.architecture === "mcs51") return true; if (qbs.architecture === "stm8") return true; if (qbs.architecture === "avr") return true; if (qbs.architecture === "avr32") return true; if (qbs.architecture === "msp430") return true; if (qbs.architecture === "rl78") return true; if (qbs.architecture === "rh850") return true; if (qbs.architecture === "v850") return true; if (qbs.architecture === "78k") return true; if (qbs.architecture === "r32c") return true; if (qbs.architecture === "sh") return true; if (qbs.architecture === "cr16") return true; if (qbs.architecture === "m16c") return true; if (qbs.architecture === "hcs8") return true; if (qbs.architecture === "hcs12") return true; if (qbs.architecture === "rx") return true; if (qbs.architecture === "m32c") return true; if (qbs.architecture === "riscv") return true; if (qbs.architecture === "m68k") return true; } else if (qbs.toolchainType === "sdcc") { if (qbs.architecture === "mcs51") return true; if (qbs.architecture === "stm8") return true; if (qbs.architecture === "hcs8") return true; } else if (qbs.toolchainType === "gcc") { if (qbs.architecture.startsWith("arm")) return true; if (qbs.architecture === "avr") return true; if (qbs.architecture === "avr32") return true; if (qbs.architecture === "msp430") return true; if (qbs.architecture === "xtensa") return true; if (qbs.architecture === "rl78") return true; if (qbs.architecture === "m32c") return true; if (qbs.architecture === "m32r") return true; if (qbs.architecture === "m68k") return true; if (qbs.architecture === "v850") return true; if (qbs.architecture === "riscv") return true; if (qbs.architecture === "rx") return true; } console.info("unsupported toolset: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); return false; } Properties { condition: qbs.toolchainType === "gcc" && qbs.architecture === "msp430" // We need to use this workaround to enable // the cpp.driverFlags property. cpp.linkerPath: cpp.compilerPathByLanguage["c"] } Properties { condition: qbs.toolchainType === "iar" && qbs.architecture.startsWith("arm") cpp.entryPoint: "main" } files: [(qbs.architecture.startsWith("arm") ? "arm" : qbs.architecture) + "-" + qbs.toolchainType + ".s"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m68k-cosmic.s0000644000175100001660000000010114776170045031432 0ustar runnerdocker_main: .dcall "8,0,_main" rts xdef _main end qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-asm-application/m32c-iar.s0000644000175100001660000000013614776170045030717 0ustar runnerdocker PUBLIC main RSEG CODE:CODE:REORDER:NOROOT(0) main: MOV.W #0x0, R0 RTS END qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/preinclude-headers/0000755000175100001660000000000014776170045025655 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude-headers.qbs0000644000175100001660000000107114776170045032126 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { condition: { if (qbs.toolchainType === "keil") { if (qbs.architecture === "mcs51" || qbs.architecture === "mcs251" || qbs.architecture === "c166") { console.info("unsupported toolset: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); return false; } } return true; } cpp.prefixHeaders: ["preinclude.h"] files: ["main.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/preinclude-headers/main.c0000644000175100001660000000006014776170045026741 0ustar runnerdockerint main(void) { return PREINCLUDE_VALUE; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/preinclude-headers/preinclude.h0000644000175100001660000000013614776170045030160 0ustar runnerdocker#ifndef PREINCLUDE_H #define PREINCLUDE_H #define PREINCLUDE_VALUE 0 #endif // PREINCLUDE_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/BareMetalStaticLibrary.qbs0000644000175100001660000000005714776170045027154 0ustar runnerdockerBareMetalProduct { type: "staticlibrary" } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/target-platform/0000755000175100001660000000000014776170045025222 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/target-platform/target-platform.qbs0000644000175100001660000000132214776170045031037 0ustar runnerdockerProduct { Depends { name: "cpp" } condition: { if (qbs.toolchainType === "keil" || qbs.toolchainType === "iar" || qbs.toolchainType === "sdcc" || qbs.toolchainType === "cosmic") { var hasNoPlatform = (qbs.targetPlatform === "none"); var hasNoOS = (qbs.targetOS.length === 1 && qbs.targetOS[0] === "none"); console.info("has no platform: " + hasNoPlatform); console.info("has no os: " + hasNoOS); } else { console.info("unsupported toolset: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); return false; } return true; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/linker-map/0000755000175100001660000000000014776170045024151 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs0000644000175100001660000000033214776170045026715 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { property bool dummy: { console.info("linker map suffix: %%" + cpp.linkerMapSuffix + "%%"); } files: ["main.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/linker-map/main.c0000644000175100001660000000004114776170045025234 0ustar runnerdockerint main(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-application/0000755000175100001660000000000014776170045026440 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-application/one-object-application.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-application/one-object-application.q0000644000175100001660000000015514776170045033151 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { files: ["main.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/one-object-application/main.c0000644000175100001660000000004114776170045027523 0ustar runnerdockerint main(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/0000755000175100001660000000000014776170045027467 5ustar runnerdocker././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/static-library-dependencies.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/static-library-depe0000644000175100001660000000173614776170045033265 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication import "../BareMetalStaticLibrary.qbs" as BareMetalStaticLibrary Project { BareMetalStaticLibrary { name: "lib-a" Depends { name: "cpp" } files: ["a1.c", "a2.c"] } BareMetalStaticLibrary { name: "lib-b" Depends { name: "cpp" } Depends { name: "lib-a" } files: ["b.c"] } BareMetalStaticLibrary { name: "lib-c" Depends { name: "cpp" } Depends { name: "lib-a" } files: ["c.c"] } BareMetalStaticLibrary { name: "lib-d" Depends { name: "cpp" } Depends { name: "lib-b" } Depends { name: "lib-c" } files: ["d.c"] } BareMetalStaticLibrary { name: "lib-e" Depends { name: "cpp" } Depends { name: "lib-d" } files: ["e.c"] } BareMetalApplication { name: "app" Depends { name: "lib-e" } files: ["app.c"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a1.c0000644000175100001660000000003714776170045030134 0ustar runnerdockerint a1(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/a2.c0000644000175100001660000000003714776170045030135 0ustar runnerdockerint a2(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/app.c0000644000175100001660000000007014776170045030410 0ustar runnerdockerextern int e(void); int main(void) { return e(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/c.c0000644000175100001660000000006714776170045030060 0ustar runnerdockerextern int a2(void); int c(void) { return a2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/b.c0000644000175100001660000000006714776170045030057 0ustar runnerdockerextern int a1(void); int b(void) { return a1(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/e.c0000644000175100001660000000006614776170045030061 0ustar runnerdockerextern int d(void); int e(void) { return d(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/static-library-dependencies/d.c0000644000175100001660000000011714776170045030055 0ustar runnerdockerextern int b(void); extern int c(void); int d(void) { return b() + c(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/BareMetalApplication.qbs0000644000175100001660000000152014776170045026637 0ustar runnerdockerimport qbs.Host BareMetalProduct { type: "application" consoleApplication: true property bool dummy: { if (qbs.targetPlatform !== Host.platform() || qbs.architecture !== Host.architecture()) { function supportsCrossRun() { // We can run 32 bit applications on 64 bit Windows. if (Host.platform() === "windows" && Host.architecture() === "x86_64" && qbs.targetPlatform === "windows" && qbs.architecture === "x86") { return true; } } if (!supportsCrossRun()) console.info("targetPlatform differs from hostPlatform") } } Group { condition: qbs.toolchain.includes("cosmic") files: "cosmic.lkf" fileTags: "linkerscript" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/shared-libraries/0000755000175100001660000000000014776170045025332 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/shared-libraries/app.c0000644000175100001660000000022714776170045026257 0ustar runnerdocker#include "../dllexport.h" #include DLL_IMPORT void foo(void); int main(void) { printf("Hello from app\n"); foo(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared-libraries.qbs0000644000175100001660000000151114776170045031257 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication Project { condition: { if (qbs.targetPlatform === "windows" && qbs.architecture === "x86") { if (qbs.toolchainType === "watcom") return true; if (qbs.toolchainType === "dmc") return true; } if (qbs.toolchainType === "msvc") return true; console.info("unsupported toolset: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); return false; } DynamicLibrary { Depends { name: "cpp" } destinationDirectory: "bin" name: "shared" files: ["shared.c"] } BareMetalApplication { Depends { name: "shared" } destinationDirectory: "bin" name: "app" files: ["app.c"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/shared-libraries/shared.c0000644000175100001660000000047714776170045026754 0ustar runnerdocker#include "../dllexport.h" #include #ifdef __DMC__ #include #define EXPORT_FUN _export BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { return TRUE; } #else #define EXPORT_FUN #endif // __DMC__ DLL_EXPORT void EXPORT_FUN foo(void) { printf("Hello from lib\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/0000755000175100001660000000000014776170045026174 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/system-include-paths.qbs0000644000175100001660000000023014776170045032760 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { files: ["main.c"] cpp.systemIncludePaths: ["foo", "bar"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/bar/0000755000175100001660000000000014776170045026740 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/bar/bar.h0000644000175100001660000000010214776170045027646 0ustar runnerdocker#ifndef BAR_H #define BAR_H #define BAR_VALUE 1 #endif // BAR_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/main.c0000644000175100001660000000013014776170045027256 0ustar runnerdocker#include #include int main(void) { return FOO_VALUE - BAR_VALUE; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/foo/0000755000175100001660000000000014776170045026757 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/system-include-paths/foo/foo.h0000644000175100001660000000010214776170045027704 0ustar runnerdocker#ifndef FOO_H #define FOO_H #define FOO_VALUE 1 #endif // FOO_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/BareMetalProduct.qbs0000644000175100001660000001275614776170045026031 0ustar runnerdockerProduct { Depends { name: "cpp" } cpp.positionIndependentCode: false Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "stm8" cpp.driverLinkerFlags: [ "--config_def", "_CSTACK_SIZE=0x100", "--config_def", "_HEAP_SIZE=0x100", ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "rl78" cpp.driverLinkerFlags: [ "--config_def", "_NEAR_HEAP_SIZE=256", "--config_def", "_FAR_HEAP_SIZE=4096", "--config_def", "_HUGE_HEAP_SIZE=0", "--config_def", "_STACK_SIZE=128", "--config_def", "_NEAR_CONST_LOCATION_SIZE=0x6F00", "--config_def", "_NEAR_CONST_LOCATION_START=0x3000", "--define_symbol", "_NEAR_CONST_LOCATION=0", "--config", cpp.toolchainInstallPath + "/../config/lnkrl78_s3.icf" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "rh850" cpp.driverLinkerFlags: [ "--config_def", "CSTACK_SIZE=0x1000", "--config_def", "HEAP_SIZE=0x1000", "--config", cpp.toolchainInstallPath + "/../config/lnkrh850_g3m.icf" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "v850" cpp.driverLinkerFlags: [ "-D_CSTACK_SIZE=1000", "-D_HEAP_SIZE=1000", "-f", cpp.toolchainInstallPath + "/../config/lnk85.xcl" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "78k" cpp.commonCompilerFlags: [ "--core", "78k0", "--code_model", "standard" ] cpp.driverLinkerFlags: [ "-D_CSTACK_SIZE=80", "-D_HEAP_SIZE=200", "-D_CODEBANK_START=0", "-D_CODEBANK_END=0", "-D_CODEBANK_BANKS=0", "-f", cpp.toolchainInstallPath + "/../config/lnk.xcl", cpp.toolchainInstallPath + "/../lib/clib/cl78ks1.r26" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "sh" cpp.driverLinkerFlags: [ "--config_def", "_CSTACK_SIZE=0x800", "--config_def", "_HEAP_SIZE=0x800", "--config_def", "_INT_TABLE=0x10", "--config", cpp.toolchainInstallPath + "/../config/generic.icf" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "hcs8" cpp.driverLinkerFlags: [ "-D_CSTACK_SIZE=200", "-D_HEAP_SIZE=200", "-f", cpp.toolchainInstallPath + "/../config/lnkunspecifieds08.xcl" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "m32c" cpp.driverLinkerFlags: [ "-D_CSTACK_SIZE=100", "-D_NEAR_HEAP_SIZE=400", "-D_FAR_HEAP_SIZE=400", "-D_HUGE_HEAP_SIZE=400", "-D_ISTACK_SIZE=40", "-f", cpp.toolchainInstallPath + "/../config/lnkm32c.xcl", cpp.toolchainInstallPath + (qbs.debugInformation ? "/../lib/dlib/dlm32cnf.r48" : "/../lib/clib/clm32cf.r48") ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "riscv" cpp.driverLinkerFlags: [ "--config_def", "CSTACK_SIZE=0x1000", "--config_def", "HEAP_SIZE=0x1000" ] } Properties { condition: qbs.toolchain.includes("iar") && qbs.architecture === "m68k" cpp.cFlags: [ "--no_div" ] cpp.driverLinkerFlags: [ "-D__FLASHBEGIN=0", "-D__FLASHEND=1FFFF", "-D__RAMBEGIN=800000", "-D__RAMEND=803FFF", "-D_CSTACK_SIZE=200", "-D_HEAP_SIZE=1000", "-D_VBR_ADDRESS=0", "-f", cpp.toolchainInstallPath + "/../config/lnkm51ac128.xcl", cpp.toolchainInstallPath + "/../lib/dlcfcffdn.r68" ] } Properties { condition: qbs.toolchain.includes("keil") && qbs.architecture.startsWith("arm") && cpp.compilerName.startsWith("armcc") cpp.assemblerFlags: ["--cpu", "cortex-m0"] cpp.commonCompilerFlags: ["--cpu", "cortex-m0"] } Properties { condition: qbs.toolchain.includes("keil") && qbs.architecture.startsWith("arm") && cpp.compilerName.startsWith("armclang") cpp.assemblerFlags: ["--cpu", "cortex-m0"] cpp.commonCompilerFlags: ["-mcpu=cortex-m0", "--target=arm-arm-none-eabi"] } Properties { condition: qbs.toolchain.includes("gcc") && qbs.architecture.startsWith("arm") cpp.driverFlags: ["-specs=nosys.specs"] } Properties { condition: qbs.toolchain.includes("gcc") && qbs.architecture === "xtensa" cpp.driverFlags: ["-nostdlib"] } Properties { condition: qbs.toolchain.includes("gcc") && qbs.architecture === "msp430" cpp.driverFlags: ["-mmcu=msp430f5529", "-nostdlib"] } Properties { condition: qbs.toolchain.includes("gcc") && qbs.architecture === "m32r" cpp.driverFlags: ["-nostdlib"] } Properties { condition: qbs.toolchain.includes("gcc") && qbs.architecture === "riscv" cpp.driverFlags: ["-nostdlib"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/two-object-application/0000755000175100001660000000000014776170045026470 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/two-object-application/fun.c0000644000175100001660000000003614776170045027423 0ustar runnerdockerint f(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/two-object-application/main.c0000644000175100001660000000007014776170045027555 0ustar runnerdockerextern int f(void); int main(void) { return f(); } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/two-object-application/two-object-application.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/two-object-application/two-object-application.q0000644000175100001660000000016614776170045033233 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { files: ["main.c", "fun.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/toolchain-probe/0000755000175100001660000000000014776170045025177 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/0000755000175100001660000000000014776170045026471 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/sdcc.qbs0000644000175100001660000000146614776170045030123 0ustar runnerdockerimport qbs.Probes Product { id: product condition: qbs.toolchainType === "sdcc" Depends { name: "cpp" } Probes.SdccProbe { id: probe compilerFilePath: cpp.compilerPath enableDefinesByLanguage: cpp.enableCompilerDefinesByLanguage preferredArchitecture: qbs.architecture } property bool dummy: { if (!product.condition) return; if (!probe.found || !probe.endianness || !probe.compilerDefinesByLanguage || !probe.includePaths || (probe.includePaths.length === 0) || (qbs.architecture !== probe.architecture)) { console.info("broken probe: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/dmc.qbs0000644000175100001660000000164414776170045027750 0ustar runnerdockerimport qbs.Probes Product { id: product condition: qbs.toolchainType === "dmc" Depends { name: "cpp" } Probes.DmcProbe { id: probe compilerFilePath: cpp.compilerPath enableDefinesByLanguage: cpp.enableCompilerDefinesByLanguage _targetPlatform: qbs.targetPlatform _targetArchitecture: qbs.architecture _targetExtender: cpp.extenderName } property bool dummy: { if (!product.condition) return; if (!probe.found || !probe.compilerDefinesByLanguage || !probe.includePaths || (probe.includePaths.length === 0) || (qbs.architecture !== probe.architecture) || (qbs.targetPlatform !== probe.targetPlatform)) { console.info("broken probe: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/toolchain-probe/probes/watcom.qbs0000644000175100001660000000206514776170045030475 0ustar runnerdockerimport qbs.Probes Product { id: product condition: qbs.toolchainType === "watcom" Depends { name: "cpp" } Probes.WatcomProbe { id: probe compilerFilePath: cpp.compilerPath enableDefinesByLanguage: cpp.enableCompilerDefinesByLanguage _pathListSeparator: qbs.pathListSeparator _toolchainInstallPath: cpp.toolchainInstallPath _targetPlatform: qbs.targetPlatform _targetArchitecture: qbs.architecture } property bool dummy: { if (!product.condition) return; if (!probe.found || !probe.endianness || !probe.compilerDefinesByLanguage || !probe.environment || !probe.includePaths || (probe.includePaths.length === 0) || (qbs.architecture !== probe.architecture) || (qbs.targetPlatform !== probe.targetPlatform)) { console.info("broken probe: %%" + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/toolchain-probe/toolchain-probe.qbs0000644000175100001660000000016614776170045030776 0ustar runnerdockerProject { references: [ "probes/dmc.qbs", "probes/sdcc.qbs", "probes/watcom.qbs", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/0000755000175100001660000000000014776170045025626 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/user-include-paths.qbs0000644000175100001660000000022214776170045032045 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication BareMetalApplication { files: ["main.c"] cpp.includePaths: ["foo", "bar"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/bar/0000755000175100001660000000000014776170045026372 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/bar/bar.h0000644000175100001660000000010214776170045027300 0ustar runnerdocker#ifndef BAR_H #define BAR_H #define BAR_VALUE 1 #endif // BAR_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/main.c0000644000175100001660000000013014776170045026710 0ustar runnerdocker#include "foo.h" #include "bar.h" int main(void) { return FOO_VALUE - BAR_VALUE; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/foo/0000755000175100001660000000000014776170045026411 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/user-include-paths/foo/foo.h0000644000175100001660000000010214776170045027336 0ustar runnerdocker#ifndef FOO_H #define FOO_H #define FOO_VALUE 1 #endif // FOO_H qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/cosmic.lkf0000644000175100001660000000000314776170045024056 0ustar runnerdocker@* qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/external-static-libraries/0000755000175100001660000000000014776170045027173 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-b.c0000644000175100001660000000006514776170045030325 0ustar runnerdockerextern int a(void); int b(void) { return a(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/external-static-libraries/lib-a.c0000644000175100001660000000003614776170045030322 0ustar runnerdockerint a(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/external-static-libraries/main.c0000644000175100001660000000006414776170045030263 0ustar runnerdockerextern int b(); int main(void) { return b(); } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libra0000644000175100001660000000213214776170045033312 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication import "../BareMetalStaticLibrary.qbs" as BareMetalStaticLibrary Project { property string outputLibrariesDirectory: buildDirectory + "/libs" BareMetalStaticLibrary { name: "lib-a" destinationDirectory: project.outputLibrariesDirectory Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib-a.c"] } BareMetalStaticLibrary { name: "lib-b" destinationDirectory: project.outputLibrariesDirectory Depends { name: "cpp" } Depends { name: "lib-a" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib-b.c"] } BareMetalApplication { Depends { name: "lib-a"; cpp.link: false } Depends { name: "lib-b"; cpp.link: false } files: ["main.c"] cpp.libraryPaths: [project.outputLibrariesDirectory] cpp.staticLibraries: ["lib-b", "lib-a"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/0000755000175100001660000000000014776170045027530 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/app.c0000644000175100001660000000004114776170045030447 0ustar runnerdockerint main(void) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/ctest.c0000644000175100001660000000000014776170045031004 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/cpptest.cpp0000644000175100001660000000000014776170045031704 0ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-b0000644000175100001660000000550714776170045033126 0ustar runnerdockerimport "../BareMetalApplication.qbs" as BareMetalApplication Project { property bool supportsCpp: { if (qbs.toolchain.includes("cosmic")) return false; if (qbs.toolchain.includes("sdcc")) return false; if (qbs.toolchain.includes("keil")) { if (qbs.architecture === "mcs51" || qbs.architecture === "mcs251" || qbs.architecture === "c166") { return false; } } return true; } BareMetalApplication { name: "c_language" files: ["app.c", "ctest.c"] cpp.enableCompilerDefinesByLanguage: [] property var foo: { if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (!cpp.compilerDefinesByLanguage["c"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; } } BareMetalApplication { condition: supportsCpp name: "cpp_language" files: ["app.c", "cpptest.cpp"] cpp.enableCompilerDefinesByLanguage: ["cpp"] cpp.enableExceptions: false property var foo: { if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (cpp.compilerDefinesByLanguage["c"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (!cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; } } BareMetalApplication { condition: supportsCpp name: "c_and_cpp_language" files: ["app.c", "ctest.c", "cpptest.cpp"] cpp.enableCompilerDefinesByLanguage: ["c", "cpp"] cpp.enableExceptions: false property var foo: { if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (!cpp.compilerDefinesByLanguage["c"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (!cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; } } } qbs-src-2.6.1/tests/auto/blackbox/blackbox-examples.qbs0000644000175100001660000000101114776170045022450 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-examples" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "../../../examples/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxexamples.cpp", "tst_blackboxexamples.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxapple.cpp0000644000175100001660000017473714776170045022577 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackboxapple.h" #include "../shared.h" #include #include #include #include #include #include #include #include #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) using qbs::Internal::HostOsInfo; using qbs::Profile; 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(); } }; static QString getEmbeddedBinaryPlist(const QString &file) { QProcess p; p.start("otool", QStringList() << "-v" << "-X" << "-s" << "__TEXT" << "__info_plist" << file); p.waitForFinished(); return QString::fromUtf8(p.readAllStandardOutput()).trimmed(); } static QVariantMap readInfoPlistFile(const QString &infoPlistPath) { if (!QFile::exists(infoPlistPath)) { qWarning() << infoPlistPath << "doesn't exist"; return {}; } QProcess plutil; plutil.start("plutil", { QStringLiteral("-convert"), QStringLiteral("json"), infoPlistPath }); if (!plutil.waitForStarted()) { qWarning() << plutil.errorString(); return {}; } if (!plutil.waitForFinished()) { qWarning() << plutil.errorString(); return {}; } if (plutil.exitCode() != 0) { qWarning() << plutil.readAllStandardError().constData(); return {}; } QFile infoPlist(infoPlistPath); if (!infoPlist.open(QIODevice::ReadOnly)) { qWarning() << infoPlist.errorString(); return {}; } QJsonParseError error; const auto json = QJsonDocument::fromJson(infoPlist.readAll(), &error); if (error.error != QJsonParseError::NoError) { qWarning() << error.errorString(); return {}; } return json.object().toVariantMap(); } static QString getInfoPlistPath(const QString &bundlePath) { QFileInfo contents(bundlePath + "/Contents"); if (contents.exists() && contents.isDir()) return contents.filePath() + "/Info.plist"; // macOS bundle return bundlePath + "/Info.plist"; } static QString getPrivacyManifestPath(const QString &bundlePath) { QFileInfo resources(bundlePath + "/Resources"); if (resources.exists()) return resources.filePath() + "/PrivacyInfo.xcprivacy"; // macOS bundle return bundlePath + "/PrivacyInfo.xcprivacy"; } static bool testVariantListType(const QVariant &variant, QMetaType::Type type) { if (variant.userType() != QMetaType::QVariantList) return false; for (const auto &value : variant.toList()) { if (value.userType() != type) return false; } return true; } static QString findFatLibrary(const QString &dir, const QString &libraryName) { QDirIterator it(dir, {}, QDir::AllEntries, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); if (it.fileInfo().fileName() == libraryName) { QProcess lipo; lipo.start("lipo", { QStringLiteral("-info"), it.filePath() }); if (!lipo.waitForStarted() || !lipo.waitForFinished() || lipo.exitCode() != 0) return {}; auto output = lipo.readAllStandardOutput(); if (output.contains(QByteArrayLiteral("Architectures in the fat file"))) return QDir::cleanPath(it.filePath()); } } return {}; } enum class CodeSignResult { Failed = 0, Signed, Unsigned }; using CodeSignData = QMap; static std::pair parseCodeSignOutput(const QByteArray &output) { CodeSignData data; if (output.contains("code object is not signed at all")) return {CodeSignResult::Unsigned, data}; const auto lines = output.split('\n'); for (const auto &line: lines) { if (line.isEmpty() || line.startsWith("CodeDirectory") || line.startsWith("Sealed Resources") || line.startsWith("Internal requirements")) { continue; } const int index = line.indexOf('='); if (index == -1) return {CodeSignResult::Failed, {}}; data[line.mid(0, index)] = line.mid(index + 1); } return {CodeSignResult::Signed, data}; } static std::pair getCodeSignInfo(const QString &path) { QProcess codesign; codesign.start("codesign", { QStringLiteral("-dv"), path }); if (!codesign.waitForStarted() || !codesign.waitForFinished()) return {CodeSignResult::Failed, {}}; const auto output = codesign.readAllStandardError(); return parseCodeSignOutput(output); } TestBlackboxApple::TestBlackboxApple() : TestBlackboxBase (SRCDIR "/testdata-apple", "blackbox-apple") { } void TestBlackboxApple::initTestCase() { if (!HostOsInfo::isMacosHost()) { QSKIP("only applies on macOS"); return; } TestBlackboxBase::initTestCase(); } void TestBlackboxApple::appleMultiConfig() { const auto xcodeVersion = findXcodeVersion(); if (!xcodeVersion) QSKIP("requires Xcode profile"); QDir::setCurrent(testDataDir + "/apple-multiconfig"); QCOMPARE(runQbs(QbsRunParameters(QStringList{ "qbs.installPrefix:''", QStringLiteral("project.xcodeVersion:") + xcodeVersion->toString()})), 0); if (m_qbsStdout.contains("isShallow: false")) { QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/MacOS/singleapp").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/MacOS/singleapp_agg").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/singlelib").isFileSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Resources").isDirSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/singlelib").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/Current").isDirSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/MacOS/fatmultiapp").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" "fatmultiappmultivariant").isFileSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" "fatmultiappmultivariant_debug").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/MacOS/" "fatmultiappmultivariant_profiling").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/Info.plist") .isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Contents/PkgInfo") .isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib").isFileSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Resources").isDirSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_debug").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_profiling").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/Current").isDirSymLink()); for (const QString variant : { "release", "debug", "profiling" }) { for (const QString arch : { "x86_64" }) { QProcess process; process.setProgram("/usr/bin/arch"); process.setArguments({ "-arch", arch, "-e", "DYLD_IMAGE_SUFFIX=_" + variant, defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp" }); process.start(); process.waitForFinished(); QCOMPARE(process.exitCode(), 0); const auto processStdout = process.readAllStandardOutput(); QVERIFY2(processStdout.contains("Hello from " + variant.toUtf8() + " " + arch.toUtf8()), processStdout.constData()); } } } else if (m_qbsStdout.contains("isShallow: true")) { QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/singleapp").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/singleapp_agg").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/singlelib").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/multiapp").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/fatmultiapp").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Info.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/PkgInfo").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/" "fatmultiappmultivariant").isFileSymLink()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/" "fatmultiappmultivariant_debug").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/" "fatmultiappmultivariant_profiling").isExecutable()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/Info.plist") .isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiappmultivariant.app/PkgInfo") .isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib_debug").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib_profiling").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Info.plist").isRegularFile()); } else { QVERIFY2(false, qPrintable(m_qbsStdout)); } } void TestBlackboxApple::aggregateDependencyLinking() { const auto xcodeVersion = findXcodeVersion(); if (!xcodeVersion) QSKIP("requires Xcode profile"); // XCode 11 produces warning about deprecation of 32-bit apps, but still works const bool hasX86Mac = xcodeVersion < qbs::Version(12); const bool hasArmMac = xcodeVersion >= qbs::Version(12, 2); QDir::setCurrent(testDataDir + "/aggregateDependencyLinking"); QbsRunParameters params{QStringList{"-p", "multi_arch_lib"}}; params.arguments << QStringLiteral("products.multi_arch_lib.hasX86Mac:%1").arg(hasX86Mac); params.arguments << QStringLiteral("products.multi_arch_lib.hasArmMac:%1").arg(hasArmMac); QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("Cannot build fat binaries")) QSKIP("Building fat binaries is not supported for this profile"); QCOMPARE(runQbs(QStringList{"-p", "just_app", "--command-echo-mode", "command-line"}), 0); int linkedInLibrariesCount = QString::fromUtf8(m_qbsStdout).count(QStringLiteral("libmulti_arch_lib.a")); QCOMPARE(linkedInLibrariesCount, 1); const auto fatLibPath = findFatLibrary(testDataDir, QStringLiteral("libmulti_arch_lib.a")); QVERIFY(!fatLibPath.isEmpty()); QVERIFY2(QString::fromUtf8(m_qbsStdout).contains(fatLibPath), m_qbsStdout); } void TestBlackboxApple::appiconset() { QDir::setCurrent(testDataDir + QLatin1String("/ib/appiconset")); QbsRunParameters params; params.arguments = QStringList() << "-f" << "appiconset.qbs"; QCOMPARE(runQbs(params), 0); const auto infoPlistPath = getInfoPlistPath( relativeProductBuildDir("appiconset") + "/appiconset.app"); QVERIFY(QFile::exists(infoPlistPath)); const auto content = readInfoPlistFile(infoPlistPath); QVERIFY(!content.isEmpty()); if (m_qbsStdout.contains("bundle.isShallow: false")) { QCOMPARE(content.value(QStringLiteral("CFBundleIconFile")), QStringLiteral("AppIcon")); QCOMPARE(content.value(QStringLiteral("CFBundleIconName")), QStringLiteral("AppIcon")); QVERIFY(regularFileExists(relativeProductBuildDir("appiconset") + "/appiconset.app/Contents/Resources/AppIcon.icns")); } else if (m_qbsStdout.contains("bundle.isShallow: true")) { const auto icons = content.value(QStringLiteral("CFBundleIcons")).toMap(); QVERIFY2(!icons.isEmpty(), "Info.plist doesn't contain CFBundleIcons key"); const auto primaryIcon = icons.value(QStringLiteral("CFBundlePrimaryIcon")).toMap(); QVERIFY2(!primaryIcon.isEmpty(), "Info.plist doesn't contain CFBundlePrimaryIcon key"); QCOMPARE(primaryIcon.value(QStringLiteral("CFBundleIconName")), QStringLiteral("AppIcon")); } else { QVERIFY2(false, "Cannot determine bundle type"); } } void TestBlackboxApple::assetCatalog() { QFETCH(bool, flatten); QDir::setCurrent(testDataDir + QLatin1String("/ib/assetcatalog")); rmDirR(relativeBuildDir()); if (!findXcode()) QSKIP("requires Xcode profile"); QbsRunParameters params; const QString flattens = "modules.ib.flatten:" + QString(flatten ? "true" : "false"); const QString macosTarget = "modules.cpp.minimumMacosVersion:'10.15'"; // Make sure a dry run does not write anything params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << "--dry-run" << flattens << macosTarget; QCOMPARE(runQbs(params), 0); QVERIFY(!directoryExists(relativeBuildDir())); if (m_qbsStdout.contains("Skip this test")) QSKIP("Skip this test"); params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << flattens << macosTarget; QCOMPARE(runQbs(params), 0); // empty asset catalogs must still produce output QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets")); // empty asset catalogs must still produce output QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets")); QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Assets.car")); // this asset catalog happens to have an embedded icon set, // but this should NOT be built since it is not in the files list QVERIFY(!(bool)m_qbsStdout.contains(".iconset")); // now we'll add the iconset rmDirR(relativeBuildDir()); params.arguments.push_back("project.includeIconset:true"); QCOMPARE(runQbs(params), 0); QVERIFY(!(bool)m_qbsStdout.contains("compiling empty.xcassets")); QVERIFY((bool)m_qbsStdout.contains("compiling empty.iconset")); // make sure the nibs/storyboards are in there QString nib = relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/MainMenu.nib"; QStringList nibFiles; if (flatten) { QVERIFY(regularFileExists(nib)); } else { QVERIFY(directoryExists(nib)); nibFiles = QStringList() << "designable.nib" << "keyedobjects.nib"; } QString storyboardc = relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Storyboard.storyboardc"; QStringList storyboardcFiles; if (HostOsInfo::hostOsVersion() >= qbs::Version(10, 10)) { QVERIFY(directoryExists(storyboardc)); storyboardcFiles = QStringList() << "1os-k8-h10-view-qKA-a5-eUe.nib" << "Info.plist" << "Iqk-Fi-Vhk-view-HRv-3O-Qxh.nib" << "Main.nib" << "NSViewController-Iqk-Fi-Vhk.nib" << "NSViewController-Yem-rc-72E.nib" << "Yem-rc-72E-view-ODp-aO-Dmf.nib"; if (!flatten) { storyboardcFiles << "designable.storyboard"; storyboardcFiles.sort(); } } QCOMPARE(QDir(nib).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), nibFiles); QCOMPARE(QDir(storyboardc).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), storyboardcFiles); QCOMPARE(runQbs(QbsRunParameters("clean")), 0); QCOMPARE(QDir(nib).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), QStringList()); QCOMPARE(QDir(storyboardc).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), QStringList()); } void TestBlackboxApple::assetCatalog_data() { QTest::addColumn("flatten"); QTest::newRow("flattened") << true; QTest::newRow("unflattened") << false; } void TestBlackboxApple::assetCatalogsEmpty() { if (findXcodeVersion() < qbs::Version(5)) QSKIP("requires Xcode 5 or above"); QDir::setCurrent(testDataDir + QLatin1String("/ib/empty-asset-catalogs")); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling assetcatalog1.xcassets"), m_qbsStdout); QVERIFY2(!m_qbsStdout.contains("compiling assetcatalog2.xcassets"), m_qbsStdout); } void TestBlackboxApple::assetCatalogsMultiple() { if (findXcodeVersion() < qbs::Version(5)) QSKIP("requires Xcode 5 or above"); QDir::setCurrent(testDataDir + QLatin1String("/ib/multiple-asset-catalogs")); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling assetcatalog1.xcassets"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("compiling assetcatalog2.xcassets"), m_qbsStdout); } void TestBlackboxApple::bundleStructure() { QFETCH(QString, productName); QFETCH(QString, productTypeIdentifier); QDir::setCurrent(testDataDir + "/bundle-structure"); QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); params.arguments << "project.buildableProducts:" + productName; 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 (m_qbsStdout.contains("bundle.isShallow: false")) { // Test shallow bundles detection - bundles are not shallow only on macOS, so also check // the qbs.targetOS property QVERIFY2(m_qbsStdout.contains("qbs.targetOS: macos"), m_qbsStdout); 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 (m_qbsStdout.contains("bundle.isShallow: true")) { QVERIFY2(m_qbsStdout.contains("qbs.targetOS:"), m_qbsStdout); QVERIFY2(!m_qbsStdout.contains("qbs.targetOS: macos"), m_qbsStdout); 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()); } 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()); } 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()); } 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()); } 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()); } 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()); } if (productName == "G") { QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir()); QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile()); QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile()); } } else { QVERIFY2(false, qPrintable(m_qbsStdout)); } } void TestBlackboxApple::bundleStructure_data() { QTest::addColumn("productName"); QTest::addColumn("productTypeIdentifier"); QTest::addColumn("isShallow"); QTest::newRow("A") << "A" << "com.apple.product-type.application"; QTest::newRow("ABadApple") << "ABadApple" << "com.apple.product-type.will.never.exist.ever.guaranteed"; QTest::newRow("ABadThirdParty") << "ABadThirdParty" << "org.special.third.party.non.existent.product.type"; QTest::newRow("B") << "B" << "com.apple.product-type.framework"; QTest::newRow("C") << "C" << "com.apple.product-type.framework.static"; QTest::newRow("D") << "D" << "com.apple.product-type.bundle"; QTest::newRow("E") << "E" << "com.apple.product-type.app-extension"; QTest::newRow("F") << "F" << "com.apple.product-type.xpc-service"; QTest::newRow("G") << "G" << "com.apple.product-type.in-app-purchase-content"; } void TestBlackboxApple::byteArrayInfoPlist() { QDir::setCurrent(testDataDir + "/byteArrayInfoPlist"); QCOMPARE(runQbs(), 0); const auto infoPlistPath = getInfoPlistPath( relativeProductBuildDir("byteArrayInfoPlist") + "/byteArrayInfoPlist.app"); QVERIFY(QFile::exists(infoPlistPath)); const auto outFilePath = relativeProductBuildDir("byteArrayInfoPlist") + "/bytearrayInfoPlist-Info.plist.out"; QFile file(outFilePath); QVERIFY(file.exists()); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(file.readAll(), "The data value"); } void TestBlackboxApple::codesign() { QFETCH(int, expectedCount); QFETCH(bool, isBundle); QFETCH(bool, enableSigning); QFETCH(bool, multiArch); QFETCH(bool, multiVariant); const auto xcodeVersion = findXcodeVersion(); if (!xcodeVersion) QSKIP("requires Xcode profile"); QDir::setCurrent(testDataDir + "/codesign"); QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); // the test can't use xcode module to determine version itself params.arguments << QStringLiteral("project.xcodeVersion:") + xcodeVersion->toString(); params.arguments << QStringLiteral("project.isBundle:%1").arg(isBundle ? "true" : "false"); params.arguments << QStringLiteral("project.enableSigning:%1") .arg(enableSigning ? "true" : "false"); params.arguments << QStringLiteral("project.multiArch:%1").arg(multiArch ? "true" : "false"); params.arguments << QStringLiteral("project.multiVariant:%1") .arg(multiVariant ? "true" : "false"); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); const int codeSignCount = QString::fromUtf8(m_qbsStdout).count(QStringLiteral("codesign")); QCOMPARE(codeSignCount, expectedCount); const auto appName = isBundle ? QStringLiteral("A.app") : QStringLiteral("A"); const auto appPath = defaultInstallRoot + "/" + appName; QVERIFY(QFileInfo(appPath).exists()); auto codeSignInfo = getCodeSignInfo(appPath); QVERIFY(codeSignInfo.first != CodeSignResult::Failed); QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); if (!codeSignInfo.second.isEmpty()) { QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); } const auto libName = isBundle ? QStringLiteral("B.framework") : QStringLiteral("libB.1.0.0.dylib"); const auto libPath = defaultInstallRoot + "/" + libName; QVERIFY(QFileInfo(libPath).exists()); codeSignInfo = getCodeSignInfo(libPath); QVERIFY(codeSignInfo.first != CodeSignResult::Failed); QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); if (!codeSignInfo.second.isEmpty()) { QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); } const auto pluginPath = defaultInstallRoot + "/" + QStringLiteral("C.bundle"); QVERIFY(QFileInfo(pluginPath).exists()); QVERIFY(QFileInfo(pluginPath).isDir() == isBundle); codeSignInfo = getCodeSignInfo(pluginPath); QVERIFY(codeSignInfo.first != CodeSignResult::Failed); QCOMPARE(codeSignInfo.first == CodeSignResult::Signed, enableSigning); QCOMPARE(codeSignInfo.second.isEmpty(), !enableSigning); if (!codeSignInfo.second.isEmpty()) { QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Executable"))); QVERIFY(codeSignInfo.second.contains(QByteArrayLiteral("Identifier"))); QCOMPARE(codeSignInfo.second.value(QByteArrayLiteral("Signature")), "adhoc"); } } void TestBlackboxApple::codesign_data() { QTest::addColumn("expectedCount"); QTest::addColumn("isBundle"); QTest::addColumn("enableSigning"); QTest::addColumn("multiArch"); QTest::addColumn("multiVariant"); QTest::newRow("standalone, unsigned") << 0 << false << false << false << false; QTest::newRow("bundle, unsigned") << 0 << true << false << false << false; QTest::newRow("standalone, signed") << 3 << false << true << false << false; QTest::newRow("bundle, signed") << 3 << true << true << false << false; // here we only sign the resulting lipo artifact QTest::newRow("standalone, signed, multiarch") << 3 << false << true << true << false; QTest::newRow("bundle, signed, multiarch") << 3 << true << true << true << false; // here we sign all artifacts QTest::newRow("standalone, signed, multivariant") << 15 << false << true << false << true; QTest::newRow("bundle, signed, multivariant") << 15 << true << true << false << true; QTest::newRow("standalone, signed, multiarch, multivariant") << 15 << false << true << true << true; QTest::newRow("bundle, signed, multiarch, multivariant") << 15 << true << true << true << true; } void TestBlackboxApple::deploymentTarget() { QFETCH(QString, sdk); QFETCH(QString, os); QFETCH(QString, arch); QFETCH(QString, cflags); QFETCH(QString, lflags); QDir::setCurrent(testDataDir + "/deploymentTarget"); if (!findXcode()) QSKIP("requires Xcode profile"); QbsRunParameters params; params.arguments = QStringList() << "--command-echo-mode" << "command-line" << "modules.qbs.targetPlatform:" + os << "qbs.architectures:" + arch; rmDirR(relativeBuildDir()); int status = runQbs(params); const QStringList skippableMessages = QStringList() << "There is no matching SDK available for " + sdk + "." << "x86_64h will be mis-detected as x86_64 with Apple Clang < 6.0" << "clang: error: unknown argument: '-mtvos-version-min" << "clang: error: unknown argument: '-mtvos-simulator-version-min" << "clang: error: unknown argument: '-mwatchos-version-min" << "clang: error: unknown argument: '-mwatchos-simulator-version-min"; if (status != 0) { for (const auto &message : skippableMessages) { if (m_qbsStderr.contains(message.toUtf8())) QSKIP(message.toUtf8()); } } QCOMPARE(status, 0); QVERIFY2(m_qbsStderr.contains(cflags.toLatin1()), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains(lflags.toLatin1()), m_qbsStderr.constData()); } void TestBlackboxApple::deploymentTarget_data() { static const QString macos = QStringLiteral("macos"); static const QString ios = QStringLiteral("ios"); static const QString ios_sim = QStringLiteral("ios-simulator"); static const QString tvos = QStringLiteral("tvos"); static const QString tvos_sim = QStringLiteral("tvos-simulator"); static const QString watchos = QStringLiteral("watchos"); static const QString watchos_sim = QStringLiteral("watchos-simulator"); QTest::addColumn("sdk"); QTest::addColumn("os"); QTest::addColumn("arch"); QTest::addColumn("cflags"); QTest::addColumn("lflags"); const auto xcodeVersion = findXcodeVersion(); if (xcodeVersion < qbs::Version(10)) { QTest::newRow("macos x86") << "macosx" << macos << "x86" << "-triple i386-apple-macosx10.6" << "-macosx_version_min 10.6"; } QTest::newRow("macos x86_64") << "macosx" << macos << "x86_64" << "-triple x86_64-apple-macosx10.6" << "10.6"; if (xcodeVersion >= qbs::Version(6)) QTest::newRow("macos x86_64h") << "macosx" << macos << "x86_64h" << "-triple x86_64h-apple-macosx10.12" << "10.12"; QTest::newRow("ios armv7a") << "iphoneos" << ios << "armv7a" << "-triple thumbv7-apple-ios6.0" << "6.0"; QTest::newRow("ios armv7s") << "iphoneos" <= qbs::Version(5)) QTest::newRow("ios arm64") << "iphoneos" <= qbs::Version(5)) QTest::newRow("ios-simulator x86_64") << "iphonesimulator" << ios_sim << "x86_64" << "-triple x86_64-apple-ios7.0" << "7.0"; if (xcodeVersion >= qbs::Version(7)) { if (xcodeVersion >= qbs::Version(7, 1)) { QTest::newRow("tvos arm64") << "appletvos" << tvos << "arm64" << "-triple arm64-apple-tvos9.0" << "9.0"; QTest::newRow("tvos-simulator x86_64") << "appletvsimulator" << tvos_sim << "x86_64" << "-triple x86_64-apple-tvos9.0" << "9.0"; } QTest::newRow("watchos armv7k") << "watchos" << watchos << "armv7k" << "-triple thumbv7k-apple-watchos2.0" << "2.0"; QTest::newRow("watchos-simulator x86") << "watchsimulator" << watchos_sim << "x86" << "-triple i386-apple-watchos2.0" << "2.0"; } } void TestBlackboxApple::dmg() { if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) QSKIP("Skip this test when running on GitHub"); QDir::setCurrent(testDataDir + "/apple-dmg"); QCOMPARE(runQbs(), 0); } void TestBlackboxApple::embedInfoPlist() { QDir::setCurrent(testDataDir + QLatin1String("/embedInfoPlist")); QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); QCOMPARE(runQbs(params), 0); QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/app").isEmpty()); QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/liblib.dylib").isEmpty()); QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty()); params.arguments = QStringList(QLatin1String("modules.bundle.embedInfoPlist:false")); params.expectFailure = true; rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/app").isEmpty()); QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/liblib.dylib").isEmpty()); QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty()); } void TestBlackboxApple::frameworkStructure() { QDir::setCurrent(testDataDir + QLatin1String("/frameworkStructure")); QbsRunParameters params; QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("isShallow: false")) { QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Widget")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Headers/Widget.h")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/PrivateHeaders/WidgetPrivate.h")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/BaseResource")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/en.lproj/EnglishResource")); QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/Current")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers")); QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders")); QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Resources")); } else if (m_qbsStdout.contains("isShallow: true")) { QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers")); QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers/Widget.h")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders/WidgetPrivate.h")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/BaseResource")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/en.lproj/EnglishResource")); QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget")); } else { QVERIFY2(false, qPrintable(m_qbsStdout)); } params.command = "resolve"; params.arguments = QStringList() << "project.includeHeaders:false"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(!directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers")); QVERIFY(!directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders")); } void TestBlackboxApple::iconset() { QDir::setCurrent(testDataDir + QLatin1String("/ib/iconset")); QbsRunParameters params; params.arguments = QStringList() << "-f" << "iconset.qbs"; QCOMPARE(runQbs(params), 0); QVERIFY(regularFileExists(relativeProductBuildDir("iconset") + "/white.icns")); } void TestBlackboxApple::iconsetApp() { QDir::setCurrent(testDataDir + QLatin1String("/ib/iconsetapp")); QbsRunParameters params; params.arguments = QStringList() << "-f" << "iconsetapp.qbs"; QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("isShallow: false")) { QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + "/iconsetapp.app/Contents/Resources/white.icns")); } else if (m_qbsStdout.contains("isShallow: true")) { QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + "/iconsetapp.app/white.icns")); } else { QVERIFY2(false, qPrintable(m_qbsStdout)); } } void TestBlackboxApple::privacymanifest() { QDir::setCurrent(testDataDir + "/privacymanifest"); QbsRunParameters params; params.arguments = QStringList() << "-f" << "privacymanifest.qbs"; QCOMPARE(runQbs(params), 0); const auto privacymanifestPath = getPrivacyManifestPath( relativeProductBuildDir("Lib") + "/Lib.framework"); QVERIFY(QFile::exists(privacymanifestPath)); const auto content = readInfoPlistFile(privacymanifestPath); QVERIFY(!content.isEmpty()); QCOMPARE(content.value(QStringLiteral("NSPrivacyTracking")), false); QCOMPARE(content.value(QStringLiteral("NSPrivacyTrackingDomains")), QVariantList()); QCOMPARE(content.value(QStringLiteral("NSPrivacyAccessedAPITypes")), QVariantList()); QCOMPARE(content.value(QStringLiteral("NSPrivacyCollectedDataTypes")), QVariantList()); } void TestBlackboxApple::infoPlist() { QDir::setCurrent(testDataDir + "/infoplist"); QbsRunParameters params; params.arguments = QStringList() << "-f" << "infoplist.qbs"; QCOMPARE(runQbs(params), 0); const auto infoPlistPath = getInfoPlistPath( relativeProductBuildDir("infoplist") + "/infoplist.app"); QVERIFY(QFile::exists(infoPlistPath)); const auto content = readInfoPlistFile(infoPlistPath); QVERIFY(!content.isEmpty()); // common values QCOMPARE(content.value(QStringLiteral("CFBundleIdentifier")), QStringLiteral("org.example.infoplist")); QCOMPARE(content.value(QStringLiteral("CFBundleName")), QStringLiteral("infoplist")); QCOMPARE(content.value(QStringLiteral("CFBundleExecutable")), QStringLiteral("infoplist")); if (!content.contains(QStringLiteral("SDKROOT"))) { // macOS-specific values QCOMPARE(content.value("LSMinimumSystemVersion"), QStringLiteral("10.7")); QCOMPARE(content.value("NSPrincipalClass"), QStringLiteral("NSApplication")); QCOMPARE(content.value(QStringLiteral("NSSupportsAutomaticGraphicsSwitching")), true); } else { // QBS-1447: UIDeviceFamily was set to a string instead of an array const auto family = content.value(QStringLiteral("UIDeviceFamily")); if (family.isValid()) { // Prior to Qt 5.15, int gets converted to a double when exporting plist as JSON QVERIFY(testVariantListType(family, QMetaType::LongLong) || testVariantListType(family, QMetaType::Double)); } const auto caps = content.value(QStringLiteral("UIRequiredDeviceCapabilities")); if (caps.isValid()) QVERIFY(testVariantListType(caps, QMetaType::QString)); const auto orientations = content.value(QStringLiteral("UIRequiredDeviceCapabilities")); if (orientations.isValid()) QVERIFY(testVariantListType(orientations, QMetaType::QString)); } } void TestBlackboxApple::infoPlistVariables() { QDir::setCurrent(testDataDir + "/infoPlistVariables"); QbsRunParameters params; params.arguments = QStringList() << "-f" << "infoPlistVariables.qbs"; QCOMPARE(runQbs(params), 0); const auto infoPlistPath = getInfoPlistPath( relativeProductBuildDir("infoPlistVariables") + "/infoPlistVariables.app"); QVERIFY(QFile::exists(infoPlistPath)); const auto content = readInfoPlistFile(infoPlistPath); QVERIFY(!content.isEmpty()); QCOMPARE(content.value(QStringLiteral("Curly")), QStringLiteral("infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("Braces")), QStringLiteral("infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("At")), QStringLiteral("infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("CurlyMult")), QStringLiteral("infoPlistVariables_infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("BracesMult")), QStringLiteral("infoPlistVariables_infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("AtMult")), QStringLiteral("infoPlistVariables_infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("CurlyNested")), QStringLiteral("infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("BracesNested")), QStringLiteral("infoPlistVariables")); QCOMPARE(content.value(QStringLiteral("WithDefault")), QStringLiteral("DEFAULT")); } void TestBlackboxApple::lipoSymlinks() { QFETCH(bool, multiArch); QFETCH(bool, multiVariant); const auto xcodeVersion = findXcodeVersion(); if (!xcodeVersion) QSKIP("requires Xcode profile"); QDir::setCurrent(testDataDir + "/lipo-symlinks"); QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); // the test can't use xcode module to determine version itself params.arguments << QStringLiteral("project.xcodeVersion:") + xcodeVersion->toString(); params.arguments << QStringLiteral("project.multiArch:%1").arg(multiArch ? "true" : "false"); params.arguments << QStringLiteral("project.multiVariant:%1") .arg(multiVariant ? "true" : "false"); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); const auto libraryDirPath = QStringList{{relativeBuildDir(), "install-root"}}.join("/"); const auto checkSymLink = [](const auto &path, const auto &targetPath) { QFileInfo fi(path); return fi.exists() && fi.isSymbolicLink() && fi.symLinkTarget() == targetPath; }; const auto libraryPath = QFileInfo(QStringList{{libraryDirPath, "libA.1.2.3.dylib"}}.join("/")).absoluteFilePath(); QVERIFY(QFileInfo(libraryPath).exists() && !QFileInfo(libraryPath).isSymbolicLink()); QVERIFY(checkSymLink(QStringList{{libraryDirPath, "libA.1.2.dylib"}}.join("/"), libraryPath)); QVERIFY(checkSymLink(QStringList{{libraryDirPath, "libA.1.dylib"}}.join("/"), libraryPath)); QVERIFY(checkSymLink(QStringList{{libraryDirPath, "libA.dylib"}}.join("/"), libraryPath)); if (multiArch && multiVariant) { // in this case there are 2 libs and 2 sets of symlinks const auto debugLibraryPath = QFileInfo(QStringList{{libraryDirPath, "libA_debug.1.2.3.dylib"}}.join("/")) .absoluteFilePath(); QVERIFY( QFileInfo(debugLibraryPath).exists() && !QFileInfo(debugLibraryPath).isSymbolicLink()); QVERIFY(checkSymLink( QStringList{{libraryDirPath, "libA_debug.1.2.dylib"}}.join("/"), debugLibraryPath)); QVERIFY(checkSymLink( QStringList{{libraryDirPath, "libA_debug.1.dylib"}}.join("/"), debugLibraryPath)); QVERIFY(checkSymLink( QStringList{{libraryDirPath, "libA_debug.dylib"}}.join("/"), debugLibraryPath)); } } void TestBlackboxApple::lipoSymlinks_data() { QTest::addColumn("multiArch"); QTest::addColumn("multiVariant"); QTest::newRow("standalone") << false << false; QTest::newRow("multiArch") << true << false; QTest::newRow("multiVariant") << false << true; QTest::newRow("multiArch, multiVariant") << true << true; } void TestBlackboxApple::objcArc() { QDir::setCurrent(testDataDir + QLatin1String("/objc-arc")); QCOMPARE(runQbs(), 0); } void TestBlackboxApple::overrideInfoPlist() { QDir::setCurrent(testDataDir + "/overrideInfoPlist"); QCOMPARE(runQbs(), 0); const auto infoPlistPath = getInfoPlistPath( relativeProductBuildDir("overrideInfoPlist") + "/overrideInfoPlist.app"); QVERIFY(QFile::exists(infoPlistPath)); const auto content = readInfoPlistFile(infoPlistPath); QVERIFY(!content.isEmpty()); // test we do not override custom values by default QCOMPARE(content.value(QStringLiteral("DefaultValue")), QStringLiteral("The default value")); // test we can override custom values QCOMPARE(content.value(QStringLiteral("OverriddenValue")), QStringLiteral("The overridden value")); // test we do not override special values set by Qbs by default QCOMPARE(content.value(QStringLiteral("CFBundleExecutable")), QStringLiteral("overrideInfoPlist")); // test we can override special values set by Qbs QCOMPARE(content.value(QStringLiteral("CFBundleName")), QStringLiteral("My Bundle")); } void TestBlackboxApple::xcode() { if (!findXcode()) QSKIP("requires Xcode profile"); QProcess xcodeSelect; xcodeSelect.start("xcode-select", QStringList() << "--print-path"); QVERIFY2(xcodeSelect.waitForStarted(), qPrintable(xcodeSelect.errorString())); QVERIFY2(xcodeSelect.waitForFinished(), qPrintable(xcodeSelect.errorString())); QVERIFY2(xcodeSelect.exitCode() == 0, qPrintable(xcodeSelect.readAllStandardError().constData())); const QString developerPath(QString::fromLocal8Bit(xcodeSelect.readAllStandardOutput().trimmed())); std::multimap sdks; QProcess xcodebuildShowSdks; xcodebuildShowSdks.start("xcrun", QStringList() << "xcodebuild" << "-showsdks"); QVERIFY2(xcodebuildShowSdks.waitForStarted(), qPrintable(xcodebuildShowSdks.errorString())); QVERIFY2(xcodebuildShowSdks.waitForFinished(), qPrintable(xcodebuildShowSdks.errorString())); QVERIFY2(xcodebuildShowSdks.exitCode() == 0, qPrintable(xcodebuildShowSdks.readAllStandardError().constData())); const auto lines = QString::fromLocal8Bit(xcodebuildShowSdks.readAllStandardOutput().trimmed()) .split('\n', Qt::SkipEmptyParts); for (const QString &line : lines) { static const std::regex regexp("^.+\\s+\\-sdk\\s+([a-z]+)([0-9]+\\.[0-9]+)$"); const auto ln = line.toStdString(); std::smatch match; if (std::regex_match(ln, match, regexp)) sdks.insert({ match[1], match[2] }); } const auto getSdksByType = [&sdks]() { QStringList result; std::string sdkType; QStringList sdkValues; for (const auto &sdk: sdks) { if (!sdkType.empty() && sdkType != sdk.first) { result.append(QStringLiteral("%1:['%2']") .arg(QString::fromStdString(sdkType), sdkValues.join("','"))); sdkValues.clear(); } sdkType = sdk.first; sdkValues.append(QString::fromStdString(sdk.second)); } return result; }; QDir::setCurrent(testDataDir + "/xcode"); QbsRunParameters params; params.arguments = (QStringList() << (QStringLiteral("modules.xcode.developerPath:") + developerPath) << (QStringLiteral("project.sdks:{") + getSdksByType().join(",") + "}")); QCOMPARE(runQbs(params), 0); } QTEST_MAIN(TestBlackboxApple) std::optional TestBlackboxApple::findXcode(int *status) { QTemporaryDir temp; QbsRunParameters params = QStringList({"-f", testDataDir + "/find/find-xcode.qbs"}); params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) *status = res; QFile file(temp.path() + "/" + relativeProductBuildDir("find-xcode") + "/xcode.json"); if (!file.open(QIODevice::ReadOnly)) return {}; auto result = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); if (!result["present"].toBool()) return {}; return result; } std::optional TestBlackboxApple::findXcodeVersion() { const auto xcode = findXcode(); if (!xcode) return {}; return qbs::Version::fromString(xcode->value("version").toString()); } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxandroid.cpp0000644000175100001660000020553514776170045023105 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackboxandroid.h" #include "../shared.h" #include #include #include #include #include #include using qbs::Internal::none_of; using qbs::Profile; QMap TestBlackboxAndroid::findAndroid(int *status, const QString &profile) { QTemporaryDir temp; QDir::setCurrent(testDataDir + "/find"); QbsRunParameters params = QStringList({"-f", "find-android.qbs", "qbs.architecture:x86"}); params.profile = profile; params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) *status = res; QFile file(temp.path() + "/" + relativeProductBuildDir("find-android") + "/android.json"); if (!file.open(QIODevice::ReadOnly)) return {}; const auto tools = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); return { {"sdk", QDir::fromNativeSeparators(tools["sdk"].toString())}, {"sdk-build-tools-dx", QDir::fromNativeSeparators(tools["sdk-build-tools-dx"].toString())}, {"sdk-build-tools-d8", QDir::fromNativeSeparators(tools["sdk-build-tools-d8"].toString())}, {"ndk", QDir::fromNativeSeparators(tools["ndk"].toString())}, {"ndk-samples", QDir::fromNativeSeparators(tools["ndk-samples"].toString())}, {"jar", QDir::fromNativeSeparators(tools["jar"].toString())}, }; } TestBlackboxAndroid::TestBlackboxAndroid() : TestBlackboxBase(SRCDIR "/testdata-android", "blackbox-android") { } static QString theProfileName(bool forQt) { return forQt ? "qbs_autotests-android-qt" : profileName(); } void TestBlackboxAndroid::android() { QFETCH(QString, projectDir); QFETCH(QStringList, productNames); QFETCH(QList, expectedFilesLists); QFETCH(QStringList, customProperties); QFETCH(bool, enableAapt2); QFETCH(bool, generateAab); QFETCH(bool, isIncrementalBuild); QFETCH(bool, enableD8); // skip tests on github except when run in docker - this var is not propagated into the image if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) QSKIP("Skip Android tests when running on GitHub"); const SettingsPtr s = settings(); Profile p(theProfileName(projectDir == "qml-app" || projectDir == "qt-app"), s.get()); if (!p.exists()) QSKIP("Qt is not installed"); int status; const auto androidPaths = findAndroid(&status, p.name()); QCOMPARE(status, 0); const auto sdkPath = androidPaths["sdk"]; if (sdkPath.isEmpty()) QSKIP("Android SDK is not installed"); const auto ndkPath = androidPaths["ndk"]; if (ndkPath.isEmpty() && projectDir != "no-native") QSKIP("Android NDK is not installed"); const auto ndkSamplesPath = androidPaths["ndk-samples"]; static const QStringList ndkSamplesDirs = QStringList() << "teapot" << "no-native"; if (!ndkPath.isEmpty() && !QFileInfo(ndkSamplesPath).isDir() && ndkSamplesDirs.contains(projectDir)) QSKIP("NDK samples directory not present"); const QString buildSubDir = enableAapt2 ? (generateAab ? "aab" : "aapt2") : "aapt"; QDir::setCurrent(testDataDir + "/" + projectDir); if (!isIncrementalBuild) rmDirR(relativeBuildDir(buildSubDir)); static const QStringList configNames { "debug", "release" }; for (const QString &configName : configNames) { auto currentExpectedFilesLists = expectedFilesLists; const QString configArgument = "config:" + configName; QbsRunParameters resolveParams("resolve"); resolveParams.buildDirectory = buildSubDir; resolveParams.arguments << configArgument << customProperties; resolveParams.profile = p.name(); QCOMPARE(runQbs(resolveParams), 0); QbsRunParameters buildParams(QStringList{"--command-echo-mode", "command-line", configArgument}); buildParams.buildDirectory = buildSubDir; buildParams.profile = p.name(); QCOMPARE(runQbs(buildParams), 0); for (const QString &productName : std::as_const(productNames)) { const QByteArray tag(QTest::currentDataTag()); QCOMPARE(m_qbsStdout.count("generating BuildConfig.java"), isIncrementalBuild ? 0 : productNames.size()); const QString packageName = productName + (generateAab ? ".aab" : ".apk"); QVERIFY(m_qbsStdout.contains(packageName.toLocal8Bit())); const QString packageFilePath = buildSubDir + "/" + relativeProductBuildDir(productName, configName) + '/' + packageName; QVERIFY2(regularFileExists(packageFilePath), qPrintable(packageFilePath)); const QString jarFilePath = androidPaths["jar"]; QVERIFY(!jarFilePath.isEmpty()); QProcess jar; jar.start(jarFilePath, QStringList() << "-tf" << packageFilePath); QVERIFY2(jar.waitForStarted(), qPrintable(jar.errorString())); QVERIFY2(jar.waitForFinished(), qPrintable(jar.errorString())); QVERIFY2(jar.exitCode() == 0, qPrintable(jar.readAllStandardError().constData())); QByteArrayList actualFiles = jar.readAllStandardOutput().trimmed().split('\n'); for (QByteArray &f : actualFiles) f = f.trimmed(); QByteArrayList missingExpectedFiles; QByteArrayList expectedFiles = currentExpectedFilesLists.takeFirst(); for (const QByteArray &expectedFile : expectedFiles) { if (expectedFile.endsWith("/libgdbserver.so") && configName == "release") continue; auto it = std::find(actualFiles.begin(), actualFiles.end(), expectedFile); if (it != actualFiles.end()) { actualFiles.erase(it); continue; } missingExpectedFiles << expectedFile; } if (!missingExpectedFiles.empty()) QFAIL(QByteArray("missing expected files:\n") + missingExpectedFiles.join('\n')); if (!actualFiles.empty()) { QByteArray msg = "unexpected files encountered:\n" + actualFiles.join('\n'); auto isFileSharedObject = [](const QByteArray &f) { return f.endsWith(".so"); }; const auto isQmlToolingLib = [](const QByteArray &f) { return f.contains("qmltooling"); }; if (none_of(actualFiles, isFileSharedObject) || qbs::Internal::all_of(actualFiles, isQmlToolingLib)) { qWarning() << msg; } else { QFAIL(msg); } } } if (projectDir == "multiple-libs-per-apk") { const auto dexCompilerPath = enableD8 ? androidPaths["sdk-build-tools-d8"] : androidPaths["sdk-build-tools-dx"]; QVERIFY(!dexCompilerPath.isEmpty()); const auto lines = m_qbsStdout.split('\n'); const auto it = std::find_if(lines.cbegin(), lines.cend(), [&](const QByteArray &line) { return !line.isEmpty() && line.startsWith(dexCompilerPath.toUtf8()); }); QVERIFY2(it != lines.cend(), qPrintable(m_qbsStdout.constData())); const auto line = *it; QVERIFY2(line.contains("lib3.jar"), qPrintable(line.constData())); QVERIFY2(!line.contains("lib4.jar"), qPrintable(line.constData())); QVERIFY2(line.contains("lib5.jar"), qPrintable(line.constData())); QVERIFY2(line.contains("lib6.jar"), qPrintable(line.constData())); QVERIFY2(!line.contains("lib7.jar"), qPrintable(line.constData())); QVERIFY2(line.contains("lib8.jar"), qPrintable(line.constData())); } } } void TestBlackboxAndroid::android_data() { const SettingsPtr s = settings(); const Profile p(profileName(), s.get()); const Profile pQt(theProfileName(true), s.get()); QStringList archsStringList = p.value(QStringLiteral("qbs.architectures")).toStringList(); if (archsStringList.empty()) archsStringList << QStringLiteral("armv7a"); // must match default in common.qbs QByteArrayList archs; std::transform(archsStringList.begin(), archsStringList.end(), std::back_inserter(archs), [] (const QString &s) { return s.toUtf8().replace("armv7a", "armeabi-v7a") .replace("armv5te", "armeabi") .replace("arm64", "arm64-v8a"); }); const auto cxxLibPath = [&p, &pQt](const QByteArray &oldcxxLib, bool forQt) { const bool usesClang = (forQt ? pQt : p).value(QStringLiteral("qbs.toolchainType")) .toString() == "clang"; const QByteArray path = "lib/${ARCH}/"; return path + (usesClang ? QByteArrayLiteral("libc++_shared.so") : oldcxxLib); }; qbs::Version version(5, 13); QStringList qmakeFilePaths = pQt.value(QStringLiteral("moduleProviders.Qt.qmakeFilePaths")). toStringList(); if (qmakeFilePaths.size() >= 1) version = TestBlackboxBase::qmakeVersion(qmakeFilePaths[0]); bool singleArchQt = (version < qbs::Version(5, 14)); QByteArray qtVersionMajor((version >= qbs::Version(6, 0)) ? "6" : "5"); QByteArrayList archsForQt; if (singleArchQt) { archsForQt = { pQt.value("qbs.architecture").toString().toUtf8() }; if (archsStringList.empty()) archsStringList << QStringLiteral("armv7a"); // must match default in common.qbs } else { QStringList archsForQtStringList = pQt.value(QStringLiteral("qbs.architectures")) .toStringList(); if (archsForQtStringList.empty()) archsForQtStringList << pQt.value("qbs.architecture").toString(); std::transform(archsForQtStringList.begin(), archsForQtStringList.end(), std::back_inserter(archsForQt), [] (const QString &s) { return s.toUtf8(); }); } QByteArrayList ndkArchsForQt; std::transform(archsForQt.begin(), archsForQt.end(), std::back_inserter(ndkArchsForQt), [] (const QString &s) { return s.toUtf8().replace("armv7a", "armeabi-v7a") .replace("armv5te", "armeabi") .replace("arm64", "arm64-v8a"); }); auto expandArchs = [] (const QByteArrayList &archs, const QByteArrayList &lst, bool aabPackage) { const QByteArray &archPlaceHolder = "${ARCH}"; QByteArrayList result; QByteArray base( aabPackage ? "base/" : ""); for (const QByteArray &entry : lst) { if (entry.contains(archPlaceHolder)) { for (const QByteArray &arch : std::as_const(archs)) result << (base + QByteArray(entry).replace(archPlaceHolder, arch)); } else { result << (base + entry); } } return result; }; auto commonFiles = [](bool generateAab, bool codeSign = true, QString keyAlias="androiddebugkey") { QByteArrayList files; if (generateAab) files << "base/manifest/AndroidManifest.xml" << "base/dex/classes.dex" << "BundleConfig.pb"; else files << "AndroidManifest.xml" << "classes.dex"; if (codeSign) files << QByteArray("META-INF/" + keyAlias.toUpper().left(8).toUtf8() + ".RSA") << QByteArray("META-INF/" + keyAlias.toUpper().left(8).toUtf8() + ".SF") << "META-INF/MANIFEST.MF"; return files; }; QTest::addColumn("projectDir"); QTest::addColumn("productNames"); QTest::addColumn>("expectedFilesLists"); QTest::addColumn("customProperties"); QTest::addColumn("enableAapt2"); QTest::addColumn("generateAab"); QTest::addColumn("isIncrementalBuild"); QTest::addColumn("enableD8"); const auto aaptVersion = [](bool enableAapt2) { return QString("modules.Android.sdk.aaptName:") + (enableAapt2 ? "aapt2" : "aapt"); }; bool enableAapt2 = false; const auto packageType = [](bool generateAab) { return QString("modules.Android.sdk.packageType:") + (generateAab ? "aab" : "apk"); }; bool generateAab = false; bool isIncrementalBuild = false; const auto dexCompilerVersion = [](bool enableD8) { return QString("modules.Android.sdk.dexCompilerName:") + (enableD8 ? "d8" : "dx"); }; bool enableD8 = true; auto qtAppExpectedFiles = [&](bool generateAab, bool enableAapt2, bool codeSign = true, QString keyAlias="androiddebugkey") { QByteArrayList expectedFile; if (singleArchQt) { expectedFile << commonFiles(generateAab, codeSign, keyAlias) + expandArchs(ndkArchsForQt, { cxxLibPath("libgnustl_shared.so", true), "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", "lib/${ARCH}/libplugins_imageformats_libqgif.so", "lib/${ARCH}/libplugins_imageformats_libqicns.so", "lib/${ARCH}/libplugins_imageformats_libqico.so", "lib/${ARCH}/libplugins_imageformats_libqjpeg.so", "lib/${ARCH}/libplugins_imageformats_libqtga.so", "lib/${ARCH}/libplugins_imageformats_libqtiff.so", "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", "lib/${ARCH}/libplugins_imageformats_libqwebp.so", "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", "lib/${ARCH}/libplugins_styles_libqandroidstyle.so", "lib/${ARCH}/libQt5Core.so", "lib/${ARCH}/libQt5Gui.so", "lib/${ARCH}/libQt5Widgets.so", "lib/${ARCH}/libqt-app.so"}, generateAab); } else { expectedFile << commonFiles(generateAab, codeSign, keyAlias) + expandArchs(ndkArchsForQt, { cxxLibPath("libgnustl_shared.so", true), "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so", "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Core_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Gui_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Widgets_${ARCH}.so", "lib/${ARCH}/libqt-app_${ARCH}.so"}, generateAab); } if (generateAab) expectedFile << "base/resources.pb" << "base/native.pb"; else expectedFile << "resources.arsc"; if (version >= qbs::Version(5, 14)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libplugins_styles_qandroidstyle_${ARCH}.so"}, generateAab); if (version < qbs::Version(6, 0) && version >= qbs::Version(5, 14)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 5)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6Svg_${ARCH}.so", "lib/${ARCH}/libplugins_iconengines_qsvgicon_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qsvg_${ARCH}.so"}, generateAab); if (!enableAapt2 && version < qbs::Version(6, 0)) expectedFile << "res/layout/splash.xml"; return expectedFile; }; auto codeSignProperties = [&](bool codeSign, QString keyStorePath, QString keystorePassword, QString keyPassword, QString keyAlias) { if (!codeSign) return QStringList{"modules.codesign.enableCodeSigning:false"}; return QStringList{ "modules.codesign.enableCodeSigning:true", "modules.codesign.keystorePath:" + keyStorePath, "modules.codesign.keystorePassword:" + keystorePassword, "modules.codesign.keyPassword:" + keyPassword, "modules.codesign.keyAlias:" + keyAlias, }; }; bool codeSign = true; QString keyStorePath(testDataDir + "/qt-app/test.keystore"); QString keystorePassword("qbsKeystoreTest"); QString keyPassword("qbsKeyTest"); QString keyAlias("qbsTest"); QTest::newRow("qt app") << "qt-app" << QStringList("qt-app") << (QList() << (QByteArrayList() << qtAppExpectedFiles(generateAab, enableAapt2, codeSign, keyAlias))) << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, keyPassword, keyAlias) << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8;; codeSign = false; QTest::newRow("qt app no signing") << "qt-app" << QStringList("qt-app") << (QList() << (QByteArrayList() << qtAppExpectedFiles(generateAab, enableAapt2, codeSign, keyAlias))) << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, keyPassword, keyAlias) << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; codeSign = true; QTest::newRow("qt app aapt2") << "qt-app" << QStringList("qt-app") << (QList() << (QByteArrayList() << qtAppExpectedFiles(generateAab, enableAapt2, codeSign, keyAlias))) << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, keyPassword, keyAlias) << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("qt app aab") << "qt-app" << QStringList("qt-app") << (QList() << (QByteArrayList() << qtAppExpectedFiles(generateAab, enableAapt2, codeSign, keyAlias))) << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, keyPassword, keyAlias) << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; codeSign = false; QTest::newRow("qt app aab no signing") << "qt-app" << QStringList("qt-app") << (QList() << (QByteArrayList() << qtAppExpectedFiles(generateAab, enableAapt2, codeSign, keyAlias))) << (QStringList() << codeSignProperties(codeSign, keyStorePath, keystorePassword, keyPassword, keyAlias) << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; const QByteArrayList ndkArchsForQtSave = ndkArchsForQt; ndkArchsForQt = {ndkArchsForQt.first()}; QTest::newRow("qt app (single arch)") << "qt-app" << QStringList("qt-app") << (QList() << (QByteArrayList() << qtAppExpectedFiles(generateAab, enableAapt2))) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), "modules.qbs.architectures:" + archsForQt.first()} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; ndkArchsForQt = ndkArchsForQtSave; auto teaPotAppExpectedFiles = [&](const QByteArrayList &archs, bool generateAab) { QByteArrayList expectedFile; expectedFile << commonFiles(generateAab) + expandArchs(archs, { "assets/Shaders/ShaderPlain.fsh", "assets/Shaders/VS_ShaderPlain.vsh", cxxLibPath("libgnustl_shared.so", false), "lib/${ARCH}/libTeapotNativeActivity.so", "res/layout/widgets.xml", "res/mipmap-hdpi-v4/ic_launcher.png", "res/mipmap-mdpi-v4/ic_launcher.png", "res/mipmap-xhdpi-v4/ic_launcher.png", "res/mipmap-xxhdpi-v4/ic_launcher.png"}, generateAab); if (generateAab) expectedFile << "base/resources.pb" << "base/assets.pb" << "base/native.pb"; else expectedFile << "resources.arsc"; return expectedFile; }; generateAab = false; enableAapt2 = false; QTest::newRow("teapot") << "teapot" << QStringList("TeapotNativeActivity") << (QList() << teaPotAppExpectedFiles(archs, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("teapot aapt2") << "teapot" << QStringList("TeapotNativeActivity") << (QList() << teaPotAppExpectedFiles(archs, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("teapot aapt2 aab") << "teapot" << QStringList("TeapotNativeActivity") << (QList() << teaPotAppExpectedFiles(archs, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = false; generateAab = false; QTest::newRow("minimal-native") << "minimal-native" << QStringList("minimalnative") << (QList() << commonFiles(generateAab) + expandArchs({archs.first()}, { "lib/${ARCH}/libminimalnative.so", cxxLibPath("libstlport_shared.so", false), "lib/${ARCH}/libdependency.so"}, generateAab)) << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", "modules.qbs.architecture:" + archsStringList.first(), aaptVersion(enableAapt2)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("minimal-native aapt2") << "minimal-native" << QStringList("minimalnative") << (QList() << commonFiles(generateAab) + (QByteArrayList() << "resources.arsc") + expandArchs({archs.first()}, { "lib/${ARCH}/libminimalnative.so", cxxLibPath("libstlport_shared.so", false), "lib/${ARCH}/libdependency.so"}, generateAab)) << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", "modules.qbs.architecture:" + archsStringList.first(), aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("minimal-native aapt2 aab") << "minimal-native" << QStringList("minimalnative") << (QList() << commonFiles(generateAab) + (QByteArrayList() << "base/resources.pb" << "base/native.pb") + expandArchs({archs.first()}, { "lib/${ARCH}/libminimalnative.so", cxxLibPath("libstlport_shared.so", false), "lib/${ARCH}/libdependency.so"}, generateAab)) << QStringList{"products.minimalnative.multiplexByQbsProperties:[]", "modules.qbs.architecture:" + archsStringList.first(), aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; auto qmlAppExpectedFiles = [&](bool generateAab, bool enableAapt2) { QByteArrayList expectedFile; if (singleArchQt) { expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes", "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir", "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes", "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir", "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", cxxLibPath("libgnustl_shared.so", true), "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so", "lib/${ARCH}/libplugins_imageformats_libqgif.so", "lib/${ARCH}/libplugins_imageformats_libqicns.so", "lib/${ARCH}/libplugins_imageformats_libqico.so", "lib/${ARCH}/libplugins_imageformats_libqjpeg.so", "lib/${ARCH}/libplugins_imageformats_libqtga.so", "lib/${ARCH}/libplugins_imageformats_libqtiff.so", "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", "lib/${ARCH}/libplugins_imageformats_libqwebp.so", "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so", "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so", "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so", "lib/${ARCH}/libQt5Core.so", "lib/${ARCH}/libQt5Gui.so", "lib/${ARCH}/libQt5Network.so", "lib/${ARCH}/libQt5Qml.so", "lib/${ARCH}/libQt5QuickParticles.so", "lib/${ARCH}/libQt5Quick.so", "lib/${ARCH}/libqmlapp.so"}, generateAab); } else { expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { "assets/android_rcc_bundle.rcc", cxxLibPath("libgnustl_shared.so", true), "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so", "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_debugger_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_inspector_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_local_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_messages_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_native_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_nativedebugger_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_profiler_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_preview_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_quickprofiler_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_server_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_tcp_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Core_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Gui_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Network_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Qml_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Quick_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "QmlModels_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "QmlWorkerScript_${ARCH}.so", "lib/${ARCH}/libqmlapp_${ARCH}.so"}, generateAab); if (version < qbs::Version(5, 15)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt5QuickParticles_${ARCH}.so"}, generateAab); if (version >= qbs::Version(5, 15) && version < qbs::Version(6, 0)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQml_StateMachine_qtqmlstatemachine_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_WorkerScript.2_workerscriptplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_Models.2_modelsplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); if (version >= qbs::Version(5, 14) && version < qbs::Version(6, 0)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQuick.2_qtquick2plugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Window.2_windowplugin_${ARCH}.so"}, generateAab); if (version < qbs::Version(6, 0)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libplugins_bearer_qandroidbearer_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 5)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6Svg_${ARCH}.so", "lib/${ARCH}/libplugins_iconengines_qsvgicon_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qsvg_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 0)) { expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6OpenGL_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_Models_modelsplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_WorkerScript_workerscriptplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_qtquick2plugin_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 5)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQml_Base_qmlplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_qmlmetaplugin_${ARCH}.so"}, generateAab); else expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); } if (version >= qbs::Version(6, 2)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libplugins_networkinformation_qandroidnetworkinformation_${ARCH}.so", "lib/${ARCH}/libplugins_tls_qcertonlybackend_${ARCH}.so", "lib/${ARCH}/libplugins_tls_qopensslbackend_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Window_quickwindowplugin_${ARCH}.so", }, generateAab); if (version >= qbs::Version(6, 0) && version < qbs::Version(6, 3)) { expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6QuickControls2Impl_${ARCH}.so", "lib/${ARCH}/libQt6QuickControls2_${ARCH}.so", "lib/${ARCH}/libQt6QuickParticles_${ARCH}.so", "lib/${ARCH}/libQt6QuickShapes_${ARCH}.so", "lib/${ARCH}/libQt6QuickTemplates2_${ARCH}.so", "lib/${ARCH}/libQt6Sql_${ARCH}.so", "lib/${ARCH}/libplugins_sqldrivers_qsqlite_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Basic_impl_qtquickcontrols2basicstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Basic_qtquickcontrols2basicstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_impl_qtquickcontrols2fusionstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_qtquickcontrols2fusionstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_impl_qtquickcontrols2imaginestyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_qtquickcontrols2imaginestyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Material_impl_qtquickcontrols2materialstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Material_qtquickcontrols2materialstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Universal_impl_qtquickcontrols2universalstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Universal_qtquickcontrols2universalstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_impl_qtquickcontrols2implplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_qtquickcontrols2plugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_LocalStorage_qmllocalstorageplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_NativeStyle_qtquickcontrols2nativestyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Particles_particlesplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Shapes_qmlshapesplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Templates_qtquicktemplates2plugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Timeline_qtquicktimelineplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Layouts_qquicklayoutsplugin_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 2)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQuick_tooling_quicktoolingplugin_${ARCH}.so", "lib/${ARCH}/libQt6QmlLocalStorage_${ARCH}.so", "lib/${ARCH}/libQt6QmlXmlListModel_${ARCH}.so", "lib/${ARCH}/libQt6QuickDialogs2QuickImpl_${ARCH}.so", "lib/${ARCH}/libQt6QuickDialogs2Utils_${ARCH}.so", "lib/${ARCH}/libQt6QuickDialogs2_${ARCH}.so", "lib/${ARCH}/libQt6QuickLayouts_${ARCH}.so", "lib/${ARCH}/libQt6QuickTimeline_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_XmlListModel_qmlxmllistmodelplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Dialogs_qtquickdialogsplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Dialogs_quickimpl_qtquickdialogs2quickimplplugin_${ARCH}.so"}, generateAab); else expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQuick_Window_quickwindow_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_tooling_quicktooling_${ARCH}.so"}, generateAab); } } if (generateAab) expectedFile << "base/resources.pb" << "base/assets.pb" << "base/native.pb"; else expectedFile << "resources.arsc"; if (!enableAapt2 && version < qbs::Version(6, 0)) expectedFile << "res/layout/splash.xml"; return expectedFile; }; auto qmlAppCustomMetaDataExpectedFiles = [&](bool generateAab, bool enableAapt2) { QByteArrayList expectedFile; if (singleArchQt) { expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes", "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir", "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes", "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir", "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list", "assets/dummyasset.txt", cxxLibPath("libgnustl_shared.so", true), "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so", "lib/${ARCH}/libplugins_imageformats_libqgif.so", "lib/${ARCH}/libplugins_imageformats_libqicns.so", "lib/${ARCH}/libplugins_imageformats_libqico.so", "lib/${ARCH}/libplugins_imageformats_libqjpeg.so", "lib/${ARCH}/libplugins_imageformats_libqtga.so", "lib/${ARCH}/libplugins_imageformats_libqtiff.so", "lib/${ARCH}/libplugins_imageformats_libqwbmp.so", "lib/${ARCH}/libplugins_imageformats_libqwebp.so", "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so", "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so", "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so", "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so", "lib/${ARCH}/libQt5Core.so", "lib/${ARCH}/libQt5Gui.so", "lib/${ARCH}/libQt5Network.so", "lib/${ARCH}/libQt5Qml.so", "lib/${ARCH}/libQt5QuickParticles.so", "lib/${ARCH}/libQt5Quick.so", "lib/${ARCH}/libqmlapp.so"}, generateAab); } else { expectedFile << commonFiles(generateAab) + expandArchs(ndkArchsForQt, { "assets/android_rcc_bundle.rcc", "assets/dummyasset.txt", cxxLibPath("libgnustl_shared.so", true), "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so", "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_debugger_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_inspector_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_local_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_messages_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_native_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_nativedebugger_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_profiler_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_preview_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_quickprofiler_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_server_${ARCH}.so", "lib/${ARCH}/libplugins_qmltooling_qmldbg_tcp_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Core_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Gui_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Network_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Qml_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "Quick_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "QmlModels_${ARCH}.so", "lib/${ARCH}/libQt" + qtVersionMajor + "QmlWorkerScript_${ARCH}.so", "lib/${ARCH}/libqmlapp_${ARCH}.so"}, generateAab); if (version < qbs::Version(5, 15)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt5QuickParticles_${ARCH}.so"}, generateAab); if (version >= qbs::Version(5, 15) && version < qbs::Version(6, 0)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQml_StateMachine_qtqmlstatemachine_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_WorkerScript.2_workerscriptplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_Models.2_modelsplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); if (version >= qbs::Version(5, 14) && version < qbs::Version(6, 0)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQuick.2_qtquick2plugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Window.2_windowplugin_${ARCH}.so"}, generateAab); if (version < qbs::Version(6, 0)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libplugins_bearer_qandroidbearer_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 5)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6Svg_${ARCH}.so", "lib/${ARCH}/libplugins_iconengines_qsvgicon_${ARCH}.so", "lib/${ARCH}/libplugins_imageformats_qsvg_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 0)) { expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6OpenGL_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_Models_modelsplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_WorkerScript_workerscriptplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_qtquick2plugin_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 5)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQml_Base_qmlplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_qmlmetaplugin_${ARCH}.so"}, generateAab); else expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQml_qmlplugin_${ARCH}.so"}, generateAab); } if (version >= qbs::Version(6, 2)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libplugins_networkinformation_qandroidnetworkinformation_${ARCH}.so", "lib/${ARCH}/libplugins_tls_qcertonlybackend_${ARCH}.so", "lib/${ARCH}/libplugins_tls_qopensslbackend_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Window_quickwindowplugin_${ARCH}.so", }, generateAab); if (version >= qbs::Version(6, 0) && version < qbs::Version(6, 3)) { expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libQt6QuickControls2Impl_${ARCH}.so", "lib/${ARCH}/libQt6QuickControls2_${ARCH}.so", "lib/${ARCH}/libQt6QuickParticles_${ARCH}.so", "lib/${ARCH}/libQt6QuickShapes_${ARCH}.so", "lib/${ARCH}/libQt6QuickTemplates2_${ARCH}.so", "lib/${ARCH}/libQt6Sql_${ARCH}.so", "lib/${ARCH}/libplugins_sqldrivers_qsqlite_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Basic_impl_qtquickcontrols2basicstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Basic_qtquickcontrols2basicstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_impl_qtquickcontrols2fusionstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Fusion_qtquickcontrols2fusionstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_impl_qtquickcontrols2imaginestyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Imagine_qtquickcontrols2imaginestyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Material_impl_qtquickcontrols2materialstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Material_qtquickcontrols2materialstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Universal_impl_qtquickcontrols2universalstyleimplplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_Universal_qtquickcontrols2universalstyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_impl_qtquickcontrols2implplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Controls_qtquickcontrols2plugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_LocalStorage_qmllocalstorageplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_NativeStyle_qtquickcontrols2nativestyleplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Particles_particlesplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Shapes_qmlshapesplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Templates_qtquicktemplates2plugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Timeline_qtquicktimelineplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Layouts_qquicklayoutsplugin_${ARCH}.so"}, generateAab); if (version >= qbs::Version(6, 2)) expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQuick_tooling_quicktoolingplugin_${ARCH}.so", "lib/${ARCH}/libQt6QmlLocalStorage_${ARCH}.so", "lib/${ARCH}/libQt6QmlXmlListModel_${ARCH}.so", "lib/${ARCH}/libQt6QuickDialogs2QuickImpl_${ARCH}.so", "lib/${ARCH}/libQt6QuickDialogs2Utils_${ARCH}.so", "lib/${ARCH}/libQt6QuickDialogs2_${ARCH}.so", "lib/${ARCH}/libQt6QuickLayouts_${ARCH}.so", "lib/${ARCH}/libQt6QuickTimeline_${ARCH}.so", "lib/${ARCH}/libqml_QtQml_XmlListModel_qmlxmllistmodelplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Dialogs_qtquickdialogsplugin_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_Dialogs_quickimpl_qtquickdialogs2quickimplplugin_${ARCH}.so"}, generateAab); else expectedFile << expandArchs(ndkArchsForQt, { "lib/${ARCH}/libqml_QtQuick_Window_quickwindow_${ARCH}.so", "lib/${ARCH}/libqml_QtQuick_tooling_quicktooling_${ARCH}.so"}, generateAab); } } if (generateAab) expectedFile << "base/resources.pb" << "base/assets.pb" << "base/native.pb"; else expectedFile << "resources.arsc"; if (!enableAapt2 && version < qbs::Version(6, 0)) expectedFile << "res/layout/splash.xml"; return expectedFile; }; QStringList qmlAppCustomProperties; if (singleArchQt) { qmlAppCustomProperties = QStringList{"modules.Android.sdk.automaticSources:false", "modules.qbs.architecture:" + archsForQt.first()}; } else { qmlAppCustomProperties = QStringList{"modules.Android.sdk.automaticSources:false"}; } // aapt tool for the resources works with a directory option pointing to the parent directory // of the resources (res). // The Qt.android_support module adds res/values/libs.xml (from Qt install dir). So the res from // Qt install res directory is added to aapt. This results in adding res/layout/splash.xml to // the package eventhough the file is not needed. // On the other hand aapt2 requires giving all the resources files. // Also when enabling aapt2 the resources.arsc is always created, eventhough no resources are // declared. enableAapt2 = false; generateAab = false; QTest::newRow("qml app") << "qml-app" << QStringList("qmlapp") << (QList() << qmlAppExpectedFiles(generateAab, enableAapt2)) << (QStringList() << qmlAppCustomProperties << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("qml app aapt2") << "qml-app" << QStringList("qmlapp") << (QList() << qmlAppExpectedFiles(generateAab, enableAapt2)) << (QStringList() << qmlAppCustomProperties << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("qml app aab") << "qml-app" << QStringList("qmlapp") << (QList() << qmlAppExpectedFiles(generateAab, enableAapt2)) << (QStringList() << qmlAppCustomProperties << aaptVersion(enableAapt2) << packageType(generateAab)) << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = false; generateAab = false; QTest::newRow("qml app with custom metadata") << "qml-app" << QStringList("qmlapp") << (QList() << (QByteArrayList() << qmlAppCustomMetaDataExpectedFiles(generateAab, enableAapt2))) << QStringList{"modules.Android.sdk.automaticSources:true", aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("qml app with custom metadata aapt2") << "qml-app" << QStringList("qmlapp") << (QList() << (QByteArrayList() << qmlAppCustomMetaDataExpectedFiles(generateAab, enableAapt2))) << QStringList{"modules.Android.sdk.automaticSources:true", aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; if (!singleArchQt) { QTest::newRow("qml app with custom metadata aab") << "qml-app" << QStringList("qmlapp") << (QList() << (QByteArrayList() << qmlAppCustomMetaDataExpectedFiles(generateAab, enableAapt2))) << QStringList{"modules.Android.sdk.automaticSources:true", aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; } isIncrementalBuild = false; enableAapt2 = false; generateAab = false; auto noNativeExpectedFiles = [&](bool generateAab) { QByteArrayList expectedFile; expectedFile << commonFiles(generateAab) + expandArchs(archs, { "res/drawable-hdpi-v4/ic_action_play_disabled.png", "res/drawable-hdpi-v4/ic_action_play.png", "res/drawable-hdpi-v4/ic_launcher.png", "res/drawable-hdpi-v4/tile.9.png", "res/drawable-mdpi-v4/ic_action_play_disabled.png", "res/drawable-mdpi-v4/ic_action_play.png", "res/drawable-mdpi-v4/ic_launcher.png", "res/drawable/selector_play.xml", "res/drawable-xhdpi-v4/ic_action_play_disabled.png", "res/drawable-xhdpi-v4/ic_action_play.png", "res/drawable-xhdpi-v4/ic_launcher.png", "res/drawable-xxhdpi-v4/ic_launcher.png", "res/layout/sample_main.xml", "res/menu/action_menu.xml", "res/raw/vid_bigbuckbunny.mp4"}, generateAab); if (generateAab) expectedFile << "base/resources.pb"; else expectedFile << "resources.arsc"; return expectedFile; }; QTest::newRow("no native") << "no-native" << QStringList("com.example.android.basicmediadecoder") << (QList() << noNativeExpectedFiles(generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("no native aapt2") << "no-native" << QStringList("com.example.android.basicmediadecoder") << (QList() << noNativeExpectedFiles(generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("no native aab") << "no-native" << QStringList("com.example.android.basicmediadecoder") << (QList() << noNativeExpectedFiles(generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = false; generateAab = false; QTest::newRow("aidl") << "aidl" << QStringList("io.qbs.aidltest") << (QList() << (QByteArrayList() << commonFiles(generateAab))) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("aidl aapt2") << "aidl" << QStringList("io.qbs.aidltest") << (QList() << (QByteArrayList() << commonFiles(generateAab) << "resources.arsc")) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("aidl aab") << "aidl" << QStringList("io.qbs.aidltest") << (QList() << (QByteArrayList() << commonFiles(generateAab) << "base/resources.pb")) << QStringList{aaptVersion(enableAapt2), packageType(generateAab)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = false; generateAab = false; enableD8 = false; QTest::newRow("multiple libs") << "multiple-libs-per-apk" << QStringList("twolibs") << (QList() << commonFiles(generateAab) + expandArchs(archs, { "resources.arsc", "lib/${ARCH}/liblib1.so", "lib/${ARCH}/liblib2.so", cxxLibPath("libstlport_shared.so", false)}, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableD8 = true; QTest::newRow("multiple libs with d8") << "multiple-libs-per-apk" << QStringList("twolibs") << (QList() << commonFiles(generateAab) + expandArchs(archs, { "resources.arsc", "lib/${ARCH}/liblib1.so", "lib/${ARCH}/liblib2.so", cxxLibPath("libstlport_shared.so", false)}, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableD8 = false; enableAapt2 = true; QTest::newRow("multiple libs aapt2") << "multiple-libs-per-apk" << QStringList("twolibs") << (QList() << commonFiles(generateAab) + expandArchs(archs, { "resources.arsc", "lib/${ARCH}/liblib1.so", "lib/${ARCH}/liblib2.so", cxxLibPath("libstlport_shared.so", false)}, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("multiple libs aab") << "multiple-libs-per-apk" << QStringList("twolibs") << (QList() << commonFiles(generateAab) + expandArchs(archs, { "resources.pb", "native.pb", "lib/${ARCH}/liblib1.so", "lib/${ARCH}/liblib2.so", cxxLibPath("libstlport_shared.so", false)}, generateAab)) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = false; generateAab = false; auto expectedFiles1 = [&](bool generateAab) { QByteArrayList expectedFile = qbs::toList(qbs::toSet(commonFiles(generateAab) + expandArchs(QByteArrayList{"armeabi-v7a", "x86"}, { "lib/${ARCH}/libp1lib1.so", cxxLibPath("libstlport_shared.so", false)}, generateAab) + expandArchs(QByteArrayList{archs}, { "lib/${ARCH}/libp1lib2.so", cxxLibPath("libstlport_shared.so", false)}, generateAab))); if (generateAab) expectedFile << "base/resources.pb" << "base/native.pb"; else expectedFile << "resources.arsc"; return expectedFile; }; auto expectedFiles2 = [&](bool generateAab) { QByteArrayList expectedFile = commonFiles(generateAab) + expandArchs(archs, { "lib/${ARCH}/libp2lib1.so", "lib/${ARCH}/libp2lib2.so", cxxLibPath("libstlport_shared.so", false)}, generateAab); return expectedFile; }; QTest::newRow("multiple apks") << "multiple-apks-per-project" << (QStringList() << "twolibs1" << "twolibs2") << QList{expectedFiles1(generateAab), expectedFiles2(generateAab)} << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; enableAapt2 = true; QTest::newRow("multiple apks aapt2") << "multiple-apks-per-project" << (QStringList() << "twolibs1" << "twolibs2") << (QList() << expectedFiles1(generateAab) << (QByteArrayList() << expectedFiles2(generateAab) << "resources.arsc")) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; generateAab = true; QTest::newRow("multiple apks aab") << "multiple-apks-per-project" << (QStringList() << "twolibs1" << "twolibs2") << (QList() << expectedFiles1(generateAab) << (QByteArrayList() << expectedFiles2(generateAab) << "base/resources.pb" << "base/native.pb")) << QStringList{aaptVersion(enableAapt2), packageType(generateAab), dexCompilerVersion(enableD8)} << enableAapt2 << generateAab << isIncrementalBuild << enableD8; } QTEST_MAIN(TestBlackboxAndroid) qbs-src-2.6.1/tests/auto/blackbox/testdata-java/0000755000175100001660000000000014776170045021077 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/0000755000175100001660000000000014776170045022020 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Vehicles.java0000644000175100001660000000142314776170045024425 0ustar runnerdockerimport java.util.ArrayList; import glob.RandomStuff; class Vehicles { public static void main(String[] args) { System.loadLibrary("native"); RandomStuff.bar(); ArrayList vehicles = new ArrayList(); for (int i = 0; i < 3; i++) { vehicles.add(new Car()); } for (int i = 0; i < 3; i++) { vehicles.add(new Jet()); } for (int i = 0; i < 4; i++) { Ship ship = new Ship(); ship.isInSpace = i % 2 == 0; vehicles.add(ship); } for (int i = 0; i < vehicles.size(); i++) { vehicles.get(i).go(); } // doesn't compile, must be a bug // delete vehicles; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Car8.java0000644000175100001660000000107214776170045023460 0ustar runnerdockerclass Car8 implements Vehicle { private InternalCombustionEngine engine; public Car8() { engine = new InternalCombustionEngine(); } public void go() { System.out.println("Driving!"); engine.run(); } public class InternalCombustionEngine { public native void run(); public class ChemicalReaction { public native void occur(); public class Atoms { @java.lang.annotation.Native public int hydrogenAtomCount; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/engine.c0000644000175100001660000000305214776170045023431 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include // javac 1.8 is required to generate native headers #ifdef JNI_VERSION_1_8 #include "Car_InternalCombustionEngine.h" #endif JNIEXPORT void JNICALL Java_Car_00024InternalCombustionEngine_run(JNIEnv *env, jobject obj) { printf("Native code performing complex internal combustion process (%p, %p)!\n", env, obj); } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/vehicles.qbs0000644000175100001660000000574014776170045024337 0ustar runnerdockerimport qbs.FileInfo import qbs.Host import qbs.Utilities Project { DynamicLibrary { Depends { name: "cpp" } Depends { name: "car_jar" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } property bool _testPlatform: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "native" files: ["engine.c"] qbs.installPrefix: "" install: true installDir: "" } JavaClassCollection { Depends { name: "random_stuff" } name: "cc" java.additionalCompilerFlags: ["-Xlint:all"] files: [ "Car.java", "HelloWorld.java", "Jet.java", "NoPackage.java", "Ship.java", "Vehicle.java", "Vehicles.java" ] Group { condition: Utilities.versionCompare(java.version, "1.8") >= 0 files: ["Car8.java", "HelloWorld8.java"] } Export { Depends { name: "java" } java.manifestClassPath: [exportingProduct.targetName + ".jar"] } } JavaJarFile { name: "random_stuff" files: ["RandomStuff.java"] qbs.installPrefix: "" Group { fileTagsFilter: ["java.jar"] qbs.install: true } Export { Depends { name: "java" } java.manifestClassPath: [exportingProduct.targetName + ".jar"] } } JavaJarFile { name: "car_jar" files: ["Car.java", "Vehicle.java"] Group { condition: Utilities.versionCompare(java.version, "1.8") >= 0 files: ["Car8.java"] } Export { Depends { name: "cpp" } cpp.systemIncludePaths: { var paths = importingProduct.java.jdkIncludePaths; if (Utilities.versionCompare(importingProduct.java.version, "1.8") >= 0) { paths.push(exportingProduct.buildDirectory); // generated JNI headers } return paths; } Depends { name: "java" } java.manifestClassPath: [exportingProduct.targetName + ".jar"] } qbs.installPrefix: "" Group { fileTagsFilter: ["java.jar"] qbs.install: true } } JavaJarFile { Depends { name: "random_stuff" } Depends { name: "car_jar" } Depends { name: "native" } name: "jar_file" entryPoint: "Vehicles" files: ["Jet.java", "Ship.java", "Vehicles.java", "Manifest.mf", "Manifest2.mf"] java.manifest: { var mf = original; mf["Extra-Property"] = "Crazy-Value"; return mf; } qbs.installPrefix: "" Group { fileTagsFilter: ["java.jar"] qbs.install: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/HelloWorld.java0000644000175100001660000000043714776170045024742 0ustar runnerdockerpackage io.qt.qbs; public class HelloWorld { public static void main(String[] args) { System.out.println("Tach."); } public class Internal { public native void something(); } public class Other { public final int countOfThings = 0; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Manifest.mf0000644000175100001660000000003214776170045024105 0ustar runnerdockerSome-Property: Some-Value qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/NoPackage.java0000644000175100001660000000014614776170045024514 0ustar runnerdocker// package this.should.not.be.parsed; public class NoPackage { public static void doSomething() {} } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/HelloWorld8.java0000644000175100001660000000024114776170045025023 0ustar runnerdockerpackage io.qt.qbs; public class HelloWorld8 { public class Other { @java.lang.annotation.Native public final int countOfThings = 0; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Ship.java0000644000175100001660000000036414776170045023571 0ustar runnerdockerclass Ship implements Vehicle { public boolean isInSpace; public void go() { if (isInSpace) System.out.println("Flying (this is a space ship)!"); else System.out.println("Sailing!"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/RandomStuff.java0000644000175100001660000000012114776170045025105 0ustar runnerdockerpackage glob; public class RandomStuff { public static void bar() { } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Car.java0000644000175100001660000000065514776170045023376 0ustar runnerdockerclass Car implements Vehicle { private InternalCombustionEngine engine; public Car() { engine = new InternalCombustionEngine(); } public void go() { System.out.println("Driving!"); engine.run(); } public class InternalCombustionEngine { public native void run(); public class ChemicalReaction { public native void occur(); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/inner-class/0000755000175100001660000000000014776170045024236 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/inner-class/InnerClass.java0000644000175100001660000000021014776170045027133 0ustar runnerdockerpublic class InnerClass { private final InnerInnerClass clazz = new InnerInnerClass(); private class InnerInnerClass { } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/inner-class/inner-class.qbs0000644000175100001660000000005114776170045027157 0ustar runnerdockerJavaJarFile { files: ["**/*.java"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Manifest2.mf0000644000175100001660000000010014776170045024163 0ustar runnerdockerSome-Property: Some-Value Additional-Property: Additional-Value qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Jet.java0000644000175100001660000000015114776170045023402 0ustar runnerdockerclass Jet implements Vehicle { public void go() { System.out.println("Flying!"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-java/java/Vehicle.java0000644000175100001660000000005414776170045024241 0ustar runnerdockerinterface Vehicle { public void go(); } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxwindows.cpp0000644000175100001660000002673214776170045023157 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "tst_blackboxwindows.h" #include "../shared.h" #include #include #include #include #include using qbs::Internal::HostOsInfo; using qbs::Profile; struct SigntoolInfo { enum class CodeSignResult { Failed = 0, Signed, Unsigned }; CodeSignResult result = CodeSignResult::Failed; bool timestamped = false; QString hashAlgorithm; QString subjectName; }; Q_DECLARE_METATYPE(SigntoolInfo::CodeSignResult) static SigntoolInfo extractSigntoolInfo(const QString &signtoolPath, const QString &appPath) { QProcess signtool; signtool.start(signtoolPath, { QStringLiteral("verify"), QStringLiteral("/v"), appPath }); if (!signtool.waitForStarted() || !signtool.waitForFinished()) return {}; const auto output = signtool.readAllStandardError(); SigntoolInfo signtoolInfo; if (output.contains("No signature found")) { signtoolInfo.result = SigntoolInfo::CodeSignResult::Unsigned; } else { signtoolInfo.result = SigntoolInfo::CodeSignResult::Signed; const auto output = signtool.readAllStandardOutput(); const auto lines = output.split('\n'); for (const auto &line: lines) { { const QRegularExpression re("^Hash of file \\((.+)\\):.+$"); const QRegularExpressionMatch match = re.match(line); if (match.hasMatch()) { signtoolInfo.hashAlgorithm = match.captured(1).toLocal8Bit(); continue; } } { const QRegularExpression re("Issued to: (.+)"); const QRegularExpressionMatch match = re.match(line); if (match.hasMatch()) { signtoolInfo.subjectName = match.captured(1).toLocal8Bit().trimmed(); continue; } } if (line.startsWith("The signature is timestamped:")) { signtoolInfo.timestamped = true; break; } else if (line.startsWith("File is not timestamped.")) { break; } } } return signtoolInfo; } static QString extractSigntoolPath(const QByteArray &output) { const QRegularExpression re("%%(.+)%%"); QRegularExpressionMatchIterator it = re.globalMatch(output); if (!it.hasNext()) return {}; const QRegularExpressionMatch match = it.next(); return match.captured(1).toUtf8(); } TestBlackboxWindows::TestBlackboxWindows() : TestBlackboxBase (SRCDIR "/testdata-windows", "blackbox-windows") { } void TestBlackboxWindows::initTestCase() { if (!HostOsInfo::isWindowsHost()) { QSKIP("only applies on Windows"); return; } TestBlackboxBase::initTestCase(); } void TestBlackboxWindows::innoSetup() { const SettingsPtr s = settings(); Profile profile(profileName(), s.get()); QDir::setCurrent(testDataDir + "/innosetup"); QCOMPARE(runQbs({"resolve"}), 0); const bool withInnosetup = m_qbsStdout.contains("has innosetup: true"); const bool withoutInnosetup = m_qbsStdout.contains("has innosetup: false"); QVERIFY2(withInnosetup || withoutInnosetup, m_qbsStdout.constData()); if (withoutInnosetup) QSKIP("innosetup module not present"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling test.iss")); QVERIFY(m_qbsStdout.contains("compiling Example1.iss")); QVERIFY(regularFileExists(relativeProductBuildDir("QbsSetup") + "/qbs.setup.test.exe")); QVERIFY(regularFileExists(relativeProductBuildDir("Example1") + "/Example1.exe")); } void TestBlackboxWindows::innoSetupDependencies() { const SettingsPtr s = settings(); Profile profile(profileName(), s.get()); QDir::setCurrent(testDataDir + "/innosetupDependencies"); QCOMPARE(runQbs({"resolve"}), 0); const bool withInnosetup = m_qbsStdout.contains("has innosetup: true"); const bool withoutInnosetup = m_qbsStdout.contains("has innosetup: false"); QVERIFY2(withInnosetup || withoutInnosetup, m_qbsStdout.constData()); if (withoutInnosetup) QSKIP("innosetup module not present"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling test.iss")); QVERIFY(regularFileExists(relativeBuildDir() + "/qbs.setup.test.exe")); } void TestBlackboxWindows::standaloneCodesign() { QFETCH(SigntoolInfo::CodeSignResult, result); QFETCH(QString, hashAlgorithm); QFETCH(QString, subjectName); QFETCH(QString, signingTimestamp); QDir::setCurrent(testDataDir + "/codesign"); QbsRunParameters params(QStringList{"qbs.installPrefix:''"}); params.arguments << QStringLiteral("project.enableSigning:%1").arg( (result == SigntoolInfo::CodeSignResult::Signed) ? "true" : "false") << QStringLiteral("project.hashAlgorithm:%1").arg(hashAlgorithm) << QStringLiteral("project.subjectName:%1").arg(subjectName) << QStringLiteral("project.signingTimestamp:%1").arg(signingTimestamp); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); if (!m_qbsStdout.contains("signtool path:")) QSKIP("No current signtool path pattern exists"); const auto signtoolPath = extractSigntoolPath(m_qbsStdout); QVERIFY(QFileInfo(signtoolPath).exists()); const QStringList outputBinaries = {"A.exe", "B.dll"}; for (const auto &outputBinary : outputBinaries) { const auto outputBinaryPath = defaultInstallRoot + "/" + outputBinary; QVERIFY(QFileInfo(outputBinaryPath).exists()); const SigntoolInfo signtoolInfo = extractSigntoolInfo(signtoolPath, outputBinaryPath); QVERIFY(signtoolInfo.result != SigntoolInfo::CodeSignResult::Failed); QCOMPARE(signtoolInfo.result, result); QCOMPARE(signtoolInfo.hashAlgorithm, hashAlgorithm); QCOMPARE(signtoolInfo.subjectName, subjectName); QCOMPARE(signtoolInfo.timestamped, !signingTimestamp.isEmpty()); } } void TestBlackboxWindows::standaloneCodesign_data() { QTest::addColumn("result"); QTest::addColumn("hashAlgorithm"); QTest::addColumn("subjectName"); QTest::addColumn("signingTimestamp"); QTest::newRow("standalone, unsigned") << SigntoolInfo::CodeSignResult::Unsigned << "" << "" << ""; QTest::newRow("standalone, signed, sha1, qbs@community.test, no timestamp") << SigntoolInfo::CodeSignResult::Signed << "sha1" << "qbs@community.test" << ""; QTest::newRow("standalone, signed, sha256, qbs@community.test, RFC3061 timestamp") << SigntoolInfo::CodeSignResult::Signed << "sha256" << "qbs@community.test" << "http://timestamp.digicert.com"; } static bool haveWiX(const Profile &profile) { if (profile.value("wix.toolchainInstallPath").isValid() && profile.value("wix.toolchainInstallRoot").isValid()) { return true; } QStringList regKeys; regKeys << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows Installer XML\\") << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Installer XML\\"); QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); for (const QString &key : std::as_const(regKeys)) { const QStringList versions = QSettings(key, QSettings::NativeFormat).childGroups(); for (const QString &version : versions) { QSettings settings(key + version, QSettings::NativeFormat); QString str = settings.value(QStringLiteral("InstallRoot")).toString(); if (!str.isEmpty()) paths.prepend(str); } } for (const QString &path : std::as_const(paths)) { if (regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QStringLiteral("/candle"))) && regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QStringLiteral("/light")))) { return true; } } return false; } void TestBlackboxWindows::wix() { const SettingsPtr s = settings(); Profile profile(profileName(), s.get()); if (!haveWiX(profile)) { QSKIP("WiX is not installed"); return; } QByteArray arch = profile.value("qbs.architecture").toString().toLatin1(); if (arch.isEmpty()) arch = QByteArrayLiteral("x86"); QDir::setCurrent(testDataDir + "/wix"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling QbsSetup.wxs"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("linking qbs.msi"), m_qbsStdout); QVERIFY(regularFileExists(relativeProductBuildDir("QbsSetup") + "/qbs.msi")); if (HostOsInfo::isWindowsHost()) { QVERIFY2(m_qbsStdout.contains("compiling QbsBootstrapper.wxs"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("linking qbs-setup-" + arch + ".exe"), m_qbsStdout); QVERIFY(regularFileExists(relativeProductBuildDir("QbsBootstrapper") + "/qbs-setup-" + arch + ".exe")); } } void TestBlackboxWindows::wixDependencies() { const SettingsPtr s = settings(); Profile profile(profileName(), s.get()); if (!haveWiX(profile)) { QSKIP("WiX is not installed"); return; } QByteArray arch = profile.value("qbs.architecture").toString().toLatin1(); if (arch.isEmpty()) arch = QByteArrayLiteral("x86"); QDir::setCurrent(testDataDir + "/wixDependencies"); QbsRunParameters params; if (!HostOsInfo::isWindowsHost()) params.arguments << "qbs.targetOS:windows"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("compiling QbsSetup.wxs"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("linking qbs.msi"), m_qbsStdout); QVERIFY(regularFileExists(relativeBuildDir() + "/qbs.msi")); } QTEST_MAIN(TestBlackboxWindows) qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxbaremetal.cpp0000644000175100001660000002725514776170045023422 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "tst_blackboxbaremetal.h" #include "../shared.h" #include #include static bool extractToolset(const QByteArray &output, QByteArray &toolchain, QByteArray &architecture) { const QRegularExpression re("%%([\\w\\-]+)%%, %%(\\w+)%%"); QRegularExpressionMatchIterator it = re.globalMatch(output); if (!it.hasNext()) return false; const QRegularExpressionMatch match = it.next(); toolchain = match.captured(1).toLocal8Bit(); architecture = match.captured(2).toLocal8Bit(); return true; } static bool extractCompilerIncludePaths(const QByteArray &output, QStringList &compilerIncludePaths) { const QRegularExpression re("%%([^%%]+)%%"); QRegularExpressionMatchIterator it = re.globalMatch(output); if (!it.hasNext()) return false; const QRegularExpressionMatch match = it.next(); compilerIncludePaths = match.captured(1).split(","); return true; } static bool extractQuitedValue(const QByteArray &output, QString &pattern) { const QRegularExpression re("%%(.+)%%"); const QRegularExpressionMatch match = re.match(output); if (!match.hasMatch()) return false; pattern = match.captured(1); return true; } static QByteArray unsupportedToolsetMessage(const QByteArray &output) { QByteArray toolchain; QByteArray architecture; extractToolset(output, toolchain, architecture); return "Unsupported toolchain '" + toolchain + "' for architecture '" + architecture + "'"; } static QByteArray brokenProbeMessage(const QByteArray &output) { QByteArray toolchain; QByteArray architecture; extractToolset(output, toolchain, architecture); return "Broken probe for toolchain '" + toolchain + "' for architecture '" + architecture + "'"; } TestBlackboxBareMetal::TestBlackboxBareMetal() : TestBlackboxBase (SRCDIR "/testdata-baremetal", "blackbox-baremetal") { } void TestBlackboxBareMetal::targetPlatform() { QDir::setCurrent(testDataDir + "/target-platform"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("unsupported toolset:")) QSKIP(unsupportedToolsetMessage(m_qbsStdout)); const bool hasNoPlatform = m_qbsStdout.contains("has no platform: true"); QCOMPARE(hasNoPlatform, true); const bool hasNoOS = m_qbsStdout.contains("has no os: true"); QCOMPARE(hasNoOS, true); } void TestBlackboxBareMetal::application_data() { QTest::addColumn("testPath"); QTest::newRow("one-object-application") << "/one-object-application"; QTest::newRow("two-object-application") << "/two-object-application"; QTest::newRow("one-object-asm-application") << "/one-object-asm-application"; } void TestBlackboxBareMetal::application() { QFETCH(QString, testPath); QDir::setCurrent(testDataDir + testPath); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("unsupported toolset:")) QSKIP(unsupportedToolsetMessage(m_qbsStdout)); QCOMPARE(runQbs(QbsRunParameters("build")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); } void TestBlackboxBareMetal::staticLibraryDependencies() { QDir::setCurrent(testDataDir + "/static-library-dependencies"); QCOMPARE(runQbs(QStringList{"-p", "lib-a,lib-b,lib-c,lib-d,lib-e"}), 0); QCOMPARE(runQbs(QStringList{"--command-echo-mode", "command-line"}), 0); const QByteArray output = m_qbsStdout + '\n' + m_qbsStderr; QVERIFY(output.contains("lib-a")); QVERIFY(output.contains("lib-b")); QVERIFY(output.contains("lib-c")); QVERIFY(output.contains("lib-d")); QVERIFY(output.contains("lib-e")); } void TestBlackboxBareMetal::externalStaticLibraries() { QDir::setCurrent(testDataDir + "/external-static-libraries"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("unsupported toolset:")) QSKIP(unsupportedToolsetMessage(m_qbsStdout)); QCOMPARE(runQbs(), 0); } void TestBlackboxBareMetal::sharedLibraries() { QDir::setCurrent(testDataDir + "/shared-libraries"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("unsupported toolset:")) QSKIP(unsupportedToolsetMessage(m_qbsStdout)); QCOMPARE(runQbs(QbsRunParameters("build")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("Hello from app"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("Hello from lib"), m_qbsStdout.constData()); } void TestBlackboxBareMetal::userIncludePaths() { QDir::setCurrent(testDataDir + "/user-include-paths"); QCOMPARE(runQbs(), 0); } void TestBlackboxBareMetal::systemIncludePaths() { QDir::setCurrent(testDataDir + "/system-include-paths"); QCOMPARE(runQbs(), 0); } void TestBlackboxBareMetal::distributionIncludePaths() { QDir::setCurrent(testDataDir + "/distribution-include-paths"); QCOMPARE(runQbs(), 0); } void TestBlackboxBareMetal::compilerIncludePaths() { QDir::setCurrent(testDataDir + "/compiler-include-paths"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (!m_qbsStdout.contains("compilerIncludePaths:")) QFAIL("No compiler include paths exists"); QStringList includePaths; QVERIFY(extractCompilerIncludePaths(m_qbsStdout, includePaths)); QVERIFY(includePaths.count() > 0); for (const auto &includePath : includePaths) { const QDir dir(includePath); QVERIFY(dir.exists()); } } void TestBlackboxBareMetal::preincludeHeaders() { QDir::setCurrent(testDataDir + "/preinclude-headers"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("unsupported toolset:")) QSKIP(unsupportedToolsetMessage(m_qbsStdout)); QCOMPARE(runQbs(), 0); } void TestBlackboxBareMetal::defines() { QDir::setCurrent(testDataDir + "/defines"); QCOMPARE(runQbs(), 0); } void TestBlackboxBareMetal::compilerListingFiles_data() { QTest::addColumn("generateListing"); QTest::addColumn("customListingSuffix"); QTest::newRow("do-not-generate-compiler-listing") << false << ""; QTest::newRow("generate-default-compiler-listing") << true << ""; QTest::newRow("generate-custom-compiler-listing") << true << ".lll"; } void TestBlackboxBareMetal::compilerListingFiles() { QFETCH(bool, generateListing); QFETCH(QString, customListingSuffix); QDir::setCurrent(testDataDir + "/compiler-listing"); rmDirR(relativeBuildDir()); QStringList args = {QStringLiteral("modules.cpp.generateCompilerListingFiles:%1") .arg(generateListing ? "true" : "false")}; if (!customListingSuffix.isEmpty()) args << QStringLiteral("modules.cpp.compilerListingSuffix:%1").arg(customListingSuffix); QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0); if (m_qbsStdout.contains("unsupported toolset:")) QSKIP(unsupportedToolsetMessage(m_qbsStdout)); if (!m_qbsStdout.contains("compiler listing suffix:")) QFAIL("No current compiler listing suffix pattern exists"); QString compilerListingSuffix; if (!extractQuitedValue(m_qbsStdout, compilerListingSuffix)) QFAIL("Unable to extract current compiler listing suffix"); if (!customListingSuffix.isEmpty()) QCOMPARE(compilerListingSuffix, customListingSuffix); QCOMPARE(runQbs(QbsRunParameters(args)), 0); const QString productBuildDir = relativeProductBuildDir("compiler-listing"); const QString hash = inputDirHash("."); const QString mainListing = productBuildDir + "/" + hash + "/main.c" + compilerListingSuffix; QCOMPARE(regularFileExists(mainListing), generateListing); const QString funListing = productBuildDir + "/" + hash + "/fun.c" + compilerListingSuffix; QCOMPARE(regularFileExists(funListing), generateListing); } void TestBlackboxBareMetal::linkerMapFile_data() { QTest::addColumn("generateMap"); QTest::addColumn("customMapSuffix"); QTest::newRow("do-not-generate-linker-map") << false << ""; QTest::newRow("generate-default-linker-map") << true << ""; QTest::newRow("generate-custom-linker-map") << true << ".mmm"; } void TestBlackboxBareMetal::linkerMapFile() { QFETCH(bool, generateMap); QFETCH(QString, customMapSuffix); QDir::setCurrent(testDataDir + "/linker-map"); rmDirR(relativeBuildDir()); QStringList args = {QStringLiteral("modules.cpp.generateLinkerMapFile:%1") .arg(generateMap ? "true" : "false")}; if (!customMapSuffix.isEmpty()) args << QStringLiteral("modules.cpp.linkerMapSuffix:%1").arg(customMapSuffix); QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0); if (!m_qbsStdout.contains("linker map suffix:")) QFAIL("No current linker map suffix pattern exists"); QString linkerMapSuffix; if (!extractQuitedValue(m_qbsStdout, linkerMapSuffix)) QFAIL("Unable to extract current linker map suffix"); if (!customMapSuffix.isEmpty()) QCOMPARE(linkerMapSuffix, customMapSuffix); QCOMPARE(runQbs(QbsRunParameters(args)), 0); const QString productBuildDir = relativeProductBuildDir("linker-map"); const QString linkerMap = productBuildDir + "/linker-map" + linkerMapSuffix; QCOMPARE(regularFileExists(linkerMap), generateMap); } void TestBlackboxBareMetal::compilerDefinesByLanguage() { QDir::setCurrent(testDataDir + "/compiler-defines-by-language"); QbsRunParameters params(QStringList{ "-f", "compiler-defines-by-language.qbs" }); QCOMPARE(runQbs(params), 0); } void TestBlackboxBareMetal::toolchainProbe() { QDir::setCurrent(testDataDir + "/toolchain-probe"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("broken probe:")) QFAIL(brokenProbeMessage(m_qbsStdout)); } QTEST_MAIN(TestBlackboxBareMetal) qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxproviders.cpp0000644000175100001660000005110214776170045023467 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "tst_blackboxproviders.h" #include "../shared.h" #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) TestBlackboxProviders::TestBlackboxProviders() : TestBlackboxBase(SRCDIR "/testdata-providers", "blackbox-providers") { } void TestBlackboxProviders::allowedValues() { QFETCH(QStringList, arguments); QFETCH(bool, expectFailure); QDir::setCurrent(testDataDir + "/allowed-values"); rmDirR(relativeBuildDir()); QbsRunParameters params; params.arguments = arguments; params.expectFailure = expectFailure; QVERIFY2(runQbs(params) == int(expectFailure), m_qbsStderr); } void TestBlackboxProviders::allowedValues_data() { QTest::addColumn("arguments"); QTest::addColumn("expectFailure"); QTest::newRow("invalid js value") << QStringList{} << true; QTest::newRow("invalid variant value") << QStringList{"moduleProviders.provider.aProperty:three"} << true; QTest::newRow("valid variant value") << QStringList{"moduleProviders.provider.aProperty:one"} << false; } void TestBlackboxProviders::brokenProvider() { QDir::setCurrent(testDataDir + "/broken-provider"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains("Error executing provider for module 'qbsothermodule'")); QVERIFY(m_qbsStderr.contains("Error executing provider for module 'qbsmetatestmodule'")); QCOMPARE(m_qbsStderr.count("This provider is broken"), 2); } void TestBlackboxProviders::conanProvider() { QFETCH(bool, generateConanFiles); QFETCH(bool, successExpected); const auto executable = findExecutable({"conan"}); if (executable.isEmpty()) QSKIP("conan is not installed or not available in PATH."); const auto conanVersion = this->conanVersion(executable); if (!conanVersion.isValid()) QSKIP("Can't get conan version."); if (compare(conanVersion, qbs::Version(2, 6)) < 0) QSKIP("This test apples only to conan 2.6 and newer."); const auto profilePath = QDir::homePath() + "/.conan2/profiles/qbs-test"; if (!QFileInfo(profilePath).exists()) QSKIP("conan profile is not installed, run './scripts/setup-conan-profiles.sh'."); // install testlibdep first QProcess conan; QDir::setCurrent(testDataDir + "/conan-provider/testlibdep"); conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); QVERIFY(waitForProcessSuccess(conan)); // install testlib second QDir::setCurrent(testDataDir + "/conan-provider/testlib"); conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); QVERIFY(waitForProcessSuccess(conan)); // install header lib third QDir::setCurrent(testDataDir + "/conan-provider/testlibheader"); conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); QVERIFY(waitForProcessSuccess(conan)); // now build an app using those libs QDir::setCurrent(testDataDir + "/conan-provider"); rmDirR(relativeBuildDir()); rmDirR("build"); if (generateConanFiles) { QStringList arguments{ "install", ".", "-g=QbsDeps", "--profile:all=qbs-test", "--output-folder=build"}; QProcess conan; conan.start(executable, arguments); QVERIFY(waitForProcessSuccess(conan)); } QbsRunParameters buildParams( "build", {"--force-probe-execution", "moduleProviders.conan.installDirectory:" + QDir::currentPath() + "/build"}); buildParams.expectFailure = !successExpected; QCOMPARE(runQbs(buildParams) == 0, successExpected); } void TestBlackboxProviders::conanProvider_data() { QTest::addColumn("generateConanFiles"); QTest::addColumn("successExpected"); QTest::addRow("no conan files generated") << false << false; QTest::addRow("conan files generated") << true << true; } void TestBlackboxProviders::conanFileProbe() { const auto executable = findExecutable({"conan"}); if (executable.isEmpty()) QSKIP("conan is not installed or not available in PATH."); const auto conanVersion = this->conanVersion(executable); if (!conanVersion.isValid()) QSKIP("Can't get conan version."); if (compare(conanVersion, qbs::Version(2, 6)) < 0) QSKIP("This test apples only to conan 2.6 and newer."); const auto profilePath = QDir::homePath() + "/.conan2/profiles/qbs-test"; if (!QFileInfo(profilePath).exists()) QSKIP("conan profile is not installed, run './scripts/setup-conan-profiles.sh'."); // install testlib QProcess conan; QDir::setCurrent(testDataDir + "/conanfile-probe/testlib"); conan.start(executable, {"create", ".", "--profile:all=qbs-test"}); QVERIFY(waitForProcessSuccess(conan)); // now build an app QDir::setCurrent(testDataDir + "/conanfile-probe"); QCOMPARE(runQbs(QbsRunParameters{"resolve"}), 0); QCOMPARE(runQbs(QbsRunParameters{"build"}), 0); } void TestBlackboxProviders::moduleProviders() { QDir::setCurrent(testDataDir + "/module-providers"); // Resolving in dry-run mode must not leave any data behind. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); QVERIFY(!QFile::exists(relativeBuildDir())); // Initial build. QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); QVERIFY(QFile::exists(relativeBuildDir())); QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("The MY_DEFINE is app1"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("The MY_DEFINE is app2"), m_qbsStdout.constData()); // Rebuild with overridden module provider config. The output for product 2 must change, // but no setup script must be re-run, because both config values have already been // handled in the first run. const QStringList resolveArgs("moduleProviders.mygenerator.chooseLettersFrom:beginning"); QCOMPARE(runQbs(QbsRunParameters("resolve", resolveArgs)), 0); QVERIFY2(!m_qbsStdout.contains("Running setup script"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); // Forcing Probe execution triggers a re-run of the setup script. But only once, // because the module provider config is the same now. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList(resolveArgs) << "--force-probe-execution")), 0); QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); // Now re-run without the module provider config override. Again, the setup script must // run once, for the config value that was not present in the last run. QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); } // Checks regression - when loading 2 modules from the same provider, the second module should // come from provider cache void TestBlackboxProviders::moduleProvidersCache() { QDir::setCurrent(testDataDir + "/module-providers-cache"); QbsRunParameters params("resolve", {"-v"}); QCOMPARE(runQbs(params), 0); const auto qbsmetatestmoduleMessage = "Re-checking for module \"qbsmetatestmodule\" with " "newly added search paths from module provider"; const auto qbsothermoduleMessage = "Re-checking for module \"qbsothermodule\" with " "newly added search paths from module provider"; QCOMPARE(m_qbsStderr.count(qbsmetatestmoduleMessage), 1); QCOMPARE(m_qbsStderr.count(qbsothermoduleMessage), 1); QCOMPARE(m_qbsStderr.count("Re-using provider \"provider_a\" from cache"), 1); // We didn't change providers, so both modules should come from cache. params.arguments << "project.dummyProp:value"; QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count(qbsmetatestmoduleMessage), 1); QCOMPARE(m_qbsStderr.count(qbsothermoduleMessage), 1); QCOMPARE(m_qbsStderr.count("Re-using provider \"provider_a\" from cache"), 2); } void TestBlackboxProviders::nonEagerModuleProvider() { QDir::setCurrent(testDataDir + "/non-eager-provider"); QbsRunParameters params("resolve"); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(("Running setup script for qbsmetatestmodule")), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("Running setup script for qbsothermodule")), m_qbsStdout); QVERIFY2(!m_qbsStdout.contains(("Running setup script for nonexistentmodule")), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p1.qbsmetatestmodule.prop: from_provider_a")), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p1.qbsothermodule.prop: from_provider_a")), m_qbsStdout); } void TestBlackboxProviders::probeInModuleProvider() { QDir::setCurrent(testDataDir + "/probe-in-module-provider"); QbsRunParameters params; params.command = "build"; params.arguments << "--force-probe-execution"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("Running probe"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.boolProp: true"), m_qbsStdout); WAIT_FOR_NEW_TIMESTAMP(); touch("probe-in-module-provider.qbs"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.boolProp: true"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.prop: \"value\""), m_qbsStdout); QVERIFY2(!m_qbsStdout.contains("Running probe"), m_qbsStdout); } void TestBlackboxProviders::providersCondition() { QDir::setCurrent(testDataDir + "/providers-condition"); QbsRunParameters params("resolve"); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("p1.qbsmetatestmodule.prop: from_provider_a"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p1.qbsothermodule.prop: from_provider_b")), m_qbsStdout); } void TestBlackboxProviders::providersConditionProbes() { QDir::setCurrent(testDataDir + "/providers-condition-probes"); QbsRunParameters params("resolve"); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("p1.qbsmetatestmodule.prop: from_provider_a"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p1.qbsothermodule.prop: from_provider_b")), m_qbsStdout); } // Tests whether it is possible to set providers properties in a Product or from command-line void TestBlackboxProviders::providersProperties() { QDir::setCurrent(testDataDir + "/providers-properties"); QbsRunParameters params("build"); params.arguments = QStringList("moduleProviders.provider_b.someProp: \"first,second\""); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("p.qbsmetatestmodule.listProp: [\"someValue\"]"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains( "p.qbsothermodule.listProp: [\"first\",\"second\"]"), m_qbsStdout); } // checks that we can set qbs module properties in providers and provider cache works corectly void TestBlackboxProviders::qbsModulePropertiesInProviders() { QDir::setCurrent(testDataDir + "/qbs-module-properties-in-providers"); QbsRunParameters params("resolve"); QCOMPARE(runQbs(params), 0); // We have 2 products in 2 configurations, but second product should use the cached value // so we should have only 2 copies of the module, not 4. QCOMPARE(m_qbsStdout.count("Running setup script for qbsmetatestmodule"), 2); // Check that products get correct values from modules QVERIFY2(m_qbsStdout.contains(("product1.qbsmetatestmodule.prop: /sysroot1")), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("product1.qbsmetatestmodule.prop: /sysroot2")), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("product2.qbsmetatestmodule.prop: /sysroot1")), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("product2.qbsmetatestmodule.prop: /sysroot2")), m_qbsStdout); } void TestBlackboxProviders::qbsModuleProviders_data() { QTest::addColumn("arguments"); QTest::addColumn("firstProp"); QTest::addColumn("secondProp"); QTest::newRow("default") << QStringList() << "from_provider_a" << "undefined"; QTest::newRow("override") << QStringList("projects.project.qbsModuleProviders:provider_b") << "from_provider_b" << "from_provider_b"; QTest::newRow("override list a") << QStringList("projects.project.qbsModuleProviders:provider_a,provider_b") << "from_provider_a" << "from_provider_b"; QTest::newRow("override list b") << QStringList("projects.project.qbsModuleProviders:provider_b,provider_a") << "from_provider_b" << "from_provider_b"; } // Tests whether it is possible to set qbsModuleProviders in Product and Project items // and that the order of providers results in correct priority void TestBlackboxProviders::qbsModuleProviders() { QFETCH(QStringList, arguments); QFETCH(QString, firstProp); QFETCH(QString, secondProp); QDir::setCurrent(testDataDir + "/qbs-module-providers"); QbsRunParameters params("resolve"); params.arguments << arguments << "-f" << "qbs-module-providers.qbs"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(("p1.qbsmetatestmodule.prop: " + firstProp).toUtf8()), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p1.qbsothermodule.prop: " + secondProp).toUtf8()), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p2.qbsmetatestmodule.prop: " + firstProp).toUtf8()), m_qbsStdout); QVERIFY2(m_qbsStdout.contains(("p2.qbsothermodule.prop: " + secondProp).toUtf8()), m_qbsStdout); } void TestBlackboxProviders::qbsModuleProvidersCliOverride_data() { QTest::addColumn("arguments"); QTest::addColumn("propertyValue"); QTest::newRow("default") << QStringList() << "undefined"; QTest::newRow("project-wide") << QStringList("project.qbsModuleProviders:provider_a") << "from_provider_a"; QTest::newRow("concrete project") << QStringList("projects.innerProject.qbsModuleProviders:provider_a") << "from_provider_a"; QTest::newRow("concrete product") << QStringList("products.product.qbsModuleProviders:provider_a") << "from_provider_a"; QTest::newRow("concrete project override project-wide") << QStringList({ "project.qbsModuleProviders:provider_a", "projects.innerProject.qbsModuleProviders:provider_b"}) << "from_provider_b"; QTest::newRow("concrete product override project-wide") << QStringList({ "project.qbsModuleProviders:provider_a", "products.product.qbsModuleProviders:provider_b"}) << "from_provider_b"; } // Tests possible use-cases how to override providers from command-line void TestBlackboxProviders::qbsModuleProvidersCliOverride() { QFETCH(QStringList, arguments); QFETCH(QString, propertyValue); QDir::setCurrent(testDataDir + "/qbs-module-providers-cli-override"); QbsRunParameters params("resolve"); params.arguments = arguments; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(("qbsmetatestmodule.prop: " + propertyValue).toUtf8()), m_qbsStdout); } void TestBlackboxProviders::qbsModuleProvidersCompatibility_data() { QTest::addColumn("arguments"); QTest::addColumn("propertyValue"); QTest::newRow("default") << QStringList() << "from_scoped_provider"; QTest::newRow("scoped by name") << QStringList("project.qbsModuleProviders:qbsmetatestmodule") << "from_scoped_provider"; QTest::newRow("named") << QStringList("project.qbsModuleProviders:named_provider") << "from_named_provider"; } // Tests whether scoped providers can be used as named, i.e. new provider machinery // is compatible with the old one void TestBlackboxProviders::qbsModuleProvidersCompatibility() { QFETCH(QStringList, arguments); QFETCH(QString, propertyValue); QDir::setCurrent(testDataDir + "/qbs-module-providers-compatibility"); QbsRunParameters params("resolve"); params.arguments = arguments; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(("qbsmetatestmodule.prop: " + propertyValue).toUtf8()), m_qbsStdout); } void TestBlackboxProviders::qbspkgconfigModuleProvider() { QDir::setCurrent(testDataDir + "/qbspkgconfig-module-provider/libs"); rmDirR(relativeBuildDir()); const auto commonParams = QbsRunParameters(QStringLiteral("install"), { QStringLiteral("--install-root"), QStringLiteral("install-root") }); auto dynamicParams = commonParams; dynamicParams.arguments << "config:library" << "projects.libs.isBundle:false"; QCOMPARE(runQbs(dynamicParams), 0); QDir::setCurrent(testDataDir + "/qbspkgconfig-module-provider"); rmDirR(relativeBuildDir()); const auto sysroot = testDataDir + "/qbspkgconfig-module-provider/libs/install-root"; QbsRunParameters params; params.arguments << "moduleProviders.qbspkgconfig.sysroot:" + sysroot; QCOMPARE(runQbs(params), 0); } void TestBlackboxProviders::qtBug51237() { const SettingsPtr s = settings(); qbs::Internal::TemporaryProfile profile("qbs_autotests_qtBug51237", s.get()); profile.p.setValue("moduleProviders.provider.theProperty", QStringList()); s->sync(); QDir::setCurrent(testDataDir + "/QTBUG-51237"); QbsRunParameters params; params.profile = profile.p.name(); QCOMPARE(runQbs(params), 0); } void TestBlackboxProviders::removalVersion() { QDir::setCurrent(testDataDir + "/removal-version"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains( "Property 'deprecated' was scheduled for removal in version 2.2.0, but is still present")); } QTEST_MAIN(TestBlackboxProviders) qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxjava.h0000644000175100001660000000316314776170045022044 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BLACKBOX_H #define TST_BLACKBOX_H #include "tst_blackboxbase.h" class TestBlackboxJava : public TestBlackboxBase { Q_OBJECT public: TestBlackboxJava(); private slots: void java(); void javaDependencyTracking(); void javaDependencyTracking_data(); void javaDependencyTrackingInnerClass(); private: const QStringList m_blacklistedJdks; }; #endif // TST_BLACKBOX_H qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxexamples.cpp0000644000175100001660000000740514776170045023277 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "tst_blackboxexamples.h" #include #include QStringList TestBlackboxExamples::collectExamples(const QString &dirPath) { QStringList result; QDir dir(dirPath); const auto subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); for (const auto &subDir : subDirs) { const auto path = dir.filePath(subDir); if (!QFileInfo::exists(path + "/" + subDir + ".qbs")) continue; result.append(QDir(testDataDir).relativeFilePath(path)); } return result; } TestBlackboxExamples::TestBlackboxExamples() : TestBlackboxBase(SRCDIR "/../../../examples/", "blackbox-examples") { // setNeedsQt(); } void TestBlackboxExamples::baremetal_data() { QTest::addColumn("example"); QDir baremetal(testDataDir + "/baremetal/"); const auto subDirs = baremetal.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); for (const auto &subDir : subDirs) { const auto examples = collectExamples(baremetal.filePath(subDir)); for (const auto &example: examples) { const auto relativePath = baremetal.relativeFilePath(example); QTest::newRow(relativePath.toUtf8().data()) << relativePath; } } } void TestBlackboxExamples::baremetal() { QFETCH(QString, example); QVERIFY(QDir::setCurrent(testDataDir + "/" + example)); QCOMPARE(runQbs(), 0); } void TestBlackboxExamples::examples_data() { QTest::addColumn("example"); auto examples = collectExamples(testDataDir); examples.append(collectExamples(testDataDir + "/protobuf")); examples.append(collectExamples(testDataDir + "/flatbuffers")); examples.append(collectExamples(testDataDir + "/cxx-modules")); std::sort(examples.begin(), examples.end()); for (const auto &example: examples) { if (example == u"baremetal") continue; QTest::newRow(example.toUtf8().data()) << example; } } void TestBlackboxExamples::examples() { QFETCH(QString, example); QVERIFY(QDir::setCurrent(testDataDir + "/" + example)); QbsRunParameters params( {QStringLiteral("-f"), QFileInfo(example).fileName() + QStringLiteral(".qbs")}); QCOMPARE(runQbs(params), 0); } QTEST_MAIN(TestBlackboxExamples) qbs-src-2.6.1/tests/auto/blackbox/blackbox-android.qbs0000644000175100001660000000100514776170045022255 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-android" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-android/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxandroid.cpp", "tst_blackboxandroid.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/0000755000175100001660000000000014776170045022173 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/allowed-values/0000755000175100001660000000000014776170045025117 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/allowed-values/allowed-values.qbs0000644000175100001660000000013114776170045030545 0ustar runnerdockerProduct { Depends { name: "qbsmetatestmodule" } qbsModuleProviders: "provider" } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/allowed-values/module-providers/0000755000175100001660000000000014776170045030417 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/allowed-values/module-providers/provider.qbs0000644000175100001660000000054414776170045032763 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false property stringList aProperty: "zero" PropertyOptions { name: "aProperty" allowedValues: ["one", "two"] } relativeSearchPaths: { Helpers.writeModule(outputBaseDir, moduleName, "from_provider"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/non-eager-provider/0000755000175100001660000000000014776170045025676 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/non-eager-provider/non-eager-provider.qbs0000644000175100001660000000067314776170045032116 0ustar runnerdockerProject { Product { name: "p1" Depends { name: "qbsmetatestmodule" } Depends { name: "qbsothermodule" } Depends { name: "nonexistentmodule"; required: false } property bool dummy: { console.info("p1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); console.info("p1.qbsothermodule.prop: " + qbsothermodule.prop); } qbsModuleProviders: "provider_a" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/non-eager-provider/module-providers/0000755000175100001660000000000014776170045031176 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/non-eager-provider/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/non-eager-provider/module-providers/provider_a.0000644000175100001660000000045614776170045033336 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false relativeSearchPaths: { if (moduleName === "nonexistentmodule") return undefined; Helpers.writeModule(outputBaseDir, moduleName, "from_provider_a"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/0000755000175100001660000000000014776170045027045 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/fallback-module-provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/fallback-module-provid0000644000175100001660000000050114776170045033307 0ustar runnerdockerCppApplication { name: "p" property bool fallbacksEnabled Depends { name: "pkgconfig"; required: false } Depends { name: "qbsmetatestmodule"; required: false; enableFallback: fallbacksEnabled } property bool dummy: { console.info("pkg-config present: " + pkgconfig.present); } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/libdir/0000755000175100001660000000000014776170045030312 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/libdir/qbsmetatestmodule.pcqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/libdir/qbsmetatestmodu0000644000175100001660000000013414776170045033454 0ustar runnerdockerName: qbsmetatestmodule Description: just a test Version: 0.0.1 Cflags: -DTHE_MAGIC_DEFINE qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/fallback-module-provider/main.cpp0000644000175100001660000000012114776170045030467 0ustar runnerdocker#ifndef THE_MAGIC_DEFINE #error "missing the magic define" #endif int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/0000755000175100001660000000000014776170045031125 5ustar runnerdocker././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/qbs-module-providers-compatibility.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/qbs-module-p0000644000175100001660000000026014776170045033353 0ustar runnerdockerProduct { name: "p" Depends { name: "qbsmetatestmodule" } property bool dummy: { console.info("qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-provi0000755000175100001660000000000014776170045033470 5ustar runnerdocker././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/named_provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-provi0000644000175100001660000000033214776170045033470 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_named_provider"); return ""; } } ././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/qbsmetatestmodule/qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-provi0000755000175100001660000000000014776170045033470 5ustar runnerdocker././@LongLink0000644000000000000000000000021000000000000011574 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-providers/qbsmetatestmodule/provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-compatibility/module-provi0000644000175100001660000000033614776170045033474 0ustar runnerdockerimport "../../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_scoped_provider"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/0000755000175100001660000000000014776170045031054 5ustar runnerdocker././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/qbs-module-properties-in-providers.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/qbs-module-p0000644000175100001660000000157514776170045033314 0ustar runnerdockerProject { qbsModuleProviders: "provider_a" name: "project" Profile { name: "profile1" qbs.sysroot: "/sysroot1" } Profile { name: "profile2" qbs.sysroot: "/sysroot2" } Product { name: "product1" Depends { name: "qbsmetatestmodule" } property bool dummy: { console.info("product1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); } // multiplex over profiles, sysroot should not be cached qbs.profiles: ["profile1", "profile2"] } Product { name: "product2" Depends { name: "qbsmetatestmodule" } property bool dummy: { console.info("product2.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); } // multiplex over profiles, sysroot should not be cached qbs.profiles: ["profile1", "profile2"] } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-providers/qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-provi0000755000175100001660000000000014776170045033417 5ustar runnerdocker././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-properties-in-providers/module-provi0000644000175100001660000000036514776170045033425 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { property string sysroot: qbs.sysroot relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", sysroot); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers-cache/0000755000175100001660000000000014776170045026534 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers-cache.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers-cache.q0000644000175100001660000000034614776170045033262 0ustar runnerdockerProject { qbsModuleProviders: ["provider_a"] name: "project" property string dummyProp Product { name: "p1" Depends { name: "qbsothermodule" } Depends { name: "qbsmetatestmodule" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers/0000755000175100001660000000000014776170045032034 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers-cache/module-providers/provide0000644000175100001660000000044714776170045033434 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_a"); Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_a"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/0000755000175100001660000000000014776170045026402 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/providers-properties.qbs0000644000175100001660000000071214776170045033320 0ustar runnerdockerProduct { qbsModuleProviders: ["provider_a", "provider_b"] name: "p" Depends { name: "qbsmetatestmodule" } Depends { name: "qbsothermodule" } moduleProviders.provider_a.someProp: "someValue" property bool dummy: { console.info("p.qbsmetatestmodule.listProp: " + JSON.stringify(qbsmetatestmodule.listProp)); console.info("p.qbsothermodule.listProp: " + JSON.stringify(qbsothermodule.listProp)); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/0000755000175100001660000000000014776170045031702 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_0000644000175100001660000000040714776170045033617 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { property stringList someProp: "provider_a" relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", undefined, someProp); return ""; } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_b.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-properties/module-providers/provider_0000644000175100001660000000040414776170045033614 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { property stringList someProp: "provider_b" relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsothermodule", undefined, someProp); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/0000755000175100001660000000000014776170045026174 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/providers-condition.qbs0000644000175100001660000000065514776170045032712 0ustar runnerdockerProject { name: "project" qbsModuleProviders: ["provider_a", "provider_b"] Product { name: "p1" Depends { name: "qbsmetatestmodule" } Depends { name: "qbsothermodule"; required: false } property bool dummy: { console.info("p1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); console.info("p1.qbsothermodule.prop: " + qbsothermodule.prop); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/module-providers/0000755000175100001660000000000014776170045031474 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/module-providers/provider_a0000644000175100001660000000042214776170045033547 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false condition: moduleName === "qbsmetatestmodule" relativeSearchPaths: { Helpers.writeModule(outputBaseDir, moduleName, "from_provider_a"); return ""; } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/module-providers/provider_b.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition/module-providers/provider_b0000644000175100001660000000042514776170045033553 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false condition: moduleName === "qbsothermodule" relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_b"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/0000755000175100001660000000000014776170045030640 5ustar runnerdocker././@LongLink0000644000000000000000000000017500000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/qbs-module-providers-cli-override.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/qbs-module-pr0000644000175100001660000000052014776170045033247 0ustar runnerdockerProject { name: "project" Project { name: "innerProject" Product { name: "product" Depends { name: "qbsmetatestmodule"; required: false } property bool dummy: { console.info("qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); } } } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-provid0000755000175100001660000000000014776170045033347 5ustar runnerdocker././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-provid0000644000175100001660000000032614776170045033352 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_a"); return ""; } } ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-providers/provider_b.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-cli-override/module-provid0000644000175100001660000000044714776170045033356 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_b"); Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_b"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/0000755000175100001660000000000014776170045025121 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/0000755000175100001660000000000014776170045027740 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/header.h0000644000175100001660000000006214776170045031337 0ustar runnerdocker#pragma once inline int hello() { return 0; }qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibheader/conanfile.py0000644000175100001660000000056314776170045032254 0ustar runnerdockerfrom conan import ConanFile from conan.tools.files import copy import os class Recipe(ConanFile): exports_sources = ("header.h") version = '0.1.0' name = 'conanmoduleprovider.testlibheader' def package(self): copy(self, "header.h", src=self.source_folder, dst=os.path.join(self.package_folder, "include"))qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/conan-module-provider.qbs0000644000175100001660000000045614776170045032046 0ustar runnerdockerCppApplication { consoleApplication: true name: "p" files: "main.cpp" qbsModuleProviders: "conan" qbs.buildVariant: "release" qbs.installPrefix: "" install: true Depends { name: "conanmoduleprovider.testlib" } Depends { name: "conanmoduleprovider.testlibheader" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/0000755000175100001660000000000014776170045027260 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/lorem_ipsum.txt0000644000175100001660000000007014776170045032351 0ustar runnerdockerLorem ipsum dolor sit amet, consectetur adipiscing elit.qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/conanfile.py0000644000175100001660000000160314776170045031570 0ustar runnerdockerfrom conan import ConanFile from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps from conan.tools.files import copy import os class ConanModuleProviderTestlib(ConanFile): name = "conanmoduleprovider.testlibdep" license = "none" version = "1.2.3" exports_sources = "*.cpp", "*.h", "*.txt" settings = "os", "compiler", "build_type", "arch" def layout(self): cmake_layout(self) def generate(self): deps = CMakeDeps(self) deps.generate() tc = CMakeToolchain(self, generator="Ninja") tc.generate() def build(self): cmake = CMake(self) cmake.configure() cmake.build() def package(self): cmake = CMake(self) cmake.install() def package_info(self): self.cpp_info.libs = ['conanmoduleprovider.testlibdep'] self.cpp_info.resdirs = ['share'] qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.cpp0000644000175100001660000000007514776170045032125 0ustar runnerdocker#include "testlibdep.h" int foo(int i) { return i * i; }qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/CMakeLists.txt0000644000175100001660000000044114776170045032017 0ustar runnerdockercmake_minimum_required(VERSION 3.15) project(conanmoduleprovider.testlibdep) add_library(${PROJECT_NAME} STATIC testlibdep.cpp) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "testlibdep.h") install(TARGETS ${PROJECT_NAME}) install(FILES lorem_ipsum.txt DESTINATION share)qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlibdep/testlibdep.h0000644000175100001660000000003514776170045031566 0ustar runnerdocker#pragma once int foo(int i);qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/main.cpp0000644000175100001660000000013214776170045026545 0ustar runnerdocker#include #include int main() { HelloWorld h(42 + hello()); } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlib/0000755000175100001660000000000014776170045026567 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlib/conanfile.py0000644000175100001660000000162314776170045031101 0ustar runnerdockerfrom conan import ConanFile from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps import os class ConanModuleProviderTestlib(ConanFile): name = "conanmoduleprovider.testlib" license = "none" version = "1.2.3" exports_sources = "*.cpp", "*.h", "CMakeLists.txt" settings = "os", "compiler", "build_type", "arch" def requirements(self): self.requires("conanmoduleprovider.testlibdep/1.2.3") def layout(self): cmake_layout(self) def generate(self): deps = CMakeDeps(self) deps.generate() tc = CMakeToolchain(self, generator="Ninja") tc.generate() def build(self): cmake = CMake(self) cmake.configure() cmake.build() def package(self): cmake = CMake(self) cmake.install() def package_info(self): self.cpp_info.libs = ['conanmoduleprovider.testlib'] qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.cpp0000644000175100001660000000014214776170045030736 0ustar runnerdocker#include "testlib.h" #include HelloWorld::HelloWorld(int x) : m_x(foo(x)) {} qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlib/CMakeLists.txt0000644000175100001660000000060514776170045031330 0ustar runnerdockercmake_minimum_required(VERSION 3.15) project(conanmoduleprovider.testlib) find_package(conanmoduleprovider.testlibdep REQUIRED) add_library(${PROJECT_NAME} STATIC testlib.cpp) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "testlib.h") target_link_libraries(${PROJECT_NAME} conanmoduleprovider.testlibdep::conanmoduleprovider.testlibdep) install(TARGETS ${PROJECT_NAME}) qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/testlib/testlib.h0000644000175100001660000000014314776170045030404 0ustar runnerdocker#pragma once class HelloWorld { public: explicit HelloWorld(int x); private: int m_x; }; qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conan-provider/conanfile.py0000644000175100001660000000044514776170045027434 0ustar runnerdockerfrom conan import ConanFile class Recipe(ConanFile): name = "qbstest" version = "1.0" exports_sources = "*.cpp", "*.h", "*.txt" settings = "os", "compiler", "build_type", "arch" requires = ["conanmoduleprovider.testlib/1.2.3", "conanmoduleprovider.testlibheader/0.1.0"] qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/0000755000175100001660000000000014776170045026256 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/subproject.qbs0000644000175100001660000000167314776170045031154 0ustar runnerdockerProject { qbsModuleProviders: "provider_a" property stringList wantedProviders: qbsModuleProviders name: "project" Project { name: "innerProject" qbsModuleProviders: project.wantedProviders Product { name: "p1" Depends { name: "qbsmetatestmodule" } Depends { name: "qbsothermodule"; required: false } property bool dummy: { console.info("p1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); console.info("p1.qbsothermodule.prop: " + qbsothermodule.prop); } } } Product { name: "p2" Depends { name: "qbsmetatestmodule" } Depends { name: "qbsothermodule"; required: false } property bool dummy: { console.info("p2.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); console.info("p2.qbsothermodule.prop: " + qbsothermodule.prop); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/qbs-module-providers.qbs0000644000175100001660000000022014776170045033042 0ustar runnerdockerProject { SubProject { // This strange construct tests QBS-1836 inheritProperties: false filePath: "subproject.qbs" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/0000755000175100001660000000000014776170045031556 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_0000644000175100001660000000032614776170045033473 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_a"); return ""; } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_b.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers/module-providers/provider_0000644000175100001660000000044714776170045033477 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", "from_provider_b"); Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_b"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/broken-provider/0000755000175100001660000000000014776170045025303 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/broken-provider/broken-provider.qbs0000644000175100001660000000043414776170045031123 0ustar runnerdockerProject { qbsModuleProviders: "provider_a" name: "project" Project { name: "innerProject" Product { name: "p1" Depends { name: "qbsothermodule"; required: false } Depends { name: "qbsmetatestmodule" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/broken-provider/module-providers/0000755000175100001660000000000014776170045030603 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/broken-provider/module-providers/provider_a.qbs0000644000175100001660000000013514776170045033443 0ustar runnerdockerModuleProvider { relativeSearchPaths: { throw "This provider is broken"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/probe-in-module-provider/0000755000175100001660000000000014776170045027021 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/probe-in-module-provider/probe-in-module-provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/probe-in-module-provider/probe-in-module-provid0000644000175100001660000000051614776170045033245 0ustar runnerdockerProduct { qbsModuleProviders: ["provider_a"] name: "p" Depends { name: "qbsmetatestmodule" } property bool dummy: { console.info("p.qbsmetatestmodule.boolProp: " + JSON.stringify(qbsmetatestmodule.boolProp)); console.info("p.qbsmetatestmodule.prop: " + JSON.stringify(qbsmetatestmodule.prop)); } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/probe-in-module-provider/module-providers/0000755000175100001660000000000014776170045032321 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/probe-in-module-provider/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/probe-in-module-provider/module-providers/provi0000644000175100001660000000130214776170045033377 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { property string sysroot: qbs.sysroot Probe { id: theProbe property string theValue: "value" property string dummy: sysroot configure: { console.info("Running probe with irrelevant value '" + dummy + "'"); found = true; } } isEager: false property bool found: theProbe.found property string theValue: theProbe.theValue relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsmetatestmodule", theValue, undefined, found); if (sysroot !== qbs.sysroot) throw "this is unexpected"; return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/removal-version/0000755000175100001660000000000014776170045025323 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/removal-version/removal-version.qbs0000644000175100001660000000033414776170045031162 0ustar runnerdockerProject { qbsModuleProviders: "provider_a" name: "project" Project { name: "innerProject" Product { name: "p1" Depends { name: "qbsmetatestmodule" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/removal-version/module-providers/0000755000175100001660000000000014776170045030623 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/removal-version/module-providers/provider_a.qbs0000644000175100001660000000053314776170045033465 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false property bool deprecated: false PropertyOptions { name: "deprecated" removalVersion: "2.2.0" } relativeSearchPaths: { Helpers.writeModule(outputBaseDir, moduleName, "from_provider_a"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbs-module-providers-helpers.js0000644000175100001660000000160714776170045030260 0ustar runnerdockervar File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); var TextFile = require("qbs.TextFile"); var ModUtils = require("qbs.ModUtils"); function writeModule(outputBaseDir, name, prop, listProp, boolProp) { console.info("Running setup script for " + name); var moduleDir = FileInfo.joinPaths(outputBaseDir, "modules", name); File.makePath(moduleDir); var module = new TextFile(FileInfo.joinPaths(moduleDir, "module.qbs"), TextFile.WriteOnly); module.writeLine("Module {"); module.writeLine(" property string prop: " + ModUtils.toJSLiteral(prop)); if (listProp) { module.writeLine(" property stringList listProp: " + ModUtils.toJSLiteral(listProp)); } if (boolProp) { module.writeLine(" property bool boolProp: " + ModUtils.toJSLiteral(boolProp)); } module.writeLine("}"); module.close(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/QTBUG-51237/0000755000175100001660000000000014776170045023534 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/QTBUG-51237/qtbug-51237.qbs0000644000175100001660000000073714776170045026053 0ustar runnerdockerProduct { type: "custom" Depends { name: "mymodule" } qbsModuleProviders: "provider" Rule { multiplex: true outputFileTags: ["custom"] prepare: { var theProperty = product.mymodule.listProp; if (!theProperty) throw "Oh no!"; var dummy = new JavaScriptCommand(); dummy.silent = true; dummy.sourceCode = function() {}; return [dummy]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/QTBUG-51237/module-providers/0000755000175100001660000000000014776170045027034 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/QTBUG-51237/module-providers/provider.qbs0000644000175100001660000000037414776170045031401 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { property stringList theProperty relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "mymodule", "from_provider", theProperty); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/0000755000175100001660000000000014776170045025236 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/main.cpp0000644000175100001660000000007314776170045026666 0ustar runnerdocker#include int main() { HelloWorld h(42); } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/testlib/0000755000175100001660000000000014776170045026704 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/testlib/conanfile.py0000644000175100001660000000153014776170045031213 0ustar runnerdockerfrom conan import ConanFile from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps import os class ConanModuleProviderTestlib(ConanFile): name = "conanfileprobe.testlib" license = "none" version = "1.2.3" exports_sources = "*.cpp", "*.h", "CMakeLists.txt" settings = "os", "compiler", "build_type", "arch" def requirements(self): pass def layout(self): cmake_layout(self) def generate(self): deps = CMakeDeps(self) deps.generate() tc = CMakeToolchain(self, generator="Ninja") tc.generate() def build(self): cmake = CMake(self) cmake.configure() cmake.build() def package(self): cmake = CMake(self) cmake.install() def package_info(self): self.cpp_info.libs = ['conanfileprobe.testlib'] qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/testlib/testlib.cpp0000644000175100001660000000010414776170045031051 0ustar runnerdocker#include "testlib.h" HelloWorld::HelloWorld(int x) : m_x(x) {} qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/testlib/CMakeLists.txt0000644000175100001660000000034314776170045031444 0ustar runnerdockercmake_minimum_required(VERSION 3.15) project(conanfileprobe.testlib) add_library(${PROJECT_NAME} STATIC testlib.cpp) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "testlib.h") install(TARGETS ${PROJECT_NAME}) qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/testlib/testlib.h0000644000175100001660000000014314776170045030521 0ustar runnerdocker#pragma once class HelloWorld { public: explicit HelloWorld(int x); private: int m_x; }; qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/conanfile.py0000644000175100001660000000036514776170045027552 0ustar runnerdockerfrom conan import ConanFile class Recipe(ConanFile): name = "qbstest" version = "1.0" exports_sources = "*.cpp", "*.h", "*.txt" settings = "os", "compiler", "build_type", "arch" requires = ["conanfileprobe.testlib/1.2.3"] qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/conanfile-probe/conanfile-probe.qbs0000644000175100001660000000103114776170045031003 0ustar runnerdockerimport qbs.Probes Project { Probes.ConanfileProbe { id: conanProbe conanfilePath: path + "/conanfile.py" additionalArguments: "-pr:a=qbs-test" } CppApplication { consoleApplication: true name: "p" files: "main.cpp" qbsModuleProviders: "conan" moduleProviders.conan.installDirectory: conanProbe.generatedFilesPath qbs.buildVariant: "release" qbs.installPrefix: "" install: true Depends { name: "conanfileprobe.testlib" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/0000755000175100001660000000000014776170045027464 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/providers-condition-probes.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/providers-condition-0000644000175100001660000000065514776170045033473 0ustar runnerdockerProject { name: "project" qbsModuleProviders: ["provider_a", "provider_b"] Product { name: "p1" Depends { name: "qbsmetatestmodule" } Depends { name: "qbsothermodule"; required: false } property bool dummy: { console.info("p1.qbsmetatestmodule.prop: " + qbsmetatestmodule.prop); console.info("p1.qbsothermodule.prop: " + qbsothermodule.prop); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/module-providers/0000755000175100001660000000000014776170045032764 5ustar runnerdocker././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/module-providers/provider_a.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/module-providers/pro0000644000175100001660000000062314776170045033510 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false condition: theProbe.found Probe { id: theProbe condition: moduleName === "qbsmetatestmodule" configure: { found = true } } relativeSearchPaths: { Helpers.writeModule(outputBaseDir, moduleName, "from_provider_a"); return ""; } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/module-providers/provider_b.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/providers-condition-probes/module-providers/pro0000644000175100001660000000062614776170045033513 0ustar runnerdockerimport "../../qbs-module-providers-helpers.js" as Helpers ModuleProvider { isEager: false condition: theProbe.found Probe { id: theProbe condition: moduleName === "qbsothermodule" configure: { found = true } } relativeSearchPaths: { Helpers.writeModule(outputBaseDir, "qbsothermodule", "from_provider_b"); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/0000755000175100001660000000000014776170045027763 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/qbspkgconfig-module-provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/qbspkgconfig-modul0000644000175100001660000000017314776170045033502 0ustar runnerdockerCppApplication { name: "p" Depends { name: "libA" } files: "main.cpp" qbsModuleProviders: "qbspkgconfig" } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/0000755000175100001660000000000014776170045030714 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.h0000644000175100001660000000076114776170045031740 0ustar runnerdocker#pragma once #if defined(_WIN32) || defined(WIN32) # define DECL_EXPORT __declspec(dllexport) # define DECL_IMPORT __declspec(dllimport) #else # define DECL_EXPORT __attribute__((visibility("default"))) # define DECL_IMPORT __attribute__((visibility("default"))) # endif #if defined(LIBA_STATIC_LIBRARY) # define LIBA_EXPORT #else # if defined(MYLIB_LIBRARY) # define LIBA_EXPORT DECL_EXPORT # else # define LIBA_EXPORT DECL_IMPORT # endif #endif LIBA_EXPORT void foo(); qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libA.cpp0000644000175100001660000000033514776170045032270 0ustar runnerdocker#include "libA.h" #include void foo() { std::cout << "hello from foo: "; #ifdef MYLIB_FRAMEWORK std::cout << "bundled: yes"; #else std::cout << "bundled: no"; #endif std::cout << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/libs/libs.qbs0000644000175100001660000000246614776170045032364 0ustar runnerdockerimport qbs.FileInfo Project { property bool isBundle: false DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } Depends { name: "Exporter.pkgconfig" } Exporter.pkgconfig.versionEntry: "1.0" name: "libA" bundle.isBundle: project.isBundle bundle.publicHeaders: ["libA.h"] files: "libA.cpp" cpp.defines: { var result = []; if (project.isBundle) result.push("MYLIB_FRAMEWORK"); return result; } qbs.installPrefix: "/usr" install: true installImportLib: true installDir: "lib" Group { files: ["libA.h"] qbs.install: !project.isBundle qbs.installDir: FileInfo.joinPaths("include", product.name) } Group { fileTagsFilter: ["Exporter.pkgconfig.pc"] qbs.install: !project.isBundle qbs.installDir: FileInfo.joinPaths("share", "pkgconfig") } Export { Depends { name: "cpp" } cpp.defines: ["THE_MAGIC_DEFINE"] cpp.includePaths: [FileInfo.joinPaths(exportingProduct.qbs.installPrefix, "include")] cpp.libraryPaths: [FileInfo.joinPaths(exportingProduct.qbs.installPrefix, "lib")] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/qbspkgconfig-module-provider/main.cpp0000644000175100001660000000020314776170045031406 0ustar runnerdocker#include #ifndef THE_MAGIC_DEFINE #error "missing the magic define" #endif int main() { foo(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/0000755000175100001660000000000014776170045025473 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/main.cpp0000644000175100001660000000030514776170045027121 0ustar runnerdocker#include int main() { std::cout << "The letters are " << LETTER1 << " and " << LETTER2 << std::endl; std::cout << "The MY_DEFINE is " << MY_DEFINE << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers.qbs0000644000175100001660000000234614776170045031507 0ustar runnerdockerimport qbs.Host Project { property bool enabled: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } readonly property string beginning: "beginning" CppApplication { name: "app1" property string chooseLettersFrom: project.beginning // This indirection tests QBS-1747. Depends { name: "mygenerator.module1" } Depends { name: "mygenerator.module2" } Depends { name: "othergenerator" } moduleProviders.mygenerator.chooseLettersFrom: chooseLettersFrom moduleProviders.othergenerator.someDefines: name files: "main.cpp" } CppApplication { readonly property string end: "end" name: "app2" Depends { name: "mygenerator.module1" } Depends { name: "mygenerator.module2" } Depends { name: "othergenerator" } Profile { name: "myProfile" baseProfile: project.profile moduleProviders.mygenerator.chooseLettersFrom: product.end moduleProviders.othergenerator.someDefines: "app2" } qbs.profile: "myProfile" files: "main.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/0000755000175100001660000000000014776170045030773 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerator/qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerato0000755000175100001660000000000014776170045033562 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerator/provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/othergenerato0000644000175100001660000000124314776170045033564 0ustar runnerdockerimport qbs.File; import qbs.FileInfo; import qbs.TextFile; ModuleProvider { property string someDefines relativeSearchPaths: { console.info("Running setup script for " + name); var moduleDir = FileInfo.joinPaths(outputBaseDir, "modules", "othergenerator"); File.makePath(moduleDir); var module = new TextFile(FileInfo.joinPaths(moduleDir, "module.qbs"), TextFile.WriteOnly); module.writeLine("Module {"); module.writeLine(" Depends { name: 'cpp' }"); module.writeLine(" cpp.defines: 'MY_DEFINE=\"" + someDefines + "\"'"); module.writeLine("}"); module.close(); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/mygenerator/0000755000175100001660000000000014776170045033327 5ustar runnerdocker././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/mygenerator/provider.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-providers/module-providers/module-providers/mygenerator/p0000644000175100001660000000255014776170045033513 0ustar runnerdockerimport qbs.File; import qbs.FileInfo; import qbs.TextFile; ModuleProvider { property string chooseLettersFrom relativeSearchPaths: { console.info("Running setup script for " + name); var startAtBeginning = chooseLettersFrom === "beginning"; var moduleBaseDir = FileInfo.joinPaths(outputBaseDir, "modules", "mygenerator"); var module1Dir = FileInfo.joinPaths(moduleBaseDir, "module1"); File.makePath(module1Dir); var module1 = new TextFile(FileInfo.joinPaths(module1Dir, "module1.qbs"), TextFile.WriteOnly); module1.writeLine("Module {"); module1.writeLine(" Depends { name: 'cpp' }"); module1.writeLine(" cpp.defines: 'LETTER1=" + (startAtBeginning ? "\\\'A\\\'" : "\\\'Z\\\'") + "'"); module1.writeLine("}"); module1.close(); var module2Dir = FileInfo.joinPaths(moduleBaseDir, "module2"); File.makePath(module2Dir); var module2 = new TextFile(FileInfo.joinPaths(module2Dir, "module2.qbs"), TextFile.WriteOnly); module2.writeLine("Module {"); module2.writeLine(" Depends { name: 'cpp' }"); module2.writeLine(" cpp.defines: 'LETTER2=" + (startAtBeginning ? "\\\'B\\\'" : "\\\'Y\\\'") + "'"); module2.writeLine("}"); module2.close(); return ""; } } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxbaremetal.h0000644000175100001660000000450014776170045023053 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef TST_BLACKBOXBAREMETAL_H #define TST_BLACKBOXBAREMETAL_H #include "tst_blackboxbase.h" class TestBlackboxBareMetal : public TestBlackboxBase { Q_OBJECT public: TestBlackboxBareMetal(); private slots: void targetPlatform(); void application_data(); void application(); void staticLibraryDependencies(); void externalStaticLibraries(); void sharedLibraries(); void userIncludePaths(); void systemIncludePaths(); void distributionIncludePaths(); void compilerIncludePaths(); void preincludeHeaders(); void defines(); void compilerListingFiles_data(); void compilerListingFiles(); void linkerMapFile_data(); void linkerMapFile(); void compilerDefinesByLanguage(); void toolchainProbe(); private: }; #endif // TST_BLACKBOXBAREMETAL_H qbs-src-2.6.1/tests/auto/blackbox/tst_blackbox.h0000644000175100001660000002756214776170045021213 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BLACKBOX_H #define TST_BLACKBOX_H #include "tst_blackboxbase.h" class TestBlackbox : public TestBlackboxBase { Q_OBJECT public: TestBlackbox(); private slots: void allowedValues(); void allowedValues_data(); void addFileTagToGeneratedArtifact(); void alwaysRun(); void alwaysRun_data(); void artifactsMapChangeTracking(); void artifactsMapInvalidation(); void artifactsMapRaceCondition(); void artifactScanning(); void assembly(); void autotestWithDependencies(); void autotestTimeout(); void autotestTimeout_data(); void autotests_data(); void autotests(); void auxiliaryInputsFromDependencies(); void badInterpreter(); void bomSources(); void buildDataOfDisabledProduct(); void buildDirectories(); void buildDirPlaceholders_data(); void buildDirPlaceholders(); void buildEnvChange(); void buildGraphVersions(); void buildVariantDefaults_data(); void buildVariantDefaults(); void capnproto(); void capnproto_data(); void changedFiles_data(); void changedFiles(); void changedInputsFromDependencies(); void changedRuleInputs(); void changeInDisabledProduct(); void changeInImportedFile(); void changeTrackingAndMultiplexing(); void checkProjectFilePath(); void checkTimestamps(); void chooseModuleInstanceByPriorityAndVersion(); void chooseModuleInstanceByPriorityAndVersion_data(); void clean(); void cli(); void combinedSources(); void commandFile(); void compilerDefinesByLanguage(); void conditionalExport(); void conditionalFileTagger(); void configure(); void conflictingArtifacts(); void cxxLanguageVersion(); void cxxLanguageVersion_data(); void conanfileProbe_data(); void conanfileProbe(); void conflictingPropertyValues_data(); void conflictingPropertyValues(); void cpuFeatures(); void cxxModules_data(); void cxxModules(); void cxxModulesChangesTracking(); void dateProperty(); void dependenciesProperty(); void dependencyScanningLoop(); void deprecatedProperty(); void deprecatedProperty_data(); void disappearedProfile(); void discardUnusedData(); void discardUnusedData_data(); void dotDotPcFile(); void driverLinkerFlags(); void driverLinkerFlags_data(); void dynamicLibraryInModule(); void dynamicMultiplexRule(); void dynamicProject(); void dynamicRuleOutputs(); void emptyProfile(); void emscriptenArtifacts(); void emscriptenArtifacts_data(); void enableExceptions(); void enableExceptions_data(); void enableRtti(); void envMerging(); void envNormalization(); void erroneousFiles_data(); void erroneousFiles(); void errorInfo(); void escapedLinkerFlags(); void explicitlyDependsOn(); void explicitlyDependsOn_data(); void exportedDependencyInDisabledProduct(); void exportedDependencyInDisabledProduct_data(); void exportedPropertyInDisabledProduct(); void exportedPropertyInDisabledProduct_data(); void exportRule(); void exportToOutsideSearchPath(); void exportsCMake(); void exportsCMake_data(); void exportsPkgconfig(); void exportsQbs(); void externalLibs(); void fileDependencies(); void fileTagsFilterMerging(); void flatbuf(); void flatbuf_data(); void freedesktop(); void generatedArtifactAsInputToDynamicRule(); void generateLinkerMapFile(); void generator(); void generator_data(); void groupsInModules(); void grpc_data(); void grpc(); void hostOsProperties(); void ico(); void importAssignment(); void importChangeTracking(); void importInPropertiesCondition(); void importSearchPath(); void importingProduct(); void importsConflict(); void includeLookup(); void inputTagsChangeTracking_data(); void inputTagsChangeTracking(); void inputsFromDependencies(); void installable(); void installableAsAuxiliaryInput(); void installedApp(); void installDuplicates(); void installDuplicatesNoError(); void installedSourceFiles(); void installedTransformerOutput(); void installLocations_data(); void installLocations(); void installPackage(); void installRootFromProjectFile(); void installTree(); void invalidArtifactPath_data(); void invalidArtifactPath(); void invalidCommandProperty_data(); void invalidCommandProperty(); void invalidExtensionInstantiation(); void invalidExtensionInstantiation_data(); void invalidInstallDir(); void invalidLibraryNames(); void invalidLibraryNames_data(); void jsExtensionsFile(); void jsExtensionsFileInfo(); void jsExtensionsHost(); void jsExtensionsProcess(); void jsExtensionsPropertyList(); void jsExtensionsTemporaryDir(); void jsExtensionsTextFile(); void jsExtensionsBinaryFile(); void lastModuleCandidateBroken(); void ld(); void linkerMode(); void linkerVariant_data(); void linkerVariant(); void lexyacc(); void lexyaccOutputs(); void lexyaccOutputs_data(); void linkerLibraryDuplicates(); void linkerLibraryDuplicates_data(); void linkerScripts(); void linkerModuleDefinition(); void listProducts(); void listPropertiesWithOuter(); void listPropertyOrder(); void loadableModule(); void localDeployment(); void makefileGenerator(); void maximumCLanguageVersion(); void maximumCxxLanguageVersion(); void minimumSystemVersion(); void minimumSystemVersion_data(); void missingBuildGraph(); void missingBuildGraph_data(); void missingDependency(); void missingProjectFile(); void missingOverridePrefix(); void moduleConditions(); void movedFileDependency(); void msvcAsmLinkerFlags(); void multipleChanges(); void multipleConfigurations(); void multiplexedTool(); void nestedGroups(); void nestedProperties(); void newOutputArtifact(); void noExportedSymbols_data(); void noExportedSymbols(); void noProfile(); void noSuchProfile(); void nodejs(); void nonBrokenFilesInBrokenProduct(); void nonDefaultProduct(); void notAlwaysUpdated(); void nsis(); void nsisDependencies(); void outOfDateMarking(); void outputArtifactAutoTagging(); void outputRedirection(); void overrideProjectProperties(); void partiallyBuiltDependency(); void pathProbe_data(); void pathProbe(); void pathListInProbe(); void pchChangeTracking(); void perGroupDefineInExportItem(); void pkgConfigProbe(); void pkgConfigProbe_data(); void pkgConfigProbeSysroot(); void pluginDependency(); void precompiledAndPrefixHeaders(); void precompiledHeaderAndRedefine(); void preventFloatingPointValues(); void probeChangeTracking(); void probeProperties(); void probesAndShadowProducts(); void probeInExportedModule(); void probesAndArrayProperties(); void probesInNestedModules(); void productDependenciesByType(); void productInExportedModule(); void productProperties(); void propertyAssignmentInFailedModule(); void propertyChanges(); void propertyEvaluationContext(); void propertyPrecedence(); void properQuoting(); void propertiesInExportItems(); void protobuf_data(); void protobuf(); void protobufLibraryInstall(); void pseudoMultiplexing(); void qbsConfig(); void qbsConfigAddProfile(); void qbsConfigAddProfile_data(); void qbsConfigImport(); void qbsConfigImport_data(); void qbsConfigExport(); void qbsConfigExport_data(); void qbsLanguageServer_data(); void qbsLanguageServer(); void qbsSession(); void qbsVersion(); void qtBug51237(); void radAfterIncompleteBuild(); void radAfterIncompleteBuild_data(); void recursiveRenaming(); void recursiveWildcards(); void referenceErrorInExport(); void removeDuplicateLibraries_data(); void removeDuplicateLibraries(); void reproducibleBuild(); void reproducibleBuild_data(); void require(); void rescueTransformerData(); void responseFiles(); void retaggedOutputArtifact(); void rpathlinkDeduplication(); void ruleConditions_data(); void ruleConditions(); void ruleConnectionWithExcludedInputs(); void ruleCycle(); void ruleWithNoInputs(); void ruleWithNonRequiredInputs(); void runMultiplexed(); void sanitizer_data(); void sanitizer(); void scannerItem_data(); void scannerItem(); void scanResultInOtherProduct(); void scanResultInNonDependency(); void setupBuildEnvironment(); void setupRunEnvironment(); void staticLibDeps(); void staticLibDeps_data(); void smartRelinking(); void smartRelinking_data(); void soVersion(); void soVersion_data(); void sourceArtifactChanges(); void subProfileChangeTracking(); void successiveChanges(); void symbolLinkMode(); void symlinkRemoval(); void renameDependency(); void separateDebugInfo(); void sevenZip(); void sourceArtifactInInputsFromDependencies(); void staticLibWithoutSources(); void suspiciousCalls(); void suspiciousCalls_data(); void systemIncludePaths(); void distributionIncludePaths(); void systemRunPaths(); void systemRunPaths_data(); void tar(); void textTemplate(); void toolLookup(); void topLevelSearchPath(); void trackAddFile(); void trackAddFileTag(); void trackAddProduct(); void trackExternalProductChanges(); void trackGroupConditionChange(); void trackRemoveFile(); void trackRemoveFileTag(); void trackRemoveProduct(); void transitiveInvalidDependencies(); void transitiveOptionalDependencies(); void typescript(); void undefinedTargetPlatform(); void usingsAsSoleInputsNonMultiplexed(); void variantSuffix(); void variantSuffix_data(); void vcsGit(); void vcsSubversion(); void versionCheck(); void versionCheck_data(); void versionScript(); void wholeArchive(); void wholeArchive_data(); void wildCardsAndRules(); void wildCardsAndChangeTracking_data(); void wildCardsAndChangeTracking(); void wildcardRenaming(); void zip(); void zip_data(); void zipInvalid(); private: QMap findCli(int *status); QMap findNodejs(int *status); QMap findTypeScript(int *status); QString findArchiver(const QString &fileName, int *status = nullptr); bool prepareAndRunConan(); static bool lexYaccExist(); static qbs::Version bisonVersion(); }; #endif // TST_BLACKBOX_H qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxbase.cpp0000644000175100001660000002573314776170045022377 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackboxbase.h" #include "../shared.h" #include #include #include #include #include #include #include using qbs::Internal::HostOsInfo; using qbs::Internal::removeDirectoryWithContents; using qbs::InstallOptions; using qbs::Profile; static QString initQbsExecutableFilePath() { const QString qbsInstallDir = QString::fromLocal8Bit(qgetenv("QBS_INSTALL_DIR")); return HostOsInfo::appendExecutableSuffix(QDir::cleanPath(!qbsInstallDir.isEmpty() ? qbsInstallDir + QLatin1String("/bin/qbs") : QCoreApplication::applicationDirPath() + QLatin1String("/qbs"))); } static bool supportsBuildDirectoryOption(const QString &command) { return !(QStringList() << "help" << "config" << "config-ui" << "setup-android" << "setup-qt" << "setup-toolchains" << "create-project") .contains(command); } static bool supportsSettingsDirOption(const QString &command) { return !(QStringList() << "help" << "create-project").contains(command); } TestBlackboxBase::TestBlackboxBase(const QString &testDataSrcDir, const QString &testName) : testDataDir(testWorkDir(testName)), testSourceDir(testDataSourceDir(testDataSrcDir)), qbsExecutableFilePath(initQbsExecutableFilePath()), defaultInstallRoot(relativeBuildDir() + QLatin1Char('/') + InstallOptions::defaultInstallRoot()) { QLocale::setDefault(QLocale::c()); } int TestBlackboxBase::runQbs(const QbsRunParameters ¶ms) { QStringList args; if (!params.command.isEmpty()) args << params.command; if (!params.settingsDir.isEmpty() && supportsSettingsDirOption(params.command)) args << "--settings-dir" << params.settingsDir; if (supportsBuildDirectoryOption(params.command)) { args.push_back(QStringLiteral("-d")); args.push_back(params.buildDirectory.isEmpty() ? QStringLiteral(".") : params.buildDirectory); } args << params.arguments; const bool commandImpliesResolve = params.command.isEmpty() || params.command == "resolve" || params.command == "build" || params.command == "install" || params.command == "run" || params.command == "generate"; if (!params.profile.isEmpty() && commandImpliesResolve) { args.push_back(QLatin1String("profile:") + params.profile); } QProcess process; if (!params.workingDir.isEmpty()) process.setWorkingDirectory(params.workingDir); process.setProcessEnvironment(params.environment); process.start(qbsExecutableFilePath, args); int exitCode = 0; if (!process.waitForStarted() || !process.waitForFinished(testTimeoutInMsecs()) || process.exitStatus() != QProcess::NormalExit) { if (!params.expectCrash) { QTest::qFail("qbs did not run correctly", __FILE__, __LINE__); qDebug("%s", qPrintable(process.errorString())); } exitCode = -1; } else if (m_qbsStdout.contains("Memory leak:")) { exitCode = 27; } else { exitCode = process.exitCode(); } m_qbsStderr = process.readAllStandardError(); m_qbsStdout = process.readAllStandardOutput(); sanitizeOutput(&m_qbsStderr); sanitizeOutput(&m_qbsStdout); const bool shouldLog = (process.exitStatus() != QProcess::NormalExit || exitCode != 0) && !params.expectFailure; if (!m_qbsStderr.isEmpty() && (shouldLog || qEnvironmentVariableIsSet("QBS_AUTOTEST_ALWAYS_LOG_STDERR"))) qDebug("%s", m_qbsStderr.constData()); if (!m_qbsStdout.isEmpty() && (shouldLog || qEnvironmentVariableIsSet("QBS_AUTOTEST_ALWAYS_LOG_STDOUT"))) qDebug("%s", m_qbsStdout.constData()); return exitCode; } /*! Recursive copy from directory to another. Note that this updates the file stamps on Linux but not on Windows. */ void TestBlackboxBase::ccp(const QString &sourceDirPath, const QString &targetDirPath) { QDir currentDir; QDirIterator dit(sourceDirPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden); while (dit.hasNext()) { dit.next(); const QString targetPath = targetDirPath + QLatin1Char('/') + dit.fileName(); currentDir.mkpath(targetPath); ccp(dit.filePath(), targetPath); } QDirIterator fit(sourceDirPath, QDir::Files | QDir::Hidden); while (fit.hasNext()) { fit.next(); const QString targetPath = targetDirPath + QLatin1Char('/') + fit.fileName(); QFile::remove(targetPath); // allowed to fail QFile src(fit.filePath()); QVERIFY2(src.copy(targetPath), qPrintable(src.errorString())); } } void TestBlackboxBase::rmDirR(const QString &dir) { QString errorMessage; removeDirectoryWithContents(dir, &errorMessage); } QByteArray TestBlackboxBase::unifiedLineEndings(const QByteArray &ba) { if (HostOsInfo::isWindowsHost()) { QByteArray result; result.reserve(ba.size()); for (const char &c : ba) { if (c != '\r') result.append(c); } return result; } else { return ba; } } void TestBlackboxBase::sanitizeOutput(QByteArray *ba) { if (HostOsInfo::isWindowsHost()) ba->replace('\r', ""); } void TestBlackboxBase::initTestCase() { QVERIFY(regularFileExists(qbsExecutableFilePath)); const SettingsPtr s = settings(); if (profileName() != "none" && !s->profiles().contains(profileName())) QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() + "' could not be found. Please set it up on your machine.")); validateTestProfile(); // Initialize the test data directory. QVERIFY(testDataDir != testSourceDir); rmDirR(testDataDir); QDir().mkpath(testDataDir); ccp(testSourceDir, testDataDir); QDir().mkpath(testDataDir + "/find"); ccp(testSourceDir + "/../find", testDataDir + "/find"); QVERIFY(copyDllExportHeader(testSourceDir, testDataDir)); } void TestBlackboxBase::validateTestProfile() { const SettingsPtr s = settings(); if (profileName() != "none" && !s->profiles().contains(profileName())) QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() + "' could not be found. Please set it up on your machine.")); if (!m_needsQt) return; const QStringList qmakeFilePaths = Profile(profileName(), s.get()) .value("moduleProviders.Qt.qmakeFilePaths").toStringList(); if (!qmakeFilePaths.empty()) return; if (!findExecutable(QStringList{"qmake"}).isEmpty()) return; QSKIP(QByteArray("The build profile '" + profileName().toLocal8Bit() + "' is not a valid Qt profile and Qt was not found " "in the global search paths.")); } QString TestBlackboxBase::findExecutable(const QStringList &fileNames) { const QStringList path = QString::fromLocal8Bit(qgetenv("PATH")) .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); for (const QString &fileName : fileNames) { QFileInfo fi(fileName); if (fi.isAbsolute()) return fi.exists() ? fileName : QString(); for (const QString &ppath : path) { const QString fullPath = HostOsInfo::appendExecutableSuffix(ppath + QLatin1Char('/') + fileName); if (QFileInfo(fullPath).exists()) return QDir::cleanPath(fullPath); } } return {}; } QMap TestBlackboxBase::findJdkTools(int *status) { QTemporaryDir temp; QDir::setCurrent(testDataDir + "/find"); QbsRunParameters params = QStringList() << "-f" << "find-jdk.qbs"; params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) *status = res; QFile file(temp.path() + "/" + relativeProductBuildDir("find-jdk") + "/jdk.json"); if (!file.open(QIODevice::ReadOnly)) return {}; const auto tools = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); return { {"java", QDir::fromNativeSeparators(tools["java"].toString())}, {"javac", QDir::fromNativeSeparators(tools["javac"].toString())}, {"jar", QDir::fromNativeSeparators(tools["jar"].toString())} }; } qbs::Version TestBlackboxBase::qmakeVersion(const QString &qmakeFilePath) { QStringList arguments; arguments << "-query" << "QT_VERSION"; QProcess qmakeProcess; qmakeProcess.start(qmakeFilePath, arguments); if (!qmakeProcess.waitForStarted() || !qmakeProcess.waitForFinished() || qmakeProcess.exitStatus() != QProcess::NormalExit) { qDebug() << "qmake '" << qmakeFilePath << "' could not be run."; return qbs::Version(); } QByteArray result = qmakeProcess.readAll().simplified(); qbs::Version version = qbs::Version::fromString(result); if (!version.isValid()) qDebug() << "qmake '" << qmakeFilePath << "' version is not valid."; return version; } qbs::Version TestBlackboxBase::conanVersion(const QString &conanFilePath) { QProcess conan; conan.start(conanFilePath, {"--version"}); if (!waitForProcessSuccess(conan)) return qbs::Version{}; return qbs::Version::fromString(QString::fromLocal8Bit(conan.readAllStandardOutput()) .trimmed() .remove(QStringLiteral("Conan version")) .trimmed()); } bool waitForProcessSuccess(QProcess &p, int msecs) { if (!p.waitForStarted(msecs) || !p.waitForFinished(msecs)) { qDebug() << p.errorString(); return false; } if (p.exitCode() != 0) { qDebug() << p.readAllStandardError(); return false; } return true; } qbs-src-2.6.1/tests/auto/blackbox/blackbox-clangdb.qbs0000644000175100001660000000077014776170045022237 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-clangdb" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-clangdb/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_clangdb.cpp", "tst_clangdb.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxandroid.h0000644000175100001660000000310114776170045022533 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BLACKBOX_H #define TST_BLACKBOX_H #include "tst_blackboxbase.h" class TestBlackboxAndroid : public TestBlackboxBase { Q_OBJECT public: TestBlackboxAndroid(); private slots: void android(); void android_data(); private: QMap findAndroid(int *status, const QString &profile); }; #endif // TST_BLACKBOX_H qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxqt.h0000644000175100001660000000516114776170045021547 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BLACKBOXQT_H #define TST_BLACKBOXQT_H #include "tst_blackboxbase.h" class TestBlackboxQt : public TestBlackboxBase { Q_OBJECT public: TestBlackboxQt(); private slots: void addQObjectMacroToGeneratedCppFile(); void autoQrc(); void cachedQml(); void combinedMoc(); void createProject(); void dbusAdaptors(); void dbusInterfaces(); void emscriptenHtml(); void forcedMoc(); void includedMocCpp(); void linkerVariant(); void lrelease(); void lupdate(); void metaTypes_data(); void metaTypes(); void mixedBuildVariants(); void mocAndCppCombining(); void mocFlags(); void mocCompilerDefines(); void mocSameFileName(); void noMocRunAfterTouchingOtherCppFile(); void noRelinkOnQDebug(); void noRelinkOnQDebug_data(); void pkgconfig(); void pkgconfigQt(); void pkgconfigQt_data(); void pkgconfigNoQt(); void pluginMetaData(); void pluginSupport_data(); void pluginSupport(); void qdoc(); void qmlDebugging(); void qobjectInObjectiveCpp(); void qmlTypeRegistrar_data(); void qmlTypeRegistrar(); void qtKeywords(); void quickCompiler(); void qtScxml(); void removeMocHeaderFromFileList(); void staticQtPluginLinking(); void trackAddMocInclude(); void track_qobject_change(); void track_qrc(); void unmocable(); }; #endif // TST_BLACKBOXQT_H qbs-src-2.6.1/tests/auto/blackbox/testdata/0000755000175100001660000000000014776170045020160 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-without-sources/0000755000175100001660000000000014776170045025375 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-without-sources/static-lib-without-sources.qbs0000644000175100001660000000037614776170045033327 0ustar runnerdockerProject { StaticLibrary { name: "a" Depends { name: "cpp" } files: ["lib.cpp"] } Product { type: qbs.targetOS.includes("darwin") ? undefined : ["staticlibrary"] name: "b" Depends { name: "cpp" } Depends { name: "a" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-without-sources/lib.cpp0000644000175100001660000000001514776170045026643 0ustar runnerdockervoid f() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/partially-built-dependency/0000755000175100001660000000000014776170045025412 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/partially-built-dependency/partially-built-dependency.qbs0000644000175100001660000000220514776170045033352 0ustar runnerdockerimport qbs.File import qbs.TextFile Project { Product { name: "p" type: "obj" Depends { name: "cpp" } Depends { name: "dep" } Rule { inputsFromDependencies: "cpp" Artifact { filePath: input.fileName fileTags: "cpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description ="copying " + input.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } CppApplication { name: "dep" Rule { multiplex: true Artifact { filePath: "main.cpp"; fileTags: "cpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.writeLine("int main() {}"); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/0000755000175100001660000000000014776170045025713 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/export-to-outside-searchpath.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/export-to-outside-searchpath0000644000175100001660000000057614776170045033401 0ustar runnerdockerProject { Project { qbsSearchPaths: ["qbs-resources"] Product { name: "otherProduct" Depends { name: "dep" } } Product { name: "dep" Export { Depends { name: "aModule" } } } } Project { Product { name: "theProduct" Depends { name: "dep" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/qbs-resources/0000755000175100001660000000000014776170045030510 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/qbs-resources/modules/0000755000175100001660000000000014776170045032160 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/qbs-resources/modules/aModule/qbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/qbs-resources/modules/aModul0000755000175100001660000000000014776170045033322 5ustar runnerdocker././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/qbs-resources/modules/aModule/aModule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/export-to-outside-searchpath/qbs-resources/modules/aModul0000644000175100001660000000001314776170045033316 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/0000755000175100001660000000000014776170045023612 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/import-searchpath.qbs0000644000175100001660000000030214776170045027746 0ustar runnerdockerProject { Project { qbsSearchPaths: ["qbs"] references: ["src/import-searchpath-app1.qbs"] } Project { references: ["src/import-searchpath-app2.qbs"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/qbs/0000755000175100001660000000000014776170045024377 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/qbs/imports/0000755000175100001660000000000014776170045026074 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/qbs/imports/CppApplication.qbs0000644000175100001660000000001414776170045031504 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/src/0000755000175100001660000000000014776170045024401 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/src/somefile.cpp0000644000175100001660000000000014776170045026676 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/src/import-searchpath-app1.qbs0000644000175100001660000000005714776170045031403 0ustar runnerdockerCppApplication { files: ["somefile.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/src/main.cpp0000644000175100001660000000001714776170045026027 0ustar runnerdockerint main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-searchpath/src/import-searchpath-app2.qbs0000644000175100001660000000005314776170045031400 0ustar runnerdockerCppApplication { files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/0000755000175100001660000000000014776170045026420 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/transitive-invalid-dependencies.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/transitive-invalid-depend0000644000175100001660000000051514776170045033415 0ustar runnerdockerProduct { property bool modulePresent: { console.info("b.present = " + b.present); console.info("c.present = " + c.present); console.info("d.present = " + d.present); } Depends { name: "b"; required: false } Depends { name: "c"; required: false } Depends { name: "d"; required: false } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/0000755000175100001660000000000014776170045030070 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/a/0000755000175100001660000000000014776170045030310 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/a/a.qbs0000644000175100001660000000011214776170045031231 0ustar runnerdockerModule { validate: { throw "Module cannot be loaded"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/b/0000755000175100001660000000000014776170045030311 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/b/b.qbs0000644000175100001660000000004514776170045031240 0ustar runnerdockerModule { Depends { name: "a" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/d/0000755000175100001660000000000014776170045030313 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/d/d.qbs0000644000175100001660000000010114776170045031235 0ustar runnerdockerModule { Depends { name: "b"; } Depends { name: "c"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/c/0000755000175100001660000000000014776170045030312 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-invalid-dependencies/modules/c/c.qbs0000644000175100001660000000006614776170045031245 0ustar runnerdockerModule { Depends { name: "a"; required: false } } qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/0000755000175100001660000000000014776170045023335 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs0000644000175100001660000000535314776170045027227 0ustar runnerdockerimport qbs.Environment import qbs.File import qbs.TextFile Project { property var projectDefines: ["blubb2"] property string fileContentSuffix: "suffix 1" property string testProperty: "default value" CppApplication { name: qbs.enableDebugCode ? "product 1.debug" : "product 1.release" cpp.defines: ["blubb1"] files: "source1.cpp" } CppApplication { Depends { name: 'library' } name: "product 2" cpp.defines: project.projectDefines files: "source2.cpp" } CppApplication { name: "product 3" cpp.defines: Environment.getEnv("QBS_BLACKBOX_DEFINE") files: "source3.cpp" } DynamicLibrary { Depends { name: "cpp" } name: "library" files: "lib.cpp" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } Product { name: "generated text file" type: ["my_output"] property string fileContentPrefix: "prefix 1" Rule { multiplex: true Artifact { filePath: "nothing"; fileTags: ["my_output"] } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info(product.fileContentPrefix); } return cmd; } } Rule { multiplex: true Artifact { filePath: "generated.txt"; fileTags: ["my_output"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.filePath; cmd.highlight = "codegen"; cmd.sourceCode = function() { file = new TextFile(output.filePath, TextFile.WriteOnly); file.truncate(); file.write(product.fileContentPrefix + "contents 1" + project.fileContentSuffix); file.close(); } return cmd; } } } Product { Depends { name: "ruletest" } type: ["test-output2"] Rule { inputsFromDependencies: ['test-output'] Artifact { fileTags: "test-output2" filePath: input.fileName + ".out2" } prepare: { var cmd = new JavaScriptCommand(); cmd.highlight = "codegen"; cmd.description = "making output from other output"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } references: "ruletest.qbs" qbsSearchPaths: "." } qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/source1.cpp0000644000175100001660000000235114776170045025423 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/source2.cpp0000644000175100001660000000235214776170045025425 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/lib.cpp0000644000175100001660000000241514776170045024611 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" DLL_EXPORT void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/ruletest.qbs0000644000175100001660000000027514776170045025717 0ustar runnerdockerProduct { name: "ruletest" type: "test-output" Depends { name: "TestModule" } Group { files: "test.in" TestModule.testProperty: project.testProperty } } qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/modules/0000755000175100001660000000000014776170045025005 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/0000755000175100001660000000000014776170045027072 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs0000644000175100001660000000156514776170045031075 0ustar runnerdockerimport qbs.File Module { FileTagger { patterns: ["*.in"] fileTags: "test-input" } property string testProperty Rule { inputs: ['test-input'] Artifact { fileTags: "test-output" filePath: input.fileName + ".out" } prepare: { var cmd = new JavaScriptCommand(); cmd.highlight = "codegen"; cmd.description = "making output from input"; cmd.sourceCode = function() { // console.info('Change in source code'); console.info(input.TestModule.testProperty); File.copy(input.filePath, output.filePath); } var dummyCmd = new JavaScriptCommand(); dummyCmd.silent = true; dummyCmd.sourceCode = function() {}; return [cmd, dummyCmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/test.in0000644000175100001660000000000614776170045024640 0ustar runnerdockerblubb qbs-src-2.6.1/tests/auto/blackbox/testdata/propertyChanges/source3.cpp0000644000175100001660000000235214776170045025426 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-rules/0000755000175100001660000000000014776170045024024 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-rules/wildcards-and-rules.qbs0000644000175100001660000000166314776170045030405 0ustar runnerdockerimport qbs.TextFile Product { name: "wildcards-and-rules" type: "mytype" files: ["*.inp", "*.dep"] FileTagger { patterns: "*.inp" fileTags: ["inp"] } FileTagger { patterns: "*.dep" fileTags: ["dep"] } Rule { multiplex: true inputs: ["inp"] explicitlyDependsOn: ["dep"] Artifact { filePath: "test.mytype" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating output artifact"; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); for (var i = 0; i < inputs.inp.length; ++i) file.writeLine(inputs.inp[i].fileName); file.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-rules/input1.inp0000644000175100001660000000000014776170045025742 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/external-libs/0000755000175100001660000000000014776170045022731 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/external-libs/lib1.cpp0000644000175100001660000000002514776170045024261 0ustar runnerdockervoid func_lib1() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/external-libs/external-libs.qbs0000644000175100001660000000162514776170045026215 0ustar runnerdockerimport qbs.TextFile Project { property string libDir: buildDirectory + "/libs" StaticLibrary { name: "lib1" destinationDirectory: project.libDir Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib1.cpp"] } StaticLibrary { name: "lib2" destinationDirectory: project.libDir Depends { name: "cpp" } Depends { name: "lib1" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib2.cpp"] } CppApplication { Depends { name: "lib1"; cpp.link: false } Depends { name: "lib2"; cpp.link: false } files: ["main.cpp"] cpp.libraryPaths: [project.libDir] cpp.staticLibraries: ["lib1", "lib2", "lib1"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/external-libs/lib2.cpp0000644000175100001660000000006514776170045024266 0ustar runnerdockervoid func_lib1(); void func_lib2() { func_lib1(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/external-libs/main.cpp0000644000175100001660000000006314776170045024360 0ustar runnerdockervoid func_lib2(); int main() { func_lib2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/moved-file-dependency/0000755000175100001660000000000014776170045024323 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/moved-file-dependency/subdir1/0000755000175100001660000000000014776170045025674 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/moved-file-dependency/subdir1/theheader.h0000644000175100001660000000000014776170045027764 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/moved-file-dependency/main.cpp0000644000175100001660000000004714776170045025754 0ustar runnerdocker#include int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/moved-file-dependency/moved-file-dependency.qbs0000644000175100001660000000013014776170045031167 0ustar runnerdockerCppApplication { cpp.includePaths: ["subdir1", "subdir2"] files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-invalidation/0000755000175100001660000000000014776170045025372 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-invalidation/file.in0000644000175100001660000000000014776170045026627 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-invalidation/artifacts-map-invalidation.qbs0000644000175100001660000000420214776170045033311 0ustar runnerdockerimport qbs.File Project { Product { name: "dep" type: "dep.out" Group { files: "file.in" fileTags: "dep.in" } Rule { inputs: "dep.in" outputFileTags: "dep.out" outputArtifacts: { if (!product.artifacts["dep.in"] || product.artifacts["dep.in"].length !== 1) throw "source file not in artifacts map!" if (product.artifacts["dep.out"] && product.artifacts["dep.out"].length !== 0) throw "generated artifact already in map!"; return [{filePath: "file.out", fileTags: "dep.out"}]; } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } Product { name: "p" type: "p.out" Depends { name: "dep" } Rule { inputsFromDependencies: "dep.out" Artifact { filePath: "myfile.out"; fileTags: "p.out" } prepare: { var dep; for (var i = 0; i < product.dependencies.length; ++i) { if (product.dependencies[i].name === "dep") { dep = product.dependencies[i]; break; } } if (!dep) throw "dependency not found"; if (!dep.artifacts["dep.in"] || dep.artifacts["dep.in"].length !== 1) throw "source file not in dependency's artifacts map!" if (!dep.artifacts["dep.out"] || dep.artifacts["dep.out"].length !== 1) throw "generated artifact not in dependency's artifacts map!"; var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/allowed-values/0000755000175100001660000000000014776170045023104 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/allowed-values/allowed-values.qbs0000644000175100001660000000067414776170045026546 0ustar runnerdockerProduct { Depends { name: "a" } // tests VariantValue property string prop PropertyOptions { name: "prop" description: "Some prop" allowedValues: "foo" } // tests JSValue property string prop2 // setter for otherProp property string otherProp: prop2 PropertyOptions { name: "otherProp" description: "Some other prop" allowedValues: "foo" } name: "p" } qbs-src-2.6.1/tests/auto/blackbox/testdata/allowed-values/modules/0000755000175100001660000000000014776170045024554 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/allowed-values/modules/a/0000755000175100001660000000000014776170045024774 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/allowed-values/modules/a/a.qbs0000644000175100001660000000066214776170045025727 0ustar runnerdockerModule { // tests VariantValue property stringList prop PropertyOptions { name: "prop" description: "Some prop" allowedValues: ["foo", "bar"] } // tests JSValue property stringList prop2 // setter for otherProp property stringList otherProp: prop2 PropertyOptions { name: "otherProp" description: "Some other prop" allowedValues: ["foo", "bar"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dependency-scanning-loop/0000755000175100001660000000000014776170045025043 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs0000644000175100001660000000170014776170045032433 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile CppApplication { name: "app" cpp.includePaths: buildDirectory Group { files: "main.cpp" fileTags: ["cpp", "custom.in"] } Rule { inputs: "custom.in" Artifact { filePath: FileInfo.completeBaseName(input.filePath) + ".h" fileTags: "hpp" } Artifact { filePath: "custom.txt" fileTags: "whatever" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + outputs.hpp[0].fileName; cmd.sourceCode = function() { var f = new TextFile(outputs.hpp[0].filePath, TextFile.WriteOnly); f.writeLine("int main() {}"); f.close(); f = new TextFile(outputs.whatever[0].filePath, TextFile.WriteOnly); f.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp0000644000175100001660000000002214776170045026465 0ustar runnerdocker#include qbs-src-2.6.1/tests/auto/blackbox/testdata/grpc/0000755000175100001660000000000014776170045021113 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/grpc/conanfile.txt0000644000175100001660000000013114776170045023605 0ustar runnerdocker[requires] grpc/1.54.3 [tool_requires] protobuf/3.21.12 grpc/1.54.3 [generators] QbsDeps qbs-src-2.6.1/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs0000644000175100001660000000164214776170045023422 0ustar runnerdockerimport qbs.Host CppApplication { name: "grpc_cpp" consoleApplication: true condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasDependencies; } Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++17" cpp.minimumMacosVersion: "10.15" cpp.warningLevel: "none" qbs.buildVariant: "release" Depends { name: "protobuf.cpp"; required: false } Depends { name: "grpc++"; id: grpcpp; required: false } protobuf.cpp.useGrpc: true property bool hasDependencies: { console.info("has grpc: " + protobuf.cpp.present); console.info("has modules: " + grpcpp.present); return protobuf.cpp.present && grpcpp.present; } files: "grpc.cpp" Group { files: "grpc.proto" fileTags: "protobuf.grpc" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/grpc/grpc.cpp0000644000175100001660000000357314776170045022562 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include class ServiceImpl final : public Qbs::Grpc::Service { grpc::Status doWork( grpc::ServerContext* context, const Qbs::Request* request, Qbs::Response* reply) override { (void)context; reply->set_name(request->name()); return grpc::Status::OK; } }; int main(int, char**) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/grpc/grpc.proto0000644000175100001660000000026714776170045023140 0ustar runnerdockersyntax = "proto3"; package Qbs; message Request { string name = 1; } message Response { string name = 1; } service Grpc { rpc doWork(Request) returns (Response) {} } qbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/0000755000175100001660000000000014776170045027523 5ustar runnerdocker././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/exported-property-in-disabled-product.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/exported-property-i0000644000175100001660000000073414776170045033414 0ustar runnerdockerProject { CppApplication { name: "app" Depends { name: "dep"; required: false } files: "main.cpp" } Product { name: "dep" condition: eval(conditionString) property string conditionString Depends { name: "nosuchmodule"; required: false } Depends { name: "broken"; required: false } Export { Depends { name: "cpp" } cpp.dynamicLibraries: ["nosuchlib"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/main.cpp0000644000175100001660000000001614776170045031150 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/modules/0000755000175100001660000000000014776170045031173 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/modules/broken/0000755000175100001660000000000014776170045032453 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/modules/broken/broken.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-property-in-disabled-product/modules/broken/brok0000644000175100001660000000005614776170045033334 0ustar runnerdockerModule { validate: { throw "broken!"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_wildcards/0000755000175100001660000000000014776170045024223 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_wildcards/dir/0000755000175100001660000000000014776170045025001 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_wildcards/dir/file1.txt0000644000175100001660000000000014776170045026530 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_wildcards/dir/subdir/0000755000175100001660000000000014776170045026271 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_wildcards/dir/subdir/file2.txt0000644000175100001660000000000014776170045030021 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_wildcards/recursive_wildcards.qbs0000644000175100001660000000226514776170045031002 0ustar runnerdockerimport qbs.TextFile Product { type: ["txt.out"] qbs.installPrefix: "" Group { files: "dir/**" qbs.install: true qbs.installDir: "dir" } FileTagger { patterns: ["*.txt"] fileTags: ["txt.in"] } Rule { multiplex: true requiresInputs: false explicitlyDependsOn: ["txt.in"] Artifact { filePath: "output.txt" fileTags: product.type qbs.install: true } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var inputList = explicitlyDependsOn["txt.in"]; var fileNameList = []; for (var i = 0; i < inputList.length; ++i) fileNameList.push(inputList[i].fileName); fileNameList.sort(); var f = new TextFile(output.filePath, TextFile.WriteOnly); try { f.write(fileNameList.join('')); } finally { f.close(); } }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/imports-conflict/0000755000175100001660000000000014776170045023454 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/imports-conflict/imports-conflict.qbs0000644000175100001660000000022214776170045027453 0ustar runnerdockerProject { Product { name: "Utils" } Product { Depends { name: "Utils" } Depends { name: "themodule" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/imports-conflict/modules/0000755000175100001660000000000014776170045025124 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/imports-conflict/modules/themodule/0000755000175100001660000000000014776170045027112 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/imports-conflict/modules/themodule/utils.js0000644000175100001660000000005614776170045030611 0ustar runnerdockerfunction helper() { console.info("helper"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/imports-conflict/modules/themodule/m.qbs0000644000175100001660000000011114776170045030046 0ustar runnerdockerimport "utils.js" as Utils Module { validate: { Utils.helper(); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/command-file/0000755000175100001660000000000014776170045022513 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/command-file/list.gcc0000644000175100001660000000001114776170045024134 0ustar runnerdocker-ltheLib qbs-src-2.6.1/tests/auto/blackbox/testdata/command-file/list.msvc0000644000175100001660000000001314776170045024352 0ustar runnerdockertheLib.lib qbs-src-2.6.1/tests/auto/blackbox/testdata/command-file/lib.cpp0000644000175100001660000000001514776170045023761 0ustar runnerdockervoid f() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/command-file/main.cpp0000644000175100001660000000004314776170045024140 0ustar runnerdockervoid f(); int main() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/command-file/command-file.qbs0000644000175100001660000000105614776170045025557 0ustar runnerdockerProject { StaticLibrary { name: "theLib" destinationDirectory: project.buildDirectory Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib.cpp"] } CppApplication { name: "theApp" cpp.libraryPaths: project.buildDirectory files: ["main.cpp"] cpp.staticLibraries: ['@' + sourceDirectory + '/' + (qbs.toolchain.includes("msvc") ? "list.msvc" : "list.gcc")] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/0000755000175100001660000000000014776170045026413 5ustar runnerdocker././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/precompiled-headers-and-redefine.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/precompiled-headers-and-0000644000175100001660000000057614776170045033077 0ustar runnerdockerCppApplication { name: "MyApp" consoleApplication: true Group { files: ["pch.h"] fileTags: ["cpp_pch_src"] } Group { files: ["file.cpp"] cpp.defines: ["MYDEF=1"] cpp.cxxFlags: base.concat(qbs.toolchain.includes("clang-cl") ? ["-Wno-clang-cl-pch"] : []) } cpp.treatWarningsAsErrors: true files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/file.cpp0000644000175100001660000000002114776170045030027 0ustar runnerdocker#include "pch.h" qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/pch.h0000644000175100001660000000240214776170045027334 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-headers-and-redefine/main.cpp0000644000175100001660000000237414776170045030051 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "pch.h" int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/qbsVersion/0000755000175100001660000000000014776170045022313 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/qbsVersion/qbs-version.qbs0000644000175100001660000000130314776170045025267 0ustar runnerdockerProject { property string qbsVersion property int qbsVersionMajor property int qbsVersionMinor property int qbsVersionPatch Product { property bool dummy: { if (qbsVersion !== qbs.version || qbsVersionMajor !== qbs.versionMajor || qbsVersionMinor !== qbs.versionMinor || qbsVersionPatch !== qbs.versionPatch) throw("expected " + [qbsVersion, qbsVersionMajor, qbsVersionMinor, qbsVersionPatch].join(", ") + ", got " + [qbs.version, qbs.versionMajor, qbs.versionMinor, qbs.versionPatch].join(", ")); return false; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-binaryfile/0000755000175100001660000000000014776170045025036 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-binaryfile/binaryfile.qbs0000644000175100001660000000360114776170045027671 0ustar runnerdockerimport qbs.BinaryFile Product { type: ["dummy"] Rule { multiplex: true outputFileTags: "dummy" prepare: { var commands = []; var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var source = new BinaryFile("source.dat", BinaryFile.WriteOnly); source.write([ 0x01, 0x02 ]); // First data. // Do not close the file to test the auto close functionality. }; commands.push(cmd); cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { source = new BinaryFile("source.dat", BinaryFile.ReadWrite); source.seek(source.size()); source.write([ 0x03, 0x04 ]); // Second data. source.close(); source = new BinaryFile("source.dat", BinaryFile.ReadWrite); var destination = new BinaryFile("destination.dat", BinaryFile.WriteOnly); destination.write(source.atEof() ? [ 0xFF ] : [ 0x00 ]); while (true) { var data = source.read(1); if (!data || data.length == 0) break; destination.write(data); } source.resize(0); // truncate destination.write([ 0x05, 0x06 ]); // Third data. destination.write(source.atEof() ? [ 0xFF ] : [ 0x00 ]); source.close(); destination.close(); source = new BinaryFile("destination.dat", BinaryFile.ReadOnly); destination = new BinaryFile("destination2.dat", BinaryFile.WriteOnly); destination.write(source.read(8)); }; commands.push(cmd); return commands; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/successive-changes/0000755000175100001660000000000014776170045023742 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/successive-changes/input.in0000644000175100001660000000000014776170045025417 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs0000644000175100001660000000136414776170045030237 0ustar runnerdockerimport qbs.TextFile Project { property string version: "1" Product { name: "theProduct" type: ["output"] Group { files: ["input.in"] fileTags: ["input"] } Rule { inputs: ["input"] Artifact { filePath: "output.out" fileTags: ["output"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating output"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write(project.version); } return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/always-run/0000755000175100001660000000000014776170045022262 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/always-run/rule.qbs0000644000175100001660000000116114776170045023737 0ustar runnerdockerimport qbs.TextFile Product { type: ["blubb"] Group { files: ["dummy.txt"] fileTags: ["dummy"] } Rule { alwaysRun: false inputs: ["dummy"] Artifact { filePath: "blubb.txt" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "yo"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("blubb"); f.close(); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/always-run/transformer.qbs0000644000175100001660000000102214776170045025326 0ustar runnerdockerimport qbs.TextFile Product { type: ["blubb"] Transformer { alwaysRun: false Artifact { filePath: "blubb.txt" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "yo"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("blubb"); f.close(); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/always-run/dummy.txt0000644000175100001660000000000014776170045024144 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conflicting-property-values/0000755000175100001660000000000014776170045025636 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/conflicting-property-values/conflicting-property-values.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/conflicting-property-values/conflicting-property-values.q0000644000175100001660000000206114776170045033475 0ustar runnerdockerProject { Product { name: "low" Export { property string prop: "low"; property string prop2: "low" } } Product { name: "higher1" Export { Depends { name: "low" } low.prop: "higher1" } } Product { name: "higher2" Export { Depends { name: "low" } low.prop: "higher2" } } Product { name: "highest1" Export { Depends { name: "low" } Depends { name: "higher1" } Depends { name: "higher2" } low.prop: "highest1" low.prop2: "highest" } } Product { name: "highest2" Export { Depends { name: "low" } Depends { name: "higher1" } Depends { name: "higher2" } low.prop: "highest2" low.prop2: "highest" } } Product { name: "toplevel" Depends { name: "highest1" } Depends { name: "highest2" } low.prop: name property bool dummy: { console.info("final prop value: " + low.prop); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/date-property/0000755000175100001660000000000014776170045022757 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/date-property/date-property.qbs0000644000175100001660000000105014776170045026261 0ustar runnerdockerProduct { type: "date" property var theDate: new Date(1999, 11, 31); Rule { multiplex: true Artifact { filePath: "dummy"; fileTags: "date" } prepare: { var cmd = new JavaScriptCommand; cmd.silent = true; cmd.sourceCode = function() { var d = product.theDate; console.info("The stored date was " + d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/0000755000175100001660000000000014776170045020727 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cli/Module.vb0000755000175100001660000000023714776170045022512 0ustar runnerdockerNamespace Fake Public Class [Mod] Public Shared Function Cool() As Integer Return 420 End Function End Class End Namespace qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/fshello.qbs0000644000175100001660000000016014776170045023067 0ustar runnerdockerApplication { Depends { name: "cli" } type: "application" name: "fshello" files: "fshello.fs" } qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/Module.cs0000644000175100001660000000020114776170045022474 0ustar runnerdockernamespace Fake { public class Mod { public static int Cool() { return 420; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/fshello.fs0000644000175100001660000000003714776170045022715 0ustar runnerdockerprintfn "Hello World from F#!" qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/Libby2.cs0000755000175100001660000000020314776170045022377 0ustar runnerdockernamespace Fake { public class Libby2 { public static int Cool() { return 22; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/dotnettest.qbs0000644000175100001660000000213514776170045023634 0ustar runnerdockerProject { Application { Depends { name: "cli" } Depends { name: "HelloWorldModule"; condition: !qbs.toolchain.includes("mono") } Depends { name: "NetLib" } type: "application" name: "Hello" files: ["HelloWorld.cs"] Group { fileTagsFilter: product.type qbs.install: true } } // Mono's VB compiler doesn't support modules yet, and if we try with C#, it crashes anyways NetModule { condition: !qbs.toolchain.includes("mono") Depends { name: "cli" } name: "HelloWorldModule" files: ["Module.vb"] Group { fileTagsFilter: product.type qbs.install: true } } DynamicLibrary { Depends { name: "cli" } name: "NetLib" files: ["Libby.cs", "Libby2.cs"] // fill-in for missing NetModule Group { condition: qbs.toolchain.includes("mono") files: ["Module.cs"] } Group { fileTagsFilter: product.type qbs.install: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/Libby.cs0000755000175100001660000000020214776170045022314 0ustar runnerdockernamespace Fake { public class Libby { public static int Cool() { return 45; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cli/HelloWorld.cs0000755000175100001660000000042414776170045023334 0ustar runnerdockerusing Fake; public class HelloWorld { public static void Main() { System.Console.WriteLine("Hello world!"); System.Console.WriteLine(Mod.Cool()); System.Console.WriteLine(Libby.Cool()); System.Console.WriteLine(Libby2.Cool()); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-extension-instantiation/0000755000175100001660000000000014776170045026502 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-extension-instantiation/invalid-extension-instantiation.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-extension-instantiation/invalid-extension-instant0000644000175100001660000000104714776170045033545 0ustar runnerdockerimport qbs.Environment import qbs.File import qbs.FileInfo import qbs.Utilities Product { name: "theProduct" type: ["mytype"] property string extension Rule { multiplex: true Artifact { filePath: "dummy" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var f = eval("new " + product.extension); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/conditional-export/0000755000175100001660000000000014776170045024002 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conditional-export/conditional-export.qbs0000644000175100001660000000053514776170045030336 0ustar runnerdockerProject { property bool enableExport: false Product { name: "dep" Export { condition: project.enableExport Depends { name: "cpp" } cpp.defines: ["THE_DEFINE"] } } CppApplication { name: "theProduct" Depends { name: "dep" } files: "main.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/conditional-export/main.cpp0000644000175100001660000000243514776170045025436 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef THE_DEFINE #error "missing define" #endif int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/importing-product/0000755000175100001660000000000014776170045023646 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/importing-product/importing-product.qbs0000644000175100001660000000207514776170045030047 0ustar runnerdockerimport qbs.File Project { Product { name: "dep" Export { Depends { name: "cpp" } cpp.includePaths: [importingProduct.buildDirectory + "/random_dir"] Rule { inputs: ["hpp_in"] Artifact { filePath: product.buildDirectory + "/random_dir/" + input.completeBaseName fileTags: ["hpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "copying file"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return [cmd]; } } } } CppApplication { name: "theProduct" Depends { name: "dep" } Group { files: ["header.h.in"] fileTags: ["hpp_in"] } files: ["main.cpp"] } CppApplication { name: "theProduct2" Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/importing-product/main.cpp0000644000175100001660000000235714776170045025305 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include qbs-src-2.6.1/tests/auto/blackbox/testdata/importing-product/header.h.in0000644000175100001660000000001614776170045025651 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/0000755000175100001660000000000014776170045023572 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp0000644000175100001660000000016714776170045025663 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void plugin3_hello() { std::puts("plugin3 says hello!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp0000644000175100001660000000016714776170045025664 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void plugin4_hello() { std::puts("plugin4 says hello!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs0000644000175100001660000000404314776170045027714 0ustar runnerdockerimport qbs.Host Project { CppApplication { name: "myapp" files: ["main.cpp"] Depends { name: "plugin1" // not to be linked cpp.link: Host.os() === undefined } Depends { name: "plugin2" } // not to be linked Depends { name: "plugin3" // supposed to be linked property bool theCondition: true cpp.link: theCondition && product.name === "myapp" } Depends { name: "plugin4" } // supposed to be linked Depends { name: "helper1" } // supposed to be linked } DynamicLibrary { name: "plugin1" files: ["plugin1.cpp"] Depends { name: "cpp" } } DynamicLibrary { name: "plugin2" files: ["plugin2.cpp"] Depends { name: "cpp" } Export { Parameters { cpp.link: false // marker 1 } } } DynamicLibrary { name: "plugin3" files: ["plugin3.cpp"] Depends { name: "cpp" } Export { Parameters { cpp.link: false } } } DynamicLibrary { name: "plugin4" files: ["plugin4.cpp"] Depends { name: "cpp" } Export { Parameters { // property bool theCondition: true cpp.link: true // theCondition TODO: Make this work } } } DynamicLibrary { name: "helper1" files: ["helper1.cpp"] Depends { name: "cpp" } Depends { name: "helper2"; cpp.link: false /* marker 2 */ } Export { Depends { name: "cpp" } Depends { name: "helper2"; cpp.link: false } } } DynamicLibrary { name: "helper2" files: ["helper2.cpp"] Depends { name: "cpp" } Export { Depends { name: "cpp" } cpp.defines: ["USING_HELPER2"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/helper2.cpp0000644000175100001660000000016714776170045025643 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void helper2_hello() { std::puts("Hello from helper2!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp0000644000175100001660000000016714776170045025661 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void plugin1_hello() { std::puts("plugin1 says hello!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/main.cpp0000644000175100001660000000033314776170045025221 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void plugin3_hello(); DLL_IMPORT void plugin4_hello(); DLL_IMPORT void helper1_hello(); int main() { plugin3_hello(); plugin4_hello(); helper1_hello(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/helper1.cpp0000644000175100001660000000041114776170045025632 0ustar runnerdocker#include #if defined(_WIN32) || defined(WIN32) # define EXPORT __declspec(dllexport) #else # define EXPORT #endif #ifndef USING_HELPER2 #error define USING_HELPER2 missing #endif EXPORT void helper1_hello() { std::puts("helper1 says hello!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp0000644000175100001660000000016714776170045025662 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void plugin2_hello() { std::puts("plugin2 says hello!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-inputs-from-dependencies/0000755000175100001660000000000014776170045026456 5ustar runnerdocker././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/changed-inputs-from-dependencies/changed-inputs-from-dependencies.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/changed-inputs-from-dependencies/changed-inputs-from-depe0000644000175100001660000000341614776170045033172 0ustar runnerdockerimport qbs.File import qbs.TextFile Project { Product { name: "dep" type: "dep_tag" files: "input.txt" FileTagger { patterns: "*.txt"; fileTags: "inp_tag" } Rule { inputs: "inp_tag" Artifact { filePath: input.baseName + ".intermediate"; fileTags: "int_tag" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } Rule { inputs: "int_tag" Artifact { filePath: input.baseName + ".dep"; fileTags: "dep_tag" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } Product { name: "p" type: "p_tag" Depends { name: "dep" } Rule { inputsFromDependencies: "dep_tag" outputFileTags: "p_tag" outputArtifacts: { var dummy = new TextFile(input.filePath, TextFile.ReadOnly); dummy.close(); return [{ filePath: input.baseName + ".p", fileTags: "p_tag" }] } prepare: { console.info("running final prepare script"); var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-inputs-from-dependencies/input.txt0000644000175100001660000000000014776170045030344 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/empty-profile/0000755000175100001660000000000014776170045022754 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs0000644000175100001660000000005314776170045026255 0ustar runnerdockerCppApplication { files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/empty-profile/main.cpp0000644000175100001660000000003114776170045024376 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/installable/0000755000175100001660000000000014776170045022452 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/installable/main.cpp0000644000175100001660000000235114776170045024103 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/installable/installable.qbs0000644000175100001660000000221614776170045025454 0ustar runnerdockerimport qbs.TextFile Project { CppApplication { type: ["application"] name: "app" consoleApplication: true Group { files: ["main.cpp"] qbs.install: true } install: true installDebugInformation: false installDir: "" } Product { name: "install-list" type: ["install-list"] Depends { name: "app" } Rule { multiplex: true inputsFromDependencies: ["installable"] Artifact { filePath: "installed-files.txt" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); for (var i = 0; i < inputs.installable.length; ++i) file.writeLine(inputs.installable[i].filePath); file.close(); }; return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dot-dot-pc-file/0000755000175100001660000000000014776170045023047 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dot-dot-pc-file/dot-dot-pc-file.qbs0000644000175100001660000000027614776170045026452 0ustar runnerdockerCppApplication { name: "p" Depends { name: "qbs-metatest-module"; } files: "main.cpp" moduleProviders.qbspkgconfig.libDirs: "libdir" qbsModuleProviders: "qbspkgconfig" } qbs-src-2.6.1/tests/auto/blackbox/testdata/dot-dot-pc-file/libdir/0000755000175100001660000000000014776170045024314 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dot-dot-pc-file/libdir/qbs.metatest.module.pc0000644000175100001660000000013614776170045030536 0ustar runnerdockerName: qbs.metatest.module Description: just a test Version: 0.0.1 Cflags: -DTHE_MAGIC_DEFINE qbs-src-2.6.1/tests/auto/blackbox/testdata/dot-dot-pc-file/main.cpp0000644000175100001660000000012114776170045024471 0ustar runnerdocker#ifndef THE_MAGIC_DEFINE #error "missing the magic define" #endif int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-process/0000755000175100001660000000000014776170045024370 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-process/main.cpp0000644000175100001660000000104114776170045026014 0ustar runnerdocker#include #include #include int main(int argc, char *argv[]) { if (argc != 2 || std::strcmp(argv[1], "help") != 0) { std::fprintf(stderr, "First argument to this program must be 'help'.\n"); return 1; } const char *env = std::getenv("SOME_ENV"); if (!env || std::strcmp(env, "why, hello!") != 0) { std::fprintf(stderr, "The SOME_ENV environment variable must be 'why, hello!'.\n"); return 1; } std::printf("qbs jsextensions-process test\n"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-process/process.qbs0000644000175100001660000000752514776170045026566 0ustar runnerdockerimport qbs.Environment import qbs.FileInfo import qbs.Host import qbs.Process import qbs.TextFile Project { Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Depends { name: "cpp" } type: ["dummy"] name: "dummy" files: ["main.cpp"] Rule { multiplex: true inputs: ["application"] outputFileTags: "dummy" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var exeFilePath = FileInfo.joinPaths(product.buildDirectory, product.cpp.executablePrefix + "dummy" + product.cpp.executableSuffix); // Synchronous run, successful. var process = new Process(); var pathVal = "why, hello!"; process.setEnv("SOME_ENV", pathVal); process.exec(exeFilePath, ["help"], true); var output = new TextFile("output.txt", TextFile.WriteOnly); output.writeLine(process.exitCode()); output.writeLine(process.readLine()); process.close(); // Asynchronous run, successful. process = new Process(); process.setEnv("SOME_ENV", pathVal); output.writeLine(process.start(exeFilePath, ["help"])); output.writeLine(process.waitForFinished()); output.writeLine(process.exitCode()); output.writeLine(process.readLine()); process.close(); // Asynchronous run, unsuccessful. process = new Process(); output.writeLine(process.start("blubb", [])); process.close(); // closeWriteChannel test process = new Process(); if (Host.os().includes("windows")) process.start(product.qbs.windowsShellPath, ["/C", product.qbs.windowsSystemRoot + "\\system32\\sort.exe"]); else process.start("cat", []); process.writeLine("should be"); process.closeWriteChannel(); process.writeLine("should not be"); if (!process.waitForFinished()) process.kill(); output.write(process.readStdOut()); process.close(); // readLine and atEnd var testReadlineFile = new TextFile("123.txt", TextFile.WriteOnly); testReadlineFile.writeLine("1"); testReadlineFile.writeLine("2"); testReadlineFile.writeLine("3"); testReadlineFile.close(); process = new Process(); if (Host.os().includes("windows")) process.exec(product.qbs.windowsShellPath, ["/C", "type", "123.txt"], true); else process.exec("cat", ["123.txt"], true); while(!process.atEnd()) output.write(process.readLine()); // TODO: Test all the other Process methods as well. output.close(); }; return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/nodejs/0000755000175100001660000000000014776170045021442 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nodejs/hello.js0000644000175100001660000000006114776170045023100 0ustar runnerdockerif (console) { console.log("hello world"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/nodejs/hello.qbs0000644000175100001660000000044614776170045023260 0ustar runnerdockerimport qbs.Host NodeJSApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } nodejs.applicationFile: "hello.js" name: "hello" } qbs-src-2.6.1/tests/auto/blackbox/testdata/prevent-floating-point-values/0000755000175100001660000000000014776170045026070 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/prevent-floating-point-values/prevent-floating-point-values.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/prevent-floating-point-values/prevent-floating-point-valu0000644000175100001660000000013414776170045033371 0ustar runnerdockerProduct { name: "p" property bool dummy: { console.info("version: " + version); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/distribution-include-paths/0000755000175100001660000000000014776170045025435 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/distribution-include-paths/subdir/0000755000175100001660000000000014776170045026725 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/distribution-include-paths/subdir/gagagugu.h0000644000175100001660000000010114776170045030655 0ustar runnerdockervoid printStuff() { puts("alalalalonglonglilonglonglong"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/distribution-include-paths/distribution-include-paths.qbs0000644000175100001660000000013014776170045033413 0ustar runnerdockerCppApplication { files: ["main.cpp"] cpp.distributionIncludePaths: ["subdir"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/distribution-include-paths/main.cpp0000644000175100001660000000013014776170045027057 0ustar runnerdocker#include #include int main() { printStuff(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/msvc-asm-flags/0000755000175100001660000000000014776170045023000 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/msvc-asm-flags/include/0000755000175100001660000000000014776170045024423 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/msvc-asm-flags/include/header.inc0000644000175100001660000000000014776170045026334 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.qbs0000644000175100001660000000025014776170045026324 0ustar runnerdockerStaticLibrary { condition: qbs.toolchain.includes("msvc") Depends { name: "cpp" } files: "msvc-asm-flags.asm" cpp.assemblerFlags: ["/I", "include"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/msvc-asm-flags/msvc-asm-flags.asm0000644000175100001660000000007714776170045026326 0ustar runnerdockerinclude header.inc .code main proc mov ecx, 16 main endp endqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicMultiplexRule/0000755000175100001660000000000014776170045024340 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicMultiplexRule/one.txt0000644000175100001660000000000014776170045025650 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicMultiplexRule/two.txt0000644000175100001660000000000014776170045025700 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicMultiplexRule/three.txt0000644000175100001660000000000014776170045026176 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicMultiplexRule/dynamicMultiplexRule.qbs0000644000175100001660000000155714776170045031237 0ustar runnerdockerimport qbs.TextFile Project { Product { type: ["stuff"] Group { files: ["one.txt", "two.txt", "three.txt"] fileTags: ["text"] } Rule { multiplex: true inputs: "text" outputFileTags: ["stuff"] outputArtifacts: { return [{ filePath: "stuff-from-" + inputs.text.length + "-inputs", fileTags: ["stuff"] }]; } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("narf!"); f.close(); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/rule-connection-with-excluded-inputs/0000755000175100001660000000000014776170045027350 5ustar runnerdocker././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-connection-with-excluded-inputs/rule-connection-with-excluded-inputs.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-connection-with-excluded-inputs/rule-connection-with0000644000175100001660000000222414776170045033350 0ustar runnerdockerProduct { name: "p" type: "p_type" Rule { multiplex: true Artifact { filePath: "x.txt"; fileTags: "x" } Artifact { filePath: "y.txt"; fileTags: "y" } Artifact { filePath: "p.txt"; fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() {}; return cmd; } } Rule { multiplex: true Artifact { filePath: "x2.txt"; fileTags: "x" } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() {}; return cmd; } } Rule { multiplex: true inputs: "x" excludedInputs: "y" Artifact { filePath: "dummy"; fileTags: "p_type" } prepare: { console.info("inputs.x: " + (inputs.x ? inputs.x.length : 0)); console.info("inputs.y: " + (inputs.y ? inputs.y.length : 0)); var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() {}; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/0000755000175100001660000000000014776170045024040 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/after/0000755000175100001660000000000014776170045025141 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/after/numbers.l0000644000175100001660000000513614776170045026776 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of the examples of Qbs. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /* scanner for integer and float numbers */ %option noyywrap %{ #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE is missing! #endif /* need this for the call to atof() below */ #include %} DIGIT [0-9] %% {DIGIT}+ { printf("integer: %s (%d)\n", yytext, atoi(yytext)); } {DIGIT}+"."{DIGIT}* { printf("float: %s (%g)\n", yytext, atof(yytext)); } "{"[\^{}}\n]*"}" /* eat up one-line comments */ [ \t\n]+ /* eat up whitespace */ . printf("Unexpected character: %s\n", yytext); %% int main(int argc, char **argv) { if (argc > 1) yyin = fopen(argv[1], "r"); else yyin = stdin; yylex(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/0000755000175100001660000000000014776170045025302 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/flexoptionsreader.js0000644000175100001660000000671114776170045031402 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of the examples of Qbs. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ var TextFile = require("qbs.TextFile"); function readFlexOptions(filePath) { function splitOptions(str) { var options = []; var opt = ""; var inquote = false; for (var i = 0; i < str.length; ++i) { if (str[i] === '"') { opt += '"'; inquote = !inquote; } else if (str[i] === ' ' && !inquote) { options.push(opt); opt = ""; } else { opt += str[i]; } } if (opt.length) options.push(opt); return options; } function unquote(str) { var l = str.length; if (l > 2 && str[0] === '"' && str[l - 1] === '"') return str.substr(1, l - 2); return str; } function parseOptionLine(result, str) { var options = splitOptions(str); var re = /^(outfile|header-file)=(.*)$/; var reres; for (var k in options) { re.lastIndex = 0; reres = re.exec(options[k]); if (reres === null) continue; result[reres[1]] = unquote(reres[2]); } } var tf = new TextFile(filePath); var line; var optrex = /^%option\s+(.*$)/; var res; var options = {}; while (!tf.atEof()) { line = tf.readLine(); if (line === "%%") break; optrex.lastIndex = 0; res = optrex.exec(line); if (res === null) continue; parseOptionLine(options, res[1]); } tf.close(); return options; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/numbers.l0000644000175100001660000000523614776170045027140 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of the examples of Qbs. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /* scanner for integer and float numbers */ %option noyywrap %option outfile="numberscanner.c" header-file="numberscanner.h" %{ #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE is missing! #endif /* need this for the call to atof() below */ #include %} DIGIT [0-9] %% {DIGIT}+ { printf("integer: %s (%d)\n", yytext, atoi(yytext)); } {DIGIT}+"."{DIGIT}* { printf("float: %s (%g)\n", yytext, atof(yytext)); } "{"[\^{}}\n]*"}" /* eat up one-line comments */ [ \t\n]+ /* eat up whitespace */ . printf("Unexpected character: %s\n", yytext); %% int main(int argc, char **argv) { if (argc > 1) yyin = fopen(argv[1], "r"); else yyin = stdin; yylex(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamicRuleOutputs/before/genlexer.qbs0000644000175100001660000001174614776170045027633 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of the examples of Qbs. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ import qbs.FileInfo import qbs.Probes import qbs.TextFile import "flexoptionsreader.js" as FlexOptionsReader Project { Product { name: "genlexer" type: "application" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "cpp" } Group { files: ["numbers.l"] fileTags: ["flex"] } Probes.PathProbe { id: flexProbe names: ["flex"] platformSearchPaths: ["/usr/local/bin", "/usr/bin", "/bin"] } property bool isFlexAvailable: flexProbe.found Rule { inputs: ["flex"] outputFileTags: ["c", "hpp"] outputArtifacts: { var options = FlexOptionsReader.readFlexOptions(input.filePath); var sourceFileName = options["outfile"] || "lex.yy.c"; var headerFileName = options["header-file"]; var result = [{ filePath: "GeneratedFiles/" + sourceFileName, fileTags: ["c"], cpp: { defines: ["CRUCIAL_DEFINE"] } }]; if (headerFileName) { result.push({ filePath: "GeneratedFiles/" + headerFileName, fileTags: ["hpp"] }); } return result; } prepare: { var cmd; if (product.isFlexAvailable) { // flex is available. Let's call it. cmd = new Command("flex", [input.filePath]); cmd.workingDirectory = product.buildDirectory + "/GeneratedFiles"; } else { // No flex available here, generate some C source and header. cmd = new JavaScriptCommand(); cmd.sourceFileName = outputs["c"][0].filePath; cmd.headerFileName = outputs["hpp"] ? outputs["hpp"][0].filePath : ""; cmd.sourceCode = function() { var fsrc = new TextFile(sourceFileName, TextFile.WriteOnly); if (headerFileName) { fsrc.write("#include \"" + FileInfo.fileName(headerFileName) + "\"\n\n"); var fhdr = new TextFile(headerFileName, TextFile.WriteOnly); fhdr.write("// a rather empty header file\n"); fhdr.close(); } fsrc.write("\n#ifndef CRUCIAL_DEFINE\n"); fsrc.write("# error CRUCIAL_DEFINE is missing!\n"); fsrc.write("#endif\n\n"); fsrc.write("int main() { return 0; }\n"); fsrc.close(); }; } cmd.description = "flexing " + FileInfo.fileName(input.filePath); return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-textfile/0000755000175100001660000000000014776170045024536 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-textfile/textfile.qbs0000644000175100001660000000300314776170045027065 0ustar runnerdockerimport qbs.TextFile Product { type: ["dummy"] Rule { multiplex: true outputFileTags: "dummy" prepare: { var commands = []; var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var file1 = new TextFile("file1.txt", TextFile.WriteOnly); file1.write("First line.\n"); // Do not close the file to test the auto close functionality. }; commands.push(cmd); cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var file1 = new TextFile("file1.txt", TextFile.WriteOnly | TextFile.Append); file1.write("Second line.\nThird line."); file1.close(); file1 = new TextFile("file1.txt", TextFile.ReadWrite); var file2 = new TextFile("file2.txt", TextFile.WriteOnly); file2.writeLine(file1.atEof()); while (true) { var line = file1.readLine(); if (!line || line.length == 0) break; file2.writeLine(line); } file1.truncate(); file2.writeLine(file1.filePath()); file2.writeLine(file1.atEof()); file1.close(); file2.close(); }; commands.push(cmd); return commands; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/run-multiplexed/0000755000175100001660000000000014776170045023316 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/run-multiplexed/run-multiplexed.qbs0000644000175100001660000000072714776170045027171 0ustar runnerdockerimport qbs.Host CppApplication { aggregate: false consoleApplication: true name: "app" multiplexByQbsProperties: "buildVariants" qbs.buildVariants: ["debug", "release"] files: "main.cpp" Probe { id: checker property string targetPlatform: qbs.targetPlatform configure: { if (targetPlatform !== Host.platform()) console.info("targetPlatform differs from hostPlatform"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/run-multiplexed/main.cpp0000644000175100001660000000001614776170045024743 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/0000755000175100001660000000000014776170045025135 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/lib4.cpp0000644000175100001660000000016314776170045026473 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void theLibFunc(); DLL_EXPORT void theFourthLibFunc() { theLibFunc(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/thelibs.qbs0000644000175100001660000000033114776170045027273 0ustar runnerdockerProject { Dll { name: "thelib" files: "lib1.cpp" } Dll { name: "theotherlib" files: "lib2.cpp" } Dll { name: "thethirdlib" files: "lib3.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/lib5.cpp0000644000175100001660000000003114776170045026466 0ustar runnerdockervoid staticLibFunc() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/lib1.cpp0000644000175100001660000000020414776170045026464 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void theLibFunc() { std::cout << "Hello from thelib!" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/theapp.qbs0000644000175100001660000000203414776170045027124 0ustar runnerdockerimport qbs.Host Project { CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "theapp" cpp.minimumMacosVersion: "10.7" // For -rpath Depends { name: "theotherlib" } Depends { name: "thethirdlib" } Depends { name: "thefourthlib" } Depends { name: "staticlib" } files: "main.cpp" Group { fileTagsFilter: "dynamiclibrary" qbs.install: true qbs.installSourceBase: buildDirectory } } Dll { name: "thefourthlib" Depends { name: "thelib" } files: "lib4.cpp" Export { Depends { name: "cpp" } cpp.rpaths: [qbs.installRoot] } } StaticLibrary { name: "staticlib" Depends { name: "cpp" } Depends { name: "theotherlib" } files: "lib5.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/lib2.cpp0000644000175100001660000000021614776170045026470 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void theOtherLibFunc() { std::cout << "Hello from theotherlib!" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/main.cpp0000644000175100001660000000032414776170045026564 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void theOtherLibFunc(); DLL_IMPORT void theFourthLibFunc(); void theThirdLibFunc() { } int main() { theOtherLibFunc(); theThirdLibFunc(); theFourthLibFunc(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/lib3.cpp0000644000175100001660000000021614776170045026471 0ustar runnerdocker#include "../dllexport.h" #include DLL_EXPORT void theThirdLibFunc() { std::cout << "Hello from thethirdlib!" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/0000755000175100001660000000000014776170045026605 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thethirdlib/0000755000175100001660000000000014776170045031107 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thethirdlib/thethirdlib.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thethirdlib/thethirdlib0000644000175100001660000000126414776170045033337 0ustar runnerdockerimport qbs.FileInfo Module { Depends { name: "cpp" } property string baseDir: FileInfo.cleanPath(FileInfo.joinPaths(path, "..", "..")) Group { name: "thethirdlib dll" condition: false files: FileInfo.joinPaths(product.theotherlib.baseDir, cpp.dynamicLibraryPrefix + "thethirdlib" + cpp.dynamicLibrarySuffix) fileTags: ["dynamiclibrary"] filesAreTargets: true } Group { name: "thethirdlib dll import" condition: false files: FileInfo.joinPaths(product.thethirdlib.baseDir, "thethirdlib.lib") fileTags: ["dynamiclibrary_import"] filesAreTargets: true } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/0000755000175100001660000000000014776170045031116 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/theotherlib.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/theotherlib/theotherlib0000644000175100001660000000134414776170045033354 0ustar runnerdockerimport qbs.FileInfo Module { Depends { name: "cpp" } property string baseDir: FileInfo.cleanPath(FileInfo.joinPaths(path, "..", "..")) cpp.rpaths: [product.theotherlib.baseDir] Group { name: "theotherlib dll" files: FileInfo.joinPaths(product.theotherlib.baseDir, cpp.dynamicLibraryPrefix + "theotherlib" + cpp.dynamicLibrarySuffix) fileTags: ["dynamiclibrary"] filesAreTargets: true } Group { name: "theotherlib dll import" condition: qbs.targetOS.includes("windows") files: FileInfo.joinPaths(product.theotherlib.baseDir, "theotherlib.lib") fileTags: ["dynamiclibrary_import"] filesAreTargets: true } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/0000755000175100001660000000000014776170045030054 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/thelib.qbs0000644000175100001660000000150514776170045032033 0ustar runnerdockerimport qbs.FileInfo Module { Depends { name: "cpp" } property string baseDir: FileInfo.cleanPath(FileInfo.joinPaths(path, "..", "..")) cpp.rpaths: [product.thelib.baseDir] Group { name: "thelib dll" files: FileInfo.joinPaths(product.thelib.baseDir, cpp.dynamicLibraryPrefix + "thelib" + cpp.dynamicLibrarySuffix) fileTags: ["dynamiclibrary"] filesAreTargets: true } Group { name: "thelib dll import" condition: qbs.targetOS.includes("windows") files: FileInfo.joinPaths(product.thelib.baseDir, "thelib.lib") fileTags: ["dynamiclibrary_import"] filesAreTargets: true } Group { name: "to be ignored" filesAreTargets: true files: "broken.cpp" fileTags: ["cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/modules/thelib/broken.cpp0000644000175100001660000000001514776170045032034 0ustar runnerdockersyntax error qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-library-in-module/Dll.qbs0000644000175100001660000000062014776170045026355 0ustar runnerdockerDynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle"; condition: qbs.targetOS.includes("darwin") } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false cpp.minimumMacosVersion: "10.7" // For -rpath } install: true installImportLib: true qbs.installPrefix: "" installDir: "" importLibInstallDir: "" } qbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/0000755000175100001660000000000014776170045023136 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/my static lib helper.cpp0000644000175100001660000000240614776170045027530 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int helper_function() { return 156; } qbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/some helper/0000755000175100001660000000000014776170045025341 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/some helper/some helper.cpp0000644000175100001660000000243614776170045030255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "some helper.h" int getSomeNumber() { return 156; } qbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/some helper/some helper.h0000644000175100001660000000244314776170045027720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HELPER_H #define HELPER_H extern int getSomeNumber(); #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/proper quoting.qbs0000644000175100001660000000233114776170045026622 0ustar runnerdockerimport qbs.Host Project { Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } type: "application" consoleApplication: true name: "Hello World" files : [ "main.cpp" ] Depends { name: "cpp" } Depends { name: "my static lib" } cpp.defines: [ 'DEFINE="whitespaceless"', 'DEFINEWITHSPACE="contains space"', 'DEFINEWITHTAB="contains\ttab"', 'DEFINEWITHBACKSLASH="backslash\\\\"', ] } Product { type: "staticlibrary" name : "my static lib" files : [ "my static lib.cpp" ] Depends { name: "cpp" } Depends { name: "helper lib" } } Product { type: "staticlibrary" name : "helper lib" files : [ "some helper/some helper.h", "some helper/some helper.cpp" ] Depends { name: "cpp" } Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory + '/some helper'] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/my static lib.cpp0000644000175100001660000000257514776170045026277 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int bla() { int n = getSomeNumber(); std::printf("Hello World! The magic number is %d.", n); return n; } qbs-src-2.6.1/tests/auto/blackbox/testdata/proper quoting/main.cpp0000644000175100001660000000265514776170045024576 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int bla(); int main() { std::printf(DEFINE"\n"); std::printf(DEFINEWITHSPACE"\n"); std::printf(DEFINEWITHTAB"\n"); std::printf(DEFINEWITHBACKSLASH"\n"); return bla(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/0000755000175100001660000000000014776170045025673 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.q0000644000175100001660000000206514776170045033573 0ustar runnerdockerProject { qbsSearchPaths: [ path ] Product { name: "mylib" Export { Depends { name: "top" } top.productInExport: exportingProduct.name } } Product { type: "rule-output" name: "myapp" Depends { name: "mylib" } Rule { alwaysRun: true multiplex: true requiresInputs: false outputFileTags: "rule-output" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info("base.productInBase evaluated in: " + product.base.productInBase); console.info("base.productInTop evaluated in: " + product.base.productInTop); console.info("top.productInExport evaluated in: " + product.top.productInExport); console.info("top.productInTop evaluated in: " + product.top.productInTop); } return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/modules/0000755000175100001660000000000014776170045027343 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/0000755000175100001660000000000014776170045030145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs0000644000175100001660000000024314776170045031455 0ustar runnerdockerModule { Depends { name: "base" } base.productInTop: product.name property string productInTop: product.name property string productInExport: "" } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/0000755000175100001660000000000014776170045030255 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs0000644000175100001660000000014014776170045031671 0ustar runnerdockerModule { property string productInBase: product.name property string productInTop: "" } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/0000755000175100001660000000000014776170045023054 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/linkerscript20000644000175100001660000000002214776170045025564 0ustar runnerdockerTEST_SYMBOL2 = 1; qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/linkerscript10000644000175100001660000000002214776170045025563 0ustar runnerdockerTEST_SYMBOL1 = 0; qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/testlib.c0000644000175100001660000000235314776170045024671 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void dummy() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs0000644000175100001660000000374614776170045026471 0ustar runnerdockerimport qbs.TextFile DynamicLibrary { type: base.concat("custom") Depends { name: "cpp" } files: ["testlib.c"] Group { name: "linker scripts" files: [ "linkerscript1", "linkerscript2", ] fileTags: ["linkerscript"] } cpp.libraryPaths: [ product.sourceDirectory, // location of linkerscripts that are included ] Rule { multiplex: true outputFileTags: "custom" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.warn("---" + product.cpp.nmPath + "---"); } return [cmd]; } } Rule { multiplex: true requiresInputs: false Artifact { filePath: product.buildDirectory + "/linkerscript_with_includes" fileTags: ["linkerscript"] } prepare: { var cmd = new JavaScriptCommand(); cmd.sourcePath = product.sourceDirectory; cmd.buildPath = product.buildDirectory; cmd.sourceCode = function() { var file = new TextFile(buildPath + "/linkerscript_with_includes", TextFile.WriteOnly); file.write("SEARCH_DIR(\"" + sourcePath + "/scripts\")\n" + "INCLUDE linkerscript_to_include\n" + "INCLUDE linkerscript_in_directory\n"); file.close(); } cmd.highlight = "codegen"; cmd.description = "generating linkerscript with SEARCH_DIR and INCLUDE"; return [cmd]; } } Probe { id: checker property bool isGcc: qbs.toolchain.contains("gcc") property bool isLinux: qbs.targetOS.contains("linux") configure: { console.info("is Linux gcc: " + (isGcc && isLinux)) } } qbs.installPrefix: "" install: true installDir: "" } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/scripts/0000755000175100001660000000000014776170045024543 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/scripts/linkerscript_in_directory0000644000175100001660000000004014776170045031743 0ustar runnerdockerTEST_SYMBOL_FROM_DIRECTORY = 1; qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/linkerscript_to_include0000644000175100001660000000007514776170045027717 0ustar runnerdockerTEST_SYMBOL_FROM_INCLUDE = 1; INCLUDE linkerscript_recursive qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerscripts/linkerscript_recursive0000644000175100001660000000004014776170045027571 0ustar runnerdockerTEST_SYMBOL_FROM_RECURSIVE = 1; qbs-src-2.6.1/tests/auto/blackbox/testdata/require/0000755000175100001660000000000014776170045021634 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/require/zort.js0000644000175100001660000000044714776170045023175 0ustar runnerdockervar File = require("qbs.File") function createCommand(filePaths) { var cmd = new JavaScriptCommand(); cmd.description = "Create another empty file"; cmd.filePaths = filePaths; cmd.sourceCode = function() { File.copy(filePaths[0], filePaths[1]); }; return cmd; } qbs-src-2.6.1/tests/auto/blackbox/testdata/require/require.qbs0000644000175100001660000000071614776170045024023 0ustar runnerdockerimport 'blubb.js' as blubb Product { type: ["text"] Rule { multiplex: true Artifact { fileTags: ["text"] filePath: "one.txt" } Artifact { fileTags: ["text"] filePath: "two.txt" } prepare: { var filePaths = outputs.text.map(function (artifact) {return artifact.filePath; }); return blubb.createCommands(filePaths); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/require/blubb.js0000644000175100001660000000061414776170045023261 0ustar runnerdockervar TextFile = require("qbs.TextFile") var zort = require("./zort.js") function createCommands(filePaths) { var cmd = new JavaScriptCommand(); cmd.description = "Write an empty file"; cmd.filePath = filePaths[0]; cmd.sourceCode = function() { var f = new TextFile(filePath, TextFile.WriteOnly); f.close(); } return [cmd, zort.createCommand(filePaths)]; } qbs-src-2.6.1/tests/auto/blackbox/testdata/check-timestamps/0000755000175100001660000000000014776170045023421 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/check-timestamps/file.cpp0000644000175100001660000000004014776170045025036 0ustar runnerdocker#include "file.h" void f() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/check-timestamps/file.h0000644000175100001660000000001214776170045024502 0ustar runnerdockervoid f(); qbs-src-2.6.1/tests/auto/blackbox/testdata/check-timestamps/main.cpp0000644000175100001660000000001614776170045025046 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/check-timestamps/check-timestamps.qbs0000644000175100001660000000016014776170045027366 0ustar runnerdockerCppApplication { name: "app" files: [ "file.cpp", "file.h", "main.cpp", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-no-inputs/0000755000175100001660000000000014776170045024032 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-no-inputs/rule-with-no-inputs.qbs0000644000175100001660000000127614776170045030421 0ustar runnerdockerimport qbs.TextFile Product { name: "theProduct" type: ["output"] version: "1" property bool dummy: false Rule { inputs: [] multiplex: true Artifact { filePath: "output.out" fileTags: ["output"] } prepare: { console.info("running the rule: " + product.dummy); var cmd = new JavaScriptCommand(); cmd.description = "creating output"; cmd.sourceCode = function() { console.info(product.version); var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/env-merging/0000755000175100001660000000000014776170045022376 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/env-merging/env-merging.qbs0000644000175100001660000000137314776170045025327 0ustar runnerdockerimport qbs.Host Project { CppApplication { name: "tool" files: "main.c" } Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "p" type: "custom" Depends { name: "tool" } Rule { inputsFromDependencies: "application" outputFileTags: "custom" prepare: { var cmd = new Command(input.filePath, []); cmd.description = "running tool"; cmd.environment = ["PATH=/opt/tool/bin"]; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/env-merging/main.c0000644000175100001660000000015414776170045023466 0ustar runnerdocker#include #include int main() { printf("PATH=%s", getenv("PATH")); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/per-group-define-in-export-item/0000755000175100001660000000000014776170045026207 5ustar runnerdocker././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/per-group-define-in-export-item/per-group-define-in-export-item.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/per-group-define-in-export-item/per-group-define-in-expor0000644000175100001660000000045314776170045033043 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "cpp" } Group { cpp.defines: ["MAIN"] files: ["main.cpp"] } } } Application { name: "app" Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/per-group-define-in-export-item/main.cpp0000644000175100001660000000004114776170045027632 0ustar runnerdocker#ifdef MAIN int main() {} #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/0000755000175100001660000000000014776170045023761 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir2/0000755000175100001660000000000014776170045024621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir2/file1.txt0000644000175100001660000000001314776170045026354 0ustar runnerdockerdir2/file1 qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir2/file3.txt0000644000175100001660000000001314776170045026356 0ustar runnerdockerdir2/file3 qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir2/file2.txt0000644000175100001660000000001314776170045026355 0ustar runnerdockerdir2/file2 qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/install-duplicates.qbs0000644000175100001660000000020714776170045030270 0ustar runnerdockerProduct { Group { files: ["*.txt"] prefix: "**/" qbs.install: true qbs.installDir: "files" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir1/0000755000175100001660000000000014776170045024620 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir1/file1.txt0000644000175100001660000000001314776170045026353 0ustar runnerdockerdir1/file1 qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates/dir1/file2.txt0000644000175100001660000000001314776170045026354 0ustar runnerdockerdir1/file2 qbs-src-2.6.1/tests/auto/blackbox/testdata/output-redirection/0000755000175100001660000000000014776170045024025 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/output-redirection/output.txt0000644000175100001660000000006414776170045026126 0ustar runnerdockerthis is a plain text file this is a plain text file qbs-src-2.6.1/tests/auto/blackbox/testdata/output-redirection/output-redirection.qbs0000644000175100001660000000177714776170045030415 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Product { name: "the-product" type: "output" Group { files: "input.bin" fileTags: "binary" } Group { files: "input.txt" fileTags: "text" } Rule { inputs: ["text", "binary"] Artifact { filePath: "output." + FileInfo.completeSuffix(input.filePath) fileTags: "output" } prepare: { var binary; var prefixArgs; if (Host.os().includes("windows")) { binary = product.qbs.windowsShellPath; prefixArgs = ["/c", "type"]; } else { binary = "cat"; prefixArgs = []; } var inputPath = FileInfo.toNativeSeparators(input.filePath); var cmd = new Command(binary, prefixArgs.concat([inputPath, inputPath])); cmd.stdoutFilePath = output.filePath; cmd.highlight = "filegen"; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/output-redirection/output.bin0000644000175100001660000000400014776170045026051 0ustar runnerdockerѸvʷR'.wl >}䋂b-(OOt:e"lhėʉO*d4ќih{*͎OZӮ ;oXUlXvҁiSH+,Ģj2@dq*:gwϰ:;[KΕRV2xȊ4{xǻIGD~fsT6ma엝 cy}@9l0k/ƌnn]MxmMd8f}KJ7Dg䃟'NʠH}{ʳO|lCˡQnff] o aF}s-{$˵z2{tmT7WC) t-߈`FY`"a;cGEa^}rk\en[sƎH-zT)o4l\oUWB tOx7RR{\ZQ%jīc 垽l+v x^=PC_<';?쩭iY}]U9}.ҪYr&gxł#r/  }xzhsds-v%>[]knt5pM?a3d)Srs uxf)?kmK^pXƀ",~ Hк<YXJAx3ސ',1ﳙ6rt@`Ǧń£]I80tJsvH@puDvC`@JOh ڦdIR/t t]QJb@/rPUIpVz26ξ"Ėϴ!ëZ'xnI.H5'w/Ci\ -. @h?ٛ)Z+ÈsC2j0.8,ѸvʷR'.wl >}䋂b-(OOt:e"lhėʉO*d4ќih{*͎OZӮ ;oXUlXvҁiSH+,Ģj2@dq*:gwϰ:;[KΕRV2xȊ4{xǻIGD~fsT6ma엝 cy}@9l0k/ƌnn]MxmMd8f}KJ7Dg䃟'NʠH}{ʳO|lCˡQnff] o aF}s-{$˵z2{tmT7WC) t-߈`FY`"a;cGEa^}rk\en[sƎH-zT)o4l\oUWB tOx7RR{\ZQ%jīc 垽l+v x^=PC_<';?쩭iY}]U9}.ҪYr&gxł#r/  }xzhsds-v%>[]knt5pM?a3d)Srs uxf)?kmK^pXƀ",~ Hк<YXJAx3ސ',1ﳙ6rt@`Ǧń£]I80tJsvH@puDvC`@JOh ڦdIR/t t]QJb@/rPUIpVz26ξ"Ėϴ!ëZ'xnI.H5'w/Ci\ -. @h?ٛ)Z+ÈsC2j0.8,qbs-src-2.6.1/tests/auto/blackbox/testdata/output-redirection/input.txt0000644000175100001660000000003214776170045025720 0ustar runnerdockerthis is a plain text file qbs-src-2.6.1/tests/auto/blackbox/testdata/output-redirection/input.bin0000644000175100001660000000200014776170045025646 0ustar runnerdockerѸvʷR'.wl >}䋂b-(OOt:e"lhėʉO*d4ќih{*͎OZӮ ;oXUlXvҁiSH+,Ģj2@dq*:gwϰ:;[KΕRV2xȊ4{xǻIGD~fsT6ma엝 cy}@9l0k/ƌnn]MxmMd8f}KJ7Dg䃟'NʠH}{ʳO|lCˡQnff] o aF}s-{$˵z2{tmT7WC) t-߈`FY`"a;cGEa^}rk\en[sƎH-zT)o4l\oUWB tOx7RR{\ZQ%jīc 垽l+v x^=PC_<';?쩭iY}]U9}.ҪYr&gxł#r/  }xzhsds-v%>[]knt5pM?a3d)Srs uxf)?kmK^pXƀ",~ Hк<YXJAx3ސ',1ﳙ6rt@`Ǧń£]I80tJsvH@puDvC`@JOh ڦdIR/t t]QJb@/rPUIpVz26ξ"Ėϴ!ëZ'xnI.H5'w/Ci\ -. @h?ٛ)Z+ÈsC2j0.8,qbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/0000755000175100001660000000000014776170045023161 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/foo.narf0000644000175100001660000000000014776170045024602 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/ruleConditions.qbs0000644000175100001660000000043314776170045026671 0ustar runnerdockerProduct { type: ["application", "zort"] consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "cpp" } Depends { name: "narfzort" } files: [ "main.cpp", "foo.narf" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/main.cpp0000644000175100001660000000236414776170045024616 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/modules/0000755000175100001660000000000014776170045024631 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/modules/narfzort/0000755000175100001660000000000014776170045026476 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ruleConditions/modules/narfzort/narfzort.qbs0000644000175100001660000000203514776170045031052 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Module { property bool enableGroup property bool enableRule property bool enableTagger Group { condition: enableGroup FileTagger { condition: module.enableTagger patterns: "*.narf" fileTags: ["narf"] } Rule { condition: module.enableRule inputs: ["narf"] outputFileTags: ["zort"] outputArtifacts: [{ filePath: product.name + "." + input.fileName + ".zort", fileTags: ["zort"] }] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + FileInfo.fileName(output.filePath); cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("NARF! ZORT!"); f.close(); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/0000755000175100001660000000000014776170045024406 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/fakewindows.qbs0000644000175100001660000000072514776170045027442 0ustar runnerdockerimport qbs.Utilities // non-existent versions of Windows should print a QBS warning // (but will still compile and link since we avoid passing a // bad value to the linker) CppApplication { condition: qbs.targetOS.includes("windows") files: ["main.cpp"] consoleApplication: true cpp.minimumWindowsVersion: "5.3" cpp.defines: [ "QBS_WINVER=0x503", "TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath) ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/main.mm0000644000175100001660000000575214776170045025676 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #import int main() { // This gets set by -mmacosx-version-min. If left undefined, defaults to the current OS version. std::cout << "__MAC_OS_X_VERSION_MIN_REQUIRED=" << __MAC_OS_X_VERSION_MIN_REQUIRED << std::endl; bool print = false; NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:@"/usr/bin/otool"]; [task setArguments:[NSArray arrayWithObjects:@"-l", [[[NSProcessInfo processInfo] arguments] firstObject], nil]]; NSPipe *pipe = [NSPipe pipe]; [task setStandardOutput:pipe]; [task launch]; NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile]; [task waitUntilExit]; NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSString *line; NSEnumerator *enumerator = [[result componentsSeparatedByString:@"\n"] objectEnumerator]; while ((line = [enumerator nextObject]) != nil) { if ([line rangeOfString:@"LC_VERSION_MIN_MACOSX"].location != NSNotFound) print = true; if (print && [line rangeOfString:@"version"].location != NSNotFound) { std::cout << [[line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] UTF8String] << std::endl; print = false; continue; } #ifdef __clang__ #if __clang_major__ >= 10 && __clang_minor__ >= 0 if ([line rangeOfString:@"LC_BUILD_VERSION"].location != NSNotFound) print = true; if (print && [line rangeOfString:@"minos"].location != NSNotFound) { std::cout << [[line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] UTF8String] << std::endl; print = false; } #endif #endif // __clang__ } } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified.qbs0000644000175100001660000000131514776170045027413 0ustar runnerdockerimport qbs.Utilities // no minimum versions are specified so the profile defaults will be used import qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } files: [qbs.targetOS.includes("darwin") ? "main.mm" : "main.cpp"] consoleApplication: true Properties { condition: qbs.targetOS.includes("windows") cpp.defines: ["TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath)] } Properties { condition: qbs.targetOS.includes("darwin") cpp.frameworks: "Foundation" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/specific.qbs0000644000175100001660000000175114776170045026706 0ustar runnerdockerimport qbs.Utilities // a specific version of the operating systems is specified // when the application is run its output should confirm // that the given values took effect import qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && qbs.targetOS.includes("windows") || qbs.targetOS.includes("macos"); } files: [qbs.targetOS.includes("darwin") ? "main.mm" : "main.cpp"] consoleApplication: true Properties { condition: qbs.targetOS.includes("windows") cpp.minimumWindowsVersion: "6.2" cpp.defines: [ "QBS_WINVER=0x602", "TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath) ] } Properties { condition: qbs.targetOS.includes("macos") cpp.frameworks: "Foundation" cpp.minimumMacosVersion: "10.7" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/unspecified-forced.qbs0000644000175100001660000000161114776170045030652 0ustar runnerdockerimport qbs.Utilities // no minimum versions are specified, and explicitly set to undefined in // case the profile has set it import qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } files: [qbs.targetOS.includes("darwin") ? "main.mm" : "main.cpp"] consoleApplication: true cpp.minimumWindowsVersion: undefined cpp.minimumMacosVersion: undefined cpp.minimumIosVersion: undefined cpp.minimumAndroidVersion: undefined Properties { condition: qbs.targetOS.includes("windows") cpp.defines: ["TOOLCHAIN_INSTALL_PATH=" + Utilities.cStringQuote(cpp.toolchainInstallPath)] } Properties { condition: qbs.targetOS.includes("darwin") cpp.frameworks: "Foundation" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/main.cpp0000644000175100001660000000711614776170045026043 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef _WIN32 #include #include #include #include #include #include #include #endif int main(int argc, char *argv[]) { if (argc != 1) return 1; #ifdef _WIN32 #if defined(__clang__) std::cout << "Unsupported compiler" << std::endl; return 0; #endif #if defined(WINVER) && defined(QBS_WINVER) std::cout << "WINVER=" << WINVER << std::endl; std::string command = TOOLCHAIN_INSTALL_PATH; std::replace(command.begin(), command.end(), '/', '\\'); command = "\"\"" + command; #ifdef __GNUC__ command += "\\objdump.exe\" -p \""; #else command += "\\dumpbin.exe\" /HEADERS \""; #endif command += argv[0]; command += "\" > qbs-test-dumpbin.txt\""; int status = ::system(command.c_str()); if (status != 0) return status; std::ifstream in("qbs-test-dumpbin.txt"); std::string s; while (std::getline(in, s)) { #ifdef __GNUC__ static const char *majorOSystemVersion = "MajorOSystemVersion\t"; if (s.find(majorOSystemVersion) != std::string::npos) std::cout << s.substr(std::strlen(majorOSystemVersion)); static const char *minorOSystemVersion = "MinorOSystemVersion\t"; if (s.find(minorOSystemVersion) != std::string::npos) std::cout << ".0" << s.substr(std::strlen(minorOSystemVersion)) << " operating system version" << std::endl; static const char *majorSubsystemVersion = "MajorSubsystemVersion\t"; if (s.find(majorSubsystemVersion) != std::string::npos) std::cout << s.substr(std::strlen(majorSubsystemVersion)); static const char *minorSubsystemVersion = "MinorSubsystemVersion\t"; if (s.find(minorSubsystemVersion) != std::string::npos) std::cout << ".0" << s.substr(std::strlen(minorSubsystemVersion)) << " subsystem version" << std::endl; #else if (s.find("operating system version") != std::string::npos || s.find("subsystem version") != std::string::npos) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); std::cout << s << std::endl; } #endif } unlink("qbs-test-dumpbin.txt"); #else std::cout << "WINVER is not defined" << std::endl; #endif #endif return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/minimumSystemVersion/macappstore.qbs0000644000175100001660000000112214776170045027427 0ustar runnerdocker// just to make sure three-digit minimum versions work on macOS // this only affects the value of __MAC_OS_X_VERSION_MIN_REQUIRED, // not the actual LC_VERSION_MIN_MACOSX command which is limited to two import qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && qbs.targetOS.includes("macos"); } files: ["main.mm"] consoleApplication: true cpp.frameworks: "Foundation" cpp.minimumMacosVersion: "10.7.1" } qbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/0000755000175100001660000000000014776170045024661 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/source-artifact-changes.qbs0000644000175100001660000000305114776170045032070 0ustar runnerdockerCppApplication { name: "app" type: base.concat("dummy") consoleApplication: true Properties { condition: qbs.targetOS.includes("darwin") bundle.embedInfoPlist: false } Probe { id: toolchainProbe property stringList toolchain: qbs.toolchain property string executableSuffix: cpp.executableSuffix configure: { console.info("is gcc: " + toolchain.includes("gcc")); console.info("executable suffix: " + executableSuffix); found = true; } } Rule { multiplex: true inputs: "cpp" Artifact { filePath: "dummy" fileTags: "dummy" cpp.cxxLanguageVersion: "hoppla" } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { if (output.cpp.cxxLanguageVersion !== "hoppla") throw "This cannot be!"; }; return cmd; } } Rule { multiplex: true inputs: "cpp" requiresInputs: false Artifact { filePath: "dummy2"; fileTags: "dummy" } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info("cpp artifacts: " + (product.artifacts.cpp ? product.artifacts.cpp.length : 0)) }; return cmd; } } Depends { name: "module_with_files" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/modules/0000755000175100001660000000000014776170045026331 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/modules/module_with_files/0000755000175100001660000000000014776170045032033 5ustar runnerdocker././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/modules/module_with_files/main.cppqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/modules/module_with_files/main.cp0000644000175100001660000000001614776170045033300 0ustar runnerdockerint main() {} ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/modules/module_with_files/module_with_files.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-changes/modules/module_with_files/module_0000644000175100001660000000060714776170045033405 0ustar runnerdockerModule { property stringList fileTags property bool overrideTags property bool filesAreTargets Depends { name: "cpp" } Group { prefix: path + '/' files: "main.cpp" fileTags: product.module_with_files.fileTags overrideTags: product.module_with_files.overrideTags filesAreTargets: product.module_with_files.filesAreTargets } } qbs-src-2.6.1/tests/auto/blackbox/testdata/clean/0000755000175100001660000000000014776170045021242 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/clean/clean.qbs0000644000175100001660000000123014776170045023027 0ustar runnerdockerProject { DynamicLibrary { Depends { name: "cpp" } version: "1.1.0" name: "dep" files: "dep.cpp" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } CppApplication { consoleApplication: true name: "app" property bool dummy: { console.info("object suffix: " + cpp.objectSuffix); console.info("executable suffix: " + cpp.executableSuffix); console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } Depends { name: "dep" } files: "main.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/clean/main.cpp0000644000175100001660000000235214776170045022674 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/clean/dep.cpp0000644000175100001660000000241514776170045022520 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" DLL_EXPORT void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/0000755000175100001660000000000014776170045023213 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/file.c0000644000175100001660000000002414776170045024272 0ustar runnerdockervoid func(void) { } qbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/subdir/0000755000175100001660000000000014776170045024503 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/subdir/theheader.h0000644000175100001660000000000014776170045026573 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs0000644000175100001660000000052314776170045026755 0ustar runnerdockerCppApplication { Probe { id: dummy property stringList toolchain: qbs.toolchain configure: { if (toolchain.includes("msvc")) console.info("msvc"); } } files: [ "file.c", "main.cpp", "subdir/theheader.h", "subdir2/theheader.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/main.cpp0000644000175100001660000000004614776170045024643 0ustar runnerdocker#include int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/subdir2/0000755000175100001660000000000014776170045024565 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/buildenv-change/subdir2/theheader.h0000644000175100001660000000000014776170045026655 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linker-module-definition/0000755000175100001660000000000014776170045025055 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linker-module-definition/testlib.def0000644000175100001660000000002014776170045027173 0ustar runnerdockerEXPORTS foo bar qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp0000644000175100001660000000312714776170045027244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ extern void foo(); extern void bar(); int main() { foo(); bar(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp0000644000175100001660000000314314776170045027230 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include void foo() { std::printf("foo\n"); } void bar() { std::printf("bar\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs0000644000175100001660000000073014776170045032461 0ustar runnerdockerimport qbs.Host Project { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } DynamicLibrary { name: "testlib" Depends { name: "cpp"} files: ["testlib.cpp", "testlib.def"] } CppApplication { name: "testapp" Depends { name: "testlib"} files: ["testapp.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/group-condition-change/0000755000175100001660000000000014776170045024523 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/group-condition-change/input_kaputt.txt0000644000175100001660000000000014776170045030001 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/group-condition-change/group-condition-change.qbs0000644000175100001660000000113114776170045031571 0ustar runnerdockerProject { property bool kaputt: true Product { type: ["kaputt"] Group { name: "kaputt" condition: project.kaputt files: "input_kaputt.txt" fileTags: "input.kaputt" } Rule { inputs: "input.kaputt" Artifact { filePath: "output.kaputt" fileTags: "kaputt" } prepare: { var cmd = new Command("jibbetnich", [output.filePath]); cmd.silent = true; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/toplevel-searchpath/0000755000175100001660000000000014776170045024132 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/toplevel-searchpath/toplevel-searchpath.qbs0000644000175100001660000000001614776170045030610 0ustar runnerdockerMyProduct { } qbs-src-2.6.1/tests/auto/blackbox/testdata/toplevel-searchpath/qbs-resources/0000755000175100001660000000000014776170045026727 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/toplevel-searchpath/qbs-resources/imports/0000755000175100001660000000000014776170045030424 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/toplevel-searchpath/qbs-resources/imports/MyProduct.qbs0000644000175100001660000000001414776170045033054 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/blackbox/testdata/versionscript/0000755000175100001660000000000014776170045023072 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/versionscript/versionscript.qbs0000644000175100001660000000152714776170045026520 0ustar runnerdockerDynamicLibrary { type: base.concat("custom") Depends { name: "cpp" } files: ["testlib.c"] Group { name: "version script" files: ["versionscript"] fileTags: ["versionscript"] } Rule { multiplex: true outputFileTags: "custom" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.warn("---" + product.cpp.nmPath + "---"); } return [cmd]; } } Probe { id: checker property bool isLinux: qbs.targetOS.includes("linux") property bool isGcc: qbs.toolchain.contains("gcc") configure: { console.info("is gcc for Linux: " + (isLinux && isGcc)); } } qbs.installPrefix: "" install: true installDir: "" } qbs-src-2.6.1/tests/auto/blackbox/testdata/versionscript/versionscript0000644000175100001660000000005514776170045025727 0ustar runnerdocker{ global: dummyGlobal; local: dummyLocal; }; qbs-src-2.6.1/tests/auto/blackbox/testdata/versionscript/testlib.c0000644000175100001660000000240614776170045024706 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void dummyLocal() {} void dummyGlobal() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/probeProperties/0000755000175100001660000000000014776170045023344 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probeProperties/main.c0000644000175100001660000000236414776170045024441 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs0000644000175100001660000000213514776170045027240 0ustar runnerdockerimport qbs.Probes Project { CppApplication { Probes.PathProbe { id: probe1 names: ["bin/tool"] platformSearchPaths: [product.sourceDirectory] } Probes.PathProbe { id: probe2 names: ["tool"] platformSearchPaths: [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); console.info("probe3.fileName=" + probe3.fileName); console.info("probe3.path=" + probe3.path); console.info("probe3.filePath=" + probe3.filePath); return name; } } Probes.PathProbe { id: probe3 names: ["tool"] platformSearchPaths: [project.sourceDirectory + "/bin"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probeProperties/bin/0000755000175100001660000000000014776170045024114 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probeProperties/bin/tool0000644000175100001660000000000014776170045025002 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-dependency/0000755000175100001660000000000014776170045023745 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-dependency/missing-dependency.qbs0000644000175100001660000000136614776170045030247 0ustar runnerdockerimport qbs.TextFile Project { Product { name: "theDep" type: ["genheader"] Rule { multiplex: true Artifact { filePath: project.buildDirectory + "/theHeader.h" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return [cmd]; } } } CppApplication { name: "theApp" cpp.includePaths: [project.buildDirectory] files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/missing-dependency/main.cpp0000644000175100001660000000240214776170045025373 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/aux-inputs-from-deps/0000755000175100001660000000000014776170045024167 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/aux-inputs-from-deps/util.js0000644000175100001660000000025114776170045025500 0ustar runnerdockerfunction sleep(timeInMs) { var referenceTime = new Date(); var time = null; do { time = new Date(); } while (time - referenceTime < timeInMs); } qbs-src-2.6.1/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs0000644000175100001660000000424614776170045030713 0ustar runnerdockerimport qbs.File import qbs.TextFile import "util.js" as Utils Project { CppApplication { name: "app" files: ["main.cpp"] Depends { name: "dep" } } Product { name: "p" type: ["p.out"] Depends { name: "dep" } Rule { multiplex: true explicitlyDependsOnFromDependencies: ["hpp"] Artifact { filePath: "dummy.out" fileTags: ["p.out"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating dummy.out"; cmd.sourceCode = function() { File.copy(project.buildDirectory + "/dummy.h", output.filePath); }; return [cmd]; } } } Product { name: "dep" type: ["hpp"] property bool sleep: true Rule { inputs: ["blubb.in"] Artifact { filePath: project.buildDirectory + "/dummy.h" fileTags: ["hpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating header"; cmd.sourceCode = function() { if (product.sleep) Utils.sleep(1000); File.copy(input.filePath, output.filePath); } return [cmd]; } } Rule { multiplex: true Artifact { filePath: "dummy.blubb" fileTags: ["blubb.in"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating blubb.in"; cmd.sourceCode = function() { if (product.sleep) Utils.sleep(1000); var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return [cmd]; } } Export { Depends { name: "cpp" } cpp.includePaths: [project.buildDirectory] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/aux-inputs-from-deps/main.cpp0000644000175100001660000000004314776170045025614 0ustar runnerdocker#include int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/0000755000175100001660000000000014776170045023311 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/dummy1/0000755000175100001660000000000014776170045024525 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/dummy1/dummy1.pc0000644000175100001660000000014614776170045026266 0ustar runnerdockerName: dummy1 Description: dummy1 package Version: 0.0.1 Requires: Libs: -Ldummydir1 -ldummy1 Cflags: qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/dummy2/0000755000175100001660000000000014776170045024526 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/dummy2/dummy2.pc0000644000175100001660000000014614776170045026270 0ustar runnerdockerName: dummy2 Description: dummy2 package Version: 0.0.2 Requires: Libs: -Ldummydir2 -ldummy2 Cflags: qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/pkg-config.qbs0000644000175100001660000000074414776170045026051 0ustar runnerdockerProject { property string packageBaseName Product { name: "theProduct1" type: ["theType"] Depends { name: "themodule" } themodule.packageName: project.packageBaseName + "1" themodule.libDir: path + "/dummy1" } Product { name: "theProduct2" type: ["theType"] Depends { name: "themodule" } themodule.packageName: project.packageBaseName + "2" themodule.libDir: path + "/dummy2" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/modules/0000755000175100001660000000000014776170045024761 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/modules/themodule/0000755000175100001660000000000014776170045026747 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe/modules/themodule/themodule.qbs0000644000175100001660000000202114776170045031437 0ustar runnerdockerimport qbs.Probes Module { property string packageName property string libDir Probes.PkgConfigProbe { id: theProbe name: packageName libDirs: [libDir] } property bool probeSuccess: theProbe.found property stringList libs: theProbe.libs property stringList cFlags: theProbe.cflags property string packageVersion: theProbe.modversion Rule { multiplex: true outputFileTags: "theType" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info(product.name + " found: " + product.themodule.probeSuccess); console.info(product.name + " libs: " + JSON.stringify(product.themodule.libs)); console.info(product.name + " cflags: " + JSON.stringify(product.themodule.cFlags)); console.info(product.name + " version: " + product.themodule.packageVersion); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/0000755000175100001660000000000014776170045024212 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/project-dir/0000755000175100001660000000000014776170045026434 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/project-dir/file.cpp0000644000175100001660000000001514776170045030053 0ustar runnerdockervoid f() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/project-dir/main.cpp0000644000175100001660000000001614776170045030061 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/project-dir/missing-project-file.qbs0000644000175100001660000000011514776170045033172 0ustar runnerdockerCppApplication { files: [ "file.cpp", "main.cpp" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/empty-dir/0000755000175100001660000000000014776170045026124 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/empty-dir/irrelevant.txt0000644000175100001660000000000014776170045031026 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/0000755000175100001660000000000014776170045026761 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p2.qbs0000644000175100001660000000000014776170045027777 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p1.qbs0000644000175100001660000000000014776170045027776 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p3.qbs0000644000175100001660000000000014776170045030000 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/project_filepath_check/0000755000175100001660000000000014776170045024637 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/project_filepath_check/project1.qbs0000644000175100001660000000005114776170045027071 0ustar runnerdockerCppApplication { files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/project_filepath_check/main2.cpp0000644000175100001660000000001614776170045026346 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/project_filepath_check/main.cpp0000644000175100001660000000235114776170045026270 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/project_filepath_check/project2.qbs0000644000175100001660000000005214776170045027073 0ustar runnerdockerCppApplication { files: "main2.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/rescue-transformer-data/0000755000175100001660000000000014776170045024715 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rescue-transformer-data/transformer-data-rescue.qbs0000644000175100001660000000014414776170045032160 0ustar runnerdockerCppApplication { type: base.concat(["out"]) Depends { name: "m" } files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/rescue-transformer-data/main.cpp0000644000175100001660000000001614776170045026342 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/rescue-transformer-data/modules/0000755000175100001660000000000014776170045026365 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rescue-transformer-data/modules/m/0000755000175100001660000000000014776170045026621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rescue-transformer-data/modules/m/m.qbs0000644000175100001660000000064614776170045027572 0ustar runnerdockerModule { property bool p Rule { multiplex: true Artifact { filePath: "dummy" fileTags: ["out"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating dummy"; cmd.sourceCode = function() { console.info("m.p: " + product.m.p); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/filetagsfilter-merging/0000755000175100001660000000000014776170045024612 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/filetagsfilter-merging/filetagsfilter-merging.qbs0000644000175100001660000000144514776170045031757 0ustar runnerdockerimport qbs.TextFile MyApplication { name: "myapp" type: base.concat("extra-output") property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: "main.cpp" Group { fileTagsFilter: "application" qbs.installDir: "binDir" fileTags: "extra-input" } Rule { inputs: "extra-input" Artifact { filePath: input.baseName + ".txt" fileTags: "extra-output" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/filetagsfilter-merging/MyApplication.qbs0000644000175100001660000000031114776170045030065 0ustar runnerdockerCppApplication { consoleApplication: true Group { fileTagsFilter: "application" qbs.install:true qbs.installPrefix: product.name qbs.installDir: "wrong" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/filetagsfilter-merging/main.cpp0000644000175100001660000000001614776170045026237 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-artifact-path/0000755000175100001660000000000014776170045024333 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-artifact-path/invalid-artifact-path.qbs0000644000175100001660000000065214776170045031220 0ustar runnerdockerProject { property string artifactDir Product { type: "t" Rule { multiplex: true Artifact { filePath: project.artifactDir + "/file.out" fileTags: "t" } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = function() {}; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/0000755000175100001660000000000014776170045024400 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/explicitly-depends-on.qbs0000644000175100001660000000675514776170045031344 0ustar runnerdockerimport qbs.File import qbs.TextFile Project { // Cases: // step1 + in-product final -> step2 -> step3 -> final => rule cycle // step1 + dependency final -> step2 -> step3 -> final => ok // step1 + module filesAreTargets final -> step2 -> step3 -> final => ok name: "proj1" property bool useModule: false Product { name: "prod1" type: "final" property bool useExplicitlyDependsOn: false property bool useExplicitlyDependsOnFromDependencies: false Depends { condition: !project.useModule name: "prod2" } Depends { condition: project.useModule name: "module1" } Group { files: ["step1.txt"] fileTags: ["step1"] } Rule { inputs: ["step3"] outputFileTags: ["final"] Artifact { filePath: "final.txt" fileTags: ["final"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "step3 -> final"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } Rule { inputs: ["step2"] outputFileTags: ["step3"] Artifact { filePath: "step3.txt" fileTags: ["step3"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "step2 -> step3"; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } Rule { inputs: ["step1"] outputFileTags: ["step2"] Artifact { filePath: "step2.txt" fileTags: ["step2"] } Properties { condition: useExplicitlyDependsOn explicitlyDependsOn: ["final"] } Properties { condition: useExplicitlyDependsOnFromDependencies explicitlyDependsOnFromDependencies: ["final"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "step1 -> step2"; cmd.sourceCode = function() { console.info("Using explicitlyDependsOnArtifact: " + explicitlyDependsOn["final"][0].fileName) File.copy(input.filePath, output.filePath); }; return cmd; } } } Product { name: "prod2" type: "final" condition: !project.useModule Rule { multiplex: true requiresInputs: false outputFileTags: ["final"] Artifact { filePath: "product-fish.txt" fileTags: ["final"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating 'product-fish.txt' tagged with 'final'"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.ReadWrite); file.write("Lots of fish."); file.close() }; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/step1.txt0000644000175100001660000000000314776170045026166 0ustar runnerdockerhi qbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/modules/0000755000175100001660000000000014776170045026050 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/0000755000175100001660000000000014776170045027416 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module-fish.txt0000644000175100001660000000001414776170045032366 0ustar runnerdockerModule fish qbs-src-2.6.1/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module1.qbs0000644000175100001660000000017214776170045031473 0ustar runnerdockerModule { Group { filesAreTargets: true fileTags: ["final"] files: ["module-fish.txt"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/0000755000175100001660000000000014776170045022757 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/file3.h0000644000175100001660000000235114776170045024133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void file3(); qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/nested-groups.qbs0000644000175100001660000000222214776170045026263 0ustar runnerdockerCppApplication { consoleApplication: true Depends { name: "themodule" } cpp.includePaths: ["subdir"] property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: ["main.cpp"] Group { prefix: "subdir/" cpp.defines: ["REQUIRED_FOR_FILE1", "BREAKS_FILE2"] fileTags: ["cpp"] // This group has no files, and that's okay. Group { files: ["other.cpp", "other.h"] Group { cpp.defines: outer.concat(["ALSO_REQUIRED_FOR_FILE1"]) files: ["file1.cpp", "file1.h"] } Group { cpp.defines: ["REQUIRED_FOR_FILE2"] files: ["file2.cpp", "file2.h"] } Group { name: "disabled" condition: false Group { name: "indirectly disabled" condition: true files: ["main2.cpp"] } } Group { name: "no tags" fileTags: [] files: ["main3.cpp"] } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/0000755000175100001660000000000014776170045024247 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/other.h0000644000175100001660000000235114776170045025542 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void other(); qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/other.cpp0000644000175100001660000000253414776170045026100 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef REQUIRED_FOR_FILE1 #error "missing define" #endif #ifndef BREAKS_FILE2 #error "missing define" #endif void other() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/main3.cpp0000644000175100001660000000235214776170045025764 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/file1.h0000644000175100001660000000235114776170045025421 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void file1(); qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/main2.cpp0000644000175100001660000000235214776170045025763 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/file1.cpp0000644000175100001660000000254614776170045025762 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef REQUIRED_FOR_FILE1 #error "missing define" #endif #ifndef ALSO_REQUIRED_FOR_FILE1 #error "missing define" #endif void file1() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/file2.h0000644000175100001660000000235114776170045025422 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void file2(); qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/subdir/file2.cpp0000644000175100001660000000253514776170045025761 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef BREAKS_FILE2 #error "unexpected define" #endif #ifndef REQUIRED_FOR_FILE2 #error "missing define" #endif void file2() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/file3.cpp0000644000175100001660000000244614776170045024473 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef REQUIRED_FOR_FILE3 #error "missing define" #endif void file3() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/main.cpp0000644000175100001660000000255314776170045024414 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "file1.h" #include "file2.h" #include "file3.h" #include "other.h" int main() { file1(); file2(); file3(); other(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/modules/0000755000175100001660000000000014776170045024427 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/modules/themodule/0000755000175100001660000000000014776170045026415 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-groups/modules/themodule/themodule.qbs0000644000175100001660000000030114776170045031104 0ustar runnerdockerModule { Group { cpp.defines: ["REQUIRED_FOR_FILE3"] Group { prefix: product.sourceDirectory + '/' files: ["file3.cpp", "file3.h"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/find/0000755000175100001660000000000014776170045021100 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/find/find-cli.qbs0000644000175100001660000000177114776170045023302 0ustar runnerdockerimport qbs.TextFile Product { Depends { name: "cli"; required: false } type: ["json"] Rule { multiplex: true Artifact { filePath: ["cli.json"] fileTags: ["json"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = output.filePath; cmd.sourceCode = function() { var tools = {}; if (product.moduleProperty("cli", "present")) tools["toolchainInstallPath"] = product.moduleProperty("cli", "toolchainInstallPath"); var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine(JSON.stringify(tools, undefined, 4)); } finally { if (tf) tf.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates-no-error/0000755000175100001660000000000014776170045025522 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates-no-error/file1.txt0000644000175100001660000000000014776170045027251 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates-no-error/file3.txt0000644000175100001660000000000014776170045027253 0ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates-no-error/install-duplicates-no-error.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates-no-error/install-duplicates-no-error.q0000644000175100001660000000135414776170045033251 0ustar runnerdockerProject { Product { name: "p1" Group { files: ["file1.txt"] qbs.install: true } } Product { name: "p2" Group { files: ["file1.txt"] qbs.install: true } } Product { name: "p3" Group { files: ["file2.txt"] qbs.install: true } multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] } Product { name: "p4" Group { files: ["file2.txt"] qbs.install: true } aggregate: true multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/install-duplicates-no-error/file2.txt0000644000175100001660000000000014776170045027252 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-command-property/0000755000175100001660000000000014776170045025104 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-command-property/invalid-command-property.qbs0000644000175100001660000000161314776170045032540 0ustar runnerdockerimport qbs.TextFile Product { name: "p" property string errorType type: ["output"] Group { files: ["input.txt"] fileTags: ["input"] } Rule { inputs: ["input"] Artifact { filePath: "dummy" fileTags: ["output"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating output"; if (product.errorType === "qobject") cmd.dummy = new TextFile(input.filePath, TextFile.ReadOnly); else if (product.errorType === "input") cmd.dummy = input; else if (product.errorType === "artifact") cmd.dummy = product.artifacts.qbs[0]; else throw "invalid error type " + product.errorType; cmd.sourceCode = function() { } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-command-property/input.txt0000644000175100001660000000000014776170045026772 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/0000755000175100001660000000000014776170045022447 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/mylib.cpp0000644000175100001660000000006414776170045024267 0ustar runnerdocker#include "mylib.h" namespace MyLib { void f() {} } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/consumer.cpp0000644000175100001660000000005514776170045025006 0ustar runnerdockervoid helper(); int main() { helper(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/tool.qbs0000644000175100001660000000327614776170045024143 0ustar runnerdockerimport qbs.FileInfo import "helper.js" as Helper import Helper2 CppApplication { name: "MyTool" consoleApplication: true property stringList toolTags: ["MyTool.tool"] Depends { name: "Exporter.qbs" } Exporter.qbs.artifactTypes: ["installable", "blubb"] files: ["tool.cpp"] install: true qbs.installPrefix: project.installPrefix Group { files: ["helper.js"] qbs.install: true qbs.installDir: "qbs/modules/MyTool" } Group { files: ["imports/Helper2/helper2.js"] qbs.install: true qbs.installDir: "qbs/imports/Helper2" } Group { fileTagsFilter: ["application"] fileTags: toolTags } Group { fileTagsFilter: ["Exporter.qbs.module"] qbs.installDir: "qbs/modules/MyTool" } Export { property stringList toolTags: exportingProduct.toolTags property stringList outTags: [importingProduct.outTag] property var helper2Obj: Helper2 Rule { inputs: Helper.toolInputs() explicitlyDependsOnFromDependencies: toolTags outputFileTags: parent.outTags outputArtifacts: [{ filePath: FileInfo.completeBaseName(input.fileName) + product.MyTool.helper2Obj.suffix, fileTags: product.MyTool.outTags }] prepare: { var cmd = new Command(explicitlyDependsOn["MyTool.tool"][0].filePath, [input.filePath, output.filePath]); cmd.description = "compiling" + input.fileName + " to " + output.fileName; return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/imports/0000755000175100001660000000000014776170045024144 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/imports/Helper2/0000755000175100001660000000000014776170045025445 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/imports/Helper2/helper2.js0000644000175100001660000000002614776170045027342 0ustar runnerdockervar suffix = ".tool"; qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/exports-qbs.qbs0000644000175100001660000000055114776170045025446 0ustar runnerdockerimport qbs.FileInfo Project { property string installPrefix: "/usr" qbsSearchPaths: sourceDirectory Product { name: "local" Export { property bool dummy Depends { name: "cpp" } cpp.includePaths: ["/somelocaldir/include"] } } references: ["consumer.qbs", "lib.qbs", "tool.qbs"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/lib.qbs0000644000175100001660000000345414776170045023732 0ustar runnerdockerimport qbs.FileInfo DynamicLibrary { name: "MyLib" multiplexByQbsProperties: ["buildVariants"] aggregate: false qbs.buildVariants: ["debug", "release"] qbs.installPrefix: project.installPrefix Depends { name: "cpp" } Depends { name: "Exporter.qbs" } Exporter.qbs.fileName: name + "_" + qbs.buildVariant + ".qbs" Exporter.qbs.excludedDependencies: ["local"] Exporter.qbs.additionalContent: " condition: qbs.buildVariant === '" + qbs.buildVariant + "'" property string headersInstallDir: "include" cpp.defines: ["MYLIB_BUILD"] cpp.variantSuffix: qbs.buildVariant === "debug" ? "d" : "" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["mylib.cpp"] property var config: ({feature_x: false, feature_y: true}) Group { name: "API headers" files: ["mylib.h"] qbs.install: true qbs.installDir: headersInstallDir } install: true installImportLib: true installDir: "lib" Group { fileTagsFilter: ["Exporter.qbs.module"] qbs.install: true qbs.installDir: "qbs/modules/MyLib" } Export { Depends { name: "cpp" } property string includeDir: exportingProduct.sourceDirectory property var config: exportingProduct.config Properties { cpp.includePaths: [includeDir] cpp.dynamicLibraries: [] } cpp.dynamicLibraries: ["nosuchlib"] Depends { name: "local" } local.dummy: true Properties { prefixMapping: [{ prefix: includeDir, replacement: FileInfo.joinPaths(exportingProduct.qbs.installPrefix, exportingProduct.headersInstallDir) }] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/mylib.h0000644000175100001660000000063014776170045023733 0ustar runnerdocker#if defined(_WIN32) || defined(WIN32) # define DLL_EXPORT __declspec(dllexport) # define DLL_IMPORT __declspec(dllimport) #else # define DLL_EXPORT __attribute__((visibility("default"))) # define DLL_IMPORT __attribute__((visibility("default"))) # endif #ifdef MYLIB_BUILD #define MYLIB_EXPORT DLL_EXPORT #else #define MYLIB_EXPORT DLL_IMPORT #endif namespace MyLib { MYLIB_EXPORT void f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/tool.cpp0000644000175100001660000000060314776170045024127 0ustar runnerdocker#include #include int main(int argc, char *argv[]) { if (argc != 3) return EXIT_FAILURE; std::ifstream in(argv[1]); if (!in) return EXIT_FAILURE; std::ofstream out(argv[2]); if (!out) return EXIT_FAILURE; char ch; while (in.get(ch)) out.put(ch); return in.eof() && out ? EXIT_SUCCESS : EXIT_FAILURE; } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/consumer.qbs0000644000175100001660000000132314776170045025010 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "consumer" qbsSearchPaths: "default/install-root/usr/qbs" property string outTag: "cpp" Depends { name: "MyLib" } Depends { name: "MyTool" } files: ["consumer.cpp"] cpp.defines: { var defs = []; if (MyLib.config.feature_x) defs.push("FEATURE_X"); if (MyLib.config.feature_y) defs.push("FEATURE_Y"); return defs; } Group { files: ["helper.cpp.in"] fileTags: ["cpp.in"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/helper.js0000644000175100001660000000005514776170045024264 0ustar runnerdockerfunction toolInputs() { return ["cpp.in"]; } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/helper.cpp.in0000644000175100001660000000026114776170045025036 0ustar runnerdocker#include #ifdef FEATURE_X #error "feature x must not be present!" #endif #ifndef FEATURE_Y #error "feature y is required!" #endif void helper() { MyLib::f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-qbs/exports-qbs-products.qbs0000644000175100001660000000000014776170045027274 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/0000755000175100001660000000000014776170045023406 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/fileDependencies.qbs0000644000175100001660000000071114776170045027342 0ustar runnerdockerProject { Product { type: "application" consoleApplication: true name: "myapp" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "cpp" } cpp.includePaths: ["awesomelib"] files: ["src/narf.h", "src/narf.cpp", "src/zort.cpp"] // Group { // fileTagsFilter: product.type // qbs.install: true // } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/src/0000755000175100001660000000000014776170045024175 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/src/zort.cpp0000644000175100001660000000243314776170045025701 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "narf.h" int main() { doStuff(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/src/narf.cpp0000644000175100001660000000243314776170045025631 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include void doStuff() { doAwesomeStuff(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/src/narf.h0000644000175100001660000000235414776170045025300 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void doStuff(); qbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/awesomelib/0000755000175100001660000000000014776170045025535 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/awesomelib/magnificent.h0000644000175100001660000000252114776170045030172 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MAGNIFICENT_H #define MAGNIFICENT_H const char magnificentMessage[] = "Just. Wow."; #endif // MAGNIFICENT_H qbs-src-2.6.1/tests/auto/blackbox/testdata/fileDependencies/awesomelib/awesome.h0000644000175100001660000000250714776170045027352 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "magnificent.h" void doAwesomeStuff() { std::printf(magnificentMessage); } qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/0000755000175100001660000000000014776170045025031 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot2/0000755000175100001660000000000014776170045026635 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot2/usr/0000755000175100001660000000000014776170045027446 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot2/usr/share/0000755000175100001660000000000014776170045030550 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot2/usr/share/pkgconfig/0000755000175100001660000000000014776170045032517 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot2/usr/share/pkgconfig/dummy.pcqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot2/usr/share/pkgconfig/dum0000644000175100001660000000014714776170045033231 0ustar runnerdockerName: dummy1 Description: dummy1 package Version: 0.0.1 Requires: Libs: -L/usr/dummy -ldummy1 Cflags: qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot1/0000755000175100001660000000000014776170045026634 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot1/usr/0000755000175100001660000000000014776170045027445 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot1/usr/share/0000755000175100001660000000000014776170045030547 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot1/usr/share/pkgconfig/0000755000175100001660000000000014776170045032516 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot1/usr/share/pkgconfig/dummy.pcqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/sysroot1/usr/share/pkgconfig/dum0000644000175100001660000000014714776170045033230 0ustar runnerdockerName: dummy1 Description: dummy1 package Version: 0.0.1 Requires: Libs: -L/usr/dummy -ldummy1 Cflags: qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/pkg-config.qbs0000644000175100001660000000077614776170045027576 0ustar runnerdockerProject { property string packageBaseName Product { name: "theProduct1" type: ["theType"] Depends { name: "themodule" } qbs.sysroot: path + "/sysroot1" } Product { name: "theProduct2" type: ["theType"] Depends { name: "themodule" } qbs.sysroot: path + "/sysroot2" } Product { name: "theProduct3" type: ["theType"] Depends { name: "themodule" } qbs.sysroot: path + "/sysroot1" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/modules/0000755000175100001660000000000014776170045026501 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/modules/themodule/0000755000175100001660000000000014776170045030467 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pkg-config-probe-sysroot/modules/themodule/themodule.qbs0000644000175100001660000000100214776170045033155 0ustar runnerdockerimport qbs.Probes Module { Probes.PkgConfigProbe { id: theProbe name: "dummy" } property stringList libs: theProbe.libs Rule { multiplex: true outputFileTags: "theType" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info(product.name + " libs: " + JSON.stringify(product.themodule.libs)); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/generated-artifact-as-input-to-dynamic-rule/0000755000175100001660000000000014776170045030456 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/generated-artifact-as-input-to-dynamic-rule/input.txt0000644000175100001660000000001014776170045032345 0ustar runnerdockerold.txt qbs-src-2.6.1/tests/auto/blackbox/testdata/generated-artifact-as-input-to-dynamic-rule/p.qbs0000644000175100001660000000300514776170045031422 0ustar runnerdockerimport qbs.File import qbs.TextFile Product { type: ["mytype.final"] Group { files: ["input.txt"] fileTags: ["mytype.in"] } Rule { inputs: ["mytype.in"] Artifact { filePath: "output.txt" fileTags: ["mytype.out"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return [cmd]; } } Rule { inputs: ["mytype.out"] outputFileTags: ["mytype.final", "dummy"] outputArtifacts: { var file; var inFile = new TextFile(input.filePath, TextFile.ReadOnly); try { file = inFile.readLine(); if (!file) throw "no file name found"; } finally { inFile.close(); } return [ { filePath: file, fileTags: ["mytype.final"] }, { filePath: "dummy", fileTags: ["dummy"], alwaysUpdated: false } ]; } prepare: { var cmd = new JavaScriptCommand(); var output = outputs["mytype.final"][0]; cmd.description = "generating " + output.fileName; cmd.outputFilePath = output.filePath; cmd.sourceCode = function() { File.copy(input.filePath, outputFilePath); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/build-data-of-disabled-product/0000755000175100001660000000000014776170045026013 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/build-data-of-disabled-product/test.cpp0000644000175100001660000000001414776170045027471 0ustar runnerdockervoid f() {} ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/build-data-of-disabled-product/build-data-of-disabled-product.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/build-data-of-disabled-product/build-data-of-disabled-pro0000644000175100001660000000010714776170045032707 0ustar runnerdockerCppApplication { name: "app" files: ["main.cpp", "test.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/build-data-of-disabled-product/main.cpp0000644000175100001660000000004314776170045027440 0ustar runnerdockervoid f(); int main() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-race-condition/0000755000175100001660000000000014776170045025607 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-race-condition/artifacts-map-race-condition.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-race-condition/artifacts-map-race-condition0000644000175100001660000000437314776170045033170 0ustar runnerdockerProduct { name: "p" type: ["custom1", "custom2", "custom3", "custom4", "custom5"] Rule { multiplex: true outputFileTags: "custom1" prepare: { var cmd = new JavaScriptCommand(); cmd.description = "reader1"; cmd.sourceCode = function() { for (var i = 0; i < 1000; ++i) { for (var t in product.artifacts) { var l = product.artifacts[t]; for (var j = 0; j < l.length; ++j) var fileName = l[j].fileName; } } }; return cmd; } } Rule { multiplex: true outputFileTags: "helper" prepare: { var cmd = new JavaScriptCommand(); cmd.description = "helper"; cmd.sourceCode = function() { }; return cmd; } } Rule { inputs: ["helper"] outputFileTags: ["custom2", "custom3", "custom4"] outputArtifacts: { console.info("writer"); var artifacts = []; for (var i = 0; i < 1000; ++i) { artifacts.push({ filePath: "dummyt1" + i, fileTags: ["custom2"] }); artifacts.push({ filePath: "dummyt2" + i, fileTags: ["custom3"] }); artifacts.push({ filePath: "dummyt3" + i, fileTags: ["custom4"] }); } return artifacts; } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "writer dummy command"; cmd.sourceCode = function() { }; return cmd; } } Rule { multiplex: true outputFileTags: "custom5" prepare: { var cmd = new JavaScriptCommand(); cmd.description = "reader2"; cmd.sourceCode = function() { for (var i = 0; i < 1000; ++i) { for (var t in product.artifacts) { var l = product.artifacts[t]; for (var j = 0; j < l.length; ++j) var fileName = l[j].fileName; } } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/0000755000175100001660000000000014776170045023144 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/d.mm0000644000175100001660000000027514776170045023726 0ustar runnerdocker#import void printGreeting() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog (@"Hello darkness, my old friend!"); [pool drain]; } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/e.cpp0000644000175100001660000000240214776170045024072 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int d(); int e() { return d(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/d.cpp0000644000175100001660000000411114776170045024070 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #if defined(WITH_ZLIB) #include #endif #if defined(WITH_WEBSOCK) #include #endif #ifdef WITH_PTHREAD #include #elif defined(WITH_SETUPAPI) #include #include #endif void b(); void c(); int d() { b(); c(); int result = 0; #if defined(WITH_ZLIB) const char source[] = "Hello, world"; uLongf buffer_size = compressBound(sizeof(source)); result += static_cast(buffer_size); #endif #if defined(WITH_WEBSOCK) const bool supported = emscripten_websocket_is_supported(); (void) supported; #endif #ifdef WITH_PTHREAD pthread_t self = pthread_self(); result += static_cast(self); #elif defined(WITH_SETUPAPI) CABINET_INFO ci; ci.SetId = 0; SetupIterateCabinet(L"invalid-file-path", 0, NULL, NULL); result += ci.SetId; #endif return result; } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/c.cpp0000644000175100001660000000237714776170045024103 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void a2(); void c() { a2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/a2.cpp0000644000175100001660000000244314776170045024155 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include void a2() { std::cout << "a2" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/main.cpp0000644000175100001660000000240514776170045024575 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int e(); int main() { return e(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/b.cpp0000644000175100001660000000237714776170045024102 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void a1(); void b() { a1(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/a1.cpp0000644000175100001660000000244314776170045024154 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include void a1() { std::cout << "a1" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/static-lib-deps/static-lib-deps.qbs0000644000175100001660000000620714776170045026644 0ustar runnerdockerProject { property bool useExport: true StaticLibrary { name: "a" Depends { name: "cpp" } files: [ "a1.cpp", "a2.cpp", ] } StaticLibrary { name: "b" Depends { name: "cpp" } Depends { name: "a" } files: [ "b.cpp", ] } StaticLibrary { name: "c" Depends { name: "cpp" } Depends { name: "a" } files: [ "c.cpp", ] } StaticLibrary { name: "d" Depends { name: "cpp" } Depends { name: "b" } Depends { name: "c" } files: [ "d.cpp", ] Group { condition: qbs.targetOS.includes("darwin") files: ["d.mm"] } Properties { condition: qbs.targetOS.includes("windows") cpp.defines: ["WITH_SETUPAPI"] cpp.staticLibraries: !project.useExport ? ["setupapi"] : [] } Properties { condition: qbs.targetOS.includes("darwin") cpp.defines: ["WITH_ZLIB"] cpp.staticLibraries: !project.useExport ? ["z"] : [] cpp.frameworks: !project.useExport ? ["Foundation"] : [] } Properties { condition: { console.info(qbs.targetOS); return qbs.targetOS.includes("linux") || qbs.targetOS.includes("hurd") } cpp.defines: ["WITH_PTHREAD", "WITH_ZLIB"] cpp.staticLibraries: !project.useExport ? ["pthread", "z"] : [] } Properties { condition: qbs.toolchain.contains("emscripten") cpp.defines: ["WITH_WEBSOCK"] cpp.staticLibraries: !project.useExport ? ["websocket.js"] : [] } Export { condition : project.useExport Depends { name: "cpp" } Properties { condition: qbs.targetOS.contains("linux") || qbs.targetOS.includes("hurd") cpp.staticLibraries: ["pthread", "z"] } Properties { condition: qbs.targetOS.contains("darwin") cpp.staticLibraries: ["z"] cpp.frameworks: ["Foundation"] } Properties { condition: qbs.targetOS.contains("windows") cpp.staticLibraries: ["setupapi"] } Properties { condition: qbs.toolchain.contains("emscripten") cpp.staticLibraries: ["websocket.js"] } } } StaticLibrary { name: "e" Depends { name: "cpp" } Depends { name: "d" } files: [ "e.cpp", ] Export { Depends { name: "d" } } } CppApplication { name: "staticLibDeps" type: "application" consoleApplication: true Depends { name: "e" } Properties { condition: qbs.targetOS.includes("linux") || qbs.targetOS.includes("hurd") cpp.driverFlags: ["-static"] } files: [ "main.cpp", ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/0000755000175100001660000000000014776170045022715 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs0000644000175100001660000000431014776170045026157 0ustar runnerdockerimport qbs.Utilities Project { StaticLibrary { name: "staticlib 1" Depends { name: "cpp" } files: ["unused1.cpp", "used.cpp"] } StaticLibrary { name: "staticlib2" Depends { name: "cpp" } files: ["unused2.cpp"] } StaticLibrary { name: "staticlib3" Depends { name: "cpp" } files: ["unused3.cpp"] } StaticLibrary { name: "staticlib4" Depends { name: "cpp" } files: ["unused4.cpp"] } DynamicLibrary { name: "dynamiclib" property string linkWholeArchive Depends { name: "cpp" } Probe { id: dummy property stringList toolchain: qbs.toolchain property string compilerVersion: cpp.compilerVersion property string dummy: product.linkWholeArchive // To force probe re-execution property bool isEmscripten: qbs.toolchain.contains("emscripten") configure: { if (!toolchain.includes("msvc") || toolchain.includes("clang-cl") || Utilities.versionCompare(compilerVersion, "19.0.24215.1") >= 0) { console.info("can link whole archives"); } else { console.info("cannot link whole archives"); } console.info("is emscripten: " + isEmscripten); } } Depends { name: "staticlib 1"; cpp.linkWholeArchive: product.linkWholeArchive } Depends { name: "staticlib2"; cpp.linkWholeArchive: product.linkWholeArchive } Depends { name: "staticlib3" } Depends { name: "staticlib4"; cpp.linkWholeArchive: product.linkWholeArchive } files: ["dynamiclib.cpp"] } CppApplication { name: "app1" Depends { name: "dynamiclib" } files: ["main1.cpp"] } CppApplication { name: "app2" Depends { name: "dynamiclib" } files: ["main2.cpp"] } CppApplication { name: "app3" Depends { name: "dynamiclib" } files: ["main3.cpp"] } CppApplication { name: "app4" Depends { name: "dynamiclib" } files: ["main4.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/main1.cpp0000644000175100001660000000013514776170045024425 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void unusedFunc1(); int main() { unusedFunc1(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/used.cpp0000644000175100001660000000002414776170045024355 0ustar runnerdockervoid usedFunc() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/unused1.cpp0000644000175100001660000000007514776170045025007 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void unusedFunc1() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/main3.cpp0000644000175100001660000000013414776170045024426 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void unusedFunc3(); int main() { unusedFunc3(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/dynamiclib.cpp0000644000175100001660000000012114776170045025526 0ustar runnerdocker#include "../dllexport.h" void usedFunc(); DLL_EXPORT void f() { usedFunc(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/main2.cpp0000644000175100001660000000013514776170045024426 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void unusedFunc2(); int main() { unusedFunc2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/unused3.cpp0000644000175100001660000000007514776170045025011 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void unusedFunc3() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/unused2.cpp0000644000175100001660000000007514776170045025010 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void unusedFunc2() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/main4.cpp0000644000175100001660000000013514776170045024430 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void unusedFunc4(); int main() { unusedFunc4(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/whole-archive/unused4.cpp0000644000175100001660000000007514776170045025012 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void unusedFunc4() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_renaming/0000755000175100001660000000000014776170045024047 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_renaming/recursive_renaming.qbs0000644000175100001660000000021714776170045030445 0ustar runnerdockerProduct { qbs.installPrefix: "" Group { qbs.install: true qbs.installSourceBase: "." files: ["dir/**"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_renaming/dir/0000755000175100001660000000000014776170045024625 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_renaming/dir/subdir/0000755000175100001660000000000014776170045026115 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_renaming/dir/subdir/blubb.txt0000644000175100001660000000000014776170045027732 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/recursive_renaming/dir/wasser.txt0000644000175100001660000000000014776170045026660 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/generate-linker-map-file/0000755000175100001660000000000014776170045024724 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/generate-linker-map-file/main.cpp0000644000175100001660000000241214776170045026353 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs0000644000175100001660000000153614776170045032204 0ustar runnerdockerProject { CppApplication { name: "app-map" files: ["main.cpp"] // lld-link has different flag for map files, test it by switching to "lld" linkerVariant Properties { condition: qbs.toolchain.includes("clang-cl"); cpp.linkerVariant: "lld" } cpp.generateLinkerMapFile: true } CppApplication { name: "app-nomap" files: ["main.cpp"] Properties { condition: qbs.toolchain.includes("clang-cl"); cpp.linkerVariant: "lld" } cpp.generateLinkerMapFile: false } CppApplication { name: "app-nomap-default" files: ["main.cpp"] } Probe { id: toolchainProbe property bool isUsed: qbs.toolchain.includes("msvc") || qbs.toolchain.includes("gcc") configure: { console.info("use test: " + isUsed); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/0000755000175100001660000000000014776170045027755 5ustar runnerdocker././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/exported-dependency-in-disabled-product.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/exported-dependen0000644000175100001660000000065114776170045033314 0ustar runnerdockerProject { Application { name: "app" Depends { name: "dep"; required: false } files: "main.cpp" } Product { name: "dep" condition: eval(conditionString) property string conditionString Depends { name: "nosuchmodule"; required: false } Depends { name: "broken"; required: false } Export { Depends { name: "cpp" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/main.cpp0000644000175100001660000000001614776170045031402 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/modules/0000755000175100001660000000000014776170045031425 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/modules/broken/0000755000175100001660000000000014776170045032705 5ustar runnerdocker././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/modules/broken/broken.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/exported-dependency-in-disabled-product/modules/broken/br0000644000175100001660000000005614776170045033234 0ustar runnerdockerModule { validate: { throw "broken!"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/subprofile-change-tracking/0000755000175100001660000000000014776170045025355 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/subprofile-change-tracking/main1.cpp0000644000175100001660000000235114776170045027067 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/subprofile-change-tracking/main2.cpp0000644000175100001660000000235114776170045027070 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/subprofile-change-tracking/subprofile-change-tracking.qbs0000644000175100001660000000030614776170045033260 0ustar runnerdockerProject { CppApplication { name: "app1"; files: ["main1.cpp"] } CppApplication { name: "app2" qbs.profiles: ["qbs-autotests-subprofile"] files: ["main2.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/0000755000175100001660000000000014776170045023426 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/after/0000755000175100001660000000000014776170045024527 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/after/lib2.h0000644000175100001660000000241014776170045025525 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void print_two_numbers(int a, int b, int c); qbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/after/lib2.cpp0000644000175100001660000000257114776170045026070 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib2.h" #include void print_two_numbers(int a, int b, int c) { std::cout << "a=" << a << ", b=" << b << ", c=" << c << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/before/0000755000175100001660000000000014776170045024670 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/before/lib.h0000644000175100001660000000241414776170045025610 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void print_two_numbers(int a, int b/*, int c*/); qbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/before/lib.cpp0000644000175100001660000000260114776170045026141 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib.h" #include void print_two_numbers(int a, int b/*, int c*/) { std::cout << "a=" << a << ", b=" << b /*<< ", c=" << c */ << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/before/renameDependency.qbs0000644000175100001660000000005714776170045030647 0ustar runnerdockerCppApplication { files: ["*.cpp", "*.h"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/renameDependency/before/main.cpp0000644000175100001660000000247314776170045026326 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "lib.h" int main() { print_two_numbers(2, 3); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/0000755000175100001660000000000014776170045023462 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/test.txt0000644000175100001660000000000014776170045025170 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/direntries-command.qbs0000644000175100001660000000072214776170045027756 0ustar runnerdockerimport qbs.File Product { type: ["out"] Group { files: ["test.txt"] fileTags: ["in"] } Rule { inputs: ["in"] outputFileTags: "out" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var dummy = File.directoryEntries(product.sourceDirectory, File.Files); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/copy-command.qbs0000644000175100001660000000063214776170045026560 0ustar runnerdockerimport qbs.File Product { type: ["out"] Group { files: ["test.txt"] fileTags: ["in"] } Rule { inputs: ["in"] outputFileTags: "out" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/copy-probe.qbs0000644000175100001660000000040514776170045026247 0ustar runnerdockerimport qbs.File Product { Probe { id: theProbe property string baseDir: project.sourceDirectory configure: { File.copy(baseDir + "/copy-probe.qbs", baseDir + "/copy-probe2.qbs"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/copy-eval.qbs0000644000175100001660000000026414776170045026072 0ustar runnerdockerimport qbs.File Product { name: { File.copy(sourceDirectory + "/copy-eval.qbs", sourceDirectory + "/copy-eval2.qbs"); return "blubb" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/direntries-prepare.qbs0000644000175100001660000000070214776170045027774 0ustar runnerdockerimport qbs.File Product { type: ["out"] Group { files: ["test.txt"] fileTags: ["in"] } Rule { inputs: ["in"] outputFileTags: "out" prepare: { var dummy = File.directoryEntries(product.sourceDirectory, File.Files); var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/direntries-probe.qbs0000644000175100001660000000043714776170045027452 0ustar runnerdockerimport qbs.File Product { Probe { id: theProbe property string baseDir: project.sourceDirectory property stringList subDirs configure: { subDirs = File.directoryEntries(baseDir, File.AllDirs); found = true; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/copy-prepare.qbs0000644000175100001660000000065614776170045026606 0ustar runnerdockerimport qbs.File Product { type: ["out"] Group { files: ["test.txt"] fileTags: ["in"] } Rule { inputs: ["in"] outputFileTags: "out" prepare: { File.copy(input.filePath, output.filePath); var cmd = new JavaScriptCommand(); cmd.description = "no-op"; cmd.sourceCode = function() { }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/suspicious-calls/direntries-eval.qbs0000644000175100001660000000013514776170045027265 0ustar runnerdockerimport qbs.File Product { name: File.directoryEntries(sourceDirectory, File.Files)[0] } qbs-src-2.6.1/tests/auto/blackbox/testdata/pseudo-multiplexing/0000755000175100001660000000000014776170045024176 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pseudo-multiplexing/pseudo-multiplexing.qbs0000644000175100001660000000036114776170045030723 0ustar runnerdockerProject { Product { name: "a" multiplexByQbsProperties: ["architectures"] Depends { name: "cpp" } } Product { name: "b" multiplexByQbsProperties: [] Depends { name: "cpp" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-with-dependencies/0000755000175100001660000000000014776170045025425 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-with-dependencies/autotest-with-dependencies.qbs0000644000175100001660000000211214776170045033375 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "helper-app" type: ["application", "test-helper"] consoleApplication: true install: true files: "helper-main.cpp" cpp.executableSuffix: ".exe" Group { fileTagsFilter: "application" fileTags: "test-helper" } } CppApplication { name: "test-app" type: ["application", "autotest"] Depends { name: "autotest" } files: "test-main.cpp" } AutotestRunner { Depends { name: "cpp" // Make sure build environment is set up properly. condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } arguments: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, "bin") auxiliaryInputs: "test-helper" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-with-dependencies/test-main.cpp0000644000175100001660000000046414776170045030036 0ustar runnerdocker#include #include #include int main(int argc, char *argv[]) { std::cout << "i am the test app" << std::endl; const std::string fullHelperExe = std::string(argv[1]) + "/helper-app.exe"; return std::system(fullHelperExe.c_str()) == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-with-dependencies/helper-main.cpp0000644000175100001660000000014314776170045030330 0ustar runnerdocker#include int main() { std::cout << "i am the helper" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/ruleCycle/0000755000175100001660000000000014776170045022107 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ruleCycle/ruleCycle.qbs0000644000175100001660000000247414776170045024554 0ustar runnerdockerProject { Product { name: "the cycle of life" type: "cow" Group { files: ["happy.grass"] fileTags: ["grass"] } Rule { inputs: ["grass"] outputFileTags: ["cow"] outputArtifacts: [{ filePath: input.completeBaseName + ".cow", fileTags: ["cow"] }] prepare: { console.info("The cow feeds on grass."); } } Rule { inputs: ["cow"] Artifact { filePath: input.completeBaseName + ".cow_pat" fileTags: ["cow_pat"] } prepare: { console.info("The cow pat falls out of the cow."); } } Rule { inputs: ["cow_pat"] Artifact { filePath: input.completeBaseName + ".fertilizer" fileTags: ["fertilizer"] } prepare: { console.info("The cow pat is used as fertilizer."); } } Rule { inputs: ["fertilizer"] outputFileTags: ["grass"] outputArtifacts: [{ filePath: input.completeBaseName + ".grass", fileTags: ["grass"] }] prepare: { console.info("The fertilizer lets the grass grow."); } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/ruleCycle/happy.grass0000644000175100001660000000003014776170045024262 0ustar runnerdockerhappy! happy! joy! joy! qbs-src-2.6.1/tests/auto/blackbox/testdata/system-run-paths/0000755000175100001660000000000014776170045023423 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/system-run-paths/lib.cpp0000644000175100001660000000235314776170045024700 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/system-run-paths/system-run-paths.qbs0000644000175100001660000000147214776170045027401 0ustar runnerdockerProject { property bool setRunPaths Product { name: "theLib" type: ["dynamiclibrary"] Depends { name: "cpp" } qbs.installPrefix: "" Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "lib" } files: ["lib.cpp"] } CppApplication { name: "app" Depends { name: "theLib" } files: ["main.cpp"] property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } cpp.rpaths: qbs.installRoot + "/lib" cpp.systemRunPaths: project.setRunPaths ? [qbs.installRoot + "/lib"] : [] } Probe { id: checker property bool isUnix: qbs.targetOS.contains("unix") configure: { console.info("is unix: " + isUnix); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/system-run-paths/main.cpp0000644000175100001660000000240414776170045025053 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void func(); int main() { func(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/0000755000175100001660000000000014776170045023132 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/script-ok0000755000175100001660000000001214776170045024764 0ustar runnerdocker#!/bin/sh qbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/badInterpreter.qbs0000644000175100001660000000220014776170045026605 0ustar runnerdockerimport qbs.Host Project { property bool enabled: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } qbsSearchPaths: base.concat(["qbs"]) Product { Depends { name: "script-test" } name: "script-ok" type: ["application"] Group { files: [product.name] fileTags: ["script"] } } Product { Depends { name: "script-test" } name: "script-noexec" type: ["application"] Group { files: [product.name] fileTags: ["script"] } } Product { Depends { name: "script-test" } name: "script-interp-missing" type: ["application"] Group { files: [product.name] fileTags: ["script"] } } Product { Depends { name: "script-test" } name: "script-interp-noexec" type: ["application"] Group { files: [product.name] fileTags: ["script"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/qbs/0000755000175100001660000000000014776170045023717 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/qbs/modules/0000755000175100001660000000000014776170045025367 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/qbs/modules/script-test/0000755000175100001660000000000014776170045027650 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/qbs/modules/script-test/script-test.qbs0000644000175100001660000000206114776170045032637 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Module { name: "script-test" Rule { inputs: ["script"] Artifact { filePath: FileInfo.joinPaths(project.buildDirectory, input.fileName) fileTags: ["application"] } prepare: { var cmds = []; var cmd = new JavaScriptCommand(); cmd.description = "copying " + input.fileName; cmd.sourceCode = function() { var tf = new TextFile(input.filePath, TextFile.ReadOnly); var s = tf.readAll().replace("$PWD", project.buildDirectory); tf.close(); var tf2 = new TextFile(output.filePath, TextFile.ReadWrite); tf2.write(s); tf2.close(); }; cmds.push(cmd); if (output.fileName !== "script-noexec") { var cmd2 = new Command("chmod", ["+x", output.filePath]); cmd2.silent = true; cmds.push(cmd2); } return cmds; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/script-noexec0000644000175100001660000000000014776170045025626 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/script-interp-missing0000755000175100001660000000002214776170045027324 0ustar runnerdocker#!/does/not/exist qbs-src-2.6.1/tests/auto/blackbox/testdata/badInterpreter/script-interp-noexec0000755000175100001660000000002514776170045027137 0ustar runnerdocker#!$PWD/script-noexec qbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/0000755000175100001660000000000014776170045025736 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/test.txt0000644000175100001660000000000014776170045027444 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/test.cpp.in0000644000175100001660000000001514776170045030022 0ustar runnerdockervoid f() { } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/artifacts-map-change-tracking.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/artifacts-map-change-tracki0000644000175100001660000000525214776170045033116 0ustar runnerdockerimport qbs.File Project { CppApplication { name: "TheApp" targetName: "TheBinary" Rule { inputs: "cpp.in" Artifact { filePath: "test.cpp"; fileTags: 'cpp' } prepare: { console.info("running rule for " + output.fileName); var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } files: ["main.cpp", /* 'test.txt' */] Group { files: "test.cpp.in" fileTags: "cpp.in" } } Product { name: "meta" type: "custom" Depends { name: "TheApp" } Group { files: "dummy.in" fileTags: "dummy.in" } Rule { inputs: ["dummy.in"] Artifact { filePath: "dummy"; fileTags: 'custom' } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "printing artifacts"; cmd.sourceCode = function() { var dep; for (var i = 0; i < product.dependencies.length; ++i) { var d = product.dependencies[i]; if (d.name === "TheApp") { dep = d; break; } } for (var p in dep.artifacts) { var list = dep.artifacts[p]; for (var i = 0; i < list.length; ++i) console.info(list[i].fileName); } File.copy(input.filePath, output.filePath); }; return cmd; } } } Product { name: "p" type: "p_type" Rule { multiplex: true Artifact { filePath: "dummy1"; fileTags: "d_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var blubb = product.artifacts.qbs; }; return cmd; } } Rule { inputs: "d_type" Artifact { filePath: "dummy2"; fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { }; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/dummy.in0000644000175100001660000000000014776170045027407 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifacts-map-change-tracking/main.cpp0000644000175100001660000000003714776170045027366 0ustar runnerdockervoid f(); int main() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-install-dir/0000755000175100001660000000000014776170045024026 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-install-dir/invalid-install-dir.qbs0000644000175100001660000000022214776170045030377 0ustar runnerdockerCppApplication { consoleApplication: true files: ["main.cpp"] qbs.installPrefix: "" install: true installDir: "../whatever" } qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-install-dir/main.cpp0000644000175100001660000000001614776170045025453 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/out-of-date-marking/0000755000175100001660000000000014776170045023732 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/out-of-date-marking/main.c0000644000175100001660000000006014776170045025016 0ustar runnerdocker#include int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/out-of-date-marking/out-of-date-marking.qbs0000644000175100001660000000106114776170045030211 0ustar runnerdockerimport qbs.TextFile CppApplication { name: "app" files: "main.c" cpp.includePaths: buildDirectory Rule { multiplex: true alwaysRun: true Artifact { filePath: "myheader.h"; fileTags: "hpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/0000755000175100001660000000000014776170045026670 5ustar runnerdocker././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/non-broken-files-in-broken-product.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/non-broken-files-in-br0000644000175100001660000000012614776170045032767 0ustar runnerdockerCppApplication { consoleApplication: true files: ["fine.cpp", "broken.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/fine.cpp0000644000175100001660000000235114776170045030316 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/non-broken-files-in-broken-product/broken.cpp0000644000175100001660000000000714776170045030651 0ustar runnerdockerbroken qbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/0000755000175100001660000000000014776170045025403 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/helper_lib.qbs0000644000175100001660000000031114776170045030212 0ustar runnerdockerDynamicLibrary { name: "helperLib" files: "helperlib.cpp" Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } qbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/project_using_helper_lib.qbs0000644000175100001660000000046214776170045033154 0ustar runnerdockerProject { property bool linkSuccessfully: false references: linkSuccessfully ? ["helper_lib.qbs"] : [] CppApplication { consoleApplication: true Depends { condition: project.linkSuccessfully name: "helperLib" } files: "main2.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/helperlib.cpp0000644000175100001660000000242714776170045030062 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" void DLL_EXPORT helperFunc() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/overrideProjectProperties.qbs0000644000175100001660000000245714776170045033345 0ustar runnerdockerProject { property string nameSuffix: "" property bool someBool property int someInt property stringList someStringList Product { consoleApplication: true type: "application" property string mainFile: "" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } name: "MyApp" + nameSuffix Depends { name: "cpp" } files: { // Check types of the project's custom properties here. // Provoke a build error if the expected types do not match. var wrongFile = "doesnotexist.cpp"; if (typeof project.someBool != "boolean") { console.info("someBool has a wrong type: " + typeof project.someBool); return wrongFile; } if (typeof project.someInt != "number") { console.info("someInt has a wrong type: " + typeof project.someInt); return wrongFile; } if (typeof project.someStringList != "object") { console.info("someStringList has a wrong type: " + typeof project.someStringList); return wrongFile; } // Return the mainFile property that is set on the command line. return [mainFile]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/main2.cpp0000644000175100001660000000250514776170045027117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" void DLL_IMPORT helperFunc(); int main() { helperFunc(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/overrideProjectProperties/main.cpp0000644000175100001660000000237014776170045027035 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/wildcard_renaming/0000755000175100001660000000000014776170045023631 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcard_renaming/wildcard_renaming.qbs0000644000175100001660000000014514776170045030011 0ustar runnerdockerProduct { qbs.installPrefix: "" Group { qbs.install: true files: "*" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/wildcard_renaming/pioniere.txt0000644000175100001660000000000014776170045026172 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rpathlink-deduplication/0000755000175100001660000000000014776170045024776 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-lib.cpp0000644000175100001660000000004314776170045033061 0ustar runnerdockerint dynamicFunc() { return 1; }qbs-src-2.6.1/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication.qbs0000644000175100001660000000241614776170045032326 0ustar runnerdockerProject { DynamicLibrary { Depends { name: "bundle" } Depends { name: "cpp" } bundle.isBundle: false name: "DynamicLibraryA" files: ["rpathlink-deduplication-lib.cpp"] } DynamicLibrary { Depends { name: "bundle" } Depends { name: "cpp" } Depends { name: "DynamicLibraryA" } bundle.isBundle: false name: "DynamicLibraryB" files: ["rpathlink-deduplication-lib.cpp"] } DynamicLibrary { Depends { name: "bundle" } Depends { name: "cpp" } Depends { name: "DynamicLibraryA" } bundle.isBundle: false name: "DynamicLibraryC" files: ["rpathlink-deduplication-lib.cpp"] } CppApplication { Depends { name: "bundle" } Depends { name: "DynamicLibraryB" } Depends { name: "DynamicLibraryC" } consoleApplication: true bundle.isBundle: false cpp.removeDuplicateLibraries: false files: "rpathlink-deduplication-main.cpp" property bool test: { if (cpp.useRPathLink) console.info("useRPathLink: true"); else console.info("useRPathLink: false"); console.info("===" + cpp.rpathLinkFlag + "==="); } } }qbs-src-2.6.1/tests/auto/blackbox/testdata/rpathlink-deduplication/rpathlink-deduplication-main.cpp0000644000175100001660000000010314776170045033234 0ustar runnerdockerextern int dynamicFunc(); int main() { return dynamicFunc(); }qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-rule-inputs/0000755000175100001660000000000014776170045024036 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/changed-rule-inputs/changed-rule-inputs.qbs0000644000175100001660000000202014776170045030415 0ustar runnerdockerProject { Product { name: "p1" type: "p1" Rule { alwaysRun: true multiplex: true Artifact { fileTags: "p1" filePath: "p1-dummy" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() {}; return cmd; } } } Product { name: "p2" type: "p2" Depends { name: "p1" } Rule { requiresInputs: false multiplex: true inputsFromDependencies: "p1" Artifact { fileTags: "p2" filePath: "p2-dummy" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() {}; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/reproducible-build/0000755000175100001660000000000014776170045023734 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/reproducible-build/reproducible-build.qbs0000644000175100001660000000067614776170045030230 0ustar runnerdockerCppApplication { name: "the product" files: ["file1.cpp", "file2.cpp", "main.cpp"] cpp.cxxFlags: ["-flto"] Probe { id: checker property bool isGcc: qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("clang") property string objectSuffix: cpp.objectSuffix configure: { console.info("is gcc: " + isGcc); console.info("object suffix: " + objectSuffix); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/reproducible-build/file1.cpp0000644000175100001660000000240314776170045025437 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ static void f() { } void f1() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/reproducible-build/main.cpp0000644000175100001660000000242514776170045025367 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f1(); void f2(); int main() { f1(); f2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/reproducible-build/file2.cpp0000644000175100001660000000240314776170045025440 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ static void f() { } void f2() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/conflicting-artifacts/0000755000175100001660000000000014776170045024435 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conflicting-artifacts/conflicting-artifacts.qbs0000644000175100001660000000050414776170045031420 0ustar runnerdockerProject { CppApplication { name: "a" targetName: "theName" destinationDirectory: project.buildDirectory files: ["main.cpp"] } CppApplication { name: "b" targetName: "theName" destinationDirectory: project.buildDirectory files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/conflicting-artifacts/main.cpp0000644000175100001660000000235114776170045026066 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-language-version/0000755000175100001660000000000014776170045024226 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-language-version/main.cpp0000644000175100001660000000001614776170045025653 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs0000644000175100001660000000210614776170045031002 0ustar runnerdockerCppApplication { name: "app" files: ["main.cpp"] Probe { id: compilerProbe property stringList toolchain: qbs.toolchain property string compilerVersion: cpp.compilerVersion configure: { var isNewerMsvc; var isEvenNewerMsvc; var isOlderMsvc; var isGcc; if (toolchain.includes("clang-cl")) { isEvenNewerMsvc = true; isNewerMsvc = true; } else if (toolchain.includes("msvc")) { if (compilerVersion >= "19.12.25831") isEvenNewerMsvc = true; if (compilerVersion >= "18.00.30723") isNewerMsvc = true; else isOlderMsvc = true; } else { isGcc = true; } console.info("is newer MSVC: " + isNewerMsvc); console.info("is even newer MSVC: " + isEvenNewerMsvc); console.info("is older MSVC: " + isOlderMsvc); console.info("is GCC: " + isGcc); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/install-root-from-project-file/0000755000175100001660000000000014776170045026131 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-root-from-project-file/file.txt0000644000175100001660000000000014776170045027577 0ustar runnerdocker././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/install-root-from-project-file/install-root-from-project-file.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/install-root-from-project-file/install-root-from-project-0000644000175100001660000000036714776170045033173 0ustar runnerdockerProduct { name: "p" property string installRoot qbs.installRoot: installRoot Group { qbs.install: true qbs.installPrefix: "/install-prefix" qbs.installDir: "/install-dir" files: ["file.txt"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/0000755000175100001660000000000014776170045026617 5ustar runnerdocker././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/transitive-optional-dependencies.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/transitive-optional-depe0000644000175100001660000000004614776170045033470 0ustar runnerdockerProduct { Depends { name: "a" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/modules/0000755000175100001660000000000014776170045030267 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/modules/a/0000755000175100001660000000000014776170045030507 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/modules/a/a.qbs0000644000175100001660000000006614776170045031440 0ustar runnerdockerModule { Depends { name: "b"; required: false } } qbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/modules/b/0000755000175100001660000000000014776170045030510 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/transitive-optional-dependencies/modules/b/b.qbs0000644000175100001660000000004014776170045031432 0ustar runnerdockerModule { condition: false } qbs-src-2.6.1/tests/auto/blackbox/testdata/archiver/0000755000175100001660000000000014776170045021763 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/archiver/test.txt0000644000175100001660000000000014776170045023471 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/archiver/archivable.qbs0000644000175100001660000000036514776170045024576 0ustar runnerdockerProduct { name: "archivable" type: "archiver.archive" Depends { name: "archiver" } archiver.workingDirectory: path Group { files: ["list.txt"] fileTags: ["archiver.input-list"] } files: ["test.txt"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/archiver/list.txt0000644000175100001660000000003014776170045023470 0ustar runnerdockertest.txt archivable.qbs qbs-src-2.6.1/tests/auto/blackbox/testdata/referenceErrorInExport/0000755000175100001660000000000014776170045024621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/referenceErrorInExport/referenceErrorInExport.qbs0000644000175100001660000000054714776170045031777 0ustar runnerdockerProject { 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 } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/referenceErrorInExport/main.c0000644000175100001660000000236414776170045025716 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/0000755000175100001660000000000014776170045025321 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/main.c0000644000175100001660000000003114776170045026403 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/maximum-c-language-version.qbs0000644000175100001660000000137614776170045033200 0ustar runnerdockerCppApplication { name: "app" property bool enableNewestModule: true Probe { id: osProbe property string toolchainType: qbs.toolchainType property string compilerVersion: cpp.compilerVersion configure: { console.info("is msvc: " + (toolchainType === "msvc" || toolchainType === "clang-cl")); var isOld = (toolchainType === "msvc" && compilerVersion < "19.29.30138") || (toolchainType === "clang-cl" && compilerVersion < "13"); console.info("is old msvc: " + isOld); found = true; } } Depends { name: "oldmodule" } Depends { name: "newermodule" } Depends { name: "newestmodule"; condition: enableNewestModule } files: "main.c" } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/0000755000175100001660000000000014776170045026771 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/oldmodule/0000755000175100001660000000000014776170045030755 5ustar runnerdocker././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/oldmodule/oldmodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/oldmodule/oldmodule.qb0000644000175100001660000000010714776170045033263 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.cLanguageVersion: "c90" } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/newermodule/0000755000175100001660000000000014776170045031317 5ustar runnerdocker././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/newermodule/newermodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/newermodule/newermodul0000644000175100001660000000010714776170045033421 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.cLanguageVersion: "c99" } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/newestmodule/0000755000175100001660000000000014776170045031504 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/newestmodule/newestmodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-c-language-version/modules/newestmodule/newestmod0000644000175100001660000000010714776170045033432 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.cLanguageVersion: "c11" } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableRtti/0000755000175100001660000000000014776170045022251 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/enableRtti/rtti.qbs0000644000175100001660000000043114776170045023740 0ustar runnerdockerProject { property bool treatAsObjcpp: false CppApplication { cpp.cxxLanguageVersion: "c++11" cpp.treatWarningsAsErrors: true Group { files: ["main.cpp"] fileTags: [project.treatAsObjcpp ? "objcpp" : "cpp"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableRtti/main.cpp0000644000175100001660000000330514776170045023702 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #if defined(__GNUC__) && !(defined(__cpp_rtti) || defined(__GXX_RTTI)) #error RTTI is disabled! #endif #if defined(_MSC_VER) && !defined (_CPPRTTI) #error RTTI is disabled! #endif class I { public: virtual ~I() { } virtual void x() { } }; class A : public I { void x() override { } }; class B : public I { void x() override { } }; int main() { const auto a = new A(); B *b = dynamic_cast(a); (void)b; delete a; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/multiplexed-tool/0000755000175100001660000000000014776170045023467 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/multiplexed-tool/tool.cpp0000644000175100001660000000013014776170045025142 0ustar runnerdocker#include int main() { #ifdef WRONG_VARIANT return EXIT_FAILURE; #endif } qbs-src-2.6.1/tests/auto/blackbox/testdata/multiplexed-tool/multiplexed-tool.qbs0000644000175100001660000000361314776170045027510 0ustar runnerdockerimport qbs.Host Project { CppApplication { name: "tool" consoleApplication: true property bool _testPlatform: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Profile { name: "debugProfile" baseProfile: project.profile qbs.buildVariant: "debug" } Profile { name: "releaseProfile" baseProfile: project.profile qbs.buildVariant: "release" } multiplexByQbsProperties: "profiles" qbs.profiles: ["debugProfile", "releaseProfile"] files: "tool.cpp" Properties { condition: qbs.buildVariant === "debug" cpp.defines: "WRONG_VARIANT" } Export { Rule { multiplex: true inputsFromDependencies: "application" Artifact { filePath: "tool.out" fileTags: "tool.output" } prepare: { var cmd = new Command(input.filePath, []); cmd.description = "creating " + output.fileName; return cmd; } } } } Product { name: "p" type: "tool.output" multiplexByQbsProperties: "buildVariants" qbs.buildVariants: ["debug", "release"] Depends { name: "tool"; profiles: "releaseProfile" } } Product { name: "p2" type: "tool.output" multiplexByQbsProperties: "buildVariants" qbs.buildVariants: ["debug", "release"] Depends { name: "helper" } } Product { name: "helper" Export { Depends { name: "tool"; profiles: "releaseProfile" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/0000755000175100001660000000000014776170045024126 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/product.qbs0000644000175100001660000000040114776170045026310 0ustar runnerdockerProduct { type: "outtype" name: "toplevel" Depends { name: "higher1" } Depends { name: "higher2" } Depends { name: "higher3" } lower.listProp: ["product"] Group { files: ["dummy.txt"] fileTags: ["intype"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/dummy.txt0000644000175100001660000000000014776170045026010 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/0000755000175100001660000000000014776170045025576 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/higher1/0000755000175100001660000000000014776170045027125 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/higher1/higher1.qbs0000644000175100001660000000011114776170045031154 0ustar runnerdockerModule { Depends { name: "lower" } lower.listProp: ["higher1"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/higher2/0000755000175100001660000000000014776170045027126 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/higher2/higher2.qbs0000644000175100001660000000011114776170045031156 0ustar runnerdockerModule { Depends { name: "lower" } lower.listProp: ["higher2"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/lower/0000755000175100001660000000000014776170045026726 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs0000644000175100001660000000073114776170045030566 0ustar runnerdockerModule { property stringList listProp: [ "lower" ] Rule { inputs: ["intype"] Artifact { filePath: "dummy.out" fileTags: "outtype" } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = function() { console.warn("listProp = " + JSON.stringify(product.lower.listProp)); }; cmd.silent = true; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/higher3/0000755000175100001660000000000014776170045027127 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-property-order/modules/higher3/higher3.qbs0000644000175100001660000000011114776170045031160 0ustar runnerdockerModule { Depends { name: "lower" } lower.listProp: ["higher3"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf-library-install/0000755000175100001660000000000014776170045025126 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf-library-install/protobuf-library.qbs0000644000175100001660000000151214776170045031136 0ustar runnerdockerimport qbs.Host StaticLibrary { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.8" protobuf.cpp.importPaths: product.sourceDirectory Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); return protobuf.cpp.present; } Group { fileTagsFilter: "protobuf.hpp" qbs.installDir: "include" qbs.installSourceBase: protobuf.cpp.outputDir qbs.install: true } files: [ "hello.proto", "hello/world.proto", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf-library-install/hello.proto0000644000175100001660000000017114776170045027315 0ustar runnerdockersyntax = "proto3"; package protobuf.library; import "hello/world.proto"; message Hello { hello.World world = 1; }; qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf-library-install/hello/0000755000175100001660000000000014776170045026231 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf-library-install/hello/world.proto0000644000175100001660000000013414776170045030443 0ustar runnerdockersyntax = "proto3"; package protobuf.library.hello; message World { int32 value = 1; }; qbs-src-2.6.1/tests/auto/blackbox/testdata/error-info/0000755000175100001660000000000014776170045022242 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/error-info/error-info.qbs0000644000175100001660000000346414776170045025042 0ustar runnerdockerimport "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 { name: "myproduct" type: ["foo", "bar"] Rule { multiplex: true 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 { multiplex: true 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; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/error-info/helper.js0000644000175100001660000000016014776170045024054 0ustar runnerdockervar x; function doSomethingBad() { nothinghere.works; } function doSomethingEvil() { throw "OUCH!"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/0000755000175100001660000000000014776170045021603 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.qbs0000644000175100001660000000114614776170045027176 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuf.cpp.present); return flatbuf.cpp.present; } flatbuf.cpp.filenameExtension: "hpp" files: [ "flat_filename_extension.cpp", "foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_filename_extension.cpp0000644000175100001660000000077114776170045027176 0ustar runnerdocker#include "foo_generated.hpp" #include using namespace QbsTest; int main() { flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("John Doe"); auto newFoo = QbsTest::CreateFoo(builder, name, 42); builder.Finish(newFoo); auto foo = GetFoo(builder.GetBufferPointer()); assert(foo->name()->str() == "John Doe"); assert(foo->count() == 42); std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_cpp.qbs0000644000175100001660000000105114776170045024077 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuf.cpp.present); return flatbuf.cpp.present; } files: [ "flat.cpp", "foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.qbs0000644000175100001660000000111414776170045026522 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuf.cpp.present); return flatbuf.cpp.present; } files: [ "flat_relative_import.cpp", "bar.fbs", "foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.cpp0000644000175100001660000000076114776170045026465 0ustar runnerdocker#include "foo.fbs.h" #include using namespace QbsTest; int main() { flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("John Doe"); auto newFoo = QbsTest::CreateFoo(builder, name, 42); builder.Finish(newFoo); auto foo = GetFoo(builder.GetBufferPointer()); assert(foo->name()->str() == "John Doe"); assert(foo->count() == 42); std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/foo.fbs0000644000175100001660000000011614776170045023060 0ustar runnerdockernamespace QbsTest; table Foo { name:string; count:int; } root_type Foo; qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/imports/0000755000175100001660000000000014776170045023300 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/imports/imported_foo/0000755000175100001660000000000014776170045025766 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/imports/imported_foo/imported_foo.fbs0000644000175100001660000000011614776170045031146 0ustar runnerdockernamespace QbsTest; table Foo { name:string; count:int; } root_type Foo; qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/conanfile.txt0000644000175100001660000000013014776170045024274 0ustar runnerdocker[requires] flatbuffers/24.3.25 [tool_requires] flatbuffers/24.3.25 [generators] QbsDeps qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/baz.fbs0000644000175100001660000000014714776170045023055 0ustar runnerdockerinclude "imported_foo/imported_foo.fbs"; namespace QbsTest; table Baz { foo:Foo; } root_type Baz; qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/bar.fbs0000644000175100001660000000012114776170045023035 0ustar runnerdockerinclude "foo.fbs"; namespace QbsTest; table Bar { foo:Foo; } root_type Bar; qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_relative_import.cpp0000644000175100001660000000107614776170045026526 0ustar runnerdocker#include "bar_generated.h" #include using namespace QbsTest; int main() { flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("John Doe"); auto newFoo = QbsTest::CreateFoo(builder, name, 42); auto newBar = QbsTest::CreateBar(builder, newFoo); builder.Finish(newBar); auto bar = GetBar(builder.GetBufferPointer()); assert(bar->foo()->name()->str() == "John Doe"); assert(bar->foo()->count() == 42); std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat.c0000644000175100001660000000152314776170045022676 0ustar runnerdocker#include "foo_builder.h" #include #undef ns #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(QbsTest, x) // Specified in the schema. #define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while (0) int main() { void *buffer = NULL; size_t size = 0; flatcc_builder_t builder; flatcc_builder_init(&builder); flatbuffers_string_ref_t name = flatbuffers_string_create_str(&builder, "John Doe"); ns(Foo_create_as_root(&builder, name, 42)); buffer = flatcc_builder_finalize_aligned_buffer(&builder, &size); ns(Foo_table_t) foo = ns(Foo_as_root(buffer)); test_assert(strcmp(ns(Foo_name(foo)), "John Doe") == 0); test_assert(ns(Foo_count(foo)) == 42); free(buffer); flatcc_builder_clear(&builder); printf("The FlatBuffer was successfully created and accessed!\n"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_filename_suffix.qbs0000644000175100001660000000114114776170045026461 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuf.cpp.present); return flatbuf.cpp.present; } flatbuf.cpp.filenameSuffix: ".fbs" files: [ "flat_filename_suffix.cpp", "foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.qbs0000644000175100001660000000126014776170045025620 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuf.cpp.present); return flatbuf.cpp.present; } flatbuf.cpp.importPaths: "imports/" flatbuf.cpp.keepPrefix: true files: [ "flat_keep_prefix.cpp", "baz.fbs", "imports/imported_foo/imported_foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.qbs0000644000175100001660000000122314776170045026526 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuf.cpp.present); return flatbuf.cpp.present; } flatbuf.cpp.importPaths: "imports/" files: [ "flat_absolute_import.cpp", "baz.fbs", "imports/imported_foo/imported_foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_keep_prefix.cpp0000644000175100001660000000115714776170045025622 0ustar runnerdocker#include "baz_generated.h" #include "imported_foo/imported_foo_generated.h" #include using namespace QbsTest; int main() { flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("John Doe"); auto newFoo = QbsTest::CreateFoo(builder, name, 42); auto newBaz = QbsTest::CreateBaz(builder, newFoo); builder.Finish(newBaz); auto baz = GetBaz(builder.GetBufferPointer()); assert(baz->foo()->name()->str() == "John Doe"); assert(baz->foo()->count() == 42); std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_absolute_import.cpp0000644000175100001660000000107614776170045026531 0ustar runnerdocker#include "baz_generated.h" #include using namespace QbsTest; int main() { flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("John Doe"); auto newFoo = QbsTest::CreateFoo(builder, name, 42); auto newBaz = QbsTest::CreateBaz(builder, newFoo); builder.Finish(newBaz); auto baz = GetBaz(builder.GetBufferPointer()); assert(baz->foo()->name()->str() == "John Doe"); assert(baz->foo()->count() == 42); std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat_c.qbs0000644000175100001660000000105514776170045023543 0ustar runnerdockerCppApplication { Depends { name: "flatbuffers.c"; required: false } consoleApplication: true condition: { var result = qbs.targetPlatform === qbs.hostPlatform; if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasFlatbuffers; } property bool hasFlatbuffers: { console.info("has flatbuffers: " + flatbuffers.c.present); return flatbuffers.c.present; } files: [ "flat.c", "foo.fbs", ] qbsModuleProviders: "conan" } qbs-src-2.6.1/tests/auto/blackbox/testdata/flatbuf/flat.cpp0000644000175100001660000000076714776170045023247 0ustar runnerdocker#include "foo_generated.h" #include using namespace QbsTest; int main() { flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("John Doe"); auto newFoo = QbsTest::CreateFoo(builder, name, 42); builder.Finish(newFoo); auto foo = GetFoo(builder.GetBufferPointer()); assert(foo->name()->str() == "John Doe"); assert(foo->count() == 42); std::cout << "The FlatBuffer was successfully created and accessed!" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/escaped-linker-flags/0000755000175100001660000000000014776170045024140 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/escaped-linker-flags/escaped-linker-flags.qbs0000644000175100001660000000074114776170045030631 0ustar runnerdockerCppApplication { name: "app" property bool escapeLinkerFlags Properties { condition: escapeLinkerFlags cpp.linkerFlags: ["-Wl,-s"] } Properties { condition: !escapeLinkerFlags cpp.linkerFlags: ["-s"] } files: ["main.cpp"] Probe { id: checker property bool isUnixGcc: qbs.toolchain.contains("gcc") && !qbs.targetOS.contains("macos") configure: { console.info("is gcc: " + isUnixGcc); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/escaped-linker-flags/main.cpp0000644000175100001660000000001714776170045025566 0ustar runnerdockerint main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/0000755000175100001660000000000014776170045024525 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/choose-module-instance.qbs0000644000175100001660000000062414776170045031603 0ustar runnerdockerimport qbs.FileInfo Project { qbsSearchPaths: [ ".", path, "modules/..", FileInfo.path(FileInfo.joinPaths(path, "modules")), "other-searchpath" ] Product { Depends { name: "limerick"; versionAtLeast: "2" } type: ["text"] files: ["gerbil.txt.in"] Group { fileTagsFilter: product.type qbs.install: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/0000755000175100001660000000000014776170045027766 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/0000755000175100001660000000000014776170045031436 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/0000755000175100001660000000000014776170045033235 5ustar runnerdocker././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/generic.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/other-searchpath/modules/limerick/0000644000175100001660000000007414776170045033240 0ustar runnerdockerModule { condition: !qbs.targetOS.includes("Beatles") } qbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/modules/0000755000175100001660000000000014776170045026175 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/modules/limerick/0000755000175100001660000000000014776170045027774 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/modules/limerick/lord.qbs0000644000175100001660000000031614776170045031443 0ustar runnerdockerModule { condition: qbs.targetOS.containsAny(["Deep Purple", "Whitesnake"]) version: "3" Depends { name: "texttemplate" } texttemplate.dict: ({DID: "chewed", THING: "cord", IDOL: "lord"}) } qbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/modules/limerick/ritchie.qbs0000644000175100001660000000052414776170045032133 0ustar runnerdockerModule { condition: qbs.targetOS.containsAny(["Deep Purple", "Rainbow"]) priority: 1 // Overrides the more general "lord.qbs" instance, // which also matches on "Deep Purple". version: "2" Depends { name: "texttemplate" } texttemplate.dict: ({DID: "slipped", THING: "litchi", IDOL: "ritchie"}) } qbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/modules/limerick/outdated.qbs0000644000175100001660000000005614776170045032315 0ustar runnerdockerModule { priority: 100 version: "1" } qbs-src-2.6.1/tests/auto/blackbox/testdata/choose-module-instance/gerbil.txt.in0000644000175100001660000000021714776170045027137 0ustar runnerdockerI once had a gerbil named Bobby, Who had an unusual hobby. He ${DID} on a ${THING}, and now -- oh my ${IDOL}, now all that's left is a blobby. qbs-src-2.6.1/tests/auto/blackbox/testdata/discard-unused-data/0000755000175100001660000000000014776170045024001 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/discard-unused-data/discard-unused-data.qbs0000644000175100001660000000141314776170045030330 0ustar runnerdockerCppApplication { name: "app" type: base.concat("custom") property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: "main.cpp" Depends { name: "bundle"; condition: qbs.targetOS.includes("darwin") } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Rule { multiplex: true outputFileTags: "custom" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info("is Darwin: " + product.qbs.targetOS.includes("darwin")); console.info("---" + product.cpp.nmPath + "---"); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/discard-unused-data/main.cpp0000644000175100001660000000004414776170045025427 0ustar runnerdockervoid unusedFunc() {} int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/0000755000175100001660000000000014776170045022775 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/includeLookup.qbs0000644000175100001660000000103614776170045026321 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { property string name: 'includeLookup' qbsSearchPaths: '.' Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } type: 'application' consoleApplication: true name: project.name files: 'main.cpp' Depends { name: 'cpp' } Depends { name: 'definition' } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/main.cpp0000644000175100001660000000245514776170045024433 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::printf("%s..\n", TEXT); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/modules/0000755000175100001660000000000014776170045024445 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/modules/definition/0000755000175100001660000000000014776170045026575 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/modules/definition/fakeopenssl/0000755000175100001660000000000014776170045031107 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/modules/definition/fakeopenssl/sha.h0000644000175100001660000000000014776170045032021 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/includeLookup/modules/definition/module.qbs0000644000175100001660000000051614776170045030573 0ustar runnerdockerimport qbs.Probes Module { name: 'definition' Depends { name: 'cpp' } property string modulePath: path Probes.IncludeProbe { id: includeNode names: "fakeopenssl/sha.h" platformSearchPaths: [modulePath] } cpp.defines: includeNode.found ? 'TEXT="' + includeNode.path + '"' : undefined } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/0000755000175100001660000000000014776170045022020 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.proto0000644000175100001660000000154314776170045026745 0ustar runnerdocker// See README.txt for information and build instructions. // // Note: START and END tags are used in comments to define sections used in // tutorials. They are not part of the syntax for Protocol Buffers. // // To get an in-depth walkthrough of this file and the related examples, see: // https://developers.google.com/protocol-buffers/docs/tutorials // [START declaration] syntax = "proto3"; package tutorial; // [END declaration] // [START messages] message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; } // Our address book file is just one of these. message AddressBook { repeated Person people = 1; } // [END messages] qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs0000644000175100001660000000127014776170045025671 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } name: "addressbook_cpp" consoleApplication: true Depends { name: "cpp" } cpp.minimumMacosVersion: "10.15" Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } files: [ "addressbook.proto", "main.cpp", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/main_nanopb.cpp0000644000175100001660000000477514776170045025022 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Kai Dohmen (psykai1993@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include #include #include #include "addressbook_nanopb.pb.h" static_assert(std::is_array().name)>::value, ""); static_assert(std::is_array().email)>::value, ""); static_assert(std::is_array().phones)>::value, ""); bool writeString(pb_ostream_t *stream, const pb_field_t *field, void *const *) { constexpr auto str = "0123456789"; if (!pb_encode_tag_for_field(stream, field)) return false; return pb_encode_string(stream, reinterpret_cast(str), strlen(str)); } int main() { std::array buffer = {}; tutorial_Person_PhoneNumber phoneNumber; phoneNumber.number.funcs.encode = writeString; phoneNumber.type = tutorial_Person_PhoneType_WORK; auto ostream = pb_ostream_from_buffer(buffer.data(), buffer.size()); assert(pb_encode(&ostream, tutorial_Person_PhoneNumber_fields, &phoneNumber)); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/subdir/0000755000175100001660000000000014776170045023310 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/subdir/myenum.proto0000644000175100001660000000007414776170045025710 0ustar runnerdockersyntax = "proto2"; enum MyEnum { VAL1 = 0; VAL2 = 1; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/conanfile.txt0000644000175100001660000000012214776170045024512 0ustar runnerdocker[requires] protobuf/3.21.12 [tool_requires] protobuf/3.21.12 [generators] QbsDeps qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp0000644000175100001660000000315314776170045026632 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include int main() { MyMessage message; message.set_msg("msg"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/import.proto0000644000175100001660000000014314776170045024415 0ustar runnerdockersyntax = "proto2"; import "subdir/myenum.proto"; message MyMessage { required string msg = 1; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/addressbook.proto0000644000175100001660000000232214776170045025404 0ustar runnerdocker// See README.txt for information and build instructions. // // Note: START and END tags are used in comments to define sections used in // tutorials. They are not part of the syntax for Protocol Buffers. // // To get an in-depth walkthrough of this file and the related examples, see: // https://developers.google.com/protocol-buffers/docs/tutorials // [START declaration] syntax = "proto3"; package tutorial; import "google/protobuf/timestamp.proto"; // [END declaration] // [START java_declaration] option java_package = "com.example.tutorial"; option java_outer_classname = "AddressBookProtos"; // [END java_declaration] // [START csharp_declaration] option csharp_namespace = "Google.Protobuf.Examples.AddressBook"; // [END csharp_declaration] // [START messages] message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5; } // Our address book file is just one of these. message AddressBook { repeated Person people = 1; } // [END messages] qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/needs-import-dir.proto0000644000175100001660000000013414776170045026265 0ustar runnerdockersyntax = "proto2"; import "myenum.proto"; message MyMessage { required string msg = 1; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/create-proto-library.qbs0000644000175100001660000000254714776170045026605 0ustar runnerdockerimport qbs.Host Project { StaticLibrary { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } name: "proto_lib" Depends { name: "cpp" } cpp.minimumMacosVersion: "10.8" protobuf.cpp.importPaths: product.sourceDirectory Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } files: [ "import.proto", "subdir/myenum.proto", ] Export { Depends { name: "cpp" } Depends { name: "protobuf.cpp"; required: false } cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.8" cpp.includePaths: exportingProduct.protobuf.cpp.outputDir } } CppApplication { condition: proto_lib.present name: "consumes_proto_lib" consoleApplication: true files: [ "import-main.cpp", ] Depends { name: "proto_lib" required: false } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.qbs0000644000175100001660000000143714776170045026371 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } name: "addressbook_nanopb" consoleApplication: true Depends { name: "cpp" } cpp.minimumMacosVersion: "10.8" Depends { name: "protobuf.nanopb"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.nanopb.present); console.info("has modules: false"); return protobuf.nanopb.present; } protobuf.nanopb.importPaths: product.sourceDirectory files: [ "addressbook_nanopb.proto", "addressbook_nanopb.options", "main_nanopb.cpp", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/import-main.cpp0000644000175100001660000000314114776170045024757 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include int main() { MyMessage message; message.set_msg("msg"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs0000644000175100001660000000150114776170045025706 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } name: "app" consoleApplication: true property path theImportDir protobuf.cpp.importPaths: (theImportDir ? [theImportDir] : []).concat([sourceDirectory]) cpp.minimumMacosVersion: "10.8" Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } files: [ "needs-import-dir.proto", "needs-import-dir-main.cpp", "subdir/myenum.proto", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs0000644000175100001660000000120314776170045026020 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } name: "addressbook_objc" consoleApplication: true Depends { name: "cpp" } Depends { name: "protobuf.objc"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.objc.present); console.info("has modules: false"); return protobuf.objc.present; } files: [ "addressbook.proto", "main.m", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/main.m0000644000175100001660000000373614776170045023133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import "Addressbook.pbobjc.h" int main(int argc, char* argv[]) { AddressBook *addressBook = [[AddressBook alloc] init]; Person *person = [[Person alloc] init]; person.name = @"name"; person.id_p = 1; person.email = @"email"; Person_PhoneNumber *number = [[Person_PhoneNumber alloc] init]; number.number = @"number"; number.type = Person_PhoneType_Mobile; [addressBook.peopleArray addObject:person]; [addressBook release]; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/import.qbs0000644000175100001660000000134114776170045024040 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result && hasProtobuf; } name: "app" consoleApplication: true protobuf.cpp.importPaths: [sourceDirectory] cpp.minimumMacosVersion: "10.8" Depends { name: "protobuf.cpp"; required: false } property bool hasProtobuf: { console.info("has protobuf: " + protobuf.cpp.present); console.info("has modules: " + protobuflib.present); return protobuf.cpp.present; } files: [ "import.proto", "import-main.cpp", "subdir/myenum.proto", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/main.cpp0000644000175100001660000000423414776170045023453 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include #include #include "addressbook.pb.h" using google::protobuf::util::TimeUtil; int main(int /*argc*/, char* /*argv*/[]) { GOOGLE_PROTOBUF_VERIFY_VERSION; tutorial::AddressBook addressBook; auto person = addressBook.add_people(); person->set_name("name"); person->set_id(1); person->set_email("email"); auto phone_number = person->add_phones(); phone_number->set_number("number"); phone_number->set_type(tutorial::Person::MOBILE); *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(nullptr)); google::protobuf::ShutdownProtobufLibrary(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/protobuf/addressbook_nanopb.options0000644000175100001660000000015114776170045027267 0ustar runnerdockertutorial.Person.name max_size:128 tutorial.Person.email max_size:256 tutorial.Person.phones max_count:16 qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-temporarydir/0000755000175100001660000000000014776170045025433 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-temporarydir/jsextensions-temporarydir.qbs0000644000175100001660000000113414776170045033414 0ustar runnerdockerimport qbs.File import qbs.TemporaryDir Product { targetName: { var dir; var dirPath; try { dir = new TemporaryDir(); dirPath = dir.path(); if (!dirPath) throw "path is empty"; if (!dir.isValid()) throw "dir is not valid"; if (!File.exists(dirPath)) throw "dir does not exist"; } finally { if (!dir.remove()) throw "could not remove"; } if (File.exists(dirPath)) throw "dir was not removed"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/0000755000175100001660000000000014776170045021610 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/one-grammar/0000755000175100001660000000000014776170045024015 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/one-grammar/types.h0000644000175100001660000000325414776170045025336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include struct Tree; using TreePtr = std::shared_ptr; struct Tree { std::string val; std::vector children; void print() const { std::cout << val << ' '; for (const TreePtr &t : children) t->print(); } }; struct YaccType { TreePtr t; std::string s; }; #define YYSTYPE YaccType extern TreePtr root; int yylex(); void yyerror(const char *); qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/one-grammar/parser.y0000644000175100001660000000117314776170045025505 0ustar runnerdocker%{ #include %} %type expr %left OR %left AND %nonassoc NOT %token ID %% start: expr { root = $1; } expr: expr AND expr { auto t = std::make_shared(); t->val = "AND"; t->children = { $1, $3 }; $$ = t; } | expr OR expr { auto t = std::make_shared(); t->val = "OR"; t->children = { $1, $3 }; $$ = t; } | NOT expr { auto t = std::make_shared(); t->val = "NOT"; t->children = { $2 }; $$ = t; } | ID { auto t = std::make_shared(); t->val = $1; $$ = t; } %% TreePtr root; int main() { yyparse(); if (!root) return 1; root->print(); std::cout << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/one-grammar/lexer.l0000644000175100001660000000045114776170045025311 0ustar runnerdocker%{ #include #include void yyerror(const char *e) { std::cerr << e; } extern "C" int yywrap() { return 1; } extern YYSTYPE yylval; %} ID [a-z]+ AND "&&" OR "||" NOT "!" %% [[:space:]]+ {ID} yylval.s = yytext; return ID; {AND} return AND; {OR} return OR; {NOT} return NOT; %% qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs0000644000175100001660000000223414776170045026732 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); console.info("executable suffix: " + cpp.executableSuffix); return result; } qbsSearchPaths: ".." Depends { name: "bisonhelper" } Depends { name: "lex_yacc" } lex_yacc.outputTag: "cpp" lex_yacc.yaccFlags: ["-l"] cpp.includePaths: [".", ".."] cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" consoleApplication: true Probe { id: pathCheck property string theDir: { if (qbs.targetOS.includes("windows")) { if (qbs.toolchain.includes("mingw")) return cpp.toolchainInstallPath; if (qbs.toolchain.includes("clang") && qbs.sysroot) return qbs.sysroot + "/bin"; } } configure: { if (theDir) console.info("add to PATH: " + theDir); found = true; } } files: [ "lexer.l", "parser.y", "types.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_prefix/0000755000175100001660000000000014776170045023755 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_prefix/lex_prefix.qbs0000644000175100001660000000060214776170045026627 0ustar runnerdockerCppApplication { qbsSearchPaths: ".." Depends { name: "bisonhelper" } Depends { name: "lex_yacc" } lex_yacc.outputTag: "cpp" lex_yacc.yaccFlags: ["-l"] cpp.includePaths: [".", ".."] cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" consoleApplication: true files: [ "lexer.l", "parser.y", "types.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_prefix/types.h0000644000175100001660000000325714776170045025301 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include struct Tree; using TreePtr = std::shared_ptr; struct Tree { std::string val; std::vector children; void print() const { std::cout << val << ' '; for (const TreePtr &t : children) t->print(); } }; struct YaccType { TreePtr t; std::string s; }; #define BLASTYPE YaccType extern TreePtr root; int blalex(); void blaerror(const char *); qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_prefix/parser.y0000644000175100001660000000122514776170045025443 0ustar runnerdocker%{ #include %} %define api.prefix {bla} %type expr %left OR %left AND %nonassoc NOT %token ID %% start: expr { root = $1; } expr: expr AND expr { auto t = std::make_shared(); t->val = "AND"; t->children = { $1, $3 }; $$ = t; } | expr OR expr { auto t = std::make_shared(); t->val = "OR"; t->children = { $1, $3 }; $$ = t; } | NOT expr { auto t = std::make_shared(); t->val = "NOT"; t->children = { $2 }; $$ = t; } | ID { auto t = std::make_shared(); t->val = $1; $$ = t; } %% TreePtr root; int main() { blaparse(); if (!root) return 1; root->print(); std::cout << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_prefix/lexer.l0000644000175100001660000000045314776170045025253 0ustar runnerdocker%option prefix="bla" %{ #include void blaerror(const char *e) { std::cerr << e; } extern "C" int blawrap() { return 1; } extern BLASTYPE blalval; %} ID [a-z]+ AND "&&" OR "||" NOT "!" %% [[:space:]]+ {ID} blalval.s = blatext; return 1; {AND} return 2; {OR} return 3; {NOT} return 4; %% qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/0000755000175100001660000000000014776170045024230 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/g2.l0000644000175100001660000000012414776170045024712 0ustar runnerdocker%option noyywrap %{ #include void g2error(const char *e) { } %} %% %% qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/g1.l0000644000175100001660000000024014776170045024710 0ustar runnerdocker%option noyywrap %{ #include #ifdef _MSC_BUILD #pragma message("whatever") #else #pragma whatever #endif void g1error(const char *e) { } %} %% %% qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/g2.y0000644000175100001660000000007714776170045024736 0ustar runnerdocker%{ int g2lex(); void g2error(const char *s); %} %% expr: '1' qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/g1.y0000644000175100001660000000007714776170045024735 0ustar runnerdocker%{ int g1lex(); void g1error(const char *s); %} %% expr: '1' qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/main.c0000644000175100001660000000246514776170045025327 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int g1parse(); int g2parse(); int main() { g1parse(); g2parse(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/two-grammars/two-grammars.qbs0000644000175100001660000000034214776170045027356 0ustar runnerdockerimport qbs.Host CppApplication { Depends { name: "lex_yacc" } consoleApplication: true cpp.includePaths: ".." files: [ "g1.l", "g1.y", "g2.l", "g2.y", "main.c", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/yacc_output/0000755000175100001660000000000014776170045024147 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/yacc_output/types.h0000644000175100001660000000325414776170045025470 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include struct Tree; using TreePtr = std::shared_ptr; struct Tree { std::string val; std::vector children; void print() const { std::cout << val << ' '; for (const TreePtr &t : children) t->print(); } }; struct YaccType { TreePtr t; std::string s; }; #define YYSTYPE YaccType extern TreePtr root; int yylex(); void yyerror(const char *); qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/yacc_output/parser.y0000644000175100001660000000122014776170045025630 0ustar runnerdocker%{ #include %} %output "parser.cxx" %type expr %left OR %left AND %nonassoc NOT %token ID %% start: expr { root = $1; } expr: expr AND expr { auto t = std::make_shared(); t->val = "AND"; t->children = { $1, $3 }; $$ = t; } | expr OR expr { auto t = std::make_shared(); t->val = "OR"; t->children = { $1, $3 }; $$ = t; } | NOT expr { auto t = std::make_shared(); t->val = "NOT"; t->children = { $2 }; $$ = t; } | ID { auto t = std::make_shared(); t->val = $1; $$ = t; } %% TreePtr root; int main() { yyparse(); if (!root) return 1; root->print(); std::cout << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/yacc_output/lexer.l0000644000175100001660000000045414776170045025446 0ustar runnerdocker%{ #include #include void yyerror(const char *e) { std::cerr << e; } extern "C" int yywrap() { return 1; } extern YYSTYPE yylval; %} ID [a-z]+ AND "&&" OR "||" NOT "!" %% [[:space:]]+ {ID} yylval.s = yytext; return ID; {AND} return AND; {OR} return OR; {NOT} return NOT; %% qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/yacc_output/yacc_output.qbs0000644000175100001660000000050514776170045027215 0ustar runnerdockerCppApplication { Depends { name: "lex_yacc" } lex_yacc.outputTag: "cpp" lex_yacc.yaccFlags: ["-l"] cpp.includePaths: [".", ".."] cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" consoleApplication: true files: [ "lexer.l", "parser.y", "types.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/unistd.h0000644000175100001660000000022014776170045023261 0ustar runnerdocker#ifndef MY_UNISTD_H #define MY_UNISTD_H #ifdef _MSC_BUILD #include #define isatty _isatty #else #include_next #endif #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_outfile/0000755000175100001660000000000014776170045024127 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_outfile/lex_outfile.qbs0000644000175100001660000000060214776170045027153 0ustar runnerdockerCppApplication { qbsSearchPaths: ".." Depends { name: "bisonhelper" } Depends { name: "lex_yacc" } lex_yacc.outputTag: "cpp" lex_yacc.yaccFlags: ["-l"] cpp.includePaths: [".", ".."] cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" consoleApplication: true files: [ "lexer.l", "parser.y", "types.h", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_outfile/types.h0000644000175100001660000000325414776170045025450 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include struct Tree; using TreePtr = std::shared_ptr; struct Tree { std::string val; std::vector children; void print() const { std::cout << val << ' '; for (const TreePtr &t : children) t->print(); } }; struct YaccType { TreePtr t; std::string s; }; #define YYSTYPE YaccType extern TreePtr root; int yylex(); void yyerror(const char *); qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_outfile/parser.y0000644000175100001660000000117314776170045025617 0ustar runnerdocker%{ #include %} %type expr %left OR %left AND %nonassoc NOT %token ID %% start: expr { root = $1; } expr: expr AND expr { auto t = std::make_shared(); t->val = "AND"; t->children = { $1, $3 }; $$ = t; } | expr OR expr { auto t = std::make_shared(); t->val = "OR"; t->children = { $1, $3 }; $$ = t; } | NOT expr { auto t = std::make_shared(); t->val = "NOT"; t->children = { $2 }; $$ = t; } | ID { auto t = std::make_shared(); t->val = $1; $$ = t; } %% TreePtr root; int main() { yyparse(); if (!root) return 1; root->print(); std::cout << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/lex_outfile/lexer.l0000644000175100001660000000045414776170045025426 0ustar runnerdocker%option outfile="quark.cpp" %{ #include void yyerror(const char *e) { std::cerr << e; } extern "C" int yywrap() { return 1; } extern YYSTYPE yylval; %} ID [a-z]+ AND "&&" OR "||" NOT "!" %% [[:space:]]+ {ID} yylval.s = yytext; return 1; {AND} return 2; {OR} return 3; {NOT} return 4; %% qbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/modules/0000755000175100001660000000000014776170045023260 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/modules/bisonhelper/0000755000175100001660000000000014776170045025572 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lexyacc/modules/bisonhelper/bisonhelper.qbs0000644000175100001660000000065314776170045030617 0ustar runnerdockerimport qbs.Process Module { Depends { name: "lex_yacc" } Probe { id: bisonProbe property string yaccBinary: lex_yacc.yaccBinary configure: { var p = Process(); found = p.exec(yaccBinary, ["-V"]) == 0 && p.readStdOut().includes("bison"); p.close(); } } Properties { condition: bisonProbe.found lex_yacc.yaccFlags: "-y" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-host/0000755000175100001660000000000014776170045023667 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-host/host.qbs0000644000175100001660000000236514776170045025361 0ustar runnerdockerimport qbs.FileInfo import qbs.Host import qbs.TextFile Product { type: ["dummy"] Rule { multiplex: true outputFileTags: "dummy" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var output = new TextFile(FileInfo.joinPaths(product.sourceDirectory, "output.txt"), TextFile.WriteOnly); output.writeLine("architecture: " +Host.architecture()); output.writeLine("os: " + Host.os()); output.writeLine("platform: " + Host.platform()); output.writeLine("osVersion: " + Host.osVersion()); output.writeLine("osBuildVersion: " + Host.osBuildVersion()); output.writeLine("osVersionParts: " + Host.osVersionParts()); output.writeLine("osVersionMajor: " + Host.osVersionMajor()); output.writeLine("osVersionMinor: " + Host.osVersionMinor()); output.writeLine("osVersionPatch: " + Host.osVersionPatch()); output.writeLine("nullDevice: " + Host.nullDevice()); output.close(); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/0000755000175100001660000000000014776170045025621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/environmentChange.cpp0000644000175100001660000000237014776170045032001 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void environmentChange() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js0000644000175100001660000000025514776170045027734 0ustar runnerdockervar File = require("qbs.File"); function fileList() { return []; } function filesFromFs(path) { return File.exists(path + "/fileExists.cpp") ? ["fileExists.cpp"] : []; } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/hidden/0000755000175100001660000000000014776170045027054 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/hidden/hiddenheaderqbs.h0000644000175100001660000000233214776170045032337 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/including.cpp0000644000175100001660000000240514776170045030302 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/main.cpp0000644000175100001660000000235214776170045027253 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/trackExternalProductChanges.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/trackExternalProductChanges.q0000644000175100001660000000125314776170045033445 0ustar runnerdockerimport qbs.Environment 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(path)) Group { condition: Environment.getEnv("INCLUDE_PATH_TEST") name: "file that needs help from the environment to find a header" files: "including.cpp" } Probe { id: checker property bool isGcc: qbs.toolchain.contains("gcc") configure: { console.info("is gcc: " + isGcc); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackExternalProductChanges/jsFileChange.cpp0000644000175100001660000000236314776170045030653 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void jsFileChange() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/0000755000175100001660000000000014776170045022213 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test3/0000755000175100001660000000000014776170045023255 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test3/test3.qbs0000644000175100001660000000024114776170045025023 0ustar runnerdockerCppApplication { name: "test3" type: base.concat("autotest") Depends { name: "autotest" } autotest.allowFailure: true files: "test3.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test3/test3.cpp0000644000175100001660000000023514776170045025023 0ustar runnerdocker#include #include int main() { std::cerr << "I am an awful test"; std::cerr << "FAIL" << std::endl; return EXIT_FAILURE; } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/autotests.qbs0000644000175100001660000000077714776170045024770 0ustar runnerdockerimport qbs.Host Project { references: ["test1", "test2", "test3"] AutotestRunner { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Depends { name: "cpp" // Make sure build environment is set up properly. condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test2/0000755000175100001660000000000014776170045023254 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test2/test2.cpp0000644000175100001660000000041614776170045025022 0ustar runnerdocker#include #include #include int main() { std::ifstream input("test2-resource.txt"); if (!input.is_open()) { std::cerr << "Test resource not found"; return EXIT_FAILURE; } std::cout << "PASS" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test2/test2.qbs0000644000175100001660000000025214776170045025023 0ustar runnerdockerCppApplication { name: "test2" type: base.concat("autotest") Depends { name: "autotest" } autotest.workingDir: sourceDirectory files: "test2.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test2/test2-resource.txt0000644000175100001660000000000014776170045026671 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test1/0000755000175100001660000000000014776170045023253 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test1/test1.cpp0000644000175100001660000000043314776170045025017 0ustar runnerdocker#include #include int main(int argc, char *[]) { if (argc != 2) { std::cerr << "This test needs exactly one argument" << std::endl; std::cerr << "FAIL" << std::endl; return EXIT_FAILURE; } std::cout << "PASS" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotests/test1/test1.qbs0000644000175100001660000000024314776170045025021 0ustar runnerdockerCppApplication { name: "test1" type: base.concat("autotest") Depends { name: "autotest" } autotest.arguments: "--dummy" files: "test1.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-array-properties/0000755000175100001660000000000014776170045025520 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-array-properties/probes-and-array-properties.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-array-properties/probes-and-array-properties.q0000644000175100001660000000017614776170045033246 0ustar runnerdockerProduct { name: "theProduct" type: ["the-output"] Depends { name: "mymodule" } // mymodule.prop: ["product"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-array-properties/modules/0000755000175100001660000000000014776170045027170 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-array-properties/modules/mymodule/0000755000175100001660000000000014776170045031023 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-array-properties/modules/mymodule/mymodule.qbs0000644000175100001660000000115214776170045033364 0ustar runnerdockerModule { Probe { id: propProbe property stringList prop: [] configure: { prop = ["probe"]; found = true; } } property stringList prop: propProbe.found ? propProbe.prop : ["other"] Rule { multiplex: true outputFileTags: "the-output" prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating dummy"; cmd.sourceCode = function() { console.info("prop: " + JSON.stringify(product.mymodule.prop)); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/0000755000175100001660000000000014776170045023450 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/empty.m0000644000175100001660000000003214776170045024757 0ustar runnerdockerint main2() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs0000644000175100001660000000013614776170045030373 0ustar runnerdockerCppApplication { Group { files: ["main.cpp"] fileTags: ["objcpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/main.m0000644000175100001660000000011414776170045024546 0ustar runnerdocker#import int main() { @throw [NSError new]; } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/none.qbs0000644000175100001660000000023514776170045025116 0ustar runnerdockerCppApplication { files: ["emptymain.cpp"] Group { condition: qbs.targetOS.includes("darwin") files: ["empty.m", "empty.mm"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs0000644000175100001660000000017714776170045027620 0ustar runnerdockerCppApplication { Group { files: ["main.m"] fileTags: ["objcpp"] } cpp.frameworks: ["Foundation"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs0000644000175100001660000000011414776170045027247 0ustar runnerdockerCppApplication { files: ["main.m"] cpp.frameworks: ["Foundation"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/empty.mm0000644000175100001660000000003214776170045025134 0ustar runnerdockerint main3() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/main.cpp0000644000175100001660000000300314776170045025074 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #if defined(__GNUC__) && !(defined(__cpp_exceptions) || defined(__EXCEPTIONS)) #error Exceptions are disabled! #endif int main() { #ifdef FORCE_FAIL_VS #error "Microsoft Visual C++ cannot disable exceptions at compile-time" #endif throw std::runtime_error("failed"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs0000644000175100001660000000026114776170045026337 0ustar runnerdockerCppApplication { files: ["main.cpp"] cpp.treatWarningsAsErrors: true cpp.defines: qbs.toolchain.includes("msvc") && !cpp.enableExceptions ? ["FORCE_FAIL_VS"] : [] } qbs-src-2.6.1/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp0000644000175100001660000000236414776170045026164 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/ld/0000755000175100001660000000000014776170045020557 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ld/coreutils.h0000644000175100001660000000241414776170045022742 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" DLL_EXPORT int foo(); qbs-src-2.6.1/tests/auto/blackbox/testdata/ld/ld.qbs0000644000175100001660000000106714776170045021671 0ustar runnerdockerProject { Library { Depends { name: "cpp" } name: "coreutils" targetName: "qbs can handle any file paths, even the crazy ones! ;)" files: ["coreutils.cpp", "coreutils.h"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false cpp.sonamePrefix: "@rpath" } Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { Depends { name: "coreutils" } files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/ld/coreutils.cpp0000644000175100001660000000242014776170045023272 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "coreutils.h" int foo() { return 42; } qbs-src-2.6.1/tests/auto/blackbox/testdata/ld/main.cpp0000644000175100001660000000253114776170045022210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "coreutils.h" #include int main(int argc, char *argv[]) { std::printf("%d\n", foo()); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/conditional-filetagger/0000755000175100001660000000000014776170045024572 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conditional-filetagger/main.custom0000644000175100001660000000001714776170045026750 0ustar runnerdockerint main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/conditional-filetagger/conditional-filetagger.qbs0000644000175100001660000000032014776170045031706 0ustar runnerdockerCppApplication { name: "theApp" property bool enableTagger files: ["main.custom"] FileTagger { condition: enableTagger patterns: ["*.custom"] fileTags: ["cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/new-output-artifact/0000755000175100001660000000000014776170045024102 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/new-output-artifact/new-output-artifact.qbs0000644000175100001660000000175714776170045030545 0ustar runnerdockerimport qbs.TextFile Product { name: "theProduct" type: ["output"] property int artifactCount: 99 Group { files: ["input.txt"] fileTags: ["input"] } qbs.installPrefix: "" Group { fileTagsFilter: product.type qbs.install: true } Rule { inputs: ["input"] outputFileTags: ["output"] outputArtifacts: { var list = []; for (var i = 0; i < product.artifactCount; ++i) list.push({ filePath: "output_" + i + ".out", fileTags: ["output"]}); return list; } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { for (var i = 0; i < outputs["output"].length; ++i) { var f = new TextFile(outputs["output"][i].filePath, TextFile.WriteOnly); f.close(); } } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/new-output-artifact/input.txt0000644000175100001660000000000014776170045025770 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/0000755000175100001660000000000014776170045026464 5ustar runnerdocker././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/change-tracking-and-multiplexing.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/change-tracking-and-mult0000644000175100001660000000052214776170045033152 0ustar runnerdockerStaticLibrary { name: "l" Depends { condition: qbs.targetOS.includes("darwin"); name: "bundle" } Properties { condition: qbs.targetOS.includes("darwin"); bundle.isBundle: false } multiplexByQbsProperties: ["buildVariants"] qbs.buildVariants: ["debug", "release"] Depends { name: "cpp" } files: ["lib.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/change-tracking-and-multiplexing/lib.cpp0000644000175100001660000000001414776170045027731 0ustar runnerdockervoid l() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/0000755000175100001660000000000014776170045024354 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/remove-duplicate-libs.qbs0000644000175100001660000000204314776170045031256 0ustar runnerdockerimport "MyStaticLib.qbs" as MyStaticLib import qbs.Host Project { property bool removeDuplicates property string libDir: buildDirectory + "/lib" property bool dummy: { // most BSD systems (including macOS) use LLVM linker now console.info("is bfd linker: " + ((qbs.toolchain.includes("gcc") && !qbs.toolchain.includes("emscripten")) && !Host.os().includes("bsd"))) } qbsSearchPaths: "." MyStaticLib { name: "requestor1" } MyStaticLib { name: "requestor2" } MyStaticLib { name: "provider"; Group { files: "provider2.c" } } CppApplication { consoleApplication: true Depends { name: "requestor1"; cpp.link: false } Depends { name: "requestor2"; cpp.link: false } Depends { name: "provider"; cpp.link: false } cpp.libraryPaths: project.libDir cpp.removeDuplicateLibraries: project.removeDuplicates cpp.staticLibraries: ["requestor1", "requestor2", "provider", "requestor2"] files: "main.c" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/requestor1.c0000644000175100001660000000006614776170045026634 0ustar runnerdockervoid provider1(); void requestor1() { provider1(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/provider.c0000644000175100001660000000002414776170045026346 0ustar runnerdockervoid provider1() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/requestor2.c0000644000175100001660000000006614776170045026635 0ustar runnerdockervoid provider2(); void requestor2() { provider2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/MyStaticLib.qbs0000644000175100001660000000030414776170045027244 0ustar runnerdockerStaticLibrary { Properties { condition: isForDarwin bundle.isBundle: false } Depends { name: "cpp" } files: name + ".c" destinationDirectory: project.libDir } qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/main.c0000644000175100001660000000015414776170045025444 0ustar runnerdockervoid requestor1(); void requestor2(); int main(void) { requestor1(); requestor2(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/remove-duplicate-libs/provider2.c0000644000175100001660000000002414776170045026430 0ustar runnerdockervoid provider2() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-library-duplicates/0000755000175100001660000000000014776170045025241 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linker-library-duplicates/lib1.cpp0000644000175100001660000000007214776170045026573 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib1Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-library-duplicates/setup-run-environment.qbs0000644000175100001660000000232514776170045032256 0ustar runnerdockerProject { DynamicLibrary { id: idLib1 name: "lib1" Depends { name: "cpp" } files: ["lib1.cpp"] Depends { name: "bundle" } bundle.isBundle: false Probe { id: checker property bool isGcc: qbs.toolchain.contains("gcc") configure: { console.info("is gcc: " + isGcc); } } } DynamicLibrary { id: idLib2 name: "lib2" Depends { name: "cpp" } files: ["lib2.cpp"] Depends { name: "bundle" } bundle.isBundle: false } DynamicLibrary { id: idLib3 name: "lib3" Depends { name: "cpp" } files: ["lib3.cpp"] Depends { name: "bundle" } bundle.isBundle: false } CppApplication { name: "main" files: "main.cpp" Depends { name: "lib1"; cpp.link: false } Depends { name: "lib2"; cpp.link: false } Depends { name: "lib3"; cpp.link: false } cpp.libraryPaths: [ idLib1.buildDirectory, idLib2.buildDirectory, idLib3.buildDirectory ] cpp.dynamicLibraries: [ "lib1", "lib2", "lib1", "lib3", "lib2", "lib1" ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-library-duplicates/lib2.cpp0000644000175100001660000000007214776170045026574 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib2Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-library-duplicates/main.cpp0000644000175100001660000000027514776170045026675 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void lib1Func(); DLL_IMPORT void lib2Func(); DLL_IMPORT void lib3Func(); int main() { lib1Func(); lib2Func(); lib3Func(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-library-duplicates/lib3.cpp0000644000175100001660000000007214776170045026575 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib3Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/no-such-profile/0000755000175100001660000000000014776170045023172 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/no-such-profile/no-such-profile.qbs0000644000175100001660000000006614776170045026715 0ustar runnerdockerProduct { name: "theProduct" property int p } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/0000755000175100001660000000000014776170045023551 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/someotherfile.txt0000644000175100001660000000000014776170045027145 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/imports/0000755000175100001660000000000014776170045025246 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/imports/Helper7Base.qbs0000644000175100001660000000022014776170045030050 0ustar runnerdockerModule { property string directory property string fileName Group { prefix: directory + "/" files: fileName } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/someotherfile2.txt0000644000175100001660000000000014776170045027227 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/groups-in-modules.qbs0000644000175100001660000000132014776170045027645 0ustar runnerdockerimport qbs.Host Project { Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Depends { name: "dep" } Depends { name: "helper" } Depends { name: "helper3" required: false } Depends { name: "helper7" } helper7.fileName: "helper7.c" Depends { name: "helper8" } type: ["diamond"] files: [ "rock.coal" ] } Product { name: "dep" Export { Depends { name: "helper4" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/rock.coal0000644000175100001660000000000514776170045025342 0ustar runnerdockercoal qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/0000755000175100001660000000000014776170045025221 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper4/0000755000175100001660000000000014776170045026564 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper4/helper4.c0000644000175100001660000000235514776170045030300 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void helper4() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper4/helper4.qbs0000644000175100001660000000022714776170045030637 0ustar runnerdockerModule { Depends { name: "cpp" } Depends { name: "helper5" } Group { name: "Helper4 Sources" files: ["helper4.c"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper6/0000755000175100001660000000000014776170045026566 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper6/helper6.qbs0000644000175100001660000000023414776170045030641 0ustar runnerdockerModule { Depends { name: "cpp" } Group { name: "Helper6 Sources" files: ["helper6.c"] } validate: { throw "Go away."; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper6/helper6.c0000644000175100001660000000235514776170045030304 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void helper6() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/0000755000175100001660000000000014776170045026567 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.qbs0000644000175100001660000000004414776170045030642 0ustar runnerdockerHelper7Base { directory: path } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper7/helper7.c0000644000175100001660000000002614776170045030277 0ustar runnerdockervoid helper7(void) {} qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper5/0000755000175100001660000000000014776170045026565 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper5/helper5.qbs0000644000175100001660000000034014776170045030635 0ustar runnerdockerModule { Depends { name: "cpp" } Depends { name: "helper6" required: false } Group { name: "Helper5 Sources" files: ["helper5.c"] cpp.defines: ["COMPILE_FIX"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper5/helper5.c0000644000175100001660000000243414776170045030300 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void helper5() { #ifndef COMPILE_FIX nothatcantwork #endif } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper8/0000755000175100001660000000000014776170045026570 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper8/helper8.qbs0000644000175100001660000000050214776170045030643 0ustar runnerdockerModule { version: "8" Probe { id: baseNameProbe property string baseName configure: { baseName = "helper" } } property string fileName: baseNameProbe.baseName + version + ".c" Group { condition: version === "8" prefix: path + "/" files: fileName } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper8/helper8.c0000644000175100001660000000002614776170045030301 0ustar runnerdockervoid helper8(void) {} qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper3/0000755000175100001660000000000014776170045026563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper3/helper3.qbs0000644000175100001660000000023114776170045030630 0ustar runnerdockerModule { Depends { name: "cpp" } Group { name: "Helper3 Sources" files: ["helper3.c"] } validate: { throw "Nope."; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper3/helper3.c0000644000175100001660000000235514776170045030276 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void helper3() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper2/0000755000175100001660000000000014776170045026562 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper2/helper2.qbs0000644000175100001660000000041214776170045030627 0ustar runnerdockerModule { Depends { name: "cpp" } Group { name: "Helper2 Sources" files: ["helper2.c"] } Group { name: "some other file from helper2" prefix: product.sourceDirectory + '/' files: ["someotherfile.txt"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper2/helper2.c0000644000175100001660000000235514776170045030274 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void helper2() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/0000755000175100001660000000000014776170045026500 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/chunk.coal0000644000175100001660000000000614776170045030444 0ustar runnerdockerchunk qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/diamondc.c0000644000175100001660000000327114776170045030425 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "usage: diamondc input.coal output.diamond"); return 1; } FILE *in = fopen(argv[1], "r"); if (in) { fclose(in); } else { return 1; } FILE *out = fopen(argv[2], "w"); if (out) { fprintf(out, "diamond\n"); fclose(out); } else { return 1; } return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/groups-in-modules/modules/helper/helper.qbs0000644000175100001660000000206714776170045030473 0ustar runnerdockerimport qbs.FileInfo Module { Depends { name: "cpp" } Depends { name: "helper2" } additionalProductTypes: ["diamond"] Group { name: "Helper Sources" files: ["diamondc.c"] } Group { name: "Additional Chunk" prefix: path + "/" files: ["chunk.coal"] } Group { name: "some other file from helper" prefix: project.sourceDirectory + '/' files: ["someotherfile2.txt"] } FileTagger { patterns: ["*.coal"] fileTags: ["coal"] } Rule { inputs: ["coal"] explicitlyDependsOn: ["application"] Artifact { filePath: FileInfo.joinPaths(product.destinationDirectory, input.baseName + ".diamond") fileTags: ["diamond"] } prepare: { var cmd = new Command(FileInfo.joinPaths(product.buildDirectory, product.targetName), [input.filePath, output.filePath]); cmd.description = "compiling " + input.fileName + " to " + output.fileName; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/not-always-updated/0000755000175100001660000000000014776170045023702 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/not-always-updated/not-always-updated.qbs0000644000175100001660000000137114776170045030135 0ustar runnerdockerimport qbs.TextFile Product { type: "p" Rule { multiplex: true Artifact { filePath: "dummy.txt"; fileTags: "t1"; alwaysUpdated: false } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating dummy"; cmd.sourceCode = function() {}; return cmd; } } Rule { inputs: "t1" Artifact { filePath: "o.txt"; fileTags: "p" } prepare: { var cmd = new JavaScriptCommand; cmd.description = "creating final"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/0000755000175100001660000000000014776170045022563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/main.cpp0000644000175100001660000000236414776170045024220 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/data/0000755000175100001660000000000014776170045023474 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/data/subdir1/0000755000175100001660000000000014776170045025045 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/data/subdir1/bar.txt0000644000175100001660000000000014776170045026340 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/data/foo.txt0000644000175100001660000000000014776170045025006 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/data/subdir2/0000755000175100001660000000000014776170045025046 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/data/subdir2/baz.txt0000644000175100001660000000000014776170045026351 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-tree/install-tree.qbs0000644000175100001660000000033214776170045025673 0ustar runnerdockerCppApplication { files: ["main.cpp"] qbs.installPrefix: "" Group { files: ["data/**/*.txt"] qbs.install: true qbs.installDir: "content" qbs.installSourceBase: "data" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/deprecated-property/0000755000175100001660000000000014776170045024142 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/deprecated-property/deprecated-property.qbs0000644000175100001660000000021514776170045030631 0ustar runnerdockerProduct { Depends { name: "themodule" } themodule.newProp: true themodule.expiringProp: false themodule.veryOldProp: false } qbs-src-2.6.1/tests/auto/blackbox/testdata/deprecated-property/modules/0000755000175100001660000000000014776170045025612 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/0000755000175100001660000000000014776170045027600 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs0000644000175100001660000000120614776170045030542 0ustar runnerdockerimport qbs.Environment Module { property bool newProp property bool expiringProp property bool forgottenProp PropertyOptions { name: "newProp" description: "Use this, it's good!" } PropertyOptions { name: "expiringProp" description: "Use newProp instead." removalVersion: Environment.getEnv("REMOVAL_VERSION") } PropertyOptions { name: "veryOldProp" description: "Use newProp instead." removalVersion: "1.3" } PropertyOptions { name: "forgottenProp" description: "Use newProp instead." removalVersion: "1.8" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/0000755000175100001660000000000014776170045024464 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/lib4.cpp0000644000175100001660000000007214776170045026021 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib4Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/lib5.cpp0000644000175100001660000000007214776170045026022 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib5Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/lib1.cpp0000644000175100001660000000007214776170045026016 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib1Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/setup-run-environment.qbs0000644000175100001660000000706314776170045031505 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { DynamicLibrary { // Product dependency, installed name: "lib1" Depends { name: "cpp" } property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: ["lib1.cpp"] install: !qbs.targetOS.includes("darwin") installImportLib: true installDir: "lib1" importLibInstallDir: installDir Group { condition: qbs.targetOS.includes("darwin") fileTagsFilter: ["bundle.content"] qbs.install: true qbs.installSourceBase: destinationDirectory } } DynamicLibrary { // Product dependency, non-installed name: "lib2" Depends { name: "cpp" } Depends { name: "lib5" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib2.cpp"] } DynamicLibrary { // Non-dependency, referred to by full path name: "lib3" Depends { name: "cpp" } files: ["lib3.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } install: true installImportLib: true installDir: "lib3" importLibInstallDir: installDir } DynamicLibrary { // Non-dependency, referred to by name name: "lib4" Depends { name: "cpp" } files: ["lib4.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } // Testing shows that clang (8.0) does not find dynamic libraries via // the -L and -l mechanism unless the name is "lib.a". Properties { condition: Host.os().includes("windows") && qbs.toolchain.includes("clang") cpp.dynamicLibraryPrefix: "lib" cpp.dynamicLibraryImportSuffix: ".a" } install: true installImportLib: true installDir: "lib4" importLibInstallDir: installDir } DynamicLibrary { // Recursive product dependency name: "lib5" Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } files: ["lib5.cpp"] } CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "app" consoleApplication: true files: "main.cpp" Depends { name: "lib1" } Depends { name: "lib2" } Depends { name: "lib3"; cpp.link: false } Depends { name: "lib4"; cpp.link: false } property string fullInstallPrefix: FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix) property string lib3FilePath: FileInfo.joinPaths(fullInstallPrefix, "lib3", cpp.dynamicLibraryPrefix + "lib3" + (qbs.targetOS.includes("windows") ? cpp.dynamicLibraryImportSuffix : cpp.dynamicLibrarySuffix)) cpp.dynamicLibraries: [lib3FilePath, "lib4"] cpp.libraryPaths: FileInfo.joinPaths(fullInstallPrefix, "lib4") } Probe { id: osPrinter property bool isWindows: qbs.targetOS.includes("windows") configure: { console.info("is windows"); found = true; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/lib2.cpp0000644000175100001660000000014614776170045026021 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void lib5Func(); DLL_EXPORT void lib2Func() { lib5Func(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/main.cpp0000644000175100001660000000035114776170045026113 0ustar runnerdocker#include "../dllexport.h" DLL_IMPORT void lib1Func(); DLL_IMPORT void lib2Func(); DLL_IMPORT void lib3Func(); DLL_IMPORT void lib4Func(); int main() { lib1Func(); lib2Func(); lib3Func(); lib4Func(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-run-environment/lib3.cpp0000644000175100001660000000007214776170045026020 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void lib3Func() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/0000755000175100001660000000000014776170045022475 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/after/0000755000175100001660000000000014776170045023576 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/after/trackAddFile.qbs0000644000175100001660000000077614776170045026634 0ustar runnerdockerimport qbs.Host Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: 'someapp' type: 'application' consoleApplication: true property bool dummy: { console.info("object suffix: " + cpp.objectSuffix); } Depends { name: 'cpp' } files: [ "main.cpp", "narf.h", "narf.cpp", "zort.h", "zort.cpp" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/after/zort.cpp0000644000175100001660000000246314776170045025305 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "zort.h" #include void Zort::shout() { std::printf("ZORT!\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/after/main.cpp0000644000175100001660000000265114776170045025232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "narf.h" #include "zort.h" #include int main(int argc, char **argv) { std::printf("Hello World!\n"); Narf narf; narf.shout(); Zort zort; zort.shout(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/after/zort.h0000644000175100001660000000245414776170045024752 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef ZORT_H #define ZORT_H class Zort { public: void shout(); }; #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/before/0000755000175100001660000000000014776170045023737 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/before/trackAddFile.qbs0000644000175100001660000000071414776170045026765 0ustar runnerdockerimport qbs.Host Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: 'someapp' type: 'application' consoleApplication: true property bool dummy: { console.info("object suffix: " + cpp.objectSuffix); } Depends { name: 'cpp' } files: [ "main.cpp", "narf.h", "narf.cpp" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/before/main.cpp0000644000175100001660000000256614776170045025400 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "narf.h" #include int main(int argc, char **argv) { std::printf("Hello World!\n"); Narf narf; narf.shout(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/before/narf.cpp0000644000175100001660000000246314776170045025376 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "narf.h" #include void Narf::shout() { std::printf("NARF!\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackAddFile/before/narf.h0000644000175100001660000000245414776170045025043 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef NARF_H #define NARF_H class Narf { public: void shout(); }; #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/properties-in-export-items/0000755000175100001660000000000014776170045025416 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/properties-in-export-items/main1.cpp0000644000175100001660000000237314776170045027134 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef P1 int main() { } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/properties-in-export-items/properties-in-export-items.qbs0000644000175100001660000000137214776170045033366 0ustar runnerdockerProject { minimumQbsVersion: "1.6" Product { name: "dep" Export { property string theDefine: "" Depends { name: "cpp" } cpp.defines: [theDefine] } } Application { name: "p1" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "dep" } dep.theDefine: "P1" cpp.minimumMacosVersion: "10.9" files: ["main1.cpp"] } Application { name: "p2" consoleApplication: true Depends { name: "dep" } cpp.minimumMacosVersion: "10.9" Group { dep.theDefine: "P2" files: ["main2.cpp"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/properties-in-export-items/main2.cpp0000644000175100001660000000237314776170045027135 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef P2 int main() { } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/0000755000175100001660000000000014776170045024077 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/0000755000175100001660000000000014776170045026323 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/0000755000175100001660000000000014776170045027773 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/0000755000175100001660000000000014776170045030227 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs0000644000175100001660000000143514776170045031175 0ustar runnerdockerModule { property string p1 property string p2 Rule { inputs: ["in1"] Artifact { filePath: "dummy1.txt" fileTags: ["out1"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName + " with " + product.m.p1; cmd.sourceCode = function() {}; return [cmd]; } } Rule { inputs: ["in2"] Artifact { filePath: "dummy2.txt" fileTags: ["out2"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName + " with " + product.m.p2; cmd.sourceCode = function() {}; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/in1.txt0000644000175100001660000000000014776170045025315 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/disappeared-profile.qbs0000644000175100001660000000031714776170045030526 0ustar runnerdockerProduct { type: ["out1", "out2"] Depends { name: "m" } Group { files: ["in1.txt"] fileTags: ["in1"] } Group { files: ["in2.txt"] fileTags: ["in2"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/disappeared-profile/in2.txt0000644000175100001660000000000014776170045025316 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/combined-sources/0000755000175100001660000000000014776170045023421 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/combined-sources/combinable.cpp0000644000175100001660000000002214776170045026212 0ustar runnerdockerstatic int i = 1; qbs-src-2.6.1/tests/auto/blackbox/testdata/combined-sources/uncombinable.cpp0000644000175100001660000000002214776170045026555 0ustar runnerdockerstatic int i = 2; qbs-src-2.6.1/tests/auto/blackbox/testdata/combined-sources/main.cpp0000644000175100001660000000001714776170045025047 0ustar runnerdockerint main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/combined-sources/combined-sources.qbs0000644000175100001660000000026714776170045027376 0ustar runnerdockerCppApplication { name: "theapp" files: [ "combinable.cpp", "main.cpp", ] Group { files: ["uncombinable.cpp"] fileTags: ["cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/smart-relinking/0000755000175100001660000000000014776170045023266 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/smart-relinking/staticlib.cpp0000644000175100001660000000003014776170045025741 0ustar runnerdockerstatic void myFunc() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/smart-relinking/smart-relinking.qbs0000644000175100001660000000164214776170045027106 0ustar runnerdockerProject { minimumQbsVersion: "1.6" Probe { id: tcProbe property stringList toolchain: qbs.toolchain property stringList targetOS: qbs.targetOS configure: { found = toolchain.includes("gcc") && targetOS.includes("unix"); if (!found) console.info("project disabled"); } } DynamicLibrary { condition: tcProbe.found name: "lib" property stringList defines: [] cpp.defines: defines Depends { name: "cpp" } files: ["lib.cpp"] } CppApplication { condition: tcProbe.found name:"app" Depends { name: "lib" } Depends { name: "staticlib" } files: ["main.cpp"] } StaticLibrary { condition: tcProbe.found name: "staticlib" Depends { name: "lib" } Depends { name: "cpp" } files: "staticlib.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/smart-relinking/lib.cpp0000644000175100001660000000055314776170045024543 0ustar runnerdocker#include __attribute__ ((visibility ("default"))) void publicFunc() { #ifdef PRINTF std::printf("Tach\n"); #endif } __attribute__ ((visibility ("hidden"))) void privateFunc() { } #ifdef PRIV2 __attribute__ ((visibility ("hidden"))) void privateFunc2() { } #endif #ifdef PUB2 __attribute__ ((visibility ("default"))) void publicFunc2() { } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/smart-relinking/main.cpp0000644000175100001660000000006514776170045024717 0ustar runnerdockervoid publicFunc(); int main() { publicFunc(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/0000755000175100001660000000000014776170045022643 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/versioncheck.qbs0000644000175100001660000000037314776170045026040 0ustar runnerdockerProduct { property string requestedMinVersion property string requestedMaxVersion Depends { name: "higher" } Depends { name: "lower" versionAtLeast: requestedMinVersion versionBelow: requestedMaxVersion } } qbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/modules/0000755000175100001660000000000014776170045024313 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/modules/lower/0000755000175100001660000000000014776170045025443 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/modules/lower/lower.qbs0000644000175100001660000000001314776170045027274 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/modules/higher/0000755000175100001660000000000014776170045025561 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/versioncheck/modules/higher/higher.qbs0000644000175100001660000000021014776170045027527 0ustar runnerdockerModule { Depends { name: "lower" required: false versionAtLeast: "1.0" versionBelow: "10.0" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/0000755000175100001660000000000014776170045022700 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/output.txt.in0000644000175100001660000000027414776170045025411 0ustar runnerdockerfoo bar baz ${foo} bar baz foo ${bar} baz foo bar ${baz} ${foo} ${bar} baz ${foo} bar ${baz} ${foo} ${bar} ${baz} foo${bar}baz foo\${bar}baz foo\\${bar}baz foo\\\${bar}baz foo${$}{bar}baz qbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/expected/0000755000175100001660000000000014776170045024501 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/expected/output.txt0000644000175100001660000000021614776170045026601 0ustar runnerdockerfoo bar baz fu bar baz foo BAR baz foo bar buzz fu BAR baz fu bar buzz fu BAR buzz fooBARbaz foo\BARbaz foo\\BARbaz foo\\\BARbaz foo${bar}baz qbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/expected/lalala.txt0000644000175100001660000000003014776170045026461 0ustar runnerdockerdo re mi fa so la ti do qbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/texttemplatetest.qbs0000644000175100001660000000076114776170045027033 0ustar runnerdockerProduct { name: "one" type: ["text"] files: ["output.txt.in"] Depends { name: "texttemplate" } texttemplate.dict: ({ foo: "fu", bar: "BAR", baz: "buzz", }) Group { files: ["cdefgabc.txt.in"] texttemplate.outputFileName: "lalala.txt" texttemplate.dict: ({ c: "do", d: "re", e: "mi", f: "fa", g: "so", a: "la", b: "ti", }) } } qbs-src-2.6.1/tests/auto/blackbox/testdata/texttemplate/cdefgabc.txt.in0000644000175100001660000000005014776170045025557 0ustar runnerdocker${c} ${d} ${e} ${f} ${g} ${a} ${b} ${c} qbs-src-2.6.1/tests/auto/blackbox/testdata/build-directories/0000755000175100001660000000000014776170045023571 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/build-directories/build-directories.qbs0000644000175100001660000000200314776170045027704 0ustar runnerdockerProject { Product { name: "p1" type: "blubb1" Rule { multiplex: true outputFileTags: "blubb1" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info(product.buildDirectory); } return cmd; } } } Product { name: "p2" type: "blubb2" Depends { name: "p1" } Rule { inputsFromDependencies: "blubb1" outputFileTags: "blubb2" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info(product.buildDirectory); console.info(project.buildDirectory); console.info(project.sourceDirectory); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/driver-linker-flags/0000755000175100001660000000000014776170045024027 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/driver-linker-flags/driver-linker-flags.qbs0000644000175100001660000000054514776170045030411 0ustar runnerdockerCppApplication { files: "main.cpp" Properties { condition: toolchainProbe.found cpp.driverLinkerFlags: ["-nostartfiles"] } Probe { id: toolchainProbe condition: qbs.toolchain.includes("gcc") configure: { console.info("toolchain is GCC-like"); found = true; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/driver-linker-flags/main.cpp0000644000175100001660000000001614776170045025454 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/0000755000175100001660000000000014776170045022251 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/main.mm0000644000175100001660000000022414776170045023526 0ustar runnerdocker#include #include int main() { std::string s = "Hello World"; (void)s; sel_registerName("qbs"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/staticlib.cpp0000644000175100001660000000252014776170045024732 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include extern "C" int cpp(); int cpp() { std::cout << "Hello world" << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/linkerMode.qbs0000644000175100001660000000346014776170045025054 0ustar runnerdockerProject { CppApplication { consoleApplication: true name: "LinkedProduct-Assembly" property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } files: qbs.targetOS.includes("darwin") ? "darwin.s" : "main.s" cpp.linkerPath: cpp.compilerPathByLanguage["c"] Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { consoleApplication: true name: "LinkedProduct-C" files: ["main.c"] Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { condition: qbs.targetOS.includes("darwin") consoleApplication: true name: "LinkedProduct-Objective-C" files: ["main.m"] cpp.dynamicLibraries: ["ObjC"] Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { consoleApplication: true name: "LinkedProduct-C++" files: ["main.cpp"] Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { condition: qbs.targetOS.includes("darwin") consoleApplication: true name: "LinkedProduct-Objective-C++" files: ["main.mm"] cpp.dynamicLibraries: ["ObjC"] Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { Depends { name: "LinkedProduct-C++StaticLibrary" } name: "LinkedProduct-BlankApp" files: ["staticmain.c"] } StaticLibrary { Depends { name: "cpp" } name: "LinkedProduct-C++StaticLibrary" files: ["staticlib.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/main.m0000644000175100001660000000012214776170045023346 0ustar runnerdocker#include int main() { sel_registerName("qbs"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/main.c0000644000175100001660000000247514776170045023351 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { void *memory = malloc(8); free(memory); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/main.s0000644000175100001660000000004714776170045023362 0ustar runnerdocker.globl _main .globl main _main: main: qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/main.cpp0000644000175100001660000000247314776170045023707 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::string s = "Hello World"; (void)s; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/darwin.s0000644000175100001660000000005714776170045023723 0ustar runnerdocker.globl _main .globl main _main: main: ret qbs-src-2.6.1/tests/auto/blackbox/testdata/linkerMode/staticmain.c0000644000175100001660000000241714776170045024555 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ extern int cpp(); int main() { return cpp(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/rad-after-incomplete-build/0000755000175100001660000000000014776170045025257 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rad-after-incomplete-build/project_with_rule.qbs0000644000175100001660000000106114776170045031514 0ustar runnerdockerimport qbs.TextFile Product { type: "custom" Group { files: "dummy.txt" fileTags: "input" } Rule { inputs: "input" Artifact { fileTags: "custom" filePath: "oldfile" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating file"; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/rad-after-incomplete-build/dummy.txt0000644000175100001660000000000014776170045027141 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/soversion/0000755000175100001660000000000014776170045022207 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/soversion/soversion.qbs0000644000175100001660000000041014776170045024740 0ustar runnerdockerDynamicLibrary { name: "mylib" property bool useVersion property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } version: useVersion ? "1.2.3" : undefined Depends { name: "cpp" } files: ["lib.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/soversion/lib.cpp0000644000175100001660000000001514776170045023455 0ustar runnerdockervoid f() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/cpu-features/0000755000175100001660000000000014776170045022563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cpu-features/cpu-features.qbs0000644000175100001660000000073414776170045025701 0ustar runnerdockerCppApplication { Depends { name: "cpufeatures" } cpufeatures.x86_sse2: true cpufeatures.x86_avx: true cpufeatures.x86_avx512f: false files: ["main.cpp"] property bool dummy: { console.info("is x86: " + (qbs.architecture === "x86")); console.info("is x64: " + (qbs.architecture === "x86_64")); console.info("is gcc: " + qbs.toolchain.includes("gcc")); console.info("is msvc: " + qbs.toolchain.includes("msvc")); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cpu-features/main.cpp0000644000175100001660000000001614776170045024210 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/0000755000175100001660000000000014776170045025004 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/probes-in-nested-modules.qbs0000644000175100001660000000176714776170045032352 0ustar runnerdockerProject { Product { name: "a" Depends { name: "outer" } inner.alt: true property bool dummy: { console.info("product " + name + ", inner.something = " + inner.something); console.info("product " + name + ", outer.something = " + outer.something); console.info("product " + name + ", outer.somethingElse = " + outer.somethingElse); return true; } type: ["foo"] } Product { name: "b" Depends { name: "inner" } inner.alt: true property bool dummy: { console.info("product " + name + ", inner.something = " + inner.something); return true; } type: ["foo"] } Product { name: "c" Depends { name: "inner" } inner.alt: false property bool dummy: { console.info("product " + name + ", inner.something = " + inner.something); return true; } type: ["foo"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/modules/0000755000175100001660000000000014776170045026454 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/modules/outer/0000755000175100001660000000000014776170045027612 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/modules/outer/outer.qbs0000644000175100001660000000060514776170045031460 0ustar runnerdockerModule { Depends { name: "inner" } Probe { id: foo2 property string barz property string named: product.name configure: { console.info("running second probe " + named); barz = "goodbye"; found = true; } } property string something: inner.something property string somethingElse: foo2.barz } qbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/modules/inner/0000755000175100001660000000000014776170045027567 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-in-nested-modules/modules/inner/inner.qbs0000644000175100001660000000061414776170045031412 0ustar runnerdockerimport qbs.Probes Module { property bool alt: false Probe { id: foo property string baz property bool useAlt: alt property string named: product.name configure: { console.info("running probe " + named); baz = useAlt ? "hahaha" : "hello"; found = true; } } property string something: foo.baz } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-file/0000755000175100001660000000000014776170045023631 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-file/file.qbs0000644000175100001660000000506514776170045025265 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.TextFile Product { type: ["dummy"] Rule { multiplex: true outputFileTags: "dummy" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var origPath = FileInfo.joinPaths(product.sourceDirectory, "original.txt"); var copyPath = FileInfo.joinPaths(product.sourceDirectory, "copy.txt"); console.info("copy path: "+copyPath); var original = new TextFile(origPath, TextFile.WriteOnly); original.close(); File.copy(origPath, copyPath); var origTimestamp = File.lastModified(origPath); var copyTimestamp = File.lastModified(copyPath); if (origTimestamp > copyTimestamp) throw new Error("Older file has newer timestamp."); File.remove(origPath); var copy = new TextFile(copyPath, TextFile.WriteOnly); copy.writeLine(File.exists(origPath)); copy.writeLine(File.exists(copyPath)); copy.close(); var zePath = FileInfo.joinPaths(product.sourceDirectory, "zePath"); if (File.exists(zePath)) throw new Error(zePath + " already exists."); var created = File.makePath(zePath); if (!created || !File.exists(zePath)) throw new Error("zePath was not created."); var entries = File.directoryEntries(product.sourceDirectory, File.AllEntries | File.NoDotAndDotDot); if (entries.length < 3 || !entries.includes("file.qbs")) throw new Error("Directory did not contain file.qbs"); entries = File.directoryEntries(product.sourceDirectory, File.Dirs | File.NoDotAndDotDot); if (entries.length < 1 || !entries.includes("zePath")) throw new Error("Directory did not contain only zePath"); var moveSource = FileInfo.joinPaths(product.sourceDirectory, "tomove.txt"); var moveTarget = FileInfo.joinPaths(product.sourceDirectory, "moved.txt"); File.move(moveSource, moveTarget); if (File.exists(moveSource)) throw new Error("Moved file still exists under old name"); if (!File.exists(moveTarget)) throw new Error("Moved file does not exist under new name"); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/0000755000175100001660000000000014776170045025653 5ustar runnerdocker././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/product-dependencies-by-type.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/product-dependencies-by-type0000644000175100001660000001042614776170045033274 0ustar runnerdockerimport qbs.TextFile Project { CppApplication { consoleApplication: true name: "no-match" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: "main.cpp" } Project { CppApplication { consoleApplication: true name: "app1" files: "main.cpp" } CppApplication { consoleApplication: true name: "app2" files: "main.cpp" } CppApplication { consoleApplication: true name: "app3" files: "main.cpp" } Product { type: myconfig.typeDecider ? ["application"] : [] Depends { name: "cpp" } Depends { name: "myconfig" } consoleApplication: true name: "app4" files: "main.cpp" } Product { name: "other-product" type: "other" Rule { multiplex: true Artifact { filePath: "output.txt" fileTags: "other" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.filePath; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); } return cmd; } } Export { Depends { productTypes: "other2" } } } Product { name: "yet-another-product" type: "other2" Rule { multiplex: true Artifact { filePath: "output.txt" fileTags: "other2" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.filePath; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); } return cmd; } } } Product { name: "helper" Export { Depends { productTypes: "other" } } } CppApplication { condition: false consoleApplication: true name: "disabled-app" files: "main.cpp" } DynamicLibrary { Depends { name: "cpp" } name: "lib-product" files: "main.cpp" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } CppApplication { type: base.concat(["app-list"]) consoleApplication: true name: "app list" Depends { productTypes: ["application"] limitToSubProject: true } Depends { name: "helper" } files: ["main.cpp"] Rule { multiplex: true inputsFromDependencies: ["application", "other", "other2"] Artifact { filePath: "app-list.txt" fileTags: "app-list" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "collecting apps"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); for (var i = 0; i < inputs["application"].length; ++i) file.writeLine(inputs["application"][i].filePath); for (i = 0; i < inputs["other"].length; ++i) file.writeLine(inputs["other"][i].filePath); for (i = 0; i < inputs["other2"].length; ++i) file.writeLine(inputs["other2"][i].filePath); file.close(); }; return cmd; } } } Product { name: "dummy" Depends { productTypes: [] } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/main.cpp0000644000175100001660000000235114776170045027304 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/modules/0000755000175100001660000000000014776170045027323 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/modules/myconfig/0000755000175100001660000000000014776170045031136 5ustar runnerdocker././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/modules/myconfig/myconfig.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/product-dependencies-by-type/modules/myconfig/myconfig.qb0000644000175100001660000000005714776170045033277 0ustar runnerdockerModule { property bool typeDecider: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/input-tags-change-tracking/0000755000175100001660000000000014776170045025276 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/input-tags-change-tracking/input-tags-change-tracking.qbs0000644000175100001660000000354714776170045033134 0ustar runnerdockerimport qbs.TextFile Product { name: "p" type: "p_tag" property string generateInput Group { condition: generateInput == "no" files: "input.txt" fileTags: ["txt", "empty"] } Rule { condition: generateInput == "static" multiplex: true Artifact { filePath: "input.txt"; fileTags: ["txt", "empty"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var out = new TextFile(output.filePath, TextFile.WriteOnly); out.close(); }; return cmd; } } Rule { condition: generateInput == "dynamic" multiplex: true outputFileTags: ["txt", "empty"] outputArtifacts: [{filePath: "input.txt", fileTags: ["txt", "empty"]}] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var out = new TextFile(output.filePath, TextFile.WriteOnly); out.close(); }; return cmd; } } Rule { inputs: "txt" outputFileTags: "p_tag" outputArtifacts: { if (input.fileTags.includes("empty")) return []; return [{ filePath: input.fileTags.includes("y") ? "y.out" : "x.out", fileTags: "p_tag" }] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var out = new TextFile(output.filePath, TextFile.WriteOnly); out.close(); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/input-tags-change-tracking/input.txt0000644000175100001660000000000614776170045027172 0ustar runnerdockerempty qbs-src-2.6.1/tests/auto/blackbox/testdata/QTBUG-51237/0000755000175100001660000000000014776170045021521 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/QTBUG-51237/qtbug-51237.qbs0000644000175100001660000000067714776170045024043 0ustar runnerdockerProduct { type: "custom" Depends { name: "mymodule" } Rule { multiplex: true outputFileTags: ["custom"] prepare: { var theProperty = product.mymodule.theProperty; if (!theProperty) throw "Oh no!"; var dummy = new JavaScriptCommand(); dummy.silent = true; dummy.sourceCode = function() {}; return [dummy]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/QTBUG-51237/modules/0000755000175100001660000000000014776170045023171 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/QTBUG-51237/modules/mymodule/0000755000175100001660000000000014776170045025024 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/QTBUG-51237/modules/mymodule/mymodule.qbs0000644000175100001660000000016314776170045027366 0ustar runnerdockerModule { property stringList theProperty: [] //property stringList otherProperty: theProperty.concat([]) } qbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-in-inputs-from-dependencies/0000755000175100001660000000000014776170045030564 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-in-inputs-from-dependencies/header.h0000644000175100001660000000000014776170045032153 0ustar runnerdocker././@LongLink0000644000000000000000000000020700000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-in-inputs-from-dependencies/source-artifact-in-inputs-from-dependencies.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/source-artifact-in-inputs-from-dependencies/source-artifa0000644000175100001660000000313314776170045033253 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Project { Product { name: "dep1" Group { files: ["header.h"] qbs.install: true qbs.installDir: "include1" } } Product { name: "dep2" Group { files: ["header.h"] qbs.install: true qbs.installDir: "include2" } } Product { name: "p" type: ["custom"] Depends { name: "dep1" } Depends { name: "dep2" } Rule { multiplex: true inputsFromDependencies: ["installable"] Artifact { filePath: "output.txt" fileTags: ["custom"] } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var tf; try { tf = new TextFile(output.filePath, TextFile.WriteOnly); var artifactList = inputs["installable"]; for (var i = 0; i < (artifactList ? artifactList.length : 0); ++i) { var artifact = artifactList[i]; tf.writeLine(FileInfo.joinPaths(artifact.qbs.installDir, artifact.fileName)); } } finally { if (tf) tf.close(); } } return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/0000755000175100001660000000000014776170045022545 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/scanner-item.qbs0000644000175100001660000000133714776170045025645 0ustar runnerdockerimport qbs.File import qbs.FileInfo Product { type: "t" Depends { name: "m" } property bool productScanner property bool moduleScanner property bool enableGroup Group { files: ["subdir1/file1.in", "subdir2/file2.in"] fileTags: "i" } TheScanner { condition: productScanner } Rule { inputs: "i" Artifact { filePath: FileInfo.baseName(input.fileName) + ".out" fileTags: "t" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "handling " + input.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/subdir1/0000755000175100001660000000000014776170045024116 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/subdir1/file.inc0000644000175100001660000000000014776170045025516 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/subdir1/file1.in0000644000175100001660000000000014776170045025434 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/TheScanner.qbs0000644000175100001660000000017114776170045025305 0ustar runnerdockerimport qbs.FileInfo Scanner { inputs: "i" searchPaths: [FileInfo.path(input.filePath)] scan: ["file.inc"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/modules/0000755000175100001660000000000014776170045024215 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/modules/m/0000755000175100001660000000000014776170045024451 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/modules/m/m.qbs0000644000175100001660000000025114776170045025412 0ustar runnerdockerimport "../../TheScanner.qbs" as TheScanner Module { Group { condition: product.enableGroup TheScanner { condition: product.moduleScanner } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/subdir2/0000755000175100001660000000000014776170045024117 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/subdir2/file.inc0000644000175100001660000000000014776170045025517 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scanner-item/subdir2/file2.in0000644000175100001660000000000014776170045025436 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-config-import-export/0000755000175100001660000000000014776170045025037 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-config-import-export/config.txt0000644000175100001660000000013114776170045027040 0ustar runnerdockergroup.key1: "value1" group.key2: "value2" key: "value" listKey: ["valueOne", "valueTwo"] qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-config-import-export/config.json0000644000175100001660000000023714776170045027201 0ustar runnerdocker{ "group": { "key1": "value1", "key2": "value2" }, "key": "value", "listKey": [ "valueOne", "valueTwo" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/loadablemodule/0000755000175100001660000000000014776170045023131 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs0000644000175100001660000000224614776170045026615 0ustar runnerdockerimport qbs.Host Project { LoadableModule { Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } name: "CoolPlugIn" files: ["exported.cpp", "exported.h"] Group { fileTagsFilter: product.type qbs.install: true } } CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Depends { name: "cpp" } Depends { name: "CoolPlugIn"; cpp.link: false } consoleApplication: true name: "CoolApp" files: ["main.cpp"] cpp.cxxLanguageVersion: "c++11" cpp.dynamicLibraries: [qbs.targetOS.includes("windows") ? "kernel32" : "dl"] Properties { condition: qbs.targetOS.includes("unix") && !qbs.targetOS.includes("darwin") cpp.rpaths: [cpp.rpathOrigin] } Group { fileTagsFilter: product.type qbs.install: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/loadablemodule/main.cpp0000644000175100001660000000641114776170045024563 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #ifdef _WIN32 #include #define PREFIX "" #define SUFFIX ".dll" #define dlopen(path, mode) LoadLibraryA(path) #define dlsym(handle, symbol) GetProcAddress(handle, symbol) #define dlclose(handle) FreeLibrary(handle) #elif defined(__APPLE__) #define PREFIX "" #define SUFFIX ".bundle" #else #define PREFIX "lib" #define SUFFIX ".so" #endif #ifndef _WIN32 #include #endif int main() { auto lib = dlopen(PREFIX "CoolPlugIn" SUFFIX, RTLD_LAZY); if (lib) { auto fptr = dlsym(lib, "foo"); if (fptr) std::cout << "foo = " << ((int (*)(void))fptr)() << std::endl; else std::cout << "function foo not found in CoolPlugIn" << std::endl; dlclose(lib); return fptr ? 0 : 1; } else { std::cout << "CoolPlugIn not loaded" << std::endl; } return 1; } qbs-src-2.6.1/tests/auto/blackbox/testdata/loadablemodule/exported.cpp0000644000175100001660000000245214776170045025472 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "exported.h" extern "C" { int foo() { return 42; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/loadablemodule/exported.h0000644000175100001660000000243714776170045025142 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" extern "C" { DLL_EXPORT int foo(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/missing-override-prefix/0000755000175100001660000000000014776170045024741 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/missing-override-prefix/missing-override-prefix.qbs0000644000175100001660000000001414776170045032224 0ustar runnerdockerProduct { } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/0000755000175100001660000000000014776170045025730 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/0000755000175100001660000000000014776170045026510 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs0000644000175100001660000000014014776170045027772 0ustar runnerdockerCppApplication { cpp.includePaths: project.sourceDirectory + "/lib" files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h0000644000175100001660000000002114776170045027432 0ustar runnerdocker#include "lib.h" qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp0000644000175100001660000000004114776170045030133 0ustar runnerdocker#include "app.h" int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/0000755000175100001660000000000014776170045026476 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h0000644000175100001660000000003614776170045027414 0ustar runnerdocker#pragma once void lib1_foo();qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs0000644000175100001660000000012614776170045026675 0ustar runnerdockerProject { references: [ "app/app.qbs", "other/other.qbs", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/0000755000175100001660000000000014776170045027051 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs0000644000175100001660000000107714776170045030706 0ustar runnerdockerimport qbs.TextFile Product { type: "testproduct" files: "../lib/lib.h" Rule { multiplex: true Artifact { fileTags: ["testproduct"] filePath: "fubar" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating text file"; cmd.sourceCode = function() { var tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine("blubb"); tf.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/0000755000175100001660000000000014776170045025043 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/lib.h0000644000175100001660000000001214776170045025753 0ustar runnerdockervoid l(); qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/multiple-configurations.qbs0000644000175100001660000000046114776170045032436 0ustar runnerdockerProject { StaticLibrary { name: "lib" Depends { name: "cpp" } files: ["lib.cpp", "lib.h"] } CppApplication { name: "app" Depends { name: "lib" } cpp.includePaths: project.sourceDirectory files: ["file.cpp", "file.h", "main.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/file.cpp0000644000175100001660000000005014776170045026461 0ustar runnerdocker#include void f() { l(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/file.h0000644000175100001660000000001214776170045026124 0ustar runnerdockervoid f(); qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/lib.cpp0000644000175100001660000000001414776170045026310 0ustar runnerdockervoid l() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-configurations/main.cpp0000644000175100001660000000005314776170045026471 0ustar runnerdocker#include int main() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/export-rule/0000755000175100001660000000000014776170045022446 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/export-rule/blubber.cpp0000644000175100001660000000235214776170045024571 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void hook() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/export-rule/myapp.blubb0000644000175100001660000000003314776170045024600 0ustar runnerdockervoid justSomeFunction() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/export-rule/main.cpp0000644000175100001660000000016614776170045024101 0ustar runnerdockerextern void justSomeFunction(); extern void hook(); int main() { justSomeFunction(); hook(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/export-rule/export-rule.qbs0000644000175100001660000000217114776170045025444 0ustar runnerdockerimport qbs.File Project { Application { name: "MyApp" files: ["main.cpp", "myapp.blubb"] Depends { name: "blubber" } } StaticLibrary { name: "blubber" files: ["blubber.cpp"] Depends { name: "cpp" } Export { Depends { name: "cpp" } property bool enableTagger property string description: "creating C++ source file."; FileTagger { condition: enableTagger patterns: ["*.blubb"] fileTags: ["blubb"] } Rule { inputs: ["blubb"] Artifact { filePath: input.completeBaseName + ".cpp" fileTags: ["cpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = product.blubber.description; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); } return [cmd]; } } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/system-include-paths/0000755000175100001660000000000014776170045024242 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/system-include-paths/system-include-paths.qbs0000644000175100001660000000012214776170045031026 0ustar runnerdockerCppApplication { files: ["main.cpp"] cpp.systemIncludePaths: ["subdir"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/system-include-paths/subdir/0000755000175100001660000000000014776170045025532 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/system-include-paths/subdir/gagagugu.h0000644000175100001660000000010114776170045027462 0ustar runnerdockervoid printStuff() { puts("alalalalonglonglilonglonglong"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/system-include-paths/main.cpp0000644000175100001660000000013014776170045025664 0ustar runnerdocker#include #include int main() { printStuff(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/vcs/0000755000175100001660000000000014776170045020753 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/vcs/vcstest.qbs0000644000175100001660000000051014776170045023151 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Depends { name: "vcs" } vcs.headerFileName: "my-repo-state.h" files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/vcs/main.cpp0000644000175100001660000000017514776170045022406 0ustar runnerdocker#include #include int main() { std::cout << "__" << VCS_REPO_STATE << "__" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/0000755000175100001660000000000014776170045025006 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/probe-in-exported-module.qbs0000644000175100001660000000010114776170045032333 0ustar runnerdockerProject { references: [ "dependee.qbs", "dependency.qbs" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/dependency.qbs0000644000175100001660000000013314776170045027630 0ustar runnerdockerProduct { name: "dependency" Export { Depends { name: "mymodule" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/0000755000175100001660000000000014776170045026456 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/myothermodule/0000755000175100001660000000000014776170045031353 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/myothermodule/myothermodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/myothermodule/myothermod0000644000175100001660000000012114776170045033457 0ustar runnerdockerModule { Depends { name: "depmodule" } depmodule.listProp: ["myother"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/0000755000175100001660000000000014776170045030311 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs0000644000175100001660000000113614776170045032654 0ustar runnerdockerModule { Depends { name: "depmodule" } Probe { id: theProbe configure: { found = true; } } property bool found: theProbe.found depmodule.prop: found ? "yes" : "no" depmodule.listProp: theProbe.found ? ["my"] : [] Rule { inputs: ["in"] outputFileTags: "out" prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating out artifact"; cmd.sourceCode = function() { console.info("found: " + product.mymodule.found); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/0000755000175100001660000000000014776170045030434 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs0000644000175100001660000000077414776170045033131 0ustar runnerdockerModule { property string prop property stringList listProp: [] Rule { inputs: ["dep-in"] outputFileTags: "dep-out" prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating dep-out artifact"; cmd.sourceCode = function() { console.info("prop: " + product.depmodule.prop); console.info("listProp: " + product.depmodule.listProp); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/dependee.qbs0000644000175100001660000000042414776170045027266 0ustar runnerdockerProduct { name: "dependee" Depends { name: "myothermodule" } Depends { name: "dependency" } type: ["out", "dep-out"] Group { files: "test.in" fileTags: ["dep-in"] } Group { files: "test2.in" fileTags: ["in"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/test2.in0000644000175100001660000000000014776170045026365 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-in-exported-module/test.in0000644000175100001660000000000014776170045026303 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/makefile-generator/0000755000175100001660000000000014776170045023721 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/makefile-generator/app.qbs0000644000175100001660000000121714776170045025211 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); console.info("executable suffix: " + cpp.executableSuffix); return result; } name: "the app" consoleApplication: true cpp.cxxLanguageVersion: "c++11" cpp.separateDebugInformation: false Properties { condition: qbs.targetOS.includes("macos") bundle.embedInfoPlist: false cpp.minimumMacosVersion: "10.7" } files: "main.cpp" qbs.installPrefix: "/usr/local" install: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/makefile-generator/main.cpp0000644000175100001660000000012314776170045025345 0ustar runnerdocker#include int main() { std::cout << "Hello, World!" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/configure/0000755000175100001660000000000014776170045022141 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/configure/configure.qbs0000644000175100001660000000101614776170045024627 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { property bool enabled: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } property string name: 'configure' qbsSearchPaths: '.' Product { type: 'application' consoleApplication: true name: project.name files: 'main.cpp' Depends { name: 'cpp' } Depends { name: 'definition' } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/configure/main.cpp0000644000175100001660000000245514776170045023577 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::printf("%s..\n", TEXT); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/configure/modules/0000755000175100001660000000000014776170045023611 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/configure/modules/definition/0000755000175100001660000000000014776170045025741 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/configure/modules/definition/module.qbs0000644000175100001660000000166414776170045027744 0ustar runnerdockerimport qbs.Process Module { name: 'definition' Depends { name: 'cpp' } Probe { id: node property stringList targetOS: qbs.targetOS property stringList windowsShellPath: qbs.windowsShellPath property string result configure: { var cmd; var args; var p = path; if (targetOS.includes("windows")) { cmd = windowsShellPath; args = ["/c", "date", "/t"]; } else { cmd = 'date'; args = []; } var p = new Process(); if (0 === p.exec(cmd, args)) { found = true; result = p.readLine(); } else { found = false; result = undefined; } p.close(); } } cpp.defines: node.found ? 'TEXT="Configured at ' + node.result + '"' : undefined } qbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/0000755000175100001660000000000014776170045020756 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/lsp.qbs0000644000175100001660000000031214776170045022257 0ustar runnerdockerProject { Product { name: "dep" Depends { name: "m" } Depends { name: "Prefix"; submodules: ["m1", "m2", "m3"] } } Product { Depends { name: "dep" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/0000755000175100001660000000000014776170045022426 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/m/0000755000175100001660000000000014776170045022662 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/m/m.qbs0000644000175100001660000000001314776170045023617 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/0000755000175100001660000000000014776170045023663 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/m3/0000755000175100001660000000000014776170045024202 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/m3/m3.qbs0000644000175100001660000000001314776170045025222 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/m2/0000755000175100001660000000000014776170045024201 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/m2/m2.qbs0000644000175100001660000000001314776170045025220 0ustar runnerdockerModule { } qbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/m1/0000755000175100001660000000000014776170045024200 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/lsp/modules/Prefix/m1/m1.qbs0000644000175100001660000000011314776170045025217 0ustar runnerdockerModule { property bool p1 property string p2 property bool x } qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-library-names/0000755000175100001660000000000014776170045024351 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-library-names/main.cpp0000644000175100001660000000235214776170045026003 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/invalid-library-names/invalid-library-names.qbs0000644000175100001660000000046714776170045031260 0ustar runnerdockerProject { minimumQbsVersion: "1.6" property var values: [null, undefined, 5, [], ""] property int valueIndex CppApplication { cpp.dynamicLibraries: [project.values[project.valueIndex]] cpp.staticLibraries: [project.values[project.valueIndex]] files: ["main.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/installed_artifact/0000755000175100001660000000000014776170045024014 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/installed_artifact/installed_artifact.qbs0000644000175100001660000000070514776170045030361 0ustar runnerdockerApplication { name: "installedApp" type: "application" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Depends { name: "cpp" } Group { files: "main.cpp" qbs.install: true qbs.installDir: "src" } qbs.installPrefix: "/usr" Group { fileTagsFilter: "application" qbs.install: true qbs.installDir: "bin" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/installed_artifact/main.cpp0000644000175100001660000000235114776170045025445 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/nsis/0000755000175100001660000000000014776170045021134 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nsis/hello.bat0000644000175100001660000000002214776170045022721 0ustar runnerdockerecho Hello world! qbs-src-2.6.1/tests/auto/blackbox/testdata/nsis/hello.nsi0000644000175100001660000000056114776170045022754 0ustar runnerdockerSetCompressor zlib !ifdef Win64 Name "Qbs Hello - ${qbs.architecture} (64-bit)" !else Name "Qbs Hello - ${qbs.architecture} (32-bit)" !endif OutFile "you-should-not-see-a-file-with-this-name.exe" InstallDir "$DESKTOP\Qbs Hello" RequestExecutionLevel user Page directory Page instfiles Section "" SetOutPath "$INSTDIR" File "${batchFile}" SectionEnd qbs-src-2.6.1/tests/auto/blackbox/testdata/nsis/hello.qbs0000644000175100001660000000054614776170045022753 0ustar runnerdockerNSISSetup { name: "Qbs Hello" targetName: "qbs-hello-" + qbs.architecture property bool dummy: { console.info("is Windows: " + qbs.targetOS.includes("windows")); } Properties { condition: nsis.present nsis.defines: ["batchFile=hello.bat"] nsis.compressor: "lzma-solid" } files: ["hello.nsi", "hello.bat"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/0000755000175100001660000000000014776170045025717 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/0000755000175100001660000000000014776170045030441 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir1/0000755000175100001660000000000014776170045032012 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir1/file.txtqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir1/file.t0000644000175100001660000000000014776170045033104 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir2/0000755000175100001660000000000014776170045032013 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir2/file.txtqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/nonrecursive/subdir2/file.t0000644000175100001660000000000014776170045033105 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive2/0000755000175100001660000000000014776170045030010 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive2/recursive.txt0000644000175100001660000000000014776170045032546 0ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/wildcards-and-change-tracking.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/wildcards-and-change-tracki0000644000175100001660000000045414776170045033057 0ustar runnerdockerProduct { Group { name: "recursive" files: "**/file.txt" } Group { name: "directories" prefix: "nonrecursive/" files: "subdi?/file.txt" } Group { prefix: "nonrecursive/empty/" name: "no files" files: "*.txt" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive1/0000755000175100001660000000000014776170045030007 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/wildcards-and-change-tracking/recursive1/recursive.txt0000644000175100001660000000000014776170045032545 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nsisDependencies/0000755000175100001660000000000014776170045023443 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nsisDependencies/nsisDependencies.qbs0000644000175100001660000000467314776170045027447 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Project { property bool dummy: { console.info("is Windows: " + qbs.targetOS.includes("windows")); } NSISSetup { name: "inst" destinationDirectory: project.buildDirectory Depends { name: "app" } Depends { name: "lib" } Properties { condition: nsis.present nsis.defines: ["buildDirectory=" + FileInfo.toWindowsSeparators(project.buildDirectory)] } files: ["hello.nsi"] } Application { Depends { name: "cpp" } name: "app" files: ["main.c"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Group { fileTagsFilter: product.type qbs.install: true } destinationDirectory: project.buildDirectory } DynamicLibrary { Depends { name: "cpp" } name: "lib" files: ["main.c"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Group { fileTagsFilter: product.type qbs.install: true } Rule { // This rule tries to provoke the installer into building too early (and the test // verifies that it does not) by causing the build of the installables to take // a lot longer. multiplex: true outputFileTags: ["c"] outputArtifacts: { var artifacts = []; for (var i = 0; i < 96; ++i) artifacts.push({ filePath: "c" + i + ".c", fileTags: ["c"] }); return artifacts; } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { for (var i = 0; i < outputs["c"].length; ++i) { var tf; try { tf = new TextFile(outputs["c"][i].filePath, TextFile.WriteOnly); tf.writeLine("int main" + i + "() { return 0; }"); } finally { if (tf) tf.close(); } } }; return [cmd]; } } destinationDirectory: project.buildDirectory } } qbs-src-2.6.1/tests/auto/blackbox/testdata/nsisDependencies/hello.nsi0000644000175100001660000000023114776170045025255 0ustar runnerdockerPage directory Page instfiles Section "" SetOutPath "$INSTDIR" File "${buildDirectory}\app.exe" File "${buildDirectory}\lib.dll" SectionEnd qbs-src-2.6.1/tests/auto/blackbox/testdata/nsisDependencies/main.c0000644000175100001660000000003114776170045024525 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/0000755000175100001660000000000014776170045025701 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/main.cpp0000644000175100001660000000001614776170045027326 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/0000755000175100001660000000000014776170045027351 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/oldmodule/0000755000175100001660000000000014776170045031335 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/oldmodule/oldmodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/oldmodule/oldmodule.0000644000175100001660000000011314776170045033315 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++11" } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newermodule/0000755000175100001660000000000014776170045031677 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newermodule/newermodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newermodule/newermod0000644000175100001660000000011314776170045033435 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++14" } qbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/0000755000175100001660000000000014776170045032064 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/newestmodule.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/modules/newestmodule/newestm0000644000175100001660000000011314776170045033464 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++23" } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/maximum-cxx-language-version.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/maximum-cxx-language-version/maximum-cxx-language-version0000644000175100001660000000036014776170045033344 0ustar runnerdockerCppApplication { name: "app" property bool enableNewestModule: true Depends { name: "oldmodule" } Depends { name: "newermodule" } Depends { name: "newestmodule"; condition: enableNewestModule } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/build-variant-defaults/0000755000175100001660000000000014776170045024526 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs0000644000175100001660000000114714776170045031606 0ustar runnerdockerCppApplication { property bool validate: { var valid = true; if (qbs.buildVariant === "release") { valid = !qbs.enableDebugCode && !qbs.debugInformation && qbs.optimization === "fast"; } else if (qbs.buildVariant === "debug") { valid = qbs.enableDebugCode && qbs.debugInformation && qbs.optimization === "none"; } else if (qbs.buildVariant === "profiling") { valid = !qbs.enableDebugCode && qbs.debugInformation && qbs.optimization === "fast"; } if (!valid) throw "Invalid defaults"; return valid; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp0000644000175100001660000000003114776170045026150 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/0000755000175100001660000000000014776170045022742 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs0000644000175100001660000000422614776170045026237 0ustar runnerdockerimport qbs.FileInfo Project { property bool isStatic: false property bool isBundle: false property string headersInstallDir: "include" Product { name: "DllExport" Depends { name: "Exporter.cmake" } Group { name: "API headers" files: ["../dllexport.h"] qbs.install: true qbs.installDir: project.headersInstallDir } Group { fileTagsFilter: ["Exporter.cmake.package"] qbs.install: true qbs.installDir: "/lib/cmake/DllExport" } Export { Depends { name: "cpp" } cpp.includePaths: FileInfo.joinPaths( exportingProduct.qbs.installRoot, exportingProduct.qbs.installPrefix, project.headersInstallDir) } } Library { type: project.isStatic ? "staticlibrary" : "dynamiclibrary" Depends { name: "cpp" } Depends { name: "DllExport" } Depends { name: "Exporter.cmake" } Exporter.cmake.packageName: "Bar" name: "Foo" files: ["Foo.cpp"] version: "1.2.3" cpp.includePaths: "." cpp.defines: "FOO_LIB" Group { name: "API headers" files: ["Foo.h"] qbs.install: true qbs.installDir: project.headersInstallDir } install: true installImportLib: true Group { fileTagsFilter: ["Exporter.cmake.package"] qbs.install: true qbs.installDir: "/lib/cmake/Bar" } Export { Depends { name: "cpp" } cpp.includePaths: FileInfo.joinPaths( exportingProduct.qbs.installRoot, exportingProduct.qbs.installPrefix, project.headersInstallDir) cpp.defines: ["FOO=1"].concat(project.isStatic ? ["FOO_LIB_STATIC"] : []) cpp.commonCompilerFlags: "-DOTHER_DEF=1" cpp.linkerFlags: exportingProduct.qbs.toolchain.contains("gcc") ? ["-s"] : [] } Depends { name: 'bundle' } bundle.isBundle: qbs.targetOS.includes("darwin") && project.isBundle } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp0000644000175100001660000000006614776170045024173 0ustar runnerdocker#include "Foo.h" int someFooWork() { return 42; } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs0000644000175100001660000000254214776170045025452 0ustar runnerdockerimport qbs.Probes Product { Depends { name: "cpp" } Probes.BinaryProbe { id: cmakeProbe names: "cmake" } Probes.BinaryProbe { id: ninjaProbe names: ["ninja"] } property bool test: { var data = { cmakeFound: cmakeProbe.found, cmakeFilePath: cmakeProbe.filePath, crossCompiling: qbs.targetPlatform !== qbs.hostPlatform, installPrefix: qbs.installPrefix }; data.buildEnv = {} Object.assign(data.buildEnv, cpp.buildEnv); // deep copy buildEnv from a probe if (qbs.toolchain.includes("gcc")) { data.buildEnv["CC"] = cpp.cCompilerName; data.buildEnv["CXX"] = cpp.cxxCompilerName; } else { data.buildEnv["CC"] = cpp.compilerName; data.buildEnv["CXX"] = cpp.compilerName; } if (ninjaProbe.found) { data.generator = "Ninja"; } else { if (qbs.toolchain.includes("msvc")) { data.generator = "NMake Makefiles" } else if (qbs.toolchain.includes("mingw")) { data.generator = "MinGW Makefiles"; } else if (qbs.toolchain.includes("gcc")) { data.generator = "Unix Makefiles"; } } console.info("---" + JSON.stringify(data) + "---"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/Foo.h0000644000175100001660000000040114776170045023631 0ustar runnerdocker#ifndef FOO_H #define FOO_H #include #ifdef FOO_LIB_STATIC #define FOO_LIB_EXPORT #else #ifdef FOO_LIB #define FOO_LIB_EXPORT DLL_EXPORT #else #define FOO_LIB_EXPORT DLL_IMPORT #endif #endif FOO_LIB_EXPORT int someFooWork(); #endif // FOO_H qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/cmake/0000755000175100001660000000000014776170045024022 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp0000644000175100001660000000007314776170045025452 0ustar runnerdocker#include int main() { return someFooWork(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt0000644000175100001660000000024214776170045026560 0ustar runnerdockercmake_minimum_required(VERSION 3.10) project(qbs_import) find_package(Bar PATHS REQUIRED) add_executable(Consumer main.cpp) target_link_libraries(Consumer Bar) qbs-src-2.6.1/tests/auto/blackbox/testdata/installed-transformer-output/0000755000175100001660000000000014776170045026035 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs0000644000175100001660000000141214776170045027573 0ustar runnerdockerimport qbs.TextFile Product { name: "install-test" type: ["text"] qbs.installPrefix: "" Group { qbs.install: true qbs.installDir: "textfiles" fileTagsFilter: "text" } Rule { multiplex: true Artifact { filePath: "HelloWorld.txt" fileTags: ["text"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating file:'" + output.fileName + "'"; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(output.filePath, TextFile.WriteOnly); file.writeLine("Hello World!") file.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-shadow-products/0000755000175100001660000000000014776170045025336 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probes-and-shadow-products/probes-and-shadow-products.qbs0000644000175100001660000000034014776170045033220 0ustar runnerdockerProduct { name: "p" multiplexByQbsProperties: "buildVariants" qbs.buildVariants: ["debug", "release"] Export { Probe { id: dummy configure: { found = true; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/installpackage/0000755000175100001660000000000014776170045023142 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/installpackage/lib.h0000644000175100001660000000256014776170045024064 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" #ifdef MYLIB # define MYLIB_EXPORT DLL_EXPORT #else # define MYLIB_EXPORT DLL_IMPORT #endif MYLIB_EXPORT void f(); qbs-src-2.6.1/tests/auto/blackbox/testdata/installpackage/installpackage.qbs0000644000175100001660000000226614776170045026641 0ustar runnerdockerProject { CppApplication { name: "public_tool" Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Depends { name: "mylib" } files: ["main.cpp"] Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "bin" } } CppApplication { name: "internal_tool" Depends { name: "mylib" } files: ["main.cpp"] } DynamicLibrary { Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } Depends { name: "cpp" } name: "mylib" files: ["lib.cpp"] Group { name: "public headers" files: ["lib.h"] qbs.install: true qbs.installDir: "include" } Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "lib" } } InstallPackage { archiver.type: "tar" builtByDefault: true name: "tar-package" Depends { name: "public_tool" } Depends { name: "mylib" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/installpackage/lib.cpp0000644000175100001660000000237114776170045024417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib.h" void f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/installpackage/main.cpp0000644000175100001660000000240514776170045024573 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib.h" int main() { f(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/0000755000175100001660000000000014776170045022473 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs0000644000175100001660000000175314776170045025523 0ustar runnerdockerProject { CppApplication { name: "main" install: true property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } files: [ "main.cpp", "myapp.desktop", "myapp.appdata.xml", ] Depends { name: "freedesktop" } freedesktop.appName: "My App" freedesktop.desktopKeys: ({ 'Icon': "myapp.png" }) freedesktop.hicolorRoot: project.sourceDirectory + "/icons/" Group { name: "hicolor" prefix: project.sourceDirectory + "/icons/" files: [ "48x48/apps/myapp.png", "48x48@2/apps/myapp.png", "64x64/apps/myapp.png", "64x64@2/apps/myapp.png", "64x64/mimetypes/application-format.png", "scalable/apps/myapp.png", ] fileTags: "freedesktop.appIcon" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/0000755000175100001660000000000014776170045023606 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/scalable/0000755000175100001660000000000014776170045025354 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/scalable/apps/0000755000175100001660000000000014776170045026317 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/scalable/apps/myapp.png0000644000175100001660000000000014776170045030141 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/48x48@2/0000755000175100001660000000000014776170045024567 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/48x48@2/apps/0000755000175100001660000000000014776170045025532 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/48x48@2/apps/myapp.png0000644000175100001660000000000014776170045027354 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64@2/0000755000175100001660000000000014776170045024563 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64@2/apps/0000755000175100001660000000000014776170045025526 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64@2/apps/myapp.png0000644000175100001660000000000014776170045027350 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/48x48/0000755000175100001660000000000014776170045024405 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/48x48/apps/0000755000175100001660000000000014776170045025350 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/48x48/apps/myapp.png0000644000175100001660000000000014776170045027172 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64/0000755000175100001660000000000014776170045024401 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64/mimetypes/0000755000175100001660000000000014776170045026415 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64/mimetypes/application-format.png0000644000175100001660000000000014776170045032702 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64/apps/0000755000175100001660000000000014776170045025344 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/icons/64x64/apps/myapp.png0000644000175100001660000000000014776170045027166 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/myapp.desktop0000644000175100001660000000030514776170045025212 0ustar runnerdocker[Desktop Entry] GenericName=Image Editor GenericName[fr]=Éditeur d'images Comment=Create images and edit photographs Comment[fr]=Créer des images et éditer des photographies Icon=overridden.png qbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml0000644000175100001660000000066514776170045025763 0ustar runnerdocker myapp.desktop CC0 MyApp The coolest app ever

This is a cool application.

https://software.house/myapp GPL-2.0+ Coding Wizard
qbs-src-2.6.1/tests/auto/blackbox/testdata/freedesktop/main.cpp0000644000175100001660000000003514776170045024121 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-fileinfo/0000755000175100001660000000000014776170045024505 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs0000644000175100001660000000531314776170045027011 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Product { type: ["dummy"] property string messyPath: path + "/../" + FileInfo.fileName(path) Rule { multiplex: true outputFileTags: "dummy" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { var output = new TextFile(FileInfo.joinPaths(product.sourceDirectory, "output.txt"), TextFile.WriteOnly); output.writeLine(FileInfo.baseName("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.canonicalPath(product.messyPath)); output.writeLine(FileInfo.cleanPath("/usr/local//../bin/")); output.writeLine(FileInfo.completeBaseName("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.fileName("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.fromWindowsSeparators("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.fromWindowsSeparators("c:\\tmp\\blubb.tar.gz")); output.writeLine(FileInfo.isAbsolutePath("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.isAbsolutePath("c:\\tmp\\blubb.tar.gz")); output.writeLine(FileInfo.isAbsolutePath("c:\\tmp\\blubb.tar.gz", ["unix"])); output.writeLine(FileInfo.isAbsolutePath("c:\\tmp\\blubb.tar.gz", ["windows"])); output.writeLine(FileInfo.isAbsolutePath("blubb.tar.gz")); output.writeLine(FileInfo.isAbsolutePath("../blubb.tar.gz")); output.writeLine(FileInfo.joinPaths("/", "tmp", "blubb.tar.gz")); output.writeLine(FileInfo.joinPaths("//", "/tmp/", "/blubb.tar.gz")); output.writeLine(FileInfo.path("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.path("/tmp/")); output.writeLine(FileInfo.path("/")); output.writeLine(FileInfo.path("d:/")); output.writeLine(FileInfo.path("d:/", ["unix"])); output.writeLine(FileInfo.path("d:/", ["windows"])); output.writeLine(FileInfo.relativePath("/tmp", "/tmp/blubb.tar.gz")); output.writeLine(FileInfo.relativePath("/", "/tmp/blubb.tar.gz")); output.writeLine(FileInfo.relativePath("/tmp", "/blubb.tar.gz")); output.writeLine(FileInfo.toWindowsSeparators("/tmp/blubb.tar.gz")); output.writeLine(FileInfo.toWindowsSeparators("c:\\tmp\\blubb.tar.gz")); output.writeLine(FileInfo.pathListSeparator()); output.writeLine(FileInfo.pathSeparator()); output.close(); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/0000755000175100001660000000000014776170045025227 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/compilerDefinesByLanguage.qbs0000644000175100001660000001757014776170045033017 0ustar runnerdockerProject { CppDefinesApp { name: "A" // eqiuvalent to ["c"] since we always need some compiler defines // for the architecture detection, etc. cpp.enableCompilerDefinesByLanguage: [] property var foo: { if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (!cpp.compilerDefinesByLanguage["c"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } CppDefinesApp { name: "B" cpp.enableCompilerDefinesByLanguage: ["cpp"] property var foo: { if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (cpp.compilerDefinesByLanguage["c"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (!cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } CppDefinesApp { name: "C" condition: enableObjectiveC cpp.enableCompilerDefinesByLanguage: ["objc"] property var foo: { if (!enableObjectiveC) return; if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (cpp.compilerDefinesByLanguage["c"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (!cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } CppDefinesApp { name: "D" condition: enableObjectiveC cpp.enableCompilerDefinesByLanguage: ["objcpp"] property var foo: { if (!enableObjectiveC) return; if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (cpp.compilerDefinesByLanguage["c"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (!cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } CppDefinesApp { name: "E" condition: enableObjectiveC cpp.enableCompilerDefinesByLanguage: ["cpp", "objcpp"] property var foo: { if (!enableObjectiveC) return; if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (cpp.compilerDefinesByLanguage["c"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (!cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (!cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } CppDefinesApp { name: "F" cpp.enableCompilerDefinesByLanguage: ["c", "cpp"] property var foo: { if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (!cpp.compilerDefinesByLanguage["c"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (!cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } CppDefinesApp { name: "G" condition: enableObjectiveC cpp.enableCompilerDefinesByLanguage: ["objc", "objcpp"] property var foo: { if (!enableObjectiveC) return; if (!cpp.compilerDefinesByLanguage) throw "ASSERT cpp.compilerDefinesByLanguage: " + cpp.compilerDefinesByLanguage; if (cpp.compilerDefinesByLanguage["c"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"c\"]: " + cpp.compilerDefinesByLanguage["c"]; if (cpp.compilerDefinesByLanguage["cpp"]) throw "ASSERT !cpp.compilerDefinesByLanguage[\"cpp\"]: " + cpp.compilerDefinesByLanguage["cpp"]; if (!cpp.compilerDefinesByLanguage["objc"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"objc\"]: " + cpp.compilerDefinesByLanguage["objc"]; if (!cpp.compilerDefinesByLanguage["objcpp"]) throw "ASSERT cpp.compilerDefinesByLanguage[\"objcpp\"]: " + cpp.compilerDefinesByLanguage["objcpp"]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/test.cpp0000644000175100001660000000000014776170045026700 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/app.c0000644000175100001660000000003514776170045026151 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/CppDefinesApp.qbs0000644000175100001660000000057214776170045030423 0ustar runnerdockerCppApplication { files: ["app.c"] property bool enableObjectiveC: qbs.targetOS.includes("darwin") Group { name: "C/C++" files: [ "test.c", "test.cpp", ] } Group { name: "Objective-C" condition: enableObjectiveC files: [ "test.m", "test.mm", ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/test.mm0000644000175100001660000000000014776170045026527 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/test.c0000644000175100001660000000000014776170045026340 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/compilerDefinesByLanguage/test.m0000644000175100001660000000000014776170045026352 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/undefined-target-platform/0000755000175100001660000000000014776170045025227 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs0000644000175100001660000000051014776170045033001 0ustar runnerdockerimport qbs.File import qbs.FileInfo Product { name: "undefined-target-platform" qbs.targetPlatform: undefined readonly property bool _validate: { if ((qbs.targetOS instanceof Array) && qbs.targetOS.length === 0) return true; throw "Invalid qbs.targetOS value: " + qbs.targetOS; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/0000755000175100001660000000000014776170045026254 5ustar runnerdocker././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/import-in-properties-condition.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/import-in-properties-condi0000644000175100001660000000005414776170045033400 0ustar runnerdockerProduct { Depends { name: "amodule" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/modules/0000755000175100001660000000000014776170045027724 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/modules/depmodule/0000755000175100001660000000000014776170045031702 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/modules/depmodule/m.qbs0000644000175100001660000000004414776170045032643 0ustar runnerdockerModule { property string prop } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/modules/amodule/0000755000175100001660000000000014776170045031352 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-in-properties-condition/modules/amodule/m.qbs0000644000175100001660000000023514776170045032315 0ustar runnerdockerimport qbs.File Module { Depends { name: "depmodule" } Properties { condition: File.exists("blubb") depmodule.prop: "blubb" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/sanitizer/0000755000175100001660000000000014776170045022170 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs0000644000175100001660000000305414776170045024711 0ustar runnerdockerCppApplication { Depends { name: "Sanitizers.address" } Sanitizers.address.enabled: sanitizer === "address" property string sanitizer property bool supportsSanitizer: { if (qbs.toolchain.includes("mingw") || qbs.toolchain.contains("emscripten")) return false; if (sanitizer === "address") return Sanitizers.address._supported; if (qbs.toolchain.includes("clang-cl")) { if (cpp.toolchainInstallPath.includes("Microsoft Visual Studio") && qbs.architecture === "x86_64") { // 32 bit sanitizer shipped with VS misses the x86_64 libraries return false; } // only these are supported return sanitizer === "address" || sanitizer === "undefined"; } if (!qbs.toolchain.includes("gcc")) return false; if (qbs.targetOS.includes("ios")) { // thread sanitizer is not supported return sanitizer !== "thread"; } return true; } condition: { if (!sanitizer) return true; if (!supportsSanitizer) console.info("Compiler does not support sanitizer"); return supportsSanitizer; } qbs.buildVariant: "release" cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.8" consoleApplication: true cpp.runtimeLibrary: "static" cpp.driverFlags: sanitizer && sanitizer !== "address" ? ["-fsanitize=" + sanitizer] : [] cpp.debugInformation: true files: "sanitizer.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp0000644000175100001660000000006314776170045024703 0ustar runnerdockerint main(int argc, char *argv[]) { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/retagged-output-artifact/0000755000175100001660000000000014776170045025073 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/retagged-output-artifact/retagged-output-artifact.qbs0000644000175100001660000000242714776170045032522 0ustar runnerdockerimport qbs.File import qbs.TextFile Product { name: "p" type: "p_type" property bool useTag1 Rule { multiplex: true outputFileTags: ["tag1", "tag2"] outputArtifacts: [{filePath: "a1.txt", fileTags: product.useTag1 ? "tag1" : "tag2"}] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.filePath; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); }; return cmd; } } Rule { inputs: "tag1" Artifact { filePath: "a2.txt"; fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.filePath; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } Rule { inputs: "tag2" Artifact { filePath: "a3.txt"; fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.filePath; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/emscripten-artifacts/0000755000175100001660000000000014776170045024307 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/emscripten-artifacts/emscripten-artifacts.qbs0000644000175100001660000000023614776170045031146 0ustar runnerdockerCppApplication { name: "app" property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/emscripten-artifacts/main.cpp0000644000175100001660000000235114776170045025740 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/non-default-product/0000755000175100001660000000000014776170045024052 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/non-default-product/non-default-product.qbs0000644000175100001660000000063014776170045030452 0ustar runnerdockerProject { CppApplication { name: "default app" consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: "main.cpp" } CppApplication { name: "non-default app" Depends { name: "default app" } consoleApplication: true builtByDefault: false files: "main.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/non-default-product/main.cpp0000644000175100001660000000235114776170045025503 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/0000755000175100001660000000000014776170045023634 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/product.qbs0000644000175100001660000000067414776170045026032 0ustar runnerdockerProject { Product { name: "dep" Export { Depends { name: "lowerlevel" } lowerlevel.someOtherProp: "blubb" } } Product { type: "mytype" name: "toplevel" Depends { name: "higherlevel" } Depends { name: "lowerlevel" } Depends { name: "dep" } Group { files: ["dummy.txt"] fileTags: ["dummy-input"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/dummy.txt0000644000175100001660000000000014776170045025516 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/modules/0000755000175100001660000000000014776170045025304 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/modules/higherlevel/0000755000175100001660000000000014776170045027602 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/modules/higherlevel/higher-level.qbs0000644000175100001660000000014414776170045032663 0ustar runnerdockerModule { Depends { name: "lowerlevel" } lowerlevel.propDependency: "value in higherlevel" } qbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/modules/lowerlevel/0000755000175100001660000000000014776170045027464 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/nested-properties/modules/lowerlevel/lower-level.qbs0000644000175100001660000000076014776170045032433 0ustar runnerdockerModule { property string propDependency: "value in lowerlevel module" property string prop: propDependency property string someOtherProp Rule { inputs: ["dummy-input"] outputFileTags: "mytype" prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = function() { }; var prop = product.lowerlevel.prop; cmd.description = "lowerlevel.prop is '" + prop + "'"; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/0000755000175100001660000000000014776170045025432 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/dummy.txt0000644000175100001660000000000014776170045027314 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/list-properties-with-outer.qbs0000644000175100001660000000033514776170045033414 0ustar runnerdockerProduct { type: ["outtype"] Depends { name: "higher" } lower.listProp: ["product"] Group { files: ["dummy.txt"] fileTags: ["intype"] lower.listProp: outer.concat(["group"]) } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/modules/0000755000175100001660000000000014776170045027102 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/modules/lower/0000755000175100001660000000000014776170045030232 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/modules/lower/lower.qbs0000644000175100001660000000061314776170045032071 0ustar runnerdockerModule { property stringList listProp Rule { inputs: ["intype"] outputFileTags: "outtype" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info("listProp: " + JSON.stringify(input.lower.listProp)); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/modules/higher/0000755000175100001660000000000014776170045030350 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-properties-with-outer/modules/higher/higher.qbs0000644000175100001660000000011014776170045032315 0ustar runnerdockerModule { Depends { name: "lower" } lower.listProp: ["higher"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/inputs-from-dependencies/0000755000175100001660000000000014776170045025067 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/inputs-from-dependencies/file1.txt0000644000175100001660000000000014776170045026616 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/inputs-from-dependencies/file3.txt0000644000175100001660000000000014776170045026620 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/inputs-from-dependencies/inputs-from-dependencies.qbs0000644000175100001660000000233314776170045032506 0ustar runnerdockerProject { Product { name: "TextFileContainer1" type: "txt_container" Group { files: ["file1.txt", "file2.txt"] fileTags: "txt" } } Product { name: "TextFileContainer2" Group { files: ["file3.txt"] fileTags: "txt" } } Product { name: "TextFileContainer3" Group { files: ["file4.txt"] fileTags: "txt" } } Product { name: "TextFileGatherer" type: "printed_txt" Depends { name: "TextFileContainer1" } Depends { name: "TextFileContainer2" } Rule { inputsFromDependencies: "txt" multiplex: true Artifact { filePath: "blubb" fileTags: "printed_txt" alwaysUpdated: false } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "gathering text files"; cmd.sourceCode = function() { for (i in inputs.txt) console.info(inputs.txt[i].filePath); }; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/inputs-from-dependencies/file4.txt0000644000175100001660000000000014776170045026621 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/inputs-from-dependencies/file2.txt0000644000175100001660000000000014776170045026617 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/0000755000175100001660000000000014776170045024137 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/dep.qbs0000644000175100001660000000027614776170045025423 0ustar runnerdockerProduct { name: "dep" Export { Depends { name: "leaf" } Depends { name: "nonleaf" } // leaf.scalarProp: "export" // leaf.listProp: ["export"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/property-precedence.qbs0000644000175100001660000000060414776170045030625 0ustar runnerdockerProject { references: ["dep.qbs"] Product { name: "toplevel" type: ["rule-output"] Depends { name: "leaf" } Depends { name: "nonleaf" } Depends { name: "dep" } Group { files: ["dummy.txt"] fileTags: ["rule-input"] } // leaf.scalarProp: "product" // leaf.listProp: ["product"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/dummy.txt0000644000175100001660000000000014776170045026021 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/modules/0000755000175100001660000000000014776170045025607 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/modules/leaf/0000755000175100001660000000000014776170045026516 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/modules/leaf/leaf.qbs0000644000175100001660000000101714776170045030133 0ustar runnerdockerModule { property string scalarProp: "leaf" property stringList listProp: ["leaf"] Rule { inputs: ["rule-input"] outputFileTags: "rule-output" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info("scalar prop: " + product.leaf.scalarProp); console.info("list prop: " + JSON.stringify(product.leaf.listProp)); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/modules/nonleaf/0000755000175100001660000000000014776170045027231 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-precedence/modules/nonleaf/nonleaf.qbs0000644000175100001660000000015514776170045031363 0ustar runnerdockerModule { Depends { name: "leaf" } // leaf.scalarProp: "nonleaf" // leaf.listProp: ["nonleaf"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-list-in-probe/0000755000175100001660000000000014776170045023576 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-list-in-probe/path-list-in-probe.qbs0000644000175100001660000000050214776170045027720 0ustar runnerdockerProject { CppApplication { Probe { id: theProbe property pathList result configure: { result = ["main.cpp"] found = true } } property pathList res: theProbe.found ? theProbe.result : [] Group { name: "files" files: res } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-list-in-probe/main.cpp0000644000175100001660000000003414776170045025223 0ustar runnerdockerint main() { return 0; }qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/0000755000175100001660000000000014776170045022165 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/bar.capnp0000644000175100001660000000020214776170045023746 0ustar runnerdocker@0xc967c84bcca70a1d; using Foo = import "foo.capnp"; struct Bar { foo @0 :Foo.Foo; # Use type "Foo" defined in foo.capnp. } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.cpp0000644000175100001660000000027714776170045025546 0ustar runnerdocker#include "foo.capnp.h" #include int main() { ::capnp::MallocMessageBuilder message; auto foo = message.initRoot(); foo.setStr("hello"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/imports/0000755000175100001660000000000014776170045023662 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/imports/foo.capnp0000644000175100001660000000011314776170045025463 0ustar runnerdocker@0x8a2efe67220790be; struct Foo { num @0 :UInt32; str @1 :Text; } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/conanfile.txt0000644000175100001660000000012014776170045024655 0ustar runnerdocker[requires] capnproto/1.0.2 [tool_requires] capnproto/1.0.2 [generators] QbsDeps qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/greeter-server.cpp0000644000175100001660000000130014776170045025624 0ustar runnerdocker#include "greeter.capnp.h" #include #include #include class GreeterImpl final: public Greeter::Server { public: ::kj::Promise sayHello(SayHelloContext context) override { auto response = context.getResults().initResponse(); response.setName(context.getParams().getRequest().getName()); return kj::READY_NOW; }; }; int main(int argc, char *argv[]) { const char address[] = "localhost:5050"; capnp::EzRpcServer server(kj::heap(), address); auto& waitScope = server.getWaitScope(); // Run forever, accepting connections and handling requests. kj::NEVER_DONE.wait(waitScope); } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/greeter_cpp.qbs0000644000175100001660000000235514776170045025200 0ustar runnerdockerimport qbs.Host Project { CppApplication { Depends { name: "capnproto.cpp"; required: false } condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); if (!capnproto.cpp.present) console.info("capnproto is not present"); return result && capnproto.cpp.present; } name: "server" consoleApplication: true cpp.minimumMacosVersion: "10.8" // workaround for broken capnproto cpp.staticLibraries: qbs.targetOS.contains("windows") ? "Advapi32" : [] capnproto.cpp.useRpc: true files: [ "greeter.capnp", "greeter-server.cpp" ] qbs.buildVariant: "release" } CppApplication { Depends { name: "capnproto.cpp"; required: false } name: "client" consoleApplication: true capnproto.cpp.useRpc: true cpp.minimumMacosVersion: "10.8" cpp.staticLibraries: qbs.targetOS.contains("windows") ? "Advapi32" : [] files: [ "greeter.capnp", "greeter-client.cpp" ] qbs.buildVariant: "release" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.cpp0000644000175100001660000000033514776170045030164 0ustar runnerdocker#include "bar.capnp.h" #include int main() { ::capnp::MallocMessageBuilder message; auto bar = message.initRoot(); auto foo = bar.initFoo(); foo.setStr("hello"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.qbs0000644000175100001660000000115214776170045030170 0ustar runnerdockerimport qbs.Host CppApplication { Depends { name: "capnproto.cpp"; required: false } condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); if (!capnproto.cpp.present) console.info("capnproto is not present"); return result && capnproto.cpp.present; } cpp.minimumMacosVersion: "10.8" capnproto.cpp.importPaths: "." files: [ "baz.capnp", "capnproto_absolute_import.cpp", "imports/foo.capnp", ] qbs.buildVariant: "release" } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/baz.capnp0000644000175100001660000000021314776170045023760 0ustar runnerdocker@0xc967c84bcca70a1d; using Foo = import "/imports/foo.capnp"; struct Baz { foo @0 :Foo.Foo; # Use type "Foo" defined in foo.capnp. } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/foo.capnp0000644000175100001660000000011314776170045023766 0ustar runnerdocker@0x8a2efe67220790be; struct Foo { num @0 :UInt32; str @1 :Text; } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/capnproto_absolute_import.cpp0000644000175100001660000000033514776170045030167 0ustar runnerdocker#include "baz.capnp.h" #include int main() { ::capnp::MallocMessageBuilder message; auto baz = message.initRoot(); auto foo = baz.initFoo(); foo.setStr("hello"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/capnproto_relative_import.qbs0000644000175100001660000000103614776170045030166 0ustar runnerdockerimport qbs.Host CppApplication { Depends { name: "capnproto.cpp"; required: false } condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); if (!capnproto.cpp.present) console.info("capnproto is not present"); return result && capnproto.cpp.present; } cpp.minimumMacosVersion: "10.8" files: [ "bar.capnp", "capnproto_relative_import.cpp", "foo.capnp", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/greeter-client.cpp0000644000175100001660000000116514776170045025605 0ustar runnerdocker#include "greeter.capnp.h" #include #include int main(int argc, char *argv[]) { const char address[] = "localhost:5050"; capnp::EzRpcClient client(address); Greeter::Client greeter = client.getMain(); auto& waitScope = client.getWaitScope(); for (int i = 0; i < 2; ++i) { auto request = greeter.sayHelloRequest(); request.initRequest().setName("hello workd"); auto promise = request.send(); auto response = promise.wait(waitScope); std::cout << response.getResponse().getName().cStr() << std::endl; } return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/capnproto_cpp.qbs0000644000175100001660000000103414776170045025541 0ustar runnerdockerimport qbs.Host CppApplication { Depends { name: "capnproto.cpp"; required: false } condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); if (!capnproto.cpp.present) console.info("capnproto is not present"); return result && capnproto.cpp.present; } cpp.minimumMacosVersion: "10.8" files: [ "capnproto_cpp.cpp", "foo.capnp" ] qbs.buildVariant: "release" } qbs-src-2.6.1/tests/auto/blackbox/testdata/capnproto/greeter.capnp0000644000175100001660000000031314776170045024642 0ustar runnerdocker@0x85150b117366d14b; struct HelloRequest { name @0 :Text; } struct HelloResponse { name @0 :Text; } interface Greeter { sayHello @0 (request: HelloRequest) -> (response: HelloResponse); } qbs-src-2.6.1/tests/auto/blackbox/testdata/no-exported-symbols/0000755000175100001660000000000014776170045024112 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/no-exported-symbols/lib.h0000644000175100001660000000011614776170045025027 0ustar runnerdocker#ifndef TEST_LIB #define TEST_LIB inline int success() { return 0; } #endif qbs-src-2.6.1/tests/auto/blackbox/testdata/no-exported-symbols/lib.cpp0000644000175100001660000000003214776170045025357 0ustar runnerdockerstatic void someFunc() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/no-exported-symbols/main.cpp0000644000175100001660000000006714776170045025545 0ustar runnerdocker#include int main() { return success(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs0000644000175100001660000000137114776170045030555 0ustar runnerdockerProject { DynamicLibrary { name: "the_lib" Depends { name: "cpp" } files: ["lib.cpp", "lib.h"] Export { Depends { name: "cpp" } cpp.includePaths: path } Probe { id: toolchainProbe property stringList toolchain: qbs.toolchain configure: { if (toolchain.includes("msvc") && !toolchain.includes("clang-cl")) console.info("compiler is MSVC") else console.info("compiler is not MSVC") } } } CppApplication { name: "the_app" property bool link Depends { name: "the_lib"; cpp.link: product.link } files: "main.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/0000755000175100001660000000000014776170045022221 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/name-filter.qbs0000644000175100001660000000035714776170045025140 0ustar runnerdockerBaseApp { inputNames: "tool" inputSearchPaths: "bin" inputNameFilter: { return function(n) { return n + ".2" }; } outputFilePaths: ["bin/tool.2"] outputCandidatePaths: [["bin/tool.2"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs0000644000175100001660000000031714776170045027202 0ustar runnerdockerBaseApp { inputSelectors: [ "tool.1", "nonexistent", "tool.2", ] inputSearchPaths: "bin" outputCandidatePaths: [["bin/tool.1"], ["bin/nonexistent"], ["bin/tool.2"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/non-existent.qbs0000644000175100001660000000016614776170045025366 0ustar runnerdockerBaseApp { inputNames: "nonexistent" inputSearchPaths: "bin" outputCandidatePaths: [["bin/nonexistent"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs0000644000175100001660000000047114776170045027617 0ustar runnerdockerBaseApp { inputSelectors: [ "tool", ["tool.0", "tool.1", "tool.2"], {names : ["tool.3", "tool.4"]}, ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool", "bin/tool.1", "bin/tool.3"] outputCandidatePaths: [["bin/tool"], ["bin/tool.0", "bin/tool.1"], ["bin/tool.3"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs0000644000175100001660000000052214776170045026126 0ustar runnerdockerimport qbs.FileInfo BaseApp { inputNames: ["tool.1", "tool.2"] inputSearchPaths: "bin" inputCandidateFilter: { var fi = FileInfo; return function(f) { return fi.fileName(f) == "tool.2"; } } outputFilePaths: ["bin/tool.2"] outputCandidatePaths: [["bin/tool.1", "bin/tool.2"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs0000644000175100001660000000021614776170045026743 0ustar runnerdockerBaseApp { inputSelectors: "tool" inputSearchPaths: "bin" outputFilePaths: ["bin/tool"] outputCandidatePaths: [["bin/tool"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/usr/0000755000175100001660000000000014776170045023032 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/usr/bin/0000755000175100001660000000000014776170045023602 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/usr/bin/tool0000644000175100001660000000000014776170045024470 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/mult-files-common-suffixes.qbs0000644000175100001660000000042314776170045030130 0ustar runnerdockerBaseApp { inputSelectors: [ {names : "tool"}, {names : "super-tool"}, ] inputNameSuffixes: ".1" inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1", "bin/super-tool.1"] outputCandidatePaths: [["bin/tool.1"], ["bin/super-tool.1"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs0000644000175100001660000000023414776170045027731 0ustar runnerdockerBaseApp { inputNames: ["tool.1", "tool.2"] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1"] outputCandidatePaths: [["bin/tool.1"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs0000644000175100001660000000043714776170045026647 0ustar runnerdockerBaseApp { inputSelectors: [ {names : "tool", nameSuffixes: ".2"}, {names : "super-tool", nameSuffixes: ".1"}, ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.2", "bin/super-tool.1"] outputCandidatePaths: [["bin/tool.2"], ["bin/super-tool.1"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/single-file.qbs0000644000175100001660000000021214776170045025121 0ustar runnerdockerBaseApp { inputNames: "tool" inputSearchPaths: "bin" outputFilePaths: ["bin/tool"] outputCandidatePaths: [["bin/tool"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs0000644000175100001660000000047514776170045027630 0ustar runnerdockerBaseApp { inputSelectors: [ {names : "tool", nameSuffixes: [".0", ".1", ".2"]}, {names : "super-tool", nameSuffixes: [".1"]}, ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1", "bin/super-tool.1"] outputCandidatePaths: [["bin/tool.0", "bin/tool.1"], ["bin/super-tool.1"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs0000644000175100001660000000030614776170045026757 0ustar runnerdockerBaseApp { inputNames: "tool" inputSearchPaths: "bin" inputNameSuffixes: [".0", ".1", ".2"] outputFilePaths: ["bin/tool.1"] outputCandidatePaths: [["bin/tool.0", "bin/tool.1"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/mult-files.qbs0000644000175100001660000000051414776170045025011 0ustar runnerdockerBaseApp { inputSelectors: [ "tool.1", ["tool.2"], {names : "tool.3"}, {names : ["tool.4"]} ] inputSearchPaths: "bin" outputFilePaths: ["bin/tool.1", "bin/tool.2", "bin/tool.3", "bin/tool.4"] outputCandidatePaths: [["bin/tool.1"], ["bin/tool.2"], ["bin/tool.3"], ["bin/tool.4"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs0000644000175100001660000000022014776170045030052 0ustar runnerdockerBaseApp { inputSelectors: ["tool"] inputSearchPaths: "bin" outputFilePaths: ["bin/tool"] outputCandidatePaths: [["bin/tool"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/0000755000175100001660000000000014776170045022771 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/tool.40000644000175100001660000000000014776170045024021 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/tool.20000644000175100001660000000000014776170045024017 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/super-tool.10000644000175100001660000000000014776170045025152 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/tool.10000644000175100001660000000000014776170045024016 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/tool.30000644000175100001660000000000014776170045024020 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/bin/tool0000644000175100001660000000000014776170045023657 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs0000644000175100001660000001255214776170045024250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com). ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.FileInfo import qbs.Probes Product { property varList inputSelectors property varList inputNames property varList inputNameSuffixes property pathList inputSearchPaths property var inputNameFilter property var inputCandidateFilter property stringList inputEnvironmentPaths property stringList outputFilePaths property var outputCandidatePaths Probes.PathProbe { id: probe selectors: inputSelectors names: inputNames nameSuffixes: inputNameSuffixes nameFilter: inputNameFilter candidateFilter: inputCandidateFilter searchPaths: inputSearchPaths platformSearchPaths: [] environmentPaths: inputEnvironmentPaths } property bool validate: { var compareArrays = function(lhs, rhs) { if (lhs.length !== rhs.length) return false; for (var i = 0; i < lhs.length; ++i) { if ((lhs[i] instanceof Array) && (rhs[i] instanceof Array)) { if (!compareArrays(lhs[i], rhs[i])) return false; } else if (FileInfo.resolvePath(path, lhs[i]) !== FileInfo.resolvePath(path, rhs[i])) { return false; } } return true; }; if (outputCandidatePaths) { var actual = probe.allResults.map(function(file) { return file.candidatePaths; }); if (!compareArrays(actual, outputCandidatePaths)) { throw "Invalid canndidatePaths: actual = " + JSON.stringify(actual) + ", expected = " + JSON.stringify(outputCandidatePaths); } } if (!probe.found) { if (probe.filePath) { throw "Invalid filePath: actual = " + JSON.stringify(probe.filePath) + ", expected = 'undefined'"; } if (probe.fileName) { throw "Invalid fileName: actual = " + JSON.stringify(probe.fileName) + ", expected = 'undefined'"; } if (probe.path) { throw "Invalid path: actual = " + JSON.stringify(probe.path) + ", expected = 'undefined'"; } throw "Probe failed to find files"; } if (outputFilePaths) { var actual = probe.allResults.map(function(file) { return file.filePath; }); if (!compareArrays(actual, outputFilePaths)) { throw "Invalid filePaths: actual = " + JSON.stringify(actual) + ", expected = " + JSON.stringify(outputFilePaths); } } if (probe.allResults.length !== 1) return; // check that single-file interface matches the first value in allResults var expectedFilePath = probe.allResults[0].filePath; if (probe.filePath !== expectedFilePath) { throw "Invalid filePath: actual = " + probe.filePath + ", expected = " + expectedFilePath; } var expectedFileName = probe.allResults[0].fileName; if (probe.fileName !== expectedFileName) { throw "Invalid fileName: actual = " + probe.fileName + ", expected = " + expectedFileName; } var expectedPath = probe.allResults[0].path; if (FileInfo.resolvePath(path, probe.path) !== FileInfo.resolvePath(path, expectedPath)) { throw "Invalid path: actual = " + probe.path + ", expected = " + expectedPath; } var expectedCandidatePaths = probe.allResults[0].candidatePaths; if (!compareArrays(probe.candidatePaths, expectedCandidatePaths)) { throw "Invalid candidatePaths: actual = " + JSON.stringify(probe.candidatePaths) + ", expected = " + JSON.stringify(expectedCandidatePaths); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/path-probe/environment-paths.qbs0000644000175100001660000000037214776170045026413 0ustar runnerdockerimport qbs.FileInfo BaseApp { inputNames: "tool" inputSearchPaths: ["bin", "usr/bin"] // env takes precedence inputEnvironmentPaths: "SEARCH_PATH" outputFilePaths: ["usr/bin/tool"] outputCandidatePaths: [["usr/bin/tool"]] } qbs-src-2.6.1/tests/auto/blackbox/testdata/installable-as-auxiliary-input/0000755000175100001660000000000014776170045026215 5ustar runnerdocker././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/installable-as-auxiliary-input/installable-as-auxiliary-input.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/installable-as-auxiliary-input/installable-as-auxiliary-i0000644000175100001660000000542514776170045033274 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Host import qbs.TextFile Project { name: "p" CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "app" Depends { name: "installed-header" } Rule { multiplex: true auxiliaryInputsFromDependencies: ["installable"] Artifact { filePath: "main.cpp"; fileTags: "cpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.writeLine("#include "); f.writeLine("int main() {"); f.writeLine(" f();"); f.writeLine("}"); f.close(); }; return cmd; } } } Product { name: "installed-header" type: ["header"] property string installDir: "include" qbs.installPrefix: "" Group { fileTagsFilter: "header" qbs.install: true qbs.installDir: installDir } Export { Depends { name: "cpp" } cpp.includePaths: FileInfo.joinPaths(qbs.installRoot, exportingProduct.installDir); } Rule { multiplex: true Artifact { filePath: "theheader.h.in"; fileTags: "header.in" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { for (var i = 0; i < 1000; ++i) { // Artificial delay. var file = new TextFile(output.filePath, TextFile.WriteOnly); file.writeLine("#include "); file.writeLine("inline void f() {"); file.writeLine(' std::cout << "f-impl" << std::endl;'); file.writeLine("}"); file.close(); } }; return [cmd]; } } Rule { inputs: "header.in" Artifact { filePath: "theheader.h"; fileTags: "header" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }; return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/env-normalization/0000755000175100001660000000000014776170045023634 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/env-normalization/env-normalization.qbs0000644000175100001660000000031114776170045030012 0ustar runnerdockerimport qbs.Environment Product { Probe { id: dummy property var env: Environment.currentEnv() configure: { console.info(JSON.stringify(env)); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/no-profile/0000755000175100001660000000000014776170045022232 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/no-profile/no-profile.qbs0000644000175100001660000000012614776170045025012 0ustar runnerdockerProduct { property bool dummy: { console.info("profile: " + project.profile); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/list-products/0000755000175100001660000000000014776170045022774 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/list-products/list-products.qbs0000644000175100001660000000043614776170045026322 0ustar runnerdockerProject { Product { name: "a" } Product { name: "b" multiplexByQbsProperties: ["architectures", "buildVariants"] qbs.architectures: ["mips", "vax"] qbs.buildVariants: ["debug", "release"] } Product { name: "c" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-disabled-product/0000755000175100001660000000000014776170045025234 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-disabled-product/change-in-disabled-product.qbs0000644000175100001660000000014014776170045033012 0ustar runnerdockerProduct { condition: false files: [ 'test1.txt', // 'test2.txt' ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-disabled-product/test2.txt0000644000175100001660000000000014776170045027024 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-disabled-product/test1.txt0000644000175100001660000000000014776170045027023 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-assignment/0000755000175100001660000000000014776170045023640 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-assignment/imports/0000755000175100001660000000000014776170045025335 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-assignment/imports/MyImport/0000755000175100001660000000000014776170045027115 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-assignment/imports/MyImport/myimport.js0000644000175100001660000000005214776170045031330 0ustar runnerdockervar key1 = "value1"; var key2 = "value2"; qbs-src-2.6.1/tests/auto/blackbox/testdata/import-assignment/import-assignment.qbs0000644000175100001660000000104014776170045030022 0ustar runnerdockerimport MyImport Product { type: "outtype" property var importValue: MyImport Rule { multiplex: true Artifact { fileTags: "outtype" filePath: "dummy" } prepare: { var cmd = new JavaScriptCommand; cmd.silent = true; cmd.sourceCode = function() { console.info("key 1 = " + product.importValue.key1); console.info("key 2 = " + product.importValue.key2); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/0000755000175100001660000000000014776170045022426 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/lib.h0000644000175100001660000000001214776170045023336 0ustar runnerdockervoid f(); qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/qbs-session.qbs0000644000175100001660000000103214776170045025377 0ustar runnerdockerProject { StaticLibrary { name: "theLib" Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++11" Group { name: "sources" files: "lib.cpp" } Group { name: "headers" files: "lib.h" } } CppApplication { name: "theApp" consoleApplication: true Depends { name: "mymodule" } cpp.cxxLanguageVersion: "c++14" cpp.warningLevel: "all" files: "main.cpp" install: true } } qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/file1.cpp0000644000175100001660000000001514776170045024126 0ustar runnerdockervoid f1() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/lib.cpp0000644000175100001660000000001514776170045023674 0ustar runnerdockervoid f() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/main.cpp0000644000175100001660000000013114776170045024051 0ustar runnerdockerint main() { int i; // Should trigger a warning and thus a process-exited message. } qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/modules/0000755000175100001660000000000014776170045024076 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/modules/mymodule/0000755000175100001660000000000014776170045025731 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/modules/mymodule/mymodule.qbs0000644000175100001660000000014414776170045030272 0ustar runnerdockerimport qbs.Environment Module { setupRunEnvironment: { Environment.putEnv("MY_MODULE", 1); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/qbs-session/file2.cpp0000644000175100001660000000001514776170045024127 0ustar runnerdockervoid f2() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-files/0000755000175100001660000000000014776170045022651 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/changed-files/changed-files.qbs0000644000175100001660000000137114776170045026053 0ustar runnerdockerimport qbs.TextFile CppApplication { type: ["application", "stuff"] consoleApplication: true files: ["file1.cpp", "file2.cpp", "main.cpp"] Rule { inputs: ["cpp"] outputFileTags: ["stuff"] outputArtifacts: { return [{ filePath: input.completeBaseName + ".stuff", fileTags: ["stuff"] }]; } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write("crazy stuff"); f.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-files/file1.cpp0000644000175100001660000000235014776170045024355 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f1() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-files/main.cpp0000644000175100001660000000235114776170045024302 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/changed-files/file2.cpp0000644000175100001660000000235014776170045024356 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ void f2() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/conanfile-probe/0000755000175100001660000000000014776170045023223 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conanfile-probe/testlib/0000755000175100001660000000000014776170045024671 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py0000644000175100001660000000111114776170045027173 0ustar runnerdockerfrom conans import ConanFile class Testlib(ConanFile): name = "testlib" description = "Represents an arbitrary package, for instance on bintray" license = "none" version = "1.2.3" settings = "os" options = {"opt": [True, False]} default_options = {"opt": False} def source(self): pass def build(self): pass def package(self): pass def package_info(self): self.cpp_info.libs = ["testlib1","testlib2"] self.env_info.ENV_VAR = "TESTLIB_ENV_VAL" self.user_info.user_var = "testlib_user_val" qbs-src-2.6.1/tests/auto/blackbox/testdata/conanfile-probe/testapp/0000755000175100001660000000000014776170045024703 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs0000644000175100001660000000124514776170045032123 0ustar runnerdockerimport qbs.Probes import qbs.TextFile Project { readonly property bool forceFailure: false Probes.ConanfileProbe { id: conan conanfilePath: path + "/conanfile.py" options: ({opt: "True", forceFailure: (project.forceFailure ? "True" : "False")}) settings: ({os: "AIX"}) } property var check: { var tf = new TextFile(buildDirectory + "/results.json", TextFile.WriteOnly); var o = { json: conan.json.deps_env_info["ENV_VAR"], dependencies: conan.dependencies["testlib"].libs, generatedFilesPath: conan.generatedFilesPath }; tf.write(JSON.stringify(o)); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py0000644000175100001660000000116714776170045027220 0ustar runnerdockerfrom conans import ConanFile class TestApp(ConanFile): name = "testapp" description = "Our project package, to be inspected by the Qbs ConanfileProbe" license = "none" version = "6.6.6" settings = "os" options = {"opt": [True, False], "forceFailure": [True, False]} default_options = {"opt": False, "forceFailure": False} requires = "testlib/1.2.3@qbs/testing" def configure(self): assert(not self.options.forceFailure) self.options["testlib"].opt = self.options.opt def source(self): pass def build(self): pass def package(self): pass qbs-src-2.6.1/tests/auto/blackbox/testdata/variant-suffix/0000755000175100001660000000000014776170045023126 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/variant-suffix/variant-suffix.qbs0000644000175100001660000000172014776170045026603 0ustar runnerdockerStaticLibrary { name: "l" Group { condition: qbs.targetOS.includes("darwin") Depends { name: "bundle" } Properties { bundle.isBundle: false } } aggregate: false property string variantSuffix property bool multiplex: false Properties { condition: multiplex qbs.buildVariants: ["debug", "release"] multiplexByQbsProperties: ["buildVariants"] } Properties { condition: variantSuffix !== undefined cpp.variantSuffix: variantSuffix } cpp.staticLibraryPrefix: "lib" cpp.staticLibrarySuffix: ".ext" qbs.installPrefix: "" install: true Depends { name: "cpp" } files: ["lib.cpp"] Probe { id: targetOSProbe property stringList targetOS: qbs.targetOS configure: { console.info("is Windows: " + targetOS.includes("windows")); console.info("is Apple: " + targetOS.includes("darwin")); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/variant-suffix/lib.cpp0000644000175100001660000000001414776170045024373 0ustar runnerdockervoid f() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/symbolLinkMode/0000755000175100001660000000000014776170045023110 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/symbolLinkMode/indirect.cpp0000644000175100001660000000002414776170045025411 0ustar runnerdockervoid indirect() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs0000644000175100001660000000714514776170045026556 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { property bool shouldInstallLibrary: true property bool lazy: false Application { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } Depends { name: "cpp" } Depends { name: "functions"; cpp.symbolLinkMode: product.symbolLinkMode cpp.link: !(product.qbs.targetOS.includes("linux") && product.symbolLinkMode === "weak") } property string symbolLinkMode: project.lazy ? "lazy" : "weak" name: "driver" files: ["main.cpp"] consoleApplication: true property string installLib: "SHOULD_INSTALL_LIB=" + project.shouldInstallLibrary cpp.defines: { if (symbolLinkMode === "weak") { return qbs.targetOS.includes("darwin") ? ["WEAK_IMPORT=__attribute__((weak_import))", installLib] : ["WEAK_IMPORT=__attribute__((weak))", installLib]; } return ["WEAK_IMPORT=", installLib]; } cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" cpp.rpaths: [cpp.rpathOrigin + "/../lib"] Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "bin" } } DynamicLibrary { Depends { name: "cpp" } Depends { name: "indirect"; cpp.symbolLinkMode: "reexport" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } name: "functions" files: ["lib.cpp"] cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" cpp.rpaths: [cpp.rpathOrigin] Properties { condition: qbs.targetOS.includes("darwin") cpp.sonamePrefix: "@rpath" } Group { condition: project.shouldInstallLibrary fileTagsFilter: product.type qbs.install: true qbs.installDir: "lib" } Export { // let the autotest pass on Linux where reexport is not supported Depends { name: "indirect"; condition: !qbs.targetOS.includes("darwin") } // on Linux, there is no LC_WEAK_LOAD_DYLIB equivalent (the library is simply omitted // from the list of load commands entirely), so use LD_PRELOAD to emulate qbs.commonRunEnvironment: { var env = original || {}; if (project.shouldInstallLibrary) { env["LD_PRELOAD"] = FileInfo.joinPaths(qbs.installRoot, "lib", "libfunctions.so"); } return env; } } } DynamicLibrary { Depends { name: "cpp" } Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } name: "indirect" files: ["indirect.cpp"] cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.7" Properties { condition: qbs.targetOS.includes("darwin") // reexport is incompatible with rpath, // "ERROR: ld: file not found: @rpath/libindirect.dylib for architecture x86_64" cpp.sonamePrefix: qbs.installRoot + "/lib" } Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "lib" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp0000644000175100001660000000022314776170045024357 0ustar runnerdockerint somefunction() { return 42; } #include static const auto func = []() { std::printf("Lib was loaded!\n"); return 0; }(); qbs-src-2.6.1/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp0000644000175100001660000000055314776170045024543 0ustar runnerdockerextern WEAK_IMPORT int somefunction(); extern void indirect(); #include int main() { std::printf("meow\n"); if (&somefunction != nullptr) std::printf("somefunction existed and it returned %d\n", somefunction()); else std::printf("somefunction did not exist\n"); #if SHOULD_INSTALL_LIB indirect(); #endif return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/0000755000175100001660000000000014776170045021777 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/testd_x86.asm0000644000175100001660000000011114776170045024322 0ustar runnerdocker.386 .model flat, stdcall .code foo PROC nop RET foo ENDP END qbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/testa.s0000644000175100001660000000004014776170045023275 0ustar runnerdocker.globl symbola symbola: nop qbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/testd_x86_64.asm0000644000175100001660000000005614776170045024643 0ustar runnerdocker.code foo PROC nop RET foo ENDP END qbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/assembly.qbs0000644000175100001660000000440414776170045024327 0ustar runnerdockerimport qbs.TextFile Project { Product { type: ["properties"] property bool dummy: { console.info("is emscripten: " + qbs.toolchain.includes("emscripten")); } Depends { name: "cpp" } Rule { multiplex: true Artifact { filePath: "properties.json" fileTags: ["properties"] } prepare: { var cmd = new JavaScriptCommand(); cmd.outputFilePath = outputs.properties[0].filePath; cmd.tc = product.qbs.toolchain; cmd.sourceCode = function () { var tf = new TextFile(outputFilePath, TextFile.WriteOnly); try { tf.writeLine(JSON.stringify({ "qbs.toolchain": tc }, undefined, 4)); } finally { tf.close(); } }; return [cmd]; } } } StaticLibrary { name : "testa" files : [ "testa.s" ] Depends { name: "cpp" } condition: qbs.toolchain.includes("gcc") Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } StaticLibrary { name : "testb" files : [ "testb.S" ] Depends { name: "cpp" } condition: qbs.toolchain.includes("gcc") Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } StaticLibrary { name : "testc" files : [ "testc.sx" ] Depends { name: "cpp" } condition: qbs.toolchain.includes("gcc") Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } StaticLibrary { name: "testd" Group { condition: product.condition files: ["testd_" + qbs.architecture + ".asm"] } Depends { name: "cpp" } condition: qbs.toolchain.includes("msvc") && (qbs.architecture === "x86" || qbs.architecture === "x86_64") Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/testb.S0000644000175100001660000000004114776170045023237 0ustar runnerdocker#define bla nop symbolb: bla qbs-src-2.6.1/tests/auto/blackbox/testdata/assembly/testc.sx0000644000175100001660000000004114776170045023470 0ustar runnerdocker#define bla nop symbolb: bla qbs-src-2.6.1/tests/auto/blackbox/testdata/product-in-exported-module/0000755000175100001660000000000014776170045025357 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/product-in-exported-module/product-in-exported-module.qbs0000644000175100001660000000025314776170045033265 0ustar runnerdockerProject { Product { name: "importing" Depends { name: "dep" } } Product { name: "dep" Export { Depends { name: "m" } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/product-in-exported-module/modules/0000755000175100001660000000000014776170045027027 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/product-in-exported-module/modules/m/0000755000175100001660000000000014776170045027263 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/product-in-exported-module/modules/m/m.qbs0000644000175100001660000000016114776170045030224 0ustar runnerdockerModule { Depends { name: "dummy"; condition: { console.info("product: " + product.name); return false; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/0000755000175100001660000000000014776170045023614 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/module-conditions.qbs0000644000175100001660000000061514776170045027761 0ustar runnerdockerProject { Product { name: "p1" qbs.architecture: "a" Depends { name: "m" } } Product { name: "p2" qbs.architecture: "b" Depends { name: "m" } } Product { name: "p3" multiplexByQbsProperties: "architectures" aggregate: false qbs.architectures: ["b", "c", "d"] Depends { name: "m" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/modules/0000755000175100001660000000000014776170045025264 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/modules/m/0000755000175100001660000000000014776170045025520 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/modules/m/m1.qbs0000644000175100001660000000015414776170045026544 0ustar runnerdockerModule { condition: qbs.architecture === "a" validate: { console.info("loaded m1"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/modules/m/m3.qbs0000644000175100001660000000015414776170045026546 0ustar runnerdockerModule { condition: qbs.architecture === "c" validate: { console.info("loaded m3"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/modules/m/m2.qbs0000644000175100001660000000015414776170045026545 0ustar runnerdockerModule { condition: qbs.architecture === "b" validate: { console.info("loaded m2"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/module-conditions/modules/m/m4.qbs0000644000175100001660000000015414776170045026547 0ustar runnerdockerModule { condition: qbs.architecture === "d" validate: { console.info("loaded m4"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-variant/0000755000175100001660000000000014776170045023106 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/linker-variant/linker-variant.qbs0000644000175100001660000000064114776170045026544 0ustar runnerdockerCppApplication { name: "p" property string linkerVariant Probe { id: gccProbe property bool isGcc: qbs.toolchain.includes("gcc") configure: { console.info("is GCC: " + isGcc); if (isGcc) found = true; } } Properties { condition: gccProbe.found cpp.linkerVariant: linkerVariant } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/linker-variant/main.cpp0000644000175100001660000000001614776170045024533 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/install-locations/0000755000175100001660000000000014776170045023617 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/install-locations/thelib.cpp0000644000175100001660000000007014776170045025567 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void libFunc() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/install-locations/main.cpp0000644000175100001660000000001614776170045025244 0ustar runnerdockerint main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/install-locations/theplugin.cpp0000644000175100001660000000007314776170045026322 0ustar runnerdocker#include "../dllexport.h" DLL_EXPORT void pluginFunc() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/install-locations/install-locations.qbs0000644000175100001660000000242114776170045027764 0ustar runnerdockerProject { property bool dummy: { if (qbs.targetOS.includes("windows")) { console.info("is windows"); } else if (qbs.targetOS.includes("darwin")) { console.info("is darwin"); if (qbs.targetOS.includes("macos")) console.info("is mac"); } else { console.info("is unix"); } if (qbs.toolchain.includes("mingw")) console.info("is mingw"); if (qbs.toolchain.includes("emscripten")) console.info("is emscripten") } CppApplication { name: "theapp" install: true installDebugInformation: true files: "main.cpp" cpp.separateDebugInformation: true Group { fileTagsFilter: "application" fileTags: "some-tag" } } DynamicLibrary { name: "thelib" install: true installImportLib: true installDebugInformation: true Depends { name: "cpp" } cpp.separateDebugInformation: true files: "thelib.cpp" } LoadableModule { name: "theplugin" install: true installDebugInformation: true Depends { name: "cpp" } cpp.separateDebugInformation: true files: "theplugin.cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-timeout/0000755000175100001660000000000014776170045023514 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-timeout/autotests-timeout.qbs0000644000175100001660000000151614776170045027745 0ustar runnerdockerimport qbs.Host Project { CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "testApp" type: ["application", "autotest"] Depends { name: "autotest" } cpp.cxxLanguageVersion: "c++11" cpp.minimumOsxVersion: "10.8" // For Properties { condition: qbs.toolchain.includes("gcc") cpp.driverFlags: "-pthread" } files: "test-main.cpp" } AutotestRunner { Depends { name: "cpp" // Make sure build environment is set up properly. condition: Host.os().includes("windows") && qbs.toolchain.includes("gcc") } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/autotest-timeout/test-main.cpp0000644000175100001660000000255514776170045026130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main() { std::this_thread::sleep_for(std::chrono::seconds(5)); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/0000755000175100001660000000000014776170045023553 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/p2.cpp0000644000175100001660000000004414776170045024576 0ustar runnerdocker#include int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/subdir/0000755000175100001660000000000014776170045025043 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/subdir/external2.h0000644000175100001660000000000014776170045027106 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/p1.cpp0000644000175100001660000000007014776170045024574 0ustar runnerdocker#include #include int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/external-indirect.h0000644000175100001660000000000014776170045027333 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/p3.cpp0000644000175100001660000000004614776170045024601 0ustar runnerdocker#include int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/artifact-scanning.qbs0000644000175100001660000000105014776170045027651 0ustar runnerdockerProject { CppApplication { name: "p1" consoleApplication: true cpp.includePaths: ["."] files: [ "p1.cpp", "shared.h", ] } CppApplication { name: "p2" consoleApplication: true cpp.includePaths: ["."] files: [ "p2.cpp", "shared.h", ] } CppApplication { name: "p3" consoleApplication: true cpp.includePaths: [".", "subdir"] files: [ "p3.cpp", ] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/external.h0000644000175100001660000000003714776170045025546 0ustar runnerdocker#include qbs-src-2.6.1/tests/auto/blackbox/testdata/artifact-scanning/shared.h0000644000175100001660000000002614776170045025170 0ustar runnerdocker#include qbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/0000755000175100001660000000000014776170045027323 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/main.cpp0000644000175100001660000000001614776170045030750 0ustar runnerdockerint main() {} ././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/property-assignment-in-failed-module.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/property-assignment-0000644000175100001660000000014414776170045033354 0ustar runnerdockerCppApplication { name: "app" Depends { name: "m"; required: false } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/modules/0000755000175100001660000000000014776170045030773 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/modules/m/0000755000175100001660000000000014776170045031227 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/property-assignment-in-failed-module/modules/m/m.qbs0000644000175100001660000000026014776170045032170 0ustar runnerdockerModule { property bool doFail Depends { name: "cpp" } cpp.dynamicLibraries: ["nosuchlib"] validate: { if (doFail) throw "Failure!"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/0000755000175100001660000000000014776170045027473 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom1.in0000644000175100001660000000000014776170045031404 0ustar runnerdocker././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/usings-as-sole-inputs-non-multiplexed.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/usings-as-sole-inpu0000644000175100001660000000302114776170045033234 0ustar runnerdockerimport qbs.FileInfo import qbs.TextFile Project { Product { name: "p1" type: "custom" Group { files: "custom1.in" fileTags: "custom.in" } } Product { name: "p2" type: "custom" Group { files: "custom2.in" fileTags: "custom.in" } } Rule { inputs: "custom.in" Artifact { filePath: FileInfo.baseName(input.filePath) + ".out" fileTags: "custom" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return cmd; } } Product { name: "p3" type: "custom-plus" Depends { name: "p1" } Depends { name: "p2" } Rule { inputsFromDependencies: "custom" Artifact { filePath: FileInfo.fileName(input.filePath) + ".plus" fileTags: "custom-plus" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.close(); } return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/usings-as-sole-inputs-non-multiplexed/custom2.in0000644000175100001660000000000014776170045031405 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dependenciesProperty/0000755000175100001660000000000014776170045024353 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dependenciesProperty/product2.cpp0000644000175100001660000000236414776170045026626 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs0000644000175100001660000000240314776170045031254 0ustar runnerdockerimport qbs.TextFile import qbs.FileInfo Project { Product { name: "newDependency" } Product { type: "deps" name: "product1" Depends { name: "product2" } // Depends { name: 'product2' } // Depends { name: 'newDependency' } Rule { multiplex: true inputsFromDependencies: "application" Artifact { fileTags: ["deps"] filePath: product.name + '.deps' } prepare: { var cmd = new JavaScriptCommand(); cmd.description = 'generating ' + FileInfo.fileName(output.filePath); cmd.highlight = 'codegen'; cmd.sourceCode = function() { file = new TextFile(output.filePath, TextFile.WriteOnly); file.truncate(); file.write(JSON.stringify(product.dependencies, undefined, 2)); file.close(); } return cmd; } } } Product { type: "application" consoleApplication: true name: "product2" property string narf: "zort" Depends { name: "cpp" } cpp.defines: ["SMURF"] files: ["product2.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/0000755000175100001660000000000014776170045023250 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/dynamic-project.qbs0000644000175100001660000000246714776170045027060 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.TextFile Project { Probe { id: projectBuilder property stringList refs: [] property string sourceDir: sourceDirectory configure: { var tempDir = FileInfo.joinPaths(sourceDir, "temp"); File.makePath(tempDir); var srcDir = FileInfo.joinPaths(sourceDir, "src"); var projectDirs = File.directoryEntries(srcDir, File.Dirs | File.NoDotAndDotDot); var list = []; for (var it = 0; it < projectDirs.length; ++it) { var name = projectDirs[it]; var productSrcDir = FileInfo.joinPaths(srcDir, name); var productFilePath = FileInfo.joinPaths(tempDir, name + ".qbs"); var file = new TextFile(productFilePath, TextFile.WriteOnly); try { file.writeLine("CppApplication"); file.writeLine("{"); file.writeLine("\tfiles: [ \"" + productSrcDir + "/*.cpp\" ]"); file.writeLine("}"); } finally { file.close(); } list.push(productFilePath); } found = true; refs = list; } } references: projectBuilder.refs } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/src/0000755000175100001660000000000014776170045024037 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/src/app/0000755000175100001660000000000014776170045024617 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/src/app/main.cpp0000644000175100001660000000003114776170045026241 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/src/app2/0000755000175100001660000000000014776170045024701 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/dynamic-project/src/app2/main.cpp0000644000175100001660000000003114776170045026323 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/0000755000175100001660000000000014776170045020732 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ico/ico.qbs0000644000175100001660000000343714776170045022222 0ustar runnerdockerProject { Product { Depends { name: "ico" } type: ["ico"] name: "icon" files: [ "icon_16x16.png", "icon_32x32.png" ] } Product { Depends { name: "ico" } type: ["ico"] name: "icon-alpha" files: [ "icon_16x16.png", "icon_32x32.png" ] ico.alphaThreshold: 50 } Product { Depends { name: "ico" } type: ["ico"] name: "icon-big" files: [ "dmg.iconset/icon_16x16.png", "dmg.iconset/icon_32x32.png", "dmg.iconset/icon_128x128.png", ] Group { name: "raw" prefix: "dmg.iconset/" files: [ "icon_256x256.png", "icon_512x512.png", ] ico.raw: true } } Product { Depends { name: "ico" } type: ["cur"] name: "cursor" files: [ "icon_16x16.png", "icon_32x32.png" ] } Product { Depends { name: "ico" } type: ["cur"] name: "cursor-hotspot" Group { files: ["icon_16x16.png"] ico.cursorHotspotX: 8 ico.cursorHotspotY: 9 } Group { files: ["icon_32x32.png"] ico.cursorHotspotX: 16 ico.cursorHotspotY: 17 } } Product { Depends { name: "ico" } type: ["cur"] name: "cursor-hotspot-single" Group { files: ["icon_16x16.png"] ico.cursorHotspotX: 8 ico.cursorHotspotY: 9 } } Product { Depends { name: "ico" } type: ["ico", "cur"] name: "iconset" files: ["dmg.iconset"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/icon_32x32.png0000644000175100001660000000123114776170045023226 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/icon_16x16.png0000644000175100001660000000121114776170045023230 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/dmg.iconset/0000755000175100001660000000000014776170045023144 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/ico/dmg.iconset/icon_32x32.png0000644000175100001660000000253614776170045025451 0ustar runnerdockerPNG  IHDR DPLTE7E6C6C6D NNNzzz ...OOOUUU"""ppp 888bbbfffjjj]]]///ARFWHX}݉n{谢aoK[HYBŞ[jCT˥ݺO_mzTdUcÜɀތ䢏ގFVhsŪٓhuTchvK[Žbp_lWfKZÿx׽ӼιǺľftRNS )2 4 $ .372?(au#!?-X5q:>QVWZfw&(/F9L,Y%L+MkL#6"(wIDATMKqon(nP!ֱS"BK/ ЩSk.K 몳\>Cz XrN6 "[:{8+&4`I4ͿxXhuAV`1M3VHc@#bRLOAZ1, ϲ/*RG%d|5j5r^%;cxrp0\pY{ˮpB0<0Uˮ.%#y5)r̕5[5Ǿ>GSs7JF5 Ƙ48 `( dߣ0 6-{K7rc$:$=o:-Xh..Cp>zTH}jbIYJg㭾Rx4g)R☜eV٩My HٖհDUA#sAN'mDO014K}g)>^ZIENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/dmg.iconset/icon_128x128.png0000644000175100001660000001221014776170045025613 0ustar runnerdockerPNG  IHDR>aOIDATx] |WڿD"R ڎFbf|7Ӗ)ih1ZeQ6XcOX$ds}7yysk)RH"E)RH"E)RH"E)RH"E)RH"E)RH"E)R ;ϯ9sIĥ;bނh>}BKp~s/p%;Ř9siW>Zp߿{#}YB/@M+Y _r~𫿽L%44>c,%072PS/U &/@ hDA)?]h++(+(+(+x#@?RU@e/gǾfߥNgC7i,vMv5:Kw%>v_f 2VoN`-[(8|z"s=Ϣg=`#G7{YE{Ű]~3zP?  <5köD2Ok@i*@4ye/$~x%M8h: (@46< x/5ooƵ-`icOQ$~ŝ{C0 yR_qB{?.D'G)CتXAA|;wysYM3w @VD@m`&J=3VF0c%p$pre!4K^pl$ "wN..=$oiIzRG>34xncOѼen Hg#(É;w%qv=bo8Z`ijN͖ܺ>!d4Z`[svN4ת8j'H iÉ

`5Y'(R}dlh~v[a`Ýک0_[ZU 5LU. ;69N s B4F+vVNɌ?:(13wR-&ku xF|ڪPzIv;N @ǣ==tV&B@.>+'myc'p ?h^tҾ0שWAm 'B^2V= dbIˆL*B|J+6j޼sӧOç~?G40F7ePQ@1;Ć=zz-;w~oCLG½t%@8ʠAگ]6k07}._˜M3GNfd&8r5M6uÆ | :3pb}Zɓ'*bj+x6{$W{GȚр tϦmf#vcK#?!۷Çk޼=^VZxON>a jٲ߸aVhOǽm֡Ntb_m [q=**J[]vMc#_h̻/9s$QUly* alyOh9{Bxx0.\Єo .b|y2<СCqJ9IJo[{&_ͣP{av!T-Q =uyGW!,/߫Yf{0gm_<~ZxVx0HBX2 [2 @hx5=@ /"  Zqcbb̙3llUk.M5kG*"yٚ(z+_ r0aYdP@<ohbeGVDw_fz+_ r5k53.' B|[`ul{ŒEC [gA\xb-̃x2 xٳg')yBķ!*|4]"އS Aٳ:&ǔ6^U Rѧ#86Liɹ-O9w$awi!4 ! 8 Ƀ '󏑴yӾFZpؘvKሿ4-87n& YcuQΚ#1evI"{=E3G z~(N)TT苘h粐\qѺ4u> Q@y _Oo ]P*#(AJ*\~#Neh;r50,P 1oTV-,ou+>A -1,\'hݪU0L4M2` uQԁDBXfgQskͫ'~GO*A\RZj{ &d8 z HfA3@CiN{y2 @o\&;ёe;pD@+]0u xW(Q1]d Pgȑ0d\2n yإ#X@PqǎétC8=z1Mb{ˀ {$x!82߼yÇ_˟tI PO)`xZjdvۻSN]WLie&QF-c^C1> T |TD[m *=r @H>CfWǿt:u|A!߫(/J=z ׇdy8{0  ϗu_~O`D@G}Af#0\/>Od4hР'zߤl_E{u?Rde@@؎ !`A+}aN<8]V.A%! Pk׮0P  g aÆ ۄS(l?S^k-Z[־Ch`$}B`,#Bt|k:P~V ͗=~8M2<*Th̛<}u} BeΞ㯨]31 y^,,T @baiI!\0~q|RtbCIGі>z R&/M@5v,sM֭,!ؖWC|z|vIuHVZ}9^zxu89ƌ~m8s'8'w>dȐM}Yضm۱qtA?嵛GѯI5tK܃H,UIENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/dmg.iconset/icon_512x512.png0000644000175100001660000006455014776170045025623 0ustar runnerdockerPNG  IHDRxi/IDATxx\ϨYղe[܍ ^B dIv&dHd!MoPj:ۀPm46Kz^ڣS{dI;=;|"B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!%B8/[B!yo (}BC3@ȟ!ׄ<E!~w !?z#@-BH>׆P)M!X?O&BU$ So$qF &7"ۼ0WE=Gӌ_# FN#~Xl񏘼/VG:% BH{E[A ('oG>V+'?}*.$Cwac`"Io04P+'>JI! K.YO+ əG,ĿYg_YZ_}^NB@}4fb0$_p<ʲѕrB-ҷF*fuS_g]QPE' @ [!'_`'BS{D|VxXD x_d 'YX?!'e"aU_g|gcI!)gtOm@M @p_7"BLr9şB$}X$RBHf3V7 XQP`q?BH ;95P !$3f& WQ !$jm& şBz~{; aO!WW/B'k?u4B @(#|?!{4B!yP !gh(xi(B?!^N@(BhşB şO!O'B@BS !P !?!B@'Bh(B şBB!4B!O!P !?!O!O'B@BS !P)BhB @+(Bh!@KzgB!46QWR !;7şB @x*?!b?!|(ѿg(GGU2xTKyAe$)>vD[wbmhz]JcOn=MԳBE7X(j)1e2AJGʨ~2()(9tźeSҹM*;6˪}{K"d8`&E!\ RQUSeZTT>^fr زڑHOSEy2|v|yǐ%xoG/B"1(U _@cFPF.?Ѧj ݷ@^󺼿c!?1Pė@07Lx;eSQ<٬ b~nj%,&Q)篯Fu)/?=O4/Y;{?G!HS#!WN8ȱUGjreaR^BHD73PN4/0F7MV4xǦ鲮cc^^|g,8/>B?}#3 @|}7-{AFÎU}=[v5d y&q\i?%y1R_Su 8^^g. dt#b7xrK_o5IKʍ'6gd'@34nZ?ɬ@!0|z͵j/}([ W39{7F L?Q_&_# uBh(_c 9'ɟ'^%CbdZ$p2Zh$BhlZir rO<ۉ5!ǪBKLB̀ 9쁧4\r Z,0 lx !4~Cѧ!'U+?CoT @&4Ax̤1C?2d/F7.@dn}w4Fk,#(o% FCȑ숿"  !|_~c:\9^f @^fHR1I.U^sY2n%A)j+. ]KU-U)p _E  '?Z9i_/wUyCc9}.[gȩ*"ɩX/<%ս/f  `T}{Ŀ Uں_v\}\S4 0@h9?נ<$*fQm3We-9}._[( DGز9}K[W_.KZW:j_+,_q*Rp kK !圞O>kB_Z[$˃ ʽ !E?2g=|~)$pպ[r:CΑ  ĄH1W7mn3l?Krr~ 1L|fh sglNν{\ꏁ*K%i?k./En-d_]]33пKՎ-VBOY~}YAXhBRQQP~`nԮT\#ULƖ?`F]ya >ȤyAA( \ iqRA yyQz0A{u ąqbcO91#ʾfYںsY9 ϙP>FX9/ M*ϋ8?7} ВR]ԟ>1˽5;6&l[Pq,9 4{qw#o<|,/| k ro\زކ-==߄1OA0+VM`!c==ߞ&Nsuj@g+-gz["xm·,v)Fm==ߘ:^9xJm^ZYV2=B@<(R(zz xc`/za  "޽lݲNԹ2[B@b;1qFO7LޏB@#M·(k>oBR<6;i\& 0֣<-CuIWsUub8廹kDg=f?_mq6ǢBhHZxk'/Kvx\49< WEWx%U! e+ !4$`s 4u{k*y  aA@^mZzZy]qf{#6[BhH*FZvXfY14p OBhHȩ.2-Q3g<ѷy^^2mHB m"X;/zC+ J34_Oןuu`+ @oO0#B@BJI$" (mE B/.cv40oo*5kQ̋N +^Gyx=k'^;B@BL 0K0g 03B@Biޘ&P !4$ @= ׎mEȵ d03KۗK|ï  EOEUR(`f kH۵ފr))(w !H߄8&|u0@_?bq@,}?B@\k7 XIcO/:!ވ[=z_|6q];== M@H~EXK->7~~_a qɎ]oX^t -ËN|m/uuu.]+۷o$ķd/KhE'$'(ޭ( q:0u;ӄΐ}x/"GN?{נo۷n 2fNg҂~ʳ&GL>^wun#FHkRiKKK'= ޼v$$sHjv`j$^t&5R6$E3දI~T7`i?3^/K0 ?yQ;㏿%{뭷> ,L3$uVhT{v3jN۟O&^ As?3at'5 U/SLib?4%D}|C2XoeZ}g眨݌W+:ȤsZh @MAāezſK.93MyyyF :::tMܩI-_9^^>ȷף%E߬]IQ[k:'MTwo-[zſOto HF @my_|$T&@@]UuW_}ډ#E(znVcKfHFT&{QZ 6@wϋOi8Ha?ЅTzh{ӟ7o~g֬YK`߿a ɀU^kzb/Ұĥ#z~޿kؽtɊu᯺ a駟~_YY٤l?Y57?4$#( ο~=o! :{=z=*E7 '7 {4?S|ߜSSSs77nܹsNvmؔUpU' Uu\VqN*۳/iUZ_v͛A0?/6O3vX~=zEj_OTG}19tM@K$+Y=/8"?|n@x @,gOx&0jUZYUT)֢JbСƎ{i*IEEEOtݺuzF%I՜ )/DU)ES:͋eϋu991ra7W#eY9Gea T&Ɣ @=jx5몭9sUT„ ҿimMmR{T.7z'?'ҤRį5fT//PZ'wmy#?28S}t@]3,ErYͲVkو]McJe R\P,RVX*%@ST}?_BxҼmH~c.jo ᯫ˥1U}-օv}'I&yj_sftyWrպUm@^G!$xd>U;>@];*x=2iGI_7f P@/%ŗ^zi'tҷU>%GԨQ2dꒅ k@Ѩ56?Ik d?iY"*yL(wt#*z}|S(G^zsmy(jQCjC 2mvxRG1⋏?3[YY9.]CVC^QÂ*ihhEٛO?}?kb(gd>!&L@ -_tVUj8_<{?T=~j*Ň24@1N>䯩51~k.Ybwl٫E*(UH>בֿCߏ??*U'd!j^$KZWԊIx>K4q}eE.c/۠9sg圁UQ'<=A.g(o U>}\׫?]lٲE֬Y~SS⏚܎*T*KunѷiHָg#rÄ9Al/U /ZмP6tltSQc5Fv/'>h,jYuPNJr\RU-yZaD|}>Q_zlݺU{۶mZ @AA7N3 vgw;`_eo  ٍ0<3NF:f:^XܲL.,jAז IUxD_sfj.E @ Cwbertar:JRjg?-⇨߽{߾}9RԾ1yd PgN=+-[ҥKӍ3@9a@QeTNXfvmm;K7@Tڹpo*9к%5?H rh?_AKuߑf Zd9}S[0`}<-YDZZZ?|=JKKE WZS ~[s Y-xl)pcFkG>1{ZGyݜfp PP[Y")2NWKJ?~K,D:+T j9a[p3@C۞SMI#Ckp~'w̑/ <-%4LųS˱mSeSkX^gU^:;;?#Fh4hL8Oq`َNfdU}ͺ[Wl=s~Zng~OTZC` @MO9\6IJcCkkk5~5Q০Iss]V[k>28`e*^Qsc$}eO@|pMe5gʕZ?LT#1i$Sd7Oe;6iܼٜN܁v?vn4]:BF4G\h5?!{@j"xaPݏaf[3A0==,9x _rɄ 9ro?+:V(7MRiA=i*MVY+mmmL?1FX3'vo^? [~E / #flZ} ~j< B3"8lP?AEGMQ]Ӫۀ@#҇Ef?Z~T &8ZB@޽{c=7-㙈iHNhn\5]w`ݛG.\V?CQ dJxm>IAӛ.Hc}}'J}Uz?#1) -{[-iH[6ޭwYj~?^ 󺚉݆ۥ5Ƌ_i5'#)/jnn;)}#fd;! GI{z?Æ i޶2={r߳w&KZVKU]$^ sm~Azgڜ9WkU ӲR-'KT^q/3[^#/4"-Zc⏷n*G ^Z!g$? :\0BOea/Т:sdz2ks2Mm!|| e:6iִW6׫Fm 5R @xT@~…ZTTTh8J#PHhU>!2iXZTuoz#/ec^ (RS+&qɱUG!vs2[:6k^OW &v6z*"o>F*v`2"Àq8JC^KJaPy%Id%ߟA .ޣ0)N8`%}ïmϿ`j~iObK0pm12dE0F{;Ⱦ -ٵ[4%%[;whYݍ(QȞaA𱾟h??5΋SOF- 5 .v#*Tj_a2M^,/KUa@htǻ]Y!*;pVX7Q'h}!a&,_t_ Zo~2.uf @"3 rGK$,lY*?,/>ClmjĆ?*$BW[,7^fe/>"o'[fT/YD d?< ] ob='kk0htڀ̚jD xQlEqBCJc^m}cOb D߾PG?ǿJ}#;Te nP(yځ 8QN9OeMnu%/Sc;QħƍgHChRmSF@,XY B?Sv3J[ﺾYwp <{|Q;P=rvpRxO*mR}DMƣ y՛WQBCGğ*~' Տb?c Ņ|t+@KFM{/FFѽ!#sc@QZƗ7AUpr];e `ǡ۟%OKCHU';FhCzDi}>gjB_:_mvoܸqZ?Qxinj9 0p8jO@B ,DjԲAm05L[Svj*Ԋ SvT{Ϸ%XR|Ïc]FYܺ\X\=d yMM!vǪ~E؀t.RJ1io GLn>s=&DFS҉iq$Ƒl AK+MTj^]RXvD|?>~"---b]+ƒIz? 2&M:$[ILk׮}S7Yb?7cf?o[#l/Rl  T|T?*kE{J>"՟{m Pyk3Q:?L o̓f-?+? !9s_ozG>7䜜|I^R/}ڶ P/RQ~6}oL(fo%"d # x~K[m6Ex!húȑ# Jr#hKɨ"ď^{UbYd cnx8:'[b"fNJ+/SS >Ga*]-,ܵ!2,(T>@wxfG:#Z> p sj?~hàd<|QnO& f`*KMPP-e= !`Η쁧˔99?n__FP(;c&bU}z>y/h|&X_G駟իo嫿Me*W;ϑC['َi!hMZ<j.]q\hD$Гb1On¯[BQow-z,j"d6n8_&,om|uȹ99aK z9o} 9m4|HgWԾEZ)5kp`pݼH=j׿{cֿĩ7rז0?\FTER|rmF_Рҿ6kqH0o$wl^;krU#yMC4s:'&H~GQOe'L&WoUM? !>Ex7oK:)9We?Xw(:9e b_6k?_iq`#??Qτ!??jG9M1yPwl'w̑TZa[ Dg[a]>hCюL)*sb/RaoODcxF(Ҭ*}71🬚Bv <^24' HLZ?Ub>>|SQt>GO?h=ӆ;a?#TKͲjՎS өF޾iz_)_}4`R} /ϧLASl|m"x/1_k?ذa=FY;pSy\c͢ѭ8Oe3#خݽ crrd|y|ڶת(^rdJUH=#G1J7[עkS}O}} :TG_&L?] (N4bڵoi8/d]i t]u{vh:>Kt7aLNʨH]̇33;0hD?RȰ$Vlꩧwci 8[:ɣJk{Nyf̮5wJcǩ}\=B߭脭8/~*ZquLz& &Uy歖|9ȶrFgtDV en⚌Um}g;UF O>s>@Q!EEb?-^m|vMݻ5ч#.P"2rȔ~6/ g鏚cШ&}y: $n=)-Ǐiu_w*3v<#;vFYjm3}67h [N?| *!uuuZ z *1؈ UG_ڿo2fxV۰g\Y'O|Af|N{Z6UN{Ÿ3h"j^~XcCLz6 U2_{?FO2*ƻ妉7ҷkf6M0`5~DN+̙O87qDm{p_. ͢bG[U,ڧ $,jYm}Zis{ ֛[&aYv@6?c&ODc}Rgj̢}bO>>*fßM $ܱy\}lV>;lXQa.]ԾW q!gڸ\,`f+ Ąq PS ??>fw 섟BHji&uX_'<Ȍ|zQ{aPJݦsmG 5(w3P"&]C;ځH*~nHTCa K-L׆kfѿjo\5s̅ҷ?*K@ ~r^;dž2Lga#鋴?"f#Go6?[ Fo[n7&>C@7VӤQg,Tm~hDXE,WۧOn f!:Mt~֜ş?7GԏA?hO0ADɕTgQci!sOi>Pm+VЊ0c~f?XGل T%{瞗DGjh!@;k[+g>|pFY>F>z2.ѾX~Iw+~1~c*l_D4rB2g KQi>㯅 b/vMZ:.Xg8eбv)19i!ZNl>kpS7M|ܬ͛J>za Ⱥ J(ccY ˪qkB|ϙj؏]_MM3x_oǰޏ6?Ҝ {6 Վ>`|9+jet˯)1pW[jGE/!@wPfoK.*2u4ܡn7v"~S=r*PhX鏙n x≧- ů? !$L'C 3"~DXG3G?sq0=Uw俵l]]熬l}g3ECaw?}]L.gg-3&7Ȁh˯I@s%9O|H?_oCʿ2=C0|/CZ8 !$9ϣSgGDiT lT[D' pO !sP?ۺh[ o ܬE?:mŭ00Xo*gY;ci!֩GH<7#Տ7b }?r~38<]V̙3qٿ寛M}K@g&$TE+sq3w="c`yEˠ=Uf ѿ~_G4 !m͆A|sևJ2(>wRC:d=xfDGT+ xwx/s?m a?ּ?υ`vٳg/3~O=02kV~?1O|xƍZ?ި*D6H~f_ jKz͖Xc ) xq)EL;G A J\E~2!feϚ5+97k ?fĝx3|aၴt:#7!*oݺuZԫWc#%?̀u [ߞ@͎(o˄xzgc=nLZ_׷ڿ٫sڌ4TA-$]u{10A\?7!vK)cǎ~/uA6jǿGе@nO,~,;v)-z{\„ $b`8"BH~1x?mI*+oFVa?/Z2r1@u; vG ^鏷*HǺ}?1+E- "o}[p81 ?cѷ~Mg9^ |Y#Tυ?Tt?Р ?*f> Bwf lAy U?sV&n5/LYehH>Gf⏿?~7u[-PmP7n8-/**: a-3{ձK,ya @Ea3fK< 74aPL:}7EQk8|fb?~X>A*"kC`۟2mwyL1/o0'f tcJ~O n~B#@hAOLGWqz?pB?QM#k ?2(;x_&" h[3OO(}E_?fHO;]|s0z25552f-AFgcv|ODVF#C`$_ kvExoQ>X[69SO=?X Y3D/01'%Fzv Dt?Xr__DX_ ?0ѿ%Zc1Юm_K?Vp'3C1(fX,Yc|ݟ0[חW7}cL>}?Ac?챘̕+Wn}yM42OzkD'"f3ShߘfԬ?hllԊc}JDV`."P߬戻?1 юA$&O@ 1/T3Ma];L|LE2%n&DF./S*#ZbX|2FP}f >ώRV 9䇍k0~0H3g0Jv=j9e3>¿YeB1q|3#4iioTi0XG{P%wC$:qQ&*]F`g̾6 |~#P`Gn%b Qm/*!b `2"?}>|0cy\xf1N;]q^@`g>O@hɡ6*=;Y1@6?}+!O 2&0PVYu5`?R)ww`f$Iܓ72%!Ÿ7igDtMGG?`_J[eEFvvvjVlJ~z*w3c7/ 03b<#n`_ot3Ԗ ˇ95ao胔?@b?RzL>aտ̟?wygXEyrC8љED 1DUScyfM0~c?R0FVRz=%C)$.Sfw9裇ʡ3\T t?JIto>G;U F0B#@'XԚQچL>k[b/Wښ^ר vZ-6IGO,X$`e$C}?kcϖ-[!?f?M rGD^Ei HMD\D;@V?#F`S$ ?gC$̔j#Mt_h sS@H80NgnZ2{lsУW;i~~Y'-@U?6o޼?o%Qa !즪(kQjE^>h{LCkW]{^4Q.G hiTCb?W'V#7*xt*aYwsN,m27p>G/K?o h!<"G@b?zǢ"}ٳo[|9*,Ͷ52yYG@IUEw(5k3[;0y  8d+m8MMMZYߏ>?(Q_+"u뮻e0i=4 /TGZK~4)>XGx|/3hO<ĭ .(Ί3~vBHe|L¡ ]c4&/++E(ӧCA?0vQ3Ж?3#?/BHf y@Du&"}O니=XOEvc?CwDUNcO@q"L<k~}/k?@n?<0+T7'MS@4dTd}O)+VhU-|!Y9DȮX2m7|u*@'Y?i!Y3P鯷sf)!ɕF?!*31c-Vn%ߣBH AD d18[@?~W7U\9zQu !$(L} }}DGbE֯_d^^k?3g2O@VF Kيu (K&>⏴Y" Ǣ%۱uEW^y6?h?o !$%7B7}ʕ+TcommV臹\Oqp"jy`1OJYH!BlrDVFh=ĦI;ӧD*Tk \XCO叩BHP=6!k{`-b 4GAY}Џ]?n?1N͢74tDsn%]wk P~3/̆+30wrh86g&IͫAv-ccY;V~b R{SWΜ9Yf-fd#`' }޷BM\t36#5S^~aÆI]]ۉ  G1W?oJv ~Rq? !۷/#L#+=1sG*(ྠ׉S~Wc~Cvsj̢}BHPvݙ00(CĿ|r>bocc#g_uU3Fz U? sb;ŋv{7?$ =i!^Ts wͱ.|Hc?fCJ G~x0YNK|Wܣ5K@'\nHuSB:֏5AsU}j|SM.??% !#pb tK ۷oׄ*Tר;H0KENXl<ߩ"G E4dZbmN*i~lǮ~.~X7|Cq,\5>ٿ8*wDŽE4%vQd@j9l#͝:ĉb?L8ϟ? J?YYG@5*=bgO%O{# ~hF3m Rf!窯)Ԑn\QϢ?BA @&: JQ鏝( 5#J|384>]yrpȏN6a !Koޛ[LC"1B;tZ^!"(t= /,CBhp4eǁ ,]ݎ!8w슛n zo\d 6Zgm~FTSi!9bVLe ǎ~cb~`kj_ք$7Iq" x,U~O& zP:?qx!a+ Ԩ Cki9X#ƳI_uF $ xvENg@Æ RSSC#ׅϣv&q_\"Sķf? dY#&7]vkv}!~q@_ TbV^=_߽sF1NGm"~#ON? !$@LnqS C 1u)LCI/!Ǡ~_s̹{S5;G HͲFo1 Q p+`&h* Ґɩ? !gq))[-SV':4D = ⏏A9R \7fJ?RuV ~|ս%{FvBÒWo1U~ A?KVV?~s#S#TYf=>{i~fsD'ASi!4 7g&790j@?Rfo'AZwXG袏I&DV˝jYW3wbG PD?Mw,._[C+j^ z]S7Ckު&pwa>f[ZBBboQլDrqZ&B?U~;|]ݡmkoSi!n>zϷ, @0BЯ%_c4'h"yc{SlѼy^1c; ?X rd;_? !ħi:|2\,Àn ׆@d[يP˗^]`faO, Si!4@⡉*ۄIh DdqO| ~T֭[z*<'fۉUDjG(4e {TSNZ}!^K/~g̙oXb:/Y [ (4DNfqgy&h~Oj†O?c-)n;(B7~%c'N/!I: ޣ((=TE>34}TWE-[/[^xaUȡ"~'~? !$ m L:*9O?KXP+NXN6 ڕko.8N|*oV#v|}*}ߨ*oRk=6y&6}7ѿ]V n* X/$~ۂ$`$N10 f_LČ>q}z[ifѿYzޭ ;cb烝S} B`40Y$"IG7q_[}|}$~,f9'Swc쾇%BH~~#j"1/02K3 6cRv 0.8z ? ! 'Ѕm$ d8 1F-{SBB0,&os`AקopbMoUW"NBH|>87|n?5Uw e7n|F4 m@=f"qwtVt2.S !$mC\Fَsi3ۉ=?p!$U+}QW~1"| ? !Dl h?մTSpc>(43;Sz6ZX s<K &|ֿlفtDOh!gc{~>Uw[`%4<Brj2!Nis's"6B@!!nM$4F?݌@:Q{}<şBHZTm4h?S&~) #4Bwŧg0QΤS !7J4sLWL98EBqod^ҍ3YG'4@g"Yٸųq !~ V|,!BBy=-E !%A'C#߯(P{ŝB!B!B!B!xXIENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata/ico/dmg.iconset/icon_16x16.png0000644000175100001660000000074714776170045025457 0ustar runnerdockerPNG  IHDR(-SPLTEDUcnŹARARt~ARBSL\N]O_P_P`\j]lcocqdrkx{܇|܈Ƒʩ̮ɿ\tRNS,O 3 xE2 @H~_\b1mߏ^V QX [q;>k>+˰Vvk+}A  "╕zW.u{)C / BɸV{|klHH,+Xx?Z76>!mh%Z۳sc,wL<@Hy ܿ&e,>ux{ҟ @>ޗVkm DclD;tZڎ@HBeGςׂ!)Ab ?x^}C@/7˚ty@WcǏ&z}ע=0"9w`0+ a<.͗Pq^o?>p 66pNx>.{Wy%d&KDf[yOpDK8AٵLB1  jq sx?8k0>ߑʳ(zrx?ɓ K)>{~3 Y? ώƮaǏPya-^ t92?`DU_R<V)^0LAP2J;arz1o){?WavxZ bTȔV \aV} ]ԣG^؏/yiӦȟHYt5oMAktoF$(W{챻da÷سg]!yv %,@(6Y_Ͼ+JoDX[㕅@G^T2e*u3;f#F8RN竪9 A0 o/y_V?L"(*m񖑾~Kv3|;w%ŒjP rŻanÔg2 -L0(!0ڳnk1 )+W[r. S5"*T^+|u$yz|.\T{>eJuY|~$vq|U$!EEOQ @(2nqc=vx}fؿu~}ǩI8f-P[ζqET?v_.] UT?sɼwd.{6ozhrsvRIr6lX?cƌbUX򽮔0ꟋQ5`b6 Hʸ0#b.Nuq΢7Z #K+Đv_xH7-Z mg!7I;ug F|̙#f̘r.JXj ? Rv[XdsbFƒHE5eϛ7OlٲEL>}ӦM;i'0pߋ-zG,2DBż@M!p}3xw' 6@(߾}ضm2e@KΝ+-[vkڵkS Ti# qJ|ѢE \f}W^bرbժUC׷m۶bO+CV][dg]T8 Pw6Sq M8Q,]T>믿 9O~1a~zA0` Gf? X>icl៑yM ۑgKS:Acw}'~7k׮ _ѧOߺu_ƏD?S%!V\ HmG~גJf9v9ӞO4dիO0z?R~ Ow.\c;R~`Z X_p߇z&EP+oL~W =-ADGyVnO?t{wСw\(~а`r} ÔD߱!W{/H-G1A 3h?? # ` 6}kmV3//~DD{׮\A9~~^3BcADw%~"gzJw9~Jq 5(9芌If+es;=m{m%KXo^;qҤI})mw9}giif6U^k񢇬t=7jAT=b=EQ(`zO1F?hf/gΜ)~m!yɓ'[ ~a҆nq`%mmZ~CNM0wzkwo>#jbۻEڿBNAhWT^iCW9TfX(Fd<?x*gh5bp}[|H類_ڃY~7o>!'gMSG ,?MV[i0~ zNqᐵ1|,ϾCC_hkW͞=G ElQ؃_[;pos'HZ1db/SuNA;c܏#0ɝ7cE/m:駌՟`>8vXLJ<>Wīzla۴Mbuy#&C z駟TOʛYq_J9 I~kو#Wi .M"l1 nN 0@k-~h>?(I&Jb?ps,z7D1߄ڣƁ]|LF"zן ߦ-n"5h }o5FM!,FMFٯ/~(>]Xs,$$ޖc;>V{`@\ǐ!C` E*foƍ_R/GD`8::4ғ\W|lua6MqMYcUƪ_y-^hdj__6P|7NGrhH$|Kݮ'+ǡHthh>sXnݺs~)>#NՁyuP&p&rj@{VM^9 =herŢKEɹ8%G:oIq#uؒ;au8]WA{^|>>_ O1IJ C.8N GM~=H)ʁ!ZjLI>IƏp&rsዣC;4ŤWAuVWKPym$``'-{F58vwJjѐzӇy`V5 @*GziZ_vB)w rNYq9.n"l1n聻&RшA4cw7(Rq^Ec fOG+i` ?jx.cL 2R7~9Pd{ZH_ &(e4c, 7HF0"]tG6< _%i.BʿA{c%U$Td {ɔ>I|XM&>@k؝}hd Ez7 jh(Uw0 s+KP[6J[ʊ 7HF0|=뫯Ѽd\$}jժ;ȯgX2FL k՗*U?#lG]F b[9-4PP/UI%!ڡAnӾos2T`z&"ҏ:!>3'\|kU꯻z6b8K5?dJXNj\R䨯5TD&F࿈~ڰ{bIbPb4d]ojwDӕWyJ䳔jCEڕՖyEznXv܂>R{(E]?j`2`xS…P.ntG*yW۞BJ b!25,xIK*'Oڲv~2$&9rGI0|7&SPxdIiѢś*}*;3qt!ȫn3 S TpzH/GT5fvɪ 7xCJGbJ )G뿯O>dʮ\urگ &dj׈زe'i(^/EYe0~9B {)}Ї=K.yHeUd<'W7 d hPIjlq 5\UӏmN* @̭۶m{;#S!dj7-1m1$&bEuL =r_*PT]2*vO`'-ĺ`KemY&"a V}0 )HM'!H }ֿjժw E?D@A%خV% DD IC}D7߉E[[T1UEWw`Wl"Et*Wh` pkVFwW1 ͂3++*UGa򑱁?"XPHmU^!ަD"a8+?F?nbLAϛC>dzr[ҥՊ}[S+W Y_orѿ}(A==)Ѝ_ [_Gm/P[⏁?·`gN$k](q %^0(ˇ9(={_d nf?3iE'+K*u5h ?mf D?=<4MnCOyn I#˖-{s$ GoM‰Adde"EܕC]è?h E+!`Ķ>.&S) e9+>(W7fT!g֟wPzD~>}eNL 'Ak&\wu8+ߏ)JN?n@ @~]d5C@]ʸHjCcZ/xg M R!xlf͚uRA?+;"2GG+`GY/ QAM 8?">h:0F .~?D %K~L W*kG?31qĿ ߉ Yw2vVVUA?3OXA@Ypnv)p4EǎC9oOab_xᅁY9gYVq'Or5|5\.(A+?}ptX!D"x|Ge圓qյ]àx0r) wy`$G_""e5G/F{r3G^쓜]ytc@N<0~0,"fmm e+T_00)OH m9,.{`GƏ^~nB*A:hiݺuO?)pR3}n0('Ge1K#h aL X2haÆrfTtҠGcMG[}taZ/҅;ѫ h@(Ӕd 4!C}}+"ܗy|١#pLZ5 ,ի?8wh8$ 9)4~"v[-0nݺYH{0-Vs066Kն>;HvM0H{ m2rtCVӁˁׯ [0jGǿ0jjUOdd,bfGZs hDne͋/W_|zlҤɇ=P϶mfwa0Ce>_Vu=7nܹN:P-{6Q@Rp R"i>~)OP 7PڃQk(1F 2[[k}J ]@{}%*iVu5cF}૩H3sj hm *s3|?n ,r(㪨Zm+CBU@k)cpש݃SVz\>W ޟ6bj/@OPX@>ZQ+hIe\PVN +) eU*]]e^[EE+ϲWsԵћ}^'( Fu2ʧ>Sٚ0UZNU2`7VP?{z]9^{)OW;SJo}>D-n 2؊tC1WYRߕHBaFgj^RWqgh^0x}{ojO'Bp-Rš2֢J(lp3E #/{~VziAri[<`-4EgkFO{+n4zH2MSty iD1'Ͱ "/AAAAs$t3IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/0000755000175100001660000000000014776170045024515 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/input2.txt0000644000175100001660000000000014776170045026465 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/irrelevant.js0000644000175100001660000000005714776170045027230 0ustar runnerdockerfunction irrelevant() { return "irrelevant"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/custom1command.js0000644000175100001660000000011014776170045027775 0ustar runnerdockervar Irrelevant = require("./irrelevant.js"); function sourceCode() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/probe1.js0000644000175100001660000000013314776170045026240 0ustar runnerdockervar Probe2 = require("./probe2.js") function probe1Func() { return Probe2.probe2Func(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking.qbs0000644000175100001660000000013314776170045031556 0ustar runnerdockerProject { qbsSearchPaths: ["."] references: "import-change-tracking-product.qbs" } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/input1.txt0000644000175100001660000000000014776170045026464 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/imports/0000755000175100001660000000000014776170045026212 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/0000755000175100001660000000000014776170045031145 5ustar runnerdocker././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command2.jsqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2comm0000644000175100001660000000011414776170045033334 0ustar runnerdockervar Irrelevant = require("../../irrelevant.js"); function sourceCode() { } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2command1.jsqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/imports/custom2command/custom2comm0000644000175100001660000000006114776170045033335 0ustar runnerdockervar Irrelevant = require("../../irrelevant.js"); qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs0000644000175100001660000000240014776170045033233 0ustar runnerdockerimport "irrelevant.js" as Irrelevant import "custom1prepare1.js" as Custom1Prepare import "custom2prepare" as Custom2Prepare import "probe1.js" as ProbeFunc Product { name: "customProduct" type: ["custom1", "custom2"] property string irrelevant: Irrelevant.irrelevant() property string dummy: probe1.result Group { files: "input1.txt" fileTags: "input.custom1" } Group { files: "input2.txt" fileTags: "input.custom2" } Rule { inputs: "input.custom1" Artifact { filePath: "dummy.custom1"; fileTags: "custom1" } prepare: { return Custom1Prepare.prepare(); } } Rule { inputs: "input.custom2" Artifact { filePath: "dummy.custom2"; fileTags: "custom2" } prepare: { return Custom2Prepare.prepare(); } } Probe { id: probe1 property string input: Irrelevant.irrelevant() property string result configure: { found = true; console.info("running probe1"); return ProbeFunc.probe1Func(); } } Probe { id: probe2 configure: { console.info("running probe2"); found = true; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/0000755000175100001660000000000014776170045027470 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare1.js0000644000175100001660000000000014776170045033050 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/custom2prepare/custom2prepare2.js0000644000175100001660000000045514776170045033067 0ustar runnerdockervar Custom2Command = require("custom2command"); function prepare() { console.info("running custom2 prepare script"); var cmd = new JavaScriptCommand(); cmd.description = "running custom2 command"; cmd.sourceCode = function() { return Custom2Command.sourceCode(); }; return cmd; } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/probe2.js0000644000175100001660000000005614776170045026245 0ustar runnerdockerfunction probe2Func() { return "probeData"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare1.js0000644000175100001660000000023214776170045030103 0ustar runnerdockervar CustomPrepare = require("./custom1prepare2.js"); var Irrelevant = require("./irrelevant.js"); function prepare() { return CustomPrepare.prepare(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/import-change-tracking/custom1prepare2.js0000644000175100001660000000053714776170045030114 0ustar runnerdockervar Custom1Command = require("./custom1command.js"); var Irrelevant = require("./irrelevant.js"); function prepare() { console.info("running custom1 prepare script"); var cmd = new JavaScriptCommand(); cmd.description = "running custom1 command"; cmd.sourceCode = function() { return Custom1Command.sourceCode(); }; return cmd; } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/0000755000175100001660000000000014776170045022201 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/tag-mismatch/0000755000175100001660000000000014776170045024557 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/tag-mismatch/tag-mismatch.qbs0000644000175100001660000000176314776170045027653 0ustar runnerdockerProduct { name: "p" type: "p_type" Rule { multiplex: true outputFileTags: ["x"] outputArtifacts: [{filePath: "dummy1", fileTags: ["x","y","z"]}] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { }; return cmd; } } Rule { inputs: ["y"] Artifact { filePath: "dummy2"; fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { }; return cmd; } } Rule { inputs: ["x"] Artifact { filePath: "dummy3"; fileTags: "p_type" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-fileTags/0000755000175100001660000000000014776170045030605 5ustar runnerdocker././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-fileTags/outputArtifacts-missing-fileTags.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-fileTags/outputArtifact0000644000175100001660000000057214776170045033552 0ustar runnerdockerCppApplication { type: base.concat("txt") files : ["main.cpp"] Rule { inputs: ["application"] outputArtifacts: [{ filePath: input.completeBaseName + ".txt" }] outputFileTags: ["txt"] prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-fileTags/main.cpp0000644000175100001660000000003114776170045032227 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/0000755000175100001660000000000014776170045026557 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/nonexistentWorkingDir.qbs0000644000175100001660000000057414776170045033652 0ustar runnerdockerApplication { name: "kaputt" type: ["nutritious"] Rule { multiplex: true Artifact { filePath: "Stulle" fileTags: ["nutritious"] } prepare: { var cmd = new Command("ls"); cmd.workingDirectory = "/does/not/exist"; cmd.silent = true; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-filePath/0000755000175100001660000000000014776170045030603 5ustar runnerdocker././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-filePath/outputArtifacts-missing-filePath.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-filePath/outputArtifact0000644000175100001660000000054214776170045033545 0ustar runnerdockerCppApplication { type: base.concat("txt") files : ["main.cpp"] Rule { inputs: ["application"] outputArtifacts: [{ fileTags: ["txt"] }] outputFileTags: ["txt"] prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/outputArtifacts-missing-filePath/main.cpp0000644000175100001660000000003114776170045032225 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/texttemplate-unknown-placeholder/0000755000175100001660000000000014776170045030676 5ustar runnerdocker././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/texttemplate-unknown-placeholder/texttemplate-unknown-placeholder.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/texttemplate-unknown-placeholder/texttemplate-u0000644000175100001660000000024114776170045033600 0ustar runnerdockerProduct { type: ["text"] Depends { name: "texttemplate" } texttemplate.dict: ({ wat: "room" }) // typo in key name files: [ "boom.txt.in" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/erroneous/texttemplate-unknown-placeholder/boom.txt.in0000644000175100001660000000004514776170045032777 0ustar runnerdockerBoom! shake-shake-shake the ${what}! qbs-src-2.6.1/tests/auto/blackbox/testdata/output-artifact-auto-tagging/0000755000175100001660000000000014776170045025677 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/output-artifact-auto-tagging/broken.cpp.in0000644000175100001660000000002614776170045030266 0ustar runnerdockervoid f() { blubb(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/output-artifact-auto-tagging/main.cpp.in0000644000175100001660000000001614776170045027731 0ustar runnerdockerint main() {} ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging0000644000175100001660000000176114776170045033346 0ustar runnerdockerimport qbs.File CppApplication { consoleApplication: true property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } Group { files: ["broken.cpp.in", "main.cpp.in"] fileTags: ["cpp.in"] } Rule { multiplex: true inputs: ["cpp.in"] outputFileTags: ["cpp"] outputArtifacts: [{ filePath: "main.cpp" }, { filePath: "broken.nomatch" }] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating main.cpp"; cmd.sourceCode = function() { File.copy(product.sourceDirectory + "/main.cpp.in", product.buildDirectory + "/main.cpp"); File.copy(product.sourceDirectory + "/broken.cpp.in", product.buildDirectory + "/broken.nomatch"); }; return [cmd]; } } FileTagger { patterns: ["*.nomatch"] fileTags: ["utter nonsense"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/0000755000175100001660000000000014776170045023755 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/pch-change-tracking.qbs0000644000175100001660000000031014776170045030253 0ustar runnerdockerCppApplication { files: [ "header1.h", "header2.cpp", "header2.h", "main.cpp", ] Group { files: ["pch.h"] fileTags: ["cpp_pch_src"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/header2.h0000644000175100001660000000240614776170045025442 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once void printPersonalGreeting(); qbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/pch.h0000644000175100001660000000236014776170045024701 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "header1.h" qbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/main.cpp0000644000175100001660000000250314776170045025405 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "header2.h" #include "pch.h" int main() { printGreeting(); printPersonalGreeting(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/header2.cpp0000644000175100001660000000025714776170045025777 0ustar runnerdocker#include "header2.h" // header1 is forced-included via pch. void printPersonalGreeting() { printGreeting(); std::cout << "Was geht, Rumpelstilzchen?" << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/pch-change-tracking/header1.h0000644000175100001660000000250414776170045025440 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include inline void printGreeting() { std::cout << "Tach." << std::endl; } qbs-src-2.6.1/tests/auto/blackbox/testdata/separate-debug-info/0000755000175100001660000000000014776170045024001 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/separate-debug-info/foo.cpp0000644000175100001660000000244014776170045025270 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "../dllexport.h" DLL_EXPORT int getAnswer() { return 42; } qbs-src-2.6.1/tests/auto/blackbox/testdata/separate-debug-info/main.cpp0000644000175100001660000000236414776170045025436 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs0000644000175100001660000001075614776170045030342 0ustar runnerdockerProject { CppApplication { name: "app1" type: ["application"] files: ["main.cpp"] cpp.separateDebugInformation: true Probe { id: osProbe property stringList targetOS: qbs.targetOS property stringList toolchain: qbs.toolchain configure: { console.info("is windows: " + (targetOS.includes("windows") ? "yes" : "no")); console.info("is macos: " + (targetOS.includes("macos") ? "yes" : "no")); console.info("is darwin: " + (targetOS.includes("darwin") ? "yes" : "no")); console.info("is gcc: " + (toolchain.includes("gcc") ? "yes" : "no")); console.info("is msvc: " + (toolchain.includes("msvc") ? "yes" : "no")); console.info("is emscripten: " + (toolchain.includes("emscripten") ? "yes" : "no")); } } } DynamicLibrary { Depends { name: "cpp" } name: "foo1" type: ["dynamiclibrary"] files: ["foo.cpp"] cpp.separateDebugInformation: true } LoadableModule { Depends { name: "cpp" } name: "bar1" files: ["foo.cpp"] cpp.separateDebugInformation: true } CppApplication { name: "app2" type: ["application"] files: ["main.cpp"] cpp.separateDebugInformation: false } DynamicLibrary { Depends { name: "cpp" } name: "foo2" type: ["dynamiclibrary"] files: ["foo.cpp"] cpp.separateDebugInformation: false } LoadableModule { Depends { name: "cpp" } name: "bar2" files: ["foo.cpp"] cpp.separateDebugInformation: false } CppApplication { name: "app3" type: ["application"] files: ["main.cpp"] cpp.separateDebugInformation: true Properties { condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } DynamicLibrary { Depends { name: "cpp" } name: "foo3" type: ["dynamiclibrary"] files: ["foo.cpp"] cpp.separateDebugInformation: true Properties { condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } LoadableModule { Depends { name: "cpp" } name: "bar3" files: ["foo.cpp"] cpp.separateDebugInformation: true Properties { condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } CppApplication { name: "app4" type: ["application"] files: ["main.cpp"] consoleApplication: true cpp.separateDebugInformation: true } DynamicLibrary { Depends { name: "cpp" } name: "foo4" type: ["dynamiclibrary"] files: ["foo.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true } LoadableModule { Depends { name: "cpp" } name: "bar4" files: ["foo.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true } CppApplication { name: "app5" type: ["application"] files: ["main.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true Properties { condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } DynamicLibrary { Depends { name: "cpp" } name: "foo5" type: ["dynamiclibrary"] files: ["foo.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true Properties { condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } LoadableModule { Depends { name: "cpp" } name: "bar5" files: ["foo.cpp"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: false } cpp.separateDebugInformation: true Properties { condition: qbs.targetOS.includes("darwin") cpp.dsymutilFlags: ["--flat"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/build-graph-versions/0000755000175100001660000000000014776170045024224 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/build-graph-versions/build-graph-versions.qbs0000644000175100001660000000005314776170045030775 0ustar runnerdockerCppApplication { files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/build-graph-versions/main.cpp0000644000175100001660000000001714776170045025652 0ustar runnerdockerint main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/response-files/0000755000175100001660000000000014776170045023116 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/response-files/response-files.qbs0000644000175100001660000000563214776170045026571 0ustar runnerdockerimport qbs.FileInfo import qbs.Host import qbs.TextFile Project { CppApplication { name: "cat-response-file" files: ["cat-response-file.cpp"] cpp.enableExceptions: true } Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: "response-file-text" type: ["text"] Depends { name: "cpp" } Depends { name: "cat-response-file" } qbs.installPrefix: "" Group { fileTagsFilter: ["text"] qbs.install: true } Rule { inputsFromDependencies: ["application"] Artifact { filePath: "response-file-content.txt" fileTags: ["text"] } prepare: { var filePath = inputs["application"][0].filePath; var args = [output.filePath, "foo", "with space", "bar"]; var cmd = new Command(filePath, args); cmd.responseFileThreshold = 1; cmd.responseFileArgumentIndex = 1; cmd.responseFileUsagePrefix = '@'; cmd.silent = true; return cmd; } } } Product { name: "lotsofobjects" type: ["dynamiclibrary"] // clang-cl does not use response file internally, thus linker complains that command is // too long. This can be worked around by calling the linker directly Properties { condition: qbs.toolchain.includes("clang-cl") cpp.linkerMode: "manual" } Depends { name: "cpp" } Rule { multiplex: true outputFileTags: ["cpp"] outputArtifacts: { var artifacts = []; for (var i = 0; i < 1000; ++i) artifacts.push({filePath: "source-" + i + ".cpp", fileTags: ["cpp"]}); return artifacts; } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + outputs["cpp"].length + " dummy source files"; cmd.outputFilePaths = outputs["cpp"].map(function (a) { return a.filePath; }); cmd.sourceCode = function () { var index = 0; outputFilePaths.map(function (fp) { var tf = new TextFile(fp, TextFile.WriteOnly); try { tf.writeLine("extern int foo" + index + "() { return 0; }"); ++index; } finally { tf.close(); } }); }; return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/response-files/cat-response-file.cpp0000644000175100001660000000431014776170045027140 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include using namespace std; int main(int argc, char *argv[]) { if (argc < 3) { cerr << "cat-response-file: not enough arguments: " << argc - 1 << endl; return 1; } if (strlen(argv[2]) < 2) { cerr << "cat-response-file: second argument is too short: " << argv[2] << endl; return 2; } if (argv[2][0] != '@') { cerr << "cat-response-file: second argument does not start with @: " << argv[2] << endl; return 3; } ifstream inf(argv[2] + 1); if (!inf.is_open()) { cerr << "cat-response-file: cannot open input file " << argv[2] + 1 << endl; return 4; } ofstream ouf(argv[1]); if (!ouf.is_open()) { cerr << "cat-response-file: cannot open output file " << argv[1] << endl; return 5; } string line; while (getline(inf, line)) ouf << line << endl; inf.close(); ouf.close(); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/0000755000175100001660000000000014776170045023010 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/after/0000755000175100001660000000000014776170045024111 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/after/product3.qbs0000644000175100001660000000016414776170045026364 0ustar runnerdockerProduct { Depends { name: "cpp" } type: "application" consoleApplication: true files: ["zoo.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/after/zoo.cpp0000644000175100001660000000242714776170045025431 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::printf("zoo\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/after/trackProducts.qbs0000644000175100001660000000014714776170045027452 0ustar runnerdockerProject { name: "trackProducts" references: ["product1.qbs", "product2.qbs", "product3.qbs"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/before/0000755000175100001660000000000014776170045024252 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/before/product2.qbs0000644000175100001660000000016414776170045026524 0ustar runnerdockerProduct { Depends { name: "cpp" } type: "application" consoleApplication: true files: ["bar.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/before/product1.qbs0000644000175100001660000000016414776170045026523 0ustar runnerdockerProduct { Depends { name: "cpp" } type: "application" consoleApplication: true files: ["foo.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/before/foo.cpp0000644000175100001660000000242714776170045025546 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::printf("foo\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/before/bar.cpp0000644000175100001660000000242714776170045025527 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::printf("bar\n"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackProducts/before/trackProducts.qbs0000644000175100001660000000012714776170045027611 0ustar runnerdockerProject { name: "trackProducts" references: ["product1.qbs", "product2.qbs"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-propertylist/0000755000175100001660000000000014776170045025472 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/jsextensions-propertylist/propertylist.qbs0000644000175100001660000001114214776170045030760 0ustar runnerdockerimport qbs.Process import qbs.PropertyList import qbs.TextFile Product { type: ["Pineapple Steve"] property bool dummy: { var plistobj = new PropertyList(); if (!plistobj.isEmpty()) { throw "newly created PropertyList was not empty!"; } if (plistobj.format() !== undefined) { throw "newly created PropertyList did not have an undefined format"; } plistobj.clear(); if (!plistobj.isEmpty() || plistobj.format() !== undefined) { throw "clear() somehow had an effect on an empty PropertyList"; } plistobj.readFromString('{"key":["value"]}'); if (plistobj.isEmpty() || plistobj.format() !== "json") { throw "readFromString did not set format to JSON or object thinks it is empty"; } plistobj.clear(); if (!plistobj.isEmpty() || plistobj.format() !== undefined) { throw "clear() had no effect on a non-empty PropertyList"; } var obj = { "Array": ["ListItem1", "ListItem2", "ListItem3"], "Integer": 1, "Boolean": true, "String": "otherString" }; var infoplist = new TextFile("test.xml", TextFile.WriteOnly); infoplist.write(JSON.stringify(obj)); infoplist.close(); var process = new Process(); process.exec("plutil", ["-convert", "xml1", "test.xml"]); process.close(); var xmlfile = new TextFile("test.xml", TextFile.ReadOnly); var propertyList = new PropertyList(); propertyList.readFromString(xmlfile.readAll()); xmlfile.close(); var jsontextfile = new TextFile("test.json", TextFile.WriteOnly); jsontextfile.write(propertyList.toJSON()); jsontextfile.close(); propertyList.writeToFile("test2.json", "json-compact"); propertyList.writeToFile("test3.json", "json-pretty"); process = new Process(); process.exec("plutil", ["-convert", "json", "test.xml"]); process.close(); propertyList = new PropertyList(); propertyList.readFromFile("test.xml"); if (propertyList.format() !== "json") { // yes, JSON -- ignore the file extension throw "expected property list format json but got " + propertyList.format(); } if (propertyList.isEmpty()) { throw "PropertyList was 'empty' after being loaded with data"; } var opensteptextfile = new TextFile("test.openstep.plist", TextFile.WriteOnly); opensteptextfile.write('{ rootObject = ( "val1", "val3", "val5", /* comment */ "val7", "val9", ); }'); opensteptextfile.close(); propertyList = new PropertyList(); propertyList.readFromFile("test.openstep.plist"); if (propertyList.format() !== "openstep") { throw "expected property list format openstep but got " + propertyList.format(); } var jsonObj = JSON.parse(propertyList.toJSON()); if (jsonObj["rootObject"].length != 5) { throw "going from OpenStep to a JSON string to a JSON object somehow broke"; } propertyList.clear(); propertyList.readFromString('foobarz'); jsonObj = JSON.parse(propertyList.toJSON()); if (jsonObj["foo"] !== "barz") { throw "the XML plist did not get parsed properly"; } propertyList.writeToFile("woof.xml", "xml1"); propertyList.readFromFile("woof.xml"); if (propertyList.format() !== "xml1") { throw "round trip writing and reading XML failed"; } propertyList.writeToFile("woof.plist", "binary1"); propertyList.readFromFile("woof.plist"); if (propertyList.format() !== "binary1") { throw "round trip writing and reading binary failed"; } if (jsonObj["foo"] !== "barz") { throw "the binary plist did not get parsed properly"; } if (propertyList.toString("json") !== propertyList.toString("json-compact") || propertyList.toJSON() !== propertyList.toJSON("compact")) { throw "json and json-compact formats were not equivalent"; } if (propertyList.toString("json") === propertyList.toString("json-pretty") || propertyList.toJSON() === propertyList.toJSON("pretty")) { throw "json and json-pretty formats were not different"; } if (propertyList.toString("xml1") !== propertyList.toXMLString()) { throw 'toString("xml1") and toXMLString() were not equivalent'; } return true; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/host-os-properties/0000755000175100001660000000000014776170045023746 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs0000644000175100001660000000064314776170045030246 0ustar runnerdockerimport qbs.Host CppApplication { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } consoleApplication: true cpp.defines: [ 'HOST_ARCHITECTURE="' + Host.architecture() + '"', 'HOST_PLATFORM="' + Host.platform() + '"' ] files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/host-os-properties/main.cpp0000644000175100001660000000025014776170045025373 0ustar runnerdocker#include int main() { std::printf("HOST_ARCHITECTURE = %s\n", HOST_ARCHITECTURE); std::printf("HOST_PLATFORM = %s\n", HOST_PLATFORM); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/0000755000175100001660000000000014776170045022430 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/0000755000175100001660000000000014776170045023753 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/app/0000755000175100001660000000000014776170045024533 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/app/main.cpp0000644000175100001660000000006014776170045026157 0ustar runnerdockerimport helloworld; int main() { hello(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/lib/0000755000175100001660000000000014776170045024521 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/lib/hello.cppm0000644000175100001660000000022614776170045026505 0ustar runnerdockermodule; #include "dllexport.h" #include export module helloworld; export LIB_EXPORT void hello() { std::cout << "Hello world!\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/lib/dllexport.h0000644000175100001660000000324414776170045026712 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef DLLEXPORT_H #define DLLEXPORT_H #if defined(_WIN32) || defined(WIN32) #define DLL_EXPORT __declspec(dllexport) #define DLL_IMPORT __declspec(dllimport) #else #define DLL_EXPORT __attribute__((visibility("default"))) #define DLL_IMPORT __attribute__((visibility("default"))) #endif #ifdef LIB_STATIC #define LIB_EXPORT #else #ifdef LIB_DYNAMIC #define LIB_EXPORT DLL_EXPORT #else #define LIB_EXPORT DLL_IMPORT #endif #endif #endif // include guard qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/library-module.qbs0000644000175100001660000000303514776170045027412 0ustar runnerdocker// Checks module in a library Project { DynamicLibrary { condition: { if (qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) // TODO: investigate why MinGW 11 fails || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } name: "lib" Depends { name: "cpp" } files: [ "lib/hello.cppm", ] install: true cpp.defines: "LIB_DYNAMIC" cpp.rpaths: cpp.rpathOrigin cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } CppApplication { condition: qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16) consoleApplication: true name: "app" Depends { name: "lib" } files: [ "app/main.cpp" ] install: true cpp.rpaths: [cpp.rpathOrigin + "/../lib"] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/lib-mod/CMakeLists.txt0000644000175100001660000000122214776170045026510 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(library_module VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_library(library_module_lib SHARED) target_sources(library_module_lib PUBLIC FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES lib/hello.cppm ) add_executable(library_module_app) target_sources(library_module_app PRIVATE app/main.cpp ) target_link_libraries(library_module_app library_module_lib) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(library_module_lib PRIVATE "-fmodules-ts") target_compile_options(library_module_app PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dot-in-name/0000755000175100001660000000000014776170045024540 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dot-in-name/dot-in-name.qbs0000644000175100001660000000123414776170045027357 0ustar runnerdocker// Checks that module name can contain a dot CppApplication { condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "a.module.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dot-in-name/a.module.cppm0000644000175100001660000000015614776170045027127 0ustar runnerdockermodule; #include export module a.mod; export void hello() { std::cout << "Hello world!\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dot-in-name/main.cpp0000644000175100001660000000005314776170045026166 0ustar runnerdockerimport a.mod; int main() { hello(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dot-in-name/CMakeLists.txt0000644000175100001660000000070514776170045027302 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(dot_in_name VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(dot_in_name) target_sources(dot_in_name PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES a.module.cppm ) target_sources(dot_in_name PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(dot_in_name PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/0000755000175100001660000000000014776170045024145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/partitions-recursive.qbs0000644000175100001660000000145114776170045031056 0ustar runnerdocker// Checks two modules split into partitions, one depends on the other CppApplication { name: "part-rec" condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "a.cppm", "a.p1.cppm", "a.p2.cppm", "b.cppm", "b.p1.cppm", "b.p2.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/b.cppm0000644000175100001660000000045514776170045025253 0ustar runnerdocker module; #include export module b; import :p2; // private partition export import :p1; // public partition import a; export void b() { b_p1(); b_p2(); std::cout << "hello from module b\n"; // these are also visible as they are public in module a a_p1(); a(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/b.p2.cppm0000644000175100001660000000014514776170045025567 0ustar runnerdocker module; #include module b:p2; void b_p2() { std::cout << "hello from b.part2\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/a.cppm0000644000175100001660000000032014776170045025241 0ustar runnerdocker module; #include export module a; import :p2; // private partition export import :p1; // public partition export void a() { a_p1(); a_p2(); std::cout << "hello from module a\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/b.p1.cppm0000644000175100001660000000016314776170045025566 0ustar runnerdocker module; #include export module b:p1; export void b_p1() { std::cout << "hello from b.part1\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/a.p1.cppm0000644000175100001660000000016314776170045025565 0ustar runnerdocker module; #include export module a:p1; export void a_p1() { std::cout << "hello from a.part1\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/main.cpp0000644000175100001660000000005714776170045025577 0ustar runnerdockerimport b; int main() { b_p1(); b(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/CMakeLists.txt0000644000175100001660000000077414776170045026715 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(partitions VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(partitions) target_sources(partitions PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES a.p1.cppm a.p2.cppm a.cppm b.p1.cppm b.p2.cppm b.cppm ) target_sources(partitions PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(partitions PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-rec/a.p2.cppm0000644000175100001660000000014514776170045025566 0ustar runnerdocker module; #include module a:p2; void a_p2() { std::cout << "hello from a.part2\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/0000755000175100001660000000000014776170045024142 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/app/0000755000175100001660000000000014776170045024722 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/app/main.cpp0000644000175100001660000000005714776170045026354 0ustar runnerdockerimport b; int main() { b_p1(); b(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/dllexport.h0000644000175100001660000000324414776170045026333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef DLLEXPORT_H #define DLLEXPORT_H #if defined(_WIN32) || defined(WIN32) #define DLL_EXPORT __declspec(dllexport) #define DLL_IMPORT __declspec(dllimport) #else #define DLL_EXPORT __attribute__((visibility("default"))) #define DLL_IMPORT __attribute__((visibility("default"))) #endif #ifdef LIB_STATIC #define LIB_EXPORT #else #ifdef LIB_DYNAMIC #define LIB_EXPORT DLL_EXPORT #else #define LIB_EXPORT DLL_IMPORT #endif #endif #endif // include guard qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-b/0000755000175100001660000000000014776170045025127 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-b/b.cppm0000644000175100001660000000026014776170045026227 0ustar runnerdocker module; #include "../dllexport.h" #include export module b; import :p2; // private partition export import :p1; // public partition export LIB_EXPORT void b(); qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-b/b.p2.cppm0000644000175100001660000000021214776170045026544 0ustar runnerdocker module; #include "../dllexport.h" #include module b:p2; LIB_EXPORT void b_p2() { std::cout << "hello from b.part2\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-b/b.p1.cppm0000644000175100001660000000023014776170045026543 0ustar runnerdocker module; #include "../dllexport.h" #include export module b:p1; export LIB_EXPORT void b_p1() { std::cout << "hello from b.part1\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-b/b.cpp0000644000175100001660000000035614776170045026060 0ustar runnerdocker module; #include module b; import :p1; import :p2; import a; void b() { b_p1(); b_p2(); std::cout << "hello from module b\n"; // these are also visible as they are public in module a a_p1(); a(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-a/0000755000175100001660000000000014776170045025126 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-a/a.cppm0000644000175100001660000000041714776170045026231 0ustar runnerdocker module; #include "../dllexport.h" #include // workaround for gcc bug export module a; import :p2; // private partition export import :p1; // public partition export LIB_EXPORT void a() { a_p1(); a_p2(); std::cout << "hello from module a\n"; }qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-a/a.p1.cppm0000644000175100001660000000023014776170045026541 0ustar runnerdockermodule; #include "../dllexport.h" #include export module a:p1; export LIB_EXPORT void a_p1() { std::cout << "hello from a.part1\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/lib-a/a.p2.cppm0000644000175100001660000000021214776170045026542 0ustar runnerdocker module; #include "../dllexport.h" #include module a:p2; LIB_EXPORT void a_p2() { std::cout << "hello from a.part2\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-lib/partitions-library.qbs0000644000175100001660000000550014776170045030507 0ustar runnerdocker// Checks two modules split into partitions, one depends on the other Project { DynamicLibrary { condition: { if (qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } name: "liba" Depends { name: "cpp" } files: [ "dllexport.h", "lib-a/a.cppm", "lib-a/a.p1.cppm", "lib-a/a.p2.cppm", ] install: true cpp.defines: "LIB_DYNAMIC" cpp.rpaths: cpp.rpathOrigin cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true Depends { name: "bundle" } bundle.isBundle: false } DynamicLibrary { condition: { if (qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } name: "libb" Depends { name: "cpp" } Depends { name: "liba" } files: [ "dllexport.h", "lib-b/b.cpp", "lib-b/b.cppm", "lib-b/b.p1.cppm", "lib-b/b.p2.cppm", ] install: true cpp.defines: "LIB_DYNAMIC" cpp.rpaths: cpp.rpathOrigin cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true Depends { name: "bundle" } bundle.isBundle: false } CppApplication { name: "app" condition: { if (qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } Depends { name: "libb" } Depends { name: "liba" } consoleApplication: true files: [ "app/main.cpp" ] install: true cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/0000755000175100001660000000000014776170045025261 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/b.cppm0000644000175100001660000000017614776170045026367 0ustar runnerdockermodule; #include export module b; export import a; export void bar() { std::cout << "hello b" << std::endl; }qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/a.cppm0000644000175100001660000000014514776170045026362 0ustar runnerdocker module; #include export module a; export void foo() { std::cout << "Hello a!\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/export-import.qbs0000644000175100001660000000140014776170045030614 0ustar runnerdocker// checks that module is re-exported. in this case, that module should be added to // module map in dependent files CppApplication { condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "a.cppm", "b.cppm", "c.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/c.cppm0000644000175100001660000000017614776170045026370 0ustar runnerdockermodule; #include export module c; export import b; export void baz() { std::cout << "hello c" << std::endl; }qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/main.cpp0000644000175100001660000000007314776170045026711 0ustar runnerdockerimport c; int main() { baz(); bar(); foo(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/export-import/CMakeLists.txt0000644000175100001660000000073614776170045030027 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(export_import VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(export_import) target_sources(export_import PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES a.cppm b.cppm c.cppm ) target_sources(export_import PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(export_import PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/0000755000175100001660000000000014776170045024140 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/b.cppm0000644000175100001660000000007614776170045025245 0ustar runnerdocker export module b; import a; export void bar() { foo(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/a.cppm0000644000175100001660000000015114776170045025236 0ustar runnerdocker module; #include export module a; export void foo() { std::cout << "Hello world!\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/dependent-modules.qbs0000644000175100001660000000131514776170045030263 0ustar runnerdocker// check the (private) dependency chain between modules CppApplication { name: "dep-mods" condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "a.cppm", "b.cppm", "c.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/c.cppm0000644000175100001660000000007614776170045025246 0ustar runnerdocker export module c; import b; export void baz() { bar(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/main.cpp0000644000175100001660000000004514776170045025567 0ustar runnerdockerimport c; int main() { baz(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/dep-mods/CMakeLists.txt0000644000175100001660000000076214776170045026705 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(dependent_modules VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(dependent_modules) target_sources(dependent_modules PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES a.cppm b.cppm c.cppm ) target_sources(dependent_modules PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(dependent_modules PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/0000755000175100001660000000000014776170045024624 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/a.cppm0000644000175100001660000000031414776170045025723 0ustar runnerdocker module; #include export module a; import :p2; // private partition export import :p1; // public partition export void baz() { foo(); bar(); std::cout << "baz from module\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/partitions.qbs0000644000175100001660000000127114776170045027530 0ustar runnerdocker// Checks module split into partitions CppApplication { condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "a.cppm", "a.p1.cppm", "a.p2.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/a.p1.cppm0000644000175100001660000000015614776170045026246 0ustar runnerdocker module; #include export module a:p1; export void foo() { std::cout << "foo from part1\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/main.cpp0000644000175100001660000000006014776170045026250 0ustar runnerdockerimport a; int main() { foo(); baz(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/CMakeLists.txt0000644000175100001660000000072514776170045027370 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(partitions VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(partitions) target_sources(partitions PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES a.p1.cppm a.p2.cppm a.cppm ) target_sources(partitions PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(partitions PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/partitions/a.p2.cppm0000644000175100001660000000014014776170045026240 0ustar runnerdocker module; #include module a:p2; void bar() { std::cout << "bar from part2\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/0000755000175100001660000000000014776170045024644 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/b.cppm0000644000175100001660000000021614776170045025745 0ustar runnerdocker module; #include export module b; export import :p; export void baz() { bar(); std::cout << "hello from module b\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/b.p.cppm0000644000175100001660000000020314776170045026177 0ustar runnerdocker module; #include export module b:p; import a; export void bar() { foo(); std::cout << "hello from b.p\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/a.cppm0000644000175100001660000000016014776170045025742 0ustar runnerdocker module; #include export module a; export void foo() { std::cout << "hello from module a\n"; } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/partitions-dependency-on-module.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/partitions-dependency-on-module.q0000644000175100001660000000134114776170045033232 0ustar runnerdocker// Checks that module partiton can depend on other modules CppApplication { name: "part-depmod" condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "a.cppm", "b.cppm", "b.p.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/main.cpp0000644000175100001660000000004514776170045026273 0ustar runnerdockerimport b; int main() { baz(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/part-depmod/CMakeLists.txt0000644000175100001660000000072114776170045027404 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(partitions VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(partitions) target_sources(partitions PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES a.cppm b.cppm b.p.cppm ) target_sources(partitions PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(partitions PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/decl-impl/0000755000175100001660000000000014776170045024276 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/decl-impl/hello.cppm0000644000175100001660000000013114776170045026255 0ustar runnerdockerexport module helloworld; export void helloImpl(); export void hello() { helloImpl(); }qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/decl-impl/main.cpp0000644000175100001660000000006014776170045025722 0ustar runnerdockerimport helloworld; int main() { hello(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/decl-impl/CMakeLists.txt0000644000175100001660000000103114776170045027031 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(declaration_implementation VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(declaration_implementation) target_sources(declaration_implementation PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES hello.cppm ) target_sources(declaration_implementation PRIVATE hello.cpp main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(declaration_implementation PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/decl-impl/hello.cpp0000644000175100001660000000015114776170045026102 0ustar runnerdockermodule; #include module helloworld; void helloImpl() { std::cout << "Hello world!\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/decl-impl/declaration-implementation.qbs0000644000175100001660000000137114776170045032317 0ustar runnerdocker// Checks that module can be split into a declaration module and good old cpp implementation file CppApplication { name: "decl-impl" condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "hello.cppm", "hello.cpp", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/single-mod/0000755000175100001660000000000014776170045024466 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/single-mod/hello.cppm0000644000175100001660000000016414776170045026453 0ustar runnerdockermodule; #include export module helloworld; export void hello() { std::cout << "Hello world!\n"; } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/single-mod/single-module.qbs0000644000175100001660000000125714776170045027746 0ustar runnerdocker// Checks simple case with a single module. CppApplication { name: "single-mod" condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "hello.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/single-mod/main.cpp0000644000175100001660000000006014776170045026112 0ustar runnerdockerimport helloworld; int main() { hello(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/cxx-modules/single-mod/CMakeLists.txt0000644000175100001660000000071414776170045027230 0ustar runnerdockercmake_minimum_required(VERSION 3.29) project(single_module VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) add_executable(single_module) target_sources(single_module PRIVATE FILE_SET all_my_modules TYPE CXX_MODULES BASE_DIRS ${PROJECT_SOURCE_DIR} FILES hello.cppm ) target_sources(single_module PRIVATE main.cpp ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(single_module PRIVATE "-fmodules-ts") endif() qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-and-prefix-headers/0000755000175100001660000000000014776170045026127 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-and-prefix-headers/pch.h0000644000175100001660000000233314776170045027053 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-and-prefix-headers/prefix.h0000644000175100001660000000233314776170045027576 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-and-prefix-headers/main.cpp0000644000175100001660000000235214776170045027561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-and-prefix-headers/precompiled-and-prefix-headers.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/precompiled-and-prefix-headers/precompiled-and-prefix-hea0000644000175100001660000000037414776170045033147 0ustar runnerdockerCppApplication { name: "MyApp" consoleApplication: true cpp.includePaths: [product.buildDirectory] cpp.prefixHeaders: [ "prefix.h" ] Group { files: ["pch.h"] fileTags: ["cpp_pch_src"] } files: ["main.cpp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/probe-change-tracking/0000755000175100001660000000000014776170045024312 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/probe-change-tracking/probe-change-tracking.qbs0000644000175100001660000000177014776170045031160 0ustar runnerdockerProject { Probe { id: tlpProbe property int confValue configure: { console.info("running tlpProbe"); confValue = 5; } } property int tlpCount: tlpProbe.confValue Project { Probe { id: subProbe property int confValue configure: { console.info("running subProbe"); confValue = 7; } } property int subCount: subProbe.confValue Product { name: "theProduct" property bool runProbe property int v1: project.tlpCount property int v2: project.subCount Probe { id: productProbe condition: product.runProbe property int v1: product.v1 property int v2: product.v2 configure: { console.info("running productProbe: " + (v1 + v2)); } } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/localDeployment/0000755000175100001660000000000014776170045023313 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/localDeployment/localDeployment.qbs0000644000175100001660000000133014776170045027152 0ustar runnerdockerimport qbs.Host Project { Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } type: ["application"] consoleApplication: true name: "HelloWorld" destinationDirectory: "bin" Depends { name: "cpp" } cpp.cxxLanguageVersion: "c++11" Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "bin" } Group { qbs.install: true qbs.installDir: "share" files: ['main.cpp'] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/localDeployment/main.cpp0000644000175100001660000000357414776170045024754 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include int main(int argc, char *argv[]) { if (argc != 1) return 1; std::string s = argv[0]; for (auto &c : s) { if (c == '\\') c = '/'; } const std::string mainFilePath = std::string(s.substr(0, s.find_last_of("/")) + "/../share/main.cpp"); std::ifstream in(mainFilePath.c_str()); if (!in.is_open()) { std::cerr << "Failed to open file: " << mainFilePath; return 1; } std::string str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); std::cout << str << std::endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-non-required-inputs/0000755000175100001660000000000014776170045026026 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-non-required-inputs/c.inp0000644000175100001660000000000014776170045026746 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-non-required-inputs/a.inp0000644000175100001660000000000014776170045026744 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-non-required-inputs/b.inp0000644000175100001660000000000014776170045026745 0ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inpu0000644000175100001660000000200414776170045033244 0ustar runnerdockerimport qbs.TextFile Product { name: "p" type: ["p.out"] property bool enableTagger FileTagger { condition: enableTagger patterns: ["*.inp"] fileTags: ["p.in"] } Rule { multiplex: true requiresInputs: false inputs: ["p.in"] Artifact { filePath: "output.txt" fileTags: ["p.out"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.write('('); var inputsList = inputs["p.in"]; if (inputsList) { for (var i = 0; i < inputsList.length; ++i) f.write(inputsList[i].fileName + ','); } f.write(')'); }; return [cmd]; } } files: ["a.inp", "b.inp", "c.inp"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/0000755000175100001660000000000014776170045024757 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/setup-build-environment.qbs0000644000175100001660000000032214776170045032262 0ustar runnerdockerProject { Product { name: "first_product" Depends { name: "buildenv" } Depends { name: "m" } } Product { name: "second_product" Depends { name: "m" } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/modules/0000755000175100001660000000000014776170045026427 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/modules/m/0000755000175100001660000000000014776170045026663 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/modules/m/m.qbs0000644000175100001660000000130014776170045027620 0ustar runnerdockerimport qbs.Environment import qbs.TextFile Module { additionalProductTypes: ["m.target"] Rule { multiplex: true Artifact { filePath: "m.output" fileTags: "m.target" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "creating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); var env = Environment.getEnv("BUILD_ENV_" + product.name.toUpperCase()); if (env) f.writeLine(env); f.close(); }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/modules/buildenv/0000755000175100001660000000000014776170045030237 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/setup-build-environment/modules/buildenv/buildenv.qbs0000644000175100001660000000031414776170045032554 0ustar runnerdockerimport qbs.Environment Module { property string varPrefix: "BUILD_ENV_" setupBuildEnvironment: { Environment.putEnv(product.buildenv.varPrefix + product.name.toUpperCase(), "1"); } } qbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-changes/0000755000175100001660000000000014776170045023421 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-changes/dummy.txt0000644000175100001660000000000014776170045025303 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/multiple-changes/multiple-changes.qbs0000644000175100001660000000140114776170045027365 0ustar runnerdockerProject { property bool prop: false Product { name: "test" type: ["out-type"] Group { name: "Rule input" files: ["dummy.txt"] fileTags: ["in-type"] } Group { name: "irrelevant" files: ["*.blubb"] } Rule { inputs: ["in-type"] Artifact { filePath: "dummy.out" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { console.info("prop: " + project.prop); } return [cmd]; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/0000755000175100001660000000000014776170045025576 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/0000755000175100001660000000000014776170045026363 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/0000755000175100001660000000000014776170045030033 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/0000755000175100001660000000000014776170045030556 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs0000644000175100001660000000001214776170045032063 0ustar runnerdockerGroup { } qbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs0000644000175100001660000000004014776170045032063 0ustar runnerdockerModule { condition: false } qbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp0000644000175100001660000000003114776170045027220 0ustar runnerdockerint main() { return 0; } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken0000644000175100001660000000013714776170045033140 0ustar runnerdockerCppApplication { qbsSearchPaths: "qbs" Depends { name: "Foo" } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/installed-source-files/0000755000175100001660000000000014776170045024535 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/installed-source-files/readme.txt0000644000175100001660000000002614776170045026531 0ustar runnerdockerimportant information qbs-src-2.6.1/tests/auto/blackbox/testdata/installed-source-files/installed-source-files.qbs0000644000175100001660000000062714776170045031626 0ustar runnerdockerCppApplication { consoleApplication: true files: ["main.cpp"] qbs.installPrefix: "" Group { fileTagsFilter: ["cpp"] qbs.install: true } Group { // this overwrites the properties of the group below fileTagsFilter: ["text"] qbs.install: true } Group { files: ["readme.txt"] fileTags: ["text"] qbs.install: false } } qbs-src-2.6.1/tests/auto/blackbox/testdata/installed-source-files/main.cpp0000644000175100001660000000236414776170045026172 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/0000755000175100001660000000000014776170045025621 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/app/0000755000175100001660000000000014776170045026401 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs0000644000175100001660000000010514776170045027664 0ustar runnerdockerCppApplication { Depends { name: "lib" } files: "main.cpp" } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h0000644000175100001660000000002114776170045027323 0ustar runnerdocker#include "lib.h" qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp0000644000175100001660000000004114776170045030024 0ustar runnerdocker#include "app.h" int main() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/0000755000175100001660000000000014776170045026367 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h0000644000175100001660000000003614776170045027305 0ustar runnerdocker#pragma once void lib1_foo();qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs0000644000175100001660000000021514776170045027642 0ustar runnerdockerProduct { files: "lib.h" Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.sourceDirectory } } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs0000644000175100001660000000015514776170045026570 0ustar runnerdockerProject { references: [ "app/app.qbs", "lib/lib.qbs", "other/other.qbs", ] } qbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/other/0000755000175100001660000000000014776170045026742 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs0000644000175100001660000000107714776170045030577 0ustar runnerdockerimport qbs.TextFile Product { type: "testproduct" files: "../lib/lib.h" Rule { multiplex: true Artifact { fileTags: ["testproduct"] filePath: "fubar" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating text file"; cmd.sourceCode = function() { var tf = new TextFile(output.filePath, TextFile.WriteOnly); tf.writeLine("blubb"); tf.close(); } return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/0000755000175100001660000000000014776170045023631 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/exports-pkgconfig.qbs0000644000175100001660000000756214776170045030023 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { Product { name: "dummy" Export { Depends { name: "TheFirstLib" } } } Product { name: "SomeHelper" Depends { name: "Exporter.pkgconfig" } Exporter.pkgconfig.versionEntry: "1.0" } StaticLibrary { Depends { name: "cpp" } name: "BoringStaticLib" files: ["boringstaticlib.cpp"] Export { Depends { name: "cpp" } cpp.defines: ["HAVE_INDUSTRIAL_STRENGTH_HAIR_DRYER"] } } DynamicLibrary { name: "TheFirstLib" version: "1.0" Depends { name: "SomeHelper" } Depends { name: "Exporter.pkgconfig" } Exporter.pkgconfig.excludedDependencies: ["Qt.core", "helper3"] Exporter.pkgconfig.requiresEntry: "Qt5Core" Exporter.pkgconfig.urlEntry: "http://www.example.com/thefirstlib" Depends { name: "cpp" } cpp.defines: ["FIRSTLIB"] qbs.installPrefix: "/opt/the firstlib" Export { prefixMapping: [{prefix: "/somedir", replacement: "/otherdir"}] Depends { name: "BoringStaticLib" } Depends { name: "cpp" } Depends { name: "Qt.core"; required: false } Depends { name: "helper1" } Depends { name: "helper3" } property bool someCondition: Host.os().includes("windows") // hostOS for easier testing property bool someOtherCondition: someCondition Properties { condition: !someOtherCondition cpp.driverFlags: ["-pthread"] } cpp.defines: exportingProduct.name cpp.includePaths: [FileInfo.joinPaths(exportingProduct.qbs.installPrefix, "include")] Qt.core.mocName: "muck" } Group { fileTagsFilter: ["dynamiclibrary", "dynamiclibrary_import"] qbs.install: true qbs.installDir: "lib" } Group { name: "api_headers" files: ["firstlib.h"] qbs.install: true qbs.installDir: "include" } files: ["firstlib.cpp"] } DynamicLibrary { name: "TheSecondLib" version: "2.0" Depends { name: "Exporter.pkgconfig" } Exporter.pkgconfig.descriptionEntry: "The second lib" Exporter.pkgconfig.transformFunction: (function(product, moduleName, propertyName, value) { if (moduleName === "cpp" && propertyName === "includePaths") return value.filter(function(p) { return p !== product.sourceDirectory; }); return value; }) Exporter.pkgconfig.customVariables: ({config1: "a b", config2: "c"}) Depends { name: "cpp" } cpp.defines: ["SECONDLIB"] qbs.installPrefix: "" Depends { name: "TheFirstLib" } Export { Depends { name: "TheFirstLib" } Depends { name: "dummy" } Depends { name: "cpp" } cpp.includePaths: [ "/opt/thesecondlib/include", exportingProduct.sourceDirectory, importingProduct.buildDirectory ] property string hurz: importingProduct.name cpp.defines: hurz.toUpperCase() Rule { property int n: 5 Artifact { filePath: "dummy" fileTags: ["d1", "d2"] cpp.warningsAreErrors: true } } } Group { fileTagsFilter: ["dynamiclibrary", "dynamiclibrary_import"] qbs.install: true qbs.installDir: "/opt/thesecondlib/lib" } Group { name: "api_headers" files: ["secondlib.h"] qbs.install: true qbs.installDir: "/opt/thesecondlib/include" } files: ["secondlib.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/TheFirstLib_windows.pc0000644000175100001660000000051314776170045030105 0ustar runnerdockerprefix=/opt/the firstlib Name: TheFirstLib Description: TheFirstLib Version: 1.0 URL: http://www.example.com/thefirstlib Cflags: -DTheFirstLib -I"${prefix}/include" -DHAVE_INDUSTRIAL_STRENGTH_HAIR_DRYER -I/otherdir/include1 -I/otherdir/include2 Libs: -L"${prefix}/lib" -lTheFirstLib Requires: Qt5Core Requires.private: SomeHelper qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/secondlib.cpp0000644000175100001660000000020314776170045026272 0ustar runnerdocker#include "secondlib.h" #ifndef HAVE_INDUSTRIAL_STRENGTH_HAIR_DRYER # error I CANT LIVE WITHOUT IT! #endif void secondLib() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/TheSecondLib.pc0000644000175100001660000000027214776170045026461 0ustar runnerdockerconfig1=a b config2=c Name: TheSecondLib Description: The second lib Version: 2.0 Cflags: -I/opt/thesecondlib/include Libs: -L/opt/thesecondlib/lib -lTheSecondLib Requires: TheFirstLib qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/secondlib.h0000644000175100001660000000025314776170045025744 0ustar runnerdocker#include "../dllexport.h" #ifdef SECONDLIB # define SECONDLIB_EXPORT DLL_EXPORT #else # define SECONDLIB_EXPORT DLL_IMPORT #endif SECONDLIB_EXPORT void secondLib(); qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/TheFirstLib.pc0000644000175100001660000000053514776170045026337 0ustar runnerdockerprefix=/opt/the firstlib Name: TheFirstLib Description: TheFirstLib Version: 1.0 URL: http://www.example.com/thefirstlib Cflags: -DTheFirstLib -I"${prefix}/include" -pthread -DHAVE_INDUSTRIAL_STRENGTH_HAIR_DRYER -I/otherdir/include1 -I/otherdir/include2 Libs: -L"${prefix}/lib" -lTheFirstLib -pthread Requires: Qt5Core Requires.private: SomeHelper qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/boringstaticlib.cpp0000644000175100001660000000005714776170045027516 0ustar runnerdockerint calculateLuckyNumber() { return 12 * 13; } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/firstlib.h0000644000175100001660000000024614776170045025622 0ustar runnerdocker#include "../dllexport.h" #ifdef FIRSTLIB # define FIRSTLIB_EXPORT DLL_EXPORT #else # define FIRSTLIB_EXPORT DLL_IMPORT #endif FIRSTLIB_EXPORT void firstLib(); qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/firstlib.cpp0000644000175100001660000000005314776170045026151 0ustar runnerdocker#include "firstlib.h" void firstLib() { } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/0000755000175100001660000000000014776170045025301 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/helper3/0000755000175100001660000000000014776170045026643 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/helper3/helper3.qbs0000644000175100001660000000012114776170045030706 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.includePaths: "/somedir/include3" } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/helper2/0000755000175100001660000000000014776170045026642 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/helper2/helper2.qbs0000644000175100001660000000012114776170045030704 0ustar runnerdockerModule { Depends { name: "cpp" } cpp.includePaths: "/somedir/include2" } qbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/helper1/0000755000175100001660000000000014776170045026641 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/exports-pkgconfig/modules/helper1/helper1.qbs0000644000175100001660000000016114776170045030706 0ustar runnerdockerModule { Depends { name: "cpp" } Depends { name: "helper2" } cpp.includePaths: "/somedir/include1" } qbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-imported-file/0000755000175100001660000000000014776170045024547 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-imported-file/test.txt0000644000175100001660000000000014776170045026255 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-imported-file/prepare.js0000644000175100001660000000013314776170045026540 0ustar runnerdockerfunction prepare(cmd) { cmd.sourceCode = function() { console.info("old output"); }; } qbs-src-2.6.1/tests/auto/blackbox/testdata/change-in-imported-file/change-in-imported-file.qbs0000644000175100001660000000073114776170045031646 0ustar runnerdockerimport "prepare.js" as PrepareHelper Product { type: ["output"] Group { files: ["test.txt"] fileTags: ["input"] } Rule { inputs: ["input"] Artifact { filePath: "dummy" fileTags: product.type } prepare: { var cmd = new JavaScriptCommand(); PrepareHelper.prepare(cmd); cmd.description = "creating output"; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/symlink-removal/0000755000175100001660000000000014776170045023311 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/symlink-removal/symlink-removal.qbs0000644000175100001660000000057214776170045027155 0ustar runnerdockerimport qbs.File Product { type: "removal" Rule { multiplex: true outputFileTags: "removal" prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { File.remove(product.sourceDirectory + "/dir1"); }; return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/add-filetag-to-generated-artifact/0000755000175100001660000000000014776170045026470 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/add-filetag-to-generated-artifact/main.cpp0000644000175100001660000000001614776170045030115 0ustar runnerdockerint main() {} ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata/add-filetag-to-generated-artifact/add-filetag-to-generated-artifact.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata/add-filetag-to-generated-artifact/add-filetag-to-generate0000644000175100001660000000211414776170045032762 0ustar runnerdockerimport qbs.File Project { property bool enableTagging CppApplication { name: "my_app" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: "main.cpp" Group { condition: project.enableTagging fileTagsFilter: ["application"] fileTags: ["app-to-compress"] } } Product { name: "my_compressed_app" type: ["compressed_application"] Depends { name: "my_app" } Rule { inputsFromDependencies: ["app-to-compress"] Artifact { filePath: "compressed-" + input.fileName fileTags: ["compressed_application"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "compressing " + input.fileName; cmd.highlight = "linker"; cmd.sourceCode = function () { File.copy(input.filePath, output.filePath); }; return cmd; } } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/0000755000175100001660000000000014776170045022703 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/after/0000755000175100001660000000000014776170045024004 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/after/trackFileTags.qbs0000644000175100001660000000345514776170045027245 0ustar runnerdockerimport qbs.TextFile import qbs.Host Project { Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: 'someapp' type: 'application' consoleApplication: true property bool dummy: { console.info("object suffix: " + cpp.objectSuffix); } Depends { name: 'cpp' } Group { files: [ "main.cpp" ] fileTags: [ "foosource", "cpp" ] } } Rule { inputs: ["foosource"] Artifact { filePath: input.baseName + ".foo" fileTags: ["foo"] } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = "var file = new TextFile(output.filePath, TextFile.WriteOnly);"; cmd.sourceCode += "file.truncate();" cmd.sourceCode += "file.write(\"There's nothing to see here!\");" cmd.sourceCode += "file.close();" cmd.description = "generating something"; return cmd; } } Rule { inputs: ["foo"] Artifact { filePath: input.baseName + "_foo.cpp" fileTags: ["cpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = "var file = new TextFile(output.filePath, TextFile.WriteOnly);"; cmd.sourceCode += "file.truncate();"; cmd.sourceCode += "file.write(\"// There's nothing to see here!\\n\");"; cmd.sourceCode += "file.write(\"int foo() { return 15; }\\n\");"; cmd.sourceCode += "file.close();"; cmd.description = "generating something"; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/after/main.cpp0000644000175100001660000000253514776170045025441 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int foo(); int main(int argc, char **argv) { std::printf("there's %d foo here\n", foo()); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/before/0000755000175100001660000000000014776170045024145 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/before/trackFileTags.qbs0000644000175100001660000000344014776170045027400 0ustar runnerdockerimport qbs.TextFile import qbs.Host Project { Product { condition: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } name: 'someapp' type: 'application' consoleApplication: true property bool dummy: { console.info("object suffix: " + cpp.objectSuffix); } Depends { name: 'cpp' } Group { files: [ "main.cpp" ] fileTags: [ "cpp" ] } } Rule { inputs: ["foosource"] Artifact { filePath: input.baseName + ".foo" fileTags: ["foo"] } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = "var file = new TextFile(output.filePath, TextFile.WriteOnly);"; cmd.sourceCode += "file.truncate();" cmd.sourceCode += "file.write(\"There's nothing to see here!\");" cmd.sourceCode += "file.close();" cmd.description = "generating something"; return cmd; } } Rule { inputs: ["foo"] Artifact { filePath: input.baseName + "_foo.cpp" fileTags: ["cpp"] } prepare: { var cmd = new JavaScriptCommand(); cmd.sourceCode = "var file = new TextFile(output.filePath, TextFile.WriteOnly);"; cmd.sourceCode += "file.truncate();"; cmd.sourceCode += "file.write(\"// There's nothing to see here!\\n\");"; cmd.sourceCode += "file.write(\"int foo() { return 15; }\\n\");"; cmd.sourceCode += "file.close();"; cmd.description = "generating something"; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/trackFileTags/before/main.cpp0000644000175100001660000000251214776170045025575 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main(int argc, char **argv) { std::printf("there's no foo here\n"); return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata/bom-sources/0000755000175100001660000000000014776170045022416 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/bom-sources/bom-sources.qbs0000644000175100001660000000011214776170045025355 0ustar runnerdockerCppApplication { name: "app" files: ["main.cpp", "theheader.h"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/bom-sources/theheader.h0000644000175100001660000000000014776170045024506 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/bom-sources/main.cpp0000644000175100001660000000005114776170045024042 0ustar runnerdocker#include "theheader.h" int main() {} qbs-src-2.6.1/tests/auto/blackbox/testdata/productproperties/0000755000175100001660000000000014776170045023755 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/productproperties/header.qbs0000644000175100001660000000160714776170045025720 0ustar runnerdockerimport qbs.TextFile Product { name: "blubb_header" type: "hpp" files: "blubb_header.h.in" property string blubbProp: project.blubbProp Rule { multiplex: true Artifact { filePath: "blubb_header.h" fileTags: "hpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating blubb_header.h"; cmd.highlight = "codegen"; cmd.blubbProp = product.blubbProp; cmd.sourceCode = function() { file = new TextFile(output.filePath, TextFile.WriteOnly); file.truncate(); file.write("#define BLUBB_PROP " + blubbProp); file.close(); } return cmd; } } Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.buildDirectory } } qbs-src-2.6.1/tests/auto/blackbox/testdata/productproperties/app.qbs0000644000175100001660000000041314776170045025242 0ustar runnerdockerProduct { consoleApplication: true type: "application" name: "blubb_user" property bool dummy: { console.info("executable suffix: " + cpp.executableSuffix); } files: "main.cpp" Depends { name: "blubb_header" } Depends { name: "cpp" } } qbs-src-2.6.1/tests/auto/blackbox/testdata/productproperties/blubb_header.h.in0000644000175100001660000000000014776170045027117 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/productproperties/main.cpp0000644000175100001660000000245514776170045025413 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "blubb_header.h" int main() { #if BLUBB_PROP != 5 blubb(); #endif } qbs-src-2.6.1/tests/auto/blackbox/testdata/productproperties/productproperties.qbs0000644000175100001660000000013114776170045030254 0ustar runnerdockerProject { property string blubbProp: "5" references: ["header.qbs", "app.qbs"] } qbs-src-2.6.1/tests/auto/blackbox/testdata/generator/0000755000175100001660000000000014776170045022146 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/generator/input.file1.txt0000644000175100001660000000001214776170045025036 0ustar runnerdockerfile1.cpp qbs-src-2.6.1/tests/auto/blackbox/testdata/generator/input.none.txt0000644000175100001660000000000014776170045024772 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/generator/input.both.txt0000644000175100001660000000002414776170045024775 0ustar runnerdockerfile1.cpp file2.cpp qbs-src-2.6.1/tests/auto/blackbox/testdata/generator/input.file2.txt0000644000175100001660000000001214776170045025037 0ustar runnerdockerfile2.cpp qbs-src-2.6.1/tests/auto/blackbox/testdata/generator/main.cpp0000644000175100001660000000007214776170045023575 0ustar runnerdockervoid f1(); void f2(); int main() { f1(); f2(); } qbs-src-2.6.1/tests/auto/blackbox/testdata/generator/generator.qbs0000644000175100001660000000230214776170045024640 0ustar runnerdockerimport qbs.TextFile CppApplication { name: "app" files: "main.cpp" Group { files: "input.txt" fileTags: "generator.in" } Rule { inputs: ["generator.in"] Artifact { filePath: "file1.cpp"; fileTags: ["cpp", "file1"]; alwaysUpdated: false } Artifact { filePath: "file2.cpp"; fileTags: ["cpp", "file2"]; alwaysUpdated: false } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "potentially generating files"; cmd.sourceCode = function() { var f = new TextFile(input.filePath, TextFile.ReadOnly); var content = f.readAll(); f.close(); if (content.includes("file1")) { f = new TextFile(outputs.file1[0].filePath, TextFile.WriteOnly); f.writeLine("void f1() {}"); f.close(); } if (content.includes("file2")) { f = new TextFile(outputs.file2[0].filePath, TextFile.WriteOnly); f.writeLine("void f2() {}"); f.close(); } }; return cmd; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/0000755000175100001660000000000014776170045022366 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/foo2.ts0000644000175100001660000000000114776170045023572 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/main.ts0000644000175100001660000000102314776170045023656 0ustar runnerdockerimport Animals = require("./animals"); import Foo = require("./foo"); import Extra = require("./woosh/extra"); function main() { var mammals: Animals.Mammal[] = []; mammals.push(new Animals.Human()); mammals.push(new Animals.Dog()); mammals.push(new Animals.Cat()); // Make everyone speak for (var i = 0; i < mammals.length; ++i) { console.log(mammals[i].speak()); } (new Extra.Boom()); var greeting: string = (new Foo.Greeter()).getGreeting(); console.log(greeting); } main(); qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/extra.js0000644000175100001660000000010614776170045024044 0ustar runnerdockerif (console) { console.log("This doesn't do anything useful!"); } qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/woosh/0000755000175100001660000000000014776170045023525 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/woosh/extra.ts0000644000175100001660000000002614776170045025216 0ustar runnerdockerexport class Boom { } qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/foo.ts0000644000175100001660000000013714776170045023522 0ustar runnerdockerexport class Greeter { public getGreeting(): string { return "guten Tag!"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/animals.ts0000644000175100001660000000055014776170045024362 0ustar runnerdockerexport interface Mammal { speak(): string; } export class Cat implements Mammal { public speak() { return "Meow"; // a cat says meow } } export class Dog implements Mammal { public speak() { return "Woof"; // a dog says woof } } export class Human implements Mammal { public speak() { return "Hello"; } } qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/hello.ts0000644000175100001660000000003514776170045024037 0ustar runnerdockerconsole.log("Hello world!"); qbs-src-2.6.1/tests/auto/blackbox/testdata/typescript/typescript.qbs0000644000175100001660000000200514776170045025300 0ustar runnerdockerProject { NodeJSApplication { Depends { name: "typescript" } Depends { name: "lib" } typescript.warningLevel: "pedantic" typescript.generateDeclarations: true typescript.moduleLoader: "commonjs" nodejs.applicationFile: "main.ts" name: "animals" files: [ "animals.ts", "extra.js", "woosh/extra.ts" ] } Product { Depends { name: "typescript" } typescript.generateDeclarations: true typescript.moduleLoader: "commonjs" name: "lib" files: [ "foo.ts" ] } Product { Depends { name: "typescript" } typescript.generateDeclarations: true name: "lib2" files: [ "foo2.ts" ] } NodeJSApplication { Depends { name: "typescript" } Depends { name: "lib2" } typescript.singleFile: true nodejs.applicationFile: "hello.ts" name: "single" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-joblimits/0000755000175100001660000000000014776170045022152 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-joblimits/job-limits-init/0000755000175100001660000000000014776170045025164 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-joblimits/job-limits-init/job-limits-init.qbs0000644000175100001660000000036514776170045030711 0ustar runnerdockerimport qbs.Host Product { property bool _testPlatform: { var result = qbs.targetPlatform === Host.platform(); if (!result) console.info("targetPlatform differs from hostPlatform"); return result; } } qbs-src-2.6.1/tests/auto/blackbox/testdata-joblimits/job-limits/0000755000175100001660000000000014776170045024223 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-joblimits/job-limits/job-limits.qbs0000644000175100001660000000610714776170045027007 0ustar runnerdockerimport qbs.TextFile Project { property int projectJobCount property int productJobCount property int moduleJobCount JobLimit { condition: projectJobCount !== -1 jobPool: "singleton" jobCount: projectJobCount } JobLimit { condition: projectJobCount !== -1 jobPool: "singleton" jobCount: 100 } CppApplication { name: "tool" consoleApplication: true cpp.cxxLanguageVersion: "c++14" Properties { condition: qbs.targetOS.includes("macos") cpp.minimumMacosVersion: "10.9" } files: "main.cpp" Group { fileTagsFilter: "application" fileTags: "tool_tag" } Export { Rule { alwaysRun: true inputs: "tool_in" explicitlyDependsOnFromDependencies: "tool_tag" Artifact { filePath: input.completeBaseName + ".out"; fileTags: "tool_out" } prepare: { var cmd = new Command(explicitlyDependsOn.tool_tag[0].filePath, [output.filePath]); cmd.workingDirectory = product.buildDirectory; cmd.description = "running tool"; cmd.jobPool = "singleton"; return cmd; } } JobLimit { condition: project.moduleJobCount !== -1 jobPool: "singleton" jobCount: project.moduleJobCount } JobLimit { condition: project.moduleJobCount !== -1 jobPool: "singleton" jobCount: 200 } } } Product { name: "p" type: "tool_out" Depends { name: "tool" } Rule { multiplex: true outputFileTags: "tool_in" outputArtifacts: { var artifacts = []; for (var i = 0; i < 5; ++i) artifacts.push({filePath: "file" + i + ".in", fileTags: "tool_in"}); return artifacts; } prepare: { var commands = []; for (var i = 0; i < outputs.tool_in.length; ++i) { var cmd = new JavaScriptCommand(); var output = outputs.tool_in[i]; cmd.output = output.filePath; cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output, TextFile.WriteOnly); f.close(); } commands.push(cmd); }; return commands; } } JobLimit { condition: project.productJobCount !== -1 jobPool: "singleton" jobCount: project.productJobCount } JobLimit { condition: project.productJobCount !== -1 jobPool: "singleton" jobCount: 300 } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-joblimits/job-limits/main.cpp0000644000175100001660000000533114776170045025655 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #if defined(_WIN32) || defined(WIN32) #include #include #else #include #endif static bool tryLock(FILE *f) { const int exitCode = #if defined(_WIN32) || defined(WIN32) _locking(_fileno(f), _LK_NBLCK, 10); #else lockf(fileno(f), F_TLOCK, 10); #endif return exitCode == 0; } int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << "tool needs exactly one argument" << std::endl; return 1; } const std::string lockFilePath = std::string(argv[0]) + ".lock"; std::FILE * const lockFile = std::fopen(lockFilePath.c_str(), "w"); if (!lockFile) { std::cerr << "cannot open lock file: " << std::strerror(errno) << std::endl; return 2; } if (!tryLock(lockFile)) { if (errno == EACCES || errno == EAGAIN) { std::cerr << "tool is exclusive" << std::endl; return 3; } else { std::cerr << "unexpected lock failure: " << std::strerror(errno) << std::endl; std::fclose(lockFile); return 4; } } std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::fclose(lockFile); std::FILE * const output = std::fopen(argv[1], "w"); if (!output) { std::cerr << "cannot create output file: " << std::strerror(errno) << std::endl; return 5; } std::fclose(output); } qbs-src-2.6.1/tests/auto/blackbox/CMakeLists.txt0000644000175100001660000000376014776170045021115 0ustar runnerdockeradd_qbs_test(blackbox DEFINES ${QBS_UNIT_TESTS_DEFINES} "QBS_VERSION=\"${QBS_VERSION}\"" SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackbox.cpp tst_blackbox.h ) add_qbs_test(blackbox-android SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxandroid.cpp tst_blackboxandroid.h ) add_qbs_test(blackbox-apple SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxapple.cpp tst_blackboxapple.h ) add_qbs_test(blackbox-baremetal SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxbaremetal.cpp tst_blackboxbaremetal.h ) add_qbs_test(blackbox-clangdb SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_clangdb.cpp tst_clangdb.h ) add_qbs_test(blackbox-java SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxjava.cpp tst_blackboxjava.h ) add_qbs_test(blackbox-joblimits SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxjoblimits.cpp ) add_qbs_test(blackbox-providers SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxproviders.cpp ) add_qbs_test(blackbox-qt SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxqt.cpp tst_blackboxqt.h ) add_qbs_test(blackbox-tutorial SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxtutorial.h tst_blackboxtutorial.cpp ) add_qbs_test(blackbox-windows SOURCES ../shared.h tst_blackboxbase.cpp tst_blackboxbase.h tst_blackboxwindows.cpp tst_blackboxwindows.h ) qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxtutorial.cpp0000644000175100001660000000511514776170045023320 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "tst_blackboxtutorial.h" #include #include static QStringList collectProjects(const QString &dirPath) { QStringList result; QDir dir(dirPath); const auto subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); for (const auto &subDir : subDirs) { const auto path = dir.filePath(subDir); if (!QFileInfo::exists(path + "/myproject.qbs")) continue; result.append(dir.relativeFilePath(path)); } return result; } TestBlackboxTutorial::TestBlackboxTutorial() : TestBlackboxBase(SRCDIR "/../../../tutorial/", "blackbox-tutorial") {} void TestBlackboxTutorial::tutorial_data() { QTest::addColumn("project"); const auto projects = collectProjects(testDataDir); for (const auto &project : projects) { QTest::newRow(project.toUtf8().data()) << project; } } void TestBlackboxTutorial::tutorial() { QFETCH(QString, project); QVERIFY(QDir::setCurrent(testDataDir + "/" + project)); QCOMPARE(runQbs(), 0); } QTEST_MAIN(TestBlackboxTutorial) qbs-src-2.6.1/tests/auto/blackbox/blackbox-java.qbs0000644000175100001660000000077114776170045021567 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-java" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-java/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxjava.cpp", "tst_blackboxjava.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/0000755000175100001660000000000014776170045021257 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/embedInfoPlist/0000755000175100001660000000000014776170045024163 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/embedInfoPlist/embedInfoPlist.qbs0000644000175100001660000000236614776170045027605 0ustar runnerdockerProject { CppApplication { Depends { name: "lib" } Depends { name: "mod" } name: "app" consoleApplication: true files: ["main.m"] cpp.frameworks: ["Foundation"] cpp.rpaths: [cpp.rpathOrigin] cpp.minimumMacosVersion: "10.6" bundle.infoPlist: ({ "QBS": "org.qt-project.qbs.testdata.embedInfoPlist" }) install: true installDir: "" } DynamicLibrary { Depends { name: "cpp" } name: "lib" bundle.isBundle: false bundle.embedInfoPlist: true files: ["main.m"] cpp.frameworks: ["Foundation"] cpp.sonamePrefix: "@rpath" bundle.infoPlist: ({ "QBS": "org.qt-project.qbs.testdata.embedInfoPlist.dylib" }) install: true installDir: "" } LoadableModule { Depends { name: "cpp" } name: "mod" bundle.isBundle: false bundle.embedInfoPlist: true files: ["main.m"] cpp.frameworks: ["Foundation"] bundle.infoPlist: ({ "QBS": "org.qt-project.qbs.testdata.embedInfoPlist.bundle" }) Group { fileTagsFilter: product.type qbs.install: true } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/embedInfoPlist/main.m0000644000175100001660000000053614776170045025271 0ustar runnerdocker#import int main() { NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary]; BOOL success = [[infoPlist objectForKey:@"QBS"] isEqualToString:@"org.qt-project.qbs.testdata.embedInfoPlist"]; fprintf(success ? stdout : stderr, "%s\n", [[infoPlist description] UTF8String]); return success ? 0 : 1; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/deploymentTarget/0000755000175100001660000000000014776170045024606 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs0000644000175100001660000000074014776170045027476 0ustar runnerdockerCppApplication { files: ["main.c"] // Minimum deployment targets that: // - will actually link (as of Xcode 8.1) // - exist for the given architecture(s) cpp.minimumMacosVersion: qbs.architecture === "x86_64h" ? "10.12" : "10.6" cpp.minimumIosVersion: ["armv7s", "arm64", "x86_64"].includes(qbs.architecture) ? "7.0" : "6.0" cpp.minimumTvosVersion: "9.0" cpp.minimumWatchosVersion: "2.0" cpp.driverFlags: ["-v"] cpp.linkerFlags: ["-v"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/deploymentTarget/main.c0000644000175100001660000000236414776170045025703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/0000755000175100001660000000000014776170045025051 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/ByteArray-Info.plist0000644000175100001660000000054614776170045030726 0ustar runnerdocker DataKey VGhlIGRhdGEgdmFsdWU= StringKey The string value qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/byteArrayInfoPlist.qbs0000644000175100001660000000223214776170045031351 0ustar runnerdockerimport qbs.BundleTools import qbs.TextFile CppApplication { Depends { name: "bundle" } cpp.minimumMacosVersion: "10.7" files: ["main.c", "ByteArray-Info.plist"] type: base.concat(["txt_output"]) Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: true bundle.identifierPrefix: "com.test" } Rule { inputs: ["aggregate_infoplist"] Artifact { filePath: input.fileName + ".out" fileTags: ["txt_output"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating" + output.fileName + " from " + input.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var plist = new BundleTools.infoPlistContents(input.filePath); var content = plist["DataKey"]; var int8view = new Uint8Array(content); file = new TextFile(output.filePath, TextFile.WriteOnly); file.write(String.fromCharCode.apply(null, int8view)); file.close(); } return [cmd]; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/byteArrayInfoPlist/main.c0000644000175100001660000000003114776170045026133 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/0000755000175100001660000000000014776170045021651 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/0000755000175100001660000000000014776170045024016 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/0000755000175100001660000000000014776170045027657 5ustar runnerdocker././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000755000175100001660000000000014776170045033111 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/216.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000003672714776170045033132 0ustar runnerdockerPNG  IHDR -sRGBDeXIfMM*iؠ3j=AIDATx]|tB]Jo"M:H QĆ +ұQ{z wus\ٻr{3oٙ7 NO('B54`4|H 0W)y@S!quњ`4|H 0׹n޼I͈3eBwR 䣞eʔI!J|رTRƌ\ 1\")t)惾` BkAKmݺuF=zW_}ׯOӦM|6}6(R^wI>|8}t5PRwߥ o LB`^Ge)_ӰaѣCR&SO=Eo,YRC j h9sf)i޼y[oц 70əV.\L>,e˖F`;t Xv!C2hHƚ5k;CݻwlxXgϞ#GѣetPie2zZQ@ҥgkז")%O,44OCX)j$Y͚5+=3kQb$ϒ?4<"g?kV^-w<(>,V/^^u۷J;*0&[>i 0lWc + 0ش3F ^zg6냺1~,9gΟ?O||.^(3)MB^;gA[NHw}gիWl2SX,\?~<{ti5ݜnOes+B gk R)֍7̇/_hѢiT9=g>1LSTR7|c00ձ}0 `4,bMed`03kb@;g76̾)kA+&d`Sț7 lTJwo޽*0OQ e˖1c@kb`6FFFҋ/HO<ȑC/X˙ @;wKaN/({2h^|#ЪUdLeo peRW\\3Mjjq_fݏ=}kFf`Mfo݁3/_駟L<FVSZfdwA>}:ۄ'HVFNլ͓' 0H8vn^Um ٫/_6x5?~hC! ıs}|Ac߾}&2I69y8sL15(`Y'6mf3e9jaBiO(3Pu Zjej@gV?L2?`6BS:LReRA.K.(>?-8%y2&nI',{mg!1SΜ94h *PdL 6cF{06ErT^EBtp>[^J3/GdtMDŽWkŕf>%= 'W׬;g.\08f ќ!s\}gDGGճdF+]n<2kҕkZʚMΜd8|yY<R h^4CBB2ؙ˨C鳟8ɉnWѴ%_Үtq,F< IFm޼z-Z͔IO1E1=7Z1Lj֬, 0uZ|H3f%s*@s/?A)QksDH;1c^e}2u -k?>:cN<dbp쉍gK6 ̛KVOx0k//ںos5[IhWK\aLlP͉׎Ѹqߧm 4'Ii>Ϟ=;OBl#V"ҐBʷ8o5}~O1ʓ+ȓ4$_$%trFdWӯ˶=Ծa5^E.QܘnZ9Rn$olYL 7*SeJ2DVPG>c5j]tI4K{q?b"z뭒ѝ9Y^6n-ݴ"gB0x$YZ 33,T\ Ш(Wt'PVJ`殤&̥)o&Ii3ƄWiʹaafTtQiWb~$_|^_ PL(͔C(@nݺs\.wIB;Z~6M[ )!)dӶGit %'I-)`>,WlC^yOΝ. ҐΙY=qjW,ETr˭0 v%pN0Ϥ$oY6PjR'0ƕtg vO{ddbF:v.3h&> u;5Iٲu0/ͬTB),<}?;%T:#]f?  ͕#\I 6҆hW(1 4N ܴYȉ3494yvA/T; _e{mK )79KZ ?_K`tf,KLti W4gUDcx4DRx`&Ŵ(;}N|v\Ǡi ж_U|3_bN˻H7H``03Ѻ]1g84YZԩ`G&Wf 4OS~K7;{c)Y! ,nb 1B["r ̧s_(ח#R>mg1CΙ~+pu!ӮxB,MZ/Y{~V#uZƪa~~._NxfL{<<+@`O:H9`ܵ; !m^ +g%? F9v*4UtU$0tJ"wX2WL 0ќч?΢M,rNhjJ$@e89B,k`?lH?83q+݆vJ:?KgfAyU浨 OJN)zcsO'lXfNz}fZl[Euiz+a?N($,W tl;Ŷӎdb:gGNˈ#u_{b1a>yqz҂ # Y :up*i0kygS!#IūfpL #m0h,e#AUg: O8iyWU@s'خy`F]_M_R@̗e=4ž4|I 0_RW {%4|I]]vS@,Y@%uuaO gM_R@̗e=4ž4|Ic= ȧN4K?5Gu}"ḁ o1]$d%B^-Q+A 0t=aKe;baRR% h$Ar%vFu*!Y{=83QD<h:^[ќGwt+GPbeik-+)h~vEf`8@P^-5Q|BU,Ao!`:ՌV"%99ԠBqYgyΔ1߼FWY Q ~+5YQhsƕFe5`,owN Cm#-T0]tMmŅ|\SS,KjeK˽!oVa".9@`:{Jb|~ٵ1U-$YZ m^ә*RAĸ襮8-Pêeh޺h#N"o̔{ |뉻_IMRZLZaFm-AjX/ؤ3D q_ h+[ԫ*$BWjb3ڠlg 'b4NP$7m&vjU0 Rr(l*ҙF"Wl= / y =gj=k}Rղ%YJ˻UR4R*)0):YM /'l]OK6W#bXѩF9B{WP|,(wQ"E[nB/l׊kF]W`/U|M{H Exר ZmrZ0]CgϦ~Xf.ꟕ-^ތiuX|ڸ3RhWOW ^}003F+רGFh`.0 0:|` .;Jvޝ^ڹslg"$LÙ4Dնޔʲ yuui,o^W>i C_z|.h yHF <2;djР 4ԩC9@O.|\%&z(f)Ox_+|[ eA3Ii=We5 f$06>U-KӇqCeVFw_-0wݻzEm۶իW _U^3gy{]%![X>G`0?g-.\`ث- z;DHϒJ~5>ȃ|0(>$pi ?ñOY0:R+/_N-YӇ4J`t^f iӆxqo|1V@nݡx,_ZIͱ<: hWYp@xx!dnhK.СCnݺ4vXSKU裏o<~f>4>ِ-lth\ݷC}06"yKӔaфK%qt͘#$Xde`3ț7/0 riX(W1n8j4͓)0W1c6c73GN6&/ ׬yTfQl36~IWF,+<}yZ6niUrth'9@{|;1zƀ5x' m HZKx7:7UdHDs4qDRJ&XAfQ`>xaZO; c_i:)zMh2sfFW6Ky\+XgYM:VmL7Se̙x׍gJݝlP2ȫڈC~c:v,+ۂWZ tJLv$(Cz#0V)j<́Hg=}b2s<{`UNUx3_jy)5Fa*TȤ=);=GFFcǎ5 MlP8*A*ccc'x:QI0y 0IN3oUZ=e[5j0eȞ;-5,YbVf#IJN{rx`*/_l*`&X%dZ Y J`nOƓ|i>qFSN&g^OJUWŷ`&6mQz$֎}ҹuLWR#=i+..xMO-V OiĘ}me~ZڵkƧ~j+V, MOg*VhL0N@ LxQg5%0:.X@?ЀidI8pFf2j׮m˟~+lqO2O |h0 xԨQ/#1*\uY v>붭[* h.V xV gijI>$1O1~'VZ&!w ^sxKeDiMϑ# L Z^'ǥYZi|2U ʇMYe Tɉ 4R -6 #>|,$6A7K'?^8N֨vi\W痴~$/UA{YBCoHbU dk.\r~lwٲe9^D@7ӈNP!B`^ɁEYЖGh4{0p39ۃLZ+Wa.] r!n^׬YS“af"/1%8$e#'P?ѝ/|DK7ES$յY%%[h/KxlЂ1&oUEXDF[fww*P~֬Y^-[P~N8*KhuA^wjZPzycśӍWHrbiCrM#Nxt*=9IZ@2y>9x (0bDUӣmࣣ&I-J?X*;fsSuU @;r}7ksŝIpD[xk4bSx(-^X‰h'C=t@]Һu눗PѢE=v:!1nO]~L;-a nrPK^"l+"#Bn/~[N{4C(iܱ :e"4l0dw^uʣm+"$0g˖cf&@1h?n}?7.q RRڹ~ A3l 7ز}6} ^Cb.* @+xC,cRddǠ@:N3f ^6#'`j㧉fGlnهm[~v3t潤 ŝofQLeЪUFLO< FJÝgBHzA<#cf0%0KZvĉCoD#7$0ځ,<7jc4pXB}Q =x`hP)  $ЙA'|"Zix*p?uhk kVO@cg.KG|0t!:>D)犈΀С/%J$ TZs.ܳE0qiKNGRwq` B^Hbpd)6. tGXrOiwЁ_L|@σz0PBXg-?`ky֞@%k7Yc'h[i+~j9XA]Fi:*Y3WH 3 8d0 u4g'a(q0U֦)/ S@pUVz|ĝ dTgV ZIdc ^%K&Zځ.3< ZW>G|C BrElC:'\ l2+1˱ @ J36%6/iy"##%?m HsVE8&rshl.J%0/m]tqjV F&@ʕ-ޘo҂ vhTVAHZ?h4tN-@b qmޝy4Zc 8Q y0xάi3܎YJIg)?y&?Ӽhp}:iĝ ) MadZY-?NefɑYJ0!;2< {gf0;%LE$/wSOOu\lYv0CRZ~ Qlh@-"ҙD?c rA~0G*GpjeRZ:˚L3 6)2e%p턦p%y:Z#a/(5T0)F<)<tZdOU:c?Vlv,kU( bd\:Iϣ?!S,$.h@Y?GOSX<_AkA|bwb fi2%J<ǹkZbtWZ2C&sHtkO54l2 vPN`@~8& x}>~}/ֱi9PigZLT<|!)U$IcdK#NE Z2)i֐,\9śh0.+'h"T9et)u:9!Y1Zr9e9Hpo8&%:6"w2fb:;:zL5 KhUF8}C(SY4_zyRQS  #Ç`׺X> - 4@tXni(G4§uK@ ]?2|(>}[ x`$`{Z8i=ɂX^7>U.S=܉xܢV12kUV+bDb2!F"`"΄KWziD"@%|\-Xy`⨷kXU~7=,ΫiA`_U?mỸ~vX>G\E,#ݚf4jn:ƻ 2R*#C"k9l5fEܧ+nX]Uh.4'S~7>ptN"kzmLT(D , Ș[pȞEzÃ%PEhOkQx۟ OI >Qc?wwaK Y: `nRhVIsN(-A5-jC~O  {gsNn`'zWY. COziAt[˕%[r t8F@$2 @sdkCM+s=ġ6X0-]`mI⽶@gJ_|Ugu^3SJghNVEG_f;hHW\21aJ`lǺ:H'ohE% Q.* 6vnR)#ܣx1dXTOТ0b+@V,Xdv(~LB3=Ѯ-R-X`^pF%[&$$p~Æ ԱcGѣ#a7NM 5kaޏv dwl?wgwxu5($wh7!0 ?˹ 0Uөgћ5WoUy˜x)mlؑڋ.?TS ? S~Ծ}"eN>̙#{#+T@)C4-?sXExCp:Ƀ1L/,Yx*\|US HҼI/g8߶)Qѧcc9.Y3,tΰ)?Թimz_ת: P8J^|MZd4 q/_ÇӔ)S=c`6v[˗%Fn+4oTp~znݭd?4 AՏ| `V5-Bw,S'tHW,(*CY111{ѸqLMAc::kXz'hرZn-Mܕ9\Y`rXԠl`-9gddIfP W%8v5<:O$TCi NmfG ] YSV $03[Ov'Ӻ<1m5ѣiȑoƪ\I ئMziȐ!TbE)3L #Qtlv(L_Ty v&m\TZ:9):ݮ2l 0;V;Gvެg`]+8g*J("oɓ'g*^(dT VhڴioStt,Oe252O8fΜI R޼yU-S*RΔض(ߟyvbnHzwgU^'ư< `01qs 7w5u3pЧ}wR|RyAeܸq}[oEe˖=ϐ=Ԕ-7|RO+ҁ#`74B> BڶmưA:˗ D/ʕK==/3ub ԲY7o6:w  L6;ߨz~ʕɓ'}mJۤYqqqF,YG1]vֶm[c͚5&i ,4Lr 8.0g}f+VUSXU=qSO6J<JٳzŰ30[ *T1bqD  3TZ fDy̤ B A5jK/D={ٳ{4afL59LSkSJ.W\GȐvAϚL~{ۤA/,ƾtCɴ Cy2m~F,._>͛7O` cFTׇ;$lu`ѢEF&M_ŋ79z41p,֑D0oDFF@2/K/1j5kV_4?nrU'_)ɩy.0aFa ?x؞ R0!PG uFҥEU &P߰_J;w7Zfof3pg2?ä*A8,=#Air~AyhWX & ׏4LlL[AR uV{?5 e1ȧz&0),Aq5X*<H|VL=NYUf#/p1?=^?&@ cÃa2 asRGBDeXIfMM*iHw!IDATx]`UU * DBQ#( X(6l_,(ꮠ`]iJҫ*z!盛\^{ὼw sϝ3͜-d8Q,E- Gmc@(@vIn9/T)RD89P`p)z?rHڻwA-Bl+'p" &u]Gwq]s5矋t X%,0mb\}x?ߴiS3yd7 =| xM^L||-йsgvZ6ܓQ&BcnWj-lK.m^usA5de7̶)Sf͚sl ޻oK.1_}) -E<l? Usvvǰ^oѢ6m+h"2ooB T*p~"}Ç~qgddӧo|n`VZfȑ#5ǏwhѢY ؟,/^] nkټyLv\aꪫ w%t)mA$ۦZϝ.bŊ3GQ`vg}E۫/~ ق ?f˖-mXxm>_ `f-7Gy$5M6fΜ9.iv?8yҿ1Qd?aW3-ZY6l3,h8sLӪU+Wո+?>OPZ_g,2GLjԣfe[M6x\$oC6̕SMJZ: gW* 7 +L҇ӐQSY*)̦ig;fAJY6 醫/j 8T h394QH#&cCo h mѸilLҪԆKcԊ뙁0DhWcFb/ʗIx.cOШKi5:Z~PYX/y+8iOݛ]q'5dF8X=Q4N;3 /#5EXv8^\~D_q^*lݵ3XKI%`m;/|JK|b+CIV"~Enݰ5*['Ux _q ٥cZHH"xn#v8.Bs| 9{r] t剙.,xsC+ Ѫpi N;J;:Asw{2Eo@'0tcS0-g[j( M>[֥kF箢%<=$% !O;=<ʖ(-5wz^-6m:/x9vNQhN` 3Fu赇oFujHН,pCH|1@sye6U 6+B)OC@ӉQ2إ=о3GDYxz~"z pXjpE2m-[*רW^7 *`63)TFUz[鮛 i<g2Cې0|*jU.2^&/XC{SL!n_)5|[ٵ=f XJtr } <$~MRډ4nJZy38~Vg P˗IOvj-#^>=C[J_P3@)ʃp]Y1&/\C'SZF(X|,*&;]ӱUCT*rZ"n 4zI>L0y/l%VzMvKqXH99FT*tn7a2_ڋDx=[ī>cr F0[N7U5Py}!i UDVbxj6o)ڄ`=z 0vر.u궣YT,Kr=Ҿ)]P=T3/|Ų×āR&W 6̓^L8]hz{p/BE&v G(ܱV๻[\FLHI4wn0Σb{x&ET_?)3Kn:/s/璹ׯw5;Ҳew&˯˯=:;[ 3,܋f4^LSnw ב`Uvj8[R23e8RGhfJ~Ky_͎Yh9j_G= *w} 6a+HyuArO%\6)hZ FL`M6@Kvymp/Ӽ{1/Qn|9u5?p8%w}#"lh? )-Fl`MRC#?S}.`mDSN׽V xIKN#t /6 &Le'&&/mQLM4qi>WKJ7ïfLJRzFs  큇Y+]X1w_υb ͲB`Gt6uVLKB _2P : /\w}.CQAu|1\ڄ<裆;fUT}v 8!9W|ݏ!|ּysqhlͮ>+xn[`T/o$#d'TpV̲e f0bk³\$hkچ‘C GqixN+b'$ VGhVlj?`(a닂OCD{D Gp$_L 9d^7(t{ˬX¥^)x%/(9%XOk^֮%K2_Ͳy0w4`SxD|9fr]wO"{~)['϶i@p)nH ,4$;=2lO0FM?ˉ0hŻ\p' .V,!ݖFJf,XyܡM0f|g}/^L< 8 YG'LD/"Ka3eԣ7Ԯǻ4e YBم=#GӑӉdY@xlWx9̓|v>J*e8x?4nև9|C\"u W  ,0ӵ>`͚lTȃ?[xxUfr-d0SNGBy Q3u?$L$Vb'0tS{8w:t\^gLbRk&@e.ZF-0= ׶T(IMы%%+spsLf>ѰWm"LDU 0S0gĈTdIB3& 4 mDCI(L<) r4*pj&ZZf@ t f 1_2x.bA%u ,@f4<3@P)hXw m0 y j> hsa"sf";Ki4%^*N ^ 85N-`it&"ZӀ=~G씢ϋi‹@P)ѰX'_%2ohk;25 =f&b#J[{K.l/XPUm=ԸN"hRǸOd=Q4{:Y2(x(Vet(10Sa6iImY_9=+Is_jk瑳: TțNSBRٴ}|y^PRCC𓫷@ݸs? d[LF&;q>[K36t!!|=@N~!^Nw! ?J(aA#>+o`^8hpX4] BM7F:2J;qK]sA;+jVDq@Y9O^Sg>h X/ kj]|B~o(%=P#|[GZiB aة%jZѣ;$ծCMp8u\f3yB8 tejLs{eCyzA6T4dWnY`7/w!v ~s1 `&ϠU8& d-_J$HǸ<4g r),?(_9ϟ&+6M< E~ X3Tv=ձϡ4M1b})i!xGL2y7‡%p-==/Ӹ 8 AR%%3wiǎsK@2!\o<֑A ƫM21:¡}%0+g"^=:AX@8 c !#hw)k 8V\<YnݺwNM6 &H^! ^L֡=ԮŢM(Y`m&QR_pyf&7b!M|1il%4Q#?Ncfn~{7 ]EMϞ= VZuY֒mZY|Y ~rh:LW>6S؁»[ yl shy$3y,+!|$hg.H\֢,BqNBτë}܀S>KDo$t~KyeYz$]ګl5.X͐!C\R I`mKOvDW6{+,<'M:a_-˻$ݦ_[Zk@f´M? $ʶ-B׮]MrrRoވ4 :u(^6мA =5&Zj/,] yUc\ndAYUx8=O9."ӏJZ E`&pÁ,Qݰ<3 1v9+ti\`QF)  `#6omM;%cNt1W6DBAUհ@ۇ?S1Y,;*??m۶5bܻv@?7z|`[:uꘟ~ɭ> [a;ZL );?(M| -L|O>C͉E@ce'-#Py6>1dٴiq/|>ܻDG8P`4@9|0<(PкKs@ Ʈx9S/G8(1x9e1DՍˑ(; n ^Dq Q&poucr$ʎc2{#Qv@ [LHeV7/G8(1x9e1DՍˑ(;_H1IENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/48.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000527214776170045033121 0ustar runnerdockerPNG  IHDR00WsRGBDeXIfMM*i007l $IDAThY{P? ((I4ZD1DMd&Pch[Zu:ՙS'jD8E ((TtM`<{飉_dg8l^[ٙVow:J'% v&V"%@y zx5ذaCZZ*Ƃ? cx]o)0UX uLF".OBAe=xS"G` b(j_/<Xzs}~M9}d 8G FX>B=IoMFJZe2XpȆ76  z7"6unJ\oOJj=z&n7TxaZZey„q녇3 7;Ӄfx)>,f^raA㈟S7y1Os,1zGR@fg`f(N2erC&o`L,2@1+MBǴHRq08pEy2@xn/-q^0ލ AW_?Nawִs㣭+EXq IA3^kImw `cuh jm%gSZ-9Kڷa],c F3ŵcWHYgckx/uۉvAجY{-"Sqh1g svYf`DAĬ` S yBXR-Sq1#3SU5kWy_\q.rq.#CU7²:xviKpJ(W^qTdժUX761JJ+=Tpia4T]--)SYRB*}ˢڴiXQY%1J1 %JƠ񬇳davPUU5^F).g`[kjjC}uu5YQ1oX[kCٹQȘ+nƛ=;^KW"LV4P ^c=0n'xQOxRdHXR`>;q"}N3BV*zZ~)s0;$P`q2l;ךEnwL@#= [,0D_A g@uN;S"6;Ae 8* #ʓa: UR{Fg^ s=HrT2 IrmaL! aZ+ hm,JB|I ?RBza0$ ޢ(49r` U|"/ց3( H3X 5TDyQT6uRҎbpJEZ ?~yIY 8unSV2la F7 kނ93R0OBɔAƕ*>t0>HѱTvOo,ZZZĉG3<* -:WxY„8.C` +k'Q%ۊgzx,$Rl]8cd$#XшO'O& j;vPM4(S!b ޠ;qfVG[б𝯁 aw%;3͠׏KcǏ#BqV^enܹowI襯sZ @ͨ0e:XRfV.ZH).=6B@|tR3>"2I (--c;%ΥxRF$g`0 }RT-Kmn>3lڴ ,dq. e7V˗1&&F+d,(0ƌ巇 l */Ɣ 3/ɿd&:cݎR):˚7ҀouF \֣bV]{䪥:IENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/180.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000003023414776170045033115 0ustar runnerdockerPNG  IHDR=2sRGBDeXIfMM*iVՖy0IDATx]E~d#\ QDPD,݁(gx("DAD\@ X` yaaI7[MM33;3;;3SS]]z]]Dnr9'('tdvWpWtqb 8:Dq}iVw$sQ䃼.rBhϞ=tBGWp88 8q^{5jԨk׎f͚% gϺnH>:zR78 V Rt*)) />W)))V=8X7eq@fwǢEW_mpŠ}hVYOÇyve.f ,6uǎj] 3bQ^vm5j(Kho7 =: L5|pUR% &hoXlXn}}*99ْ,>@5T&M,` ` n;P*t3@O^|իau71Z_Lϫt{Kҽp _ڴ<)"'ocW;v9׿XL'ç}wT*U,+l/HC=ftϟo -VD,׀SNU͛7BjM {UZZ%D LX[@ɫVR7pd 9o޷B W_U"8 KI4NW<*VXtq6l&L*t3As myȑF^V9\yvGjٲe"8%V e[, ;' zzӧ04nf۱c< 4֭+4?h34wľizQߞ0!Od'|R&dho"6m&N<ƍa2[~4O bsA9m>V\Y sHܑS`isn̙M6;h0"k.KjZn&dD=a/Y;g ٫i ::k4cV3-R@ uqQ sXP!H);jPŋņ 1_[= eeԡ~~:@CȦ0'Pm{@m@TkEL7dժo߾)ڼZĠ8>:O4Ě՛wY$s|@CXgϞ^٬hJhwZk`eAD~%@1 N6-"s $Xӟ&^ME$mٲe"[8Gױ EtYz_' GA3hG`ꢷJ(Q2N G q `u9 {-TV+ܽ`Tp!XX pk-RRwvϣ LZ_BIBP$3P6Yf4e7xOAtw3oRW(Q)kz"gd#K=' %owæǯfk,7,U݈ӽxtޟս&8nc)L~3i*SVI$2uF/ȇ3 GdF@|g& ÜrU*bѿ1ad,^1 k(k{0FO_H kUu)(2Qޤc T =u1+wxvRܰn׏#@kF7)ܽ.x5Xah$[S骖lB ҮɼO'6Rx-@vO Ax`w:ֶq;tq(6uwvNף{ Z%;{F~xKCҙZT|nWko9?"A}2KӞGe*',&JbeDػK+Z|NnFbJ_R)y&Jg`c+YƒH3* qF:|$kVoI_{C "Xϋjޠ&5]Le`9,XE#(r+&ғ]\*]hG:Wh ~\"a0)跗)=@Ut!̣w7 t N F[jA5~dk5ţTO>\ZevkwGqd^X^Ԡ+uiN.%UPDP~ /^jEy%ծ&m׫A PhAjbHWݐӌEie\(xe"-0T*_C?JF7@vkU/0,57L y4fƉ'v+w +]̼Yl]/$AefqWPty%|-9ݡ9=qu8Q0>VXmgCn0$?|zjUD/׃\A"fZk Cxfzz:VThQ0h$Xqj4oU*eyQ3șԒ״k*"C"~֫TXiOno6szq]=ƫ #G`<~2,ǃ9=M~2]g}F+׺uk>}<>dyS57yk+F[@t=]G@f}>Pv_m @>~ZtoV_W<ҭ%V(k% )! 'Eču+n2BHU3guЁ @۷oa"M7Dk׮s|%%Sۺ\%ժZ#XD6ו)/]%GRB@iE#7oޜoxDSN~衇@Ol֑nFp A%/_gJkESy! ]v4{lJ]+ݻ+f̘qA](5`a=nX#zy7~wls:g$nv2q 5ѣ" ].SpEӕW^){&皂,^JCnD͊Μ }zuu%O}ByNy ? O?RdOp.]T/r#_IDqu*cƄ`9oTUUýVomژa> k.]?6daYuoeZ98JII· >U.mzklu[ԓ#'r m։]*~6ef7*Wߧv=xhfep-M&LPIIIVMZlZ(QB -6|/XEt5_L^=ç +i@]XupL3*42 d??-ѿC6[T)O#GC,4jM/~POXk24?v Ԓu[!oU `nmwn"c*ŸgGYb{a*5<~lo֍|؀ֶ_['<;!fjrxO@V! *ߦ`ԩxjV(#h3̈́."ܹSw}VSE6^B1tj֬YV;/J&?ۺHfmm^f >]o`yO%''[M EI~2*rffz7Uʕ-o96l`Q`VaVfx1aY%_k=,A{ pCLVl-G-T&M˙f)&29?*MػW9T԰87T<4nCh dސS=/ vJCNJ,y]/ 0dM֯__8K"Z!d48e޽jСJMrMEaN.GZ1y<^Mo… u2#7TUVD1v]w)8K&D 2۷OuS~r@`6##Cz ` ˌ+VP1C?M+Zmu"$B<+;6jHʸ 7YYU e@74 Z*Rij&ǃMneI*UTЏ{Dcmfe-#|FG,- qfekskԨ>CO X7`"ׂ4xzGOo* !:7ܦ"&16Y\4 6s5r*H()̾}UVY7Ah Mpe?>=B9 ;O1\荒YcǎUճ^dr{3Դi,z[E@>P6|B]rBs/HEv~XLiL>?ʔ)5Chdh;ЫlCZ {?ScjLQ شw5xx5jkg&h E0EwzRxS@{ioU_W{ܯxk㇦痢Tm~TRE 3o' ^@'Ly܌ 6wKWbcF,Yy74i* åW;0NN }7%{(;buīP8|XQ^<[xX}>} E 4fΜI_~p!/ѯJ|lWO-\v [t#i}T\AV1R0Vm֚ݰ_V1pNO6ti7lԨQ^n@A;&?B/K4)ྫྷVRHGP3h\XM4[Ha ڽb醧.X#BuF<@#G5k `axA)?^c A=~. d_%k%QEe3ӄkpДmz-Pܰxa %DyVHF6g <'xyњ4h EFYf~X {Ş2}a,\\iڲn/C_'~EKz,ʥB#Mɮa2}Y$r~lV?q]5B\ njKk>sN"voDI{&/ׅ*ƍ :!7Bڱ {4 PCr=ڌ^u:ˑ`4aF4$D0B:D`0axA-F?¬Z.>B+7Qi~ث@E: !0aSPSFRu"{B #*(G~f~Dq*q#ekf,vК`=D#'Bפ/JloZ(E%L* [a:z2M_ ++7,e^j׸.ui^wGƷ=yx{:?ܸMFmx9 ;(qC-,Xo)[jB$RfdLh$J{0rc ;`:ձ2 }aM+aVF;Pbj)2,OIWFM`HAq@k`Jh֊ƂŖ ,MְAvʉ^7WtR2}A^f_~q dzh3h;-e7, R wsME.śc3K(wsWZ$eBOؙKhq6Ѻ!~^hnūu[Tb^Z,r$ caI솕2Cd~wHB/iKP9u!X<4鿻Q It6vK{햝ܽNVJ\< M[vPJR7=p kH?u5+$ZTY~2-E x-/%umMP/ɅSe"0_@冱BNF6<ܷ?z29db2h=,r >zs)W5 XnϏc՞pi?b.„qx~?8bS]E2GQ)*bM[e]n~);Ͼfy<dX@IB&~v&dgo`*egpp(WqI k%t}\R:.ŚreK_\@_%41cU(-f7΍c+; x=}Zě`!Ha`XT+wc) h>yI179 6z 9‚d[i'jk5*ӱS]R9z_git0=CAc~(rns2/^;{U+GMOfDQa؀6i^Z]K{gvI`Q?ɫNIӣw\K7wBEm9hmq1 -q/nxf`ۺW|k,k+\;ZU+ *g$eVJ d]C+mekϻa ChqRH Y̽7Iyib;bD`Y`XooĿ޹k^^ː%WtnmӬ5I=AИDc%`f=4A n?bXoٰVj3%CAAuh09‘8B*/ ݰz37 D1_}Āc$!a$Xs/|ʷ} ŊnD֯ G #CbCr)AHע}{PGOhYݬ:& kPdذaCԩJH@il^E2ݰnH kWap|{ȞGҩZr'w0"C6l,sBa A?.I%1EFO?k\'wm}iV{d?K885LbH[K^l1~|ɈXVZ!.l{uKSQۮQQBn:ׯ"UVR sa%*)9@S0Iz5۰Q[zqp/K>kzA,2.7wmI˂APX\;Xr?^g z}%@9WqAlPm `ƵY_~3fo/[Eڵ+h7 ]Iwh#񫏳Z瘀HnA#{$F$ʎn1$fX$&^,/^^lai#4gjyk!oЬk0׿Uމe?pe|X9*URbEaml5Ƞ͚g ת7xnQ˓py񓉪77?ռ|P u#[i~mu) l~cWq%l-`kjĉVsmJlYS*42x'_dM.oQ h-S7uwHiGjժeδXқݻv6 ,1ME;*\q :lM-|Aw^YYXo Ijj۽,2@f^n6{U||oMxlg xm iѢ6m;SB74 f_zYV8l]nF~V́4M6-[Z@CcTc>8ktu{E閂q`IbbJ9g߾}e`p./&-mD:u$izQݦxkx*RXgXB|XQ1] FcǎWQ8JWܸ&̡˗^zY RaxxE> =4ib[i1D\ kN;nbΟ8y>|XldlXcSyڷo//xt-u9֬0- ϦS<βunצԮ][=Z7G\ ("ˁ|h >_/ZHuݲ֑rh'L:|AS"+Nj Zǫ$ ئe {aۿ:@֜Ƚ| hNӿP*_@ɗ_~9s P"7>55{M˙n/k_6-r5ȑ#|'k.;:v_~Q;wmM?DGU﷤f*Ufr.m,E5_D/`VV^m]| ݌c(;qW&2ςc:v@[=> {)Y d-)8:l͛%Aƍ% !* f$+ N}l [`]"9TCvo \>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq.b{g8>wq~IENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/196.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000003347714776170045033131 0ustar runnerdockerPNG  IHDRksRGBDeXIfMM*iĠ˳6IDATx]E.GF%+`b@Ā"f,(>$I *Ar>$_o-=vogaofg{zΦ8MB(`qR, X 0aO-, X 0S ֝={c2asܹs#G |Ϟ=;e˖͹fObBO IIIW_;`[H=V P>}oӧ4ix%@ɦ(­Μ9d^tر#'gΜyZO?eB~MrwS;NwV=.bK!`ஒw N:K*pT1 kL} >'? ʕ>4h,YRk(:BU0aSa` ?`0#F(v M2y@0+W]:B&P_wpnݺjĉΓ"' L~cܹs #h?Ԝ{7pt2cRnF?CUtV!5, 3<"\ kFއnꭟ(Fbr|ӿYò k׎ BE!~ -X7A=޽{]w嬹p{c~Uln6GӺ]jѢ={vl:kL/6f͚g%9֦C]bE5zheNCd @hAaK0Q_ȣ9/_>5x`ua>@m]KD8FW X:BQ`@-ܢ֯_p:Ѯsȕ+Hu5|nLA[o9F~BƍӝZ\:9w.x;-(+Y0pBr9G 5jB "-[V}0*O@"m?sS9q5 8铒Ϩ׾z~ߧkw)Yj QݹubH< Tm!Lr4d=`u6r.'hkv~[Fr -Vc.RG|[089Ή+B똳Qv{49z#'ӗS' .?@}'hzٲek7E%ݣaiuFK,^{+&QP/&hG}7PoЬ(WPLMs'sL_. &r`(0<3k4 3'-\r/0h yh԰Zjߠ*,"_I $[ *^8!-=s4n8y i PիWJFu]3_ՑkdA]Y`"- .Iy+htMjT%g0(o[f?2~`8z뛩ytTr6G xq Zj {S׾T@"Wz8ƒ#4i B 貼AB_T)♫byexߧv&HE~1VlN奋 0z]( 4ɑ#ϛvK'OvWvm_/א 'pnb/shwSi' d'ԮSN8f/%SթZOP5*E~9N#JKGdcf~<3zZeBZD iFhK6+1/Bo&u҅y*V )}{O7 KmeK-e~I$` V4'!Wܴs"jW.͎wu*uQAɚQB,@~/'k"kd28عԉ3@w9<3RSHO3a E  7K9y S6RFVA:qsٿ@ZmܾOEkVD B3k:a+7OON,rѮߩ6E^Ө:]RPPо GԾJ[w Q^UL`@B8E_Rb-M$C ; !eOH}?FE i?!Fŋ;6ٔޓȠ q-nZEfӌh`iQJed]\tD*=7 |"Ȭ͎?%u}-qO=KZ5Su,;:*Rk%}Xop)S=ݷ un &ZT.S-[YbQ=qvbe ͊\0V$z6AkU`9~0 !*ܔVqiKsò.彠'PYn m]. /m{_W[i eWf! Ja*eid ǡ="_fk59~ǥ У}#9 Ȍ|>97  Rr]'`ѽwhݞ(Dʠhxm=jX[um@N ac݆iOPsXG{vzfCIGf)ѦnݨK7b^ڙīܬqfD{!]h!]ol+=D0XJOAA ss:ؿM`5P^k4K 6F9|(U) ;m6bCy}`F鐑_|l}թS')Cmr1fdacf J[2:QRr;Iι|e͚54{l;@"( ƉcE@K%XфongVF<`8C=:9?<ha|H]7olْKه7; 6Hz>_ñ9֣7&5*2XS<2rME ixpUiۏO0R6,V T]˦.ب嫯r6,ôuoI9"Q dq@@`ܾ1h zӃ m}rx_[4P˄{{_> <>,  >EjvZe, 'O%%&cy0C04} N6mӖ>*^y:qJ''mٲE6tiժ͟?_VP,:.x>Fl0xqgMUʕQf_0ݓ'?~^|Ea_~) 0b]/KѣG;yjFf.!tI1U xQR0CA,-W7ԁ۬8Ŵf͢-Z]wE۷ow,gܹtUW5ݺu'Te?wlRh-8x+꫖{Ϳ4MQɋ Oi=IWὠ|k0̂6&ob#GȏЌ۶m;S}i'T͈gC76<=ڣ}-V%}KyJƽڦ4;j 6&$$mFm۶ JQ?SVŽG/(yPop|vi))CpBfԮ];իmڴ)fCp M6Իwoڼysd<0`͈@Ќ{4o0{K3R6u;R[~mC`?/ 믿 4d^~wKu?Z*J7{u G&6@GЭu}4=A BwAs5k֌fΜ)Lњ1cƈaGcǎIy`l0͈<կsTVڤA笀+"癠Ki|tB̨zdq0N ̼ed) -$Mz){ pA֭[+R9ՂN)v]msP{ߦٺ{" %&<6h*.HꫢPOSY7(f%a~u*aٸj%K:8L $(fD~[:M0ҹub O>&$>3ESxDM 6L)RD.K.&0j֬~GIwoC'ahڵK=َ &4pa[a)x k/~OdGW]~厂05P{7:v쨠t Ŋ.˭ǰ"PMKJJRo⋣to1Zj_9M E3:Sy1QS:4VTwP|PAd*6}-# 0$/L7soꫯV-rxft2pb`F[@47E%oАL%Bc&Ka+V.]bHFfOy)6۔^:uJkXb]L{+懓&NQ< 4ۧq'L7M?)ŋFmK p/>Zj|/nzg==4I #yOkX 3,ӊ.]TaڄnF( |sV>°NfW_3{ylf~Ђic;hx޽p-8 (PBjСGH!1g:ri^88*S~0yʿ00N#a2)Ki<3YKtB3s῞8%06$kj˗Ν;-a'>}𧮚 N}haνo׿$8N"{>f|ybZQ8x G_`}--G7!YJcR7ST;StXڥeg#]z1o'9X3zD Fn eO-L `%&[f_TzݞPO<|MbɲFȌy{+UD9,K|϶MyI,V a$9lMqd )^pAOl!~#36x{vJlr]QS =HbUun%Km tV@uqK "!Xnme;ww u@+oZ<ȟgQ{_NŃҠnyo, 4>qf.Dof\4xЌ: ,q׾DFc&/$ & b,guCɄ4fb[=ǴT+mŀгCNǫ߈63=]S}%C[JWx[ Bknf.Q8Lӈm{`o&aÉs0rȑ#%b9A|Y]/,:-b7.*cޗsn(DM;hk%(,vh'>wZ ?"\턐{,Rvޒl~cbv ,efLۣ%qըvаG+(0 f OO?4ٓ{92 lb*#?L/>f.^asnđL+ yx=-OGj1UY*EY"49:( !-̙#ijj >i!Ͱ [9{F\īJ5`"Ҋ܇Kj]Jy|@КB#0N_Mo.Q6NheM䭳.Q)MLes>m)I,4`@]<߯}0#5_9*EufA ֌myCƬ*ӌ`֌5 ρԁؤgmH|a #kM_GGC>H_@يR `Hnx&,RrlRGPV"ɠ?Qn)fĶZl<ةՑҚQ(L?/sҫ_L< 4t53ꋪj-Z2s|) TX#P!e-J4yy6|'t2RoFU@Fz4cvь k+ykX3"4R ͨ14Y-۰^j\!k :EB7Ý^iQy9Ͽ,9{6Mn:7KT Y}'usuW8[ϛ"})SEu;t )4ׅu P6m=f\N rtovڡ =է3U.[Bhx[eC^^%4gy_W%8+n:zʰEzo$UMVJ.a~ q-h)GЀ֌hn1xK(:UiP.Բ^5iڑSYm6Nm(<=!qB!e"^9Z>a nUQ͊طLVnI/pQ%:RNͥ-v~ȃ &ʂ7u bˮbAY-~L*T, "GZb@hhBA`=4f\A.AaV2^zFrEw m`Y4t4A~gsKGW,ڃ݌yZ~4!a>Si~D[%7+(Y d+غ_ B<ᶢRys4[ʕiKfD#1رI ǚq: rhF/ү 10ޢ>Zϟ)'{uYx1=4m4iw y`-Hcƌ4)tъZTzA㬿6A?hnI>GԚ^QEFZׯ.ff?!ݢ])G3K ;ˎfw/Ż VЏZaT,;~BU_(~~׮]QD!P^ ]3= kn:ѣaȡCC ٿ`0WT.C308N 1##jR]Ԃ˻f?A1@̑Je<ڭ4G^wtn ~BJ7OadĚ̵5S7^}2~z뻙^'*x U1jD'#:gΜq~nu]^||S{dkqW(LhJùuuE.OPO}Zmd-AzՕ T-Z/"Y}`W'?+o 8qZ.璇W'D٣xdHʕK'(?es ByMF*𱓒 \M("_RwYь[#,BPhd朗%K:o m Oo&T޽{ƙ@u.z`MYbB$#_0!AfhҤInݺ= (&J*{=J[ DYn^MByOV<9@I]j֭f8P`sD}^z7_wd'i@ :UO<ʓ'uѽ{w#\v8I(eA>cULGݕhsM͛W4u1_T&M dKCf\rI'NX>^q *-9m26_`SO=0%EGUjڵsўDBoFA_x 6Thy 8=:, B`1ed`xE s4#X?!G)!Re5 p9r$ 6v-`~hŋOH" T7{+HxLC^ڵkw3w^ X@7le V;C]v8]@5b#Y@OH:;jGd, 21ALb.6X`k& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.QDY`+& X@.Q EjIENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/144.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000002243214776170045033116 0ustar runnerdockerPNG  IHDRFsRGBDeXIfMM*i?? $IDATx]|?@{U ("M@}I<) JOE^EDJPB |6&ٛ[nݝ9;sN>ʼnI @ <4O"@r%@wr Mϟ`_ (` d@&/&<y9! ?<@ L {˳ac۲e뮻B ,z!{n;d)}Zs祜I OojO>Dծ]& wY:dyjΞ=kMy@6p.\J, 4:ҩzvZ})fNoŖ@8۶mS{Mh6m8uy .qo>[P}ފYJjjzUҥ,*Iy+WV{zܱ$sBwbj/R5h2&$nUVj֬Y6g<Eh |rյkW8Y9q&Ն lv[9 sNտ^qc#JvMhѢj*99oQO hW#FPxo+<ݕVNjԨ>#"ZHC SH9!Bn@oȴ|ռ7 ky̙ /t/P-uǎՂ .h탺 ::uJ*>>&ٵ@u3F_F@ӿY ]avvR `4+>,EZ,,y1IࣥRprJս{w[q~뭷7l;b_0W"Bs2v؛߱,O9?7/"iĉQF6n'iiF}v|@4:}&ίWNU)Y`bqV34NjTM fhHP/ڬZzpLOi>q>|*SɩI"IU>~ >fJ>yojYu5,b4~r:dB2Zb7,#Y @,XHW ||6RZ@>:},Xޚ4~M-IlhC`*^8=_G grlϏO><ĂB|bj H GgΞon,kv1<& QlmoU_[;xuzOcTR"DMW+Q0H9Ngf.Szn) ڂIƎKK,Ν; XsGr?" 7@?32◕0WArbYz]kior ŗ))B>gXGRWKhǾ>8Ϗ ?5Fh{O"/]NNR6 PT6wפP|bI@Tdh޼y4az)11Q#ҢE z饗W^r AĒk?74 x|:-MsK';SbAjۨ&ukӀ.*Q\NXGvTBtQq4p$'k=tuԡYm%eHh#>6mORl@q²upHqܭ篡Uw5mS~r6lE2C_tOS_KKқ+ֺ>q=$ZBD(8+Xv8B׭JwhFeY Ai,ϼ7~wTE M;  c’%m1.fЛ"K$'EkY%@s"P eAYa_۟HXǁeܕ4s*R da R'#)c+ THJխ>MK) rwY:ʼn-ۮ4. JBy,`D}DHԻgtJ#PtK̔#PTUt#PtK̔#PTUt#PtK̔*f)Ĭa~`>%,>;z 8}ox::XNcGw`QoEdq *(@ simz_d^S*Wy8FQKkGq<ڈFpy:XZ6E ,tB2n"V,Yp$C}~bE`Gʃ}:&`A$ oՠ}Dְm"||B+g=$WT^p=pU oM-EzըqʴpcY`P0$XTWw@j=艾=BRRH|F@J UaCiΪMf.iEM= ÷uIY R?voӈZկN?0<<Xpc BF tE F<<]RzԼ^u)=1< < %/')Է[ʍ2;p2_CL,z^ޜhPCn ,Yꆐr<ήm, ȬB'X-ƔԲa-zԫc Kجq%cAYԻ)XxXm(HTcJ>z.PЙj\-lۤkȘ6S*2i裏xeG DFܰfu5[i)O= yr,,Co[qfXNya M{_ԦIm8>l6} ;4jpIceڵ~ ϛ;4,H,'~O+j~ ς 7 v W:!^xEhupfe3Ԁ_ſ&!]>啱KPѢt7[|tf+fjӦMb;5?i"l79ʣi,\a1&-Qfo_u%kH^7VIIIRH(#6RF <.g(5&n+!B[ ^%=#\%ʧ˘t>-6ky?>:p+,a \т:x-X_KtfuM7e 2I&UV)gk@_?*}N,+S@2 6jذ-|} >ٲe,CRr2ݬL<99Ēw|YfO".8@j@^IF^;ü.#$eg^{lY7c&*Unߝos+y"&/dj۷+<iABh^r4m=XaQ.-p,:*Et!t p  ,^%".)?3 Ģ)ת'g )vY1-xbuUWDʩMT\YF&=5,].xcϗs70]i֩QR5^G;X-[P_«ud=શ S6b_ +_) ֪# 1[g}֭kTNMdCB tv;Z U>]YKT-tMomL&˨:93!x]c J);,^Xw$X>l}LXu" h<TFbl"2j<"x #D}w} %KxnON&`%nW Yp%ڣq+6p q7y|x75e%1c5X+'c,vʦˀcP K^zXg2L_y2Xa؉S⧺_vvSx?,Nl@(:NeO?""7-$ ^_ahD dc 1#Atp.?$o[4wGz^kcű5~6cA8T,L, (ХaÆ ~klC⏱m7|XoXp} 5#ssWeFkYv)`( BEţErWFJD`yAͰ98W9_z &ӊ tKieriUpE{2}ڵk%GMNp ucK+W#,gw0eoR}g XC ʠz#xn r|5;5 @H&f82o߾֎:Bc)FkM. ȭGy' $BP)B d>Dƍewqe˅exXnȍCQ3AȀ l 5[dD2˸A. Ru|qSk3SxoO!Gţ<%+e`0R "k<y|aA;$XA^0w|)d.~J ] ]f^yrxg`n DBe`K$T Mcɱ~N*Ʊϯ xL,5~:oEAP$Ays]> 1z,r @ f<^g.cUT*g͍ͮ@]q޴I?XӀ {Gyxh\”txo{0*9X~AsWs nm6SVZ) Z^mM[>B-ȣ+kYHΑ3Bm.[vHW`I:pc_|K ~ri t$gAkak[k,Yp iY)"lIJc/0zpշ0 +.+B_`zpit qezwEu.݇t䏺:a 7*TTXzLXP~\*e<۝7A߯dyR >;,Kҽ2֊,b[k; ,)aA/[y^-, }sߢap!GqE }ENzW?xuD)_QxOc<+% y?;14k4^BMk| )5ciDwT>{g,}:Rヲ?,D T: 56'В ؞ց"]Xv7s@98~#Q=FϬFc^㷉f @ ;~o1\Wl8&E ៀˬ[4A]Tyk|[QFna*HhF]VT>ȃXlKHNbyo"~`,ky45>X YCjpx⊾kLѰ4<C ^C$hD A sZ=O7ΑD Lk f ߿?5mT`:ab=ڲWSlKE2 K׶M6۲s$";'(&tiV k % {P<..+[u2Yl 7D'1 ΤQP ò;>3AvլYS;־/Ȫw KzD#}Ke(㼆џH\ d2 w|rl7 kA9&N,&X]( pMypsǑmmvNн[35R~GVDdXJ V~p +i'KZ ejԱc=Ozi'%%EPLS;4g'L?l,z+WEr1j(y^2ݐ( 0Bx҂ ؕgj]Z: ֭[N9m57yc@a{WT^QHPɼ0W^ⷱ$=11Qs=`j @w|DYB[P9. (D* S!w[f#9h55 U8v&}9Y5k,[<2f + $ћ9..NdvAّ$#pS6IP[fH h͊3gFA2M, $e}]W3$}4w\ծ];H}|,cXؒ>SҨLGVժUD$ݥ5jHM8Q*vފ_ Iif )[>|:q 89Zjɞua^2FiAA 턻&{x*8lDhl{ɽ.iрDqI#P픀]I#+qy䔈J\씀G DmWJ\^f<9%mG W2;%)oە<)@Nxۮ$ȕN xrJv%@evJ#S"޶+ xr%./S]I#+qy䔈J\씀G DmWJ\^f<9%mG W2;%X?ft1IENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/20.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000176414776170045033123 0ustar runnerdockerPNG  IHDR sRGBDeXIfMM*i^IDAT8TYHTQҦ,ERHjD$" h!_@¤z(262%b-ũ1gsO9:-{aATT4"9xWU󹯯HKKCQQBQ0p~>aqڿ{N4v|@ 'R!K ]_GK^ a]fǧ`!!`2ߨÅc;QӁ+MJ΀Ό~)N\@K N4ւ1GK!U$ ~9S^/, ~u @,7(IHLJMX}CG}~(؞XDSHm6"s|=}JTspB}K2 (+-()9h">f@3( !f&$`@f!{"##BGBdNcϰqzlBٌ!mfa2=A-XuOM#qܞh3TTzT߯EJoɋUT<:ܨ;pю#obMp ydFll T*wH^{?*kL3W/ZF6>3OUEˈ{󲐜Rc27/7s4Bnێ0Z{M"_qGBr&8?| ۃ;&Aͤ;W|x Yy|r:>k[m!kD::;hdtBf2Oa\^f"d! W^ J_seejSuNk`N338q~m-EQIENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/60.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000713714776170045033123 0ustar runnerdockerPNG  IHDR<<:rsRGBDeXIfMM*i<<\ IDAThZ{tWߒS2ZP5eV=xXJ]CQkctG5*fz 0MD#Krس'Η+yӝ|;g{_505iҤGGMj@OOOOύM ѣGpP=F#t}RݱcxРA2ܱcG޾}񮬬i\^4)SPKCӧuS -/^6m"eE(CӧOt* 0,+??ׯ_ϝ:u2,iX2/[lK,{)>OnP )^&׹C(///u5H;>44cbbTZ au+_}jٚH ߟϟٮXr(FaՊK85qAVnx= 9sLV5;v,_rEwQ WPSfpv~>?0\Ҫ{{qh!xwZ=ȹsxᆵa={={(\9Ym䬼.Exd]s"8%,$HD`e!ߢj鵮/R/1B]VJw{+5 РO<-?oJMkQK^)왠FX|i٦J(\!xVBzBJvWIcb%_GQܥ j›I)^P$ce2#ۑ{Ulw.D>C.r P`L(GZ~>WXLQ-:CϤ?[EgʵewdQ/vu"?sMU*F[[iʪʑ?:J@?~~ުαOuф}+zYu{aeY;k,隊n>][jL{ ?ٹ&SyXKU.B`{cނcP5l ^[PDτ+E%6Z;"AyPT~2{(/l0IN]<-2rI4~~b" 皇?U"x#ĂPЇo%?o:SliN%݌\Rg\- j9JiD& Úٍ競ȗ3\[KV,,.ُLA=;5x"S-Jy oP$uVVCqpb^M0R߾}imDFvϵP65/5hƚGZϦ`qM'ҥ m۶Mѫ}0v NPyFiPsYd&d?Дē&M'SrZZn¼ 7w%E_9?OWP… 9$$ C 'N((?SNMM5RA'krxxlM  4O8_%ĺP YQ=˗/ijvB GƏ YL)"5̙~~~vOׯK"ߎgv^bvwR2qӭ9v,v=z0kk8`|b*})Uv?} _N#ϕ+%ej[ue\Xݿ|óWlV<)yevMMyqFFfEyalxֲԻvy'ĘD:N:zux$ƌ p1 Q7tVH$^&5 (T .$ݦĴ4[; Ptذa$eݻ$[ϮciɆhOHQ I-,`>_X[Tڧ#oՂ$<wM"+~4x6̃L5Qm,$c,y۴Xh㨧JDgMORKCd;cr ,X]RA{UzGl WdV&cХ;4iXoCq: /?uq;BH?9D2gs*Bi`J ?)wIv 5- flsQR.UEڐRxKVOMDm;q IaيZ 85xjPոW*"Qx͝<n4al2ҽ<f茣Ur^]_z>Fo$5^{5zF`@=/.A@)l- hXdH*)&Պ-5h0XN'/w?}ÆL/WXT/x"LNN6""/ڸ1V8gkwh&-gpMbd,&2Ϙ FdɐhBM6Ps/- 7I\ gfЏG^ gJ tm5Y:ȑ#ܿ@aas|[l1wREUyY c L#G@YenŻzRppq[9mK5XL̫*![j% %+Q[ʎ }᠀:=&$$q,-3LƀSi.L@ڦ9ܷonڶm[ްai bcBJqYO; k/`FUE@PA@%E@PE P ']("4(" E@PUE@PD@t"(" Ҁ"("CVE@PTPPE@PBUBpuȊ"(*J"(@" @NYPE@P@i@PE@ATI!+"(( ("(!*!8:dE@PE@E@PE P ']("4K."֦(SHnjh?`B˔>}B~<Ӹu,"$Ng"h ԨQԮ];0aKN 8z 9E@jT%F/Xn6ر#Ժukj۶-Z2d iX -gH(v4`GC?+)DBm׮]Էo_6l Rҥ у'د"(>F@n !GC ЁdP V%JkFO=\{i~(P7Vw޴b ]{"`BF1hР[ԲeK9ǡC/… cWfJ/K+W.ɹ(@b:"GPT" @*˃OwIݿdr 7~6m*o!QU `wc~oN7n X=TlY9U<ӿE \F.v) b`Pxx銽>SPUs޴^B3?m4zwhp'u(͚5 -4? Hy"TP:Yqu։=za<P<x zשTRUw"8U3ړ4B?v}'gQLL!`qӛ;'O޽;uڕd"a (/FYpX"g|ȑ{Qttqbw*U$,о}{l*z"'lxgΜ)9sYvKvY@}[ebzdPөUUf}7m$?(1qW\gW_}+&?\"ޜi=y$}4p@gOk9 Sa PϞ=sΔ)S&+A@wƚ7?L}7JO]L[zu u]҇)#PӠH-qsJƌr`#Oǝw)@͚5喪YNlT38mߧ#F6`< 0zW^TP!EB:t졈*8A2f3gРA?G WaǥH"+PN再dFg޷o}_҅ mm0JIFte͚^xz饗(W\r%z"U>#[ꫯDٳGQw3h>eʔ7x}Q}["\U~3˗<>AO(T zM&` 8 pF3?YfаaCjUoN3"{xڵaѣ1嵎x<SRvCF"lTH6dzEoOdޘ_ ɓ'uޝy0tD֡(*3UQXp9C[n%50 @٩pW;E(P }sѢEe 0F U}=VyժUi„ $o0߼'6"̷!7y4w\ߨtBJ!)C@C6d aߧ;v&pȂ|TXQjw}2r]Ct<8~)..βLpP=B vb99E_`P` ^Z ;V6a-0= 7t`ϯ>P ԑ#&M$ŋPL#&CcаC`޽I&79(#P:0!>:Tػw`w*;R{>v|e@jE@[G V8p+&t%;z !9{ *aG@4(D:lE) z,[L\XBf2B`ߡC#M5F@ОG3?`XBgw3;! ߔrnР-ZA!<3%$Я_?:x R3vK(Ao=gN7P(==~{n)"4lذŅf @.3ɔ)ЫW/~hyJp(*1MI ʲ)S;kN(0yE pP p.$z0fQ֬Y#:׭[WV!z'E Y>\{~@ll, 4 @GkqLOv)BuIdpY"$䴅nq۷{G#F@2+tQJҹsgzW@r;I(*0K#aɸ캧愸g~yd3f oݺk֬)9)9{9@(N09"FF@1`H53s͈Sg~/B.mذAnWG֎K5Du]r]s Fes+X~˧!7y 5 6SL97,`sɘXK̟b&v~ͅDEEYl8G"pu?~O + 1}@߶-ݰ].|J=uGexhZ}㊀/P=/]rܼs?=pz/Ela6F͠ewmpfgFhAaylHtRvhNjS:\~ ^x¬%Ġi'ߡ)WɭV;}}<r:vꌣ[oQ$*`eȐN>C|'ڟ~:8+/t-^J_1 6 ;4sLjԨ`d8@O6cc9/$d'u0ﴅS?(2"g0z }6|(Ӝz}zCE@FgpDGM]@4oKQY(gHp-0ve1czF[XuZlQj^͙MfzGӦM￧>}Ptttg}l3>yy }Ќ' ҋ&z7}DkrLӱqX>U"-Kp:s! svC>~>u*}Bl>{d `(+_~Qdpw$};iU,QZ)O9 hS U>`:ں [iߋ< YS7i5͒9篥l95]^so9aQ7cǎRM~as}٠]<iOɒ%,"?d sQSiˮɊٲ }oBn~{V,AMkYY!ᦊ 8t"!tL,}5v?rB&$ok`7C'b臩iɆԂR8aWzꩧDBAi᚜F^͛S޽ AcWЃؘd{&ʕMJda~Wl5Q7PʥDD"刺U*@ыcf.jfL9"A^Ihb9"1Qڸ mwj+F8? wvKeoF<;v쐾BXBpzԼ[t}I(8 ڰ}}D7krtS{bᏖgh앴lpX4?1;pwDgSƅk%?c:1\Q?(!{ZNnАZ.oӦ }4x`>H֌>{ԣGze Xg/;C_s@d%޹QXps8}3aU)UH\EKJl"p5T*i|uv?BBplyʆd(NPYЂ3o,SQ$&eqͅ~a ;V9P9޴ۮ๨s~,yDB Ёo?Mz2MdAuzCK[vzٲd!"y" '"i7 X@HeHo{$C!!QbPalRv"?DdVʇ43aI&"ʂh8_qƍS޽I&7'GFY۬Xq'K?F RXfp݀[IMJXB/5¬ǚg,[q3)&;_%0B(8r0x;t *ȝǸ1ݏvqqwʊTNU/ILؼ6>/lKƗ0VEA?# 'VZ0ɸysY\lA#8r|fu|9R'0Lc{~@͚5iE`WOlςBaXǏ?,SD"Owf-+KY8(^iK6Ҫ{%URq@Yo/7ƫMB#~㍻x2fZ~X5o3F&z 'Smm_V,)IU"NQc\ $Я_?:x @P' K(!䥉h&̀sqK @*`d%6FGqcҨKi&Ǫ@eK5? 1E@/ %2 vCܼ[tҼB>`O)ęؑ ך%tN2!.k۷o/I_}e #qL2ٳ,Iu8o 1b {p yJbs!\ k#cT"ԼVyʟ9gt|z]p ъ3裲lpʔ)2n(F@17w?  LY}0V mUjKpNKx*e6Κr\ { xaBL"[mf8Kޢ8 ?r2ջBfZ<Ω!nWM}з~+}ΝW_(?w}3W6]e*\]A6sv.]#~9@(<?r4 a9bl=CX]-▚#n]yDYe2ZqdV+jXP\ K,I#Fƍ'kԨ!P89Ώ@2.T +VRC׺4el;pyXrq,lZcく*IC!40qlڳy~ɀaӒxW=-94/ά.rT w &?ҰaCAЅ{ qb^?U8͊u'Jw+Yx,x]ͳY:Eo&+mWP:pKj&9wFss_D/~ ^讼ά\ydVg(a!?i +0tŊ 6r+gq~!*)8?`xJ-wqri*L=ο7cY*}h?}*rpMYA27NSyqB~!$I5 ,I-se\'*KXI9 j(myPj,G(xU=c_ru)aA5p-IU-]ZpyˀQ!]JY10h}5 0C4T^=Oc笢ekKJjdqL$=5˕8?ܽ!poŬXymb 6楃Y# cXq~q_G$/]Xq@;&~2r/?g=O®F^>|'WlѦ_ ~L>M+D gBRE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:zCE@PE9*"(^G@C7TE@P*Ο#"("uT:at(}zM)MHk2zFyNAw)# ~eȐ_HĒ/ڥ˗ %@ * 1}z72M|@ӗ.Xq[=! ˝`NPQSm)kxb7lnT\1;O/^P2b}h#t}&6bңw7vMk ;.7˙ZխH3s2;uḏNu9:^x͟[%F mb9 hu^d#>|2ey6E @_?wS*7PGu+[ipӍe K7Ҋ{Ӑ95ZT8(^{PXa8lL?9R(uvy]%,8$fPW)2qe+p=YN dOVV[=wosT$_.邉Óu- ]Q\Qbl|`v|3>#;BQ;U2C&qT[7(X"`2iM `y9浨dVoj_3Sp`]ky5? uD@2<>H n,+EOnUQqBgoʕ&ZmMv:F87T3*I*IbscL#w4(Ib -af>ݙl9޺W.Wz(/(oX @yJ"Ɠesp%幆yt<ͳ3_UL8?9eW?*%OrRkͰrbtP(OvzU]ڰ3ogVk5/jo]+MjUe}7W+g4 q~J{ ;e-Mͳ8' .%yVOO!x \$vMk&wR2E :r& េZEĞ Y_$G`![>#!h4? &BO% 7I<8!Cxa#O2KUΨHIuu-@y  (. /տ# @*!f^#/9EUzHe*rgce;:cȱH͛7S…)221[ð0!XpfuYۡթפ^1bW]9=ث+F؃?NG2eP/^(n*y(Q0=Ӻ#{ t,os=D=$o&P|'ɟ"vE`H`޽{sTJ?`<  B(*23*unې=*qNin<O'+w{)zk%,4:BGEu֥ʕ+ӫ*<7*">b6 ba/4C>?[íkIӆBϴk3z~!a.\O?j֬I_|?V\Iw}7nݚ.]j1SXNNQ/Eqf7qvu=β%(Yne8!:4rY_ aWSTDAíS)^pr #jԵ}^5ՙ5 ު(*=Eʎ޽:uD 4iӦYn_R~ە[$ >ԴiS5kVg'Qn"xF[ԦgLe /r\P >>yul)yBȸl#agfڷoO~;-Z(usSqW裏r>|q nQN\y x@++MgOS]/(}'2l05ޮ4 %@tttw'u0^."l\FԱy-ʝ=`<8G"T` GL翻IMaQ5 @9%KНw)u)VX|EOFr{ z7$oɻ 8̙*Sv' ^8W=W| IB n1tKGhPGDq~SdӧOuO=ر#ѣG"Ɖ2`8n?#D_g_vD5:9< *Y^ؓ7G xQh[շXqz~ԝx馛n'Z׮Bd B (g(Hxbؒm+@IDAT@zv)g'eozJ7 /)mذAR˖-e]Y/d,I|ˆisD(+8Z.ϙM^t-b(ns8?Vp{漞em{ɂG ԝEi'ؕ[_(RPrrr[l9܅:Rg3\VJB(kmG d#ԱI,J2ԽVo lܒoXv'Ѯ Gƍ'̖\b4T -OSy-{8;Ъ; eUi//~ w)\aG ԝg e 6() sΉGynrK \9K~NkJ_' xl~i^c_kd&;&x~{=%&'0w0XNs̑>8hwگgW,',z7BfuY J[N7-p%j5i҄yLҎ?wߥӧOgjAD]YݪnEά氆C3+_iB9ߍ3+S~D=d>ԕ0ʢSCѠ]AA,_,Mέܺ_ !>0ɩ2Dp;C%81fOȦ=jF &fg.p?Ct-ٳ <өSO/"CAp [NY2m*RVj+?Ȥ'DXA.w7a2m\(d9m ԍ ?(1FYL9"i{Q\nna[mlx? b<hߤEe_о$AA#Ώ_=̧ y:/kN |#8LyR0ɟ~I &iBJv< Q&L~@\Q3w5R9*pFPhc0iTqwJ~SqVnAӀy ɩSJԍصkdJ2y?6[vcxb0}4Z4P-ҹ5*7,zlnZG7rq\׉ J֭KNܠ S#ʎm+o}i 'qo)$mZ)W-VF4MxxuL!֑IΛ7ڢԳN0Ҡr+,~2B XN 0-RJ%$E\dPO:+<^ձ02. !d믿.yص1w_}|;}}BIZh9Oq=?yo\g%`87/KzT4VE3Iy'aÆX$/ Ɖ\_}Uɬ3frʕ!Q@ת-*[rE_ȝ+=Vf<#G(66V) 8A]?~xuFtK(f3B^O__\.S볿?0Sp1npׇ~ʝ;7;alofD.;ݫK [1U ?렟>`٣d=}U׸\/R…w{ZNiCGA?}@?굞>c t,:f΅y %:)N| g D?~/o=sk#М GC f'dUjU)Iz2P-'~o1k:[7dgP8J7{@!3mӦM.N {y>I&Dϵ>OǦ&܀m#٥JW{qPlۻwo2e87~ X}qG aUxxeϒF! ~N+PzئKP7'I}ħ]vT"DQPy~+N(0@h{!B*-mG`hիW:mڴH?>C4kCX҉f'u"Hn <9sfڵ+ٓ## #`Ԗ ŵbzϟw 8Е?~5[! tKZ3SAiR8Eȉsg;?(QKA!H0I{l?tըQb23J[NV~'ocρuP?;[nu=cM̏N>mCy xok0/_# @2.]jݺ$:J>CL[N rS2*C#tΜ9+W\ :)$@2u~[cX"ETHvh^x:J:3 /=-ڵk&L`͠ZNI=zrʖP[ɝ/=?ihȚ5v8qšC;߱E &>soW…-&iN%'(vno3kͤXP\' ZlsjIM޻`Wnon͟Y"JTH@Ox06$ v xYסCUɂ";.;wtf==Tn4iS/~\DOwmv7#uL (^kذa֬dA!U@hqqq.^z Zi1u-<1&ܵek25?B?U<[GvZ]WLIB;Nj魗\=fPׯh eӓUfѱ7IѤ7+9rp{.>\s^-b@P (OK믿vay/9,1.{׵v핺Zx;H@Kyt9'v%bŊ.FbZ ! =m4PgfYdqk.}zI`}utb%Nzgһrۼyso+nQm()֠CiG[~ p 8s[Neʔq 1A @M0X'+S]۷o֮Y"pBR ǏwHaZa;pbZlck@n,G@CvE߁KӘ;2mƱxll1ʠ6E 1BJ[Gwaa$!yo($Ύ;iv9`~X…d7Mc| ێcqӂA5cG ̙3]7V&Pm\eԩS<7t݅zKOe'7jժk…IC $XIةoݺuGyzPdOMc0U`x*fr5m4Mk)UzJSSxqװa,:2)0*"޹sSNVM3&m… ox08O[i+B;wɁ~+;鷊x{\;شi0L3ܼޛ๓Iϟz)LY9I^-+'-q#f藋OwyW`Cg_-*@2 u>H~! K)c;fx|ŐCx͋ O =Ӗ0OK2W>x$Ag+0 ьgީ>~ѐ!Cw0Bjc@ 뇈'^z¯2p_Ha&9/<>ݶEO[c0Y_~"+\ؑI~@s,~3LG%[2I1QlqD6?iTfM+'R@냈dѢEt=^+d`acU4fp9x}hpgN9qZlZy73LLz?";91 ϝ;7}Tfq(MNcNƸIFFd> La.9ǜUt2& 8A`.!ӺukA:v:o君z*=\5""B"@;2 4r\j\?Ds#[wQ"S9X!f~Dӡiy}QGYN`v˩RJbu{& R9-ܓI>O"##-oIb ?LG<~3K#*Kɭ([dZqfW?/(tN~S [$EJ*%49rM EYnau?v:JG7 -txS6 ְ(3[NvSgm9lْ͛GȬF,'0 oWcgϦ#FC$P|jL6-eW|YӔIBAd83{o%"f詾B}HN ,o`Qn< 1c5l0M;a&}y-XM9f\` NT Y`Ffl958,0f.ęZv儾"nݻ`XN8Ȗ'gI6jqB!fIB9"%oLm bC I irթS&NHcƌoq6<(Y݃p< [(:?Ά#ۺ_.S,+`A)1c.Пְ4Voh)o޼GI~p' IC6 L2{ c|AILdYtkiԅMʂ.ǹl*z/ ;b>}c\P۵k'Γ'O@z2ֱcGQy+eʖ- tA'1Foٹ @l\"aؽF (3e2pVu$[Nsf1G[N@w u0I0~0IQ0IMWi ٳ}oj9FA04~"2/ࢿmk /+ 8 =dʔzAK.zJfk=+2\?-[6y{q矻bohU65ΟVsrdV̥O=qc-'0/qTS *X0IٓI+WyL %w`}LON;I"L4Z f.y9]ylU08j{%@ >\^ZhPxiV2ehȑ$Z7.s~CX{s>97Rv'(H_^0Chs8sVFsl׹`0ȨԥKq1:r3I$!Lcb&-)e&3[0Iw2ĦK~x%~x%.;4hЀMF+aE7㹀‚zہ8#<"]sE| qgbi.s9):#eC h/!cϳ'` ;;{?aӳE6o]g܀0Mi҂2^(h?cApuADȑC?b}Cm $nGΜ97vP{8fbjѥ6sBb%q8-9ۿ`v[NY9p67\u p5xSrž [Z[NLX`X&>*0Ig:;s1?s9$[+M]Q\zAla+aP9PbŊi%zuhhjSzSnurEe#O C !"[Osj:uٙX%?(),'0-T/K^$Q׮\6̫"&ٖc ̝$s//x݇Dw8ʂ]8YiӦi24'ᅣy΍iw^@d.twT"BZ0/ 2y͒Y:fcw /qA K/I~@Nn$ &W_Is{G腏~6?KJ2T~-o4AaF{ӗHLƌmܸ1aMԍU{@8q!QSdfIG LJ" Te\~jPIp0R7<8eX.[|СێFsRcۙd̙HBٰMG>ڙ$6엩f?ŝ 4d+`u xM{,Xk<:tf;1mVPu8 M3R71@؋~LkCFg)h9;pҁYڮS.mN.T줇xQaL$y2I̟?O #NN;$>~F^L=w++({!ΩzTܕ2Jep{&1Ijl? Ko߾-))ae]A&DժUK |(F7D%g&Ib(X ?qغ?Չ?j(o/BzǹxΆe:D9tz~3.XMYt/V/zUIn3%vKݙ `0Ä0ynv=/+B}, K ĒC$CLt$Qg 3ɨHf,B%ΟB0g!9?ѯ31BӰq;h٬Y3;wl&UT;}0!þS!6C 8RgwW}~ ,2/=q_f.ZN̬6dbyL2wES$,+0;1ON\@n] j/$asrk6}%v/S@P@vf`̠A4^e% k{U({ )X @2g/+dᤪm6ƙp8k9-; |{aϟ?_$<{0]7 $Qȧ? w?2ɔ͔I~E~@,[_CFϢ[P޼ʮܢD~վ}{^Q'cܸqR73 M'%l>_^\ aNz/Ch]Rēu1E $/;  [UĎ9dVDZq'mynRU+#q: kumKa 8;<.iFhsG$Gz3OV` &CyJ~'<~xNjY(K6 }Q7|oNRY(q Ms]8z󊕑\5BpkS|*@L .[q2z5YjW(>؟0??})V=ƹr%VNfOG1kl}x(ܫ>EZA  v+=7QV,S<ո߃(Pn6٨ɓǠЂ/ t GczFq6Q/ҖVa 3Rym]ԢNy*S8<_5P`Ŋ9I+U`$?ylރ$zfOoq5rͳ@sWo%hq2ԠJiQd ijHc&tXX$Oi ׈'k-R97WV1`ohrڼmj-Jj\~ )aXcEya䢵ȿhh ݢ$Ss/8֙s鏹y=V)U 1ig'XFq1dCXk~} f؁'ˠ풌*I*i'ei+ 6ZXZuT iwYrݓ~W;\ulig1WvfX)L:8s!{2#'[T|%PB(rH~=}6^I[%+KtT~/6GsJ ?^CXwJP ȥ:rϬvksf5Jvrr7-';ܼs2燂L2DKaḧ́S9CXO/2p}Pb?@څk" 5rB~@ 5b3gV3ìZpPYNv&ycC$|vEh-:kU{ eoTԸ:w`PkΧO~LlE,c@Ѧ8U895#оI u ExT^K Dv&˴i0.(HJ83{&Zu/5Y2`6ςh+6L9kIxUu]j*W%͎Fc ,.iά`u-Ȭ8@Lr|PH̡SWLkzE+8K\%P߸XIЫ)IXseM+M'I=I3a}Wv6aA@eGEAF@b⧑3DIㆈDaDdܩOYn۷ufKU_眪ImítV]yJ}$?ׅ7¥rA'(#!ipIF,>T v_~Wm*Cu:l,aG*/{T7dsoc?ԘL P$i!וR`ؐ `XxcyT}k]#,[HѤ~@e,י )VV0 !nT]Xʪ7JUlO^ӹe2!mS,zXdu]yMGNc嵣/ɘ7mUO0K2,ي WridH̖:ͳ "CԾjҩ ?D.m~$7&  xW^hVFt5u ҈c9!_0bď}Ib>K?hޏ ?ݽO^̶Fk Щ6lFW<}_lZ* 4#ko,_HvZ͔p ^oܶC?-x^ y`ǟ*Y jbK _}d7ͳ֭i9L/^X$Q7]ӠNUta0 '@p=/Cؙm$y YvdKFz&*i /8 ^xC~kiҭzD( 4i8إk6ʚ/][nm]EPݧV|%`#*sa D@j,> Y0FV#>ɉ)-ܿ  |I<\ժT5{eg[d.S̆ @l/Xq Ha$@Z)F)3ZjdumLTR*e}m:/ȝ{^,YeRxI U(j_@_AUm52/KW䄟_j iJ|.$@Uu ES2({6oaFmeL1j! bZļpn0 ЊeiH d  tl^ H4T`(×dx1qh|@E LUh|^:H_U::yL)^|IS \A6CYY3I p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'@8b&@$@$@#@:aHHH p#f$@$@$>HH'Hri}A=7fz@ Y mZ ˡG|`^X@{ËKxg.?p=BxxU ӯP|BZHK5KeowTԑaYCrݢ4%X|l3DA\KV5(M<iZmB<2@d;4xɟTxh/靝% 4>M 99b :\7W[n?BeU9\Hj>`ۥtiD/LdP!?e'RSΒWcGk'?OWdڲdOi LG*ؑHf'k4_궝55~2;?}jN(G'v-; mf*rN.rJ#j`2 ;3H ,.zO Y#)SYI#wV}!yFG/PS/-'dKKDTG.yްMh|mߚT囮SGݩ'Օ[.#WhTrZ;0NXdmaR ][$_ݓ/-q8kP:bƀBұe#i~,^صba]"Y,Tl g7c励lJ&'gɊ#2BIAPU#]mmY| "3O Qq?:55 zEB׫]Jꂡҭ^+̀nm5> .]0>@\z05j?Βo`31c'O"?3Vsɳa&Qql|@9iߢFV$KeƇc 0:Ͷy}"DTMC(F~ZhyIű>Y&`|:tJ-d < sަӫF3'\5yGNxyJ•UUcFV;bN;]z7$a󗖶Y Z4+W+>ߪ`rdRY+2>xS~:utXq:rӄQ:ceԪ+=(w]Gk,#}qJxIb=yV^8dtج ʣh| fg5dW}GF]aЂ+'J/7Y&=J\@ Wޑ|Ɉe͗䟈j't`s:5hLweNW?iuv+0f %+X|#@HO[PV^{+!ZW^*9y% ??=uѓmns(@Z=WXk\yԜ;:cetP䍺@Eg8MHR:ֿk^#%ktIJx?sa3X u)ضŪ8"-ד][ɕyV( 9j^xL`7d0,Yfb#ի]V^XW^Ca>X}S %$FxIԝ rAfv`C|UP!J1ʥ'7-[+Яuk~[%V-`vG-YX UtKV (|ÌuGyr>z^#_niA9\y{Q?TQ6y0VÍb](#Z v G :X.5W{鮛gg}&)8o XoyѫN?*!C(fޗG:O󑮼SgTqTL% :3FңtS[ړ0:K4 >Q׿UƏ/C-!˯K#a)ujȅg^gݴx2> a߃^1cefh,7XA TMH(a56|t՜;UGNXDNwfzʣ/P4V6:ݿ=hs(EuJOw0KruJ]2EdTp!@PJj>pw降rd]yMGVXt/UʀA6?o~03l&`f7!bIDATKt)$.e̙s9\37vږ wrT'9q 7sV_ZƼ"PT2pE+U:ጕn)=@{Z6'WWVۢB`lj,"đS oTRY~;a1ۃ\0I|qΛ7Oټyeu8 d?Invs :3:b!\U+ Oe9bfͳ_9h3Vtik3VB?YHXGFE夛}nչy.f7:ڧ4ԑYr^vjc^:%KX^cT/,WXvL0A?w! Sy{OMj(kCv0<rߘE|Vs^i$r٘BȂ~~<  ru/l1?'"FVok>ѩcIvY2E;;)@gNWZ%wu<,ľ9rXK`_8cW6cedn,Y!paY- Pt0QjO}Yvj,oi|];"SHN 5J'8 _p~m+:ltޮ'ؔЯ_?{2p#2$W[ג*;|m`>߲#6r$щ2Ib`>ڎXT9R(TQ6:w`:zMfEVGw窟Ӟn0B ;j#JAϏ 9;:ۜ;m a$:IBP^{Mӟ,YYΌvK,N|gu,Xw* j|L{oTSϖf:m-Al ` @/  X>~(e빰C~׮]ٳm^z= M&'O*U;sb!|EyўoҥuY3yOA@~pڂ5u `ձhJHm '@x?cGN"md_أ}2DVDdcsG?~d?iH9E#c!vﶩz#dtHH DɎ;dԩ7L篢+#^q ҲIvd$#pQ}I}#O8+^‘S8W^'uWI5LJ5 n1JFw^3g6C?]|>#7,\s]B3F8ЭtiD-_+Ku10,.t*]a9SgLmz/0YUL'Z(BV-hdIY+5ad/ILIy}vtHDƍF-n8=BF>W^m U~6A'RﯾJ: s9X\:ҦUV:ynҳ}lqOYچ6)t.mZ؆=s_B ,5F'ZkY0$Y{@jc_Dz7#0ܙy;q@@o)7o|ed̘12ÞL"a0>Eúr農@wܸ}Ybv3V2eudʄ:cLY=6cm)VU(B#*Xy-8q${䄗AYuuS%T>01:,~~/-p/r79(%AѤI5аaC+bB<-%ͳYUuWKKg_3._n+m5nQ?e>Yb$8 '&ȩn&˚/idY"lI??5B>#egI0czH>J(t5|(߁,zrUWY;p@H^+f Ni*oh| źzv+zd |ffH9ujd+g՟QSe[,łSS77-]6d( ~~~~M>ݦ!/m=Bܠsشi\}Oش>PVu`phM@Ҳ8}N;Uvֶ|EgEg]|MI(J0EVɷ66rz]^eaO Nk)] ;=m 6 a:%1Xd1B?|]t'q$rezr՘~EN-Mqa[.c5[ad%| x ӗD{ o w\ ڢ ֭QM&$i-gIVQ0Tx=l"/巿uLWFpS,%YXY~k/T#Z"{tŽ<4 Xgٶٱ~<@:HkL:k|*L#שcG{WmfĨc xj6"/cJo^qTPfT[@*K#@p<2i$:, e4)$ c ^pfw_{ 7СCw'p7xq 'ڒR d ̪/w>˭ǔ7 XI&F^x۷; a$@I$@DL鯿ZfΜ)?`/=WwW<ըQCnF]]O &@ܻ `7os=yf+;:. vٲǏu$ THyK Ϗ|Ϗl8Q㧹cN%ga HP!:tt0qZXTm[`]+_|Yڶmki2> 0|0 $@R03@ǏǷ~+f͒sRjyI N gzfhsb!1))$@ @ L×@o3f>o 7>SNf 7nI@p@ Xc{޻K~m~PL5Æ ~YF`uȦQ^0+ؿ?,|G`ogh6^~eζ6! N.g^x 8p<_Jnj{~$o=nZnV˭]?UB  4țw͛e̙2o<[0|XH1Ou c^+7tԯ_>CC H- |/K̀W_}øGzh_N]pc`.]`u!һ= D@41/M[rk.}acǨ}nsp @h"32ѡ)#<"f͒۷ jjѢwWZ,ݓ^%cnI (_ǡ,7>`Æ rc=f>ba$L`WʕeҤI2uTiԨobI (B[5X[wߵ X6o;v{a?|uP ?O7t#%fe C իp5ʮc .BiA -)32DdܹΝ; @jځ{&Mdڴi2qD[ϹixKM* @iP w1c<䓖h\hF2^bG?n ŏ  Te oZ|E#G4s޽-Q&\$@A0_&nFϗ[֮]kn5[xwn~{cFB"@liOnn̞=[̙#wu p v 6)SԾUMs"t). [0?9992}tytPnFCxair-e@TA  iK.y뭷&?묳߷o_kq  t$@<\/<x:u {ƍW_}|Ç[VOv0= h#K ]۷o-hvÎ}n}dʹ+!R,fx6l`=ccw3ŗŻ\LL>]>+L_Z^lQF#,#8 $G ܹs;wڕ4i"ӦM'JJl<܉,W (5 R㍙J;nݺu2c y' 먋ྲྀbŊrW[߬Y3{XnH pf*#oZ|E~~ݻ4D C$"! f%ϟ?,~#{X 5w:s=NwH (AiD͕9sٳeVvT>L4iTR A @( o|@NNx駭x\qiOVV}F?Tj #@~u@|| ,ةo߾{ aH"J b@||rRé!s@$(2YhOJLH~i  "Q,D$@$@$Oϒ @$ PDZY(  '@χgIHH ("Y, ó$@$@$IVHH PY  $ HV+ E$@$@(, D@$"  |xHH"I B ? >맊+frHgj$ s:'MTZx#Q?A"W{ks.)UW]E?]s5[)ers\h  ׎h/m۶EvQO =}Q PǝoTE75HW$VK .`RRӧ*Z pTZU1BQFvy@5P$"+2.Ö`ںuz衇Lf:yb B 7xC8qB ter yf?T! ;ΝZnm&y*ڵkWkLQ d&GD9=!ғW4^w2jⵢK+iC]t5s`rm|תJ*vQ-ZP3f0E4b ri|=qJk(5{65g,ߤfdFE'I"Y$V<̙CK}7eч _~-[FL#e e薞Giׁ#T0  s礸394j:tSj2*jΊû`r{QӨqİbz.`рGn)OtvZm/]__剑3Nx$)_!ʌi! q6ms"ME/ |މA^fD.XM1sѕ`0xE>(_,mOť['W ,\0[nꫯҔ)S_?O5vٝ2_a-YGycc|uXlܱRMx(Sf`/r( 4;6,q#vńT6I *[!5R n4`a?(j.]i;e6~ k &TMaFd4\/,sTUj\ل67_wXZTwyFiaАnѺ{iphR<Ľ( +#Ҿ,|q06n:}=P_xN>AE@18 dxzenT_1f3&/Hx8 }Dn8 a 'B+P[ c+5*"^sf䓧B' (;ǩJRS[XZȌMkV:JӴ57YXx;zzv/KmϚ>c1p1Ee! # 9b޶G9yief^ECn5^&-\G+7ye6pdɜ݂9vb 2׫CB;V%ߌNx[xݴ G1oJH}FԘO\6ܥX^^)L-Sgoj`+%32HB(df,zu,4uሑY Skh\W Xg|n\sUB^wjʒ F~n2lm)5TفnlTE*Hf]uֹJRkJ<ӖnǓ|daS˖,F=҉ #K 0ovjʉz-+Ty,\j7zKعESW1i8\ȬJSfש$k𺹼P\"%qEAeV#KݙB`㵮I 2=&+! >XPXʲ]v+/.Yp wkZTVT52a]augA 7Gx 72; ioA=ܹ32n7ԡ<)=9(exX iu)Z9)8[N?< H oqI 976>H sQM 4QFXattq1"˕e5狠M%4V)K߾XmY26Ro|2fCz p8i~{]=Dz8OFP1sxO^vHD !￧FQ޽MUfȷzj뮻n^Q{nBP.P62gD?H4`!4xTpGlE3=v*U;:S`(al Ka^wu裏Ҏ;0 ګxc:/ 5 s^ Y֣'O 7=mDw(h:.;ʇ/YڷoO;wkךC>;:ǏJ;޽{ui\(./ŞF{qNtoqVF7er omU{j{;8o1x)Kfzn6<Ub7Wɟ `_,|r 1/M|;U=8z\2` Qy=yC|VI?ؾȾƜse޵kzWT);d h,>b%KSd!M;US#FO#kʏ3A uIśJ(^L@OTҥqlC2Xjkkժ5ǽts(q >֧M_lZ@0'8bٳj Zf}t:vK4l,es^5x {pVI ? \J Z6lq)#Ͼoܙ_BB͞=J˗Qŀ<3OP6u DC ZcϏn2 ڰmr`4!􍸇{ZtLfM {8a` 2kt-H@E>v0k3`VM/M1H8;%qȂhp9y }4f&myL9IMfRr3=i.l)f\r̕*U"CӧɌs%fSx'o=wIEW> `aܲd,WK_N\(ɔjr1..[n@F~$s0@qN7|WY8?ݩy^^9 !;d+,Ѡgӈ_"mdͯ).oьww/K%c@)KaA iK"[覽K.ԱcG h 0@.?ZF}G7$J00y< NC׿.Eu5N..AP;8e~e:7)(_<*Ih#+0ry<ՖB@mї6b(ݲ6Lq^o")D[EfW/Ohe HdXk;\9,Z#] Y XȨ*K,Л7N4;į?O3B|0BK ~ 0gfZnj] 5UQRf}أ To"rj{z?lf zX"o!5x 79O\؏ o}7m9m{8}f͡<b &)kV СTi8ӌVy`@BfT1D`axGt#2G "yq+a 6ʗ*Fu~lɋ7dWEa ;͛"'j/TwV kXTGk9oxe'˴RMxz Dp09s4 Y;躺U%-Vƃ,j, I-P4s&r3H:+[c"wzF"CDo{JegoO]oA(L)BޤFy]jlBI;@%R<)xǩZW[v"=8P {x XD*(`NZ'nzYeDݼ9~Gwi/;c^MNhgm߬yr+zȝ ČNQQ^3Iy uq~XV/3tƶkӐ=P9z7 o5O@tjՈyTbi)6aZz9s¹E S>0^jeޛ̕)9hG ߮V ,FgJ_IOtRV@ᝲi/܂ zxiW)H]nfOܲ \/}46VAAדNRi XTn׮]{А!C*|g?@={$KAF[ ȣTBԭ}SY 2o{03o}23]!s/ B n. O ׃ـUy*ܟ`Vt7g'e3xO=<$Տ@/0O` gKkkP{8ԻwoY _'S!~iK2ǽ.=c<>^i"s&K(Vj]; h׬VS4M[QI׃bI=x,V^{G{V~\Vߨ,v7֙}WhժU @Ծq坱sBvF$98%5E2 /1Җ˔(Jo?~7uB.ʃ"+,5P0sKS=)^wJ(ūxqcէO3Pk7|pcv@ոqj ],QmF3WeҼSڵK 8z5jbhOc9W՜jϑo{1ߤ'jf]X "ˆQg(+hu^G-1t<9" wK:z(]:t u<ҦMh޽t-p[[+-{rWfk <}N<B__e4vƀxual3ѱZħtdR:MW {ѱL;֩-Ew?>M2VXA;v i?#Oӓ"?FIO-kru1""P: .ZɈo77vނRrwҶXLji-QOw`ӾDҠ^]wS~;k׎֬YC NI> i-O 3ҲyyzsCiٗhh=!qd0H_Aq =n[ k6^Z2}<'HB%_wIT{) Y%e-/Y"<|=e9OoϜV o5ذXu;o1m5Y WD=@sW':/37ڸ N:{ /jfPZVIؤ,?LT3Tk0>4ʦ׺O̹KԮU X c' 苣1/aQ@6,:)3 E&7ZDaI)]xv F=x0/nUd0(}-bvdW/U.xT/gx ;[MӓSa X:4A"Qr K|\K_׵A FϛwC+gFR ټjY2qj0*8 a UTP^I9 ӝ^~g6䠞wFD!|6€! f'J1@`cPԱ$p@0؆r_ V9B:V_F:;}hi2n ҀUEUe@`Eu@sJS:N, F}~o`J͸,#ƠuH/"OJ 12dڳ$h^,ꛔ,kf‘#G"谖*]`ƏN8QG/z 7$cee s샚;w!I`}RfxF?s*##Cԉ}T$$$3f@5W@@ZtǕ&a2?Dk 2ʺ3cǎUh[+''Gw}Ƴ>}*++5a1({TaaZjq& j~}cXt9^+9MRjݾtƍ,fk(ٔ<{0tr1/E9+65ISƬ.F]jjzꩧ i/ vŋ hȜ3v`r'lpaQUmN `#G4?d޹}QA~P(cWKU* w8m)2K}bb"^4uXP™l!vb x]u)t<33߻wo:Seݪ#ϫXo pB:/M-3w}Wuڵ/w6]U+PR#}gɶ]Cc쏧79]ƅ~ܓO>Iqqq:G2?l&M$1|QRfӒm9_ȖGh)5|MbV\05z-9˟\i%>+zhr )lq}tXBl;Է['uj ]N`o:} D Mr&wS⌵3>w7E./%\ieY|vpŮÝlIs?VŧRO7IRnQ1=є~+w6vSAu ~,W)Y?}{JҖwSѣtϲ"F>g$̉XK dȇcxNtRf ;e%5׫W/y-B4MPLU357L7A7 hOFqt] 廊J+*ћws/o0b -yBh"*4yuۣ(B/rɶI&SX%r D',a2煯'dđ5X6Y:Z2(L:oXDWT1 eV7Lxx,{8e^m|ނ7oɝ# ʸH``%#e[zpxSk=Ar 1&IY >u# X%w$l l A5F)+N͹`*0&06r viDZvk ŌW??bVFT(gpr85mPzmToK\#;e󩐨v88N}lt֭3_wGgWKE"ܾ5a40N`wsI t߸{ӂ)a4sI}@?+ށcpfAeIz[`ǟ &}Y_rIzCԷ+EAͤu)>[J`j]f~ϩ2KQE\1+?Pd6碾S~'TsRx:δZ|Dd񠎕|9}j뛤:ww(7UM]V%eH 6A:Dgot\JHDSQI1n[4B:=8B;vGHm޼Yns,IqǸC]TuߌJLgq:h 8\y)׈"&L-IoV#o0`}9:3EɓkH1e]F^KsQΝv:yuXW$ 0 Xd;r:?w/D]Z]+Y@fp6lؠ]ݔr'z i14@{zⷖ˖-SM6FLgp0XMc[ON5)R0272  7}FL3 D\8zo/qL7 1hG|F#76NI~vE0t.`@b`Fɐ(tm}mRnkdltnx;spkA|YšsofDǛ%0pf s!S|IENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/16.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000145314776170045033116 0ustar runnerdockerPNG  IHDRasRGBDeXIfMM*i4UqIDAT8R]HSa~;nMG\δdHԅ?eA兴+# *"&$(CDMMZ8kZm܏g_ 9$-A,nFewpnW$(<|JH)"!@ &ctZ l6L*F\PsAdfw -Q 5gUFM cx3uDTu4"haZ\@'zb2"נ ]#a+>8U8ʀj3*y]ŦFfFӝˈ,xqQ.{ư?$m7Q6h!lN"ƣl"rEՒȞ DZb*ըQTWjT4ja>,`~11[?fKx Z;q6A z}Qd@TAֈ>KQ7z¤#K!fhK!.3I1.c,.cpx*F& ` K|(/ܱ*pb.'OHzn;Y G6edHHjQDK.axYt:it]+@`h >ӝ99z~0Lz0tK(FZqqV#keqFu?:2/1E!Y`:^JF64@8;{yTΝ;iժUGW{t83 eʭ U|rXzwPŲbIwy!{SAId0j7|5[RmRIXTűs᜜Oy9[=oxi$M]+ {g5g=z(O2iiKKO7}UK⹋?6bc FgϞܭ[7^diZn YU #Y34`1@!~ku$CrX@nWU 9$A3DCRI&$^*կ>NFE~'"1;a(ݕ<)+>ZS%mJ@ʤ._>HIH:"A@$*"SU|`BBBx$ k;@ ?Zy,HHYQ(AyBXzSBҲ?GRDHuMBJ6zh"E^T/a XBjHHې}VZDg41nd:_|x,lHGyPv{P ֝NQ&AN +;{%1۞8+@!אyzՔ`d+M5g31f/W/  1^BRlFpKV9keR"`i vN;E(uZXG@' [4sҽ'nipT) T∙5kᦨ $]' qV@@}UTT~ʽ{6ڳYllJ<:Yqa=trK"fj3jP!9>v=y|;xwwι9.Kp999C/ҵX )pJf V=˻x ɡXjjjʳKy= PL&x7E>}0DddHHHІill X{ P=ÇYϝ;WimPkJ'Oh qgGGG Ċ+ĭ[d{rϲ23hx.jJ+>)C2Zxz[ g3f 8Pd ťGDDPH^U{2j mwwoS/%2  Qxpm۶Y 53bU[]O+ij 5몈YY( Zr1o< O5kֈ T\$wg/΋=l u1Ͳ xDIyTbGbX^hGxߵZ[ѣ\`=SF|B8}N$'qZ{xn:ڼrrr /OWMa4п/͞=ONYYYrZ;1[J)>ޞ[SsӍ*k(9:sfFР7vi1؁ tbA}}xh`P,n~>eܤICCfӻ[@r:8KyI 9;;#]),M {N~}.N+҃o}b7{΍!^J*8s2 iI۝a-K_(j؁[ `]]d3) Z2g2 ~ЏxRPG}zUPHlmx=Am)P Vᐻm2SmC<^QBԟ=C-`04B\a\gKvm Az,'{ 97em7`wN,'$,hTXqu-UE^ VX Am /*23S(\PȝO;2lJs _7KidZ$dz]b#w R)cZuxrۓ촱l5AQ!j4,Ə =B?,72AZ4kVk- L7g4&YFPVdpG?/M3'֚֒MJ:ū`}S Ih--KUVѰ@Z/OM Zfq_L&ک Г?U/yfdfhԨQuVi^HZ6q H5@*0̕f.EG7F/z\,,,˗Sxx8;dȍ{)Q!,ES kŷu+t֮NlذA 0@ ۷oڡwT|Dų v¤#6o,5egԳ^\|٪_]~Z{JB^QR[E6mHNNWSzpŃ!H6Ş= bҤI8Rw=ׯx7DAAKAWĉIb<}_%L-YDdddh#H@|yy",,LSE+jׯ_/e yb̙ZZ{Vp{Kz)fd@꾉Zn:'J}16>>^ 6Lי &Çw$V U]/:MoZq*CڵKkʱsEa\Q|A񭲲R]V cdAM6;s}'2smniRZ%$׷`!2rXThHOCĬLWə╏GREMmj UVr\R,.i^vR1< x1zk>N(**:DӪU4((u$]i;g8%/7wp"e=p *3 .;wKKR(~Dk7o|<\1 +K%y( ya0d}DŽ't+<@Jʫ)vi:;A6ÒN:prT:u/aR>@NO!H8v2*B~d8M'=:q}>KZ9ini6ϟ?/`ΝK7n$ м: \Rx}8ORf7ʕ39s@n=l$JSNz˔)SƱZSI(Yƍ̈́ \(>Z6OW6Fաb -P@t Kv8eF;|\z饗 _?/~uqhZT@>*ZIШ1QiɺmfjӨ&m\ - b>70(1* ŵ$}4Yt *Qɕ;:E@TA#Y~ۼ7MW7.$T 'oM{/ti2>|D@?8=TT)K*7%:`'шsThaΏēgR K欤eƖA5_9@>Ȑ4Pzٿ{駟h+V)8׿R~R"](؁~MF;E Q~*Uz 0_ NZקjǠ `̧L:,`_7/奲l'7C ` Q8O~u}YLtczTLqy,&hصkWi>zᑇ6e~6V RE|dyr6O[?H-VZԣRll$# ).4Q '3}00k*$"1ۖ]D kd+0c]wEˆ03lMgM+[TDQ0+x`xgpufYF5_\wL<=l?u>3>;$f() A*T 4_3Ry|\ٰX1-~ ,`!is(?Par>}4l<:q4@eH @4abC9g/GM{_HUaPЂ|?H&/S'e"? `NfBKP~6>?ϰnKB!/}_}6a5YtYRRkG}ScW&H*p)M:p/rw `кh΃Ԫ~Uy]*^{j}魯QS% V8/:{RaiHkm.&]!_negLi _\ymU[vuMk1o5b5wz&l8dG&?+Xf}?CiKֱn6bjT?L-ʢ 0J'-|,_t~w5jاd^`2 yrȏsxx#ʖ,*BI|/&h/!.6ç8C'%?#@H aȩh!KBptRV@G(Ĕ:H)ыJ]]6)͎MPv;Asjt w_Z|eeA,. xs\G0ש]{s\G0ש]{s\GmLn`J-=7t OO{G5}zbXX3_k2GG S5 +@oʗE&1Z+Pݪi[ht,c1(Q XA^E=u7My 2  1(WZEݺuUE |_Ѣ^U D=(??&Ѳ4_o\:uIJz!`*gC۷zx)C|"]Z;rZbO4xBL, HIcwv9D}zfJ@[*\8 Gh=믩I&qM( QX{QUK]xgf__4['V7*|;R^M64{lzw70?\|(o2BĂ[y*?nmKتs\H=f`"H|uccw*RY$b $:PyS9j޼9b `mN XG! pwԇĩ2@H3aEq?),ZkTz4'{1(6mJYUxo@[=s`U$~5+Yן!޶O*?l`5[M^DL8Px/ziҥ?$(Ǧ,W%(_qyUPVrxmX¼#-#dEm?uJ0x]aN0(3j(߿Do!Cr]6KY܃z`||Eɢ[t`Eќ5>LnRjwS^cN9+a`HF#0lLus8V>fΝgk&[=5\ N0}4ç,kZ! ;7[4M1i l 5ٛ~dC_\a+/R힘_0\nfRj_HINtM߁C o]ܯ9|!:d{9S`A*?ZZGK˔-[ּ;:A1UI`zMKf۶m6mNf 0tSF4zU*, q9"->~ΔR{0r$(˿43a@) ѥgV 0%0Bl"20͘*(T4h]6 N es` XM Řҁc(}d± HW&vL/K˪cPVr3q tBi)dÆ OVկf}1<1ёmA53ۑ}JZb#|iXihJf/6+XwRygWcǎɛΔR23$ vѬe@#WM6m0l+d+̰B ݝ/(`$57.O{^D!Ìe62'W1cLzlKZ+ l޼yw `CtOr=b)A>GJ NMZ$[ᘤ +ʗ2"0 ?3R|v0dΔde"HY|=MFZg[SY Bm[^}Ku0g².n!t|1m)ydF|.?9 In r}ٕ4 mK+Q'pLC&Oo!zgLPOEZ%h;Q{,s]π!tS7j$f/:f,K9{cfR@hӑ% 辰|['V :87~-<M^a|/~ג5[,z,ʸ ^!A!P³,v噖XQN,]421@(2 Tpa#t"D*ȊiM6-JeҤ5e(|NAID' =l(Nj/( ^sl04:kéoѬek8baYEMA' a%_~~7[Ai)A2 e=aFfGGGv"j5jkl}nEc'iԥ8;`9 x2gubpi»A7xʦ]3O+P=*{/Ҏ -WgAs,5~9u0.XTOZAP ODw,=>X,]]L0!a] հvɏ8`heYeEH|/ct- Ν;=OBMƿna-7GBDrw24'1!Y`HBI&tI)Jٔ It(`!}`og_6{`GS9A_OY8 2Gݍ.wlʤpg_C9N wߑa2(~ AΛ'>0{1fYŴX#@?kڭyM_J Bgh°ʆ}pw0{1SKH&aN,E]X, e2X#gHnI%^  k8r6$лl 4_"-M-XUkZ[|Oך-;i ǣʥg9tgd) ZzZ GܽӜrރ _<ĤA\![Wu&FG;Q} 5b]N'[/W?A% ^,$74+7·:}3"9k Ty!hͬO9PVZhF_h2!|7TxLO~D,-Br([T %* xsG0U{sG0U{sGlnb[SSiwSi] 0tiv(ILN˨o:)`0.0՘Eb0 ଵo;؛áo{vC8MʗIt{\#M$vX,W_QUYq! k1(]ӈt9^rZ>ݺi**I/[V*x]u1s_:W ۅ1, ӳ!|/˜6M`o%0{7լHr>x4ϔ9D.!tAL~ R 9a6'Q3fO uCKzkw B&fbb V&]4T&s0WLq\5q{h"^^^w@--"g0K{bR>D˥u>7Hr- iO ;a'ia^`?V } ``3M&R`M8*V(1PKti؀Cԭza)lYteĒK2yU_xf' ydT\SZ- e9jBx`jP/ 2>α#1ˬB` h 毾Nuk+_,AM V _~˗x7Dzg[PVAV 4Cmդyg9v( # _9I[pDg9p*o*'VlRO09LhGFحm%`=V_/\|( a Of ~Q>N[zܐBjR<C,YKv8I,jQZk >g"[|(Ûo*G_~%!66Fت\T$=* |c0'AFH㽺gJU//# *SI| wFTRYGd6Bdl:` * v7|wb%)IﵛCaϋW^yEoX2 H(@p,Y"B7a($pЍ{bjTu7R~qLԮy}񳮌%bZg' (K79CЭ1|yZ qw͙]YUrl'@ߣG @. s- E5աxIg t'3vJ;ߚo-|U;t$єm{yeQ".;A ̖d+dׁ#fΊ69S0tl~iS@ @J)kfȐ!k>ho=Q MrIǃGb ¹yrd 3Z 9*p ȃR\8g?T\ KF%"d2f«%ں,-~Uϳ`*8jٚg5(ooƋ_yKMXg9L/`m}fӦM r'O˾?'G2*H[ׯ7wyY9(}i/<P6m+'w%[PwKY͚5 "yb `kw6PVe?CSJq%c VF'V)Mݻw'rm j &L Qp rJ_wsH@qT7;Dkz=+Ieˉ@UB㏉=p%imfnz*~6iqn{1DCCɒek!:Baxkr<@In&=@In&=@In&=@In&=@In&=@In&=@In&=@In&=@In&=@In&=@In&=@In&#)IENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/120.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000001706614776170045033125 0ustar runnerdockerPNG  IHDRxx9d6sRGBDeXIfMM*ixxUIDATx]xTն^!&HҼR.ൠ^=O)D H/"AUB@h@Bg>ٙ 3əIe2:}M@c5+ǾYDasxAȝ̵kU"""(WpոFd:իGq =dۢjpq&XuMqԩNjq֬9qCOVCU p@{HluE(=cYNJJR'NTUVMZ_eY?=09u]/[˗Ϫ;3?͛ݪ9 dG ⓘƎwK=1 =`k.ip$pa{q 6ϟ_ @QkN\={CB0Xqw]Slv6oެzemZժU^#V.]ΰ&dN!CWp)n.]N~ԅV7h?hѢjذaR@䣻e[/âk!h 9r}ڶNB a}"y>¥4jj4~"r-MN~ߺ S}8edڏYK>,_y\}|tF!.'[nMK,!~fb`Q)!s!<"#sƿC>϶q'w9HN@)=s%5*QČ3dujmE&fXO'̦;Q"HTptyZc?uiV+- MTL}_ٳgKhN'[fz4oFfR$`d{}o8q'+Qԩim*UXbLWAFv͚5fΜ)@nڴI*THέpm]`9\J#'B(.p;AxyS y~vZ!x{-jVR.LRL,L`h1;fJ*\g;վ^%f~ڶ(iP6n]GGtwLYke]uOWoB8n#B@T +\ XI!< D@= &g&|8n2:t)Xk kyR $z) ]ʋ f3֥0H "Zy%=q+.Q@.Pt`]P|3{}\sdԺ{Dש"Ҡ˗..3er? i*HJ932'޾v%Xgʕ*Ϋ:Ѧ݇!/f~˺\ sT y2kuqäOhEkx?w҉3x%ȫ5# 0LWdHJp.ꈶMjӐ~ݩe"0#qMEߚֽGd}Oϓ'sm(E$GIQF V yL[Pjb7Ox 0!lX3!!1j1^ەB^Sz7VLTb CE I<x,ʃ1A!6 QjhdֽxzӅ!P <3m5iF%) ^k<)RDr\[!S)| >|yjذ!}R`Y[;y04@0@s10s̈́ƵEY&|O/"5kLj&zFћo)ʃj(ԯz p_;au~ne[%'Xӛ7)+:Ϛօ=P͉ґ#GBطo=ԦM,szlt.]v1^?VuL - SQmToN9'pOb`Y[A݉Jﭰgoa[{mjُ1\p_˱͊>: zOf0SeջwoKą:l\ -8GTllk 7e{H}0ijO o޷WvfMX#(TܹsbS?P&s]H[uc+rޚͱjs߱cz,`BK]-d" 0@x6mmLDwtI-X@̵'j>p~K/)D>H3BSdIhT\\KV-s0BLѧ*O ْ1L[Oօ_-tyf]u'%2EPh>iXm2SGS—rt21Iu] 6f[uoz ū8U`ZB~ ~b w%=rgMw&Lcw#C?YL j3 3O+~1M˃[s&+5۟UtgQ7xKA:`?ejի_P3VlTg/Xbi,~OAZIBşR/|8Q4HQ>wlj &U9U=T5b";ȩnW?9E1iUVTԝO[w[Z $E!a MYLxÚaF/+E&PL<ȌG:3ypMGcǎ%Lօz4}K=/[WL>` 1Ӗ:pYy8n&ziڵij6,xF֭['~5jB <Ǧ_|177Ů^,Vë~;Q+ƂO-S֫"C?@lyǪE~.cʹxbjժ%<ǂŏ-Bb[wuU (s}X5^:g%R֭K<Fs!CIP& ؤecφYʼ6J>AŲU' o%?letWԢneke *a79={@x7.cت'aEeS: )Ϊa!04 #gQ`rk^yخQ(%׵kW|\ FIKO#f@(dXɧK: @F2s)R0`;Qı ,XK $vMGE`KY@<&cKaJ3d6 /O [2 <8rXօ=M?0vb]2+Cg3,U<ױ zy:܇ <̤@cdf@6Xn<[9Y~0S1uK"˾d k{Zi 5#L.ne3C4|0Q$Iy_ֱC&5+3'LfvN`=gd3ţ_K%@)[>M7f^ {`Ĺ+i׵h~Dl3Da+">hR]@Vݐ311GgUk2`SK)8L}]:2v Jo g՛UeyNL^G[Jùkz;dZR\;i6gwN( a]1{W+{Q$#U´?8*}4f* =q'>P^z&  E<=W M9fAɛ[LK J(F/A<jA:b0dC `|\BSp菝tQ ̄zUǺ2"{֔ Ğ={cǎO S-6<%^f,.ǺA0|e!``ƋW?$bg1Mt\&_XG)XfwՓ4tZflyYZKϴ_]}:d`-8EK0׽խ콮\W X3;%{1sȚsԩ4l0S0yw[JXvp-eɍ'˳-<3|;>y6TEw1(L ӓZ|Q&%_b`\R'pz֦aM=%lcb LzA.]}'f]|3VG#=ȉg`yCZ"ր{%\g$'zҒOiJ.?e,_Zُ+6ƪ?SRXUjʂ-9 @``ԅ] X\|scJY7f){QϷpI:vl|5{z}gOHTY~oQ[@V'dB9sܾWAyY&HَmH > xھ}b:߬تȩȿ .:\D ~]h}[3 k#Ό3T-`[Ǟ@t ,L!C(D01> ?+P x!oʃ´RM`Un,0D0^3\R%5~xK[ˡ)&9\7%Rz\e`Q@eM좟ʖ-+lb6 z01'u;G !֍u5kC"hGL6x-| CN# C0vhiv08v-:80ۡE!Z`;4;;D lF`chaТ`p- Ztpa CN# CgF:ט.cIENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/40.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000466414776170045033125 0ustar runnerdockerPNG  IHDR((msRGBDeXIfMM*i((zf IDATX X{P_885 ͸0ll4cu?q*a4^իWcQr :, &V}*s!,{}ll1+Kbl2?^xrCL\Dkb܅gqv v> dm7!DP0vYo>{%Aav:FJz_!9\]jсbK!QGpY*(( 0BlT8EE@uPJY~.X]=Dѽ0NVL%A~d>#$>-˦? ED +p{7a0v-+`/^3iIPsgG7A> *";%'2\[c8C\t$DPoz/ ;ŒlM~"mãppOùP Q!: [Uq'i;sPx Ϝs W`ɶh<tdr՗JEDž?rAbˀ {eLΞ|$LX[{ANJN}bqq23B,ߟ_\ЙZ;p_cY_܁055Ұ^~/pƍ򓟢kɓΝ yCL.,} sԵj-fs낵85 `ժUPlhȽz}P/q[MrTSU u-( r.1ϤV4 J[tz}RjH;~` RA'R5fEGQK))S^U 5`Ͳ0i7;~Zyft%AD xy#*T<,h3u045~9Y$J^2@P0=uСdm_9xŬrEak%˓\\OQ3A}P$ rw謃KD( ewRğJwJzm`/R=p80!x nF#07!~ {AvKޛUJ۩)FȚBV wN ,B*{b}8++K%If]y e%n6w!+Vtοy̧cSS02'Ko}yT@0xrt/k2 dPQJKKK`0KJJd2}AG@fjll"6O sT {@Od֦ PQ ieޞcki@[QXIENDB`././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/Contents.jsonqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000001312614776170045033116 0ustar runnerdocker{ "images" : [ { "filename" : "40.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "filename" : "60.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "filename" : "29.png", "idiom" : "iphone", "scale" : "1x", "size" : "29x29" }, { "filename" : "58.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "filename" : "87.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "filename" : "80.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "filename" : "120.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "filename" : "57.png", "idiom" : "iphone", "scale" : "1x", "size" : "57x57" }, { "filename" : "114.png", "idiom" : "iphone", "scale" : "2x", "size" : "57x57" }, { "filename" : "120.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "filename" : "180.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "filename" : "20.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { "filename" : "40.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { "filename" : "29.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { "filename" : "58.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { "filename" : "40.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { "filename" : "80.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { "filename" : "50.png", "idiom" : "ipad", "scale" : "1x", "size" : "50x50" }, { "filename" : "100.png", "idiom" : "ipad", "scale" : "2x", "size" : "50x50" }, { "filename" : "72.png", "idiom" : "ipad", "scale" : "1x", "size" : "72x72" }, { "filename" : "144.png", "idiom" : "ipad", "scale" : "2x", "size" : "72x72" }, { "filename" : "76.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { "filename" : "152.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { "filename" : "167.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" }, { "filename" : "48.png", "idiom" : "watch", "role" : "notificationCenter", "scale" : "2x", "size" : "24x24", "subtype" : "38mm" }, { "filename" : "55.png", "idiom" : "watch", "role" : "notificationCenter", "scale" : "2x", "size" : "27.5x27.5", "subtype" : "42mm" }, { "filename" : "58.png", "idiom" : "watch", "role" : "companionSettings", "scale" : "2x", "size" : "29x29" }, { "filename" : "87.png", "idiom" : "watch", "role" : "companionSettings", "scale" : "3x", "size" : "29x29" }, { "filename" : "80.png", "idiom" : "watch", "role" : "appLauncher", "scale" : "2x", "size" : "40x40", "subtype" : "38mm" }, { "filename" : "88.png", "idiom" : "watch", "role" : "appLauncher", "scale" : "2x", "size" : "44x44", "subtype" : "40mm" }, { "filename" : "100.png", "idiom" : "watch", "role" : "appLauncher", "scale" : "2x", "size" : "50x50", "subtype" : "44mm" }, { "filename" : "172.png", "idiom" : "watch", "role" : "quickLook", "scale" : "2x", "size" : "86x86", "subtype" : "38mm" }, { "filename" : "196.png", "idiom" : "watch", "role" : "quickLook", "scale" : "2x", "size" : "98x98", "subtype" : "42mm" }, { "filename" : "216.png", "idiom" : "watch", "role" : "quickLook", "scale" : "2x", "size" : "108x108", "subtype" : "44mm" }, { "idiom" : "watch-marketing", "scale" : "1x", "size" : "1024x1024" }, { "filename" : "16.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { "filename" : "32.png", "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { "filename" : "32.png", "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { "filename" : "64.png", "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { "filename" : "128.png", "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { "filename" : "256.png", "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { "filename" : "256.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { "filename" : "512.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { "filename" : "512.png", "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { "idiom" : "mac", "scale" : "2x", "size" : "512x512" } ], "info" : { "author" : "xcode", "version" : 1 } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/88.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000001323014776170045033112 0ustar runnerdockerPNG  IHDRXXq04sRGBDeXIfMM*iXXHIDATx\ |W?%}W}bjGjhW>3Z[ZZX"DȆI+oyHͳ9s=뤘,CٲsP?GNy`hÇٙ\\\ƍrk*6ԩCCQ._ks!LJHHPfRJ„k||||ĉULLcXyQT+=1aըQ#h$fsRV-b UF>237ȽhNHJ|dv 3g*]@3fMU&MR&'=|~v* xgmG'48}8M] ׷TȍH5Օ;ƽ$Kb+7ڣ xegԓd S>8aܻw?^TumP^ R-<[=b9Ln.)DCoKwRtr/}Xb͛GݻrM8RvhϞ=dV%%%C)ݍ"c毦.N{ȅc\{hACr̍fY~LC# ih#1q4ovZW#žʁt^<'2|:4EmT'$Za5i҄lBk֬!^ӧ &kTPxs}xf=4{r6!"Ovws0n]*ujxzH[IY1ZCVn;D3msWnP^T;=rz:(ϱx{S~I 8J]S%jƦF{רGi&ܹ3-ZT(@@=C_,HN] TɢEؿPO*(5<F`WcNP8VPC[ 7 w6ЮΑtζlr3*a[ՏCK<RB_Of3Mwg篆%iݮdׂ婯ޱIloA,_OJ3_ iK7Ӫ<\vslِt1,Z֩B/7ME FiSpaJ߬%E}, նmڕ͕;޾Kl<@ kTH bJXnMYܻOE}f76N3sF^l@MkW⪘3N9+F)J-),!z}x^ C GZiWNF+~>Qb>0Gxy(m3H7=NAy"ج" DߛF⑳WXT6vm!LCRב1e:e. Ϯ>o)VPCc!mI]3t^kV`+:N lRu*ƀZfqe$Muc"Ԍ$K\Q(Nr 0J,n,5Q|}/AeKGAtݕpܡ hsp!TVsx6=_܇p%}1 EД>}թVy#![scW:{1Ow)Qv6.>Al[V hԸvi,ˆtaaaC(Shؒ kS:#g^2p9^ZIIItA"5[ME@c; t]Z|(w!wEX%n=rNq,Y,#cf%?Z>y(8#\ީ Сo _-# QzR_fˀ_{CvɼK9#ߦ?%:6h+o#Qƍ^z4qD  ,ٗG [_{ `Y@-sIč=P/ƟFoQReț֮]X`ħyj۶mo%ס~:tZ[Q Z吔[MT-UۇjW+;=ږN8:u_zjٲeB bQN^R/ޢbd<hXNmAkҶ}̝ P5:Tvy>,ҷo_u9v5ݾnܯm: 4g,S݆MU. lsH>y z -:}uV w[v(FG xH+10x%rRZp5|L3t:ƎNtҼGQ? \ H͚7Ml_J |͛ 1hX3pΝ 1wBwh.SJn.AКVZB@xDM2Eݿ_WiiЕg(W_ox6`ڻm۶U)#Bԍ5 ;xcyMf!CHW#:g'O~慣t) Ms8&+]wspc4] oe L>p@ue]nWfz7|-+ 2hmk_yoMfwνXRt@q~Z/0ROnvooDjk߾ڻw^qRGg訿M_ޟ|<6v*Q"cU^v\HZkprF/eL!]CfTXU>b% ŪbŊFg&qZt^ VU߬۩a_5RNw NA_Y8vH?ٰaC6E%KT3gΔlP1l~ncϔS~ l SAGi, O?h>BX5F%OOO?~x7o/q4(;MLrm4Zs'LYa!@WЄv\|9 29yt(҂cli9 |l7q eU|d 0V@V v̈́\&Xc8ՠիVNBޙ8 &u,d߼ܢSZDU0dG u!%o=^l$4l#]?b_ŏ>KC% ;|jRɪ@d%#}x Zso /ǫ+!AXd@jy}.'&QǦuh'дjPSj} 0LYQREߚmt_ C;;354+,t ISE/5+DPG^TL]a]Ԅ2rе[$e7I )U=ͮ7겝` jm{mu8в_xIpӫ+{p? jKӈ~=Jpٙ.W{njӦSV-[cX߹#[Tsf7",I NMx4bĽQseeV@D#9o'yc6'B{Z {xԻfݹsG3Fq6a,@i?ͥ ؙ3gT>}֭t(],_SAF=0enݔ& A\k ud)#~n!=(P `$>'ʖ-kh5sbn t@5MԸqc2d*UJ>L{]9"K]vkw@& ܻw߿٦}dfJ9 R&-lݺjVm>Q ֑%K6mژc ZMtʕsӳZH<AW3Yfa$'OVjjFho(/^\ >\9sƔ%t M\ABFgB}9HʠG_\8/|}zzu*.ի4q#66V1B V ŒZݻھ}Y P_Rv7-ݬ66W= (wg'Ϥ_VlM5!߶'hOh]t)2wpO:&GѦMk9u2Ya ͛Sdd$oԬY3\{?* /Ji ,4Qg%ӅK)ò?ictFTZyD0XBGԭ[7ƍGNm:t(TR%yXZ6עE'Χm,_:THLJ.F]APu$ۢݬ.g Z)W@k H8}1HZ eJ xǙ٣Ŕ5W6P6LVxH/ M:U7vR &F9\&Fn CCXҮwҟ3}Y*HrHhL(t:.\H.XKƕ -V̠RWL? .m?ii]рAR& A*:=(f~X}4c퉎L_!Lr8H/7 7P^TPi 5"JW / 5H!6q'6즭Nnyhh 3iHZntV"z:.aQM+lm;ҡ%Q g>g; $ـ|=G(d 6"J4V*d%\LYK6ӦG~֩rdM!;v} 4lPa:o^"\Hb8D;PC:N`}:W- 8lv˄8ZtPb.1hүkUԫ} .ˠc6/NiALO_lQRݪa'qg H黅XKr$ҮAv[/A(x`1Z0 , ;wBR [0f[v+qI0܊>Gb'ޘ0,` "i瀣7tqV"k4о`Kj//+a47Ni%}}"?b=/@W(eqQV^httͣp a,'mohtks:( _01 )MHo)C'u9_$Vb9)^ӇeBdZC-p9@bxL3!L:_<4C)AzZQ>fZ>رmbhZG"Z&cH ۾Z L^LNZkFiރVh}OS$@ÛԮL+y><%x@I畓޸H0?e:fuu[&R5=JL 03 WkZ K6肋̬@1}x\b«?֗{+cz0 FQ,v]i/%*L1&#0C5*>0 }0C`SY'NJI`CPըqJf!Z kw31Pdf Oe9GxOUX}Eeʔ"ZXWebRbjeXh^ qwU 1^_pMzo!/GG}5jD< P\&xbkܧ\:ͰWD 7O_ɯ!| wC`Ᵹhr],:@Z{֨H/>|X SP% H0(92aKihyI/P17oBBa]i:+ݰ:.555Ä7@A˗ ]gA*;|@@Kh 7I ?}:4o cgi1nN6MժU ʏ%b̙c)++y26'՘,R/MI?' UQE>wQ kV,Y˚9zeBcpMhxIk*>X ڸIrXc t_lz˶y,u03{"ۤ>oe2s **g]rJաCŞ6OF՟iҢ WS.+ݪW>E9zJj yw$uq dJr^z%ŋF+pV!xFꫯ 5V[}J(?Va $Ik7: dV43LFpuoaVKL~v+aͨuzLgYH KNsc4Z @̙3Uzv鷇ZŞnH᯿R >';:  S]%&^_DYi 1v5=FOvdujAԩf͚%VNO~6| rjbFN,}6cv&ivء`hӝ]8+}'%%ejv4z% !Ĩ1cƨ FY%N.> M;-ʄhQK&hv⢣YX^2b5 ΰ _YVɾhK_رZz&7.5ݸvZuˍ۵ߕ[Yͯ+β G{Wvm5}tOh4r@Z{ot< 1c[ Ye=ғ?Gr i^ҀZqϳB|]l1|p#>;W2&G u~㞣jO+gϛd{Rv]wyGkƀTe~RRR|Hp+<"Q*K)ij;M9|ղeK,J "7X꙱scgg>ܲjWmS IA~v(.|<4 EOrz;sXIO 9<SNĝ!o@YհaC#@@# =ᘳ|u6ޚ3 #[þy`pp}铟V%+jɥ _HT!p?] 3Y6QJY tI4Fykit$0`y 7R*|.g?NȬ9@fSbF;$Z t2g}6{1kxk@,K_hPMb .Q 0@Hb}=i\wѨ}/,:O+nksVVqoP?Ʒȍ!]D'|8t`x7>J< L9 ­hDX?Mו[:\y.@A! uf"l&oNZ?ԩ,pSt*qXOH`BAkꭼ$peG~9/]y5rÜϚWÇ$s 6Z`OoUn'shڜYCљN ,? ϛ;߼)?^IrHUܽ2OG6K4x;g O+08z< /s' 6r"b0 W7\pfx=[^ ԨvrK9h1ש.!/g\~4Í2@jR=w'4QPG?́IsڗVMyj#`'0{mi09&+b&ΰPޮa `0ڛb* &!X.g@w% $0mP4T;I1"|׷`gFntͮ>3h%^ '#;mE{;*.iEޤNeZ !t%vGm]20׏f!l5ZujHvh3 P>Ǝ+|… MM= ~+jR3?%msOab,SnlČ7Xsٖ}oDßHU P"WzSf 'c)+ĝuRe`ӐnWLcUf,:qZ x5_SߧpK_{f# )!)YScl4Iպ,#B"(Cӈwk½cc!J֬^q1 u4}di)וI_s5;O> ~:iтМ؟)sJ9d襝A0\RDZͥ6'k*cűtGitt'B]U&GR\y1* ~@eG+P aN@r[Z!h%(@$ګUV)xj&QfM_F4m4Fkkm$‘!"~Z ϟ?^V0k}衇ݻMtռPHG+ݫ}fΜ-[#[nt񦓪yGHU;U hV #ĉbҩ<HM$z <0ԊW:|Lߊ ]/Hp+BvhOoČ'>~P(XO8lfTdd&Z+fr8(,х&\6MiӦ,S^BSwZgC Ύ} -)0C_)ț5LK~ }EH?>_#@|~#j5pGH?>_#@|~#j5pGK+e+IENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/167.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000002732614776170045033125 0ustar runnerdockerPNG  IHDRtLsRGBDeXIfMM*i5^.@IDATx]|UҟPBދ` <#؞PlaC6|"(*Jzenv9nݳgflR .BBNn\\p@Y YѸsb d9%dk]tIjE2m8r{IPfΜ9I"P W%$dsSO֭[֦'k$hk90(Յ  Ν5k_˛7z뭷ɓ'%T J"B/ʱT=%v%KB jȑ&?ݐ~&ikxկ_??~"o`j͉6H[h͛g$԰#k -G*WlhRS_Cd@ v]m߾~It#i5N_h"ժU+JhFN1+(P@} ip ik]v) A#&F_l-[J?HaE" N[={V 0@.\/^-鏶nZaE"N _U (}y{n#[{D7rUD 8\dj׮]Pj__Х4)>c`kJ pښi޽WYf`B֯L)8u~[;׬YS;G +pϫEmik2 BKo^-[q3$r S~5j(UNʔ 7Xm͝#GG7l |s l'~0I+"iҥ)4}I  @ ӧOO+WJȞ3m4ՠAҞ֌Q/:z0՚WWXuMzl|嗪xԤgovIZJWםd8|$" ԋ/e&`5Xz׭[WM8H7+rD"k /hdNuhKh5_>S3O GkwT<N_:iC a ?~]ҪImzgektW|:p8xh8Gm޵_~:]Y?uFg)d A qP_Q88LE9z.^Luj ҥƦcnS{3@Tp:5wzug*[jWLKwSlw9 _{9 /%ּ5j ʵ[wGJQԨ} ¡^Ǩ)֪3K>Hmi032_QuA=u]| % !Gh4c)m PI^(Ee"{$P? $֭yΟQ11؉g8ѫJ>,qNj,qDZ3ёhShY,ʙbClE%w+SJOA*tw3|PS,ѷPlY)wte㛿xG̙(glcQyE ^&g /J4a_g- py50>uDl^`"ygƦ=c'r|yr}g]r1OSc-{Q&H WJ"! iz.ڣ kK2YTZuWP%hvRtsԬvy-QYm۶gч~Ht\)zw~鸏?; ܀f-~Ѽ^٨PܢǴK6f͒o㮃 9A[կD/)!kTff\o8Egٺf* 0ScҲ;za2rZAݻ7=Z<ӝK{/eMxmڹ>1~+ uN'VP[iֽԴV9f9憪aӚrB%3QPh#4?pskWi, L=iԟ=h*TDaM@A)Y!C/^{`><ʞ=ѶNMCGEqdТFO~NGdzuJu[i7 'ft'bvyPf8+t@{/3賟C(_-?%&͒U(; &p+eCΡ:JRYK2G2FOӧO_P!yF vWmCr]P/#౓ RknЊ<쇇c(8!$K YKoӊ )W(_ @h( =-5RSG%]0ugǩ-V+4kiw{)+S ;r,u;ӦA2ܳ $rdjgN02 Am+EJ_Z@ 00l. ǰCo(%ݕ(`el@\uWP?A$g? CڲG:$’hM38Is4s5#?*14rJ,kmbn,1b"-MxܕSҗc?Ix5?+x&DA=~k-;حQ CM38aϳSؙ4w8"0P Նc0؇-Woޙa=Њё\9Ѿ'hąTAVEt}O)> WВ-̈T(a2Ԁh?hua״vh|]a0kp| o:gտCRTS%?pAP>Tg}-jӐ\ K8QS&om|}_υbz8В&p":E\pF,#'!g2(qq"\pF,#'!($b3%'If@L}/!N c'e/YBr:ꎿNˬ._uŒ_|'4!&{ZP ɷl[k$ ww# oЃe>ئ 5YAhјghD@4jV!(hxԲA5]ԠjY@D|xƲ^f ;0@~>'F1+ٟa:AIkO׻E]j's\ϋٰ4:+6.f8zvtC1Ϛr-(n;`:gMg}kFQe6sWnK70 6(7Fv.\Do!Jey#COsg 4!w5nmR̞ Oքz YLj-D#DgSkK2bݗen=#… r>h)>t{=1X*(g;#PpЖ'Oa朣ZDӇF?AL8ئ DZC-;a#G0aXćȾ2ЬYY\WkNT Z=fv`›׫JAP nB[>DgϞMr =裴uVqԣG0(kt -W0mԹU}^K F=' CC7V~ };/Y4AP [Xׂ![4}Gk׮5ZyN:%k~w gSWh#;аu cz1H`|a—&yRNЍ%ЈO؁d|ttϠ,m˖-#PӦMiܹB? Z=ħI0v^ЂgKͨu*@SJ]FF N!2Ck}4ӗ)w| (#?ˆ7tM2%4~mFg֐G o7C}+U(YDv&]pK=쮼.㳨'ޯ\&Nv@r<[)*u!c ͼ  x Ps {-e:ەSڼy)5GmWzx`YLt,XQE7 xR=0u+򘄄h1rHU|yC2<צMV|#ɷn>5ꙁ')tr/1 /LSz TݟyI@a οS͟zOnrH>=΀44 6۪yIhuEtA_bck9SOTg]lWR`?xC?q(8E3NKB*Tu 4ou}v=t6~3?Dx.* ȶmTMAg?cZH'sI5kv })`SNM}R8H !([hNעE `Sd͟/T=[A}?~e9-qM|ъ eHSY~%G(6O7SYBPeʔQÇ7A=lHJh FSb} BLAOnhSs<MKܶBI Lv^'HǏxҰѨ9ݕx@[VQ}bUƻz R ŐX0'ŏGϔ%2qg25d&>9ҥKh2yy\`A$\f<ӪU+?>G%J0mI^2L2g!O|0:'H8uŦ4x,7wI:'wkgI @@zK-AH񀳎I^?4_FԩSbŊigA+Km{_L]B壟|qQp 9>s笠y9@1;p#=9DpYVsbsO%,f~JkJ 0ԉ3rbPΘl @5d.k4c)}ʚt I㭲;4 RMK/D4F ~8- `M\M{ˇN&)IW(8Ag58g_fӯ|j ^fka&c=Aae& ߉+B2~@7ً-sC S߸yE R7&L@<@<`h֣SNxV ZL;xZ=K'[N-~^ti9I-vY8u(E6kH!`a"!ܹ!(Z'B6RotF%Bw_#Pڱ0 *1f $ٸAbv[3&_-:`ܛ((Pj֬I<ݐƌCժUM+3vWVmI9=g|.57l¯\o>TQ (Z):B?\&i]xβ);aw CPWz]=Q{=*UJֆ`Gؾ}=u' y 6jws-?p6<@_ Ni:pM׫$ni-+u γQG^gi=2j2 7[:i{o2AxIti7x̌р0(3o+K4 "29 -V(Ыn`i L+f_&~]r<'ѢaGtz88o$6ǧ 7BKx6,o;x):}\X&-\C˸t{Tܸ@ޏiiY2N`<3RCP1aGb *W\:M<Vg򗝣a4e X֦ۨMên+hJ`WSI` σiCn`Zߘ8Nc']~' AN 0+yG=5pP _tCB+o#zaS׾_>0p ZPwygcV5 Kq JeAgxꙤRNLX,8ŧzuNS2|^d;oi"g_ϳW)- ?>9)Dp*>ݩE'| Ɩ)s sc?iֳ/R8hKX/ bFE^ Sy a4(t%jJB={oKzK[*Z0KPz2]i>@x|xƴj(v6<A+Jlwj^_ܕJeyheˀB_ 4 xSFMp7Q dl Ae%Ah}S jW*#EP @7r4iu&ڠeQ&67ʥ&}qw#=Ξ?9jTic885l󗓗oR_i1z:1,@ gìժP^֞:V#(MPZ3%F?sÆ 7xU&vX.O˗iӢ\\ :Z~϶noK ~e`HG @@(E nmP 6؝5SaΑ>>´]`tj~ MxV=< <]u7@aY{fL+KZMsd? 23 xcK]r_ XY#FmGPK.;@؜e˖C@|ZW~$ץ]M즩ZcZZ>%` I: n~er<p LLY1[ ̂H.x1 2ײA5]ԠjYy34tI|&^tǟaԨQ4n8O$ >Gx? o4ѯf o`6g&|#5~i8 yFk`>Z+!KY zcj4jܡ@y09|3؟T͛77d2M9:)8sM:y*4y -ݏԴ?%T[Sq;O/1NΓ!uUoK$5xyMX&%8S||zYh6hi@9-Z(2UN5܈p "eO?)>Ș? > gѻ58apv:lӦezNn EQڳgkdѰ'#G(4s/;zr0r>?º-8˖-k`k, ڦeڲeTtCpjA?~\*wRhP$A5sL# _CK&D8Am"7lؠ:wl@ -QeʔQ|✁Ӱ㪑'(yjܸizvU>}ѣGEx*7p e ` :TyvKɇFw8]SF@DSSjÊOV|Ұtӯlذ:u.Z4.$q 9(~YFw}IhJQ[S(QB 2(+5v& A4h`@?jkۘջwouA#D7j\3Q?Wŋ7 6NGW+WԯLzF́kc;pzq~? AZN5a ׯ4H5 NN+VP:t0`Ԡ3;>uJ^k lFI{k$`3n$]8psA*|9sF֬WXQfOW^&[[.(0*\p`0 L7.8wT?8?f \pn~pLr.8wT?8&Y[p, -Inpgp\p$7Kp838|wK.8`%8p~0 R N?f \pn~pLr.8wT?8&Y[p, -Inpgp\p$7Kp838|wKtIENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/256.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000004461114776170045033121 0ustar runnerdockerPNG  IHDR\rfsRGBDeXIfMM*igI@IDATx]`t{tiJ/ *XяPEl_vQ퀂|HAz=^B}:Mի'oYci,! /~/9=ˬ&˦J*RFЦ 06]'N(JtR!.xUTݒ<Y!sUB%d0಩֭[' q˪ut#<"`1H 'NаaԐ lBg  D͛7k@Mg0{:lpxTTȑCRǞO!ٲes e >K1#-}PjUy;tp*a޼y25k|G'߀_~OSDDMxC.==z|(ȑ#"غu|{K/Pj1wPR6lHVYCP(GS 4 qB);Zl)֨Q#YJ鬬`,7ܲe(̨Q$nB'A[.ѲơK.R:삤)!C(̜9S8!:IߧOz(22ҌS@6=tAl5M`?lэuo |81(?ʊraA~_!oϥ5[wKQMyYj]{k?R#s;#9tM{K7"y1D¿xC }i4sfpѻp WreirjVU{blE-[Fݺu2:*y/\n;=#EJX}J}*LZ}`AjՔݷ%eJ\gq'lySбX 73|jD1w -ݸPj/.p!^,Ϊ wBhoLa@w^ ELɀ{+Gw⃗A)>&@q3H6ȗ;'e,?#+;K&EUHqЦ3:ML\T>~w?R왳?*R/)F? n& yh,v:.$&PDx'iʕuV\PFq 'tOE: ۰aC6m=U|"鸜gGI-Mٲf9sH[ Ӏ50Oz<g2qE8g"=Utel'"4x ,_\8Pfr@|yX?~I|t}'٥v;Ҕk(+JV=}NNg%<b8 CyRxD/\oMC7v )03g2j^*T4nX^*o~5!ASj& V?N٨@T.J A83pd{$})Ϋ*pyR8`-LF J SJ^n]Ͽ[|*,w sUԽ<!%VnCvF<$hQ"dG-!K8-/C]A'JU% yy!dጼ2V8 ;(/2d0aK)4@-*[x?l"x?Ɏg;)WDdQ33 K7^TU+@1kBŠ%=r ={rJ8?QQ r^XAղBR*SDW?e)@'Y~1t K/C0pk^7p.7=<3` Rf.Wi;6󊅳RRT©L| qԶm[yNB,QKVu=%>A2ẒJBys $_SBpSN_z81}ZMډk8Sd.?_/ 'murP^{c(cJ'W+T %|' yѓٟ2Iƞ gjJbHi>3jW,rTH 6OUe|(/ 7Idf3ڟKKpy,zo'̥Av/g\~d.{(ŀx_n'eMj&5+u^ q<3,HE @7A>(kXCA0 ҧXv,MY8 ?XA V35%d@3 `-g@kU_93%ly4oQ ([6-@'." u;IvS~zTzPsz?oOvFdM^FN^C02EKtIy=(7ܸ(>v5 Ul}?Wnw;>fgpcSzLuSkī6="d `X-`EkeU'&Bpns+f*3V=B:TЙp"2sV5e'f|g!Xb8;S (j۞t)WoqצW©VoHNR'Vf?w}ssd D<~SF׻^CJ@w:cy/O0*C -[`%9!ad$p:M “ PPlEs X8N#(}X;0 (N*D@X6AdbCa٬RgpeK eJ!`N&A ,0j*ep!g8XD@X6AdbCa٬RgpeK eJ!`N&A ,H<[} ^a0n Z)]kO3>E盒`݌ 8k̼!Ec&cwzݕ Vq qg޳t e}'=TExj# "Yl#[VW]ZΘR^QfdW3o$:dS@I,Wlf8VܳiJ4ࡎԸVE'a_|Mi4m&:tھQ5 }j>!c-%p(!OG,9[x=}r F5p¬m۰*ծT,){'Vaml2ŨnU$w7E/?7=ضm9@m31Y2)n,@I3=sNw[zƢ8@J)?dpB1U+C5j-*W\=qrβZEv6a*BJ?D&ָ:!dپO,G u 6s猠^]ns2·I{OЁbgbiЅtzp`_( d} p>Ж&WE:U[:XcT`÷69xeL jdT9k޼.ց-!:·C3gUiמz"yE5;y^W+T>-nv±dZa YYTy"/0xQpFju8;؝Wdcd3p5lYOHuŤN%Y`g1buЁjԨ!^x&`ċ" 0Ѵf?kğ(X@@Kj rѠOɆ?8@8)2oرT~}ݻ7}ԱcGZbp*v?O9(OiAkGs>$+X nɉQ6Hbb_e{ш'(?pz/eCϞ=K|ժU^yjذ!=t[An=c9YNMkRNMJ">/gܠ!4ĩ8gmC|BVIqiCxȕ+Wm&!74h@=:tH#Mr3WDvWOٔWh 1d MCvI@-U"s'~իG0p@!?\YYgN8(ky70pt_nd}-^ &]tn&pJOĨJFo%G,A1$!\W={YWo$bX8ϧp\;"1}f6r8 $l2[sδvZLt1$x'o)S({˷$efezݜn:/Lgke58SzNRxϥW)[Fك~x'?LRJNhTVő{+g(/ |(A(:Y߿~i1WO,qC("X]ͨS27)&ۚ֡ɟ@o ${R29${zg'ڸJ -ZD7|3s=a,@̙E-ˊ !2n'Oɒ}67%I&0ٓy $ p.]ڵkgd'Hpf<ժ ٸF9+Z pHJQLח/y&Tk]IV>cp5IVX%O? 7@/?~\ҫ8z>g2nQDqpe6JTʕV:ݪ/@ (@gSNYoA_^ *X ~Z N7o~[u V\?kӦpBkC0;0HH(IttU_8[ha͟?NtL}W\r$ Ubm@dO<6lu9/Uo.Xjٲb&&op}Q+&&= Joʕ+gc[*zC^ X+9kҴOJ0y?#*?оpVD 5?n#A1C8a*A W=oȑ1-HP@<<ըQ#kXH:VTWɞ}1Hx}b"pN(.:u֬YcUUT)k| P|G=ɓz7-+AzǓlviF 1]8qmذaQo֩Sǚ0av8@@Ŋu Ea*(.'=#+?9(luģ?I ;MȐ1m8pP&g_8NjA+t#˗۵)ؙ%yZHPN>*V^` [PKSpsuMN@'_X:Sob>̘1vEa}eF^m-/X-|J-[6ZlOx 3_]su'yBgy;6^YVo\La Si´N| ,ha͹s=^ծPz3%3I$9|3|_+33XEG]EM-'Y<|*$ǺR${,houM!Cǭ?yr*:`* SjJ!:`ܣG릗ѾKs!V%HuƲMVnT^h`GA|ŧ+X @$JaunZf,cxwdso8 ]4fBx;ol̀ !iZj?[я뽇O7Ј iߑ}92&ȳijr2[Ѣ*|߶))]918 q Yls=H4mZ#rd"gT\+m_ ((آLLo&%Tߡ 8&ʻpr'BXSB88ŏ?KK,!&VJUפޡlKsg] 'N0?}LEw+{zCs@z+if>4fj:wN y 3c 'BG <+< ׃eͻ#o|Ew˩ՓЀX>X8~ХF Y%Ȇ-E8k48sVZĎ+)99[8!H[x?/GsOaD}``T>mqB6ٳQrX:'V`y28c9}lڴꋶp4]!LrvY{/PĂ:ٳS>}dO$a,M;|Fvc*RO&HuPg/3WEaNk舧u^=KHFӧ9R(۞us>5=l77LE@g41v>}7i1<+=$NSJ9 ~w]LOUCF`8p`m Y 14#Ծ_:iPzpWy"8?1<ӜP8%j WiW|8-(ʔf %Sh-[Fx$޿$"=CO}!zaԱG4fgg݉O+#Cx= b;9+K8#H[oѣbŊ .\,YmKr8_E{K}&^CrIm]9(X%>(NR+pէ.(Vu*qyb9uᄲcf8POһKM6ڂ, s7N~FX”LcOEĉSgiԥdC R /QP.qX>R+=2\;d=cǎOyR"E$[3KkwGsW0dbɚ4XS}I d a4̙S3Kl]r pF,$KNSEE@Kwe!m,P|رwFl~f͜ɵާ^ղ4oB/PRğNԟُq> s.0NTf+8o'z^,&7W89q'f)G1‚q[w `=uWkz}6)W( * H4&WYXvgfԦ^e*gNNtA/CBY'|U=%%|>6z )@JԤzyjZG(+Fiѻ A2XR1D`P~#͡f*355) AMVڞ_eu]!5^ՊMԛx=Zf+03bR-=jArycIֳpu+Q*gètK9'71/9ů铟 g+'5 GcШ)i@bZk{)mܱvL y8) PP‰4!lWv^NwBg.OP9deL}~6-,B: ~-}GhA>tB3 _)m s=$UI3X~9PA83`B@X1Gvt)pbBr|Y8/۰>&/\#JQ0pm|kZc?5Y('˗u涗׋#>0>OKC+^$cCṊC,0mR<5a~(©D&ȉ\EzjerǴfl-v" Ҡ A|#eM]l*! @ ' /yUy"p:bP'?Yb9tgLo(+##ҡ?b&^(]$4A̙xuAV_g,{`{'R%,@a@EFd#'ɋ-/@R$Gs_v^Y)cOX=@1ӡm{ KˌA6ٓ 3:|cP-ĺ0}TC"8@ fv^A@kYW-^Kƿ GF`gl_ XaXf^qG*?Pfthm}>2Hq,@ b2e0N¯X_<5u9^ / @  "?,|O][PA8e켪94@`t *3N:`uqGr)~͐yqP=&( ]|H7&蚛CA@x@"` 蚼 A! o S<@ 0HtM G@7)A $&o@#`  H ]A 0 dg$ 23CDmr y@ ˑRpg/Ӏ}i2tpɹy9>˻bCCqh [f9 5w <&gv1r,,A(< 9'F: #}F5M3TCS+ߩ3LNI<| ^+ۛIQiπm #ܾ.2 I 7V>#ka>:mm :PeǜĄRkQ]h!1}&&t K:x]}{[>HoCW|rpǴxSfV>= 'Hfe4\&rCyByh5``㔍 ^xYأ/Ł*1%$ iN K\÷6$NSg8 zƃwh\yIIW oϞ=m6jڴyE,*gB 29k:qlH tgj;S8Sq8Mp4r^L?@V y%|^x|uvv7ف0D_p>3z뭷СCt]wѿoZWHB8xQqrT+$M[oK Rd ۀGQ$w4$ہ-!J/x @a 'LҦ5S-L[ɧʲpsPpKOu+(z̙}3azWizp駟~Q|$>LPx&ny"sНkIlym՛V|${IrL@mTq~boy ۹E9S5M Zxz])i(qB=lExzZ_z}v Lz ͚5ԩS'j߾(?,<..{=U}R/y(ieA"niB|t\\rȓy|_$?QGZ1T?J8*ΫG;4U[yWs^AȰnO S֫]:)D,n{}5·9rDO>sَ>Q,v{NolR%?uEhΪm4{yV33BB&8[};*/ٌ!A&U+w9WWsw^#cQRokVF|ꫯdg._^NY ,XZjE]t@ttP<'5V%p7ҍ @,yx՞}) WM!Fpy+b e2/R:ME ٳ߽S ˚ɝ?uTzWhѢERUXP\WԔѣiܸqR>}(***eW:Yy7?|]w{dl Wgr4AHt@^wNMd+6xy3!%T~Lp9E zJ q7AP7=CmڴW|Pl7~8u?ڵkӷ~kpO=hLGri n1"УOK':{۷onݺиqc&YƧ.$V(^ʎxh(Ivb-X=w!OhxZRf J؁u/p@xLA ԛV%WiqKB! &Ν;;)p?(96{ljҤe˖ᾪ\Nz`p\2ծX wؼα) 9C>DIDAT/,fRn8T.s\xL=:!vծ?\d}3~5r{o7r_|f_q;'?xj͜9Ӻ馛`,VwVr^yx ec]qٺ5,AS ՓX?O[d{!Zw02 g#˟mcgETXe=l4~=֭[eznȑ =.Â*_ukbŊ2[p}ɍQfe1) !τIg\<[ Heޒq;\Kk@!Xt/^:D4h 裏 `Chذ|wDⅴ^IV׼{G @ApG"͑0j(z ?ʅ xQy,YNbU\3 i@!@ `Ja޼yn]#^"˳={{0!06{Hx1? J|Uҭ@eZĿm۶@ݺuw1!=%O?DmذA=\e0y饗^Ez0a]tC|)S$u(=TSVP!߿?у5K.01~ᇲ3+A6!6nݚ O/MKh;(8e|ݺuHO$k'>>^ C=$N5dHOxC]Nz… ɓwbB!A@ׯ/X<b XnŊ?~FϨ=dIt@bؽ{w{CP.I $ xJ0fYKzjzI5l!zu~O=8 ,(5R>) x}OeÇKnz!4MsGWF n ab M{KQM-R-)ĥJ/2?)XU #` M,;6,iР'R7Ciֺ ;v8{$U7 2 Qf͚%Ν+%Էo_իEFFq~s@RX0w!%{󄊪[nB&eʨSv= aޯ M Tk TM6z׼ Y[Մ?R7uˠ\rwU!'ȪgdAqSN_p&?\rѳ>K}({qNaL CA zqtzZL|be]+TKSi&FkiZ6j!hbLj5FX U0F1"kQY]{zfEDѓ{gΜ],qZxT*7ڗ0VSS`@ a+lD?BjEh4bII vwwqh ;Jt[WKs3&&&q0N4 Y т+|UJR :E׃Zq… ^o%sb˕^,?)ө1kxv`_|>Wp1`(wXNcV~8?[k*þc@ִ4*DE 6B}%X{6,$QZӷ ndOŒgRa) &brbUϡъ.zp 51##wɧ]O I&&|p!Y6ɕ:H1Hmnw'O~LeX{B>!.@xml1HV+*:R(ZxE fowt͞8aEqe@'ʜd`nq޽2ƾﶍg(S;kPs!p~ϕo4QʁdpvK@ITA\ERIENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/32.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000345314776170045033120 0ustar runnerdockerPNG  IHDR szzsRGBDeXIfMM*i  bIDATX WkLTW XM+%6AjjjQhl&hSӴiQ6b 5E((`w3WaI̙39g{oJ^/( u}P dM&BCC(J ͐8ity|444_Io_Ԝ< O[v 25ʺP$ĎBVgTF8\]pke th((E:BMrd|l=pV @ Ҁep,x/F "_U  :r]dZZr Ta}lZq>ȇAAA ]]͗y$ 8p!AV)K-]rhh\E/GM_f[S&؈YZ"w-6'tR)I>MIaz1Ơ$2@Fr+Z7e|r0]2cqv'L?~ے ۲֛!}d6~XR* Վk|1"7U\G㮝;vtc}Uvij38}RL4ucՁ:,bC>]ՠ`;ۭfb0ΘnL@6YۯYFc;fHz?N5l&ۋ_#A;P}iLNNKSSSYtta˝۸:;C%;3I_ 6_GTR ͉*v(=\GcL~2 W;wlǨ("lXi,:nD+hp F' H$0[XG%Ouv#GğlB݉"BfTI?yd,}|**BpjZ0V&Fd $@MAK8o<9(g 66d@s'aRRt?gz:2?,2`R(}29hgu4 _oltIENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/80.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000001207414776170045033117 0ustar runnerdockerPNG  IHDRPPsRGBDeXIfMM*iPP1LOIDATx\ xTE>I:;YHEhgD 7V?o /7++Z%YNarDzT7,2xhIyp(1HٹT["8/yTI!_/OWv- 6kHXEnAʖ/hgO# C2P*Xψg:Q`SHrKeks|҅5 ă"c^D{/Mh{_֋7 , ҝ+(;G^fw U(iր9 SBOU {<褞߿f0)kT-W\o eq:˲8(VEݳj@EB_42i1}!;j(9xR& @3--ML2E4hP޶␜ڰa}:y@[P#){.ޢ9MM| b/^[RԩSϽpNDl1ϐ@񻹜,Znep6'ngJt<9J& Z \ :t(될 2iؗo_GM#iX#BG[~Ce 9iݺ| sƟ[Y>рr]_sP˔J7g8 +eς^<^d E>OӿHJ'+B6`<.p%k[jhÕ'u\)dyNo2eu/7эSXrǰMM 2vLGX dObޝ)Q)2}Z`Arn7Ewv]6c_^HH2؋$Ҟ uXG=\dF.1C{X+9*xs޷=նm='<= w GPON~n Fz2|^Rԓ]ER焐 J-dqƐG*8|FE' d "E8v`q<>:{x DծU'FUeC@:Fn0ɶ8]%RH /-pe||P&SDIڸqco%PnԨ7o˛:Xws犆 @X/&\~d);@}( @ӁwyoРA3~XPE˨X"2x2֨Jپ}{vZU]w5 8%\"׭[' ٙVDZѫ *֫Hɏ0~/\#9ϋ|IZH`y>Tjd0E40a˚߫NX zh'v^kډZ`-v"`X {YzIENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/87.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000001300014776170045033105 0ustar runnerdockerPNG  IHDRWWqlsRGBDeXIfMM*iWWRjIDATx\ xUE@ ;" , ȎN@}oA=5cXgϞgZl;Ho&M0V*?ZQMtE^5BUq)AP%~.m=Ic.ѿu~:?X%Aw@A"5ՇA|LkvkB0153XzTٟ2YׇcQ~݊?Rc#Z^z%.%''V,ָ cQC73оT;$XX2LN+vQhЯ[S`v'=E}oAC0!YlzV }i+ԥ55S]^)Qf+&ܸEWl[#(3+BX[elmwA%'Z6duT=W>LxFLժUŴEhi%y*eanB;=JAį,\[d|wh Tq"Waf s02_SP Kq ?cI+8 CaQ"r?9:y2֝ q[wlCZ!UES4~ ܻq;:U΅ByZp2hTԢE Ml݁:j,Gl}x8\h*46apPe5~$}Kc,YB;vzKcƌK.h<֬D#wbsы_2 PvxS_բy/X YFF}{ԩđazwڄ#;&%Xgyhx >^=6be5q uC) bde15kTfR 85s5z֗tl^]Mj>5F}Txx;sR+;pu+eMDcYP$!Ne"/_^ysfB9^&3I\#`Aʕ+Ƕ\j)5ZqJ!L:egVk.6oNFqF knHr@voj{=; {hҥKŬzȰ~VɛW?=oh<]-0nh:v\SÀIp"EDDg͸>ނjи*e)ST%Gi#4o^MH><[؂VTx tF-LB8ڷoO6l LFHGB0r¯驱3髰y5V|!jRIjk$Fo(hR=p@:pk8'dZ e4|ꬤ `ira/? b~B8'T4̗P6lHQFь3W^kIk9xJ| m$-s*pD NFQ>XC%`t$QǚQ?NQ7RZ~=m޼YFy. N%t(pb˚0q;%_b|([pQ1"y_ 9 pt҅= + {'08_Hд 4: ɳDҥMI Q\HB[ջҬe[(26T-Ry \]鄊MP@ȮD4 ͓aS5+ ϑP@E à<P<ѪG9+s:Tu7ghI~7G"Ń&֡R \y]* ֚թY+ ֆ0?LU3xcaw&-!ŝ]z>\Vm/.lzZ\%)_b+=2xd\hshh_Jh+k-o J|bؗ[ߟ#"f)?\~Ml30zƛ$2hÅc$88#f0XObc$\U!ptYwQQԷ\s$W~eŠs2N%R^Cړ+AP&X$ɡ`Fv.DhA| ]Mx#SP' N;C1GyTtJO=R2FK+(`@BVMhǯS:V5ا{ʷ MgXSJvF~r~ӣmd$xz2TR)&T`b͙{סǡ=NlY`t?BQӎCQtJ"o}emm9FBgJO-a{-e=q_ r}1 ۅ_`;rm/X#o#qZ~Uwua Aץ C79G}I7 OM?F?WúW܂J@|;ֺI] ?9Lޡ9\ɨ!>Dc<ߠ1R"##iʔ)s9s& 0@ %# k߬?COt  2Sڮ&AfΘI ի4 `oW3&bo@DQhOc]g8Nwk_p`vRD\ y&Ý!ř8?Zj%2{/!qW|I{ZFfN]J`VMW%N`7z(ӯ,&aoCǪ_c}͎+6aX@rɓ%.[)PӗnSŭgG7Z>Zm^ buxĄв珨9{r<:cSrfe׮]k׮Z޸qch"kjBW̥WT i V%6_ \6-w>CxM1 ɱ5.+v]8]@[y\xS Z8䗽*((H43@65_TŹav٣:7Z ́B+ X~Oo0a4Yn}o:+ ?msˆey9HDfD3<7\"ժUe[ͫx5\Z\g$:ئ$9R9s,\*e:} Ϣ /` &5jnݺݻw[bpe.xiǎCr̜5j.\h=/Tj0d\?Aʕ++xEN^Et]|_Հ@ݸqCM4I!aş;)54zX/>L3VB4? v5߰(7 pF1ik_*p5@k\}A,+Hr\; pmDƪ+4\ ͭFlBs+ pmDƪ+4Fp$qIENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/50.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000000600314776170045033112 0ustar runnerdockerPNG  IHDR22?sRGBDeXIfMM*i22u˯ mIDAThY{pA!(01*O @%HP(ȣ)Ӂ2;+#j)NQB-hʹTKP-o Q $@xJIHI"7M߹/7 w9;gw{η]."jjj2Y, HcՕ\\\vV<`i&7o)`@]UG:JҤ$8q"T]^d s,)E5P>}xڵ\WW)9Z&&J\RR/+% @ @C͛73]M#"TN#&e]]]nQyyYlj3oZXzMbn^u=<꿋SiicX^%ԘƲZlzFTgj0_!c1%+12oI8ɶە;wrDDH˳g/sgS{R>>GdpWGџDY$TrDuD鍍Mř,ʹnQciOipbc_ij~7ҟ|FNzr#>ML 9)z0:(XG:iĹv:oN$iH= ^8+w&=Fz'+г~7N-07NT %"U.Zw7麵LҎ#'TF. (2A{83]B"W]]۷QF|̆0ի|-?QvWTR:u!̙3VV s8$$DA6la5kٵd3 7shh[Rx51Ay lڴid{$eJm6~M3r\w__Q}Ȼaȸo|[m3ݔO^zh@tas&3 ou/< s-lz.{g(>KʒsQq!)G`` ^WTk:)>ܕa?}E/ey 5=ۃ䠸}Vz$|=h8 xϧ1._Nk6GOh`O?rN:Gs Q4qă=&OD(} xz_| ^ I'D=@#Cki9} uҲJꉔBR1JфQ@J酪nyx@"=9~Z:AbBvHJ)/jI jr8^߰䴥@IU1Ԋll_ݲUP4[-2eͣ=q\E, Q٩OHVA{ ƨ XGG,b qV Ȃ1A1<5/GO2=@`}|tۓB(2eI)Va];-i9pY2v11L C~RUTתmB%}?,ǢUEB1c+T 7{Y+ Q#Cj zkf{Lal`ED9WrJq"XN/goMW Φ09!JHZ}-G0xHH 1dPOSw#U(/"/̝D?  c7CeXUYK? O+~5K8zyKRAA! MOGnj 3@p7[y<__<ŭP ^vda$̌zPgȇ45wӼ3ƺ̬l^p!7x$UF 6>v6Uy;U;O05؉sWB5I7U7_sB8bϞ=PcЖ69<'=/Wxذaݍ yzzVMz6ڀA"AD@@3;sދhӬܽϥBw;;;܁%nʲGw^/~u Gzn4sˣիWSQQcjnЂ%TWWW_}UxzzE>}D\\AnE(ٱc ACBBĮ]rwmSRRRĄ 4b7}F'O'O |]S577Kz5('''z8ޫ x~Wv RPpA,_\xyyIaіVEEmMaB)T]CkXmRUǕ5z:i]S *#@nxqqaYX"YqQ/va1vX űc4MM]x2%qb߶$J\tEܤ[sdaooGoڑx.^Q!ށ_G)L!ń OQQQmmݺ, =,ƿQ/(5I/{tl^1ңOn=< ?5N6,!yZ>bW>^ KX]@4כ͛'%Gzv>`/%ːzyՙ0h(4\Y+I][o(J1t&S]}|(Nd`Ͽ/u͂:=xunRO#_^ejnJ j0W|-kOR3)n璏[.煚j{ȳew,HYdeP3ssq&7f Pʚ {)E^p#,,oƱ.9;9j;O"ӗ;;CH+0k۪P+0uʽR>Iӽ'M mi^ @/ΙL?>T]3νvXYe~ӓ(vR)8h @ɦSy]-4WifńK`K O,#S-9w+4CnXT׋j ~F4󲲲).n57yME8}Ӆ _`y(>NK^ѦMg +!C_!O_RJy&F;#gY&f+TEyetRꊳA>ѣZ ^zgH:/8i`Oh4iѣGk^HnWX!Lؿ}$}|H!ץ ݦE`xr" @ A9w\TjEyUU9}:S̜9Sc7tP*z tW8ŠA>>$.{RSтTU׈۾>Q gS8>G=#iگZL8Qׯ+Ӵf"rkgW̼Ws}\8X.(J5,F;-Yk)""f̘>=Jk8 />h"BX;f_B)<MtXd6p)T.:wFQ'zK].|h! 45Yj[,"U>dae .hPWcSՏ6 'Fа~^;*JHk\z:Һ?jkΞ=[J6jgwo QGI#4Hc:fy':T'bS|hclPm` EJ1!  ~] ~htV7ok NT"`o ڵkSZlXeEW+@ٕ^ vu `%SNXX9/_NU6U6ަʿs玘<0yl:@A`ða40Kt-=H8-֯_/TTejUURj0CA1FC~u[n"..NI $*((1}t$FG{<~ :mM*o e)5\7wMuiݫU Q)-qUu)bŽG)@7 ]t)g?P<|P~_9:*gY9"*V'dK* 2%y'\^~W~X3vߩbc++@IJe˄NG.\Q'£+S>K(5#K|~X~&bTJ+5lx΢o~W'/@<-3ӐB]!q5WɆ*iΜ9@ԩS L}/Y=Zl|"M}]#n~*ӑn'&Ơz{Zf2C57q٨/yץ)%0Fqu'=8¯mFܩ yqF9s&iӆ\\\wHIϢ -{OPJz&5FyvgxHtoGhOΎ 4r-V 8؛'"Hp{y`oGvt#ڰ$C7 ţڵChŶtnqlDҒtlC/ӹkwip?ےb >uZm ~F٠3Ξ`ҎuKnGi9+wτA{]7` 2]Kn H9xx^ |EF2aP^cXl<4xuU/ZVe d ym.1[链N}[W {xD9y]u~`q*#+Gc2Qn^Sçiՠ>n*aXܳc3sdz r,C};%'^` iҐ2rro.k#fv6ބ1x137ɻ#ǻԛѡ95Oՠ 7"mJ(;7TkՌ>~ן~F?9Nن#ⱈQ.Ύ̴ZTCrR!_k:ѧFрjmPɋ G<@ݺ,Y,Lt2ȃҌ߽!g8 WUHwjE4s̥K.<#VZF'-3zKx٧iԱUS2'V%$$мyșZ'OOO:lL[xB6g A.;ffN\'mƼ3^bEn*qgG;Ѕǰx#APk^+Ԯh%A=>/ݴAK۝C/U޴ltW1w>1}.M 1l2sTv_@SKhŋU㲻8%5'Ĕe;Ħ=f}ѣG uP_GU"h$'Y򻻻)*A8OKKcǎՀAdr:"Zg„ "KkifROJJK,M4ьPVFvaLXB͈PYr|^OUU-$c3F9sFrTX#ȸp￯1KEJrES``ڵk hh LϞ=+ZEhM #bȐ!%6+͌q $5`c o~Fi(F#׮]+h5,Ÿ[LRtY^8!XC9w~~~Zw e^3J-Xl.&s?:(XFݽ{WL6Mc*z0FaPTclI3b I-+ybvhl !B>txo/hT^=77b/l2_ק}NbVAJ;DҺt^a\$oذΞ=KW֬YC7Fr|" f,KYThS=$7R/ jJe{Sco^2N#C6Rc?*rx<".* i2~V* UB9dCCQ]ńO8vDy[:(HrzI_v^)i*:1f0z:ǚf/08[;qbmQ6峗XZEE 9yaw?D(]tG,'LR (#J}&nӊ k9|dT Q 8bd2H+{{ԧƿN!QNGc9Ctjį̛2C9ȁ] 5)2vr9*L;~;D^Gy4 ı eo[8.C9ЉC90\R|o Qf^!^z8Jс=8tx!y 2^ !"uA f֜o  MKL֟b$PqO; L6 K4^QniѢE4h "% Қ0\,rnQfV\o)VB:~@bFc2zWh 8Tӄ:hLDߢs('G鼰вe[9x/ٴiݻmF .$~Vd/]o_ __3?=3~p-ȇxC Vc@ ߬n|?@ 9yXX/tuvQvvXrv^tI+c9[VoGwT/JTQ4IJT&CHHͤovDҡ#(󭦻]>VɊ-t܅|<)OEbxPJF6 ;)ըV,^}#JK 뷓XS_ʛ@9w5boܡ6keaUw{ b)YVa؇KpT,=S29Cy[ :ݙbݦ5;=ɉ~:E{gP+ՆBfu<@3{! LDn=$(aE/XQ\`t.`yj-%f,,̬@V>^x/nݺQvԎѩ?6M?w(:Nr(_5nt*!Oǎy޽}p߼${43ڸKop7"7 ,`___w}^2f"/ݲ6gQv>~vdfB .ZϞedoݙC/P:rQi 7~[n@ z\Νy$*/7_6mʛ7o_N_r-Ԋ._5Xf|Tss8&&Ǎg/0j p@G\^  ~%txx8{zz*塜Y:hE`i`C9s1\zBDs,y;5yaxʔ)lfPرc E4]I4[C^~Cm 2/ij߾} aC`9SPWYIkJz%ab5UTQVV(\~[@$r現ڮ"\s ͛@jݺ5nLIK6r!"WC|˔jժ=X5^Cz9<|27-kڲ<Zs7&qoౘ^],w @X[Yiw)rG'YVPAxt+)U.K wIz۟X+m@",p% "yJ\(py'Sg;'4yv9ͣ8ky1%)*m "2#S.YwI.!I jIv@./)-VN/N2d%t.-6y' UA"}ԝ{j[9!%M^|xТIh'#LzP jX}ʖmҖd9m4fpe]ԃHT|A /8 PgWV"Aq4V{F^vj7$˕ ڒQGr[Qoi_Y@p-kXc wVÍHޑPodųJ,pCyQpp… U&sիC#҂j5C\g v,k>tRq .`$[NZ-1nf'񎈓F*iii=<<ꋢ%Jj[x1ߟ=<FcX#*a67wB؊:.ȎlJ4SJS .jTzj%wD*sԹ)IENDB`././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconset/100.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/appiconset/AppIconSet.xcassets/AppIcon.appiconse0000644000175100001660000001477414776170045033130 0ustar runnerdockerPNG  IHDRddpTsRGBDeXIfMM*idd/AfIDATx] |M_IH"i 5-zxJ5u NOھ)-Y9J1ADC<쓓$7q͍/{^{/Ņʊpc()#D8P*_vozؼo.h>ׯ_?sN\Z)@`b4:uW`h`^?*66Fa(%իUΝM =;A5jO>D&V@`Fٵk4h  3=o5c-[TsQ|u’ʼ%YW8p@ =}ȷu,O<:q/C3͟r& l\,N>-1 f}\=zM6͢h(Z@̇J\fѧW񹿳8%-.fZǎ;x6ٳgu  ^gf]S )%ݼ?;6W8thjRy3-=S}<Q(MVY`,40VGkP``zUBB,hE~|GܲO8(TS]([ҥw؅' OJ#4ϣoo/JMϤQVԦqu02?4x`bC<]܇#ФIyAف7 9Go&o]=+ԭM06 @7UX,x]0v!>wg҉FJ!"0?(.%ҬUUatU> oJ' mK `[0}0v: uw+6j-Ý9w> ##j@f)QRjt̶:tK+3_Pğqtt orf0瞣VZNdzzJk?E!u+QrjI@wHC{&?b`wz}`j\E :D'NKճgOz'%#88Xc\unHUA jɪQuh۴!ޝP @9? .=q4|p9Oko&-&_yemA./,\i?{cś@&@P9wE5~x/&j%0rJ*WFK1#zFǩA aǕWбy,xHYo^eFJF88Pٳlσ&]RԢнjܔ,[NE3ͯK6(tD̘1C5h O7'(ϭq jHRaT1.YxŁf[B>\5]!$L.q_oʩDcm\H8Pݺu+VPl%o߾*,,LW'JH뒫ƙsΩW^yE =V[i[VZ-{ګh ksVyU> :͒Yx駟V111f"C{pM2eSNzkyC2t0h*Dwի0UPPRhW.<~6uZ_[vԩ =*V{~uBiG_q9Un]˛(]օThJҝ9<3f0SEЂ聐hO/-&g};D"ɒNI JL\RI: ZJddⵅ`0| l͚5%=Zi&gs&!_~[M>ӰaC5s<8ZvlA~aQg;=Z:ul< D .aVK/Ȭ̰WB믫K.I3mnͷ #N3 >gm}Q۷o7„9wѲHOH2iݛ'E-2T7Eijr]Kg+gf9em۴bYf~0,X~jb*U 4pze*S  &X%tٲem۶Zc$z"S-ijRQ &vƜWc>]]]^0P=0_/8DʕPTR!pbdћk"TUԯiű3CEdi|o wP\ 46v-;NUpǙ'$&38Xi„ xypr;gFCgkpY`0>!ffp pcc!n+8^}UI%@::Acǎp3ftMM6FI<-7OfBx F4U5o5 !A|~vdKT)\wE)tvKȋZ[t`:-ov#E$ 0 L Fvj6@f.3PWX@Hr>8>95wiBo>5ڶ(UB5c~<ޯ3V/)n*'RDڎ B[K J3zNJP&j7>m(zU애F~8G/vF?sQ? +,<6O/w=$a^䨶qNq4o0;0QQ豧${djw@JJ`ZQR §G/=ҏ=>no9uGqɄ08š԰ hyKPw+8a4Ԯ^sKKN8^MHz~ϱ.~K-6=̪[2=ixZ~I~u?ϟڇwlҁbAA< Y$@f85y_6ԩ9KhNy6:RU6夾NtwMӄE+Ve9n7oM4I*k0c:upjѨm;jfC4͸ l37-L K %OԑSG?W~ԋ(x&R}a7'/Bl -zAv <jsޣpTDi3#[P&{!kxJ01'Lnv6f$:I7y˒͐4DtK= 0) filez.push("empty.xcassets"); if ((Host.osVersionMajor() >= 11 || Host.osVersionMinor() >= 10) // need macOS 10.10 or higher to build SBs && cpp.minimumMacosVersion !== undefined && Utilities.versionCompare(cpp.minimumMacosVersion, "10.10") >= 0) filez.push("Storyboard.storyboard"); return filez; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/0000755000175100001660000000000014776170045027315 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/0000755000175100001660000000000014776170045032233 5ustar runnerdocker././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_0000644000175100001660000000123114776170045033242 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/Contents.jsonqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/Conte0000644000175100001660000000053314776170045033227 0ustar runnerdocker{ "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "icon_16x16.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "icon_16x16@2x.png" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } }././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_0000644000175100001660000000121114776170045033240 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/0000755000175100001660000000000014776170045032116 5ustar runnerdocker././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_10000644000175100001660000000123114776170045033206 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_10000644000175100001660000000121114776170045033204 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/MainMenu.xib0000644000175100001660000063673414776170045026563 0ustar runnerdocker 1080 11D50 2457 1138.32 568.00 com.apple.InterfaceBuilder.CocoaPlugin 2457 NSWindowTemplate NSView NSMenu NSMenuItem NSCustomObject com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion NSApplication FirstResponder NSApplication AMainMenu Test 1048576 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: Test About Test 2147483647 YES YES 1048576 2147483647 Preferences… , 1048576 2147483647 YES YES 1048576 2147483647 Services 1048576 2147483647 submenuAction: Services _NSServicesMenu YES YES 1048576 2147483647 Hide Test h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 1048576 2147483647 YES YES 1048576 2147483647 Quit Test q 1048576 2147483647 _NSAppleMenu File 1048576 2147483647 submenuAction: File New n 1048576 2147483647 Open… o 1048576 2147483647 Open Recent 1048576 2147483647 submenuAction: Open Recent Clear Menu 1048576 2147483647 _NSRecentDocumentsMenu YES YES 1048576 2147483647 Close w 1048576 2147483647 Save… s 1048576 2147483647 Revert to Saved 2147483647 YES YES 1048576 2147483647 Page Setup... P 1179648 2147483647 Print… p 1048576 2147483647 Edit 1048576 2147483647 submenuAction: Edit Undo z 1048576 2147483647 Redo Z 1179648 2147483647 YES YES 1048576 2147483647 Cut x 1048576 2147483647 Copy c 1048576 2147483647 Paste v 1048576 2147483647 Paste and Match Style V 1572864 2147483647 Delete 1048576 2147483647 Select All a 1048576 2147483647 YES YES 1048576 2147483647 Find 1048576 2147483647 submenuAction: Find Find… f 1048576 2147483647 1 Find and Replace… f 1572864 2147483647 12 Find Next g 1048576 2147483647 2 Find Previous G 1179648 2147483647 3 Use Selection for Find e 1048576 2147483647 7 Jump to Selection j 1048576 2147483647 Spelling and Grammar 1048576 2147483647 submenuAction: Spelling and Grammar Show Spelling and Grammar : 1048576 2147483647 Check Document Now ; 1048576 2147483647 YES YES 2147483647 Check Spelling While Typing 1048576 2147483647 Check Grammar With Spelling 1048576 2147483647 Correct Spelling Automatically 2147483647 Substitutions 1048576 2147483647 submenuAction: Substitutions Show Substitutions 2147483647 YES YES 2147483647 Smart Copy/Paste f 1048576 2147483647 1 Smart Quotes g 1048576 2147483647 2 Smart Dashes 2147483647 Smart Links G 1179648 2147483647 3 Text Replacement 2147483647 Transformations 2147483647 submenuAction: Transformations Make Upper Case 2147483647 Make Lower Case 2147483647 Capitalize 2147483647 Speech 1048576 2147483647 submenuAction: Speech Start Speaking 1048576 2147483647 Stop Speaking 1048576 2147483647 Format 2147483647 submenuAction: Format Font 2147483647 submenuAction: Font Show Fonts t 1048576 2147483647 Bold b 1048576 2147483647 2 Italic i 1048576 2147483647 1 Underline u 1048576 2147483647 YES YES 2147483647 Bigger + 1048576 2147483647 3 Smaller - 1048576 2147483647 4 YES YES 2147483647 Kern 2147483647 submenuAction: Kern Use Default 2147483647 Use None 2147483647 Tighten 2147483647 Loosen 2147483647 Ligatures 2147483647 submenuAction: Ligatures Use Default 2147483647 Use None 2147483647 Use All 2147483647 Baseline 2147483647 submenuAction: Baseline Use Default 2147483647 Superscript 2147483647 Subscript 2147483647 Raise 2147483647 Lower 2147483647 YES YES 2147483647 Show Colors C 1048576 2147483647 YES YES 2147483647 Copy Style c 1572864 2147483647 Paste Style v 1572864 2147483647 _NSFontMenu Text 2147483647 submenuAction: Text Align Left { 1048576 2147483647 Center | 1048576 2147483647 Justify 2147483647 Align Right } 1048576 2147483647 YES YES 2147483647 Writing Direction 2147483647 submenuAction: Writing Direction YES Paragraph 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 YES Selection 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 Show Ruler 2147483647 Copy Ruler c 1310720 2147483647 Paste Ruler v 1310720 2147483647 View 1048576 2147483647 submenuAction: View Show Toolbar t 1572864 2147483647 Customize Toolbar… 1048576 2147483647 Window 1048576 2147483647 submenuAction: Window Minimize m 1048576 2147483647 Zoom 1048576 2147483647 YES YES 1048576 2147483647 Bring All to Front 1048576 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help Test Help ? 1048576 2147483647 _NSHelpMenu _NSMainMenu 15 2 {{335, 390}, {480, 360}} 1954021376 Test NSWindow 256 {480, 360} {{0, 0}, {2560, 1418}} {10000000000000, 10000000000000} YES AppDelegate NSFontManager terminate: 449 orderFrontStandardAboutPanel: 142 delegate 495 performMiniaturize: 37 arrangeInFront: 39 print: 86 runPageLayout: 87 clearRecentDocuments: 127 performClose: 193 toggleContinuousSpellChecking: 222 undo: 223 copy: 224 checkSpelling: 225 paste: 226 stopSpeaking: 227 cut: 228 showGuessPanel: 230 redo: 231 selectAll: 232 startSpeaking: 233 delete: 235 performZoom: 240 performFindPanelAction: 241 centerSelectionInVisibleArea: 245 toggleGrammarChecking: 347 toggleSmartInsertDelete: 355 toggleAutomaticQuoteSubstitution: 356 toggleAutomaticLinkDetection: 357 saveDocument: 362 revertDocumentToSaved: 364 runToolbarCustomizationPalette: 365 toggleToolbarShown: 366 hide: 367 hideOtherApplications: 368 unhideAllApplications: 370 newDocument: 373 openDocument: 374 raiseBaseline: 426 lowerBaseline: 427 copyFont: 428 subscript: 429 superscript: 430 tightenKerning: 431 underline: 432 orderFrontColorPanel: 433 useAllLigatures: 434 loosenKerning: 435 pasteFont: 436 unscript: 437 useStandardKerning: 438 useStandardLigatures: 439 turnOffLigatures: 440 turnOffKerning: 441 toggleAutomaticSpellingCorrection: 456 orderFrontSubstitutionsPanel: 458 toggleAutomaticDashSubstitution: 461 toggleAutomaticTextReplacement: 463 uppercaseWord: 464 capitalizeWord: 467 lowercaseWord: 468 pasteAsPlainText: 486 performFindPanelAction: 487 performFindPanelAction: 488 performFindPanelAction: 489 showHelp: 493 alignCenter: 518 pasteRuler: 519 toggleRuler: 520 alignRight: 521 copyRuler: 522 alignJustified: 523 alignLeft: 524 makeBaseWritingDirectionNatural: 525 makeBaseWritingDirectionLeftToRight: 526 makeBaseWritingDirectionRightToLeft: 527 makeTextWritingDirectionNatural: 528 makeTextWritingDirectionLeftToRight: 529 makeTextWritingDirectionRightToLeft: 530 performFindPanelAction: 535 addFontTrait: 421 addFontTrait: 422 modifyFont: 423 orderFrontFontPanel: 424 modifyFont: 425 window 532 0 -2 File's Owner -1 First Responder -3 Application 29 19 56 217 83 81 75 78 72 82 124 77 73 79 112 74 125 126 205 202 198 207 214 199 203 197 206 215 218 216 200 219 201 204 220 213 210 221 208 209 57 58 134 150 136 144 129 143 236 131 149 145 130 24 92 5 239 23 295 296 297 298 211 212 195 196 346 348 349 350 351 354 371 372 375 376 377 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 450 451 452 453 454 457 459 460 462 465 466 485 490 491 492 494 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 534 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{380, 496}, {480, 360}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin 535 ABCardController NSObject id id id id id id id addCardViewField: id copy: id cut: id doDelete: id find: id paste: id saveChanges: id ABCardView NSButton NSManagedObjectContext NSSearchField NSTextField NSWindow mCardView ABCardView mEditButton NSButton mManagedObjectContext NSManagedObjectContext mSearchField NSSearchField mStatusTextField NSTextField mWindow NSWindow IBProjectSource ./Classes/ABCardController.h ABCardView NSView id id commitAndSave: id statusImageClicked: id NSObjectController NSImageView NSView ABNameFrameView NSView NSImage ABImageView mBindingsController NSObjectController mBuddyStatusImage NSImageView mHeaderView NSView mNameView ABNameFrameView mNextKeyView NSView mUserImage NSImage mUserImageView ABImageView IBProjectSource ./Classes/ABCardView.h ABImageView NSImageView id id id id copy: id cut: id delete: id paste: id IBProjectSource ./Classes/ABImageView.h DVTBorderedView DVTLayoutView_ML contentView NSView contentView contentView NSView IBProjectSource ./Classes/DVTBorderedView.h DVTDelayedMenuButton NSButton IBProjectSource ./Classes/DVTDelayedMenuButton.h DVTGradientImageButton NSButton IBProjectSource ./Classes/DVTGradientImageButton.h DVTImageAndTextCell NSTextFieldCell IBProjectSource ./Classes/DVTImageAndTextCell.h DVTImageAndTextColumn NSTableColumn IBProjectSource ./Classes/DVTImageAndTextColumn.h DVTLayoutView_ML NSView IBProjectSource ./Classes/DVTLayoutView_ML.h DVTOutlineView NSOutlineView IBProjectSource ./Classes/DVTOutlineView.h DVTSplitView NSSplitView IBProjectSource ./Classes/DVTSplitView.h DVTStackView_ML DVTLayoutView_ML IBProjectSource ./Classes/DVTStackView_ML.h DVTTableView NSTableView IBProjectSource ./Classes/DVTTableView.h DVTViewController NSViewController IBProjectSource ./Classes/DVTViewController.h HFController NSObject selectAll: id selectAll: selectAll: id IBProjectSource ./Classes/HFController.h HFRepresenterTextView NSView selectAll: id selectAll: selectAll: id IBProjectSource ./Classes/HFRepresenterTextView.h IBEditor NSObject id id id id id changeFont: id performCopy: id performCut: id selectAll: id sizeSelectionToFit: id IBProjectSource ./Classes/IBEditor.h IDECapsuleListView DVTStackView_ML dataSource id dataSource dataSource id IBProjectSource ./Classes/IDECapsuleListView.h IDEDMArrayController NSArrayController IBProjectSource ./Classes/IDEDMArrayController.h IDEDMEditor IDEEditor DVTBorderedView NSView IDEDMEditorSourceListController DVTSplitView bottomToolbarBorderView DVTBorderedView sourceListSplitViewPane NSView sourceListViewController IDEDMEditorSourceListController splitView DVTSplitView IBProjectSource ./Classes/IDEDMEditor.h IDEDMEditorController IDEViewController IBProjectSource ./Classes/IDEDMEditorController.h IDEDMEditorSourceListController IDEDMEditorController DVTBorderedView IDEDMEditor DVTImageAndTextColumn DVTOutlineView NSTreeController borderedView DVTBorderedView parentEditor IDEDMEditor primaryColumn DVTImageAndTextColumn sourceListOutlineView DVTOutlineView sourceListTreeController NSTreeController IBProjectSource ./Classes/IDEDMEditorSourceListController.h IDEDMHighlightImageAndTextCell DVTImageAndTextCell IBProjectSource ./Classes/IDEDMHighlightImageAndTextCell.h IDEDataModelBrowserEditor IDEDMEditorController IDEDataModelPropertiesTableController IDECapsuleListView NSArrayController IDEDataModelPropertiesTableController IDEDataModelEntityContentsEditor IDEDataModelPropertiesTableController attributesTableViewController IDEDataModelPropertiesTableController capsuleView IDECapsuleListView entityArrayController NSArrayController fetchedPropertiesTableViewController IDEDataModelPropertiesTableController parentEditor IDEDataModelEntityContentsEditor relationshipsTableViewController IDEDataModelPropertiesTableController IBProjectSource ./Classes/IDEDataModelBrowserEditor.h IDEDataModelConfigurationEditor IDEDMEditorController IDECapsuleListView IDEDataModelEditor IDEDataModelConfigurationTableController capsuleListView IDECapsuleListView parentEditor IDEDataModelEditor tableController IDEDataModelConfigurationTableController IBProjectSource ./Classes/IDEDataModelConfigurationEditor.h IDEDataModelConfigurationTableController IDEDMEditorController NSArrayController NSArrayController IDEDataModelConfigurationEditor XDTableView configurationsArrayController NSArrayController entitiesArrayController NSArrayController parentEditor IDEDataModelConfigurationEditor tableView XDTableView IBProjectSource ./Classes/IDEDataModelConfigurationTableController.h IDEDataModelDiagramEditor IDEDMEditorController XDDiagramView IDEDataModelEntityContentsEditor diagramView XDDiagramView parentEditor IDEDataModelEntityContentsEditor IBProjectSource ./Classes/IDEDataModelDiagramEditor.h IDEDataModelEditor IDEDMEditor DVTDelayedMenuButton DVTDelayedMenuButton NSSegmentedControl IDEDataModelConfigurationEditor IDEDataModelEntityContentsEditor IDEDataModelFetchRequestEditor NSSegmentedControl NSTabView addEntityButton DVTDelayedMenuButton addPropertyButton DVTDelayedMenuButton browserDiagramSegmentControl NSSegmentedControl configurationViewController IDEDataModelConfigurationEditor entityContentsViewController IDEDataModelEntityContentsEditor fetchRequestViewController IDEDataModelFetchRequestEditor hierarchySegmentControl NSSegmentedControl tabView NSTabView IBProjectSource ./Classes/IDEDataModelEditor.h IDEDataModelEntityContentsEditor IDEDMEditorController IDEDataModelBrowserEditor IDEDataModelDiagramEditor IDEDataModelEditor NSTabView browserViewController IDEDataModelBrowserEditor diagramViewController IDEDataModelDiagramEditor parentEditor IDEDataModelEditor tabView NSTabView IBProjectSource ./Classes/IDEDataModelEntityContentsEditor.h IDEDataModelFetchRequestEditor IDEDMEditorController NSArrayController IDEDataModelEditor IDECapsuleListView entityController NSArrayController parentEditor IDEDataModelEditor tableView IDECapsuleListView IBProjectSource ./Classes/IDEDataModelFetchRequestEditor.h IDEDataModelPropertiesTableController IDEDMEditorController IDEDMArrayController NSTableColumn NSArrayController IDEDataModelBrowserEditor IDEDMHighlightImageAndTextCell XDTableView arrayController IDEDMArrayController entitiesColumn NSTableColumn entityArrayController NSArrayController parentEditor IDEDataModelBrowserEditor propertyNameAndImageCell IDEDMHighlightImageAndTextCell tableView XDTableView IBProjectSource ./Classes/IDEDataModelPropertiesTableController.h IDEDocDownloadsTableViewController NSObject NSButtonCell DVTTableView IDEDocViewingPrefPaneController _downloadButtonCell NSButtonCell _tableView DVTTableView prefPaneController IDEDocViewingPrefPaneController IBProjectSource ./Classes/IDEDocDownloadsTableViewController.h IDEDocSetOutlineView NSOutlineView IBProjectSource ./Classes/IDEDocSetOutlineView.h IDEDocSetOutlineViewController NSObject id id id id id getDocSetAction: id showProblemInfoForUpdate: id subscribeToPublisherAction: id unsubscribeFromPublisher: id updateDocSetAction: id docSetOutlineView IDEDocSetOutlineView docSetOutlineView docSetOutlineView IDEDocSetOutlineView IBProjectSource ./Classes/IDEDocSetOutlineViewController.h IDEDocViewingPrefPaneController IDEViewController id id id id id id id id id id id addSubscription: id checkForAndInstallUpdatesNow: id deleteDocSet: id downloadAction: id minimumFontSizeComboBoxAction: id minimumFontSizeEnabledAction: id showHelp: id showSubscriptionSheet: id subscriptionCancelAction: id toggleAutoCheckForAndInstallUpdates: id toggleDocSetInfo: id DVTGradientImageButton DVTGradientImageButton DVTGradientImageButton NSSplitView NSView NSView DVTBorderedView DVTBorderedView NSButton NSTextView IDEDocSetOutlineViewController IDEDocDownloadsTableViewController NSComboBox NSTextField NSButton NSTextField NSWindow NSButton _addButton DVTGradientImageButton _deleteButton DVTGradientImageButton _showInfoAreaButton DVTGradientImageButton _splitView NSSplitView _splitViewDocSetInfoSubview NSView _splitViewDocSetsListSubview NSView borderedViewAroundSplitView DVTBorderedView borderedViewBelowTable DVTBorderedView checkAndInstallNowButton NSButton docSetInfoTextView NSTextView docSetOutlineViewController IDEDocSetOutlineViewController downloadsTableViewController IDEDocDownloadsTableViewController minimumFontSizeControl NSComboBox noUpdatesAvailableMessage NSTextField showInfoButton NSButton subscriptionTextField NSTextField subscriptionWindow NSWindow validateAddSubscriptionButton NSButton IBProjectSource ./Classes/IDEDocViewingPrefPaneController.h IDEEditor IDEViewController IBProjectSource ./Classes/IDEEditor.h IDEViewController DVTViewController IBProjectSource ./Classes/IDEViewController.h IKImageView id id id id copy: id crop: id cut: id paste: id IBProjectSource ./Classes/IKImageView.h NSDocument id id id id id id printDocument: id revertDocumentToSaved: id runPageLayout: id saveDocument: id saveDocumentAs: id saveDocumentTo: id IBProjectSource ./Classes/NSDocument.h NSResponder _insertFindPattern: id _insertFindPattern: _insertFindPattern: id IBProjectSource ./Classes/NSResponder.h QLPreviewBubble NSObject id id hide: id show: id parentWindow NSWindow parentWindow parentWindow NSWindow IBProjectSource ./Classes/QLPreviewBubble.h QTMovieView id id id id id showAll: id showCustomButton: id toggleLoops: id zoomIn: id zoomOut: id IBProjectSource ./Classes/QTMovieView.h WebView id id id id reloadFromOrigin: id resetPageZoom: id zoomPageIn: id zoomPageOut: id IBProjectSource ./Classes/WebView.h XDDiagramView NSView id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id _graphLayouterMenuItemAction: id _zoomPopUpButtonAction: id alignBottomEdges: id alignCentersHorizontallyInContainer: id alignCentersVerticallyInContainer: id alignHorizontalCenters: id alignLeftEdges: id alignRightEdges: id alignTopEdges: id alignVerticalCenters: id bringToFront: id collapseAllCompartments: id copy: id cut: id delete: id deleteBackward: id deleteForward: id deselectAll: id diagramZoomIn: id diagramZoomOut: id expandAllCompartments: id flipHorizontally: id flipVertically: id layoutGraphicsConcentrically: id layoutGraphicsHierarchically: id lock: id makeSameHeight: id makeSameWidth: id moveDown: id moveDownAndModifySelection: id moveLeft: id moveLeftAndModifySelection: id moveRight: id moveRightAndModifySelection: id moveUp: id moveUpAndModifySelection: id paste: id rollDownAllCompartments: id rollUpAllCompartments: id selectAll: id sendToBack: id sizeToFit: id toggleGridShown: id toggleHiddenGraphicsShown: id togglePageBreaksShown: id toggleRuler: id toggleSnapsToGrid: id unlock: id _diagramController IDEDataModelDiagramEditor _diagramController _diagramController IDEDataModelDiagramEditor IBProjectSource ./Classes/XDDiagramView.h XDTableView NSTableView showAllTableColumns: id showAllTableColumns: showAllTableColumns: id IBProjectSource ./Classes/XDTableView.h AppDelegate NSObject id id applicationShouldTerminate: id applicationWillFinishLaunching: id IBProjectSource ./Classes/AppDelegate.h 0 IBCocoaFramework YES 3 {11, 11} {10, 3} YES qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/EmptyStoryboard.storyboard0000644000175100001660000000073114776170045031605 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/Storyboard.storyboard0000644000175100001660000000540614776170045030572 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/assetcatalog/main.c0000644000175100001660000000237014776170045025415 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconset/0000755000175100001660000000000014776170045023315 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/0000755000175100001660000000000014776170045026100 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16@2x.png0000644000175100001660000000123114776170045030752 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16.png0000644000175100001660000000121114776170045030376 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconset/iconset.qbs0000644000175100001660000000012714776170045025470 0ustar runnerdockerProduct { Depends { name: "ib" } type: ["icns"] files: ["white.iconset"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/0000755000175100001660000000000014776170045025717 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs0000644000175100001660000000022614776170045033171 0ustar runnerdockerCppApplication { Depends { name: "ib" } files: [ "main.c", "assetcatalog1.xcassets", "assetcatalog2.xcassets" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog1.xcassets/0000755000175100001660000000000014776170045032306 5ustar runnerdocker././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keepqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog1.xcassets/.kee0000644000175100001660000000000014776170045033041 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/main.c0000644000175100001660000000236414776170045027014 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog2.xcassets/0000755000175100001660000000000014776170045032307 5ustar runnerdocker././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keepqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog2.xcassets/.kee0000644000175100001660000000000014776170045033042 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/0000755000175100001660000000000014776170045026414 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/multiple-asset-catalogs.0000644000175100001660000000022614776170045033160 0ustar runnerdockerCppApplication { Depends { name: "ib" } files: [ "main.c", "assetcatalog1.xcassets", "assetcatalog2.xcassets" ] } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/0000755000175100001660000000000014776170045033003 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/o0000755000175100001660000000000014776170045033162 5ustar runnerdocker././@LongLink0000644000000000000000000000020400000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/o0000644000175100001660000000123114776170045033161 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.jsonqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/o0000644000175100001660000000053314776170045033165 0ustar runnerdocker{ "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "icon_16x16.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "icon_16x16@2x.png" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } }././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/o0000644000175100001660000000121114776170045033157 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/main.c0000644000175100001660000000236414776170045027511 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/0000755000175100001660000000000014776170045033004 5ustar runnerdocker././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/o0000755000175100001660000000000014776170045033163 5ustar runnerdocker././@LongLink0000644000000000000000000000020400000000000011577 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/o0000644000175100001660000000123114776170045033162 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.jsonqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/o0000644000175100001660000000053314776170045033166 0ustar runnerdocker{ "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "icon_16x16.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "icon_16x16@2x.png" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } }././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.pngqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/o0000644000175100001660000000121114776170045033160 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconsetapp/0000755000175100001660000000000014776170045024016 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/0000755000175100001660000000000014776170045026601 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16@2x.png0000644000175100001660000000123114776170045031453 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16.png0000644000175100001660000000121114776170045031077 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs0000644000175100001660000000036214776170045026673 0ustar runnerdockerCppApplication { Depends { name: "ib" } Depends { name: "bundle" } property bool isShallow: { console.info("isShallow: " + bundle.isShallow); return bundle.isShallow; } files: ["main.c", "white.iconset"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/ib/iconsetapp/main.c0000644000175100001660000000237014776170045025110 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/codesign/0000755000175100001660000000000014776170045023052 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/codesign/codesign.qbs0000644000175100001660000000341414776170045025356 0ustar runnerdockerimport "../multiarch-helpers.js" as Helpers Project { name: "p" // we do not have the access to xcode version in qbs.architectures so we need to pass it here property string xcodeVersion property bool isBundle: true property bool enableSigning: true property bool multiArch: false property bool multiVariant: false CppApplication { name: "A" version: "1.0.0" bundle.isBundle: project.isBundle files: "app.cpp" codesign.enableCodeSigning: project.enableSigning codesign.signingType: "ad-hoc" install: true installDir: "" qbs.architectures: multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] } DynamicLibrary { Depends { name: "cpp" } name: "B" version: "1.0.0" bundle.isBundle: project.isBundle files: "app.cpp" codesign.enableCodeSigning: project.enableSigning codesign.signingType: "ad-hoc" install: true installDir: "" qbs.architectures: multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] } LoadableModule { Depends { name: "cpp" } name: "C" version: "1.0.0" bundle.isBundle: project.isBundle files: "app.cpp" codesign.enableCodeSigning: project.enableSigning codesign.signingType: "ad-hoc" install: true installDir: "" qbs.architectures: multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/codesign/app.cpp0000644000175100001660000000003114776170045024330 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/0000755000175100001660000000000014776170045022737 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/mrc.mm0000644000175100001660000000010514776170045024047 0ustar runnerdocker#if __has_feature(objc_arc) #error Using ARC but shouldn't be #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/arc.mm0000644000175100001660000000010714776170045024035 0ustar runnerdocker#if !__has_feature(objc_arc) #error Not using ARC but should be #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs0000644000175100001660000000061614776170045025131 0ustar runnerdockerProduct { Depends { name: "cpp" } consoleApplication: true type: ["application"] condition: qbs.targetOS.includes("darwin") Group { cpp.automaticReferenceCounting: true files: ["arc.m", "arc.mm"] } Group { cpp.automaticReferenceCounting: false files: ["mrc.m", "mrc.mm"] } files: "main.m" cpp.minimumMacosVersion: "10.7" } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/mrc.m0000644000175100001660000000010514776170045023672 0ustar runnerdocker#if __has_feature(objc_arc) #error Using ARC but shouldn't be #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/main.m0000644000175100001660000000013614776170045024041 0ustar runnerdocker#if __has_feature(objc_arc) #error Using ARC but shouldn't be #endif int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/objc-arc/arc.m0000644000175100001660000000010714776170045023660 0ustar runnerdocker#if !__has_feature(objc_arc) #error Not using ARC but should be #endif qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/xcode/0000755000175100001660000000000014776170045022361 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs0000644000175100001660000000452714776170045025646 0ustar runnerdockerProject { property var sdks: {} Product { Depends { name: "xcode" } consoleApplication: { console.info("Developer directory: " + xcode.developerPath); console.info("SDK: " + xcode.sdk); console.info("Target devices: " + xcode.targetDevices.join(", ")); console.info("SDK name: " + xcode.sdkName); console.info("SDK version: " + xcode.sdkVersion); console.info("Latest SDK name: " + xcode.latestSdkName); console.info("Latest SDK version: " + xcode.latestSdkVersion); console.info("Available SDK names: " + xcode.availableSdkNames.join(", ")); console.info("Available SDK versions: " + xcode.availableSdkVersions.join(", ")); var targetOsToKey = function(targetOS) { if (targetOS.includes("ios")) return "iphoneos"; if (targetOS.includes("ios-simulator")) return "iphonesimulator"; if (targetOS.includes("macos")) return "macosx"; if (targetOS.includes("tvos")) return "appletvos"; if (targetOS.includes("tvos-simulator")) return "appletvsimulator"; if (targetOS.includes("watchos")) return "watchos"; if (targetOS.includes("watchos-simulator")) return "watchossimulator"; throw "Unsupported OS" + targetOS; } var actualList = project.sdks[targetOsToKey(qbs.targetOS)]; console.info("Actual SDK list: " + actualList.join(", ")); var msg = "Unexpected SDK list [" + xcode.availableSdkVersions.join(", ") + "]"; var testArraysEqual = function(a, b) { if (!a || !b || a.length !== b.length) { throw msg; } for (var i = 0; i < a.length; ++i) { var version1 = a[i].split('.'); var version2 = b[i].split('.'); for (var j = 0; j < version1.length; ++j) { if (version1[j] !== version2[j]) throw msg; } } } testArraysEqual(actualList, xcode.availableSdkVersions); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/privacymanifest/0000755000175100001660000000000014776170045024463 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/privacymanifest/privacymanifest.qbs0000644000175100001660000000110014776170045030366 0ustar runnerdockerProject { Library { Depends { name: "cpp" } Depends { name: "bundle" } property bool isShallow: { console.info("isShallow: " + bundle.isShallow); return bundle.isShallow; } Group { condition: qbs.targetOS.includes("darwin") files: ["PrivacyInfo.xcprivacy"] fileTags: ["bundle.input.privacymanifest"] } name: "Lib" bundle.isBundle: true bundle.publicHeaders: ["Lib.h"] files: ["Lib.cpp"].concat(bundle.publicHeaders || []) } }qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/privacymanifest/PrivacyInfo.xcprivacy0000644000175100001660000000065514776170045030654 0ustar runnerdocker NSPrivacyTracking NSPrivacyTrackingDomains NSPrivacyAccessedAPITypes NSPrivacyCollectedDataTypes qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/privacymanifest/Lib.cpp0000644000175100001660000000236714776170045025705 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int foo() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/privacymanifest/Lib.h0000644000175100001660000000234614776170045025347 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int foo(); qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/lipo-symlinks/0000755000175100001660000000000014776170045024071 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/lipo-symlinks/lipo-symlinks.qbs0000644000175100001660000000122714776170045027414 0ustar runnerdockerimport "../multiarch-helpers.js" as Helpers Project { name: "p" // we do not have the access to xcode version in qbs.architectures so we need to pass it here property string xcodeVersion property bool multiArch: false property bool multiVariant: false DynamicLibrary { Depends { name: "cpp" } name: "A" version: "1.2.3" bundle.isBundle: false files: "lib.cpp" install: true installDir: "" qbs.architectures: multiArch ? Helpers.getArchitectures(qbs, project.xcodeVersion) : [] qbs.buildVariants: project.multiVariant ? ["debug", "release"] : [] } }qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/lipo-symlinks/lib.cpp0000644000175100001660000000003414776170045025340 0ustar runnerdockerint foo() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/overrideInfoPlist/0000755000175100001660000000000014776170045024726 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs0000644000175100001660000000064114776170045031105 0ustar runnerdockerCppApplication { Depends { name: "bundle" } cpp.minimumMacosVersion: "10.7" files: ["main.c", "Override-Info.plist"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: true bundle.identifierPrefix: "com.test" bundle.infoPlist: ({ "CFBundleName": "My Bundle", "OverriddenValue": "The overridden value", }) } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c0000644000175100001660000000003114776170045026010 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist0000644000175100001660000000052514776170045030455 0ustar runnerdocker DefaultValue The default value OverriddenValue The default value qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/0000755000175100001660000000000014776170045023125 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/zh_TW.lproj/0000755000175100001660000000000014776170045025305 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/zh_TW.lproj/eula.docx0000644000175100001660000003006214776170045027113 0ustar runnerdockerPK!87l[Content_Types].xml (MK@!Um=H8j ^I_Nm/d}g͌&kĤ+ٰ JyfO- J&ˋl evd py ">JHq΃bz0;9l^Füܙ0pzֺi yll"U?<ҷd}] ԁlPK!`N _rels/.rels (JA 0ޝml/RM>@I}{QRK'|\ä^OiAQ8xޮgw`t8HT`]_-hBEeJ(.vIbAg/8^ 莘j Am.arůJFH %v}}fqߓ@ML̵~ U.ns=y%H]APK!? word/_rels/document.xml.rels (OK@a٤jz^oRib r|o~'jS%)tƗ7 +u*`__^i{1őLVS{tj2ԲC(iaYؔ ¦Q ='WUkɛE*$!s܌b5,D9r?'Hz hMA,8;_3bd0;bocۑ#INl$b^}PK!e word/document.xmlWMo60tOaEvEl']<m HHQ Z` -+0`(e1ReYF|?>C7\Ҁp0ZUC+^M핪VQOv'Cc*KA;qM]]'Q9+W1tC=2L#Ŝa"DtEl1I2*Z`gbBenRP9.pQ8 ffDf!rSz:'!fTAxyr[茏GU ؓFyk+fp-#)Tͦ.'O _ ]>]Fg82:C*BE gfJ,&8+"f_V}//PK! (word/theme/theme1.xmlXKo6 xߕW b-EϴDKP@2q;Rv׻ɢER7ΐͧ\gtV ?(2*L& vaF6LL/+?ݰk-hjLy:e?%n_$;\`,H;gOIo+k?h `u>^ EXP`ÖJ^,hp{Bœmmyqr*Ղf<#@>n^a,UgK;erþ`2 ~\.'An8gGN/?VAn87W鸍GP*2C|֙!Br>GT^N^-g_ fLZ 6˹&/r&-欁pK,y&Q1Ơϻτx0&],"NPspb8&0e&}HY =̙Կ+ Wi| ;m*g@ rlq֮|_SWe|O%Zy8mYüzֱ;]'Wݹ\Ql#v.hLZ@*,(9 7ecM"~EX[o9XPY,!*NgRe2"gjsu;VOIZuu֞`[՛6z=89KMqf7c膓ڒhܙ궸Q( lAl)lvͪr ?uLA v81u`Q+}t"ADƗ zL(v_hVW q(z7PK!N0word/settings.xmlUmO0>i煼ДQP[֍ شpKd;-eىn_8?\zq`CRL$D`YQp ABL 2 vDW]lsM7=BO1uE GDD#G8ROMbkdhI5(QХQ"Rb%\b{ېkNq7F0A frlĆ3M#JU#)Jb5 3_ Ww].'+-AG͎餥nijuҵq~R*T\,_mApAIYP& ì@qD^H. Zׄ1'z6bzTdfPYYkҸ) QE0dKadޯA &EEV-0EdA 8w"Fa\5{ Tߥ47Oq[e{t4>1>7|SZ x1GT *E֣TO3*<_9dd戱n6<UPo0/\VBD}R[vP}#*7 ]$r,|5Pn{yI>)>vi3Mu8PI+s(Sɋ ܡnuTIjmcTGUqҖsm=zc=6ذ2e=6b.Hܛ_JT{SEe'-ǨamTdW߀rx6flٞZY8Mp8f8 gţlz^PK!t?9z(customXml/_rels/item1.xml.rels (ϱ0 hoPK)t;JGILcXji߾+t(QE]1hjP >N~j.G{J D60o,W0H9X)ctl'_uݓ|P=;6w#w Ev d*yB1ߪ kPK!s?(customXml/itemProps1.xml $( dKk0wY~v\K y,R()i]vSdH"4&e. XLb! cPO0 /'g: yl;K̺uP*Jֽ9{OU?Ő? 6s'iE3Y-|iđx%IC/yn߯8{G۬G`,IsIS{1mt PK!ݸ5< rword/styles.xml[W8>y}6ts4,ϊ-|e'Q(qIW>HhnKh`y݉$l]DsOF,ց5#/5z7<:;tկ鍊x2. ')\\1OŕHYof"?g9bNtP)2eU:!9{$c,!dRX&4YmA)s5QU *)9& +60`+ / ,ͨTK#F4nM~R[K#F4n--|D)o:v;>܏x̘/791gYTBnjmL%oŚ$QMY>k4*s-yDZ [Vo M=3&ei iiLV͆6m ϰ.E^٠Kwvb[2c+VJk*~V7bv@"F )(p/B ڨ6*D 7`8xQaQ!Ǩ6*D hBڨ6eTHA"FQ~10gTcTH1* hBڨ6*D (p/B ڨ6*DoT3*1*RFQ!mT@"FQAQ!mT@"F5 qF>FB ڨ6*D hBڨ2*2* hBD_~]z:o3~ԟبEܬ7М)u-oa1BSԎς\sulz77 ~04S9Ky;y}nG]AkGeo5\|J/G ow}oV  Փph@KGp&%j1Cc M0TF7֍B+FI mߨnVjH`(o!Oj81b%5K QRCp)J X!+uK QRCpsRCVjH`(o!OjP%Ԑ![jڜEYۄY MVGdE{VKZZ-4UKhnP܄2 (=nZa7Oj\%QԸj)5ZW-JR㪥.qR%5ZW-JR㪥.qRԸjKىW-JR㪥.qRԸjKj\W-JzUKnqRԸjKj\%5ZrJzUKR㪥["lE4tKlX%!pǝ0R Jqu/C L8r|b8oVao,zlΫl6kG=}ү*Jb}j4r@_C2M nVuxD+6zxO+H~딌7? !GPK!ޑ(customXml/item1.xml $( D˱ 0W k $ NJE#=Bs)I}{}E=99(A02]OIZ7'hI}WI#br{J… ]p.7?P&zdH9Dm=Ι#VuPK!Bioword/fontTable.xmln0xk4-Yt*Pu4=xftڍUT$sqMp0% Tbr]/YX0WpK ~u楒_\VyRQHT:cu$gD[dm 4=FʒVFPiHSJf/Jj5,x { VFv#(=F~%=`r ߯x]]$ଯ>hs3,|-ޡR; D{h&(u_V):GRamh (%o7VfTuakgh!\aP8MƽtGW;u =xǝBw~:}zI͇O^9;,o>оA* ]lk_-q  ]M&^WLWٕW.,p^L? 29i_PK!fvword/webSettings.xmlJ0;ܷi)mAx>@6aLd;uEd>7fGd7 ?6mz%{eC#N@bs5î'exnĔR$=ScϏF_(CXitA%3֤\Ń83hxF}p2/#Xd}k5ڌ5>~yNaʻ?3:"r^hx,?pz=F\'-w+N:nak,ȶi?PK!~bjdocProps/app.xml (RMK0 һlD"lsHm0MB2ZV{ɛGwL*,`oWS}wZ7r;BDs>ʎ( u =3MH"nS+BXAIWձBoI鿢&_~7$G-LĄBH(+UY.Ad<1pթ4Y 1:b)PqrW 淀CQ%KǼ;G'cΒjݷV8lT^S 2XQiwx6O7#`(:'7[ߢK z\-*>_bq PK-!87l[Content_Types].xmlPK-!`N _rels/.relsPK-!? word/_rels/document.xml.relsPK-!e  word/document.xmlPK-! ( word/theme/theme1.xmlPK-!N0word/settings.xmlPK-!t?9z(^customXml/_rels/item1.xml.relsPK-!s?dcustomXml/itemProps1.xmlPK-!ݸ5< rword/styles.xmlPK-!rW;b#docProps/core.xmlPK-!ޑ%customXml/item1.xmlPK-!Biom&word/fontTable.xmlPK-!fv(word/webSettings.xmlPK-!~bj)docProps/app.xmlPK,qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/hello.icns0000644000175100001660000524214314776170045025121 0ustar runnerdockericnsDcTOC hic08aic10 gic13aic096/ic12ic079il32l8mkic11 is32os8mkic146/ic08aPNG  IHDR?1 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  @IDATxl۶m[Qa@DQ$ @,_?O_җ/ٟ:~+_ D#PDbk>kGb-;&E<lLկ~??މ=>+՘m]ܔlJ??HlC9^n7$P#߱MIF5ہdZfS`@՘Fâ'Uᦨ>i_2r|z`]i0lj]H|2#xdYJaz1Ȗ8?P3 k#@Y Yd"!ϖV,qOIm+B(<į^<]]K a?Q#gY?Fz*́I 2l moS #/2 >]Rɑȶc%&{hji~/|/ iڐ,x$;u LI5`:o[0c1P)k#jw AzQ4ÝˍHAye-=<٣K#{)&@'v,iڪ4F$;ɓ2 H)@5j(V(H!RJi4!1a gP9ǚs!ʱdtt+Tɧ+}g-;f8Z(gN xJ.q)?O%x$Ww{@#*8ʞ3&9 2nF[2>2@݋0 Op+c RMYɍ6J=“Ƨ L5ځR'DK!$n :ǩc3>Ʊg~X )xj8cͰ{>ȁ@{GnPVaˬªBUe-MH-ؔ <){dxrGRFb" jKbXK;lp;4}"u JNjEiO| "F^tG2fė >Rgt#Y9=MoUF3~{Rnz7:sEL(U{5nɳA Xh77U5fV@!&JISc#00+uG JNvzޏ#0ajz[`k>^K))g-@7X/@jl!|jW?(N֌NIx Dv]&&DǪ*7ߝ1-YhfHi+Qo#dZ0<)l$WUiCLwǓd1MAbmex$(&6>Smi{E/;IKVFzӬV}F{ S b>Yvh#^Gy~F?1a3`ifTu6,vj x ۤ5ДvD.26j#"ÔZVen\GF~9Cp+TUţ=d&j]B^^ <$(e sfaD h?knde3wz-CV׏ |g}|TS1Z'[U ·l"ȿFXH8Q*ɷy2Rnu1ԈױFYlbs7Q.RzDF"Ld|TU*#fŬ% %2kx `E%GhѪ< &Z -p] A-ެ̇,pV|m@wOiXqjjmj.JReLrPruۢ?P}`K@hJ@UVJ{ xbjI&'F.5]2+e90l|ʤ'M`36nh0AJ/CdʧfS $5XBk=/dE@'H`F؍X#]52|OSU%0.r߭D%= z-X#X)bgUc0Gj= M N3~ITE9r)gJ~ hD]M7?@[ݴ7 71g홫x-J(=>CiGA [2.Ga567CU ͰѰ 2HULC^^#tXWnш7gu@VgV=F9)r5ʘEUI50~JdR&eUzzz8%Cj܈{dޡAz&&ͥl(MǶ}</2;@0zVuceG'$VD]M$6lr%C| q9lz6Q10Ix<T9w'C ,F9grN0 _0E2S']dzú7^I{<ˍڕhI&Z$[{Qo& F;Oꭄ ~o.5#Gx9R 8lӐq g*R:R bT+Gbz7}*ͦ88`ʇ{毅3zZbdc)?y"ijFIOS{@#яt^4u!dnBInVzH؟[?AM*<&0gh碣c`ng燡8AY;tkxhPkI#Y ) ?ړ;>g$ >YJri2^kho%x: Oϛ8r%u-.ZD9hA?sOdž{ պ/8Ɛi$˜ϯia#gRmr^{;p^yj ̡P(2v;+kIJps9+|%Bl-^E,›B +#,OSbϰxKCCh_(zkĜjǧ$JrF1)UΖO8z43\5ll@ǍF uUI7}[hYhoXH ȕFaaYލ1=PFHXI/S<)CL`TTʡFS6\ P'H#'jbG1w 8A|VMOs͑oDQ)i`-Gϙ{ҍ^6cJW&]!^.d+Vl M8UО[,7d4Zؿ=חc0qۜjEnìfتz{]$ w?٭s9h'`$HCk(Q§)h c>L![8.jNW*op;lLLʬzRdMGny !A`H7@Q3p%Uƫle]JpY0"gq 4GHVUlU몱zJ"M`XS|}fՎ( 3œ5ɴ`F`6d41Q-=\Xa2|3-ԇ'*?p uNa^RIxæϱJ9!Rr| }E]Sԋ':[1y37bTj=2-FAiThjlnKnI):l LȔtvsM81> O ]PU,M*OZnslVWHl]L 4m̪3lVG ŖE`ws-U;s9eb24r2E󟸅w E)>>0̍1kܚ+t U愇 r 6Avlt`-҄9F+zׅuX?V^ >s |fJ8/DE^ Efpx~ljX 9|#%|r-$0CHH&\ GB <ߕO R{7Cz[㩜R c)R"ȪvxRɬ|P=zjkZ"d6вu3QJ騽-{42ٞRUΎ-OJ5bda;UʠY<V Y;/#[u W/cDc#wI:$)&!=O]ɀp e9e2{cHL&Z`4+ ,:H$;w[tJ l.0UXz cudRdAPnJrpSuܺlY2FY)-,JYsC&U3l(I6qhw_-Jc#-od50 /y7MYV*ρdBe%ҎH_IV2p} y) xCT!>D?x9! @P#e=U16]12xǻ^Y9 ?{ՔJ_A!.Hy~'oun1%FĨMTJ a bdk'ƈ)a|ٷa8Ü$ ^c?Tlr9zL̙1tm|sW6QU( δXLѱRt8'[2YF%ϳ_A)+E'Tc>ɵ4aB rl$1,^f1rJ <ϑSU @־Mб>IK.+b{wmf/t 2Y#Y=sR5l ̮)FHڸ>h,-Z\!V]c?94Ijۭ|dG2x{?V ܈5n.4MVuiZVr Jd aB $kVѕi*}-,L;Uu\ܱv8FCS?T:4m[ٺr^h욛K&7@KoXz,7ꀪf^6l-JazYD4ƒ8>>F(' 赘&6O<}o۶ҢTDc,P" xX֘awE-4)@I^&pkl(fd–IY)a=4Z(Ue97i}LIw]Wyn7HUj Hσ?zhE1tTR}"$_Hb&8IS9ׅ+8Iǜk[+ֵ#/*2FbZQMf;z%Xz wqskm sr+Q1J02Y1wZ.B^1ʨ[U2j!UFٳd=db-|0yZGB̑4hI\P6V]t$PU?ď|IlzRmS;ҳچu1 hJJ(|,OY/hRve8qΪ,2,tl"eQ&H7:qr[8Al5&6 P6goc.ߏGQl7+7CO"6AZZnJ-{U,A!wlPils2 A&4|d˴ܐpyR(ebCʞg#f$0s=J0Njډa#ELJO3OF%Y`Ƭ xtzI p4ɭbIϰ23_0ߏ3o|rlus֑@q}.dpork@^2z{;ji.<8֨?ґa2Ycx/2戞0-Cy<9aK CClJ8]) =F2$[WEӱ~'LO5O_RY1 P|v<[B vL&),>6ko 8pL 8'ʱ t̑) dnrQTxssIb.2 MĵW (<dU^U+̺%Tj\1d)]Y h:ƛ@˪MvUmiP$`#MmFЛ' Ti@o&B gұH@);T Vv+,^F^%a@q{Q0Mo[lmRlrhq2UzSV%LMSKoJ>&^8'ꬹH`dc'=YOMV U֐a-,sKh3OL%@V+KU|k(/Ⱥ zUk mN9clgX p/h*x="dHWi!xY 0ù^5b du%ۡAǘLvCǑTs<4fZwa2=kcp,Ȍ2eo˺׻*Q#cdp˾Ȁ.(ܲxoҴ<1w#2)ch ԅl32VswM8ɔH I]YeT2FȘ'&eUiJ@C[#)Y5-,Ow@j:} w? ^S]6&, itY%86+2F;F[d2?î蓶ݫ~w Y6z)p'E$^ ' *.27S}6!p,FRbdsd;1Ѹ<7:AG]>zw3Cv;2y&16Pg(;`aFՌn; {!H`9 Ǫ̑Y= ׸j'Khu+4sw)5O1{ r&Jöȡ.SeGDĽtV)Y"+ȭ1"lcjQE eG#TepgX LƟvJbT_;Ywga>~az w ӮF65R 1eQc_gظ5CجdV6du<[2nd C&37XKؑFL#&X;LFPeb|2z'ln?1PE߶(=&5Uew5kYւ!4a]'H&\2y NɵF gy irƋ66gv}hOK.6 ުp=gpLH] 2lx?$3ǷUVJ> 2"dG0JzhLmj*7Ѹ睯r7cr8׫KI߼} 57[ M:N捣/֫J2s; }+QU$g-+0UZ׎[)+Y5h mO8A{nSAMYW;zbp:U1˙vkP- 4"1]TUj&#(bfU)Dz,(Ɏy)Jڑs-}*_Y§ih1 BUk5[~<5&>lY@Fü#A-H/D,GzD0x~R[!,itOg( GQș"@d}0^ӱp$qOIJ2rJ6tӱ) wn^ndzKQLӧ҇>x@xH!>1탡WmF mze#ReL6+L|>p4RykJ'ʎbm&nz#=IM䬺Kf]VZ)$km%KHر.Gh0Y'jt|ǜQkyt5>f'CȻ7^VeO@-VJsI k #}f[&[_45M/(wb`;ذgmkW#jmKm]=XLGzvGFUvo\OcT;Ęw!gv#Mdq =# 4:MLEօ1BzMa dXL]RnueeVp!ÂX)G&/4ⳳ^'E^A`j >zv~h7Y =4tSf~/I>[֞#`ޖ0%+`Ay2YpJɗ#fPAƴJ~jqh([frJ>O!,x9,O|:٪i9Y&5;bլȚR&CӔ21cdϟ$g_@vA&m2fSݮJP).z I5ImO@un{D+9sm1Gd?foS0 =V1KN+|T'|/]|S&v <4ȪaʀqyeY} q_[o>vǨxw9$Uźz0JLM7HBxл)0R0}_(@H17+^?IL4`d{!JQc A2 p2$ ڵ.D|G٬fkmT^ZwUF&# 3$}u9Vj;tZKuɂLf"(O4:&Sm<0L=L {~)at@?k}"p;9Y|WCP),nj Y쀶! sNTt IU bs>Qm㎲O#{{5kO֠6a<bL4¬i) %71-h(p:n:<aC]Xӓ1Iܶen@q0yß_/MW*".M1CY WmKD ~tyx=KO )1Y/}a<{z2=6= )h"9#q> 45i`dL$ܸ0b&>g @7z˵vH(zVrVM % Y<+|#>9i\&2r 9l|l3L 2r#b2P$e-"i#O3ŚI{)),aU16# L{X4Yq~BRoG>a&r 󁋜#o:F|#$Y9hn7z ^ܔ2׈kDRޒp2vlWH&1ks{p2~;pK?#nJ6QrGJHdrr] `^IJ=_XI.Τc%-TIiﻤd5b }l'%8jCki5z?f(^#X]-17/w.80i%]FUp<&C=˄J& l1: 7#5f( UXj@Np?򪲨XFHQoJ8XlnXf%`Kf<˕=^i{|-}\-9 V$lZɒ{P)M_LK)4H)V ΰY;k\WKot%̪0C|J!(L'Y"Tj0޳ {zI"\urv RhJ{Izad-O0! h?^׏jHqGAe#cÏD&b7Ȉ~氨tqTƤ?Fr _MT=ix'@JVN&ƴdJ"L"r8ogY"fD ޴/XMYa*;Jw.#[ƇdE-E# O_)s[/ےU( ȂG'=;UǞ#8?'lJ;(Ip%JjH 2GC4FegƤqlP##p| D|_6d&Fj@8M->*9O%>k,q,]@e ,%y&`&<ݸ.@dP&VVXYI)1Z"gҦ'0iA/#֗cbU=D̡3>ckL񕸉p|0JWt+^ , n3OD9#DgDynC q~z ^0zeCɔZZfwIZ (zLBlqU.u&qE;|R:i쁙 `a)@gg.͕of՛sߞ0e .2&qܲ5]>=zRډsqp+9+ RcL1 A%XPFdK l[jkh:1' ו#c|*r%7xo1>w)P5Mo 8@"YW2٥+9 5TdN6A 5&H$2@P(~`]vgכ`hOf~fu皫ӱPO9L!dJv}Z3#@V{N Yվg$4Z "x7.TϜׯ$M ('̉azVEU29Ⱥ6&vzh-o:yxfe. yAr(4Q ּ;Ϊ75OCfs~o(odӑȽ4@V2Ylëf5 `Zy$v)m2yoaP˴6Yɹ?{cmЙq(M87(|;4nm0,Di-"*e|Hْ>鎖"z3K#* G10psyjb4,k']{ 4((6c2S8J_eǭ$# Q >Mz $ "CUp+eX#\4&K#‘)c9P_lEmrL/oXّROgB#aG7Us/ZJM+^^`d|7U&nq3Yqe{{Dm дp8^69׫+,)jPvN:SLq1cq|:NrLRnPfa2M'nb8%F)^3Y:i*$6)u[(|ki5jaL+mŜ}Nʬ Vp42F(\4y&#@$N οcj6M.3vpV[;):b6Uᛇ\n%3ڤ:L2cĭ7vxr+ | Mpk.+dό f҆daX U;ݥeLU#WA#vL*AlM`97>lG8ګ&˼%\t&yz^L9C;2pxG@ueܧ-M0 ȧFya [-qWR޵az6&Fdy9abOx]L &xǵxq6aR]1#itqn(XLFQnzHkd;E"%OhmLd0} =,Jd4 օXK]%CXIcd@] ۄ4f Qv4-GnF|xڅ fBDWLӃLLX(&&`+6ꝫ"i"M9|J n>dW^]]ors;CsTL/voMhwiڊXDMW?U3ϘQe-| 7<_88O-eb8OU;$~>Cmu7x[`R9Dn-kzm3K$\ M@&s@G`qLcjLo hT- Lμgs^cJua8d.sp-)@[Ll*b>'mnOinFX@N,H? SFL Sr|. w8xf(ا&k%'Ql֭4%p|;2`z&k8-͊g2N Y9lþrX [ 4[ܸIJֵ+d^v)/͘&LAFd8k:Đ@JHr|rLp[.h)ݩ<~YgJxwL|, &cV!PZ'3w-EfD<UeusID7P#r>;EpCeC>yb]r|dd&ziFd:֏yF;Bq+eZ%[H IϤ. ,G:˪lzRç󉦲k?U4eJv @U di"tv^ΡvՍM$RP1J0V ˔Hrs;ۮ|f UUmǞ#="YdŁ^8=mKO)'Te2EU-s'ILиFJr`|*i4Eqd!@S>ګ?DLЯiJP!ecrȰn?%AWZ6;N! h ~ gAxJDFP0+@;Sbn>A+[@h6,8y&4)0]c-#?GJ/2$R nvF뢤2,4zJ]<2 xya'e ? K7m{_ˈ[lRȔ2䔹ĪܐԖ1^#5Z#Y4FnFwqFn;AU`dU1^n63&k=I&2MׄU/STK&xLL&h dQ)Pshixv3 R&d ӍL@IDATq+9>妫z,. ;z3,[C)-;2.32^d 肅ܺ#ebu\G#q@YA{ah]MjT̊XO'Lr7 .)%.@7U=;yTXĹpb%XOF;E L@ӠA/wfl6<3P$?>s@&`%/J=@<,4yP#?kQʁ>kIƔQpG]^W0x=e%jl O}k(~1Y5`Z2SBK1B;A/zUvӳҒ@bb*O^h nYQ бؼ~/A0A G>,Fa ;fEZO4=F4@@)5֮ZWUZ( Gb(tyFs Dn?d9%`RŽ:^d k$N:ůJ<.O8ƽztLZ _E~_w$h ]u+h$AG-yH Sm\1󜑎 >S3Lи۪q1L`lҮІ|Wl:#>ZnOSg*&P HǔKpG9 Z1]Fv|2IV)40q,"{ pϑ1[ZpJ0Zdrn!׾TTqYƎ3D UK_'ًׅMd#{,w̪^8Kdۓw$K\h.PWZm( kLӱ)+L#E& "F rH4_)늼Myh*TE $P+2 L&7e<>㵈6);f;Uj[!p'>!&7ᗆ5;o=QF5CLfNɭ7$,OM[0ډaDXMsWCU-%ܞc֫FVMt+idL*i1jpjd?"۠6rե$C)7, oK3U8xLXni2&W6ỖX( u.:*2_ /rcqϐL|ߴ#AΎw7.K*ÞGH-U}b(k &g&?O\V9|.|GczebRltw -O= 喡|S#R.8~UtT ظjZs< 2*o|w5ݳz 0Ƌ޻4j! 'Vc^~_&'^o}[|g?ce[^m}#kF0@w92[ / #sMXx.8&042=q ˷RP[H;Fن4M! w%:6 n/H@TJ QcU@`AaŸ"|f^$]Lc{P"Kxϥ{4BW?0 ɜ10h =^e&^韛M/\ يZ`]bU`F$#71m?ϙ|~dc}<I'3=*MkA{OI;Le~ӟGѮ_'n'c(Zda@̽UV dϊg?|O04q.>F8x}>0w|H^J&:RpGL&)S0^C+*daYODx$׃12H 0d[#+Ϸ?[ Ont;xڐ_{e^?]J><%`ZdR)? ' ~9"E&`-Y6ڱoTԛ{.*u.+m7 ܫf<_`=1y<O׿?B. rh >a>O3o *Y]@Ekl%-O Py=-9Ӳ#~Hi/;cUk4 6b-Vr&ΜDM\}!ucdF %[Gq};{IH,9c-X|j4B6qoO$=J# PM0 +zwzs?1ɢ˚ԍ_t¼MژvkwG24-_0G*&5U5Lwa2zCO$Ys0M'e;xXf`"<78>͛oqe?#k1l ?ܠN(o|kt@DzP}rӥ ?7~#gۃRۥvKQؓޔ /%[N ]5?B~zM)-L>d' s+`\Ԙ阎 A45**:'r@--i^&@<\c퀗m)kp(~)齯{R4s9FciU`;'`#~1{CgҪJBcc>MW/fOTi ǑvJdx\~Y<΢׻Fs-4v -p/h.tT7%qpޓGc2Rr>@,ՉOPud[&$o2>+K\wM* AG`źHZ ۙ@|?fn]pMǭM^JQ=7XY FX |Q4MRafX|؉077ʪuY [`i.Ŕխ!֛OVSwpt<vin%^JYJiB\V -±8>Χє'VNysn9ɁMzzgm !bF>惝C|WS>z _toN?W8Z3;0[;:}Qq}N(Frِp/BUt8Lx"M 4..ZS㣯D_ns 8F:h߿\E_4BY#r[- "pXkhhHѻ睒@t iJJV U&%[ B8^y Χ)88-ckzMKv&qSMdD]N!g7@%XDRܾ1ZZJcZQ)+6 Çx?Fn&_L8NJgkb[d"pȝ Zt6o!BE*|(0ZaM {I"T%J+_AdMB AHQ1gEE=7m0wΞ5ohƇ{&&; ~F u>5NvZ|յ{XKtl@F1ΑhDn /?=;U"L>^NU"OJH]cr35 R෴M%FF( l-_mr5uMuqpggZFGmGHE=Ɂ-ujߧ_ĵQ!5M(#t=DRWVړY3R(@ʕ>hOwSEsUWԔƀ!;_ .4_F~/X]í=#ۺ0K%T:2B99׉O~S@jPVNPSiE?8MBu z )#3 zǔ?6nI!]Jݚͧ([SEc+-קfL$&?SOĈPuX`FV 'R(D*A|9k{&(wt y$y!"+=)i8![E,ȲL;⥴?qlWI!8NQij0Nyp Ι-G?϶7%1hGh#. #s"Xz"Դlt?{IlC\9~WG TrA)=~)iRSarCDg8Mij^o7.$7C_:-K8)&Nͤ^VA 30e8)&2崱7ZKR$8M;lmFhޘ=;U oӾ#B5-pߟ9.[B-uYB@^;?K!&a׈AƘ- D|*'{ A0֕!fe4 +ڈ6B+8De wR9.';_ ҩB[7".maM<|jr7 ߶Cխ eZ?VȄYY5(".Y9æ#1B,1:'Z]5@Lہȷ/Q?&F9`EM0'QbִI>Nk4N +>g#ש=iz.F9MWN:=Бxnw铒8?Vb{X+Jn g0]J l+[(I4 ̀ ID"Gn!*,(^̦&fJ")TB՜>jR.XF-(ԘNtEM6eB Vmcɢ]V|TuLBzdN&S#T[ fxY+XOߥr8ܢu]X!}륜PMhR9 ._h%I'lRq4lF:ƽr51~r..)kD`"EuB3~hYBݍ@HOVR]><ʘj% ǑȄ>?xN,h 7fW)TQQ 4fcW=(qW:׷g'jk"|6]4TScd-'Y4q{@Q'wOch+x~jԻ|',eN5&h,QoeR-?qۗW>x3"1AV~G[yj|ŘMoN^>)%8UWj!.nx Hg *ߝWꪋ24)۽2eOͳ@kbʁ@-Fu]L!D +NAn8OmQSF632+DD:鰚Ѻ'3D h^ilM ,˴9Fl U e sd>\̚VTU1fRouBpX ! 3@o~V,o,"wjhUDst긯εCa >:\Z~hCh4M4-@ƩUV E[țXEK_4$^8-CĨ89F8Kؾ-T4A:QKJOs hKp=K@#!!|S'b?svSnc,h_]~ESfKU'G3~?Tv秖8HHZ`BKd|N%8J 0)AP_QXi#*6k M!)} I0DbR⚁S?z#34Fx3!dF(%f;f7~-\IKNZQ83#p2YE1iE I`+A@vzOydN[?Y{R.bDZZ r8tY| \B9L..;3Ҍ3*|+O!D+Tp98?~rO#'I4N/Ә_~6zUFTlCJjkt1Ŭ({.P4c@Ɯt<B6GX]kYz+= X%L+-ٴrCL!S(EnԄLܔsMY4[]OAѳ鬘_Fˏf*o]mgMc`U4,E ,~̼kJi eA꟣16$K _n  o4m ' 1bOwP](_ Z>*$o9@)O͈GwY?V @7If]Y{fp( A5*()gkBȻU阉1UThʉ>Vg1ZUp2xe6ntķMt3)5_73'/#aKEMlc^?]`HFs !+Y9JETZo/? փρN^tT|~q$:֤(U4B=+U:40\8;ϕ+AV)ÄL?HZ6 Z m{'L!Rh iS:ŷ4w$_Őg/? AtbbC4Rpyz=M?Ư]Ɋ 3nOoʙt!iRSS̲8zsU(_~| ZHRK!WԔk+D>,a J1Z Di_ ռa$-M˘.hBríP3|)M?O&c4xh/w im֟D mRj_f/1>Q:5MV ^||ٸ:JIJ D#cF(Cn䌃DC8/?-!#L姟Nɿ~H3QwH\ժD=k,mLS=f\:)Kd*b-55b)o' FhH mU_ S@SR;o[E5V__ !WoZ g=WѾ:Bu+]i8$>4YE9<N"UXQ%߅U7z/Zf~FCv uYR@IJQazܪM%^Yk)TdqLT1M,sm?Ń@bI4@Sxm4 \zW%[.~k)=C}a'ef:#:pFɁ3 Mx/8,Mm\cBF{lKSz G9OB[QpS&ydB> %.K>"Z8$N#aˉ1mv>k oLq9hB!|  @;dS~>f @HRKJ!Ψkop]!3C )P-Nj 䶾:w1AFh-O()BGMDӁ`BLs2!S7?q'ubp'J hC-d5O!=I|]9mCL UɏHR4"eUԘS;ۥDL@cp@vkw-HUB0YۑRMK7֊Kz@\1m>:ArK{/lt͠_,K(cfZ ӣU5<&קG >DݶLSYn, 1ۙd 47 o!r9p4 b''!P%v#<4ÍB퉐>C֎Yb"Ё& sB)גZUB`iqN="4]tNqw]_[G܃UAb7)Y%>^ gR9J`Sc S!Y&~Wi)mFmԃr~rj=,)8N8BL{߷B0UiYqUƮTCVBI׀*a΢43)]UhVSFHۇ8z`M2  ع)\=x|(rtȥ, rY)Drj.ɦ)Kg-Ȟ)L@7hMEPcu-2a)6m]?͏|#%O(''ٜ@{~{(Z.#8tk`"*h+ZZ|7LcN{qG6R]efB_4-e7G)3fˍ i-] uZ؏8VN;4r[bUPhC-_SP'Ο'Z"Q#wxpF~쓈k\bS!PØr8nW=;rPp {]6z_ӌo(ˏU/h9 ZzB@LcR3kc!.7Gc)C\ӟH5K0ߤIQ% T4%N׈,U$VXHN$3Ѻf)c:4!8FU/FgD]B:NrphmI ygp+ ЙҀ9tC;;8 *zx)6:b z?NO\ˏpڄ7nS:9)M2FMArdU bW;> ic[ hzD< {IDc)s$zK*?>S4uÀ?KlƏcV HE%-jyM#Iί@r>7`.[:O ժ\`E9.L:}\ڮD3zY*q N ؔ,gV{q8T3KXC֌ Saފ \9|L=p:=]2A>ORnLUT ӈOEB#Հ(ҦE1MEer$6Ek*wC QHLiFIU 4fǝ/(''FUo-l )j.D&>;Q~jsY8jHw1䚶.~Sc'Q]+ @P" @R+~ %6x_zKjIi"e on6)# 8i@uq9(ȁSC+VŪұEY)- F;f`:h)[ rDSc nq-_b $嫷eqز55w2)h@ǁ8dP1'p=z] s]~QSm|?_!UliBmE9)Iєn{;6ӳ?{  ҷ\UeB9^~*#y_R@:s+?Z/ᗘo\Wp&a%X3m *b9ԟ_BC۠)IJnJvB|jU^R4m[ Etz99Bj 7峢Z~%Yגc>}1ASdz*ږX Yp`SG[h(|rp[/rsozB '%ʯi>'9Ûϯy5OPbtX|#3"Ј& y-"B(@kVds)HtJ#/uգB$??)D)~8'4_ԁp:CD{X-~o>]r3 `mWJ#mcip) qW)-?zXtl g`Ojm^VU8jr㘢S`;SHOhESt~d>+y["-@AT`:Uc1\ )מ ՙ1:@_'q_ KXiCHD('OΌb(rv_w#u/cw!xYpOnf: )gs3 ~)BNu tf+:Jݾ*]D/Nh~?.$Zj۸HM^'>BXpTB1!|fX x!ܰhFS/J)l:'l1gk0DKQϹC|*ZZpMї^MMy6YnqiVB4_^9ea[2B4T11:E{ZAX)B-p64o ~:w2:k)GZ]!K'~ FLUdjE%r3j]ɯFZ XM[ jBT1~6~bNXo|:)~0Eߏ)DbrZPpgU9Ş?ާY웉Ң`!ܣeA y~1~8XF&H$)?hQK)SWęw כ^L"R84L;8%csgtnN>҆C_-#~n !F*,遜tJlڈ2HU5\Qfshv_~O_MߟNNIYݻ2 Z^@_t\]/ͽ7^x:ugx@'o"sl G~Ԁ(÷k $Joh>ES -|ˇ9^]8Q{D-B^;qONo_hTvmKԃiP)^/\Ɩ8 g~n:"Lpc獇6ݑ'n~jB @7qKpTƩC 'q!NQ7O:{tbΜ4!F`B)QѺO A(~92&e Mgٖ`[/u 5q>0}V Ӭ4q)UTH4DΑV*^i!88!GF *."T-):/yNב-e"ݙn(Dd~t_9h@K {=SqGӅ߹t5Oh=v6ZT!`*dNR5 0 Izv ő5@3YHubRiZiic1qZNM!VylqҩmjKqTED[t Pۅ;Mp%Ә9?DiyVrMUG M6|uN't)-_8l.c`tZlv]%֪)߇LYn6td! rDy"ݔq#H뛘72leFa=5\),!p![:tYdBL''%ȗ*)!|L75#kʁCe~_*vY 5u-"[]--!Z\ |>KǙyfƵDEi:½e:h>KoJ%[9IaFe8F5C֢I~zz$ȩPMkqԄ[,cNͤv08'q粅D3-i혱,+Uk/FШ:!ep}y^.>rWnpp$*BjHϴE9tKp~ rAb!^ө>! P WIN=Ƭ6?!rڈ`'õ?"fjБ.d8|FOf*R3S)DTѤ9|81خBX=?Zj'% A]CxK #|&ݔhGdAbێI$M~:SԾݿȉRg$h.16նktrˁ@UDK< JBY)᩹_^%b&e RRHGe #Jr򻣢tԚZNcV%J|9Iş)/ ^Z_ncW>8:/G!!@!vs?]5^"w1e7&)LEuZH""4 |ROu&g Ș#3z崛B6u\~^' ^#S h@BG!xƽtUcubL0A{u+!AДE4]9}~K} rf+i? :/Ujxf3gy YTbSNHʭQ?{~&+DN*䢐{S @ĿiV֎8``f*:c4D?ӁGASUؑN0މZ7/ZU<_ԧA8N "~=-[V/.QQ#Z̔#lQbU_"Ct"$2YӑF;%Ǔދ03 tw.* D֧p%2N}Epw}z7*g9־uU?!Eg JR+k~=9S"f:˥ #'RǶŐ}+d~*5|QsӦȅL֧m~ϼJKDLZSniL42-{[NLt4Ca'sbZ1*·sAy}g [fjMy4mSu2\z~hNY]MSR-6>F?ŗش[iqW''-^HzéJA@9X*S++VnjkTI1{t8mk T:gY!n 7jx9nr/N(4 $`XB ]=W=uo9">ȾJO#ms$#L^^E+^Nnr>CvN0C˔5!}J9R\3] " ̢Ji9b60GJziќj._+#X6h+D2>2P $׭e_QL)B8_ƦhfO/{`Yu'.g8@dOQG??2?2j[ciڳ=.%Ok2#rwa%pnq8-/f>Be Y>#jsi4ej'90/d2 (f,_z8=I{"itcvk^+²5.Dc 4jU߳Gv֬њ'l嚊:厾pˡf[L'vY1P6i%s^ѵhO -8pp'ci!+=@q9'DY Ҟ~t!2ܪtUD~^Yb{Hp*GG˯vй+熱>B"UVA[~ueIj QÊ!eP:a^~\עE2kD$ji@>=OJ('ZR\E\|Nߚh;!RqCZhED 7e‰3,sVf0d $`w-> ODѽO CV }9|!_WplZhѶi>:䡕 /qn3@A[u웮O5sWꉻE7mei|@+uYz| ^TbB2@Vvz9dd/"X(΄7B.pS~ |L͘8OOu Ejtx4K%,5vAZG+5.+a+N44jΆd[QYDԪ)C֦E+A S3brO-Y>fJǡ4 kսeyP@ZS]@IDATLNJ)usON-C#&ҳ܆% !M"S76iIQV'ZJ0 H%ظh3%*sM97 D>,ѐgM/ALtMD zH8v׊O V !8BKkCM(0*E h|9@Dug]xvV,)molE|Xd9.D^&jQ5r@Y禎"s/ͩOjq(s~B$VTrkTTKZGSwpYҪ\\!-D7ަjoB4҈SȘ4AQ8ojH% -1嗂o\!#OS~BmPxj$Mx>񫒾(: =ILj0)CVMJnQmXs8i'ũDN5fjݓ3CronN8pcn,đ`&fTW.J大CRJ` 85FJosR4*QYó0qjUo]@8j1 $o_uhZ2Pǩ@ȫ95nz:I f@B LhxDU+Q"YMd>oh|V%b 4]9Ӗ*ed F4&("'lZ'hK#+}Qߢ6j\Vz~S4p>PMlVeL_h[BIxr;viH,gI !UB|h;\n`-kьclhfed@o_6 ׇ|9ESZEM#71{ϖhzw@ߎ,P5d!)]VDodB)~;nlǡ9'hJ˪P &CqIis4l5#AS+ZRU۔gBwn!HS픧@=+q+=J VqRHAnZYSx1?x4Rh9_ڈؖx*brƟdCK%i~ESDfBVy~k筀b'X[gcCԛ GI 燗`T!x+1O Tgjse_xM"DЀiX`Z2kd@#U7+E I|NFHY9F>2g:vceG{Z!d| 9'ȪˡP kY W8?)E'^ũiRb~>p9r0*YT Ǯr;m8%*9g%Dm "(Tb)#Aˊf1s#$/nTt'9pF>+ym&^j.>JLJpgk>UPU+ !~ V4ĽswסE02) Zj΀Z)){"'j`J9W^LE2n6d6fF06>U.$ߔFI|ӅmRb)$ИΖ0%KO H0x, S;Ua>|8i>&~+ JhZU1ŬhpldMhgĬ~j`ZKi@ ˯P"/%0a96kR-c$Z.ɤ#176p +rEk,Ans:!j^]8sZ#r0 |d4#1Da$L:g͙RX!3:bpfJSr'qsJȩQ/d,!H|SCf|6$e4Vbj+j"ˢ×Uo9Gde!9p'\CLceIيE38r)(QhhdV'89C(s$VM'u+c.+?*9[[*]A>On2择:cKSFz*N9#k1p+Q?]W2p*|:/* 1åC-}#͏1LєrʅҜ>~ӻʘ8r9LKW'~ ʈ6J4# '0fF!`NɟŁ ir5cd5#:jJIa!̙NЌ:)KMS(.d*e~FlHU(&JWv"K2!1D \ 8Ks9YNV_9p¿1՞VcYBz,JLY<?e'ܪ9! kZr;\p"Wc!+p3ѴdCJ6XʣHMҦʱ[/%MBjVn~ |)BRS8BĬdK $U(H^jRrKB2Deq*)Y/* T}t"OH 'hn!@֐_")R $e4mbdx{6r 19)BzcRJ1`m̑ )BխJRƻ::V'ƬĶZh1ӌ\~4#S%&M⨻!|Q>WMKg󥳶+ܴ,UЊr&S"ʅK"aHsBMHI.mPeM4TVbY!n eA0~)|'#%[!@Ǐӊ0Yh9Mӯi"UâZ+OgP7Iis88O zhd.8Hsj>~dJ+Zq 7euАo>@HՓph>\K=Gid$d6 AmPF6-r19ɦ:gs~꯶%^*!F"jF̵ThG{ KtcVn*4 bpj)*]o1 ݲ'N6rPRTWN7AhRF=)88$}6'xX),zBъ*P ]"0D|D}P_'g L,4;E7/NĨgYњ%&trR3Xs/u| [cKf>{>?P.W#cyQc)]DމRpBfL\{%8 h!8*Y"%FNqdRhy8/dZlHT8L_8p&JA֠'QgLi$l"ӴOV m-DrJ_Ԉ*h]4#:[wnK@DRS hPeANmBEMtb3"}QN1f  /H0W?&*D7q/˴qYf$@Qhkr'bm\a6Bc)3[h& P[p@魗>$r|`: !igI^iRt4 W(p,f\\$+W]H@=hFv!ҬѲ5ͺ|QAb 1SȈPJR3Ѧt+#7>Zha]c!2BE)`H`䐎 CtYiFWf )12\#[8( B9֏( [!E+Iǔ “2|S:AKyєD bl&^bE,+3BrFŨG]BDՊ a/)qDk 'im䟛'ΐDjO@]`KgI{6ӗph2H>aD[dT#MNd#--g`ULk.:\?|hL\ 5oteO GK|x8)ZbDOW2g"7(Th@Qr-f~$6~:'zOJK6RF۾ee!;NL"*qg]/Z'ϴDQ`m$0eqt2&[35H{U(Z542Ԋs6 K1JvYi&~K9g)!%de^srT~?r+Khug[|V8E#MYu9) Q3 7"_MpW"Ĥ]#]|2>]a '+e‡Ub%")Hyd0MJIYJtFRof$F9C!j q7ZWa}ь4^Sc(4dSp^VUTV!61kq(&]4BM뇃)+z+`OkZCE+]Q8tiMRBa'7PQ#BXueDF3%e\JQՒ45LcV"i#zx8ֹ*j.U4|K/2|Űs̴zMIT@)K7 `J|8ߍT.+fDR+4$p#)Q4MKiG~`@6d o9Rd8~!Q7-d e3)F"h!mttlLWt mO8wPKSz%R^vk%ܸVx>BMHCS"p-B D4V[hS<${qEM+aShz&0Qt);(udhM d'%LvO/)Ub#'Md;VVU '&);MmQ?%"1F08h| GF~Y9VU\]k8 6_ Խ.&ƻj"p MQ1 WZcD6M3B UQ2䭰x Hxi+D)8v",`tZ:S~E?&JP,PiB)fY.~=DB|`R]u9@Օ )7rȝP! !gROϖIj!#N8JU Z7|Hn5m!?YEsfwU)M,&Gz]{I)F:)*A8AL~%@r=/`Sʩ|8۴ъ*'郘" R}ZIiiT*3½0!ZoGMP7{.KLT>D39BQӤ +4YcRg8Bi-*&Q*5oB7zm]ꭺFȩsl 7FS 1GT]Z[&gM!h|Y_:|j*xO„f"f߫Tb c U+IԛLxr]NWvw^,FS' Y 'hmX)k$? 1‹⼐rբ)UOJ98|矄'?~Dm#Z5Be"8YƦmȘR@8c$?cBE[_q)Bmu1#@j(jIB**1~vS8%X)ΎC; 4͚Rch,%8H/.q8cy8& #@ƌHl MYܭh:-6vA/jG jadO$ZȬԭ%|ގLêXtS-B|4NRUsЛSkl%R4ST ),c|j%QBJ߰c;ҨB a5J5bmA#h YY@!9C~-D8Y 8D@nzԤlQDZ݊mv-ǭC- +0$3gA`wϦoUF7,3rTqnJB/x48F Y&饬*1HkYn< EJF gTooF5\RR6`ڱǍ3.ܛ VVe"7KC3L@Lq7php|RΙc۱q]A4 #̻R6'%uyqάr%&|]MZh}y2dr-Ea&1)[2Y5^4]hw09mK訴dCؒ G#" -m~K#tiA܈JWrrni&]@ЬZgE]oL+iX)箏hF;6N R_p>x U[o/ߥFۭQWlϗ,*nc3Dbv#=U8U$xSjB҈iT/#2=L#ю&dվrլɻ+\|fE @@?}pHR)[/y&&}â.2 Fe`1rGvy)Mt<%X`&@Vzc dȗYkq:Pp@URl rbHI}%In1}ڽ ҫ(ke9BE$$;zF|r*RMK4OnOVn AQ{e2,R)(OV;ҸhNWHU-혡笝X64}߭Z}4PWgԗY-=ӫ "2+K(a >kn9g2Y潊.ř5g kܕE]c+'X^Ya(DGU{qLi;frb<Ҕ3{{>H(xbѳgoiLML\R -#i*czh3~]-7XLye "5vdXFtUA*tF7 VL ^L:7z@y)r[ًYdu17ǑIO 0+@>-I QY/,T-\+_ Q:u6<1ǢUJģi%*.V%Z. >Msa_}!tp90)Әq4}QmL^J"C mm{,jXhS]8MUd>$S SNs;Ujz嘦G_#JY[371R]׵vSbʱ L 0WzQlP[HyL.HMrː&bhQ-3wYE+"-1a|"U@U~piNkJOU *2&,کCjS`]dO̟8d9A@ILGMY%ūd_X[1L:M4rk{ι8wb3gN&CGOWQƆ6╅)i&,Fl"H^jAYԓF m4Acڌ `*@# j4$Xot&q,blu=^&i̅%LwjƪZ* 0+LGV"xs#W񎉍f8>sG=ۺdW"s ,]v>sItcL]4ybewFVHu x2|L2_K]v-:#\I/vH[ˎ^~Pq)Gj.C=󰣒}uWTHTYZ4~m҆]zzYc vDLڇ`] *㉛&+b>c -zaa%-y%\di!#kI01Yi'd?FgeJQ#HƬߖzi4&id %@ȀAJeGSp1&PVy?aYgr( 7 Q]8 0=@zCj?^MKgJ>ZFaFZ/2@?9= gJ|3ί{zLamGY[ټօwCo/rлT *(iDȽ1xF8*]sG%92LX=hky{i`LxWhz jL_ G>@(l@ ;b3g惔VjR5gdGsD5vڸMѢ&S@R].dz᎘h4ֈ6fLsu3_zFY̻*Aպhj$^_嶺?sÀcsͮzt77x<[87 L54Uȴ 0D4u%sH`㪲=SG`D9H]2܆;R LX΁6Gօ |9$YW i8׋.1’Ju53M̹T; | fOo3п @d#iҗijsuQJz0lYMWEVUȳ}zjJaݬ9[1YAv.7Vly-;6~NIQ;f.>fұv]t5 {9ʶF'ddq^Gf1MM 3B0VvĢj4.LS ܍z@MK$+-J@dSdFXtxx^2 [ j8Osn8oe h 8ҠE#~"Y)(?96tٔwnL0m4 Sr (k=5 +0myt/Y p,#z Tsj֭.! xp M6g8Ø>lPLA/YW?214Z5M,W"ˎJvY#{Wo#HXd3$ UȀA5F:[iĺdT5h^g ]XW*A%]8q 2@ >* #-绮5؈|:Vv#|Gs4>PQsitaA&nR?eβH T#m#qv@1ύإ֑˽LܐSoL*@sӬZ{GXQPG4/k$G'pBPo>1oxʭ^=J);.kԲ)VE~*7ߢn3ڇw/ʦ̪hun@F$MӴ~KY8 y:ޟ=e%%ְH>A E ¸ĕ]F9 MI|Zi/€'YÉ}G ]3 4y_1U1Gՠđeઽ b۪2m.ܱgw"[S㖏x4"\i!@wߎ]Hߍ`U2O+Q` Is)'3YGZC 0ebG a N^q@κ A X`WnEj83S51qHU ْ:ͫ0B 7HoYJXr`4e-n6RX 2j5s>eR.ChJHAs/chnV4ȅYJmW>}YuQ^+mc=lW'8ͿۚWCu[T,r( 1),,gR#knȡ<}uЫ$gEoo╄)U Fxɚi[?)܀>>k3ld0x\IiSZa bc;Po|В~?Rᣫ# P@hƐqAfd(WJ5B#0J<{GsL/#EwLӠFion-{ZvG3y,c?ű{Ҽ捣KL*ΤFjFӬԆ"1@bV՛3tR`]JX/cQCvU%TtqX YaZתW5g8XrlkظJ}C{)b0=1ZP bd^Yϧ] 6;_/YO;5z"$1MWl<Vs֘ck+#1n4fY 6II, Ț.dF{VJM<[9C@ ?FoY,r+ Ld@j@f@ybK-#׎4JN FUsFDhS{dN`*mʎzy "SLs>._;&z֨K#Z<+eo*O) .  lL<m khGaJ島dJ1!`viTYeB\ ka%a#j hJpߵ14 ;0UϟVvzϝeG 1bS)(UM)#۪dd˷pHGJOޫjl}ơ*Pc&BWS8fvGzz H 7Z6 V1% lP} JR<v)G/FP>5D zSjQ97 |1Z)WNSvL0ZzY Of!s*%L(LdcrطjL8XS;U'+a@̼FG|Ba(y[ ߫?Oq>;2?eެV Fl ]j)Oކ)4rUG_03پ6?|6<뭽Yɀ>Z$7J<m=^hƿQԘ[x펔1@8LǤR!c!֕WC֛?,MK0r5#:s)}<0>&-\˓0i591cw!E&fUs= n2zG"LC 2L$2#S޺94 r\ȟWEͪENC ˅o.[[/Udnu)%'!OdbY8e@])+b7 !AaDGSîR U$;*ol{>'ޏȆ: gptUw0٫۾Yw٪A@t3 '2ƃ11I0}Li"%<=s0/?dk{O2zʪ9$A9<Z_{0m@4v gMX-Ǽ0i;-AUsId>s'MjnHrY~M 3Ȏ' r%~c܏"1(T?LrWrE΅Z i.J_$rCǛx[bDSh2+g%vbOΎڤ>e%YVMQa5O,czyQ|>މכ c2*1n2( XUH;n ]d dzĎkgR_p&ԒƧyo3;z/GXĎ)뭚yu)M&cқ.G&xQ̭x|WC?Yߡ0祸_*8jύ& 7%(f/"U͒4} #121>e]92ߣ\DWsN„}*=~Wt}#xJSwPmŠS)T72J[Ѱ$#E}wDʗ3%@&kwHyʏ޽9G)OGNײ)"@ wL[>kh#arīGRΙ!}-mB#2'Sڽx ՙtyY, 2{QbzVU7"58ޱshHz07ژ 70Ի TV^{U( xtl |K6R$F k^{ji[2A'瘃cE)㙄JIj`Sf[5+ϿAܞ*esei05VOɿ> s=mLb2DŽeʶM(*Zgc2}mcs&FE$g.CHX vK17*veIDAT3< Anΰ߷ j\YhR$a"Lw_RP]ɞL}&Zʪv`#a5lp0s Yi-AdilXxIX^V[|RL&1 2mHF&;7`SU:M#e]} h&;ro(mzaorCέ=8ֈLܬ=O [ЮTW0 o.3 [%[8;j٬p&rwQz-9Ʉ/˔&"z4}\>9[#3H#5WXmB|yazW{RZ(j;3r?8} 4)d'm )TʪU1ɺf15&^K;4gWJqOIV@-j#y__UUdtBd5*+G Xc e-Ħ +#1"󑎹gVւvgWGݺ44@ D]Snd`tB{4ŗ[D`z 5w'RwEv4%#UOsk)]^ io(nIhOv2Jl A-L1Y ͆ݟ #v{%HQ2MJ@{i "p4J 12 +l5N| >=Fzm1o1 8˄-LfVԱ=s-@J]=|J kN O֫F}2SֈU0"\~=~mߥXRU+u6l>2ekO oL$C FFfh4W{al\G6"C^5Ȳ[&qssrxAueD74>cKfظFFx-KQ?}b<%cv M+Ec2t[{OL Y#>r9V.֥f4 R Nwў"``,8d]x2;*[A jڭ 9>9BiU >c11#MHGzt#2YiUko(%0F{ᦄL*AI,1;30֒OV1īnP&Y%n1` ˼|Xk/(y?RVd܌h }_#xLQME0f;@KO-J(S^x}sE4iP ^IX#?e'6ЙJ9\9)YmbmK(hbdBUBj\8&R/!f>IENDB`ic10 gPNG  IHDR AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs%%IR$@IDATxl[dGajqY7U $?jY{ޙTIMӟ7|?~k'}|I! R?x|2 oX9[z1j5_klIVqWnfZN'Q۶FY%5d3TaSv)ByCJVw2X9Ar䶲37@ JYgDjIh{sȧ];Y&RO~ l$V"%F؁u"% &l0kJD0L;Eo Fi#)!JV(0lZ\Y>OW-u*WJ-gYJ.FJٺvG} x0g2 sv&10YEC0fkU=E1(!U!U^bע1f;řFZ,sW9{e?YimmHq'UwHmUɡq|B 6OSP4iυ#Vjb>RUQ5YB\x|j*3v^[$%<'*A#u] $ 0qEErf4lׄ*V=4UnV2AֹLA9< k~uc-hmrVpo妪㤉jKf![yVLߜ)Ny[X)1`d%lU5Ls)})T+sA6+[ö& mt]u2J^9+r3,a@&VQmsj[Qvxx}mpsUSwv}=+NdKE6[\w}Ć'ck`L0` Hy|h=? ^Va&Wo)k[3jdQ+E %Z`xʦJaziBM*!hTȐR",l3J^ ސdiZS>p@nn΍/.v|[lVR6ҴraRYA_NӉ0vJ:TwBY#d ބpz}a2CϹWKjJUI54-q Rb49=Һ,**ˍ@ʪla)>R"VjJpy_`c9wϪJi!zĿ/UYYs5dwEl*o%VˊOkjۄ 6Q=zx2Yzd(Ap23``#";Bm.KN?OoRJ؞7Fjg>MP&# #_`S0JhR"!uvFDV XY)!NFR=)ʍFO^ tzVR7JՎ)<_J*X?Je$`+4`|S5 ?J'Buۖni*J .7AψS<㬅IKu'(jmajuǯ#;+|G jJ#t d@󆳒b_ *iF8_ WXljmcHIUqp9RRRm tMMn$VLNޡRֈoH%elxgA|KL )UBU`8t񽗦WErP#gIsϻM2Sׂ)4dƓ!FٚÊ(ץZ.mV?ӺЈ~wRIn*H#{C?s҂4!ez=&'R+yZi$td=\/QXGqŋR.ųʶېT+!6RUR4bƫ5Z2uFqW!YrÈ!mC1?׿vM̅u$`,JY׀[dṭ|=r* 3Yn 5:[~0F[)M) 3b ~:ZKy0Lb^0̆4ϔ>7< l% 6-RyAM9 NJG ZmdɐgUU}%@rl7<[xYV3d7J0d(ty8oy ;ZUxtZF-ο~<իf_v>Ld4L1R7C+`Vb@9,ۣOIr0waX %,p& .Rf0ER #Qq|4!` @0@spڊ iB&İ褔H[b+7@TSH]GS"OvʖLV#V-l0mdPho[ڥDh;73Ū.R{H3\_z[0eIgѮLJm2[xnH IekZG][l*>nD3Md1`)*ۘ5̀ 7-^k՚; " <.1V{gkUeo+:?J3'5jB> Ⱥ@VibTNCܺ/(%xdMH?gJٺV9^V82X6C)XIeYMe#e)R4u&=F#%x:}'~NEٵ#5~ϰ Xi Px&34^ouVxd0E/%[2I^_U3o#0 +\Kc[&RTH,* ƋXUXV))VN}..Mix^ex@!+\ "{F2o6q#Eə %lN՗2LRcmQ [zVJM:fS.+jʧ`b,V[ZYwXJh?}me#P;c 4ix(Iu1*ZREwWXy® DmX1C%No/JV;W]އ,8== ֖f$JUǩfHSªF[L'apcLz< _΍@VVZe"륪idJH1 %0qCZsj %H-J} 5{A 1lRd&biTW"xO`>7Too6YxZl<嬈7v&6|YVel2)?sT%}aX{߳ 41Aй&lcUUNW#)kvKVOo] #LovDV|L44(ht$VL[>MmzsJA RZxj3pfOdRJ }UL l;ivL܉ 1ҡeJfͣ2%՚8AHԇ;>MS5L4 ^(oL>uGAL9 p$ 94tg?OLQt.3Mb%Vy攢LonTL&J~rr'bEO#{3sVUqfhEȶ$BAaꢵL\GbLJȬeuAз%@Zx;D4Y4FJҝg$Il@nFB*7^}J n»m[2< L# RKJ&7\R)7el*bc M31z7z)iTy}Al&!g*<' Xp- 9COcQp!*a&ϓ mKjd<7QHkGo*`d#t4{JU.JDGDU5vYSVri )%$7+Uʪ$T@+tv%΁S⅄MR6apMV>+&|@ӐۚS!U0TXSZAl_(e;- [[.l;1ì*e]I/3Îؾs6 :rdo< m}(ʶQ;fe%Q1TVjY} }+܅*iUUc%RCdxlk:Bbf"<â h'&g)Hµ4 `30]r7B1!LR njĕRĵf%а\˳T 0$=qXEEg 0irIƪ/AL[VT]ZFpnڶpUU Lzd) F6r o[zD8.ҫF9ZkZb[KШOOaY)B0~YB5Fx6=TduQۧtv.`ȧ@n5.uznU*zTf# ]~bgI&Vª 42֎C!|VJݭ RYm]_)9,(mAS-{-Y.$ E;>HY,O c!V)J((^UJO$?^Io+h(k&ƪF l:<#i)Ae4; L @TInFy,Pk8&q( SIH!Fʇ:q:V)Ę̭i6UU-++i =2B Ѕ0bр`Lx0I]<>q2j',᪻" U*jV- lU˪;M](匧 t |'ȹUYTǓa-d<PJBL[t^Hd"3 `ԊƣH+Z !#br836XgU.Е#F8}Neb5Sr!CkHUyZ&!PB[stiM+Aڊ d䙃- azŽ=L)0E:,e ʜdڡ34O}²j0iMy*7[ a9Wd"S ۚ>VR Rߔg+U蟂x=粅ƨQ#uxbz^.TgG)M^@'u 46 Fv-r bR#1BJyWL"6D+?.Zgbۜ'~19`8db&i0&S4Rz1lguqK)2kΘf6 c)kUEUNagեRސ^U3`dXr IYmW T.̊n+d|D|UɳP 0+)G԰#d噖1`]ֳ`)<@oKf磤Kk[i&!獴*Y΁UʍZ }W.J+5+uڪ"F!\}0B9eh;L7#Cm)s##V_ֶvQ#[z0|!eW. ph b ctXA欋p[Lo%*[l._x4ܑXM7pkۜ10͌սk0ziMɊtP52Uϧ ܤhjVZ"YUYukͬF@z94>̿ S%kcU_!H4-YFm&i.$s"U5 r%ˡl`r|uքH2"Yhkэ#if{\ VB':=܉ȒY d[2qV[>4@ +$^Jb`QyؚοTnDS2$$pcl dI%hHξhxJ%xmTdY%1Z ϙ q&tdn!wrB%M1dcG7s]*<=ܜaf|ݑZ| !KlJS-F/n|)9a+hmMjKl Yv 4ẚSTRdeV*s c(Qڊ&dtif;.U5^M%CqR+ P67mVg-R_xLeknIJ-dgk-A4 L8(ilUawbAm>VUx%֎0V٬Nd n.`JF%;&2 XI%aʖU!LFiĄxB@ZU W`DMߌ Il.lOv ݋T [&54!+aI&*k \}y޺s4J5gYz٪Vn2vja-d6S,+N  eP@)W3*JنRE2* lRfӽZkؚЄjiV״縳"B')KE)\i?0M%m&%@?/)A-:KsMJJǔxJNZFcۖFedC&եQ ۝[BԈX(DbDjB|)ddueFsǗ߉Nw`z[^mNT!VJdUe^U%iȔ'93g$1X^jA S6Gy}wLOV{cȮKeԘh(m;cd&HΫ0m ͌'Ʉ ,CY[`mTK> U&9eLRjME6Tx^հb4{4 i΁Lz4|zٟ YRv1֡d!ax+, 1[Q߲Vo/R<;aoIoigҹ6 ll}vZQp/sَCmcv҆ldl}TmS U^1ҥ-m-zQ#;B4 aMZKU-mXV%+%(˃@b:]^2X9Ki*rIbVOȓaRPv,O\-dZ7- !iBhuWpaKo`ZJg}?iR,'VXRЂrkln-UvXUf!†x?;[c찟gdmm3tA➞R QE7#M@3RePHVX։<[W˳ J i+8 Z׷5)HVx0z㍪hz<6Y*줶Bg%esÈF&ۊK?AiMk@L| R2}A*IܨQ"IYgS*Y+Orl[_*IY  -YxJժF$r_5vDiuQ',s#;/L@+0s-E 9XEUONĘdJ& OMP(V/Lc;YT ^l.(a10{lM[HzkLVsJcO|r=#+[&VVNܽ4M0ax;;@d\miPH 6RJ臓y )yae+QH_2HpH.E 4Аvb}:0Q)dŶHZGf@[1#t'o[$Ȝ G9kDz;܄*xG)Fj+P([ǧuZ}& $ k+'ƒ!' `THPvy0N 'n)}W-d`.m#5ϭ6@%p?;fV!%m}1c8&ʭx@h 1blI3UR:1i% T"H4sF+lx)2!Kc XEZl[*o)8FW<[ݻ=4:FZ#&M0xAiL|~;#zjG/6$}c#a-bx 2Y u,[`u풽$*>d ]lY۞V6lR*)l}(Y4)!h")^e4`T,bLMR[͌fW h#Luj H) c[m!0 lH sͰB&be ĜaVVUNZ%bL0'Xk,U؅gҫNcs V @dP4sƃNpGFRlޖ ТIp+<YV)6 e1նj$wyN,řcdC*+EF[y2zHZ#|l1οUq7,svYXaR ڗ 8$7w3fעfb<JR•c6'+ZAV^jnP RʳB6~͙ 9)ާlsV F*Ec+eSo#7َ@pH(FV0|B kKj#h|d 5@& P 6}&W6PKfÓC3J3yzX˶ >4AΕ 3 [ݮJOC K) UVlFVc[C!gC$CydJ65@H73I UUG`zX;,۴l o_6${ ~<4X[9tXM^1i{ #%͠`Y "VʏB)ȹ,[Ѵaqo9%*H h\;_jhd3\x&m^Ȗ:01Yb"0an`dL&;xQui VJ)čCG H0e)J]kGY S5Ed1 V2,PnI4k[ [YJlćZ(DfB&`)gE: 0U%)|OݒZ)2b4N*W!&e`@Iߺ sT6Fz}kTVzBi*񛇪5ϝ%dcv n uJ`$1}G#z gCJUxb0HOqbmx&I!ں*1)8Wagz@k) 7!}eʁ @ƍZZFM(o)7V]5$Qak PRiK#& M6F5R4sP Z[21`gI2鑑R %JًDS d 3Cj!;HRe9wQC"{WfYJ<@VYH1 J0V5>#r\yL{m@Ƕ Hϊ׫.JeSb*K/Ķ&#RUdoNP#b)v?*yHUy^*Idz䦍L2ՐZZ;U<4Bˤ_<P;΍v8wY)-`G=rV4j9pJ!R!DmeMEcgOS^4C@%a\fVVBU֪hIf8[5a;™-@MHOC (iu5v#Y*d1[Ri0|ʒIyg/ A"+<=ޓcK#$gǰ`RgRMBa8DLv!3)ĈQ yd8(mJN85@C[mf/;l@)+Lb-),,kfS' 0-e? [ME&gBb1NT퀍Yi$PU}"O`&#Ys:ZUR=K""HhT"]N>p?h*[{'sSۜ99rAy1j1g$Pɞ`]p%,2fwH> dcp6YO;C2g"k~Uk͜Pao]y0!JV#Es P\ha9clv+n"`,HkdWU֍X-Xn!VXE5&1"F[ D3'L=!9iJ``Ha\kiQmT0|dW5. FlU>VlyEUQ =ά>3(ܿeK% d:t.kQmRKD;;oNYE&~~X2Εgi$BL Y3 +}J3¶i]ēN斾E#Էt6U5J,3To@[0ZDѿ4Gy3J5-:?=?lcV%L8leL@\U8 O% H+a'A Wg$>udmDX(%4U`𲙴f$hM1n׷ctFGۮJXٖ%PYkϛ1FmN1i^m[[ D<-`+j`"c:]0 Ylk-\UZ)Y]?lђl9cw ivF<[&Z w-eZH=3`?!WҊ!&`)ߟ i[*$Jq>w>9nm~ UzzYVm 0$ 3!G2In@cl%kە3M-{,xq9O\ySBO\ *Yc:Zck$%Pō@ @dBl-Xa8%b>#i_$dlsʖ0=U`[j"=Jd@zkQ+"F%F̳Q D]I1(io7ɦTWI<u. UHdsCAV@Ff2mgQFA msi1F[I>+tvʽ|:) M?+ES'u0>D+Ѯ*n}_HM63#E 欄CʭXXP+5j0KL)˯;|ƽV~c3a;g YkR2po)+4G|G Z8KY6<HzmVU#;81=e[n} 8p#朕OhR ߴ]RV&#Z1 iĐþl:H),Ԓe&"mD Uɶ K,eVY#ln0+^#DuTw$IV-F_J[&1셑&V qDŽ9+aCe JBQxʲ1|l ^T9q.oC3:ڊPl'bm]R>1mJc 7P/B)s|xޔ+%o.ȞQy)%?H-;͐OU୕sn-u"UJ06ZJ*}8X(U!=NZBDx:b&CvYRp&AݭjZ(A`b`jiP W[ %}eLV mu 1' ~^`UuDΙXkJ%*@dsh8(4`aǯcܞ5+.ߐ&8HͶ Gf[*C++&@|m{P*ʡB)¶ i #LR4ۺd[c,C[2F*{w-wUV \=mxmNz ? p>gni3-l0[[gZTX+)Ei[6%d<mY&l%nHJj1"C&"&x_ךI7dHwH|!50 ,z9plN]h=x FUUEjmV$ a<[f>!P4AYm{du(e0} L\֑{jRe #:f<6;dV4 [KUbg&H`ϥx)u쀵PU@P6CnT6>Y<Pk[ h~ODY/FRKaT%{e>΅6eۥ Š2`ോaˤNjV|0f2JVȯ ړN); 3(i`!~=#o5 Y@U@1k|J1ssN۠B% _B"#9F(o$FU˜3%U5-L,*{tbϰ^UѪekaTwF+)MC#,r0yƓz)+ж$CivlLC65H0 t9^HNHTpT`dYE07Py4U_~ (uTG;C3d/ve% 1|RZ۲`Lnͭ+oZ%4@wP@lge c`¶۠XJ/1@S` {IvǗբ٤D_CGmwΧ3-`z]Od%mm >*oݹ([5[{&2]J `x!&+4᪐a G*PV )%4]q[[ȝZlaU dR]uU T5X AkOJ c+_&u׮`񕜱y I,xj'\vlrBnT_(nK&0dJܨ{nab+R2pX i^0k1ʗ=m9|/_,Z[q0)g*GJ).2OcC9li;ȆyI zIUdz֑ϔd]{ս+Gi}REHJ%@mjӐ%S9 P*Tm->_?bKemQK0ӔV?܂K᠗搂4mR֔"+̢cW%[$*^2L%)sFΥ qVdp:@Voe"L\tEpWڋlDy[f>ѬhxYυ@2d5L;磞4)ŭ. c[}A֐URp]v>{xغ:" Pk&Px~S;^i)ڴr's3!4 @#;gJLIV[ +).\@4F0!#J( Ujc lM_ 1BZʑ.Vdඬ Yh`haK&hl{YY|^0@֓Rl2

]*lUU%dR2X[W~w uZdž#v Q"*9L J]Y XU$ (9?OG,yӆf] 4t?|gVguZ2VLLUv H $F9=ICm2ǗӴ5J\w|F@)@uG: 3e xMkηW8MUa]ZVGLUJZU> }iYAdY@vc J"7?aOug$p^7MvnYtL~ &m\RAFV !m]Bmnoja1=ϗi#7R%9E֫mx*Y)q=βZd*۷^nƐZͶQJVN6aC-8`Lx2APnrY'a!eMTY8]rJUJ5Fs $1jڜ 4dwtw=֢jCGnzSVV ~|'i01$M3XE+'V5nۜVnjː,lNUakUmzRjlB9}yf"!#5l3Xʪeaclh~jQ53F ! #`ZU{inVp۶4Z e^SЅrirj0&Ic+֨E rJwҿif²unZX-XHeLifU+i6PI>*gΧPqwLy/ !m-1zi ͣmnrE*k*-Eal55@2Gֶ~ShϊGD*>4 ۬Vt$17b8aB=^[+}1nx'>N[l) lU M%JG+pm1 cEĘb ɐ:e wM%[!A}sif{;|.Ć@U=_Lj*J ʅԔ. vfڳ$s;S{vHq:ś"載 0"xa;qg!e 3rz*A`Ers">a`Y+3-y7"vZL]d+RΘ8L[ˁ@H g: 1ٔS L&ucToFnmUΊrWi'|̩m GJ :d֍,VJ TKVEZc%dk0^ȔBks.>?X9%ДgX Xd-FORdY7͚Uge[4ۈR o`$Oۦ`YViSUOЍjMU;]a10 Ԏj6`[)[ iMA +5ʺ,3PGBm!]BֈawRVwO?B"M$&0K1Ub}jٶFAVI 􂛹 `bU9FdVuimKrR [] DnPjkmx<WMm;@\#),V[dڦTB`a0YmxܟdZLc+(ՆeKo՝R> +D PhIL%1ɪV7%VSnX֭mu5슪e ̙oF^ϒϔcE!]iJR|G&N c nlJ<W٥C'UaYݧJfcD*"*+ >gB.jնj~d} 4un F?d4"gas=Pp󲞋.cke%zOe #, V5&:ɇL*,{!xA#Km[w$J\TȓEUWgMF neAT3lJ#F}Q[flil(Z 0eYH! JeVV#Dْ% ʺJ$]"kFmɀp*\U@R o!yvB%x+%[uTM3M}mipS['mnm2YƀV-FfE#K u&8|LIՕak6rVYQӼ¦/VHURy+gmgdhL6XdU/NiWi`=Qϐ 7-P#L 7$Rp%\ m!jz3'_J9_qMEI,ʪ)V :# ҳҗ̖Ugm3y{5$x̵|iL @6+4d4PI?J0_ZۺVp2J"*"[đa^-+s#auQJm AJx[۾+SITeT>I͠\adk@d5[T!يSTpNYቯo2*F3eK0[npwl9ea|nTJ3@ liRt< 2: f yF$H8&A|[ jSZ>pkz P8zyV@%YdKc6'VB'rk3JkY?Y_nfk g +Isd/p]lL?Q* 1)y0~i 7&n< [M엿z,/U: a6dkit۴)UJP;[&n-^G;lckM!6d 3⋑ 9|+$9[]Bn0[l[zVa #8umV!_d\ZM n}-jD Jam%#NmJ%,Rߜ)3-0R:|>u9VWh<+$Cs8Jqz2MSy =S<<2>7)<aBFJ kx[xjK >+@wHa*:Po 3Xk.#ŨJHiU% ,XlJ[ 4:P"V#dlfbl- x[%m$^j>9h3rMY΀J%H,%`]KuJP Y e{4LjQO1]uFBVrϳ\Y30i"[Ue񥚹pz2VEU`"mRxxLv+>0d=YbJ|> U5y==.=5 mJ+Fx~%SIu.z|&TNC0p&GƀW.Q44^P:9 -Ƙ(bH2? [V& C2t)k`mQyt"miY.sJV oIH@K&*)}1( TUaQOs7`RpT2&0r& N9Uީ s  /l9鑳%E:ܛn4ey2u#dX4,Rdx2K!oۦʹd(VEY̅w6ιRpy嶜[^<Eb(-ftYzUg!wOJ"]Yj+&??nE:+ Zj~[>RH֎!H\<5l lakcx<2Q|1 w1RZy7*C@pJ0Es{ mVzQ辏@-۬}N >E9RХ!|k)]"MQ\+?&}YXM]JlZ0~eOzԟuᙕ. G|vbrH h$=]Z'*s8[ f @ͬюRm4=>)ZNP`de΄^d1V3[[&m3cT!5v]&[V[%!Yk^U2]iƩ1z[VU 8(q(d9FZުgIzɹŗRPjg dgJ6`l)a ͪm:@%YYi"^͖,F700O 1$)k$L_;Re;Y9_W lVLy{[~]ʿZLj+ 0ObL6a0m&nV3'a4Zw9 n$VGWEt 1ct\mus [x -ȶ ^U4‡CciLD0))!m 8V1O01}ѓ `@(RyVa6CwDY!Y9m-DdHU~%Hبi]-$sdHQJi"H3}жB.y K`hkC,n`9+yq)l@[ *4 7U)%I\Q6v ]o@HqbrLF ҚZyJ!k*Ym[|j(y<3qf !8{ޚJycdeU9,h<ػHĪv([M Jda1 lcV:=# S/%VWx_ Vw:" VX&5FxcKYeR]Tu* +DbI>BUλR Σwh4V%U43<>qݽEȖJJ,2 b$dFdp$۶́vRnWUHGSV ܐp#Ym0$@ae1s e[ 0F c%14<1jc4e988,+)ۺށ<+IiݤB7l#6Ah$8& yq`X +gt"7M>]^r[]zaLgTE,\iUlw"֎k{ *N,E#C*lݥ;59믿(*8v*2A8K4 d M# YoP lRJl ;{Mga'g?TYpwA0'aCIc3R~CCZHZpÛ' ed[oQ̺`:z#0I#%1G5ј <@)'huWy Xɬp#H&i09LsY߱Jk'!B4;N(DI:s8(=Ga?Nɳ.1d/#e ^քaASod bUdDFu"sN< S4I/^U c;F5?ЄVeչƶ*b[VKƜɭMa0F޹jd堝B]R6i%6za#i3ebXr`vj$%P^))ĂLfc*i4Uk.if^dr. h %m`liH 1I840Ar )&0xe2d/ҖX-O6%qY,E)@*R:8,F=W&Ed5 %O{kH*g8Q"zyv|SKšZEӪJx(g `k$*"|Rۄʕ4l6[ ш<7a&fHζg۪3Jad(h4J{Zf%Z<8;~7aUĦ:W0d|x ӐP:~5@;#UNoúq_:trtNkI(pR bs6 8F 3˸JfٛUwg*b$ ``ee0 s*':cy0mʻ(@T"u!BUQφ/#HżkJJ)L h' RVHJ%bdM ʟ^(&kb%BJKZDX+I&SeW+4(ZEzٶɹ~QRU'Mϓ*5\1Vn\GJdn&43,E`+%X*l z%HR04VF֮Rz }*' L0XF5S"[s 7 SPhVn8U$FH8êdil}" V]D(Lf.RYa:i<3}dNa#TKVV9F#bZaHXƴpFJvWyNö~ʸLFi`+箽HRMh nG ׂg&g[igZL)GC)ˊF40p-?O3>sJl[Ir Pض.1Fm#6amit6T`I,ifDZmbOZ+N&'00@ݡ"[HF/4Ob[eۦ2>e:&"O{m1gURlawKe*7L燉- sc%kQ->՚cjQG).BJDZv/ *ٲ&Qh6F"gU }F10);Sk+Y3̼Z;nlnw=l#!  JlsRuoL@ sB-Tb5Z{XĂCzWנi@چWkB[魓*$K AQF +"sUFTn6]I )g+[454RX*TOulM K 6زx4tůQ)`kҋ-&P#]VT-qA# S/[7~y¶-Fi` ")uJeK!*'SJol"\*ZeZ*d""Ֆo`TX[@䆁i8(1 7$VRi$6 0VXIds΄F(RZD Wcz;,=l2A flaYa +Ye9% 9_ +bẴL0v3gHš>Mؖ J,[ L1}rllMέ+0rw| +t `uL>",+8VYͤl+^۹FʪEj ?^m΁H7|Vc˄I1ͯLSp%pنdmmvJ[i<  e*c%ą-a@jZ!l3QWޗ*,YbX70BpMrJǽ']U?:gnmt:La24V& e%itR0R&; nfUT& $BG e`%xAڜ^yM0n;&M[/5eV4I aCs>EzJLnSvȢ4mt"VSbYi0le5lw΁om`Twb+6ӉʙfsNVH̜Xd>JJ\#"{-2K!PuY߇|>nZ[ [9@;z)kw.@cv(<. IUb5d6HkDZ0H>Fʅ 1oLv|V  eMH OVm&(ʄ; Mge Y&L UmT"DN $׊좜-%~O"@v}ݶ~cːՂJjf<@o +s[moNPͷSe["༲1̀%-Rڑ<#rv:eDGkY3)1 ϓc 0$ECQTOcTԢozZ) zTHLS_w2XtVUYє "Z 7[*{sҔXj['0l3&c%? 7L9 /UJ0@oۚsO FVw̰H୵ݑLk=C|?]KyzhXkRZ7=@@M*oUwl200N WVYbɡ#H4{ps򤡗~B;O<%rX!FIqT}sUyCR$ZaV^$SB R[# *L}FprV- OqWE>: [0p(bYt 9h (I1̀!ܺ"LUfHYd*h\ ou̘ L,(sJNS")A,jdZ}menz/@YL(aHC[m9)YlZ#`$oO+ %Ȱj0ANc)p\1v.leG*W]b[;|Yb'Sr7#`cl܀WC# &knn;@YpӗL dPirIy#tW;v3fnf[q:XRT/b* i&n4H-/652+8s dhCDkd/Oxlx32^@'Qkn6|fsì\wsv0"1StRVDS;k&;o)RYmYU;Pu6gDcJ/R폵ʮ<7+!ŭOk4Y` p[M3DzJ3zK*;[[0lhHkIo0PZeu11pènUKdSkA;aҩ4Zx%)< -L²Mskxa ^Kܛ7 2M~~' xCʜLL `wXI]iΩـjL f絈d(v pߓMp"fu/ۜRN!m<$Nزv]Qế`Z`v.&q֮}SQ,g@h!0o揔D ؅`P6cfn&'P۶P $@,lȲ'gZK5-g0Jrl|lcl e⦒m$)H|d|-uLVKflC$K$sDdyZ6?3ck*a$&z3+m hWpjJ YlvR``%3I*""HDxU%Cln}39% P XHiKiהm%)mk4OH)e0;n"/$0db)SWu շb]=6Ά󧯑lbzZ2ۆIbUV=cL2tN`Q`ӗѯJX @o]YiO_6[6C x}kGS(߇ Slcl6==aݿO6͔rcଋgk?1ۆƮ v14'ད)ڄllHتđzQ 5O[[g[+lBc$gKg[Y{S2^&V m0Z[eeWOVd 5mkz[2UK ~&P fª( zpMm+kU6~Uμiv&Tk*nYld^ab97g+.xX(@沢 T\%͊-EJi 2V]QL3x=))r;R`tII 7*4z9,@)Goh vp xgϢ:Zo4 |כll3#cxZtWU#[%ES 퐙VSxk8-VvmVKʶ*sUh?[/Z _ o4 y,n 4R{0YuҶ2ۮ/mGMdL#Xsl%19 9ם5$>JыS".j4% +%/e˼WQIH@Yx>m& o%f\fM `2JJU{g@LA5RV Ev/RVJ9UʳO)E lEJkeWobJcebu϶QTQ8LAeRT3f3h]iBXPJU`hD)g¾1DMBilRe"%0l1h+[ mY|a)ӒMY-e4cqcJv%du4X9uP4ƛ&A+ɳ6ڕԝP彍IX`?,qٝ CFSJO)@ֶt?=R8r}i*l}BC1g jWEl lDn%ւF2H܄WN$K#07*a r e䆁4 :3j1@W؍!ϔ Fj 5Y$Vh,=Cyi*-mmulU-7V iLcnVdp7^L:*X VbCkАmil㑷T) i|)|gI`NVV WB)Vx a8}p-$VhC:ޮk&F&@ceE)Bշ.uJyRdȔzlj-1Jld{gYH;ԋUvU9ۈ6sVRݧfk[*me]2Vvc*V84d:es+4pG\jۦ*]z3t- ɼv fL3 0l1kT9O`@[Y]sV3ZR춳Ja[.n9`PSyb[@4Ii =4Yh|Z pSkM-1Ҷ8*([eu)@)ѱ{݅h M1ٮ*|> )~S1^3C`%cj麼mfsl9s=ߤ`%Mo`xl[u/b-4׳r΁X|?װ.DΜ1[)B۷LsOOS$s-1VKvj|@FP`K<*3 q?9T^ SV`^2da>_^3tɄ.dal2KPIbSXE[UIi *e @S5}eJ5UU2dsEbAvs _YMEYhː [@KkO;lY_&%&ch<ȣD7I&Zlql ٓf,[$5,QV0=lEcijuumX ~%0> R9%OcӤ ʦ=HldqŔjgOgJ$J#j=`K dJ Yjc+%hUCaH߳3a]5VjcTnٙVyzryjJF̳M^ɪ6^: l RZg϶4aSBΥ-bVv|Hj$u7I3Lme 9BנB@Av @Uz)hĹBB kBx`X4񽖵8L"1iVߘ O|'RZ*Pah sz*l94F⑶Uy|be<>ZH)bDZshJ83^&W2D xU&l0شx]z7*Y2cv# Zg*Vcj+9(f<0 >UlLc1 %n`+dUm37C<k)FxzC k [cinTJ0Fn02"ފa&MP0>jπ{l}S{שM70\ ~qڪ7 ҐŁWvn l M8VU$aUP{"_)dR/F&BUVU#[d9FcJC Sh+Idi ) B*ٴ֍q"7,l0Y;@cu̺#cNvɝa rb+^bl_V%aR %W{>͆O& |bT U Y_MGIjeKa5lk%.v0RxRox XRRl{ ʥ)n"3VJl?&wood֐1##<@lSBRk-EH$`[%yZ#ѐR9g.& YCi5R@Z[*Lfȗ$ 䩄grc%iVX_@i=-op+|ꢜ@ 'iH8 #,fb>w4`>da⬜di򯗕Z5q`Meyt5 BǬ#^`Kn7CU>4]{> 1² e Cr!e+dNKєlZ;&; < >zv4gFMdUYJNڹ[\5 0@gۜ(90,EbJi0d)m[1b%@C:JLL*˩{(: ) _S&4$Ɩ)+rM+ [Wì4p1O[hjP ? -.sȭy*yFʩ/)dF[)䨙6Aǫ0e K Mv?-}wAC4Y3U%#@w}Cy7ΰ1ަTD"۔m62L&f7xWb&y:yǬg enŋt;x֥&![Z`XYeɜ*4@%/l8LȐVX0fh7%dSZRP{i!#􃍭is K50/XI*dhJ`%vĬ04`FnZ|%Wr6-2Tx@%4=*_S +Uv3:,lZm{C߿;-RHs$Y]d(6E#ٴֺTHI̹&hzi:Q4aUewit&pXSI%h͓޴bq*`d%OLLzs|榋춁wZۜɄsbDa]V4Umx]#0.mgȲx/nm+HlW։(ؒ&!n?`œNlV?ՔLtQ R;c ` z3idV>3i"M璪H9@,e)j hK$n$٘n(0s[b$I Sjdp U,J`aZ[ 0 \* l0 % ӟTEVLjaVT|-JH>a&u~ĞsX#Q=:)%lwMȔK2NBsV"B)~V4iVUF̀U1+n~$*`mWYeř, F`\#޴B)''5ʄqNAϧ)Y~r5rP!cCTR@kS)˝R %%iHgp'ULm+@S‹ FU;JV0Gk4jSl`kKLYw6OcKi]m͙X+q<,%lF?ϞU*gY*&Ab`1δxHMi%.<׈91- &+|dZGέr$f8M$^ֲm d^ʳ BTgҽbLu!=Y 1׿3@Uւ /&v1 ~oQg dӣLf΄7ٶ~t3IzIJ7$10=O@U]la+粬s+CV 4LbS?ר ?!i|[ʶ99BV`(E&(kWnp 뤭uL@"'+ *aCCLV)uZo4z>4 rEg4za?jUS^NyH̺yvj׎o$7y~00Pu:+;@pb€d[R/'KcdEӕBS|d9%Lg_UKȳ^e$Ll)J1:+<ӟӂRZ=VET,O,0n{F˪rْZwTɐ}a^VNYe1 +g7a_a$m i;HJJt!4L/k*$+| @*~Vy'VtH9 2cmHg w UaCe[&mcrV*O%MCně͖3 qz;R13BnQ7 zY2=2ȔS#gYeB678 2.rty!D>X•$N,fVeX-BLL'GI{K{@#L^{U7BJmQwƓmY$Ylsy|+i¢֫ mm3܀q '̀T`DŽ#4k>۵T@& ?ۺ0q>]P!nߵsLPImM#1!;;rDxZGMmeu5M_79q+++4 qQ,iJL>gU7M) XTN(G o GJ YRK-9JaX 1-1dHXR P\3zU&eIJ|R.qWhˁB0;cBG"K\14H@RVAP[H 9.ƓiQaYQZp6sǧȎCcH e0kecx@T]jJ~!+f{h sYx.*NiR;Z@h[9i"3kplkv!uZUarHPdm"]moպ`30RJZ7?F/ue@&6&z΍fpAKGB3@p?k%U w0*(7?HX4ի…0iK@Ѷ ~9Qy24RFm~ΚICZTɄ!s{@b$O+!Xbڶl9_ލOݒX`ME7 o+U 7XddmUm6F1LoSwjkp*'lm㫕k8G`u*җ", P(ٝG- ̭pp[J@V_gugŌR%Xu3_k9 R#Am"ipw%E|(llӫ%+:BHVM{ |l>IJn]&H)iUֶ!;TLM[-Yחu$9k%f6R*eHg'Y9ASI[&'%^d-z]sR+묵Ij;O&5UW*s J)O % VJbؓMOߗ ِ} >KKFyq"oL*I.3Au]eՔߛ@"JH/7y.?jT"6 )츅J/mdHЖE 1Mի{ox+!cXp-YCjom<ӯ=}(2v(cgm;]bI Fv3gku^aB/[8 FY;9q~c Ֆ5fͱŸ,Fڅs=˝}ZS! ,hT:n5[JkZtVk0ڹ)m[0&{;5B_#YrU0R:&?oND@[ؖJc3/B:+ϭl+ pll3TmQ/TuV80*[G|! Ȭ5D* n[?D;Q~EdsRe\ CB UTWrU +O@{Q]\VUT[F%#,0pe %R-iL*[,#,0L&A.b2Caq'2+a|hLFHۮEb:mMV:Ẃcvo96 PmoEmΔL-7|@& FpzvUH@IDAT= {KyjU s.hZe%DV*!|: `q >ޖ土R}V%GYZ&Kƫre/OF!h*}Zns+^}jD3dv]X#hr}j[J<&^/P][)剷AU)ɐn#XJT 1b>EiZ4Y]h0"P,\σҖ ^&[ #QeC)i襄HRzeK,kU>nM$ a-J0ِpMHs3t]+%Kn ʹ'-= wp HSԮV@ߘT-s`kG`HmU"DZV %|YU۲|EݧZLv%-Youܲr,li`RyZa +̧D)@aYL 0P5Ykjbҕ|?SIG;[fP׈Idid< Z xdx{p%mDZW$\O-"lvEupWu:[ÈdFdh[` ow%/P*=MYL|u]%jӓuuqa l1Oٶ@$@)J K% ktzU2z@Zz.0)HJa n9z5Bbgb#&"Cr,`0Z(kMp>9vNp,p0o섑A` xjy %n0O29-fHluL YJ"Ťqʺ!`!Ԣr0=?@~(϶.AJ b7P`5#m)*E3TXSW8Rlw3,= K|HVd@6IjA/d.j]G4Xx,Z6%ƖaslY,Z Ķ=JzK`}3Z&:Vwk7#/UUlUK/+lˆhR1ŷhh:_0*Ne[C2.O!%l; a pCQ4cD#=9,ީ/,F -1*6ز.Z&VMeվ|:lR  [ʴRU!YWY8 m HS4J* ڡ*6W-K I u%OWđp2VOf-N;^&; TIFZuJ5R z XV0RƼӎT"$`̭Rv JSe3A.!grI?[1l^_)O-Δ?QL(܃izjd%ӭy,n;r!KV`h1+Uvp_JVXk[d&<3ݩ^75-eV9L@-GXA"'j%[''++)E Ɩ^<,\JFl$Rʋb~Ϫ!U`dHV2olr6t:3l ['JJF6+W)kؠ4g+je=r ^ XUujVHM9@G#DZV0y4qȐVs~OVf;c4 o>0[&l27|tMH+BUYa%^etb|4mp)8lʹ5m7Ic3lXa3i Y5a{U!Jv.DV @hd@0A0Fd)OT?_߽Bd9 a:`k&)7n>@zr]¶^ VygԎÍr+L` (lY\˺%Ytⵅ R⭶ >BF.@xG"Ai[ӭkت͖#j[<^nL;H|0yޢS%&vS|<~?VF烜m߶IDɰic|Nࢼb7o耘3 ztY/zA2 VZ+mNbVVky7*PÕa"29D܊$͆l6*x[XZxzeS-}ڮufs?sn %| 21|#0Sߟ)2ܵ {z1*[ x#WSGL*DxMǧT[9>e3f$0xqaYSn XPST4['*1yZv;R MK&dm#3,1ւr{[[GLY$ zzga%LF- P@i T'lWFa3о琡zLS(g'n$%&lF YgxYaȦm֯M7R~QShxgѸ4ʍKhH+VޚT`Iuo-e-vHlu ZM*ʶr 7$92SNܖ`eCh3DаM)Uw@ <#mYnR [nK " `~`X)Mܖsð fUdFJhb6dhAv30q)c `KPw+^ax+Y{mUdHoDŽ ^"_=l-gm ->ܐdץJQ6Y,}LletKBn xl]hl U%-C# _97]0r87J Mm)LNz; jjb%UHW:DURt4ꅱ #>5O0$ Vc[k@ *_ $\5Lb|ðNk|HV>>sd^υTPjI$v|9c2wF{hrȭZ,Yp揱幩 L4d0H VAֶVX4IbʳyfփˍLoMa&6*ҖUJc6*`k$y>?LA8ue9FyRnfb[+A]Z^R[a`j|&f d m֔]^H5Lܤx"òb<)rO,[G.!saTaZ[\1-j}CdSabJ9CLRaw0J5!Zm,RyV ']ALAyx'31{LHb'9?|hmKf;Sh7mWym9dm=cEF/hTޚ*%JHyi݌ar(4J!Dl1 ֨ zL]9+# PwM޴d@Ha #7%~΀&.}+\lL [AF6QVKJVBVd IIm HN=7&)N,ۊwwiLlK )5u/Vb snVd{^*#vs̪f0:BH% 01Y+-:fsلp+鲀% ӖX!5SL'2ObQVTeO@)ǚ_60 a oSx|ȭIVV1ֱi LPάvjx&V wT%Kuj) `tM *r#[ L=3OC˧i3dB'vdUU8gl<)RBJ&%KO&}>+cJa"ee"9XT,0p5 &;qM"|)ӯĔjjZyY%uX9%1iʚ25CYD4=,0g̰{X(myzU? J}ϫS~bU*e};j}98dW# .kK#Ta(G}-5)}ddCXE-2:^}ڝf8IeUl72O ~| `kWO&`@/GN,Fn4W{R6O@n i0ֆJٚOWERtJXN:c6X*&m"f`۫e*_ |-,!P/XJ#ܗ _JIgK#%}%duQ[ dJ Xs4Cd3vL&J$j -pe"&km%}ЈxMXh65QO+rikJr:>u8M-Âv[H fqxbȚkDk@ך'Fm[6@V3+3Ok$ \/|7MbJDr3F0YWU^U &I@@a4VzMǡ0i`JSO)+'`9ui$n1Vlp`%a.4*諭,&@S/L_-Zùj-pdT#F*q3N*vulp%[ 4F_[k%+}h p'mUۜ0vNԋhԥ?R CV# ӡdWheX:+$7ۆ]#s&RNtkY 5/I?on&u5$2݈ME6.R3$S{x *H*TʙIOۆo s nٚ=j`PնQVL23VA&*MEe%``[H gbQP{K'Rܥ{#"&f*BėIa`+Wф3iz{ZR &s )56VlG rְ֨t}% ުUB_@*IW PRH%S(}8ީ O϶-qJzEʏ[)M3Ċ#f0l-2>+zc`JZ;T.}i'SKT<o q[^fVhiZ lUoE0iɚyc}RGl%rZ&3ڕ4ZVLbPUYi6݀T3kw:}R6OZKmá[ER1go Rd]ZS୦l6rĶ 5q`孳J]|Ϣ12(4jݵӫgŖLmxLAP &a#U2'Øĥu9MTRH/dJIfOL<\m&K/ض{g`J V^JHaLyl3͏$X1 0?mHCV/]DFmV\Y:fŽ^2=CRy?O=Y妪/^-gk3@w3 hd= dJ) $hd1+6^ KT/ ى|o,iMJBILgAU&0C ‘mv eMad@ YLKx@o=7LD idf Oj%o3JZxv$ߪ#sMiYdZ[O]H%9)Otm]d#pMԺ3A֮fs@b0 i}%_=e-;Pzv'N3$Euil[n0{Û #j  t1!1ل7XVPTJ5 T/UB[(zgn[ޢhUiSPr#[;b)=x[_ϩch2\1 0q I,՚[[-kţ)Exg r4J_y%&h ^Lt"9$@cڻOH #l|VS#L>Vw;c L6=\.5HVvLsXok K#g8a'3C+L#I&Ua0Uc|1GH1h@i!iDxIga&^KܤRmMiR! A2|1l ޖ}a[GWI< zҷu#[hXaLgi*7Inmi̇}` QE#ˇۏ~ u.(@HFmC_êj!P[p_.xwAp++&!(0`|d#gFsEZ ;eHk2,*XaK>AڎW%"Rn QǴZ7L9C-&e"( 0]`5M +<78'TQH s-ƞ'Rmr ? q)@my]|-`|)ZbVV]8TF?T5o :Q$ZF|ll>dK c]DOMʗ@7a"Uqd0=)\% +-qD&A  [w]I r&ZsWUpY)})(3[zW+4B6'ӫ596+[Q H_* ȶ*DYS F֢5:*ĢﭜE q@ *VU΂t(%.MkvRT;%Dx@tJ50}7~ \a-L”Ȝ(9[X0V1lh&Q(0lz#fhZ+9%hM̳B)cV0YarZX frY2*[ ,dhd{>xVa#hC&Sg!%$1'RV) aJg HddF,78H ll}V-efx_SDJO)%2 K1HkP\tLl)jK(mEl$  &e<JYd8mKVq_ltHMĶN;*ժʿM omJ Vg*mV(8#f^#@jdUZr a|bJ[ ={F@7smΧ [|:V(;yF6,ElE-wrck #{[焺cf{]Xp[,*Nԋ`д[MK wބUɦTKP!`; @6^b)cx$<Ӑar09Cl}:b-ϾͿv(W&/ | 6+U4h)zEO-YʚJN$[ WulZl1{D7sg>҄ss< i+hZabwxkr[ ̊ (kH[w9H9[ 7P/+cnJ.~ga|<,)Uf~k$BI L_[5=%,[+4<ܶ͡!+Jl#4?(E5Vq,,zve&շz ֨J΂`I'봺K7bh.gM`P€m (1qWOca 1P-6}F]ȑjs9cEѓqϪzdeE#2"Ĝ)o#[+l7TBOVIYs6U6XF"p'AbWƲJ %Y%.J!RG&aYXf0X4WI T֗s3?,9QFV@jem^ĘHzmֶJ[+Cx7긾𶀒&VutW` )ћU d{=|l7SnBk ʑZx(Ļd3!h&̪IL}yRoK,*)(jVxuJV( 1!NWljch%Ac^Ebhl[Z0M.UaJVXG[!0g4V,N#*(Uɚ;K;q[91m)+T$&m,#IS<B(L':Vֺc!%'V!1J`J'n"kw/] 8e@nmR# ;>YJYjԖFj;f[̉1`<=|p}{01X|&: >}B3"%$E)bۚmO4ȞfsvEi`rï dmYhl5 cv…YuKsm]u%-fb{i0c oyU;+E3(Y Ԃ3Wu躪" :su}|bg$gbV3ɡm>Vr8X PV mLCgcJ xk7HeK,{+)DU|4Mx`Öh)YdѓU"Ϳ.&% m%КJJsçyr8缂֪pU̪$ ӊ)j^/_HUH%]8\3ުGl[VdFΓL<7<,zb9dRI)XdKjYY&[_Q /[FSKLϓ'/aA)'A/ lerʶzFJnE[YmgSH:ޖd)oeBl"Um COWk $x{պm\lP[/8ٖ@#z+O:m'Hf@/Zif#6X}bK#1Xl4LYm5*Ee۾z)8PҋLVi!H~|5yzy x Rhʑ@'T!ie[;/Rila6X a>7wUX'[TE^TL8Ky(H[G )1FRXB,TK+$ȼݛdVOY(ʁJLj)E-=ve1RXJ%6e S3ZoZ^4/%Ez1l (,luydR_y%@H2?PҦT*=-:Y(JFv&Rr>l۔ں 4j<9hZ iV a(e 8CR~.io60bRV8l".^UXu}OUpW ;BnHV![J @ߓBfKܻF`F*k=H'[Wi 3 m YlT|W1r>0FSQ!Pm8Y-O[z^xI] ^xwUmi&'H04ݶ^ o7\mG&ly&]ՖU#E x|EjY\E_L =) TH`mTU!雜9@#!~l`U:z!|X "+823ii>B[[W4pcÎP Q孛 q^AiHšIxR*}.-{ asIlwi1֎#X +ȶyVҜ `"1 Sm/ꅧ0  DZ9(,N=n`B+jDZ%8 /6-YYo/w9YVc "9=J^NT!c"^n^빴ʕpvzH[!F[+lrW:g rO!˳i4䳵@zp[ 7[2}m'%k#Vnf \yf^z!I>ymmJ_a+q&hZ+ML-9 C#+(3Uo]IdTc$j35=L<22O#6 #YS@3HćmӏL2kL՜Vm |X w/a}+kM07v lmUM߽iͶ!e:Wb8`rt:Za%U,\pJ[&iƠ˿.44ŶN{JlczoR"8wRMK@r0W$ʊ4 m]H526+C;>?CH~}6O+*Nbܒ_'ZkAFHW_ʋbNE}[ʘ~Ó9,}֎WZ7,VƺcԴTj(|hYu F~|-p韩 l03HmVAL<`S >&!YoK̡Rf"@dU #0Xzk.ӋsNr_&+`^ r S:NeHO-d}fNO\6ZaDy'/eu4ۮi#jJGP`LV@o ӋĭVt4[J[Q orVɀUӈNZ .MNqdY,Umb>ʛ^~"7 +< .kG} c.J2(MnCVU-( v?|*,k%(B/Gª6F,-+_ma&[ZQ+﹬??4 UMHlKlc[0RlWV(H.]-@Vy2gSs +Q³}Q*QHSa%d#3X:I@IDATlNǪ46}4$n*weNad_XIGq}!O R"1ʶ& Z+,ō̵0i}WҟDUՈ (XF +*r&ɹ*kM8&Ua/&&$m dZe{ 煉){s)yeiZ$T;ܐ {?d枠RTm$QVZV([!\9y͆g:g' `iutϿvk'l4Oުm5s12\HQ & wĮ Y ee1Z5Llۉ^}+e҅H]ӎipǮШ< \)OUHYijH$xW(֙RZ0t.# +Kkg{3ĶN!{U"J[X7ڕ]$M*t&9,RJ @Sm420bK P6UH1"P'7<=Z)QV[Ԋp& #%޴ХyEVX0`K;c0R=;wLS#k tinӐm\]Z)d@I^]+Ʒ_{NGFyLd li*Wa3Mo+ n92 VVLJ7-lLhUiWRZ;LMA}yebL7y ^PThUU6)xִ zcK#H;y'Uwu; 5uJk@d0 l.t9*\d$10jO<i3I/jHqc;L&SU(`-͖2ԝĖL1:t*|XṥŧQBU&f0Է\SsD eB8>{&V|}Vjey5[MoJ( "kquPBL i北E2TҬ:{hK ܢȦ ZS ktIo z9d2o 7 YcUZbdR*'0 _j )'iF̧B]PN3XShOUUwSⵆZ;rYc ҊdjyɪPAS9ჴ Up#9)L, S۩Tj[o+h r[DokİkjHUIQ49H*$!`+VdrKkw3-^8~"1`%`nn4hWee4lOCјy%Ti!JVcc`Y^iO& 7bJ93Z֊!vR -86~J8K b|lJ*!އQ6C嘀vl);y$++V_k R48^-&gH J^ö͓ *1Sm0?dїȮ/w6SVLm)O٩ :R*`5Pu'|rHy {ۮLy4p]0<:HO&`q݈=*`!xhܚVISsU@3rˁ9+o#UV'@םygAl7lWlvRd-- LLշRVm/6*s8&8ɐJ6y"o y PflL7FJP40gRHv|)ɐNjllJ2F܅4f/0̧B-U!Nb$]xB&4BkSe"㐪$ zX3FXdTyڄ];qw$4xM߃$c,`Kc#RJ1[dv.dY@Mcl+dB`̬66d^1 f bJ;-%غ&IO)͜$M/$q0.Z)*۞mr$AJj%rY! ɇ hiCJ[3X)@-4s`(l&lcr;Z+!'pXRV[M%(nu'ӯJGVJVm s[BysZmhO W?qMbD sUP~ꙏP"J$Xhlx|"wv$VJP*4 Yw:T<%zJr-9cnv, ӛDR cڕXsKcm`+-ggTK@[<_PXl103L*EFcml.?lem@]ښ0k2Y$YI>R BG,΂LVRV ` X;պ ۀilnU^MVV%Vepxݖ iA$pё=z2 8PEY P$Ni7@*ȼ1[+dv<&43KI[`|Z)ͦv4$,M?]^ZJcM1 WhoH ~akNHxX 2XZ`v6rsd6Ykˁ;5%$lcKwvdH@Zpkȧq'R{g;Wv: &:i`f>$>Z O ,n{m 4?la%V3z(j;1Ohx Ҕ4ŹCM9jC =lYWK nK\#@5odx[``D[k#a1gےҏRRp#pgB`4 uV#j)upwuV]uH&y+2YB@8s%dZRÀ۔a[<ctö <޹Z$E,%+{@o-qgNA:>7`)V On>nRt.nH&R(4 H[*h{p^fNg1|bnH8[ 0 L C+H90S9[-yFl nl4[݆Zyv[L23r7m7F37OJU7- +\7Zp`%eAb ܈eRI`Ep)+4R R iKq0Yn;^):dZtpʀuxxU#U"a@ Ps}B|TRUp]N*uji!,: Ky ]~T+oKy[}^d}&6]OceF ,eYd9qx2z+8ސu3">%t?ؚM_TS [cl3Էv&KBy:P^cF6^[hJE|kn45Y^ 5>,wscJdM?RwdI38PSXy s%HMZJ2=b;<} 6n||l9CX*q@ViJmgo]*@JvVT Ylk w٣S{4d YB*pp+37ax&&#B^pctL!70|,hqcQFlrnN"dUZ+C-h^T%x uFV9k$"C \Pvʏ*=[Z7pyd0`Ȓ5;*,dK5FVI Man}\_RJ&i* -(1+ d`Pdq:A@PؐYY4@0m$15 f%{:"jZ[@ Ic+ԶSZؒ &_}% F(Ķl|%Rl}WKiNmU7Vd=%eP uՎqlhk!Ve5J`քR90XLt$>b 4j({\v훳|&jdX,\ VЗ 4,[Yb>L  )o;fQ-)En; UJױ5W>H@ک&ŗ*IoΪ0e;є.GJ׷LZshۄfKvhꘀ ^$Ku^%*ĪfV)S jư~>IuB-fҪEwx$9zq 2Ĉ3RLT1awu {z^CCiw P1+AVtpֽ=G2| E<})$a0S#6Lb>  Y52X 7$̻anQ׾Q֪aUR֞>  `RFJIoE:K%)V>-@9uLfifCgd,0֘}?{],0@U.NU-_MC 1UDVEN k!->`mB ê<*–rnK۲@J V![dGvleܖOnJ #n.Rrv:uM1Z+t{ kGUR brCp%U%?G%#x0ƨd16TJ-=Lo;Om0q JvJPލI)+1Ĝ>G8ć l͖Huxֺ״0VLdeM/C@10VV8W2Vu.[_Y%L"t(̲߯- Y1DsZy"YI&5g!% s/Qkۚ&G дSL NDC aƨŬd#EY [2Lc*"^GsR [V@8CWsՆond0̜l6'6MS"F%HnsMz :F(x^r 2[7DۦvC)Gƶ-,tgx ̇ Ӌ_T!2`Z&$H-,3uZ{)9Àh$YMy Aζd>4o9޶{0 m̓G֚*+ @Z75;0$LiV9T^kXSL OYQ 3p)"d+V76~ϡ֔*ɼYVR_BF%XmgY``#R}nw#pL\wVU{J5ea% +) jn'&}f7*z<ʆ9ifH2ЋRu\ ([;X+hWQ _#d`5*'J xvMc-yZsPIik 1`&O6}b;Y0Be6A=Jri):%{O-0dY1,eYC*eml'C u5Lé(4hb,7+^I̪.ɴVdİN 6[Ę)d4 @Sm+s$ï)>sk}cF+/HJKP#@pଜi6$e%VhuLQn[ao*)$/0"ܪp.;19h$88ipm[Ǔa+2IӒ*)yWlk|nmeG*s3 [J Vx<1@a1VJd1P ̶`HiBЋ$ [yE O_V=EnMRa)߉`YTurϢTej Jc2M(Tyjg%W[yR)('*~bV+%+%čhe/PelS:N<b%c3ǔu`l+dE9{=rߞ,\U4c&o・: CڎX,XYm5/r&N2ɹ]Qj,GzXŏAkCoU笩DXHy<Hİ5q1F軒9Ag;Oc" 8 [lxW#k,ŧx^Ӳ35xV}c! 7Xv@RϙzM!#Vgƈyzjs3U[b 5_}yYaV;931ar)(wJvfF֫oK0j֜#?b 5MY_>m>mOJ9Z 45r8Sǀ í*UKx4XIut.H2mk ||aE3U BE0+]/VzI0ASYsrkMkV!`0ZP60ޚF6,lanjm JIO@_ RVYJxz [+<IF K fh=löKK]r# [i.振J2̿!&P2[?֕sTUCa)͌!Uҳ"fn;[#ͧ)A lzOx*=]o#b^<%R d5 L2~ [T6IV =KBYl)VZCG<}3vGhq,^I ͓*?lɚ`/.3'˿L# PvQQ ]ʶw]74s>'7u):U$)='`HЯ=JlZ"ґpJE2:&h6Zw>7D| 0I[8 <@eaTYijXV) e`2 [rb=1u34@0 s [ R[ Py X8E . e iuɿB_@&À,ڱձ;!RXi34ɐq?e{pNZ#ayb> @# ӱ"@b #&K_F :W9`(Ebd)ֲY*4vӶHǸ4i $0!Qmd0.x,R{ L I#єښ>? H̳SoʙWk UzYJ)4+ ZȚ#`PGbl-EM1MY$ĶF p"_mV0KsBXkػ/T1b_zlmH̶.]&kszQ˜@GPDzI9,d*4r &%S\3sn`z-Y[g+X+dV%CL sT%vJdRCEV ׎L szp02=,ܣ r0 W@:S-Ok 18k3Tbh&*ު*.)7 C4>lH*Tk< j+MnpnL2¦ʶ۫J 1A%CYg嗲 XV- +;m"AX̿ֈyV8c]%BH2&dКFЧB ~%V91LOf#Ë4N־z1Z4a`>skL+U07k^~iy8b$Sf֚֫ȹ8B!1|Mo;dz^ndPrH\/O H!+٬ /S7+?Ju9#LLYfEնm4XDzXa^m1F󜳔5Q[^֎OClZG)4ַ$13|pZ_ +c UVRs S8)F?*1g-z6V - 9d*zQ x%j+ŷpY;[ Hoek-ɴdkQTp-gh^ 4o nu`VyVOJA&+_TnRt^&RsPI_ܤljmMa<,o [Za+{NW/z)'%i 8ɿKw d9Xz5O-X5^"ª8 Z 09O)YeXtd&?/g3}5Uw |mr4;Qsvp @QiV@osbE2Ͻ+U67L )8K8y`'D T"3KjNN+w0.FfHd_&SB=i!cEi 嵳O#G`l3'dgւTn5[n]ŝ|BIf> Wm$AYߵm+1<6M km [66n[*U-8-ɚKmH+Ɯp)HMe /hJ:,RV{ 4x>dSg2ApK?"F+J`]m欶U*O#m &d5ZtU2O|dp]ʻdhK`ekd7CjDJKu@$NμC%kW' #vH ߄+U_%x`azۙ*hJT 38mqzXV)l)[1ZMi PL"u6sn(  a[J' pVhjmh%SoU+2$f3)`1cbE:J#+ڭa*tb(+p˟L&0Rm)XVd21,94RZ1œ Rɔ4eP ;>TnfLĢWbb؊1yi]4]#)Kt? D2'B Wo )U᭶>F>OpR'W*RY)LoP XY%p YRRB ܖ8p^$Τ,ڊs "7M0|Μ;#`;8g })aώ'#凗u"5;O=ǝT([5`% ESi&1 # +Q+tZ"dT I 2| >4j0{df0[$Zd|nrA aUi~FvRj'<ֶl[@ mg9sxFJdZEVQLTL'A?29 H& Gmr湦&Y>7m8RvU]Ϥ,$H.9)]fcӛ;d^ z ~kXz.Me%K صĸؿokPbJ2t@*T( يRkK jB]t4Ԫ1᜕xQ6%As %R8LV6MUG^&?w] a1ր?}bl[-0Ml}(q۬(ivX$ I0^--pLOCczCVSUə/ `ƧDV$mN6^OkWK@#FSY {ppCsdhT>_0cja + ncIOkU!aQJي[́>U"J9H+uVbJ.#8mO U}#U-Y 5&TBT[dcݍAVJ6mZ_rU_bkקSSr0md@IDAT26q[),EOvwҚ"l)F¥nD +B) ["+6l_ѓ dʭ}}v{ uIYwE-Xu{Hrd_Di 0 )e~I1vyjTaG#v.i`KdVYBZr[^k ˰-L$2gX!ebJL+>P^R10VA)nyz)&.`B!eaVdx@sl1w3xBcx+Ofs"kgNQgoT29[6c 3bZ6 kPms~Rȓ H,[^@k$1>WqGR+%/d4Bj[_ ڭ4婼B.f`I(XI&sc諼ee1RD0o'~'}EmUzeS1 F4C-d905O3`$Վ`V^y;eˤT&Yk[z_p+UKE5vVRV2VaY7RMrŬ#2[V13u?r\4q5jZdUYi;-,F;fGcWb2kT-%YPZ#z %6U(JHa ]* 3=V)0s`J/ p񑩄 y2`r6=l4c~d+GRw:$)I͡nCI/<0=`ӊɶkjzNiŘ76+WIvϪ@-U@UGs4+-s%1egW ;Y!egkԨ#K?RɬBakiuFzy'(ĀC?f" o|7>Y*-LDZ=:Ji*f(i6kA)k/v 0R?Wo@%J̔LC%[ 綫 _/>0^R_ /YsEd NV\eD֢֜^3m8=K7RƋV%8so )"a,"V"Va`XUj;m>DʭRiCgI!7MadCjj;^Va<  )e7b.$PIkG 8!{gFpy 3RNwXЎ{ Ne.`H0Ođp|`&8fMSuu<IkD۲JĺJL.A6UxrJptj<o LJqmWEp2xn_o> 3ݐ9[\jQbHϢF:4ސ4y$1+ԀCGnEV(C*yS8/ӈK uT?R6ĶKgYaVZI[ cX#b OHZ#U9mn,RFWHc<v|fKmQ .\#-)n@4xUĵ&v 0Vi3fY[!kՑFdGJ^|"CJdjUmD^R5R^kH8 6' Vmfhl4E&3!.^3}jN;`E\4xDQU P *_!evF[Vb+X?04lnF4," VvU M¿B1KR#4|SPMgW%9&$l X4VJ}`aPfEzn[_)3W{z:Eklp>e ^ѵXb0֚8څTD^383oM67ǘٶsp̡*FU;L螮Ta4&T1Lٜe{ ,Ҝd21&O㫾"ɡku"! ;&Hc22UVp:K~n!#?C\+[nom{tHfpL$??zwQ 1&7jbd]H)t lmb)bRJsl`ƣtRղb(5Ub$bٶ ̀K2%miq4x(Tһ H)F1J hn담ի&kFJ,ZaVaM+l- )imFM/\[37dn=/^1EԬ2.9fWժTSL8P&R:-m@&Z$(E;TgT`LbKmȓU&Ro}_=Zls&̡ d#öOGT.@!ZjħBP;4vf0j&)PȤF**Ca Jf`ϊn~-4Wl-0 LF0q9AoTi& \DXI;~?, wde壄3 4pEwk49xUmkVjcWDp Rx 2U.Ft!Wx\L ́ lezR+F]mfK5,IEZm*V(m3LnZJm#qdJ-O2r ۞:3gSl3ԑCchŵ<kwi%(L)T@KYԱ?J(Ifj\ʶcUh4 9}rCFEʊL oT֑h9gm0b0Ŀ)a7*߮nfHpo 8i)oZv-jIנn`lH`}Y1^+WY2omwUU/Ֆ [h:=xe=,ؕ7gάU >β|Z j5_Ll:(g3Hf$gRPU*)T~|+$ ƶ ~ӦD2J`!i S 't]+Unk Ө&ALvjb$F:]#TSPw SnE֚ SW'* #XiyWnMa C<4j$Rʊ9Zoʜ] Ubl Zu-h9%Xqע.*FUS;$1LimfJ`&P"-&eLf$.=$v^KbHOoZUX2cೲEl[K\GLda(*^V[b0x"%V!.bjNAX_al"E`cEb$Fܢsoc;ei~cעŖ]Zjtq`%&bIuTKL0R4PrI(k[A+ TNfg-~q>R"RG)3`*ჱz}׽׻_U 嶕Fߖj(eA*jbhO$Y<âmy*d/rgJ#ܔιZl{md[ z3i$dRr 0lt^|E y{ ɮS41 ?+=R6MJƎGVB0j;L)6roDRL\6+F 6r)mO ַnraRdH],Y Ob3|15~Ƚӆ &b AiGߖ#*̶5eD9aWIUd9aLrӷQ ζ'r-ץr5r2ء`)'R輯Jݘr|nĢFs˿BnZąTU:j~$^ 1dCKYqcs7&+k鋩5@C9150۬EbTm/y؄*fZ)ʂRJ8~:*ȶv*>b󯑭vެ8gFRB+Mlx+(l410O@>Hv[XUHG*&s]ȜgexϨGS -c|bLնDU\tϰ.0TZ]Ͱ$MM͉h1d",\ VV|5<0 ׀`ۜT 6rdV?˥d9oT)X5-Ɛ $C<du!"K)P~ܟoiZ9ˊE$ m˚V4dut#iv-6PB^EL6é jmiXkUb́ý;T Jl)\ e2ۗWRV!6>~F҈ GZjPf7=3JrIp~Sb$^ȤɇM;=`Ki `ȪCf/`+mK >V"ώ"!ЇE^9%r"3,`+>wdTv9״ؔZ9RuXIe$A|;60Ǣ[eSYwoxbVY_=dRUo_3I(YU[娑dEWiU1i3?Rʲl N}Z' ׂm}pPRahD_mV @1Ճ&2uU~D 4V 8O0)|݂ To%kvpOr[]O6R `!; ճaUa &s4`E JY+m}+exy]]m4a)۞,TeO }}DzOF;r3` X&0 W#[)6G"r;'Jd@.8A )[sʷ6=@V<1OzǼB(KqvaEgǓŧﰲ*4֑À SD'V f$5a/;F sД d)9[TBʺ(_A¨]]̕l6VZ虜č]Tcb6s)sS;fT*KD0<%RV`6-ڜ9W'xyGl)kk$j; 4OP rlkey΂M, l)À,қ#(a>݃BV!پ m{-sp+7-zt]+[#l4|BUf㠋p'͓ l!&^U7?C Zc.ٔ<&LmY_8+2:*& )^p;m7d-/8[ xTqWT3%*Rk$A_UNaFa=@Qa% eؐsKJud@C¢a hb Rb q$юFmv}~5##*>RٚWUn꧝ZXk( /j+]a+a[خOP&)e)+|yI`UkU $Pv6F-7 &oT3tQ&PnEFRH%2c͡w@-%y#Y*LA g^Ӕ$sӆJiUE:M҅s R=[&$`VSdJ6,ʲmeWi)Hex++ VLVH僴YUUꤶE>< k*'vE|zHt@cSj$`)i Uav"Yjm0"l%]%s!kZY) *ij]-j7.MNV HV@'mSdHb Ym0hMe 6M)%_ob[ޥ&0O|2ctOYjdO؊ji^^6Az#jԢ-dPGQH,/0?ഃoU% 9|TKՂZUX+4Ue sWc?`*g1ȶU@LRzオX鎴0{;/YX# +,Km 84mWOS!А jQ 'noUuZOiiXa#I|iTjִ~ׂRyJ[40[%m.[[`yJ4k#Ud J5 `o)< w/t._ JPgE)g[Ey"ۖQP?mҤ bP(j +25mR^#U= t42[Gs1xQl AUUCmAyVR]HSeLjxfNH Sf|MՆG )Yj'24Ε}my*$Z;Yf-'/RVTS$[_p+~dLJPld-@oBJFR,$6S##e˧1fXy+R#m9jZoBԔʻ.ϧ-@\!13J2̭"!Vg!E@ICƴzjJJU67+* fxU_BT%‚ /Fv3@2@c~TvʮJӀLUvHٶwN)>`] epmenS,LۅbZۊ+^aׂ/՜ ;IJ*#`vë;F(Gr,pҿPR9\I@/[ xV̽xn`da̧& Jċ bWduou . nVZ(a⇮lo*&%TbU)pԂg/O!=~*/ `_CE:T, *,a&yLr($ Д3FP`XNj.YPkN 4*%[χŚ hj6L8+ydBjd-"{aO)O\TY4H4,gVniS5j) +) -Xy@ )؊R*$#S4I`)x6AUUb|}mxV^~Rf H;45[udkHc-1?.,'gf$h8d^khmɚy}j?P/hB@@R£z% %aU+MΛ-;4H%1MUV?!kn(WYd1𲘬tɁIPa0%r$% f-P; shΆyɫ|p`^*6g'hm-0@-Z{:ZleaMV UiT۪di}W"쌁OYrbRbץ¦9 m>\;L=zжU]"ӖdSwĶF3׽ziʡvVa`3l65O_V7@`[mZ]zQ )(k ﮬ4[9j'X4e@!7P[wk[}}%ӷWbيg[EUk|Rĵ8}>g&}R50qʭ&ƸbWQFFY e|xI|:URC2-a2z,rn1ޜqi@jl m+v|3T\uV @۔uMIvz|CTU7XV"ll*d"m%恑JFaJ e͍e4@V2Xmg$ c.4%#I(9^'wcA<(7􅭨0^x(̅BJzJYXDr.lրTzLضm+R!Zsz3g@U\25eB0/eG(OV9FjTu+mZ'ai OP. _S"T~$N֐NNJ8nP91+^V&#sF4F}òޢjCR&b*7` Hp3[4,;qVH4mǓYyYOLCaH./O8p oր0~>iyucqVsn1`V `8XֶP5 eyb2y&ՑF  L)Ucdq埅޷ϙViIe1Y^Jv<=ŧmR"]lZ$cxYc6dyRV̕,@!Zr[ר_S+=>a%RVUuIR6ׂ$*O\xMexJd%>5ʲ-j' ekx}=HLd 06ƶ'Zz.>? B]`ά߿WǁCy&0j*9P&{ /k˭G ECV wc$(db$0s[%%5dK]9[>u~Ȍ$h*͐8[x2a9ڽ%m.#3) MjP[vەrP(K#))ȜsCX\I`6LOq.4u!spU;=`asrV VH綾ڍmV X9&7AsvaJ<zn0m^nLyɒ;~ AG]Vaf)ʭqZftu hTdȶnMo}dtQ)+퀵Q[$.7OUR|m  IP4!*Kʊ+L`VƐ X+i>Bf:2BVDf*73{ʹV UӚ+VТRUͣxmckJ 4wRu؍D %2LׅQ)$' Y?4XI&MōRG.srW̫xh6YֲUUn۱m 5j&Jf-,lM8 OF{xuT(諥(\҉4̲IJ5|*R5T 0=9JKdVvKu*tR_$)<{0Rϧl+Un;ؚ #3Ӎ1p >pRynH)3䡧,5gbUZxAad#f+Gy&K|Q6,O +cl=QZZXp[7`&km>]N&m`|y!3,.v3 1eC&( p2F<$\uJSiv<> yLLEGS}cem} :H+U 7lppdZMҐ&B VWdd37úmֶ =jEY%B4jN!~o,FGb$-])jz]_RV[Oc*Hnʚ*JNUmLJwԫi6@ ú-ƚJ$Kjڴi] fh 2d7N# cli70 sh6s;dH$Ȱs3_i쏻ZIe7q(]ˌlنU5.IVN+&r2)L*ԊLFHNC zI)sQn *5P05D-ދ5!6{ Y*x[Q)[ddOv xkhU-0\yHMk7J;ldVUnaX lZİ)wDLYH f])DvŖڪܜv)a2<\GbT9),%L$!2f`k LCad40ҜmI"E&+0, f5J<80Ԛi9_GK)jgAj/:`USdUb$PQ@`URtinVҟRlxa &,_&IH蠆$w JȽs&LAGdVMNc 2r?V&3bWbyR"aI 5p+,[c`bԚY^P9LOde"iT0MW\W|xa$I8P@ǭ7Vw)FU*gkoN|iW=@@0I9Xc"rP !FJ\LzV1ii[8|h3`jg nO0 z)Tm.d]@)پl+dH6M/YJW$Mi֝y`d2UU4—s`Ksʮ;Whr- T_zdJ 5ňVY 0֔VK&VZ30WXGn4kgbk Fl$a@c+qHI0VnFZIXi6aU161^&gZYj)E]"[VUFkGT Y#)[2V7kdR1 yNC/Iĭf0+sVBQ+5/m4H&sɪcvЈc ['9k'V.k{c #0U" m[kj2`gHnk}a d2=}okkT۞;>@:#ah^ς'Ѕeΐhz7C`RkGap34[+~ByԈsﷰJ8kv+WE8a=O%+ k)Hra[%VJ, Uv>C_=F`TwREp^A` 0K&%`P pz@w^['"b~17ZhR:+YHXI0xRJ<},C%RLJ!0*mh\ ̪V^^;q-m0%ϪvV4?ȹ/ l1lM-\9Qܚ_U_*UV-l] 0^``}H01(݉낡4m7(}Rj )SDNÄXV(ol8|!#+[I|+~_G p1)7Fۊ$9CP 5L[ 7Ǫ*l5 (ui uYY)Wd}vKѴV_ 0 nVc xʺ+-VH*l&pjd m}`Yi7OVYB Q4T9dMcmڶR4RU 췿y*,w2`!+hv˜}>ʑi)m)17˝Z|z5.JB<7F(lw %ȅlU'ΩI!1L?JrS//wmʊl$uPZcD&)OYJ69Jv@o_8՚H G /eKcA 1Kk7[lɺ7ٝ -5m;xWIu[ DS1ALTa:f$O%qGV|>) [V|!oKV;)2Ha[ywW9l6~&lzѳZYM+[kA#*AJV*{uPPUC7fH!bd liR!Jf+LFa[J QHl+DVeծ|z2>q)N `eK1h;rE*d)]TWtƯi|R 0ad-9)@(!0#EHϊ/dC‚Sd]UORJ$}aQ7֕X19PJYRTH3#oy LAh"3b%dX fv-@jM`l}0 9fI9lXE[ ]|ت*"Ý 㙛v z@%UbZFKǶoZHՈ^ V67k) %^-F6#+O|kyM}"%(n[wʖ,-ɁO?e-jHU,Hk憤)Jj]̧FVLJypW[V[!)gXmi2&+g7FB8ʰrXT%l짠Ԛ V[gζB AlW*t W/煾|}1dR0sӐ{dUZs+>B.Tza2Ϫc͢o|0LV%XZ;ƞ[wEidMd[xM-N 5WBOd5r z[n.H`6.0iάo[?ϞUYg9sl'Ǩs0aҿUd)ux $.D"XmW/0~iX6as )͟H&1 oOFizK)堣H&e/$ΣFkު<`L޴}Sk"e8b[JbvøyQi&?mJR1.:%ZhץR ܧ:2s)V)!ka+FF)׿T}G"_6p*&UU(7P >퐎$l`9 cB&^=t@RZm|%+@0HK[W.:̹48F9gUұW2%R#d%oO|ڨb 㕤 (lEV (T5ishKb Uڊ͖l'@Vї`2xX lzoVJٟr)l3LZ >?N pΓL *7Ƴ60@LU 9[a@Gpa&V6llb=aPY*VG:e g 2Aq9ݭdɬLR s渓tR5%3UސHl%SKo);$J1欤IqF|d [0=~~̜C ԨPad⻄Jv"JU1(ұ*jjD=Likn9(VbV<@6r,&[cYYj Req82"&bAĝ!)ɬ7@{"[@vi*I) @Ĵ-eŇ1̌TP(2\Hp+G`n`YXnHКum[;t$LkLdx CJo۪#|VF4VH/Ko]m@b*)`ÈZ8|7`gTe̳⭆7, F,ewR {q঑:=#Ŷ%z[%+`JY JG 1 pԗ٨SF4 ?O:}{)m+)s6b1@BRp4)H31gW}4b%Rޭkxd>MދJT9Z46 @y+>w?Vk {.a/Ha\ h6cw#1 PQ )m,q..<]Wu�%Z9@ Wb))cUb]WΉM81mNoTm}qq/leRvb8/lH@ck bcl$kJ,XM޶dt$xA rZ=$Lc1"Ld(4X>@1`f,ՊWcе*!XmLJlfSHu k-ę2ʭ"~Up,LN \IWym7g|R!D]·Oթs6aj<ʤ$NaZm-mLj ߄۸o==vVud)kLu^_hBGqΗJE֋i9TUnOAyaY2UիFpMKYuA5fU "D:1\1p.( :]kQ!JadC&`SdFLug7"B#P.DLlԮ+}0jBI"1H-j?uh&3TjKc`Vǎ,R'fΈ1Oce$xni8󆧌tdVM@Yn1Wr* 3IOfMJ\/FO<9*v.<\m/*4&LF`Ս T9t@ݍt\[X'l1 5%g) ([S. AF#4W5C6 1+Ay&Vz{U8LfF;c&kT/[ƃ(Yv94 0JښVŰr"K)WU_򙉭W1Kdы CC#ۆΥmc &JFVAV3PUCU<{1𲍗YuxP$)L6U YMGrJqV8Njz2D44B՝K9Y[@fJpF6Oc(1R%RjH\ؾl5 1$Z'4m ^Ǻ nyW߹ s9X5B&NT`RErV||zjɼR=;[8R#+x`m[z=k}14dڅ,Ǫ &Wvm'M&t"92iUbKA(Pw u{xpNP 5C[$.ZTb o0nPH@! ۨ #P1mH/_&oH* #X`'UHèTSHI3윲FQAY2MD*4įpI#`ʪ0CV)$0U)UYjfsiCf#h`lf UY+cP6#sK/5*1 CXSWATX PU%+ܘ. ʥēIx1CoM̊FUJm#x@R'paII(X5UÕpR \U!ZuXY0BUC֢vVa1 &mP$v4|`jVfҩ;x$LL wHoz%H *24TGP뇬Nrpj նRF%ƬVtL` V@rV.`| ZX!1L1ߣE69m.oK_ 1[UѤiadS{ØH%RȪW{*!5Lz]=`Cz]VlVtGАx/Z_V˄܊糳gRwHӿf H[$0r;+gV;  sS2=jzY$$##bib0UpEm rjZ .Mud+Ykk!@6 RZ9g8is`+RRD2q}?[EuE֗`[_ i*&omʞ8qla'up{5t4JA)4BZ2̹?mnUËmrdgEk'؊upS/p%g5jø><;l;NqHYw @0+{m"4 ec]/KN s"r.4`E%S9m%pJJCfuir>W (w+i+v,2WΓ8fUdn%o>>ٮ@/)#VW)Ȯ5IܶiŨbɍ3&ֺ.hu$k݃f]@ zgȭ10Ag+|R6[]i&V-ʡ"klnւQs&V @V d'+%} º_5. `VمBV"a.=1n&D_V}("w9$clÊҫ1L|aY})MG pj+:,&Ī2ο*$鴀y!g/=LVEgECX!4V 4)} Vjd1;*+2<`]IJ:3o 1 `.s01,TIZR׌'0ms37$ f*ZaFOM5^ˣliDgķe8X-PU->+WĭiI|)bbzdm Ǚ.6[aQŪvEo0 НdIQ"ӖJ0NLLJbDgPZUH#2ZbX):Zw!Kn~OGLyR|S"sH|C&RƋbW$ԅO% i0`+wm<=ㅛkQʄg#=貰}$ # eas1*`4w xn0L5wZ%XZ%ؘEb[PγQDtVsVšFziسt4<&+2Sn k!EIlM֊IPzd %4o`vٺnԚfn*` T 1~]B0Vjĵے40M X Z$oQO'{># wN9#V?e&Q^5vjkɻmFI Ng-X!ld"t4RM j,vdH"C .4Hj2G JV;zΕdHo I ̬xV5{ jcjlkmMWEqbaU>+VJ+XR]SɲjfV g"U R mɘ Zux'g l}aU sleMNd"Nd]Pv'im4gNt. 瀵vulה!kj-ZV .B<7*%fDjY%-y3' k'))&&sXLQ"z#mW X:E<񂬾M(%ʚe6I綍Q ia) C$])%i&ɭSDƬ0`*!YES*2s)Uz4JR4V>;89Ra/իB̰lIiK Ț PR/J"C>PznxvIJH-`JWέ9ʋMQp 31c!5"5G(xx$_Y[J|b[ edHoV%h5 [| \a$F?PpUvM)o) gjgU(K)X9K̇ߍ%h'ж|wid [wj1v!EFhe~npk$汪Ylɬd4nȇ#{1x |KTND>wWa%hr _euaY2%f&7TVT|7#vχm>;Bi*JV|>bJi0V7VΪu ~i)M6@G`0mp@ P% lçlUV`Ȝ+[tdsiKc PTB>ì0Qz<7k]*ё[)i,+o+{s#Suxz4 0 hJl`k7YYLֺ@&8\秆TC"KV*sJeiTS|4I b +T}%OXCҋSw$jfuX&mƚUS i Ә v4/R<ޮJKI#5f>A[ut]jQwV0̀6l5}>2STY%YM@V%DwZTK`4, ,Z_<#sH)DR#Xk*Bf/#z74&˶5* 3uTf5>ת0}X+lH+:A3VJfe%Pb (}@ T^Gj@/@ U@ܐ&9)D^\z*KaQ.b,IU1M@9PQ7kpPn̛ݕ )@dU!r9[Ϊ^!FaGpÂյ9/iɄn0[/7A>Vo?&`ܨ;r2Җ_Fcs||UVh_B e [kk%f٫"+83賍@9$֚okZ/e)5"[sāT%p}+p}Q:=c5.PG)Fqusr  ]&C%AVt/k dvvCAFJ ӴcND" l[b]L%9bm9QZiZeƈ"k7 ,GXîHad&^xBq@ ץGLb lk _gqe[U j)007-kW!;%r[bX;r pC K/`} 6AoasQ#v|dY%1*j*,#!rڑ3"Se=eh%;g̓eۊ-vah-'\Zd쬤/(xתEԮV'hSt4YL#C5Wg.ՇR!MV)u3 *%0VάjB&QE/&sɤwYֶP)`d}s|z}0 a>RU)#A&hY| rc >FsKP_aٶv=n۪g2lBYZ<Rz"sZ󷲢Q K5sVD 3EJ+gu|UQx[cd1 #rj" 9'#Ff[>A`¶pǁU*`%?a]g׋$ sXY'; 1AßۑlYwcJ>Zd2+YnVTdd`J*rdò1*R_+၂w]09sVŪbZs"2Mf 饈g¹KJYEٔfO l3u"%y #Xm@4 v"KeaknIbKcĘ4bd?SL(˶5UZYAOf[*䔵Y\r*ip5O%>l04 :tp 7ʐ@UY?, ]>+AfoNTdvfʪy2 xAi6jSڊ0o+|N&K`H8-q)ebmZ15(]@́6=BYq{%*H@b 276PA+Vt(ly)64祸?B-|VcT>Oa|Yy`pԞQ|$5D-[d;2P~:Niې,OClb6q/bVJGgmel)dkFTXRڮ0+VʉMk+$`g`^4֔^{ [٬nϯz9HeE)H}|JHM ~ pIkJ*v ͐'VUFѤh8 [1ZsSLzF=/ΎZݪZ yVd%E#d1msp{ZHV9p?1!ۄWxPip>rJ08TlܬxZVn%Y܊f6M_m+܄9dqCL珋0ƣQˆZ͹dZ4 Q+VTB[AX*x$j&:xgE>:µ9H S;kg9^ekȜO!o᭞R<Z.ZĢrJ8s)GXkQmSn#72IAsja ` =ᥒ})xj[ lc$&:ӑdrldىY/9XEó" h (^o50 V{~Xɒ=MoEJ)4=q&f2Ӗ>!{GsD 7Zfv&.DY{g@hX+*$б~ ӛ^ A{Y0Xjيe . V&/*1^P*Fs^#Y L՝GR r$pJX6|dZ$e L MP՞^F"T 0ƴ P[t.HjisFf+%h;aeR1XUaJUuu@R_f p>7ZG6M@v8#yG0+oJEB+ZPEK)>\p)D0[aR ȀrX j'1ϗƶU}2$m&!@2Wb!v)RF NDvA 10RB!@r%]ac~oKܹRqGcۊiz#V!E)+7@/_6XߴܺC)oS27OiKvaE.em|z:x/U dExlk?PzP@^4x@j'6⑶Y2.ST2R0IȰFV1^opS`B?,db{_,L D6-0-g \m^ 0gVJl07U#T<1k =,a}vg'vVSiXZq^-18 ӕbkG,Mj4l yt!5>LlFU%7F87J۪0KTY+4ܐJ0,Y7 y#5R4*Zq$ jC!%J´xz2?͓|~)$V%F1Ɗr*&=Ϩ֞~%[֑Fm hRi@OLV!vV@@Z*ʏFmWJ W(gMIomqoV*d0[aV{.bL+:&0$ f7M_p54)b)J| ݃&QB [cD$+eEƟ! ,|Ug % 5eU1JdUEgg*V. XdbvN*0vmD $7zZ O,*WH*aKCJ [fdaϹZ&StJs72x2UZt9 a#`zJ2I2L-0p% &K_ʊxQ RuuGSh0%ysE"`5 HimHJ <&2cyd=J5R I#4oeQ)[">ζU3dd6؊jG-7Y  ve~їEAʄilzZV(S#Y,eZ1VUm5w۲<)38otf1<1uO%h^ @!I/Ut +e(,]memkMVƣI6 ,"%&&"S*`Nt,h*0*A+|4Ez0B8m Ln@Te54],w3idז2ucR5R5B'բMOVH{ ܩXIVdx*kުH]QI֊QI#-[wv9x Sb)-C82Q0TcȊʁmn@dp۪Q6 ,B@}+!IdmV| l)*vpC;W#0n=H_\Jں?CfVcu Fa#ܤJ,5Ba2$Y9 3%WUvKl6bVRMd`8Z8Z7im;lc[炡m(PSQ/ٍM?3RSI֨;Ht(H/3MǙ|z], ϑ}vc ɍ3bYdEUoS%uv]ng;Ɩ*4]T7>X8F ;m30w"V%ed@_9m$6^R P#%TUfs1MUJ둓=6=q`GwJIo+lV|B@2k.HXҶʪ´-qmr|_v8ƚyYJ|aYa0}ʖ{SNOmk%Ī( ?}[=}:[d`a\k@HYk (uSyG|'q柞UO׋@6f: =NȿF /B)rzoN24yJa9cR!kJr{+lbdR1v>GHJb<+\ `V$%3Ipo~D# Fm 'N\dTBq(:ʦouvj* xtx +шi[Su#eM]Nw$Ȫ+Y%R[tg>bR!bHlk c}SR ſ@~xgQI]Wbuǀ*+-S^ۛ?FS<[3dWnJNۮC"T"E) 8?%>M1P"AY%ݵUxNalT%kgPmOaomZԮ;Q(lٹ Dhy*'xA $NV֚s]+g+ު1jG $[k@jVH `Мp*tVky~6P%p% x4= gKRA 3L3IW&9ЛƁL_q jVgN OS/F-%QU m-Pΐؗ,4lTH&ONmLʪZ;x#h iJfwnՇ5}[7IܚM l*kjt)#bn}43ГMvo(L\tcdxuT5[|"A(#4B&NiA&OYG^H7iKjbI/9na+1+s3^gJCjK )k 4?iURc*?7qN~ZJck%PVbZL[ !E J: xa gn;a=J8(?s8&Y#UbxQm2UP@ɳ#j-0"r|87xY-]J0-^MBߓ'*[Y@W-S Jpcn-(kT #,*s/)+UdݥO/ۑ㯿9>m6A-rTWN/_*E*TFa)͖aRVYꕴ5,kXe 3ɓNUp{KbMfũ^]J1&pGHOp^kDj;syYʶm!WS.B֔@^A\kd&J֨d+4v *mepY@#wD-< 'm6[a;LrHJW(-m 3ê6Z&V*Vު5+8@$֝cxb=e$PFM _#KvXaڕU*,|>G(!da+9{*Rm1+۶)3 &m*G-=\VTU;k!-| Y]j1@ NQjrq'M$@fՅ2uGJrJшEvy xyeOʜV)$|z|`1o G/HV- yfmiw:KZUډ@ +[.sʑaT/j1 8)P"7N̜3=m (U97vGy}thJ"h Um6S! `Y< ;[LdN !+k_ 5^Ti&W(‰{}Zd"TJmsNy%pb&Y:jt.mHqv֙E)dhېOTiR=@!kpm"ipN\a T xEJs=ψЗ-2O&IȬe!jb>]4˿̔k[0C&ʹtRwpTU[%VH`R6ܐ^U!ډ"=ZE-`)aF9E+ ?$Y]i %F Y#˼u۳I91 #cHQ:G ccUrwLiW^Z  /q9ץ?HR"lV]3*LL T7J!,UIL R-qd Y96^8] 0sz<@ڶJl;xA@AX@IinymΝTn$5 ~}3!m_45@s'Vbѹ-⬤`Ah_vVo9L8GkB)Ɯ9sW1 Y:n %p#UH)`c] g[/UgM0ϬZV(0S~r^ P*p@"#܆.p>h ,hjs{}E-h`dVuR:ʵ14^icUFjHYMê=AU!q}kanib`G9TY XKm#]Ib=G|CYInVbRZ-ԑJouJ[bx@lL\Pn@JJk8Q}ԚYd\U-l.M5nRm`sV+`dKL-Y>R [ր*YHg#ZSUJ(iO [EJ>gLjs[wG̰R%ek FR`fbNtN*6qVqm3ɹBβ"W@Fڊ MbOLi&Pg"3i2"} dRz94O-@&{f)l#颚4ƶ#6Nmil 2\k8ު"^j11|/eUe%&7df)QƠ4gMFoM-Y.k3L9魶ad7V6@<.<F1^z=Mu5e8Ot̿V)o`Jvl\* 6Fw¤iVuX>a >d&q-Z'3[|)Jj ˦kZ&% ,At:|1и% XŬsO+Zo&P\ @*FE|2RfjnfYOM [ *@V<ۆ pC1e#fR.Kٷ{Ӗs)4OcC]+4kͰ0GDdWTϡg> y2sⰕ9%0&-7 {Km; VK ق=k/MFJ4b_5+-`"2mk4R&ni+Y0 'ǖ nT̀x`01fWIFǪ zR)1LYk^-U95 # 4B| =:H݅mU-RV)e&&"͖,2e [NDF/eB-fl黢ݒψ ϝTЪٚ Y/VIDX0*(lhlWF )'!0~훒#"C*]l(cXZS4o#|Ye҄R![8@ 3[ [)"PB~ rL0RؑSw0"+W${ĪUgb V3dv:$eY4h_1g6FV 몑4V[RH?ƨ|q sTh5'xV"c /l )=z }8!:P4'E܅XV^ʳ%fNTqǬjp]5 do n)~dSjꀞ_D<H;a3kclg ɤ^R1(G-֪x[Dmcqp Ȋ BӞ¦B$HI z Q"U4lZ|ZHat-U)|Z10_*g)l-5A9k{Z_wO>pUVXsb`Θ9 &JpN 0 [) "eVQw2XJ$kKzI1O#ɭmaybzL K vິ*!CƓU 0Z1>Jo"#X)m K!;ڏ }M ;*padɤ}])-@dd'`VM$LSf#7ja pPx(Õ].5J@`h 1OC^'K$0[|-TYkT5}@*n`KtU;/CO,RU#qJ<5g9i1'R$ck*iT`4W#Fm2I[ XR9/9O?F7b" o3[JiYu78huVm`%%8%gkDCM$n-@kf[ c%%Fe{K7LVB?yhu+|Y\h*k-W<͐Q;)$\[pНڅHJu56X/9E36HOiv|Rւ&WrZkb#pVMYL߳j)5MΐIg494 iDZ np:YGbC-EA@$Tx+Fjfh >@JH |IU$Wp[ntUedBVfUnfË˱%Rjٷ!bj}D{CoG$gojxY)2VYU58eL'nȏޜV ̻9Z,P4ٚ,s1.i[9s~ qXzy.@*RH%|g8R"[) 4bgksf?Vy7>6n,T7mPM޳1z7hl&N :61Fi`̭]w2VneU)d.' ZU[ J7&)4;mG5js_9g?e1\`[H>Y#(}@#PWݑ %nWAXغ(Ifju &J),RO|apV tsdܶoVPJWFp$WH nYBQڕ)-|z`A8E*mj6.bA5ҲH)[)aߑ?/mY6`Mie‫z;"jTJ/ny%lw>bsgRajy"D m)=n+Se&ЛAvLz^ dh _$ ]Q[ 'EG PI 4aO*Y-Ś+O@OVy)<)lkTNfyJsHLDx0jeaso9Ui+7UUH#x@)+dFȺϳV0&Ą/1@A| ԫr2ByV(yj$|0G2ޟ+,k={osH0&ȒEv^O`o#m)i7>f*Ls\>9o#7UJ2qz1e+/NuZGf *f> }ip %hr+H< Rd0pδmz:@βHFJ# S#^mUŶ&ϖ U< 0Gqg^N|]0JzK8v倓 嵃 mUȶto#>#يƣ S֮i m`[2Z$uL`^օ-M>[ g[|&y&9tsx<)m(VR9X b$nM 'c҄D7)26{p"PyDvd GVh+U4 I;'Kyb¿m#uc͙ ƈ9+tYrRi1S$ӌhW!c[!,b })@j& 0Uن62aj]6Y̦zMs<,u֝!*Hj 8@ټj#ihٹqY`ikp[jRpdp/.A)̿vJYU!;辺V[$OMV U& 3]Zjj ˲\-F#[^Lɟڄr[_3(*Ǭ5P8H$ܷmZ |-YI~lTȡ芺+eSqB[BNaeޖb1U4;,R6A>0>u)!UtJȲujdbΫz ){ZӅc<Ҷ)mK)LGS"'[yv?Ϋ* (-`c+bf8Ϥ{ u!q󮽪d[ccЏ̳^ỦUO`إ! duG MDpr[XIz*dmAlU$AzWu~dl+^*+ aop2؄T޺m/m]lug=["yn)2! m֌kׅ;1\Z㆏r4MVUi)I`sUp)|ś16IY۽ɚn ^ HYnE)붲P"&kA3CD^e<÷]]b֕iUaDZuw4u?ٶ)LO-AvV<\ >4Zm>}ȔslCbH:Yc,,}<čUFa2e (1I)_k[d|L"VUf7B`혭u{52@wpW]'dz {Ccd[F=߫:)MU [$wm)`G6CdUi 70=[zU/i(􀒙pfn/U0eFFn|6sXVUV%WNJ_ 2& :X䆱x2SΜ,TkJN d0x @V5Xb+3Bjt*\VٽJl Z_C&f" BlBmpz&@#_*&[!51H%E&ZU1%S-RFJVe]7ΐUJVӗX U lUL;VzY=k>R5ӈH?0{y`$uE075aTBP3g[#kβ.圆en+ւ`SYm<ͦ܄肤@c!%`HnRe3g|MUVJFNy'0 +lB*1-5@vFd%dmUᳲR|ͮSI tƹ 1vE'S6Z준(e-w]HHQӞ2LUOi2zORZzP3,z{K0}PXLC۴lb|]9(՗@?f+^o6[s$eMȤ2-0?Ț*%4p^3Ce0TldEGYXܧAdNF0ڊjϒ, ҚX]k +چex91r* {ȺaOytgRMkçeJ6^x.JnM%!&+<,vp9 ]TU֍HQ Jt34Bd})mZl#}*= T7sz ²Rk#'8HWBXJjYKBvEe0+]ƠD6 k#'@2ɿumw^4S&y;"oӨ2ٚDT[ٔ >42^-*ԒuH[$F0E[E\Un[{T sj[¶a>>r"ж~4 OTZibUJv. *LF? \ܕ^I9tWRƸmlm[ Pա*4Ptyo(l7' Gm)BsX hZ[׺9"h[ +,[ 8Wÿ8=e ?_ iUNa& #ך@-P +wc4Q[wZ <V+ 4^<+;y8 jj'F*A<^_kEx mMD9FaQk%s.A֐dTV$, l!mGR(ѳ 18eD_,kA:bH#A1-dE]&ɐ8X)lx-mVL05ZGd򔵦lRꧬ@tH6l0[Ub6֔݌n72]axݎ$Ë@$Tn̵m;2 nKS/GbTYpom~ 4[eE>L S'ˇhN[t*WCe1-̧'44lA#U iT%EVa?l¶?kitms)k3`NêPڨ 4lOdzMleeW)M1=mX(yehHxVL2̙}iu l)T˙lVQ[V oUUu̫CYӸL˓ി߇uL K)3;]z + -x|DdnԊWւ'&+FU'ЋzmIXHuJVw6@7MLPBZ^tXnR 1^ȍWo %=1Pf}9HRNUH@SQ6jȚvLY²xÀ^3]<1Վ 4l }T'3 R0ئe%hB-hmw@bHmƜgm?CJU񵮻B)a[I0dY `|&fV*JRybU枂˦T\G?\kk.]d٪UXm%ZX@j$f<-ސM RU-0j-%5:ކZaitycM!HZ/0spj#L!IY}M0bJm@V {i Ys)0>妶.@J S<_FoE[~0OS6gLI<ȉ(WK}hY$WG-܄;,`V [ja +] [M&V \ϏLu3e 3`" a7Ӗao- q70_[2|(:q2}uӹ*@lĥ?SliTMCJ U4U*[?>WҽA=hDxV# ݀6r;Vtc@[&V C nH. >' ^ah*Zmިɪ1XI>hR^ ]UƮ  bԈHF (w:QcX=5:#Sh˪ԒͰUj?bL3ԗk+&0ʙ.-C EC㯿"NATw*Og >]8H aKP8$sⅭU!136g `F&u(irkuw_5jV zxc%xAPZH* q:UPQ4}@az>dTnHcPP"+IX;&N` ͆Eia, 2-LEUEVIؖ[* +l 2xp$Lq"m  i2FU EO A =xc{WyKsKd o%M!l<@JT8}%֎|(!(:Z YA~+ J'$B<` 1g[Y>BX/dq*/cU[ڍV$SJ9ƪEaն [CVj!`DgSe:Fp&T(# _6A:F V.By]+l+6qu&4~} 2,`*`d"41Y*alL΢\6~t{闲l5Wk4mR.VUy#bU+elHVîrf@ ׽ }xkMvuZLM k `->74rCZ=\̧gb+iˊU!*@˪Mw,LdӸ*Dh٥Yo[*)G@IDAT+2`M5;^j~o#RRʳ[ZնV ^$kza+'KfJup:/eZ;leE( 5Ϭү5V)kJ$6 %VJ#2L*RR+9 GJGks!XL+QbJHhk]U7w*z] [7D [SVeX9=f +(DWFe 0gc&kF\;zJ >YIhc_y>9:Z 4|rez)ǖXku49l$Yc" *qiO? 'mY77- [j<"{@ |Hi`Yh뮩0y) EVb<֟Al2GT5(i as 'NO`x%m u"W [|+j՗H>5 E 1ȶj|eH0?(VlkI9' 2aF&˳<`AKy<]ϕ&I7gR]kiy Bha%h0P5v٪"h^'SGU &iuOQ Eձêʡ d Xٚ#HJ nX)K-\S@TX*5XF91 -nCa-*ɜ @,-CƶJȊ*kKl`|aHy(+%HP+t56dR懲ڟ@xrƐbol`(Qk+TzJaS--^Thk6UX;[%y6F8RVSezK}6K" h z5۬\*( > >H *Nk8{?m+G2LVl|*˶*)8}UYԑV 6Ob/uj,-#A Vk$aQVJd&6܇JJm=螠mnN7穿ѣ:j4i(l*7bۢ뢡<}em8}y t͏&En"Y- mJIc3>WgU gX9@ah`z¶VGV_ %9)Y;2zNCV!.L;@&[^x[0AbhdEaniD[YSY:ڕ8 8[ekD#Rֱ^.^d ՝xV lmyNTiA2tpz[bPn1s[5fhH5S/4)'lma٪Rh/ĪXu6$|"juJJ'+Ym$]^ .[CUoE]HG)ؔ%d+3R2֝BA mتJJDb`d]$SI#u lXei5Prd+,Uwz4!OxR9[ECz9gLpnC S}1RVc BsxkB斃Bb] #h`-d=boT_GYyJV֖mlqihG_Uɐ&:uf4w5' E3eG#Cd ,Մʭi$bk$]ϑ@rЅYO!e.sƈF ֱuG:C%cHQVdRm[ms#8e߬-Lu v.|'7Җh$<1U&/|&K ָ7L^唎Q^3U*FkfmibFe}%VZن\x.F/)VZÚfb Rh|`_LKU Ub463ܒi!d[3a2CfRYmlcw'RU&rRش0/l+?$4"-mB`A;>5J)8H 2O*VOKCΙwXaZTC6|*ѥi0SP0lz[bT k5AsN*C@tS"9v{^cTZ̓xȪ@=l*>[5 C<qz1&RnW" N(U%4ݢ@mEg%lrKx<*NpoD(2221$79yZ G͟LGjY-h*ѴQI*}e+Ԗ5\0c%M`Վ8Ac̜1"Utت*\U\_/f&}4Sfif$&OX*7k٪Rb-l͐@VJf[m X@)q?U yѳe.0U@x]=5RRp1 pg3A$[>#{#YkGm]:-=dxX 4JG*0YJ+ YrOYpyF2)TFI+f@jmXayZ+DV7O1r"eFla@"=5[8[]hs ~J$Jhy~]\Hh ,xz.WVP)mٶ*w }aVdYUnNa[ʊ) YE R̃%# N  jO+Y P3=v9M;DVm|Z 0c.=EVI+sE|*l.h;#YXy(n+[ϧw s:S r+P' 'j+6 mp!eE¹jK$1R;2+*۝4u'"YRk[ @Vav4x㉘\l^ʥ\lK8ުoD4xc<4 NLV//U@VmkVի 7a+;C-< ȿL8o&(%` so*@;dY-R"13lEnAk|S8M#5p\#[SU;QfHklY)-^6|wH/o9x+綥Ilab혜V8u#uTh+l x0$,vX岶J݃l )*Gcb2Ae 7u,E-ZȊphObUb5F[w.6XGopz.Ll1@"7sUư*bid5ϭBFYcuRHrσheLv<^y`|)Fձ!;<;`ݤچPp_C!Ʈ׏#I6FTڴH K@VbUk%9:X*F ܹR]R51U1QLV> +]HN Se'l%|6&*f ;xn,BH 7Xf\{)%u+ YVv4wYFb6Ilױ. EeQV 7>:²RlemElTB,jִC14 Pޢ&"_؜MH*.l:nWTKI4!Md!P%+BEM1Jm{vledÖgb!ٓY4HUޜܐ3-OR:`.4BIU šl/`&+JP 6  1AX14 RnbғIҋme|W*w:ڦ# &SV6&%H@y2C[/aJ-r@e 7@~ (HMO|(h767-z;#kJ 4UH"1Ybک;i>:_C oHzU=\_%+2vuX)T۝@&ߐHp!~na*8=[l OkJDf%`~|.kQG)>Tg<%Ydي<;>–SdRU4Z)o$x $H&6R*]xq> Q!7Þ^U3QybF*34`Z^"؋3Q}vtX[!"7@U 0TzIQ dlZU 7'mYβ鳭Њd(:-dbY97TmRpjmUۑJz6 H|0Rp2C 05ɪ{HCTy寻c:'+Aگ!Y()ʆYjUS^bk J8HU@*6^[k]E2J vv16ߏbU.EJ)Rk+cR i_[z0dCTT(hZneK0s)R: 5Yf%[l8iJ|U7wH{.ɉm鿫B'#pvWĝH¶΍Lr7 `kp аM $@:{<@5UhUސ2`6013}3Pev|ĝ$ X 2L<2g&il9T @Y|]rjMm9k!:PU")< =@ pUy=A- V ^T"٪"Y:]z!)Vw(l5 +if䦤Kvauw^ ܐo׿jPc`T/Y1#Uic5U3le$Of`KEÓTŇ) tcJ&V 8t `_+[JV;-sZ]-:2[J®n/JlV+"gcNG %p"ݙՋ80M"spr֋BA`)s[g*~(c |ca`D5 Qe wغx%U2dHO7#QMԈvV[Jk%z+ílR mβR3-UX%p-J^381!O-`2M8haWĔO <teI@e$_p/L/ B}6<֔sU4d1Ӊʶ!7-PGeU_rX(=w6-x!W~^?xz,Ш@>ٮ)0CH4^sլ4v| ʜRIdȦ0U<1b"A0:Q&NTj\ :7uGH悏y4⃑%x{v0 Rx+ i6HDcZ&.KQ2T.Qg%V™ٴ[TsEsk$V(Hj0=ӯD@-@ #T%3)Ns/Kw*i d-p:SoG nfHH)/`hd(JP|cF=GH%F[r#eKc毜ԅi? (5N@vc(\{$aEW 6 ?21[X48)heO7mJlN`uLJ'9AB)b6TYR:QVLdxܶsCѝdشMPZT#[B0jpd!߷0}˪%hNLϯ1VQƖz-2}jG,*1L'#Mg97d!("S76#^!e޿Jm+5 $kR$p)O.˪݅Ris}$s&^w͖fjK%N'@Rb|2>akVn>%`K`Qw3-0C]~DZk0iVQ#nr9*r3?J X ^jaUwaβV͐Iĕ'ZNMX7dBb9foValfœ*JesD~az4dZ VVR,QC8]VrL)c9@ |GºiJ aAƤ< #5 i۔V 04t}RLæ5YRLӖ[m8*%H5%|X8s8D!PۛL0-ٶ 9Դ^*hHy056?An蘲5UkM%l$UW1hfg"{t"_*=XXTh!uxTr8CsqĉD*Z&V>K-ܪ~tAk 04sjm3vቩmXܗ^)@ ^5EVV曳m3?BOnxhˤHge]5c5K<7@/t4]l {pJ`VCq'jc4z$0[]rPF[•hfl֋R /Z l 3@&0 /8 Z2UI,ee `t 0B0RH1Gs/pJnjmUܐ0O cmBۺUhJu FН Ic(#do^}EY14 _;[IOi DRFeNO&EO v`W'fjRLd149+@EzYaaV2Xjw!cFJ&Y VYz8Ja'3!`N1smk~oeU}< jkΕ4JPyH  JZۦӇ,UZQ6#O&U%\&x e8S!1xMR/t9pNjxvX2W b(u 0[PDtl 47@lakv $e̋(&)TR$&AvjЂ4Ml+yt!z{H ɤ Jǎ9O YgAOwzYCC hxdbTS5mYL&Zk:}D!AM'A?`!El%Pp])YNlHẌّ́<ܝ0lHLdݑ,1QHn"5 7ya`Őw(< 1=Lê_qt}`OZ`r|04JHEVeR%@tB"oH@ r[nyLU3t:%)DaLVH[\bZt 4l19`uRk0{ʳ o]TCCm06&X wQxMr0l304:ך@y|lRVn0 XkeVHF/xַ?^~b4J6pMG @aͨ^;vnJLT{Tn֪Ioxd C Y`L`Z'mc Ss?? !Z1@B|2ʟXB6VSSk!Bw `%g(+#S8gj`)@i0Fl C {aOSm_Hk^1^)$0l 7 O xW' !h0<دMiDgLp-OlcAh:~[LAFXZ. #UEjGᢦVaLq&v>4BOyc3t[mNIC `!?vZ;Ūԅ7lBJPZ)=T9.- OllbOI Ŷ myz ̙9網xfnLC@Jk1maBhx3{4@m)EXrT;): LMgcj j4E4JD [200 jLۮ jMrǓ`䇱[vkasY7 CO[%ĊW}qn+UK-CkLMHw1|ȀH[V S 'C8DRd@HeR‰BCஔWAN|ju2Fr[E [k `ȭ́2(e6@jDV-R|'ɤmJtme;izɤX3 CGEu'P:KCR"$/S&[JZB'oUp:kdHk`wi*̟8YcYVE8n11 a{`%e+aT3 0fP^Jmkht_ [ =uqƣL)H =\!MSAyVRuvtb{Vض7; L6:v$8Βƶy0=UekƳPȧ@©EzYaȺX b&G O`U+d[8[/^UUuQvRAN[u L)XzR]d.C]R*I+HLēR0C ccj"z4Z8"1Qd([[4ykPd4EX*%L-=m֔xa lzFFUJ'UT"T<.?\jS IcU0jC,|V ilaYΪW[vEjal*[K>hF=-@t8JP idxπ{OXƥc45dt?DJZ3j[#:HEa*8Ԩk.E*;gFlȚ6VAYZՂ܊Qeygbj`[-D#IMū-W` 4r3ia@.E,1.|[;/XXI$99I?xq3ڲ;`ߡִxD].V!ʧHYTlMl  И-^'ea[+T4uAx3H |]84 VAxJ*oxT5m sUUhK/||h++9gƊm-|k Ӗ@ V1FҖRy[1ۜ88u XC6A]<0/lRޱ4˲nTpS *L-0~4$wcL1OS|Hgfa>FR,xmˇBUتVSLHxAcxUXQLa؆s ,uNΏw4^MO%V[&a){ZX}ZzH&bsJF@^ V3同{+{ܷJ@e+Z)1?F9â¬lY,Y/́R ʙ6\ Y8I0L,ds~V* XmR9P#4щVhK 094010l3&maJLtWD hr1@c;  Y!ueױCb +s310V1^Ho*e_ ]uc†6B[+Ko놝Oct8QJ1\FS Ic_aL[.84xBF8Y(i :(+"Cʦ^K@IDAT1LDtH81`X+3}0~ I۟)Ms +^:]尬1pN46;C mch͜'7g))Yo=T.+mi,gK5 ڄL[&(F/bi%koaIWN/h%k55MԝiY#̩̙lG,E*4< 0 x̕g~ƊU :5'Ȫy• C)QlmuXRxjl$k RI ixi<7#8 J}[w3Mb `Wf*_eKl%BVԱ-%`xglR %]'[V 6jkHLSf}Ufea %M&W&J4fVg{&T̜Os涩b`p8Uœm= eTiOmI)=>/g%s*;]O c#,mf10bo`|>!ۮ9*kA ]mRVΒ2!H~^J ;sgQ(e=wt#9! )Tkk>DJ[d qqS =/ R #WEYD`[G+^LӖoUZۦD~KI.7 1fSxwVh U'lW =xA45 tF rYW"Om@>FU 'P:d%%&jl&k+:Z7@)j3@#M='hlwLi=J#mˤAIVSJ⬤TV)|77I$ZnYYa"qά`G6!l^e%x91@uԶ]/0ffvܤ#4%"†>9 /ŶPə穉lewȲu2#0@kil rK e֘H% EL5i}AblE"&j5<OF]h( rZ lwh- ncnOS)9NuT+̶FxNggEOWM Sk2OL2lU%'H*OP V#vd8MLȦjR:] ڲ]Y_&91CVd ?Hb?%.ГUU#L$uA1hT8`}9 `k (J]s'Mfe%)Lߨߕ82pP ~X8P.+EF&]&z 7Y 0^ˁEm*ls6*s_ e[l;YX V1lH ¹Í0dRި[{BU}5[na ؜#jG1gQ ,h`Fu HX"fHfLdTCZaQ8ք-˭cJu'7R% 0[E 5MWkV*TU @0AFr6w8@hx77g4I?P(L HibdP&B{>x宩#)¨Jd<2|ߑ*1ܶo,œ^D M"[3聯mUVG`L@U>u^̪5V pJ!hLa$>ٶ)|}0eY)A߹=<-&`*-X_VKYf d(+0ʵ V,e8U^Ebf-BIy@r!QH D6#KH` [Ԣ;!{TY/Ȱ-^@-Drx |2ဴ MV2AV`X9Dk}n&=OUwl3϶)1q蛒lf݆FYdvNS-\hm*Y[JhOL lxnMN<}5U64? LvdSd2ܬ"s2x+~~78K6Q̯dMbTuoZ8,skHp9gb%s.ﳐl$ 0o~J[ddӅ|lFTN&[-F5U0!m :J(mﭨR X9w& -}0V  c4~7Sx:++/HZt'u=dE)o[RS ldk5-Cju@)+[jFk+VhcοNWEjFTf @LV 0J dh˄ w|v#5g8M™9nMbU+0h!JYEfk[)nTJƇIYxdleaQɔ fX^V3!p4uUa)akjXsHucdGH=a}+)NW/gg' Ǝ;x+yRPH [bmTu+Ki6B*IPG]Zp,Jd+[ܤrmB%;9mmkY2U0va`kg*+,k噸t38}svmgbilTG YU!e; O,:5wx{3g-b`>xNqm{ hGZfhL?mHCT\|toRY(m7ף.Vid>eaQ [Ye{WY u okU1g!6X{*Ub"lS/ T @DZ&e[*[HyAFU9+L( XAIيz2B-*/g- x#9c"[E0K74k'3@S)0p&y憩o ȶ͓d3%V!Y#Ph?O3{##2Xp>:$U ):2V*?dg+*!i28haLu^ba-znw +{&RXVR9cPB!f[:7guTUC,0YupBtLcm@ Jj H'Tkѝc*iBY3XKցm#F-,t X*l}KJ<fAʩu(s).hMnRI'R"٢'dMA􌲵U{_V-Q_ +U3ITWV`rmZfb wW5'JtҶC1ݼ,r>GٴٖʼkH!wX1Td@VxY)[' RZ Ԕ d̶9ؒ YSyG/AƜ|bθDJ . Q.PH'21^ Gy\ 2dj L\wJ$6^[JmH,0$H&ÙLb1( +,h+QH@G&_9 ~TQ#ŬKJdTAxRلJ@fTE,&;F~lYQ6ՃE ۔p?gO# RH*X4H?nh00Aӟ)JL JUK+ѷ*Y@ZnۜoR1O&"ex `d͓ObH@Pɘ 9!*FmD6<4`D G[kil-e;Y)[YnD, 3+`\s ۘ@F(Y6A d`.rsF!+*Ee饬0OKyja@@4P2Ū}WxҴ6<)ʍCiU5F030J|ȍZJJ!Y%JNm Z@U}Ye"Lo絥ok )ڦo+˰SO*e5u/p@2ٶEF1ɬ+$%ĸ$C*V{I~; fbU ,!œ@b$OSwV d V42 `$gP04 0evv:l+s)k׋MY)#jA/R6m7)r뵪&$+ѝR IWh9n1Bmnxt"۫*Fz-?#ꢊ  1FqL?[>p0pR[ɊfK4F ḓ| }Ց25Cض_d9 Kj)KOm%iLWza Uύ?W NF| JƫRcwA!9$PK^{EFIo,!,S;k &TL4<^4T$}d- JZ ilz ]m+&"HQN ʶF:Ϟ%mus%N7ҺFerRjn)zyy>ֺ^+zRmUܼ>gL82k6bU u j6 "Պj#icVۂ9&|km [U/)R֗>GMJZ}RZEbdkgeeUR LlL6n;0ltR#MU LFc ϶@ZU=ahA|~u%XaLضR`f}uq{ f I6H2xMma1b҈ȲgEƼBl1p Ԏ/-Qs%N@ RS\$Xd9Jҋ=bk=O"az<3$jZ [jf$[y1RaXHL`[YLqÕF9LX10םԂ!EVR *0yb%4JR揑*w1m$tKLx=PJ!͟U]ZOz@qC"17_WUiͤ*SZ1P%k$~>B/\m&VQkYƫ"1* $`;v!޵0=Xw2@VꡔR|5 1m>5W,PG)gR l/˽sVƐZK Ma0 7L[H-AiTfHST0emVk" 0i2* [$YY5'9<ݒy+*ī*Ta'NB6g%L*S OB)i9b %zkAm T΅,04eI=H<'#d=/i[97z5E/".auר)a Yi+8c6 @GSpX3Ja;2`3m) ajLP0etJd:Kɦ'UE7SR7pyRkc$EԅɔS CPmey4^v`%49DhLad2 ܟ5C'3\VsUN9ZضNX_>FL9#%x>ꕬ4۠%1!M㫵ZHVim l9X]uԺ]沶jƻ>/… .#\gHk[ f5۔k!=Ja^2$9zuR1]]b4RVQk֢oh2\r?8XDz׺![NJmO{" K+k WK Rc\ _qbªk:vlId;l3or5G_]ß߰IPnk /6 \#3&IJ--Z5bD&LdyvdV+5lF^ Hj@[@4UK+uOY΍ID-އR!&V*rn +9>y(1dVJ;˾VaHxζ8jCd> UXxZɥ'͚"7LIf{/Ak[b9w3p3lY+`˫_H@U 1ᕜ/{G-G#4fX5+, Jъd[aHm dV`1D j!2gШJ`H*Jduk<k3p0A*k뒢A¬+ܣ=+>E?, Z균Q.MK a8OH xJ"aVl hq0כT" XPU#?["v@JFϊ|Z6F * p@# 4@V&pf M1 EZaJY>֪8 ^Jʶb x+Иʁ8F#sN&ڵ3jJ2%V%\w =Mo9-@,;N +@v\nIhtIidNi )RJI@v )T!EK] s&6L&%`+Z Uv>+d%ר^x CIfr)uFVJm}n2ec )%v L 5Nw#e+ʎ1gXGU'P;$@#:ZL "9UR6v30`m ikpVY$jZ%R}f+!ڪlb I92*j`Ăx-fX6zR5ш XqVEL4 w[[boېTd|/ȹ$m\i2V9c֚bƺd͊W'L<4#R@͘"9:/4"ht+fk ȂR]O-(U!WO=\mUJa6\iǬ־ԬɬxT°?)o*+ƨ;.#dd4fm}0v1#lJᔵn%X fd1VV #a&j9j}SaM7gKT/ȊH#a^|%OoyV!(ސ Ս0Mt|YUӋ$+ZXʁ#1 4BS[ n& ,E&#4*|WkfBU^dGWX Y/E&d th0 #Cymow[SBxzϕ4@f)`Ix0d]B!ebj}DWݯJj!jak ۾!eas.tFPVض"ŠdV*w!>vn9dcwX1D_=t ¶BL򶲬xJ5lמ`:R*̎P4Rɪ)8å0}"|`uL܃pkQ P+i֍JkO?ۙ knP- #5q&0M[~UuVdcAV୬5Cc$ni8$Kl;ILдgLL&tIc%&PD0 Tre7<=xmΕU9}b[ب!mPIY I0 Jk)%"{+|eL ̦We,pF*e%)lGVk%f" P43ekɗ"Z1dH,ż5+)!k}m `p @,]DW(eԶ&>dcImfeZ$ԺUULiLu>3#V%[mm1֚*62-A0bJoeZspAφ [`ls)|:RZR5gEuLM0X!jUwVe-1m;2ϸW{H @x4@lkg# )QIcLd$[# YUknܪj{<\l1Z[!՝uRQ߫+u[;8-BQCDPτl$&5YvR"zdjemeê">B@*@*]*]El& f^H1\NݻXJKJ A*@\րlGK5;dY1ʛ*g0pO#UvDY2ȇXJ-y7ҩgiM*O C ;/vof  %PP#񚔟~)HێfK {[ =d(Hs+v:V>Z9)uqEmFcM_ߪW6Bz_FSX\-D6Rv[s:x׈i؜ ;2O-tV<OYDw+ aQ%p$1)1 (v.g@L:J``+sLmh/߉(z\`+Ffh5 RV:ЍH 2nzof [4b"%YkޅNL/lcBvF%2Arn>\$f"N|kW.ׅHa]h %ڣ\@ֺȬSI< 0jߢ. $6|&;݆-2AVvwQD!1 Scu>R6r+c@I Ls~Шc+F訖&&'fnCAU7-OW6B^7XJɅ0a L>]oheZ T)єRIO1 ,ʻ: Ida:iL`%01BkȺ֔^,xb@*o_?oH7U3ۿ։ G2Uu|-^KBb ^dlE#kd2F09\B hŽçmZeS'm (%󓞭yDU%jiJ [ 6-Lv@j[9XtN]xk% [sS!$)=xdS%4u v86y׍ErHT{L/)i|F=ʾ{FɶҼmH<\LYcs4Ƚ &%cB-mgLGKfelƫD*0ΑZfj c ] --ʃưM@ %j+a3F+Aٙmz]0BagVқT`+Ll>DJuM1Tk%TQbͿQZ_[`dU1Y7I&`ݖੰUS`6ps+feL#E 7dO4RϠ|&s/Aja@#7w7Re2)ѡm͟`n$oɪU$ fM_P̖쿅)dBI4d} (;oQ-AvEx8*ZC =)]WR^I   )JZ r j,Oba6[0ӧi'4I\mg$Yml &!X4^V-*/IYZmdx.4v-llM3!B@,ò1&xzXe g t^I 2ֶk>Ht֛9#䖹g =dRqD)7IM"*&i吠۶ZQmǩF4zɜCپM)[*&ym9oQ'0!s/FW$K&ܪleW.aBVJm)R&4^-mVu!0'RM ,xֵHHz$oB+O+ܪz ON vQ<ר3+R,RJZsbʒ `Gi5BH&9mnxgIj[˿ɜ,Hugb`<0^9PhL3lz %#@J:5J@Y&!d͜[ka.RjyZF0юc L0`-> 0gh7 2p6la-@ MVܺ^M4Z7d NQYЄިA d0Ude5Dem־ ڑ@<ۜB] ɬu41?#6.L8c5MP ×qLԷ./W 7BVN3g[|% L#h0lò bCZ!0pfsې5U %sbJ)i$]xjG FReKֽ.`׮DSi$@v;I,P9Y/ǐjnBVL|U hg pc H헿otqT KkHmq')Fi j bdOlE'5eՈ[ì Occ^.(ƶ7 &01H 5Jd Ȇd վv@&"N*8:nGY;Yt6aOP7{$J[s㐉iZѹ~[tLfk+j3̿^1] #Bڪ}ʥtX(c{.Ⱥdi ےr)R֡hn,2ږV(JٞNϋ]VK/hEꋙ^ɶ VXY)A!j,sudZm4J%ٔ0 ed< nT6`ͳ-TȞJ֚h0]`%B ,1>`¶[1ME ~lvlO߿77V58 M.uh̍ [c`oBU)IFfHZ3@%4mkA&%(Z] F*:͙Id:.zn[l2@D P:*ɪVrlU, )تYi3٭84fͰڜŪJ%|r3or)qRe(+E kEvWpFj*[3M s M!e۴=4VLZU8)h&w7YvLH0sʍj~a'"V l k7 7Y2d_ 3/Z tL}jeu2I%izJ2ۆE҈;| j;-duoYc}%dzm&%Bd 2z6ږ50+tl L3:^ę%<-KYZW%STVc kM#̊_-}VT罹,˝#ۄ"9MVI!g .>>U PZ<`$b+-ﰛ*&Nl1*a/&]Ejl[ @*eH|3(INτRϟ JHHAD3$hK/l0` U{38/ґl&yOk%`wsd~( E&~TuaۑM5&}'R8(} zIlKQ6Ȗo TS2LiI&:bhdXN(qRxbi|=,/Kk*aˤr+M5R@@PrQP SZSn1h*a[ *28m1@FsP5vy:EO*||V@~_7VHJV F#zUgِ@TJX^W>[Ťe[IjEh%by11R-xfb]U (.&Dr[1:.{4REd/ OnV9lWγ 19ܖ-yF4Za[+=Fj6kv0opPBӄ*pZ8 73;e O@[Y[rfK\_]{] a ~.h8&VQ5 Dy?/4XWp`oyBbke{,nx#kJ0LCV (Tc CXyAiK&?YJ鈑50zm*QE3;@̙XFm:9T汥I,RK0%kfa&H9׈tgm ?ְyRVUn19]jBRyyGZz4_9AڙǕz`-4a[%0%#*ɜ8 [ 6s+<Le^7϶Sl dn`UeQSkb\pvUmגLl_á [TNe+51L&zXC Bofk>pAIº@% n]NȆ'*ؗ0,UaG[_ݕ絎5Z[};N4.zǤ=}Mg<,Vv1p@Ixsf+sPbL,@lair*c  6Mb hanHQt:O<7`jU%#Vk" $*0'Z۽x+<3\4Sf;gf-++;x0>| VxJQmmSR#@kvbX- %`"^ImdR5[.M La 3CLzuuQ76a0gwhڄdm1]1 Y T9+Yw=+Y̺09ǚ Qm=@4F30%V[tJ*!U;m]մ6B2@Ou#bUpl;%v`|}:3 َd[{ִES6ac[19 Ȥm%VSɬBJ 2x%f˭w@2s3<[HJl<#hM&oBnB9@oM$uL+t}XmɀiSل񙔵v:ƶF#&x3[2#0qTR7wbO l1S *IwL}3 @1|r-gY)[. +F/@}VVs*eu. zZJ?g@$Ւ56{I`d0)YfMf6H'-\IaJt@m13z(~-kTU4)2b[3̜8-@om=+- [Y_x)~s@/01F͟ӉkƜ @V$*Y+F@m.*qLĴ*]zd4T+lsC*WDZI͊Bej}wSbS"@ X)7L~`< (9k_,G7asS%lTHLdg+%7nR a˝Ԗ65k.!"7k ١d@aō~aL 3ETu:TX+G};/ [ ZI(IeXU*0Nr'dw1AʪϽ3DS ؖ޽v4U[5FZqm!Zg@$k `d ry&2 Dw%` *&|#Z,@\\k2$[-OVΤyFS2Q?C z3%Un [ZkWVa ˉ,Vlmk @m1 [6=JE܀pʦŮRoЫG}{T:&[R@Wd$@ a#t"@Tr oil$p$\QYsz4x%Z}߶̍TGLcHuv%^i ɬsv= J.qhĝ11'5 vEhlUd ~υЈ4):2NAL$d,қ.f 2sUJD~e7X5y-dϭrOK##:{M3zۑ08eš#XS =pjL2axPDȆ D J% JF2jO㫷\+1җHUYMf-ٜR|AݭyEUoy*HzYDJ f(d+¶oVV^`d} &"usRaHza (&k%T9(?O6f8;)qlntHJc ڸY¶cǐeiGdH}Y}*!o@*l(iK ʨ}1a}aEn aeUK̘XZ 5*Z4*5L#hױ+̡(l`dV-a:6$Ao#ϔ7da}_E[{5TJKY-

,%8wmkdШ@ TbxI`%t v:)~7V:+\XuL9a L`_H>(W7iC ތ awt}يp<6P+ }0l)˲#gNmTʝ9)Tlp7C/r@fEo r9[VD6<,a| Lfۜ4x #T%xkAiuȺcBFv8O\61^Tk6,,A `j.UD^.Uvϭl[ֶ-#@,+P#t ƫWJT13 n6ȪUU%|6?OX7МIhzusY YTE 0΅$o-FU5Od+pmZ ea4=tJ ) c-irj_h40^a]I~_Lm0JoJn$1A[Yb+4UxR4&Ue=[$u%p[^jߢSYƊ7d,qZ#ɘÕkcRwL!@ E# izkV VNS &܍5PR|I7md49ThmiF5;Fq>7SSv?Q=V 7j,dMΐ&hQm3̳F`ᕶb%ߚmdYXӍ[ڴ4R5 0r;l11Pj1YUIJ>΂a 0@u#PBP0jP6L~lM̚>5K-lU-M01ޚ-R0n/:UF#Lga/1JkMIYe0vZ)t@DaǐY#XaW"MId7k%>42 , "f67|VϊCV@ݭ‚2Obm0uWI{4Fn*7-YR2 (ZઈӓB Ė.2cQ>NPv:7L1FYRoj MS#Yz3îUϳjݜ&P҄V+ Z#y@@Zhmlli2$gTmJl El%DU"ЖF)JPy*Oi k `:7a PkU(|/l+?<CFZ~>!l g2G 2eii:ug[Zk]zm 8C/Fy̶yE PzܶpDf-GY;+ jc2;gkXWRSX5 yVtOMXYeHu!$.̙y*#\-MUx7 I.ZY)#Ra]H&pzL]NQ+F@읍R,LlL)XdAX.A6\ja^+3 Crhֶf^ )ުn*1y"=k$LkZ#CQh+EY5wRd٦*n$ |l oZF%0gҘP׋^41~eQbD[I9x"75~~*k-5)`m@ !Fjת[?&AӚV!umWiL/r%pcf+F`jw^z&MymyIiU*x]2}7PjYJ h]ӿm2w4.7AtYkR`|ĥcn[$>ﶛPK& dX+9r!j*Oo6@.Ywς s`}Ǔl^0F/5'I}mې#Fr]X506CY{``([[$ɆDzaDא, ^^RdV~ &ss;ȉ*,Lr9M7ѐ́RW'Tn%6 R^{^1^|k-aR2[ƈ:^ȟaxj͊@5PuD戧L;7.@(idl**RyЗgɓLX C$}Jb-u `KPm/Е#y93ilscZ7$4Z6660CHGUnH"u̯sU14|þOm4Fe茭jU'-oZK1gʖ/ Mw!OS)T5YQv "{dxJ u0NO[)e1YY+o̳ )§mU{>;5mzxl=n)1n#j+g OĢ.^6z58XSZ L j%3𦪩U/z1"[LӖ8fӨȶN\͇XۅIkd;=1mSzYUqWe غ ۆtd--V@*:֎cq[X Ľ<0]uםS #h=7U؊+,#aJ(뚳BJƓZRm@k}~"+P5z&Yܤi@T ͙!P˭h UNFl[UdddfhAy&|۪KeU ;otz^-CG;V6ޜmY ͺ1u`>dy)"1IJ0F*À5p#mƀ#mcnYj K 톯/uoT%aLdFDzKR*!Nnk[h}eòL ]EPlm|͗'?1ܥ YN9HCh TN+0hḱ:˫` 8 <$Mujekd PU45My6j]) |^}UŪ@µ (QU!4V3D+| hU^7d8=zFM D]V|R s1Ȳ Y 1}5`X4aئ+z*TՉ*Gjgp0o^x ƳЂ@ӯsj2Hj K1٤FJyRVH~8HV +z9 a"L2 +zsz8DZil{HݓUՖl PH[we H @o*!řl;>?%=DT鹷ޱEy^.8[$eCZ ЄinBYH2B &Ϟ;*z]z0Ut.z%=ti6? ^9Ý<;ιFRh Tb2AZ ș3#Yesl3m#**& S-1e'S+'XU}X*_pnIu@ /ss)G#X*̭ p?'R`ʶEN޶y"1 ۲IPJ9&L &*$V;\TRʖlR V,J ,2Y=2ER.RByWdm0snXɕ.10mDU7d<:m4wCz]645anM5zJ=ΕBٺkkd;P"}daj'Rb +!hH%97brFԒ( <\k}fEJ/[r+s 3ޫE4OcH)lr<\;2T x)Q EYU |%R h"Nc /ۏBIܴ0` V@Λm |*K)d%Eڪ8“U4C|m&bnCIy0x3 #ԶQmzrNVʊd=_Y% SuOKYër:PO˅JTJVIHy/MfZvOI7 ֱI3󡚌@V4sr^9yC#hD7 $rK`+l5jζFHQU rmK\"e)Me1ү*R[0[ tdp(ſ%>wZ[d˿GUΤm%$5?0Mȶ ҜK[Y( >%"Ȝ_Bɀ."CfH&E Ј0x:&h͐0Ȅi >S&;c0@ɜbZR&G?_|# yBl 5Aƴ*X8)DHh*sP qMUGrÝH6<`+姶xve7FmGiv*\c+̻4ܲr 5D5aZ3z!Śzza*L eO ȝZ `! D@_'WZmB2C&I xVF? t oz4&bNϡ/(FH$X4f˳j;Li4u* wNd%u]-9ȪhJDY3}$۽uA}j$+yOj0|aϰ` UW>RʑHA149^\SSzo?RZ"۷2!+Uㆶ ){qVf*<7(3g)]Q2&HY>AU5Rl LTE ;o~"E%czYa0%XspiZk*KdE[*7J 6:HeISǗF}2}3*N1< @Y+[&fPoQٞ.S09A 7Í[:L͊?#'kj"YG V,+[r&dJ09Ӌ0LӧC;ZA`[S-^)9TR eڱ'[nϟ1QSn4x +ipX4l[zڨe]0 EB j2E09Pɘdᝂ&1%[$ƊdՖ-`]kTMr GdȭP(sfj|8qחZ)||x]C,1ZP=eUVU -@#eu)kTaX)3ST%FeJI#*%Yz )JȀ0RjM84J Ԁ'2hrVNQ5jayF Ld\<[iLgdiDYܮc.K_ ĥ e|$K h2Ja|;NzJ})+QM{ [Xt *aÍC 0AZ3L5Y> rDb9-ԩ)^wja[Sb3vnV/ c s sJá KQg0+]h4ʊd=g.# Rajc ø1ۙO!V.Źm2W%4nZM(s+ wW)Ym4mG%(Ge+b`YT#! cH hzV͇Taɚv`>OnbMn*Yjsv4Nʈs3p˳sR=% <̥'4@XV5[igp@Mk]~ @ +dm0y0mfkKS9-^TbEjgWQ-Q" gWn "l1Vx8%&, rcz30ݛY{)rqKC!wӄVgi }&ύ!Ax4ժ@,ZH hm> cKʊlkZlCJ`lW-jVEs6-M-L`&Nj5 |l3'lfap.-R- e&m#maJwSwĊOVp3Y9pS9\-mE|LEs[ ns뮚G)33jx%+O)<㭂^*n &qݥ0"Kl&*D g+V ٝ*0mKiIt S!#h4ʥyU4>s ]B[LM9i[2)c?ϟܐD^F@奌!⛓lƅRJsv3h5jBiO!q'钁^'@ k1@V4Ro9I6*5I9.GKsZ4v2k|@G[+O2aI3׺kea)[V5&6ܗ@IDATCPImYux41X[lPtVg^yThR CP#k[բ /Ez.yG®V6ganV%O[kY>%cE&ASv b˱剙gG,`@/#k,`5x$ύ+>1jAi~4-q&S͠D#˪ɼmbۥð7G`R2z< #*A*ץS#ilo}@ [k>!Soc1Fj*+}+x>0B @&xWesf1oߛ^q:X}}SĮ*!`$P˝S5 |h'.0B*m-4jdA 0gm䦻Hӫ3AзUk ښ!sS`xl2Mk1m1Q"`px&4r L)V`J`gsHL9"E26r tVu"CkZGݖ{-1 1E>; s01|`x?udh 3C5!vd`:5_>%g2<ul~dPG%pK):fxf*nlM{곬* 8gĖU]EJv!LsZT. 8E>uuTRlR^GVn]fKa9Nԕɐƿ&XYaVl?sJQVBLdj#MȶFHJpR S08mRil;~WR/2⚝#DZH6-^0$ɳIY!% [W㶽c~B 9[ 6 )Ͷdu&W<^-=zOٺma("bU )dYߴ3~ej "5> No}AXp/*`+t) d̝sm!mEXmVֲܺ@PʮI(|@Ej1Îa-xA\Sݳ'+hK1ֺOⶫ ,ybw[!ML1J Hdב )vgT+ R4 55킧21n>BcmkD~,㹟ΎQ{}UJl=K[Ȅ뵒g duQlDfO6%CVU>ʍ-6ƚg rZm{okT l+%":)\*ZiYj[L_MdjKɰn,); x,qz+5i:,kN2LhlBJt|^_Hl|w%cWZBAU `UOOض/ 7 c$`pJQ"lx^:fZ~9@O=uȊ̥0rl`zJD]r&\s3dVzgrz xƫ)諡$PUTFlٞJj~𫲍BEV֓$fKlzbJvA=ϦE ւ;f7 R] ^j5hx2s'j嶉$xU%+RB H`b<+Aɐ1A) 7!g^Uέ "^UJPN9`_yVzHI'H㒛ӖI:*cųm%K!m}}gbz+܄.BֶM )4輐!}vH/vOlCDUgHtm:lH٘ZcD*<#lP;wQ S릒uܦ'۪Db+v n0MKYky" /*0*gE6pLQ  Y.Uؚ̎ 魋kk$v4Gg9-M3dkxt'l**㥔rC&GjXYyIhl"LIr4lJ`οVgFTlVZR6mk| 86Ofo<ɤTQ*;, ]HH%G( R! ޚRV!\@kJE BZ 0jK9Ah&yn4Rxj[GcxpbJjFV#%nR&$UH9>fM <;˫UErUTH%Vд10` dNf s0UŪv)ōU&7@e0XӬ _ewHk Ueb J}{0e+7g*8ސeNܫ];1@|}Y`GV^=q^x!kGvLTcR^G|)wL t]<;\U(# V) d0dVUPJ΂gc LtKYV[7Rns1|fp3Z-,*.qa`cٹ&RaPy\ -u@ZyPޚWVǍԖvxbXT[^hw@߫ٿv/@hPQ4}%GVJm+7oϧ,ܸ-ϯנ{saΔ7P^GUi2^U@F v{[z72LcYfL?fE2 ȡDr]mzwYUuLBF>\+`){nH(,&UulٜȾH |d@JD<}"kiwN ˙^J#5B c~WY{ʉ3 79JDؚII* *bd)z?4u [FL~\IJ;FG;íƪOTd+*!RWI4U!*[@J9(!p4ٲr4 a<۔[1緻L*\MRI[U7[]"1B(DlaJBk7 US@GfޜaksVNð)U#5,l|tV@Ȓ &ZV0܎ŽBһ{=0𢣱6V)$eMuR&81^+c[[<̑7ӖKawuyjUҵK+Eq@V5En tc|l[L*T-]wIdaUW[ 4 ";iJSx"}>¢vͣ\JmӶWTYŴ鱗M(4,WyHD~TFJ*h V2i |Dw2V@R2 si '`V{+>AVd~uҘU0idBU%r>LZ_WeS F9Ix[Y1)k5}$S"bV^ n}c82CX୶K#0>80MEPxm4ES9 10")1@&@VX 3xq=V73b$)$\Gxp*?kec+mJMy4 D桑B*ǤI0Xixd:ܚ$Oxq<0 ZHV7 IoN-O@(Um6wdzU2L-JI`";^Z[Jl]";,<&gbJvV hUa. A(1F@S0chrle&F6@/[$+q5BB@l)nHkѩ&KVJj7RU!]HkJo kطVE@f9H5y 7j]JCh.2lUKwKcv[Wy@q, SiӨ*& Hz(öchjFtWR/d4I+Pj Ufbkķ9K,@``DOy@Ǚf&Ne-Km Y ^- Ez]K  4I1jlĂ-YmVVaU4**(FͫmUrn-fmNHP FG Cwnn*VdYP!odɚމmeUk+FJXɺ[Ha p&R#lXEy `0 sU_ᯏ1r֚Zp?^`: HJ4vb!J=k19sۍ!Yt2XuX4Q><1Bf Ts[&u韏Z[ꀪr;HyK!ӴytJ:~%i:™mRZʮ\ F#*!*Ǔќn8[ɕsDJ:4OcXF@)|6o4FMAT|0Vx-y<7[Uܼ=#29|Ȅl#U6fhZ4BJ4On|4 )g 2pۜȕ37dkP7mmV֬:*2! K\aɪ:fWX/qn{4j%)'ˡ}jۤgeH4HG*B|V#+( J)̓y [,C_@8M+,KK`I L(xksÈdVA`xb尬Fe)줶MzيL0x[gʪ6_#e[r1g&@%llbo_V49ek& {{6J\H+{ Q< ]-2̡TkXwdZV@uTĊ@MV:**~M(@Olu'@Zi 4H|t4" e ).%u2/`/(cJ|)զA:Z@ٴT)0耺dKЕ^a[ A )K{F_m63&q ̪+T%xɐ1m}meW`q?_|vRXȀZ(TUMsxAf}t[ +Y_<Qz渓ppcJC"ot+)`35 7C[`LSjaQ_ .`#I)a FdH m%.Rv}Y՚X"1a|Z|VU"VPJ7Phkp Yqƶލ4e.*(a+\aHo>+AHyVHl_V)܉I7XԎJ\jY]ƐmwE*ǐeCH&1vVdמgUpT[MQ \ kSq0)3d|Z+-u|1pʧF-ѳ6^Wu([ç Ԫ 9sWR[wd4E2٪B<jwWHQ E eug@[[Py%)a*Ȅ*<=nYUJYO{彭JU#4"s00}X~?gDgrj.pM)]@v`$ۍr >&45SDVxQszіIAJ 1 lJ1: ]to# 02(–^ _g$ i1ahb[?ds|w@T\z [,m>}&Amr˧gj&MCRHeAce]RJ9>eY l 9sm`őZfP6 g@ YWg4e@& 0u&g-k+[R[ybT <[4*[1u!˲[&bY@(gEc-9ZlR O߄U$>F\wWڭ6jsF6NTkfI`@:Fj,foBǵ[ڽ%Xjx04a/P>Mr%567U@@a& 0fR}Ʉ*;@Y8Х&@&5 JS Aٚ6THhj΅D|lr&MP宊S jSdUǔRjJ<TV*[F43n< a* 4R#m4a|nCe+c2Juք024pY` K%(K웟+@WyJRHYs0p TK&p)YS'dpQ! ,d֙4zs߶1jY#oEBU%I6acn*2njBJdm.,4,@PǓ`{sK^SBJ ebR<3֪͜B]aǐbh흖Dffn|CHUBdFɬ aV@"Eb`B$9yJdZ̵Ye{zNxJ15-| F0JL'sut -XLמUBA 4Ed9v(ԶsєÝLL6`sȊJlKԴ{6IXJTH,rh[`Cƚ'j{9".rGJd(_<,3ܶ&v6@-RdE K }`(Ы{+N ƝșJ-HO݉~e!дy6#F%#jI_y nfX(29pĀ]Z+1d1qJi<*6Y5=_jy5@nV H y;BWDo!ee+-j Zh m H0zuMkKIq0^KBjz9A!N۠U9/$j v߷ M$HJ 5qUR&_Id@ʶBWk:.Q#XHid-*>a%V(:l2iLj0#U᪒jyܳl ׮;DZ 6^[+})ߖ^T ,Ծ"i+g^sk1֔m> s3da|U< ٷI/KhBʳ$#`m F(6qXhoߴjc cXKg<2">ފD|BC [a< X1d'wO/# n6nWkCc+*2:E]U(#z P%jF>cNDւSnK[K4pOdZ|{|4$֊M  P"_8o .̛ٜ_ WQ՗喡.Nρ5wR5ĝk7Lq[S;Z2³4JJ*WyJY۬Vh*YQJJi:i_[JCĊeIxV-J)1v>-s*mEbRۖdNzKh*x_B&?J ?c+u󰩺.?_QB<d^,8MgiiۦEflWt("O< M(5'$k/*ﲂ? M/V%|M\-. EmnԲVpai&''=;)URsA03'#`#02g(쀔g M@c Ɛjr$Ϯ݃f`Bd&3吕}j+_g)OR5?c'a@/:.նcњYg)|:{U4 pJ)z$O)Z)U[`Q[i`&<#1Wu^V&l 13U[¹\7s^Y|]d;-Y>0@#߳ EUV&pS#"~ڜ|f'hS vo"fˊA?+%_rk} lA׽BxהXS:VIٜ)Y\@e ` [xEӽ 4!ݏpR̹~K8' |f7CVsK3qXVw^dWrzmiPVJp21 \y{~TeE4m"rg-ZiInzh`vyyTU1# ѦmNnxV)H:R9酔.kV6:ZnN9PSd5Zjq?dɬ aRS*i9/Dj)UM ,=hi4@QeskEW1[Q_bd@p +1zɘ#=&̞ʑ: ,( `ZhDA0iH&,1 EZ )M݃o p2)/<)U XȪQ+AQlU)+Z e)$P(o{͡^` |meޕX~ɫG&k3O-/N>kp>l9Wlr j fGV#H!XDj1BJDd֢!1Z ߴZpPyt:ֲ6(|kw@X(`\h <@I`$FGҶ1"50JeEJ 5",tQVAl Y6y.( IiŔR%{l.DT+vImHLS)g΁FۄZS»{Y5<Оpvá۞V7H$@U`SQJw7NbLp7=orGNC[3D(iVz(!$J@U(7z R;Ph"2R|:|t]yLN#b*#ΜW(YT<|pXijT*v90L3dKnʪx.&tG*VJb#A{~30)RAgTqkoiڙ'Dt@iek Z'[?)y}}-w =x:w+;HQmG,q6!)AjYCyiS 6%奟VU',z# v!! I4UJ|j8@A?)H %]@H%)BVyvd?*) 黝@#ō6FHAK*`oR#_)]{TqI!H;AwG)ڠf [,fI;cUZE!TjJSk}6%BX8rw=RAljV8IfG)|W䥧KKL.O%p[?."; pskFP  !?$ ԫK'DF^r? kgYS<+ѐ8p^ iFVuiQ'6P Y Q[(1 v!z"URV15hZ "Ԃq [ص L|GD\4@4Δ,F)kF 2DWĆ FUb/8|S`LRx--D]@)U*Cpb"~q,nCH Dx+Љ|t^knb|0qx#x)a]ي)}'4kУ{a!-,k&ƌF ZF (e!VUYi: 8R%v8Ñ&H<&xR>N`dLtX8ϤZwW)6AƘBC&rԿ D'Vv]!gSsFRitvPA<5J!Ƒ2:8L/ÓjPE_ہ/hR)>A@^O6$m5FG`GFHJo׶@tlPR$p!oJY־).'s_Y@t .ضlcB6Pbp)>fvRbk$.D;*YȖGD UB6 v@6T)p%hLLČ,mm4M~zQjܵHSoV/>Wg!^^ӷ (U5x;CӉJŇ4HidxgAT6APZ*>*_F蒚Ҡ!C[Pm;h=585GwSqh@֬Km;G-JlOCPX@Eۊf!tإQ^9q>\c-qE8.0uRmr%qN?_.Fi(Y:A(.~D[}Bx$C! G0+T/t~/A H8>A)_sX%T죽&UD,A֕+Ik7dI%ӅSNMI)tӕ2JR48= bHڽRUPXG''ΜSЈn]46}~ )͚Ðmo\" #t6/@V-x<f?AZ@@o1`8߶JؠfPNF(lUq0 VmyJj#x{(ݳp\GK#($RW-+$E5[;&/OCĆS)%P.USq@A T\W>@-ِBۄO *(R~p.m1J9Jt"B0 d+ ΖDkZT)3A ?G*tS~RI#Kj7.n[НbL q7г^1Ax7,3'.EwuՂPNdvp3{p?­AKP3qwBfC_b ۪pAdp=ni,pp-L{@ᴋ5MM!T/)Х ^*+$ElDq@㴡 \W벿$E"ǷU1-BK:\9&q:,yA衴*&5U^ ff AVD݆fy(k' GLOgp:RZ8u(T;} Jt!1 27M"J2M*=<b:RAd^\ˁZ ĘbhUy˷jOLJǖmWl18KEmk 1(nV,@) _q5"Y]- ֞l+U2u34=J yU)P҂JUBDLhFwTPe YS+;Ei4LAh"ԒH1Y6'*M3 Nj X#A^_[56 >G" -amm!%]B<iOgm%p3HPf&4$ DtU@]pA)3.v)ww8.#[=;f;@vA6eb|ҝ도 ZpΤJ<0&$MR/I~{j%`x:1q8BWY6)nmKgHY#z-ƆIp[`62*6WPjIAHm_,%.YUKIjė6ybMiPjp 8Lyd1/hPPޗFd$%̀Hq@,L};ud,Y] a Z7A\`Zw?)w9ɒ"6;iJ|Tu*h"Rd&g^A4b&3Pc\mVRoԼ6RRmWU=8ޔWYm,-MJ.ވctt<#pR,"`JN|gZLc);w9 \cҦɿAU=aK^N l6|Dh`U== A0]>O[Mb53&8]R|ֈ #*ҶR @l [Iș5-Y>z5v.`")zE\X'6TEhK6oC 0Ct7AZ@5tb&6!`@hcI}@A\R"dXGj"vpժ1<"F`jaګ8`R*GކOMR/>` |DNpHdzMaрL;fc*aRk S2%)!C麀* [lWMh!<>0W0۸N >*)SG;{"Z ^Z q ʋ "MDP KW*LO(T L mHõF:&5GxJ4{O!ń3Xkwb#;z*M}Y}S^PnVg,. &YmYȪԾ(ӵ=yRכ FTB* J F#F^$k|%ړ׈Fh3L)HuMc䖌)Ef@4>۩gJ 0}  D x'j`7)hJJ`UHM'ҺL|otPb-5s!=mB[!0R34%l`%N >gsy:-?mh!UUp $mt)6=T:+mʐI 6^$\y̓w& T%_RHy#>+m!$oN(B-A>Z[gu!*8ͷq1*cK5xso}3ɒr~ڭRFC\ ~јNAR;Ytkb)oJU.%ˋ"CK Fbf&X'O~amlm)&TKsqZYJ>SUrՕN4Fy_Aӟl<<}Pmzĺ,e*k p۫:VrdA*l:S)tLqNP>?_IA0it!8!J'%3DD"fjcv/@IDATy)e?g:JӇiRG)Ix  bVzk/h"JG[)ӛW5bkq"JO!|U`<< Ae(2,P;o7F@kwFy b(h:ZHY/C(+6eoԷJW*m$6r#@N!M1f;!A7UmFFl{}MA#j|q(b+U&Dܽk_q8]dx-1 iScUĦ0],)-LIXuR<(La!R{2i"s;O-f YdRSTof R{h=U $$`tpH킦̺ Z8_~ Gkr3PN˨bdR #*$R` &`J^LG<>.Z=#~m.tX &)2CfKl.ejqp[ا7Q>#w@tNĥ-SkC>AAD&ރ0n|̦)!dg*n…ob4Zܵ١(~<}KL_Ĺ BR-c?Ad:RK[C4B )G`z2|qL]f .8Jb#} nIU) JV>?o+ mORyCNm+<*|j (]AzUmy]b X=F(u.iʕ2hgtd >d@V$".@S>BLM`4NѶnۍ 4*Q pEMLiB@ }T2|kl7A14^gzJ@T@2zb>ҩ7SXUTrX/ X_R&69+`̼M9T R 3N{#k^I/P.1K \M|-JPI, G7AMjeLTw5Ϟ}[@`"Ƴp~V1ĵ@(HycT0_j8M!GsuNGV4A?zC̍v%?6]QL.nX;\$(UzpvK,Zo0Myx 'MBI"f:RUq*r4U`ҡa *S-b--Gn .`z`"ҧ7N%&]5O1#`{Zg"&EPW#՞TS[&&hoz%`CqFFčϴKhR>$r|{J_≇-ZFJ!0#t"OV Z=`NRJ$gU`]MWeba"ųpAkభ)@hpQF/'\!kQ`FvJ7B0M8D.H•8HWkA@/s4A!n @%k8d"ij-C{mN%41`WjI#& 坥ğ)48 )'>0fqb^p=(A,GSW a(Fub KARk!]W5zU #l^#-hV &h Af=A>pG044O=bLG,Ɣ27tMV≿"n1m}- *Umf!,Y Z%EN?bcR0.ei<^1,^ZcqՎ E&eM|-]U䵴g)_ .MA/X/&Mz8Sye1BpH>f]D@18b@v^<!MiR!MUuʼno?}@QSt)qZ~lh҆4Y:NhM&,)*\H`T̛.U`SUEc!fMLӆ8D>MAÇ8 845eW;)\,Rn LRnH J_SKSOW|~p(izk)>&P&L sy ,ri#GTu!7(N'mm4xj@hb%NS.7U*dy֏10p UL S5[]%#2Ӌyj^}T o¼5h&: FlLA7o L#ASByYCKTj$>Ҫ@MIP˺6S"48k[[Uhxv|T%/e>0N.%j8Q*M 52U^4M6=s5F#3 jaԠvR¿=P`hżS{2M82RSYRqdw11K\A|^m0( hzXҐî`kuoC:@ |4i,vm b mt'Gv) zZ"(5Hw=%e̔5lD"bHB< !"ndYiik/MrGn=$O.N'Yij[CM5QNFA πMH1yf}xgKtYlb4 o@+(#G2i"n Djz;B1f&h,a[RlS؊Xwh-)E.`Ŕ2-‘+I!l74iM(y &jn;(5׿vDCSZCHwsӯJ[U%aMD,Eh $Rd8)/]G-JMI }81fU[cq)d-f" ^A:N 7N|otA#L?/JH,mmd!>)톯7pt-+k34x vn`jzLOhķ*t `2 BbA[%eԀbL-n~]38Doqad=jL&B Z,PugDŽh4TCS'Έ%5R r%83Z)xNG%: `+Y nDYnmt'2B:k? >3RY |pAm.꼮.BF`Zvo0B hC~]Agbs_. !ls d}zq'B-3m?JJfV}E =yr:)Y©RllGj!_Q1k;w\!USv_=c4[=tB+',)աZR5YkG8.^IuSkپ:SDRzwRC;x#(2y!Lˌh)s(U@TIgMqڤ`w_߇W5A.:R@ڃKl/I^NkdDBtIq |N 7MS=bR9 L`-@S.bkhA"eUd#K@s;j̫\H̺ԾڤG 3]|^qRLKw M)nt|^{HJ[`ۺ Rnd12 R%cHDUɇwnֈtp.L:v -BDؒ{Upeλ*v"JI$2摕\>{ ZTwAxS{cہ{jbUC- AcL5q43 7j=þt݉)ҜR{24$W8)~UKS.q /LJ+Prs l<ў~1IK zB;@WJɬN.HV]. "|h m`ծ8q ^V5q"geX{;k !}p:Z"c ݹ[ix@jUoOwϗF JD:H 8]!)ShրtQ)0UAxT* FxkI9R-F\h8t\XiQM\f]1ơQf" ÙsibFIcRk"*$5bqH 1 ;)|Aht2gvs;έ :H:&}f} Fe$IFh %)6҉>DNC < %L2D{%s 6U#4zU YڋKN@%X`DK0Cpa["hDC`ty]!+~}dpBY *K/m#HI,V9FDӮZ ËU.O%8̆ Yɷ[G (@,Hw(q!مఞWDiwc\W-~/ј+A?[ !J)8 TL&})P%Ԓr^ #8Zi''`:j Oq&YU['Zlz›UM{EmD0Z8 u)R'JZyL;vjJY>q=~Ui,MVzU"A~d[&6T@RG%a=Jh1U-zpCqOD)*br4MN 1$*,< E-_yL`bFHیo] jBS#r韟s@8bڇHb϶jaզHn_y:JmnNbRnR"*v$`pG-[IjĎ/f@F)6.ZQ`ISMV)+Q:Aw^}G (ՃXy;IE?G@oCAպjP 44׫ Ĕj, !+^CpZ 8ƁhSFcVPZKs]fp|CW8܆qݤ5@0!.!gm M`cBcBY~+ANlhD Kuabyv3 v.uML t!Xi2MP 6il:0;&&(D! -JP ͅǷLa@%L4'_|)Ju )Zb";MS3]iy]O7A6kWͤY'eJ||v)<4q(mJ4f ,F je0gMSEڈS2B@ij(K*2pd1b!"KĞ<b"2͞v63) 0H*Z'gc.@ ء. `! Ը(y\4M( ̻Fu/) 0\vޫN׹#HpLVI؞4D1A+ XU'@LIPtt[^ͭXnhLR G+ 7"2p%\lեĤY%tTRoҺАݹGH{OHY 3AXSpe~y%620|ֈ%Ћ5Nrh<뭮K_j'"X)bL: T BnцJK/NY\ꃠnD]d5Jӄ*U{Kv䌹fP"4) vFx3'}^&RL82@#.J8.i*5wu(0HK9)#ſ;j{pk0^`U-‹AT1_Q|OA1YRb8ӕՕ8BԠkE77=K OJ; *rl#J_:,Z#RKEJ4nT;*-6ΣҼc[#nD4Ji hJ6 Y;.~C)xmj<k$N)֪!ĪR:!)8oH OPBxG4n=.kZ@A&U\/"<1?~hǴI !)5j̤40B3YHY"Y DŽAL24h8byvf'8&ì]@֠]Kv`BȊ5‘Llm%|vH]k`h([Hv,8b M.[M_X[Ec;gt+qZ'K35HN1шb›S;T{:mFEVK564b|ۭ*$ekၩ*db X|azԝ˒]ْd]Jxk !h4 U?f1&kI?>sLM-zZ`L{%FVMS )HS»%jn@zzhRq P֥cv҆bjphRp1K$8KKLGЉ*]3 66NA;A:Z:A l8Nx:_q[Tjbw~!Bl21/ auk׿ZLϔG)C&K$>#N"Z])>bG#r*U-H{&h]JUIv+h8\I}ޥ1MU|L/pFAKYD*3~₫wkq.o#JL HVN}at/^#?~"8!V-F{@H-my"aq,A~2^qIT ہ_R1.)4Poƺ -p֞Gv3z;.ծKV&F25FAzI*JJ%Sk`L^LHq&Jm h7vp'dzV} $n b2]XKl2y 1m"M4+5K vG]7\ ;8Z[C HmJu GKYe AVU".vb2?BR>Ҷ0BdH3Y 3Z3a$(7B*ibx]8fuJ>& {zoaZx@AUA^0BZF͕L)d-ISРD氼UhLqF~~d+,V5Ap΢98%* .LY t@]TJ-M418ɴH!R#"xu::r|(Vżƅ㣑r]!R{FV"n.GIl f_݉.hpOYF@K zb8e)XdtUUUu ;4+ĺ %ʺ(4]X"4ˆR΅AT4o|Q ;&&Pnb7_{1O$A42qK{C &9Rm%vCT((yV%E.ָwr ozWij@Mlh84ە.) d/4Z J S#57pRW 9o ,FDZAZ0kvj{b#0=4(y)! ^ !~ju! ^B{&d̵Z{oa;SF:5v9 nv3^%JG@jͣGb9@x{Jl"8?CХnk03MTjR`kqҘyY!xW1VFܡUg%}CQHD)R ,Lq'ebv6]{U8RcFtIS(fj&ɺ144+vsgNWSW zko022CV+I==H#ƄkWK*0ea@C&Jm=ء[@LdL:JwU_ hDTzuQP-Y8A hZ;K<A}QC42J#Ŭ:_Dkb`KtVŁ@ST8)2rdx+*5 /H[E&>8PdZt@ +щc1 OMYyԈvA`:2)b$`@>[:N"5F/P}j\zzuYR*= HIdzj5 Xy[i&hdi-h2Y"H9v=t8vК*{e{[Ij@1~tB8>\l>YVӬD(@14)84f!MdN,%ht"RZUȭ㤍hso4T(bԥ-djfuat8E4 Hh1KВN֥W XF^c klʐZxf-Oעo:LaLRj[Q5]58״yu^8.hള 4VIj1!Z;@%xӋؖ7R֞ƵCh"osњu>g Z*! =fAԘ&i0~` jDASw5J-Tka䁪<.&FC6Aq){}ˣjOB|&1LSpiv-JD yp6[L^'2| )%&u|w+F@eZ*Ѽc.ek( 3Uhbj=PDk}g@q,8}^ 7gF8J`~eH7NMo8^ k3qnf1qjuj/Ehm1BS@ c} k=L͛B*͂4+>Zso|[´*iCgځdm[)dȻt֕rSZAudAIPFqp4)JijiPR)FiRL'$PfOB${BΥ߯Gg2 >05X@V`1`w(銌KA $MH4uVwX~jZED%]"F%CCΊtWBPbN'0(^J G`P^xs KhnہS5>Y )Fr?_/Zv&c:^"-)CXy;D8?;^Ҧhj)/>#%f;NAvF*r4KQCXRR=RZ ]zi[r?g:N-k&"ot>v@Qd_mJZw=k O X#/fU%(7YZXf.Ͷr8ËSt9DYh Pz.8jZ+-SJM;rAid#/h ^H:/ YCӒ)ot|95R)RIARJy?H:[:k7N,>H}GtH/9;*EѴ{97mC7@[b䂬FVX{ 1j1m@VTNq.f̼̀RVAk'v<1͟wK0aW⓿Fgg0~;Li k i+:~b%sH/ke讬dZnZ6dbX B*H ~3`4zB%zI9-Vʅ{f'H9HhlJ)9dbaTq*GIc[_4u}r6FYYuHJ( ɔVwdB?UhZ{mv-DIdni*-F#$~4L72؊o|] zu|YUhTXfγĪu,dcBh1eƨv@VUe#(ddH黅!7d-E2@H00oLfj[C2J79LSw ևT;me7#4O2#!+"۾&* +ꇹHi`.:)7oL~,4̀&?Fj8lT8B ZkЭbvR&Sn+8[߾u,Zvo)ju;W8܏lPgBg|IJ0 2di4޽v"$%1zEUVdi q֦m Fgx@Xk9Aawj;T01 P՜0Î)qVd0+[= gc0IYzbē<- RڕF PnZ2I[79^,l6򾜭JyºJmua+"ylmK,hUZo?$ s"5>(H} sgNKI8! LLC0&^ A+f ̜y<@ƣ ,{BjAܜ@> ;B[^@4Cv4GlckI %[m-Wr58nwJ/b.! SCfDmcY!pG*+&}uv8'Uz}O7VXa:>@0)nd41HV [΀׬IZThTVP gLc @<1E$ƫ)V@UU|0Oy; em̧)b:RZw@"'@*i~j+> rtto'FZ!*1TaK@IDATUV[2 mcFXt$([zF:Z _67h rQ6FVQ-PֳM+Ü&r%# ^4FO&iB;@IV2[Y*If[:B@P*71%,a.1R$ޜ|lUi `:bC#>Zc1m0KZK)$ ĶG֎< WbsĴ 8Eu pd@a B]6u!ǶB@୳g>YQi+?̰,}"Za-lW: J &eK2X63@&FVd 9Da6g1KUX+ي֮Z{[9 &j}ݪd Y%`qgWOW^-L.Mn<`ekX0ټa",0i;&\K4>M֔ʑ URctyb䬘 `ҐVYe+n< ﱥLc3'i>2ﱾ!D&Z%ª`Yk$X1j+]4=& d[3 2GOHqf@hUߢ3F4.Dk$Xl2 ִ] `| )ƦA 3:mPh](;q<+q'%+W8@3٦fC֐TU\ZOiWu6>Ԕ,GiP?i(X-aPcr6FT!ndmsPZ[2 ծ\ lM`_:M#3YGYO_V|j5u4\ aNɹ#Â-MR*Rd6;o]n3 L8Ԩ1OXi@ꂁ֥JJkkjaj P_0C5V^?LrjݳVǷ6^dB&v 4#*>9؝3w!Bu>YJG 8sc`qK"yR8K7--CN7eSooV):d 3yE_Jmwn۫BDH+ܧ+ (1a*d໗'&jJx7z吅/Tqa+@bVVHP`KYm'*"ۿ @Tj$^ ׺li(keʼ1hPXUMuuVYeb5%Ze'v8ewT 4N.tJ< l*bp)ZXn6.aab2jir%>0VeKL7$&ˁq0:Z-+ۂI HY>eUi8ٺ i8;Z2ow[Uh[ԥ8y?K6^V6_t|Jĭx7d@ͩg+5Aʓ1eJT-U_Uέa-hE[Fxx6` |VzrBs1"1*0Y0 e0Rm9P Vekh)YFғRk$E$m;%}'PGA =O@PKb)Z ᑂCu&'FϢ* h`a= 0_)a+es3aU2ZY3sx@Vb> eP Ù> E iA6B ds jYb[OVH3} Pc`z\_@ $M[8+|߶OY$= +PNI1Zk2[QgO2dV)BI$IU# jWɚ͚l)`l%MԦTʅԚw,Y>"lr%nx0!*aܬHd3ABYLUO- ef?ɰ%֛BbJLƛI|na̓y[p5 m%Zl(an\@\BOXK Hngc8# F!`+ieXXkT-j(87dxdIm%~>93Rb)RY7K97v[3т!^}/AC k@U $ڦ fBC,TQghfh[Xo~4FU g%BLRE6ʵT*[!ǯl91[`> YŬc[R#k@%jMQ/FRz(V8!1AXVYu kݩuK[Ѵk"(Dv]42阔 m0%Z'@V|Ukt7/ewb}m2+5R24L>"%~!KӄMLVʹ?'gcܞplmӨ"^YQ1>eD[ KZ(RG)It mB°QVgr3X 0l׋fJ9YI};9  9)f%?TxE> ~}̰Ͷ  [WezU[&d7oHY+M w'RjmU!d|W3aCіE. חώSTVp0㙧4*︾jLzdVAcmTJ xkVwj<:}^%Rn)uT#p#A(HkjkR*T%΁ c+DcJA`[!NDWN#i;o1Vc[1+%H?&s3ԑJ6!*Jqvcܴa*k$dٹ?BJ!R;n)_ 57axaZY`n@MzsK&C2Ap*Cb!Ж@!P9Y)>Y7R`BKida\c"e0fgxU=Li$K9%)<Qݍc L0y*#!`*qWs9Vlwb˼ נ)Lf @m UJ@NCY%pAuV jTZCJZ0La.Um'^ (i4rRgY.[ LI)U3GvHR gy+%+$ֆ%hF& 3r(im5I_Ɔl7uFae X8U(ojHc6ohJ`cĈe9|B%BoS"hqNjXHy6OO-CBBd@&EFLFLH7B%i(;زA)*@VW9^*Cㅭ4H L q-Z#;efЖ2AMRPXT>zYS1uC]:N&Sdu4gUI2PUȉC).X Љ,B^]b1މm-@V߿k@bZsM99hlUu3pqNV!+[X0xJUlfLdr%^Zp RG|GЊq46!ej1zu@RVy0RJ)gKmo+%049s _M7-\6B-g,,>5 힘Fu8* d LI ]`Ґ0&V~ .Dvd;-ѧ` PIURwOm \mJ+h0O-Lnuf*W.YY^Zk݃K+~&.4˜NJC殬0FIǑIC6OUH Lie"ʶ%E @b j79.La蔩i2YzdN+` pM^B֦% AWc˧*bl mdE X9CY-2 Ҫj-a U:dT[YXBU>m唺#56Rz>kq 彚0O>B l)7?^\SMI "V"k%Z+nr̊V YYJVzB>f燳hTU>` ]lVy]?_J$ࠤ-)yfR!If%W`1$fk>0@css*{ . fMcrwI-wP2ATk۩g4 |/6qMhj$=L:cpK֚y_뻦Qq.2x-R4$К>$[^ Em) m=; W#"+2VaZW0q2R6Tw^%&5f֜X뮪iUU i"RxRem3Ma:/T%v·,= n/CqK?81[7C_"&zrH(Y}SV)e49 4I)+2SnV'y[Yݭyl07ʥsڜGSG+CUQUo~[Y+%+!Vډm1!  [V); J9!Syj9W l>_4l&eYFJv:^Of+lw^VnB#! *Y3L|WCܥM"UEd,< IF nG'kCja]֨AVH L ̿^CM61 uU~W2Kt [3'۫: B)X 6|p B>HP`/#`mlMkuVmz .HQΊ6НOo+ePx%LtwO w brzY%/zb4)Km]( FIsR"܉m%Hl&+W[B5yȁ^U_'UK@5eRA*s9F $PUS!II>UR#I& Lg4: ,E6[%d<{apo*vV]wlf&Lmbjke+i eYIP.Ј cn9Mӵ ʝ?r Y# r0#E_y3e}֔Ca5 $| * +K pVUdՐjg<d/FƔy&UV* om3u )J[+ȖzrF:p .FzsDT@2֪)*̧=S]dH+1p$>_pcN`TԔZ`R6 *0[CGtjϫŰX)c^MJ)x)Kv"[̰T-4z !q~;1ϫ+ḓ 26A4)Lr&k*d3w 7@^Z|0ZwL oz:V 9,"#] , >[ḑِ-7=砤QeHprX`Jd `bl)iҗm)Z-Dn쬔ߢ&nE0\WjtpZ&0 }#`UYmzx!Ɗd6mL ٶ SnJHRu|Ci d~.R[݂2fb^T>o!uӬFm A/rY@(c``b{S߲ LelN#T TmV"U6 i%Eƅ[ iH 4Tbl9X3c##JZm<(E2rkݑm~%; ^k al; sX# uF9ɶaN}"@l#ag"E4ȶt'+ґ6qߝ!֗Ֆ[-yTKF!Of+,gdH1<+4%=`UO&i:_ W[h PRy'Z]Z<̭uGvɪ讚 *_֙U8ȂƄ:&ӫ*k0=Ɩoe#o+G!s#| {#@20{ĕw ѓp4onabV xƚF p@T$!mVԫn$q^GTfB_!VV{c5|X`r(R&+i /(;U!CX3Lc6[dE+iZd5~)Vkx6v+Cā mdl$,#i+ [_C#8(Qh+KƖ9K”al0JjQ;VsH`h [[]gղuHRΎkxriI`{`0G(ېR:lLh`[M3;HJ@JvW+&I] Z K;Zz6+пZZ]#tr$1+冽+ZIuM 1ܤZLz+*ҟ'!2dkj)6b̜2EIM9s2o %C}v4yugSSÔ1w>207!mYU-*YzPUvg)WR;@u K %eۚ 3F63H^?va:USpVZӪtQb ͼTEX#Pup RdgN4>ȐR`H8VZHb)>/^}bnZmtʆfH܅aAXjAϙv݌-ۭJ:t9Ę|2Hłv*T) # m5ȤQdkMߋ]-Tc6@ɜ+/CVl$I!bp)w-lft(2!F){$QZ |`v{!l?QñLFHیlZUzEFܥt RX Vej"^#4gD6zޞf`"k]W9R*YGx 0ZJtB`{GYkHh*Rżi6kY|*Dvu)adƐ D9ϡoM!`$#!1&0ę]y:{VL*JL㍅X%ۖ8}nO,Hm J\OI`h4VO3YxgC%KLDYu>ᎣLֺ7&yÉeM+RT~riB3v*Ep6mx\zVt Yo64" ۪<1 j49h0 D~w#+Q+lPlN2cp>um遪Y#ww\/U(1-^t(ێyV+W(ZA.&pb.pFzefcJ $SOgX(Wec_=)gɰ?iEl@oz}r6AP6-Fx%0oyΤ"÷5J0WF}GI}0}6U rjt4D@),emב'*1?Y; P `l ByY~`f Q/PΖ: "M`4Lkm6VxJ)lrlmtGJnGynjS \V3HST)ֺv"s} {l*yK'&[dfE͆ױe;CL0AU:rLٺU<вƕՒRxh >>`U%r#&az>4B@bzBʙ*eYdS|OOVu$85oRȆ*4Iيξ1~)'%];[#1?!(k]֎_jIbJ[-:jI]?) l=➝ h:kUЫ?ԩ1DMU :•gf`^y-mT_@W-xm} &emJ vY!,mR>KJ΂˚>AZxTYKJh76YB#6?k {glkWHV {ؾβ4F$ZHpYb[Yl #ʳ+p]98Bsԧ^pY)Lx+HΑ^9SY hZi”Vg ƃ';#ز6-lzu9(hFBv&,JM+,XMU8O'`< fm,@ֺ[Bbd &kJ gN`>@J>`&R*tV2kγ֍CАF|#(^hmMЉzɉ߱aq+뷈imYI&UkPK2ڭ9`(0HZ"%y%Pn+imtڣlKdp%l|ll lje &V 37 sYw1CJi+2!cӼ9j(sWmmC >_.rvڷյ>* tR"ccLi; x͇z) + ֥ZXjZ0imp,2>@̼0 0,0 cfb MwBi0CJٶ)2+m* KƖFt3K G֡u!Hl%62eE$&lV~)zR* VWR?gn|sڶp%D$. Wa~Y"&&ԱT4Wd ̶֭+$4#١lcjJ ߄@$7C,Ɩ C#p>z:ݳRbcKYRJI.-:A go Pbtof++ȤD)$Rș c=q~l$gQIT%EC:ں=R`|c(DʄRsڮP Vab @Y#&If-+bDZmK*$M˹46*J6+-X 5+[&==ơ-9VaJ]VEdV)κ49-:& yJBYw[󬪎d #sj]yTeIL?@H#"zmߑ0ZV| 1#[G ͓y|9H@n)[ݑdѹvcٷ l4%d&O+A5G@-z:)8';J 7ʜXdRHn*u9"fP,y 2g%[ 5ZS:VN5Ya(1a<1؊iZtJ}FҖ2mcmpk*Eٵ0({\B2PJ;p[kLBg!9HQ<.-_r UCnL0ELkz9mb\ z1 x`̠O@c<ǝWUd9bYukü 2fFvRV S`TYY'+ R=nK%tLVޖ `K&ESw@]G< RʍVY|lb)րIuH} )>V|xMX&ǗRt|*OƄCL)LOGIZ1UoMLMe &y"x# CCSe}Z{bAZ[}&@O,[|xO0SVVt:)D'-V"1&cŖ X%@i;MzL)e4mchVg8++2L  5-@٣8t$RmU)ƈ5eг3KLVR ua2 Lke%c{%G37Rkl/2!njaYC:vJkA^UY+l([G+ +D0sM)먶gj1U`?s4bxFj[rʁE.^6[};F@%k _ Nf˧וUwm>Ȕa>n^)OpLj > W7iI_IlZ'k.{. ;mcHkz&"es "٬4tl<ЫWn}9 FI3oWIMت0h00}y=+0Z%ä~A)jiۅ؎#B€TLI2SĶr[sS <rfs cJ8C%VGL>jMBZ<ǪhaA HGG7Ӷl]`Mި0J՟l55sH3ώi<%%n&º;Û>O% H1TĭḤWXw[J ? 1!3!AWќejMV*#+u(Vjr19+[ /;FU#B&o]4d9VF`bᶉ9PcWϟfM*pK"_6j#h* ӗJ}@dEz{2ʦo5LϴOj\ԶMPU*SJYY)Q+HfK\6+<0r@Њ!(╈dFTku4m"sbع:E J)[cm0SHiR`9P  YnP H#R}3X W Ϫ's &hR0!n e$i x+!kA/[c2o0LEn9PT R xde%ƤLR"ޕrԚaOV*F^ؾޖF4`B J 86,0b*7ɱ~#e.(4C01ƀ1*+`+M5L%d0@v>_l,^]@j`KL\Ԩ-=iʖ?_z!S6gB&\sgA6ؖXI[[8,&[_ sG dj )ٔRK/%`RdM.m7@waMem%nڮ1@VRj'؛,FI7ӝmYv%ZU(拉pHPS[ȡQoI$jUOܓ0d(H0{pU̖ZJV[U?ت.O2pYF(oS(mdFu o/V/B+*TU YDD"f{X&ɤvdYYXT'꣧)(ɛ?\#Sm5ebk*H 2r287Ik3T"`![ʖnkp sxT5f Clj1]Rk&ہiHekjDfb"gҶ^L;ƿ.}wV (4 T+IFƊ/Ŝj+d7Y$vs*MdƣH"Md1ORV[#X:/p>sJ1p бl=۞pF B;&N;qM+( 2JR&UaX#BkbU}CP! jaqgnlfaE>ƾ}WdxYUPhYDSLp4y4 emwEWq۞]:VpՖ"&7Qն.=5aa\Uy 1sY+Hd]A4*L𼦜^q$úЯ)d<I R5Ku|kĶ3Cj+<}?SLmUeIm'ce"Բu?d E/*z⬰aB  Ht]7*o0g[Rߍatl 8($^ Ϲ2l s d;phYIE:_kXHm;s̗ Y=X +fB(mվܐ洽16L /ΑD`2:]B[7M`E¶ws^Ue`T0rnLZ5rd@Ћz0̕x`kHYrN纔}[:G YR\X.VQ s\0-P2+Ab Z2| Ho#?"BN*[f_zn.0 nJXu 0>,*ɰFFV2cj\m Ze1"TL]B2*Ԏ#*ݘq~FBbr ~}TmUIEdSy!. j݉UNֲ0ekZ@ /xxwò0Y@&XwuQB,ObG%#EgԪd1 6azU͆ j1 C5!v9@cFpΕT^l6[k`yيњ0FJ_Υd"ym+I2*jP?w sv3DOʭUYS rHv=^UYͣDH>)0RdZ BF vhRF i`Al5 h0  WXUV|NaV$w%6mU>r-%䔉wR²d0 i+';#m$@4Z`dޖ\]Fx;LT=5#W s[-(e)sH?`#W P3IF`V5N dU -LS BIΕHa-9ʽM44uoSZnw*$=,_MWJIzmg3똶Rnhнfes5)dkgͿ*[|20zYL lgdMb [xZE T3ئgȁxUk`>}qz ^| Ơ$UY^`DL8+r+-[ff5nt0A4"'͊b |.6Qieos}K&#D#zJmHX;+Ǹ M%ʉ_jYp֕&? &@+>myVl)XeknC3u>5߁# bC tYy,klpp%|l{aќUEIfcU?:2d!Iy*' Oc&lI|{8c8 UmsR͐- (-}{CF5q"E-4JMc&ʎZ-0~ ogVsoj[ě"JCoH洕C}oFeIJ S;[kM&ǫ'W(tF) R Cya`%”MX-C +LO [[̓"S34{u#aJЪDoxXΊR[- <YW{ĵd Fd"Kե< .lYU8BY"4p4ֺH.C(mXz)nC|"F-^p/F7F;2sn[ eD iy&iLcت)ruY<2<'f{^Q70=8Jں*!E6dd U!p+u sYWh1Rak,n$ m ~đdjHQ"blM 8EJ*1ckU4H2jOيTq ]ZG̰KCd*(]B<%J+T!f埭)fleiXيjRjd(;obs‘6beyIe^.llT%ӞUC@dU R>p#msk `4ZIaFWxe]@oaBm ByRd-g B0hT@LP.&3U ĕK+ lLV yn<)k]mVw۾)M-̖l!1 xVE͟nV֪TGjT_-e])g̫!h rDIal6ƚ 3iZGhJUHĪdaA#yOY_z1ցmdܚpY|Z *,)חy^ O#ު괹U̥8gd*+quC3bpJV#ϫya9 {;mnJ*'lld5Ĉ%0a8gdTɘl >e<9T۝ph񍗦[YDp }5Cb|%Z3i%%(i 7j' bζxXt"^b=R$x݈#`NX'>YR"C2MmE[>jiBʛDg1e1"[@V WaZ梻eA 7*|% ZmSѿ&ML"Ө-~Gy1zP:"[8AY/p"Aa jm> ώ)cۜm`@Vĕ|\lu'||^0~[ȍ_߭ [/6Q $Z&s Xd[R̀5C)mN@bv ,gbԨ>s[+-rsz<2 &ZPJ`QgIߪ.0ݘ&xjg4V70|04@ϲQ;X 2+ ȢQapY V݆-5NXNUWP fȷH dg~_ 3]3 9W-le;)EU**hLlץB2QS+LTmxatbH0deͰ)ĕ(iERضbdu)w^2xܶ7dGضbpLgw- VHwܚ /rm벎UǩTEHVkXmvj(VNД=e/DM#&;C)|iV+EJR Vql$EURYjM [i;+x)VQߎ8:ZMn?ҍdU(#p5%5^U xJA9Aݑ Wb++@;/+3lՎ/603e.k[(AdڹD]pΉ5T'S`9׈^7T"k6'Fpk(jcيzKWn~H)*dmΕm3HV9EidE`Nk'mZ_BJ<>'ֶ.UP"@nH٪r ~LUR>?­RBoku4%/-6m&RaM#yZdmgVGX],E#dE3D6d)JjD[JlK&*?Y2pi0MH3U4pyԝ{wQ tln hdP§m  hAi퀶lZ1SG} [al5͍[՟ 35q%|l<K~#Cz+$  ]eR!ܴ[)TفJ Vi$+FSO mi溼CϿKC2~gNl~lB ,A"U* ֜zdg>JTc:O+>iVEmrmtoB)|*|׹QªJ5m]Ȅmz& v\|]b zL6 |N4w].xYg3IryYL,N$Klw(okL adj!E.Ayc`da!U 8*Y%g ȳ4cL֯ CׅC#1 )ې<94;r50BbXUkm~)*7jeZ(;E7UpPBUs~8ºEmHVe;]#uRRekg%No*;}KP#X'k<d:ҨjQlZ_&̜fO^|HQs92ٺd^Sg&NA$Rj_sG He?vyck0A<`-J}v0U)l,lNc$&}>r}J5rUzUkU%Չ\&wcHx ʪ@k`"l ioư32)@*ƔJu"]j4 ۻJO9 &+ e ) 4Vy%pA,Db2^[/INlU0 TtG/-(ܑ]Ws vc+qsLe d0L`6@McB'By$٫Eӗ81[g նx+RIMrpp&+H%VTfHGUsZ4z12zel-tִX5Xl7rL/>Mm@JIkb2MB0JYV54H%uǻ;6s$Y+YbV?&R90*,=`h0$ u'.>FF I$1O FVTms*̲4}Đ0`$|5߅P* e s~[h( )VUT+ɁvJXYE퐂R4Oli*/-O{R)g K9KP:[0TU0dWM(b`47yx%jVSKl 6Y &%&%#bh$ʲQdR^3CbTuJ$M" ER H9#׿e, `RWuz5HhlƂpbeRHV0I@mMTRJ+ϭdki9yJ㭜;˜"dm*iyUF#LdM;x^z2ݻ SSOU%2OF9HekNz)*Rն*daԴH1^R_&5F`<68#g>RI0Vw $+k(G(uǤ*l)hipP%jgb%j|åSZ1??7U;W&&LL`}s.4EmCc1#%h:m}YOlh)8H"gm&H V/aʪ*lI0Ag8ΖmRv11*RJU {WÄ&fP4ZϢl*[< 9` |[0Y [bn|rpE+[fۄxѭQ݉9l}e|jai "{yרiz@p49v"ۆP UH òmdYшz5x@T S6L#Bo;Wuc}Ymh >n9ȶRLb{\_Js?dkyT)A6m`b4~>>u@gVv_|j&&kd0&=s }gb&JD40b4fi4#{.FX0&Ǹ۹5Y Yy2+9`.A*˶6 H+a]G,h]ŭ;UI1(6 4IkԈ#1*ǛGv63#TY0zs $KY%%CV”6ju * 0Z8l_H Jlᮽ3UbOE/VNIZ[R5%#Pn& QXغ4ì '`%ylŲM%`u7' +d!ԜEb<v-: +Fɳly"ҊlK.[#cNIy@/ sb`rd\*ZRUw-Z+r'[Ua U X&!% _nT&xjϚ 2 |ghh͊wBXʪ}̸Uˊ14jXmOM(ڎg.8jzjuJm+Qɲ͡bUBi@6XJUn. )0rQwk_XIZ5XU+4 (7^4{^o 4k6u$mHx zqOmga&(u3Ͽ*bLhЭ7RMmJ}kmDԨaAɰim## 0@砝}`p>0,Y&-ڒ |Tb6ƶJi*L"ʉ69%-J0Yena((OVU|hP JL)JY$kʥVUwL9ldBNۨa&[M2l'˪%n]ldZiHm+dI'xX{`B*sX!^Jy-E/0:^9.V)d `Y@4u׫g'%D eQyp[z4WU!qٖ MXBoR Z+/*VK Ĺ;F&lzuĈq}Twɬåx)P,,Kc*Yи΂JY's2@6%H[2GVð0Oo5+LF?C3_=R 4plM bP֊){W1haӦ'nG(#is$k+d2_ɐa3)@j1`$s6K^[m; ?ը'j]پR=RJ9rp®8sndA#`Yb6 s<$;V 3֚`wtj}1 s3cVΰ3v.euG0WŇ5?jWc%Prt2U%_IVB [I3X0^E&¹VPG_zb_RumN*#l͟˱HiJ*cKe؉F 1i$M]VR4R; ̓, bmd^;A/I[l-M+ɖR+eۄx^mȺKaqB圝Y0])Eolm ivHor˜9k_Ɏ,N30[[tWUCEU/4BR&6-HC *1F"@ )&cw'4UU)kZ(@b-`jJ, C .IrirMll%?̡}k3X@)X{t)`[kg hz@z4z@a[2şQ]VvuT3ReoPFNg+/+J{j*+C_0%}|̝BjAw`.:ZL/+n4Ad~%LCX X074UWP>  a%mn7s>/ +5j*|,V+rn0+8+0?(]͜_& 9GƐ ɱEȹHЪZEèjZU!mxbI=ߍi-Ha%|:{l6%BCJ٪2Ɗ/k-"1gUS9K6': cl9ךX.#_y>\.Vxim}:izdgHf΁XRpWC0YRv!^0%ZL;!뫃@-Uk*[_/L 6C"eO mw)h $0RI2ԱdWh6gr[XߔP/.A`FRRUewc%BzX!,Җj1B!~^QB&|UZ6Ne*^ jlz+/U B YHL|0HQ_RE*聾10&^#L\UR[@ `0Y]*# eET"[}km͹^Zi# $}%; BFr)/>}b8%jR3M1 Fkn>̅mL۔ ބf\3"y jNBgLI[׊L!V52djM4)6NG)`M,kcB%*Xl|4Ȕ'&'fbe륤4sَ}`"zR@~ ^ê9hjq9Pk)<,:Vƶ D>IsxX(7@a ފϗc\A*Ǒ-2qVb(1BjK4Z 0L#2qaJ)HTѐlrJd|'nɍ^H!7l0CF4)V֫:K8UYDwlut"2*l0[=7j1 VI3T%`'V P%d!#14RƐ3&kTUnR z:{5V( #ns|4ɔcRKLj݀"C=Cd7v@U叉ЖgX.NC EGP zeE,١؞i+{(~(*aHcBAlKIhu?Ti|B\ >,5 [RV%f!qZL'Bfw"kHY[V,T1ȴ.M*q@ PXmݧ!КI 1LR֞;^yA꒧x@ mEcЈNWpAS&¯cn}E\ 0mV `LV+墔2 @c J&Ax:=٫!N !kN+$6[4=VLs8s <ɘxm0- TQ{$YcN &eFhEY=FInidce۸VWE-0*p;B>l"ui[z)sYB&k'c.L:VN]+'O8+`(7F(Q+e–y0&,W%Ӊ7qȔR\XmH p,s+ @ V]I|X{qeIKQ-\;؊obfh B_6r<N1 r. Y6 S6Ҫخy0 PqQ٦2$\I>9 J\#ءŸ^o%B+9BUOd:x(7CWӶ{kfvք0*d ַ915%N̹F`]XO9+HU#:պ 1W O)Vc{H.V) gm:R!lo3нN]-oPJgh 4'v-FPh-vZA ~HFX 9Z%wޙ' bL:c<2 b|~6FSYm z|0ecH2: [3c&5eK6j\H L%6t o*m5R yn dVMbS.@𮢦˄eg##~`U.>@7iV9JNPV/k#UeM$k#&4*+2!#\.4V[EPL*OKᰣgAPJ ({)V/Mχ%p5^Hi;lB'[} ;bdĶ'WVu?՗,T4H)l[zAT )EUPݕ9.q9՚uХ|˲Y%oeżfEnvLz")J6-]l5*!$BYwE`> [d'ɶBJF%{ WN'UIĶb=#G+` EfC#([D-<*[FoАV^V,0v_9&R0i lKY9+/1 4'RRH2ŶZ]F4nem b2%-sUh^y)ĦԎj/MƳ 4G]qM#0 JUs}XIVY)^Kz|d|x]"AbLJ>#5ƴUz& )(}1(Cɨtbz^ƑpYJ>m߮10e; խv\ПߏPqdr4w!WMX'C؜:bz`&"Ћ@GBd 0 %@t6wh0d}{R;>>YYh,|T)#Sf%;R*ah酵 [ 0֮qdxn=ls9 ]Og 'J3)52I0%)v XLxפSP,h"d ;6ě%p|k䉯%dr1z#D&DG|1ki#QgхRpJ\;RU3g(Z鳛UДȾl8WB 8jt4.h$] mXp-Ac%LrpCQi~0Fr܍ç6 e)rjo.,7ƈ)4w&ڰ}ly;P+\xJȘiHx@㽯c)c3A:ҋ i9PO* ^]zɶ?Vw`Q ๹ + e 4}p, tnJ1:)$֢\{"e )51R5")Oz@Db`zs#Aʑ"7C_vd퓲ê9[S1;¢Oz9g`%_A;~'1adYi%Sd>>@a-?NDH. [̷RU/c =@#q) r5Ӝ-O{ zx|g/o|@X02^έ}檉>#f˙PT kqe%| eKCG;69lsGKn hج|`t@v 3)r#8rNSz5^O6*azj|;HblR)}jŜy#Ԏb0.VF*zDޯqJX/tx#6L-/F#=r0Pʳq}Ød2,qDFbئ5斉wD-UjMa) ڧPڧdro<|hF]Vr3ւWMWb'P#ޗc% ۹双D3L}l usf\eb& W$Ej2zw|l%ҷ0 Z'~7i,&@^]í &CvTjbd%1]^s`ŷPȔ.f:Yy98H,#pTw&W%P jy?9˦+ue"w oMF4leXIV/r@UX^Kc%]TsovsJ-0 ciG]&P5>)Rjn db#[LU#@2(]v##vJYoQFr`ۑ@ozcVdD%h7LVSn4>R%5:^eL$>qMN1XheຶOݿu߁)՞#nh`%h:|#`KVuDҫ Y >v&QEF\/nO9Rab A8 s/)wLȾ r/}}X4FJ]͢ rhb>A)a%@4n"kgjVon4`h.7Lw,wCLjHm7V]t-z1wn|U UߢԈdA*v-d!Lg52g.51~I(j&,ݥ}Sz؈mv>3.`Wvlx,jhj@X ~kÊhl>Ǧ 'PGX $<0OX֕#Z١=^heQ)t%˷2U M1<ߴfd~p|zVhkU3!䨫U'Óf&Ɠ> /&ph>A-=L{;ٔz9[idU|>07Y_1eL hUQvM)d2q,('Vgc%L}>y 䢋3hṶxsB׎ϪMHL&N֞ 9*9D=> (1@ӽEZ?{teD6$Kd!<1L0•a)Wkev.X(4o?'<(X Hx 6FuQ6}~{S,hx9;MlO&}7t5+ۉ!pjw" >-0eVL OSu=?;4d5$+dzLJaoBU#E/S&dkFaR VϐOVr-r@tC pDUSd]7^Ux#(wǶ)Zvc%qA0 ުhZRjMKMOq5B׷L>[>_)5_hjo.Ǚ;btaX3WG/ctJrFTÄk,ĭwl=/рӳ_4L {#^`eh J' H9FҤF#;.7WC4nܻ̕|^oWihkؤ) f!ykml\v$F52Yw[ÿjL 1O%G@#rCHlJ>u`Ί+b%z}]0PQS5`@㏁L9"#*e9ϳ݁&^RΎ -߭4Vx7UIx:$Ư{[^p$ȍ옏E]h8=~?]F@{4 ^ J?ʜ<ӸA aѸ@2"ZҬHl-Ug55ʻyZɲ5KQd]1)B{VR2)z{c溊GZĪ D0&v O/11L zO/^XLd"Y(ahb X6'P ӟ7o.Y ^#gmgs?9ր{>@O 87rhg뭅ƪ)_[%v:v]H &Fy' )h2JZwl^ C&t?z18eh|ەm9 @,珱X4=>Y½侢4{"ֆ(hr6? 3BêJ[&sJ{  HЛ8ݱ+L͕T1_yO)dHGY^cV"= 쨴.Vx2da kەZ{n -V2F:2(0BIc#kYѬzU12MR]?)֨n+bwIL#:ҴZrVHI#g} ۺFWA+g>4 ځ@ lʱ8|u7 ۖ/WM&+Lek$s[UÈ'#n+n툭ݛ.Yr|~(ud[MpHhyxJ9QrsaS,k [Æ?K!8Tٱ̜IdJHGbc\kF @p(k"@bMP^f~m?M/wO}]f>\5nY3BVm-$PJc99nJ=hJg% < H`=auEsjar&gSGBicV|,x7Uc|1p]YgĨvgA`Z±`0l{Q6kk%dFgQixV.!VՎ!,k}\F sAśpCaVJ@dp+E=~kO_>[7ߪm2@O=~ȮA @LtdhdUZ%L w x[ndHX& ]͛DL~[V̧>MlA7ṀY/ɴg)"uKO=̑ bHC(ؾ#⻋^GU^Yckdn#wiV~-e5+@M-,L+eJhi1XI+aG ~"TH 2,ŌQ&kcJLޜ3V<}|+cblۭn^8J޿!LkR^R> 1& Cj3$`RN!3+E^#hO+Y n2. H(jއ 6KMծk8uvp }4FWܴXEx>- XޔĪ.%D#+ _K# 1@ԎMLip@#'),4d i[G%Hi7{qv +UYIVrV1j\-&+HhOH^>MVڙ4?h e 7! _-Ap%wVJsŏ@+͟8s&sݎm!vMc##qX.pjqJ2D;̊784}/5&H;-o0~X1lgG&0rkT'JG|ШM!`2 hD LAϪY4vUҢT6z#ӌw$ \X䐠 ș#jE.A0yҏI,JH^`|FhT}7KcѾ)ݭQ^-vJ#Ebp$S"p- ;`nYp/'BOwZZ49^G`,QZD@4> U#w)lE>znAݦ,ӛ.{&P3C M%`;Tm!>=qwTE L[>}(7 n LБ@mDM'& T(fk[wLH,^JGYE& gšUen7ZhU7阏 HUG2L҇ Je˗WaylqQjOا[5q-ώU3OSH!U"9MWr~!`Z,ĕ8VUqd}.10ߪέ^Ca0@D1-BIO77U.-\)8}V0̱Yp)Q7]Aφ1z'MN mh܄rvZzG@?a#h2+a a%LYV O-r@eZ㽋%避_ztlRt$A%j.#׫q EiNC'4d)yD@&8 2@Z1=Uc $an@]d=8)R.y׉)gH S@n}]peJ^/ֆ* lÜ ^88 0Fq3Rz3+x|Ac!*7VsӢ}2Jx ê&ҳ2+pkfɂ,Zj1J-}XHAFj$fz8^?RԞh&d.v9R&86fO]YIc<ɲ0=&LJϬb5[/Y 44"I!Fg46(vMXhxJ0C-}fM77q"8Y}%UCb~-h'n2Xt"hȮgĀRYEt~E1eo뾎ZR< 9ígl4"2]mRڳhUax eL_e%]dL0r.7NnyWGDj"5cdH2lݨ=6Rg-7hD:2ǮwPܔ67sǭc;󌯥v gp42ٛͥin=ע 1܈u6Gh%}6UΎz=`/r&J9gVp"ȓI-h$OwPѳ5*2A%fqjSevD]4Q2U~Fo58Dd>fu#J/c;3O8M3!'8?Y6t;{(tlZ֏$fhLȎ~ U)iRS7T"hhJ2`JL bG%BF^4ڇM)+|t+wH(8H묷4J4FCogU`>K/lT U4L2At̟+L$MI:BHyNΆJاx( Zo?R_( n))p&sc`0" sY⪍}1-C73@2gc/PՂ!kUhɤA)eGbw`>Mbx{Lo]t4z7]N;ʐC]铅U[ ||*dHV52Il"*_?⦨*+!c㨽Ut)_>}%Jnyfԕ9FOPLz߫܌ nuNvArJ-/[p`d9EjĴcz ,23S|RmXCY,q (XPLswj!_/~qI>~sF϶ s%r dь4uz0Rps3A/.ƑR) p7QG cC Ad LTдsfѨB~l(h Vz̙LnT5v#L nyǾ@{ U-$(cj#bB{$(d88z=^ɪ6pF eǪfV Ώ8i[y<ojnFcY!==0ZiƍhAο# nFA73~5V5- TC(^Fl.Ji&!,`yQ9ޫ=uSdMq4rFGc$nJGX$\u|F|&AbmNh@yĴ@HA{"Uc>s&lPajɺH }lLA# Lle{I- sX#^0L9I@2 c5* G[[foZ ϲ.a\K ̳fۛ[Fcz}L#[r#,߱ﰪhh4}|R-J`ۇ@;yoYG]BKRp})^,b@EfϦHyȖ ^<$[Ǎ̳Ddzp#BcЩoSݰƗp=cBW[žF&;g˪4aLdV6mUgUU<xwLY T\1Po,b2 "gG@ (|䦨z  @.4b˙k-FwnAGp⓲e*EG@  q {_h`dMAWY8hUɆxeol%!s@6! +u HiZD.r:kG)=4*^g,y$1j{&Y -#R#}OZ8+&U_f!eϦT;6dVz3IJ@;b`bXcb`=>ĵ8 Jjn&#*M!&dxRk;MQ߫ ZD5Lu=d%˓a@ 1gq Hz%# 땍7HNasiᆦd.c}eqaw -ИHJHG B5+`(JHD?#ToI)U JΤ`bm2 #vnp2bfwLMGi<+,H-wA^59)$[ː!uLѮtԫ$4y:j.9șg2g-&bHz_{i4^#&PU3oDI.am*1o Ng>wT*,|t5K# 4Fj)ڧqmO/70r&J|dцU1$U%t-H +Wrlz$;|duVeU2GT"mc 4G@0\tl@fcC6m M[2qt/鬼6"8(qh [*eMq-3:& PudE,1tko$dž5R| nWhD`W&vY8>&Gz]5jiF IK4dnW=UJ}^mh^U'}-JU3RL>1ͪ Ԫr2U-UJ VTƠJf-z%i5b-q l=BjsJ#cda. +^l}"({bT%xaެď(Pd%S ™IzV6)mQ7#R1gE>|^2&% k1MdSnvμF\~jw! %٭j ,BI֛%5: |5Rv'[VרFbR"3}rVUm 5ow!djGi5e]hs-d* kigzwx"ae*5snx+asJ.U՞a>|䆦 M`sxFe8˞ðdcׂ'Χ T #rS2 +]A0lٶ0lv#wdnYxF0!֥y'x^jߠF UjrO={ĘA/- G";FiC5HY`ڇj"F6#`+x)GZ8=@!q$=٢$o#؛L3Ҕܴ≅ƾTE)p&r/@ˆ4SQ#gIֽ4♐@z;伳PbT]) 9g5XM4R'3p+g6hv}J±破/.HÖv"RFPm4xHz&dA9eNY;Ush[R@k'.xV=HZȘ]љ $tu7FcօkG|`눬 i&uM2.ö>uyn͐>A>E$疡ޢAe<秥1L;bS"[C Lhk`.ʋSUʜ#lYA_4.& 0@&^^Gr?,0qI664n,!(E;ˎwO.,>I#`#7&##?LІJ0f1"ew`L;SWňzpV>drPlb"[>d<98aQzSc!Sm)[tLdoR֕Vˎ)âv۪bxLmUAQ7%`:&' 49Ȣ0zJv#nLem$<3><cl[ N2C?P-aB/e> "dl8Irv0 H`0Lj$U>~!H)gLTGЫJZ#xoxzX&#Z G-ZR)8k҆i>H2e|>)죌i~]"9 zHz$LĎd 0>![RE蔉4Bˠ=Y~?ZZ! U(lISZJ]A.(y2ym!On$0+i8/+{V)߇u$n%P2?O5q2Ĕ`EgxJ%PNJ/ `[D:e:9Dʭ&"2@F YYn9q7p>r 'S229 Y211H}]2L>d-9#X/v+ovV&ȇ lOƑxUu1l<@}Z582^8ї2A#+a.Oϥʧ.U%XgQ.R5g7}X9cy:2W%D ŘF:efFU#+hq,42TKL}Z80+L8v J]f5ԑH,Yc %J|Z.5-ӌ 󯤋lf1fE]=vP7ٗ{H>5̍4hD pnJ"QA9K?i|;kcѢI0X&6_XR;VԢ1I~'#2qH]r-(¤0^/Y?4a-c¬t&}-yVœA$g+9=IeWPB&Sip5- %g "(:}8o+2^f+A/*^s%˼Gt1K YIzU^ `,[8*UYka->4EN;wt%ђ ԏkgkإ4uQCdBޭ1)UdzZ#g#,jĐ##4zԻ!=sDx+U8 ˟'FVem%>B>4Q#%~ (ionSlsN%BI)]PQ#m ._9%Cy+: j9P|.nt]F1sk+ځZz[H Sn"`L),>2 *H;9VdVu"^G`% ()L:ʭJ1YJ8%^;~VI;z=># S ;4HZ2~ʿUlz#8PaV6p"&ʑsȰ%9Oc^)6q+M}ɪʦwm%J%Ԫ9x>d4ªJMN&fb:pj8.ߠ);Vhlhp8UQ[.  `& #+d@=jm 7HvkCo6s;<˻H| u$/ӋK&ґ>'V)3+ia߀H&HQu '32ZrQ S荑2B/R[ad~9qbW⍦dddJFX +-ǭ*K{-ui ^ޑrLz%t$r?G;8vw6#R/<ت#ɄF (-S-iXn1Uc΋bp͑8>4v4,҂$パ-,ˣ:7"[9d1^ya Z8X@VJfYJo'9yRwơ̇̄%וO) 2U$ɮxm>MoP]-WZ.\YB) AFKh"^c􎙔ۡ##.Ց>&kJL(^HdF\7+$žw6'N?9@I?[|<ױUj9Ȣ*4^f bLJ.JZ|?D"s&e|@3˥"gPYī kpF`T9ըKSCY͂$@‚F !Arz%02cz aMDO# M;ƇrwDdJy*{Z*Q:.p̝j[&Oc{zbўFhAnV07Z`?5!ܔ-L}&IBc.ТsnuB&O#zpȋːW+efnf%Hp>ޞ]PPIFozٸF]ȼ% *"}CM)DTmiD|9\@`\٥| Y 1P ^⛕Yиju^GXS1'Q5 sxa\FPScbD o|(<+3L>sΰ [(nFo@]twԔ2>r?m4F k<%yz)z=c/́."]I}X47~>p)k  J) rLv`]]Tcz79 5vŘY#h\A{v4ZRn:-\ڕ5"mkI pkcXc v|ς'OC2 h$P/k/>\ybΤOY  o]gh-=[(S,{|-5[cLJ^#\נo6Qč>~ LIϧjm{?' RLj?Ty\7~%[<,* 4\t$x̑FK>1zaLyz3 2@oF ]cFd>^VBxn* ؊F81DXXm=oh J?罇0O]WL+qa%Gv@F+t  _;ޑa>՞ cb C6ab34m"k40>^ǜJ?`+ lEKK%Y,\]!9 ?$v F [ `r@W#r%|C*Ʊp֋;2F㠬W.b$7Y+k7ԑO]dS*^zFL:}>r-۰4‘l0x%C|0]7ʈl5`DG>QM2z E1`U%VMR^ X ʎ}^12g7`H3>@1^UDjqdoܺFG|Fv$t '-qaK諎Ud@Jct?ZJ^U+L ct?d&G&b-l >)fqM`=aXVd%kttJ6b@+3؆i`@*>ZuzEϘI91L2l gVEεg)H G-Ek;63#LYҪf4ު.9vYR`Zf?`δfݪϠ- ?T1}me{ M `J(D0ze!۞JxL|Ȯ@ M`T10\pr" 2`%`ĺ`r[1m=7JcRI4"[5|jjdHHYu?B ^61LʅZ)gt4^H 8VH)25Wȹl2 ƾ6z]N0UaGdhsGκϰ/VbUcAW[ ovX썫F. y(7fVikZo`27цL)6B \|2LdB,4QV tõꂍ5&Jϊ5x0j駏ŀ 4~DFVS|kmYft~aLvQdd5&F@EM5$#+-x9[< .'DG_P&UKL+L?9@qb0O&&V͐UUg-UEdZ䪔bWnI2;T/r1pG8x|>ʽ!PW2wϨo 0'2,+ukod/ir&4]w$[nkt3)#)zW|~ޙUt*LUa}Źr[vdUuVWFU܊_u[eUUضuls:c aVbYvNOYɺ.  }Gx)l7 r}c:6Ֆ &z(XVi +@@%T esF ęKRp%V&4 FTeNDbĕZ"9+mKRUyiHyɇPiO/ek](< b,F4UƵa` L,odMURaw+|NI/[ }kGcm;Fej)تC? O/2ӬWgI@- k\a]>ynIrX7 vk^ Scl$SJl.L*`Um:9SeI YJdFQ(eUpWl>k c <&Ԃ!M[<@\L2EjAsQj)UѓHH44r?9(q|<`s4 d5h²40^w%j>`dfZJ.ְl)$&O% +tɓU,ʤwF6f}eC|>ʭdeCr L8AF oŧ_azJmjƳ*lCU!(K/1N, @V tV RS%5- W[ ^=r#a1f<43=[UE2$V!J)옫3ɡZ)}m ")[c@S4x嶲V?6 Aѕ]*b@J n<4W{ﶦMܳHsٲVR[ #h^ k>Jl4F(4h"L:֍>s +ۜ1% əR$d' 4 b,wVx-#cVC>͐*>&=A`rk$nZXOU/F!F-`@RmHf吕#W1m43Q |L(wF)%IjS20 ,?/FJ ;lVp]׳C!2fM! ?|VϏbF{6YJ&9'z?dBXŖ&@*ޡ.I g#[iTuiȆ̶TOu%V288,Hab Yl ^# U\s Y[g(;dHUC|0P mYWN VA9feyܽjޘNσ8}kـu@SManVem%ێq o*JlDS-R&Nv󫲵 pQٮW@Of>#eճ76,'S"lKBkkň rֆMp(,VTcӚJ$L(ߥuVRJjuRIH`mlc[;bF"ͤ9k4["q&z!7TQAUz|[+fhz7XZMsØVjp/*ַV(54gCYHD0ozp0l;]jWDN#XM%ުJVz]bnZk*RId^7C)e d. `B!307@aGhf[6r[)? CPV 4%orXkd2>!MbU+J@6pg}^ )Pa`+[t wE=ĺjK_'p8ØV8Af;l)$F!gR#Pk*Ⱥb`WHd45 ̪a4>K歯U eL]i]c#yfҪ֐VUP#UUO`RLh'ɘ,6&멄^ Ba9G$m y3VKN" {|4V"fnj3iH<-l __eԧ @-YH>/kR*son <~$/ MLXo[f+H [ѶpN(jbd>~HPO5GO 8Xm-z)Lz/CߴHT9Fh$8R )XJ-lꥊ򰛤HzU!' =1Qy)sÓC* ~}/v9jM FJ+CHgb Ԏ4n=w/G6nW!e+sNQ;J8Ev"JbzE*UJm2zO=Ⱥ4x ܤx2Y2w+jxa$VmeRR\MI3dVZN$V2BndW 34PK %V$ShqK=_URVN!ec2lJzVTaSYaB4L(u(hXy#LܨĔpVV;yVH1϶P*1e@`"c6I?Fl']A3oŇVkamwsȊ@4 0PXvAf9*/ v!44E64CV_R" -m2fj@j2zߪ@"uD]Go֝ N#l V$#΋FZ|A'n iwu|$xA6-]jhWTMB!FRc-laU"@ Oݑdma3EH-0e_1/^~*Up6L.R}}`RY9Xe,ZNlU!C2Ŀ|_c[Mnϳ#9ɲ0d+gNJ!U]& qhgQWZ9@ nFPtdyxP =,Vu۞mo%SS1g$F&"4 ,H>"\mjU5 [}ETFZSc6C"ss]fH14Z-ݡGMzZsn0OXIJڨBc܄m{*k[ Ҫ36a[)V5 PFUKׂ֜ՅҴ*UmfVUV)bec>+[*x~ >r͖ =#26[ɡ-@SPv+|WxOdui<-<ZB8+ [lӴjρ Veu*([1JlCA VAS͉_7YՎ^V#IVlx8mLL s$[QwITpjݏZ l :qcW=s|2≗WpJbZ_ZAR Yۆ[,U{i!lxP( dXSTJiZ| @/I/SL1SVKOx>ڽ J՝L//o Ȑ04y+[]o$FJ(YaJm [d8MilJ`!ֶl27xȤb\SH^H760H%FxL$}[%U@/(W¡-@#lcEr+ZmU .MEg3[Q|MU3=fIS>R&Mxz OPJ_@"7FGMXz22߸>d ˫k\a&rW+ҶIRJ)ꅁ۶7B3HE@-D&5R%k5d .(MB)4gS|wm|u`o7skeadn-5,̧b0sUISfK*@ێwoFdD@kCv Po k g>2Xۦ%RZHeS c"mri]U}K{)$QUZ mYa`Vd.@9l&E^mY[&ٻ֗RMC oeY!+֚oO#rz+,hI)+䃙mu:Z}>x&#ᒲ BwTcbT4LBdMC`?r>. tdb=$%rkμxn0[hKrk(k` +`d[c$N37VQG>=O<^SJaH[= +w~]|8GХR"dV[+cg)%6{PyLL2Yj[J*85qU@#0LoՋ:Jl= ШJx y*&iJܫO&RHUHk[0[^ [* h˝G.*LCӽiSs#C6y#TvHPV"78M"n6^j .VgcY&}T>a<l ck%#gPHuQ(d[ ֲ9/,,+KURjJF)~cl7I5 "xfSD֝kǤVrQGBJF/ #"R8;?1٬dY񈑢v&gͼ-9T^saj$NlfLW RA>@ F. b(*lB6TVuW"ѿdP#RȦ_aR+o͘Ssj$fyܿhb2%"Y!@&er7a}Ah֋ o @Ԏ5s M]j}KKb(u;+M`+ x[$N-i%OY 0xdzҽ4YhqM~~lWe)@/uvlonC*|*OwX 2]lwQ-Zۦ;E66N-=+ Wi7AʚbGSFlpZXmui*J<,@/h2; QF dRJU3wMxu5s^0VJh>Ҩ]'0.U_ɯGK,kH+NX,2]56Mz9yJu&ԅRS~s 獊l(̧B3C~93#x&b8#7*Fa.f^ @O#뢰5*`e}w5A_%0VJf0Y%݌yXJ`4e9̰ 4qvb3 R40> F&IUV[ަ2҄G5՜9"S|$Qm$Kʚ #sk$+gL9[Mku5 d\ ObkF$M6ʛY֫: @*& bI_?,ŇC>bH)tC^xXgG>GoV f #3 G)+<[{:cz|]`d7Y0^ vx#ИA ([I1r  &M'AzrZ2U)ڄH=8eRZh qpVV oF 4* mwKWOK5U߰v}@2/`++@*a+=}?U!ƨ2UJ[k YƖ F'h0YwRuj0YVZ(ɹ5D$hGYߍs2XjN[b";=jl+>&#s 4KL8Ԡ ~%v)j=xXy"VBx|5Un +ƃ)+ȪEgePdEbxcoG`0+S zR5RԷ,qZxQ/@ߑ`%hYa ^ϰ/F\# %}>ֆ1CL}#UQJARUleNbְrJIVk_Zm扭Rjm&R^;Қ?mOv]1-C+:xϮ9YM*3i+INL8 *k;9$^9-Mݼ5lvzcMh `ϺP ] +$cȿx[z#׷9VmG!HOtXc໮[Jr_,Vz/'1li=LG0Rnr%-m*a 5-=bkY*k6J>șKu|h*ܽ{';xcWB̭R^x5u9aրJV1f)RVR*Z4m8X'G[Xma8p]bDZ"{5 CQv{=a0jXmJ:];QG }k j1s fz@1d3Up3؎ L>| LϘ<ۚF<~?ߙ3~G 1`}w+Yzc.YcJg+g\R*j RtXLV!+)ab$\0g[^-[0 6RkQ|0Tb˪0"ACfr|~=Awi0YdM},ـEJFsCm@Jnȶ`569bX4$c)k z]9Z[)Al@{xL05s8cNr|ŰJ?r6VJb2qQn S Y xZɊa2`VRBF/y#Uv! ,U&&A*0Jz'ɧr+ʓYO!{ \dc+%1sXR~(i &8p'#ƳiBlY 0鳒-τSȵKMFj#WGjsn~F ɇ3X~EaJj[YS5+Bmov(4 9\Y1e /wvb2pXiVQ]6rVJ-YR㼦xb͜lAO8|%)UGEN0p%SsYd|+T0gzx _WFI&Vg;^Yu9+,$!U5l^x!W)sB6x Qʥl9્:U mZ c+`ܚpjYg7R[n)%Hc@Ht ]FN=y۩-V63~I0N5]+a%nĖmc|iұFR[jN+޴}қ#7.M c[RȀ.FJɧB=B%UuRoGd-NLM׫}OҫKȍ8I3DWy{ T":33ީ#Ypk#)ϤyT5ײZP%t?9ސzY*(la_9Z +ZQ8d@!\;ټ{'~n`b*ϡZYaB`(uuo|V0OkO4Nl*WjdRGXP><1޶vf,g47JDB[`l%'U(is M)0kZvKQVJְS;l#miauT}kkR];[bJ׷49bRo[&0F!AL$ n40A4i2FYS`CīHR9Fu0EqoRV㓛c6L[J߽5l[dZݶy(@@ /tV7;>q*!xL7Fo6 lx(G)ɭp?9a|k.; d ڄFJDK-2q9#Z1(>?'$~ 0Iy-h({|Ɛ&3 Ys #Ո~*ҚmϭIe}xB[3#Fʹia$˶6dRpavP%(&i:"iu!%ںLJ@0;[֚ކg`R+ \LHu+3Wع[kVH񩩔%NVh+ӏjGVSv?K5(U 2`` pk33ު7̲i4RcpEgxV۬"a1RBSH!73{1ˎWWL0ul[vHBJdn+UaWuxc<&rgdza`J)`kv8WԈ;3@@kV&MV@$SyAFx֨%âdH-^hW @,h[1-vbJ)aK-ǫJnKc|^- V5 S8&OV-LF&֖@0`> ?P4w]jC ׅϑwjgfX\G[!g4H)&MX4ְIJ1}bH ]-,Evςce*Y3!vR& 7i+gw̓)kjMp1 \ʶ{Pw1՟VڨL4}R Ȑ[O# +lK+ZqO֨W9\D1֯qKcŇc˔l@F%UIsz=v3 >R},d&dzmjgZζocX >+"@2JIH|~#>)Is>:ڊZxXyl[>)L\wlVs˶FRJl7TD[U&U0BL1Ecۯ}:5UfےY)u&K:B)!WNkv| Qjc r\[::V5M7'%옝ԶkJꥄrddLM_-Uз.i~IMz8xR~NHϧkd嬵lx%@ѹ00ys5mie<-jp|x꼬`YHaI[8]vEkרڟGF`Y۾v1x.R:i Yw2AX-M+V8eBRbL)d=0, kvUga%/U v̭K랙 dy 4c65ٜo9zZq`af2iUh0uIg)L` "F44R4M S9 dVO*Y[j L<>/%rUu!3!;! F 9تjh0RW >lΕ0I\&{ ɜ E2/C]$/wj @_pZ+J 1mUN@Sw*| m]d[ʖ(xٲO墪bhd+L #ad7 `BJC?mu<L͜~H,'0*(`4JhۅH1q^@r@bm Zu vdjØRxzlbC%2jea$Ñ^t¬+T"`xw_GVH 6[@/kLI? xMQc*z<}WO\[f:dpb[oL[e(VyHdVǔ%[I FUV% lHTodVȤHM*'Vw{2) 4.|27*,H [Wl+?T&W! a{ Ȥ*h:I3r.C.R&dʐXlyR4;19{^1 # IcׄL66~d[y 4pXM&K/fA3(!(1kY <˪jdab*#<I$a"rmq'Qj+lU%8(Ƌ籪ơcl(CRrk2v#Rڲ退WB#eEJG54kv͌%OЪ\ȮjL CN>+y8i۫Io aV dbcŖ,bL#~Renm{ueIrL@ p$\ i@"jP1 & yPG ØyvHIFU(]mJY LY"eŲ_lV\]ï'BX9 ʁή #+gDZ͆)({ o!y>P֧ub73+̺4:hr}f< "JMi"ҔNA$/|/ 3GvWz)`<3Z3V(1s[UQ/0n uS!4`dyalj[ʿ)h $­M% +2ga@UfCfn R;2Ul <;UU+PYl Z UV ⌬/R`l.L-!+h&4I ܃Ra>ÝecJ3U1=FHP_Z*/o&,4V$ 05q>46Ni +nH}@9 Vґe{9TbfĶBD6%Qa`R&QUG#܌;/F s!jNV-=OZdzu@xQ*dˁ!\0lJlHSU@`4I/0k/FN1[gi[2s.mڛUG-GBV _˝&,Z\gUD437,&sXar39 hiULJ46ٖ_jL0ֺ-n#'H%FY@a UR2lB>qȺ[W$t~BjˇUB9 ζxxRlL*y N4{l])̄+@VvjSup&sVΰ319bTޗvZeV j; m1 T87[UU!Bkh'Hs An6=J&jϲ6'PT۽aT9,j:Z)8TҪl7'|m1%{Ϝ D4ENK L@@c/^fQJY -ee- %a9Q PJә&lz%1v>̀6b&_LlBXDn_#I)}Ru&4Z|2F4C$X* qX$H1# +$U!vs Z#ma1m]`*?t=;zeB/092< ꕾZL۲qe#1<]kʹ.-`U!RZ tzTH ?ȚfH`/&A>&'83_S*O'Cхha&(E2a[m@=Y1Vܬsg JU C H0=ؑ;> ɻ"i< $#GzY.Z}Kl=\jy w(JHqкT}mĶ▞%4g"{»:Ja> O8mDŽ{rQ!fVd#$70$maV*r)VӶ [i,xbL ^ ]~qBQ`[$,h`nUKl@Ț'@Yw|7F[ 37m![ Px,TE[#[If0_3*Օں^BCCֲDn@ԲbTgjWE4 \䬝FŰJi4*] X#l@*e VnxUV8V/]Z[kEl1d0RB/r~\H4̓';mc5m0E]QJd?@{;L:cfR u_Qx!|V3wCJkOy'4lVP"F?,(H*/rx[@$U#*V#ae+KO r!ۿVF 4aʎ` H$㠼3kQr}}Gp&׮o{Ah݊Cp<xGmCZn@ f[;Vcd: 2bLO *Ր t2ݒד&^E2iCP k)exXt,JWGȐGLel"g+1V[< (mwRY?^58u {Fv4n4j4@U̥~L#x뾦/~OO6%79mU51Ƅĕyu8TU$=DV/Ux1.+[U0D'mз. !+|E)elkr+[^1 N5oZ*RmX! F`jsVuUG#1QrKiSv{^N[jX <}(۶Vɵpm=$+}2=2̜+DR`dos3G9˳ LNTۜB:mU-9WSnHo{߷BvịW}1jEDA 6OHvYbH,h0Y0z+\JlSv )*XwLbBҊH+^q [!|aYrV޶p)1`%nKgiaI&f.0^ BaT/*QN`?}lTr zxO#q%[[]MS'f_~Om xp&̤p[Ejmaa=k0ObzwYo;lkQdl+1+^VP"xƪЖҧ$9٨VǑu3Y#WXϐIi[HZujb-X8u'lYQe"ZIY̥]VV=0-2g[XJ*c0+{jMO&ZJ MH37dt$#(q _CfÐ,eFʇZ)??^k>j˪F{l1+ p>84Uξ+Qxx!a@`琀PN0R+T+NiZ&3?7(އ޽\IgKO7OS z=Ȝa&a"##j탣`sˀڭly0|*ٜ7ajI XlW0IœgcU' K$q.d vU!Z1VLp4ٚ  4 CVh2UYE֋ 7J?,P (K寖FէU XH0TV3 y0 Tv&*%LК Fv-VB|ws\W2 DIU`*̭0F)H K.'aϥʅ\#I p%Fe&sJݥ0, {}0zEV7^5UjH+ڀ.O^R0Mek+m5'ݕ#ҡ̕l+F~$ekmVؖ t @ *Zdcd9ٿ(3!Z ME߄<%ëUhDb;yhduiě  Yb*Q>紷<'alx@,^5{40યޜxZmҜjK5GԈ8>[|zO^]rJhT1 DZ܆ɜ9o%Fm[vo g"&d[{k;f+Lbeb `+ۑakz1;ZVw׏ 2[k7ó#ۦn^-5 @6S9 ²ڹr Sl]]9`2$SeA"/%i.- RX40)dE/ड[!:&p tUnRք+@ }dVߜNc*vȮ.x@jي4y+MJ~3e47βZ4\o[MJux2naw *06iZ+˓[J${iJ>ܴ!hhJ-,EZFVG`aȬ4֮ZJY &MinCl~қMϳ{3sV[dkXJXMbk]R/woGu@8[_v?PmkdZZ551kwgYe<}pgikm9PB@Z;HV&rxn i21QlלV),0R1]K^4)1ybV*pǼkIlZc;JtjzīRtLf0xX15Ik%|la&cEmdˮun1UY -DVhHo \#@ Of 'fnzkM3yz[uFkY@ hDlΈVx4<͓ls6Յ$Xa*2 [[ i] xbmSU# aoMJpg0!E%~*;Yn퉚m WCYQzYӰM` =bX5?1$pGtlxU}=ٴe1c*[!O[k-gj#ӝ<>J2'֥ -}&j ")i:?PH [`ڮV[lS4Z37LYႲ&puDv-1*>4RB)(;l +i emE$ 0v@N@_Zj-EL-:x?h ӑeXͽ+*ToŔBS! йdʁeb`m * $ >Z*D;)%f¹4-MΔ]|VH}VNR)_V%x30"%26Fa\iLI0 F f>@JRř>q`zV-4 `P(VJ_k 9 V*AJy%Kc-uV}(DZk=h"R&lW=49[oQ[32jSMY9r8Қ> unoY>)hM>VH*0Vi WJ^5 oZ ץ Vds"jrVf |J5}@7dzUԺ3:+0`4jnVxjwĔNJ0>ZdL kW0ifknAl l*4:8gu2|Rvpԅ޴HlsHYDVgLZ 6maUn@9 c <&&'IJM2B<Ç^lSo)S݀5CY&!-)D&lx6IJX\$6p| [s#Ҷ7 RQa@{D +>Y]1Xz}ZDo|6uc69l 4v[V',CxX.Hb )2h'`xUxʑߞD_$f#EHVN?гeEfMMk%k̭^Bx|f-qda]Vjk0Z5'<ҖX x7PZ E'MJt|Y>Ǒ'r[];ҷ )&VaԘJ%\$I,JH f7 նv d?eUFGn$=pkOܘ[&M2Q([!@dcVmOVn+hJ PZA RZ+į$MPTHUҖL֍yau #@7‘ `fRz)0FpʺaĬ&rh+ f)e[RL:^LeU lH/Զ T5 |TT)t<Jo=nVsH c` iFV~5I[kbJ2z_gG($Pox2ϠwV0^ֵrXLvǏ(͏\}A(iDU1C6pC@>O& ;,>ekZm"Ym^6z>6 h/U4p2s]T@>{#2# z-!MɄ3ISezH!1; U1d)Kܞ mUB ghzy2t5@m-reZTOHpVw0׫Tӑ`:^dO#q晘T #F ,tj+mrRUN3@-Y`KԂ 0yR|d÷Kel@PR[%Y->}_8T٧YV̆ 7[)Ayُk9ׂqi8C"WV[bH] +`{wz'mRxU:>``Ž4 fH̤,1-S'ԝZkz>p)pڥ0>G}r^%Ww̺'h9CX#UNj#I=KM*rall ɰZdɖAoӥHJ;jBR e+{ 5HĻv#=Im[9mx+H|[Օ|酤1gU"mst_VY`bz= 3 [6DHm_U+ea$uPp_ xxZSbRV)A*珁͟Ws) Sv [C>{LaVsW`+XTX1+tL4U'mH2_9eO-: hBd>Jb%udklm;2 4jr+FS܄PT^i+UHV<&a,R_X1|dCMS `@&0-`K` blr`+ofm2w |  EǩX ~d0[Yڑa L&Ϋ#4VU@ |:`Ue+i[c0<Ln{֔Z +#*l*shr*}CmK: C3a+֬l*/<3e+H5p&L#6YR '+%*L^J9d,ɴ!3`^#Se.g5LLfdYY1C9 e{jJDnĔX%̤.4ea@#mYsW<n dRSJE V"Vkdӈ`b6XTBwyfwoƐJyWhD*B5lceE%uT#'$ 4RkälLۜu̙cL+̹*JU}!z9+RZTK4$ĪZm4O-GT3{|xڮa]pɀl NwG׋UuMZaOwY*&g-iB:/PKfmϐ5e4J04jd-F4YK55692$Z0aX͓hjKSL1:C߳XӭO)HJa@fԈUbV/P!abJ)xsx֢D`RZkL9͐,lr>EdkV!#lUYͣP}$ܚ焚E=(~ lOfJ`1s.L$zE VkJ4UYl `-> Hv+΂mnJn 2匧@ b>x^9nɶG_fK_k{|s=V$9Z)-z l03E`$Vʫz)\H5p&"DsD mMaܔK-P*2mbJlV2b˟sY<[@IjfJaЏXW%|0ymo%Fض1mq"G U-U"(m CO J,7 (aJ`C֚FN3CSueIj1&F+ڒ-!LmabU&CcK.d UMUY*pi*UJJz7g=vvzK VĶ7R13^H @V*<CxUGK⩒%.A`YJ#IB9= g9,Ֆ?fJatZ̫ml*!JecnB|szEUZϬtRt$SWīaHokk aJa+iԚuQeNTs3+ k; S+b9ekd MTa3028 O#{h[S=3j[ۆY-T ,Jx$H*x}6'FU%A3*;Є5 b0anZ! } OFklZzMe<'-Fe 2lg9+ t0 akķaCs@(`'L}af GZmudLo" e%![\ןԶpcZ)~JM6 %PX`h_Ʒz*%jk q׫.deJƖ@9`bxǔb@Sw.$@],S_Ua*̭W q*!PnNah ^ ; )I@IDAT3$H)me`J[;a0;Q T3SF8%PUY+l"Adч٦ƶ*MIdh?o3dJ$HC&dmmU<{a|Ɗy3VxDS=/<`@`@[tW.\B<`ޥXݡ^0gJ|j'EJy2+. Cw #ٖΧ DSv.|fz^mpdi5gA [:RB\/@mXW#`%YVL\6-ۦ#msԚƃg@٬ :OV_UI&*<ŘJoLGLVx>ȐC%y`*MC>] RkTc%`>U U><̓m(K@iۓt3W{ 9Od U<`%h`j+T[90e!rf p!_yLgڮRPGXy %+OzY1Z$g!Cz5e%`zVAПd$=h"ea6@|=tRiV"m:6a ' Pb]o&4Y͡PX*4# _攋>58u|CT"ުB(kE~<9l-@ l÷[)p0InI`IQ9ڶ㫲8Yz.62U чHW?nّ1}P&6A_7J+`Z7P7I'gRGYVa;J3V"UεłaW"v()ɭpd duZ}X-^L$}<'i&<1ĝF<ˊ !) _UnxA6Wdb>LT":ԗ8eHP?UI99# )E jdM vRHl0m#g[>eV|4kBYLۺ(fMO&U6\-M,8^0 N mqhrY+2wscV%զ5^(Ab`@7t;NVAvx=YCSwVI4@"YI5";WOX6E!}%mi2;| 1UuW"|d΅?=n4Vq֑ hC߶3d;R;gB^oCըWV r_)Dl84}Iϊ*&`6j0V $̑BIr !afCێ F B#& mam%)5-nl䌑e\e Lëg/k & 4L6, l̇ 3]aWKra7v8vsd+u"^u,l>B>V 5 ZҖBنg)|R/$B+}[xHaʙ Y[# @6'xli" H4|Jե>Mt aXt4ZGy|sYEWjpEW;%g:YKleB_yؚCO\ڨmk9h8p( r٭%kx3 GVJzjxReuL(O"c&amw$˪H @#{-L5ɭolƳZFyjQ*K#M6JX&:uFx mnF6~jW Rj ̭U9m'sld`^]BaaVu->O 3H+ڕ* ,k4Ȯ^Z3jSp#3. 4fUo+, iJmֆU%0nvuJ P $"KEwl9y>#` Q"=ggǏ 7;!r&N3-e[Tk*$02n5A֜#L6 Յo 1x~@xyNןꧪ)o?5q!ɟ'tLXzYmSM:m<ڞP#"}1m9^՜.@APUljE'ʪ5 >R_r6)9]4Pa3j$͖ ^ b<%& oIaw.)ar&t$ȍBY%xZsQ2AJ0 L5JIUՋlqHl{//4R6j|+vUMH,63+k#={Q1p1h,Ev%^XS4^p\/2G5dC# [ekt')kĝV%}k? U?:VU!\L+$n < /}Z#,@` uӘNK5m7]xNLJ,7ֲ3:b 0h*ߑm,Ou)DuQd"7k>me4M@J!,d}mOtQ"X֖,5*YAk[hdeMOwj{h60JjZ+ VrciM*ˊZzY7+OK/"a!+l:bXiZLVTS #,݌*!?` 4s*<.oZis# nN <:Z_OWb9, ^=[<RsܻskiVF mN*oVb:ζBJQR # reHzk kx{*He15e1boT$DB㹘'Fi23IxjL4C7$%&VZX/+HRZTg0U;%l"0! ,kH%@>LƍmLJhoNrBareT5%3^ a) ;osȄ5ݱ~(29%$SfPxJYKߵps~+gW狫s}/O)2CŨ9N 07Iz+=tWhd*ёV.$&CX *v "Έ0*CIK=x;O̜ P AF1$C_}  5({7 >5c - hݛSx3!mr/aдb*Gn)0dUW4a(ML&,RPbq&@z! [3nBbҷ%D!RX`BY`Zb+gbT@Pb-Ə|l)1 avȾH=h[횿gYP ̫K[Y׎_ x[$pw^s ; A 1p3dU5[<&ϖ*pEJ:XS c˓9 TR|h0A)V_Fz}!VH^--@t_l dע#(kS6Нۺ&ƺ^a['h YCGzPVy@Xtb(+0V-= d})90*D!鑆vL F9Y!Y14J%%9P L^i?/2lB8o0@kg{.\mUVi`hU[N*Uc SN{P"I Ha0R #rYkoT5VNnNuŧI t٪&O*% U[*{Ly1 xVh+(ՊL0= ^^Y]'Rh+[ʭb  kZ@o6Z]Ln xlm_@#/20>$s <,&Uo [xSy1L5gpbڅ*WB<4x$Fi֚4M֙8C)xkUi7vRAA 9=Zp%XZYW;֗u{ -*uĶǺe%K[K';?G߫r9clwbqC Y[8ޕTm<Rܶ^ֶ>̓iHnk7$ 4lW]ܬ"}*a­-ATvEڊܪ0}y?A jU&HV9dXWK9r`<KJnL!p0F(2 HHZ@ V4 .0/ӷX 0U +F#g #%S X [b<"~xl>HnbJ 40%͐O<^n^u{lx&g|0KVY(7 ̜>SJ|/@%R?sa7@&搤G-A䆎QU&p@c&d#-X 1jeʧbRw٘[z[Q9Yn}Do3Q"|bN7#4T}]5^-lLRe;* gJW#:5M'@*La0ޟLb.s/ʲd0 jH4FOZ]V`$AƲt찶=1^[@ m)d`lRnu &*lՋ87hB})ζϯq:YE$m l єV]͸K뺺z|,=4Vo]2&qz7j/l~zuwi@thR6s#;WwP^ ƚ[ۮlj ψ08mr6O-"V N-G nV[nSKqT" [u( AdxN֎*/} ƠSam{)7ʃ"=Ȟ&|h=Jbb3im?;Cߟ>Ƚf[a*+hBSt(pRʮ@ eMgXJ}3;-$J Zgg) 8VlpuEB mpRVjwdbkjfhx̫GV¡ #\lL2 0U0R&9d1b7!F>pHZ9X) zc̑dLPa6,\-D6pkz0IE{jV})s`0Xwh$[L;E@ S5w t_Ry{,H[{dİOĭy~ą,ҳ~o[1 ?z3#Ȅ3A$v'ji0@C̟M™V [a@*%pnV# YVI&͓4•+ae%PbToM!&M@4Ra+5*T%lgLo,>=VF'J$beKYm%wRu&7k̈́pmٺ( ,DZX[͉."E>[ Ћxy3ȭh~8^s}]Ye`zZI֬N@)MI>k|zӲovJK5A 3'm+(|)Z`¹MU ?tWvpe,{F&YߜRFWv-a5!'&kY 1g@oKmU̖b9P G @Ä V%ה#27A}m닄n$,oa@ X $ `w_y:Zj*/\~?FDfVvukTi'PvZ_cw;ֆtn'۝]KN fѿB8eϤPPCte"_^o]  >io~#}G&bx%nwL}Y86ޱؾ! q]ïOG(vb))8b+2(Lm|&7;{l !5eZ O!C|^?&<,cY#UBPgiZ2- @%Ԁ jm_4ѐǩNFA8,S'2M,Ą<1bȤ=?f) ^k)]JV;6KS,(+klRjg cY. '+V9orƠ!%\S"LsH,y%h8dNMJFB%ZX2Yd:Z]j@s(FBXڎKhw ]8 :ΖTUu7>@JJfUm TRVd/˦tη&0R==̍n' 箞h_- ӯ#m `1cvuQBQï SY̑%)U*oT́ʋ)tQj-]4LJRbIH5D*DED#>2h"Uil٘t%`<)`5wjG9AY8H(׭#V/蘚 +n }{iȐh̹{ͣʲbV/-/iNg?GЄ;v6{XL oEۻ#rik[R@t@vN+< SB`xFűLPp,g&D {+E#a*Ⱥ4MB^hMB+z;0SX\q3wE4E3Rcav6nAoF 4^*^Uɧ~%ZG&1[q u}\`H][7۠=`) }avb?텀~0led@|zL}?oш_j plsHLBdvҾxRf{{ ԅOgΊQ/S|jt]Qێ mBlrhÄ{<ќW(Ȝ@[B\I0&Z|%Nl f Gclť)PJjn][xU[T[̋G->1XwM틙`iq!ECD\ K!x9*k%u$#ki)-}xO^|o7Ρ=hٖf XL tK)'\\!@R fqB{gU <dwb P̜?ߨ䢟(u)C5Bn1Y!1kZ D8Vrޒam.DUzγ,L+?Ó+e 'e!DP;w9)8 K ͜o q*!Bq1+l(8Gx.ɶw|ծl]FiS:M%޲ `>|lZw'vbb&h:6.e7S HpHބ|.b. [ DpFSe0}RvڷnvST4I#_egb0Fg8R=1۝!mmӲ ׽ a6&;μ#U"Ҍ,&K0m*9Co2;jZ]20|1κ_uOB5)ƗBDJA8ZHS ;MHL;%ޯ|G]I}k4ܮ>h᠔ע^OV6RB3_|Ajb˼N;y?ت ].YR6[ z"wfEF RL #!MM̀R!Xc^lSUOAR^-z#CmU&KIRL5К5o |XJоzptʫE(8LS?91ΜZUZn@6^)! o#f`U6-Cʁ1D= )e뒯3-~L3-`}dox]i6%v+thGfоА;Ymg"(@ozxT!)@VV?a]o~nOp2嵮i[/q#dxsBtai‘  G`*ށR] 2A)f"14sOFJÞkʜO0h hW Yg~Si}9kQNs؁G޲M%]/Y:Jυ8v +AFha,XY-J,AK~b1,!RIu;.RQs8n :jQ/c_4X?0شLi<w1۳lj+ı/ކ;~; ^Q.^Pc!#5cU nzCvPꎒM@6&h'1gbS (q;F_Ưj]ҽyq :|TY℠9ʁ(y~2 }LKǂ)pt;4-+~Eo6 5AzmBRFeN_Úb_|"Nbn+U$u*X54 8JeԺd `YnYȮ2^bZH/RpK{ &2䥚Fb%p8߲yj )irƳd5jK1qK^VaO)£,M΂i#m e; -؏vUm^8&0k(,h$qmy3(A}2b)B}[⊍4MGlR4}!L$> Qڂv4&ʹI,)s DLjniR&,A0#NH m D;D S+JϺ@O ^?shhj#)tt9"d7;IU`4r)LTKX*ϣYŌe Z&⇫+VXS?d^gMMe^1 /@^d;b^6f%̽ !u"̏Cow ЮW46TY _KQҁH[ #B 4KfID&h)fWg3L4_:*2h|Jڂ+k0d&[smƷ"hQSHqEd#CD7VV,ȅ`)63Ӵⓦ"A'^T24'ui",8^!O] jIUU. AebQvZ‹xhd ʺa*I&K)a&ć+g-, apڈl9B;@^};tmI @j\pwV币HT!hB;el\-!B01 )l-&>DI EDTqĺ,)ʉ+WKI^!_SkZ"*L1d6(Ahwh焦B~ 2]jGPHLY602IM'H [&tD}Ffp 1}띷îN)em$ATUyl_F_|s`6J|,3ؽ+Yu6$!-U1X;}.W}"ֿx3RiACTlmZdRrci.Bjl2}X.$1D0Ùd{V,D'"_ط)L Z('"h*Agw)d_Х}3X*D!_hg.B ;6Q08U@=;{w,ɹAD/FY5ݻ;s|<~jjj)+%P>mIDĹ2F5NDp ] {)?x?$nwahelՖԑBǮ?r,c%Jd~Ma:Z8iT3%hӁ/.$Mvn|J_`|Lx(*]X"N?}H"lYjxYD,ݥ Zvb@hbA}ti 10QuWäTik55Œּ ɨbFFlI B RwKV FS ^@ oR)¹`^lbXMˇ^ pL%Ьccq]  y>ȯ%&؈QЭKc@Oֱػ^RkfWoFY-(L^ A<++КݑzKM3oZ)]Tձ,~j*)TiNa:pb~8#ބe5Ez 1$̩A1#7N4rYmiK .fd ZH[J )pp:w*gw]vHDw*K&_@D#87K41"Wѹ8uھvH~H>R`RrGaydZJjV ycdS_: #o ãml:K 0bG6p,>wo;4u׎ץy([RScXv@&C(hf'ӆ7ex`^G^t4UeلJ\hZjyKfٶ`]1XUK1.C W`VRkȂ:np"% ]Aڅ/^0b6\fl3T ;dd:]Y2ӳjQ\,.S?{ nTb (;ߎw2)Dpn/$2t KXpW3 v9YCBd] bGn߷X^zPV.lgM KG' ݅6[c\Oj+Gi r &DV_Vq/)oeꝘ/kyf&uRJB1^-5*[_AXOOJ,kF_lI=6%- fp?GG)"],%ki#q)߄j#_;k. i o@rR|FpNҭf*wש%[vIǬ5fvD@V4^iNdlZ2{5 Al`^ mկ?079FjrIؼ לnxYqD^[|z'b)K141mr'CVU)~@?3^42O9` )`:Y7hLOg, FF-W3ۄ+.{{qHKH0 Ѻs ǤpdbزuP@GVJz$!-u)k$[Xh@BV3Ϣa[^|AvepĐ'IMh𥴮T5TWKj*d▲ &b;IaZ4vYI )zY2ʪ*z8,5磣Dl`f@^%0vчNjń ݈<5US%LșdI65&+^V!hi#@j@X}wz>0irFxHZq ^?VO,/ +l]ʮ]R|dk.AAL`V,g_>[o?mRʩ5FB]d.^HƳ5vѴRr 8VagWKR|aOݨ:7RwTD4yXFg bnYD>+>/:5\VOVSghlhde;4N8 :U1ӢI:U%kɊeo}k/tҦLlݍQ F,CB@+z<uP^+-.-Ŀ xZUKlې$q ɜC&HEoQ +M -f-8oDGִ! Y1?_i~fc km{{)eߐ2֛o)O*PyR@U?P8NO:~uN5La;ZIK2K}US)Dί)&3[AKD!)V2p9j˗mR{sdǒ,彋ER2R4vYyK!*c4C oɤ @`F%κHY e+'5n:Y,{9) z[zT&q/6|c- M,zlgRMJ5H*^J)嵐JWL#v:Yx8f- XB.afKg4O^ʣ%̓YJ9kdy H!+oJSdJ:%͐WZAx)>ۈ/Xޖ^L(fb;8p!1-mg9P'ɤ!# y8v/m*Dp,8Ԙ%Z.}w%"/}4W# =fHeg3d wM),V+qp%TDT \S|)E)z tLYe38D gpMB$0߱YG+!~kv}YR6n)e6(7!)Ş՗a t}3qpXj&_j-owS(UZҳcnu=̈́5}  mK^`mviTi/8L֮-VU8V֒\PlFH5@J;tTZ{ᑛEIJ꒑BGrDcuר ؾD7a-YHiljyvh! Gf,;%5*_q B L[ YKfَwJ@]/{:9sgҐ[,Őh|Z"! ,KgpdL0yK6!{ôDžf Ww (^7?T1YFmy·[~W }Mۦڠ9YKYvywf-O֭TRv ,>WA%7.`W|H ڲ!4B\j6%ϲZYL@bل }zYVJ!A1S#f&~-ƔR+ RL?5lx4AdTu.6R+SB ZJLM o)KrU  +GP%[)xiqz ITO9 @͓f41q d*4El[HMg U=\:f =5I_p_=v}'C3UØm6Q0B`K"\*:Ce"/#" fCfȼ,q3[^lk4SD‰)7MCW_W/jm^b`:e@j4  Zڙ'5% #)Z1B $j>"H*ٔ-6I.&h^@6K<%۵Oo>D֣i6ВwĘaG!_|5HUF@Mw ,ЉuAjiv@)Fr"8b3a>£3fKHVЦ 6訑&jeUu|ѹfT6sưb@[K E.[-em\m{Df)t\L6kîQ3,@Ӯ(60 S[h_@r[ kP mY*qphq_}KMġߒ YKaYy熃Fpj t`JRfR2KP|kmCX⠲]xB6pQΕ($bg3HUvoHOa4<@zei3f8_ WXPh]~̃_9fF9e{D`p`8ږ" 4I2}J,/.d‘kBحO֦&&>Nn]TZď^>ć~Hp֎΍gm M, 41)<T·@ZX' yA xL̈Ӥ,xN6p4%hxYW H_lC*S?uiԚT}kd O^P]@6ܭ+i_ hr8mTC~۞,7YjJ,֫5 mvC1jyU*IP)$Τ-PU[CޅSeϫ$h>ؑX A/CfZ n)ʼn{yߡt,_~e .eJ1l{&I˧v1Lƥ>GBR\x<][bݖZ$2]!R_/%໔D6.]8tZJ hxPm x!SF(0M޲ɣ 4I*I6ҡ5o"iw-6'qʞOYz_RC->Duv*ŕ#,ɣ{XPViy׻ ;2l/:D)m ͊a!:fX]F1(Dx|CF,}b#T/1=WSm<s2 yfWY6kM4T@w><2[ǒ%׎9śDP d -' 4Sv)+ k5q>kg?ř;|t >c~Vg{l 'efKlzbh4?D`NnȪt(TJQ| I)&4u8 &$AŤױ>f?]-o_˲ ,A*I!),mI "FWBXȄHYP ̪ǏFnfKoHpZ6%YfIaM$RyBK~۸e8m$^mwwu[ݢzyfhBnQ#^@+Yx[i HFOSXmUS0CE1ٺ+ćD, #O`Sc: ΘIu8.Zc4g:ȔZ*b~Q?ͱ'ӽg#و]^sovJڡ<_D,1-I!LDIK5,\v~߿iFRS}df2ti S \U;y !,I_ п{:<=ڵ-hacTQM.j~HuD"R^) m pBvIa νͫr@N4 p4 QHrsGWߜiHyuApkcPQmGwYju"/Q4ۨ h6ިiUu>R~0xkh hHx )(IP`h|@pkwGiNFN%^ƻ.38Ob$XU: [&-d^,cvֱFr˜@HX()΀u! T"#Kv,Y yScCWWD 6ފ̭twuB "ꭇ y"]5+DhQNaOGxđ{`J.$HIp& p\E`"Ll (IR H@@XOр<_#1f Ac Kf+TkٖBCcꦑu/Yx{qZ#-("1d^!t:AGWMm8+׮Hf#T VM G,U MN'AHWŖPvx/0h~}㛲Th*BYt!Rp vapÀ<Q+XzM yv_*Ӿ/\Á~+gAv @є5/d hL@KTSbŤ<RgK@m1#?|2{Rb{gN YU=#(_J\VD,$m"Xu𲦭 ܒ gx8%Y-B,7@*ZReB3A|޲T5+Zyko#X8Oٗ5!eۑcc+%@-LRb>MÔUSy+!qivNUT"-mG@|̺|C.n  !rC;UX6=t4٠3kwtaRtxj-i"f*:G6>FbH4@%FiQ>s_}'Bf v2x T\*b`Z D!fUpf)D&>OGj[} EAy59ׂ2R t jH,$ZK4W0ݷR@A1^|W/1ϧI0\kGRhtpZ! C2AƳ/]G6G|>YT"S[#,>K_+eZD/EJ,Ż^֘Z3ZJ:UO/>+:imF ta/mViIujx" 9ZPng H\[>Қ 82hN4Hb8sqR ,VC@XcwK/ rϊ^²WiZ*!Fi4,V-in:FcX ^yݓ2X2-5d)DWyLY!sNG(V hS|HUiVtx GB1m,B)̲G!+-ggw:5>cRӥсs% (KXXbJXJBrY9+sBpX8]7$RrJO-fg.}Z-ӟר_\̆ { bw}e}yL{߯RwôMcgji` C,mewѪ4xgiJ_aJ"@Y-qU@@-+de!p |3mEt6pQ:[GXc؝T ]5:wb-CZ{@Ę f0%5dجT"!_U_#p|hNxc'],G24)%20)4^_K i_R>'ykuNo2|L?!q <rS[vd)ӚX $NK زv/K%E3 ­^X#lGd>?!+lamf%"{fpI5iӜ8 Y]qK1@mK)1H޽w+.3a :4Acvp6, 6<В >/[߭vjǢg+LVmU•D Ȟt7+9i<V';Deh@%ND7egJ@KmR !eMP6&D1>eÓ2$Ē6DzbkdlH)UaQ0J:حlV6 y3Ef#MK>qSc jcr%۩_,[=0ҋMwu bMkX$eB Gto\Z_zvPեtCVXa3w0=L_v nRbuy Mhc^-Ԕlֲ,*fxD4d笼‡D+X9>$T]Y Dsgb)hRZj `c7ZzĕEcSH 0 )(`]۩.M$NU=Ɲ7R3`K`)AcͰ ɪE` 4<-!Dfٶ`yN\p\׋`@IDAT:0$0A$C𦄷T^UghP 14ki!GO×kGM 6pĜxJ<+t7NHM LT$! @8oFj3yZSYH-fȲ@qǢ-BJa{}Gͮ.ݴ`Mn&dp嘬`K42|[="pJYVh;@#ۦfPIL8Fy[6[yI#^TRٙأs8J񒸒YrXrAbdbA rqxsa Cک2r-cgK瀉|.(t]C/;FNR 8ĕtb~ZaYUyKAyK֐jf{dMBn&t5 P&hk"C6-q\޵S8&\@fd4'l~ ]_jkTIc ,PX &Y!^ڵv*OR H} j$bQs} _ fhj4'ūT tQ&.{Jwƈ2ixDi`|VgޙPEK8M68\ w#͙P3 k<WmY%e֦v]]0e!,"(e)UYV du/ŀ5U1Y-,4#('mM ﵡ SkٝtʚA,oܒslgij/0m!qU%U D_M%pje͟xd18_R-3@7yC%1NT BsI$ܒ!DoJd:n y%&yWGX0rA-6v}Χ33[!얂uzv$QU|Ri(sQfd%$PmRzӖ Th)&Fnβ&ve[vu9jmAZr̻i$-5\9DAе(t H)AKgKd`O@My^tbW+ PcbmJ ŷ)0˘eM[j؝kmӄkvT-*KgpSȦA௠xO9˽wLw|d }ͯ]ݛv l#Rhv!铂Dh+ DըSC!K ,X7G5v3AwU=c7nBxĔY19䥺WL_J HY`IrX2U<s¿\? Yw; f^$rf$q:SId1P|d]`4&o*4eÌ_-8N.RCǤV8GAyMj]tcyKRhFZ {u8β>>,+keRiB&lQELg H`jDדr=` X'~mW[J:8)XsoVNHVW s#2}H}IsR22 ̓в@ߖfX:v ́ i"  Ѻ|41NVV#2_@妝>Ur-ڣ@+GJ9Ce`MZdIj-([!d! 㸦R wƴCF`ʦrK4qx2L l,x!Ez R&5?Ryw▕,R-k!}(zɏr>4AG W9ܻH Bii<"ƼAܖ*I1,02cxK!pȆ'2Ug!$g8R Yg0vͣ--eF/#G(VVaL$' pw)7Ip\&D_^,ZJyR -ν_uMk to,~KU =߁pw LGx)c :8f5_?N6t״y61&;@|xVLR}~pclzl8|AR&5~AT1y IM;PE|4,];qrsOd-P_8>M9PU:@A> Q -P5єg1A NB{\yسT%C!$m8@YC,k&6Ec3ũoSNYhď󔕔´#qz+gr!Ф2q^)i/` k*RffWt3@XǫZE಺T #R̒jfQKfL翛J_<[bZ%רhȶ )l/!j{w /ӱTk V3ukt#™PM%BrL)>ZĄ3KfG\GUƯЦ3wwBNX4y:2:6e0Cct2hdچ`vcDTP $e| %fb!fK1B9_z)|Q_jx4}%h2gG!,SSs+b U2 qH|ڐ;Y MPWeY#XTA@xϔ m!ư,ִ'j@<>Gm'-`&JP!Kpϧ5̀E$ui(~ ֢r9[kcM25k\B#P0*f9PP`[Ǹ 0!%<@a>kw b e;].A{R@w`SEY 8HʼnRxjKHV-&db!@7Pn qw^U#~ٳk$B SӪǴI]'ȳtfD5'T;|Yc Q,n)fRg Og߲ ִ^eK 8gkM*HbJxqzI5d)iw/}ׅ8M>{lmylMFNhMR%]@BT)I kǣH}3a@Fx@oŷ$ͼsoh7!o61mr@a`LDwt5<ܙ vJ/˻e 0nN7*B,2,IAl4@S)ww} n',۩^Lh'Ni_uq]v`c[0 Ζ7SQN=4*_r}韠g@lٙ$Fȶ;qg c" _I8<$?mVU-L !ñ L!205q1 hgL.)63ZLA\ y7 SCpd@i+cY I=4+%Y++vdݿ.dYj  lv[B &ZF6&\9ov{1TRqvţ]A~,`ib6F ޵ Kd#B0H!+OR,7hdc&%Ȗ+铵gDP;4G.3g#HE3W3Ov:FVL )xO4ZmO2_$t\ŖZ)_ 򽶔hR)F(4%xa#4B#!x*0x mHKY8TB\S"Jd#8АU1 ,YV`趇SRD,gT4 iD)đi WVUxr*y>$ѴxLX6=pk@d6|T{t5a8DZb ]*ZH(q;v }q;jZ&rZ Q G [Kx`S>w" Qڞ!P+D` !HG|AѤѤ6蝀flR "󬦂'w-v} 41od`ToUΔh%h^%FddSUNq4SQ6/>fz_ɶ b)qiN[B ߻L@m2"{Upi.HayF;sjؖF$ XVJ/p{!zi]<XSpl-yӰYAHgO8@;r"9Zs(qd:!nRzv$0+t5* (9D|$;jU1m9Nż RFgSV#Tt3* 85or+&`6-›*p#XA֐@GJyx@}hNhZOav piZ@4u Vx/~_IШ} 9Xn&aZw !R@~\VUn)Nb&"s8F.06+(qdiYܮhE󋉠9h|AqO_R^#f _űx#($jQ  I%٘&{O!Ї)oTL 0Pդؒg 6[3tl1Qج;T٘R͈/ǻ&Hf#p喉 $ -(ud"j%"~".tJ b*qA!d ôc)%|J YCBJ,4r%d)Rm "-Sm_e ;Xӄ|{tǗ67Ⱦ^f䝀l"AIۇwdeḶ%ӆȍljBǕE HYJ)XJ^@v;0rHJ3x)qM??NFٚBX!4R;Ь^jQá 0)@ׅiP8lb,Z+Rt_[ ۝DoTT\ )ZyLFXeƮP iG8)W0|W{NHJ\/7yUNؿ庈-ݎڂFdKYC;%U!-f&ND.Alʽ㫎;_m Gv'5s$qeR,erUe-YiK@(2)%PRJI٪t ]nnvKXݙLIB&^ D v!fDZđ]ӫ)\P%gmr1RjvņIʴ Ȃ5D3a !ɦْ .bhFYȉUb)Ri mfZRbLقIDP}1& RHhd)nImrF|ގZ#UZwtүe4r)YWťxYmD ܑ jzY6P̀ $& ׿u1f3@EyqG-FvK)- ۵BmﺠmYk ͐`15"ŮVź0.z#W7vY%l);dwKekJ-Cbr.P4x%+cȊyF C ̝ ]6Cd'ۖ冰J=8txRD,锭ehu/H @#Thm%!S3 i @g⦢#X`IAV :@#Y;l#;^@%0 ^g)C.*[*W%4,v Jw)-+8|V#WJGf "@^sw,RL l6R8R1>ucH-974ͯK3410$o,2NlkmD*/2_!D@] h*)4?.~ Րʝ͓ThifW1ߒTZi:h £p: M>-Y)A]R[I,[Yq5^@YiZ4hċԤnFR"(3)#J@D/:"͉vbB@fELd QBf)A7LgH &h"bZɺT@FU{kUBAUQ0k~ 5$Z˼9dUAј!}tWE9~]Q۔ ޘ\51x!b d-y@FœaUqT!;RBKM3Zw&hb[ݶ3-IYn2p3c}9OVp%R@:.!~ ?kSkwz!↴Dkf+/NDSɳSx#K9J1)ᤆ#cO(U#̆]d 2Bf1DLγwOnKXٴvb kyc0; l{/p+hj\SԒOӣ!;2eK8٤?Q݇H!J"fK?tYɚP@Eä`$d3ǿh86ZyL4&@B5%N'xٔo7 fWc,1gbd^b۔lJ,Y`G|laWkyGڎld#ԑxfV_Cl=H!jM41p>foG9\+i+5MAO0y1Cr{e@,n 9q-[ Ҕ"iBʉ3Xڠ{c8)kY1 F7-A'/@ 9V %eM &B4b|ͭIm3"`P W*(#b Aqe>mދ\[Jg 5N1-to Ct \.Hw^@ }>zTmi3F:#Rn#p <> %#hlx6!.^8|).p*)weM+y4ȊWȳn4)WHYu+zv6ܵ^~BS[w[mr%~ⶀ/.AT d"Z$k4'NȘc~= lNqSm; MMJ:JA ̆Gf8MX'e4 0d{fЊlr@mWY 6x6M6cg.UwtH<.Mp+ˆl0M6[v(0Y%D!d!5q5/E Sܲ4%Ҵ ?kϚEf[ l0@f7l] L榕ؕ0 o. 'nGb'CtMX ORژ GLM[(,&n S[pm`@)% vkzR%-#[a}+!|cV(Nd1Q$kjKlFR8A"f!|(@fnAqXU7 b>_/, 4OKCv>qd-IXfUP9LBuw2p1_\UNKvS0yFDLp+;Oh_cfWbZ283oS F \5ɻm*1DBOXe:vzS$w޾G ?YMfh<61v.dͩ mGme{8K64HVm3|Kd+!T5R{ AuYxwO(,`mmS: \t"@-d5!T]dZt@J ``jd$ unZFR ƁD-q}f!;6EYgn?KEǦ60,9. tl8ocJwA] }{*iڵ#MM2~3@!Ku)Wخe傖 dv#S$CAc@] K`6!#H)Db)8aK!R:ŕ!*fk'f l_7vR R820)+EM!7Xd%d%nK16Z? pY&V@hYB m SZ-~t?]gtM%4e PF\2gtAxDUa1/s!-hZF=*YK9J xLALDTGv8R@PK}S1lCH@e~K qLp^hx{׋O\S&v ӄ_W_N}R#481C*[dץFT╤c,"p{M^!&3̤BTշv8o?Ϳ:aQ\Ie ffi3 }4rnwK|4>))_IS,%l\/}Yd̒dB `5) S8KC}Al}+^>3._0e /t;.MOJCu1BJll0dO-0iKPȖ%`iK&Pje-YtgeamZ2P\yLch]h `i쿁Č'kw fl6@ ~牏#u$`Rk_Q8L⛊l*ķgU6[iݙL7 oN]y *Gy_QRBC4#*hGvQ*4 F^- gX-)+A;rJxc)m#њMLGХ 0bl+1bDG6 `%7X h"ЄgD`n*%q($b 9ŴW~ӫ&Q\I?IqMu ҅.U=F`!)+LwF g KO hdNRj rcL\;%U{% | HFB$@qXa LP~2RdI9^wK&>i8y$R81!LG^vwlKH <łB]/dcïiXF8mZ"@AVx;J`d ;jjMQ`f.(,4$%T\wKO@d7mM43 f #EӢ]`ˊ)U*}`DWcp?~w=#qft4/e XZ2tde3@TRv[.Ph_r,8q^ YVH잵Dh0YxRp1\m<U-8)e`{2CRks tyC{jX,eu}$6 4R˫&{>l$FMDwƈk>(yو .5` lΚ\$Nw )B|E$"4]8B&T| 8|qR E?X2j&K6ВDEZj*FWr3-1 ZʺՋ2ZqtevʐWR!Nq|۔8r A/$ݡxnL'pqlF4]G얂`8m`sOꤔdh򑁉7@¹+-%VȈKU>5ƥ"(W>v-[)#`6U Sll;g;}KUF?kڨM<TjV{/1mJICJY6M&`1yOuz0:^.[{o:73d$B$rz{pt 3O]S=2lDdt_u}uF ;j76DF b\Yέ;(^V몦` -•n)IuCj:Kv̀n9T|.*GS^ +Suva `ľ"!zc;)q䲶P=9 rvOMx]GTXw˟fW~jl֙ wа;4 ,N3LJUao :(luڔlj#)mP)CLGa]Ou0:֗gB, pN_.VSH,mU!DS#!.%+_XVXW';1(cyxFkǮYÓjRy&tR0SX@zY)B.MU "`2)B),_`wlO'{oCy1ñwN Ӊ,π4~0ޖ(N>#9.i-tf8HRxRL-Y-;|q1r:8?W 9?ZmR#֐FiGev#PbAvf#Ӕ2K|hAwC6-F1^J7ؙ8ɮi+/nl׳rLA@ƻO`ԅďV*P!EJi/hͯטnά?o}VڗFy2Aiu,Ul&H xZ41A^ֲSXQy>}jqdG`ז>XCP_xԂr#w2Mb#J36sYo92!)Od3S[ӑK&$1F` Jgר}YVEgR8)kdBx|e(d ?K}"@#.௢㪢pLRCV*"(Sh)[vdH*~3a <ByMel>~4\j8ܒ,B p[dd8)}ZRp6U{%'הY{i)d:b|;TKLA6SpOJvyEnLG;IRNw]t k+EL3*@ <ƀ7^rM!2>##gDE1'b`JlApb)hkc!559yy&\Ӗ<)C !1!`Yc4~M pF̮m^Y!@Hpbe) W%oj|0Ok3jS䘲Dp3r^ ʶGSP/ŋ2R !!+Gꠀ ³8&Be<m%] p %b>t؏eu[)1bk?j}iFVR-/RhꔁmI(XI#P`@YK) q8k oy]pRJOM\괹:jGGp#/T 6-vr?̘; UgOg;NP^ivSL16%fh|)S)EWpRLʷ@/PU>i`^͌Ѩ&!Ŗ^PR|Y BFR;BȤZ*o@q"Ѥj:I͟^!''!tZ,uTyd1@]>C3O%H߲cABvݮIDĉF८9UAC/r)lCfSNaMJ*Z pKư/-"t; Be#3 SߙgcQ `ě=2KÕ8iK:e)x툻ui`%d!@Kc /4! ^ wv$Gav,)(oGM% *tp'd:%3#Ju|~<]whl5^D6QEmyBm\ }1Y+^T jTA;#eƫJqJQP]q\Z]/ډXIBe4ۣv^yV U֯eBu5Nz G qBo4-|*%YWݖbnB&8YJْw| JTx3DB2OMS+A[ 'q 1OMgzvdکI:4`3c d; Qд}r `<[Fb)CN! TwŽ›DNZE jU"7.,CG`L^ t5MLJyV#HtH Z-T+eJ첊}G&I*3OG0rsEP;LrT oke@Ar; z!k`RW=2/t!0z17gw!Lki^<>dWUJκkNq"%oeȘ u o=k.}nH@Y),` U4):::LVf#\V3` |(5Τ?r:$y%; ޔ0gQUKLA8ѤjZ3@tG&|`jBYH(h`q\BPy]e+O*xG3%\b'FkHG}00]_ ۻh<9 騋o_my-z@`9LIZ`UA0C%|-i6msH /m;iO %%S ( />n4}]ZE+A53˟]]woUE%"E2_=;(e%-i /(˧ w\ٗ/'Q\D#&tpo;|188L`/*A{OґÕ;2AJ,+%v!*Ⱥep̦a Qh)E-2Y&Xf ܺnjJFE'LĹVoٴ<üi $z>O"֔ɁLmż*]SPH'ˀwMP^_L@EÏƣR ñI18g {HӁoWkbT ]7gf 5aRx<>N ndB|;e!&Zc5-3.4q|`1dIŭ `G)AdI#FRҦl Ӂ04dBFk&YֲW^!@Ss, Ae&`za \\V*]TD!&T l34H}'XVʐR8 "N%|'i&]P[ ]] gԠ|c%NrS'FڲI*Tr/BxK LԒ0ye{Ĵ_^;B8W7SRI~}FtxYw]X Teᖥ /V&9U]GrRZKYfj[&[|GGa"CQmdKCdIPtzhUnf4%zWK烞~?P 4.ؽkyj&BTřZWLP#}=q,]:*l bo-O~ϡISLP=F<|KU"@fp10+@Chr ā0-ɔXl0wio0!uG{MK)4dxbL6AldNȝ_wd M[p&9c6oF'0.d&Ͳ4y{fPhC4KjUZ6 q ‹;6WC(UN{.;OOtdFN^L14&9}>'iC9P#HM4y4jdÙ/x/IR?o6śhnZ3يUy;LdRFlo)C Gϫ 0*3:6ߕBSyڕTW kw>|K놉fBkRD2K-)KjbY8`jgb_D}`6e@6MX L[8Jv. O-T&cw_ҧ0͹.jr8&Ւ*»V6me["LR\Rk6Fd;N:k!Ȓj#"䗿&~y/^@KشRnw;U-ULT4ARy:2 ^t64*Anbtj-DH[G [ bpY\# Y`D M ysg ~jF< 2sRkx{ V%SցRmR3LIѴ-Vȿӿpc} IM؍ lN),!D\Pډx w'@hnMHBд" 4 du$.hP%5L|¬π 5?rBl+BjrU) ed >Ry2>/UyrSb@j-X֥ϨdL9Nvj~F\Ù%Kyjˏ?ͦ mNwmHk`Y%vt+USi)K! R9"pFBP_uiSߎꮵ7 q6qY+@J )ND /K0 m#V/"&DHd!DVl[8A,#;Y2/w7G^F%H!mMT56Xpyv{%qXN+fkԒǟ]Gun8Z?jCx׎l3o0KfYcvhh8|@{`wY~8DIB8}&IAx|Ah#|R,<1yza6$fO39^)q|V,`#11ODd FM Ke ٪# wu)3A3)we 35!T,B)NdRu:F2d7BR`ޮS.,e8( /5ãՅ AhBqM﾿@{#ut Svg&KlGm~hY֡u8-thb,P 5P\/jȖab|'f+G0ID,we֒p% <([UIS.{Dcu_I J,j[FN$]*S_W ?5>szI9C6)z)dJ,# G;4ʵ5Zyl<U= p^sr4RC(u Ir-X *ey]SS ;8R@xI Dce] Y;L٫\jpR`xsq}oCEfhGsWbR̖T'@%;Qn)UZ' OEᦅv;֑XxdH4<%;r+N7!Fy՝Iu!)Y'QDSoLR!Zw~U1q0Q@A8,^RBǝߵ#o`-m_-Y`}yv.0d u/o)0R<:KٖJtCX ]:w܁o6-7Ҝf@Ӝb)|1KY`hyq8Wu*;n C66M'YWyW0BniqO3fZKqۈ{™B c1#@XL>\>*)A% WX%zvuԘ4"nNZyd߻vj圬۾Ƅ]HZ)dU e o|0wbAQhiޒ:Xv/>GH |ie#iɧTEҨ,5jUXVX%k l<6)O͋kV6A: CW+ټhT-.@m׆Z٪ a򖚦v%/ S&UƮW`׾ MڗR>BBgڟ|>}"ޜ|GW`X^#<6Ku, 9DUPV *[2U8(-a7t#rdRʵ2⤤#%""V-BKA`KÓE`bʖuo^]Nru&&rym0, Z:^!6xlWVaDy0>]=ƫOP_n!Rbfw%hY4X ·o)uVv| mM)F|Z& ,Eĥ4-,>wH8a^;8 ZOJEdMhHK^>!y/PVm4x<2d`MҗJJ[ڗ*|Y`6`%YK=_B@Ufk7]JǮWۋ&@ :XJI{!_ cyٵZ_m՗-mGmv!sN l\ 4r;c\->WP /' h 2>0> og\W9L*_-5g/p-$O Y1hp8v-Djjs,q|\f8S|w4[/FԮy4[m/Ն2e1(!矐 T,˯SI ~ ;yI CPB†FDMRc%zUYFR1UKP 3BRv!{3c|&X 8Y8OVd^t"ϴ~" Z7f$ ߜ-; KbY ұsXhJ 4WRu_,(Y62kJ,Dm'iגgWftIՂ}!jgNCn _֪+.|qbrZKH%Ô#i7_aou!7bc 67|[Fޕlj[*, d#;:Z~L|V 9Dc$E-FerrhB趁ci"IUFe1 #b ^Bxj}J$XUKl 4Lh!1sDlTu&Q% (eC" @ĪJ'[sT iUe2 !N5O+0Z)D%@IDAT&(獭PUYeRGu bY31 "#8zw915Jl*=N]pb(1" f҇G p@%D\!bULU}łfKL8#U9lYȕte^鐠{  bҴ xvo/YtžAJū뷄LpV,D^dZFqR0dR e$JJ;}#!Y)fۉ1̶Y-xcF U4Bט碄8 ٖRvJ5jk*QjB`0Y1?؛g@ĝF5ga U)πTB1{4ZW8CAKJ-&YU/Vn)U!PI*o*y)Y (M Vm`M! q5-KU]LKVh  Y^Ti-TyIPK;e4YUIaEAh{k[Qo}_?|_iҾ .WF`NTKeH Vyuפ|ȈM>Z^kf.pdJu5 2- (T.N SȈt]Yt6=d1߲ܐf vFZk9e)W>q!idx{)7w/%PP;j^: .Rl VP6fPJ@"2,Ƭ[96$ͤ2 f8NO;gm>WUS8>3yzw?o~ WJc)n)n80RSo!(l0u-WP6Z eb]l\ ͥ01>rVŖd,.L6J™Cr׆ )ִi +(+i~lJۅx_KctȂ 'Z)(\ПY+ bBXeMg e/f^E'6RP.+i@"x?}]M@I4xq[VzմA4%b&Fw%=m_ 1ZݿCMO5E^`-[&Zޏx dY;[VCRnו]2)nrK&"fpMwA]&ԯnٻ^Uqܽl|j-1 a1a Mr n<`MMGj3Hax1`ԶT`|?dWbfx"%jfMYv5j379z8I%q:j(eծ ߲'*ˎ;,RŤZ _tu{Ok: S.aX'Ў[m*EkvLQ`(SW K!@6?B"p3T8U*[G:k|xH'N-; dJI-eg^OѹTZ$RSU8ȂvT/W O<rS k+e{ڎ.`"S!AՅ=R& w݅H0Q5@$]2eë2e1YK&m,%(KPmWHwJ0tZ C  wӼS #,bY:˖s?<̚x淔;b,e,y}ydޫԒB9T[t'q1/p.{N xy S,pVx R(#,]\F{7I6}clmW6>씔0(PG9ퟯ{w N%me}7>{zLY#`mRJ<83u DyȣT{eo L&e|Q4Y5᪐*],Kd4N4.QuJ;8L` zQ4Z;6vX s6.vp Iu <MD,k)%PWȧ#`F:RPﳾs~#̻1`wMw:gDZ4<;ʕ! HY&O6fT!D4Mɞ#xS#(V+CZ7y)+lHـR_j2dc4̝fZ9 &(kB[#ıD(% 04^6l(% @RlgFʘz6*GH-b#~_m?T!8Bf3;\AY ?ι#)U#(3P5ЍUbZP v|k#e=B(\D5JA ͍d)kS@{#@ھ mSF֫UyjTQIm#:VlAoj- bz1qY%'BKKŸgvׄ흷/k;5R|8%X<%ijh|y-rdP2 NZyVlKS\%r10*ᛍpN#Kb8B'yf(|[3560j@e+ϳh VdZkA R/1K,fpZz-)@Xm3r|>.q:1H3Mφ*֥۬yb6u&%(cI~ȕߔDSߞQ#2%"Ct2`UuQSK >%Ӯ<))7I@(kvUp b>~l!o*:q ml٭Hdqdo Z˲Hj3R.ZUD੉DJ J99J}t<"ȋ,Zx6X o.~ƣi4dhԀMkHȌo F'c\%|[hj&7 Z)\lSAZ@I]YWWB.i67S~-gcc7$ܜY-ۋ툏0A:D"SXV#3L>*؂ `5LŔ dU\: yXƗ*{YYUDG[X ȂgRÓ GlԤ+oYlwB#` ŵ7poFѺ["9Gy,6 Y tN7pc W DVπ4Ku׾C4KZo4d?vm;:^ }LMlޡI x@`@CkANj@Gy"Z$ıBi8SBKjㄧr DŽw}  %D;& NClNĎbL)░V0eg3!ӏy޾G_| e Z!YRpCY^HSUN5Z2a-R KrHZ3&1+Y֩ƼHSz~DNA>A2. ^7!O_A6F" J |A6<Z e!ab:Nw'IN+]'țe;UAsJ̍*֥R<oIoi&dZR;I|芠ٯ ˮ]u&Aʒ2ZeDcCjÇϟfG.Nxb"h~8v%s6ԶR18eiFk5#FD DPNĹ6 &f |T0V#}$ M/ 5UoYbRuc60@XRk(3SXF\ $ i"Si/$٫C@:Rhl,"c8b!ㄫTF\kܲCD0D\d!q7Yf:6;i7,ݿ[&dL6vRE|1ΤT84+ uD6 NaK lEABP̣)Ku@_8p;%h]}jwPD"bpC7XfQRZgp'_(~~K]vwP5Pa)̎ 8> _6'Md9,``8DIG&Ŕe@8EnJpxV* Ḑ :b^%(P^ڡeG|gHU$ NB]l4YKv<)K)|j!Q+0/ 1F^ܾ\\LSKHLRU50@F@d3c*~fl/])63XkK`@U z]Řh,BK4YP_.x7d;>dHh5j¼5|_G|#21)KtRK;fP.[ F 0d8cҔշl|q&P KUeTJx`4e8kGXn8II5ψ3bi k#Pq\&FƄ(AKKJASE&G#$$Wݹ4X-fFR CȐu3I$hH4O@q,D,3N&TO_I?W0s)ıwi8ᑣ ,hH)dWNJ#(M i`-0V(FXw%8. <|vGIZtzMށC,or2:J)F&#1X@/|uI2R"N74^ Q|~wTLd9`KX_&l#* @|R6QGBKMTTT#"#0UMW@Kޔ4Me8A0k [ pFAIX!X.DŽ`:1!o4-wЪ) tlj :LA%hmP{ʁvL4|T|cIp(4C-kYmd!8b]V( 2+&*SPI3sB'upAЈ A%|䕛 8ӣoQ_b#Ҵ;m$ـ8ܜTyGkd!)M88Q`)oO6%:  [)6T8~ڤ 8o;hxj5w/%RHa< DzQTRTr>&-t5fȻyVRh6lKǕD0+ٙXJ v+D"ZЇ%BLVR* 'EI,>^ Mi6WӡxĤ^klAL"☫U+IDvjjDR CMZ'_D~`ف(Ա 0jWo Ѷٮ+|qRb8h t4\ P@ sl%֑"0 b` o)@КO0ĉ\#xw߅umU8LmoT(;%qxn$ bABlq7X)hk0Yc@"G.0ex c׬GȆ,i9]_ܡu"VXg)DCܐRe!8+D`@@ARRAK hWOM'Bem58\P ^8eZ BāJ,(.1Z3Q%%.+et}7d#EFDЀZcZpPIm"LJ!ߒ1 .RJ]Y)?t5m o7*pw&ϼsk1&@ ۠Xj襰g N)钚ZK:5u@_,2<s @ 1Y 2ã <BҊIsbO"> nkA+W?UlWpx1#%0pK Ax"ھX %Q@4rc_|`i7`=Ư0AȔ :1,ۦz-uco<{b|Y"|#/Rn 5UՐ4%!JZ=IֻcIz}kguoX2}:~,` 2&"95h%YtWGA 4lN`Y18' 7oGh8<`g^VG#K -qő+`|D,,? ܒO{3_|[A!R`b ԐklKD@ CX2b:-yv!=o;p iT"MouҤrM(f,)0%<_WE vL 7emj$/j1b#os1߆r IlkͲd o V6ⶉ\#pzz1Z땔e6O[P "hvO:sS5of3a deT!j[v\& >K`b)HS_7h?`noQ#{ӧIXFmK* 15-ʕRNdb4Aő7,kx,XJѵk` X1 BĒ,-!>b Ųp4"_yx %)[Mɓ? %Z.pO~_emܝ#n 2$^>!<3g@%phfK!) ֫r6%Qh{!Y@dWkBFPUBǷ$c^m8Z#Yy1P#?H'uE9{O9™QpQ>25@-<- %P#l]Geq\>%Uů -&Db_鄋YyOv62ι^В2`zHqFLR*='m~JUU֒Yqs-."g^/;}[KR'(Κf*3 @Á`ts,oOۿwIf͖tx<+%_yYեJYQ <.ȗ;Iɿo&$wwEd  D6LSIASm%pK41lw%^m<8LThf qx N)CYRl#; ڴ~_."w? x]AI A;gL1Yǘ1q}A֜*Tψ㴬#۬D;Aiw?4WܟOӆWiťXZ趻g'>S1;qaIm*^\__1M^b; QRFmiZbowmVnӨf|zy:ƞhjjI fO*Y 0L _ЄKU;4qՈ!؅#ı~#TQ81YRm'&Kq2M|l b4=fɨYMlRR@ P[g@%q&DVکrjmG UEYNQ (j_ dVg&zG@.JS{g]U ١bGA /_2²Me32}u dRh<<_bצw{lţ0X2h湟(}fpP&` -I;dqOgKB^̔GՁ49|_TŧVɼ8r`Y qUjG'rxϋB/WthѹmP_&۝CC3I,%3B{E0Oѩ{)?R-Qū?.~QfsJkڮZT YG#%Vȳ#3TYKR:`Ff4LGND9HRdhJPhZ8 e)@S̫m (*Lp"tZ SJ'kmAVQDhH>ȷGAYA:j-) c)x8b""Wc4ũaujlFRL8BK vO&#vHIj'%3\cSl)#ԈY^IFCP0O | Won# yYVRLm"X[vF{c7O Ad]*_0E;#רUI[,Ȑ1 bHX sqJu+&^ͯ-Ękv5ܓ=X$2/'H,)^ {PkǴ&dqYN@U&EJ-*xM+GLj1&̺1dHKT;z j >mj EׂfZS1}hCn_y,֨e QfZd]M|L¼ua5/k:ypAYN*"n`^S3Ʈl4$aԟQpL@0`) &yz0!TJ!B )GMʲ#$B+jTHҧ6R#%XMY \ 8|6D h$NMXht>\` JƁ~uk GcdWGK)$̴?uʘY 7d퀕 MM7Iĺ:jIMv8΍[ q@ Y;Zm;|?c Ӈv#9+m߲C0RF햦 NNGO)}}h+\ >ڏy(ӯE}Z H D 7* $Z@1)yN1]HE@HuwX^O7l`xIRM >Agyt YM<+o#;P*fz 6mwcNn{>b=@ :*!۾(tȵ)+xK\!@i!\#>&0SҕI ,D;sុvojZ)^͆$ Oa|v?Mxr>͠W/FA|c#lUeЀDzC{0J0T. K4LT]xRR abdjB I! d2 )&6`Yxחkԁo_pd {FYLLy̪v , IPoʉnj&Y%h$κ@y2ZfZXT+d,Si_#Nӱܐ5)~Z7d_!R{QФtoÔk/lƵ7Wgq:/‘%>%[ëoJ<&D6^D,R L ^-*NWh,H<8Jn#bsROtjdD)Um6A wdx >+$ۻFL1,7@,qE,Ac2@Zܞ3%!Oe1+RdR[.uAynkm$3@鈌R1vOV"^NIUXj4b24?fR_]:T]B^hqkø?!XB%~eP{2lgUhuSc!uB(]⩹ufqFq b>Z8_Bigkö,+V5>q:V^5[b|,Fbq\5\,?U T?|cF&06Dޙ|! l&~4^/-@c8vh 7@b{c4q^wWK)Wxw2hl6}(#H!*MA*_D6rè1g kWhѾک*d:!јyxLlm*B-xjd_ MYHZ8>S#GA^Z|ghoΤeگT{Jlv +b73)Sj41eklj\x4 Bqk-F .!J)(kIĶ7q NШ r4" 6` ~tV"FcRb's]ljg礀(g;V̬)W"T L\繕l4d2Dpp%D JHuaR@7  ͐D*Z-حSUc☄) (#,#+yok>$ l_1L7e{/H \F) iSS  ;z@IDAT<\9:*xNyf94YKϳ,Yb'}(VbDӴ<S >T SZ+{mhvS֥<gw!S+8W^{~׿;tt~uo;8`EKlf8B24BdU-yKE 6^@\0{qH4g`K[Ubv6ex&ˀ -ɟ3Rrg%j$2Q.||YID_#ʚn΂y;iBtdHh8ӱtDBs"P"T%]&o  ZBu:^ٛc<ز`KQ0`vd ̒5$P oS6(A3trtCԫ2<\`MїljBqwi<x{^d%AX ΘMhR`7de>m2 L,X`.y֐R˽oTz']eKޒ!cFm'.mZ@tS0_[Q;G86bGNjRVeDCYڻv+Tk%v%[ Ye既dh}zSc "ʒ5pA#%(`&uP8rU @ޫ)D -eo-A Fg] W& JHfU&NQ6BU:߶ oCzRAS??E" Gۙҁ mh@j] ZW9$5#A(7;xuWv5-(+nruR۩ uߖ-X H^-3|qj8b篶eRnחĽ}~}NG;""rW-j- & t| -_7_.hϏ&$8{ϴoT&[!)YY%1ļs)K&v$`JؙOʙYt,szɢ 9"{+:s1hffWeMl_lSM%N\P 7?AuL ҷBˍe&[ydbYRyAx9._%hjۈ%f4qcDK e'EΛ ndb$)H{6_&L)o<`eA,Z6%ՒwH1"S4lc@wҺm`q <&4.Ŵd)Y[tQ d V!8Nt昵0ag a-.`HO-!+d@ڝ* 'yG`K(l3ly9,e(E#P,YZIH PPU q},r޲x lB"6Ҝ ;Yl Of&Mi(%mB/^#y/ucUI gKSpbJP Q/4K`'bb:ZK0]WJ1x *F&@3ݣup-p"I!X*|Mh!x4 x%,,צ8٩Ni m1!MYTZ=Z8Q e;ᗒ.zˍ^JLMjhl`y% ,20q L`iZvܴƩN~ץ泡z X]stUXe&Ɓ nBqFp c_ TY߅ﴑ4ќyM2fާfFEPĥl@fˊkGSޖ4U OW+a-5aE4SGcb« g$Y*'J$E_RL'/.~FE竇$SIQLWC6@ qjŵ@ ֲ*dfDŽbQ&~f;3بuor۱5#A2숙V/ޫ]Uz;O_~)_ճ.ii>Y\wKwsSHdjrܶp:7)yhXIAxPk^qIy(`,fZX|YLUڦlMB* šF|dߦͭDπvtb}ؚ3H3gb\!ZCGv͉H6^ @‰v=HA 4Y" ?R$n7L#Lp*lGZ6M̲HY2?ϛ.=HuW W?!z#Iit޹֮F A8~//t8r)^m%O2%b5JY`xLC,W+lChզyP9ӧEbO LΗ͖\#g7 {9ΒojFl{5._Jutꋃ/iJ d>jt,Qed>DVL1x"8⮑VKI}MEC&C; 5V*x;}5saLd 칓94'7(Ԏ3˥,e->e x)fmJسl}4%-:&Y 9%']㔨єe"UAw5UiKUM HⲬ!eh0K i bGyCyM*&-S`oU:F=~& Bf`w@]U8YZ%2TbӒ4GՎڧ"byKQ,%;dm 1|x)EKMo25+9~cI8LLږ╋[) OD&EFl6UO]INƒU[iײMD\e 8A?RnD6C?> asٮ phJlG/GľȶEvO2W8yR&Qyx}T| 5kr!1){n(FVqe[w8fF2pLȢYF,mP#/@;,`hw݇u7*2f3ؕ-K ?NS!M^`C,u() Q\,N4%irR 6#šCscn`jY #pβpYfkjT)&)hfx]to rU,28vwb]2R1?[|HGffOP "8~l`1{ eXEEsjÔbhU-6 oL|8ɛL'MO̗))Π^ӕwJȪc;p d vF ^,卶1ɦCj!/v8 U '\` LIo.49ffg @&fb4EOX( ]MeעMW[rۉFj$F DIU(s.oj4] l 6I-b)Ss+]KuZ)FȀLy ?ZQZAp}XݍRDdz)Ѵ,8@q:+wL-)ShYBb*gbN ^/̑!3ih9 o.6Bsdjuu7BSXba 0كK('$@K!4R)^#' Fsqc'ޏ o` Qxf3m}-UJB! 9mS)!|}jgh;m )Qy&MJ|ZEpU8_ըlCh3#tՌg+{^fjT`F \8CRӗ>ƾgbMh~1SZ -Cx >fiwbxw$&q8[ b`\Df#sf1NٶP뛏C$Y?C<=f0]P1m_E;׻1~'!k0%ؼ ƻ!r޾ښ|70^I61\ QV0W64mG yFKFbC,.gԔWbKqa :Sg  h)E In ÛPSWȤ,S7d#+3D ۩l7O1, `(BfɤXD$#"-1=k;X5mGb>)F,wzJ*ż@1ʙ. BWo ljZܾ]4Ih=`Y%U-[ ^tk/6G+tp2=__}02#y 8@ULLD`Á tZ]W*|/NLJ,0~_d[l1,شh@t ThU؁XV##5 *&KPPI+灕20ĒZLRP-_`LK+ɐrJ@8)31R /Z Rlб<=]' H") X6ZV*W)GwNIVf-[.%>a2U@,%O/XvFYj1X}s2e1|#\:FG@fHus[6F#L|v(͙8= j-yS.DDE#@A!<=D֥+xJ'GIF(AV)xǗ|mj5hD2YPĮ%ci~_ w^Hb 3*NL_-?m Ѽ( K ERS5C Hy} ^ `68y]pC}HA-gy9DLܲYzI50 x=x#%ܵA̩=m_bqdMNLOS 6U A-(TCE\2O ܮo/KlLT5L`I1֑8 FSV@YV @Vo;G=׸4Yd>tDT|[{ ӨuɋYa<_ӘFjP^ϚB`7p߁[ɳ|r+ b;3 ?Y#BoͶfNwPkHj]Q..)4ۄUR !T"7Sp q&0p& QGB0_647Z]SFp2H" i#I1HtXqZ̤ B# p>Ib`ys=2O!Ab|,}X vm<cK(am$вKK .̊"ÄY;Sy)Y֋TGt.z9!TNjj,##j 62Ma7?yU\6}qkr*"dʑѤ<ֱxax$AGmQU xP/&i8f3BLce!<-_`lf ;A]dSyÉ'(P[V@&+sjX0#+]w) c?oB™I,2A9ڑp^&iN86"yCcvG)tl+>DV_c^/Bx?t1Bir.`K+I_Ҍ`Y4 @d )/S95%pgQ !b6hInT‹e]'%ʍT6S-sM |Ljbc >Z^d"^,#dl%% bpF!~õj1ٖ #R G)@J o>LԘ8pt6Ŧa$ē205"Mۨ{Z ()n~/R.Lq=וjJ,2C&wVHp;rC`J~%5gr̻UBij$_:RK3vMxaܐy d4,&vJKw>Txh w,~ʧK{_ޜZ5HYߜY*r,hl@ˆǤ/ [ T\9|U`-ŘvȺl>>i4r4vO8M:$`I^e+WL 챭J6M4ۓ<[vqymDoɋI)tjT&M^ L`ZVE bQ"kYkKM(hc-?|jnꥩڂ%YYLV`6&h :H3(l8 lWoLTQn7d3p̎XW~+lC& ;SE9-aFT:ր^j` ÔrElJ-OeyZтZ;u{!K׸q-kJfCUYzOʩ)ԎW]Lxȵìb&;LvI%HwR 1nM1 Y6>2+%͆(Nʕ 0uey#!ha6Tɱo'OBY6:G]%h>r#vw4}[[BT\UxKY&bo ķ4F6if`TXwx4UR 9&뱬Kսv$֖T̻-"MB.G6D*\`VxUR(hi*Gh=`jRٔZΔ׷ tp(4em[{^ _e 7@UȲΊ +IlJ,ߴKdǑp@૸;Ng> rFX@~ì+-Df jjj~<"$N"3%ˎA̧R8@^[B'-YU!^,KQ5N{}?'TO}Z پ6"LlGt C*wV})E0]_b @+KkՒjN&`Mҥ$ 뽨rR&QK4 (43gJ3BbD/$$.ʂo;Rb8wj-3Y8a Vk`^wJO'e^ gb^ajJjg)#`:If^&Ϥ x Bx?x^{A&)`=(S< nc(cq)1IhZ!h3Y,D'b5>C!riȎ Tݧyl 9 YL)fl4NSDm])b&ALVk^3`4^^Da<# 3L]Ec k gux,RT[OdFT)#%9=_8^Ds@ϻ@T~s~}4:s6{n0'^t1wzJ9ɺH/ d|}Sud5hA_kV *qH{lUĻZAH L\aM]W LNFt0*h6cBZ,0\b/,rS)l@J <:ʺBJUnהE_OODZ̫%K.)eY-ͦXL٘Z#+8K U%088LI3t,.ho;]~ti }Me3»c$F :ڣ( h$h 7 %p QnA{fuo_QʐL ޒ,NsvZ MV^`K)R^=PKvtk/VRU_ /{|xg ) 7V:q+#K R]]MSCdŕh65BW(g ൣOyФ uJ*GRm"P3[JU83;L]J OUD*9ߊiGlBTv&jzJh}R{m:ԑ饩ֲZȂg8)_ <\ǷB+)  {QZBʕxiXzQ\y8g|!tSS 8ZK1>0/ E [Y2Mkfz"$[kYSlH Z+TkW蔜ÆI/XG"L\*)R)W,eLR#1}]a.,5|@F &4m~sj A3g{1Hpv"5Q^@xR=KAcK5Mm{f7jc'0D|7ЃAFo!(whp|3tb4V;NbpRFE`Ь_ZpVĘ^b%Ѕ=9RM \/]HWNS@Vy jť, #~׫p*AHZݵ`jRȉZ;eqZjPT|D3vd Zxvz\My" S[^5}17^Go*P*A@1٭lUy]熉e?h:}'IʣlyXy ooNۣo;Y2ARb"|d;B|*/CHJaq@ͦd=>SUtzё}ɔ'C|\'}͒KlbB ȎIV P*,Õ4 ck*@?s00ɽV R  NIhinil bUV(&e@[<HϷrP SK!kPq t*SĉL%M' ^+L _TbGU(X,MG/d<)90,+RC}>} }KJ#K) e&[H+O|M4ٗOvdj=eF+6e`@gp)/v8Mm JaJM C;p uMhz6UkIޱDpŔ :w ^t:5m4Y=YKXv2W~kd寐i^+K v7JpZ-( ΔɊ͐rgHrB ZC,r|`rK^ܜr1bVm'#%FҗN%}qeR;(t&,)*"==y)Û AW 7O-!)T M)%`!ԘOS? SK\ d%L7P.ScwuqΤS2$܄f` eehapA?Yo0XFń F!:6#F~= ~q 'roԴc8Fe&F-M<2xJ(WB\YvqK8b]"81ӱ{ܝL"3A'YچGSv+je, _lJjM%f{lW%(0 fTzcڠc@Lk њ5yɐƜhj  "%hL-.1AqJ^SSok[0lM۾\*3UtHELFW>r")H1qX@bxqdRр,+'ۦ}qr)*BEE"pXj`ټ:)$RG* ( Sjn-!FK՚,D sBʝJ})LmMF$H՝gm)I=筬;=~/I}kf](Ц 0#ة*AO]*Q)C(d*(,Hr5ǩF4{G$ܲq.(:c@4A,)(1XМUAk9lmVi݁QkA9٦uJ\n:* WobY SmmS,#ԎBO3˻HU$[_ ~iT14Wԛ?HA֮'Uy)f¿Cӿ`k v'0R~<lh1]423s^TuJh88]9&4*ٮPѴ hcФeK!F3)JZb:7ϑIetp "Wd^-4Eez%GF]\6bbK%5" !h4Fx8€QK  ށQNLZM7m%ӂ0#I1Kdq%Y%Zx ɉL!YBAyHzU)hT.6(@6~| %ASڝDU4qXct2*>)) /NJ;D} /v &hHA)6!CEMnXP @V K7@GЈ%KS%FJ) B{.M R &K![) J XJ-xR㘰}Qb}v!hR&ˤX U,^mDU6}>bU#Crѿ\ K{6s"p`||F=>SiJ?k6f@uKPKh8Jj|Fitlc!>e垊e̚iY 0 p^:~"µ&FЗE͖Mi;: R(a2w]Dw}b oBGkkn933'e^!+QXm 1j-s;፡C^ߔ)Y%hۗX-{/LmB ؁7vAAX o ^b>}j^ĵ]˾ k8@h2)!B0{ -3G@/j? *K!ՐzlŲNG6'ڎ䳲ˆ0̔Ct@ꈃ!> SU#=_ !_#F^=>^T>A%;6X Ji!%םe&c~j@k)(+; uY)Ma4"J,#k;#.y7[}f-He=!eڂ8ͦEdYFlo;VG}AJzubڵ)fIUeʾQ."+/* fYfa,uD+H)Y*NHg>JJ$IGHh'Z _(SFE`*h) TKA)x*U!X|1{= T;Z, rVG3V/̲#)0jWb0Ǘ*P U/,WB'>THC% ?B{ϐ_~*6 ZR> }<4Х1 ۅ'SUfTe)`Kt; y|Zc }fMsewm$0Z3m-ܳl ST,q*WƢ5RǛԖb R4bh<A/ʗZ6dj҄U@LP!_A> }g{8a$BR6Zſ4хL-ͶES"XֲB gFG! ֲ9eqTM(q௲Ts:nzyK|%RzR”jGl1r GYKl!Nq9,1;)KSBi7Uj5Z\KdY~(MtJw!i4N7yyp2}_?Z7 mh3",E?%ǩ@%k HӱT#C΄$i|} g8ydb2x6aTR*6 TI M OYTA0DL_yb%hJlQIAX%#K)W ag A LVpN.ySJ o)k9+w]|kT`:D|{4IEښNY/#2NB* |7SHmms3#kt&k$O|JS)m(Ew]j!͉ tbz\2gx _U THv|x^()C|LǹV0hZ*irCBL.@1N)~YJaV T&Bb`sGX2Ij˪"Û`RkrH߱1e,:͏ܣVTA 3 浣P9eJSCF.೪e ĨԚS\@7V lě?ZY`"<vT-I!!v]Fup~Sỽ|`NvmP`;p,BY09/Ff8U9NLP(u5?.#⑁H),xɿ";s buu88| zd gTKjڝ@3I"@ؖʙFR%ffxJėqz56o^JUs&T%.h*c I(aJuT }%R #*i qdGhpH>yYO!MAèմ*Ah KA|_K5?(;ACپEi<c{ nTfn{wd>oY!4wdKpqz! LGN EMWYiIy cZ6 Va|My]3 Lz5qjqEv4/3?NG6YSUBZR8< ;~_8+kǥUB6eL1"R4&,kJ`F>#^R8CuΛEJP9z=VG+K!1}LAPaYnY /T7"xImSָ%Y00=ZLM;r;}G{@[Q*D,(`j-ңZVJ&jK,h!F Sjt 0o^ ɶf0L"4Hy>2S"t( t.WF'Muμ2#޿N >GDw|"Ua6lL1% ZiL ۬36-ʙh )x>}3o!G 5/O(0Oo F(u\aV\ܱXPƯ0ZU#B `Vk9B; F1^.:‹x:L`M ) ,)!M t"7%j=^Mb]mױؒ&VSX&3o ͩвrL@jPIXRw ǯȀ zȣɲΐ>~"w o(HS{^)&: BJhצ+z:WKZY-Msop/2 i Ws{b28/PRb4.F^*&"e)ŔJTqU4ր|S%PP5A d6|u:ZW)۾kpS+KSIIY&8}S~K5 Q h% 4@ @ N4 {,)ձQL&NxTwSߴeH=j-F ‹MA\n=H{O_N~w0TE)?8]fl"+E]eJplSۈ$=K%_v8q֤^5=-őWbwJa)A|Ô ^kKV tNUV+./o_SP[ "V״.h* R&ӏ&w8EPսIQ@ФА/y 26Fgh4z 59\-3 /RiTZSQ+_t Ѣx1$8Z D+Q{/4POGV :1N/x@U7^[^e B3LȽP jyWsܭzͲéE5Fސ+S Q [V@ohRb@:hۚXeJL G,}>bH֦8F`1-ȖUA֬.q%R3@˲Bc'U U Kgf@ I R3iXA)MUCVVnFSR@xd޿[}4NKmg7 rK*qn bB5d-@ڥ:B!ʾؗQ.6i;-+pU_rVVBhY +FKFѫV9BTDM{(9A;ͿXNk7'+Dadͯ&Z]Y#Q+DǒNX24"{e7FyAUo⣍``f0MJNF&7m-6|)h|-DIV E/~2=kHqe/?_LimL`Ǒjf6av9lx8&Ӆ!Ck*(K\,%PDz8|GR^V@#RPRrc"1ƇLG`d{EkVX%3xyBhƌP\k _R:Z@)e6T{ &b)1,2kc4)2oV^tb^+g [ pڗ%A- %R TU8 &)qeh&1& $(<*U ThC5\*}YFW#[|В?i*)1Rmlqj lY—JB[ ڂr7hxVbeןZjud8" G.>ٺg*>]m MJٟ׾K|:ڎMk<{w5H[ d03 ,lj]' nk"bLi_'2A Z9dq1*4_lLy%R]* >0F㙎7Jf2]+@'S)]KN H#vu/@rH##?.pWʒ(*$"EG.*A+K8-e#`C}vUGډܷl%R dV2YkYC!ë. {w3 !CϔT 7%Bd#"YLJ?^L<L_UKVK.8mn?qHHo#T;-M<7&g@"lj'aϽGビ')o0A=5HǮ_Ccj!3EqthGcP>y+lqo>}R"iTv,Nq?^JSoCk;8 Mgŷ Y;"!_ f\/UV@2)ǨUA ز8WQV"" <Gc4P nHRe!RNZ_ u\@`d WyOi4-v]Rj+ie}Z:B&5U jdj-_e#ՁhǝZS|l/<33! tiw o45サ̡YyK5lOK-}4mI(ESc!Ҭ{^ ] KJ-]GH=38ZLl&Uֲ#2bۮ 4t c1?_۔=c2ˌ@KsgG:ϟ?eZ n/[#AY\ľ-^bdKجq'7[Jwβh#HT*qSt^2CO\ 77Lh`qsKUJ!ȉ{AD!^yۇ;K3jJsIM )#4F dmx඙HK]&jhuu2zƧZvb)W#ܥDk )wU9=DI >AH烐>[֙'xɟMP|'čV Kq%!3) ڸ,Ux#GZ}Zv0:C&ƊQq՞ ; gS槆/W}G-ы-#S,F#)5R; ^*kBqd\|R l桬3Y,<_wvT0(,] B0v !J|Wg FD9*_9Zv} HCd!fK}ۖwڵq[s%4Og-%,*R]3M,QK!KEq~_ʺ7DVSxu%JU2N4QmU]oqGL0;U:ЅuuԎ᪲_/Z ޙ24V hy0ZxT IU[)B[SK9q3 t-!e.4] Q.4T BXR0b}/HbY x?D;:":R:1֦i򐖑Gթ2SZkT4S}r,=Y 3LIlMg}7l`owD(XVh$oZר*>2BjzE17l3Sژ@Kw+n]YVN{Wr)=MLCxbDʊBW%o jQ*,X|)yeVF@'r'h;tk˲CY: 4U|`Yf,BSR3%i*)xVSn)ky(a/_Yc%: 81,-2#q$Y h: xW$ ǩd% qeIS*,Dښ,D-e%-8Jtr^n#ӷZ3?7ʩet;8&ұ#tJ{ɹ3WNHpi)t qB'-2 \ DTrIݨRJD&kHH;ºGȧ5A|⁼I\2RƳ̻")XSD<-+UE `3åz|82<!n '064\;:swO/p4Rv2FGPx6D[VS;:3@"?=/ Q{ij_`Yy(,ٶWHȆ+4RL"EHJHi#׫#U[02BY̤* |\ v.TB%Rgydc2l5&J0qYT$q%`ZєAV"K PkQBLCAq!UYwUm3PGUpp,|UUAy p1E Z0qvjqG48~AĶoLYUV^9Z hQ ,Fm"hoD#Խ?r/6ǒ# ͲC*g+}l Ͱb)4f#Ao4cAsi{^tOR V@m rdRT)TR\J6P }LaI!tR6LDPt @a"DF[>Szꦌ5x%k i/K/5'j/7j LQ [NFjMZ^!lSbY'O.I_Wk-1L4!#DFX {/!Yn`5tDqwܥ:%C+F:knn`r]G`_r*O5zI ʊ{a)6B u65IeB۴V)ڐJvR8˞N/<4|{#i>5L, |/| ՐZ ~f}y=0g[+iNc;*G8̑XĤX%@YIA #ka.DUp|ǯ:|Y @#bp:-(],"誥Y/ !&/W3Cث A0l}jfO78q4K4KYׁ1,f\<8Z02 )ENĻ^!e)Z'Ûr' BdMlcDÝHJ_ 0H@ĂbUa AXUKsh1Ǭ$d1RL(A "N|"N8A^t(<8 YhN'-j5B%[ISm o DZ~e?~vY;"f%f㙡%2[yxdA/wn^~O;=R7y?3* D0hk۔M 4b:ܮm2o $xVj"]qFRVսЉyJ YVwFeM&RfkZS&?ߖt tLjHjmIZSy)f8|Y4-.eoft H! ee ,YX6E9eiX!K<.H]4Md^JP Y 7Lj~tz!;c?H_nޒ}6kGπ2%H1T'FAJClP\ KJ܃y ?nR}'f klk<o fmry"|A$gd*Y?Y,Nq|c reݍ^*"Kj̓& R4fv,UUCa h&46T5_IMo*vPDJVU t88`K4 5ikDSZ6sLQY}RJ|V 3ʬ812|U}]!]AI6$e a8qseY^, цS-COF{ U_ 32PJdz4 D٭Y|#2}%+Hghz-.J)^qjlNé~{˯f3ؾ:Jt䧣ܡQ_Xm Шj dxF~>~h>?A̒5ɂWN+JYQv-1/CtpX!0Tj5J3r!-rAF]ccGBEzM@]MV eqҬj|mٮFHPwQBzZY*KYmTkN3"pکgpۋaٗD0RR rAë_ɮWc#)6?DrUa`NZFbu X`UdW^-dӒ ^,螩>'Xe&f&Wu  kYq]mHC߅C/~B3L(n4!t_SCs^ujZAC o*AS *DN)L*\Y2)H $$1pėqM(H,%pޭN}B9s|4rV<;kjjYV ɒ%Z Û6rK^6)`J #6 "+x RV :LlJX*jaTxˑcV"֢ZqA⚎&HxV|o.j1i,qث;MgMD* RJ VYK"j- qZ*d@-';VxC6]-U 8b^ ϭL___|)NU-+)6L@Squ"ʟ>4ބ_۩ v܁M R Ɨ· ?)j!H,<)ː>n`r0:NILU_cؾv-nˎTY+qJ51,D8t. O^B`::uKUpq"^U:iQb;߳Pɉh n !LqjMUw c B/h*A fHY1Sn;8[uz!R),AtF÷BRDSD:* LVD ">yY쟡\|,6KZ Rf`mBU5BeJέ"St[wH.KA%D/՟HϿW kneh]V%bB"e% MN#vJ\#[Gʋ̮ ̶vJIUbf1^ &PUCĩ$fڕUy&UP 27^4F1obl J̋cv,!jk\JIKSjֱ+]Ǫ B]&q,n8\87^lkp.d8!ބtj4!Z^)Φ )ڑvG{aQ;s:%]7ReiA[phhZ&ƗB를A[z;!5H?!(Og10Ӌ-U, lF1@-G#]AVMX=&9Aqf)8c]f7lr>T D:=K&v! v94M-1]>xjG7 JMUp`Rd/y#f4(i<_*>KRYL%J5atqmyUh h@̝ D)lpR dqK f%5%ӱj)AX҇,٪r]h6XJ ])"-5e RǑ88Lg'>H̲\(&x"EQ~bk)'j;Uut1 Y#+$P )G.}%{?zg~t>)K4 k&)#4b}{`__",YyRl GCp$U{y{e ln0]]k9C33,fې^Ľ& AT3ӨZ " ̣16 to{̍Bm'v 5 v/O‹Yj|ťH2AZ oPaWP-HJ 2ZAKZ%@v[6<. jkNRB+U5v"y8BA{Ym6LVXՂ+yb4f*q&,e!WIJƌIWG+oTuȲRpq۱;~R@):qZֺHh^j#3˟$˦C6OPx+m^6C0|1yNȬ²vKДmOReyZS ښZj+"V Qu5U".\gkr 0B jFj~U:R8;F2}4[pL&tLbkUaRTuid |>8O5X uZc\w,3Kލk-LBTCBK4\zA:m,"^-AcpS8]5RźT  ftp5೪17*+v]Uu:pY3gSUd1l!iV 8k̀&HHRfb286b@EOQOkrBl1`Mh`֮t! ٹ_m1l4b1do T|x6CsnJy  WǦ ui{ PaڂnnZ)Wj]}RN}!Mn z&tjKK] ޡ)#" ͍*%OSt8+<)ASŗ95OZUR tu6RJlwʺ^K2:M?;T~|\WDRVe`6kx%8mpUY%m 3,YKr4VaC"j{L*M`̞})<^(xH#%ؒ_ѢM14! 6BOxb@6k* œq"d*8"e1dM%ʦ7*1l&زj|*AF6eG^m{dM (_.٨-BfNVLcŋTA%J"hU,FpX}ڻP@"V՝/htZk4WR!A0M;2gZK;ARQL:b1sQ,سayy㻜2%Zqy +fCI XDW Y @ T \ӝ )K4˶cىAtT!%\lTƷzJM-7tcn8G};.?|4g_P^[֢!-<@;2C6Ur;?w}^YnpctIlw.<b^5}kg*jHD1 Jv#`mSVBAcv <3)@>?ydCagچ1TYݯaa!Bd"D,3YC%ϣFz5 BȲxyȦ`WڬkRuc5ƶcnpUhR,R !-#jzbU4Co‰$k."OV g#(aZ F1K0`d-Cv8/i;]qn)>]Q;QNﳵx@#D49EϜlcC4y<2 Ÿ Q+W~ߪ|SձSJg ;~aOgZ&CZHx#녠k$e2-r]j7Yњ;04g+V/5&N/*A3IBx|)q!l0q`QV0]$FP ovHnlLjJđqtOސbW+hNC(YC*k*KSt0Cw7|]*$L^pń4p^ ށ@4VwõHkm#ȆOG@f"zoX)'JN-TS eY|&R, >i bRH͉^`;bA`3 >DՕU$'XCuW+u25>si|N= )[p945m0#/F3Q[JQhj]SK/`J-i3 =Vx(^1GniIA-1- F[-"Ahl:OME ~L:O(U#% CXZSn cA",R2Q^_jw㯄rO"jZ]U߭ `>`5^4^aj-v=7r11;R%},A9LS=@Dv-p,4 JٸA ;,7U,F(f/bURSL9<KUZƮ$Y:8-1cmuL'C!@tD_Y©)9~9ZRjmyRU.fMMx|00ä#Մ-3ʁHc %BԊ#`2)4 Ltd0mRJʍ xr(D(X;)6s[J=>:ELɋ uT=. 8m&@&2Ch, v3~DŽ\P\yo)of4'hF"|-T!\k:2ؕ3ahȵ!UIa2'HD 'vxK~7x0b_}~s~,3˾i(/Cf[گKĒup̀WdSKY>7mDG- >9O1X#bw* KY%m
6.k0fq`q`1p˻QkXF?+bf*Q_I"rWŪ ySk{9anjVSx:Ȗhp+i ״C.N<;D;KLAC CE'~CS#X1B9T&1'bT_80}tb:MB@3lwN믿&My3k-룛9M;@4[b(b~O%N%}'N?3tIիu.iF3@3H[F LL*AU<2y%Qy]TuE'RypUTo^#3{B&߯]d;jowm;R!&bQI97`j?&/e'lxkU;rwl/)ۻ9fS pX#$s_U3@ڻv2pL)֒eޱuKC:8]΄@v5䖲 Y▤,egJ;Q]hy6b{SBWP<"6-fM8L65 D N//O! w!a ##v?>AOZ#9 K`A6΍r-p0_Jkt;-Ϥ߾z0M̱{E-jEV 5KxG6Y *Ka5#$kAl:4! v ĬM7lŗk"6v%[Ȓ !Ycєx]/ŀNCN$M[SNT&US\ . xB6^ V↧M ۝,}+tuΉI%p꛷L&k:)i{[B!k*)-tv@hDFnKԺR0~LO$) kjƦR N@m R z:vY d4?D g z3oB@VAb A 'Orh;N[ M#q1,MX9>@gTY82('Ew jǷjZ::,3Q"Rv-~=Δ3-fi]]J2okO}HH{:4'\m3JEqݐf;e#0HS1WdoU O#K61+X;!} L\^= @4]q,6"Զqۊ1-ma*xԢ6ᠵqʼn k;p)NFUx-S˪٥pqLnG$"R\Tި%Kx iID6Z^!|y!Uom rk Y6X340S"Hܲp)1XB '? YjC30˚A-oxvܴv-@l"k7FQ"0|7Ȯ#2r]~_ BȻ #Gx|qo^]GRf۸r! rt2WrK326pb)|>tm ķw߿:|,/.1LXGMut&Ak`_ 0YaR)(0AY1%٭+є ,)% q?1SzYt.ZPQ/NxC`@LmVkèI#-E[P(fCl!l)148+HohUĥd0X/bjФJjW%V4gÈBx&fZ •4Z q) uG`B+VJ0NlF mbۧn-D`; ޓ eG{5◒ۛ%^]j@BKAv2R8C(h=QT9A_=Ήζבu¹ .KƳ̺]5ruк];w;"{s[ֈ,Fm,3W8'bD31ɚ$h+IGKtDfb&KU̎N@920NK #tÁGP;2)'#в5[`&`܉0<\w:A+hJRKFB N%Z%O4nwu@܁qTRm?7yu8mӱ鈯Q7sd{p˜ Ŕ᪘7~ 7-K;- o;Rvvۅrp@p(w)RւGN,e4&.\JlB44()v ɻ7<}0v!3ZeH9yU(0%*HA4l.e𛄠S6md^ Jpj* fu0!oh HiTM!z$>0ZcؗwqMNՑ]z%'J? oc@Bqi`nW Gbڀ4qIǀ~Ns' SBۂ` [ 6rj|T[2%L0l!.[斵K$Uz.KT9K=@Mf0"|~V״ ix4MRjmG!e.u]tRx'@ ( 2NCPN2ˇ]ty&q+f$˺1 ?Yޙ@   7yu;ĐZh*hrlpYR-U!H xNdӴi# 2b×3xss :ͮ[k&tu :m}h]18T^~ !mャ[&u@#uwA,]d6AQc8XVpW\]bٺ xjV ĩfpVVB')&#RlJ( P1A* .AB<-aG `JYFZK9azf!1hR{&!DTCtL[n򘓵3Ӕ%; S3r "B n5Ρr_11&-x"\s'YzBRZ8 7["7Q؅22@(a4lU.KACFeG}'Y? ;p:]T@v9Xx4WS M@H_ŕEBCԊp1AJ|7Oh vi0 IqBAʂh#M*"dR<&W؄p2%XJ C)֏<ZOvAIloǎޥz,mͲVK^3;71CH]%KKKLO1? o;d Sm$ZhZ]X-}1Ab)\;JD!AVw ~O amu颸j]2!EVwK1Lf[Dvs ߡU.KV]i,9)"X#+Y,[U6HG?zd&AW4{/0ҾBm veؠlGg&)/hLcޗ ʫKĒ v a Cd8< b&'"%p$Y%@pn/HNϋisY4!^^eKKe*G5,Ժ0٥x=N%N]x\`)U/E֮i-}oڥBqO~A0Ld|Kh6K4nCU7346)@4x벤'6 ЫRBmBXG(_8'4̀ vv!Fx1B*?{lMµ]ɻ.] )b]\>ZVpWKֳV!MԐw!XŒ)6rB#FtǑdpTMJZZ#O?F"2 ߖӯR|| p4lZP`>Y/A0j <.ղӛg8Ll;^;.R`cjڧ)?iY@,HR8<^;~%݅#4vxt^ ڬYj˻]o~S!tmayK(gj8{?" lY)CG L5B:#mo .5*OM]s=^Ȣy@2QȖt@lS0:fjKoZ|XȤ @pyɳ)%_CX>|3]L*C-yIl`@s^``L QUbv6."ZKA}&!ohΦCX#qӲGl0)aovd"TA="y q.f J@jIX/X" BgRhMi_8U՚ݏ|4>y74!wZVIP %.hڔ]]N[k&ŽN3Q%@0{#)B+4_b[Wބ5rem;/oY f~pY]jM:)4U͹r>QV _r^@[rG. /#y=en8.& kwFq^Rʬ *,eRf6R&DñS86Go?,)A&H q7@.Kg x%SlZ_e\P4oLI v!q],l/@j&P=W,]n:&%KJ7"Ū,!LJPJrWS KgWqW0.6%FݝW"7 Mh!p:P "D`)PhQh n*; 8fBA1X(__^ H;SdR@"XlfN#lR| GQ_@^{* v mٹK.\[M+l>*tʉk=#hvp/# ķ}7`Sih<Ǭ?g-kF@믿™ͲNl< x%vn]wvPm$$Y_i^MӤj^"wҗ^w^_ 3H݉6'$PZK滗3|G4@A(0xj֔ W3a)%YKYfikD.Sl)H(PiY%co4sSzg`uTkk8~;7~zrѷG[,Z,X3["HjSkGm ^WWbuŁl֮5m*o#bFޠpNO ՓXU2KLY]q)=_#ԀFZF X$^ M+d , "~Ź/+tȔ{`Yl@ 3YQo0O]R]# KsAy,b87/]H]Xe u\B^BQwQya LT,*ccY rIOwTe-1MEJJ$y{rq Q+1,S2eYsOC6Z~&ը흎 Y u!?_Kb-(IGcuEc 7D Rb4i&ͤx8DRl6íP#}W 7L]L QB -dy*!5PaQ{R]ԨJ2K& nNv+M/7d1Sjmi,5 bxV|N_| ?e,|;^v=?~ձoxMY_tnbxj8/ێ%r LLL(a) ~OXuņg};|?^z 4 4&hy.Dt>j%vhG7ZK ^."Σ E#qH} ڋ'r̩0dJ PYY,6="Hє,(O}ʛb;_)YLeM1q#? _ Na.u :~8x>Zg8h@ f\M~b/~Js &ApX{'o]V_d K?2TN1~iE֒Y͠sfnr^m{QӮjARd@LmM:woG4.بӺCmvlX*'e`^ö):pW]}V/FQlOGҕ|x#dhi6p3)R|Ez0Fu(LyʦiJS% q_ݲ]k}|<}11M2rH#Ǿ91~[GS&l68]-P`NK,륃diHeh214H% EqR]ZUY˞b LR7YjL6{Q:=;W3d^Gkx4P|:|I@rrhTiLƎ-)ˢwa3wLKS T.#K*2Z+Ma#fucJ߽@S/B'],Y8i6+:i* #ySa)+i@)Q`x,% V|pV QfɇPPL) _M92PaG%; hH# 2ktb(s6|j/7~#=<<" \C/[&c7U8d3XWٵW^e[#M_ì/&0%KA'cFm@vk-q4^*DW#ԅ&c GN.k>FT1K[B6q0َY!gվ%"_5l;F6.ՐͦO5d7Qt3dAlvg#tFr)5<#Ñb|*K!(a tū2qAYK5Fj̺Cp)X{fШB[p.Çg7]|R` x3sNL`N" 1 fyW(hf1h뵏 :bLVhv&'9m:uiZg"BV(^WL<&{euQXcJ,P##j-Dk;@bbf\]h1Db fSE$Rulx& dh$[KR TU"@kI*6Hɞ4  ^XieU A|&F815SA{iA7-d, OY*~4̐<V1U%n)NnCx cj>9n%ż8"M9A| `?fK3UM0ތBZN WNIp1e1T[4*ڧW@۬X/չH'V#Ρv伒 -~oy`(4Q Of32 !ێexHGRY"NSBۻ%2MPZ=bMP,T^yMg/~7lNbrڸm%a4$m;@:|GwGO?vۈAct) +[T56(3A 4 ;9sq`ːj7!D`D )0]KuV+; 0dk0$|eShM?xٯ1|:p{To & \ ClBo;m\-mP|L*uS/W 6.52axC^Nh_qڵl]PU~&x{mVkYS7yNXlydȏM|5V ZZB(qm;²lSI"Zl>`r'0 dCfK},7xǵ4FHSw8].b烆@%Z"o`B h#7dȂ6(ۭ` {6ZRpi `xM_pVE  ~,7E>.DPE=pm9(x#dyVwTKLWHFh akIHa6t #Y@ᬶش0X!8)Ϋ%:OS2e% Y'O #W3dIfqUUJIUw˷9qBj{9owFG]O|x?8wo&w?2Zj-G뉐&o#26r"vm Q_eMh_phL1K"L e̖pَbpT=--R,+pA 6ډ$i SS\Uv=5:粁IAK zO# ;"4)_hdiS(Ԣ@jj` 0RʒDIjb|1G|SB cb6 1oAFݫ3U BRX4Dp1X%K<"WN`ZpLˆGñ@@ȊH[:WX 2zk]HKFyOOoAvs LohLB7"[ :;Q<6B|x;;Dp*(20,e V  ( Uh-U!К?\ hX>0Є8īoZL6XGW jA'2jD\`#VU_;e5M$_5e>1.tϒ9 b*~`gvgj&ZGGALp]D&?g(UK7d8RJ|R.h 7FZ|)T >NZUF -af-*_N'oH*GblL5C~]-xL`6uS^єo}1NS'8%K5yƀ -n6bYe =d N{_[_p/"&\kKCk88fpsB`MnׂKHy NeD0U#-&€Zb_x 1Oz5@9˺C0;49!Tgjq X$d-׃]lY8.+'^w;rڽeD V fs{X&iC*AߊLS~PnF5. I 4[UR. b^gg ۲HRb&V V|UZPBVm~KG!EG*eH8wDlpDW+ 4kaʣ=HZB=^崴dW uWUu]6YPJr`7wlW,! $%dR axY Kf+FIDa8 8I)7m&ϚAL,;R}}(AZ1SÌܴ'UR6Uw퀆GKx̤.! B L!)ۿOS{F0UADif:,(Ad8Y~6~woOS&ޅݮڣT]gK%(<7s 0ҁw?BwslY)^,UNThLH@^G_f&q';LpԷLz|ܐ+gw~jƽ$bepBYSͨ̚8AGHc/]`>؋e ,o#]teTj@3$H^tB;#|TX#=$jZ @Xd{qlB̂զt/e)dԪBZZ4 rO(7Iv&yS_6{eDlSzyG[t7L k$Бv)᥆T ,LqG-^jo=x)P~C~W`Goҿы!k+B|Q"JR[5Kf/@-]&l)>Z~?"?mɶhJCѺ -"31~YH]ɣ&|h,|}m'D/BpvIa5*PW$W\&{<ěWIUEy8ЪK±M;:^T"osv+tf㽻/BDRkډzu) :D ^e}Ӝ5i4j ӠCu,t(җ|d h|32g"uR$aR,r,q*," d= bUyRh>O_|IܝH숶5X_lY bgh16" <F=sHv-F"rK b" yKRb-|4`kj=؎ /+N"[k\Jmw2ZwAFY*&)13ST2?ЯJj0]&l61X``*%shQ%«=x]tzQȖWR-M 7- U owGHj鳻7õsM73OD6 WKyDc#p=^Oݽ L0 u%]Pli/b5KHZ"x)kԝ)$Ů4/GO)ACἜ{XoKfet]8RtȺ _?.{h~Ah6SYn¶ӒN7O3,R ^՛WG'V@0vבlF:6:w۲hdUq 'P)-,lh,ECm`ge \V9}y*oN#tז)TD] ЦW dFOvK&f4r .#b jyMkM:) h߲Ʃl)Bt*MI6QX`&aYdcbF Ax$lVkI!(y\׾'%S)WS,%6(O夰CRNM/#4NQn0\ZjҩCV __[P`$A*r)b4q;nUl`x%q &pޗL&=eK>(VEDإ"5v+ FNÙc 1&P9.ׂRՖ[VCh=}^%u2.h>kwf<KlBF&"|U1NgH"zKAsS913@ eI<_fVg *J9r8@ci0,7U4"E8kZ@7C&!+7Fd1>2Lolߐ&LS<)v@Ę|41G\\ kfXj㢘P#qbŽ$v`bQh=F( 0hh&G#(M?)15: x)"_![r`z9K̦ as2l[K-w @"d38cA̤F; B33ܒ!se˷khtk$qq֮N-ZRAP},-@+ '7Dh6x[0CK_ jڎ4UM3%1b>#i|q^RR]4BuQ%(k)U(382в](a0||ǷVmnc]<\8b!{KEhh|iv;)`HA(oɇ&0)0 ȔMRpƞ~RJ5F{G+PfcV#L)Ue-㬅]mv+IeNS X[Ʒ @/!-j.;pgUx]~e%}ߣG좼a# ]}@nw틇tkZBC iN1ӛ~}e*>_}B⌎K)]32~h6;k$ۈvXR&bŖ-"%pЅxf jjg5j,+Pۗ  Aε:{iL]۵c7.| Û%#>WwlUZLsY R8LL͏ _{ ~ߏQ :B|[3! ߑ";tڅrc4IHm8)4L՝Gc=j,/_RS|{fi}^nn|U"[mظ%#pvgYQPey|}~U:jGI3}k;wzҗ Y%ЦW ܲ S&WG_P ȉQ-B,M6zHRK_Q+NSSIg_|aW[SnM7*X)[B%hbt[H*$h:Qtۥ $Y,Ų IYo/@T+`e tPie+A I-#GJU%bR A ?Ev}eYhMHf-HYfK8S@@)Ň yxQ`i{|_R^r~n늠nNCVF2'3h]\LYڵVY[jͨѬw-Ŝ?{:3-*NR],S lBLӶ_-j$+;yLqݑpc Ov:fkw/af8K,IfèB5ҿ4j~_lQHr&iN80xh:["5s'{3Y^B͕e *c0 S4  KB[E!yz!%&^Ed%})-eѴkQFGHI&3O A2qq,p)eۂعc&Or8\gɺ )˸8&i$W .xLKvʆ49PLs^h #1YR 6n)uoZ,%(K0{QU8|&UӐ{SY)Y Jp0md+3Kf)$f?!k/5բ14iЗT^pً< BQPvA8mGdq˶!|/AZw; cn˚Sզ HDܙxeKJ\ zծӢGrJj 4;-ˮr;^7'V]*&I66Poqi7veU0Jگy ;g934-2)BﺜɊ'{/4O|^lT절HZVKP*ЙդyKҏ?Kc4n騻yҜE iFԺŤ$$<=FV (@?) Z@hbA!5u! Dh:xd&}!"OHF>[fK_e4KU͠ltdJۚ%R1BGq`<2Zr$Z]ĂwjMkGrOxqIC//|AR=\Fz7o6U6:w oB)%@fY*RuqKAW)X-SvY0j/Le iGyj@tm |sQx1fD dRML &`p拴8!JM?2B/0=_O͠w? m93Vi-Jxb'8YO秏ﵻ8m-:XMb &3;bUlL:u/;1ơ_*};@w ܣ`H4Y'@*D0L!W0!=W){pWZ3)&hT i˄`ڸNY gr"#EUZ}Z yG~Z3hBS/{Q9[z{I }%B IC[fmFux@c1N4GJ Z/|ifސ;OH&+(Bv8@bK( w*Boզܲ5!)H-xoHL:) $^!;<8,HʒU+,? ?0$M;bƫ{ γbjۦtqQ8stU^MhّYR%*Hiw\EE$f =!/'mۂxE`if)˲UU(BIZD(P3RqmAH BL;Enu3U&(Bк(/s8p4$@IDAT$ِ.*A'+k̑!u9z^l5"&KK<>P{L8R*0ZKd z2բִyg1|ܠbGӜcq44$NWI"m?x,cƑBkrłz +lq̏Ы]25 oZ/i8r˚"1*S04w*#ka0zi>5HNH,IAx7+NKp8nHg0z}_iM(K4lEq Ŭ #;CbT-..LO ΊtPgDXfN^^&Y!w6^z~"Z@:f$֒^ȵS6[8ylG!-N(zۘvHv̩IQR9l dYL)#/P6"^v6xu4ˤ,K<  'ͦ)Xv2E?[^]"8i>?`HřSs\&4[& Q%w!maSl/JHYK;L3Zc6@qc8%)]V{7kJ v8<X@w:T;6"h23w )0O(kYRL!ZA*1Z% lLGKΖ஍lT{Jۋ汌& t"*++%(I6-:[pͱA!EbZ 1nz!R\j'۴#;-0>Jp b@Hˉ`MӥZlY9>(fX CHBbAT\ ^%cT8pB]۔iL9ʓ:$kIt6*!*4qsH&Z^_~WɈՅԢURD 锭W #VŐuIzӶ%xD7U0R ?4&v켽6jAV**aa@Ag&xI![kO ( HvBU2) eĜ 񐳆c:}oԎ7ӔbƴgNL64)frtNLyH:ż^UY S 0N#۲ZCS=vkjƨo=rlu9f7|WOUIKD79b ̮jWIܲ@-*&Ijw83 Z2ːxڈ߲Px>lfk3ilxjщJ4l*1 ofI(q&ZbE)R0y4')Y0Ųh̴n~r1~>T'Ӝ1lz9Os}b`3m$]vdrx^9)զfH8j1haLߔ ^e.twv NYAMRʜznGf-y)ٝ@=̒aȐbS@b$^ t_Eٿ, 3n/Dlfn~)HA/JlPI ĬSa T"S%Smf׎Y?I .0 t1ҿ|,)z|%4TlQ&h{ 5&/{.4)%@L%R $~&>\LY# RX`1=E0 5=+HUܲ^բuv [kd‡t,qBaZY \ 7[K C E`i< fgW S_OhRRZ!K 0:j5J6)'<ܦ }6.Slڂ4q܇}O !&TL.Vn0?â fR|wCPYS/Wق.륵X;)f6" ad K4fAvbʯnbz!NKZ%RwߗzV(yzlgKHSS4U}v ) Aڝ-)Iպg,w2dgKK##H\PGR]>'``K&k~%흈*X iX*䙬hbm*8J.K,{6g%ilKn@eU0e'ZT[h.D]LB9AT #+k>j )hjS+lםx56xR,٤:Ŗ*֮ RǿZ3S(Cڪ-5SK#'%pl%9MTQ עer r),!]ZA)nw>)C|oIJ0P|5<WF?AX,gߝ 4hkbx̦ǁT<\I.6RMLāu9A^5lj3L8z}i)ZS@YUa6mqjU5*BK{/1S_/KƠ`"z%.,eBBRhL<<뾠,{-"ޫWU9Nx4ar8foBR-i<WRU|O|yL[]%Dep /9|ܺ-H5c }MbBcΦ*A`XҜ,2rNQrAc!hK@Oyp !p"e] A>krS)dZ[j)-֌@͛Gܨʑݢ˖,|0Bc''^Y$֏(C f0[ʥS["~Cj՘R8&48Nfr5vt5 5 !<B8_-]V Y]M8BBV虿פt%L9Ɣhe XR"8|@!7Ѷ?]TRMmN]p)V+#0xNͲ1t$Oʯ:GH-f:Z5\:>g8J FVWO':Z9@fpBAAD;:Q|:r`AFEz০PrMm/_ELEչ\D0mh)4JNwm1~4@|gKSє9 q0mE!Be<>+Q5Bf:l z~c?oRn~RMn=D| 5^ȊiC 3v&k*eVR!RL߁㏚\u|aOFKBBغsLs ln8V:Lɿ^JE! Z$~L7uPԌsXc;(| h2:p)BV|sPMgS0L6vhS]R19M*$D bR:PxD‰j6 7Ǫ9Bȶ!9ut{Dl EmOt1ݓvIhHp@)s^ O,>ȱE"C)vY)=VrRH?ҭ*拎&/dB!n}YDRmBN+Gc+āM?{ԍm8:65dvO|*@ՂhN'0[)b2.(z'' w)t~S)-M]͞R]Q[f)4GIǬâh&W6!q9Ŷ/q|sU_'!n$]: Y8s u. SalN+C$ŀĭs0,r[NA.1fhJpNC^ :|Ah4nHjVk,iNC38V])AЃrߌ:$q Gm~@j>{OMѪvP賮X<@hD!4E//j@MU]jpr|<:|b[>y̎4YmeqJVO 5TԆH]]&mV5A4 ,[_d(mk'%qT߻zɰuH=nѹˤZR-^H?@)@gFwV:VQm8^(\ʷ9%ֽ}=(=[ [! ,n348~hGM]5QoRdʏUGsmJ@T:Mm)I"Ѭp" _M/C!:Ӭn~}Jw' $Ic'6i1*5^!k:@XuO9k.0J.BcM=hB┅FrUM R;\9'UBa1!m 躢tkj U[d՛VTH݊ZRP(Hη^N`X$rV:-2/Y__0 EN? *T-DWahz ie!XmV"G 97c*QJVPV_-:Ѫ זՌ7mi:=%H@鬺IB4EP 1.}U:7pl׾%ٹUDNWg+ko.|:,V8&tܟ]G4~?5 O~:+ W։unMB6Z{Ԛ q VXo-O׶Mב:@MIzs !Hiҷ{? SF7Hqvf֦7x mj8DKzsB|f Lv70X"C* a⮎Vݜ[mt4?q 9VfR(A8㳥I4?d{.4;LQiSDj|x! 8#ZB\>"~'gs4Z38p̎(j:h@ ZՏD'ӿVxm$66%4q$ {0»Zܝ l +sh7 B&\#A-znu6 Aн 8UcxcnQp:>nYRuA6i롆[ ?GOY3cc#dYآB pXHmQō Z0tT AfȢ+WQ-*ʂTt)k)Ee;N~Cs[ ̮^!x7Ӥ0߁]}zbjtF緍l@+&5&j(L8&ANL13X/qB SdpYCr!ZG`|gTC; ǖ*bwJ[ҊP:IU)ڪJVU*s8:pK:EI Bbc5|OٛEn0͊th\p =c6 㷖v=fl_[QP/''sV_ soʏЉmwiJ=BR@s~R=0>3P uu@ j__HճVBTdSze<\F0=&968(\]yNz5 n[FvZ|MRRq-/וc2 "ۦ\CY]Y8LDԁ s:bhBrȗQ6eCc4.Aۤ-qX3}d^?SK,+]]Kr |Ph(skB8CDmhDRjRDm63ݿGecU_ou] >auEkw]S[=¬ykZ)蟸D9B TbּWPJ0҆_{lukT cg|Qd@fA\nҭpqں4~SY9=OӋ,!mL>C`_&"iTR:[;Υx{T)u_hgXG3'." 1UhfG"ʐ!RZ+E*jE0Q':#Hw.vce50_N/8'5U a8zoK<-S.OR KҀKM\;41tb@w>'$?U-*_Ê\$ΓXnr;s}Qj^?=ʫXj٪O#ԭ xo]pHqu @bYJXЉ3Q4B wKyaѰnU! fimq5c"4MZw%ZPnw.}Eq~8Lo!@+*#v $>NdY@80}O6x* qV*䨁wӉ V=BFfd>> Z3Vke*JAD-I ׌>^pgϜa5s{?qF)7#PZtwYǥycKPٲ+u+DAr^5甯^LKut|CG3c:Lg '9p[mY|*5BVf#QbuO{>ת[fX])-GoB*֒k ǁt_gk(m 1 π+D1Jp޿Hx쿜K_:15S7|mضB/V-3wȶ6vP|Vǩ~'2短UK&7`%ݶP.\R\.^(&ǪJ4d]mUҺ <5(918Ľh54o[iq4J4BEeF^?|)@ŷ[ya<yM'5&"W)ő?O+[R:2P:tbmzUئf,*e>2q8qlEKI!2D9>Ut0KJ s9_ nwjJ'JԵ^'ڨHmww>r\Ʒ4ϧ2-+a)+ToWت(D_n{yu=r5,m3 &>DTz Aǵ7")5rp,pN+G$_?8 U݊i[5d<~rw_ܛ\ۤTT~\zUVv_}"72d"K{k},SVvEg0CaޖV!Q!o"h %rP3(} uȺVSWV!"BkF)D[7NGW7~%bvÉX)@|EgdUq\9誧jxY&궯aRRiʇ/TQ"+ddKq+', ֳNlYc.3aS*A׫ I\ZYȡzC!`xڳe|3Uֶ|n ,1D+n+|le8=$-݁xHƗ?A e!7P%^*peIswpJe|!F֊B}W!N"@yaP@m5I%mHg鼺6ֱhH4ʲh#=GdzxDzD#FEd9oPB E98rmq @C]ÁI-Ig:V%TjG4$RYR"t8t8 "YZKA4Kt+=m:W\#Q [ҿ*j@czPK/w- %5z[">Z#-A`gR6VLR{cG2 5;-SkOWΤ;7M?V!hz+Q4;@62ZfZJR!U 'RJjuǿGmX U[!thu;Z.л 󍫿hB^Ú2xC i.#Ctcz|>}KIO~ W%fVVo`m/1fD1TP8BG.K:&MWWЕш~b+TuäG:"==tFSBJǒ*pdX62u@<*g4WDM*сAKs9>k+p,CS2/5 ^(Ki fe?;BAڀAF621M٪[GڍHdeq(@Dkf=( i( h |~kOvF0 fn"!G?j, U8Vtq I6X3]oAϲRSXo|RomFn~"bR8v B<eqK[LH!YCƧ#WW2߶$D 8@:I9V"܅ęnF2N$)B҇# P |8>Z.\& irȅwk(Ƚ/h]BkP .AVt5#Ŷ V)h$M`N ۪$-O HU5YU?\5\ڀ3a=?IR׈܊[ S(OmLnWOEļiR j\5UcW9a5s&^r|]Z5NUԭU`LBbQܪږjP__}J;kI',5CSO-AEͮapte+D GQ`N 0|! ֥'64==ԒZЪym܌z/h|[Yt)r2 NtMݥǗhR^{ ln'֞6ꤡ4&*?||fXn LĚM֖(,Vqq?x-xa]a杴NsDc" AȅHYxRF+uqz#̪9BJj+Q#0t+8 C$vU,* 6}?B(ǚ(AŻq_R*"rJpDN-"KjpgR"m4b9%" L_kLQO/"@Cztԅ0* )*csEk)ehY82JƱv)J1,Rw>^B.yMB(|:l ȥ=nSkB=#KBIAt=CD!|[M&(ŖԹ\L.%1e14^'/q|zPEZ긚B3Aȶ,Ӱ2hl*8No%l8V" aҩ',[ +{txYrhr4yשjp \1;ࠖ^J4DNX>mW> ~)'`Qbe}7__<3:Z&sDˍIuFn<_ſ+`:uk*_ukNM P3V SYjۘxq||: "K~KW V]wu! zOa{b`,8I5W儘c"8rW-_5Zp5cGPA O HbI_u=G3tT+W]33,6ґ:gt'cVtBD~"*,U_{\x/ N5(kf709^r۰@T%p 0B~R{ܔ):f⊆pB׉7p3!%u8=Q֫*]n'S"j0%U!Yvڔcۥ* f(om7aj= K[}-Rӟ2Ant#PhT! _.#(AEXjDD[1Ŵe˪*I-f(;%38IL%Hok Z#t8.2Rj6tPNRړlkRs<]md:.=kPEnڦHΉgJ ȇpHqt81!e%Nz ^*:yvJCuVU+!n+q aH(on2C ~D FBꐸm|*x!J!#Uh߻ }j;uU|Nm4, jёn]5UR{{fzt[)4߉ Mc##6ܖ`aEKh/!dRpqQyfWw9jh@[Z5IlM |BVV9Rŏ̡M*3rG:7:Qr(klxrkQ ubs8ɊrB$[eyPCcN;D?`R[p_Ռ|KL>P>+i؉ԏmG~!/}0NUdV5mrX9.YΪm>m+gEԀ|~A쁀p脯7+kGs*q0\J[Hw5$ĺtV8#BΑ,Z2٩z1s*݋ X?j<TFŠdrrNDҕa%©aFHJ9d)r=EAk/ëh:hRK0hF+J;/dZ;˦*Ɋ ɲj ӡ٦02r h9{\7 d!V[5(*Z7/2;JD`s%=#,?3"ȱ$;+Y}ܡ3/z~|sp4lfԿPYBq0hoFHL:N~~gӴDޙt*֏&ZK3>?@s^vmE!&ٶX9Z}~^W:!}RW W(6\ppeH5oUH7U` d$qh! %/U GwYט(J`&Zo[ oLH!`PGqrxYEcIa͊$,>0AȗuUǶ׻3vQ|bztUM|rm]8Ϧ 1外%x UB-LT8b8zBd-(faB ,q1lq(D!Vrq<(VT +ŊVn'Ud)$ CuҤÀu!jYJPu"G2 qɂRg,\"GX+hEO!`,TA(Mb"%+fWA'LTlU Ot  u1/pD秃:)%8{U/WZtj57u-N$}zaZ1{HaON.5m2Pu8ĖҴ-)C2[Rkb%in<Є0ӱ%MpgP!WZ֏ֆp @u8,d['擱<='C|aJ0+gKϲj_0!haNFh!gB_.=k^i/=UT,kWMh|C:=}S"B8?eE[|ʐN,']Zѭ_dD'5s:L"r"9;->q1u b‹FKϩJ8N \Sq>u g%l9+۵ҵъ#ӭ.˝0qAKv馆9| wPe Qf Ȳ'ΆH yI]DI֟|{9?|J_ƬN/ʲywPhr;N,,?UѪW(ĥ>;zkZ]uV V?VEݱF wKY:*&ֶ#%p66DW>=Ŋ5 +{Q>ѐcFߴ)E2>^=8YVfUQjzU!&KF ęVU,dƑ M_Cfe)ZnC0ŠƷwX!- ഭmR@`DlR O9|uZVo"q.@εNޭlpnp GCh,fY!V9+ #o&3ChkBiܟ_rԘ҃]al_ZV ̿ K3sbW\ V/Hr2"#Mt?[.1r %X=x&ћ0RBJZ/=ʯ-4!rJ9A1͏N-IiΜF0Ƒ.UtIh:gEl -FA5>V+|X!ґ˕hjL:i4p7Ch!D 62N$0r`00JM|@0{p@R7_*ϻj5Bdms=SZ؉QZӌ`˚/׊P]+} |uk(yQVTu8@ k۫K|R$w>lfY*|5Y3q{?TOD _:4l:԰:}׀-[Sw"A '<1hOӴggBQE93ToR i)$Isp\t=lMOw}_ Wi+@:#Թ߅Czr&m'w?X*)1DD_>w2/ߧ4~H_kce=r|[" S-M~7|ARlYmr<{(w7 qNu4gi۲M8&s;J:}jlmP&j/0983~Ka4|;^k8uÙA݉5\ ?r 9E{| 8)[Od@D`$[!nN"puRmP, _:)F+xZcK !rLVW m8V݋:uktN|IRRH L_"Kؕ8\:5[hS͡SDp(/ZW -ZhPb=3Ԅ&Xu PVFiYJՉZ%V (ķ1+!A0:#^r|QҗQ]E !8gZGQ|[zitD݅tĽ\F\ v]a/Д=Uјt(*!f̗Bt++(rsZb^ īF?kɁ+]MpΖOJ.\zC|%8LXU|sa 敖.M85 0|7d:*}g^Q䊪K¡_?Jժro-A:a#Pa@MƟsOiUm0 c>NJo=>u+&_tk4hZ}%JfVp x΁oBhz`&hŴeXV"ȩ 8Ns|[r&XEk>G'BB.kw՝giRgJ}"Næf%X.֪LTNHD0SRW^F1;TF@dԈȵo3U lo=z\xzau Bo5΁],>8J$DS Ka"Lkv;UJ0+Oaȥp꿾%r)p>דj"79k gk͠9ȉXKO,UI8&-4rvjj7h̑oˡ4~!jUHŬ\m04`ms )/.cjV8l- ׿UlE "꬞޶kפZ#&J vVmCbxۛn |7Jq, ){?sde8WR|!m7Lm9@KF&DE[ހuH|3 MᶑuV-YZIYM̿nڷTw\UBp"faZ k؀%bGRz{5*]\n+qJߚ5o%ơJЬ8pN/vKWWZ4^8\P,B *@**rvJ:Y9htl19 |:KAJKmONOkc~*lDc*R{m=[Qϔу-հx<ʒl rLpl*CÏ?e5( |mH:RR'#l[Bp+qY ZƔGBfN(A@ܷ^k^'J?i gZb e;'$5ZWEN'As,*/ӫ6|{.5M]J8k#_C*,hauq Q&p(KGH&>U!BW)Gj^['ywQTӟW}~+Wl>Mwp@\VdYM`Ư5DOK١;v>es]kE8#flBU8`U" ƪn-W8Z9YoWSOt (\:9ZiD|l+9VqW ‡UM¼;t]mSCB"=ber Ԍqiй;`Eȭ+t5_4Bλk.GnJSq*am+ҭICЛ/m ̹xDSIqS?7od(K˿4_c뭆$SM-%u 1!$8h c"B.q^~ ?6͚4>׭@8m+QN/8$ \ѮB1qD?UsZCPWuV3*v,LCd43zJ{}{gǯqFvVEihk%pQ&]hâ'[d넬t|?*&U8{klH`PK)PVB_&NG 3Y?(TE5QZѮX+_ÑibtoC8hֲ: [`#{mJZ͛# 6;76>sf ѡN2H $/RS^݃T:QHݮmuxiT(xFW* oLQڌ|dkLO<*_ <ˇdU'VEwu|P"'eVۚɷ[)3"fe1ḰsTC#zE* @hr1pW`>8J*'#RV^KU֒D.VƄpRfr"' ˵Eα!\J_ \VJ;UFM%ܬ=h ߍdńŁ19i:QFހq]R:t|^-`m(Z֚1fH&hLh $EȌsGÇ"KUh%J:4QF9GKGrt;~x}J#w }4EhVHLkxgQId2NymbZQ]>^,KO B'MM:5~.7yz tQU?+-BB8Ʒ7W>͆%Ŗ[Nb{ydχҟ_}m=PSNNBsN3f i1 "bN&_]M0HO׺ N2RWUX:XE9rpVt[`~k2V].[mSv\|@ҙmTSY28Bg QEպj{5$)FoNlM׶)0mDPȓp3뙠i:mtE8 ($)qip[&,V $2\Ni'ܶ5ZWA4m|u-a[IpH}6[S$rjWhV!jf)m{;D8X-7A2DRpE+\1Sƌ t\l5O|j9u-YYJ*Z(~wuHۆXZC6{΄Id]gj=8Ri'TQU[6;=8 JOtQlV̚ 2+gD^hHM9s5&oRV"2"Ri+ZC8t8{ 9crҤବ8,p>@8t8ĭ&=d VQ {Iy(9aj]k21BwI ԤU?8S3 %[ֵ)o(Ud/:JMd2[fkU;V(}Y2O3e)@kFsk㗈{G**2>Ъ1ñmK lC@k)fa|?V[穄me1 U3n F1Q$¢|DJP Hj+*hiM {$+Y6Ln̽~0jdƉ@QiM_C'I8}$8h^Vr}sPk 8t?rDEFjU$U~90Iߏ BOΖߝc?6&MVd Y!Vo 4lL TZ@ñ*O!>'X&9< Q($QouRH]LB vn\;84$hJlLU嫍Yr]_r4~.Dk6p<>2-}'J^Vo?N(Ĵb-gB|QBp%5H\!d9y8IĔ6ۢYn)~h|2\kjQ`WAM&Ϛѕ+[VRO.cֿkRT)BR^Ej^)C&o+ͯ_~&(s+ZNSA>x,FbBq҆KdN qm8"H;8?A4iV '_-_RHY*n:p/o^'ͻkmE#68@vATZ]4>6)9BESP"ߕvd-)n!7$]8\m@8}A[ B"pE %@좜—~Z5MPcb2[`]UEK@\a>f3VQH.wTڷ~/TTW)ĩ,09tv5 w8NWW*8s$a,GUQ]o|ӀNm1'<(ꂞ.W/+]{ޡqߥmp |!hRE[ᑝ-QE# + sY`~ʪ>V] xl_Gh3k]%mrR36a60>(G ˚DT-ÊY"PIOX+~mj5`R [+6;l!WK][Y3\rsxL)_"v5K"|m1+$K.F: ET6I -V׺-o{F z9NSjHvc|YN/ٲT 9_V8;.Z**S|Ub|Vߊ@8MǢ*n)9V@ 7,r &,*9A܀>Iѷ@..>ڗ&r}UfYolֆ"Ws& ӍQWΤNґrϒ)Ȣe{9J?$cGM* !h-_o-y*2 QK*maI'^Cum)"΍(m_J!dRJ@/z#]H{uכޚܤ:4]M#Tm5+~/g^D>pU(=!iFZS77qx:í* U%N V^V7z[IY\2='CK}^w[=cՀ/CaՉXPUpVZ)_"!(ʂ uuh]}7MBVWz۫Yp J$K\V?:AcVpG/ /'QrЄ/$ִ(2 A. u1BL~w9P_W\-1G VQ3[` ǡ9Zs8l=0Ѧ/ 5HRrE  %8un!8!ӁCZ A:. k)2 RBk޷OgUEEu)pZ34"׭N kAP4r)lI g\wRgQu$ h& w&U5NC..QQЎw:DXj-8BtEPrBE\Q+M It9C*V-1U1Vi ޼/ۆ7Q>ȥX L xΙQmDŽ> [te**k Y4>͸.^ed!PBĵ ҧ Vui^&di ݏȶygl 蘶L) %%Q|s յҬ]'sAX}['8J\E, ?C{=W.֘ʱs1Mua %v,%y.1fW ~=d Sݽ4 pSϬH2D2makCzC#ۜfzBz45mduhrq %*nZR!p 9I)W(JޏtajAnvU!8r)U,HBt> a9Y)T,d`*eB֚#`Q,؄0ڍǚ⼜]i& 'ZѬw,>*Qql;"Ƚrh8j P{=djɺ&Ӂ8Bm9Ș(8t9J CĖ㣅 6_k_z ?SWEf ט QNL)XV,>dW ^yGVewB%_V&tu8zvO4mtY7ѤNg&ک'^T~P^mt4Di *{O2z0,Y!=vhwzCq?M!նHE̋rn~Eh7Rp9@FHD Á Gc^s'8tJsZ9R>(OxXM0uWZ6[C$Dm9z(F%v+]"LnEn>i(ט7?ܫ8uʝ!>7u m[$kRkۊ9GtPE[t|?&ʷ^=UįONCQi9"B=;:^euSPV)fӘQK~ yUHT-|ʢh?:nPcj1 ImKqGW~c 0O F^*NӶU9X r7Kh9BYUlVb "ދk ZA(aƹGV)4 |Ot@Q֨jP1kKSmZݩ`,:h8,"r%ajt+çI$?i'qRqu)[~W?XD9xNh[BTFxH4)<"*?cL!󴕵wK_6u&*f5u[p!8xJ*jgIJd% La?J Sj#hBȟ~ѭמr]PWѼ|[F0n!1Kj"ܐ؎\E+:N:p "S"%P`m]+AHp#)g0/&ށQthޡtUsptʅ|`EWj{eΕkٺ[^p!RW-[O+o~^5t5Z'1Gh8Y8LBᵡ$Z6Ҙ//t'UI 4SzkH[mH91l4/B**-.o &qXD/Q!ԄB"N],C68b4?\u~4Yz#|eHjsASK|ALTѴ(rTu#+L' Ƕ! 4nʭ={5g+;7\B޸'dL[":Yw8.m9Sv  (D)t2{SW7}Z E!rdʐf_$k`[jFEN{GIYDt!CI8?2^Vu2gc/48pQjGENE^kfQQԧN<(Ķ5gÉO$RNQӶׅh! ZW {unޒlIb D=0)!P`s3{EۃGX+/;oUvRH+BH>Gk9KӿFFIZXG_a(?G- \ +d|VDvgju<`,~EخZ~׈m2jRVT듁KS竏 J3" @8ʗm7LD&hS$|FJ1zz񷡼Fi[CX(| ʧIk簆6%@ 2m^ !Xu)̷>>"~LL.#׺./w_RË۶0b9\Jǚ K^|0l\7 G/BVv,d"-٫R0IdӟTADgTzV >E2# Fȷf*4懴_J[N@^e5G$=&O*UFw)TP q&0.3G:Fac/##AɚZO(gQy[BH,U>ke/?w;Ǹ½jTȖrbe) bȗŕ8͎.c6x|#CǷ>o'2~2-8yUJ$`4 FیktttuZiFax;["țO:u)+ӷ{WvfXSL mkY۞ K5Yx󴄉u&0"[`\ɋ 3[NMNbDMBӨ`1N%CjUkqJa `u LmHMϗ+7Hq`al9ߵ!N6ԓ_PS  ٫`U"a 2xVGBg m5hG^{!,|TIyRA{4-GaG/#-@YDB"Gk)Z~Y_+ ܍7?1a~!DV$,$تQ"m0[8`A&ȷA$_-*]YR,$I>sDj81IseqV%`0ߘ}3`jY0[M;pZ=?HQқYDHqSkA[k[E*8k\G%eCdpLJE4~ / ,xaNʇ*E%›'[7yYʻi`"c4Rrțr`o}0Tlp)30[kT0q ؊o %":}XqC~]'IS~UqΪ4-}bf澈B(.[+r% (%^ @%Ʒo_t{p75VGV#SaϞ"!"uWhYlxk;"$ԫ{'R  д[R40,7/NT k.ǥʃE&ʼnD5fz)DA Sz7cL *QF_+3Y ҆5T0ZGd* ڂ!:v$`'yFR|C>v.p>i<Ɂ8g/;/kJ:URm2ZFy u\"\|-LWY)U>Rd`aPF>난 e4#v,C bX< EȞH"<W%˱ F/H@Aބh4m|AءY+1 AC0Ǟ9,b$U^pEzA!0"|m>]n F.n)$:r}m6؇, &CVPwY2뛼3 G8i[m+VbB%Ijۋo%]&3Jl9w p'(Tk&5T:0) Rm \"TN-[׻F6.HPTqzZ-mĠ|oJ5'0, M׎Vz ;7]^yO- -bT-#!ztUȯ0"[t8l`?VN&-!Q^3p`0x0|=|ҙO\-0i,ZJt# Y܊ gU 6wL"oFH_ܚCl֪*Iv\k䴁c-@ڌ`^fU5ycP@ihV)9t&jP_> ExIC2[~K#Wk`|+:o1m)Lc^-d7"9 F_2z1-D)䔲R/eJu۞8P9P`+(ܢe9Z&C EV*B)zݟAu}ZǴӫqB$Va B^RrL!,>6[>LYl!,4g-5 VIQ1U 9 I>(iuEvk x N48kd۶"A͊;`רxJl Zd ~@6ahkQzo'6x'Z r:R 0p#K jajC0"$)[UIU!:@$`ĭ> m ֶUg$~tϟu)1:rlZ[\zIne m)p2DmFTMe0K \9"W `M/ 9H؏i}(Q [ʶF9\=Nm#j+Z9<=D;tJ `\MmS'AIeJG^TR".PӶ IZYxlxN10 -R+nǚ+LGm"FLd}m=95M#2L^j1p.,RE _'&|N~i+xzj;I}פ9DRO̐ K0f&l:bK&R8ǫuV Q.b[ҿGF$^ (QE< 4D"Αr!LצSUji aH$|ӿhK/XNwKOIfwD̘,_6D&Xxl8lR9J='v=cDttzUdVU OZX#*NݓrN/([VUkO?MN"8[NצuRv[¶Vd D/sL/rH^``LX0暪oSY"chY˜F+N]#B0Zg_uR"8$6x֧-U:wV8 3M% 6Ne9Vx) `|ߛ~i[ܶW.m OOt!m#LX#N;f-E-$kau|zZ[Ҕ$6m0⎂#u `lj"V&XlvDd;m%BNT䩓^E5^5",T1{֕5d7 y1Tb,dAkw~m 2q\g..ZمE"XĴUcl9Wy`hAej/} fJLvh1K0m󭋣M_;JNó.I ϡ73uq\^SJ8Kv{]pP֡Gϊ[sÉ ÄAq>=0"Ru-L | V*Ĥ[Es:eq,rU|Gioډ5^]xi_q"Q5B]IrņWj$XԆߊ]#xRH8udJRIيo [DIgBR %f#3SZJO<8pUYN(XlYYNbZ gJZ:g[?η]X2#u%TfKjs96R' FԜzj[#wp-9)߫Ic.7mS H5H`W. %;juqu bEWF1T_TDЖB~*ejf(N[ȨHU{~Y[;[ȉy!YSzgd$5m ,; `W֝Z^4;5ʐ/29ReE84uH1]/ȱ=-oUW[ ? m{F?3x+uqV'>ַ@^Q)?V(ui9!{rm]*gqYD*2vJꡜ~*!A+3xj/2NHQծC,0 [ &E!75?Ϫ"T9 qW q4bql a%io+a"/Ͷjb^YN'`cHq"{x7!=NTZ%60^4ٙ͵KӼNU"˒D?= pZ% X U/FS/:wqƼx8['BVU 6W-1YmzCFL&-lCpح; Q%7y" XIH:lC(ua|+LV  gq>yIvZe9/>EQk"I vmdBiX;<0=1 0R!}dcօ s4Pk|xξW.eD֊!+G9QqKsي0_ٽ0ar4Uk8aΜ׊OsGnR+VP<%>u5B!%Xa  SNfN/g֕b#A5Z[Z}9L Cs[U`$u'G?f(Jh`CI#۱pcyqxC%I󍣗zХx$6",+NBqx9ḁEa*y믈 bH;dPbrF,'W17uS $k;O08+\.\ݟ0. Ipl]gب i }UT+Lw|돻W}ӽWKS_i}#FMdm+:.h+__^y *tDuaƁ/}Y;_;qf@dIz cL|$Bd84N0έrTH\-Z\L?. FFm>admĄetVUm6uZs*ߩ f+i],ӮOOO/xڐJB2"ڲTV/Zeu+Ƭ] #l)tr08L%gl`]GƯ)^9L<.ErWi(Na3~<˭$Ni9R]>_}Ò*96)YQ'; BR!5Hۤ(,hW(+/.M}Ku8@d{ ~Xj"7U#-\&NA|A(T9SQ!s! C3vA k5~ȷOWD֔0}aL\nUE- [/ӟߣF3 U[EG}:499nN YGNs[$q~ĀpH;"ZJ!A*VS;%mǣPOLV*^6*iJU].dS1Q)66ڂn kϵ5 SšZk*jLPj(wh2}i ChQ* 6iA e_|w{=zպ"Md$5U=ȒڰVl&v }78ZZXxR /k }[[i@uSNm2 tHrflUURyl)8T7Z]2['2<P.g1?`qɲ֬?UGe}"X+eLB>_/ʃQ(Zк}2k"X%C5%={^P-C.K //oܭaw5G^t:iANފm RDlk:EA-|*+H^<~9SA:2(R/f!a=\AI`Lm7-r{0.2rTUu$ɥgI̲rmW|wZtRoYYՂ9R(ď 81^/-t|,ne4^a KRRʼnʒ׷;#צ-~g/[J B*L{v dT*2Sxx[q$ZL9۪6BUŭ,Zk'FBA+R@d{ FtVe":xݟIn:`f I~e,8X[UHbKDaHm 0AZťlB%|0YeE8:r0&,Z`ی`Tٶ+pgѨmbmJ1 /U|غ'x>Vm%3s":4Ǭ¨ۂe~?wXZ_A> @D*eKKMx =~R=іVaEsBY&H>WV/3mxpJQB-zF b<QpNSE ځa$L66k":OU8mvox`m73m7M4m9f0]rY^8)mu f]<'%eA,ZG0J\m JYDx_}òakD9QtNsR" U7>_VYqݙJԊԔ#JU;NlAJӿǀx`6U?fVf,pKf4#T4uR/YیF ֽ8d`۶6s}fR%Km TqleI͏^c|޹E([nvۺTkqDvY/:eٿyVvBNmhF! ,E^J~tmyϐ:h a[նNrͪp[)[uk^ 9XHZQ `HZP#O5!z"(Ɲn*CtZs H}L1YVP!F1L6k +l:[ a 6!EI8uqVxnBtYT /ws;dbCp8Hpxڐa4T_ճ7 zq ;I"fL$ "L6njwշm8fd0V%8 'Y!̉*B-pVJ__z'ߵKpqqfH@,;V[wVuV.x&%/|x"~ bp폈šrjE̛r44sܜY*,)٪bc)>Ͳ3llYYL+(îڄ}B.#눴sP%ke5,Y[RWBLK|x1L6VB*%V)WߺKD^f.?I b)Ļ"JkOArT [E)|ѦMji9?\9]Xl9: LsN,I6-e=9&U0/xJ7o[1m[ؚ|?E6&7c"E)[Y|k7vDj9|NĈG8,Cڂq(+b/ֲcP*f.zUdU!(,+I 5GfLyA0|q0m9_wmB{dA%XZD2Yuo/a8kYRr83x|x"`l8%+oB~:<`kWmQ/3xE8+lȶOm0*_8 0-: :* RäĻ8Ie0foDN KF8,܃ sծ=T:GʼnJi0"I> -)9Emm e&`̑(Kl-^4-z0m;ONLϑw ;r8{8 rA8aRL6Zk>$: |0|VB -U/EE?LCkF t$0ۤ*AYlx|a:4%` #pdV/Z/~z*xɐb6yuofO~3zѣKk=,MMU9ʇt pq(T/ #什n]KpZlY7`)U0UF0i<ahA1vH':j<+43*ȦeRRyTϔֶ娝ݙX-N8s: c$)'ߚTq`:_rÑĺaԊT-὜"kN be;@vm j2pMe׋CsF{T،c)dx[G "ֵ/]!NKFz""EPŀS#V!e.(R)XPdVd!E 0(خ19,?pcm ^,SURal1( ` R;0,53tIC&_&3Fu\|EP j ]PRj) IR7uxWAvM4g%h516T(lLA[oB͛35;sjU+h#Քl+n͑XgXYE:.Dz9A0`H[z@:zw Rg@lk]Gq#|Dzsi{M#DrPJ\֝r1G(hke;L*dzfkp/>0nSYDbdغ^,$9e6)q*w3f#׋A[Gm鈬|<|ezѠצw:2XAx$Zʭ i(`P8rM-M_^-k+^M)s<]>8ReC:TQ/Ʊ &Q3Q"*|?fO`ˆT5.k-v7>BU|FXJ$֐8řcL]aJ K5xV+ΰ^.`"4B)*Bs 할4.q+jH>ǖ>rm]'&bdؘ-mkRq,976Ej,0ǰV%ɰMC[UxDp8JB3 :n+Sk&° b/&+if ز5UʋFЛSęr9 ዿ?g}N5ouftDzEI'c#svp_*]H8|Eo`=yk^NϷ`J m3lN؃Ɩߤ8nYop!nf.\)Zk*€f_^}P_c;% )/"@'= T`0! )(i `+.¹4.|}aĚo:UN[ S©Pؾ7,514kt`n&3ȁ]^Zt"wV!2۬P Z׮F4  R@fCswRڪEmlBdRYUX |q[oxٮsg:¦]mWء=1PT52G;.H)q%@0YTĤxbr>Q/Qs9O4EGAhb⪌g {{p0qUVq'4gq[䧊0| :T*Bx}i d_oG<+b(UiW(dDLZ(U":2(g=S3dwV. LTFykUVUqު4z~Rrø㌶vPNTqD!4u BC׽:YEMFO' 6Zx ɮi-,R|$^8̙Hu$/ m"RћxS )cHkޝ?Lz @ D{i)5@+$rq t$VۥUk̨(aB*E<ֵ8 f~!#ZZ|%)NUvgMSl; 0L8'#K#7ZOb"i~'ߪ~vbH]"`tb`lKabK : /e[DJ0f,aZEhHɻSʽJGYkRL'#nW tV1(Bx+JEMҗ35K$%EpN+0/P~y'*; S>t@`!,Rܖ#+|`53s[0V֎eYN#~n0BUƱͤ`Lp'n7N]HmT58ݴӇ3NZWͤբčhL S^ a8!wJEkx1i:^LfNyAe1E#srY׵ՙ+3xmCF(M9G;:\ I!:[{+g&5Q5u1;K5Qov+|rYY['63ˇdtVd.i Z|7v euxDo a SkЩi{)H9cU`֪8NU\)Its)GO_g" t*UR;~jem BX\@!O~DXV>$_=K*dt8F뒥`$SӶ`-Fa& T8s]Dt #.&iR" Uaq!~KO nx(5b.@|"9xNzЉC6Uyt|ZmeZTZpN%H9 UcG"UNx$ wPt;_Y_.IFiI31})һ" */-DQ 9:k?u5y]vua}MaKH~Nf|f* lā=]3C*^nu+8 )$IJ|NS+ߧ4[MgAXgGU-%PYiq.,;^rOWjZ_LQ5Re Sn48!9Mɷ{(f 9NFӶ.OJbc;g&7z$\ KIV) *9d^&Lh7fg\Ub=ډo !?‚MOR1M܅V-|:1~8N_I$K6+OQe Fax5m% U!NGduh"R>Am85fe`6ݕHScY♔Z&D#!\+Hөj&%Xd|kqT]AH"v2qqvDD.:s0F[ĵéR%nK'Uj;@̐?fɑfExp8_-k${^2U{$IG8D8Ui6ChJ4S:p-=oo4pȶ)9gG>=(@GWJ+P6!48鄌Gp0aǴ磯Y &eP#%Խb1Ee8]8e[?$Mu=_E]z+A@s[G\-NP_[FDd:.?m3B5&Qq!rV=?zVSo0rͬOюogC] M!GtȡV 4ͫhNm5\C24OxHNDhqlI1!&&{j4Hp| r9~ASsAuԌuv4;(T5c < Hcu/eÜѮYN`tO+g@.u h)T%}%8OdK@IDATR( Vi\?z4Bj==NUPj!3L6M@D 8pIxHhAH2Vۢw|&Y8q'үD| "-} g@XogME3 Uz YŇ{V 8ʯmu:h%6 >A8h8i&˯ d| W2?!h 6#-5gR߄z/&۪=dz^H [>ZQCJt|y29 "/}(ODS{ }EiNXZU*jzBnuXkI!L9*ď΃%HV*th|n]U"#~i{|ՄxV-5Ŏndf̡lj4ꝉU:k-d[`>Uv9KYh`3YKo4JyZPEZs$m3y_Of)#5dRl;d/Sn~"z/:Ub)+,Vn|8'q—Ahk zk˩49;zb !/yeJsb5`[^PxE=Ne,m5@9Us"mkÖ ?¿QH{U@U狶VKYxLw D(J`:C|(~'fFfw1V/)腦G"VRVN?9@4`wҊzb?s_UKjZ,LlUZ4RUQ!ꓕiC'SCC?_1[+׉6lkUo5A'r?p3vrp‹QSoL-6\r;8O$O]ݖD_'JÌN++s} v{`<8%2~mѪl+˶mHCTP[ QBn{Oߟ*7YogӔkR{̚H۽Iչ/zPp̞B'fRrD1&݊/awMm?}֋&kC'Z?| :^30By)P 9X[/Wo y=/(J{뭩[s.SD혝isvRb8SՉLOZhE˅{OĪ+mN8Y>=5[ʲm3QvuRdkLPwro:4Ǩ[RU:@t {wtwf>nh(yL_i|؊JdGLu5<)]Mcq0ZUֆDU?:KE%½/Ď7+CB=i 88FRb?BW5'\pԏ0Gu#V4>Ι}{FEK |r-.6( VƲIus(*4P Q )O\B@L~$.okze^5)D-.C(͊b_gEcJqVŤ"oAq*#*+~CzDpjU.0YpOA?#lHA{|cTggsg+Ly]ռ#Lx| ?g{v}{tWuעqˇMu렄Fr5!+AN#szs-hVȪ ׌\=w0ûv)hO3+j)PL[uWX;@O8h:ZGS?p~BLA?J'[ +Ҷ[6)=K 38dS#ʑճDgHGѱZ ]J$aU!hĥW.]hB-jY!8zNRp)ܐB|MJKt˙l >3,tNt,|l:KPW.5~2 -(~S$*稁d!C838oӚ+%Ts*"$ڊ qAE &5rR+*Ĥ^iJWmk|TXmRï|[V1",ǁjE? [ eԼZru!R8UHX(q#,Sr޸zt eqtQQahL+Cڱt]t"I5f|k 9v*_.2NU"H?YW&Lɖ‡_`I%^Y=:+mBDuաmbMPnxЙ8VӋ[į:_9~"W()!q&RS̓T,z`||k|TYVu5P[wY S#Jdnm௱ =>wQ55D{׭YP~ ۺ84HI0PVo8*w@Dݮikrp$q\u:1 m^kUt BjdEL"WTHn ǡ,]ɨ/z{@< O jZ+#g4L+8Up83+n CI2RXsK!,>d,A??P( SSzʊ,%Ah?E/eQ)\9jYhZ6/Hr;RDo=rd˩: BrIq!|k'DJwh"/d+X{rWd1q9 #^dk/_iN!qG kխCf|hRBMa/H8Z"ҳPuOJo 4c n{m\>JZ-ғ_DVW-GouctP:WAn[optJ9D8c.JQpW𣥠 )U]~`2 mK_wvֿ=;L wM@aV-ͫ2Gźzȭn8:ƜS'08C9ǷV^?|vLD~ 7/ 'f"vda:mp< D!l<.9 n pBX#@8k`B!Vf`>Ӷ,!|OsmU.{H>9ߵpt!%kg|C`҄CXmR t]u !қ={ӖH# |lKqO?GJgj| 1YFp-TbKINՖKܝ{*[)[_|'j~qg'h=fC0fYqljql-A#* .šU4Gb:Gg9!8jQγOj%J4>$&B@V?%.) i9D0KCA$A #[q8qО#up|$kVL zMhL5AcB*n$2Q[B8n Z1gL BY ! h|O'𐎟&PkgFO!c.ZQ̖oaSQrMH XEYp`lNINj#q)Yw5&ujZֵO [ !F0ʐ)7\ ߼8 5ZQ"R1y)8ULVUt%E!P׷>몊Aܯg7&j\m@ )MZBrє±ڳmp!$‡w8(0/ኺέ6uP|uNVLH w'x#d7TRmK*М^=@HuE:ms+#ZkN]IYV DcB7ҭd}ϻW9kmz[Nֵ,HmU( q&j2(_?GI X끣֢@QfAG:(pn`avD b!m(3_R+偯8NFi\AopT9B #T!cPk ıE3m"j:2OPTo b:Ll h Xm9(wpV?+YEEz:rlꁲ,"֮` . d Ô:)Wȝ)%=Y h +E*8)e9f͗t䤌VËr"GnT=lVxk_GDzLT"B;k^ %JiKr|)|[lo wCVŊڦQ 2њtNbESD8V{ÏIٞ.Bn@iEq8:/AJcqo!Ow=}s1d+j%7Jw8@0V||ҳ@ y!q>Zn[LVfk]+Y)\eqiOgһ')!wt7LQ8΀֎݊@ м!Bk85'HPKO =_(yVlV3g񪸺6;a)Τ9Z)BZp(g_u T? H)@Hx%FŇvM1Xd*/vW~5hk"AtQ3ķMʪ<\gOV!?>|q}Mam"mWڶ܄l*f 0XRJEsV#z8 Y=_CO6vқBCv7c #JR:U4D3q! IĖSj_華jMKO7 m ^@ea2ۭ9ICb{'zRzB8(@FIKNF`|Lx' VjVNaI)!K'Wĥ 2dc: YҫU!:J3~5oRCH,Psh7(0)B[!U?6ʥݿ_mRZzqyB`D&խt+~+'tl6SERq‘E< E"XC0!ĭ] Y@=M[ ۶yWWo.?7UcuY=LV}mFyX1;3Bj9htj!x?+I4nNC~"\AvN 9`i(8mIq@<~T m6jk2z4}ZmgQ:Xt; .AEG(S%a?h5?R>⫐ORNו~@P@ԶVL!cφV L wž:zlvD;!r T]' Nr=)]V}ԛ\4Y"q|">!4]ժt[tDeZVz;4Y+&JufZitTr+,h0]rM-|Lvb[_l3ʒ-<auʕ8pYgQ&9Y%dyǃ+8xV*w) nͺ#J$A⶘, w}rў" چU]TumO֣Ϋbkfr.Y')б@3D8+}L~ZyX/J|R8p[Ʒv>JwѼZ)w2u~cskܧ?5TtcM֖UŐ*_s{`U|b5$vZ{uXFhv勢_nlf?LG!hR ͉S֘&ښg8)[ztsWҟ[=_0'gթc?${Et8OVOb+%X}J?O~ׁDET]NF?ki8H9# */rh1)ǡ}iԶqhMj·c^ [M->Ñh9b QeP)W4?q K i<%5Wc[Ezh5 1WjE 记R8эM0]ȕHJh@R$F& Gn(>P">~** 7[ %bt-9Vq6F gDBFZtE"ǧU`U*Q#=9+r֊-ꀃ՜j{Ofj2[&:0'$t?\YmK|-M!A4јs,N Z@+,U$9]ϯNV-L[\lY/S v:դS[V 1] ON5rV#Xu5D@:B$nڲ U-=G mjDw-B@Q˺kr:2GViդkm@ɢVvNZWu 񄃩NN I&m֛xGЕfLg}C1,,3eB4!?JK⏖oK $"%)|` 3?م0叺6\_VoS * `[L {IU_tQ /ZR?0fsij^zdV‰IаQkWTUFGV~bW/CD={[O/ЕQZ̹Ze8Vbc0_dt08Bǧ)[M.ժF]j ]i:zUjҶf#`2=m!6?)Nc&y+ UIuӃI%CnЖB*Q r]cQHVխrUWt GWH3XJAQρ_Q ssnx4ı 4WDܮ*eh*[2H3 @ o4m{ tL5TsV#U3"DE;MWfZ q\ux4os?~9[ח Yͨ̩J*ʈXPRtdF(Ec9|%I $vӈK58X! r{ Ҟo W ^iN6Uo@k~4n5  GVtXFQʲ Ay`'_V&U R]/AU7b Ŵ_'v{.A9UGAG]"8V-)"8i!pb BBhOmD4+ht@ hqlz+3BYg ZsX 7Ô"K9Zkuh[c)w!)wD0NZ_|$_Bkg0H:%>zpMbi+1LQ-fk r_`)}ۑM_?o}HOM `YrMr!MglzA(:\~@S3DLݿMaKm9!Mme j|p蔸&,Ɨ6 dl Lx%utS~Ƨoꪢ|QEV4k4qO!*/lČr 0Vǥ3q>mGh{ #&>[0_[#CR)ÉŐk[!2`/JNc|E{b?|QhS ,ZcӀs=D 2Q9ơ"oex!`L7:@V.hLzm VN%xd:SKω$.фoCBg0Iu|!diZFӀNvԝF |RD [E фR)Dḿ ho{ (φ>Ӊ׳ EؘB DCk gOVȖ'?eH3JL>&I 1Emm1S[h&JꐠE95PF.ap%Kߤ+IX* xhR3= BV_~%q=3E_tzED{Li YdR R=ұAsem=9$mR1! sڲLAtZDO}?urji=pŪ9%ږX aJdU)꽸C Iߤ͟_v>׼ժ h|kRQ eB$"ȵj:Zw]woN'lqlEb~<e_|qQG5C_ch8"o uM/* u&t(Q4)JSӿL"zƺ+T8]D۪-Y^H/Bqr uz(mI,|q L-A+)dBIU: E9mVT,Pj#E9QN+rmfڼ@vo-?NY#T%r%tPlZ@fl+̜^rDD"X|`Ofh,B1sX8Ӥ~QlϿ+MU R]~U֏S@]Eg[ar"}Qn;o:ES+(p~gIH'߰m`l(T@['ˑor;G"nj8rR_njUښCcA暤&Rz9yNSP1 ($ְF?Q4 _|RSY]$F+QAJH8}hMJGʋ7YX8Պмy6-AVRfXJp"KRq !`սEBR[>NStD>'덋ۯm&8@#D5Sۯ)ZmɩnV Χ)ҫ?ͮND*֞4O_ux쁦(Zhn`f')=(!%[T 8LGsvbX'x k$S}zEa [5rGXz$f|LV"c00|؎ǔt%!a9*Ymh[W?y8= M{h"*E( )ND Ǚ_.:U.QZ֝Tr\02mJ2VBSC_6)EUUŌܧ2/_x7HeX 1gC[(C!S?)IBbdK[#SBΑP:MW@Ԙo|)+:9_ėkuna>Sz[h)Yx",Z|4 1)8'븵ߺ\~3>.Y/8\uaaF˯I@W v&! Ճn"mN)RܥU +GoP[4'>[_'HJ)Yʪ2dhBfdՃDH(]V25L`[}%)kf7֡Z l6Ƕ9uR qht \ M+(PVIAE8sl7BJ'5BBC)7reYXLu #קr͂Љ%+Z`5x ^۔S)m&)d{%R Ytr]{#6';{>-[)s,swpR ğ[}oʕj5 SD\ 霍S:Zr&J ZՁcr:ZbhDBEhu_;_V42U]u+zxA# aJq;L iFw XV([ hV~-rK۞2Y\k u֒YR6rCb C΁Fbus$Ç w~Ҿ^u(=qNtcW;J@@[M*bS'Z4A K5N9N&'bXBB|_'~Lڙ,ŧV:>t Gu!3usm#زPh eLj8VRJ*7) 3*mG# ?I|bz8CDǑ\+-뼶U\b[zU+ëqTT]&YtJj4({V淚o]V5t&`| Y1B8@Cu8V|||8~#.#e(c,Et,@[>f1+-lj Z+߱K iC9~ {?q|EkAV"0>fl9L!Z04@Q>995J!8ǶTJY$Y4?m}r7r?UQGU>{ (MyU ,Q{oR+.<2>[ў?:ɇ3HIq@ U׳_)=zҪNpBpfg%թj q"R 91uɷJ齯mGWwwQWϭ>c'ҵZ#) 0>D:Gۘ)8D@D[ erKlrmK Y'*?[iҷjҌmz9KVdpl8!p*Z tQ8p-m;NC9*zʅ_m9AC:W|5T_k]gA^׉/n4dU]r, 1 ΄u&9ۦgWN#bzIO/\ԯv+W />j]b=҉YGDVZ~sQ@択31mw&wr %r+'5vɮ)t; {t FIN/ BDtN0*֚f"0jA5l&Zۢ]O߻d08s}֞!l4 _pNatWCQW:DZ%D8~rsP͇hQDU+\ji hEtC(@d!,`dyl'ddрڨPi:'?f'*|^khh*UIm@ <'Bӆ#qrU_o.(_|oI ft%V\;|Y Նlk3Q @m u:7O}X@Os^F[ Xtռ&mCv"ZJ-Y֩@|0Ǒj5_4_TZjƐ>GO )cƱX?)[˜hYΡ1zkw<^8V~ ZMlؗh9{OihׅLW׶Ңp[*R ":di-Q'Ȭb28U-N V:X[9B8RBEÁki|2Dme"4GX$<[$d+:WkLxg-/WtJKR9 hLa`m5YMxj^0/j!oY˕QuZU(7523Ɂj+K 1 H䬮Pjl>yO>![%h5l8NQk-u&heE/ݖKbӁgV>2mR֤fZ.C$Vȷ[oKSHJ}U'TB,kZ#@8BrlĻ 5*1E9$eOD/I \u2*sMH]fkvf![~%@+gdv R{۰B)q BcnHMV Iwoͨzl5K [ scsgDMy&Ѫz'$9p,xR¯+juχ?j=unӴvy3XV82?r- Orǧ`F e "nduX?XȢI+|a|[IY4VC|CVV7fѓ{\[Z{[߷ZFY +T@N<G.[1bNRV\%8DV:Ye=V/NYjՌNlu' Ͷ'I>#JV|LnħɪΩBL &!["`rjIH]"GhZ%DTeя.'Z+;Un(f8pkGC_UV.Si"rUoEÀE!@[(Rk^#%m cBj.N_.]]+Ɋvt r?! YVŎ+gW WsBcy[~9iE&B-BmaǏ嶕mpmBF)M]+hYg;ǍѪD{/d*MU(tnKG6>7?;%_)=bZ1^bQlMa1 '5BPh"5-M!"&iNʤ;+)Y@)^by8>9*t0E$y[>Oi%zW+ńTgcm3hcj::h+UIPb ~ 3\dR q^</.M~WYl*W!z#_:qB n['I}@`'h\ '`kV7i>qRg#!XYj#6DT'lG!T39 lr-Jpu\Qq[J-oI\3DQf uruFH4WUJ&=9[3! 1diˤ7AR2lM ["HzIJ&q0*OM=A;̖44;')[Y9GtV%N%Z@mR8 q q~$mUIHNm9ㄨV5>*sd:L)gspol@YT'<}V slYP 2i9AKBg &P V[tOB~d.o%zNפgJ+-쳝cګ@} j'5(>N`5E9}'l;rHʫ+A.[^V8rjXS_@Fc'R˒\̍tmCciNݺ>z(ُ~n)߭k#Du ^_+AM*'v\\愫.j[zۉ]iN+pB aGcͧ| I9v>uHD ֋vM2_ jCP+-2g Ǻ#ռ_r!@m; >>xc8(f+OybT: vbڦ́TCQ{yo,~7,=ŢY: kEd++)⊚W]U44$_ md>A+phhuE- 'rҥd>}{8̕G(:+St''+KT9@Yr9?Cį h{B3VW ҹ!o<ɞcAe\)UPY`C PBñ2@!:x hh--<@Ǒ62N5Y 4Oq>pďm+ɷ^ 38umr:ȉV/VQ[ <rX"M%qIy&[IՆG[w@IDATZz:INkrZo:ơ < h8eőB(Wb>RO_Q!46)\_7u%нB٢5`f@D1kBIA:jCuDdZF9V}RGA4D:,t|TԀV Qj> @%'GV"Ƒ6Ǻӣް:p"9ҁm{31>/o}G<@TtCRPf@9=G)ZݘD_KۚEmҙ. 8LTn' 0ͺ.DJ$Ow||Qz @8LǷzvpԧ?]UQ4>>;ؘL ֌AQk%]/_@g?Q_=@td+AʅT f`4-2Z̤"fAЀ Q;aQ94#5k yeU(fc#0-BxZe@>Qk~r{>DH&,[BB֜LSz:*rL.jmo^B_.s%ʊr GJuᲄ8Ѥ3H uъrljcdp*NholJrk^WB59Ym! ^0\.f: b!>;CoG4a VT A:eoK$4,`0kc;A#$+$LNӖ&3LY! Dz\;h,pL4k1Hb .%Pu%+SyD"&D+s=O߻|Y۪p4 4Q{ e|r6ݟMi`E[.˖F|Vy Y|HV)u!o*lk̛ʛSZsvV9$9 ЙKm=Fb*a:BI} 7@؊He+}QtZ0+)jr#XAK_(fުN> y?ǹS?~W1SX +W3Bo dXvDxqB)wqUb)|ǑVԖod%rpREhNύP*Wi=\ ȢOBI$QušoXÐ&1)$I5DN&4AbJr3CQw^&5U8LCuKU{jj d ԉP-ܲ*WG QkďLA@|Dg5`W~R}JЄ45U·hꥸ{ ۆPc|k 5`k "-תwO|@ϟ/FUNg˷EEx=ÔHTk Y!Jl$vV!+/rXMVѪkEUbZBmt: `BɆ[kQ~͙\)>DYd 3YVL   )*T B FC}ޱxܚM‘#>ʜJcRQXzJV=ՙ,n2.(AD"ԌrLZms =fjhgڳ6uׯj^ O %ߑq$uH%hB8pt sld?zp R@+Nm9]J>k:2RXэaGap |a+TMgceUᐲɯ瘲f܉b;MbHߋ)]NM㓵A:U܌M+#׹'k Pp&זՆhDy?amX%΁&ҳpI 3M ɀzӏN õdLjD8D/o.J7f"V ]2*5qXg=|[NJ4P4Yi9[dwZNS]BBN6XEJ)J)5_i3?GD:|֪!x: [L|k 0A(rE_Y qLDk#_pqs$0ilrlr1Gu,p(p/tQ8e +JC$BmKz&Y1%BlqN*lÒB@3vڶdC8e9G jbu?I=j)2CX!N,B x>znEۆf: 9.ǼȎ w|g 9li̖ܕ_f/=.!ЖgR}zjXJ| xnpsr{URs)%SCt6rm[NlHE œMjmES&Td)V]o7#"HY{1jNWGj-|ʅ'qi9SD+F"e݅Mak@Hϵ-M [N*o!GFxMv09V8RMZ!u9pPȚD8skymM*aU1^E9΄odRfU4qQ(PurEq~!rڦ9|\k⢫5NЖ!˅?e5XW,|ǿvOjqY*⨘EqBdȅ'.5d68g+Q%ۖ`NMYڣ\|fX[%lqbra0^ dd r?#q2Tq '%Gʏ9CNJ|vw AYKsʷ(-4HcҮW]ٚi!§ jխmW8ھn;hp12 qVpP&-/c6H,jj֎7&סRA_ \JM"ro j a'`pUEJSV(VњG A?ZYr,i^QUp`}'4'ṃ)P*!@|+Ċp:+MdE#G㷵jEZ.Gf)72 J--A: JX-BX=hؒlukÚŶDgƻ7/Xc!xgChkU}-U3 ϤE*Q A[i­EQVѪ(&hsw$IVdy\Fٲ`zlxV6UPU y㔵{dGdNwWf/$aБ(:ySXȋܖ% \HXRȕ/W5Uv+\ʳm2MΉPU9 YCEU`@`z*vW0}^k[B%(U 5ײD$0eWP˅QHtOܽ]UXֹ(UlN坢$H!)MB HQ´LY& o/GbhjYRF*֖b-cc.K>d20E^V o Ӊby58 ^4+:)-5`Ԍa&\q+љY.0 XY<=N8|`K-/#9K.e.JMr4 ZMc%r;1qqI\G*ĶeHRZmц">e%!,2BVu,JDWU{k.QFy]kvm֠~Œ[Ck^zBIkx?l]w)迨(Fa*T ]tl CT,XV[ }*^Y2BbMGnX@`Rx's^W]HJ7:Bek+rJqT{걖C*&WvH Yv))BXXxIYV@ IQyg9WK”UD{ԬZWE Zm5PՆA`%i Aae6TڒŦ0 OX\<{|E׿?UO[+y mZk>fZhT `μ p1D1VUy _Q)~ԻEB.2$쎱,%٭ |G2Qbtb.Ėf =K.FyYѻ.+bHl ]h`YRUXՙfE) Ze+)ڳͫ[^0RXiEN7Ja-( ՔdE;4[ K}bN)􎹱p\S|7m00p!V P (9".z4~+Ke #4NS5fB_,H(B10G%1-K`|x=X﵃f"e'`RĪ9< 0 X3҅PX-M诣ٷt!@XҶ"Q@HW\ NBIS>G2FԶjZV&Io+Jݭ_T{QL*K8K,BZ"`o >xjb԰!{})c˛඼0FV#xi$;z/}uWD^a(cգHzIQ\ج$H/$dWI>]\fUZF!袸 $ `N "H77Hw@֣6 'c(5Z[f ruSPBrKZ  m^8/tG!ȳk𠰁(>]M Kl[Sʤ_2mˋ~Jt`"0"OmazW"\V1Uew9W)ۭUzBUAEelH]vM%cx 챕Ѫ\ TsH+#alzF0] um] Äw*=A,KwB.kyZmB(+m +#,jDtVek_js70,O8 )V 0!aْh+?:?e}|!bmf`.  j֓Qy%-/6e$YVLTFs<8#*^Rlٯlt0tRxΌģcJ0EXF!%`P\ҕq)w%bdT<u*{'naH+UVںи_etւ(µ*ʊ',}6J?&'BRj`B0`)¥lCg 3/Z93㯗[X) YVR K/N`KkD ڔʣY)ҖR/JKc l#Xl Fx7Ґ[{2F^^LX2򲴭;Blc@1 b%ۦd|\y j,V%ԢVlv:+́~+$|}a0w#2Hw`fqYb Hr?R PLM9%5*+Q^OB.v:) \b pYkؖ~{*/+7QJ2X0{&C[0:E:rL %%BRWcl,lf QLunU.dH4(:%Д0zyv]{!y[kUE9xO{H4< HY0Zh]ٯ[ ⵦ_  4^uY+mRUxtrd aQeAƮ<+pL[1 w5X(^KuaY~b\azD`F^l`YD!)R.5V_n^:YNHρ*+Dqҁ :գ++:jJV:gonNGUN[!e8]8<x .Vm I x?&Y T-31ʰs.t[Q!,/1nbH*e_r; ޫf1( $#jKi\NDz^U⌶~3{@]%b!qQrP)pv?{Otz_1KMGX0%©Z2&6.URH^HF~*{*6mp@e1RMf>H)[S.*_HᢈdA]̇w~MT%% P.Q+̚WV>Lb l%k fEJ PrȹIJPokVxۢZK!*: ^HljG;3BU(*kE+%PwGݟ!TMjRH[Op%tx^cttۂˋjG/VPdפ5Ԗ}zˋ)Dzi,ڡ;_b偩_3mVl]4|Ib`bBU"Tm5(cguFN6 ]Fm]1\`0vҡX.F^/ 3BtWµml-#6\k`0WAbEd:Zr/2"{k +[yGBk5e:W!=>|BNb$(DƋٕ%<l$岥~^eۢQ KWW9Q]M H {ͲX%J//r!_W0k^xO-loy,re,C$4́]:U.$z(Mr.^H-1I)}¼(,Lj d(1PT>8wڑqY%XE | %eƥ~>7DA4LՓٶёtcڨӃ.3[)ۈQpͧZ-(*֚\-t"b-=?-Q<®!W] Y3,HpQ)·R >* ]8Z䵦d!1%^0JסR\B_ +O^=OJrU}]0HQ+ re}9cD"eej30;tZ")xZoI~Db%p"bAgUNa'tx+{e;ߔy ظv bEʞޚK1f.#?REw]R^<Ԛ@H=y4Snb=xk@vR) /D.ȘeNtZ9|mIb4=^.0g@{Y̤!gZKWNYtRyᚭ# QCF^1eIR+ R;ݢԲ[eQ*-l (gu @( =*_mgK cHQX)S=,ͿX(U޲kJd_ƒV Pgw6`ruT < KLx.^[o1"OxXTeR".ĺ6Wo+U%UU^kǃ@x J@5_?(xkA56x Ԍ+N`lg)0َ 89OEޑFc?C#$CX[4Op"Bv ت C`\`~k'݋{eed!+$):(/ϸ!m꿢0G#fV#VӫVyv+Aha(к-)zPȕ}3Ԛz5+Cy#g Ƌ6j"\E ]]/R»HlT0j䢰#!Z pF.7dcyCs2f' !Ma{rb}ڌXAщQ 4F+1E cpQD[>ڻq[YF[)pF)Io xu|1}𵥏.z STVլ )jax €7%H!EI9˿@`Ql뎒(՗o闯^P%$]P= Ѳ &ʐb*^,-EH -#iV)c 8v0!${[BdqVԁ{ch22*5 07\ܓK(Ca`NmDUJZo[0([YHl%'2QPYkN`XK<:G[+IcVmy=8'˺dW 3=mڪ*=/Z+($BJߵB I؉[/ʼ\}mC Є)$ TdQX#|fIhP%heOthl`${U]It~ޯ\*kbB012Uۚ,T2D٢e:#iVx"t~nvUw  TqR#;Z0!% #㚷DyJV\ H*تN** Z^zx,Qj|`W^gW&í`R m9oƶ\_²[҈P^Bl=dֶ+pepRVEJlb0;m+m`.dW6:Vn.YζnꎗzH:厭أ-ж$E8oTRRu}B.R3ƶ¸J,xFͻxfٺ:0@§pՌ/bnFҹdʒ pU/,}b"WDmy B]Hgy[04Je oJG$WQ\i˂ Se:`BتKvv`׶yal c~1e/xY} @$dZ%\W- I6d!ՓJJvYEʨw]ىRT*5Ch>0!Wf+ p$\\)>l~9f@5c+i] aA}T!;E*lݤ;p_2Q:kEZIgUԼ!S]kKɫ͢$/'*C'vTDo$ o) +~WX! Ewy_e{ۨ6s'BzmF.YsUy.Pi—K᯾-sz)pHQ~mmC`cQmK*! UkXɊ*y&GH1~Sj P d1yaTmB)`pm,Ȏ #ƒ6l]DW8F2lU !)Y\Zo~?*b/92|vꑨ\[BS?Jn3RrgTX鵼ז΋)XJNO\/,+c0Z˅\!0iKEQrR<|CɡqMJH:YT%J:# {0\eg!(1tH^,D.yO8'\W蟵EҐ!*2oYM8*;hk IP}}e"ޖ^VI \G1\.HkD[[һU $IL޶J}k g;Ջ^~4. `n7Dol D" Eu*2XThi(&,Za *:p5)RJcBkA l6!K*{yaHΤp$jPZF+*䢰3*&Ha'YxӓVeAyv][w;?rv!dW٫GIE_a,:U>r[Cf?U|( X`WF.Vdrvt rrxl sytkJ8Y`W=WKs1;$R!aQ̈́N0(ʲ9.Ǩhk PG`"ZQ}`6_'OcJۮ]5# /a2 \,m`G,/onJ'AðlM9iw՞k?bt%UfFOW`K'tM &ӁVy7]Ƽb"^mE5'U^JX|̒pRvtM騦lXJ 0a.wFH,1f>|T" 8 %(PPXڲGKU1B(0!SZyؖBJ|ު 7k(.jĜ%*0`O!`e =f)n%/mIs,jf$^yj>i?}WJgdTy%Y, R)c`4OeHoKd0tX+=K) NxpAZ=U (#W@J;zCv ]lNrWrJDU#lZIyV;f^l^+rk3M0p(ēYa}xBM aBxE@B(Bba!`al2 Wa\5jKhQ@!gQ_;кU"0Kyn,0Ix+o6e_DG6[:<_Te,`م^ ( Qt*D\%;z} *%T-…"tꡰ%،`b Pl$ :K}PUYjPR0kR[ xFVƐ,.rȭ41%S@6(dXvBxx)؅g[e`^zI3J!R}@ a$Sd,!^]'Gl /E SaR+VV05Ra*;#XQR)#DQsS ȾtԆYJl f[ $)blBⱒ0& cR={Qt`\ʘΞJBRœۃX`t՚Ū¶X26ڭZEo;8Z^^K'Dw ݶaأ]~p!J|/l2j(ksYxԠ0suU['X"Vo|a?z9fHeIQ i+ c=V^FQtFI1|t.o_hJhzDT$U[%[)0w?vjqqࡌrXCQ(^kH¸FgK)˭é+9]v F-B$Y @e;#{u,V׌]nRԶt\D/@,YՕ&ՁK5~!, $B[^v[ #Y6;wGݖQL5gۃz TR(cEҠ>YzUn[7H7ԚB`^)XTǃ]0s[ ڴ _|Z{R?BF1!\PPHŔN ٳx-ʖ՚2ERKZTYlKok~U.f ꋕIaq^i``B*+]`N{ͧ>bpw*Zz[%eaoK,JW*l1gj~lgnDs0˞TUO lթC96,…2R&;n8#9NɈT[OzwF $+ QxcVJ)5N:*)).] ;I)-|')cjj$mltMaǫ}[Iw9u; O _*etLt*X*("Q5` qq=VN(QQ- /3 ?ȈA@s.EgL %SHe} 5θVG^F#wcSӧOڌ$rIE^٭),k!LTu߅co@5PĐщ(V` ŶB: s*`:in!1FUy,mY(hMF\UɣXϭh@hmzʰ" &zEޑ N ,V^|.'L2^XZS~汰wYv8K&[g)0pYC2EAK>H d)JxR YzDЖ`F9Bv"3]Hz(bY` ƒv^vx11BD1*FꊩlIz,sskMn,_&^2;?h⏯oRS!lkC[njx\DWtezV IGQx)ޖR򅢆oモ VYq$RCZY\,B,IERQ$B+0k l0Z/BtA`h)ī y-:xo\YFN! uUH$͵ڎN^JtJۊ-\a aHQ0,)Ea\aEe`È_Iat[ҪePʲ'QZZ(nsx^9cqɨxRmv-آ] ajK~%a'1C[3EƑd &(6a"Kck[PD^&:;/ڸm7EUm$l\ڒ!t+# I()O3 O.vϭ$UCU'rUؙJ,Z!'Գp׶z\wv=z>}Zy%ּܞo/$l$ ~5 J9oֹ(I^׶ ,j-˙ 8y45^IU$ėM`QU WlW WW&_W ZI[\; 0*_8%~Clx'~ngU/)P+0 {:YDl3g~l+{d~ɪ&G I\{B"'!R;=Qpʋ2@:*'l< h/eBQWFYSU^,^<|#衳?gW>iSƢbk-u%xRK8;0, ~BZ^QR_'64z=CBH`j̖w.:/0 *6a)\/)}8:V6Zmg,׍l$WL?3g~,/\Mi!Mf>s_g:b0Y #BJLU:;W kۄ),9N6w<.Rv'!~U)WF?}?,fA>5py6HsTסe?6Z+Dy9qfDXt_GNJl1"@TbE)Q!.#p&9>6mӭ^! '3sU.[TVs&* pO yp D=TU H PSrI>o/B7 kL좈W7ѐc~Uю⌾)—=rQ6.G0 yMy?bq;‚O`5dkYK\W% %6C]8X%1=B~ru M^,ZS[ŤW۪ {KWnF Ϝ"Rw9rY:mb H2vPb X.@^BNge5ʎ?{)c;-E^-6^ `VL90 Q6%-.ЁI.* GQUdeQjgWq[IrԨH@'oZtR BgpQܶ.)̏FrU.\%w.vKMVL5VH R(ב@UBIOHZ"+$c$+@FBGKc0 ÙEOq!0t6$n(8cP0tVWL'Kg,V:V[ ĺY\7*QBbKoY)_^(Brb0]]y WJU.:e <ϕTx%]RQ_䀆^J9 `K`БZcdb<9ApY!bp eC5%Ć+ /mQD?]?eK!z"MrYe{v+4ޕ 3eXYt'5 ǁ` (Bb)kT1fuW£Y^ҰL 6jVHN/"Lu4e+ˆ,"\b! ޚ#:BbnR؂f[8`+ /_؞/ mQ#URF0ٚήDw]9o 苮ya'j5^B·‡ЁK,:QmRHXt cYj fkM1(V\,P2VHTxV-#:?]جV_y#,/] /Tnj<˘k-] g䌤pDy{<ʦ.BQ 0'٧@횺1J*@RQf &V,6 _YWFHZ1hX_e`WH.YR^h@b-^=8orgm\]EEErA0ƶVB?~f- KD"p)dѼlbWki+%IӋ}8m"X!H(hב F!B0T+jaȵEy=upA*2(jMrv"{xmv!ch&͡3S2Bv:\K݅sߣF )St3Z Q4VI!0(#i[lUn ?ڟ|{ w#{t\:RLPXV}3)4Ì0XoEHxEYP*=]Jʞ V\,_?`H'>);~҉2v䝁:2m;pTtFMxLew9wVTGں]w 4ih#H(D81Rxǀݶ+:0%˲,K^8}"ת]2 U:{o/DU0Ֆ~Ù1sV!ZOm)/ 0 Bߖ]`[ӹ3K^;5t<^Dbp$n8[``YZn]=,b%NX:8Ja޶` pҖr;ӣ)KU!Xtx[;fBxo_-UzD:t,eV}ҭukErc[LxO%u%pb[`<0En],K)dԼX beW(^`{iQWK鲈 CI '`YJbQIӆD~E~}te-Z>|vy Qu;f\.wYa:t.J ;>{“&OCrHG񸧰gl|{&7PG^>l4&j$mO33z%ȅ17.+̑^V,(XFJ)'Ȟ|o-Τ+(RU cY7!4U]ݰw;R]\Ҷao0g!xͤǩɀ%\ea$H(xt B,`KQSD*.2­(5,G ʝR%uNl`Fkt UxH[HVe`"26:rPҗZt XZm뎷DBDaӹz,Cef!xceT-@V.9{r,"#ײL1`ƒR|!mA=+_; o 덷 z!NITg毶"YDZSFv}5(OUYBa'Ԛ@ϵyXet0嵦\ z\SRX1PF;epWC+;p$ڑ$ ׬zPF2=tWe(!wiYZ(If7osB(Rq6RyGyC;ŪծUj 12Yᧉ'.gs < o .o`Ua;;FDZ jd1.$n@9TG [AX8Oa4gv}xwHmmOڡh:^Hm8()bTUI>4 XsippF困$k+/sB|ۖi< z{ LVs5u*q'Y l $XS=J@@ ﺦa++7W., s321f_kmsM9T &i/4R0Sw@k& 2J躞$R1ʥ|"z81=*VBa&Zd^# ϋL#U:%o lthL:m2e)B-%V[IA03Q()+&RT9E%m$0Z@3p^!T  u4 ۄh8K!cznRsOrYU+T.zRS6,F`d#a`+h25œ޷;axJnd9Ud  ! +E8N֝$I ޳{ 40PPkJ a X-=a+Yj2pn&pPe *|dmP:oJvdVTސ/+YJ h QIYxF"@Ra䶔葶V2VJd)5j>4a2!0b*1{V4;7^1}܌Q_G*8+[R^ ۔S݆rUH&Lϗí^-^\mMs{W"h~+MҨ֪VJRVUp2 2 RTT҉M-K)xbOg?(q>ֆy1O ]39WA'?]v MLxRdb"^fH FVEJx"jV[ a)> q%Ila?EdZ`?Mф=ٙj0%"JmK15+0IYUǗ"{$c8bUOMgN%FƯ UC%.db+l·mV{s%H6|j֪<\wUekMY%-h:E mYtoP^iO_ﳙgMSߐG'|)ᮥK#{LdE@mn+zRmkDIY-ՅGfxR׊+*jNλŽV ҧArVkuĺcz+YɊ z[!lnXᮮV┲R9[E+oɔ E>@HU]uwҗ#(9Y)[ 錕׋52mn|&-Oa{ԭ>iZm]/lD0gmecM% %jg3л%2>B>N$| 'P 2ߚ33wMVJLI&mkx@cˡMLh8k9lACA<׺/e$.RB/P֢SNP uV!\a>˖XP&k!YV J b',VJɻW3 FVd.9_yi WlvF!^V/OUD$$jVl[wT<+&dRڝ׸^&~OB-q/e +$vNv *ȶ[W^5ФU47 Kz%ML@(7ZR)V$=AY0b4uQD3'IPq -Ⱅ3>P <IJgoȒGJ4F‚Ta2X[n++ٖvHRmMۖ27m|U{0RfIo Iiߵpvu XkZG Gj5&h ئtExUAhAZU 砶,NPS^JIg440V3V<鹭\U<@dg5Aaxi|cPjo0sr{yV.ex%-yL0Sœm o,o`h]8%&aUR'{W aE$bTc"P̪y*3q^5omZ )RvD_$ SUV79eVcmUcjɭhZj!:dQ)[UVUݹDxb e M*AsF*V[6s8!L0=BVQw fϼlhrb٢l3`l;&RsN{9c6[}ec(iR:Qٖ"f]-R f]S F1d uofCq@щjg 4z1!cP棪ù Áa-l6΅%P;a6Mb K!c%g)CɚS #4C}ořV`8 [iڦl#L^&|:FoHm -\;LD<\IbDä-+<(T%Q/h@RFJ/<:4ɶ;^a0FٺF`nSJz^Ja%ZmR Lߨ1lۍ|#Ͱ^48 yM-&s܈3ӶL#+}<yU'֔",% ThTM'ØjG)W:E%%x51mdOP&c7F4@pάmi;U12ʭ֫R@0@x|nM-"1ֺvx &x~ם[q|hj% Kv<5UJ!H| 1HQ~SXm@YU"l < ,؝7*^*v(ej Afүڔa um|Ȕ`dVH 9'huV dV CצZB%})PHٶH"$+x.GP6`o(eg67yRڮV䣣IySX?_*x @_WKf˳8zc59#hv8Ib?F|A\o@$@ͮ Ms PkL0BU^pYU-Zh@YT^vkI [0^|]1&Ov9j +VċXd5ThT+l=Ԕ Ѷ-\Vo3XqE։b9u+m7wHv'bo۶yVd oKvTY$pR)H-"d0eXmVі,5G/KNU[b@PZ-^Pdֶ@R􁭘de_+U"Y^<:UՔKKMj:p&Uy*lZ[[}_lh ɤhJy]yI[,27V4/E b|[>f'B EVn|(zL@V7F Pۇ|dsnRjdUR(M6 ofprUr_$F2,&"07&m %FHij 0y5p H`N Jo\*ZÑV댶5ZmJ &B6L0mZTrw*Vjk7y.|L#4Vg _S[kJW#b**3X^8}L+hh5R%鳲 %.VBi b`Jfnҟ{"YmesxL&p7 x}Z@8H)Sp3i{s#FX9oyն@ ?dվ[a}2IQ5g4x؋SoƈtU~GWi)UZy`U7̤ hKq1HL@Y!X(ZGU&KX Yk{|i#Il4VL16^YUJJs[b(o&_mM;Z:^絁"asi rFduISҴ"[Y4g8 ]Ƹ`_`vV33'F(WDY9eKi\mJ kRٶ emECRvڎiH[U/hµnxL,Y6^c^(j6EJwv3,2mHD+ 6FJ̧1<:5)l/Xndr@R kauB bȐ(3l:ZEۑ`B#׿ރA&RdKu A VHaDž%+ ?-ϡ1~:7:g Ep[Uud>ʁ91$OkDtN4ka6=]%d6w+?HHW 40m!ҹL*FV&C$ZHJ+kmݷsDOF :lUU!makXIf[%0*[mm3?C|I8L!&eU}"1r C#c/-u8P%g4ǚ0VKdV,!2@V]X; }.j,?;b]dVRksStHܯV"@. `^P` S_Lw6!M@/5C\ 8pN?5k5#L+-Ӣ|z<0]ɬsȤ(K_*Vj$ʮ3^B͓^m )K)֫зJ&8f&0nsBf[1 7=yjkJkMl۫Fǖ9A;dv8}H' bpKٚ$J`Ri0mgYcV?hjD cKPjSxY& Zp70eU!o_U20%2Vv]c* e%~2=i4RT- CWURV NPX0c+iJUB$*^00 }ƫ.7l-F fc%bJ '220ШiD#$LM(ʕZ短Y2qU`qPNr`Ѩ&e^6J FSQa^d:IYV@* e L؊0OlRBJ11OU^+ᰩںV%Z-s`mly&^[ﺬjRKR[p&HAonI+%Ap!0kT.%8PJ`[S|wg ׶r@y~o\P?\v:L=NNKebk&fjP>s|D45 5/y]ϑ+VHPeNYIEUɔdPkȰ螕Rħ܊Qu-I'P6f@,(ok!U Uq 1RNA Q &$paBxsA]" C- JȪ%#>"T"Kmmg.DW̼8@Yk*u<ֲmݘB0(E$9g *m8T/mkk^jT2p/^J g"5Y-0.94b>UY70AjeV93Ab0coL+yʪ 3&Bʷ;x[N3]%Ikcml%oIp)3)eѹس򣖸I[w4L0M^XJa|0x$qÐɬ=b}'x*F+J`@mo<9A*W%YVB!_!6Q )MYӓuHxQԸs#m3ٜ@i  AR5&kU^XoLJv`kKжTȆ)EiKpO4;h< x-Sk+exkHH HkVQa`+( dz|V3pf'C#E @ʶ֙#AV{1f} We]DZT@{W=|H="93DGz35LÓ6`#?q[i6&1U&۲4P 28ӪuV@2j0R\VHPxp?v|VԂ8k XEʭNTs{sut?#Aۘlaav']L@a3аdudVGH5L8 }*,sNYan,\I,  w+;cJ%0I%,K Jx aw4b&kK<,Sӕ0>O B[}Ķ+%K&E.x fUi>J|7hAi맘HR [| S LL0G*e'VTU3$#EY-Vif4Żd+D6ܬhz"4y^yCН4@xԱ~OҨ寑+U"L $RVYfnUZ$MSjA,4Z4 9za5 [;8 Rz oӟ 9D2ZS=sc1I?x%NK+i֧ª)ud0GJ>g_Ibŗ.VMM;Я^E}~%h6kĽ副iNU%RݪlOAلya61:lUmEjY)gPyWw 4@u#O$&F*| X[<AHeCB]OT$S}cXs;2瘔 %lmx[)#{&$;o&d @[[F2s!gKA w [i0>B[H`EAikN xJٮV XdQkehUb+l kdeR̭[)[X\/,Ó 4 Õ`FFZ&dւ dH giC;rt"=RFH"3ɍx$L5^_3 Tcz֗#Tox@ 2j1w"4eƸs" g%Ȅ $~nFObnR` ܞg"cn|*-CH ZSR0G[ޖlFf%Nԡ(QZE2++P.p3MB hv)b)+}4r8: Rv%UP+_kF~HN|z<_^-|ޱ[gVhjjc<\7lHr>^i})ta8 ӡΘ&r[+)JekKZȪ;/YYk*n+(ixJJ`7L(I5sls%x3)[)Eg7g0[岨=Ԕj 1+wŪ6J٠3$`V \0Uxf5"tQeJD6,RSv = YQk$ =QhBmr<4cC +^f`d->eX @#P;k:TdBd3C{c5΄cjG@GPG({ySAe6R&UuβHs Z TA5FJfPr4i8$ ǓaBůLV-VH +m,0@VLݫ*G5Gp\*Y#as9f#ݛLRKF=(`XO'SHFӄx/)ek0L9kW 1Y:rbBmL*HU> ll_^j08}WEXJnaMbɿJ8qn 8Wmi1بEz+7۪1mX D[) .sklJ`xƖQKO*[P,Z󟶪Fv]roValߵpw.|U@ֈ8+ qW q VclYZp9I7Faq=>~ב/1Et[3h ( ՞? :"+Ž,B Bdr<\ ;FHU57V! lo~Yb#1 |h`ʀU:rؚlbh|:U D*Zs0e\{NY_mH>5b!Μ#kEb[DF2̈́9RJcM)ը ""8݉kIܐ%mJnmM=XUѬ W2\&O*cjʊiȶa0m Xp5Qht:*G򄑻%@\ad`Y9a-}%V2n^pk c@U9ᜁXIZMh54ge}CV6q٘LJf|}X/o<  ݒhg+DVq=1 dZKi!a2dt(Xe"}}ŧ)ɀ%Yղd&4UV 5wcdCVh\B>H4ƒSZ0<~?kD<_FI]&s{47 dz'J@I ߿1ڦ`OM  Qrp 0۫zIHG(Zϑ@̪l9X ))* TK/4-g}ʾֆU!kUX;n ddٶr(*Wdk`)[3w( 2]m'IMY)mx#K +C*h+hOy`٪&obR *_?R$1.2UJP # v/,l S}? D }6]RUTߐȿkԷՄF X{

]rr>(lmlf݉h.ÁJ EZH;ol[Jus:P8=@U%jm4zb| ՏβV[BۺiVMX;\Ɉ]7l{Y"|J6aVb W0]!iGG y`ycTH*bh|j+϶V9cx~+Lx nujXHRy%6& VmFe3>pnA`U[ʾ+A dmeAE=tVx@Pٚ@xg\ʖ&?7@\v̽-KƧƐUX/*nH m#VF@^v:ڶ)Es+>%lb6-7|jYmQ*+T X#b4ɤn0x;a^ ~}QfRZ^ X:5WZI&V1"_iȕt'`$3CbVlŋIZ>9huZ> lSv߿AmV?7bۨM H0Jݶs{0s { M!JV0VLXm-@-RJZl~H d9gΖ*xdـ'`ňJwUs'^23rX4*M7/⮐eɴsRH–&kG [aLVjHR~bJ]GK _+êvRl&;CEPՉ"UZ[CYZqkzkJI'!&h?V&"ǫ6cKxkkg5*قi5Umcc}>vD _'#i<%B )j 9 U BǍ!CF2~"mgi|< r9^9[T3s8 ;RS:lr@xNjaoCXRP9H&@PS>");K)U\/2)U5"'gb!2Z*m'}حJ`4ֶ *s58m ־g~{TJrCrcRkj<H$Va)ψvK洕MiJ_mu: =e>p1T2G!Cڊ!{ĆZq@!NKM*MMt7!=mJO,`})m 0p L֝n~%m4v T5>৬(EVw)Xk8  @P(0pclutEizF[;>1SiW|X|0ZT=^ejf 0'dE,`Vm\wh?jml)g>"3 ewp>xNoe(.#B5g'D8&՗ƻϗҜ2LTa0~+* UXi`A3PlgOf/6=ӵBwP%Iu]#Q!Fz<`Lv]-YJo#r%)('&H 0 o|ꢰm3ń 3I wX9RRH'(DX7mѣ@;7*)>0b(xd|HD̊I!eT3[EJ0xڳ_SȞ:z5;lƟlJbG Ovn(1Oj>0V-7  12]<ٺd͟C!S z`/81ȿ,nֶ9+jgkmrJz5$@M#jeغd# NO\lsJ6HhfpB0QX-qnV٪ZۖD#ش7,§wNYʶcfӱNƊfY1VWR-fe& 2 `% Y+Zo*]cnf 2oZ69,wiZiDX,0v*|XIi'`ǩX NfKF?~ iȯCH%uڦb("[: ^ I SAks#0!@҈+!'˳ZBzJ:9)_F&@Zm>} .4" K-:?e5V*!UuQ([H5'Bds/gV.DS/~RJx&) 揩dodwTVG (7LIY_}fPXaLڎgU%kBMvzhғJQZ/pMX: SJ}] Cz[}n>/7|!+ `ɬjUm{x v;7hi*axUe 4X1Hb,e+9 H xZ$%resY(b6z2qêZh!YqȶX֪JVd1j I"AkLk-6T)f;cpcc2)Ef*L-*ĹP(sU lKt>bn0+<_D]ZH Mޣ vMMXF9.VbN`46Jn^NGg(mUZd5Rk+YJ)ouoBW^6ڱ h@y&lYAlM&e pxл0,4eÄ9?R)|Ҩx+At3cdd 2>Pɬ՗ƖJkd-'Vhl<[kq ;,&U=F=qVHU3oE=Nʟv A&YOK䓾ak.1t>}cPP4**LG >q$[k%B.&Hl+ S ;WMs˟F4 "gdRRI )[&H`0Hxzy"l+2[4 i)^UH6y#TV &Qa"gid@#ɐכF;Hʙwj9m}ek䀪s1 m-804vzL$wWx [LVH5&s)L0oS)eiiXELO}@_Jl ltBm@UzuczCGXMrSzN9Y–1%6T!sKi2sȟRJ Sb<nyRx> mƲFI&Moq΋`c%c"`+[2/܀d2+7#Xd" ik%hck4d)zR oЕԝ&p<'+d(9d7a) 1&7 нP Fj5dV+EXH3Abrd-Ȝ 4c2wydAy s'MbU [ə'ϿEŪvcKo僤T+=|%e[i\V*M p)5ɔx` s ߐ5-ksl%>Εi 7OSB^ߎl>+VHiZU|GWQ|mem) m]x a` 8dGS"p5=Θ.ZڛUH ɺnD9[@oч/^w ke8 >2\k2[<A/G)J3t3V̭ P100^5o C{X1]w$m$[M2L3Yu/n&HL22CmǴU;JmĶ,RH.*U9Aq|7Lyˊ3ĔK<Q@lBs%K/㼯eUȪ!hQ*@mK&mQU,[N4SYy4kjK(f2Rn1]pHl;`48xL[-=Cb<2]֨Ho4 kq3 TϤQ1B6đesȄ@4awV;#{(gA-RmU?HU8s|_NfkwiSZ(kA4>P0|κLza>s|XɬHM. `<`Z33$;7|.<{ *՗|ǧ%A 2Uٴ=n&Y,@!PinH%c+rK\qf kEH%4^!1YGÓ l[Z#d~[1ƘJdfUf,,<;)pGo[!,!֦R_*Xm2dG gURD$@^>i8KH>} PyfސTW*l0$ Á̖ ҜVO9Z,F;Q^% 8ӰГ5?Rr$Ay"[}H_3"jmb:[:o@ڪ⮇dm&E) uoo_ސz HR\dðȔ,E{QhʑB $6|fȤbdM"`%D 7b $;TRlui%V++D0+ 5Fȇ,,?ƶ'/|#U`taRSkwdxdlNqFWaidH+!AM l275%7&)P"*[䖲T>*X Jڶ`I"$l-tik#e>z`b-L.h̍д&&Ķ P!IFTuJo%2't1cR&c<hGrbL( Z4 '"UyYaIYGUƳem{xn&՚U%fUUGYnc01Ϲ20MUzHfR V002y6ldYNA#ea4 LKkAXJyEh? GF ~@c\Rڷo3/Nd (+X03{&q@;Wb#w;IRЗ*)@[^&_ xӯV #8J&+ $pH@p AdUV) `uL>uG*,4ܮ7`ZTHmإ),!,kb<L IF<]li ,8 gcK +:PyN!Wl˚:+QAF`RKud90m60oڲ pc1oEb;_ST%ؑW(tR4i2\v))1!?HyWj7_VLS  /ՄRe9̓k-r|5FM)#jl(;ƙj_ aLpTs"`HunU +Ka2ȓ$V&UJivMٍnR;) 03Qʭ>sSn͖Udz5U٥Yk跅řZ[V!LvUwR]u:$`p u PV3>Juz(l攙 )e(E@B8=d>)B (1U0*!$n^ 񪬪\2R ]r&#쓅 ĂɛYH OU <+xcc:ƻO 3V*. 7I)P"[> }j:7H}4RJI4K1HBZj4hkV-h$>VJd/$C}+1>8RųF3o@T d'm*XuL8Zۺf3t4l 1js2^Y&cۘ_q$>b)d I\U }y 6+XfːXըWcKVe&m )eۊ2pVZ e]J]rYmu)><>0 %zNo_2!u&W*R.6[9I`Z3ղ(mGE>:*ѣ6 Izzܾdsk+;!PYa5!yo}FV?KV|X1tM!,gK{[0#`$]zv ##Q9Z0^`o ̹̆'GJKV4{2?g S+f WTHVQYe+;۪l=WQ!@)ZWEgKL Sf"w)͍nmZJr~_ : 509UI)^%& ē  80nQb+1A>,W%JG7 7%Ygkn]o/=%&3p#d^օ8}~ oc @aJiR$@6@r@z-/M Iekl7(Vd['@IDATb*XS<)ՐJ,TУx&JbͰ& P *2)a<FXp2UW~.Ce  )j?+[r)57pဗ2R=\e^V,YxeK_y xgg"l_L&k :ZPpOfElKfݲŹ,@ NMܚ!ea#їj<+0*4ʥLr+·F&i[FC43[@;JXEf~iZZ[QiDz".0p1yfhHۆ)G*1I/vMr|#xêy~+~oc-Ћ+SDlmfSb~Z~ RHI-Va|_0zaraM*)Q:r@Um+I02qxHʶ cK )RVbh&HY.lP쮀14v GַyRH~7 L2OAcBR ;MRUY&ّB quj! T7^bLL6LMCoˡl['Z`VԶ[a1 4RBXy6@)&ۓ".fZU c+e W-&Ͷ񑵦ը^Hu}r}wRڷiUu -dX߿eIB|kkpd| ;a8(,m)ÝBL[LUHעO؃'m:Uf#U & K̈́2k JU7LϿLH*B'TX5";/R̥lE-ɤֶ08zk~+?ߡa&B*%Ie_ONH 3 J+>R-o,8YS9B3[m/h`zCbHEI@$9QjJT!XٶZ#0)dI`7Fu+bT( D6@uM=֡+fPt{9"ص sUKV#V4Mc 3lLVjW8o9>CX(ǘIuϛCwV[Mڒf! akouMb+*䂏0T;j0em566CRuTmUg~>Mz^iTV9*+F40 usA)l<\!C>az{]ҋ!lj ʙXs!DԅD7զCY~(aJj50F!=jH&RE"=0BUQHOc֖ Za )`X9o R(3 `Hߜ9HQ&s LW^  *kWɚ͹*ė¬J-0E2r4g,=~&l՚I&!) "LPU^Ř0Le_^=miꋁsoYITa# "eg.:^dI .JF֚?,PK[+\:8KGpA&#rpII'e *AJHdV#[zy5}+cV. f*s_4@ƫW dEeږ ̭-%lʶ;,x$+$ 6-[ŖOUײ7V-U_QiQa2dxD5 f9X1F}6`2 TRSA {Y`x&Vc7rQ*WOܣɤ׮.hBʪFEt}i0֎l6N)5^ _|#Xuj&„`U+wR0s˜ZBk|a0Lz& KVOjȭJa2ur%>sE129![gb,8|r9d &ՉC|mS@`l0blUV*`&nPY 1|qrgHg;k0Ye;C4ʥlFإu⨟ܽ !ܗ _#5}%5UV}RU" #+t^t!HVؚJ YEZ7^i'% =yDx\IgdΊ k]4R9TRpg iC6!iT#e/pѭ"iZ#B|,pΪRUdn&g"PY<""ew^0@UL6Β+bCg[A/-L3Y2pMH 7 fUuU'2U/Fl/[kd,eD&a>ĥА4x+X*)EgI&%JY NK@/z O/\R>p=ΜAlm\-Om⚆9k]#Ru׋vp2+AS"Uέo ٨a%ͦygld iݨ(R"1VBA1!< t"%+,TVYmln~ U #alkf4D޴)ciYhuc"@bt)T%gUتʚJICd+Ą!B+0yL)`h46`5b+2il5 vCSmڴ4Rmcfxj& Vb]f[9nZi5@ ^YUa uIlxxVۘM՛@* LMcde2cEu߶ۦ5[@ job.Da@k]Tu0b?qJVRBGDahl9d_{wD]iR<ܬ]TnX*-͢|hDV'$8΢Ŀ?IwbEWv9ZɀgW k+&0q04HC5OLei7aX68}LHLnVZjGZ 1%3Rxyè5U_IӜx'{"h` Y&83lN1,H0ċVn/ Z8xk@umvߺ=/<>5ɧ^p4mfQ+9`rǙV6U;a<7֐&4,xřHy6l i}*irUgRItO@nd#󏜦Ȫj0r"+FVJ:N@d@i&MQJ"Lפnݧ,Mش[]ll+IҊO 7j_ OAi& R =JDcP-́+?q0\\c== T&JzևWUVMfdz1)7O-dZ[]GTP^,7K#YVjɤuuR|(1@2Y +9̖I&pp hdo P+%Ml[߲R9=5ߪJN,͟duio=JxOJu9B a? >qΟQBm4@dR;y*" % g!nT# sߏFT7yygH<1€a%+8Ue8VD+o$VZ's+R0n`@?_}^{ 7 &$cae UYOfKЪ'+eFfٶ iAޗ9[ %8ϹRHZZlu7ReDފk%qF{G i(u쾰GZ+1 I6϶&$$!V,:Y8}!VL 9י [dE\_ Af +qz8sA&2zJm@57[! d%VJaL*²Q84ybE(v]R StdH,.e6lZbȄL9<afvOkY zV&fZƻ gY^JO| gU_91ķ_6@!^`+eۄn:>LOf;~[)>i?>$ "c 3֗^#ŋ0 amcS pJEY[b|(t1 zIpxSGٓ( Ҩj[-ebmU7z@vLVo0adiMjڨpJ`55o[uY}j$CJ=,GFP8{[Hb"7f69P071Y[iR9ȎT(Ub=HzNaB: O4Ćt~id0Wq)cth 7_g^үa餀rik)J]2J)SHqxD_!2}:S)mahv$U$ %]M[ 4@"a% X ̄>bޕ'%qWXSpMpyҋ#0j`=lR4{]2mUMʹY͜ShՋauYi'e{d;H\ǜ1U!;~ڲMR/ffEDL#U ZJ#U1tEei-M~RnS(ZzUǐ)BI_ ƇLtjnL腬m @V8fސ;9m⠄ C aݳ5VhT%uh|h.Xxf{?Kz)2Xh?|icdnEbrW!v )ʪ5[hewV;&XHڧq/}`n;f0Y8lhR Pf%`>̶– ^5Z*@!Oɬ AjqH#j070/Ȕv g5 C gǙm<[mW @)g_], ICZS_$FZ̡yhVU 9sIld$.<3݌>~9W;c`>)7gkc+ `(E&/~kY'ɶ1 "{Zr5 tLk3WȄ@&l )YofY!yR& jKVH<-cmKN`x*wo|>"=-Z|!&|h͹VN,FUD^eEv@`5'hm hB& RpzO"kAolV$U4ܚ 8&a3 u$ȇx#sb[t S#;i1yLHzS,;pn2L6]^u!0T`8M&4aė2gm:;~9+!^#@~S Xyg/%Ҩ]c4J$,[UVEwl~ddp3j[WU+2L!*ϓ<dVC$^U(amxJOܢsLzd+t"7U1h(GοiʹZۺR Y!yóU J=d14 iRsVB#[&Es -MÛ<)dPLm۠ɓIJl Z+)bjž ;Vj,o!Ȭ2+,2;])+%~Z]GY1Dv4}[T:S&gaG5Y5Y`FdT$&,*w~UeRl/hv}Ro [L<#'nl 7?}D ܐ]^ - }jUJ|j C/yZ &9|Vͣ62+RЬ @[+O ߒ4d)l~}eL@YGejc:5qM[i؊d9ޖRtȅT5s>M^k'BW-ޚsm!™tH2]:n[qQ-PKsa(aT4 o'h+-d0Θ$y%W(ۅ#0F V_bVK\hTGư [.h"|R?o kl"1jH͖[ xчY=Gl"20ޟx0'͜Xք;^&oew[\;% slm6cȲzU.+e+_Ydž3l?| á*CLgR ÿ![1skXLYùaQ+%Vn@w/0[ZV<.Vmw){*a`[vbch+MXR^ﶪ4@7U RE-E&JkDt~z~5\[hjLdK1jk*cZBHk3 L0YqQ&4ɔFdlf-dfr{j9TC&d1۲HLYVSUkן̆ R.H)l͓6kȗ'GnK_(;,.3D|‘rODJ kv +n)CUF7IJ1Ta֫ MoMPS2lȶsQRLlsT1Ɩ ZTr+] ^t%$l 5g#%vUȒY}|0R¨J≔Eeke Db譶E r֔"F4@b[ba@uc1Ǚ37 s? 揟H,W z&+|Jk$qRdgbEd 4'>qRV wprl7/>J%`k(ʭ1V%⺞%3 l`|+7gI[j]>CF1" gFj*dU `WŊgd qlHzf E[+1N-h0]@ٶun rFZE@΀Fuߊ4+02;jy]e7RZ&5T$pcmk]FjMooKTdXFK_ME `QWakY8a[0L8d[3YxC-,Fs;`$-Pjʥ$t4e&M{a% bUzZYYOYd y7d%r+Pt-O$ŗR"$MkPVNMiT)&dm ӈHk-0msV^. Pa$LO2J)9&O[kVJ|[RFbpy _ CEY6X岕IVHln) ҧ GZaQ՚[ܶN @c9&ҖU*sî*0pUfV>&БMh^pOo03ױaTa6<,T 9cjӎ$^0 LL3O5⛟ scZ9mh >Y&DV z>+ DZw"J)r`.j#֔@%mMm:'Lo%ck] @^ɹvd@f_ SV>4kl)W-} h*U0%~zx7CgdAR|ĵKi0AgW%:U!/ZmMHL0mo t+,՜eȐ7j }[4 dml–F~硌BZ[g 9d ZXkͦ@"304uLTc4dxQm_2MR!=;;R %*A ,֪Z#k1٭8 71޶Q. ӛٴ'sAY;FP]˘jmYYmXYJuW)@J|8H*OH@%+I|zۜ)-4lf0 YJ+ng!-֊荲ic2+,V{9me֮Y:i:}bڍAk+$ml5u;8=KnUUǜzP6wM ϔ1-k `qd繄RtEHTܺJMeWHb2za0azxȭJ%[t):u|΍6e.a Ө" Nm3q$hX)k)R6 .xJ>J`+Ȫmo BӨMe8H@aMi%nf8x%WuYx3Yg %$D`r)3B;dY1 1tvmIzPlTN R +Vi[PNިJ a}$T>u1>LO&V/mR 1 GV1%MV~vF7txlSJ!YM )[Q0j JuXS|Am[}{]b2)kөڿ 'i q&Vm2@ |C^0lmB[Vj34 sYӍ,e[a>9$L% }TycEizn.n j@^8+)"iZ$}%Ntfo&pRZX`%f]pjZ%9RV%ug64e C ˭^_Iy2j*80JˮW2),R;n0M@grͰFiLfZ/낀-*j& VN,PڦgNv<.`+}%cxHdVhU>8cz] 1JViZ0Ev7h8FS鑔# [)8~I $ [`Dbbu)1֓>dXQ" 6|Ui<7Lo1l`h[j$aNRi{ܟV IcQ aCO$6]x8z"ïOMg7Udbm*[#eU vVzTne9a Y@XaFbXnJ,Š57! mɄ!A@֕)l+WB%J8A&aXYkA[ 97%EU񘎶m`5TNӉ1UfH;)p@ZE+85W`EMn7Um 2ր,)dXpoQ;mFuo| Y_U($VXHZ4s s ? {4gjnH^WyߐϭrO@a`YcvL&5ڬMcm^H!6Րxl~8e)kr &ן;{!jl[o lbXe-lƀe:=FZ̰*[U"R3&n]Tkm[hA l幏R>` A+g@6-Мxb:Zm5[3֗8 ȼH Yr#w4$ P @(r UhL0)aczoLs8p) %+ VS$z3Y)UE6 fm\;34֘yb >e<1Ҷk$sdO[Y)$\ȧ~)U 3k'xX*|+Z}|0_¶(rْ:8 P%'nIJm&)նOg8gKd6Ɩ|1RBTΘV{o#$=ZJYV;A[+mnmKy:X-29(eY! Z nZ)զea Ywc')ڒI1ل0R茫m̙c`Y#W8}!E4 4M2$8뎤q@kUfK HltlKiJ3Cxh+<[u&3H# qv E)2^%F(g Wu;SnM̿I2q9^*wF) 6ބQT'|TtV^~OղH79 gk݀bm@IDAT 4"k)0ul+u w0̚o-%`8k)/'4.E?ۮ~I( ` 'gb$@4g2B$PG0iYeO9b/duD{lu&gFT$辰xL9mM21 [UE_gF [K1ߍ0'=$YNQ%񔍇$H[|*iud/^O6JX[k$})/,O hl $ 36/̍&20MQb"sD46EΓF9Ru.4e'}49y*,4[wZt ֪0„2C2lma`J H:Qz{gQKi8lU]3Ca|t!~`~@H؊KŘ֨Jvu+S Lr "kjcӅX0Ѻ'푩ma|b"Қ^[։)E4PU;Yr[UYc;j(7@/'LSS<1X4UծսT{#7ٵk7R xFͧjK&;) }mBM) |{WSTe xgW*+ێ&zVyS1怇Oim.Yaeչ )+j;ll40Mݑ1JZ/&f(jU )ʰ5@taRVfg.VVBʐ:v햺j1YYU tֶl3m1(W{|oU%E֔c"V(iȚ9FAbuxV+$+KV YHkD,P0|ܕ@Z34aJdQw-@$.YΞUz)[`Rakv >sܿ$nV3e`@ D)Z%ߥRp=GFYy#alc[WjRݰ 7^s9yϡN>[ByҼ)4vO\ɐ  m)e^zj9W"b0T~dn eZ`UkJ 7TBP E[` s0;Xtb?,4ܺ? ۿ%hUyJM` &k{A$ )hY)鿷P5VA- 8-('xwORv*!HJuJDCP#fi(YI`2,cbȵP-l;2F/nP z`%Eu_ ]z! km ʅ?AV2Q?X"5lZH L3Bpw2=%YU,"rh$oB;J p- $$`X׿/4t:@ڈ3R *dl`dV&"Ä$+XX9!J0IC/Ei6[@8E'[&VInuDb|@cLs wp&s4B@9ٞTW1}2Fg<.4@E p XB%ulZʄlhl;mK)d' Vjƻ?>;B3nZ!!(ՖgVt1 I/x~,L,%`)>YPwb"60d:1W[JaZ%ުR7 ê:5K`V(0Gj11 uXK%rX|"3:R{-9tF$rkRV"̖C>0>qg "+JaTadgoRUsBDx%iĵ˜4ab}?Vۺ7&q661F;IE4@XQ-l:MYT*8d֚û*%SNW:{3p0U!y=lIwEuWTSlP C k?f6}495d-*%jNk(ɄdemS*UhNlkI_/R M| IlTBȥR,N}ܝ2HeaU =`8(eD-΅ LkLma)Fd*VY7p)V S]?>9k̐"}4p"$7+c C8[8jf"E& Cρ{jh*T65pfS*x2fKV L $ZG I/Nl uqfŤ^ M>MadJZ plabcd2QPbؾjI+ΒU)JlY&*lM%6FH"=X׫.d[b:-\܊i+v9XL*w&T+Sڜ X 1)S0ʶi ⭑F߇L)jrD52!7kE[iQiR€E 0qd}[;`MS6Z }E֍d3X *[,%2)kDMk@-5%b[2c{q˧>0e55NZ1d)m+O'8VL4s9Q;+4?m]#% 6 o3h!54XzM36@@ AVgQ 5|"̕.}{O**GCRp>@S4FBU-?Z\V>e*elɐmxzbn @En YHOP@V l'R#@ZjlYX1)Y!ׅ@1F Fw-]Q#)![)k+2sp^4fb)kwP4RX`iI6* L5y?b|[)%irkwˡa8%&Vۄx۵1MWîhe2+.L-;\;[@ݝ#;8s҈Dqlx4BkMU֪*:i8fɲmNaVhAL7еq>MhC poEkzViTi|]X?Z?eTo S [>i|`' &w*4p}"vT0[WG_SJ&71 qM]6ƥ!EX!ɐ<|70 qFhaUb}cL+b4O{{Zh^Iye+ܐM!`EpG0K3-fb[/坱'՜u8s͓2MKUա"׽ %%40pci ߝ0/%%0E/A[% uY6PjUa0Ch{Uj-E fh,_ͩkC 5Skkz!'ZȦk$xU&4OJ<0eB-Fd1!F9sbL0jFU(xҼ)>l ~K`|֎! б }dLJudCk3rX-n)#\RYtd]jcKzN S$R֍ѐeİBGTݭR^j{`n}Cy.ed@ @/璭?;~D!$,dEdK0Y ebk{/@Ic.HR)Ш*":{2`X-\]ң!B)۬0 k vJ&isgNn ƻo<`V2yE싻ɛh*g hr߳ǐxc #V~KT $xZ7ُ+pm*h`QIXvJM w[X(̙k<:r}ekj UYrzDs}ub'Hm>y~4m6$nb(h]T^ǮbHcեF0&VڱiNCVl<+' td)+DLVD|\*ʲ9Յֺl u$CƓeiº;), oF^djaA`U=xC'jdʗr u=[H|+tW![J$*VPz)<[4RV c)bCVmƃKяd]EGyd&.&@V_cI[㙳ZcJMoaA/!>ܡf|Y=wٙ$;.nF9))`uĐaD};u'⟛,HӬehH*@ȔH$5D"lU"k͊nTZa&V'}?R*P$jH1xFUx=@H&v}ڥ1ma⭯[8kWʟ^4N,.VTŦUX|jɜHǮі6,T Ԇ"t-HzTm%i#k9TxyC)ҎͣQLjyVUHrj!T.}i.j'Gxv9aV'[JVlKDTM +B (+lkݶZ ywI߽=Z1mJ΅F"X- irkȎؕ)ƤD mg[T(o 4 pސښsYz!7Y6-qUa6p %CJ- 2ԎahDd2dݭT AY95iiJ%td. )۴ZkK9jn 6C.Nʐ2*/-њ-zjeg%?d6R_RE0vFU_tXUZB-Rw%*[#!.e3) [k# Тh;[J)U im3LO?r<Y"'3]BMQkhZzG&mE}pV/30g gCC?È A㝣^}WH[筰mU68 *1aMC CwP2tƶi;[["n`kvHleh21!Sp4x+fS|?Y`9pK3%T]me4|:"EuHِFNY N.iK %l#E@&:, )&E`aۂVWbύȥ2\eYx$\oBCa81j@ Mö>4 R MKZSeVYs&Dm#<Rw$`[5%ͫ$4gU1 @f+DJJz+o)u_%V޶jr4dHan^дm 2eo-|0]#LӪ lx)g tK6m&hB~59Yb[n-AY+%v%max&H.Nf$ U5jhțd Jf-GIQ$Sʥ⻋w[aS9R)G:R\w&BVTb+bH`U~GRyG )<4 17%_9 9S Pa1uAbᵸ3-sMf+pXy%1%f=(Ga45b:/j;+JikB=M)AJ;O3g`}yJ %(D MdUml7U$ .}*rLw\`rdPk vx%x%>pV;\oek5bCt9'b3'5y1LWUO߶ i0V1.Y9Mk ;mFl=HӤY;;3 }Du0d.L~ oKc94@UR=jӖ hl['usE?0 ?>ʟ@0@y#g *paJ=  `=ke,5 Eϊ'ङ׋ lRܬ?Fj~dBZ{kHq'Hi%fFI)^V-&`.Ƌd//G}s)\0eV[6^Sj"e)0l#\G|?wU2v~ iU-c+-Uv8v]D] Ci.lOJ,d5lĶ~{۴ՕHdQ*6 ¬`[6B }T!)on+U 1@A%ցʳ\/Ŭ !+1ۻUldNDŽVde $(k9nGkk͊7&1Mx!IF:7Q-6&׈XDm(DD[=dM+E&mB@ e/q&76lB,dbŤWwl<S_ &ɓm|MlKpԦXicqcOaJ;Z q860͔Of`O gkX!ps ,pjA/c5Ҷn7+EMߐ̅^J^[)[:b`☬`%ʇ, ^}bN#G(݀RgGU)?܀;y !q͟[|0x%UI1TNEzL"ӡ`6̏L R>O#.lwu0O7C<&5"s?Q.2H4$q_WZ &\#.S; لۧݪ0P ^T[(4P9d%n.*ɬ1Hc*lNJXe>xX^9== PkkamFB 6O5 e;mΧabU^'Mߙh*DhZ+)l YR; 9 pۂZ2ȲiK!,e5^#UCN8M8cwV: %b,X6`\ 7 +2@JhAfWKf=|cU`$Yc%OgTӘ͖VLOӂ@ސ$.1UE{/{$5eUs + e (DHɐCnE(%ʉ i#Hv|{|>1I@SPkP( <+aKOnmto'@fv&",lm[nrT'`f)kWUY7Sp5D4Jl)Hkn-dp2_21v ;8,Pd a;v{:_aSVmZi oS1|Z%)5=#kM`sHFV` l)kJPZjƻNgA*7I͇8+ 'Gi&9̶=z"7ݵX*4U'e8$%fhUBL7,Ъ0+$8O2w@0 @"?S bJtT%DSnɬmg{|[ARJ kj}$/rk)FjW֕k_ʪIL6%8*1@c6.sQi>Z;, l 3T.DzVU^RVV>RUh bQZ"XA e[yrpEFf;RI.*d[XxMkR+&mҵTnN)uwJˇ0S rl5sf^*Α %JZ\ bYJиa[ILr"Z5֔ҳ0Ema5*7^@VYVjmKY9Xk,{|JIp[2#$Rڦow4VQS<Ij"bI=_g*)mEVOP^Og̙-/CfÈJ{U_e[m +bkM:k4cFm-6 rS͉+j 4 Nj>YR;02>qJCܐ9TՋ<|hx+@R]ye{ *eU+2+A8"@,ZL!-ZbmPnc:**Kcl) i%MʄYd٦Aʪ'gfGZn~'Sh7X(AZ 8l}WEJ*t jg x ^^ &l{Qy &EfrmJdUVL$KaբxQxgr}Mq3 [ŨR۳ \kk@SCz+%~CS@`fLe:fj񭉕{yr8N#'yͭQnVy>6 2K0[nvWL7LϽL)wo3 5@mxF*|{  ;5@zvɧv;#S |HLSY ^6rń @m$蝔"IP#v*0JDݯ$)C&+ =5Z OQ [7`-8{٬07|غE@ɳr* Jn ]zZɊZXI bRV!\X1+4=mn#l+ZXֶ,"=_|)'Bv?IsX;Q#@մ-|d)ZX4#kES&&({>v.4`Ǎ z3q(ֲm~}w'=[w91FLrPD%Tـl'R[ c ϤYl ĶK6P.daYۘ0j]9o|$ Tֺ-lWFiy[fqxVV4H,0;/lklE@Y[Y a|uJ;-T^ytV+eK3X2Y3雧d K_ C&zuYb+xݎ%ZeF &\| K7"%zccޮyuSWh(Bև(2V  &Jh+kUH%^DV0v󴅍DpTuXoUAXdE qzk2k̻&5qJZl- s:Jq*U7#+]Q P.ui֪5|d[\U1V.+oS!+}$5,dR*5\|ȗZ|>=Ν-v#ՈR$ԝ/mzyj$CEJ4^: mܴL01C%V>d70&$vu3En)4/1zujV*n^U 0xOח^5(^WVAg9'9M C#Yfh*U-,(aM*qr)2bdT5a0%1 lH[99wsRO)W0H)"|7a't?l7Fh:P 9ԴIz|0:4q%iB$# T&[i cBDwxENw!]>B@ۓȊ.y9 ?7g>Rp3"cFkTm$^]jM{k_ m҄j:v'ami U >R('!)7жLQ#Z֑FM L]lwU&$Ј,$1dwb쏣u4;]H/Eך̉`!œFOo+#F9ԑX ΧZb!JIVUxdA*OVVPk$M"ջȿ*J"7o ^iT xƐ2')@oȔ <H/n)X1奔)R$nv'slLdMb|u͜gmw)]d^n;<V>yfhYM1lS o] d)¥Dm}Tёi VxlL FZ"v"DNFP )&JuA=(4c}uEZ!V}jeV#1fJd)*LNP48^w۴^V&wwnrp&l *U4dV'Ovs5u4X(!jG]{ 2 -:U&f{, |n~+P׎)jն*z8q040yJ! MJ̀#_Hk%e*@Қׂ&VQTγmlXI [GT[|pRpH10&sWa85`D gJTVFxGұjMf gn {bijT󯶦YI5ZV+E#w&l!.4(GoB͖*J/[s@Sz4>ށ#ȹR _᮲E7+ZncZi"{%.YV^6gᣄįs."e %  :HYj^k!e1X{̛Cned[ ጱ8&A힭ZK-:)A$"m BdQ[kè8^i #')ZlFmk!qW#J#j[<q,U|1LMufC @YnRڒ4,5>z<h^2<3SӖڝ3lni] !1f Lඪǧ˦d"<]M_V,o$|gQj (Rlb%2]igZj+7s^Sh$dk'+7j۳Мİ՝ 'BRR>_]l檚2Tb HM7hc(`>;dVS̎/Lj ࢉ7 S2FNaQ/ʷu 7ؑLkӏZAf m1 @W7ʥ. IsSdA@*qMt4Rö|եIb: @ &) *nVlFP Rbh¾_d)#[x[Q`8%R\jY@(KILgH4Q#v'XJ()(yO~h^a[b 7|wdVJd|"Rm2T)WEV@|篧ӽU|-lnlOT#VpWБa䵫&C&}?)U0[R/;t]RĢ鑶 bhz4xnSʧ{"YͰ<؛yUWKyöw Ԏo~2qYeO&;Yg /%R|N;02m{HTZkܺ@J8[)]8l{dM"맬VD ƶ ٨i8HI*ϡ֔4lg!p9`xZRdH}9 &@*W~:QURy0 $Jv|XӴڊP/}1Wud&HSHUtm;С2Y|*Y6ώU[LTrsjmZ8mK7Ny&rC&TVW9~dkA_*+>dڑ9a%=`"UmrƯiM6@Czq%Rqxrh~|[LdȆI&2+gq(wL H1d~Q80CVi]1/̌jYJقQ<ww<R!,ԭVo!=P Yadr?MU^BJwpP[vnR-[{(Y!۬RL9{ЪI\+nTmL@-mMZk3*NUqK#CS/@úniRE-=3[ \m +JnH&lWm[TՑ-mZR.g ȳC!uaLR]8y&j+WĥZ 3vVLYx:Bocz| X!#oYY)m5=jU20IApkZ$CW\aN|ɴ@V6XʶͤToi X̜dIw o S#VP:/eaN` >%W*6:T/NS-\S&JB)RZa܀?mDҍn dkO*Rz+/\q.c@`*Mk #lm}5 UHйC w nCk8@{V[U-E 'SXN @_ @Vyb,`rpka)V" qA!$+d*ي+=zYɆ0j#ހTg`uDzdb"l@()$ιĶ֝p/q"8HA/& S򾅕+pikVh=AJU;=bFu9_W6Ȭ(Efk 9"hA^gk˰rH +"+ڏr_xP7 Qc=jrHMeUTPd=$Sn+;1,քLh(oH%xQIp/ SL)Aۭ>"+rHХ!Ɉ)JÜ@.r>F&j؀AWSIa"9%zo@8pyO\Jn   @d! *EL }rL%5EsS"b.&QO).]펓&`L禪B+RU \A;y]!):Қ^4HW$jΔ_bCj?6O%ʧ$QȘѰ_!okYZf[+|a)g`5J 3r&p5" i,kݏia R dV)3o`9= <&FaRlM<%N5!Ks~ HL &&a` )T07 !JjeE8H5mb1mA)s8m)G (,fu(n[ bgn[G$+xk 7?CZ 70-sՑ3̡ 0JySIʡ8 u*6ZѝEDY(m`$۾B@dkw)V}Z1 8K)b+jIֶ뵑[T4R'ȹyLzd@aiچC  J)c߃pV&ߴi%[X;T<"PHs~X _E>57`e o[l )Ds#E0=6Jc`ʧ*AU{mRӁ# L%V'*M)Ṏ@<Ӫ\(>`EP5;-Q)>Me1>#IHUR7cH7^>Eʑ5@g[Skau 7nܛ?өo0GԦUUWRˮY96pUx%zL A[]|xs!ΕFёsrm]l)9wvf T7Peeż?fUԖҥpG K9::mzde AOr Z*ߏm~T̥**̇f_8Ry2)T+YLij٢;Te* FJ]0&ngIlZS׎٭Ô {޿ ^Jsh!jiUa WAA0PKO3I@/0xYs"62%A.'7;Co=ghbA֣R7Q%E_ުJz|+x:1e#s<$HWlmkvoe^~Ke]gֹDzz&XNmUWw[BY ohJY}uJ:mr0PY#v N;@C97@J$impxbg$;%tlUY1p#YЯ.M 6' *h`QUn K30du: -}ӓ!gnO?\UL mV609dxxç I MH>>݀m6*g)JX_Zt'|&~3_}l McFbFz$ 0An lLm"׷gN*mGx13TsZ^fZ]vVZO#7,kNks^G/ EJNj9m$kiKZtFz[rpz8تkӨ@9[оYo^R.d?n?FfE9 ^p00&Kf%iV!&ϧN V|]^ᲵN(Uњfc|&a[z&m;{0 @LVEAw+iI6 9ljg$dش~W&JHȊI/ǼMUc[k_#[kƜF dPl)u!"Ś.5&~-PR|le YdLw`Y(?V{%"XkL|cT~SZapV W)*Lvn3,g0]HV~p!Y;&XkJ6&QIѐVB81kp v[hgvǿ]@ʽcv0Y|C&ᾛ(i˭ҪEβLj1V^)B*%]e.Z-dr&OӪ@yTa)9aˍCd؊Lza*Jq+F2c[BT1OVVQ;l َ!nԪļo[(͊+K얤V49/!ei0.jۉl3$ 7y#բ*}S[ %=Ѓ#3C 6<#a1;U0r,+lw@n*RvMnSf|UdV/UmKF)j|Laxb) } sM YZI5E.i4heb)Db;Q oN|C2w@$RngUj'%-:R6C&a5*FTBYaR{ِbz! j vdRd&d%VJ%Ua~u]UY7yZ9T@M qTfU Tb@Js"m׺µNaidl sHP sӘ 닡SFc-@Ol<5+k~Lۥ2HWȶ+\~xVko*ӄKZ1a[_KV8OUBen[*^?+*u1C-ρHxE @LJ:KV؊H)RJȲoEοQdU^Sm|ˊ*HFy&q%gᠶl 뫖]m jDf5?>*^,fPN;э(B]Zzs{G w -1Rxn]-6ZBa9yF\f6<>1lNڒ@j;H7pz.o_a&J @L`%~cYY3of w*/wJ(*n (4dۊT6l-Dm +78%LCg I!wۘ "Է-Fd~}fմLhrZ)kZU̅3$Vh+j *C ͉*:(mY ^4*Q#ɬS )52Ok!X9y.~4#[bGgk0Y/[ Vhm Sve%VY}Wzt&&`'22qӵe6PEf@? dXS):1C}?GaY_#V\1OkgHiT+K[8i6YʁlX1Y²"RĹ)߉*i%q8 R 7$ tXI% ԥlnE6O "cHV֚ku+Lc0Su$ Raz2[g OM"c!~#^!ºdk)l}0kx1M=8S[`v'{̯d-b&lN9gR-CrbBJ؏ s#ᬶ3^/lH&E2(fb{+NӢB8}Hc#`Zl+LceeJJx18+\m%ךضailvK6l4^7U!ػsd8]91e>/~ƓX̧{#j )i.}G&Lx[ 8g+9Yx7|td঍/ .!6=̀;xM^CM 4If :>YY:TRbg&x" T8 P^_[LS:~M>"dӐH[O qCbL&0}!cE)ali,&-Tn£YU!@VJOY=&[AֺWN@ji>ʫ; Bk/IJQ? jLRlmy+{Mi0s+M74CIj:=^y3Upm tϘTzq`|Ӎgi+\1{0mokMdk_k &U!E})qYd6YK 1=1uH5=c5i  pslKY"[3cZeʭ.jk*%ՂSkP}Q% ' msmMmS7ᝧo/YHȖ sm ) m 'j`%6:"1ɬ&7zٮ9HQ)gҗOxw}؊L¨-3};*`ho5^ZGVR X :Rӳu@l,H[iTUH%O#i|JR*̃7R@\-@/^_<.ǶkWT!qJb a۲S"N;UX6xƌ|OY8KH eWW{4fNq`%,Ĺ%RHѧfg72laq+%LW$LOɓr i*i8+ʺÝ%sޜ`UujZ`e `Z H:b k$S5O2w-#5#V%jЈ́lCcSy! Cz=NF.SJLkzVЊQ>}?/cPrȭl+^h6 Y YL 5LdKfuR"kZ5wol y&f6&QB&#P{i&x-vWVʘܔ"̭;ga@jE V|&m FS!CYJYJù-_IR9)G6qh(aW+LTVY@تkǛx8CmÐ9gPQ 23WOGxj},D!pr@d5CbeTUR$Oz& ruٽej5~)i rVh[MpV `!Y<=EU3F<2 +a8vO Psȝt? e C૭ZRXNT12r +jEYGzv&PUw' ̶*ND1!4La8GD&Zk魚zv(==sΙ|渷'LԚrR3 a|%6ϓFYv=#h#=\V< (iϤI)X(E֖8 Vg*+_ ehUUWkON1g޶.݆T 17L: V`Q*[2=fZdKZm9]'B:7҂OVX_l[֥rMZۦĬ)A2+R4RJ 6^2%&{ǀL%yɄnB@Thm*_Ȝa)"%Sؖp46O)NK)dJkw̳h0RU U6tDŒ@F4rت6_oV+/C-t@#F)Fv 4Zil8701=3ӝJ6LVK/`3$UY9;E,zl;MUli/Tmօ*2[J1-~b7)K( FL6{;i;V#. [kXhڲJZmax2M;& pT@]l3k>)[{0-qg Vh`@F 6g-d 5qK1E2/`Z8,%f^;lUHCR:W%HnJ [@?VLG5!cVV()i 'ڒMSIH+MCPH>\9Nf 1V֮ ÓNZ_MCa.s9ׂ^/̥D*dg$*AV?lO i*f[-PHU>|nYm$=ɺ8d ! @T1IM MM`ZHY"r´EA϶|TC)ų"Y WTzbLΔV/-2AYU֑^'ֱ 3 Bg RS>%xEbVPNӵk^Zcx*_#1(ZxX3'fIvJ66Ė>z99ҿV]i&d#/h}5R%Ӑ&S^OW;7Ujo*lXaZIS 1nl $nN fH+iU"mLᑝ*kKPsFv6@(il" d&Yi;5ً{d+ktxGPQuB#e;=2^D⏇+^Ķ|FLx7$[AL&()t@` fVdf 3hV9]َLFVi`9@멿YZ&`-gPS6yJUoT>črb]0,U&ô* YT 5{tx&*$sgI*dE0Oz|sn)^JAV 1mmV; `ۉlc LۺSvjWǘfՅ7mzS? [s@ 0LSyx[6i-Y%l+]c"۔EK;@|si0Vlm[I]ن3ר'#X [)` @vP.iFm)4nBmsFFIY;Ht^b>0lK|?-F*vp@N&݉̚*ƖFys.mHb2R՜IKӑiL0dbٶ+Uh0l %d)k6YkZHV@똾blΤZLBSv= 4Vk*qDR_TT!)i4kJPJ\#mD-dILR<-oNk2-+BƫʺF*%@Υczʶ=#L:2 d.P.$pr)LaYwuVS%%8RVXJ@=)+'d 8#1R K5/2ɡr2YrC`h0 c>S@̪r9>f cWcr6 #$%UOxIVȊ &ox `FF܊|$М4u4䔙tuo8g9yj|o`zUi<aK#T(ȤZI[gkf0LO$R3'+8U[il%Rj!Fdd=PE ^=V^[ 4 I.'xLzF&0oV]Xp *#͕6rI/TL<f Y3+(l@leGPJdbZ< iR S:J^xd:ʚWoIbJTU3PBB!J2K,i6+J摅eR X9`UX{#;f-(J [ʪDa֥YYalJjdSpd?|Grۈ'4<Sy/Y< VadJΕ%!!>_a̓ @d*k2VpR0 h^dcIJR֚8f0G c3,<w!vi)- lȥoų***#|cVR0 N Ro[!  K))nR}0T+Feg|L1&T^u/МoҿUnoM9:xN,4n[XUwb'}ë ַJQmœW8ے,axVR0~ܮrs}m z!;>Aڪ[Eĭ`a U̓ZГ\dܚj+{z-=T [>dl0RVMe1d4 G n.;HR9[el*[zb-F((4OeĘB_-ơW3&ٲ)# D;I\ݶzU"H,0dYԖLX.@OVyĕ0D4[+R6FXZ3'YJJj wLd9ץMDb̬ZU!FU)0 Te*ZY RMׂ, 4QvLXp֪xˏ~imwKįs nƨ)"+fJS`«B6 4@#u3 hTYy -Mg\ʿvs,%0^xСLE#lfT3+REyY<.ð1`TqlI伬I PXV/!{(pcB|J+FfNI^nT2@TG#`emE}Éem[1eL4RZ0P/#4JM ͶT)[KM@9e%[%@8q+Fj/mBA)Lu@Z[^ ֔ue:|0D`NHCք9Xl& im|@kQkkZk&YΖ*&;д6\kVke+rŋw^`g*&/i+Ť*&UŇsF hf}\HZ`%]ئ͗,bh_W"ۈEd`A9[)(OoNUJIzC߄ϱǴQBc P6-&|F{'Hͼn4-ANc-͓S0l0V#Ye >m` ˫IXmAI#)ګr=>߀XU {:նɾ_RA#֕lڑiԨv|H Df~m&7R)79!F!m)w+X* JYb!/rI@ٵK;́5%fof%U3NJ ~81bdUeJHPaN2[]LC (O]uʯe྾d-] 5#f(ObU VU 9OO-`x半 fi`M9Y/JՅ3@Q Abd ZīyJJ!B>ј oߴZTμF { ky~4CCc$zn͖d5iUȶf֪~%@oK)IMg7ffKf]K㥁뮼,s Ȥ^t{IBYU1T5QV+)RpA:K|n-YUu-V`+"__4o/_w$[N4kx3B1ށHo}@<<&$[o}JYnpۭ C/$]<0װ!eiؖ&ȼCqA] @ Y؊XzaXXl]MkD8 4/FZze 7II^ OI$]GWv@G`NX92 g<1 l`V RmPݘclͤm:7C7Y+~J >p{.>!J4r} #%I}R=Z%XI@9*ΈwH_x̎lԕ1M?OG6m?h8˙Q+Ī [8=P _\v-;WexH-)aCl ;][>.2A|@>UYe7Ic_mVM,P5rXcˊ3Ƚxb1Al,V $K`)g76̧Xp.P-MNg&ժ] ۚC܇TV<@#*JUTu&#lRr(Zm)eOkEE[D%0[qBo[Ȥ} D9$)Ab@,Ca Cd9[*U MSU3״1 `=}s9BSs빬{:)Z͡g!+%3̼W_**$7k!%(bmT14(vlUIتR 0vy Y1C}~.Alf~WBQV7hzq5mz~~d494+"wYUuu!ߪ%mK?9]+V;&J*5~ǧ ՜l^4Y[V-~nHahscgEBgR@||4 & -ay%gyKX 5ښv94 _ĺp 얐m4M oHpD@<2CLFs5Hx@lURnUF;쫹 mMT{WSl0@-D6Od52 R#r{l1Df)+cshFL`1]v-ȔMΡ0*jaZ)2$2&+G1 )uOv~ooUYwZ hjA_ AۮbWrΠ6:¬`S*<:܏&CI+%gBěO@형&$0ڻaںJV#~j'ea{jlT)`|;!^l N Eɦ2l|b#;^ֲHJ<7)݁| l)Y%7穼R ϐ@HϠ-? s(a˭3i`sYK^feu9liH<^rMuIԺn^a< 'kzV {lflH!Ȫ* 6UYkf1/`CbhrYh T3g+Rll x+@['vgKcmpRښ:{-TNܜ0hm>M+ٔUù)_@Jr $nt}J%v!NK_j'Q[k7d5=.f &+bꂷRa"gu@001J -rؖhkiu4L msRƶ5)׿P Qeh)YB3;zLzHw x{`̺*j+ZضmK۶Cg1zNgh̃ P +4d.*YYHRVD̐6loKl|jR)~t)H0Ͱ >Vu]Yqj3/v k0C-²õcc" Jo~clӘO+5V&fSiɄfV*0E] v@hp)&PKfh[l`]uVH>LX[9dR¢?k2dR{v{+0u)c"S0 ɕQc{kK`)|TԖЖ&Y Z0H< 2h=N#r6^UV*k](NHTYY[-ʬ0x8- li8l*ʡ$Pyd݆nk-TH $}§11C3ᣰ_9̙BJD#%@<0P&VߪY6ZM&S4+ bE2p9!@2lMsƺ7@ E7Q$m="\E&0LUnlKr*iYUVa2@mk]R/K`'Ji%#!P}~o KŲ׃MbiעJĚ6_Or EVXos{p&U%^^FfR_x)2QRpHJ,7r @?&ÙB9VSW2xdD6l5wL>~]ը<ܐhP ݒՔW^ p2*dFl9 K6jhb@/̡k?O$ tW\(Vp+N*MM=YI]z^EНx׺ L ie[Uʟ k+jrRX` i^f؊@v|$qkg+e% dRfd1d]c),t44f-:7Me9'ǔLF }ݕ)cM9!V+|@GUVJM/eI_U Ky|ZnJ,#gdMO3MRܐws5Q:|3sc0":of2$z ㌝C_^0'fHpLA4^϶MwfYm  ]Vb !{Q YζogQ˰>x&`ңc̉iB΢)Rj-$t]24*@@ KeEz%HXtQ eNʊIp筑ms2rGNH b]TV %Act6u9a`H+9T&b~mcd $je*4v[X୥b 7#[S7Go+`U%.HiD!<2;pG3Wƴ0 Җ-cU^|{]mcV&a0X5UsjdU+4pkd9ЄT ܌g+KCcAqRZyA so6Z[ h[;֕T}Oփ`!P Y̏0朆*z3~> <}6r9-?F F ALpwe+[%4զme9ridgNH)h8 1LFG}Y5U\ϛ 鼶IA)l"f"4U`lR!)R^JH[JY+ǏY!F(oM gy[kNS;RLԶl/"YSGmF/.[@V #  2oG UTRa|k3V)_'E4* W~ |k- %E@Pm5>GX3$[r*ky)f:a[Okފa2gU"Ȑq=$l;R#Y!p S"˜F0o- {?J X ([a$,LR#a ,g%VLb^vv@/%+r(V^G")LZl;0O2)OЩb( kE1Z̀VU-M{.<;~@ U> m{ݡQ _HYN ͐i )hN#I=S4ʑ )y(3#[RRY݁pNE@ 4M,VJU5 pQcv20LXh2eLVyccAF3Ɩ ^UBܕ~6Y 4f-On"%9g;-+I4<[milclbaҩDVx[gk͓+B8(QyU[Z}c*Y F)fda50rj1eb[I:RGqRdؾQasU $mL {zxCiut|lĢڥbJo3m="h#պv)K|\,7#ൖm;5ܖ+(!]vU@1@2g-M.LUҩm7zj)µ%blkQ/0F$C}P 6*\RJv@I\ ު y7` w#p@U@-жWl9gu P s+*)[~hLً-F6}ui8g og |D_jDZ= }@i!4Z)A՞B>H%ڪb#l@So`D3V[T7i/a\WK2@U$sL():6t"0KYnB'{|>WިH0+37a* q0yC[zx3UYS2d6!,NF쪵Sz~rvHM[iL)lϑB&XבIm:Rj F5+* [.^vG0', P6*P7 ;v+~煱R݌!iX;K mUR<=!#1-~T^;2[-yʗѴ3O-؊we[KHcY-+W/tl ZSbh/6`&&= aIIMlUE0RfR [2k mja˷m|ctv'IcAֻ+ $MVAL!nVh*+YgadMOl)>geξڪ݄  4'-uFFclZ M֎amaᚒ!Lׂ>S-o[m da{$2b39 @٧Yb+eme w_<; AxZ|ɺ8׍2q?o(YMxJY-܃*o_mߊimzŒ?riiyMGv> ldl4.;\Cvxr9蟌搡r-P5e2y}dEʕ:' ;5!Z5Jlf>µ{lƼf_3[7O@ DwQkBO,zmXW ,/OV ۞I6}pGbx9#8bCfl:31z ^RTRlU)JZ`::>Hg}KY<z)(WC'}ӔwR[A k-lMeCGsP_o1wr<;,^%[oPx?i%v!9o!Я/{uqgJoLmBGtYL"H K٪JsxxIJRimUp1J&Ɂ-l-`7P CC`Wilą #{U]"s CR"9XվP֨is.k&OB0P":7lZW ֜YXlYOp[2-<5H!V1H 7d0( *F;,j0*[:])V6q':* yv9e;;R%ST%ZUŰZ7}7rH)um;*6YL>ЪeS$]k-4+]?UBRJE'(E}:p1P_˹j+KP(/0M+ʦ _hVH#kffH0~\d(T=>4<&Q TH̐vn[P]&o"1@Z0YJk@\|d|-֘jiZ^lE5scTD6w^rV&iJ %dg[|۪2֦EfFd1THlgtfJkMrdU]\apg_I @C:Z2e/@j4 RZF+uݕk-/;4ruj>}F}wK0s0Z:of Nwfa"&?U6]aB6vR@! 4'3?kضZ*ntƸRvNY7eX]=\w,*% FvֆĘ.{N~^FMiv*ROS R}Fg%ui&R֜uTVdCA`+ex@15 *TYğ Ξsvgr+@&6M}$0ԝ!1ysPXmJo-)!n[SUdCBWBfWV~>O!+P+"kO&xZ)U8 g0*?G6OX9h(܋$5j*F6gng"U+ªy+WM^vHU Tp)>^ELglOU[ +[T4ZTEU=Y#uc tWgjMUsgM3>+|l Љhj  U4*):>[ C2$FwRΎ5,Fna!,K HÚ5=n%c֬_nx-Pr`XP·l9TbBL(+vmufEV8m;NvГ_U`8[1#K60L ͟#O # F@ Uö{!&1U4?` Vt6 szAYjZ<}!C+jV&CTzIi00[&l;)>ʥ/**֝T6e^Me[z "B,km cb U0+%1]W!IxJU-dK >rge=YFPSkóUޫtTY c`@Th&R~.uAڶU_Cf HqV~)a++ FR%Ӈ5537$  CM}h6**:[8Oid"A9A-j 9!>e*c/^ )[YLGf 0Զ֜̚ H|32C|([bZzICpTLb[n[7vUȘ^x[,` ܼ.A6Y1H- zq`Ni1GHtɼ(x@Ḟi`LV1煓i|5OhND enR͜Bd 4Cgw@AJlUbxUx_ S]V4R aCZ'&E'b%dFLNle+c&)symcFv ؄]6vD 4MPw{(s1z*&fh[k2&eRudThm4JŘ/&4O魁:+Jex&vUVfd.SZ ̑N珱;CJȘvQgx!Hi%scVzQVvAUi6kWKY65bi*q4[XȺV[d.ƪ t.[hSX|ҁ=\ZZ!)7R ͖@w*z5*XyYkP#5ԑIJ0{m}V!hP+P)T4udא91|bdkfmT)2n~)$U**յw0,Ft̎rSr|efyԈƖZ|ͳi({:Rj;pcg49 sV>/as%vr( -볓F jgj 7OdU"1JsugɤF1J횠!9,U֐F])$iFR"K*en<>yb Y!gfmj0^U#oCad~0Vj2iy"6A`+B-՞w掌H3!Udnī~_bD;xdfa _elU)h׵!K~a%j)[OC2mϊI ndj4^ uº[ԝRK)="d3h-f"(e}x> E$ ö=Yt#ct?HXVܐ&:)XLoZϛl#4`%+3U[U5^7@^kPyڶ}3rRx2:?mJѴ*Eiow(/" )QŘF-Mr͖s} V-^`rY*YY/ZURK9>XpdRx[e+8f(dE0@[ ;@U1#)jY+4&T^1@%FnlTev:+ep be87U?7R|[%ol27'ũJ֪g'PUpS*L8[n%0fgz+k̪em+U/|y1akx],*V ea|r-,Ac~X,q&)[rw#f"#V1CLV[dnecdEnF)&ӧ$&RME,H⢙a&k2}wM; QB)b^o $ ֧CzJV;3 } 's,bC[()LBx+D*t=Ͽ}ED!ELvƚX=T) jLvÖo xN#EiJƤ4ϻ:NwR>ڧW!+ LaLA/Ŗ 'x-oE&rch*\{z:IIoձB0iv#e.qm>逸r0@)f*PemKaAxs@IӸ4bjOl 4I_Zdo$L<>dYHX *7|2<rؾq\{uHn2kDbڳvp)+ m` l#9d.FJacVXTSvJGYBG5&Z 2Sױ #Aa c?+3rVp&n[fW{.m*YoLzʋa.7+gٶٚ*[Eprp.rVI?ʂc*F &Q%|x7BJf \HJߚsX9x XF׈!(YynPN_9T}޿ZPM[Gnb-M *"ߛ8d"R. +3nc k!tJ: A@ ѽm[2`YYu|OHw֬dֲ $Yh$jM4C&0| [ e䶛¦\ 9oN@ {p~k3=5c!:H]D(AA1u"tqe|EA_V )][5R-4 VЊgK)l &7ϯF!7Ph HBʶףylyj> =#?Fk,;4MP &iJs/dM_;f d^6L2t{"lVu;ѯVv W$J7dWw[PT@O-[NXWm)D2|/Y>f U&j[@)p8N|M4*paKz6+=Z o1UPg(>?gO V(`Hb+> i:Hk*_mф yJj~t"$1[L 30A*⑍ ߫RQeOLj8\I]5##77[)] xij~ϳ^NphsTbM7vpnZ f@*r)1n@[[ 1J Y"Wjaa #;P!Ebb ?m>Uմ!zLjfބdz1)e 2Tu>VRֶ!1fowHV9 M<)\'l8÷u'RA4jrY.Aљ~|xvQ̹U`D7! n6C)ci*+.Ș2`g{^0ڞxsZ~ZLYbUTFfe3ݳ )&\ gǏ!p-d `+dmPyIZB,Ű49+gH &5u 6|fS aPM&DyL/ CzVm0p]4.dZxXVx歷Yh"KY]7XdOfb4" k9D|c~c>Bzl&-J8XaX%YmUS L|Sa%=/NG,Qi& #A2!X@)Ĝc$&DtOЏodHYEF5(rȵ龣Ș+QKYUb` iʆY5 7k+Y+GD2do bΩd[BsPb+'e [=j6CȜ磵O/e6  6ꐪ\6f怷"E$/69m-Ehg[X6gUO\2OkUU)iH΂*[79ZTn GmVHΕCz;KABC6sB6I0f+b*_Յ?!`)`ȈsCR"MJUh0@CH0Yd)aV4HJk`.<4T?( JVu!e|)x+^!m)`3wƀU}@eν'n0^4ag<[e:rđ'jv Lj5Q(j`dVtAzl>b[5) ̖F$ V2F~WB-0!\IR֪;2FN#yj>+l`ad+>p#[i$c ݀u w߿gېVVyR ŤmV2+UaUH+fK2gXvX %<4|]z8cv8R3/,6YP*<cmB$:Ip&qX 2smAJHdl}I% 2[ sFѣ/bm {mG? ³ЍGpWxls֪syo{O[XU`鿘gQ%0'CkHT!+W+eKJ:€l% 1E%mkTGHU1s㌥eil̓%*ak1i0J6ip6Gq.0mߵyj+RgÌUea  iV59c^"qcQZ4ݗ*Vd9Z-A1Fv(d{R (5LV 8 VU37T"QE4&=My\B۱۠/e۹hŷ2y sm*vU /%`-(ݧ^uqNf(m̉$$7R)  l+ɚ!Il\DɊ &C@agP l$8Ul+dWh W$2h`|ܧa5r!6}u9u4`G9Ln";Z̭xA`|/and0 9a Ja e"+'.v BrhNUc+ 7Z@[U ceJe^049òH @/&)k87E*Ҥ'˚I#IU[be[ +Sr[g5b_;z+$kU c}`]#F)lӵ8TNGY(M)dώI|Qa=0b)@,fY mynF4T-0r:SF+V@oXy9^VDt$HE,ûsGXM-d{DfU7= cJ[bm,[m7^ uQ3؇^-^ čn9ߎ3ӑZ8Ԃ(;?tňj$ClD)B rFdȔHb@`RT)1g&]p{ dܶ )݋^ wa]<muR0q5f(+|GYcJU07Z~z-ܟMzNem:&O=D@V;כ'e[᣼Sd)9O&|LYx ,hd{k畈5A5F5C K@fa``VE1 pc^1gn4tǙML!ɡq)g+G01,SF&vmx ۔|\G6C@V#V;`~ȴh”J}Gj @˷pzۇ($Hû) [UAC<Ler.P-òl[>l=^SDdͅq;o$킆CZz(<pħGJow#M<v#OǪfiC &ekzyJBc]q(qun8 Z `ڼR,+LpK̍U.b{Ɯ l#U"e^Q^,qDvLTy/*M"lVF}H>5v<2hc7ktTZŗ5pdWHwFdlFwVdGײ?np҄GY}Vdk\ާt7"4R jP8J@29x6m{:" ­n Ttx L t1<Dx8%O&ˇa #;!g LW ^Ytk%2\2 i: )xx˺0rK"cNlJr:RjtVydk4B;z3'8W Lc X/8ZL_se;20@8 EzrkC6(|490|M0t,8uda^nX<~(ڟs!VewlJ*7 Wx(;‚@1 oߪiw wZ;b8&C؞|Xi*+ScUJ=y`zdކ[t_g™֒1Yj;r2}E`pYP7DqHC0dm ^e>5"Ɉ=K6  mC>z-I`v/9Zz4 12d;s*>Ydq1\l-:"xY1?{/ M?{e(c-C(z$d>&GaYS)m7Ma-ޑa-12}֔xr㛞RnkY(Qϔ# |{E~#Hyg,٪=Zg <SZ#8ϬnmY/ŎJU(k6e㶥TjzjQ|X. Fn!Q*9r4mƩ;Y_x- 4Z&WGOzx2[`"FKDv ]ՋldyY$. H:w~oc`,}0؍rU]"q1aG8U$M9l1&s[xZ# g+vWp_0Ԯ ywV/ RĬLT} aiJ9uu,VC2 |w[IL#cjwL18&";*DJl+pSPv5 p+<{gylҷw+4ziLϜL`FT}pJu1?7_np-Oi`Cy _cr/VH vh: [|{)m;,yU Μyہ|wjVuLmt,7m1}LJ,_s_0iFmp,0۬'eҾ^ {\k\2_u\vC-M2|FUxb=ӬTU4e].&JrKZe8$pT^êZի=cXV lQ'E'}/{]5)Îi:Ź{ekq,`[)0|x_&bTB[UES0IQ&t|Ԕ|u)+UU1 uܴXaˤURӞ2s0q  3wL80xU>;, 9Bc|1|z|f8z285oc21 CF; іOV ?oklu?Fܿj#ďA~_s;*UqxrFcJz=;e 㑔w"Zr&,#Ԭd]Mc?I2M t C#YILW۪^m6Aj$1z Z> ,7"#)sC24 O{CvCdvlz&YجhISIc-Z*MCmh`G|l(e%̱Y^$lpsT={8RMJ()kI MSZ71+y%˧H=@ӧlFleeբ[+`O? bY8j-ݫmk_,U.;CT[D'Hp%~J=#2?\yMR)a= 3Ґi2kMdNO!3wKcWՒd2> 4و+!}~U&F8fg.)Ȕ֯]]7`f-G۪f0d5b|904##cM3lJqA&n1ځWḺzSBNo"zm4fs;,y>@MeXu_+!1*VJmqlPSnjW` ULZzػvM3TjDJUџ0PGD#4cБl#ZPutxU+s3dx&X$X "14znˬrN_R#q X䆩QvTU@2.95!hg@2F88^#Ե#t_Y "g0oF%|埗l4)B%}Wr\P*!kG9/s\-(w/!)< j^l ]ڪd742Tm2C>>jU))1Ƶ!arwAhl4S=FUJ?nzetUBUrPmIZk$qxT݅z%`$*57>ۢS/j1@hQ07GQKXձ\"Q\m2h1]U3IS.ܬ|"j?* M܆i%2wJhrSBW %/ . uT+4 3W )rj-?٭ ieA fax5b{mt %ECVeGᒁV"nt?ٚߟ".ȍH!jxڧ^GZ<{GLSf*YI;ZF>%{+u "@&8)FNy "߻d5t0tߜ7/:ӶXRzV]K/*,쐃.\lr\ nM˂,gZ䪀2Gk[OEsU[q喧ojQcvsv}]^ۙX82dvk4|@:UR{nQʤD6(ıhDJxL4h< hJmҠ.K/]jYWad\vպr­dk2qV"?ҞU?宯T)$#hz92}  kl,CRse2mD}c=mh`2-k ٻ=A]r+u%7f5A 8{X*ֵgUqn#/$U z[&v4|jW~;C%R`2z+i]M6}k#6WLKHv: ߓ63R&&2A1Mϼoz>w3qJJpDֈ1YMbJ/$-#NԨD-y>%bZ6a+uK[p5TEr s@fto }k'1K”1*WBo]6QZ}9۟eLEc___O[fAa-=JQm10Mt oU#QoJY atWuVBcahA l"6nkd>5eͥezY {@J9H-Y0+%u$skRda<Rn7adVY6qc:̰W0>gsT¹}_;n"0s+ UrLHUs& rrE-xg4WvHeۊ 1ޭlϼW%O]@G¾ӳbܪg+QbXC)i\g;F %Ʊ.wV:R#&s_O tn ɔ|=ɁaLۧ21dL>^htܔ- *sۿF{]LALjeWIV8&ydeF9fG.C8@?A7{t]ٶ2!)#p z*O ޱOY5MD2e(UP͕-j,y_F0Jrv0FodJiݐԎ@ i'^^0jY9wU M28'њK+TmO-%CMh{;ȑgLdE tq2ܯLp8g"lUb.gBSX(tucz9#&:id8ΪF5k }(>;t+:2$^(wSL2 @Ҍt"l}j) K_Y9 1Hh<1d0@#=/8YڭFYdYKj}^58pkȫnsH_0~b| ƫbȪd"g|2Xi2J=%m ,3wzCl#Z=~<.-JZ3R#iJ 4bpհ%pl7`tZX%^ x #Eiް5];hdA 0m(S3Y yh7F9ht̹LSI3ȹŲB&Mb(l J7X,%dQy#tuMֺ mK$X@u"lzqU3@^3l>w@95$aOq~ 4H/&6wM0p΁}ӌ^ AH*3L2'ÓdIO6bJ,0^@e> *ш&ڍ&0a`XWG "'rPbT.a>?X` @*^I]zwRҕ',yӑad|f14*^/Rԋw<^]du=MgPOH`A x]F&ᜃcMI_)Cx!%OU)<ǘHOny[upCG*'M2As0H />JZ͍JLlƽM J^toy)h%0@2I/  `*ɎBuڭ=1i6!O Y-MsUW}i ULDp>G@kda<{p 9d o7s֞.F2>zaLT5b-`]W(±?J $?m_CG;0dnӒ`E|z ?eh%R(Rk4O!ЕC (!FhT UlsN$֒46+%[ %Y c@5SUΘVjdlRn*^^-ڕr.7h UPY/siZl0V5@ȵr=[~ ]G ,Q7IDxѬ. 4Zafw )ۡ1;Zadv Ѕ_5\nUCE8>ed "{Hq C/]һc4̓a fgB&2PJڻy[5ϑ Rf^&8єѴ*.)kĤs&'r?/FUuGGo:cF|?ܣcڈD6J=~^ٱ-JJuEdQALUGkHUS0ZVX?q-|8r$s$U$@%| QgFW4*7 2l %51@Tid l8ay7j<cnD|k(;F8EJ^bJ ˘n#g?c"zIL>Vm=|sAnaʢͳFp2dx˼L_{u-&3'Php|$UĦt̖U kqj 1@` 1zmU`*C|GYFze*}F\#O1k~:r6n稔"okO*ko -nH %G tJJpL-C#uMG)rSe8@Xf+$Z^|jlY^4*bO)4M@2;|[jOsٶ %h+GVZ|}60LFжmOJI?Xʺ#2;g-J?,o[íZX& K)0rV2)rejE]ӌx7Ti(k,#2J#jɖabGу#+yHL6Ɵ6B 3VLz.7V /kYƬOn[;2s$8\)Rq홲Ji7_Ae;h&+}vb @`%x;5.(rЎ t@IDAT4 `8 _ X㘉W!h >;zaU<#9OJ%+#wdNey*EhB4 P2v[?SU2tA=[kL@TU%S';}:k8n{ш/ƐEK…cgg3x-RFڕzu96L/ۍU{ Qik0U݈߶եhXQX @+c+p9`B8)(^Xo/3T o$aq@Re&u?(ïq~ ;+@ Y˂@ImiJSo-[Ϻ2l xs۔D0ua"/kv6QoZRv$q@CԘ^^˘-Z(WMZI)@,:2%+l70݋a +}mK \g؏p6H*RodI녋J}24Jp4#A$@צU3L{)Ďd@^0`<]z ?A|4b;A)$J&rdL,8y9@7 + "zʳ:L,&QG= :v'Tߗ$ҕJL?/ߛb*QR#+SՆ fIYD"mNo\L1Qb{FոpyMDLie,)٪L $0"S@G 맏$jlۼ*v` ;E[AC׾}y±G=n捐a>~/iZD}%+4m_HiPJϊ 84x 0ci^%G<NswL^UdJLUGI7c]Hl;2zd*Ɠ(0l(!ElĪpDfKp㓐J94M|s)%J%@RU|"Ue,5}nC)v}kL( ps9|(J(Uj|]MO=&^$R7q'<CI30Mc+"c07J<χF)uΦ+x>BU)q[#U,[2Xҥ%>-sN7t5rz;@ΎLj4'h|lEm^\ܼn*l@%.GH xd<[&69@V/M -.$1 ޱϠYU)m¿MS.% &==P#cCU|\#j!=OHIѻLЃTe>2+SړvE)X!z{LҨr]d5ʢ~?uScw]b|=v훾*4ֽccZ2R&~sd9ȶҹ}g)taI}!`JX ;dW|."E-Fco;bLI?ltqpV! Ǒcs&1*1#t3XbYhg*9Y|>[]T]&D:|R֎P]_sgXi{rlnkXr-3tYb/7Q5%=UMIz$LF-REvL,·z*֓ jD+ɮfCfM' Ȫ4OJ`<_GbWJ}GVՎFTJIXhDzWl}ʲ%3YuQ]I&ꊑk!'s+ `98#Ts{1J0[88ʎy?h872O@y]WsΘrw()bd.&v}4=cx-4J>n"Yyzp!{[^J赳6籟MhC"܈w\<[f@| ;gVF- E+!bmSLX7 0 BpQ Aj<.{+m+P$\D_W&pW\^-Yu5-,PD_dXOϹOD[8~sg%"oMl(?vi\Q9hQLi(aSv UgilV9ga%Y}d)2+G:v&vYBHXKV{F F 5jp21eKJXP;i'iO<%f2"H纣NBR[{4e>}1 Hs&#e_Z䖱˙ S-.FؙXWjA4 R<+! +57;Iodz%@߄H2Adv uYqeJvzcco&^%b'L\tr~&9=[ C j7Qz@>МcJaܝaׇ R1s݈^d.ٱ?)u yFK?:67#Db.3Ma%4ڗ6qxdCX$n1he'ia5 8k]>TVOOL0%b/D-XWa&I\F(єlsc4fpRd5dO pEng@}MMhL_4JuAvBIxIyW}nֲR3'qHGWWzW߾Ƥ9WyG}d ,Z&acʵ%a!2!}Wȍik+)1 < U j"fb%ZZc [ ӽzpFGU17bV4]HZ6F ēJ]d (5h9ր.*'cX[zSyJ[ k4( V H\)@P~g<|FJ>?H&YXWM86 $MˇdSzU'!P!y{j|0}Fvuc]40r/Б.#{?-5= /6}7#%$j7Jl[>adds^@[xQ_,kZ?i 2MEGXWnlAMOVPjǭeM$`nzǏO ɌH>bibVZ"E\k';YT`q-_/q4twt;CJ#hcs𔘪k[U5L#MI.E 01u\#cdfx8aJfww5 ʁwDo AS,澼ASh!56T"F: wMɇr2^2&iJvsJsQ12CdώGoC1J,J/C7"*+E w!Crn1CfeEVo23YI ᎘cV5z{xC}ܱdSxbbC6d%Z 7T hb2Gbؔ-d)R"Z5̖_o%y·r>yw緋 3t(T1"CHo1~H>o̱}-ͿM sMڙ0TXn"EE MĎMʽ5:N`&Ăs85271nWu- E|mtaɕ|BAU R"vДdTs4NI?ZG!ҙQhǔ[&+bta274L0d'qӒ+x]I2d])x#=;󜒸Feq]đ W ` '~z.y aǼ-M9|oȈ1[=m҈m.}](Pzmz ^/R·! \0, pl;Nmpfx]S |n.]*sYd^M6¥ϕ7Wzo5L@h2z!Eߙ-Q/)-ȧ/iL֞FvKV-FC4M7Z;p@R!a]JK?Z rVUpCVe7CE%U ¯US( D`kqS]v\F>@G_j\mծ\K>u6'.ӴjIZt,YڑiǧiY(`G8Rd-+Vpds1'0KDIHG-2<3OFӈ"{LOY{Cʙ;%3dH-Z`0&=*Ll+%-iq&]YC9=25U''sR j!kHXu_GXɔ5!@HA 3jF'>,˴OdG9ϗQĴȖ37d+|cV9C9R&K=b+'Uyd pnE㚛7CR<7}"%b_~4̪ŽJvn64S.Hm-ᨍiG. x%񩔉y &RYEVmIEWrԈI?jH P%KC00Ҡn[f@XK5H ;sn> W˭.O =%^&*SVe3AUM'xYoNVi~#}MnU ed[9G2 ޱ RF#LI){Ֆ\/\w̛ԪBR0qB)MLY|+#o;ߞYu#9u22z$ ʹ.y'ˍ?9F!v@i^gJHdVH'S ;n^GA ,pN61pd 2;t^J{.%LtP1srSUyp̻BSf@nnS6QZ4=~hS:-vt/ A9Fus/{7Y(#^ّ0GQʵp sU&E]iv0> iJ 賕 s%6pFa$ $[/x낻鏉eS#{PظpqSʽ0 zM00S0|FW9`A/.l))3w%+V`.kp?&4#&g5ddr# qDoOMWnx fFmbJB(MdUce׎ 篚@KbǬd&Z;8@rq_A[sF1YNh죅BW@G%h&9Pb-3ZWz$`a%Oq&x5o1bN@Y1 'ZPt$%fUjDd0ڜOs Fgv֕f$.zS? 2j3;% 稷ZڸEC#PlGjʗPV:GBWeG?@FVidt&J@seMJL U14|ppʹ뭄Qͭ7O&mR"` hP&F⁖a2Lђ'FHY5Rso47%n9tY`&PvY\'Yrs#?h }d~r$;n$M-dL_ODLPQ"ˬ&Glk;}-M!@U,W BqD4JWMC1 %хcDUb2d"({)/dLj"~&FH3A4)Dk('=2H$A"JxKr[ՈI9#՘@Ch+@8NsWJVqbJViq ѫ5KUWUwvD(ԕFtK\5d]),/n7ՑU)%÷3ZHA:vFCGvܦ4bm^j31ץJP/ zRVεa/4+(^]1>P|;3_ڬS#>8J#k:CJMSݕj&JϘ{]{L,%[Fzg\"<jtLrϫkL#c &jbF扸{ ZY nzG@ț#pB_\UG5FL1?S*ڍ`-\DNY@Uht5U[RKp -T+ˬKKCŐzC\ܑ!Ӊu<E o1Řg#v8&ja,ᶅ0T)4әB ZWY Ùl|MG֖«b֨Kis)rR K,r%*'/czW!YM IR|L4ѮNT"'K Z1`- Rejo+`7KhS",&2m\Rm'b^BA ZO{.*2f'IYq-#*ِW n#n D+o.ZAbwh3]BwGԣ#TjZ¥i2L ]d|vGDg+}]FHJmL!i-ka@tݞ?? Ȫh"RM]5|,иԊ1 5h"-A{E$Fd>-ecGcvNm?=-ХFio~4nδ0"m Q]i^q`6]UuSg5" b)l+9ZI'L-..w=ӝ ܳ+RbfWBNsSbFh=p;#˪UCG.3eޑYoqkhj15FkEƏ Eh S.7tkWNĠV*LY)-tb/@k:\{ W5qSTJD@\#e*uiR8sam%-6rvۭ d҂\ȎC,[=XUZ!/RIJ L$> .QI ų S %PBijakzq{ih= "mD锥D6 B(=++[KC6X NxFOCW gky6Tڶ K)ql╢iG)沉/SIjkp",zИxRfCPOǗX:8N4Bv؍C'J;_U6(uMAW_L!J]Щ{~f\5G>kldz)dZd/%CV",`p^PCt2_U6tM 0RziLH_ TM<[mRm.N{j}CfRäaFÓKxb K;gt!6ESv)f4bvvg'R—fјSrF0ybnaxd) WIl¹=Aua"t΂3d%)/fm8cJU[ 2f 8Q!^Wc:8 vdU>$lՠbHb&:eX()mڷ@ͭˇ 2TN'>8z'/ΐY`J GW1^rwrGa]&AJ^c|O:NߞL#{3IYYu D^|bYK3WJGK)q7ȚyZJXJ.AK-/BzbѤy̮.B"?Sk! L\f&HۀXbJ4):b2@Ic\&U=9&F7,\ W X"VRՋB%i+ XƘZR5G*񾭦PDb^IP{oh\1dZ⨖*ه+J*m@Ėäbw6k1ϔ,NZޕbkG+ftTioo"&A&m#h h<~:K%Q ydw|Ui ,H$##:yH1>56qȋ!RjVқDl1H2d]hZ-駆 =S!o\,>K\PbRqꍳhSmB2{_e}!׾} 0ktE{AH-Y],*\<¥J!zkDx)HsSSWeJm+䁔+@HoLl +oMyІ J5&2}2Ÿ{xZĆz06Iq?8u;~wυWGc>fjp{ih[CйthH\`%eihEZybL)@{]Mx1vF)ߵmtDhi G\aAO|gcOOUa-z7"%wlsp<K}ib%y)}9o\J&KlORħ^K|pW-)Ј>)54!T U|%x9)O}ic5*3"PjR|F?Z|6 =.!RB.Ew*)D8[߿[RG:HMYn秗ߔbVWD~_f8QSI3Dz&}EAjq5:/o,wk88 8@k4NcAC=bRJqkfq:#\\ӞdB"D\1^-vDj =6!~n\X"cJ[@c65ZZ5)~֞8F'h )BSR7։ A6To%Xp90t^;k@4Cӄ0)f7AVb :є4Zbp,#`F0Xw'^ }jpyKUuفaiY-@izU,'lsκgL?/M+g|'77FpjbV IoAҩ!2BL#t HkCmvҤZsd8kt|2IE0p%DcY:4]N iZf  ]47%#wS,iddzݭ5pPpֽɐ)P ,TEc T֨h!4)8B&Mx-NiD3&Gh)BjR7۰w󎿡J >s 1B!|@IDATbAL] g89BRS-&4 6 8xlz uum,F`"]^^|OAW$gAыGl #o"&Dxg 4by- og1oV PcN( byV 0<D mmR(m ĺкNB1 ΀BHїvTr:v~!0(^ns] Bft%PL^1SBPJ_8~ GSpcp)s@^j7Wcj8Uch|%Stj5"-&rLΐi6W-x#1U`SMB!U/$~+^N UY(M_kע xF}tAjkɪ7)Rj#BJBC"xh>ijoxL"YUHS[ n_O]+HJKÍ@eVE`4M|?Ft1kLJZ M3sY'+ieCi%JW5I; qs]#OA̺ކkl7+UIJH_SKKD TSn9~[QD1,*.0g|iFJR[5N5{3t1%~VşN;6Dig̈-&Pwj[Kn;鈑Ȃvh죇g7b4d8^4m @Ht  d7q B~?30(uS38~l2U%" vUAFףvEv5 .hFdjy1G,FK,hDّVfBѺD|+U R-Ȧ#ׅn@S(P '2Dk#( )n cJ+M h݆bJ6YIȷ.-}LBKU,D)M5Rp3 !-ŧ  xL%|CZ `xrZmAZ rpDZRόÄ4hP U[/pv%!,|?UqL8Diڨ-hA vrM\#Oy7*eSM/*\f#- GDtI3 b ~~doF4oMSpA@qx=^*4CpZRG <oUHs L97K^O-)Scz-hyF@Hgl6 5Db UKeg[ Ps-Mp)k*~4%5J;Ɨn|.CL# ^o"~Pi+Yр 'vFTŪRT( #/ eTn&@>fYNP(6 Uk8녁h ^kS"k"Cq͍bJdRm}ǺAۦ÷b3jQ dɮbQuDk8ɶC|"qRVBT- m37[yV ~c نAuAяU0p˘Ԙo.R=IE XV6&)&8;u|[jZ,ħ <#PvݘÚD)+%˧O$Іĥzp:E-,FH9Y~pǷD5.8q7C6Ъ>p_: n:#ԟT'-vGkUM_>ȌTS|31d JTU^&f8?3̔;NzY[a%wϺS5T /u8q mJ]=z&&r5"gAh.kq K#v,+|3ps;8q)чoZxL&^^fySLG +ao-A޶@&Mo+tG~ck$E_v- PbvFidz!Y=CBv#pv"12o7R5j$eJv'6_ry!qhLjCjZIKcpqM^hg{]RohO&])Y6- S,_^ZWN#wys(6NoK@h4/huh+ O_; KׂOP6 %Z a#2Dt7>G5oJ`q8R^)|njMz(R 2&{緑hi™xL ސhhZzZ@D &hmmbJ՘v կ@1qDfM>,Z45vjNDiKW$0gNdSZ|F~\ZF4ʣ U=M7AL վ Tu@1Ncm0Btpx%S)5 Xe!^k Mm%F7}FDrhvh\ˈ]!ݱGue |ktgb#Ka#EĬ3u8J=zj$N MH_fAJ dӱI]G1*xRb&ȶU G{R#0{gKo;w)4A!3AOUS)gbkO1DD |}C v?Ӣ!`VҥDZ)) A߄F@kW &}F&W,+y>i  ȳMQcj~DKfF4|@\ǠFwڐgJ%U]YR8Dz8^ߞ@i"ׅ ^ZGE jDXj.fsRK҈KX_-Ssá&)<@Iμs1T˙q_ڍfU^,SzT]/&D|φ4zWn[oJK#ل!;Fެ5k{`vz%& 0DHN9zUcZHoiևk4FDj1T )Uq%)k,vZ42[/D-~n{'™ՂdW &MJ#S)`[iM`4}]s1|!|!,֕j~ghJDP]c 6TI0fx'ļڙzs+G Ԉ>"X R<YIuR n1[%%4I+!w| 5u!b˫&˳u)G{G@-#f"B ;>54QyuM!.tJʺjpT!R&DT-Z 7.w 5p*(͇x"dJjO}C JUS)r|gْ6DsEp.%4^Krf|2Uy|jl14X 3ZyOʧ [,qMJ/24cZ ;VJ_#}.[--Е8&p ЈoRf A*- ,5jC*9?\] Iӓ7;Dafҝ Bvx%^cC#-Wjt1PK; *CF k]oenLo3}"t*5aѶ̑S&%"B9>iJ>@j! ]YJ[=K@D'BӪNhA 3)*>@|| z,J(mjRBC].'M5#q j׈ЏTdH-/n4)08e1M]!-hKp"$%`<V>UH#*%n%;ԅ4K9gU Mm4+Y.5XR~P` K-nD?[Jfaaԑ{:4+tkX%3'+ 䍋/nUJ||"BÈBtKqXʸF}Fȫn)޼@FfioLZDo?36*p1%K፬i|+Y.@c-wq8*42^A)oRBGЋÒE6e' ϴ85tO?ScSoGh:]ca6GP:xH8dpRcU4VB))F|8gy֔v) . +Ō$nܼ ^Rh1oݥ9~f.d\=qn@gab 8qq9-_}Ѥo[ZA8ΪR1ޒml7#IL2뢩+kORJ- bl\c( )ӄ5YȪQb 9mNj(~`2/##]uG i+i\BsvS*~AR3)Sq)լ)DTY<&*׀oqY:wj]DA4{?"1|MH|ߊڝ(J}*RTBkOit (.!8T)ND`ǖ୐v4LqÖI'Y+D-+u.>SMh_ t0 ![w] hp(K56NԒkJY1̠  GAz)7n̤ڪ{ぬ8qMH5 x{CZ\&v}vK|eBl^6Dc]K;+zdw~~gk*_E1Mhov>#K|'ob i ommD3rZz9Cp]o,Q[˪8o#Qӹ˅%!uh4%P+e7R[WCiס@LWuWH1A "&1x#.Mȴx#3Rk.(VjJyl`RWdR!!`wg+BCD8Wm5U%.:~÷vR @ RW o.j;Z)dkb6AgDdbUcJw/AXRlۖqvd+ E+V]86Lwƺ,Z=ǺxCt1vu])cL56^ GkPE6X ZUvI-޽Ci|R/5.wH*G5~4.l:JԀ6 *0#5PK S5!5_n#3ܒ{= J]OGKj2U%"q1OB|i*B*B"۳'#ݕ1N B-3SKqrH[ hzx% & 1*8N lI\"oJnSiT t:1&C@HѲ퉼.ٻN S8]l4!bRix>YV1b)ONA ݣOM"x[RbbRuk$w<&d)#tW&.T#B[QBxf.kx'eB 8Y%)b-N1tTBܝ-+_AYU,`4[5}*Pt)L.KLpx4ܤ:u<Sm.wuXm ae+a")% ҈,) 5&j ťԌK,>dt7Y,Axijih6$2*oUC6 ~gfh\*6o)DkfڧpEt.<5)1(`)x|4sתm.AH){JI9 54-FpnD &Ѩ+a*۰|4<)48L5<hJ[ɺDȿhA'#(Ȯ5t1޶ zx1,8'+%84hKUM5߶!hXx.T{Va]XPj1EWT̒%T 4wF \rjE3JfͿ]٪;>2fn7h:WTn@w>q%Ruc7KHYԕ d#dM}ٓ HT/ 6eL̬zSYs pfy -YF <uݹP+%V{'3 *%ҥ}''$,H#DANڹ&G:5+fA]qR#uK6o*SMv@J|qZ[ 8>O bѧ`Icq{g{ZZ@,SaD{ J .4VpR`&]K c %i:[NhЌJtz]h5 &",Jd { ;mqh ZL*ɨ"VM\ gƂ #hU[R"||g p^)"c!6ai)ZTyf )G Sk7QMXU%R : FE9~C5F+lCSR8bA֒;8huM]Z'ygӍ#y_`r'Rb%ioyx,Jh.+ ϳ^ SW"J~lVLd&vé$eR%x4]'|>}p9-O!5x.R)>5'NbJ>H#n&F+)q"oPۨe@R sDJa 0JJ5jk4 f1?@#S\W)N*WDq+uzPL(lM;`xUumwF>dk{X@G` 3d̞۬d1KІJJ0(UP״XdUG;%%PoۧF]@l>u]KklRPoDD[Yǥ-vuI5Z&1B55 F0bFim̪pQk+ݬJ!t 9 ` D%rS)!(yϿA4äÛ'2U˰֓R1;cGIpǙ&YRB Y& ,)0﹋GKGtF/Jl k i'6}CAtiiAqAX;@+8L =C-QL G J@m5ph;<5.&e|HS6e5Fjb^)0 Ghb?UYo>Y`m]NR1Oil`:JH;ZA〩=g=_F+`j?.6Zj6%KN zቴH $4`)_ 4q)FCnK98a2ͤW| !$k xLLph S>/ f-ht|MT\_t-jkMXݚx2d>6HY-͍]&(GPݟn)0r|x:a<;@][҃ǢiЈ;XM,R5Lić5R53MotgqT) tKh9{;P>\qi6YK FֈD YՖmV0If>eW)Eo x CVij:Mb¶ &SFZ; 0I ˮ= }NfxAʧ^ b*jQ|\wL!m,9l+Ն;;Rj:F٫tc) ew4pX`S$NFIPV-To  Hy8k{9PR zs";#e3TU)1(i40@!;jH F%XϡZL*AV H 6}V[c[sCcf%`Z ֔RVg%۞묽6>*,@J(eRI֬(cmf DK)X] z@\޹Slʙ(CjM1z lB%&H<똠ZY!#D85*G*f%n蝑pVd㩅s(hcZJ, VA/<3QFPXୠ+Z<#1)dmضBLz'VbےaYʺ`Lΰrp,K-aBa H@E &85}R( @c5>[eJoեTÔV>a'fT!eaz0ֺCzO*'Nrzz ado>,0P¥Y) >ʹ4˜H,ۯUerpWsx+*V4YJ)wҾ*irSR*L_'X+T53,]Iմ\#*U) k l~YzeC&u~(gg^ҵ4D_"n&=A@ V%a4Ӗe_sv~z@f*RxKV1mJi+X<;EZlejK5BʺR| dBvmW0: U̫iI pۓ{ JΘX iQӀ.3l6JO`xV%x'YA燬z)ۘ4ـ[1lk*Y`϶@ØG a+aY"i&Kl%S37ƬEz[]zW!-1]J%H<&Uh<ζe1aY̼F@0\Gw+ Z:fXں dz)4-lucgJjGU"S- E|Y.[jV+.,J5 +:TZ SŶxK<&R7¶ k}kVP"+VmsV5`!֝_O`{m$ 1+kaM nwk$Z 0`Wm;sL/.-a5 M )i‰ì |vJd^PZɀna]:Ve:- C Ev:Vz6; `(!/'};uʦ$mξgrRTU  )x&m;Q*A`@VUIVIVx=5u#nlV]T嵃ͤ²͠0r64֖y7U?^i:g-sA:lB%x^$Htr2c}J Yc 6 [7)'kg8#)1 CV3q!xZE5R&%rE6 ) ם XJI  ƙ_#; &YHLFr1HO$O6+w3) );O١3O̪lcLNdC+ A8]RRzOh @3؊ݤ~,aN];2j` |?oN:Bׅ,J @ ^Yi-dVփv-nfYb2k* FCXxs[ZVnkf0 L|Z~-;Ȼe[$L\@Oq~*$VnhvxYZmK7[6 Ze:x&hu W cIl+lEAg#m ٖf2rզ!tXwX9'1VYa+6^H@옜m{ĶapR[)&2fnUX-Yؚ)x6$0l0h<ƸF @찔5z}v+dr|*RS!t5uk bPVUWikl-/a<=M~qVR|U%x[1VMQaY1d=Jk[kn @ !~n'k6dX4ȶpOD8 T҉zaU;"L:̶ Z`1:.F|8X+\43 E^ r!(FWh|" (#Q;k.ր3(Wx&t*9w}u<ɡ^U>jI̬mX-% 7ͼ&7B>pJҬZh#7ST"*e[ YVcT*VaMPfj[V6s۰ZVƒUmVEfFWN'N D(i洍ANڄ֍FykldKLçFRJ8HfFIf̲O%1k͊ 7ڽW4ʭ^䶪(1lHc X5Y:#}c!屒X檒#4聆DBH zUi0dbc} o  m+Y|(3ޝA@IDAT K 9\_rUR R0cdmU%Kٶvx1Yrˊ1!FrsUQ$4[d4JxYѶ5Z[%lblj)0[* t (G)H L@ߍm;1qPh\1͗,,V^X%O8*_z]H#QFjJֺh~[zU=F1P k)s:٪%`hy&R@r~hbDj+*K,_B)DZ9Ϊ R Jd)%ʭ.bRJqh[L@UAWaJ5mV T-hJ[k9!e)Y@֖ YJj|4fڕK$z-)Ϛ- {1u%7rSVں7> @&喝dۆ; F Ki'ډeN/l |jit2X kqn\_㐱"[ SmijOfr+Fok-jD# "yOk@F +!+xU0I)kK`]h&]Bi>k $cB[wxOOJ6?c1<5鶙X*83H5 \k3 Z[W^ PV sw픈#}^H`eO(L*V[3,9=&#&)Ob"SZ;ְPnݴEv i-2 ]_U/XΪx€IDu|>wcp6&xWY׿Uq&U"#5j><~~`c&0}%ةda6@Ю黂@ZtȤ*wCX s>uƶJ [<[1dabxׂ\pCw|DG?R3LvzծBcxVUU%YghUn50Y<ЅK8)R FLܬ4[15"Hd}iJU7ml݃\3 jU-"v@FH5c(Q?&YXWGQXlRbn̖@དྷj~kX <0O,١Ģ-8dQb5X-6gRز"p *dp%xd}XV 󜛦1u$+G*6Ֆs@qd5M`!<3w[@`|y:Hb!D`:@ Sö Z.Pd.植[6e[F͠s![h x.8Z Ӆ+ͰmU3mX(g9=?tj]aɮ,2'#EdR1}[*1O%H{ +#u?LV5 P^4 nݭli (RLJ]g'A>OP&g*aEtdeG*1d@SZ sLIܬR^MUV/7 )sb"og<ɘp@nruHB׾ m @_,4 nmH !+l[o`A'[ [oqꛛhǐ)v9|O8gث%ۙ)&UcӤ!cbP6(7"C38W' !\x mݕo Te8`Șw pUn%{W+Lu**bY_  . J5[JJa%V 7,&!)Ԣ-l)sRb* )yxNG/0U200R6 `*=^C8cd_mՋ@_#­n@"c3n|sG:g"2s-ż5ؔZҪOsہlLc򍍡dU# ;uUVp2lr2RJF_ܪr)1`4MU#MeHm[6A+FmkH fP؍mr.4qJ#UWҨH[Eו6M?wq|BxQu^[BRj  lY!睎1VvQa v1~ek^1ZL$mG^ ֩z9XvY 4|Sn)#Զe^пΨE/V'J7?FV傿 C0HfE@b9z8+b-ll5* ՂR_[_y6 rE]&1cHmݛǶ[zL0Ty:0mu!pVwmKޏr^*%M+CekVVaV'hd40Mb)[Ic)4h<<,0< Xo%XFd6+@,Y݉&")ea1PUG,k!HTkd ):"uEpL)[SX椀m%@5*X}R31R1nF` >/0|2,v5UT Foѩ:['RPijD3FPH06)تͿTHo\S+ZPVe1dx |k@!2MO'*MD46"Uh̄BU@J(ԗFcf& C1vv4jFՈL/e/h -6[ 50[VnHEP*/IBYy,Ͳ 2|M)ںK>lWaYfuilgNU) Aym)ԋW J l;4xVLs?(W<2W(+d+5-p@0xcZYwA3&|ef4qORƽ!٨b[mpM)lw}/<(uD٪t7d2ז?Md $O[+-ܛfJolBJm)ƫb[ VxY&Bɸui0F%f5S|[lbj` 4mzYd<=H_!n|Xivܪ m6J[7f-rVd!%:5&l9q$\/ Rx  0?sٰrX3Z'@b1[d|Ue<iI ϶[ UVUY dn)P0z%`CL/Ҝq r{L' ()Xq.Md|)mL·bGnZemӉQ%VŔ0+j@+Y#eRxk$fE1˰HJEi<6v@ a[ yYe1[۬[uL60]sIż% 0az-~!Eõ26wT%6Y2Q3Tss@/d ۝b‰UnJ`1&0&>BY&>o CbYw9<7 %sK'[Ka+ʪeK1눜,e SduRNL9nc"6U h$`! :s`c"%d֔#1I1>dC}a_瀰{ߖn4yJ)qa![1SŽ,Al6JmO E Zev e^ƐR[~ i_WDIM [Fd04ail7 c(lH)JgHd1$nfJӐ N͜i$Zt}!Uշ /A'&}ob+lZF+GPvRŔ(X ? 7Htm47(W5VNT@0 _R D ֆ$neQec iY*+eغbe|}lVt RVS^&Ȥ`1VǬD mUk%*kۍ1v x%,S8#Ԏ^Pf+sed> s˜C!߄SC%kb3s wjY#r[yZE2^_WEFf8Ӛ~}lՖ e7l1CU누k ɐ 3Ri9>1 AOz޼-VH cYuzјr2zѴxX4g3xY֚^h;ΫC [;xbф ,Qh@Jn篈"+$*ʖ+mY~ /E/e nK ]/ FU@l7l[^^3$ c7/qi9yF6sheK-aU_@>CF{kKZ5\ [֍j 39Zw\̓FYLV)5 7R U08x>+^YBe_{' kjId2!hD %FNdLDa>er(klmc<1&;^L<@$jĵpaYKS-Z!K`! VFyY4˓ }Hsj 4k1`Ac i$oBA#5JUdi)[YAV7#B&`T@ΓƖ9OU x:ymidYd%R"&R9=B!DG UlUT.t@zζv.ĖV!le$xQS@]$mĶkWBi(OX*0901Bm3`! 얺ƚ$"*jRclJUQ+0dmf͠rJd'"kƪ( #4*vߍ E&/b>Ro.*7z1͐aldkԹu i+Ϫ 6m?%=[͹z9iV0Ý($lQsu uS(l<A h1@a%G[k]-WސZ[27OԾM+OcȮ0$VzIx& 1zq|Ll3%ֺ՞jE-uIZ PA&}sݘ}^V$mG˟OA)GFVaTV_Mm p vU% YuZ&pa%L~g9W&dR ?6%Ps/>!PzR΅({`Gx6zYH0Zu:F{07y|)ފeI%3^VAN#[zY5 (`Q6ö3JL1ݧ\5e*Ҵ6UktomYfV+9wɀ Ƹp>HC 21򌇉Kebx9n@q]46p2k@CƧv-ܒuvshF6ZR?aVH`AV& Í #m6vs۞glsVG9o6" :lڄ3gJ9u!U'+Yj)| as!J?mHOKqOI&dڦWS;p'륰>V$@F4UH ZʭZP65N4U@ߚ u>JܞնlgQV t(VmiN;Hؚ'gקLp$?tׇRM9T&G]gevK9HeHDv0rVlYPnˆ1p C =h4s6=hI`තA̓Ol'şt3A Y]A0>Orz] `fPӘ8^08VB(oB)[Y V'Rn -,G*lJK! `R*iK [m+lmʥVKP3-qQ m)Yctk))eܧ{ "'A-=bj#H"iض~4[MdӼn͈5?LM &QU-R0 LP0\_bۆimloϷB3Г1%ZaJxS6|Ț֎V;_3T(lOl;)1# vb$I^RVzw0Yb@BVnI`},$`Vm `Kӫ.f[j3F*Dfн b GGE_Ts*q<ɼRp? WyTy Cg0]pI(MY)q ٹ3xBx+=w9k~NmTU@1P5IF9ewXo[D I F5 X̠dAtRTV28f[O<@VnISjbfhp{@jGU:qE7^?XH1d)+J)_guнBV"iAc=Rk>ƫʊI_ -Rʽ F9\Ǫ0J`+xېVUB '9UGx(uK0`B%H[lV dʭ.TR4 @ŔUNKjM)j 'UH5Mb6Jdsbd܈m9w J̺ Ih{ q%;;I >7$dUa2L,[:v|By0n軯V&KE)xm;rZSda ZW^)ߛ|x`YLEY:~̼m盟CFLZ)VVdhg' ۔e3z״&cGv i[_BUZpSQ"lHG F磽3Ff.導qla2[| .]~}4֙VjxVTQ֑rlmRJbDjni~#a>)l9caVuY~L>s੗mə-pWʏbXH6-e!4TsH.5 LĹ%o͟I=>|1[Hi6!ϰ 𡁭j`+S`r&Z/&i]W]xU$G?iG^5j2UI#:I ,X9PXd]7Ik#KSgҚg-"M̡*J;7 HL&5$_e|[xKP D>cp-=%Rx ``bJb P*$LfUQ)O%C&Jz1Ҽ4d3"F@f#CxѨjY7nӝ wjHAZI &2)^]۲L:NbT2+(<Pڒ3, .$`TCi瀬ֲLZHV!rA Ƌ@3#*Wi[;[WjM譐z)m^Y]Kk & :RHJ*MjxZے]ӔJz+8OWhS) Xk)zrߍi3l X٩;\yn{dTb>jW;gI`UhlbUkжV4CZN0[S%NH lzd]''Pkz` l {Cx245-^t&MB_!eئ &*륇FM "++ 9VdO7mk%.NG b[%07AC\PIT1{p{^dJye~!7d].&a97bY[&fDJ9YA 70Qr怡6AMVdSpmc|fly[Drd&gUՅsSˤs{4a *I* P1`bpg!= nȍ MNcM21e:(s5;IȮ& ֥4]bnƢ!uD* ilYPµ ը-`f&SwJ#͊ oKiZa^"C+ALv%}:>EjYLCVIPhTliTbMVLf/E8Y[VVmݫ-U)7cOP @!%?szyk0vu'V_/oí܄o"d1&!!V-eЪU(a||?GW47J2v뒡-n \ ;f X{`dHMİ[s`n4.#}""v=:PXZ*dM(HVлCLeky.h*9 ke`VV9F4fHlݑ,Fla2$I@Mc>o@*I7@8@m lE 6B8+PTEܽTHfA)Rlb,[io|[i"Li [EsReR<Ɛ їL-FiKpU(T &__^!^!>+ +򮢑Ib:V 7.RpAQ;Cu`Y 5*HF`PH)l#؄w$"#NL_mqݨW,}L Ȍ40}t;ucLc ^ub]*Va%]5 ]#@4 _d}|Q#@/kU <9.)+*7 cW6Jl %Z[RB,͆ɺ@<`[_v$ F >U يle[Y[Z7'ElYY!axV`y\J'F4{9)Ɗi ԾfVJrdUwi%i)3'Y1 9A|]4Vn@P;'5K:œI I%իF?2lkC)TBXMfXo'+%Hot&ڎ=e(ۜ$%71:@\# az^rqrK)Drߚ[E@)1#+ܚZH;^h$k}utFl0!*?3&4|$ 6% ҋ_s?lHx}TkdxpUF@b%a"ӨUW9W Kfe(E*!btqT-aeFo`` p;jE:cb4H nBxbX6FZ]T5U60Y_A 18 $ݕȖlULF M<[am+B*pS6LcufIJIm$l5CӏAUYi* u?q1vRG!16̀,4R~[ pdJ)DZEYm;ZHwH[d4M̒|@IDATa<ZcUTk+$Xw[z[za`|'ȭy&;]$i5 GYWTxkU"D崿%]KVA!afSg(~z)a%;3Ll 冤jH3`jQItjmEkB% Qk>VAf%3BZH!HX!jVUݕZz$`X!)+)V;BXv7Cz" >7Mq]ªdUY &1YU%۔+F"Bm<5%-}$IaJ!PͰ5qWMє΍^ BJSaL_>h8ܡ-)E'&V)@w%4mMajwS6-U`9H9#$Y+=g'kY;+93珷4Yҭ]4sl$=?=YGLöV-k2!2*I%읡 ŘӶ )9τfRe[1nekغ`hhlnI!`0B!,%ÙhT ٛ31iN6g&EΙǸ~Kif!Fr0˯YЋ _v@3vRx&55^ٶN!Mţl[1ö^5wbf^:q] ԨJ(lR&J"+rZr* x&RȆL)k~۫U2AzdUF*L9dĨ"CNt[U^k7 [GUSQvgAc"u8 r-xY!{rsR#`4OnL i+ UFtVb_t t[ (c]`%4. $6uA,Rf2o ) W0+2@9m,mSs%d ܘHk|)0_~NskN)[ HA;f$bUDrcRl9?+{1R~1mVKӼu{%jkqN}t+&% PwC" iX׎Ftɭ;f |:i>#0J( xZ+ae @nHJc+wxvEjF"moVtLdBZ겔*V i$PJ6V[3@ &k\ F#t0!,dP`gH bB꫊oAU`1k@/}S*_Ljoc#;?}6iz]ު@MJ y35[.mm@v;:@8;IZӓu- m7U5H|t͠0o ~SC[YIpƼVE}̝Wo[@j!7jUoŰwVX__"jQk kD C#Ұ\R %}g7VݖLp-;EB1H믢Pn<EPIiviQJ$º 0Fn lAm"{e 3U&췐 [}ʔ1>;|Z+f5xSprVrBS3gIP,c:7v_TR370Jyv莑 65XB6Rg2P-fcn`UHsH#ݕ,ިJ:FG&C@@S)d @wRϔ b2t[N;lBƖFpFU4UU #m(;_4 ִUu{^ƣ!.( Z̥0u񍝀3H:J 7RΘ!= eW ${tN 4&3Q}wf$eF*ld&c#4lp[3 ֥ i PE p4-O|)۰uV1C>OX^"1Ҫ EԺֱ#Ĵv&z0Ef=I)4FR]Uʖ tX9Z^.9Tnm9UIz P L+WT4._`TWn]iPHɤF<1M(K'*ċa v|T#2ʭ LqIoھ(e" j]cV'2 C%h$5I$È0RY![א _1dyv"j $kTQ:[ @/ IO,2 Ʈdb[#M1A/YbXx`i`\ЉB ss'Tސ$ܪ#`#*$0&@fvV0PRF p.afғyd-&\ 7&Z#mJFӐa Ng|SYXF3P.6@О,eXmkDn P]Ta[M iG߲)j2T069,@d0F_fpL>fd᐀RTI\G%=,nb ^!W#!kEk7,0:3e1 yɬ]HXUe+0m(kԗbJJdގ1C[=^ $Pj30-gڵ#ˉ7S;k* ('n@ h6m*bYVʛ!ͳ*tjkB$k~gO)<4aU^}Jd$`{ /ɴF2H".(fA+ypP%dE|c3iB8lL*/**l%;)1,K5[cd_/ _ʖ =`X.m+VN ҥjgU.[ (ցccZc*:v0'6+`i 㒑dew=o$2?vč0*!ca|2k Llc@7'V(ilP _ A=qVb^ Rs jJ5|}##fP'Ri=ccXKqRnKP6-9+t-H+OZ'$Z+L,V%~l2B`p4 KYiyd|r #VhkO|'N Yib=}7Ǘ .p[H&JĢr#HYU*A}muq9VXIx;`b5YrHddB*+1eJcBYomT%,KüZ U&1CK5HI(y@Y2RiMB\K5,nfM^w:Oےe'@dXyGI(Ya A>xoPB3`Hugl [b i1m$F5#i;2l3ϳI^nJ+;R#4#dw1V.*%$aNǴP(9p` ul[9F K՚V5+좔u(C*ޫ9 SX DH P^%ĩQb|1r&&E&z݉KG8S"E穯sܚ}J1 C-=-ފk'j<1=WhmJjd5FUK]Kºc*єaȰmv6]``Lu*[/mW8G@aZY)dV3[k>J4#]`]m!Rd%g{"xAΝ183TaC(spX H7+B?D2١d$KˣPJr'qV aXkV ڪR ?gzL2J4o[W0T 1R] qkD[x ՒW XwEZ[y"Ϛ 0E^H@p#Yx:K >4Z[e[SV;-sJYwh:*ps0DlHA#MWp/8 P uF4"!]lEfJZ35C b h:2YZ,lmsLriemulam } k=8HI% [!-VYL3ˍFVSnM%kA*|4<e2F_Ya`Ov 1)ko LfR3,`4c`LΰH֐Vfʩ w2,8fV٘!ZI4fNY6[[Mk-p-ϗ-2ޚrTV0B[k79%F-GG~w DBGw3 ]+t(޶YxҙW%\()8uGV)|PY-=Z)V@ @p@'hjgȬ\TG+ qlc&MC>؉aVJ%^YN^-Oz*M`ќZGm [w43~ި.Z}n dXmy?w7^&}"g&0BsSê#+_Xc 2 CХ2+z0C_RJcr]v[bdVx1ĝ HjgK –@;Vr2@;leĪ"ՔZgK8Tfc t Xk@ʩ :1V< Ӥ)oR. uĎLr[*d3?o|fBBjz<4 VK&8߅ .Gϼ{VhK# WnB+Fm-`ԋ^ P^V O)JJԔ4d 2lWm"p}ɔ#E YX@y]Ee1L0dSUbmQh5E"v5ސW4R%>h$l=wWKFȎ䜘гPXGZ xc_y17@WkܿvgGSUIg֑m%MB`OP0qɬFV)*"2(XS(e #D%Ѭ L_/<@)&*oVHL4 LlzJYwW;[r<M\ kIb n ;ieU c97Ͽ  莪7*x)+APձm%H̔+]ކY7azR{OYx$n0Z ~V-t}:) YxF%z };{{5ZU@Lp_zFjzd4ն2m+1*= eTY d06BmUmb~@|z..Z~l hލ|++B{X zY!PҏHJ嵖ZyDF m7 ^VCU8og;yF;ZXEc J"5EZ_cHGql7.Jap XV" 7[;H /%j]JN*Ŋ?`e[6ˬ)^9U!۲J6$gdd<[}Bb fRVhS#KC&27qn= {P4|=J$FȪU3I UGU- 7C%;NtZ~(ӯomuY y3d0C +0=_ۮWBs6{ضΛV7brvl=VmzʭM}z:r8ja8,8tɰ&`Ҩ* L$ c yߢOWK>U)  6OZ;vd)S 2瀉?ӑ>7r^̼ w΂4Ⱥa. ;֯3dY)Ymí',.<&m Гy"腩;sٮRZ2- ܬd|PΪXBe(I*>MCU8ҙb+ܸ? KbQQ z!.8L*CbfʇQ[;[yf_!nBH_S(uϵV7RnR1Bw `% +H WhuJ0Zj$^58CrGh bbS0Fcz|AWĚF«mZ|YeX$ @ )"-)B-1F^ [GEZ5ƐKՉ)+`ЖC2mǧ7^ p3v[RH`dn5,`WqY on 3o [ϧ6@[](1ofSI49LL [`+Rj<%R. J%UWm] rO!dyYtY݆gQH`Y`{%WH0M%IH*)zzQ#b)-;cOSg5|2QH$}dC?7KPg$ilE&=ê#݀,ʒmL5,0[ 1r~ga$[$laTjpP 79تRƊȀڶmb2p^ J0^;EMB^ud X`_;gT=7piag5b"Fڜ^b7j"-J<>,+MCePTն9'boO/d-JUXH.i[1*1վ)MY*kƧ3/luWΟ6 KĴͳ5r q0!mia`Éu7 [2(6d46z5q )ƇK6>[}uWzѫD N& #9o%Hoz@}Մn[Ǚl*ِk16 c˰E;O-ƮٯR̭Rl la#NO#VA -^ytlU9#P*Yzf㻁i+ܶQU9,L_-|AOPV_qRHkVfՃALD˪mBS4KoB2NOb?.(%LӐ]ĥm5ϰ^rjJW/2QIeb 5"i3$K7IT >€CO3UxZ0 #H@~B "bL[rud44ٸM|X&d)Mÿ^Vƨm} HMtJ"|+2jyRo6Jśc#/2akLX)?@PH1l(o +&7%@[ xRHVxRx¶ u#[Re5?euioK ,\[ /vd~mWv겵c^sN1{9oxـ X_&Ymk. 9r^ @v卡X؆4D澡]As?%epE{(ʙc R,xUJlzvi"ЊliK ^OʘIlz0"! .0-`]-5wd4ȀF9^r4Z6,E@,r2[LSk[yKmkTż+mURpu|4ݹd# CߖOzv-`<@6nYB 8] mn;>B4$z ,U"‘@dRM7oEd(!3/m@Ijk7Ox$p4"EʰծKMSDԝlL|^O.Km[C! oU2$pv0mѶZ3\hܬm0-\O&fkΕS"vǡ:,Jg\)[$rT@9Y0>;nçF%dfeՐVH)ɀ<" d+YMP[m[ hmK/XkU0k6]|go>3lL6=Ad%|zQ6p"\IDH>l||%0&|'8797- ̟aFjMRvP#s$)iׂ^:-i4H)[Fͼ0@pdeϊHA&VHӄR.5@cȉpϹe%d"Pֶ1`>Rʅ4-ٚWk [ܴ 6T:8c ĀPKYykxGץ*WKLFP.aNJm0xl@Veh  xdkmu !iv߱ʷ A`)B*Qi|ݍ*[IJ>nZH! +ձ7=7JEZ*k gI^4_CZ<-)UO\}- KJ4F-Mk _XmTYFrNJ,ܹN7ha e s-?'瘎aOO C^eR MQGaRM^JvCT-]G+l,_[Lob5 U97>E44SfhhphV$YƸڕp`dm6y0Y:jeR-d_[Z||{xւ&VWћ9BZ2 O^}@%*$ |̥0VՖw W> j1- `lQ3pP?Kap;y`&0 I7矫P VD*'.jd+fHCJs&#l)i$C*1FQU/XJ;)+R ^fH/E\5Er泪@CZնⅾ:6JAVi[ FaH T7F04*,daUWx=oNdɏ|wKqZt瑔4yG'nTf $P#ŋdU ('f.oUiZbuT E~*GRb*̤u$oV-÷^Y8(dR ސ4p<Dp ghUKжlz|cviiIL@y1@8B a&! 7@6ÆDM[USMʃ~ErfkN`qfϔ1U,H4JR;fJ1ͅPh}n~M+k;>uLE|&͌dXJ#idK@ [.A#<2u& u%iERj»CԵ<'7Y 6 &UIy^GQF))F 4HLT9=\dˡ^jUQR$5uJaP|TjMO0dE^Ym:1`-Tqd=-e38.v {TZ3Qm&k^9()<)AxoKUsؖVaݭq˺s9$YĴ婤䆏īե(s,G 7uĐu.Z1@9R U%%J(/VR.}LE00kh mMPwsbܘ- #vX?xlulL`7'MbHY'`pÔIVH)iN^{X%MldN`nx@U9ˆmUE) Xw.d@^yXɭZȈ10p[&G 40qm-p ]" nB ch U ` IY,fcWu AjܲpkB 9ٚy}l0sj!$čt:VXnK* et>@S6@#@[*̰}ݛ/Udvd".. #Vd"fS3=FL+hQVi 2px[%޿/ZJ|ӲVœaԆ7iYcwT:($33%S7R׮e=Y[A`+,Rx%@&:&H,Y߉9% n)iD rZ3R!egA&郇х 'DYϭ*d*$CFhm5M6RY r[扴P }wy%J Zt1m%v+ ت_:rXԮFdʓb4mZ 氻u|[$tcT>`Ö́5Ȧ Hu h3H>VĜ*) m𲢪ƐJ &g.a>]@U*Ԛ@pxJm>րrLf49>7 Cd}u][ZYVBr$6p' X2D}}}-BF5F5j=P[aۨ0~5 !1ZwV/ ^l ,d&Zm0$z0*@ XKg{jۦ ȵkJ̹@Lِx>dGM 낹~?AhM̜s,Y.V9dՄ4%S ('ce5fzQޱeNc*[Hm ,p`)CV,p~d8OTwzp݃r$6$Ͷ dK/XaLl[*QZ2tZ.3q@)>TTRcF~YRtKd 8͐^V 1I+2WK@ Ad͔JllxkM6+|L]ijY2 êphf#z)yZ^9 f[ Dr n$ h[@/k#vf{0\gKUh0yrF!L1OL3T>>p *&cU%l;5PE)-[haiWʄF >7!J)dhn֖CJh:Q)+K!v|PwEDL0P|Li̪q&U5)il|0ZWb+UUo# e$T%/$^j&Myji~'ߒPUb6"CY]z.@vY2ne ZMKi9 4\FaaCu3eٲh1bBǤZkC+&1'761R*Fliښ#\y#G$>72<]uWjZȵc{ͬz5̾}Pʇ8̤S)Idmi00;p5,+e2mȲVvd7_3ղ>9xWNO`c2z[J*#"Ѳ&cٽel3x-Lf(V[l-l7J[k09~M"1ưS*ro8*- sc ZE#$llM~pUeHx񞋒s@tڊN{u*(uyѨ DaR Wr|o/e9`E92e#̖bUuFjˁLU|Y144 %dm@v&Y'­>#0JTm7|34?M[bP䮢ǡϝ`bM֕rcm$sbN x~z$x%-|  .qX)hU'О f.h,Z qXIn57Pk0ʳy `A%#zɪ2=M1DnKV eX-aħg]%@vbh~E)XvmP SFnn는"=`&`Eb쫄C#+wm$(J_9¤ }_3l;f[RUp\ T#' PlSU6DYl86VH2 m+ Yj-+ @IDAT7Oח^joszʲ8sn>̕Jֺ28[ӱRlH54je3/7oQ7?C6eCw0]/ PyV 4U"79sSۮ)y|jv7 ӱŎ̚j׶*] ]^4].6=ç:M3J1cK a RHE-T > ZI9jH Ԩw][X)dkRy V0MRH>?R2i5ןyY_BSͤrYm$[alaa ;O|a4@9[+2Gږw@1@_txV4&NcTaA U٪/YȺ%2V3VZO\4v3X9낄qt'EM#itA:КT}'V4@Swos|w5Rhf_dY">nWr/:x,ivz ^t?u? ÆEz O($hlJ)%8Ysc}6q$_VT5^ޜdn*9[.Ei0S4i UR^=SsUU#TrhU(zU6$d}"‡XpJ1Q{/߬r[VBLHRxk r ip>uz3R*s+9M|mT` v]HUY*e~@LdMU#;#A5≄]&Qr2V4xUC c3i o+o#@mͼyla;) Fه-|8ؐoNkd mcLXKU1KU5[ۺTʐcB&΅ v bg40mJJ5RFIa7 `YjcECi*zS6Ljd 4Y)D`:Z:x7VDb+\v41M-1p~ȦJ;5lJ]c&L̓U E2΋fm{((īV[iK^kj8N~9dmϙ̛+CO\Gk_16ֲx8 V]rVHJTUWHRkˡ ēqV üԶZ6&rp3`DVB ( ⮬"MYZɜKt [s+egr#3p*):fJ5'ASq)B|a@HEYU՚3,D JUyR)geeM`J!W (=/$49ύ*@#I^ux,%S"e Xk$okH7qe͌oB&mu8saYbԔ>"J%<)u27\4|wlUeBϩkTCZVYꔰ½+rPn5q1ĭNuNQ; i"nzZlH4p%}뮦3PI4jwc6F9N'+, LG˖0%Cc4{ 3iA/LwH/%CJ]xEZ:>Zq? 2D;)GVr[Az;^噗J<;tWz͐0[β9Պ'Ðz4bMN^( $k5ag ja--0_ JSp?jKR7GiNhNcxe9t'b&pMör)dD|ɐmH+wBSsH*FUkYX_*>qM=ە~.Je5QI/UaE  6 xemޙloNQú=06l-o4 4 L0Q$Γ <.&4U6m3T!Py>J`&0v3Z_.5B0@8C$=@8E|&Tt t|zd}aJl6͜f"VF*ͫp#6%+j[LpP<G#@|9K]Kʲ 7[*۝.,j^dxU,Vʖ'@ZmGr J>[yjPI[*_/VHHY2?Jilh02XRN&N1M8+Y[C!֖}^dV#Uf:x| IPB0CI- I,2,k[ 5:l|Fj^: 2L-UI3jT wkC4K@D&,=A&psTno) ݸp?"7 Ρ**|2)$OZl}aDրǠdɴF6aw͓oL |!VlYYa%ѕ-bL'[d4!ÔHx 0J9FEU (%gl1*ZdiRh")^dH+Ș4|d]uzk'+phUtlҶbkMoff"( Y%3ԢCՈm2*lk\a*똛Z@l6mG5d9?1i˦8 [A9S 4a)|g5סBnZs_o M}$ kcglCQmU>e+m44Kٖb %~b%/h׽!{E,R6pS Xm;|l _ns cha+1ʵ(ٶ^&Ҫ*MF1xQS@q&jŴX R1"VUܚjɀ~bi0LO0jM~AL^U7mc,V1Ⱥ0qf}˽\FbZɆ @R14V5"K؍.M5IY'Qi.(uaEdyi ܅bK&`xFb5[gn[rUڶT+=sEX!Fa g8=ވ)ْ X䳣av W"U _FuQɖW)X dEʖfvjJJwpl bo ^bJL#!MOFc,x)[I!yKgczXsYt َl<&L)dg%ڻڑi$&c+N0"mk-/W'IcۺCU hr`"dMJ) L #T IٶF§p> }74R?2?kcU&XyɇI$>m<JU"$嗤R༚^4d >AX}t_y;R ‹Lm*9O`mZU}}V++VAol|JYRd[̤FwZk2v-b<;5lR<*6\U Gic/w[& cw.%9Qs eױ莇9rNyj0dl] AJ;$.+PwW ܔWh6J#e)N,y-`]ZdCت[Ŭdyix6j$1Z0'3so-, 0uC^4 1d0V ]*t($\S*[j lOYtO r7X|1JygMl/[H8ުJ9TEU97X+ETsi$ȶg9U)6s^L4edVmnaa 0ħȊR{H zkA#e=fRV`}) El&s K2ڪʪݧ.j^B[cdE+HUvgQX|.d8[1>VxWԅK~-M-ZɔgjZ*sSP啦ol5F,@2V?|G=vUԖH)^貵,ʥc{7F ɪaClmx|VJ6Jb] ,:~V2@m R˝m`>VAV 1eHLWe+/۲݅MZ@5Ӝ*eTiDXEÝ]*7)>j1Z9g2][FQ_kc]qegXcYw;Y+p)4ul >|&ǓU鬍WUHVx(}o*bX[9=| nI)LM"i4@V(!5 [[!9=>)7-%7[Ԗ̙!`Ցd+ dUuV[ (IVS>&v/*\#XU#J`DrSv'7$ۚ-=)VR,`]>͔p$'MQ1&1X&n+;[t-"7&cP(1y7R7<~Ǣ4c;" (y-|ʪJWKn&ƫ ;*VVmgĐYlHa}2l[5"5Km#XJ ζpnsMviR|LBt(`[m=a, mSزrլ.WJ&B{|[C9ЋY/Rd\@i UIu94ۚvQM\7s+%Б@wd##$@3L>{ )1löL6?ÐsP+Lל@uI50Qh+e^6)VRǬZl4<3z߰q4ƳU>OhT,$͖wJ\`QF~~Ϸ#Q0RS1 NH{铐*lt fR3{? ;ٚǚc rW%EX: LHh򔲑1R1ZHaNR6 $Ph+JȄ-k aTnFB䜹 %҂\Uz2VmxJ`MfK} d3i$%R&4YUfS,MRE)b1\H<֎Yߎ0yN SV [jaUdRa;221rzTD4ؔ A'=SV_X(iVzsZ;RYLm\9`\;TZE4Vvdj+Y%M/8rCZSz . & ?_Pl2) :Nd[v [)N!ˤRGKDP2Ϛѕ0qZ$H+,# kr"sz*nɧ-X!Oxbʺ]̍R֚p\ R%fA6X8l=F+|%xEݕ-@kQLiU+EZкlpRAahgd4tpc4Rc["YsH w]LJHC"Q|VP $L_^a5lJUōv;%C`U_!f~ߊ'@?r..Qߘp[ d @ TnrtqY5[n]Y<0DrFda x[C T50 VW0R\d@|m94+^ u XiҎC@1lߕ9z"\}qOj'*ַB@ [,ܐYDj(W LY$kI:y^fBS|{7TEJ"ŭT5񾙚TBP V9kG#,[C OC*F9OnZ`ԢmfZm a_̇mm&jYs ´Uґm.@EZUmdH4҈l]DU-c5FܢBF_!U^k|Q"ʧvaǍDn{B@o rUbDUgUy]"s`N] +74V]%Ɩ10' J)dle)+Blq"-[z0Odζmsx^{xZX7R@(:з^*ϊ5sl{ZeP`RzJY[e/@f]S[e#VR#ma΀{#ika )@V9``9`3 duʾ_ ܡLd Pv+v"d&&DY -DK!3Q*hD OL+ZeR1jumSJI&#+UH)%C[Ǵgْҹ"FRk7^-& `{b٦Av)|d&VA|%X=﫰h(K6Cekf?nYߕ{ zY+!{q1M`<!+L@5"ÑH"A@#Z׎Aܢ(IJ.1Ui%l²$` b&&*l #[mFr@ѩifnƪ )Z1di+?7a lK V%u\uV*dNȘRJޡhd9Sˊ_5 ʛ XUшRZVҜj#bYΙX1m`ʙ,V(!1aU氳' &VWkcBC'JZŔpn)Rk{-Z͖q-gA.$ytr2}[?6k[#C]Yytn+auJL'Fik|&K z|+GCbz 뮝G`%غO{[ɺL<" TT@?sLnM[ϰGl `go4a4c9OX(om_*- VInz2k$z)%@cjغF|DVّɐYWPN WXֺ0:y's[Ow.94<;;CJfGBJ&h6$ J)*򬅔m<֥"~Uaj*gcPؑ1J^ LApvdS!SXSKy6,sdk@[}U}rdm "SUdrBTT+fo68C)F(@J GG|[nkNҐj8s@L`y &:E)hh|okv kS0Ye1UT/g)`lo73NAjxb%|0`JuV(Er.lg_}o M#7@Դ4a)" j&xQ+\6rʹ]n/D'"ٕp/d֑(S jSv_թS酬ܴ$cRj@/? :lZky&ƺ 犭m5x)!1ư'6&snc  uv 8>A& 3 cX XOnTܐʁHٶ6mL$^>/&!SnH9 ɤoOLY<74`Ww[bq> uoU"YlV)S&KdxOזR}(]PZ"v~YQ 4=qJ:8 ? Б>lUH̅.BSPb0&HfERK`? l%IJY*7ڜ)FJ"Ϣyü؊0ϹX1%SƧx[)<kUx"ue V YŹJ%@ ίm剭J%+G 1@- i V# j_ ٩Yu0i%B3)Fgz,+4' ZX;{n2[^gmv׎HPp5AgRU[;Ki3uِ̳k]M썵%jKV֪5RtHzUN,{+@ $#s”L{?Y: 2n ϱl%=V|v[ h;8FUFSU ÄgԨPx;@՞?f[a|3mfAYm6׀ [R`UWHe!sI:j!nB*l~YzUqڨ zŎ7\row,zkɄrRV/`n73Qx7$sf Qy1qbN&+ 2u^dRDSʎ@g<[F!Z(a]]S޼&%/8*tJdH6Ķ1Z.ye KmP f Yl<|ZWxʔa-Z[BUʖ`z5w@uWVAU[8x%ugԗͶymn)mE,!|FUX L ;@_S-f++l=ʉs2ǪPUYŲaR*‚lymP%Q$*Hn$caK4p3JgB0.vj x=k>Z8T4=7F6 ( ٶ.FS֚*JGVUQ *0 `a{ )= yQ#JUu4 HB.J ϡQfrʟ籾aY&"=)偆*MUI*gy%eiCZ4=PU ۵FS-^ mS!>&R;4VQ$ K 4'1†/2Z)ZE0Mت @+ kK'Lx1LhRH0 h$xp-Sx򑲵™[Z@8PE:첔>Rx},428Q͙S7ꋻU4BZL^lo0mZNY.6OѸz=:'J-RZmsox~/x0le1@j€X@ɪ!%2-Tpd_/Up4Ylm0`RnYk㭐A*YT(mU_N'iT%4EU4x@IDATHn \I|0FY; ,%4S<> ` w?͐݋:Z4ɐO!͸H%go>BH1Ze19T؄"UuEĕM L$J A2L,+UP"~`:Wdn+BcNh`%1]i[F۴w]I@Iaן)44'\IrD#&P*Dtu~`LX!UCemi剌p6jzoW.O)dƨ^5? oZ@P2lifPȪ%\sIp̭<݀C]w|Jr--֋@# kBj=k|a '#k$dy8ƳҨBU`t>Ћf۶.[1^v)#WeΩ j`;`7XeP˗@C9 ZwB3hຬEWdYxAUVV/Jv]U+*4mu>J(d"EdHȅ,ޚ&a0V)ȬlmeuUtX+|q3esE܄K2,YC@:$^!)>j1LlGOxYjM`D`6J3+![0AƜ lHzƺo*?O1 ΊIV먻*xJ440H>3-D`ڟ?MeE8[0Rg lY1_!0cۇ4̑<3#3Q ـFbԶI{ZQb C c<A3U ¨R3Lj4;f!cۮɄ,5AVۚZ;xXmK*D7l`䂕ucl[@*dȶ9D V6C8@o_*!} <]1|\, x3q4LG Ph吉AT<ۘձTYrJ*ېuoGqY)h%vJXCe;$͙~qIMU00uԝrQ bJ[-bVHUw/[d /8nV#@d3z0lӉ5ї!1 e]6u)JمZ '*vָ&C5)O( Jֳt_oDJ>w%`7&ʾ /EAJɯTnUPiUkRv1Xdu9峋Jf5mcJmm9[i2W(*7U/:5L-+CY֗`nV F$xdUHY cJY-iZo/He2g$, :*ՄR3k`YUu'[8NA\#[P{IVUl+'ᣢqCP)ޓFb: v8: ARJd8';r}+y*#4%P#RY:RZiD[@ọQrM1t'H^MX;7/є*lce(($iXk%X#ln;)2ϭ@ZY[ySZ@z([{:d|0[[*W%divmP+\#7TX!`Ks8w)|NIf ͆rT#(zg C<X͓@ϩE\)U1ȪjtkF-^j+5UIȊi 5A'w6)zL@Q9cFZ`$0‚,[4֖-MxQJvVKbj}|X YR1="gU#Oe1b^)X)elSGHEbd#XWcxj}Hu͆  IPxH- B[0 +j+D ΧWHVcnkeIuE@ydhwۛ E:[f-JE<ªlyfyQ"bYCi3 %l!~>%g I[u,IV-F؊_ s7@s$Bfǩ1FN̹ڞ2ދjns%YiֶLZ\ֶC%k+n|JG*[ӅkW*L)ιlJo0d|7I/Aߞ t{}_1bcn*Y9o*YZ>UʍQGl uQ%a.& 0e[y"MNoUqp"2٩m; F؊,9TֶZ% o[ڷi *z[YgkqQv@ #m)ܶy惡d*%R'uVo7U{kG #=enl)RHpn87)zD`4Rb+:R-i{o*V‡w8=M9t.`B7lY\R|\ FEiH%QYbV2J#e*D0?* [顯ci8+4 S*">7*>NS"E8CS (.u*r.BHxNX7vzb*A6H[(1REYIQmH`ųGJU9k[R"\H'C emy ͓VM׭>rk;^=} >O#07+0*H@{iHÁ-1[f>*M;[@kW x c1mfkl[ upg2*sɗ͑06OMg.E& &E-Hٮ< & `kʦZI6r pH=>hlvX龁"w󟯃\ wW}+?eKVhCNadqdP| 6T[hp}xV)΋D0ēU 䉧ojHh% @Y\~+ik#䥉hoz|p¥ō˛O颀<]bڒy; T8O fg'exԅO@?t+PK&U' VZ@>h-AeM@N^%Kш-֟!Ϙyī.%;q+.ES*&9p1!nS J] 2sR--_%pZy| g5J[UWA#ASŽp- =<)A#ځvB*FcJ5jkX8 d RŐ澂1OUP0L=!D"t^גpG8qZF,U"wR%<.؄ pBL&6gk0ջ!S#:ςjG FnLoɳ}*TtITSU;@DΌߔAE o *CMvkOALOGI{Ղ1BjL-o%LYRN<)U-Tj)~RU->;.; Y|(@c6aS*|#L)Ls4ܰSMI n[ Z#~RpyKjotwHB](SdVND  ┓mt+3L U<>昂9Kt4ueDGnϥ@C'y C# lVsA#Z8D,)m ɤMoVR,d4 *fg1}2)k1RȆ( 5YT GU-.m^LVLd0e̞ETuI}Q֯pU䮺 yC3(uZ?$C\ f%dx XHh] FLr(t ZjKY, db4^D nG/^ 9$MFF1SSuWb')\RKJAo^0)%~Sl:·霝YƬ*[Eƥ@:ZNhU: Ji?e*%%>&,w9(RD"!f@0}p 'ţ@LJx#{4;ljl1|we"~"V JAIk}WWEIW12Xc>eնՂ&fU#7Z9fU%&>rIYoԉɦ&~9rn I',4@{RFZnDB,MqZF#djRKE SOoдTKqRF4ǴKDwv8K2W& oq|O nF#w|UYih}cML*}#ǿ/iKZtM'Ch9*<6|A^)`4 ?dž%_d+#,ʼn#|:G뿭Yb], )⎟rGT>PӮ% k|;G3>.ٰUwKuED؅rv?v@h=Aiwlz2P/5.f<@Aud t-rjhc#0`v{~,78|V%YJpAoHV޷Vb 3-Yܯb8uUm@:ex%8. XA .fU)kiXBܧhK|pdIu@g(0{B&7 A0प&p DT'#d w'Z(wͥyJIiw!mI ¶hBgZ&JBF2Zzq|o\S15Bzw1LqzOY* Nq:-#+Y6Mĉ&eJ@q!K'RZ*IAvdqĵ7 ւc.] ~R F ɫnt~އ{1Kts7¦GʔRNap/kLM)-J tDLAТDKC2vҩÈo.@AQ3fJB6ׯ=JW訲\A@..Ay 5 IQV𬃷[#B|A/Ղf*D\ AWhx|V 1_JuNWt1Ը~2ATStI?i[is O=,1! 'PS*j#HiR~~xJd6W'-b"FqS(1)#\>V ዩ"JzzqV+γimOUeWGɬzUYyS@'Gap:]nQ\} N,kZckQ`@F($MqR4}-^Un1U ms" ĴY<3n }T]-Ɠb]UۚqKU4^<4)2;d@%e!"v}"C)-z͋bhvZi4*FO)6knFl%R5vv^\\"!Z ͳ5C]fG&iZ J.f0NHF YI=ߎ/>4&hdj 1iJ`f,[ tӌ3o [hR"!DХIhb%n*h Bw+G#Z&}HdېB~pq w| D谖 A5K_wX%-J7Wj-bb{gy>f)2#@ǬK5TƩҁVk-Mt8_ͅh뜯b'bZC<{jxpJ02_l0&jg Qds#l-G/n\)h bMx_M6C#и&BU  XUue! Z=>]Nd6Is>R_Fto82e&v = v&)%*v<0F ]o+UR?P4{W-U!h1 Z@jrO`A TU@ !|ѵ 3g7hkt3h&6+5d),!+ x|&`NDJ`4?Sc@ت)m5L@į콊3OAoHӑ"wR]}N'Pbbd**U]N 5SE}\8_;rI_;ώ⼓zVEoDŽ) *m4K䛝וi@ mޝxzt%ķpM՝fYWbW LkSo\-vNmd R0 YC_~xS}"85\ЅbHcvQ&S3W\ZNP8 ͂wQ8y Uj+%z1PjbS2vio\]8]=tjW@ؙq/){uP-|-0[WwżmUyq˸^:i 8m TZm"`pќKI\oaH;UͥK!hӬ z8RJ;j:b\#RbPNm ],ϳj RczB$A]f)U5ZQEAH;KF^b2ivi܏ ORU #D l+d8)&c^}%OjgV;/n^/Ѓ0U&PB T&оc /Ͽ"Z`JU|@Ϣ)hm(4*%KV8RlXb+dT)~FDѴ \;se 2VRxωX^ DNHSYvJN_9}=[ IT#.?Ӎ+41!LlRәp#^ Uv'EoVMY8Dp|:8!yUWȞX;_}DYzKCk$%eH;E@8"o[Um=qf ȁ.SJWM ABlYT-iRO*pGPmωTkԞKۤy6~dQ1o͌ڊ=_%t n1kk 0A (1EʓbK(.q~HGVʔ& m.ZO;xHҁz۰5XLjŠ2 į]:G&yC=,S]@SCĕ  J Vu.k8F2r;+`pƈkYNjU͢C 5ʜC ogg,Ob<)U峦wpq@":?-\I1<r8AFrŃkȒjWapVcdYUJP@RD RD^0hb5= )YrKᮣ Ȣ7wkk8!|%|y_3aaZ1U{.IS>|ncaAP#4,-! eC"Kř.4oֶp;kNA0S tx:5&#gRfl]_g4L1N]CZ2‹=%IZ\DW- z`J5R;T֮W \̋Jy q ,$M t5 YUc q% YŁJ=Qm>Rxw]5 !]\SS ܧ8>j7BoW K#C^K4*CL]R;DO\*E{4uYxK-D J[LDӫٳ/y%8MbZh.L%8f54>Cl+ > RvHsTy8ϴ EI8F:KzCLq^iEdžŪy]o 2|8C!hYll[˫ N#mFCRKgW;dyN9ML̴3)R Jumi7U$.L:p&Qbhqimnmq1]cx'U"ND_`3)ǔzL[f('1W{ھO;ߔ!5 T8 azy1Z+ekLv# /o2 &G%< •=-d R2AyH jbMlCmrksϥNB6U!bL:h1#nDP*pUo@ SZ"%eU @ooׅ,2ґ,J||[9R@r!z!0:ŪtBOsjAwED>#tA(AN51 %i=4n!bq 3]hYL8F SHV%}m+5+<Ʃ6A;05 49!:B)k+@+V].zm%fTHJRU#o&F^,&P>̫U8AP`:F1Bʋ[F?n*RPbJP`"M%F2A3+گf96GЂJ*i"ߒSPh4%U+RKoHے҂VyעO߃hz| (TA'I!i?9#ó |.,rx@C{:l8*||n XVwHxHU TQepeqMD ǩo&&WA Μ#)3qk͓E,i;3a~4<>~CЉ}k3d)e+IҷUp+YOzk Iu8"6H:hNF_TҢЀ-)eҮKJtg]DTYgm C3]qk6t%ACgkY=ԎH@ZBJ Ȇ6Q *4M!/Х\(!NN֠4\WSx84Ei1->,5ގPGH[F {fg" Β !@(qJM\-Rl4Z4!|$[i=lp M$t w+~hNlHʵQB/e|%KB8x"CrUAˑ\uIiU-)32]L#)u@Kgvp:L^j6Tt 3.qw+n~%~,[R+vnb=MJHkz|jJD~4jXȳ ڟ SC B%ahH-ºZp4 ATL E3w#k[k_S"|xkBXC]f^;W*'&Eo)ItR)W:Q7 'R+ƴX@\qMx4d8tp4٪p^q-peKG@*k ["t @R\ fΒl`M/%0>&b+YZ dݵ 2ষT /u1zAB H?;bM+Pz-,n%%4ӠyW Mkwoq2qgQHݣeɊd %1/M5oqjLSlz>JL>'i4d)vd#o1dĔB6i8 ź <8*uT։aLKRJ$4)Mw45ZitU֕³R1S:}q4qߏ12j|&D$# eS/{USDԀ_ϯE>-SI3,')ްoJ*Zp-ԤuE BU !Ȧ3`x#ySx/ScI4R%SZV`驡bU6b C [t %xҍ@w\ьc[cde[di8R]ȶl*[$Soaxې@bRmUDjRխ L /& g-JRrLbU`ĥJ1D#&UDfkfRJvZzҎ)ŔjQ0b|8u{j1;;? ПB"L%wLi/R|f)un=Hif ͔>jej)VZU̐U!i H!̻HNAv.M)4|)-EvAd Փ8>2F+m+, e @)0_pF #`v1z $˿խ iqH[lH0!h?h-^ )& bFgQbȝ%i ԴO6}41%{嚅ևFeŜz*IZ  ^KĆŔ=duKc@p:9K@SKA7cmyG~OK{]l lJR%8H^s t@rACը aFm5b8*Cw)uU[c sv1_SoaRtS T kɛ GSN1OgRR4H%))s')U8\M$Z ђ Pm`yOͮ~b-Ab]=pFNbDD%^!ЪҐ'|iAN.rR;̵: K? *SIN81vsE_T1p:I¤gs_6JU8?k!hFA& nZ٠ ~ ׵v#6֫Jp<7^~`HZ xG&+p4|C$㈉4S gZR~g*E9?_@8`JDTE)##hDg>ȀFUtU h%8C1Y%~)8t8+|UU f*e0d-#w %0̤(kcB[R-ibn[.B]R344hl#wR tc+Uԕ!\V5 J{k׎FQ2ehqv*@|dA~ZlpLKMEܬ_H7 B%}_תu5T*^#_`Tr^@I{;z/wdi13K/@ĉ-SKڍ`:8 Uyq܂uy0PxF\%Hbtb .qJq;Nf Rh^x CLWbR =4*F4&]|pt3hD7fbZJ $A )D2Mw88Ž]CsUvЫ>F@JMolDǵWDFBKjj T fU^i"_+JLЬ=ZW5).8)4W8h=Cи,q"@v躾Pyoh*Yު8ݭT tK_P3} rjVquij?}źpY ZL*B"F JVX#*<$RU%|#8oSJ'`[F= MdJoI|?%oTRP3R@!!a.J,4:eqzM]L Cjs gYo (F:6\l4Aqxv-Ezs维Xo˜cTDXՂW T8)NUAytZF%@@Vz8^֪|d:UQ8tVҬKUhFp^g]`%t2Ȫ)bRQťh--Gp F=MBXqm #Cdz =0ۘT.k О|4Izہ>Sjx{18.B; )]i 4AT50_{Rv0ņL7nIIzDK|.MڹTU | ?8^|8/E#2r6dWћ 7=EU#2 k+s_5T;l]FifU)Bo)D5l R'oY]fD[57)CY ]C*qF)hR<~TPW-:kbl1qLi∓ҕgg`LqVo1S@I6YYhgYhm3DSb\B"@L-g?@\fŭ߫gZ@y:%gRUv{/VpLx:1å# U_b;r%nN"m1b_onAo)L_;ګfC0>keLD!!*ٺTц`ՔUÌӠ5SW3Wӹ!;5ڳA,Oy# ڄApqG^RӵXZbh U" ͥ WM32DD-dIc,fp< NA" g}}aj]smX˝y~_ŝ"2 #ء@,:Dqb򘐵41bHZzK3NO w*Tb܌FEv)mKY!=!I+{aȞgDh(yR)zBx1D@vӵJS+(`Ml'WDa 1R|kڛ+0 N'KgL*h.MU򵘋õ2%<&pOJ\o]fJN 6qUUq4 j"r u*FF@i24NLUdbjRK¥!->d+iIZ-k@UY + PMS8ZX^ DZ#y *z^xUywIYđ5&ՔJUgU * IV*6zŞ5g lCA4`S 3 b!ĉE M(ج B2@) ̹(ht+5zi#kp#m"DeACym-DZ,g 'GgpCL!tL o,N-f7)^,-Uos"gI5Y%u!Q+ 9r+Cn)Dnt(7Ytl rϦ즚 b2LHU;,>j,@:v cJuYF4=54*yJ= g44cd|֫*NP6㈳&N$eh;! &"NL#Htb)2kAhN$mJ-U-#0AMU!M!dݳYw"z3LFSU%,%h1&V>/ϵؗũĬMkv."hԫ$TW#.™}S[<#өtEZJ}7hs[fld6ɶe.jb-@^\{,j*{Z>j4x;pU%Ī|< ֫Q@,@5ȣM{[Ju&.u`6e%"&""ȔtiiD%-h } !ҒtƳhSXFM-~"Ў'2|%5 ^Y;ґ6NڝBZ s5䧸F8*E֨ l ikG!JD_Rs5bjBAMPuFAS@o-&*r<}LTozykRtVC p)^ ,ڒ8 G6 t {; ]j\jT4;*@.Ր|"G%BXJpR|xFG\2 ¶%( fa6Ml7TU)e\#hSJgQW8w&eM#nMo.`/]R +ilyEpR|8g#ON$K*YW; D@q(@ g $35 SJ?DhJ>,*,߰eUH:ʼn:ZTEV LMڬ0SC0^"ZpRgU|`]@U5eIQ*M_XK0_F#$^ɫ n,˖mT W h!}~Īso4T.\k*80Y?6\K34$= [u `mY 4ӥFR|l3 ]\l Z#Dul@U_ yK^-1\U|"`՗ƪKF P&X;q[bꂁE%Vj6gnmρ8R0if@()ҰbRr'HUY  )I$JfBHIEGbdֶ6h*VmoViR`h*LL|[d!;ՇE-'.h'C-Mz1H9;+-s&9[b9|{<14R7 +6Om U[-Pۢ3ə&}LVnTv3s`V܌-`RHO_l>JdT%@vc/lzOv4&&-|l_ rO!sȿOޖ8 6NE-#]GClnaCgR0[z٭u,Z@pPBLjanpc i$Enɤ=}Kq0'A 2*:*-D@JP_L$& v|^e[JSIyX vF?qHN-FQKRԨw$l%:VrS4 w <=B-UE`d7 4'N׮S̊ZY%S@AN"OcZB:ՄlCS7C[T4M1a: #ؒ9`ٺ%jgnJh (`icV2 lIJ圦شbF*^%y[L(1`SVnG^ܟ<&mAp۲0' ⁎fx})XR{- :*4͠C @7@d+~"SMp΀4[|#֋r^gai WC/{bO OO=+ Y@dĶlIl喡rJ+^U1,Vn@Ǩ[ɀZ 94 4 lD&* gUV )ەe*%g$JD`DÔ5leJ ,0,phNzx1F al$vb}omΗifY+gWIc;_1.sC)}$6tqXkF a @ܬd^lpʺK 2Yk<`02&A[3@DMӬ92 29ArXJlӧR(R .,FȔ-Ci]Tb;x]9ڊLbN+ ReG+T"Gf7m 43Aʄ2'ֶMB,ۜ`$_3@8e&ȊxVHalJ9T[T1᭑V-¤Bm3ϻ6md][5"Svׂ.,ŧBU }Po :)C2DHsMIs#;:bKh0U|h$1&;PNߺoҶ.$m{Jl 4O5%7YpN4s_޼c9g0'1$jF7$},V.u<[XBi&H)5I'ϿB,׫L!|Mc:aV4;5os0 `S!B9 1j[_xnJ` fb] ijӟ h-=ddX*3! PAH2[kbM|(,ݳ-WHJdYYZO? #BUYcJ.CSd% B2)Vl[kYմ1>>t)U4B+:lG6R)1*mLɦOF0 ,ҨZXH5&Ĉ+@/ }S YEo@)c*ɤ$$KmBc( Se%ߐJd3D_% 'NfKf?׽ ܴgByx_V%ctppM}Ī|K 3LcU*ɖr[Qw0RU RSn<OC? m =++}ߺ̲PU 2@%~WknR1ںFHpz)a]`ΔߎdvnkM` #ܖE6O:YkVwF>6c2KY| mTU0 Dd]Ep[`XUapf8mna79֑8}@GUCx5'j֋k $)t4C fot 15KٔdkRSK;H޶E9>Jlueh= 5VkUUBLRa0IO}.ѿ퇇H55QY?Ll+z)dWܑk2R9OczVxri$n3+g*zckVd][e f+dC1?=nk2n6}V9H B Mb2) -U)6U>q)RJLB؊8 M+—'F(kxYn8lc܉5O}mH,1 Jyo@ !\4wwQΉdjKf5tVɘm~K #m h^ 'Ұ͇HLjzJB&"{g.*d93ɖ^kkƐUnWBA|{Ep7UeҴ4=>CעZMs><9EI֖!9זlKy*d,+`/4o!`"uk UEFjBe}=6 jKϹ*d& m7=,k ךe6s4ԋ66U̖<x3lq-`}=uC[&;6aVA*wE:*L`mJV*ADa>(i` dVxQ_ֶ aA`1a6^welU݆F*9R!Hsrc~ IPkT6&;}?<1hy[Xl6H͓OSaEi)tAmK̳FWrOhO@ MdFzTLV֊e4i$O$Ǽ6guR 4B"7v)+Y:UF|f;BVJ&MبdaJj%@3X_`¬^_˧Z w>OVUo*enaah`4:O,z5 LoclרDsV"֔R$ \a}~*,&uAҨ1O8 XU@ HtV[JlDEdHY+FRRdEòW'0 OU]FH]^|0 c~;'KS-C8WVJ!ע#4CJ 4o+෩ئFZ9=#Nʉd%}%[bw&xgOhaeeb;UɊ&yGzLS࣪Fp@OT>n>1%  /~g%Ӈ{dDZ#HO?x{oY(f+*L4[[ &-CaRa8U;[2U:F^cHc-K6SƖ+ðlk| )UC>YM4#K lmeom).x7-,nR0}d">5p |ff*3-mIjlGBZ$hZpgM`1\I&>}3(ʁ* Ss&k8ge=sYblU15 m3V 0Fʇ- Ti͊z-dsTr ^d1&?&`z[A.$۵K<e({~XmSb s(8ډ*UU$L?0JidZ<ޫ{PVF^l mT'ڮ3&^acŨiBJlf0`fl ((ׅ.;ы!&ClE ]"k!*;8iߦ )GjjSR,0RfkZ*́1[VՑ p9]X&+X>0QU ѥziZ/Yz'ٺM`U]w{ϥ!mPJ`j1Te˰vBmˏTXp]V.6[k=sHU3F `MmMgr~-[@2뜹yw+'e YiQAC70d4j;l&Kٖ5@hdlKa`dȎ e& P:VmȤa&VdS"Ķٸ^-0ܜ4̿''|sµn zcjL}VVVը0Tn6JdLTe% C ѶR4<|iRJXtCiۅPBSyks)P2{CZe60Lḽ|BJU &u+$ )!G[€U(Iʡw^k[by:3@IDAT@I[a2gE/=m)#ǡIu^ 1@?R"'AZ ֪VZK S!11JzUlE3OT5)U&:!1 Vg+ D6*kz+Y]hNUfG8SҶzQR&2^ `xUN^5[^8JY&\<#$EFUHɶs"Hīe[fIO @'jZbpɔ z:1eU3vQ'n{K? `z߃gB )baen$1^R4ҢmnuA6RҰR 9>U"eRxo@V}0n2 3u60=2̅_xIPPZ"V_,,h5-2G}D[AaxR\ea4L:H# 𯏚!:ۘ 9@I$-r79O 7*Q.k+0)E+ 3ԨSw~`!n9K/cFjN-d+(^ / kMi=ЋedپRӨtn`|?1&,/FTk#Ll01OYOK47ۊ3ٽJx[ lm1<=۲mEwج8Te̕{7F™k`r||?%(r.- kfLI+h$hk sݘ֢iJ\ֶMm4Y dm 5N70@#.wy(~CV[2C*l= ;ZH 009|O)]P!#E_uI_Sʪ0R,V62VP JJ\ [\r)&K@YY 8cEZ=&)%HcqKZ1fe9Ugk (kƐU+J\YI!˄FшH%V0Zx&zd%)Kيs@ɪk;YV3w[[s++~F0{WygJmbZ7*+U-ۚN#84[G]cdZ52„-d[Q@2D=_9?tDYfzX4ipO6fRFJ/(SN)0`#K Fc$&.Y%XȆbsJ!*1oHX@:#&Vg7Igdk Dc`HdlP`{+lrd&JIOP4*>0[YNdE+=@DJĔͤl)aJ@f0$Dѫ;>F,ZDcK)!F&VJpZ|gյ ~duJKױFnF%l5 á5T@kG`T.CC8T˪"b WRyo(iu{<^ZXaE#:?3DڵX]AMV9ACjUlQU3 "J|9bބ))+H5! Wl v:^2=8ޠIfhG!VXJŕ|>kirSL ! p'&K# c [%Ğ%'a/*٬g"No@ݗ^/V%|cYIj`Xy%idmYeG{ ]Y|x+_+'c8'hkWJ)[+lk]%R ;@V{ +W"f"YZ#mp"micsYr%ʉYUSۆT9S_H,+%"Yn#OoU^Uk<}#LVk)kG`jK?1A#Z"a)> $5rEf7L#Ta*  )'Mo[J#)=v4U%D*n #kWk<m6j>V!goe^YReyOW^#&4?l;*V2[Y3 gK {a>EbUN3IC+dǗc*%"H&_g{ewsR ZȊH s䔹)mɬ0:@#e5u-jo*7cLd}M 'I,Rn8ew `Z% Ewn'Mdž <2niasߋYIxWb dV-܅sÐݑ9 iU]2ưdd)aOS8 <#&V }3WNZLUƪQ1A9RyUtu֦\ꅁM XE@A&7sy&*kCy@)۲JRQӓU3;)4sfdI0| 72.lRVmQe5O}JS gQ` ljЈ|hצHJ#e_kXWh J-A&mdJ"1! 9$nT2Sn %~V02ÔJRj$y:H*5b;f AXI\wJ%Mi тF(aKrMWO5"Kl ΪֶZ n&B +yHYP=^[dWi<>7Ad+*%#OH%H- pZ82Eoi3KiZ#JopH m{M],F ^&ujQ#Z(KfNHl Jg銐 ӖđY/k*2d8THø^a NJ&yHirk̈́^UCd'4f\LêڝZjX*ղobw?lНUH_ [F0LVJU7fEH5$qYk%V2v5J axh 扵Q kAiUE,l1W~rFpPdԭJ?z$<u[&lgTT6{X #ju] FLl]i{m>xr ]TdEӶ1X##54.JcԲ諢_bSJ!MR ,(aҼ+UkG~ܼͥ#ױ.X GRт6}sZ_pJb4Z=^Pm$enjJwuZ(Qҫ-01%RHY<`iDb< gByY{VN䌧5~OEpnB["dj%4_Sؕ-i@̲b)#ˎ~D2)H9|O@d4U^'1ug)+erz+[ +/ meV;Tl[_aMz"yhʡ2\-8g)ۦ5YZ}YnE2۔j,rVe0gVa!HF喧cf;B.M'ڪ{V>+dVA/69m&Cv-l涭6۾M1 zuZX3mWl+eX j;s<MLWhAv!& 2\9P2'p.41NX`g&ց*&Lc%|h84 *AH4dE&x *"e++>eߎmk+xkUY_&ggtJh*k>q"] ,t=G[ڨ!bPmO!Y(7.4GUn['1#};r{kYS /J4R"+ꕧm:r':{xl_,XJ,dV=|q}V~L@aY0UX *zƨ1;m֢I`5^_,e[LgnvjBLfJC &pQZdkg6vC¹ xnK\m%U% ͛+6F;&T<10ఈ|kl#Y|r>4_MiX D> oCP0a0=ns?F/Kۨ^ zBKѲ` +\ ޷$ʭJA@j5j4xߧR95UR-,!2T01lQζb C`[ "zIc00Y- {gydhV*Ԩ'tu_s.ܶV=pVVHnWi Ev둒g67<9Jy*JքzǔjUew @T-PCi F#HC`&њF{#$-olo }ma+۴E*I3 0,q&P1ZUƇJJ0̓!R-e0s߁"mc sPh%= n hV&/TC*#5zZy"@ʧm ާReᲑmi8AVpCtr6pJJpҭ}˕ k OVXƠq 3̭RZ[m+oW%Ndh0[I>LlNLm&qd-,k;^Kh֝]k̭p3m=@)PN-_J6w.8CSb8R ԑlZѫƜ&iHUC_ " qŰX!MTIHaVJO Xڶ'h(XUڨRF/(&h[@Zp]xǷ}9x |XM)z aLn=;% ƶv6Yd8=7J/P,2Y(!-Yy+ -Ymbdtب=D`#eK[>;ST) 4L h8Ə-{ဵmȺkDÄij%Q(`ѪbFv EjlUkCR d3 ChORnLJebn;A:x4!S[;-Pr`H6C%ç6R;Y/kٶR401ֵlig[Y`&LddlKȭ )gŎdO9. mJ_M.9^.k XQZaO0T2@d l[aC8Kբ*szppG00L&Bz~iבĖx*LbT+%`%|zFɔ4=ST% dbơXPֈi~ۿSGl m໊@Нa ӨK5`Rڶƶjje+E|_jv 7ЏKd%zT@iLCfӈ7-`m@ TGvb qk>od$}.dzb>d?؉0HUH)! }V4{][ )7F@ŷMFH%dVQ6=CLnիO)-[q V#6X]E:}; 3oTH@l<bbJ&Vr?|GWbuFku_womaMZKTL0V 5ေU,52L$ZUd'&|RZmho, MI\PXl@9YfVlN'pcDonZm0TCWH:2L8fr^ %l/³eto.s6%`"Q%B #ʖ,@V Wp4w`rusPJ5X&@%"Y+li{ A Ad=._)jϥ4Gi˪*]|ZP ۮj%,4j<?!r<Ƴ jېpUMkX&L<4AWmkβjAm oLl iUHP6f$  ch~4,Rr HƷUbj YfM9<ɔ}&Ffbeh+JY5[_M`t UĊP IH.eBUVJf?CoG #8::mU&P*f|)++9UW Uj&q^ua[Hs^`)ѮB-z~"[E>Km˖!M˄1(:ݼ,*&QVp|ݭRw3l6~~zR*7m)D"=xjdK:>{gf^r4Hܨ#u9k$'=X cJF&&k&A̫LD PR/N?++JUc+9`U¤rm'n3%ۉ,vqxNG4isOiR ٕa<&JԥHWM6Ɣ`~Zio65B¢ ;̈́{'4n2M)OIuaE#,F*4G*e#U_”jEVa;ʭ=S)V 5s˰ӧV qV5-YcdCY+ե@Tdk%O=_g|[IUZfʮx]&xmdF;- (K4D 0cU>Rgں53[layN+W"ND&4VPΐsOMଜFVVpD]*HCK +VnE/i t3F QV<QtU_;UnUBRZMx=AYX# W$LlcGq5MsQk3#6d=aHb-:Eo$duCǶ%B0U01rJ[ (Vuٺc*;Zn^r[!$R p&MVG>ڵ֨MLa/IPM-Ok,bnjxH n>NoE09BJ-L+HU~ZUIi$0My*mY #2^ =Fk@mOp6`?<[4 ke3Dk2qWGV֢ʥDc6 6a`Vzxa1Sk RfO;<%sc;Oڎ kV()3J M;;N\3)c<{q3mDHYy2̇ g7r0|=yvUMx֪8 הT*mM+T%O6xĞԺT $AXJƔV*!1Ɩ%1IϥZSeBӍ ZG@Prd_jd'׋*ad LVk/3PP55tU5OjAJ 7fxn>MX=V6tC+r}e:ebEӚVt=H} v4;s)ͣĖ@V0`uRp[z)iTd'&Zei蛤ژ(1B[o8,t" i%h8݉0${ײT%ѷr5j NZ>ls* e ʊ™`fg"Jc* @!ԥK# C{yL+%gU2oͰ5gJ^ L-:5)3mA_yjWrD7 %ĆՐH z1ߺ8O3ՒTφyC(]4,m9~ {Tx$@GkO#U<7EgRhfV ,T~;;GKu[]!5Uy7L+1TP1֔u4б*'Oxm&VpnrnTԾ//w #;Q( 9_q(QU7O>VLzR]~3kQ;&͹Fֶd{ʙV)/sVn}xCٝ+,bI6<fg22jm4JVۭU|#eX4aEwk0% Աs*PI!6?L4]-`q}/U556 iLX_2kPlZ"{ ie"Vt{ֲd_![Qmoo eW);8b4uE3tQ i5I*IiUm+3-m3:#O TTk)J5@VjH al=nJѓ"V4uOЄ9moJMb~<᫲al;/A?U%DǴxWZ+j7zY((ۖ Kꎤc>!b,>=wd3*BQ=X S A@J$,jMP_^U)Eu^Fʆ"g9jR'qRg[iRVKoY[E;y[;QmQY0f `Z?^Ou: ۆIsEɜ>}!~;fΘf@ݨpk`3TV4eusWMc+ː؊i AY6n =Z >rô7rZi)a'D'>Z;Nh\{a#URң4qʭĕTUk0^za&BPEge9$ɪ!1;vnB%_C"(k'Xw.oŹhRS-zvYFMޛS׈̼9hgom1UcXRgT%ӝy㑕3L<ƶi=zkdz{vR.Ej|UV/DTRȮ6[kASb= 1ed *hX1+$ ke8mU~Znnxd|쫉FVP"9nˇF@CZ1EJFl,&NOS0)FcYbl 6R:m Ͱrgd) L/zV2Rd0J`]TB\U7xFRZh{|/fbM%[bZd6F+ԽsqPJs 2ϙO&9ФAV X]Lnϕ6nؚRGwr!)uw(U|R^ĕ#L&g;]CbU4@VٽdR `eRݳ^[G,p[%I\Eo;L} PJTnT!2!h LhZ [nXSqL.0"fRBQ2'D^sow ax#5=yK)M$xk}14#[;lmDFܹ*c6a PZF68 u< iDc`AӪ牋$*<՜n/lVۂsUB"g}J-M$P+D;|X;bX1|.Դ1fU iDYIp36O| Z?= < O lպ̦a`F Ka|l --@Y:"iJ֍6}8q)LF9:ҬDôV͚yVV'uV|01)s?麿H2bbMĖ-fUByN_0fs0E" [m5ټ&H 1YnCߖH/aUy2lVU! &Fw7L:ڙw" R@3&FU S [:{/H{,H RmW>iuJppds$D&PkNl9'uF>ꐘCɤ#w Z1lmZ mlNӔNHɹܜdkJlʟ2۽!d| uٵ4*2}Zm*0Pe5CMS H,sj];*HkC10sDd i0)FBHޖR#3ǺF;YI7 Pd4 7%U4 j.YG4 ڪ_wjnYyy$b-WdPKUhLmHYw)j3i22lm8rܜ*Zk)CV a+O̹FymγEmq5`_#Z&=[Zp0^GGR0@.\} 40)g[W*[F!LB<yN|7^.Qr|#Xaz[C z+vw&G]mJGJm`yx[#Jއ<OmzȬJa9!0 zQnVT  D)m)aX#a{G;kLZɬ2D U"n&0E΍Pl}&VYPU/[(1V۔V[TDF@IDAT)<BJIΕdK>22CB6r%-uR/,BkVo<; *7L_r[ iK&dՅ7kmx+R!V+jx◪Djy\ e;+\8fZB* LOك٪Nw gĬm iDVіnxR ՝ʶk*AcMnKM`]j@9`뢪W]KE>2R ,MSY>ȶڊ 1?[&'ZEJǬ)XGy+bS3PHM4Nz;4j}cXm48[ rv-غ^`: ^jV =)0i T}MKm߮oɓ,1rG.P%)PVɹBm8T$ x<iU 87 uD-5@|"{+M3[ X_>Cܖ>7ELJ0-PznQmfk4X{ &+#K̡vmھQ!@]5I}~'JͤTke[%KPr74)qHvugɹ, M#O5 :6-O! ;,MkKSHhm(kQ^b<m>_w O?ߓqd%k f 9TV͜FmUH 7*ɮ:iYUߖSԅC~>NU+.*3dKiȺWRliB ܄]5%(2vodJ16X2<2,X~-L+a1#k%Yy/i )L9K #P) d躈s69OYzdkpjTup }G~V.b4R.,P)֐#ƿmw >qO V^0 f0n|H2{LAH^VֆR6נ u,*nHyQU!>%m<ݖfhV/>YnO?vEyf Hw*jznmF%RI3 k Uvi0m|v gw44y>j0MLaLֶLmaV9-RUm̜3Ju ֢.1.kѻ㮔PZ.@b̹Xy@L0Qj'T5*V*=.JȇeAv|S|e+hkml&69dnKc)T4j>yd**q oZ(q(1EU1# V0U֝opwaWG{r#蟄yfH@ܚ!,EOSnk7{JDG<{Kjk]Uv|#rƝ) 0ouAvw ̀HlHnI`#xS &C 70cb>VB` ;`b]#0d>gD+պ تAt1LzՂƉ0}Ͷ5gz-DB: 7bBIC%[wdutl^.+cG QRlgz3}p5#|{5"z1̤Ph{ PvGDYcdÉmwxIuM썴Jlhf1B*܍I.`Uls &ZTs8#{EZ>w g@$qlK FHze޶U%!+⼫2a+ȔvF)F50+ϳ69TB ViHVCb1uEdƆʤDU$ }/.m^o8 Ⱥ#c׶) 0zՈL(!s]#~@ |-BR17}oG61@ {]h0ַi[<ڛVVdVYf+%*qdLZ+ 䣄Bd)[QaaL<5ǹַ=T`0d>HoVJي:v('-[(dbD=<di/ D&۩) T8dRspPJDAfFnTb%4jJ}*4-z%j$EMxp-nέ,MU Ӊ4u" H& _6xOۆjJE)dRBdI[dV<}8>R"5ZbU.c[En;`BrR ,@2KlmZ ð|~G_D:qs*:vU.kQV-`,m9eKL J 7z'Ccj䆏iH3 bд 8**X;zdr0+P&Φ*LVd~g:ZB&&8Eƪ$h ilghM9TJUw$[OL!x@}ʦ0$`$ܬ"#ɬx'VԋImalK /cUJ!Yj*kV7 Lp3ÚZu$F fh[6^m4!`V B9R_oK֨ edr>t.\`xV m`4SO".y4YV"C|$n?3cEUwzJ@UkubX5R[zO' cKf+*w@1Uy8zd5;o-k2)'.J Z]`-<g%0Ҫja+K!9j o;*|m*Zw9wbmGvݻĻa2M =Am!t^%fx$ TLg%ЈLҤrɾJb(|bl;q݀ 690lLz̿ Ȇ"L0@jϤ{N]kjtp]lbٰ&?نd 8)Ꭹ (%Lft!3Ic-K{1r@mM5ʪA/w CF$Ml%eGQ\jST{J#J jMSVǁ93VOϿaAȭRdY  /Fm&m0ń}+ﱮɐjYe3RH>z4:"# jTzaY_J#y xk}5Rzqfe 4+H0Y8-Oa17[i=*lە7|גm'Rvr_XȄ@tfPՅ64F4ɻmfB)dHSL:Y&C/V|䜹u) qK`w* ߄vW)!0h -d el3 1%,4x mW_MɼTfմrU3&2KuLP$I+o$JU0y-Kl|b^=$K`e%6azIf`4,OL V$p~ wͩoE)+% vgUgܫ P^Un%%`JC)^"Si/~?fSrND^?ķ=i|V @^e%YJ붦 9#'0ynsq]fZX[wت2*W+ʓa9!C2͐yOl[!s] 3%4= DyCVb c:2D2IIMiYLΕUWR V@ZvYja]iw`&!R]CPmp#ي^BtyV[_YB,4%Vg2;籸A?Evi=VFdMҊ!E> '@*w4{J)阔B$bemB>xE3'@__[p/qgWI`3 Ui$TeNo֔3PO 0M` /e涎I+Dm\a H܄j`y|:Z{+ L5~[7ɭ>O_!:%d̖C]mjNο 4;\mήޘ nP)S4n3` odwhmϊF,u+>x$ X1}05d+?27LWD\ḽ$hom,2749MOF#+e*8 ;mUBP4HVijg61J4M@Vx+m& ێqcFT3ͧce4sa)@jWk 08M*&¶BJ!y5Bqc  }.Y!w8F䐹m} x$so8#h%d#LNJZ(>_+:K<&*Hd`ǐMȿr9Ħ+GSU_&KsbUHwBoſm ThI0LYS)Cks?:=Rw"q$+$HcZ8uae6o4VkL"e0[1 E/==WsJ^plB+^$^4h|*_"9 *k& )/I1F6\GdDΪΟFV V*ymkdT*'dL,[wJȔ8S:x]j&5B6 fn-=Rj:RU$FaRa/kΝB9ìCdت*,E?%,+@|90XI6&LYJ`Re1 0Fxu:qW֛óT[ 315IHÔ#F*VmxFIJ*R d]NTV@6Ϝm{( cx7=2xI9[ u\SFD4gޔ Sjd3 H ati*DRÁaUm[|SYםFVH)x`[J똬Z\[ءP2RVRVgLP#;~|BG`LT4B"e2k*)KYW vuH:U4`\ ;܈ 퇓JMa)svFpME{↱JYe:Uɹ+x)uE 4WYJU 6^FBV;CbJ*Il3Qb{KO8 o])u!ƗqlV ?o2#T׶J<;EͬׯNB.2c^q4RH[Jd}ت% TIшZ6gZJ 7$^RvhTrQAS"L": V6f `zLV43+WHr0je1ig`P #WS|7o$`Ȥ:HMS*\SX՚v: %&L1چs#1p1 l|y@x|1pJnv}R,`!+[1mܧrY!OhAF 5mI6ki 6%HYͰU-w!:fHQFvV*Ndux]h0:fߜ UȐ^.f[zj;u 3slZc;^8Ji !kvfJe[Ep\8v`x#lUi_k4rI୲iM*Ȭfd7h襚ޜn,shωlcdO[_+r$YnN0]Lf`lu`dS* Tua.+ O KV ưW.C$0V2ͣ<}/b(EHHߊO Und O R^WV rz5F&[ODʨ4ܔ"gHC9ORĝFd"jxZR~-%dN/!#eHDv'l[Usg!0*ٙN<4iHm9{ʎFI"]REU!H}ֱId'{lid1zuFL kmgVE#+ށemX-m lm 4 VɜN m bsUIU]Td֥9{r %gE K ;@C+JMa\ @׉U&™l{Fj DGX X! M!040%J[MUYɐ v+mf NJpZɬ4 ^V )1aeg274x?Z&\; )B~g*+eۭe $&I05CP416vj#\}Vx40}SOC䠵r-aڊh4j";i4V굒?/&F¯0Gڒi:ٚj+"gU_`7rX/NGr[%ֲȵI洒I!;iM1]22@4dBjiP\4s9s!PR!w_n$=F8Z`d7y vmdknFF}m`kW  ʁ9PS2&Rݡat5eeOe:\I "z lR"\YcT U[uқsR Ώj"ѯb`DR5 77M@x&mUe,+k|SSkA,U >N0qBxV 1л A?+W"RLvo2AkndlRuDV|t?_-7ќZ*8}VByQv LٶJ+JSv`x&s^ l \y7\2q U;E>FZX9TPIPZa.'r@*kE)C5THf2/G)J<0J6C76V`J4}ߘwc93s>qcV>K iUUY i5a:li3'svHW*[ g%C% a)yRCu `)%4E2j0meMv]z)R`cؖI+gQUXU(Z1f,T YODv$T}"X2$K*KZ4muT!ileS# &*4RU498`L3zZA{RI3kA#TaR‘WwiX2\KY{ȢZ+oTx ? 2o~rIl]#)UX aiĥ0}:YMoLoRv|Y]TnX25EUabQ;+ 5+Qy|]LSS&E>V<tLkfg[H$̪Zea_ͲHmUmF_9oH }UY)ٚ Fd #*Q%C9 Lri, oSǶ& +@4yW(R Fq>MWRV7czɓY*xڮΖI3( Ȋ3T/\-ώ֐ZVȚ\1PLd! arLj( *a V"O*LkUpb8dGMEnll5;F61% ka$2(lt.>`xAiMPjwB&_Wq3DI$@הUulNkNF6[Y~&dm{4  YhLJ`oKHwΈ+?RìgP&W5VJ)V8N”ɬ,LRl+lnRSF6-v[)kVx&]K({-"[aV"[[rmrF>pJꂡEaXdVmRR#F2TeFVױ,,jm+TʁFjmء:WKA.F"ap!ջ'~ˡPSKmp^ԦI@O0qxczωwu)|zcz:^J [p̑B:igIfe im3Fd:7֑_|;`sZ))bؒ L#tG^˳ MgKmȿ}2@l@SU>cd mn6CeSLpÈƯ0@?{R։ӯ Hd%Eb\fa@׬jjZ!mM;*z+ƺ:ZMۋA9%RYf8nG4 j&ФXs[xcx)kGT}Ua jӈVW hZ`&HIم2 dn^])ͿYIն9K 4L~FTA #֎l<ϞKURN*+r5V29Eskz֦>-x6f%–~`R~s4V!-L+zR jgD +SJa;vV[Vt-Rp4.u)#۸>l H,G֪3v@۝0=[[!1F PX1Jl-U!  UGST*RVJTC,ɖ3LoQpb \!Yw7$qs:.'g+)" >pcs77ZXm_Ы^_R&4lo|fJlLk훧^1!c$6@W`柭nLT=3^/%"2mȲM:  ԈX )|_5_ Op_AyU}_1tXV͸gd]HJR3Yk SZ(_l̵Шe놑BtpLC h + +Il~[JXiV>TDaNakMcFܐ,y?[Y[ BI@!r*𢇂tV[E%Vd,d-=&Y)ζ0@YR%H /__=>? [QcE$<1Ldn@IMY/)Yl~2|Y+ƼSy۲k7 , H&&EFd fہ IBfhibI=cy"CcgniŴv`"gW bT5m7_ĚL0Uf(ML,\ 7 g: % :"׺Z* xn}Gò񵆑N7%BlEF#_g$n XE3߰%;_;mM>AUcPʧ75:uR*YJd xiZlN!@xfp6R(ʇhڷ:LZG)_Ux+h$J}$P g?=2eMM6XmUSH)1>?t, iQ&+V@(T']&'dRd"F#[qܿD2Ij$ML1 `?*̈́S(`B@ zbvzbzA\Vy~Ie -x=J[>IlmUan.$C/Z1MF6[ey 1FJ`Yg Q>9TD8AbZױ2$SkdUma[ɡ, Y!}םTe &wbwHR|lHV2 ;H23?אພ%ƚ@I&kIU43eT,+2RjkW%`ڔ5UE`[Z7F3N,ak W[SXT(K[UNcpv3jF)2N3մ"Ym䌪3#@^b)5nr_e+'\;>^?/0)lr<>l71eU@>Ɇ;-`;z"z9> ŚH%1EX8% l1HOEۮKݠc͟q'=0u1 T] \*X @/nNg.^~7bܚ Pl[-%h&J@ɝI|hʿH96g29%i]VHZnjm,%9@V ^~V c׿.'gnBjY}6}49#m"k@Slab0mmɄ,t0k9٪<>t0U.*KP 0,+E ܬT粭BS!s˿F *->SCT ٨Rd#꾱RZ44rY؜:<&O餔@wi<; |z_%^q_~Yu6֒zͪWgz֪U1v 14 )l0fl"_\!>1/.r)X"Ɩ#5a"{)NTd3wRڳ6*Y3[F!E*j eNsٔ>f [I@#fN,D)}yUUU"S/FRrC>767Z@#Uyb+ HAwzHרL!1)^*UVL3)5>1 fcH#K<4JɭZئTZ/%@/~%4|<4Z( 'pzL4n(MeYL9ȶm6[bLc&Z;5M&lMaVXaQ)r0rᵭuxAV6ATO{c޴u䀯K[fg hV^{kYIU%UgI Xu֫=RV[z.-@ J Sx8hlޖTS2>8v~#1Vb[ UqN:TwXa=ݿr)՞ǴWRf WKad)@ z.bSJLȶ zfP(b1%X-0ւ@6Ak%M~:&^/J۞T7iTbUEoKXAFujiXIwY ek`a@$&ď^9E4MLD%DBz4ZeEl9_– @%U"EU1u F6f2R0T*)5}~lŐ)Yл28+MsMŖU|9"&y*X#mQNNa QB4jd YUlɌWoQ:@ Dja=97s`|ւ^soT%"'uR^J!2 gBGVb'SyRZAAτU*~JOpn}_NjYWik)KuWyVH8Ok@GPUJt]hr|jWIRdVWmJSa%ɬe˜ vW @IDATeH9^X19xb+ƺ.})1*R*]|:iK4$[;YzRxL#ʱRb]Ye‹Y 콒 ܶZ'^yі yZχi[i*Yn cWyەRGS] Wwj ۮBlU 4m 1SV$:69j$^?u 1`Aj @aon Gǧv4u޼@3#ܸvBªV ks akPhk_v2}E;-Л=%OʻM(boRPIN/804CJqb:V_)ZTlka)xER5RDLn9#Ⱥ.텅3vj똹o˪JlGwLRV0VXg Ӕo0[" [`&rR)X:Ҷ1l7g"n4VoAbƨHUiLNREi3TM`*4dHpEmޟa?[E<f83Jt9FIi59C)1; @IHh*YYilks5$1A)cc[ӦfUǹ9Ȅ&'K&W^FE9AAIOc`H%rݥ\ZYpcRV*lOhZ  +2)2NSyk@Q†,@J'z;U_wdntf4WLI Ri/0L>LO }#u e1O_VVUdb%S5=L <߫`4e1?^ɰǑqJ+mL+ 1J6MGAM13Ƈ* ۀem PIJv{ 17y%.JanRFJl-Pbۣ'{j]6JhȮ@.(![ }OIwSx~kiHJrbIg9\`M;?}>jA$xnZt>" mbZ#М暈U8+2Mm1Mϧ9:@U%[Yig+dʶZv r07ղ0Ճj$(mǐB9FɈVJdsYYEJ2G6adi R U"[CYuQSI5ZTK10g]Dz&uuByrP(dYΈ#kLV.HGwv$[>dNaۉ:;})@*Hk2gaXY)UI_lя9xuVִU-q1ixtϖ *u&uekB9Џ" PE$c jx#8L"c9bttܿ8>w!k` CƖO`]%:*xsƇkaY 'Ɠg1JtIY/;T>c*aA Cq8;aW;QB&J"Qm)y4x[S&J))dbY dFfowQ0*tnkeNйr#h+X̶16UFT-[!̭/Wʵs," ZW5Т, 2RR Zx:iz>8/PCt:bRfK]Uqäш )aksb({^zi* M^kY`lm-l+6Y%VGwsFƠ4VJP`VG4+U (W?[J3C]lBzԎ&OA6C*G(k+' o=vWhHؑmk%Lmݰު{d E2J:~ &zWaq_ C?gW2aNQVm-Zi< F5rh)VMHf!4@ ӗGqHbat)0Zv d OLӄW~ߕC-[Ƥ-`z|Py`–091.)p\5VAn:;Y%RNnSL#=h2u+sI:ҬM i TU6%CJ}7ęT s1H/dH V94 a+AMVBR$ˤSHKՈo,f<[d_)R}em63CgN4 ]hg++|M >ThTrZ4gOtiHXsMۚS$C 6] P( dVTEAmDVjm@\}˦l-UZ܅5~xga&!y6+=YdZX?FeB`-O''oL:F%y0)&l*۪s2 8`wH󬁑`l1PżEV 9&rf1fnHYH]V/ikRFBV?̍i`n^&PR-M  |^xJYU_0pޤTYjZ"~3LaD:&f۟2@l\Wb&^mK5L2C`PkLunOmUh];U5,nkI'+4ٴRx$ge׿ӎQ1ĺ.-Ֆ?Rvc-t"n״d,ln^XҗJoKP @H` .y06u]Q9s7g_/O^0ObTjS`&֗8x_(EdB!`ƨйlj}ämTE})uU}I k֝ԚHce1ʚN1=!;37UVädXU! 4$B 3$8ߠ6*OOVLj7*Flk.m]5Y3צ+E)g☙:RE֪|[W<. ;,`&1 dh6|PK\J+m𙇕TIF{74b:xjmd֚PkfbR3ҥP9?/P3+YeH^Ig4uMir1hUwEmM/UaLT6@,T Io-xXlɼoE d [da֋[QaxJj Dg $r,=%V<C@dCa3UQ@m6pns0,ΕgJ8Wa•Ki$]TcSs"@vZ<&Q @#Z×;db ́ ߏz{Q10#0ol>ʚ)" ;NJD,(W 1511dH6!6ƪ 7^[D+A Lo}#5'[m @P na[{:JdyLw$F)eULxz]l h;Z#DӜ7ZTh ;UmCfQҺֹ5,]dR$XHY3X*hlNYzU'*2A Jl@Er`³P6&[-JV ISYe~+N#^$ʬxsFo~Jr1j]w<=FۖA6U61нV.p$FJ!^m2y+IM 8@*)uWplM) 3#w:d&VMvR֫" wFmr SR;B&)EZܺ7:~+8}dw )@}Ӓ`.՜)'kFd  zsPvTՕ@rW  :%Xn)4HRjEVjjJ:uiB[1lhMhV)TB]l%j aMd0'V(Y bQ9rd *+7 KlcUnkN-W c-}Ֆlx@|oi{5bt-`ۅPUf.0~R% M`m~#eMjksHY_)[ˏLDm|2OAlĪ0jm\/2FL0?q]BƣVa爡mJ-M+(6!0juǫza* IAbϭ.֬ v_9LSZTZ^x)էI7-wj1ۂIl Y[A{3Mlk*@3tH2M;nF6Qik<\h>EJȬ|(a)X%[$Xw̧^r7CC [s%3maۓ$Pi V!P9 JVVklB3 mKaP֪BYR(I/k Ɂiu$H4 I-LB,ֺ.])=qJ q%HlEn L&nJؚ o+_CnJXmcVV Yix|d3m&Sx^*>  pgYG iR2t|0i d}>)d㹵͜ #L (ee2-gq[`D1]1OXC~IS_<|HPHYc!6a"JVY3!mc6}2~Fa+CJQ0֙cn&k̫wnP DphlVp f\0L,H?FS-l0MM5S@lUJaxC;gPe;l:hl i:@3g*O|Lfh|݊/Hk6R*kdu4H EAj2HHqnZu{ȪF+97a7 %hR@<)O R`\oڔ#ЅlT$1 OiMcU" Mj9CCG,`EgTUaݒ(}4.T}砜,2Zg{3wQq:HqeA0 TĶ,cl[XY$@|'"!e!/No;%>4j]ftR4vR44 ٪u|-rVdi |Md$1b&V;镃 *ΐ:WJ@lh~l:'ѸVpLo& A,]Bndy"ysdB֚OJ&T.+L9(RV2%~dKIP *6auSZ fnTѿ啌^;vb0uIabzȍ隍!7J1 sz#PaVֽh:7ͬP- |Q-Fm Y-lO`*Yd&89Sb"O/w }8/Y)nF?nڙ|R^ +hX#GنLMUI2L)%xRqƓYZK{ 0XJ߶@JkpЈ?BtJJa*R PXp\ 2JVRy:SaY_B[ٌ|E@tjfa@ڞ鮸#d)ò f՗0j+jQ!C Ɩ-@6[3)>/$Mz2[v#{tJ%7毖!1Т.y#KsBo6AU@Bv`K\k9 > }=1䶞HnRJakYnVVL)I5o &^;Bc줝@YC/>x+2ܖy m&̙&&^ &tL0wdE%`&m$^hxV!-9}54C*Ysa;rFXmkY*$%l۶P$&Bgw ~- F6xAf%.w4X)nf^aNU͠V- Ja[%96zri7֜,O1²0IE0ikHU "7 r" e)_204dY<+0Ix|Ԣq )`Y~l0ޭ"ʐl3µVh0)em🉬- 4`HL !*~nxJiRk$d1V낡):F68 9܉~ekOm%>;NTlڈJ@0yqUsh|oқ.ZzJJ#+.8U#j&+I 읂`'m:0VQIV2rld[+o[|5'*l`X61 )[ f[tQdj{|R"sB~ib !_ )2F@[zctÉ9z 1 d_ad+a^NVxfk ϧZf% Zt:H!#a($׀;B[%'ȡQГ1' `A; SQVBV0gE 6U  gvcˇ&[5>K9T pˊ@Sq6K bjwtt9nS+xM{MIMIȬZτ[bvX;EZk6l-1#0Rݹ& fv:P%4U)x0sQt9KٚbZm1[s.*1 ~wJMUw[VHQUb)za[+ X_?DAQe.]RdV aL|c7 T0δ5%DUL*[|6B܀rC>V|8Y@/ПLTQvdCx6ծ6[υKSX-Aa3%@c4'*ն ClB+?=nHOd%F`r[QkPɘ4S DVj+:~cV R4V%THpr ٣iF%jU+쪉K YaeSR_._Mȡ aYʭ*\SU ޖm)n̖lm :2 05-7aېɬRR#ielYI ci^Mni|օazV1$ `XkLWPXV90)L}säds?0sZ֚2WP`dw!j3Fv 2ׂn`mu;2BF1 ހ,GkYYuU 1rі[3^*)a+K/+8~L+7S)RBIfAcXM ksj:`%&T5qMK4U.]ڪJUd.DžHu |}b|lŏZo ޏ^%O/@nVfuKVKل%V., ;B4IJZFJAlɪC62 `. mzY[~%;B lJ@O;څ+)$=zCU+^L,Uԥ+gkYm@VxyFb2$򞩭,=#V. ڬ2oxX* WD\s! @Vde{߬JjU 5BVuV[ iL&+6p4@ak#6)ZWIЖLcU+‰Ⱥl1=z$[͓CmJ՚~w9FZƝZmcDWl'Ʉ0JV.Ok_wi2Pwoae(,05U! #1d %i`UqFRKeNX{m++$( VC-U *0PMc%jZG:^\'h )d풭P rJf`J?V^ܬRUayvRJ|.>rzBaW S$jl0C ZpC "iTu.+~Fs`^ p[R `\5PBtLA*C0yHSud[Zw{X l 4JVSYcT9, c0@ ύ AYܒ y&ڶFj!rk \jez! hr˿IPm/*$p[o*b Oc{TbXqȊNgؕMEH;F4)}lcn, kS6 kYl j%m:Q~O8dE#`E 2"mw$ ȶ\xms.EߨpUܟs+FVeqØֶ1O[)s 쇑P%hjn[՚:a=lEʒYCPZbX9^1Oƶu'R1l1uIYOIkCZkD9FVHHY^%Bf;D Ver[IJzU007&rƃ'H#Q`}mss3qjE?T56Pպ&؜5U v+wKH[>iUhK -D̶J0TN#=su0]2%tp0U(ۚ'02޶ V@ E 48v"WXx#mJ$AVb+[k7̊* ^`T5^lζl||@Y237$Z~am2yOAkGք=&[M*a"VΪmVRL',]/>V t:V/3TLhl;KM镬[XmMREX״KE'`UB@,4 WkMSV긭l,sLS@%B_Ynpkq+ŭ; H EBY{דZA MV>=Qe5C]dabp%͖8|"7Vn=,}@G#ªZͷ=!GCr-RU ,/m*ծYuTŎ9* '48s~rٶ*JɀcbJf+͜_H 0B9F襑-PIYrⲶla WUg]» `@Ddy;aJ ô]Gog+<k ZU;]\maɬ0[%GwZ9$׊Gv-=J2~G8U* + 4xѨj1&u ry_  49J|Z*+OW@Gh^8)Q9=!_˴4SpC }1ICf$c@vdCTv DXR c$L0nfL8+1ILLI Y u~'K [sy5FՎ0`a*8=ЍŰq1 `**Lp zaʖIfBȰSK5æBy+@qgBbeHU"@l͖Z#e(D֪c(,\&o 9Bj=&Zg CY9=Q((a$mOqlJ0ЂrbmH[i4r8{9Y VK9NW:V97mcX/49ة)ŕ|~*Kzܿ )z9?Cn<+XFĭrnÀF]5Mx뾧=)2%Qbp%|lcDy  m);\VLTzbkjEi68vaPKdd$lU(Jd1r) =J'0a^Vлƶ$`UZ`;! pX6= 9#s~?H [ D=E&g*# PoM`󮇖 h*1>+4I'`U ՅIgAfK\>s7 K?>Mo!{U!`ՂLfEy}u gm1;K9g?fc5RkDήX/id5=.p.0pbSզJ R! 揤i`OJ+B3dٚ.d k!u!׿een(Ĕ ?d:޺LU)XǤDjZVjhR )65+ +d!kߢ~^ԬLR̜)H < @`1#EAƤlz2ƺ@bFI3.բFb&vziNÈgLΡieU+M LDGga+,%dlSrhJ㭶10+X4l iպU[ k Lpưni/T_zxVC`5RvgԢK/orrn0Y6 TX/Xa)dTE 70^`KL(i%Ybp])kg& ά`(9ȖfUH5;ynL4VnJqOWmaAL1NiU[1^+@ř~:Q[tWV8PV` "Tk<9}U$S6Rz[aB 0gf"aIxzh'g{-R0RG#VသTQ}vh-Q>FJ_]jib:{dl&(ۀ^@ Z 6U'X!^wOs﯒Hy0@Q p2YwDJ@Rފ)8pQ]*wud~~e?hW6>a |Lm(S],=sήd'!kY'0ZƛnD</x=,rk(@0p㴤Z4(Y3'dN=l Ta,9PѠ x2 ,F1}&Bc]JݿeDLw!Phi>LKI0 ,[)L`5ݨ̐[X)3E Ll tۜ@>zta yK"!=^{ lɊёRW5W\ t=f|We$E9+i6@DRJ9ȂL1tyJx$%`aM|'OΓ{Bg o72z/hnd4mn>o ]?l.Ao nӆFw:/+(77䣗O#iiHu1(#rU+  P9ّ+|6doȖw4Y\q^i%@fb LAH_d?Zr{wוI&ѶULkd._啺&ylz-1nj+\ljtuu541tYR>JXϔyySRڐ OL#Q$h7]+bX*UQ9Ԩ-9$12O<+m gF0gell~ 8׸3Ղޖ'M6 .jk1d)U9jЂۧc27JL#ґQc&1d_ы4cOpHA}@IDAT7&zCnW% o Τ*Fy l.OX{)[ SU#fH\u7?STα گa#i2kcDXDO62]a%YUazaɾp;`dA/r?徑JmN f/F^O CSd$ hn.S(ɔ[XBړ"-#Ълk-H֒C? H/!c f5Ī-& JUG&@[KntI XUvP8԰J[]5@ZK|ld/OPY&J䂸 v/jrGPE:}Xܶ!,|oЕ^R |z-c@bJ>,bh0g_h#ۇ2 lJn̕Ue3[bA,cOyO =eLIF俇ַѱ NjIxl ,نVr]RzkU%jwA*>v=KL d}l3o [Jb%Eb @*j!沒0B0Ģ;Cܣ&Nh!Pʤql6127X82^L@C}o}CoH+caytyCS]Īvolߠ2R/yԇh824]ѪݥliDr;ӫ◁<091,IvGOw X MBk%A0 W,MA57ڏ c2ajvk(!Esi@Vްe} ۪'`UA  |a>)"1(f%F#0P"Rn=>aAj#&6+Y$4 GYR2)4d2[%jJjo@nS)4L0}i@șPGO\E.9.Aby o_aۆ[kfU)RKAO(ta 1MbΘ#>xZf>cs^O wL+M0x#`{4 n:]r@#XoDR "J9]^y2CGX6E)}%6qaUqgn$F5F2ᶞ`1}U1) d Wv>MU9O&/kDe$J$^`DG@'eYFd5h`Kjv֢2z ܜ)8::"yflmJI;bsnn&p&s8'h#Lr0E,o12L`1L u õ&d]ynƵm<<}w˧4kV֫YHGnw7vlY~vЂ~(te[e5_w V8}(& ^Iy:##P&:'h P6K$f^HG `14"7%zMeϤ \JiF+tZcJ~[FG@&YLܱd+҇UXEk0&:ܪʛA5;/8g7(;lG3co3^FҐa P9'pGrWZ)%GNђ ֎@jtL6 d >4~ =,Qtk@Wi 4n{3 h[G |>B> ^oH#۰Z?``C 'KƤˑ7U1sf/ϭR'm"4;>YQkbG8 -[QU%hCT2+ ,Tk#e x- >_Rqŧibɖi h&]k2g"j"+4mt Mhץ PrZ0=%PP"4v3?rxV`h(t_)5)3vuH)T%m(azHT0 hCUnm%'uud6Aۺ Ƽ+za]9- u>G@NưtD&0JZ|lX2Cj*yx& % ˠzsOʺxwlbb%k /ߑ8ge0ÙОOɇ # a-ѫQUaPL Uu}}扬}]nA*LN@k$R[[륇3i%^ ]p&UɢĴIpT[R(Í`ŸYW;!#LMK2D4Lykhs1ò?X I{ J]`JzE19uOV\Bkw7 `\Oi (i0MݨΊ/2RAIU2ګg_ U՞o3w> җD#s5f/2rOUkqn?ʮoqJwA|E`2V=  xZF1ZIhր}ڷH}}*ed]Z^q+9t7j=+?xoD5teh<4ziT 0"\Wu(7`* >D L }WzJH?I߱ڵ8 dHD@ [Lܞ44 b`z>5X,`-u}ݴRMw&2(w',Zdn27w̤e()vJ$k ; Oзoz7RAqk}jϿ#ܧC-%8-CQb?#O20#61diJeG0#qRJ"q@^fxl>HYg&0rU>Gަ #Lq z Qj [|z@4W~>vXv`bc"t/ žq1A$xW(wH +h0pn%,;]/'.k J>?x͔3ߵ21ex]cĘ>{hZvA[C#4Jr>0NU"˹Pux5M,(G{^=iZ+4ƥt JB?^1n1|؊Hl14yaXG.b%ڵ@oA@)Te QCۚZL) P"܈ FG};v5#AnMb0bog$7%a=ר0}JʽDLaTXm)Hrʺ$dH'!ՑL82JdEX.8_J[lGܶna:FIDdv9+"9ۧk肕`Ti-p(§/+@wQ\%G|C{ L?Cv"*rG7Dy" "l:О +NYvӎiv>LM,Sv乭0lX hYE|B3 <27 4|!59Z~<\54f v[]y/Wʐ?l&*Ae ˋupC1 3%;rPo-|Uh۶Q4BHVo+KꟑwӘ'R1pa-L #`-Mdlkd=T#MH/<fi69gh6l+w1",SF;L4ѬƑZA˔݂^hlbUcܺr>w煛 H bŶgzG|>2RW17վ02^,}[sοTʡ5#+[j?X;P6tat9n^7J+v~|gכsn☽3^UoC# 9/Z&c=^ (6} g"MɶcUrnlsn#qau8ҠJ q%aa4 @ <)6D-hqRqޒUuT^Ayin6i01h0 `p7M~j C(kICo.e6iG8|fND$PqMqT(;&q,|s D]]c5H,EzJۧ. {v[28 -"YBlc Pcܫo6/9p 4me|yd<3(UaP`lki(qs[@DR}PJk$̊L/`mN"uG9$`BCEzS"e$=2#hD۲2>#H&Mz"Yt)]5)ȸɯC^_6tn]SA/>{r>k}=VlN9|ZI502AkP;sh"2q@Z?x~⟳RsG\ FP&PM:6-~՘eӷ^W xk |f4R]0}/ІRm;v0QC.V@h9mF %>HUL&jrCm߃P@bv1ɜ I#=LtMTĔbmLOih()D1 d?#r u`#Gtem4nqVdb cx&HЋG# -5~94)`2%9eV"e8߶ ި%z2fJU4l1J2\;Rh.}G$v`0&4^ipr@Q1eB^#5* 2$`WC U]U{oVb"pC.lc11ж2%A0ePaȎa&zDP$CA~]X)^MԨ>ް)g ^]Ec ")5,1LSoԅlO,!ݭ+!}eUL[shdkv97dc.χ |4W$|Ȉyf,Â`&a%D;&O > LL4P {b]b.aK *~2R J)DЪk '1gCC,ݔ-8YIo&p|FVjR4zUbF}(cHKS6Lk pH)sp;PޒzkPr4)Vj=<Ԉ9j`;}-rp+Qios~|b(a*ԥڑov Zoτx&dL0RHG>@wRcH2+A ( $PjIOq ((w|iT[c [#+G>/f)Ǵj|Lk3jnvLU1OY<}SJاy" &2Y‘QIгbksUb2%+v$&y4L1F 7#LWZ~&WFT=#C9*[˞.?ήOn~ql7}$&+YX˕DJ%)jJ@C&ue1igQbl[ 1e2kl 7CS-X 'i`L7dV>&L4aF"S6>MZZ 2X,jO6ğjSMc430Ѐ9$`6kq #zgj+DV" ($ #2ѥo k\;/RI 8hg|U)ަ+̷96oRjAºd>L2F*l9ָL2/)  ``FcZR W;EU(Gͫ>H2 P QTr w3iAz%U9> p=Ix=wmSU{VU1b혂'6hc<7 :VׅeF8xM!6}~^۶46C)J4<"Pf?ٺmSZx!R#@6mGQm@{עt2&pd^]LVڕLDi8++ )נ@$L; Hp,L V )AJ<oX hIYzVj!+[@Vu(rX F2J<kFI]! V5 qǔ}y{JL 0|4.ڛh퓡ٍ:o8&L`AGA `(iPH&hŷM3ϓr] ~]i[ U@4(+HLU" `ݑ@(OLnKj֣ڭ$~\SJ]|3wb2%@𴳣Gv?`JԜi O~M d^L@QK%Ytċ2}𕜤bU%E݇O/ ęػ3\=L&`\[DzS0]/=1gƝXI묤Jc[B3lze>l氡8>J{߹n-|ji"2 hD<2*:XI9^|~yeyݙ]@ ϓ,Ьvxm[U=8#pFdw FXLudQ{eU%>g&M/]yZmCe__f5A _o1} #a-Qh24UحEHܔ 3zb'oD]9]1AWQ>p USV22q/ x)TeViW"v,V@Ť hr1)+x0m"^1dJB+wէ>{~ynmd]JMɖ#8H-}])"&3E^M?^{ -EVՒQd0nds#6)w4\?/xSgk%vD\e>?F4|Wioӹ@: -[m@?7pL&doX7 988͒6ڊ#H@]xJ2;fUk'p =eG_ݥeEHes2 5[CF$g dځ{z|&eU$xzdJH/FNUaUb`w;$<;# j,vH4>5ea;ݎOuT2RGϪOYjCb~%W<)^ ۖF;,ioxw4]#)oI&SɎLtˑh'&#^U0>3$DZnH,6H-GJ/8)S"51]xvٶCeLŗ=8s`AU_ssЛa#WBbz)p0v㬷PJcIm¿64UnVudš`Ց^8ZLZhD J]M(+i Pܑ,q˜+018rp}6tޒ^[kDH"JuCk[ CoL]@Բ<.R9hy5-hIVo8 f*UolHG^nO@lZ:OtS9dg%Y/gmo1ٱhwd>Z^Y&톯Ioh]x#͡^uiVZNH=/C#,حuJ(Ϙj ->q8]YM4_7leadZA=/TD5d† /0H&H]JHkɭܶMIɤA0Ʊkha%ijg#̖&."R#A@rDa@ڃZ nfBR˰Uc&)9z۠ˆ4`s 8 ";%SߏRJNax(WecZ#RU;ꈁhշku) ƋK~ ұ'8牌K_oRO=]"hًY4(}R3!P7sA>_M)AT =qyAU%Z0@1MR#F4i+bcHf)Vj]=>OP2wboѻAhǽa /S f1Q&ܼ@b%-@ .oO%|9sd-~⒕,TEV@[|-tP)a3{[Z4Vq-ӆ Vb t`f%_OՓzVP#Q8}LbZIIL\/Ad3IF-l+<@"}rnju lĎJ +Cд\I/LYHVm%Ap0%Zl+&JH~Q7(KVǡ*dWxRkdr; ғ,2R6 =)ZRl97_L*;֮K{_M!] րg:ɐR4@8VSIK$%sy877B# <.dLP|EUGb 7(, čfgQ'^)Q |id-~C&{4jNRxʶLiY j^LpJ,VSEjoKPZ0`P )7+A^%܋LU  ^ jhG|>2&~>`^w/6 x]×>/p>=O.MVCUÑ zz}Tچ[γhDL2|ҥdҎpW'}2z L [>bw3z1$}&0 e]$̆ȶOĤgDV4-2[U;l+|0Y T2hmzvF7q ޹4;MF:"[ xoZz `P=>+TJFV- 2O%ᨤw$ȰYJL5G&-Oc9%=8%$&l;Fg 1a42Lv_f7\ٍoUdBɐu)&Ȟ|ud%Yd%ԘJ@?œa]drl$۪hd-V ]ّ8u, x?ݴ)ezPEq4H,\ɑҬ"Oi= 7N)+tVݑUg?l 5C@9ICJn ۜ&3,+1)dQ^Ϋ YIEY#oL7ǜC˨^p.}>,@4qJ4{-J02C A4 ԟU97nU q}s1ޒ0c%q/R53e밪gtχ>󪎍&,q|p/L$-2qnh=Z FRv}^2 2J>;x4?۶8Q#6zgt Os5O`J"[tOVtL,_?Yf)!Ʊy&H61RvHӑ?f0LV{v#h쓉RVdD8 y6.AF-g3w)28㿿aAGy+ɾM)"%Y9RppM7U}B&9#W#>ME K4{]lP|. d}]a5h$yyY"#ŽI#`=ڻɕpV퇔FM﨔Pze~ Mۖ-xx-0sS*Y?Y a&>0c4Ji s;V#0*R.@z\v x]ށ^{)0tiU}sxLnȎLj1ȓy4H&y/rC pVP1vc"JRD4+dlpߪwN# )Ө) sXLeA۪5umtS&D5wd@&gWS9ޕ}gjo>n׫[DZwJ6 kw LAkgq56j+#/4FQPMd]=@#UaK4ps$>k}0JOSƈU-WvȬKOFxz$& {rEv@:}D,emA0?f}?=uwg1Sbkjݓ2?]Z,LzyT)#`na PoRUe>4aFk>OA *715;FL- L0-+5@%\}sT&^#eO _L sKQ;Rsf$_o=^8l_{Vdr[dso2eGHڥgXF<жUYZx*U%P Pk21Wsk׭|0ZUom1K])[Gvs`Z5CtMĬWis9̇0пp,R2{ 8O@PNAbxpG&jȺ` Lor_07 -F6҈𾥔ۄ@I0@b1 }"hԢJ''Yf8@XP-(fh^c$DK2%aGYu؞a]j W)rch =y+~Z0oH/mbnT[Օk g70`?|}NW%Mz uZ)A˩E`j Ŭyaz[-49Ͽ`nǾl,괖#>SFzqK2тUHA׮m![9Yӷ|@-#Ȏe2I/cz>2]$+\*OzYQ k AUêdhjwԈw4Emyoґ&KnJ UMȴ%4H`éjx/ Ȉt] Pl"HI8ĵ#9*~0‘rp c^,&𽃭@&|m!n)$9ށ&4*R ,4 e *0}?G.}vU8&3Zt,כe,_WG a${z9ʬedkF@)Tn'`J>\p ,Jv0'^ǂRnXo-IV5?LjSW:jWrlI dJ:U׼="@HƟC)ֈt nL4*rvg;L hdaۈρw#J{J@ʎkj\{w @osӗ+cː45)N1V[{G4GA֥+5)&dVcd`_nzč<.Xk|gG0@ Uȍ 6sƴhҷg)WD*O bB_V8oůoBG YX0Qݢ_1ƍnaU@I>EΑ0 ~Cê:lb yܱe\?1´I(3 YR)w]-% `1}7}{U>ZX!sMӿĔGܱm uYla2oZ&`wlz"[F( h`<ͭ?S򪕚xFEV|q֕r6o>1L-0zO%;bg\xEwS(a>B5+ RdU;++Zg񼘎>^t=/0Qe4BcgeΤGuWn@lkq|M %$`\F;J߽7{ш'v[& iq#{^&1m!r 2 nu]?$Y{aJˎ[/cUIW-Ug[Z8K"`8j0n־9Ln\yWU1]|5%ʤ) ˑNcv7Li"AM>s%\r>mB5!^ƷJ2,["6?2M-?4)k6b82ע}{.$ wx@(/(=b wd(hDHz2cm w2]0`ˬ0އF%[\um= xldlqK yAJL 7 bU%=/0aVgG# Hُ? %sS|ZQPwL*/ir,F4S>aj"_INpfܴ^CQȣiђhkaL51G7oi;l.7`WpZ ͓LQ[ /L{΃W1]ӱj4z0Ne0'Vj-!Sb<b-ݝR(7;a0z4D@\{$OOcD^>za 1~rV ̑mq7v f5l(wnā 4Rk'@hJr&U}9"ۄ;ڧN9Y]ͪ*7*; l9MV[Yٸx{On35 Xh oYZƇK%䖡#}`PI<eȂF @drh%G%]@>dC`;XF0𚘁 ?L1 y{tNfU/s8+Z\XIcC}i5j sxcifMHf[w#"_Im$?r?UM$VrP4y<0UG{kv>ZdNmpN-lDVUn= GdM$ۍ$רF$.rMJ=FJd:L* %9O~q"{"RUbH՜}6W BrDz}JAh I`r^{D#AJ"Jj'癡*Uz3mIMm#LYΪc6Ve.$\U l"+iT5f+ Ϳ~o@Nֺg{5d}t~q|RUJ4[Uo%>fH|z TZpxw|3˳Mb+Fj~[5'AoƮݜͯىl#BUԫCjL&yf<[Ιy`h  OoU%;ar9 L<΂Cͦ PZM儇 TB v|Qs$y.%I E34JNs 948!R f3XBgN/"X^jϧDӜޫ$ܴ&LU 1+[{WM VJ @VVb<*n[>!B:FF;$>*ȓ-Њ:q*rfqZEG0!VB>!"M)UU?qB2Z䩑;Pg9cjz4_/kN?-\2DGʼm?'g3HĚB +JBRnAΧRI*VYD Y"x;/-\Rk !rZ-0%p\PA8Frc!5ʡڶ*8gHc01r$ 6U;.mq$ǍI&Lk*YD/^TYK )L#4%&$rC@"<$9~$AЬ$[3\¼I$ &YvW?jC֧1R[uSmVd g@$IVjv]7~@\B:3=\9Kk~B->B]~ƾEDf$BVҮTӜsnO$mȁ%׈vΕ;B `Ł7YU0*e~FGs@C ?n=rs Gvj Nմ85 , vUr+=++Axz4rG"ܐut3CВ*B)&pi$F dW`ifC!כ#D#or?kQ͖[DV0si㻷8Ѩ$h"uYIǘE,WEvr`k|gCFmI2lBn ![lf ^$J$$!ǡDuM Bkq [L$79䐷$[U=#8UºڢiGR VoC9I"Ɂ{^bOS >OߨׇEUo j<_>&\9\4UUJ9@_.@2Q-j*JZ:`nr&JL #oBh!MC򂃈\)e۩#,OUq ԅ@%$癐Tm69BMuxJ] $J^$Zi%B]|}Z>=!@ P.ƬEM# dqKwyX=8Zv_I/$Lr[ Qe+iKL1:<߄f,J 0GƱiybOm[$_NĴY1Q$ƕcJm Mȶ `+A 8_LPUEYŗ#fH l6IHsH`' VL&!(Yi"vm^ sU4`Tn+Gmse;V;I%bqn\%é24DI[q$\SL[< "$b#A[1|HTVQ&"CJn. ` NOJ87xU/+bT4RκjcD9cn0ULm4g0 a1ע$Z洁ځJpZITgi!P.)g%QʿIU!t ͓Gl1뻎hۓrձZm孙a_ΒU1Tu|9Fj8Mx@fhN'pUy2[!Vb-״h&Ah  jAI5-ӐRI6XMRˀ?E*Iy&B%9[a6*7!cZD0B|USBj<$U#PAH[!j|}{`6>v lK%UEPeTd@UOV@|k{[^L4mo~<.V3|xyWÑ{Kרu,:h\.a"1FVȡGbBՄ(B&bjԺ;mIUsƗBl)*IMRJgBQh{c w swl[a%}In U>2$DWg&ro8!>>Ib+T>8 9Mh%$=hyVwsEJC2i+i|\Fǚ!79@jQK?PJgVZlTmp1 §p3c`H i~º\6A,3F24[ ZS;S5hi[q/uc."mjaEKhU"rl[I6p(Amܐ֒:"c(SC<' 1jVVnU J-6?$֦_zc6F̪uWB~ E}M%'Վ9U#rS Һ$Θ|& ` g;IV>AkZGhJI hz8sgTՔ j䶹׏ɬk)MT xY쥙F y<{r)$8/ZϿ;9f 2%<)ZۚĪcfYVx:%r($mUrV.]E31#w&EH_FђKP :єj`FU9dDEk('g U\2gUDyVʻӗWq"zUhJVXIk_ȧQU{@FU|?j'% QS8m%B%YlUif4xsku> k-n3*B(9պ!EGHkB_A 'rѴv|mrzI fL*sU$&3HnVTl ¦ґ-OM7̐A^rLBC8vi8ZHYG8krr"7Xj_I^;nT9mUˋ< J۴uQm0|[I]$ܚOV*PN"C~J28g(l-J"<-p'JǃfhЊ0*HmvUZ -U HOIg.{g|:0V.$C9ϫ;ϑ\RpZȁ"C`\qԷH JɶWA_8pUY s`~I@;i"I2%0_Okc+!'_9emhU%&LE("4e*8k'iT++UI\BGc*4BNlJrD*<93;;83OhTb5aSqiRTʖkHs|͜-Z 5rSmfJݕUN/@)|M8P$a<%wWhTY%19] Iio_/3a]9CT&" HՐ%mfs ĺÍQs0$[!Lچ'"8?7+NֺrZa&I+6+`SԐJ~4!7%nOVU0p9HB"Cqf/n濿njdJ{\ӍdNuZހ7Zkv=Ut`5?rg$2|4H}u ZޡOj y3R@c$r+9G@+AD[ݭ<$$j/+LQ$zH*B9\(7XVJ  .$&$[d+5# TI'"ϿUJhEJ#y_w#4%u9\B%6+PcmPmzBp{c I cƗ#W2y$նk# ~`='4 7ZU$GPTt% L>ցQersDTpZ˜V8;8p"vjx[%$6<$g^qL9!̯DaY"a BU*ʪۓ7&i76 mCZmIȁrH9!٦8vTtidVHHj0DŽJ.GU*!A-NHMɛ6Σ(ድƱV^KڮjVA@bS |E)wirZ!ydWGG|*IRe"1X:15j ܐm`4[U[!Y#- ݆5>`+aheJp@'õJ%DhK(MuAIW]"~Hv5Eh-.1\ hOΊI-X<L90F3FpnN(T!#9w4@kBLVȕ#!3nB^D3scr+:l}B'H'$q\mMեqޝashMkq$JO՜Τꕾ~8@@f'BIV7XGpp9p䒐P.5<'_ B*/CJJ ژyEfH#Y(QuO'4r4JNU#+$>M0izHDu٪ִr wrwn` [B fGI [kgB8mLs"68 Ͽ=1MOطd.|E~)QmVjӭk1]1g| (I4]+Bw֣e c"4p[%mV=V@jc`IV!K ıee(*1Cx#qL%.1*:]%M=kHcRi*i$ ki;E9 y^ϣN֊@Haq O2g&& T% ?oIx/ Z| |hG cev̓V:rOJUN,m%E)Դ|7GSk m>rhT`;/H~YX۠+[HTlJ^`\CLhU„[Εu=7pU`qW݀-spI"i*b ݀-6r 5!yN@0VVooo4ʁ>([_lՅ9>*UG`[Z[pnr<j6-s[tt w.\c/ʹV&Z8%U*[aZ*!PI"1%-:;鷎jJ+Ak 8;ds>'#sX#\iZIރ#cb +%$:zYmC\ r|B[yh(5NlX Qַ̭L.F+ْ l@+gmE#٧LUj<4IOpټ}XTx`VUqJV|+ }(gĄJ֚F;&=hIH腁(4'M ʡ8"yBj֙#tf`eSr%`cdLR "%Jv!ujk*V3]WBR7\0;L6sv|h@Tm5r} *IT&g[H3[ o@ .i> r:ikMki.M89]"I.(E[\p-f-DnVNy /8$rXҕ*3uQQ&+]Y8x^ 4VR yn,'WbkHI{&WԷI5IDDVz1pjrD @uHUah&EJ]9yrF&):Ե|M( ӄLn`0my"+5Fm pRMޜV!"CB$fP[Uk*Dķ6VP8^-SCv)(-9+\"R ^AD_"$͆#WEs1;,~6 &dI$P|bB8.$MX^ LAryK;]$cvVJ 3h Q= ^fC6Vlp /fۋ*z%ꢚ'mr 6V? HH:UhhVS[o m%orMg[ROSY tcV%VTV\_e:2G_9ߊP9FpZ I<>@ OCKmK 9|BU\Mpr ^m„J9KضM"8Z2bS&;/^rT60++-09y4Tv>9x&@ctc>e$!bXd!sߛg 0 S/@B Dki$[qd2o43}vdax-ؔXq ٧_uM.!B>wpT@t[<7ٵG$ƷeeĶ$C`1U y cJ ^8$Yq IH+ {y\) d۽)~`~"#(A"3"x-m^ a Hw@&pqPΪJY Uwj4$-&mćH Egkap|yS՗ ,]Q!Tm*w4 s}(=&WVLd D.\A+mlsH^PT3q U}|5ɇFc[I%VsJEHV3P"ą4X gNhV(?*7 s!aBպ@0!T Y %r p--9m% I]V/+j%QQ4B2V=s Q6XU3gGl$ZZk-7r!u%&A#GoYI 3Ƿ5I`: 2HM;\TJZv!TXq;Dŗ9%toLTDR%;J NslU 9vL<+p-P8spl i֝\V>iфR>~N'7&mG#uǧ hD.$p`ϣ#ULwN+ѷ7j-ę-Ju/)];5C+GSV4 +ly@ƴrSxتjG@RY+ N=yp@H%pk 'ձRYql'L ރkl BHnlqo&y%k1ə\I;>9?2dJ FnT{4\t? gHҡG5֜=N\~:JhO N>8_H}c2ZW&[*&71Jv~= U1]QnrbGDC&@L`B&cBnX#|IENDB`ic13aPNG  IHDR?1 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs%%IR$@IDATxl۶m[Qa@DQ$ @,_?O_җ/ٟ:~+_ D#PDbk>kGb-;&E<lLկ~??މ=>+՘m]ܔlJ??HlC9^n7$P#߱MIF5ہdZfS`@՘Fâ'Uᦨ>i_2r|z`]i0lj]H|2#xdYJaz1Ȗ8?P3 k#@Y Yd"!ϖV,qOIm+B(<į^<]]K a?Q#gY?Fz*́I 2l moS #/2 >]Rɑȶc%&{hji~/|/ iڐ,x$;u LI5`:o[0c1P)k#jw AzQ4ÝˍHAye-=<٣K#{)&@'v,iڪ4F$;ɓ2 H)@5j(V(H!RJi4!1a gP9ǚs!ʱdtt+Tɧ+}g-;f8Z(gN xJ.q)?O%x$Ww{@#*8ʞ3&9 2nF[2>2@݋0 Op+c RMYɍ6J=“Ƨ L5ځR'DK!$n :ǩc3>Ʊg~X )xj8cͰ{>ȁ@{GnPVaˬªBUe-MH-ؔ <){dxrGRFb" jKbXK;lp;4}"u JNjEiO| "F^tG2fė >Rgt#Y9=MoUF3~{Rnz7:sEL(U{5nɳA Xh77U5fV@!&JISc#00+uG JNvzޏ#0ajz[`k>^K))g-@7X/@jl!|jW?(N֌NIx Dv]&&DǪ*7ߝ1-YhfHi+Qo#dZ0<)l$WUiCLwǓd1MAbmex$(&6>Smi{E/;IKVFzӬV}F{ S b>Yvh#^Gy~F?1a3`ifTu6,vj x ۤ5ДvD.26j#"ÔZVen\GF~9Cp+TUţ=d&j]B^^ <$(e sfaD h?knde3wz-CV׏ |g}|TS1Z'[U ·l"ȿFXH8Q*ɷy2Rnu1ԈױFYlbs7Q.RzDF"Ld|TU*#fŬ% %2kx `E%GhѪ< &Z -p] A-ެ̇,pV|m@wOiXqjjmj.JReLrPruۢ?P}`K@hJ@UVJ{ xbjI&'F.5]2+e90l|ʤ'M`36nh0AJ/CdʧfS $5XBk=/dE@'H`F؍X#]52|OSU%0.r߭D%= z-X#X)bgUc0Gj= M N3~ITE9r)gJ~ hD]M7?@[ݴ7 71g홫x-J(=>CiGA [2.Ga567CU ͰѰ 2HULC^^#tXWnш7gu@VgV=F9)r5ʘEUI50~JdR&eUzzz8%Cj܈{dޡAz&&ͥl(MǶ}</2;@0zVuceG'$VD]M$6lr%C| q9lz6Q10Ix<T9w'C ,F9grN0 _0E2S']dzú7^I{<ˍڕhI&Z$[{Qo& F;Oꭄ ~o.5#Gx9R 8lӐq g*R:R bT+Gbz7}*ͦ88`ʇ{毅3zZbdc)?y"ijFIOS{@#яt^4u!dnBInVzH؟[?AM*<&0gh碣c`ng燡8AY;tkxhPkI#Y ) ?ړ;>g$ >YJri2^kho%x: Oϛ8r%u-.ZD9hA?sOdž{ պ/8Ɛi$˜ϯia#gRmr^{;p^yj ̡P(2v;+kIJps9+|%Bl-^E,›B +#,OSbϰxKCCh_(zkĜjǧ$JrF1)UΖO8z43\5ll@ǍF uUI7}[hYhoXH ȕFaaYލ1=PFHXI/S<)CL`TTʡFS6\ P'H#'jbG1w 8A|VMOs͑oDQ)i`-Gϙ{ҍ^6cJW&]!^.d+Vl M8UО[,7d4Zؿ=חc0qۜjEnìfتz{]$ w?٭s9h'`$HCk(Q§)h c>L![8.jNW*op;lLLʬzRdMGny !A`H7@Q3p%Uƫle]JpY0"gq 4GHVUlU몱zJ"M`XS|}fՎ( 3œ5ɴ`F`6d41Q-=\Xa2|3-ԇ'*?p uNa^RIxæϱJ9!Rr| }E]Sԋ':[1y37bTj=2-FAiThjlnKnI):l LȔtvsM81> O ]PU,M*OZnslVWHl]L 4m̪3lVG ŖE`ws-U;s9eb24r2E󟸅w E)>>0̍1kܚ+t U愇 r 6Avlt`-҄9F+zׅuX?V^ >s |fJ8/DE^ Efpx~ljX 9|#%|r-$0CHH&\ GB <ߕO R{7Cz[㩜R c)R"ȪvxRɬ|P=zjkZ"d6вu3QJ騽-{42ٞRUΎ-OJ5bda;UʠY<V Y;/#[u W/cDc#wI:$)&!=O]ɀp e9e2{cHL&Z`4+ ,:H$;w[tJ l.0UXz cudRdAPnJrpSuܺlY2FY)-,JYsC&U3l(I6qhw_-Jc#-od50 /y7MYV*ρdBe%ҎH_IV2p} y) xCT!>D?x9! @P#e=U16]12xǻ^Y9 ?{ՔJ_A!.Hy~'oun1%FĨMTJ a bdk'ƈ)a|ٷa8Ü$ ^c?Tlr9zL̙1tm|sW6QU( δXLѱRt8'[2YF%ϳ_A)+E'Tc>ɵ4aB rl$1,^f1rJ <ϑSU @־Mб>IK.+b{wmf/t 2Y#Y=sR5l ̮)FHڸ>h,-Z\!V]c?94Ijۭ|dG2x{?V ܈5n.4MVuiZVr Jd aB $kVѕi*}-,L;Uu\ܱv8FCS?T:4m[ٺr^h욛K&7@KoXz,7ꀪf^6l-JazYD4ƒ8>>F(' 赘&6O<}o۶ҢTDc,P" xX֘awE-4)@I^&pkl(fd–IY)a=4Z(Ue97i}LIw]Wyn7HUj Hσ?zhE1tTR}"$_Hb&8IS9ׅ+8Iǜk[+ֵ#/*2FbZQMf;z%Xz wqskm sr+Q1J02Y1wZ.B^1ʨ[U2j!UFٳd=db-|0yZGB̑4hI\P6V]t$PU?ď|IlzRmS;ҳچu1 hJJ(|,OY/hRve8qΪ,2,tl"eQ&H7:qr[8Al5&6 P6goc.ߏGQl7+7CO"6AZZnJ-{U,A!wlPils2 A&4|d˴ܐpyR(ebCʞg#f$0s=J0Njډa#ELJO3OF%Y`Ƭ xtzI p4ɭbIϰ23_0ߏ3o|rlus֑@q}.dpork@^2z{;ji.<8֨?ґa2Ycx/2戞0-Cy<9aK CClJ8]) =F2$[WEӱ~'LO5O_RY1 P|v<[B vL&),>6ko 8pL 8'ʱ t̑) dnrQTxssIb.2 MĵW (<dU^U+̺%Tj\1d)]Y h:ƛ@˪MvUmiP$`#MmFЛ' Ti@o&B gұH@);T Vv+,^F^%a@q{Q0Mo[lmRlrhq2UzSV%LMSKoJ>&^8'ꬹH`dc'=YOMV U֐a-,sKh3OL%@V+KU|k(/Ⱥ zUk mN9clgX p/h*x="dHWi!xY 0ù^5b du%ۡAǘLvCǑTs<4fZwa2=kcp,Ȍ2eo˺׻*Q#cdp˾Ȁ.(ܲxoҴ<1w#2)ch ԅl32VswM8ɔH I]YeT2FȘ'&eUiJ@C[#)Y5-,Ow@j:} w? ^S]6&, itY%86+2F;F[d2?î蓶ݫ~w Y6z)p'E$^ ' *.27S}6!p,FRbdsd;1Ѹ<7:AG]>zw3Cv;2y&16Pg(;`aFՌn; {!H`9 Ǫ̑Y= ׸j'Khu+4sw)5O1{ r&Jöȡ.SeGDĽtV)Y"+ȭ1"lcjQE eG#TepgX LƟvJbT_;Ywga>~az w ӮF65R 1eQc_gظ5CجdV6du<[2nd C&37XKؑFL#&X;LFPeb|2z'ln?1PE߶(=&5Uew5kYւ!4a]'H&\2y NɵF gy irƋ66gv}hOK.6 ުp=gpLH] 2lx?$3ǷUVJ> 2"dG0JzhLmj*7Ѹ睯r7cr8׫KI߼} 57[ M:N捣/֫J2s; }+QU$g-+0UZ׎[)+Y5h mO8A{nSAMYW;zbp:U1˙vkP- 4"1]TUj&#(bfU)Dz,(Ɏy)Jڑs-}*_Y§ih1 BUk5[~<5&>lY@Fü#A-H/D,GzD0x~R[!,itOg( GQș"@d}0^ӱp$qOIJ2rJ6tӱ) wn^ndzKQLӧ҇>x@xH!>1탡WmF mze#ReL6+L|>p4RykJ'ʎbm&nz#=IM䬺Kf]VZ)$km%KHر.Gh0Y'jt|ǜQkyt5>f'CȻ7^VeO@-VJsI k #}f[&[_45M/(wb`;ذgmkW#jmKm]=XLGzvGFUvo\OcT;Ęw!gv#Mdq =# 4:MLEօ1BzMa dXL]RnueeVp!ÂX)G&/4ⳳ^'E^A`j >zv~h7Y =4tSf~/I>[֞#`ޖ0%+`Ay2YpJɗ#fPAƴJ~jqh([frJ>O!,x9,O|:٪i9Y&5;bլȚR&CӔ21cdϟ$g_@vA&m2fSݮJP).z I5ImO@un{D+9sm1Gd?foS0 =V1KN+|T'|/]|S&v <4ȪaʀqyeY} q_[o>vǨxw9$Uźz0JLM7HBxл)0R0}_(@H17+^?IL4`d{!JQc A2 p2$ ڵ.D|G٬fkmT^ZwUF&# 3$}u9Vj;tZKuɂLf"(O4:&Sm<0L=L {~)at@?k}"p;9Y|WCP),nj Y쀶! sNTt IU bs>Qm㎲O#{{5kO֠6a<bL4¬i) %71-h(p:n:<aC]Xӓ1Iܶen@q0yß_/MW*".M1CY WmKD ~tyx=KO )1Y/}a<{z2=6= )h"9#q> 45i`dL$ܸ0b&>g @7z˵vH(zVrVM % Y<+|#>9i\&2r 9l|l3L 2r#b2P$e-"i#O3ŚI{)),aU16# L{X4Yq~BRoG>a&r 󁋜#o:F|#$Y9hn7z ^ܔ2׈kDRޒp2vlWH&1ks{p2~;pK?#nJ6QrGJHdrr] `^IJ=_XI.Τc%-TIiﻤd5b }l'%8jCki5z?f(^#X]-17/w.80i%]FUp<&C=˄J& l1: 7#5f( UXj@Np?򪲨XFHQoJ8XlnXf%`Kf<˕=^i{|-}\-9 V$lZɒ{P)M_LK)4H)V ΰY;k\WKot%̪0C|J!(L'Y"Tj0޳ {zI"\urv RhJ{Izad-O0! h?^׏jHqGAe#cÏD&b7Ȉ~氨tqTƤ?Fr _MT=ix'@JVN&ƴdJ"L"r8ogY"fD ޴/XMYa*;Jw.#[ƇdE-E# O_)s[/ےU( ȂG'=;UǞ#8?'lJ;(Ip%JjH 2GC4FegƤqlP##p| D|_6d&Fj@8M->*9O%>k,q,]@e ,%y&`&<ݸ.@dP&VVXYI)1Z"gҦ'0iA/#֗cbU=D̡3>ckL񕸉p|0JWt+^ , n3OD9#DgDynC q~z ^0zeCɔZZfwIZ (zLBlqU.u&qE;|R:i쁙 `a)@gg.͕of՛sߞ0e .2&qܲ5]>=zRډsqp+9+ RcL1 A%XPFdK l[jkh:1' ו#c|*r%7xo1>w)P5Mo 8@"YW2٥+9 5TdN6A 5&H$2@P(~`]vgכ`hOf~fu皫ӱPO9L!dJv}Z3#@V{N Yվg$4Z "x7.TϜׯ$M ('̉azVEU29Ⱥ6&vzh-o:yxfe. yAr(4Q ּ;Ϊ75OCfs~o(odӑȽ4@V2Ylëf5 `Zy$v)m2yoaP˴6Yɹ?{cmЙq(M87(|;4nm0,Di-"*e|Hْ>鎖"z3K#* G10psyjb4,k']{ 4((6c2S8J_eǭ$# Q >Mz $ "CUp+eX#\4&K#‘)c9P_lEmrL/oXّROgB#aG7Us/ZJM+^^`d|7U&nq3Yqe{{Dm дp8^69׫+,)jPvN:SLq1cq|:NrLRnPfa2M'nb8%F)^3Y:i*$6)u[(|ki5jaL+mŜ}Nʬ Vp42F(\4y&#@$N οcj6M.3vpV[;):b6Uᛇ\n%3ڤ:L2cĭ7vxr+ | Mpk.+dό f҆daX U;ݥeLU#WA#vL*AlM`97>lG8ګ&˼%\t&yz^L9C;2pxG@ueܧ-M0 ȧFya [-qWR޵az6&Fdy9abOx]L &xǵxq6aR]1#itqn(XLFQnzHkd;E"%OhmLd0} =,Jd4 օXK]%CXIcd@] ۄ4f Qv4-GnF|xڅ fBDWLӃLLX(&&`+6ꝫ"i"M9|J n>dW^]]ors;CsTL/voMhwiڊXDMW?U3ϘQe-| 7<_88O-eb8OU;$~>Cmu7x[`R9Dn-kzm3K$\ M@&s@G`qLcjLo hT- Lμgs^cJua8d.sp-)@[Ll*b>'mnOinFX@N,H? SFL Sr|. w8xf(ا&k%'Ql֭4%p|;2`z&k8-͊g2N Y9lþrX [ 4[ܸIJֵ+d^v)/͘&LAFd8k:Đ@JHr|rLp[.h)ݩ<~YgJxwL|, &cV!PZ'3w-EfD<UeusID7P#r>;EpCeC>yb]r|dd&ziFd:֏yF;Bq+eZ%[H IϤ. ,G:˪lzRç󉦲k?U4eJv @U di"tv^ΡvՍM$RP1J0V ˔Hrs;ۮ|f UUmǞ#="YdŁ^8=mKO)'Te2EU-s'ILиFJr`|*i4Eqd!@S>ګ?DLЯiJP!ecrȰn?%AWZ6;N! h ~ gAxJDFP0+@;Sbn>A+[@h6,8y&4)0]c-#?GJ/2$R nvF뢤2,4zJ]<2 xya'e ? K7m{_ˈ[lRȔ2䔹ĪܐԖ1^#5Z#Y4FnFwqFn;AU`dU1^n63&k=I&2MׄU/STK&xLL&h dQ)Pshixv3 R&d ӍL@IDATq+9>妫z,. ;z3,[C)-;2.32^d 肅ܺ#ebu\G#q@YA{ah]MjT̊XO'Lr7 .)%.@7U=;yTXĹpb%XOF;E L@ӠA/wfl6<3P$?>s@&`%/J=@<,4yP#?kQʁ>kIƔQpG]^W0x=e%jl O}k(~1Y5`Z2SBK1B;A/zUvӳҒ@bb*O^h nYQ бؼ~/A0A G>,Fa ;fEZO4=F4@@)5֮ZWUZ( Gb(tyFs Dn?d9%`RŽ:^d k$N:ůJ<.O8ƽztLZ _E~_w$h ]u+h$AG-yH Sm\1󜑎 >S3Lи۪q1L`lҮІ|Wl:#>ZnOSg*&P HǔKpG9 Z1]Fv|2IV)40q,"{ pϑ1[ZpJ0Zdrn!׾TTqYƎ3D UK_'ًׅMd#{,w̪^8Kdۓw$K\h.PWZm( kLӱ)+L#E& "F rH4_)늼Myh*TE $P+2 L&7e<>㵈6);f;Uj[!p'>!&7ᗆ5;o=QF5CLfNɭ7$,OM[0ډaDXMsWCU-%ܞc֫FVMt+idL*i1jpjd?"۠6rե$C)7, oK3U8xLXni2&W6ỖX( u.:*2_ /rcqϐL|ߴ#AΎw7.K*ÞGH-U}b(k &g&?O\V9|.|GczebRltw -O= 喡|S#R.8~UtT ظjZs< 2*o|w5ݳz 0Ƌ޻4j! 'Vc^~_&'^o}[|g?ce[^m}#kF0@w92[ / #sMXx.8&042=q ˷RP[H;Fن4M! w%:6 n/H@TJ QcU@`AaŸ"|f^$]Lc{P"Kxϥ{4BW?0 ɜ10h =^e&^韛M/\ يZ`]bU`F$#71m?ϙ|~dc}<I'3=*MkA{OI;Le~ӟGѮ_'n'c(Zda@̽UV dϊg?|O04q.>F8x}>0w|H^J&:RpGL&)S0^C+*daYODx$׃12H 0d[#+Ϸ?[ Ont;xڐ_{e^?]J><%`ZdR)? ' ~9"E&`-Y6ڱoTԛ{.*u.+m7 ܫf<_`=1y<O׿?B. rh >a>O3o *Y]@Ekl%-O Py=-9Ӳ#~Hi/;cUk4 6b-Vr&ΜDM\}!ucdF %[Gq};{IH,9c-X|j4B6qoO$=J# PM0 +zwzs?1ɢ˚ԍ_t¼MژvkwG24-_0G*&5U5Lwa2zCO$Ys0M'e;xXf`"<78>͛oqe?#k1l ?ܠN(o|kt@DzP}rӥ ?7~#gۃRۥvKQؓޔ /%[N ]5?B~zM)-L>d' s+`\Ԙ阎 A45**:'r@--i^&@<\c퀗m)kp(~)齯{R4s9FciU`;'`#~1{CgҪJBcc>MW/fOTi ǑvJdx\~Y<΢׻Fs-4v -p/h.tT7%qpޓGc2Rr>@,ՉOPud[&$o2>+K\wM* AG`źHZ ۙ@|?fn]pMǭM^JQ=7XY FX |Q4MRafX|؉077ʪuY [`i.Ŕխ!֛OVSwpt<vin%^JYJiB\V -±8>Χє'VNysn9ɁMzzgm !bF>惝C|WS>z _toN?W8Z3;0[;:}Qq}N(Frِp/BUt8Lx"M 4..ZS㣯D_ns 8F:h߿\E_4BY#r[- "pXkhhHѻ睒@t iJJV U&%[ B8^y Χ)88-ckzMKv&qSMdD]N!g7@%XDRܾ1ZZJcZQ)+6 Çx?Fn&_L8NJgkb[d"pȝ Zt6o!BE*|(0ZaM {I"T%J+_AdMB AHQ1gEE=7m0wΞ5ohƇ{&&; ~F u>5NvZ|յ{XKtl@F1ΑhDn /?=;U"L>^NU"OJH]cr35 R෴M%FF( l-_mr5uMuqpggZFGmGHE=Ɂ-ujߧ_ĵQ!5M(#t=DRWVړY3R(@ʕ>hOwSEsUWԔƀ!;_ .4_F~/X]í=#ۺ0K%T:2B99׉O~S@jPVNPSiE?8MBu z )#3 zǔ?6nI!]Jݚͧ([SEc+-קfL$&?SOĈPuX`FV 'R(D*A|9k{&(wt y$y!"+=)i8![E,ȲL;⥴?qlWI!8NQij0Nyp Ι-G?϶7%1hGh#. #s"Xz"Դlt?{IlC\9~WG TrA)=~)iRSarCDg8Mij^o7.$7C_:-K8)&Nͤ^VA 30e8)&2崱7ZKR$8M;lmFhޘ=;U oӾ#B5-pߟ9.[B-uYB@^;?K!&a׈AƘ- D|*'{ A0֕!fe4 +ڈ6B+8De wR9.';_ ҩB[7".maM<|jr7 ߶Cխ eZ?VȄYY5(".Y9æ#1B,1:'Z]5@Lہȷ/Q?&F9`EM0'QbִI>Nk4N +>g#ש=iz.F9MWN:=Бxnw铒8?Vb{X+Jn g0]J l+[(I4 ̀ ID"Gn!*,(^̦&fJ")TB՜>jR.XF-(ԘNtEM6eB Vmcɢ]V|TuLBzdN&S#T[ fxY+XOߥr8ܢu]X!}륜PMhR9 ._h%I'lRq4lF:ƽr51~r..)kD`"EuB3~hYBݍ@HOVR]><ʘj% ǑȄ>?xN,h 7fW)TQQ 4fcW=(qW:׷g'jk"|6]4TScd-'Y4q{@Q'wOch+x~jԻ|',eN5&h,QoeR-?qۗW>x3"1AV~G[yj|ŘMoN^>)%8UWj!.nx Hg *ߝWꪋ24)۽2eOͳ@kbʁ@-Fu]L!D +NAn8OmQSF632+DD:鰚Ѻ'3D h^ilM ,˴9Fl U e sd>\̚VTU1fRouBpX ! 3@o~V,o,"wjhUDst긯εCa >:\Z~hCh4M4-@ƩUV E[țXEK_4$^8-CĨ89F8Kؾ-T4A:QKJOs hKp=K@#!!|S'b?svSnc,h_]~ESfKU'G3~?Tv秖8HHZ`BKd|N%8J 0)AP_QXi#*6k M!)} I0DbR⚁S?z#34Fx3!dF(%f;f7~-\IKNZQ83#p2YE1iE I`+A@vzOydN[?Y{R.bDZZ r8tY| \B9L..;3Ҍ3*|+O!D+Tp98?~rO#'I4N/Ә_~6zUFTlCJjkt1Ŭ({.P4c@Ɯt<B6GX]kYz+= X%L+-ٴrCL!S(EnԄLܔsMY4[]OAѳ鬘_Fˏf*o]mgMc`U4,E ,~̼kJi eA꟣16$K _n  o4m ' 1bOwP](_ Z>*$o9@)O͈GwY?V @7If]Y{fp( A5*()gkBȻU阉1UThʉ>Vg1ZUp2xe6ntķMt3)5_73'/#aKEMlc^?]`HFs !+Y9JETZo/? փρN^tT|~q$:֤(U4B=+U:40\8;ϕ+AV)ÄL?HZ6 Z m{'L!Rh iS:ŷ4w$_Őg/? AtbbC4Rpyz=M?Ư]Ɋ 3nOoʙt!iRSS̲8zsU(_~| ZHRK!WԔk+D>,a J1Z Di_ ռa$-M˘.hBríP3|)M?O&c4xh/w im֟D mRj_f/1>Q:5MV ^||ٸ:JIJ D#cF(Cn䌃DC8/?-!#L姟Nɿ~H3QwH\ժD=k,mLS=f\:)Kd*b-55b)o' FhH mU_ S@SR;o[E5V__ !WoZ g=WѾ:Bu+]i8$>4YE9<N"UXQ%߅U7z/Zf~FCv uYR@IJQazܪM%^Yk)TdqLT1M,sm?Ń@bI4@Sxm4 \zW%[.~k)=C}a'ef:#:pFɁ3 Mx/8,Mm\cBF{lKSz G9OB[QpS&ydB> %.K>"Z8$N#aˉ1mv>k oLq9hB!|  @;dS~>f @HRKJ!Ψkop]!3C )P-Nj 䶾:w1AFh-O()BGMDӁ`BLs2!S7?q'ubp'J hC-d5O!=I|]9mCL UɏHR4"eUԘS;ۥDL@cp@vkw-HUB0YۑRMK7֊Kz@\1m>:ArK{/lt͠_,K(cfZ ӣU5<&קG >DݶLSYn, 1ۙd 47 o!r9p4 b''!P%v#<4ÍB퉐>C֎Yb"Ё& sB)גZUB`iqN="4]tNqw]_[G܃UAb7)Y%>^ gR9J`Sc S!Y&~Wi)mFmԃr~rj=,)8N8BL{߷B0UiYqUƮTCVBI׀*a΢43)]UhVSFHۇ8z`M2  ع)\=x|(rtȥ, rY)Drj.ɦ)Kg-Ȟ)L@7hMEPcu-2a)6m]?͏|#%O(''ٜ@{~{(Z.#8tk`"*h+ZZ|7LcN{qG6R]efB_4-e7G)3fˍ i-] uZ؏8VN;4r[bUPhC-_SP'Ο'Z"Q#wxpF~쓈k\bS!PØr8nW=;rPp {]6z_ӌo(ˏU/h9 ZzB@LcR3kc!.7Gc)C\ӟH5K0ߤIQ% T4%N׈,U$VXHN$3Ѻf)c:4!8FU/FgD]B:NrphmI ygp+ ЙҀ9tC;;8 *zx)6:b z?NO\ˏpڄ7nS:9)M2FMArdU bW;> ic[ hzD< {IDc)s$zK*?>S4uÀ?KlƏcV HE%-jyM#Iί@r>7`.[:O ժ\`E9.L:}\ڮD3zY*q N ؔ,gV{q8T3KXC֌ Saފ \9|L=p:=]2A>ORnLUT ӈOEB#Հ(ҦE1MEer$6Ek*wC QHLiFIU 4fǝ/(''FUo-l )j.D&>;Q~jsY8jHw1䚶.~Sc'Q]+ @P" @R+~ %6x_zKjIi"e on6)# 8i@uq9(ȁSC+VŪұEY)- F;f`:h)[ rDSc nq-_b $嫷eqز55w2)h@ǁ8dP1'p=z] s]~QSm|?_!UliBmE9)Iєn{;6ӳ?{  ҷ\UeB9^~*#y_R@:s+?Z/ᗘo\Wp&a%X3m *b9ԟ_BC۠)IJnJvB|jU^R4m[ Etz99Bj 7峢Z~%Yגc>}1ASdz*ږX Yp`SG[h(|rp[/rsozB '%ʯi>'9Ûϯy5OPbtX|#3"Ј& y-"B(@kVds)HtJ#/uգB$??)D)~8'4_ԁp:CD{X-~o>]r3 `mWJ#mcip) qW)-?zXtl g`Ojm^VU8jr㘢S`;SHOhESt~d>+y["-@AT`:Uc1\ )מ ՙ1:@_'q_ KXiCHD('OΌb(rv_w#u/cw!xYpOnf: )gs3 ~)BNu tf+:Jݾ*]D/Nh~?.$Zj۸HM^'>BXpTB1!|fX x!ܰhFS/J)l:'l1gk0DKQϹC|*ZZpMї^MMy6YnqiVB4_^9ea[2B4T11:E{ZAX)B-p64o ~:w2:k)GZ]!K'~ FLUdjE%r3j]ɯFZ XM[ jBT1~6~bNXo|:)~0Eߏ)DbrZPpgU9Ş?ާY웉Ң`!ܣeA y~1~8XF&H$)?hQK)SWęw כ^L"R84L;8%csgtnN>҆C_-#~n !F*,遜tJlڈ2HU5\Qfshv_~O_MߟNNIYݻ2 Z^@_t\]/ͽ7^x:ugx@'o"sl G~Ԁ(÷k $Joh>ES -|ˇ9^]8Q{D-B^;qONo_hTvmKԃiP)^/\Ɩ8 g~n:"Lpc獇6ݑ'n~jB @7qKpTƩC 'q!NQ7O:{tbΜ4!F`B)QѺO A(~92&e Mgٖ`[/u 5q>0}V Ӭ4q)UTH4DΑV*^i!88!GF *."T-):/yNב-e"ݙn(Dd~t_9h@K {=SqGӅ߹t5Oh=v6ZT!`*dNR5 0 Izv ő5@3YHubRiZiic1qZNM!VylqҩmjKqTED[t Pۅ;Mp%Ә9?DiyVrMUG M6|uN't)-_8l.c`tZlv]%֪)߇LYn6td! rDy"ݔq#H뛘72leFa=5\),!p![:tYdBL''%ȗ*)!|L75#kʁCe~_*vY 5u-"[]--!Z\ |>KǙyfƵDEi:½e:h>KoJ%[9IaFe8F5C֢I~zz$ȩPMkqԄ[,cNͤv08'q粅D3-i혱,+Uk/FШ:!ep}y^.>rWnpp$*BjHϴE9tKp~ rAb!^ө>! P WIN=Ƭ6?!rڈ`'õ?"fjБ.d8|FOf*R3S)DTѤ9|81خBX=?Zj'% A]CxK #|&ݔhGdAbێI$M~:SԾݿȉRg$h.16նktrˁ@UDK< JBY)᩹_^%b&e RRHGe #Jr򻣢tԚZNcV%J|9Iş)/ ^Z_ncW>8:/G!!@!vs?]5^"w1e7&)LEuZH""4 |ROu&g Ș#3z崛B6u\~^' ^#S h@BG!xƽtUcubL0A{u+!AДE4]9}~K} rf+i? :/Ujxf3gy YTbSNHʭQ?{~&+DN*䢐{S @ĿiV֎8``f*:c4D?ӁGASUؑN0މZ7/ZU<_ԧA8N "~=-[V/.QQ#Z̔#lQbU_"Ct"$2YӑF;%Ǔދ03 tw.* D֧p%2N}Epw}z7*g9־uU?!Eg JR+k~=9S"f:˥ #'RǶŐ}+d~*5|QsӦȅL֧m~ϼJKDLZSniL42-{[NLt4Ca'sbZ1*·sAy}g [fjMy4mSu2\z~hNY]MSR-6>F?ŗش[iqW''-^HzéJA@9X*S++VnjkTI1{t8mk T:gY!n 7jx9nr/N(4 $`XB ]=W=uo9">ȾJO#ms$#L^^E+^Nnr>CvN0C˔5!}J9R\3] " ̢Ji9b60GJziќj._+#X6h+D2>2P $׭e_QL)B8_ƦhfO/{`Yu'.g8@dOQG??2?2j[ciڳ=.%Ok2#rwa%pnq8-/f>Be Y>#jsi4ej'90/d2 (f,_z8=I{"itcvk^+²5.Dc 4jU߳Gv֬њ'l嚊:厾pˡf[L'vY1P6i%s^ѵhO -8pp'ci!+=@q9'DY Ҟ~t!2ܪtUD~^Yb{Hp*GG˯vй+熱>B"UVA[~ueIj QÊ!eP:a^~\עE2kD$ji@>=OJ('ZR\E\|Nߚh;!RqCZhED 7e‰3,sVf0d $`w-> ODѽO CV }9|!_WplZhѶi>:䡕 /qn3@A[u웮O5sWꉻE7mei|@+uYz| ^TbB2@Vvz9dd/"X(΄7B.pS~ |L͘8OOu Ejtx4K%,5vAZG+5.+a+N44jΆd[QYDԪ)C֦E+A S3brO-Y>fJǡ4 kսeyP@ZS]@IDATLNJ)usON-C#&ҳ܆% !M"S76iIQV'ZJ0 H%ظh3%*sM97 D>,ѐgM/ALtMD zH8v׊O V !8BKkCM(0*E h|9@Dug]xvV,)molE|Xd9.D^&jQ5r@Y禎"s/ͩOjq(s~B$VTrkTTKZGSwpYҪ\\!-D7ަjoB4҈SȘ4AQ8ojH% -1嗂o\!#OS~BmPxj$Mx>񫒾(: =ILj0)CVMJnQmXs8i'ũDN5fjݓ3CronN8pcn,đ`&fTW.J大CRJ` 85FJosR4*QYó0qjUo]@8j1 $o_uhZ2Pǩ@ȫ95nz:I f@B LhxDU+Q"YMd>oh|V%b 4]9Ӗ*ed F4&("'lZ'hK#+}Qߢ6j\Vz~S4p>PMlVeL_h[BIxr;viH,gI !UB|h;\n`-kьclhfed@o_6 ׇ|9ESZEM#71{ϖhzw@ߎ,P5d!)]VDodB)~;nlǡ9'hJ˪P &CqIis4l5#AS+ZRU۔gBwn!HS픧@=+q+=J VqRHAnZYSx1?x4Rh9_ڈؖx*brƟdCK%i~ESDfBVy~k筀b'X[gcCԛ GI 燗`T!x+1O Tgjse_xM"DЀiX`Z2kd@#U7+E I|NFHY9F>2g:vceG{Z!d| 9'ȪˡP kY W8?)E'^ũiRb~>p9r0*YT Ǯr;m8%*9g%Dm "(Tb)#Aˊf1s#$/nTt'9pF>+ym&^j.>JLJpgk>UPU+ !~ V4ĽswסE02) Zj΀Z)){"'j`J9W^LE2n6d6fF06>U.$ߔFI|ӅmRb)$ИΖ0%KO H0x, S;Ua>|8i>&~+ JhZU1ŬhpldMhgĬ~j`ZKi@ ˯P"/%0a96kR-c$Z.ɤ#176p +rEk,Ans:!j^]8sZ#r0 |d4#1Da$L:g͙RX!3:bpfJSr'qsJȩQ/d,!H|SCf|6$e4Vbj+j"ˢ×Uo9Gde!9p'\CLceIيE38r)(QhhdV'89C(s$VM'u+c.+?*9[[*]A>On2择:cKSFz*N9#k1p+Q?]W2p*|:/* 1åC-}#͏1LєrʅҜ>~ӻʘ8r9LKW'~ ʈ6J4# '0fF!`NɟŁ ir5cd5#:jJIa!̙NЌ:)KMS(.d*e~FlHU(&JWv"K2!1D \ 8Ks9YNV_9p¿1՞VcYBz,JLY<?e'ܪ9! kZr;\p"Wc!+p3ѴdCJ6XʣHMҦʱ[/%MBjVn~ |)BRS8BĬdK $U(H^jRrKB2Deq*)Y/* T}t"OH 'hn!@֐_")R $e4mbdx{6r 19)BzcRJ1`m̑ )BխJRƻ::V'ƬĶZh1ӌ\~4#S%&M⨻!|Q>WMKg󥳶+ܴ,UЊr&S"ʅK"aHsBMHI.mPeM4TVbY!n eA0~)|'#%[!@Ǐӊ0Yh9Mӯi"UâZ+OgP7Iis88O zhd.8Hsj>~dJ+Zq 7euАo>@HՓph>\K=Gid$d6 AmPF6-r19ɦ:gs~꯶%^*!F"jF̵ThG{ KtcVn*4 bpj)*]o1 ݲ'N6rPRTWN7AhRF=)88$}6'xX),zBъ*P ]"0D|D}P_'g L,4;E7/NĨgYњ%&trR3Xs/u| [cKf>{>?P.W#cyQc)]DމRpBfL\{%8 h!8*Y"%FNqdRhy8/dZlHT8L_8p&JA֠'QgLi$l"ӴOV m-DrJ_Ԉ*h]4#:[wnK@DRS hPeANmBEMtb3"}QN1f  /H0W?&*D7q/˴qYf$@Qhkr'bm\a6Bc)3[h& P[p@魗>$r|`: !igI^iRt4 W(p,f\\$+W]H@=hFv!ҬѲ5ͺ|QAb 1SȈPJR3Ѧt+#7>Zha]c!2BE)`H`䐎 CtYiFWf )12\#[8( B9֏( [!E+Iǔ “2|S:AKyєD bl&^bE,+3BrFŨG]BDՊ a/)qDk 'im䟛'ΐDjO@]`KgI{6ӗph2H>aD[dT#MNd#--g`ULk.:\?|hL\ 5oteO GK|x8)ZbDOW2g"7(Th@Qr-f~$6~:'zOJK6RF۾ee!;NL"*qg]/Z'ϴDQ`m$0eqt2&[35H{U(Z542Ԋs6 K1JvYi&~K9g)!%de^srT~?r+Khug[|V8E#MYu9) Q3 7"_MpW"Ĥ]#]|2>]a '+e‡Ub%")Hyd0MJIYJtFRof$F9C!j q7ZWa}ь4^Sc(4dSp^VUTV!61kq(&]4BM뇃)+z+`OkZCE+]Q8tiMRBa'7PQ#BXueDF3%e\JQՒ45LcV"i#zx8ֹ*j.U4|K/2|Űs̴zMIT@)K7 `J|8ߍT.+fDR+4$p#)Q4MKiG~`@6d o9Rd8~!Q7-d e3)F"h!mttlLWt mO8wPKSz%R^vk%ܸVx>BMHCS"p-B D4V[hS<${qEM+aShz&0Qt);(udhM d'%LvO/)Ub#'Md;VVU '&);MmQ?%"1F08h| GF~Y9VU\]k8 6_ Խ.&ƻj"p MQ1 WZcD6M3B UQ2䭰x Hxi+D)8v",`tZ:S~E?&JP,PiB)fY.~=DB|`R]u9@Օ )7rȝP! !gROϖIj!#N8JU Z7|Hn5m!?YEsfwU)M,&Gz]{I)F:)*A8AL~%@r=/`Sʩ|8۴ъ*'郘" R}ZIiiT*3½0!ZoGMP7{.KLT>D39BQӤ +4YcRg8Bi-*&Q*5oB7zm]ꭺFȩsl 7FS 1GT]Z[&gM!h|Y_:|j*xO„f"f߫Tb c U+IԛLxr]NWvw^,FS' Y 'hmX)k$? 1‹⼐rբ)UOJ98|矄'?~Dm#Z5Be"8YƦmȘR@8c$?cBE[_q)Bmu1#@j(jIB**1~vS8%X)ΎC; 4͚Rch,%8H/.q8cy8& #@ƌHl MYܭh:-6vA/jG jadO$ZȬԭ%|ގLêXtS-B|4NRUsЛSkl%R4ST ),c|j%QBJ߰c;ҨB a5J5bmA#h YY@!9C~-D8Y 8D@nzԤlQDZ݊mv-ǭC- +0$3gA`wϦoUF7,3rTqnJB/x48F Y&饬*1HkYn< EJF gTooF5\RR6`ڱǍ3.ܛ VVe"7KC3L@Lq7php|RΙc۱q]A4 #̻R6'%uyqάr%&|]MZh}y2dr-Ea&1)[2Y5^4]hw09mK訴dCؒ G#" -m~K#tiA܈JWrrni&]@ЬZgE]oL+iX)箏hF;6N R_p>x U[o/ߥFۭQWlϗ,*nc3Dbv#=U8U$xSjB҈iT/#2=L#ю&dվrլɻ+\|fE @@?}pHR)[/y&&}â.2 Fe`1rGvy)Mt<%X`&@Vzc dȗYkq:Pp@URl rbHI}%In1}ڽ ҫ(ke9BE$$;zF|r*RMK4OnOVn AQ{e2,R)(OV;ҸhNWHU-혡笝X64}߭Z}4PWgԗY-=ӫ "2+K(a >kn9g2Y潊.ř5g kܕE]c+'X^Ya(DGU{qLi;frb<Ҕ3{{>H(xbѳgoiLML\R -#i*czh3~]-7XLye "5vdXFtUA*tF7 VL ^L:7z@y)r[ًYdu17ǑIO 0+@>-I QY/,T-\+_ Q:u6<1ǢUJģi%*.V%Z. >Msa_}!tp90)Әq4}QmL^J"C mm{,jXhS]8MUd>$S SNs;Ujz嘦G_#JY[371R]׵vSbʱ L 0WzQlP[HyL.HMrː&bhQ-3wYE+"-1a|"U@U~piNkJOU *2&,کCjS`]dO̟8d9A@ILGMY%ūd_X[1L:M4rk{ι8wb3gN&CGOWQƆ6╅)i&,Fl"H^jAYԓF m4Acڌ `*@# j4$Xot&q,blu=^&i̅%LwjƪZ* 0+LGV"xs#W񎉍f8>sG=ۺdW"s ,]v>sItcL]4ybewFVHu x2|L2_K]v-:#\I/vH[ˎ^~Pq)Gj.C=󰣒}uWTHTYZ4~m҆]zzYc vDLڇ`] *㉛&+b>c -zaa%-y%\di!#kI01Yi'd?FgeJQ#HƬߖzi4&id %@ȀAJeGSp1&PVy?aYgr( 7 Q]8 0=@zCj?^MKgJ>ZFaFZ/2@?9= gJ|3ί{zLamGY[ټօwCo/rлT *(iDȽ1xF8*]sG%92LX=hky{i`LxWhz jL_ G>@(l@ ;b3g惔VjR5gdGsD5vڸMѢ&S@R].dz᎘h4ֈ6fLsu3_zFY̻*Aպhj$^_嶺?sÀcsͮzt77x<[87 L54Uȴ 0D4u%sH`㪲=SG`D9H]2܆;R LX΁6Gօ |9$YW i8׋.1’Ju53M̹T; | fOo3п @d#iҗijsuQJz0lYMWEVUȳ}zjJaݬ9[1YAv.7Vly-;6~NIQ;f.>fұv]t5 {9ʶF'ddq^Gf1MM 3B0VvĢj4.LS ܍z@MK$+-J@dSdFXtxx^2 [ j8Osn8oe h 8ҠE#~"Y)(?96tٔwnL0m4 Sr (k=5 +0myt/Y p,#z Tsj֭.! xp M6g8Ø>lPLA/YW?214Z5M,W"ˎJvY#{Wo#HXd3$ UȀA5F:[iĺdT5h^g ]XW*A%]8q 2@ >* #-绮5؈|:Vv#|Gs4>PQsitaA&nR?eβH T#m#qv@1ύإ֑˽LܐSoL*@sӬZ{GXQPG4/k$G'pBPo>1oxʭ^=J);.kԲ)VE~*7ߢn3ڇw/ʦ̪hun@F$MӴ~KY8 y:ޟ=e%%ְH>A E ¸ĕ]F9 MI|Zi/€'YÉ}G ]3 4y_1U1Gՠđeઽ b۪2m.ܱgw"[S㖏x4"\i!@wߎ]Hߍ`U2O+Q` Is)'3YGZC 0ebG a N^q@κ A X`WnEj83S51qHU ْ:ͫ0B 7HoYJXr`4e-n6RX 2j5s>eR.ChJHAs/chnV4ȅYJmW>}YuQ^+mc=lW'8ͿۚWCu[T,r( 1),,gR#knȡ<}uЫ$gEoo╄)U Fxɚi[?)܀>>k3ld0x\IiSZa bc;Po|В~?Rᣫ# P@hƐqAfd(WJ5B#0J<{GsL/#EwLӠFion-{ZvG3y,c?ű{Ҽ捣KL*ΤFjFӬԆ"1@bV՛3tR`]JX/cQCvU%TtqX YaZתW5g8XrlkظJ}C{)b0=1ZP bd^Yϧ] 6;_/YO;5z"$1MWl<Vs֘ck+#1n4fY 6II, Ț.dF{VJM<[9C@ ?FoY,r+ Ld@j@f@ybK-#׎4JN FUsFDhS{dN`*mʎzy "SLs>._;&z֨K#Z<+eo*O) .  lL<m khGaJ島dJ1!`viTYeB\ ka%a#j hJpߵ14 ;0UϟVvzϝeG 1bS)(UM)#۪dd˷pHGJOޫjl}ơ*Pc&BWS8fvGzz H 7Z6 V1% lP} JR<v)G/FP>5D zSjQ97 |1Z)WNSvL0ZzY Of!s*%L(LdcrطjL8XS;U'+a@̼FG|Ba(y[ ߫?Oq>;2?eެV Fl ]j)Oކ)4rUG_03پ6?|6<뭽Yɀ>Z$7J<m=^hƿQԘ[x펔1@8LǤR!c!֕WC֛?,MK0r5#:s)}<0>&-\˓0i591cw!E&fUs= n2zG"LC 2L$2#S޺94 r\ȟWEͪENC ˅o.[[/Udnu)%'!OdbY8e@])+b7 !AaDGSîR U$;*ol{>'ޏȆ: gptUw0٫۾Yw٪A@t3 '2ƃ11I0}Li"%<=s0/?dk{O2zʪ9$A9<Z_{0m@4v gMX-Ǽ0i;-AUsId>s'MjnHrY~M 3Ȏ' r%~c܏"1(T?LrWrE΅Z i.J_$rCǛx[bDSh2+g%vbOΎڤ>e%YVMQa5O,czyQ|>މכ c2*1n2( XUH;n ]d dzĎkgR_p&ԒƧyo3;z/GXĎ)뭚yu)M&cқ.G&xQ̭x|WC?Yߡ0祸_*8jύ& 7%(f/"U͒4} #121>e]92ߣ\DWsN„}*=~Wt}#xJSwPmŠS)T72J[Ѱ$#E}wDʗ3%@&kwHyʏ޽9G)OGNײ)"@ wL[>kh#arīGRΙ!}-mB#2'Sڽx ՙtyY, 2{QbzVU7"58ޱshHz07ژ 70Ի TV^{U( xtl |K6R$F k^{ji[2A'瘃cE)㙄JIj`Sf[5+ϿAܞ*esei05VOɿ> s=mLb2DŽeʶM(*Zgc2}mcs&FE$g.CHX vK17*veIDAT3< Anΰ߷ j\YhR$a"Lw_RP]ɞL}&Zʪv`#a5lp0s Yi-AdilXxIX^V[|RL&1 2mHF&;7`SU:M#e]} h&;ro(mzaorCέ=8ֈLܬ=O [ЮTW0 o.3 [%[8;j٬p&rwQz-9Ʉ/˔&"z4}\>9[#3H#5WXmB|yazW{RZ(j;3r?8} 4)d'm )TʪU1ɺf15&^K;4gWJqOIV@-j#y__UUdtBd5*+G Xc e-Ħ +#1"󑎹gVւvgWGݺ44@ D]Snd`tB{4ŗ[D`z 5w'RwEv4%#UOsk)]^ io(nIhOv2Jl A-L1Y ͆ݟ #v{%HQ2MJ@{i "p4J 12 +l5N| >=Fzm1o1 8˄-LfVԱ=s-@J]=|J kN O֫F}2SֈU0"\~=~mߥXRU+u6l>2ekO oL$C FFfh4W{al\G6"C^5Ȳ[&qssrxAueD74>cKfظFFx-KQ?}b<%cv M+Ec2t[{OL Y#>r9V.֥f4 R Nwў"``,8d]x2;*[A jڭ 9>9BiU >c11#MHGzt#2YiUko(%0F{ᦄL*AI,1;30֒OV1īnP&Y%n1` ˼|Xk/(y?RVd܌h }_#xLQME0f;@KO-J(S^x}sE4iP ^IX#?e'6ЙJ9\9)YmbmK(hbdBUBj\8&R/!f>IENDB`ic096/PNG  IHDR{C AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  @IDATxli$HQ 2~Y 󐲓CU3L~o/~߿/_ n ?D_ #W P ׿ގ3OB/` c;T5Fa-٥6[&=A *eœ3CGvǍ[](8$+ z,j\cLQrcD:hۮ15"UHG&|Dڤv-HKnG: CU3L L$+eⶭ ٬4Z ɇ@2]F5M2e-M05|ǘƸFk\̉ ņ\LUh)e_>qv_3M@GyL7_;6!n1 @@ 1jgwO 2zbӫR♴eƴ |m !sӱ f0g՞IY*ɔ*ZS@ H9P՛b ̖,vᨔƑ>Ccd=.$&37< ]# O*YF /ܾȂL4x";RVh"X{2LX #}v$I31D7jZ`z-YE: J[' z d[UbVJ$r3!x9U Av' gv#&ChD>T'ò>l ZjAj98ʺ(%&ew1Jb5O`Fd{76b-@KRu49ӹ5<**ͻh#ό{gYvnK"=@ܜ [>wvVm~_\] jɰcSҶm+ϖtGxdYSnJurm]Jr#U/vUj E!ѐ)%g<>Ўz !2L6ur:jJ Z7J [[ƈMmk؁ّK9FwĈvltUG?+$p1ٮh - qܱ̹rӈ^k$ȂUU mU;L9 `p'QjǤA^Ѵ#-ؕ|$g[Yi[DivkFs G*Atܐ"e&tH &ƯОH&L k\M%@JUsЋi1"[>@+Ʊ7eJ{LT;M! eDuJzlUoV:{Zx2y:/mʭ; gw^* 3obz4{FOt90lJCzEP#?e(/B4uM#FQ#j2醹ebP<T+ KqVբkGc>L倪c;H)r2s0e16IVW~ ^Fjl+z]pW#G0h&GȰz _  +eUSՖi&-`-"9+91<YPV.-i{6t+ \&@T;9qP^L xprFҿX ۊfLc XhF #lb#vo^=.R{0Y]עG$a`8~%<@/8i,SL$LDN!*45*#e 2F?Q8(Pt\T BXѱ-UP-#52MwT%'e#n1R5pd"<1 v K7oIJY Y; ڤrPuYhy$,jmk22pσ7%m ʹ/B/V;)(󼓏.T'Se}-S)OHspڇ`#ϭݚnxy+* 2HLwHi^@&^),wTFx$F!2ed_[Urwl 0W4 +]ReT:$V- YO+g hOS( ƨΤ)=/c˜+k)'賠91]{йo@*պ}r k琦=^+8%&vSD\/Cn.;@iP4H&~7W)Ԓ[9^&0~JIk:+`2Um| )V7Z(iTL NYj%GXH0!ւL#n7+]k!&Y%JB ͢Q`@#M LLJJH74hiH$|ȜM {sնqQ&>)U ^˻AJ~lXPXX⶞4df'};@8&ҿׯҔ[&]m;}8D6WעR̢g.m)-X@]ʈ0;DRjgkUٷ,q_5_Q#kטUY5M56f]7+pW} O& u19Qv=2i=V)iL d$6.u%F J- kiC2]<#Odb*TiDɱ@I!,6"&O^6DǪݷZx퐛H&2瓧c?^ F#όLCY#DOHxG%UͰ7qF@`R&.c0m޳Y cPu0-RUƴv]YA;S#L-`z YՎiQ(q3mB m wH>? 5EI9\#^ضUjk1HACӪ0}b)YڑkdzS1+@ yWm Y#CX LS )4'x.S3@"r;9j~KhR4C&UY158*d 1~v]"Y ,O U 71ǻz+h1&z[,^_41Ք2^t4F@;n laaGYDZXiPr &pC& ZnH Ҙ!@_c>6S~:x;P:9uI) ?g}4 [@I^q~CU&n {|]س+ = R'_uzv!6s;? ±q`7Hz4BFָhWdCw%A-&%+EsTGdzxUx ^P}0-PkKt.(Ŭe= hCm#D9\'uXgU8%+9@\/RS'jbdӕ<%,kٱ4օ2Fm(̍b"6Q`|Wu)qPd8RXACÙCOI6*̇o4A&j 5^EEo+G<2֫*OG<ftdޗf~}2O0<o8&s!C?|U+-y,&oUƑFcZ̈́Lɑ[ 0P϶ G(k hK3J,cJ<@xJV FḩR{FzLV2[lk.8PIU;?O dֱ(Cr9t{`dVblJ7 ϯ9ʬm6 f8:JcNHPU,͵ƺJĦÔYΎ431# rp?YU `@ Mq}R|F8"g7TK^$[ΐ+Cs7jVKl&BކT*4Z4dH8) U'J|L<0$dİl `jI9 *s3>3h0BcWۄFx^ه&)[lFba]yȔ&RG7 vb|> ս4}$#}syE#KuUlD45{CXfŕO)5 ?*8՜evq$ȪSД2 Pc,iד)xJ@`cZRL1\j*Mx8{|]5cG-`1@A᭑R^Ѹ "Zo8O?hLM4#?i5)`O^$OG'p9d[{Wk:p?n2p2Qq;8*Ho%Uue]U;$Fm·yJ%J {.4!an֎/3FCa$10= u#ZdLՔh{aM)(y UE_ hJmj\t;]C`",G? }}U  86 z3e"O% =|hU5+oB?Mn;|7y,}js@לj* Ӥ])CUHU~K k E;W_Ԙ,[cz:]Uw;U%4ȺhGw@WnĞ/dzEj% }0eHs}}a>uiָ+>$+ h[$D$$gPlxSJwT0MHSo-MU5ZQmD4ܔE9p@is[ed$Q/̳j>&~m[U [l؇%;&ʤe10٪P M`Z[./92l<%!,@W8^gc7ʷ1My"HӑL`a->nZ3=# e cu=qz`.Z֕Y}1kd6kpklA^VswiܑC^֥J[DԒi)UvlGH1~ہu6?L x=¬[T U@6TK$Ly>߮.D;JĀ f-Ad 1TVӴdU9dGHEoVJ-924J!1^d.dJ0F~@nA<2ܪj<9rHG4QIg!2}]&f@6 ># I 00X~mt]; Î2 WhqlJٮJ 6`)^[@2xY¿rw P:*S Y%FUT.bȐh0Z;VCcU `n[]ʇk$ {?*R;=q[ Jh|j8Ga16_ e>dȟKjJUU4n}X&#.>LIrU[Þ-L 8s˟Rj>RT穥 ; 4uC 2v+BcSg=g AGI#z7XƓ%[IJ/e4l);fa"'圕`@YsIt%WԞ%q#I)T2QvM]#9 |8;gG21h;b35hG} bKNlz$=4s롔2b>_ΤԸ tߜUlUC#jb]bpdB8#ڱ| ٯ]u/9C^>3J0rJ8Cn‘I]~qX)L_}̙8ڛw9L 7T$وrvlp Luć-Дr-6{.uaT{^@n0^N\ذ-4"ec9g_G>5V)Z" W51OS V Fo7qPE X%ht]Fu~&tM7%Ya,^-x V"(t)k!ND7C@5׵e(uIŖ4;#,AUY)Cn7%Po&;L2}nC6a#S|d#?8==.@ZUI82ua@\G__7>>3?oìS?^-h},CG?ߧ!4cg|6ZHG؋w (R"qf)!eXldMoOc]@GbQj٧AU+\c ٶ%m7m&g'xj1:vbp-j;w%jD tAXN6.`3!`Dtl\圕t`uXU9}0!{RX4 ]J)4 F0Ծk\%ZXKFM#^FFg%8[4.&ׂ֒q&(Pc,7+܎^WszGػM5j 8lFdڍV5g"H?u$|ىJg[ /PL|>r-#meFcDG<@/'6FfZp7=_@-dF|U"s#%L-1#hgHg-dGz&L0E|ML,SBF4OG%Lpe|_Α6!kFyݔ 4`DU<zYq02 ^)bh+U .].ڡ>+7% z^OWbV>UkmS1{0f]3e"9IoA]x"'JhWJ4ː)$LDVI7}jSfe.g~=J9s&XRUG p0~|4|>E6`[–>!ݱGo0zUɖmO`pw t7:Fe(Y^<0Rh@6 I=n,r iddX hs85w-u!#`8PX8*ˬJ@%<)6[>FLx3p> Qpƈx mzmNB; PڽH@A)`ZH92J\h ew!.tc*i|*ŻSVrsLۋlg>py92&ՈwL>}KD-ӆڭJA2AkΡ5rCZF˵l[ }-y-Zdd+2޹%e2@-l-3d4n+~ L횭?գl@9>>ނ8#R߹&~sB#Zr R4|q㑙sgoh+OYp47ĢdLLjLځҍL zّ9#o[Q&W*c>ĖVI57d FV4 C?V#5eJ0FAh!PD nD㗕yIEId ğ 7յ'[ [%1{[ q+k (g2 fWf"c& Ӱx'Pb5Nny@kו=K2zo^ 2 Tb1- 駀r]q)!e] 0"fǵ(e wv-:k"U]ARr,`a112R]xJyqħkT*@kbDx ZׂsI4{ tL!Y>a^/)&vsi &~FNFc->21 >石)*J +mg,(s9AI۟}kM( U*due@nYqX"(j hh@ aTW{heJօ2DX#A$q(U7LI ESrX#M CH'17Nz)>|Z(,Z+KP3QUo`sUlS:3L~z%9O,sf+%sFKV jI|nΫDj응4>tG%%>78 9Lt)헲2Y;vHIdV2+ZIjԢR{csqc`Ln6ꄑUJ<=+Y'EwV͓֘m> !ht=acAMSF(kg%ëަs&IvVj7aXuW=SX1D=hͲpW{or2g$۬d]8e{Yb?3 <+ HuK/2r7'YƂ2q%L˴&X*FT@]#iLR&Z5e :H0LJ#SfB򀹑l#+DM"s~/a kD;`FebǍ>_ %}+]Hvw䎓ߍ}pFIK†aLǘhYqɾ< k ;cV" 2zZϢ4"@ZRncWMf8AVM]8 q&pd41AU+[{4{ɔ<ׅd޷}މ[A4N0ܧ,zdddazD-OV XU90Jnwq΁8@h@#G3OU^UѶMْY饇 }064"Lb`J@SddbozGfv OVԢv,YnC GP%}o;>b@o(y[*#}}苪Y$"P)Lqu>@湑٧GSrTYVrLVjJYZbm3.2n UQaG6jѫ]a!iRa`~!r`;r~geU-JM$vJ|xMl%2LWXe3!`X'J̕,@Xnt Ҭm)Y1,Gpz0#w';VBLЎg?X9h,2m[[՞-'MڳRU=#[5R471Fh73B7(>r&J-C]prl*QX U هJ!dzaw ͳ\!nh: w$QW p+^&( Hv4d]-qέ1-ԸvOW s/%=^ -b#MJxvԋ C!YiUIe΁Qs@3O;z8sĎ:"6b]X 0N@I XmGd'ޓ6wPa}|] #UÔ^CzY ͐H%=ϰ͵leL@o}"4JJ@ F~p%."d%G>Uῼrߞ ^"CR+3ϓ {HّC&2RKSu)ܑhW-@+2L무F7mϦUl%R#0|ȮIL~,L嫧adJU+dLA^KJnxz%W2]5Y]3TeZ %^h3h&‰)S hD}~ȶͻxczmbxUJM5r9Ղ8&(.NSx.}&S:H{>ZrCbdq:38,+#x-e$[gWj702QtGU7ˈJ0@10s\nT L&H"ۆLJ"E;6Dj0O?s4`H }Qp4(}&SWomr,O2+!}Hٶ^j_#e|ad2bYVd;(28oDO (/H]xâ&LK?rn=^`%ݢkkj{&k1禘ۈZ7 7-:gU2q7B.Tdsptz^/d>1!*J^L7TI/%CFɰ)Y)1Fv\O1Zdmt,k4#,3 ;񒺄!_Ftdžh$֨E8jl+@MĐu# d;9SHYW#!~$7! 8Z56Ԟ*qvW_ օT ʶ,bKb8ΰq󀭇Q[/3 $nOhl.Y_ˁ}"mNܶx6IZcPhpZR ?7 D%kQ*ݧԀ>?]c0IJ^%PTJ lcؑF4`+4dvگ@&le8ܮK%n1ٱF,0)kQos`p#`d aض\#B L6x@Zx&'[z>k=AɰV1)YPjTOS!pΔ"eّm*+<ۚ[dƕ|c2/$>#%ܚN&fZh꒻ZwLFP/ۖőm2r1C@2q# *%.Ǎk%U ]XuD5jo/2$Ы1F$0EKؽ΅4 7Jg}d#6.>|;UY_0ݍ` YX<};Z ICPd$02H@@j!FBS"@VLU]9^  A4Mp#h`s@nV2-½cŗ*JxRzlM^hՖDn(P;R6܆m>g.Fc[#_t%n7ϡ#н|ʮ玤|))1Īzz@ h^7#C1ڕ(cĎ7OaOk%% ji1d2mU.&|朒F|xhWMZ %A{. ~Kln ;J} d OCPʧg+WʍcβdG\V>6t$c"T{寚Un@j{e>1U0HLcnUYܪsaaP vDxVȂO%$# }=>5rDVI2$dE&ۍXܗ 1BLk8P{j\-x߷& J٦ea\%RϤ UY(N߱& Ďvf V|| ujVC} 2>Q[f/]"O|X"+#k!\$[F``Qn(WR)za X(<7F@ Foh`~%^;"H5 adC-?jnCVj Д,0\E2+|jגU4A|@J N@|͑ 7 H~/)}:!z nVJ*z%|zJ:F/4*,w$#,2Y kDxU)RKZ#O)+ϛh=e׳p=.$Jm-7ZLARz^#Aۙ dmzYE6e>i`@6T#hO4ΝBm࢓&d@ K ߅ik$&h^R#*ahg gXVB҇9R4m}(T=Ƶh0=`g1d+UL-J45*a:o7& "1zif[ mNc:,kեt6|j/}~' b&@( #@M|ngE_M`&S^x}᩷Y}XZZCt}3Y&4|x(= L#C2L#N٪2̄@I61J,-@Jq $;ɬW# dm e+m6o+d`|&@dЪmUUKN.Y#s]M$&b|`nidSn,PnL~D]oJ &kQjm Uws 雡ΐ2 dN/MxvTӊ\#"#p Xl6%lsh$ 뚀`^UwY ڍwJ_s2z=/RC*HYWbcq?qW8s#ɡ9d UkP}CjlʬTŕ$ v4Q^߱d O OL'#)+2M&γ$o=E]aՙ`( 1rVak^^;M?ttT->xnAFisMSJzQU^(ҕchJ]IIqq)<^H=d=pd+ɎYU^!k)`-hog$`$ W~BTx =D+)Sd0Q$FFpohǪ2^K`-pUŏͼY;.ӃgwY K)[o8s x%@.(14`bj7,׈QhCF6[}dO2 k(&~'Kl5}eJDl[ςȡ^0zץ%QWmH̄'% \sΎpw }8p&w)k4OGЕ(e@#59É;ʜ5 %&h 원'L,"0}UrVUZ#AHOzMT׈騚?FU$RG2dAg+ɌȚec`%|vJh{,ؒZZ ){ tϪ2G:@svobΎ2DРj[ &О2eD-f-OٔrMfU65 U%y% 'Aeg8[dKRNc>9x9C)Ϫhw/Â8M`dk;2º"T@IDAT:U'|$2+֮sgNjecxY;5`GGOA0^{ dG6 lm#{LQh{qu#+1Z3x~L\8_mqͳ K};S `4v/Sj$K Y?ڰW#Io#\;c c^v;zQF5 m epsGR|3KXKb"muY(riwNJ1| Qb]J4h?=FW S—J VU;r1+}Sїެv>x(F7.dwVr+#Nj- .@紧h9}:|D86 %C%$`bHǵӇG6W< ĂI LJL󇉕(1~júj嶞o7-͒`EGN_{}eq +di`8MXO.d9OazneœLTWӱAiRn.&=@0q`3k>*W L-5P:v3!0}aGVJ߱ozSd0F&6WIx鱘16 =T䦪@R/@`L\KB  [8W̡e4ķI`^Kf1<57gj.-ՖFrxcL(1!=h-]!vz%wq)dJfmOXI&nG]JpjJ<2dёFpCŸ'H.QVUQ:6MG<Kth^[-dH ,:68F{j73")T)V#4L0\M[P&Art Mؔa91ړLFdٽ0BLL0+- V8Y%?+%e$`2oDPYLuY9"1UVXU9hz`^^Qe!)̷ FPfRmyw0 IԽ(E#f^)>q.EH2GsTlPa|rh-:`䞝C#6QI/[w$zpYc4Zk!JZ PL`Ҵ1g #k3#0ސvYWȔĬUۊq(,I !)uqJ^[#F~_?4B@6X$'  %JQ8.wz+5J>?*'")2-8{VnQo-VJŚ 9F hBI+P:n\&\!O*>1"[Dax@cC%|0^Jǘ'[8۬0  -yr p3'SaWcI67L-Dj ,Xnu1q͗D.zz|`ac2SRv=HdGJǖ̹ګ?RaK:crHX#+ ۹^ٱo#@H>uj#8.Kv;8%HS;&n\ |z6]Ur#HpDckmHp,\m Q /[w%m#kxTDz^_Gti@dfUdϽ=+FȔid>&n\ QI{$$سM*^mnT´@Z[7}4m-G $)ti2Z/vM'@ c6W}gYc2%p"v6WuYY/M# 86=rW>ef%ءyƳu R4jIIY%n[U@G:"w ?|0$ V iTs.A6t~&Q^L$c%%.BC ;!%gj:FqƋJ+/6F5:"`qӱ.G%@ճ͵J`ܱ^7@&#[9̷=F:<(3^u6o2*^SIkqU] jz<|?$*zw%G/e?@S(DrG8h "&bR&6,GbGySlA[Xv +Q۽E$cŽ"CzYTT- <'u)|ĒvZάdbA<127FRrPY "sY_!*Qg-hD$1UaA6q_v[OjnCpHt&7+fF1׃)Y}bhvSZ&UkZORGiw'aHC ;"c)Ŕ4IJ)d)1L6hX#=l `z>$z3!>Ê,dQ?^p s ^-JJ%4Ԙyb2]R|z5b`? c(ɶ3sC;'CdK߭-.H%@P圑Jkl2sQNíF;h7" )٬lEmC7WWn+3=*eSxƯ@ 9 m3γ*sS\*FaJ.g/֯Nn˰c``za%>(mr8|$Pu F`MUK @v5-vpr{$ͲA6Α aUG&U;v_9_ɱ n|G?)u$h"~wM.xeHApox9 @*]ϳ%-ӑ xJXu?l Cfr-[̳}RonEMl@G%hzUj Z2J+bE.#'{Mnuw眧Z"pw@7irad xSi8f.'Wa(x19:J]ӫV;Jp,Y/1 *J1E+)\(iOJ{l F&)0w@ۓ*FXn7X U`RU|Jn_vab|8JEk@Ĕ4*&n:۩ )85x4J\ٱ(9k+9}gm*%&feh0ˆ6?+5W/Ď}6|[*simC4 ۰4[# 7Ǵ3xJ J#`?wX#'>?'zYՅÚ؊Vtl嬸RX 2 LfP)gԣl%ULmsș qF;t{GXTzJ-)Ӓ]2$Mohl %a%@i+! pLhr>`4#a%\IK#$v0@)'ğ{5ǘz+ ָR<})Tכ ?_W㈑N IC+䀪L"<GZ) z aJXډ2+f5[I #`LJh1 5jpS_ɔjqbF2<\{iS1}$nt) Ahčs;Lez:t|u:PmCcJUYM9Mx+[04}d7DRvddV:]?Јn==@#M&5[MT fU#EXFֱh1Fpϕ$nP綡m^&UU"EPLժ2Fƴ]!MǪS!cuGsy:Fd}ZY൴0MHt$`Vaj$CX4)1pxɲmhaXCJdJ;{G&"M̱wHSF8anr]0nrkp]HBx-ۤ*^U͍$kxJ~0a]]--k.(L2յ|~)I D'kiLp7EΫjkqU_mHueM~)+Q3`Z&a`]@Ҹx<3_&=vGz~(9w׮޲dE- 51<FGI{vhD s;0#%6),춏ߒPWW @%@Yb&Ѿ))vu.|>E!.Yq[vF 0gGod"}k8^ [Onbŀ[Dc"@Ǧ4SpibZ8k4tGę&va4c`$6)#Er] r53,"^ƽ1 ϡKhUʎ~׍|`-p{Χ.Y H 痋ˤ+@וگ6.ke2 MLIWA8~: T|^|8ºx-W%{(: |Gu9ex;VBTrTup'j: 3JFJ,r1 ^&oʵZm+N7 !Gz J%khO ,A'01,u͐6_mZb!n9'hbA#g%tU FFW'%V|x)4l5GӈZ>,Ua @Vݸ48` 5}֘v@NfJ>$s>߾VM6#¾(eC0jZ`2vhw$#jP'0 )4x-g,9 _L+7>ȍ y9{1 4H8@WՍM2 AиxޞFg8%`p<{z#VF+ kd B[yҨ:"aY0;$/) |j3LYlg VPIX&G0^,q|_Q#@#A wYᒎ]O)>ӈl9 Gp ;ZΡ)dx݇7Q1/Fl.F|6dyfeBYl1[2F; /FU*FI*}aQꕓ)3Ǥ BIfמ @4]s̛١阎d?sYarK)7v[Ӫ&&Ldtb֮OYK=Eiw\l#sў_<.|J#kܠYiL ݽI [.y+6X< IJq1q2R#:rC =AG2wJ& ~dQg2c)ha¢wYv#XV?>;6߯ZFzr1lVi2LG`Km-29/V֥&}WVI#m=[%0X/tLoum*QTjtHV過u9 %"-U H, Q@K7B# J[U{|`b(^-656OG5%5>Aws[ 0W%k@Jl/w ;UC =D6e:܈תvJ#8LAiFF7l\`.x#{">)()8Ϧ4&Zh,'lu+T-cT38춭rKFoIefi}|(L=H&MpD/@֧YizmڹSL8, W?@|T7r[\is- vi!sF czȦks3p`)k>xJr(߯qWn&J&jdgxJ UbEU9vHzkϜ|UZra"O}?{M8xj9[$PntHs4d|>oIn-LnnFGrsUlP8F 8iPbzGJ}?Y>[Ú\jW8?2R6@$QpOP'W9WId#[`Æ!h[Rm ϼ11-qa@FvS$޿U]9 |2l &rXᨚU&p$Qbd4.nxOPKΰ;lj| &2ekzJ%&dk=}ds,&bs)rSJ,Sb**ӯ72ڇ3okwlRncyJS @se-poBi`@ ˎR/Dz+Y[[FMTkD.rU%ƽ]FLrĘo~`)x@;*tdD* ȹhJq.9IJ=}um{@{}n51 ʖ Q/xsג?M2Ǿp+o|)nk$kۊmoϬ"rYj]]D =@= 1"f%-8M|CHJVJ?bl[!1?fU#aQHEuN2Q^W0~Я\;L ȑ}(t:J٭ɴԘML] 0ZDWbk0TwbOezLokX% FkLn%ve^uEYU~[xم J)lnc8_lyF;s[,qm}(dd2=Æbl%4i򁑵+!ᘔY5% #J# ޑ&[LG~Sz=r> ){ zD&M6Ƹ0"8@LF 4My,?A-HV7(̹qdga[cWrg+AnJ&rgߖbLDJ}N3i Jw t CH&jDU(F&}rybV#JMenIz JY0/"ɴA`μYʼn>񍸣>FJ ~,ZXV 'ĕ}2*[&%#1b8evLGё#wcUKO32NkJ՞+b)'ebBzՕўdaW뻪X )>[Lx&T 0eO #6QH޾Ԯ}m0CF:kG/fћ72dw ,sXx{bBަ43yz=AnrKyj1 =Yrk1L WVx#ahdd $~0 x4YAb9+ыH-z[ÆH]e8%^hOO,!zd)>V2X܎s)-r`FAϨ^oC2*a-jzlJR M{eEF#R%G-dř@h,ldZ4+ PdV$qG@hFߍ\cݮYH/2JG<̄۶u cjJ#l!:lV#;nd42U'ƛ%c'rLJoh>j0̥cnrdw|JSDvfD6Lj+AbFȎ۰׾?ph&{Y#ײWRS}xJMVkl bVW$p#F4YGnAVUy"Z^Y/AbmgUvpad6^yw}G|vn"FKkd &1"pVŜ-CV t0?ы]`$JU$D#ᎯFbމ0v9`2d ǮH-;YT%իDόԈ袧نUy:yaW̡vP2HPv܈sU1uй8]U06,0d kD6Z|1z dzZ\?Ej#@l& _Iv/utACUij &L#6ȦXEG#MWjI(7@+‘~6o gỦÎ"xE tԕ>c86Ua1qDe+j -ui}"|<=#Q[@nr$lF>29y+Wx2jq1UcV6Lfdh)#UkD $֪4HGU.fFh4Y[5]&r[0ZFʬ|(G酽qH2>3TW-&erP&ko5fۿڗ=1}@U&9:XO.=? [T&Frh_3yv!9}m_2#9Z²^ݔFo>dUՎRHsL*'#0lg L" {7gؿe41vP25UGnmʗwAL 52+JG|2L6.|S˜Ue,MR€hrkdU&~jOKC߆I($cPV&տ;KJ;e&MSvӆ9fq,~]˳R<ᵫAJ>&G#;jɴzѢ/Jx(dQi>Ld2|ݨ Z8@)k!F5χhWd娋ϊqb2-G "V}ͅ?B ,\]SlT k%3  2f3DkW㙧O^.%O&lhG>e 7-%O%@#`4SQ|Ԇ%0vf@I !è2gk# \٦M9foyd*mmQo AFۮEu䓀Un1d" Anx9ìհϨ);*?(ʹ\ͱ}xJڷM/?O- jcȆ5K 3Z]ѵ9>xq#N EbGJka/2zPTM,pgDzY ɪO@Ƴ7H=%s]# a"r&'Y Ruwh | UǴ dj ģ1뭺)ZȐ6iլr8}+|MN^6Q dκz|R?Qi󰹓4w$Ϟh&5[acw^޽yifu:}M hDbMHHa+Ubʪ)r[b䦴@f)/G.'Ma L]4UWjou=i̵k %2]idKTKL ^$Qinq&@MhǪ%%G"u92W2h>("7, W:7#U妷1ӏ4%}VuH&& 8w #3hPZ3^vu9*a`j L2ɖJUW% 0TV3&d9HGJ'e02`*w2$,?\uPo[U st蘧j WOS p2Lۍ#[J4d@lzZx)~2ʾL_9ECRJ ʼcV7@Uo#GsQ& ~46]̶.t %Dn :F>qivnDbX\8#>&L5y¦HAW8H SFjײ0׿(|S$:xA ݴb =kQK#Rtd# 2VJ[ȷty1Z`zagadb%2&Gm]k'nm~a7+簉ہLKwOnxdpCKjkE82W 3ĨƄ ,>u31FטV񀖔Sk$HI0anQ},~7bb."|"0YGjz}p^&2 y@9%m^hJduY{;]d]R#%7ԨoÞzBºD k*83U pT1|~Y8fUjJJR(Ed[iZ2[&Z5JEh.>4 `L^$fX es}LMUoFEx0>=g-0e?YHG_dDfe5*V-`t펽3p>K̄gI/xYJH&k$p+6"!W{~]v\['jh0iaʜI!HYkCtr;Eiw +h"s' Y)Z1Yt+#2Dv V;pGXde-r{^MUmm-Kk}Jzϰ^D WγѪHj`T7 m AV;_n\Q9>1|Yi2J٫teex4,4Fxgd՞b@Tz1)#vkV1z$NHʢ^i%]-I9l; jp?-阹Y̥l,rQlFRx JĘ+=i/h-4J[zVc*42R pY76CH?Ӣč^`K(3ٮmS4":QEXƜ_O19hPʰZ dvٿ͸g S:2Y,fK^UL˰&p&mt˗ %cA+Ӄ`Ύ@=W4(0[2FFU۱.h+J/gPX9RGYLEuɢ^@4ez] @Mࢪ\ >rAr31qn@21r)Q&[s-LD?YbJBI#ȇRVjLS^I g@j$d+IF(3l?RdUh-8-6pވk˜un4އDoG@`p+!{i0}1L4]W^9+-HL-;$g>b"U[ʮ]=jn+c6 J/Mܒa]tu5 'eC YY dp{XXu3M2<`yՂFS]JcQQikZ5`]&0em@d2FŤ^S^t$HTʬޑ[S <ٺ:VJC٠>?}--ɹd6'/1R['E$6T򁕈sh WKѥD'J07SQ􎁪(da5xUzaVyʎrvG> ŋ; ]dy6}(1UnCKbިvϽ限 GEYcf:!gV|tl#rеϬt8n6ϳjȐ4"C-5Pjz]aR9X)uZx_ R)~@IDATC4|2Ǒ)㋪p-cD2裩Lwø+MvӍ6 Td<6NcS"$P*1AxGR<9Rsw̰̙;7,߁G!7I ܱ.>E0^n212JO<O+u%h۪<\_띆F9*Uڕݶ8dUr3Rͫdg=I>3D%[Tn gB&}@]`J m:)JI0IL); -Ŗpߪ&J,dQXP{2QWUG%]H@}pP1筪 4 F%V^C׋d2O# +dH U5eTȭ7-յ?R5y"S)ThZ)d5ZҴ.s P5Uezہ2le˓^_V{ z[Wuh}R ŨvEFȢFz$@g /oOoD9 8H)8=^^w f)9p;WLPnsFUcvT㮧17yU:jqL:v֕)(1@ &-HU\̓Bn$Ƨ'+tMi:gA*7En1XvOFdbC q0M88 W\21 ~Oam 6{%Md'$,(1Z*k%1+%(NY 9^/m!Ya%ę̪"F憩7g'9nh$+|XpL2‘pa -qxEˑ8XUcBH JZ0ЕD[#FP&sPKGOXF8J4 U9f8^<1Σw1τY_Bx-՛*~wtU?iZz=AE둥ܒ.Ǝ,Yc]<_ -F'jre4#,MтqI,wTi;b&K}~|]@(>Tvd͠n#&s#:v̶j>JY吲p[ȤWɧz>u 849F;֛21((Õh`M?+#1i]k7]#\KN#rWU˦Ρ]oK%U;4r;4r BP`ZC #RbmtFhQ2\bLA#.Vm])fLhȶ?ǴL)2>GNEh%H \_"UBN l(cCە3'Mp<+bj/e22CV98k9Sze\/hgs^~/$]Je܈6;2n}=&@T|21K{2 E [OUeʎ|zJ xw5EWF/% y'f|ޙRh#!+ѸZ0iLЪc]? ~g7azʖ?plJ]J9Ei29Un"YwgQnQnbGE}fkẄ́ gזq[5)wϗ(}( Ьц<#`l2V(pvx 'Q>?@֦\:êf.d"},rGbxڃ p䓦] }ɢ5jkm-^vlt>2)@V{o|2tGI֒11e8%2F9&si&.ҧG<̐O!& #~br $RFd1H0hO +1yC5l{OlJpn0PCƧlw1R-pْi- EJuw,SeΪxJ-.}”ml11Y Lsu8Wsnc,Lܷamu' slx:otpl46 XL U1|C &h%An'MC#e䀯֏`uA]Y?٢m6; Vg ^/ z&FOQ]QU!Oʎux=[7]E* 0B&-j M>`] O z64QI@n>Zr }ϧ)LR҈UQB@:jvX\ƺ0F%# #a((}:}I֥9| Λ@b]W#vsS{sdkL$plcP4z4۪Y= 4zn Ue1)+- > gyg@-B9Saڑ@1d"R@njّfv:4f1H׻4c8dSW"[E45DY8tc 4W40&/ gg[a5V5P < 'X&S᙭ ֐QX*Mocp#DfI߶WrWjlh>l嬖3Y1Ød2'Ȱ<ɰX%V);½Mh2{CggPo#{%d kٔ L/;([(! jL~QZ.sӭc.ko [$Jn@4}Ű` K?C ɍc#b`@n6ej_{|Z`]YɎkObJe8里qr7q^q @ĤTr44Hp]E[^X:H1#Gdca.`As쎽 +#.٬R38媭a'j8LZ@Ѯ ӷʽ`-J-91_ĹUc?󖡉";jdU{#ˆ&j(tWjpv_nBW1P)t? J|xʘpG%J4P&T)@L#^7歚94y6j-%,݅-M;E>zLibLAhl&a# Z`Lvͪ*F 7#PygH UfRH-CI/+Xvߑ='1LIlV8@d; `hTa`vod)1Kl [r@)7dkaU>gR/6`(|jyGA?M[vxwSeyt5NF;  qM p☭",0<9Fld"2C6HL#}F[mU5}iIA)eȦ%JsJHAGLLdӑaxn"^;LF$]U;fBfki00eؙI*͓@8"LYՑ'F-^ޗ VSM&])1pGJ=M@4_RI[G gAٽ?7E&n koT1n+e,k,#QC];81p7??x^Ƒc>hcUJ+(sӥ ij̭L& +L|{&HJ֒?1M d*vV(*310&J#D 1W{FSw,0J[njosFkZiHQ8%!'@L\44lÍ&ֈ$vɐd{6X8G-4mTrCLL#ԅ =8")0iQΘ`J kh끌l[y”rQ سOb[I1$ӻ%; 6tzmȶځfXq+--(ѴU d.YW/^pN\Gh;d֨E$VLZHvZ0߿ jaj*,w$l]ٌz;6IxJhm fk`"(U%UeFIKᑵ C(7w sk4 1ݮx&ĎȊ?&7踏mB \ aSW56F+hZ J&"JR h?Jۖc;zldvk<}%46ǽ0dOuth"lSj"iJ)aYmU4971űdZro Hנ@b4%#W[3jn-Q6GaVkOcJ0{Wc =)exJh8vwJ g&Nl^Gz('f2صw̥#_eZxX#nn )鵘q0&}-]/OzUlc U??FN -zMkggFc1vlimBP1Z(ǡ G%6h|(|1@[v4."LtBJ *}8de+$;2 Æy 32#Vr~.=vbh0-h̑+?&kW}sF0[uZ0;_~a[Ƿ '#l:A>LVb4d>,РZv(mGCZRLlwdֺ. e L|KZ օ <Ex%/FB)~NVUVn<Яƥ*7wKY5(X;ap&4gߗwIȹ ?̯{"nvera&^?zڪdK߱%Yl^`j&rA&`gĎxoCXqep̄'M% 騅H&9WmF(9r(` OUbrJr@Wb@rhgVa9t |:}ٔ8{I@0)e{.J@ PT ,bH qUAZh88,K!8mJ>0e-xe{|/S #gG-j]mi&"c7(1^y@n))rzZ}8>* %A"O4Hz98j dڹɪ$NP~ɚ( -iL 4 ]GOPrzcG|ӌ&UjP-x K/34ECGq%P[`L!Vj4VhZ #v ΰ O_S V=UEgࠡ,a;d]۲ΥmZ]v܌x0&sf>^9>M`"o*@9g)@`J"dht UJ FV 8F6mVB֞X;6$RuGpMqS sA_4ͧTG7T^s +ij/94Ǎg",-mJ@& 0oaBuJx9C(g&>޹w 7WLr &Mm2GLCpQkWMf)uJL t΍vȰ0[U@PbȄ[??Mq2gF Y飯ųcYǴtAp7>2D+Wr=JƄPz<=:7r1.]L?c'hZ,$ęV 5 x#⑰,A&?^8w lg.0wm@yG8-,hХEW)-ׂMojsbJktW Ϥ)pGn]rX&*F{L_kvdHQ)͕4B1Z)2KC&rz9xyFX[#lk > U d_{&Ȫa<0L,&ϖwtd-sY#R"Wd141J+GLB51˱hneGwoV^qJ M\ P׈e_TaU ;,QsȊ [D=Q=^-Y OeGϬ.,3qL ?~ 6=}$br"MźJI2R6$Xtݗ&dūK1YYICSPm je1m F:GqVSߑE41ޱ1Yӈp^O9VwK[ e"ӫbȈ4tTb<zx-4J@&kMgFǪ9 rh"ktWh1M '<3q6gmB/땽}4 úd}9T%؆xÿiv_+JQ&Z Pwc(EU3p~:"*t w!)3`ygg&ʖ.45F`L;[VB#0 =̟X 'C GW{Rw4n4 sS<_n:h>97"[S:*.׋EõjDʘa0q>eD#:5ZLkAZVeDIhy4qV^_F{U6Ci[zbde-}Xf  %sMVjePeJ {ע@  ϛtU Yo"Tkuê)2qdLʘ}rkAO8ƌtT|kEVq/ÀN/SB_(ij=xdK ZeG-4gܐ&fN5g??F N8iX]mUڹrvLHRN{yLb0sْE-dbcz J 7o.;SlaUM{IrI)8(70r卮iP+ esϪeZX5q'PTNI]J%IwqB #tl.Rhe˹Ոtq18*MbU(8zF#}B%JzYU`HnHLo՗DZe%v)$%qGYV1gkC&!o@L0M 4%츖V%lJ<ѰD_x7J)"m=^pvZVj.K޶a-59]tԹ.QFUU}SxBy[ҷb]P2s{) iIUJe})i7R+-ݚl"7%C_D6˟$òqGiU$YHFbr#94N޸V])@irhd[ FЋ}[c >F ^2D-&cA4 5̼ o`DHiP~0xZ˽^P5Qi 9 (E&nWiWjnWc&l5&FP&}z 5#5mS#q;ϋ;&$H $8jpuI"pr ?W8Q#*08VazUٻY1F5OhJa:>AVW4[&}1}:6kHAf2FT" Ӕ&<@+Y%R[;] }m"h~Ww#4v񱻆iTEG@L)GA)X鶞^ ۵‘ U/12Es-cc`5*dpPi^c@ܐI TÆe6>vw YD֑,>rw ݥ04qxD]Mk[)5X)OL_Ώ86)? (T%~%ס $C9wK/Ԯ|x +ύ <7G ,6Wc7%FF`+)J rZz yRjȚܺԙzf[&\$ T^2P5H X?&44ْY`G|ܑk\J}anSb] ИEzR& 7"h Le`C<.Fg^c#Y;02>nOMd< @myZJP+ S5U>cKehle2U-ͯ,i"L |yx Ƶro*wx5gQ2FdQ)@,IZWވ-9..+R.f'bŤyq"z]cg(ځj*2%睈U2(/+-es2ٍ(KX!MzL#l4SՂ{dx>VBj[[ɀi1t#SD 3qT0a]&Zeh`Ta8QV-@ȶAӴ*{gEe}[21^; l sJ }Xk!ѱn|D,vTmɺY7W1dȹYX炁ٽmF ooD e&hxy9=@P&| :N|=N¼bL ,kwRk%f(g]q2P UKrJFp; ('55;ɱ ha.FO0q% JjzGU%"&Y)6edZd%*+G. G(:4\gnk!K >zijo4g'[ʎ|T(JXiq}ܔt|6{K)jS#F6ޞY7z'LȑL/X+JXs?V)U,'3#@N3%ңanz#d* a lM2@=tustt%UR L&ھj2ph:<5; {U2rC7AD^+%Ox. 7R` Xr\W1 2@[FixX ۹TR; +OđY]az~#48E4H (w)wplO-k +%) I%MB&7k/q #K~N1<5]mJaK?\ZR vzs+h7@]G|U-܆LlC1.%2#Oэ(1z "_ ,r3qۄ!,lzrW I9w>PZ#dĹMM6U9Ļ$RΛH  FUƷ*ct &6(2m6숗5.W{A4<8#톯T3"m/&r35ɄL:9'{O04qd}Oʐq%G&XWQ8JՎr|&Sɀ wl7U<ВMOA@ͧѭJ 2anJˎGjp,R䠑FޭѪ-){j?绒Wד ^u2"U&"R;ݡ5 =`bʎiʆ`݂U&9# ht#@ Q#~[o-@3 d=Q`g0"FZ^Lc7L7bgvzރn#@1q𞑿#^K9eUݫ 4 Z0d(M,B^ 2}hz(*O-jA)FxE< kJe鳚aƼɾdkilҞd}4LHl"$M2zcbv uS#I/ָ׳Xon{n 921Cū"Z DrәrX[z̛§w-"#oQʪƙK(l3fе֋+BP5sȄ^G&5di%,zgѸRi@]0yJ5 )H/7 Kze]άix;ӫaGAɐIkuECV#c"o|M1rk.²AVvIe 26l2zܺZ! M(cH-0&6B8H>T-pOʕ+aDǦ$hڕdHXH@ypօ@,`4R&"xGӉa{#LJpѪ䂲ksO=јZz%Sul^2LI UFׅU[@;qJLk,rhda@ T}ؔ{Q5t-@y0[gL(a 7:sq&U[C|d#$ܒ*mWO;0q 1`1h)SPƤS*_ pֈ/Yq(l%Y ɀT&*)4%LD)Y{~Ǟ)$p\n",h<㦯kmՖ٥U3t %[{#1h|S`2VLVS1ȇ,^'LP.7:eZ!%MYFpV47;ckZ' 1kh94 ̫NlEm A:}_RX_{62=T%2pWrW^,viH6̤M?Rםg<LNp-0M2UGm]nhV.ɜ ܤ|!BΥ^JmoP/~ 0ӫVjoUY!U͕#t U_ Ȭm2b`w0[ Tm̑H&)0`$~sşݫɉkZ&l%Sтqa)̶Օ (ӋJ1.1ɼq\9A> \?8+}sJ2Mn iI`_$LD (0yG2'@>+Hc4mn4w)g({Y1dE/ dkBC&-IP&enFMOĶxk zՎ i"R"t@3l( N_Ꮹn -I DF!Ҡvׇlt&pMH9-jNIueJ w8_X9Cn(bS-jG"o kأh0lr-!AhiX[3p0Tb"ib捣,4đUNI9F6i{mEб.uvD^Cπ e&Rʎ9 t\#Y{OtT#=]94miTklm-n+@hy #8zds9Rv3 UL^`FT@IDAT#}Z^pY2@|a ֫R$0?DHJ6q iJ⹱}|2,^z@cir&(zǹU#dhYا'#dEj6լBc@Wz2&}L6?fx9%~h"c4R ]ɔ?Ez@ ^C[,S"i\/RHKa`Mw[˜ɄrsilO @$Nu>JdmjlnVjJ9 E0 RU(1xd]]o }YJkϡw_^A&Q/vJ;L#:cdw|0vo JM_1[1Ro\z zGY;HpAJTa#8yJ8e//8>v&ʰF&-ݚ. %Jd "\Y@/R>pў4 }3*-; %㟟6ֿ_4L2w=+0߻TxJs֟܀-Ggh<,2x0R !%{ha%Ȝ;R"cҗ)SU¤C #UaaZ*A*5 )EeH>0`7ŷXu =FK]4]YӉ;6Ҙ3Rt;2ESH2YMzqX)Zt쉚Lv(nVP (U hqNJ6tb歁lC* s`UL U-(oQk.xsTRp& +x%R4 7A5ΐ|ē L$ 1-f:,5Repq3V]"e;'F2[sF 6=*^;>7 \c>=!ّڟ7 GZ8E6:U__*<(+PU ^)RQhH* 7KFֵvǽ^A+FsNr#RtǁĹ5qL6ZYTp r(; VPҋtumO߭));[48-׋܀Z"aJ2% .d$ۺרTr?#1eNrsoy: F@d{j-xcϲF^*QdkAsp.h: U)sHԨ;c'@UyCS"ې8$#+ݾs;@JM烡w型@y ěyZLώj΁jJ>pmΎkRJ kJu)ƪy+dmoͬd=ib<<0 &3`Z\AD1 V2>4z1>C>J-%Ƭ|`2G6˱k&&^vqNpo0}#Y GJԛJ3?PXueb6Uy$呀=J\V'FW WH #0ԂttdjZd֠@/) ̧}`nJ-\ 'UrJYmI >w_\ ҈l/zR2n9ı LD]zaJM Du C-a2<,@ jޔ`i\ӗFȷK]A֒PU)16rs$-*%C&BI 1YV¿tj@ G>uZN߶ ߯NoSi/}"JF(5mM1f] !;ʾ!#=FTaVXzO(P^-Acv_ T+u)w)J9s8K(=,hdZDJZkl\{ MXqezL9gǺTs @ Cu$.`nڅ.Ga@291@02Ak٬gLNC#Y F}A)6WH<V їCo2HOi:&(g8UgOS ]rgnEW|0"T}^Unh)G.κ7,[CCl- 6%ޱi6|b^gq|Ӛ嘹mR*Q28 _!;62Z[xLκZx} ڑH6FU#fP57 M_#+4ER-ȇ&棽 0J^E174f*䟬hhGӽ eELHпO_F]ܺ# o}&dmB#`;s@fb+L3f֨"kT՞943(kFSH; b.U4¢pҕ{x'0Ad+^"x XP8]&c\YT$-N#4aw.sU|ssi|{RO70"O19%+0̉#ed]a*YCbk()%s'#4)8尟&&NC#`iJUĐL/^# 5"QoTBW_e._( 3ar] Rf*Q?M{f2K Li8aU&C=X2=br-S տ֛Le^#>&7J)AV˞-vU&L0 2cddxy]YiK* zPjnx> GWGW !B xsH#f`b=$ 굞.& rżn?YTnW=BR fм5!N Vh0Q6:F]UKHJBgqFQZH e߮voώdTfoy;+& # E Uu`UiFl1R^ g߮Lr`BHӳiєJ2,~g J `U0C ,8a")L肀Y}+ՒɝsR&r-̛$t@ a.kO>H+ɍ 4Tqt+88d&zVu#o+Udo i.#]4lA s h9o"XK(g Zp @hN86,q"{kǂ[$۔̕9,+wcզ6eV,>J]>U- :KО@ZD_R, 'hkv5TeVu*MMGםv̳DIw+EQ{եϓϹ*&7GCF@/`퐭;l: $D2^ˋSf(֒zݚqSRk_e#".$,&@y ×'aF!(\r۔dFm-h/SmL!;zU<[>xLir@(ck[x37#vdgޒ 40ޜ1YJ՘3+9,5sJ۶0πv@4D1 k70?ضCgh.0J U#jXy'uLk?ttUX6h SĔFˎaRǍ[ bn Ŏ^s# OzA)"5L쟃o%=* #a\HJGJeRjY%g;ت/mȁObxLֈܒӻ2+A?P.i# JTZRxVW3FHYCI#88|Y#!H|Ȱ]$뛀Ԓ^O A@cibb Hc`}v2=Flz͢fq(n\pdׯK頳BwXnL)F'L&4F(5˭`%@:k8"2YHVIՀrp׳m,xwAPO$3LCוҒv%6ˑ56ę뭝A#{+G84 ejTQ`R{Z VvfZJTKoh_VB'#LfF w @PQrUߟ:]' `bIz2 &CJнc&cZ{s[R/̙RtdgV⌹_՗hsEo_8lUz%@ nxUoEZp޶ K%.3sğۂLl ,˹O{ZL! /s~Q 5; :S^VE}*r00C>Jvb|x9Ӎly!Ĕo+YP9 b EP*zJc 8fG&eJ gUF-2>F{,t5Vm$NgZWq(̑U)uqh>AX0#F2&"8+CET`!)# L| 49T.ZDLUz[ƛJ+ xq) p/.Tuu#4t%-VYGL&MgMn"0r.Z'CL} ^/\ P}6{Zv2]Mn] 7#VhO憕*པЮdU^JCsaz]L򄑲zc0axʳ؄}LibL`@SFTk9bS6y2}}{Y 4DKSn,rz%bJVr0qk隍@UgZQj=eծ %ɻr|)5Y 0E zPsQ:2{N چݔOJd*cD&Jwv̋"ڀA/zʪcĂLV^Ay= D[ #ܺA0#,1.p>64WKj~\3^JW +y ט87 5t){5+MDb&t5߽h3Q5UjzJzĄl-h3Lo oEעP 9\aNV #뽮mkt_ԘI;A$7+֎-f:fK$@K xE4h|֛5h2 r#AcVށm>]sgVq|JkR7kUIjQ҄-_=H|&,&/`JuJ^0F.%^>囯Ut@9˘̉ÍnCXAGgu#{DIGZ3]%G}G@V'&h vo&/,O~53oTݱ?֠dHGEFFfUZ{πmRyf&ɞszbEr(c\|d|/&'$^HCj$#2Oρ oLMIх#VYrw=<7Y$k~ 8wjw]hbe#(ꧽěv8D  zYɀWV$h֒F Vı!  gU vYu,@15Ԅj  gH0^̅px,J?s3HpxJM<%gUܔ5(Qjڻ]AUlPdp 5vJ톆0BK`|J@-pu L!E#x"sX-<(s'~*S&* eG#@ՐdbV@%UpS-Kzkq$:RK #)ez )t7 _$=>X~ lqL&>56$9̜Qe*Ȱ9Rïjtp0h)h(O>{F* >dJr#R4=|m5W}b`>dj@u&U1;Q>bvkn!E gw{Fhl8@/b(F ?J$N9$&zVUze3h:g~:OA$d06 4}qͭ*ww24R XFRFg-ygtYyaG~- sf o)b Ѫ>l|2 O@׮I-aUn0V۶)ɀzhICL-U3ّIߪ+FʦS9l -4UջXi[Y I&j WʿlVh 0)xv$3`nm.jF| 1\4%[2-@Z M)tmsLoDݪ"RjWRLLH|~^(Uss|ƴjbL@z]3DXU$O 1Z(vVM07Ыb"PԮP~:+Oa"gߝ+wq<+7?v@SJcF#,Zg 4ܑ ytx.Acz)^ϣ#>JLxC`eWB˜H8Y/ҰJNS5q+0% '\Ǚ-p 0۪jLZ4]ST ELf K]4sSUXv\jWA~zA#-~dx[Ǹ˞=MSBcʹiu9nh-E&7Ab*~S8#|F9+&>t4=N|1r4Z<#;vS2Fvl My^Xh0T /&pZtJmܪd7v\kǵ7*h&6+kٳ`rcfq'~ Lր U4 rlYlbۤ ;d5isΏf~`dkVChtǾr\Ldk=o#} 8#'Od|C3ܱ9j!PŬ Ɣlɐ Y=MH z s^,1rp4Zړ Hw\hg" x*P#CG@jKel$VoT2>mlr+Y˾vrHyH "]0 ZTu N "N+ǺvBK;-0C$mJ/QݫiD? 2XKJZzĞB.YQV1v [YoY4&<+ *y%XR1R&AI)4xzp&zkTm1#0F$Fȵ0&bZ(O)6?#4(q PYatyLV"q[~4jiUXtހi4:"[@Wn2A@Y>d5PNV/}xfKB*84fy5'ng# Sb8g>-CR_v1)uE&,G$#d {ڲ6 {tC3+QiE;W"Zx$ 90ݎ-0@lW M2-É;/+bJ099F [BnjFJYPVL{*O=WdpR>'mhJ/tp'·:A=~+mgGκ&ƤE2qr0u`@WƘz;BC@~&-zs<1C`+e[6rE,2F(ڷ-%Y8'6 L*Jkno.M#:lrxY)mVt oH *p2A>7kvc%Ɣ[ Fc׊^/@/RZ"[wS +cNs7PqL0&<ha&"瀌;2_p -6F3}(=B%+ 4rmsϹw˖! Ӈzm3Y+ GQz><ٱF–,d*Rf5H? Z,Az M  R 0B=؆W{f)2+LPvh4QA i:2TdHXT [  ӵ[yH뗕v"SD3=q Y蒫#uݓI>վ45j!F;p-DsN9~28qu+51 q<=`i]`7B. A@&XUzL>pr" |>dJY#tsW($D-J𕼾T"lZ*$BPVEC{"d.ϲ㕟c]6"Y4-ԥY`>+;jlp7*4;"ukjdLYaDb,#Y&SU͊h1Ϭ* KjW-җ)-FDT g|:MN~} u5BcCIJkEҒ ajX xv9$+o!ǺV:#"U*nB3ޑ^N?[ty[Hl\VH#X{hVzY FSx4+>e s0.r@Ug5l@ϋ3hJwL###EG* Ce7 Qaq'] O 3ikHDJXn" hp8MU9cŔFTEɔ2E1d0MϥYaYϓ^8ƨJh(ah10Ob ۭ+Ue#F‘m$&#&27bǞnj##n̹q `mhs.E3cLp&Y;\׏^nPz1nh|nUE>ĕzgJYL\nlpm?&JrxHCvS&_YaۄhuJMfU;6F+pC#+q@ksVEIFHbF!RjmshjS(J21o\It|dZp~2Wt=ѽ F,$6WwLYWud(02L a;/b0 uLj&sd e(Ft#zJ%L&(YeRϥO&j CWUn|AO);NTs>]D \c]W΄8LJ ~"̼h!&<3q$xŻqhgH^ʭ4|"7x2U$Y Uw)כ[)Qr+ ;xrM)՛AR˵%H_<3`ıgNck6IF5sުpݐ\)[p^e߀4Х8#ؒru|NAEF[&] -  ~]d|R8""7=¶r+ HV^nvd;b|0feH<["fNO?`4/L^Eu!WihɵsËFӨ:&nF3n.ro]бڰ!H"r u7 nbߏJ2[] 5 +`ȡ)]ѪϮO97d%bJld &OMx 8[>y]8\HW{x.Og\#zZdBe r")sK&4"| |H`Yq-ODhiIrJ AZh@֏H0k¹UoOH# wd!.Ud~*6Q\/1(G*fG0.6rPO6SQeYaV?Q&m6E,8gXox\Ha̳'#,zt. єCzgWV hΰv@dWrTJyO֞ 7Hf#")sk1@3w+HV)i*lvv#?uc"[w<|VjG9vΪa%s 1sp$TOx Mb11gTuq0P#LMKu%>yZzC`U|ιdwp5RqpU K51D65d5B 71YyCiG3̊L D9dltm-Sb!Vj0~kWr44 {#ٶ*kh[lOgP)9؜F 12U#rCJ2,Ǵd {X ˺k(uNjMg\)O4JQV<(pXȹ >Z#eb^ÈLQf?q ]-T2"j : E㾠pkg2YŜ@/'PnRz7]y:E-ڕ0a mYMpvZe& 'Cz%K0N $7Hz)#}:3]Z@D~Uᑰ&Z:6wC{1.YS#?- ݽ\S}WT׸# shyF: GUb@-#ˀ*sHR]Fzd;AR;ޏ.2>͐jOJ@501SRXVr@6+c#G2lE"%D-ȡg'9eJFo%AC>yMI܇3јF8G!nzed}dT˵#zxǞ=3$7GF~%Tچi ՒoF_KedQ}~WTG9[`nnSeG QԎڽU1Jv$Hon[9"@“Yb q-cH֬5NTSo4 Vr);jL#bW#L#rn&&ƳZ`-Me8F`sJi%;eO%MwLSfe$|!Mh V0)=BiPY%_- `:YŻ]5=dqn.rڋQr@f@w`.Ro@;؊mJmkV2`%UZH̫Q`rǼ֋q$в}瘠.B#hzۚ++E<}99#a1ֈ2 ځD U1r?AڹRSȐ^8ʻTkqP"8#Ø=%Rʆ c8KsNUI>mq؟dnIjȀ7N݀' s=Uܷ3nJ [{GЫr,ǔz1D&k /.E1\ܠkZ/xS0L]Jx&"b%ګJY P%mzG&9ㅣF @$#62@IDATxy 2D Q# )H<\&8(\7@dW w UheC0qZ+V".,lFSb|tyb,#T妫/#P)6ql X +p0LELfj'PbnOSt ?;퓹#騥jyyj!^KGXRˤQmazZD2|8PE cj,RppΔElL>s-}ܔqMLs;h0A#G6&3RJ>ϋ?H\ vH̳#hL 2|9 V)DbR6?pkh)H8t]Ȭ"@[c l+}-|aez&JX痾Y XPrO?pa!RcL҃?o`-w?+hܭud%az&#}M2%]"%m8ױjn#ISp70JhGneJ>`_m信j VĤ,Hk(=ggH%2<2+4rS0} gR#9S gC`4LCT\XHFe]U8s2G$6qӟ&d}m5D:j2enaZ8޶ 0hϔe-}%h@nyֳ(1[R`87ڱ Ldݚ!eH ԻوڎƐ1|kFVhtl: 1{4 ] 7$fU& H>ɖHH&- )?K)T@M< =J/w6 |[X>gBKL𜛋!_z?#e?$gu_g_Uc/vb~8I2=@C оOu:jb2H~Ňj tlʢzRmP+J2Q}?uU%ָRF& 2q4)eiO>4pՔbMPWJ>&cjg ;#9'(cTE% _\`haZEvCEhj|Vm gh!4ޠ)*]4v;v9ׅ ;dmU/xoM*8~Z92[d1 :0O CwhnJF숷؜11lLȶ`mȚ dm $zY[{pwF鵛%ƌ'K\^ѭ&10 XlAHJvμ=rX39Y L ose˼/3F#F<j;;vG %цp;$`몥gW"cb w/2+&l E6EfdFюƷzd=Xvl1U;jIOzx?}u/.?2zGMr{e]ӵsqW; +d77b5?ޑޗv2`)sk/lQIU'QCrVbgŻ_H΁A? OH{mIebr}T'=\f ^GU];+a֍(T Fyp$,€F072OX"H8MTGϼ&V}f.Ϥ X0$F;3qo֘&(-p^I/F A~]kjJ-L,4ОV=;C!mHwWL@&܈^L@6 .܆M7)Pr LHx|dǬVʧUa@"I!fs@ַՉ#r) :5vk>e24Z)c[2$z g>İh9`4j ϖc2ZO#K:(csSPgnF}j i>u*ꌼ-3,rs>+h+0 2#rr{bhÔ`\j:ShJ^o$S)Y&ֻJtltƮT;*=v̙T[R?&Ż;SL6+>ޞ([eun;c(X[;Jm4jQ Zm?VLhċN̟OZMiGFp)86L74|v22;)0l8k Ũ寧 4d=et a1+螙d#҅/b6qOF/`z!}__P [FSwq+|[e= lĮJ!71")a41{>vPg.#u1a*7AiTʁ U|2wyɶқwAC^ly qv#A@Uif[s%dmD1s H6FLdEC chꕍkϪ)xOzsԋb'Cj98 S\ H[V!4ۄILPx3Q^{Jد[6֋[iۦ)3ֻq>a>zQQ#"Uc(E7)cdLz 8="@Ϛ橄)kJ{GGґ_L^zu0WQHdӨ n{|:|@oŎަtUtl=GMALߔeI0EpJi002Po&rυ'ds;79rY-*`Ֆ|PӨ:ʖ&[ɧ*d@+;Xve3ts&{^GA1Hw[g%j4W ^cnʁL8}%LvkIIЭqkTFTj4dr1< #뚉^Ppn#őHf $()3g8vkL y&߼n%fhomd<}<.$k {c2r LjeP@I#B:!ۦFkܠ0}-azV;՛YK|Tˇ # >3wA%-`EvVTko#a9opg㷉er;]%[4R[1"~sGlB{9V]cґI,|%䆄y?#"݋ y.7^ tDӔIzEy]xȰ ߁gb$2Po]XSDoX/nώaЈKƧJysh+Up)h1sU-"-9+5mbu: TÍmЉT҂T wިe5fSP9ߤȺ R*)cz\ >HA0iߕ|*d22J@fK˜6E6#Ҕza؆dz;kiLd]xOzU1"%'k6d#?co_шe| h7XK%bؔɔ7:ӯ- qO/[Xu>ʇ@4wL4B/4``~v CmJy~Ѵ^C/h6#>GV%>1Z2^lڼ~{]CC,>3G@;iJs[7L&+9rӋT&xAT%.4zJ,i޿qˇU Pf5g '0lU*^M*>kX ɘOjoFӒ@vׅ߱O$2h[L8GVmR8 Xqm|uѨҸ0dSddy{eB5Arfo#P{=L{ .7BァRwɪ.y :ʎѬvKc/7d6x[ u#e RYdpzbӇAPAqKOeХQ3:wkC̑s5Z \A F.H^F0]ĵt,FϢŚJȔ#QS{M$3( (u_8'd|5Ϡ4^%G@ʰ#kJbz/׈L?1 l 0́ 9gHn Lv؈3~cjG6WHLFjA:Mq4-,UǬ1JWɄ#ilS6FsֹO' HWRѭ!'02+?z@I ІݼKa85A4VȎLR)"c*a0y+I̪y¹p3+^b=]w@`mjw̶Fnr[Zjy9$sD݂[GCɲ͓C->ulXV]I@]J2Lh[@Xg[Unz+9*qJ1rR:''5 s4#ZTTy~U1O@ذW=xcfQurنM̼ua?rߙhY3BEQoڬ<^b%O[bX4{4p(jI !FJ$v}|dJկ~A4+n gb^1 &fgލH 3~[ѝU҇JSZO-$%|&NJJxb;E+Fh+;Nɬ<H驙h.igV8ϙ>w]S:'$J0ެz{J%L]4-EKʂ^?xgWOQ뭽cFiU/ }a 2LcBK;I GbǞ[z9dbכ uTʧlnԱY.Y AApzY:ƗݴSXŒ]Pb8MlEiiq$5@^IPmhFUnkˎȜcDӱUmίqO) nmz%ĕ?&J'0R)G ( |CoCT-wjA597[Lʤg{N#>nɌoeےF$#b(1Ͻ;y990gҽ9W:*FqkLjvCڐmK45aD]BVڔHG0>vԭF 2>B,IyB߶QZrC vm#-KqspgUdp+e1:.b.C[y@u>@zL!Ëf <CJ`QZrvFZf8#[Wb۶0dtln;q?Jc-T{7DLl^ wdhR&vNp~1iR&"OnL^.J 8Y֔]4@G%GF*Ҫ@U𠀿3!zkgGkz aL¬T5leʐq9qz3o&R{ZiH&@tjpd[[]$3Ԣo~[g?a|zlc<]29"g$OCnD:"는8&ib8b(͵s(#CޜO]Mg§zڛq}Xko.Mĸ YWّ[Ra4bbksVm%Ǧ$s zё`/Mׂ!HF ; n(C]x +͓=K ,h4Ďd>M%]7:!/eD۱l3FQI8UvW^|U9+WJd ;iued8_;klu:)% =MLYMirwU[ i@ӽXϘUwc7㐍ӛvT_֞`oַ{]?73eiK}=P SN/q&a9s2 g+F.0TU^@ۦd,VU"1Ȕ&u8ۧa.hl ( I觔\A^8rJ9P; zhXո V|ǯoNvY}M3Mׇqxng9۪Y~eכ& sTbJ%;  baZ@n@[Y?.bD hALO6Y+>,Gjiij46\K,('u2gz.̦1 sn7U9öAN h㘶3#_+YYjȀZRFZhx9?!>KvivbF:0<'@{#2шl.H9 F6Bo|nn"f7; ]-3x2>îY[hS͹tu35O>$ZpOS"ǐ%, 4ݸPv0+BA2K71Qy;^aJ)pj/3AAZ5v)2q)2v/u==OQT ]^^kȎ 4Tƾm³M{ڳJ8Ɯ !4Ʒ̜ SIVuz_PY!8]K)A%W  >፣3Y]eZ|45gL\AA.<#2n-i" 7dipO KӴ$[ ^N 𣒮c|^O6Eΰn|8Dz0c@| ^:2,zetͪkhĴ//FZh2wEc$ UUYUw^LK5$P#i@K6#߹ߥnzw55$kGwFF#xnۘGc y^A>G'%F +e ʺvI9|O1C"lV/Xʂ,bh2'hzU|w ezݱ1x<1h1Y{Ȕr]@JaTb"l-UGoؠkyd-tn3uxY7>L7g#,o@&VCjnY yɇ'L m-$d"z5SjM1LyXdgg_ Ջ ;sdML[6q^ rվvC>7"\3ӻ` #?iKϏw6g%wl4&o ޭYH2pܺf>L1 1{F8%kIܸ~kvuq RfW [F)kW[&![G$ve)AJMtntU:% <e~kax5֕ c^I9~2u=Þ#r؈smcj _.ͦ`3pOJHA6t^0oO6s';.L#n7%~x{*1Ȫ\_3#+Χ­A߬*OEw3yn̿:l1ݝ9GV21#Lًm yV9?bd(A*MRCJJ}}sѴs_is[%֢ "{.R'LC1e]gP >?w͡F'öjnx`@ӟ J!M?~--;l#>gؒ4fAо=QKW{7|WLWv5+b(땑"/%%r!4/AJP+!s%}rl-z4le]Uٲdբ^J_U.pkFi`[RU5jIhݮU[II#%@z. _n_Ll\ #^{1M߶~Eߍ_j,L&J<`4- Cd8}l6k}ʾ{GovWچxJZvܺHz< AAO@c2t)!Fis]r_`Vrx-m vboW_MY5C-[ %%>z3i8v;&"@<}O&b!2XoGj/Vuef fU&P>~[;-|TP:M!3~I014דBƈ^FsϷؿw]KJJx &@n 7OL&mJB1K>+$&CdS<$WKF?pDP|cdAA~պxR$̄#1k4,\#YCUXh_K2oG`Pg$XH6א:,Ju8^%vA5: Ô 㘘I$%\U>FV(jrڑ]y-1\P}m"D׋wnj";Mv+˭9?,7^Y#Q|h@ *)J:á@<' \BRa6>pK#ݭ7%e# YٟT"Kq: CBZY,/r吘ܣߧjGDG5<|Mؐn]I/%M`e&5\PIʵ(:UhvxbgxY Ц>?!BPySeח qMN ͍-O{󳝻ͦ(g`vo6J!/^UV+v8 뛎B_+JG\IKډ[f̴ P$xG}^ )TMbx{#7Utɒ UٙK^ $+FJSeA 1&eݕѮ䯇 s-&Om[KބjWztzq}/F7vK%4hAmM+aF+)k)Ʃh hbxZkw`D,U9T*L6A LE6-hӟtFG}&DTpjp{wEFdᬾ]fh6hxB GQᔵԨy]wʂ 9Y~A֏MJ\JʝOmRS)QȾQKC16bYyjj6X En6/RHLB+XvX-= ZIJ$p 5po)`k{h|:ڵ)y$SIHyZ< HseR6 OV6bK Mʦ#l:z *OZYRJH,@R28jF^=}Im9 3}م ^;{ dMk)(OAm @bxŲφ^/_0%̹),j/!qk4rސ~YTu;(_JjR9ZbK'"/Ñ 1NuifjJ5ˡlJ)d`Z2)"jŝ,K:O3R@K$Hm/> AH:ʚvYeyL{ՁcKYs[4ȏ#B})xY,CYӫ|r2fd xxDPUkU)@A 5Kj)P$RFZO-MAApp R hܨblYZb$K-@„LfSYeC 4 RF oJp,I#`R5ZZL%ZM'@{^)&@0 1xśK[Jd5#yb5L #l-mͣ;)c_^]"p8cv݋?汄VS?C]-)9 ?U A&hGӱCdjeպD" uM(h#l˶)U14VNշ.?zO"nBU0'\@|ཀྵZU[1^׿ B5^5R[K!01m{D3RvZ|FܷQM.bʊnp&@c@dǁLD0yca.fL [^T %'5kR|jŖMY;Lt%@Yֲ  fuqp lD6j#U[+Kw}7[9k>Wy! ޱ7fd8 q:&W(ᯢQk߷ﳶ_Q >YP $@&ZލmDMJܨ eKק-"#Mhk*ʐr xͿTWe2XOj d*w+yek |&/WʶgCvۑkJp\/JQ&6J& X6-W4u B.TҲCHmpdR+d q-% 1 y&,:ܨu Y*5 (fuTҾ bRYJ,@.8ͮ 6$::Y=Bj#PI},)[6ύC>@ycw)s{ry9y)ѫmdw H=g !*AY=k#w =1Nd3L7bj;۔1dRPk))|!R''|cD<7=03BT*[{cLV Ii*nfDܣw>߿hIJ_@4 x4GМ&D,}D6Cc畄L@R,ArLMGZjVx~ 6+o7H;@8jMbnAG )K05A U)ԺSZo-!L4J b6nho,<R: to7ۨ-@zWV<&H-<A"3U5XL]vR;lhv$]ex9C#2) KjeE躈~9'Jt&u}&\JCeCil| {z ^fMИX}~RNS휛ڣ@;WFbPA ~YRuO_wR!nKT^`Y"Ħv'F@}H3YY !@hbW|MlUJUCd.eMy1,Hf$ 2R&?DV@SyFVUu d뮊㴌ѴZ1NxRkh]CȎYSEݔxM}br::FM{S-Z/S5w?V-~q%jQ݁1ן=d聯I2Ai1j-gGx)`ƫc|s#X-~[RK F("23ZA}"Z.<@/A3Q횢pJp5THb ,[GYHHӹ )@?v=Cm1KR$(V{Z?YvWo\5d5!b+lxA;jrZMNYS@K38&fk*ƹD6p 4<$bA\o]M/:GDZ<~2^6x3*M P9LGiK4/X=1@n^]ʹT}0dTeXK#uN@Q/ALOl Oپd|+_g< T(#pLwDaXg;k uگ!-b%uQlbm}^+w1XdYK fZ<gKh6"Nܽ{Pꕠll/z+/O:wswKǏj;_Jim5t  b}R l-; pKӢ^>^[.hZ{㸲@DJ@9&Bg&_SR&xh87>Q5lMYipFhxBߺ츶)鸅oHRYK|~FP@gZ 45텐N`˄ԂQ*oI -&ebW8Qǧ?qN SCu OT-@R{;sIRhA!vf74 ڤӒIe@Uyq* oźdQSx0S"&+(ke14}d]( z;ZkO!b{GRq6BD%fO@R@Ȫ~v=s}hUR4O^.u/fRh#o  *eboZb(H /մRF" 7ZPk)ִȖb|#RCuy:kY%+0Uz9@ycW55vo␪K?)Я2w'Y}k-OCKd D+sÉB)KkRf;L 0LydjRcB!8F^JPӦ:(6FiK* Gkncڧ)'P#m㯐Y%e -_@AeIe>࿋hxDj-rߟFHL ` KjoRm\` #ԅ+RN:p783-hN^:UU) poRp{n6| _oOek]; TbH}i#1̿r]&SO$Z w{O21Cc!Eo<%A _Ǖ0ܓw7>.z} 1a)T.ӗ?n`G'µ֔&o&,x@IDATR1B E]&ps: h7yLXKY3 LDf^rA T>qLj籂ekNS cF ٔ01Z,DV Gmaɶ)q ҇\-[W?K;'F̙`X`*qJL8يA[O[ {/{oJL*OC/ /~b)⫲;MaUeb)B8_\gR+o C0^"f8G' @Oƶ?zl ;aKtf0?|Fyi6I!avhk3m3~RhSl RzcJAX=v,zU G9x.)72|xZe[)쬌gY bF0 {*9S4FZ,[n1FKgM !RưdZ *sODō^Z!c4dڈe_=/M_{+Ju/X_, Ph0^%#ێ$A>'A`Z/!6R)DNbtdd9|O/KPkʤiH}|8Dx/Tn·BץNK-΋+,െh=I&+ -yq" /AǮK}K0y 4d8:!j\B%۹eG&2T^Tsi_ ^>  bfu`hkȀ[`ڗD,$5[SpTl+Oj:wfʑ{:9UwnԻrH{tl~%-ɶ} -|VJ^IF[ .|YAӢ!fq I MI41ּ8@4uLW%UJRƏT WWtA\!or`3?U)_j MRHS, mjzuGm/:]څY[^Q%(V% 9!. ZBʲc ^}3AZJ_@\a▥2bKUx)|OkhT~)G1XU[:q1=@| Jp0 ::ʲ* oGЩ䍧;?6IѴ(7$rpd;#(ilc+WW LuW${vg߷"~kxL@0ӫڠX't6? d11$P)h0Kd- @7@ 3{-@,gZ;^5āhT6cHqGxg"THZXO ߄Zhjjt񙁦t{OS9'5"JK\hgdn(kM \ | dRJLpV( avrRqe6\l +e%k!n`8DS䐍.1XϿr-X k#,q/+Tl+q}ۇfPŦi;! `T BnZڎ]! L!-π Xypf`+)𖓢 Τ%<&]ƀ qعnҕjܺ[HK*ԟ_l[TKv,uo dpU5ö㛇O~ ӟbx]f#(c#gT3Kٶ&5񔽣 ËVd])׬W.iƧ)7-qˎWZnez17OjQ5~J ( ɏVy8HJlTF?!D/q-ˢI++ϣ%lU" ~۲Tw2.rh~BGQ5ݟ!hbr@!nqP[.ʤ?@)KuW7ǒHDД@,mejh9eZ$ QkRixb43Z]DHM#|% 꾪1 +> bS7:YMV  hQ ⤚-~ ׆ɶD#[tXf˕9oBjP|'`Fk abT-Jm*9Zg8ВV~|SZ,DLUaµǏ md w?jox^!af(BQM0 Q2&"[LZB"鐅Dx4'F˜z\R4oi64Ǔ^gkK{>|4 zݵGa%û%Fi1~򮋧'r2@OOYoٲ k'5\ "(U,k+/Uł YWKjY,AS@f|0E|+ 9?؍[&̠hCӭMn‡#uk) l:Vml)~(Vd} By&&·He-0![ ;RB&1;PW'v~moxCRKjZ-!5xcRlT?{7{QŬ"_é*~&ݲrH8UA0Ñ b1-'(=cZ6@ Zr{W; u\J|-_׷y>z2ᎅ>)-la$'~nd-uh.a& ASIY+)TI/ŊiƷ HLYjS; Z)X6vY m8MY4U:Wi)/K9}x, xhvn[KW0/H׸l#CJa6%xYN9U,HGF@G.R4hyMqn{W㱢VSG t 38B~-m)PKx_-5ɄLq}cv<åGa}-в"DTMoJhm kɧfr|#) D8yKV feȼTRY㨂[" o 83!@o ~mo)u l-fq6>%]N7C0N)SRJy1ۮ Z>$̴ȪXRSkKAW]տ|8A^O9~Ӗj ! ?p"Kj 0k>(D7*~KY ,Aeo(hG(!պOci7ORB ~TRC׭ Z=."A"ƦczY:zwx4 Ianv ˗^Bozq]phV BWMйX2WGlZp^D6 <2qR8Dd"4{verdK |LbR@K`OMJR ҄@Qk*.?OO 9k$yRu ^P)l?t h6#Z&)v}LO? ?@؎F$#Qm׎XP6[ Yj?hmG|G!W Ǥo~|a4AL6kM gVpi{ydM(/|7I|a;xC[u4- lR.j(,,&*K)EF,r6ѐuQ.˪aDYxx4NB=ٮ-̒)b36gvpJ,V_%0UѱSU±#tJ&DLtd&Y )ZH%hTVSK.=% 'LgUA6F|!uK'[۾^tɺZ0e-k,1K<ElܭDP')qRb% jqI;L,eA{y]q'P{?eUPB͗?>ھ'e&bXJ)$w7"; 1+َԺc=T!/'.0?ծT(f8Ժ1R0 kͫ%e," p5:/owj V\J6\y[ɒ %G6ҩo)ʩe@K{/B+|R_SᶫMaPSe5k+I-ך N xj\Yt#3)>eEֹ(f3/%FxKǂ#^4r)UyG e:rulF'oR).T15CIa"dJpL3jVw!# ,5M"ib~AUjY,1̕9ʲ̝vh#m010ݖ] (t;5/ʍanhFeBpR|4ZLJ?KL1XKN̆it2p>ad b.D%[`v"M!X*(EbQyx BpZo&{!M4NA`2UJR>]/0 Dv@|M>⍥>&$ Ii|!2lrf<#^s|Xf._CZlR1}o  B-el!mDlˍ׽Ѳr8k(/>AU?5qL #h8I;uR[ plJ&Ra3Ь?G gY,$Q- pnTA݁>w'K]v lͯU5@J15=;8T՗4dZ"B JiQ5G, g@Y1f4jfF_.⬑CY 3|+y jW1繆1CCHZ~b5zҖpq`RNOC h0p1Oݣ3rkDr6EF/R ()lB,U%0"{G]0MEG#tujHW(ubZ-+l6~7LYzan^jKj_ OwBR$JI#$eS LBע,<1u!(vT|i O nD^-/f8R;ک4-I gvо6/k gN/<=5YQL\]Zƀ d wBxfΑ tn8FՅ!-$ZF70 7/Z}l/\kxMT- Ryu0Gi)i{;٪d$fUK;\ۑx%mTJ"~޴К6޴e#G6@$dq* Zq%Rnqx*RS`|/ZXy&k}/wn9g~m xA|3@DM-:**,&n5mhn)xb D8!+E:RL;AZd),wrYrY QR`AdžikRVO(7ꔫwp%M !HJ vb PψlGbUɦ\_qESִWg壒 TNYbmzԾ$ņK뀈y.fW㶣,E)f+|8153 K#Rk;4 j,5&٦M-` O!K͌f:se㛡mȟWU_wn LN ̚4,CsPB%y"e)Rd.q4]a!@q {sLRII;,Y1UT8,`R]tWK%[bԽ 4#n8CS`88%?x;#_K*dMR/m0Hf[^D̓2P,h~y,:A^` qL^9ZY3pb)K^h8l`4I_-|6=\M[2N^t;qH ZtH|Yjb )>0Gyx2D ; R%p.-(2-SIRa@+ɔe) Єw dYh2\j=~"7XS8o gCIHhLDLӧÈ@dY38'tI:׫a y^?^`vHLP x}v/w{t#Y`RbLY`)nT4I&D}B)[v[!CN!#ܷX#fǬlt2b1!_uTnu|g##P҅6{~{K0ډy 06%k#z*G T~ @.C2ϯWi6T+fԐrMmб[-q+$a@ב>eAR4;Z;Y7@pڝ%s _P`f.&9e)-_YrE-F 0\o,Vp,dSo2Bł|cG dFR͖f.GMJ)]b7i|XeA\Ne"/K 2"D|>hK!nf5CBpc4m%NSa;ClxQ&2xM_q4$B&$j(oU[j*ѱl MՄ@AӱByyZzM4[mm;aA1Ovʕ9~LVwJ;O Ꟃr ܎usGe3Arq.%"VKe!yWJ nS|RY -wbG 3}G(Ft! ?UN,+bt L5h];Ɔ0eSRz_],/sdy<B`vuW }=cV^WJd pd;>ljVF4A&Z0~I~~2N9X ؖx - d_S4%xKay(Zũi}/})@@<d1Y:TÈD4'j- #BPǖYIc6o5) >a]#<)`MyRZy^d1k*PDRkf8c`6%# :yF|.C,k-SE# Qp; Růڦ^iidk2AdqRj9~CvAU Y!+\ &l Δ(YD$Մ tMSR N#!4N_yC)'ےD̫jS<9f́-SSÉ T%`XK;jbNѐ.ϣ;'gOw:l[3`#BW~ )!\==lB`?s4OٽZץTbYI\- T1/}8ejm9dyp{MbJBxTerA)BT vp(MLy3\}*34&PπX_Ut |:8‰ۚHMX˕>{RhNkEC ?I!+L$~"pb)x<ɭR=SH)"*[++Q"%ɖXn HwCf#׷*xAi)1ŦB`"Z/)q&_^A&o]x/u?XmP Lkf#hp^J RP {}K6NOL3)+kWяo:S^LL ,UtZ[.2BȝC(ȐE5cH L9&2o_`3Z &CjaI!׈UҮ8eAbm3m`Dx1ADƱ'ez2 ].%h %Nf)Pkrq4 B3qnwN;S`b4^8fBGs^%,]-8 [RYdq8%4KA;7{BLA__5"(|cҤЍ7B@*j;Hh|)| ھICpeY#(,>;h~[FD/C!p8{-v;z}m;B0^Z`)__1VިĉpjW@1#f_Mjd#Ԉd%NyENZ2L|`+ 6C=v?LJ;꺻@w}؎x`S5&4 "1cT7R-A#cA;h@6i8&K0F41lJRRʉfy-6\^qFiy?D4X=r֖ \ L@׏p#2 ~?r8S晬 ➪ X-6jRJ(xGӿ;s!iWZ'"(rX۝ԅsxRDvTɆ#*mAӐgX ]@/0oq~-a/olD6 S(6= 㣉BtI!#`K45R S0x?PPT bz_LY]6xU Ί`e4 ,Td1`\*rRR l]AA8`F!SՄw8%|.1<M1, >m|؆ZtdbVUA^0j )MkDW.ȌZ_-kgD+ :F*>J]3 Y)PX< z5R;mm#=q!?ů_dUni~.<|0ٚ:B B,ChUf.B1~Zk 1ݥC(r)˵XHI/(f!VJ"ҀLk)5lYTY8˗)(`=ҞS3^E +'GEnW#ȄB&L*42d8BQY6ԻM&Q#K2z֔OΛF+1]$qD z({z }*a4U6AGl /5SUpsL-Mujd8P5P1Kj~{% 504IdcD ^BR~^-y/(GK2H 3)Xʳ_ġLMEBୗA`4qORsSyBB*DӏPE 5Ck P!%)ZU ZR83L"̈8g8Ied@}V1&_<N3-S&J0 ÆB:ḱ֧2NDHcц)?ц{ūzmKTq%TP꜉sX,Yxh %ory7E17 ɚ:SQ)aπhY>,# 4E0}`^;/dՀ\$: @JDCL91!,_ b衐3ӫE*_um;G @IDATʥHc D$eWKLߨO!nWF4/`FzȅO_I՘`G.Kr7q#gj S*VtLEDi8!I_GRp鲌*6r蔕)eS:Zļ2& MVHHHk *MhHi*eVCŴQz༨U>IcCȚY[RPfEG_~7߈L$+P9h&0[ژalui !NQNU7#6t#Dt(04QoNӺ}1zn$V_zn;(:iqkEY'mJϢqpT3EMє&JKKC05ӑN?) Fiz=j,\63A]eyk@-4Fsuk2qttLY~eݨN$aB@RLݡd!pL[6fUsDt8)?Z]4 "e8G5/[YWbrkǡeҩ%A Ok[ BQ ,9]/Fט6DWbJ>7c(]qb{+ձMB֊8pa wE* BJrtPo6$>D 2k[D,9ĩ{(S/E#t[ N+ג@%L<hqԲ [{4ǩєLŅ/ҍ:en$ 0UKUF nrEM;Ǭ7Y>t'm96J&8d',={DRXKE|L%UOWc*Qz s}4 IH&˷"49SJ&H@t`lm'*%|MZiFӌK4+}h\<8i@b @'%~8Sh9qpNH M q=\gir8 ۮ~l 1 dwЇ 5i*`Vڱ/!J3W㇎BvD,JViLu !1p \H Bj%,5%ZXB!%aP:rΫK Fa&)#հ7S(ZvɅ|W {oM**DS9c;4#hM:/q{l! hpF|]q 4').iAHu%E)6 ǔ>Mΐs`l N%XٽD%.t5xJy*M4_aT7֐vlp2vYrDéY_6ƑSu4#3yw74F,*i%FYR|6)})0ט?a9)PǢ,gBGWX53*AH쒮IJ8BMHȑE9U*Z2VQMr%. iB[D4 )j%4m'!nFc˩z@#SHߴҍ8z_fВ)e`O@}oO8 dǜG9GS-H0M"4'[5Ksb,BR;098QQSEJ7 aree%Sju^'iS_IKXALm 8m-RDFv@|5;Wl!/X/HPRBN-m;hڱ^'.?j)|YF{6͙[ߏ.S]qo4R '\{+6?{M k ܪSK0DhrIH/܊ZgU*J͊ĩZْ 9 ugHg _^ďAVnԆD!IˁOV +gH%@AG9_`7O)8oN*K_:'F:]# ;>ܙ# d!hF̚"38ʹ2_3|]C7ZBS DUʊP %&kp,`6"* ށӭ3D&8+ O:D=Eus%95b)C Yh-),d|NB1bf6ů&?j4 _6hZ3**x#D!;YimkyxpLsM;D4_nB'>dˁ=\/Z\Kع 3ථDj Y/&T1n(MƦe!̔vnMlJ+o4eCSӳJY)y" ;c[ #|і fd ί|_sȉѿH\kXk-mKdL8?Z>N Ȣ@SN 1%FHδF5 ʤ֒tS qZue 1S= S.ͨ_5`EG淜SP\锲Qt,LFFM %# ^"܎Gb8҉]GLH]Y!]/8M|^ )ueBpJ !/1ߔ}-ܷ%~Y-U' Ozgv}&%1qnBH!3M5&QU@S~4kMGN"f:8@SM'˙N˔G#'0ZQc#M!i*Bwvڋg߹Kd^ K@4%C\?|H}C$VZίNuU$22@ T1q*h*" [Ѽ!0dR {]{%YKdʐG,=S!>)'DVE9d|ꀔ[ldcKSi4>C0ubdk-QS" Hh*\X+8?}^qTzjHn8G/9v*v  %\'?N bk ^[fD^}lrNuLBO|OWĴMi[`~+uTJIA|U2D 1LmXA|)KKt6"?:qǜfфDYS%y, X׋6 Qv=3/LJQ&T.')4S9;1-CW.;v@,%b:FŔ˗+nFӪ,Ήo4DEF!xN4LE6 XZ5JG-#X?MۓDj 1]8ȜWx+ d>k0eQb=oYKG:;GvHjDq:lj19_mيNfjU_En41<.a95SwЇO5IUOǸ(*-$Ec|oyI}x$6-)ƕlm'-VmQbR@Vi{ ?@@Bs 1+eW}(!B픿Zr}?./d!1G/瘊R5\7 gf5RFQ055j.t"E#p)J`E22LbF)p&Bf]8M'X҄"p 0@|H4yyVm*%Drs3C@p3V/"&_gրmM:Bֺ8RZs=T/eq5'av+r&dq:]Q6%/[4/4Z#I_}iZy ƯsmY`QtQ?Ͻ.򶚎\cFsS:#4rpړl)Ĵ΍R9zSHQ|k dS&6U!/NTBL58L81!/F$$Ocm||cL!:4e@DGWJA (L)>B)H䫢BiJ$5<! M-}:d#Y|9b.= Je&SnJ$" ڮF7·lӊ !S#q g#"G ܾytASWk[_؊O)F)Tbt ?Ae}։w;i 䵹­ir;+#T= ZEv438l_t{G&N r%#đa!Yd C(6O8Ӻ5d-JXI8+$)q_ہҟZtIYi=5:',ތpV'BNl<>9V3ե2d('K/Z'|tM'_[2Lǥ\%ZF 4tl,DV!jHhTE\S#*Ɣֹ;GOʻ c.0N[9s ?A)!3rmNA'5o] Yf˯P09xcj6X:>CNd,2ͫT)WOA#sJs![b")&n$+t!BSXTV&B5|Z|;L c!/R6)&ZR qZ(O@(LgD-Sf|c -?DVbi!!^gvZGv^ŝϚ8R#9g r"9iBj%кl`8p,1NBzFPR`!rV(C/@\GUKq rg)B门JRN~rIqX+ⷘn}c܍B̴,N+sݹFpEtHLƚj;r-D@SiDRDIс0"(ȴS]N;C8?~VsӚnj)9e2ӤEyVYQz@"d|J+ĩsԕQHzRX|UYϧ,cc =\愱piCvxx?Sl?E.=h4T@#HM 5Q|FS#sT&'%sDq*Z-@V9Jâe*aԘ(܎q*$h8z3҄8Z+/e#Qfw0u4JY~j)Mc!"/ltJx'BʞV:azf6*>"|Ig"7dsDgć}sg[PZl(Ki(d/$V嚆d)Sb"\84ҴJ ;8RcT jX>&ƪKty!_f!T S-!H[,%/!\oL.-BƦ5VjIIDɯ=VVNR:,בݳ}VK)Tu,3EBpx]aBC/kjLV|d8xr,oK;8 Rp4F!32H8@i/QQLGHt,'AS"dL։>q‘M_j99h|i*'h &i"+,[E] hُEWN_Ϛ0u1@qklG#~)}<zEj'809s4@X!`n:Èk^THa־u|D#K\JJ&uU6;qJg-HJJr[?gH=b}S4٨~:|=\}}\>Dt;f+Loʑp lK9hu?f|bpl L-Ȓ80Y!r%nh"p2Wr֏cY!,5#(\#tNU߁BcsZ'B "@#/ܭDi7JkYр|[^4j+9)V( Lu!42Z!|iЏVFL%6]y g|fmrL;vw臔b7vثDhqLuRL) qiyxܺ{+/jiw3˳?ʬnMm ~:l(+)1ZՉDZ ?誑οk9LM!kOkEy!WE:Xo D`jZh`; d?d_7tXeazpc>P-ߎE0if8'ā9/4ꡬ=!dbVT:.+D#̝D4gSa*-ɩjjT SCE)/0:u#BE/ʩ )CsHR;WԺjqƳ/~-q'wBv 7ml𙨮خz( iNN9q}Kg! |S]MS)|C3>GtZȢ . "hbZ5l sFvTWT3mXvؔ)ZUc*T'}ޣ=~%g_+Mb gn紐z4&8GȞN`wӺjqgĥkh𝏯9{.߳ pAvCS!ֆ`REu iE9&cvRDKXD8R«kl@FNEVZ A“()Pqp- & X~N .Ui#K/4v%ZYRYĄ( O#/=(%*.W!&War@+Hs n}ˠWunRj?Z*[qLEv|m˿[U/.Y!NBM[ڇ^ X+ڢUQf35%&Fv,Y@SG@>羯7'ݦRO`DB%R4E gɖotX!kmݣuLM'M~KiTB:r\Wh~W[|e08C"X3Ze+)Ԑin/ F ٖڬ2MBu|!8>5pOi9@NLuV3 4Ss8_yPilmP˷BVtp=PZX{e[,LF`kU9U\Hd)@Gt 9dDӵwؿF`d\m;VH 1? >{ xU*jUKO6 uhhX>?Jx- nB "Z{4Ιi힣 mZ5*b麹B})T?q8;=4j8OnX6dUK7B<-.~޿Ϻ9ZJ kj?YzDHM!jLc|T7%hZd K㙌Q*|>NvAd~SHW8B¤-YiƑD~:@)X[H 3LmsBMcM1ʑU* XdS4SS?lөk)dXu*b1ݼs\TD [ )98#ҙ5ƙA!ͤmo4`yFsbtMKXh DFsWX FfTמ8Nݭ5vP.,jCW b* 'ࢁjI7R5>qqH qBȶ^VW5 Cv_ui<ہp4t 3w|'R-+ZIl m*V xk4򥤃L,8wU1,kr7vd5G*zBWn*뀣|#\̥5˭^Iu"&)`6u/tTWh|cT{mS o\KZWJb;k+1BN:|~h}(.mX T=S!v/h"M[p7kAMW}zzp)duMDZ')c`9Jm]u5] sZQwTWq_3 MHJW_'3KC{yT_fϾ\npR)s->o+] N}r[LIFuIViZCm&_.'+QI8Z5}xxdxRt ^Vgr?# nJYW,r8;U!p94R.lr)%Ƒ2?&^c1L8pdK6!EQZ^ Af@.S9gAMOD)X9&ǡ ._3RK_WҵG_S|)|!k9HDԥA) ̩DRt|(t(U1%EC2S]!9_nBW1Ͼtw@k1lO?ߔ,-RN'ZoğYƜ%.4 ωGϘp `)m,fh>Zk/$"Lȭ0FSqlbCW&#N>*@8P T Дaּid&J.1㳢n. Mq8D8*r ya7J$jE2SN,\NEu c:*VL-&#[)MC`p#P)J UJ̍Bp^cc^-Y!c:ISju(BlTֈ12"Q9)SڇrpMA u=L!CvNvj6Q,·B&(˭Qu _"r.8Á w1; [Gqv# v ={ 擇+"Yғ2@9BQH܈SbJ_-f0!h-V=b8A$~|y?$Zu̱LdMDI#f)D7?#0&i"[4qE-B)ÿ*1E.Ŕ%e*djHg`mo^{"[Ƭo5L=]Bro+aiaLӐ l9r[~)ӌS'BZ%&kD+D6cFm#sc(p)"Sk*QjVK~:ѹo3\Naɶ`AX-BuVz׆+Bi@ `Սk%+~pprǚEtY*ε&JOѭ9:tqB8ҧ 4DhR6@pĩp8U*J!+ h@|(G{NS5ޥ;X4YN6G" O\|Yc@8ԸCワ@)l +"fJvn|}EEjOHz E4tT݊|Ѧ:o~wsTISN1]!S`@65*B !N ϿݿwW4V \9̋,-6nTn-s#?[{(eS84mCѪDHb=JHE%ڐ|{GCt\w>9JxRE}B%]VF֎Һ6-ٟEi`%H)Z'x#F_4tojJhH%Qa*)KZ-" @=-\FGHZ*zF 49dJM4) xE*iC,ɺ 0Zu/bdS:Vh)]hd>vVIUK:'M"ՅeYcadt$)kB8keVn*7_Q؆gϵ'22!etg3{:K^40 ,!8~<@!7/{_?r)6xQp:!zn(q\%ɩ+d3qUa.76χS[G9,) '%OO6_LG)cugp"_jB=~QF#-NJH~js en*]\t{4_? >g=42S|c>\ xՙTe#q\&2|TG2̐c ښ+]_e$^"@"p L)WH&E,5R >FZu(O]SFhME!Ɩh3{wv}5n--j3eͭƪ.dܑDΑ‰7"wLm {?<_w|>i M[ZխQv߹0VhF%pJkEPķgM_&5͖5饵s8)#D~:YVT m0YB/vAK. :x :jmdu‘`[82f_ȸՙ xI$2|q@bp"p kG?wu'!M!S ٔbK)iKup,cj9!PߦUL+7*"e/G("O>g8)Mr;W,ͻ(HÜ6XBzZ-+,'.%HuY6oTcuF8s"é5ՕĘ)cYe:יִ'o'^T%BF|u9qr1Qă^?}E"Ryhj'WnpmKA)DX4C4&M6`vc+J"u:!-lo~i%ZϨPWNՅL@# :<+ޢ K$MЩq! o53)N hjl Pm@8v?kY,nl#J ?PruUJA _}NDrʕ!8UeS#3SoKT,-9BY[~u9B}c?=o{gc[fj;6rÁ+`J 4>μ|RoI2>9uʵ+7Ydi_RREW+@9|b~QwMZ4 lBZьˑ˗✴kP׻Oq}%v|uբ) ^?Vr,KWp~ |&5N}v I4J|0a%^JBW[r7tGQc19-L8D1nxlH͜8 DSΩ1D: PKRi,Y-8B`VNR&o~OMy_m-:az[êݴ&/fмo<:*YE~U̩=)e2FOPf2 ,2}ʅYQN ?ޟ8\nm )(T^{AQQGǗK)C:}a!exAof4[B﭅rsix\5v˯4ZmߡEh(ݟxF =lRDztqRD 4m3 |mfESi?F!nVĬFR ?nM:F>MU7XPiOځ:š3ڲ*80>Xrj9KǡNKsnxpLn)uY(JԟN@YQX34Sm[4 Y;( uVpd13#_>%[B $(xykn[pg7M&a@I#ۆ(~LMGU1MJUPv+>?М!zFFRʬFU"wOXJp/~D5/'wKoxB_-)UWrwA|ѤfK:SBƴѦՒ"|2#h4%$ UL)U7Ugi2C%8:(%2!ux?c}X􍦉9T;"L!F)%|HяO<*?-Umr#2Q#YFu&uq H}!E9jiq,5Ӛ,߁!1-EhZ௴DL S>A`g65󣹹c:z Ҏi f.uXk6B>j%jCE1 -p4 ,2{D+<YD2d]^:T!7Keut^WB! IZÕ.? ~%tC|!tڔvZ޵5xz}SKRS>AOwYL'F9L 9L91jhZ3]&p:@Q8B~rt8Hj1@~霚1MZ 1 ] KhbW Q[u`4%‘"L")GlN6B(M!IS×bT(AXL:0с0~)\Qrj _/!9g%UNkp{)r qLLiW~#`49A]vBF 鐂ddj۔ٺ5Rrx5BLVcǂOB5&o Q ۟iQQ%RhU,A]sEؿf97RΟ6\p|V@$Fk 1tujÙIЁ`De 'dPnR 'b,S!Z}^}(aL*+! w.I1nd3)I2C61။"B)p||gc܃d7Ӊ˺?y`~)65V^NsRZ$5:9s\;Էm@R"W]:ڒNT|Zo~Dv5JD 1mjb8uiZH'Լtw9@7M46(2Da j9HUئm=NSN+ODI; n48! Avo heD!BI /SƤNÇOV魷DosvH4B-U1>Z|fO匬]2V.qΎ\FDk F4kαF_V7I-U#H0Yx$sX|q+trw@[(8TARSaeV>n-66MSRH,ڊp{%&Rp'k4SVzwc{GҪ%◸8+ (\ FbLc)z)hگRBD P"0:!~`'req<~pY|WEr)J;' n? zUQ.6Opӏl*u˺KN/v⽆Y4*-nVm4cIZC(ʷ]8R@R.6[sKCꐚb \ !wa1'?]`jYF ^oO/rKlWRȘ8ғ2}?I^t!6dB@6Jl?$ N '?Z9՝JO[FS"ư)PhtQX&A!Ɓsjͱ04Mos>n!P"dRkic\+U0Э-iN IMtYTBDl1RJ!:?}[Zp A>:ObHJ:?r aR]+w%n4'$hrDL *)<1}*B4L?_(eQfjEs!z`фƻνsnVDXԀE1io4(LVb:BXGO4DZP1wߎvՊC!N֢64fqМ]·wq2h%K'4SRd9m ͒l :?BD!YaP92Z568VUݎDӏ%tx'6AR=td5Szi!|1})E(L U8BV Íhz̖e-ƎXpK6y+!~ # -sDKO!r9Ό!K Y&22~hFij!g;{n⪓Fp \@96,`FiUq34֦M0k.`FZMg)=Z;IjJBTÔ}AFVDcjL# #˄۽BM>۟&5!rc|j s* T)FqD5q{q*cxVy>>hAS`,ʷVbIi@>LzH Mj<4u ?AsͩbէIiU"DMAMʶ'N{|*]'ZU&n"0Y##tdMW~ej4JQf֟PSRa"pJI A68p22,Ќ@ |3TKZ8G}\|::OG9SBBF+B B3`%:ڀ<~}H|#AbMEMsN8G D!)hRuь,VqQŃ=(ν Z;POӞѴEKACȞ7kS"62j L Gv_zA5SО\EԤ.Zs_ߢVB[ U+m4-]"&>':Mo@IDAT9Oܝ{/ g@LFk 8ԀR淟eȌsE;*%֍@bl Ja!GTg)&! 1QbEL|Qvq!peƹ+~!(Y]C D#oDeGH@H Ëtz ݳ>Ϥu";G@ kGWϼMRiϬ+K)7: ݐ}/YoVWҁ,&)n(1\<CH " iZVcQJ::[gwe7zWJ)5dVW'ځ/Y hբJ)Y׽⃏i+:J,WCB54vviFSy:Vͱ<Nh -Zb?J^)?4qVrF3[dhL#:}S ZMGMRhUgݫaъ"qϊ᛾pR!P6 JzF`tiO6G¤JDHqDuR$$ou!ƶ#[o[?ܧl :tn+"n9LUԃ:(ekV(jU!c:."J1dTˈ Q çv9NiMA)ć}[nƖ0 qT"oʿj(Jd1!8Z@UT0M;D1Ke2f||Qd[oե`+1䏉_Kdj ׃tgC"Qؗ(H*kj[@\.J[;/h#Hi@ޤU7ńXDjߘɐ1pt*c3?,Q.r]=WW?\l65"ՒFʢD|"0 3ͷ/z#NLSvMZ@SPk3U(gN(3YV )8\CP|!,Nz'l1VБN8}u[idU;'+gTJi ?~C_WUn!Vsg@\d^SsJqNrl4VJoQeZi[Z/T Ҙr%ΆmYcir"t@$ؙĺGeuɉ/&>GH*5D؉H V 1w(9N^t-ӌS?NSoi@6Ĩrj䪞NJ4Tm֊v4/dFh=p,>Ϋ#B!a0q!˵AђW~W ۡDYĮ@x!8GF1q ʹjgJ+*7YjՆ)S40EUZ whՕFd]%[&aS >*Q4Iah9嚶EO81WXBQ[U'MR8ucBE4瞫JY˅׉6p|8tQc4OOʡB-ň4lKvUB:}rgtU7VDbBBL'p Z-OB`M}rI4 ^KD*M_D4;pׯTnKeP ȱR;+'r.WreVF|:9hk(ĒUs0LȘ|L*Nyo^ȞAreYl on} D_B?XQ91X6#2PԎ 5Wr<^|a9)4u͏]tDRd 9 46`6v^-K֍;_&e65b8n%Ta_oYL`_b."(@`)K,aP!~%R]ܙZ\@{rʹ)NjRKY:h@Buq 0+Ov` 绱!]/EP¾s'Ǐ?Pi@F%P,ÚV֭C-ś凚)**VBMP;Ggijo1f4%ljEץtvo-8N yOs+b6JuR0k08ZYlʖ0vqwQ`:&w> $ܒM0JYY'oU}m?}65 /$~Ȧ;ztv+*]);Ub7oo5HhxT+h#bYKUC? Ä3RDI@;nEBF NHRqXj|Y:lR.Nl`d!FRn?Ȧ 4.UUmH!)h@:M]X)KY>вr:hl x=T$_]CW{_r뒯Xh&b0;DRR| A`=3 /!k V"k7<&ZqP " D%/_`ıe D=Km)Y8o#Db4*xA0- JZ*x1˽r3Q@\9ψ}XG3k \|(yJM}h)&A!0F7!'S65N ^k'eYk|qAUJ01Abq^ 2oԔ(k@iqdӗc$H";_K_#ͫNST" x<~glwf]o)]ح<<)-)cF~NtA`aV֤`B̺mwx>Rb^-b;.lR؃BKGL`~AK0<iO—D!ݾJ偺5m)npǿ@&_8+G׵-sz=ܗ3=yiNmB{;Ԩ/KJ,AI-pZY'SJwCs38 -4%B"fJ0vś4n$Nԥvb×#tq ļ3:D4 Ɋ lYLˤ6/?e~:;47Ȼ^2tavmj[ =AK#U+ u'`ɔ{oMI( Ak/B!m2&FbF!@ B--{ZM^ZT55mO.@ǤJX9)%J_ [s?%^(nIݵ3y8T|OORV}uj{! t/@VUd1Bd1&ϼ{돱Z/E{c|jb4Zdئtbj0̆o*A4&Y4őC9\{c4YfTf,nc8U 2Ws=%uh,hmg@"&T+[7!>R5OcwSK d.ޞQth;)%!\L'; e,TɚA ˺ZbިI;vxKE`dy (4՛jq]-)(L"%hfZʲKU|x*yu,YjjHW"@b|"p&-;~uGzבTV MS$%yi ST1 x& #Jx T7T4 bRz"]*ڑ(bHSG a)$ iJw!@J h67.{xj#|οKWӈ%Ғ.àزj9>56@S4_/M:̀/F48^#/ߙŁ+E!IV'_̐BwjeS,K Y-p0-S}xRm3}UUa^8F iD,d9 9*Ԁo8c* u֠@,<,o  dfy'꘎.kJaU&g(4ZH_d-bR_ks;G;NGƌP 'uy9>}dqk<#Ҧr4`ߩ=wFrȆԽNH \0DI3A9wkE6?+Om#))7%k<[V#)d:L)Q@@};e!m "0BIXK__ )?C8/+jW@MY#۔g@TlK[~ V>AT #Glje[t0?$f fB: ڋODmdA]Թjk9*'U{$ڄ gxBRKJ\UL%8.F3GOypۉ9kSGKI5+-L]Mȗhd&fzU Ch 08%e-|槁w%N٥Ř*LT(frCD4!omjj8b&H_PQ!w{(N*6M_m[YlAt*SU\a"mٌZ85J͒TM t8ZGVJmdOWhOK%%$ FAcgk$§M⽇z!ԅTT@;A (wβm '%ftw>'&i TmA#8Tl*%XLNMRhl:q"|ʙ{'ܴ}L '(~lp";t:Iʉ#Ҩl ٨h[w>{kO!dt9 Ԣ >N<Џ? O;pg5AY)BTӇ3q#!≴Y̒!{VPǂDX[bBZ,E .pkܲJT Lu`j|vNR/1)yِZC4msZWÝ,&K^m/NAkC7bLEr[+./V 'U%%NE[J-gyHu,Dj LYN"pAAaH_~"h6Nǒ0-)[Ƒ!KlF8 RmY8@^68|]6Rw Mw 񛧽ӿ-+s}#)<2bI Vw, +db; dU5|"WLq.R seFI#/[̶inrUL/\3Kx[6 rj]dw޽~RJ!aAĹ'p|4a))3l`s(Vx_v@2|N?o%@U!|ڬoJ3}r>suKY1ԺXZ,4SdqBx֝ Hu<_hpup]82ۅ-[!vRxEH!]{qCjKE֎T)4:T6:Pe:Jpx`|9|#$hL0 * نlSb-U|h&7?$nB}%eANU0Rۑ )V!Lwyߙ֜8`! cϞvDlmDU105U9eqgL('n /tX A/xq; ґe{ɯkj1|+mkI]f,gf|gk#bpO4ud鈛8Y\GA[~7&FQSHϿw~'Pn4R c7F~V14!k*pl٥"!bM+1&ƚ$a15}bWՃf46qE(vydy KQS X_=c P ʒl XS#*@@v*ʻ;?j6]Ӑ1\V-TY!NX*'4g)K{LVV>#C PIz8}/;S ǃwY7 cDPEY#Ubٖ}yy3౫ӲA1ijHۑm]׫Q irLoNBSU؁ 4j8ۻuێ*)OؗZ/u@gbY1Mj<^͉ynwCHZ}2d]N-BLZт8P' &+l0ߧcw8 K’WpRRѤ8M.Uqjk!Nq)t([*6ʁb7'5WBHj)Xf~ceRO _y5el]A$ZԥClxOAԓJ-QBi-kF)8H˺S3*H)g~!^Fdh@(^,)HW,A{D(POo \ӈߜ lD CN8oPBߏ? ).eM|uſa^_b/7˧FtLU+6I;Rf @|5y ?O?&1&+Uv@˼i*lL!(GdN;d!%|@K7>֖/ _$07@ >3"=}xW+48]o řT$lNoP%?aeן+|5J!߲A߶)(NCTv> 0N:4cEwٚv z))n;M". HC\ )d oڵ^l/l]G+O#$2e:%>C_W|7JGChobZ/p7yK:Iwg ւqJ^\Rf{tc4C%AsOvGsκQRPf iIq2sb#Ӂ\s[:/Xɪ&6ZZ⻁ɿMIy1lAҒlZUm "n nfq9t}wI Z v1ژX %=p^~n]_d n)fScfpe4xA]ttxUIgSem>@:j<q ďRax=~Q n@{iemć}Y:mL$S׫0l1q٘|d>hm_%ٯW._ R:)RBI$ZdR8+vD#abR}hY_aUxD0#E!,WZ=!+%\|"MpDAߞj^b2_#"DSu@m-Z iʣ D\{S pgkf┛F8RTbHHuuJK@=AhBl`qAke F QswmG+*p0q΄XRȖ6xsvTRuǷnS.}_َ.y$YJ( o;Cn/1 Fzu8bYng@v ^xxbq4B(,%TUh)Δ;{ypϠau)#oHUŮ>T#@++*޲KDUA% l&kcUǿp_V'YFV#%p|jm^ ԺX*z>a|t 57a_ܴbAvg`)e)$a-XQx2}l%mHH ;XQQ(&=~_)>{3<1sRcЄ;{ 94ۻX [khKWq>oqK^#]p+EX-ٞ^~_H_y?vxjw͖,Cu, t_-c߻rg}iR FMo<30K)LKr+D{Rl}{ JݮzozB+)ƺegaÕ/eS-\nqȧハ-ٙ㺇1Py8cD(04A1 MŸMU)ZLx`ةeٻ%C qN {y<iDDZ to@A m@\-,b #cMh0S Sˌo wLBfԂb}udLJ'goJ$M):64R \G,rWP,MgFVƃ3RHG39D!!1)@Eo$L'®TWV0BM:y5v賿rMtR_^ѨX97 n)oZ^'_yМeN[,;ac QJ5y'DŽhtRbi k*` ͆#-)lNsIMac@e ӊHMcLȓT1yYHֺ̲Ѯ%PRKa*UI}ԋHC>R#3Aؤm-DURUi ͫD)E?} *؄#^ 7b)f$dhMS[zRovͷHS3C3 <]] DŽDnGm$Ĵ|ii*lNv*[%))OzF'iNtwpqKXv\{h q8tԤK ?3 '&M˯c(ٜ;7`<0 mOK7H. 3hQl**OCvpN \S/ +yn"´NҨu8)`»IY/!?tMB ^TYLq #u՝ ZR)X-|K.!T[*@K`VRz-G;_ʹT,`KjI[(%SK'Θh1=֟1y_i&H Ƥ̙FdL^_}y$JxGOdA۩eja:ZRFIjyp G{n"S#w r4Xä`j16ȞZ0%/-)d0Z[6%|3t'OfYO}ƗNZ"[' (On|dé^;}S# D1q∇u&DX>{LSbL7.4B"WYQ6*m`MS[[e-d 6qȶliOT奘Mm.Amj1_ Pjd3uKJ!kϔfX`dtHYw|tzKm4 `!`@U18ƶ<3]w!0%8j_)l6bʦJSqBˬ{G:ӿwtg'xW|7g;q %A!mf3 ɛAMɤ~;~?qԋOw+ '6ޖj:O>{xIehm'HSY:RMe9p4{cN9_mwc[v!b !:Һ`S͉˺>}_qJ i,h_z1)+6_( L #(,$6Cp,Ǽ P5kb;X?Y> vva-]~uP;A`}VUggR<&\ynz-)ޕA +)DBY nB?r}Z)0 q>g*jZ hJpH1oUIyO{e߇o`YdԈKm%3 $|?y &*c:zj8Z`)vh*KU,qw73*avۯ{dRZEf@%e_Rpޒ95|{_ouD5_*`4UXzɡV&n}Z |;AjfMg|7nW:Yc4\FZ lLqчe_Rmde 1MTTY֭V;|)CkJa{Zv޿-f⤞ݥ/^G^&֒LaA}7ؿ'G?I5.h6Y~4BU |)7\mf4qgA O\q很P4F-d f')nKu`)^p㙇QK|%[ 7y}IJ(jB$[ ,%efÑ,xܑr6W1r`dLe֒"0(捪WFێ%3k?QeELSiYSHy:Fҗku.C QfJA2J␯| &1j bR4eq1,4ӨB$Pw,12xELM, -B^yx[vCZSVա#hĽ.M^pq~=Lc-($ dӝ|MYԫ8Z8`낷M;f.=aŖtK;LJ x14~>fxƦQudUĹ;~{I@W.ˊyKWRg-33HU8k GSsI*@,!)  kqUwGR@3R'p34 Ĝ:6Mg7~ !lSt:y Tvq\&8]QBĪ[V p>-8ij5j CGmMy8H]nA'nfdaz+U0q S 1އ;fS.45m8SvY oٿ1Q3$K`wM,rb t+h ]8NOo&W/&`$ɺ:pH 6!si#"d7l(p!)9bK*oVFp3zwaU#ÿU+o:I:FE.e W3O;(hq|ߏ'~7gqTŤf9e-Dۈ-4bfȦ,Zo)޺*T ұS d 2j ޳Lʒ8e1PSw"4xGmb&KgrKFT{x{yVBbHnuo9\EQUˆ[2)n/ot+ { lx4FDʉ)i@JGԷgeLf"0x^(JYn#p h kRV% 3d1pԔ J!hiXLcEe,r5D4RJdȽ+[nhbA(+TZ"t@ti{ -'YF^jmɶk5IK-j cnSʥ,ã) d<~P_'ՋO')^;L UayLOgO޹ _-T O`MKɜR^in.1H `R+IEW{䆱 į ~ MIЖ I D*l<}Q[ ^8NBg\ G7X"SLֲ.}$( 1+ `֮N|ah#mmo3N@U`]wO?yhr|ux7p)1'.h 5t¤ڋS`yc3K(/τb`!V G9bV8ܲkQC;6H =WXq`w,C7ӗo;dyO,K9=L:;ny=U;4H<1UISզ'[GK 2 Ù4!{{R K5*˲CJ['iu@DkVLq!=-+ugp}wfj̏חQGC_dַBxL7}JVK?QwD6Wx;jfB.#R@ށ/E5b ֜G׎-[^2,ܗ}3ZR tѤRK,0U:xYK8*iJ :K āe&råWcZ}hTqTK{ *-OFLU.F`s[?RL͸ Ȼ̔{TQenx)gnJOZCA,)&%ɳZ ƾ/+LGqt-cVScu/Epn2LJ2Ci)V[E3OmKO+zU2 ~ d4鄔5+Q^6{ҷߪRvD ݯW (/+U n#X"گFC >fBYӋavNbvQL y3/!L BM;J'czQ0[e䲝/}h~?0/0?^@2M9R KQoFmVeZK),qK7{XmY{q`֑U( DZ3%+\Anv SSn4^goR*Ko OڬZSI-wtxAMTu3H3J%fɻ)2%o㻦:q"Gq`Jy@k'zun @6KaЫ&jXRfCHB.uf)B'RZrym z JjLwU)$Ԝ'Wd}fg\(+gY c>OwUpL d %nqږŏ`)='dI-yȲ0)7$}+)`#ݽot"__~SyF$s>-PX\@62| jF7IvPφfc3w!faeō%@yL%ȀC?xH5nf|c@,4]|bz$U94-t5 ~vh㉛%R 4Ex~ŎLPm>M٨tbޫΨfv F2M i+/u\J ]jvԾHQ4v:& Ӑ0xu&*L%ϦI m#R 2YwY)"<eItvC@}+2v ɻ]dnЏO14wƭZ݄r0/ ֮f<4B Y81u1I偺+TKPgR  f6ިmH/Æԅ)ݾ dTߴx &@cF0#&!qt]Ve$Bn31A-1.J($Xy:cnxA1Ύ7XCM̢)- -?=TCb<;!k_:Z?t"]׌;}6^ "K)g\ī!@np|.,M"V;*@8~hd.:^pZH} (76v|"-ysu:_(i#}ӊW]TMI£-$ oGvv`I ]ٙ(T!ip1J.D3G>&[#΋' Dպo۽l(gjMbIiek*Z R 1e 2A!ZRw^ꥣmG0 [6\@X f~ k-HNV!1{t kStpծ*~Զ !qCkMGLQH!b6OD֩Bx<#v=pu@q;^/W*Y^,NB@Q`7-3uMR;HBs?LJ ,\#Ud^4`ijݲb@W\R{\!n;ٴ>Ư;'cjm뜥0K [kkR޷x17fiEMK!SpE. fT«r:a Llh wte &4 Q)1,ّ5RI HS ӷ֥ {Aةmx18fo񯞏W5r7"ܒ v2Uc ;+~9rꓗ橊+`3@ L:"\PVr˄v@*JL_dH`[h5!,1;O!KD@jL%W 4)-S&1rLB)w0d-Si MdG-o 4e4>P) #DgnXj+DҩQ{QhIm毤QDPӶD5AH㿫jK` iz%kbeTr[ }8sx|MR?wL=tb`p9زW" FGK$ۃіj/t"S0['.ϓMM-.5*K7ﵗAZ2$[V(F) x`b,YRv~abUĿwGfpv֐4>mY2K` (hӇCYeV/cH ;HK*PyIu:U^/[B#BVpUVw3+,M)8eoxz# M(YIf'*_IJ>>qx.GhZWUw)xFF{%H!Y{LyYd,bck*;_ܑ" G 3-wn-k:8epԎ7@`rʺ Tj_GJ-T"ԔȲ ZV!ee/3ĩr*qsG: ?/eD ^eIi mB7]Y',P -H~j955I8d&<вITf#o&\Dj yHV:UfS7.m A5J! p -3MޒwXjR"v5C) TqB,߭M!dZ*UۄLeYRvdkŔ@jꐂYmCFP  'CK ;j5ъ !&)4Aet,5V|qU#YJ *ZDhu˺ tZʒE05 Dm4fVSYq,!b8_SbA_ljFY;dA;E@N0T (7Rf&R|@njq萅t&%Mަ{R*Z[nh@LNlj"-;״@K1< "lUARkbASU,@JP_ Nx83 XS]l݁jG=)젦& b8(:AّӗE?jNZ5 6]qrQ-1 ȼe|.ęMP\@i X)A%^s{o|D8SxUkZGʕS>?YHŵeRފ"K9KDDۖ)7 D <A;KoΖZd+Ij/6('.=(-*!if,R-qz1wǴTR#B&rl RJZ""1!RDd)T뎯;mYv \w}+4=)L.7YRW4h\ &.副QL#%)x+/e)Dyc"QI{̧au\ǩb1qR턓BxDj $ aS&B3L!:X8I L"T7C;d#C٪3e\Ma X>@KU1Vz-YAT7b%—GtSDK}y炥3P#E$P<`bYjȲ%o0^#> '+TːXS JDIB X[6p@c& _##l--Gg M-eŬij,*łSp+)s3-#0LY !Gp8%&B0^&0tψY]G 盇H0L0&V\RydU ,{&C<4N|y%Ry|A|.@IHގ3Y|˘BljVGR yAD*OşҎ,յ_dmU=f4 S]yG0~ B$kٱ!,Z-6Gfbʍ*R(` o"h)L\c^k>?dlTuPʹmX >ӗII%6AKbA".Ъ xqxU)kÉxSǁר*LGv:@V ՖIdZ38Xe2u&30$%bԀ,@G1so%/~d*@y]̀cV;Bç3xD؇\KY ;=%<\9<3Z<W>{ PaDlYóq|j!Bj'Tjįq~c/Uc@BKU^,? ڧ͈]W mPR-`=+W"kX;7!Rs[wckniS{'!߯ 'ZU{wKhtL}P5QrVK>㬘 cqv]5[9@|'J#V}/>pRjCJn82r`%RaC&Eɿkq$8pb '3@~?50t!MVh =Y9 7Gnm#ҫvĿxJeZc|΄P3RsYupd'L ؒ/1g 2h<#cK-kW3]'<2E%I?co(#=g MA'c2J=BVb__ h^J &d0c T0gJUҨ *@?^jW~&zH*Cgq 983c(E{#`9V^LskJG< |0{n rP cD#-[q39t 7.؆3'ϕ^l Q4v|혬=cd;wYz z>@bG#,T9LF,dZDaX;r߫dZ5<6F%UcUD1i4z*HJ>tIhwP&ӆp AV}!*z1 P-  ڛն}.-Tz3ǧw bﱉ w$TͶ%] =.p>l0)6#~&!oEd[)Sj&leU4&2e6B/F$0.G澩. k<Ũ GiMbdʺD%-;LD؞k!GXI"@J=E?1&=8XC\WĜbn6h -4%@+тp J!`l&@l L.d\ Vmt94S-ӱasR?HmcڰϨqJ}-SPb֘7-'N&ځ{6(^CkľJ9܍x"KUݫRACQ\cd>2FYD #&T"gXVg WeBh.gUdr!%U^1c )Rx?[-)(=D|UDZq3Uu)J)Uz`T-~lhWx1ra̅jw Ip u ճz\VJ0^T4OGkھcrV kcxbHYCS/b=l= Ar2 +l9`T*,%JRYib%0}K⻩YJyUʳ2CCL\1t <"xzS۪jwKd>\on `ޒ2Zcc`w3:h"H:PU+!a`ZYW}dYaψ#qMTBb86Kx9ZMi)ZF) N̪#(+!eg:*$HGkrp4Wu%"*&RV M\NRfuw8~qÄF f֖iY% dJZoZDd 3FJaz9 kHtLdvU֭{[FB R*%R CeLڪnTάbhty;iJ͊Ęe*+Ven eGE֒pZm?}|"albS)#uyJ#dTM鸭Jue2>e}ZXoSk V%_t2*,NOp88 |].Ȱ)JpΰhI HbPI19PFZvVb;#E|S7ON#҇XN*X4UmP#W2HOcwUKF: a((12VME$ "+ GXeᔕU;C>kW`J/ }.Sbd0`@Vru P$|0β+g 2UQ;j7b[Uv+;IVz.(U<9b*#~sU(u$K)bJh.@ *s^R$;m+1YF^ϭ<12sg zJHνH|Fg8.;LS*cLJ4 _ 姥]8i x|^ySsw97Ms@K<+V-@ & zUuv-RFw6%L7\X蕑E9 `Llp[ e#NϟC S)]ZXu7v|bd]ϧ2˦ F##3qq@oKSV#hwJLeNv}?ZΪ)Бqk64Y/E/0JV(FhˀR0A:v4')?C3!1^*C(w zvL.VĔ0jsm" Jp@|25#o#= (ͱuJ&n=7*C蚑H\.|&bvV{L95CCא2fUףz bՆvUxbd7Ho= _p}KLzxdw|vh=S|}Y"k7 q|K5%u%n.GXd2r/Ov;;5NJ#ĆrΪo4b/dq;ΆĎP*f;LY T/~#lXfzύ@0T҄4a%kn-iL9I& 0?Czrk[,/@?^`IdBl >\{X =`֎q=<:V7B+Zrowm(p?cnUnDΰ{!s1\>E\+xJX7TaF7b;H&kQ>㴐9"F~m2嬸 UAv,Ew6y$jiZh_8\j'悔Vk#3OdAFcKuh ;LRM 1aKR)".g@^hUdȐPSG_R{:FFD.@q"@:Fgmls-Tu)5fϺ^-.ߥbdJL7oed#ԍ=%, :zbó 1 CFMx"[=gJ R( _uk(Mis2sUJN;TUg(Ziǔ0f=2-G(젴.z11 I1zeU.pSC݋,,Rjy2g|ȟ[LXuJF'Ћ٪HV͊@.hJ|U# dAƪ#):A,-%@֠r2R{ 5iD0Rv4Bbd YKs31%FDb"Фo(/)hվ3oLn 80lCz@ick |^FV%'Y,r辆d*f d]^ѣG&~^8;s:Yܖgo b@]ڕ`|Aȭ?0he>~-ni 2ffy)#&3EFI:9n 1q;E09|rWrkxǺla Jdg *DwTuQU;F&hb%$c+@O<^U# r.OMn-X]1g 6tR}@SDtH#ØxQ 4w-~UJ2L0W"wYkV"qA1`XD(3bŪnU˙fi4w,(E1}u~rx$K2|Ep]׳$!YsVEpJZjtG o Ji?3T1D -ҧ̪G'(Qr_nZ›{LW?ّ^P2f{FJjUE%]ZFpb$C3>]ERܕkp>N]F8'M777cz@XWHz Ld ݕ-,%ac#1b]xVqR[}`9g#E]3Hp;,jd_'=?ѹH4+d4>4 ο^mE eأӿSvMQE6 ɖoN #LziDw׈$원}D ȢmeX{kb i!;j˒jL V-YUwi"*-IT&jD-C87י bj32V"WFݿlR iܖFimF`3 ^oQ)#jLhxeG}ݝ^J#ȦUyf% bV4Y9ªWvp$Vmtb<%ڗyKc ن߉ڹ.G/I-ȋ+2ޞ$+D$1ebt$@&bE k̛E8GXz8UaH @0F#n ^H# i'rFN J/3aKVhhb_6Uyj2Z\L^اA 8YSަGt!)7:>Jid|8VHf7[%@ ޸v9czz3lU+Ջľ JFz 4j#*`-VcJ-x43#`2<[@r4Q@6и}2i%L7μoniW[5H.}v5UdW9D'I$sA#Ųojs{"p P@ T鬁*Qc ?>CEuz )Fb)c@}'6~ko4HzAJIoEC R&s9;@$ kr%tlJ2c\߹F5LPvĘ9s3]z-+%qnl7M$v4eN&*ȡv95` +v1/5=m3w^Sr䳭Fh &Dj]xLS6±, u ώVzU8jFhd.|G֠] ClĦ#WGA2DŽ}ڭв ĿXd MDc' %r !n&'֋O|g+ٶ(kC]_ ֬;FҜe+ɘ"e}oĭX?(E1kW}ߏ"%f]9J[h}-]h8HH]&mBn/h4]9[0o7-T&ldp=f4akdbx;̖&Rj$ |6+RnD4!vZ-{Lh0hFGGuEʎV II6itk(!y:fk_*kME-Z@0A^ڄOWV9YƊ@8 GUc/(1ڸ{' ؓ9t)U-=wTBʪ]I˴ܔ29={$6 }iC2eY9x|7Zs|vJuz)}1 X5h! ;' Rpǜ_@o6Fd[##z3Ʊ*wBU2̕?hџoW2JSdP&Jr4xa"9R#cJ@;fhxd.ՒR.;hi=i&VV sHTm4;];CQ҅ɟޔ޶&4 `3(¹%o`3Ȟy| &C Y#drȄP5@@RjHn 杛p5LD 07]GoZdd+, z-+RoU-w),ǐ) sV;Duй}!NέQ˻ MFGU>Yɘ>ԖSxMj1յj:.BpXHd<}@{ղoÓ8%ȪZzd ppwLUA۾Km[zUYo("buܚU륱[oh00ƪ/TUٶ2]2轕/5!M,,}K1pohJ}p,$2GQu-+鴆YjA>^5d=YY9U[4HAL67%Z81J2 !XL}ߓJ٪[ޑVkf`0ܞj!PMɡUd8'V#jՒ^G X #/B@ OGCwK}jl2=#zn]o{˵YSҢ׺iU}[ $:#o^X(DA)fG9YGdxHh4Yv8c8e e&3[%v0]31R ׻S;/s 9aZfŇFl pjB@ۑm=%uj]6??$[ԛ}^HiɞHGUGx4bf"s6]d!=&O~Cu[iuz#EpS$M )ȄK ~FW7htGUT+;bJ5FM鎬Ykend` lJ-e̎@5nyʔ selx|;v%x!w3߯3&Mբ}'ȯ|.cZ"몑۔ؿi8& ! qH~}6[c0".V1@_]׬YѷdүqDv#L6=%XYx0(.$1[#cfؠ[yЗn "MY? اj>TJiQRuO +#SbڡH<Ȇ$Ó'”] 4Kvd(4ҧτCBITXU㘹ԭ+iQ4H_(`+g=Z̤@IDAT_Ǫԕ\(]lCߣl|?uyG]d O#PAja .vJ2URc)W*i-׸czx%jC%|_4q>z+0rCB/eo\-%WXwPjJUX^p1Zz+?L)XM=GUbGb`>+|7RŴj;D7i>HG@hTG1롊"x;d眏,™~>4]}1oQѢ瑮1g& *"VYa UہO=sxST4natd0!p `ZİEY *3h\ւ[# C%nsn 3GfUV[ݪ.%[V b4Jɭ*q `D͕)וh8#v;>l3lyL 4 9MSs4:#֛Zq-)& "#uTzdr]Oi0Pj8Olz a7"ɜ2!hZ9siϊ.F_|jz;4|DGL L? J-&h #f\IFIЈY ,XPpSg͚'3،4Ԯ/#21Ľ U1m07@Ua>c|S9H[2U4&hD .\{VdhJLV RZrNp/q>ЎY׻cnmӈ&]*L-\x=[LV96G6}wA*9Vbj8 XHD)wP.VՕfԫEiS00ݱH8G%O90[#eX ^ΚOX8!~3I_ovmYUߌkh|&75,d1w9SbxBW@ӄP JU-FdxPu)%͹yV"WfbU3.m#e2L-ϭ J94a2ڵ6OeߜnTvh`.ϕώAxzy&)+P*G;QNO^ %E$)ihKAiD` qlId@ 4 GL9O>[ S@k)_2 rK1YdTR|ԕ͠MR;ŐMO)Z_٦qi< 1(U"\nhczG;Sd>:m@wK 7@܊Y_pL0"q2<7;"*LX$CQ@;ph%}րT] 699"ɐ;2 euT NC}61C-1L@z=F;6M<՞Jyɦoۙ;*ɺ3'S7voV-(|t6S`0`n.R]c jr>l&j v00Q ]eUr+,@ e-eU6ZkysUVٚRe&  &ĪJ<Uňz+Ed6lt&6Jw $(SNFCm 0] ~ G 1=n WzB5%߀uW M-Ejns; Twg|*9 KVv*6(2ee17*7~ ڧONFJ0D rfXk'Ρ3>4->xLL,.qi1M:rhSVȉ8V1& -P Ш->qjᦳe4*dBld8"ab<Y5t5d#,M*O1ret[<=HzhOUwNj 52Q-`ARR@5[<{qen^%4W"˘NzgYs)=XP:BUh9os/-RʿDwñV *q#YCC#fy*B;%>4pxs,څ࿉GgәI߄>2R Z&r>^ f^ŌdsMkL'7ʰ,ȚVbnJu5XR.ϐo^"ڎʎFjn b]l%A0)C,_ntwW ҈nAC2dSMڇ#l0@>@ :n d/X;&D"qHF|]\ڙGdR!Ϊ}╔DSy"9O4^I 3o\)c2UJ8TA-9hPYK<픋@t4TK82 MO^{uapN)=FLd&H%I01d ˳'o:ڰ[w/jX{^X/A--LF]L<G/PN 4>%hL*x)@#CȜS4rbf ADn1|,c`Ȉaуڑ@ +R9-q1{3O>BɛtYʮ@֘?1##P^RJQz@T^&Î5DJY4 "Fu 'E*i>b0|,B 0rl~*3db5'Rvպ84k>- M0q<{\9A][ ϓ>d ~aA@F#g (!kR&#tYgq$`R'-w;nYJLdǺoKL5V9m,רּ0uGv HHitݝ_=| / =~fR )Y3Re{OQ]"·\6BoKUƫ~tU(fePkDўhza 5)` gA @:cl1ɯ-a>4|`Vo+_05ao;ԢdSinkf p$DalzOSAIZ|7 &ӯݔ٪ui̭5(-7z +b]xcx'N#~6bd44K6%=LP@n.J9=F27. ] rƈZ҄kQ!0UX =d@A:bjwA=Mu%l%44R\8P )kP2%#(OŴ lVS:dpkP,A|ڍ&YYD {ga\WS50>6=%Qbְ! v9鿡_ /% $LmE$魝fxYjVbڧh4*?i`#lMO%ВvLfX?: G4L`S|_Xы=&^; U;B!烔EΉd5ECoV3c.q-".U-E[߷)9z>v݀9- ZhL0"QWXv$ e˱ՙwl5 oʆVfEl ^S3<}n]"ό143RdW(152rCn%-"FVN)Fȓx srZ $ 82IQF9!1zvOP柭#8pl2A%4xULnmR Sf.5 U1dtzU5=lۦ ) (ɢ5iRWn|dJ]RQT0A&"ɺK` onU@9TF#ćkI$ |^[hLߞ$6 m1Acvd^K#$nG +#7N-3@Ð{Uh*GvdES{FzJ?sergE L)rG^U kiNj X1qMT.7F/Qc(3Ss}'!IbՔJ{C mpd[Ղ1H)/*%d4.≸u}߷r:vh4BUv 0 OK +QLH8pGomps],+ ڶ˧2 OO0o{+ȁ^%GbZ9'LAptI5qLǺ?[Y>vZr'K4Sh|c[QÞZF2rl4,"ύHC Tv&ȪvXII?eb]33[#Iᨤnaؓض`zhX KsICc#C@#_3p `Zӏ̖&!J̶L3ȧߌ4%R>݂ |d&n2ю lj (#FW`k/0c#ʎp_HI]GNc؇'h@|d\m(FoJ) $բTT 8Ar۱S໎j@ eJ0oF0"_nF{|g۶|& % (ݦ3ZKkt)v$YpX AV8(p˪ U[Q@f*GQIp}!lP‹}L0S\Qhk`L-Pqp& ,Eȶ"k|ܐWFL)'1_4ֻ+|2'.B+uh'sD#ӟ?bjouWIfÀ iw,d.gӆ-OX MU#xVo|2dYWRjh9qXK#Pa6lkP d@%$qvVcVL8G/^晴Ю 상Y@Z˽uOFf ,S;R"d;lޑgflhJnƿ0n+Pȹl 1L#:Vb%x]d΁!0v̇?_KhLm&z"oY4lz3Wj OdFXX*1A^c Z*ɅEG Uma]mYU8P1x>/ s?)+v7(UB)71%g>R#db8/[d}8 {J7] )R`>Yx.s7T¼& d+[;Y&2Ǎ3Tyf*$MGn &@jɹϸ dx(>I˾14)yGVkgbVG/<1ŀAmleJ0@`)R㦯1 Y[t2QU=;"h!nt\N&SdDG) XK1&e$gHpkWHI,-+؇BT"Jptǰ\duߧ6 @QW)i&ƷoQV1 x(珏z -@v)Xһb|JY/8_F| 4Eʎd"S)@ f+@y|)a`GW)څ?d[db ݎFln\ؽcLzj2}FGG9.WGr.~xKT=: W>n4]l;®9 IQ$HMT#}az2-"[Yb|wzhkKQ4 )x}v8Maշy([@NOVdEQv& @vk2v{Fni:6v-4D@ڲ*UMċw@ P*Ocj>}+UwَrnMoQu/pL7=9+zt M^v$1s$HvMW@59Jph` rJtl%ʵ`#RKLДU'xfB6Nd"kTu2M{*uͷv:7nn{KNl .aj~EWV*9ʙ2FU7#$v|.kAN Ǫ2wUhO-v/3Pjx#4F<}Upex2`TV gdK.b"1b-R9ssTURҪrm4d%}"̳i`i,czyb;( z1]O )m zْ,xJ <8Uc!^.nnW ح4Z0j[q4ů`$^<0@)410gK:ȾJ@  6{*Eɇ 62%eqLJLtp]JM29һNʾ%ƭƮ YkrmNχ!\;AxU}8,԰ ;R:RM׋'hȳQuUd#lah@Cb@ o= k +5v|0Τ7[&SoǓǹF7 #d;㳥(9+bJ1IHb9\-w#e- n:xVMU'6'%FraGL/z+og1MF,ĵ?NOVy*dK[+ə~j}l<)Y]/SIVrL8YorAS.#u['Ȥא`J>=@-}+bsEZ˺cp#޾ô^ y5Flx]; A% D#&@8@F(W"MggQ; T*ݗOYfŷmKvlb]iļ$.ųwC$B U*φ2Q#k7=q@J0}bRՓ6[ą)R퀣pĊ!>2h@UD eƷ+])+Y9[#"|")w&OGUz ?NyĂcC,7)Y-|ZT@kh]2oY7b~{b9cU-]Ld.Z#H9Uvzkg.0|2U1w[p/IuZYiWpW%8tg0 d$&P5%6!'Q}3waބgJ(7B2s]0R!Fci(ajY;Agգό3M#qglQM߃#16T8m@nkR4r1Maۏ\UNK8ʘ1>q Y>E_f2Xr]|(HG~ζ!cR+Jl]ޑ(2n}|N4->&*P#”E&rSmHG1Jemz{GnFK^nh]`5xbCHdž: |`p%$F\Gnxb]8 ]MaՔ!>`C&7T4 .4v晔 ]}}T ,2?L02OG,9,+}QRJSUI\BS\*>ssxw |̇C6C j]HVҲݚXFYż+2fԯ}㭂/˷Qt)aJGH-xё88)ei7bJ*%+dLMϼ&K;md™] h 2YF iZ#e-2b/YK%KcQ5vCv,|-?3Zȼldcijz ]2&YJB#F kdb%1Y^1ra|F8X#0ISO D#x`|0TmK!F6ryrstYzG@r%矞,0aXH`ql%@(o(-G`tY w񲮪 g z߫ 08ɐ`_BGU ӯw b] pΥL'Zȇs^ I`Fj{c`jw(YJcĦ+ԂI̸Cua# 6d߆U1=ek(%0 j:JTڐVt~rx/Dh n]XUgk EU4 A @Y #>LlF[$Adn(@lt+7PFg*&,<yk3@pwA΢w=,z]} O_6KcMl:_W $&JaJp&o"R&y#4DkĴmU ƥ,g/R=& b6{.ҳ_{VXFyFihȎ1dv%6;g((ҋo_.c;W0OHpdJ-~!D2JAQU &0 @Jp{4mzm>Veꢌ ؓX_Ovv)g [S3AuƑ-F8$sM 'jdQ]JrUsI%츪Uk0[ƽV%5n]H (!9J_=p~6GO&6e;#1+Y4TȪGi@d U%= ̵$hPS61-e%F 8ZCԻ}6g<F)X c@fJ<+ٔ"d&1[ureǺ4Nc*e>ܱoh?m=r=MxK9%=ikNJƑ/Ւa ?L),٬y:jH2l۔}g[oXL>87^cc~U[@hJˉJM,#,Pm@ Suy&?s7mȢ[G-i9`ڶ rFV&Z6ȑ kT) "%hRǾ$ہQn"ެ&Sjzb%Ah! n2I,U)1AtѺf<2ZcպFԒ͕-7&kkpkGΡ|Z&";v+ 5"E}D'bPV7Ͱtϸ 4p1aJUBI5UEz|:"מ?qҾmJyrFɿk"9+KPz3#a7%e&jߔ[!FU PfMIS#oid!AbPj郆<%lze{(&@vJL-Q{XjdJV"9@dX=R$;4e1 {U%nmvX[dZÄn GKg%y䩤Q)lfG: ..⿜9h7}XG[*&vN!d[itnjOwqX<17^#c0@O =#>L,0d*E[YI3L#y_7PFJJ01j)a-pu~H@4 fXKLFDRӈRp%xnHU7LX#Gq#-O)׫UI5e@ZHϼF,AַŰ9PGұH=7?WgUA&>7Gh 8A-V:cl∾vp~wcLE 1 S%#M'eÿkeÜ".0r>xgY&F{A~/[@Kk%k В8Fvە{a)sf9#ɀٲDn'&hægCG9%xzۡF< MdL#%MZs~i=H@^|Qa$7Xܮ9E]٪Vj]OGjX~=i2's$ bQJU1gS)qL5}fEtlְ#l Orj߬X;Ĵr&8^Gn~;ۍ,/nTU*&,hU!hnJZZ^jg@I|"sSi.Eb9t4*0A]|~ @e>ɀb|0 ɭN%6 xm2wI`PWRMPGv4n-$N}̇J#H^nU188H # H&‘㭀p  5vSU%< rN,G'|P:]I֮2\~cX C< U;kA>] Ύrᆶ#Puľ}hPU^")"Wrd2oGhPww^|[ [D uT p;9Tife:{Y0ptYsT*^1*CbdSʬT9pJzr|HDo.F+ah#YSnj"=@֪Q`~hIn.Li*bԪ]G&YUHr ܐEGHXHܠg#TUX1|0F8lJk i c h`FL| VdLڹ 8e&+BQƱޘ}T1oȏ #1=MkaTEĵT}W H,8h؊m,)eU^$sJ9Vei&Iș+?~2a#܇1aZ^ձG]nI>ML.|3L9C%|xѽfFny]b2>97kVu U$KU)9OTܾ3zTG^4_H]nFSh@bJRKUb$Mx>QU~׺kjs8G};ت@jI&p/!pd%sp#0UzX&P piRʂ7z 4kC)  Lj|2@aUhI&$shxّ8GϤ)2J4>HRE'-}#d߿ V [o- Hcd=~n} zCi{q<@[R--7hx.R鍓H&gN w䟉]cP[2}́FspD9807֐a4 i:L +ᑲA[,z> mCHLrv->PJ#: VpVz4 G98n2rf]dzXAh$+-Fh`x+$5I%[dzOm%`΢v wU95v 4,RFV8!'A;vPg`0 .F\ a vd}f=*CAF]clP;0}ER2W#JdUy:4BhĕYF2NO)B0'SFf Y)˝7)HSd H2&ux,׫Vﭔ͵2fa/90[n'=[}.dNmG/ԧϰ-ӇCٶ= !aݥÂ#}QO'FKbUv`H$ i8HqXG† bxd=^#co옘 G+e"1t"8s5؍7nC/)֘H_ \{o{af@ wnkVUO`>ɠ@)vI ς#s=컕Xӱ;T% d1ʑ|(`n$&v_K`GmA?1!?KAfam቙DUO}T 4QVʿ0Yz7S"Um F2a%JAnr$˓QU#e@Kć @{Vl!,*=RIU@fh9)+w|d. 1MȮc Jo3Lݭ&*96] SF d[5d/eWSY*g$i0z‡@̐ :Q E^zS7n 7XԮF]--m"3o/9Z5e&U!mU7'n^&$΂paGiLpO3>$*9aAݏkv.nٶc+))S;1f. H!R(Ù+WkAtWJܔ@hebr-&FS0izv q9@D `4 a%dZRjm\I;pR<+-g G&4^@IDATf͍I aH3EwD[XMo GB4J@♟{2Jp}˨*1iA WF*yi0ʳu{ F CJ_b( iTExiio+ a/k`J |?c;j_n^ #VM dq(s&_U|]C|zFn52'n4@)($Lt!M" ǯIo.b2RILl4nL4O>)sS!rJus[&g6DLdVu}X=F@>r]'' "-²h7`٧#ʎ鼟veWMH]d1rQ &RK5'O|s30Y%>5l庪 -Z[kmIQ&!A8O/ +pL}ab< Zg-3_&Mz|ITBZ) A4JHjXePS\m+agdzitq0 sƧ &^O#LW}D2jT"ZYYR#] rb*a2J"9T#ܱyٱ=sƩ?MUd2v飯7\5lF~[!R[D&znc3e|\9 _2^d3SX#a'RI7G.\whD{#kR0eemt<‘QPh¿^Ԭ`̇U MQB0q)#`[JÓFWi2mPFi1IJ%1#2g ܽ'jln#x οq ȢC; Ȉ!=%&:;6VJYao(7 M~0Qcl#Șwe,&szݍ Pꌼi3wy --ۆۄ7I5n7$1181C]i ОCdzҕ|Ǡ2 ghY w 4<(J6!sk@˽C7 ;.  5X.@XN1es|}j$h 0Y@etLÔ#09_p3 B&dO8e?}dܫ 􎪗>jnQ?L&4M-N@z t)jvSzg9)H>yj1#%{|LkH24U4ܔezyi"CU8"l*l724Y%e01*:vbb@IvX{_rgƴ#̝hvJpO[Y/0#R4OUYJ)e/a7 3x \=#XݪѻwYƗOo5iڡL٠UD FV2JN"4 5dJ副*vN)S5y{_J^վ!F4WPummG61 kdN1;*u5YJ<+C6opZ+Sb((4uz%6ޑ@0=~n-tXcs1ܐI@ ~MG־FG#tݱR*9G//yeÓs7C|!PU\ ,VaPEcFgaʪP9$cJaŁfIs>IW㜵trY9 ZL(wmwzxL& ^q|nhQ^LUlF'@ wAJLxd3lVkUC̹T m5Ժ@" ȷ>x9lj6[ S& E]%ӄt)a펾U酉 `-FӔFz(wdX Y6S5hׯ13^sch UreDmʭ[W ř2K&oHYm h4ngqU2q7=evDnaث,r<'ݥ}3vaߐdie2LaVG3k,H-ݱ妴L]yWu_Iӈ9׾F.Xw˵0琕$%N8c\Y0"[<sKgTaJJ@ 4w>/ZY2l1l%i]0 AnXcpGULS..- *$ ['Fx^#RN d Tob$}-ެUkwTu/Dcm4'9dU] 88!h4p~B%<[]nDCwYq/%3!sPbVtT]# €2n2%&7LU ,Ie΢X޸&ƨeYY%[4!Su{. В?SR;2A1T8WǬ)fy|659eeޑ 8O(R%A)R*W[Vx/l-̿$W^i/a&d0P1Fh[ OCwKv޳{QEg8&1}ā >P|5ʕ& G%L,L,ǖ'e&U13- ~x-J'h ?-'k=c2,7(sk-5R Ur4ȷ>4@Fx6 3RͧMSjOP)7U6:,BIf+n jJLJ,@-L uI[8.)&0aʅHG|z蹟!Wz $x'HJH$2,'T2|gE$DG 'vRօw׫yUuYYō .cbZ#^ ob43%ޗJjS0]VA5Eq}K z}ܮY^0.hVsVr~tig}J&¢vGa\ɞ1 HmWWYqY2KlUǬʪPd(&idу wq%]ځ%jzB![sWh Rp%zU}x(;ua4fHq6 &C ̐RnvhmJM)!vhxr$ęhqTu_W`N7)WEI&`VJUS2"F훪 dyߎs]/S.< }j+89z8 ([ӕD%LVx qF`:6N Fe>8zwv(ZFjg%0+?o2adddJ9כ AkG]<ەfw,pkOu-C >~0ɔ(c GJVkZD$庐YO>Rb!0'%F8^FC:e&j%,}OpQZ)ȂͭԬOXHW142YodړQvqG)M$kW/ Pa^U MAkr@"[_Luf7YBP {n6O0:qo. u9f0N\tb-"畺ў{@IR_)5]u<ߺfتH@AUݮa2Uc~4#Kiiۖ<w^Ic[ڷc=3yfKXR)g ؑ9p/FtVr2X{W 몑3T9AWz~q ß1Rz~pA&ȳ#Y71ٓ#`*mA;#uU%)Jdm;{L[LGHG?-6]Sj0);2` ߫kF?|" E2UP84Ջy&b}.ޙ8}+%E dHߡxv>ߌ"#Ò`oGH]Ws&iRnISb4<9g۬ct5J ǭPDād3aP9ލ[)y"2 İ~7:|˔42ԋdUfJܐ0۔m;Ἴ.2pnݔ2[)ٱdF$*1$5JĢ %KMIJ}b:j,'Pr1Ysb4 1:-sU2V|%G a &-ihDn`Ȉzt} ]Q:HQ/PWd9oĭݒd盠?cӈ3Mo>#ʶ[k*i:YI 0j;OAhIJdx`LJVpGVidrLʳ{@L79. " ›UY5YΕULql;Yc]io[;`w +G2|!R&hl㳪8[kUZd"O]݈0o~`S%"+ɪYU1@$ê2޶pǀ-C-S|:[i^Ԩ%ѳ1 4b#: SU׎9pGVe{\vKb]UFk ^Y8 pT_IVa8MG҇hAM,Ϲm˻^fB evhUX$`Ҟș;"P @0D,b UhK_55P˞Nl R;r.G-x3a.jaЈZRƘ~訚QFÎ_}3׸;vGsENlI(3&UzMQsnd2Lip)3 LOt|.G<+vm4;5bփsv$M`[q;SO#1J,nU-r>,v|Ǿ -&H#ǀޮH䬀ݔ22O@ $:ʘ0%|fT30?PF}=e"H 7,7&RcJ{qL8ewވ3uELMVk)kQ8$?rkQ!FP&s{֞ J)U`_UmJZf"ȢdFFDf[&PE8%k$4-<@z̤x-xgwN`}"H-e?5T87#'ڇ S9;>M?eDn& 6H&܈hzuu0^PyeEo4&h|q1&5ZyVMj%~Ϋֲ&Es&ʯM =4_G)|{4;d2ɿc>&qM7 Ls^o?*V^8`# J _Ob.&&G RP;2YuuHJ 7xyM>d MeʕvX靈nOUp_?l9PU3~c5S(Ɂ ' E SLHhGezj?_B)BF7_KX2)зaH8JGQIš^@c%b+bU2vO])eJU0g 9׈!/H.0+Uu 49nerh)uj)s3G:*EJ=Ȕ[mn5|@dh)CF3I{LD>n-Dngi"/6%60+yurF(+ǑM4:(a$x U*(mߒȱ)u54 .G %g4(ЋYHA!PL֟dH ]3p`ɧiV2Y4l0&4^ `e'>rMU^%]A͒_[0Hn U7)r 0pz#+(ݥVݎ&?k(u$ !2H(Q(F#c9:*VUc$g[2߬LBv@ 7L]r-wh(`j"dZ^0+ނ? xZcn-Fh ^HI3 ЈSqȰ^C-/F06RnuĪp>sץ\c|YSdFh@zp2NYCsRXӄ3/=r_ #54(+UXM\:x&_Gim kPJǖHw\UD@5t5ƴLFH݂XBB2M棅%Q&.7S8 M]o5s|ap@> +ȖOJ>?(ydH@N/'Mnxʞ L{6^qla/dAU/'^$%FIX;Fx`a  󹭟1=ASk JS{UeAGkYAzJ-S~ )2/Gօ6NIK %-*`O`&@@1%bU;f}u) ^2mV ׂ753m Uc:fMo"9ۊngMY/^5aX&шl1%O$ ؿHͭmǍ'Ӣ,zVo1R^#)Z#ϪrE>2&E`Vz z.RI127ޒaHޛz"IIx:w gB#"~Y`S`Rm2qLs2TOGqd do n0@7ĤO5ek_2 3xc`@#C$ 㑎$XY}V2=~r4]^oL%X(1,'>/ %<dVІEƜcVrS!wCJio6QmXnk^-Pt= ;RW|w-YW3 0n=vT] BdK6a)ĎeJGD|2;伭q$H~qbcs@:&k3AՔxj)9ݒaRU-c!hRu5-R%k7Ts5p/p,4 Qn4cVVˆ6Fƽ^Qщ f]OLbɢȞݬfeh;٣oMwɭ5qJpۧ+lgH2RY92ш"w宀!*M$n#Z^TCYf>`%d[Gdw &+31ߋ1d0P2Ah0»b$YʪضpG&ԂV\/OIPF/ײT,K|[i0lmVʓRzJH$p|02c7WC)ߗ1HIq0[JiG2Ce2q|~dkF8e(Fw>k#~-1 R  rzs J5Zhe< (D9e5>Qm`dV)qB  ȅ4khG  eP12~G 9e<1_Hc|lgؔahz2ah@PpIl#`LbΖQQ: yKVWyf%`taQt>Z㌿dwȐU@ܑ2,,bnM" 3>M] R/+!㪚5[j[#^ ۖ;*9h䉀[ s1@s['vM`a $@֠RKh([%fk0T pUAIlrkLc.%dFk(3gY;}s7w߾Ug"Md}t7V%?)Fa;ؒŶ0Z{R` {%; aVuS1iX.>ݥ,hĴg%7Zܔ4Y24@kp.H)LQmЋJΏ7XNGr 7.@ccJo(XuO|IJuj8ޑL/[4+2U ?[< [o e]镄bOtJd -MkIFfHJ3D R* Ҳe&d.e H12QՈx6wՖɧ?*^AJH U12z3wd_@)XKdNW&dM9a jL&sJdMv)2Q вvs&fL)_/!SJRJlOGzxYq",'+߻'s1kw$3w\&+#Ea.cڄ?$hS2QzRo 2y@C@9ꢷ C0Ȃ̶d ېvn9n:P4}@U?js ǖ$`E06+7##4vby>!LȶA|]?'6|AJi5"P#,2ye2n\- I&w~x6& dbkO/G6VI% Ld;sTaֈ FkTM4'L=e1P-g{UAazy XK:j+% Pz\֒UBv$.6edXWsB/ <%YY5?2Rp(Rph.p Sj|%]vRb92=eV4d0F _MlxVcW3vM@92JkWHT .M$fe:cxaL h3T A6"ϺӨʛU;V;7#fW. ^0B(ȖFBH㘕Q)7<3Ɛe0jtIis<)EG4Wna%$AWN·IKDa C0MJM>e/R C~EJq [PY߸Fɪ:"U 56@XC @b#OtUU\c|fiPxAFV|DL&LSx^2D:7J4`/g"j!.`9ˁ dV0#7P2$I$* `@؜@ Q(DN N\Ofc}7shh\h7ZU-90Alk4+rTKJ}"mU;nUŋ*H1x11%CE=.kG {c@;k$ˤod#"˦ `i HO8F3 7 "SDb@C+9)gC4%Cyf𵛥PQLYc"{A|%_1ęlɟoW$n}=R*[4H6űܺJ}ĭH 6zM|} dz5 Y.Bf=4{v (gG1F%YR a<=5829h5ؿ*I,Q] ``dHW BYuЋȐsJUα 2[CULR2T10AyRǣ0H󐭮MV%.e7>4'ѽZ)fb4J1ƵOs#.3^&wR%//^e@yACʷCBfh+peʉ2 %L|Mi=GhLG2Adw4Hd,"{z ā iB R@#nDҾKVcqTϼ54j#iL*97g; 6 -gFZ+ ^Hc$dەն̳Ƭ ߢĊ #il+i=2HL p8•:UR|5k'3ZD# ȵ#d€'#H2#Mx Md Ȏ[)R 5mI#TSc-UFNJ}ݺ+|< gJFKCP* yr,61pFࢉ2t'Ù'cnu>AdGuTv c@Uz;VIP* .}~\6.cOcL([b2&K)if]obX6&>Y_NCP )Fdi v*OꊩW -H]Li(u%m:Ogtw{fmolm+#U}iŽ+a,hmg"S 6foF v|_*6402)U[ +kl ^; ( S }0涛AJdb{@5.bmb 8>oՙ*o h7Ʃ>,%w.2FP" ܚaՈ2f[M@ M12 dWJ 5EL>J3>skHJ-nTFHl^q nooGoU ]5g}=]ȷɤnFJLQlbȀ^ny>5]h+sHO#gҝ;sϹrL#b8vYPfHb{" N]) +82̹4~2.XKb2I&e&sޟ+|Ϙai' rLm5j]JЫn%JǾ4p% SeϞLW[l~w |Fv ``A ʆ&۬Y#w^+Erz,dAo]Kܔ0j֘RUY'nQ <ٱ[ idHx{i$CP`iU3}Tjș Pm&=]]uO-&kriK^ޞ31YcQO8ߌQ)Ak{]az#Mt0ĀSպR1ʞh&D#s ``U]@W5Q)vPc=@IDATUMLL;GƩ6GEV{1@dOIyLLOt9lJ}'$V@J4=̑4x>w"R{/V{x{I}Lrjl0ȔD0ML9}; 1 RqUnJaGy &hP> ]h WSE:dXUe 𕈑@eGUWF搘!}D[&iF&ĖqT%7.LjVg21 3E>wz5ʍDϤc{i^z#Yu6H%IHc +yCexMͲ ;#0Lh]40_U%U-ϳ&&墮eJ-J'O-C* 2GUX q+3-CkPb[KC0#LTE<r|hTrF&۪k՞`"AC |>׆yo7tהּ)"5M1 Zl crẐ4ޞVc_꼲s&1ǷRcرNϳ.$Y1,Zf,|G@l")6inG[ &.8,Iov[ 2ebU+ 0~MS#qlaGFyWh~*93AVe4Y#aDkcz de[^t aid"yY#ql 3EA MY5E0df/d9eh|f E)6er79=ApLIp z88gMx{Q /bd _ܥ+@6=J60Ld&\oĢ'Ro5YUp@@'C&ه c吔KX xGn.%K$'m3`H}2wlc@-kGx"V^CZT2̄l{ח{Zk6K `([aC[/ZF v$n-C 4]; r+$֨ϟL$+FHhLR ٚMH'@'dDCyGT"zeE)#)dH8@s)mݵ(I_J sxE{X1~Cۤ7v|Pc1Qnm Ԙ.\W^z3]^88^ڊaܙ';lnVi2 sGrz=c T{ko1GbE [FO F'(Bw\AqJ6Vʰ̤YkjCifabu" V]2ȖJ"q-}$.HQVx1xAS٠ܐ= M-2AhJ0>J 0E8Æu]'QNh9mΪvS>ZY0@tlsd[)IU9(cԬMF&ˠfaH^lP:jI)S"H07^|1XR֕g-0b#4:*aH&]S qJx % ϊck-ArI-*;"}.m(%b‡ۥd]k_KL.<˔JD{ӭDj.o.+',Q$gYJ|.נOɪb{~C`"#yO| 8ڛ߀ +5gQcJS9I3W^^ї8O14pL=eyfp"v}$ĪfUz2L6=,3sȪZ);TWХLbI%X)it{r67b 6(鞋tyb2_F.B#g7r$+t9d-Q0a2 0rFιqrڧ6c>?9sth8L4i^mYUcXc #{%{MbLD cZ@.Ta;fU1|<إ`42[M1R' 2=E|yђ ըKȭQor|g\\sd71,c0|Zm``L0}|jeEn%92)MI ;z1e<}|7i,e,ǮI?/^K d}:ڄIӕWо#c2&"P"=@j2+dֆ$@YWޡF@ʺ9Ƥit# `@;  "٦E/߻e2}{1&Oc1^ۡknuWcuC&67\d$3e mU-Lda5t9'w4#QfBG.x />Ӫ\ISc&)HXH1"% (]H&v<.w& xFx_ hɜ??وI0RmdqFtMĴ䬸>^ )0D<ͮDK]gSd]+hVmfa]u9 1ae0'Drxx8u5j셑< zU<25dȍ> GF(ݍȄ)|=ϙgHd7)u6hkdE č 1q|yM[ _ɬlnU-kr;(g=r0E0U #UBט |v4WoX&kP#eY4@2! s2CjOe:n%3;< J te Ӱii>A{d-jo( w?(+4ASTMj^adk;?ud9kɜr&[uLA6)FL>,.@-"`$G.K㹚鍦jlZ[$6 )]DA݅U ǜ2V<%#,hHȔʘvZ)ځ.$3̡U uCU=K-z̼Zz2$& R*MA\c %*-LD4Lcc E6ed $^UaN{|ep-9lɸcKlvjw>+ǨnSXq w.[}@:-dezSG@#ix%Snab_Wc>d2 k8A f5PfvǑѯ9[ d)۰1FWrWjUC6TUG R gC-Im`O"X@Pʍ9U€{4LoIlr &팄_,s'mc%eH\@PLj v laRGcL&Jr[ɵ$ܑ,h|gnr Nnϖ/>NWFЛ-r!F nhkp^o]̖FlPS,27 n\x] ~Wks\n SjzCq"M&2xgL`]M16To(^*vUSkvmTd5S^zMGc81&YdBt4dn$]Z¥?[R ԕ`x 1AږgLK z1}R5zwMU"#ư' \-x6D`PnUk]]SuObպrdZFoU^dM}l#Y-zF0I?0KiJG"@:u92P5YlYg{Yd0J`lJ|vME ", =,Rt[\I{hq#0L9ܙ WV-lï]Ľ$(H{ZFMl=EG2 '=[qkޱuʎ~eM_WJKi᠋@iG*ZU$b@:0Z.`2OyJ ͪc ?7LxLeL |^1^Ȝid ngV+qr47@`" j[-ぎ䘃ݬѱܳ4?]Ѫ ݶA&2~<5oOSaR{߹Ll9.Fh,L t0l[FFʍ\d&T_FyNf` Ȧ[lJ$tk(xJmǨ xP)[Ʊ5X>܈5zs{K[b uh%$AHLY [&.wφ2)]H\G ЋCffiEJ]q*' eSj Gc#jQbb _eXQoq)EoO9R9ӓª eV0  Qhk*ܮFmDW糖* jp(2U|8WOذ!̻vK?X2H#s#0[>Rw*gdL(,@ XY5QU %Z#FPE R#Y4dG7O 1bc2zU}p6RP-HzxU<̡gI*צRN.x@Dl|~Pf~>B T\Uc0"̶*f#c Z8#L|dt%@5R#Fι_8 ߈9 RM[CI"D F7E+բqnFYõ4{[ZL \>#iVI}|@]OVa#$eU˕9C?ض0x]ر+(`*˔D/@.#}XV"uGX8kL3C<5 RlDnV-߭ /FcZ}x J6뷰<Ɣ R2hަw&[lz #/Lh:p%&OWxbḻuihڮ3l:H]5vJ@K}9(YM8٩ 3 U[|e1;!qMKsU&@67'Z0`FИF 8ʪi?CΙ'p"a;#e{Hq$ĘB/Dm.nnazltJ\>ݥA sYC[44 断54}oО;;sИU%_k|%lVnmĪC&mmE[tp 2S9R;vp)m<X$nU [i4kCS>/Ye&db}FO&,؞HUĽ쎞(:RW;뭽~A\#Ȑ ĶCS{_ .=\6Q#AnT,b*֮J!J].-)b>7)tT"f̙qDд0A# [h ȟj!Q'f{#,/n s_PnlJoCL&aU{ kKV1'本}vM1d&Ԓ9WȺv4W҃ #g-1@߹ɀ[FId =]R(7NC2YJdܬ^2Ȑ?>HI#`* ;8ܯB륗kg6oj;1xuNVexʾRXn5B&pk繮Z@-J10A!B>b%̞1`}T$ 9W@ck+Ȫjo$V hPF)|,SO]N0ֈ|Ll zf-D^BI pL6FJsAY',:zNZz=Wwנl-^̏m%ٷ\vJhDxXc8%FHbX5ꝸR.؏MUY5`I]%i0 i1LoJ=T>4JxVߛw}XƑRÙkF %= 0fV폴IzZ0z={,hLO3J)a]J֠8dCdJx>,2°UkWJʷ3rq|+YFd!<7Os/5=  Z.ܬĀLP洞 : ͪ Cb͢)1 X1gY2HU"mB6İqZ8`zn-6@{Ȧ8ʔ<`Y`6IҪb]@LSj:*X F6TYc) xZbFa  Fb)1J}~U)H݂3F`b%ZFDa25rZ|8XE_7i 0^ˆiA) ܺ-%M-@$x ͲF)[&2yV4}+s'=LΜRGJ@z/!CJ!Ops%=^؊RuШ#29#0 j-h( яdHbcת-^@"7hD4s֛X/[^lcC Tg7ӱf@K}T~/[|#ΧM-M)4_EgUHEZڑ:E.J :cO #;8ؤа2V @ D-ZdTJ % `XiWڕhТs+, d-i: F+g< <)#YvA-@S2} 6aG2)Gjy-O/&>8Р@Y 4ZQ? [@W94 dG]wD  -}3n94O-%ǖ_W$ Uw: 04ez 9|:4zٷE/A-A}[@$𷇞@x_Ƨǃԛ22ت-q@I9)i6OIwJ2^5;"k}yzU4F@(k$x#Ȫ"TȆcuх1-˜1߿dmncqmV'(ڹј|___<5츹4.Y`>!E)i&Z^ ?[<1a12؈mŁ ȁ57T Hx:2%RO&f9`V+{%%|=F7e ^IOg{Z) 2]h͙"KX~OW.m1g- x@ ڥ*51_ {XXI"Ļ#SE;ʦFǓvlF8deΰ)erN ڛ,6 mr^IdΰmsdMυ)-04<1@ j%L8a? 7 0r?=LKu7l-0a&‘K3̪[ ;(1rQ >.h$@TG>l壥 1U1s4f{."Ӌ@κ`F|R◤_l ݥ)"w4#V(ZiA٣6.WJsT ]J)iĉ{wQ _ux %GnަUR]ᲞU)TrTVsJ.|bh=Jrm2w;s5GT]Jk@is% Y7WMl/$ùG( H`rFݱ7ϊ,e RM%!LCU}_BiP1DEMJ?w!d` . 8% fd& +$R4O3,6M;)Ow(7@ \PnnikDZA(CC/d++FPaa}sd-m,5`9#}s58E$\ #tB[F!jSVc!= c[e1ڑߏCb4 L=K4m x zcWgȽCcJG&2bhgU̱ Z||4ћL<){=z5™g{ %GwتkO5M=:+V4xXtS4Hqbpplsղua8G/@hğ h|6d2Lɪv7Q4dV$Uu% 8^nJW( 3i es4Mgko"(o+ (ezl4m($J-\U(=>L & ,`%F>s̪.o$&ngW@sU sRE&c&n4FW10fƞ.v|1[E i_\vYz/ rNbz0=V b\&>djXK]-Doq psl4қ#ElaedDK]w'[e>" ȂrtkTɐc\2< k֞ Y/(aMITNю>Z5* @Miz1OqTD ]8FɫqTMp@k^N/ͻ<>Lb㚒QVELv$[ Ir!L5` ϝCeNP̶Bz@c/Pؒ=,Oz7)&ӕg`4ܥeLnKPW ]ن34Mz5+i`OzJd}1M4rkKpKr hCdWvQ0bc\3)c <`.,V]#ޱJ] PSc$xB﨑g@S8CdYrSL)e* 56"C<@YK+8W^cu)\x \2H-odo{M9}bęgҬ3 R__EXDEڅ.y9g:,OO)fڕ(l3G9M0 zZrG PMZT{_$ F8%O?P(L\*F O,L`ڡer}OSIWJnZp`5fl%F3YsW!T.h/VN(Æv%k!0Hm9\{,fmaG?#׋Qrd}:zsЛD; B.AkLDFz9x)M@*svLa2z);koFMؗVI#eV@X)&sL&Sb,2? *arK`z+:b>a2&J=e+r;SGy>5[D"edv9]4;6ڱ(+6k8Y$g&#>"rseJ4ű U)E2+ H8TxdJy{֨]șl6W& X#z@ .nږ,Uz?6!J)"CzM0Rphb4-74YxL3JRMRc|!e̋)26z:HYif=& Ɛ)JL%10@LWJ@ɭJ%G:JM #ǩ%1)րe$7&Z}{4җ$F9|ji=2^nj˪cG&|%d;T9!b4LY[4T'[Xd =]>9T?+$nE@D/*es;>ߤ6&uXZh4f.;Ҭ==bajoF8ur'F#\pN2YJ/`:֨ϪF 'cHJZ*Y2݈8O@#e]2eiL!+:֘,^ DY57 P!EMDSr蕀$ >M|[5 OSDXi=BF^ư<@ k1O#j}:rY!)9+ XR e2ѱq!C%͚i14즎]daz'д3fs) s^6C1dM8瓸֟Xyvdp (pʭg(&hۖ k?qrQRch0hLNU-? ^ޣ"έZjF3'#T, <ґLo?Jwìja+&pI4LlU2 #a!&R2}0pT] W`[m\d7B6av}|L2Weoę#19cڼ0@0DCh62A)Dο0RKyC1||\7#Sm甘]!v8Y%Y);Z٢L^9̇cc}hUk1' }dth%3)#[=`ݤ=1YLU&:}aé&XJYp-n:ˆ1BUUE ~.k1 Af‰EJ Lq&1|)X+ 5"^hi+6j x"A?#@d}q9hs7ʤU&M Y? zk7eZX)|b"P`,4}%<Vpȭ=WILBtRo:=A@׽c#r7 )QѨ=B7:F߿L!0QhCKz 5ԌmFe@2)ȶ#~ZHU99V]~k\{>a݄Ʒ %;訴 >Z@)rgsU#yGia@ι2Wf1FH,+4JJyVK\H@j1A#to|>&UCHdvx[$`QuaKSVۅtoK^cUTVt~B#PrG֮䗅J[8"n+|Ujl gљ>Ւ`kSOEz9qٸzˆj'v ;ڟ2Z3}uMWk DYE+05v#&ض'Eid40^hvw #{Q`?lv H!4Y@X;@ k wm%VQ4ITʭ f.z2 hn񓘐!]?у(ٓFMƻ ȭToJ|H@Fflm(HJß'/M TĀ^ɺזIS }sk,25Z@n&'7V0R1L)1Rulyz.![H=\`Ȕp7vuM--i7(zB7r bf;VܱkvsT#$y;i7؞e^ h6,${LiVқyF7Ts Z@K!ꮺ k$vijmʖi" +wM yʼRёP҆oLmD&ԅI.w'O-'o[gTz- ~5n7'.WՂ/ǎ1&6-FCzp8 UY5Rz^;Oz6; z-SW#5Qn\vu!qS1M7>ѲY/wħX HJ&tJ.KJT( 9#8hɤ'0Ywdz)muC%qH\>>)(J-l(!`ZDJJ4-Y \H$n ^3=P >qnEɶhG;רK8* oR#4:k,f& #aa]M?F#X [<1FOQ'ۑ֑5z+ ,ˌj AJU o4C/"[7^j4.w`5ʦo4LR:RmDJ#^䏇Ⱥfk8"?GA^xD/?k%n jW-(`)"Ŝ I$StMX :@V3)s!g2>@jL0o*I@eN}i֒>U=1J8)>UJzFSx"Ya7P:^#&LCi/ت:R:r Fݶv--&JF1`whYo0M; g]@{-Os[XFF%8ޑQoVHڬ2׎$S+5EW@wI3 禚!`>[54 #mB@t *<7 +шQ·FW1O6G:Atq,d+8g+ÎF#|]?WPaR@VW*#IH) @W*Ejad[Gνt~ɠ1ͪ.� gDfĦt 4y *9V3&%4>|0dGhD扜yk`^Ozצɜm:zɪ&EXo Bt(V&avHL os&{V% m6 RJc3S g*IDAT!z$vn&hI2dDY04ƈ@s‚^ƜNS w) dA 5҈F R1zÎZcN,t! ]ɔ0 cH=5ۛ8 Nc<;.+5=}TG4JGY8+Y)eYh_/PDʘv7Qv57hlIvn5X𕐢?Ur߬p6[U}XnI *)5/swJbz4beK e7 kJHs? T5Xsz^ T h @UZL=1,gȢOlDV@oZ2@#rCעm}7ULnGn4m|>MWj \EOᯓİ)*,%&&b|dx(b}uTqQ^DHjt/ЇZOV|4Z6i*^̜!,>&H9+CAP mbS#)k;CCuc#0arGpL&{Ȧ"ZSd{xцLZTc&cZ͕IPIV/߯~!Ԩג>/ ǘHO8J4xWc `UJXnpQ.@PfBIS6EHkkGw̥1ruz0O RXhDV=*.Hַ`UURb!h%/RdZ4MLjr69FJ WMUBb(-]Fɶ=Z p} 8ո풬v]F s sR}v YviX ~‘Y$l4=CCw+!E Ȕrrpϙؑ&ܬvHҠH*rv7N4kOMLa921m+gyC b`0 UefHUw4A haNfi-COJU)!j`JL$YG-b49ro/F4 gCϭ=A&m{;. D>4&*!u럯x#v$ ob@I lka~BLȄjCUR;2FDGϟҀ#c^LVd J }JH|1C+JA_|3Wh CE {`hs;&mjK6.|\.?PU%P( #dK %ّ'}v 2\gg۞v|] ;$Vm#R@d;``di0k!kl-QcWVr @ޕm #Y탌{Kwi=9gE0O4@SQe.J}4nǝH/3L3z~:+P,jelYW`ǰ5VTޙ;>+cazUh HBb%d?*>v J4|M)4z#14HZ2Mh`Y/ =l0}UJ!zJdWfNpmۼ?'홳wqUKZɲwY}PbdgTt琲4H?SNL@K."0nazL]!5*[ Dʺ+}kCd!yJ`߆ϵ^ Ȃ[i N;Aks%P2&J4'FrEdGFXOx%An gdx]45Ƽ欴c ce4|)ۖґR1lr1@[MI LoϟQF p$8Ұ}g'1@n`3\P Ρj/S9 rk +0^;bnמVzP?0f_F[OŚUyF*sh%.%akbd@,(tN< WQH^UՏ?{ZĞYiMwrd+ɺT-S{1qScHGA |\$o"CpVRX+@0d8c8i`֙ކ9 {s-pVo&BIKP{ğfFU!YZ*=%+]P#S\K;LRV# IF8ƴ^&CX#=F1rwdl[QUiR(%#pE[? -"d+0J6 ]c+jW1L*c5›Ŕd^0eJ*ZYq'2MݷҕyfhoJKv$ 6L/%1]Qd^Mڧ^([FVA &nDhb{^͒-\:}:Mя otڟ31,Ѻ`2&]^5M׿[*&mЖpEWB@U bp"(޾9A%EZ{悔oCUi21t +c1%dJE2klO>z90}2}U97r*J2ޔ``UzIgVz۪Ɣ]k8v]0 GGE#+ QhIC(u_YIVwz|>JU%#VWXv9.ϡ,[CyxUrYFmk'F6=˦ضRlU:M;@TC/T_.N)7ܒ˪I  H\q4ۏn*h(б^VmÕ `[$2 0@YL旂%>6| 0N)|L0[)aEw"W҂}/=|GzQTlsrS|z[C2M2ūJ O<70И5vq i`L] PT6aULkQDdHޗ!ܥ5^iZ`"r[xn&áq+/vC :V򀁦z'C cR4]U8&̉;vS⪕0ƪډ0]DZvnHOǪZLv@htqwl jGz&R!H'+0iZvi꒛Eُ8) :-uǬyiJUËLUn4Jf\|܂PDU)i*iD'%UGxw XI0YK!>?LczHǝMCdʔJC+^`'#[I2FINA?|,t%iA+-WpoӬh2H=@vte0YvP$Gdxf:6diVJHXfW]#R&1C`D)[8v82A&rU䟸G_C#taj_M%zS ;$u̚>Rt1)ȉzĆ:#52VJ)UM3{Jp߫|~_VYM[E#0ȶRct[3Ҩڼ.|9;wax&}h;X @v t(g mϪhe.OoU Y W.#b$g޷X1?vf}{*O9R0ԻqU5Q24ǟL^OO,oCmz4v%2XI{!OE[$}>MjUyqxzjɪWb߮B&kO{YCIx%zǘ<1ܷ",Jڭ^9=fϥQJrc12%w$[ C'R 5ʰ^r94dp_ǵ!dd8c Mij9w7- ]2h@b8p4͑XVt}lbU.gX lwӧk-,d#UփP2*3减c,tuGGOOIV-:(Z ʁlT5:a1Qnf9Rڑd^?FM:DcU)>:?Kߏ:ebG%Z% d"d %k1ʪ(-+ :VL8H٬Cf) =@&s&H$hY/ #uQfΙLͳŲmeV=1u;!2[]*(ʆjr9<ȡp;XCnз6Pis% URϒh,S %´j%o%]p+tlv˰ܘ$RVH76_5t*FhT4Ȝ)D-kCO9ЕF(sZj:1hR4\\,"vU'Z{rE]s&|zGsNϟom \lha?g2Q1;Q@O-T[ bI/s3 BjLYϿ gmA(R6ƧoĬ[]\CyVQ/k9cnEnݙ9 zz2 H8gd+{^#sUGrԠ1V37XhɔD8^#c,LO}FDn>u-HֳYݮZ1 q$qڜr#n@P LIJhOa%QK^+#`z0GE%-dHP#G(y#V);(91}e<0}mt'sV|s&Oznу8:?ƵXS=#ZGG}1=vZ G|U[p&p|>&uT%XA2zaJݼ.JgbJmGzGyv(#0lC zИ0ȳQL )kpPraL_JGRޱLد3ze6VF#mQM:͙#[@T $H'CӛU+m%L]ݮBr 6^T`j(]?+@)s  1ܛG%8|ѿ&4E6Ymk% my-a͊φ"a/J(=f/i5Ooߒ54b|"{)|0=J`z%GeX*OUkP6n*Ir R&OGJ2ɲGWpJFpSs(۹ގO=BU7HIbw2YazFv|`VzWPiv{otٳ.%aB)]Wij4qn=b2&`M{k0m Χ<珡Ab$K3i`- `2Q 3WBNov@-F&FMJ.dpM`%̑)U412OO#׈/єn a$PF)vbPnʟ#UBdG'H >e~m*\mAfN2!^'C dJbEU]0dp vj|x)-d:/7S+8PZ>d݅JrΪzFձ*1, |ܪӈ-6a?|f_ #a7= ۾o-XW9}>4{a3|tJ gv݈HP#eؾxzS/,׮ dZ:jtGbk[@@ĵocFH39GB>J|QA;c}dbȍ>V)i~{c-&H SKw/g^A#j)sZ< (%p21EsedvM9_Tzc#kvdM`@c}{0IE#,"5x9r2}w,+1eb< O1^K߃joJgYͰUFneoJb$M_ljlP0W$X e}$O)3ϙ& .u4H%]ZƓV"-V'6CU)`de]~ko"ҬJ1y{ .LUi/ZOiA\Wb9oZ{ u >MU]HJnW˶ fA9q%KϾ<%6A6^I3YG,ʵdd2[9Ph" &-S;u|񬡊O#̪㨋[W!SNM-PUn "rm$m澔JliIX;^8^N_cJzk%(U-0J)5²mMh04~͒ ]Hz0^#3{v##ah4ES) JU%8j7dfbRI)])WgFXki ưl> KH `/ <95/I?z[ +UJoDWkhl eG][GؐL]4'qS -MkUʜB E+y j)aFX%+q펲P%:,LO&oGh7vL&-cK|24h̐Ciq4S_MC'䃗-ҙ'L"; ]N,GivCXZd47x}qHz>m2^]KꪑxeqWJ|E|?|ÍحֻM^f T  3'Z֏@AZQ^hM _>Y[3;86KUǠ1JxY)1N#%6.ۉ f>-prh*.[ö2zop [61\?/UR-ƈ+5Q XYUv+uu\62PK*~uh5fB.FJ 4Hcr%&0پGMX@TQYa2OY UY)Pdk4jLsVW"drER:(J1GPzPV̰AH`|eLh47naCeG;еRﮒo3`%c pΎ.EWPd<+;1j$hDG %[A6 v/P>YՔʍQu*uZd$@ 1deG/ԆHSH&EʢU#5"$#grJU Z =R;圏]On e9vv}`A#e̕@-!zqiZI h 07f#2A-@r{ %97AoOrr|2nӐ ){ͬbq[A֕ ?Rr^ezsFc5O9֥Q4t8eY缕0*[zVJEsہ@$ӻҫ(nj O>#C -66gle'FdJet+5]{IA[h[Iꗔ+;U- [["eWjIn|g[%|MȪ1HY>r,RP%8CYUCvpQIHóUzxX <}.L D@[ L܈Ua%.I#a2CCwR-oJ3t Xlgi M@fޞd}ͺ;}ʦK IENDB`ic12PNG  IHDR@@% AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs%%IR$ IDAThv$Ga͈+サn#7UMtڳy"Tus8{?<4L9B[֖5@)Çgz/ P"qsʍ29PrV#iNhB*frΖBa\‰c۱?5!!OsTh;eB,d0*8)Jas !q%SmNSlʔ4)-JY`VJ!7:Z3b A"÷X=Xˁ#8v!şJ#'Z _1q)z;x1C+klgR9sy ZTXGShAlGSh934!^J]5X!sJwxp: &F3m&lZT!.v]\Qsh5׶"ysgUoW( G}t198?LEYqN/$N&jʿG1rS,dJx#P+Ԛ(''rXyl[u(0er FW3U':JW~gk2gx3Y4@C9UP\C8p:YǢe -5' >d4ݔ/#7aHk*j.3}+@NR0S!@0Rh:SSe2g 죶J]'ܼ⋿G}u!lMyoݠ:amttݫQH+>, {-oN?*?yڭ[+U+jyMoYzJan#c*DW^IƁhO?zpn=s/t1,L4~V"=S/iw3~JiLKP˷)?;~ՈJvo^;n 2NdQ.hvo_~)}.&<2_FkM(Lto#Ѻ' eOl"f}kKQHdE&ym2h>Ksz^z-At4^{5wPljʹ~O*W"*ʿɔӍj׆yFŷ$뱘~itS".s?(6Z'rZ/&C6N & y=o±y|<8CmxESҭ[ il6ˣ[oͲ)6 DM(_+t!iޏnl'BdY:RBn68܍6A"d+9yw=^΃f\&٨cdj-ͫK;_יח&l5j,ǦxJ+qtKq8b2泦 yZ1I@iL|.Ub+fUyRǖ⹷ ) y8sy d3lo0kS;M'$fFin|>5o 0<!C9ZFVcSվދ?-Vp%uj}}`{>ILmr9 ma-{\a mF{ȶ%Vv4{0WMm:ẇ5kf]Db{Ӫj]1DWGNOp'k?p)jk)xZtoժJl !r'{ $O uC:ĻET,WʅSFHb%}btX{zAdtT%kJAٚ+}c$JG9m.0u 3~}d()gϡkXzWX(!Q!zƌ6" oqy ciH bS:^JNa9D|XΝGr%#Lpd"}u*F^Sp1'c;*3LS~Hٔ?`jM )1!o@ҒQ,vBUT-/WC s94QaW+r̦lٙN4g>+AȘ5=X|c*O{4Jq߅ '!lăO(pYSRVvCt2h45| v3٪>9E|M-&D(_? Glٷ';]%wY=)[zYC7Ź. Nx9\wOVNبƬCgT/&1aV/)dnF$1:m8: tDn!0 %:ZEzIݱ!?DyBH˖0 !DLc#mdi ,pt[)8$0?+^t8敖F^Z2zppuaqE8FHd2FsD8g aLڮp5[#wLaM/Y_YĽNʼY FsMIɩIi6\$NȊ#߽o La] 1! CN] Q ƙps._l#X_W&EIENDB`ic079PNG  IHDRL\ AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  /GIDATxuךdɭ>ds8Z|"VCgGZzE7 p""|{s!xU<?s#H hhf++Y?7HVk)_Yv⥪XUֻq vKIʸ?Fknbr$D4'p&^XԴ[G`x Ɨ=yY[Id}*F@ӤxAqʣU#RW^Әb8LJW;ɔ >0RkZRK'Tl5L1-+Ku.ɗK ë:MAB|"y)S L00 )P!T1)5΂dqv>XI uBhB馵ԪF+u!Jv|XJ[:zUx"WR3 $Y]]LJ9|#$,JuLrUAl28 Ȧy!hgZ6q>'ocz*EkqvW:6Y^Vu쩀y|)L^+Sk]U.Lq/PHVԴesyɐ'wѣ 4[MmŠ^J=$TH#8ptٖ+Oa;?dS$-S< p"˹*2eaR"a;Ŗ({nrbj1ϫRƏ\Uj??p!xRj K#zUD6sa,U+ Sn6Kǟp@ʧ5LvRr{(YY)N'|‡Kw)RC2Hf<믣;,sjdqhqϧ_jԀ:.`!Od'8fNڗ)pz)Uͣ$r.2AlxNu/BZ"/@=zw 5(H _XR\څ,%`x($¯=Ŕ+l˩EkyFI7erOR^]KLAeM.%P 2K' /ب5[>Z32D̚G<悷 (*Yhr7Ӷ4bjj1h/(\\'(j!uԫhyC d] BNDxX*(=ǡ,N*p t@Ik[j s\k bHK9k|LjƆo`4\yI&?myq ^eϠ} 4CwP!N`]`x’:kçlٍ%檌;fd!w[Vr%-+7Y *i)޼Ц3f(ֹfE}L{I*4gx%@JzVpF )%I\&>ٴHoHGo,xdbZFvvr?q"E}ypfWF+nb%B;[qX!e)<)&[k^u|j3z."uMrw|z#̫ZO|qJrB\k-2B%W +0&`1nY:׋>\.I eyQ_j]G8fxRXJy:8+.pM/OD]+9m1S|}(F5' ҔS8/u̯E[⫅g[ qZ9TJvjRRel!u?Hj7uZYoCZ?tyeH)+'b);Pޥ,%uN$a'rA}WH,^UiʤYVUTSK1*w *GÌHgӯֲ.;!ն\K~3l:L,OlJ/NAV r퐙~# ,WSٓkO-qYkgĒHrn HIR@lG2B% )0Y-GW3O^h-Y¯}"eJ,ey;?j!BJ;_(rVMRd)ᥲb '~|`N2Z[;%0R6S\jy[l&S)XZlZ4gT,ey׫B{ *'_yV A̧oAme5⍸TOx`bʞ-I' Bgv?FEmwLӎ3]oSaSGܒ| tXM?u'5&>xU; )v%߽2bHK5U XS˂zM8 -xee#\b/V._Sg<π p`%CVXSy)sOq'9LMT^Nu,C,7ټ, ?OQTڮFjĕẀ 3T[\`%NJU'+HN*'x̀CZ!Npd+6W/7 kYj'&lKRUH%t Jm81#[|NX]?Ƴf-v:i'R-oc'^jS-+ ?նc I?lJʒ_P6HM@I|h?'B-uYt6ӵ9-U %xTHg2wCeH΃1qZ&RMG@<' Qb>6B1ZBUt0[&`|:3\ ).N?Z6\Ш;3%j"eP#\+N4~+׃2–Mp^Zc]RX.%lP ֫A r* Džu WR#˂@*9M9 jE~CS D9.X64@t(R), .wF_IKfŵ1֥QG Od]=_ǯ"0JYnR[P[&o)o?ӟ_W>\k%.g>)Ja8*'aĴ d1\zU _.YG*Ssp/XR~F3G"(tU˃o[᫭@9%O}StN|%\'?yW'!5Z; X%%+2ₐSt^vF>4v? g?Y:ut|5?}O׾ WUI7*^J) 7&[)p]dłN6"Jܴh>LQeWUO|ʉu:ΎV~_stW6C+_hډ?wV|Y29/9B|hjYL-w Yb \ -( k1! Y?tr8M^L0%;/}K6_ ="O2Bdz__ l!} 31gm8~|\:Ǘ S##eѤ |<P/.;pLWی~qTKK~R޼7<.h,׿u&Z!6^Ry4`#Ep)9'=~RlhɆYcY|.1_w>!@7~ԫ{YjF Yw=kӟt]b*w?߫Mg5Sw-ɦu{4ʟχ^xjqSmMe)h$^?WYī2*p7 _b;zog?ï$GGh-2YTMC!z7;j[h>j-?x´ךcej%q%>ѲR6A[a"D;Yw>JT1W[~86S> H$XqoE/ )V ޱbR8M'IRy?[:}/GH8;}yԅuBF'bN3|SlBjg#e">tW TPUG2?m![H'\*M jt]962{Sxw0A5F>D_"{<|_y/Jv%Fj@WPr_e~{M{nFo~|]?].Un=F{ n=+p.CȞoM Mefho>٤|xRu矪pdy:PV Z5bdx* Ů FY6LdYpU$!)or)چwc\wz nv*;smdty|Tw} }`6R: qi,׊|SWC>T-pҔ~ ֢N@*+r8qop%FqLαǍ|̡.G JߎCrZ~G}fr>|`YͳK7T.u9 #WXUy"lM_IF + v!frgB%"|©m9;o\Jݿ8>w[/ƻf QM>Rdj<^~a//JןOK[BWϗOTȓ7;/6j}w>J~*fp/kh.E/ g]ˇ9lS"vڋ+»!4wJLp ^įb_]?hb'Rad[/-ӧq| we|mC*dK9_?+[ f6)wb]xF=H|x٭p8tw܍\e pIAd!beʷ$dK:0 kcSIY(w>~/V'xo_T>!m|yy{=^wTi$|Rg6|P`th$aTI',#8zˆ1G\|W_ ,5 B0~}]MKW;`Oِnk/"{OJyz0xq: CJ C dI^LK-Cϵ#[90AZ:]$e]Ž/^f?[Ք#oHsJگSк]hsKcTR%qM),.@k\˵\f zR}ned_=- uMb[͕؋=P菬)gZʵ?t=&̹0)4:lUD1J<4Hm|K5Tl9 8杹R=אnM|]-vT~x%vX@۞f>k;F{K7&;Y:A%ڡk[97x?uڲ!Cwc׃?@<ӷ=)'Ʊn1ɶIJ{&ݏ V-m~_+f/;ezI&Z MM!hfO RLOb|hm,&%lw;k r' q4Xj UʹVCZi|OOٻG~|qQYG7 Ev\r`ȔOu=˕T20CAU:UAv@}Onm$N!FVPLDznQbL.FuեC&%f^b&C6OgJ -8(51(P}uwn&8r) 5(26Bx1ZDcqdےk ƷWR *wd$-H!wJq- дYwFWqp_F/[ 'q})Z/U^^p| YRpd6 Ϟt8Ѽp{D ZhU!|!]0P*+8-yx8PoIXUr^Zf4G:P2Ԇg݃KϷiFx-1lVt.q((t-E{\ 3)LW#xt^>ղ!b!&Ys@m*:;D߿PLW~xUfIaL KPuouNYw4#;#? Kgy#i-SQR,*%f. 9qnES 4J?<  UAICF88,Jo);,G8&ŕ\^^ܥ x{H#t*Qu:jŁCXtRh) Li(k Zv-$%RޥxK;/=OɶDT8~I[gRt"Y||؍%.H&,>::NdowMQEHA/`%"4kLKia9;7S뎶~Z#%(0)&8eF_r@Km5@A77cMQaA^J_-/hm0(-Src;}UێYᐂl`q ВpwzC7V-@n1=*gx ,YAH'XRӉ)FZ\+?f-HuUs%#G ?FZCBX8n)C[0 PIM <,f 8R|d%/f niAsSU;bN$edoyjckf oqIJ ǒXG<$]tU JM|"W(@ޕN!x-RbctX#Io hn|OPVqCH%ȟT*(X q6z,+`Z R r<lL> T+h]ʞpWh T. a؞OW1Ua2"tw;AB1ZL1읯ֱ{o9@8kfhq Xho[T.۬Ⲟ~"A!v8 ^p X8g%%UUthK) Wc-'&^ ,*,[^,ۈ!R!Un )+Vp PF*)*hk"\_^|@)p̮G |ˑ v- Y#AqNyKUQpUvJ"W^@p٪ 3o])%#W|A_[yR[lL鈇SkFg-TNB'[b6ۙ*Nѩ*P X)nD񪯲}-mq`TSq F@SKdSZ?V$5NilbM]A32^kg ^I3X{RC ŀTfyPˑ#/e^TAfL-_JI!FXUA)+!!o g,ز쓯uM V gY{*"T.f񫂣 %A6Z sfkeR ypwqSIg9 K QI)F !!TMIpr KYF%K-q5F#,ز!r%8m""n L 9SOP -ih*V$=,c_JZ1D&KiR<+[Z , cDZY" \'Y|@6%N*zJ>@r-ŌB-yoGIL4D:~TΙ2v)cn*Yh)ThyN;N %u=T,Wp'l8C0!ILxY4xy|UO'RX )F(.[@rR!iYL8ԅH5[j#Sd4''UP6u̧J 'G0kDwIo|e$ Mrg81:Vp7k:"Kl>8V/N A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs%%IR$;IDATH uR*1E8g/Uw5Ґp4 onnp8$pY$NQ@G;mV{W (jH}VYAe5(EGnKg .Uq0Ĵ'hJF)uwW{{꒮BJr}m)k뷍_v0[3p*Q얇[ -wФV*msPo?Ӓh4݌ (~[gSL&???-+x<@"XI{uu!sk]bx}}_'905 u h$4DyXސǒF4o oooIvl A³CF-Sl8ǎ%̋: ޏ A $1[.Ηh>&ƴ 5[f?)Ĕ{ vTJ~ u&X3:A8)Zq*+%UL*iD@#6-ȕAl#`LGLEiŊGO'H*Qn@+ bkvX酬eRarI$NS4Z ,W*wo`'4*z$hL`l* RuފI@ݮT A?K9IENDB`is32oׅي؀׀ׂ؁ׅ؁ׁׁ؃ڀ׀ր ؀%ہ؀ׁ؁ׁׁׁׂׅ׀؀ ׀׀؀ׅي؀׀ׂ؁ׅ؁ׁׁ؃ڀ׀ր ؀%ہ؀ׁ؁ׁׁׁׂׅ׀؀ ׀׀؀ׅي؀׀ׂ؁ׅ؁ׁׁ؃ڀ׀ր ؀%ہ؀ׁ؁ׁׁׁׂׅ׀؀ ׀׀؀s8mkic146/PNG  IHDR{C AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs%%IR$@IDATxli$HQ 2~Y 󐲓CU3L~o/~߿/_ n ?D_ #W P ׿ގ3OB/` c;T5Fa-٥6[&=A *eœ3CGvǍ[](8$+ z,j\cLQrcD:hۮ15"UHG&|Dڤv-HKnG: CU3L L$+eⶭ ٬4Z ɇ@2]F5M2e-M05|ǘƸFk\̉ ņ\LUh)e_>qv_3M@GyL7_;6!n1 @@ 1jgwO 2zbӫR♴eƴ |m !sӱ f0g՞IY*ɔ*ZS@ H9P՛b ̖,vᨔƑ>Ccd=.$&37< ]# O*YF /ܾȂL4x";RVh"X{2LX #}v$I31D7jZ`z-YE: J[' z d[UbVJ$r3!x9U Av' gv#&ChD>T'ò>l ZjAj98ʺ(%&ew1Jb5O`Fd{76b-@KRu49ӹ5<**ͻh#ό{gYvnK"=@ܜ [>wvVm~_\] jɰcSҶm+ϖtGxdYSnJurm]Jr#U/vUj E!ѐ)%g<>Ўz !2L6ur:jJ Z7J [[ƈMmk؁ّK9FwĈvltUG?+$p1ٮh - qܱ̹rӈ^k$ȂUU mU;L9 `p'QjǤA^Ѵ#-ؕ|$g[Yi[DivkFs G*Atܐ"e&tH &ƯОH&L k\M%@JUsЋi1"[>@+Ʊ7eJ{LT;M! eDuJzlUoV:{Zx2y:/mʭ; gw^* 3obz4{FOt90lJCzEP#?e(/B4uM#FQ#j2醹ebP<T+ KqVբkGc>L倪c;H)r2s0e16IVW~ ^Fjl+z]pW#G0h&GȰz _  +eUSՖi&-`-"9+91<YPV.-i{6t+ \&@T;9qP^L xprFҿX ۊfLc XhF #lb#vo^=.R{0Y]עG$a`8~%<@/8i,SL$LDN!*45*#e 2F?Q8(Pt\T BXѱ-UP-#52MwT%'e#n1R5pd"<1 v K7oIJY Y; ڤrPuYhy$,jmk22pσ7%m ʹ/B/V;)(󼓏.T'Se}-S)OHspڇ`#ϭݚnxy+* 2HLwHi^@&^),wTFx$F!2ed_[Urwl 0W4 +]ReT:$V- YO+g hOS( ƨΤ)=/c˜+k)'賠91]{йo@*պ}r k琦=^+8%&vSD\/Cn.;@iP4H&~7W)Ԓ[9^&0~JIk:+`2Um| )V7Z(iTL NYj%GXH0!ւL#n7+]k!&Y%JB ͢Q`@#M LLJJH74hiH$|ȜM {sնqQ&>)U ^˻AJ~lXPXX⶞4df'};@8&ҿׯҔ[&]m;}8D6WעR̢g.m)-X@]ʈ0;DRjgkUٷ,q_5_Q#kטUY5M56f]7+pW} O& u19Qv=2i=V)iL d$6.u%F J- kiC2]<#Odb*TiDɱ@I!,6"&O^6DǪݷZx퐛H&2瓧c?^ F#όLCY#DOHxG%UͰ7qF@`R&.c0m޳Y cPu0-RUƴv]YA;S#L-`z YՎiQ(q3mB m wH>? 5EI9\#^ضUjk1HACӪ0}b)YڑkdzS1+@ yWm Y#CX LS )4'x.S3@"r;9j~KhR4C&UY158*d 1~v]"Y ,O U 71ǻz+h1&z[,^_41Ք2^t4F@;n laaGYDZXiPr &pC& ZnH Ҙ!@_c>6S~:x;P:9uI) ?g}4 [@I^q~CU&n {|]س+ = R'_uzv!6s;? ±q`7Hz4BFָhWdCw%A-&%+EsTGdzxUx ^P}0-PkKt.(Ŭe= hCm#D9\'uXgU8%+9@\/RS'jbdӕ<%,kٱ4օ2Fm(̍b"6Q`|Wu)qPd8RXACÙCOI6*̇o4A&j 5^EEo+G<2֫*OG<ftdޗf~}2O0<o8&s!C?|U+-y,&oUƑFcZ̈́Lɑ[ 0P϶ G(k hK3J,cJ<@xJV FḩR{FzLV2[lk.8PIU;?O dֱ(Cr9t{`dVblJ7 ϯ9ʬm6 f8:JcNHPU,͵ƺJĦÔYΎ431# rp?YU `@ Mq}R|F8"g7TK^$[ΐ+Cs7jVKl&BކT*4Z4dH8) U'J|L<0$dİl `jI9 *s3>3h0BcWۄFx^ه&)[lFba]yȔ&RG7 vb|> ս4}$#}syE#KuUlD45{CXfŕO)5 ?*8՜evq$ȪSД2 Pc,iד)xJ@`cZRL1\j*Mx8{|]5cG-`1@A᭑R^Ѹ "Zo8O?hLM4#?i5)`O^$OG'p9d[{Wk:p?n2p2Qq;8*Ho%Uue]U;$Fm·yJ%J {.4!an֎/3FCa$10= u#ZdLՔh{aM)(y UE_ hJmj\t;]C`",G? }}U  86 z3e"O% =|hU5+oB?Mn;|7y,}js@לj* Ӥ])CUHU~K k E;W_Ԙ,[cz:]Uw;U%4ȺhGw@WnĞ/dzEj% }0eHs}}a>uiָ+>$+ h[$D$$gPlxSJwT0MHSo-MU5ZQmD4ܔE9p@is[ed$Q/̳j>&~m[U [l؇%;&ʤe10٪P M`Z[./92l<%!,@W8^gc7ʷ1My"HӑL`a->nZ3=# e cu=qz`.Z֕Y}1kd6kpklA^VswiܑC^֥J[DԒi)UvlGH1~ہu6?L x=¬[T U@6TK$Ly>߮.D;JĀ f-Ad 1TVӴdU9dGHEoVJ-924J!1^d.dJ0F~@nA<2ܪj<9rHG4QIg!2}]&f@6 ># I 00X~mt]; Î2 WhqlJٮJ 6`)^[@2xY¿rw P:*S Y%FUT.bȐh0Z;VCcU `n[]ʇk$ {?*R;=q[ Jh|j8Ga16_ e>dȟKjJUU4n}X&#.>LIrU[Þ-L 8s˟Rj>RT穥 ; 4uC 2v+BcSg=g AGI#z7XƓ%[IJ/e4l);fa"'圕`@YsIt%WԞ%q#I)T2QvM]#9 |8;gG21h;b35hG} bKNlz$=4s롔2b>_ΤԸ tߜUlUC#jb]bpdB8#ڱ| ٯ]u/9C^>3J0rJ8Cn‘I]~qX)L_}̙8ڛw9L 7T$وrvlp Luć-Дr-6{.uaT{^@n0^N\ذ-4"ec9g_G>5V)Z" W51OS V Fo7qPE X%ht]Fu~&tM7%Ya,^-x V"(t)k!ND7C@5׵e(uIŖ4;#,AUY)Cn7%Po&;L2}nC6a#S|d#?8==.@ZUI82ua@\G__7>>3?oìS?^-h},CG?ߧ!4cg|6ZHG؋w (R"qf)!eXldMoOc]@GbQj٧AU+\c ٶ%m7m&g'xj1:vbp-j;w%jD tAXN6.`3!`Dtl\圕t`uXU9}0!{RX4 ]J)4 F0Ծk\%ZXKFM#^FFg%8[4.&ׂ֒q&(Pc,7+܎^WszGػM5j 8lFdڍV5g"H?u$|ىJg[ /PL|>r-#meFcDG<@/'6FfZp7=_@-dF|U"s#%L-1#hgHg-dGz&L0E|ML,SBF4OG%Lpe|_Α6!kFyݔ 4`DU<zYq02 ^)bh+U .].ڡ>+7% z^OWbV>UkmS1{0f]3e"9IoA]x"'JhWJ4ː)$LDVI7}jSfe.g~=J9s&XRUG p0~|4|>E6`[–>!ݱGo0zUɖmO`pw t7:Fe(Y^<0Rh@6 I=n,r iddX hs85w-u!#`8PX8*ˬJ@%<)6[>FLx3p> Qpƈx mzmNB; PڽH@A)`ZH92J\h ew!.tc*i|*ŻSVrsLۋlg>py92&ՈwL>}KD-ӆڭJA2AkΡ5rCZF˵l[ }-y-Zdd+2޹%e2@-l-3d4n+~ L횭?գl@9>>ނ8#R߹&~sB#Zr R4|q㑙sgoh+OYp47ĢdLLjLځҍL zّ9#o[Q&W*c>ĖVI57d FV4 C?V#5eJ0FAh!PD nD㗕yIEId ğ 7յ'[ [%1{[ q+k (g2 fWf"c& Ӱx'Pb5Nny@kו=K2zo^ 2 Tb1- 駀r]q)!e] 0"fǵ(e wv-:k"U]ARr,`a112R]xJyqħkT*@kbDx ZׂsI4{ tL!Y>a^/)&vsi &~FNFc->21 >石)*J +mg,(s9AI۟}kM( U*due@nYqX"(j hh@ aTW{heJօ2DX#A$q(U7LI ESrX#M CH'17Nz)>|Z(,Z+KP3QUo`sUlS:3L~z%9O,sf+%sFKV jI|nΫDj응4>tG%%>78 9Lt)헲2Y;vHIdV2+ZIjԢR{csqc`Ln6ꄑUJ<=+Y'EwV͓֘m> !ht=acAMSF(kg%ëަs&IvVj7aXuW=SX1D=hͲpW{or2g$۬d]8e{Yb?3 <+ HuK/2r7'YƂ2q%L˴&X*FT@]#iLR&Z5e :H0LJ#SfB򀹑l#+DM"s~/a kD;`FebǍ>_ %}+]Hvw䎓ߍ}pFIK†aLǘhYqɾ< k ;cV" 2zZϢ4"@ZRncWMf8AVM]8 q&pd41AU+[{4{ɔ<ׅd޷}މ[A4N0ܧ,zdddazD-OV XU90Jnwq΁8@h@#G3OU^UѶMْY饇 }064"Lb`J@SddbozGfv OVԢv,YnC GP%}o;>b@o(y[*#}}苪Y$"P)Lqu>@湑٧GSrTYVrLVjJYZbm3.2n UQaG6jѫ]a!iRa`~!r`;r~geU-JM$vJ|xMl%2LWXe3!`X'J̕,@Xnt Ҭm)Y1,Gpz0#w';VBLЎg?X9h,2m[[՞-'MڳRU=#[5R471Fh73B7(>r&J-C]prl*QX U هJ!dzaw ͳ\!nh: w$QW p+^&( Hv4d]-qέ1-ԸvOW s/%=^ -b#MJxvԋ C!YiUIe΁Qs@3O;z8sĎ:"6b]X 0N@I XmGd'ޓ6wPa}|] #UÔ^CzY ͐H%=ϰ͵leL@o}"4JJ@ F~p%."d%G>Uῼrߞ ^"CR+3ϓ {HّC&2RKSu)ܑhW-@+2L무F7mϦUl%R#0|ȮIL~,L嫧adJU+dLA^KJnxz%W2]5Y]3TeZ %^h3h&‰)S hD}~ȶͻxczmbxUJM5r9Ղ8&(.NSx.}&S:H{>ZrCbdq:38,+#x-e$[gWj702QtGU7ˈJ0@10s\nT L&H"ۆLJ"E;6Dj0O?s4`H }Qp4(}&SWomr,O2+!}Hٶ^j_#e|ad2bYVd;(28oDO (/H]xâ&LK?rn=^`%ݢkkj{&k1禘ۈZ7 7-:gU2q7B.Tdsptz^/d>1!*J^L7TI/%CFɰ)Y)1Fv\O1Zdmt,k4#,3 ;񒺄!_Ftdžh$֨E8jl+@MĐu# d;9SHYW#!~$7! 8Z56Ԟ*qvW_ օT ʶ,bKb8ΰq󀭇Q[/3 $nOhl.Y_ˁ}"mNܶx6IZcPhpZR ?7 D%kQ*ݧԀ>?]c0IJ^%PTJ lcؑF4`+4dvگ@&le8ܮK%n1ٱF,0)kQos`p#`d aض\#B L6x@Zx&'[z>k=AɰV1)YPjTOS!pΔ"eّm*+<ۚ[dƕ|c2/$>#%ܚN&fZh꒻ZwLFP/ۖőm2r1C@2q# *%.Ǎk%U ]XuD5jo/2$Ы1F$0EKؽ΅4 7Jg}d#6.>|;UY_0ݍ` YX<};Z ICPd$02H@@j!FBS"@VLU]9^  A4Mp#h`s@nV2-½cŗ*JxRzlM^hՖDn(P;R6܆m>g.Fc[#_t%n7ϡ#н|ʮ玤|))1Īzz@ h^7#C1ڕ(cĎ7OaOk%% ji1d2mU.&|朒F|xhWMZ %A{. ~Kln ;J} d OCPʧg+WʍcβdG\V>6t$c"T{寚Un@j{e>1U0HLcnUYܪsaaP vDxVȂO%$# }=>5rDVI2$dE&ۍXܗ 1BLk8P{j\-x߷& J٦ea\%RϤ UY(N߱& Ďvf V|| ujVC} 2>Q[f/]"O|X"+#k!\$[F``Qn(WR)za X(<7F@ Foh`~%^;"H5 adC-?jnCVj Д,0\E2+|jגU4A|@J N@|͑ 7 H~/)}:!z nVJ*z%|zJ:F/4*,w$#,2Y kDxU)RKZ#O)+ϛh=e׳p=.$Jm-7ZLARz^#Aۙ dmzYE6e>i`@6T#hO4ΝBm࢓&d@ K ߅ik$&h^R#*ahg gXVB҇9R4m}(T=Ƶh0=`g1d+UL-J45*a:o7& "1zif[ mNc:,kեt6|j/}~' b&@( #@M|ngE_M`&S^x}᩷Y}XZZCt}3Y&4|x(= L#C2L#N٪2̄@I61J,-@Jq $;ɬW# dm e+m6o+d`|&@dЪmUUKN.Y#s]M$&b|`nidSn,PnL~D]oJ &kQjm Uws 雡ΐ2 dN/MxvTӊ\#"#p Xl6%lsh$ 뚀`^UwY ڍwJ_s2z=/RC*HYWbcq?qW8s#ɡ9d UkP}CjlʬTŕ$ v4Q^߱d O OL'#)+2M&γ$o=E]aՙ`( 1rVak^^;M?ttT->xnAFisMSJzQU^(ҕchJ]IIqq)<^H=d=pd+ɎYU^!k)`-hog$`$ W~BTx =D+)Sd0Q$FFpohǪ2^K`-pUŏͼY;.ӃgwY K)[o8s x%@.(14`bj7,׈QhCF6[}dO2 k(&~'Kl5}eJDl[ςȡ^0zץ%QWmH̄'% \sΎpw }8p&w)k4OGЕ(e@#59É;ʜ5 %&h 원'L,"0}UrVUZ#AHOzMT׈騚?FU$RG2dAg+ɌȚec`%|vJh{,ؒZZ ){ tϪ2G:@svobΎ2DРj[ &О2eD-f-OٔrMfU65 U%y% 'Aeg8[dKRNc>9x9C)Ϫhw/Â8M`dk;2º"T@IDAT:U'|$2+֮sgNjecxY;5`GGOA0^{ dG6 lm#{LQh{qu#+1Z3x~L\8_mqͳ K};S `4v/Sj$K Y?ڰW#Io#\;c c^v;zQF5 m epsGR|3KXKb"muY(riwNJ1| Qb]J4h?=FW S—J VU;r1+}Sїެv>x(F7.dwVr+#Nj- .@紧h9}:|D86 %C%$`bHǵӇG6W< ĂI LJL󇉕(1~júj嶞o7-͒`EGN_{}eq +di`8MXO.d9OazneœLTWӱAiRn.&=@0q`3k>*W L-5P:v3!0}aGVJ߱ozSd0F&6WIx鱘16 =T䦪@R/@`L\KB  [8W̡e4ķI`^Kf1<57gj.-ՖFrxcL(1!=h-]!vz%wq)dJfmOXI&nG]JpjJ<2dёFpCŸ'H.QVUQ:6MG<Kth^[-dH ,:68F{j73")T)V#4L0\M[P&Art Mؔa91ړLFdٽ0BLL0+- V8Y%?+%e$`2oDPYLuY9"1UVXU9hz`^^Qe!)̷ FPfRmyw0 IԽ(E#f^)>q.EH2GsTlPa|rh-:`䞝C#6QI/[w$zpYc4Zk!JZ PL`Ҵ1g #k3#0ސvYWȔĬUۊq(,I !)uqJ^[#F~_?4B@6X$'  %JQ8.wz+5J>?*'")2-8{VnQo-VJŚ 9F hBI+P:n\&\!O*>1"[Dax@cC%|0^Jǘ'[8۬0  -yr p3'SaWcI67L-Dj ,Xnu1q͗D.zz|`ac2SRv=HdGJǖ̹ګ?RaK:crHX#+ ۹^ٱo#@H>uj#8.Kv;8%HS;&n\ |z6]Ur#HpDckmHp,\m Q /[w%m#kxTDz^_Gti@dfUdϽ=+FȔid>&n\ QI{$$سM*^mnT´@Z[7}4m-G $)ti2Z/vM'@ c6W}gYc2%p"v6WuYY/M# 86=rW>ef%ءyƳu R4jIIY%n[U@G:"w ?|0$ V iTs.A6t~&Q^L$c%%.BC ;!%gj:FqƋJ+/6F5:"`qӱ.G%@ճ͵J`ܱ^7@&#[9̷=F:<(3^u6o2*^SIkqU] jz<|?$*zw%G/e?@S(DrG8h "&bR&6,GbGySlA[Xv +Q۽E$cŽ"CzYTT- <'u)|ĒvZάdbA<127FRrPY "sY_!*Qg-hD$1UaA6q_v[OjnCpHt&7+fF1׃)Y}bhvSZ&UkZORGiw'aHC ;"c)Ŕ4IJ)d)1L6hX#=l `z>$z3!>Ê,dQ?^p s ^-JJ%4Ԙyb2]R|z5b`? c(ɶ3sC;'CdK߭-.H%@P圑Jkl2sQNíF;h7" )٬lEmC7WWn+3=*eSxƯ@ 9 m3γ*sS\*FaJ.g/֯Nn˰c``za%>(mr8|$Pu F`MUK @v5-vpr{$ͲA6Α aUG&U;v_9_ɱ n|G?)u$h"~wM.xeHApox9 @*]ϳ%-ӑ xJXu?l Cfr-[̳}RonEMl@G%hzUj Z2J+bE.#'{Mnuw眧Z"pw@7irad xSi8f.'Wa(x19:J]ӫV;Jp,Y/1 *J1E+)\(iOJ{l F&)0w@ۓ*FXn7X U`RU|Jn_vab|8JEk@Ĕ4*&n:۩ )85x4J\ٱ(9k+9}gm*%&feh0ˆ6?+5W/Ď}6|[*simC4 ۰4[# 7Ǵ3xJ J#`?wX#'>?'zYՅÚ؊Vtl嬸RX 2 LfP)gԣl%ULmsș qF;t{GXTzJ-)Ӓ]2$Mohl %a%@i+! pLhr>`4#a%\IK#$v0@)'ğ{5ǘz+ ָR<})Tכ ?_W㈑N IC+䀪L"<GZ) z aJXډ2+f5[I #`LJh1 5jpS_ɔjqbF2<\{iS1}$nt) Ahčs;Lez:t|u:PmCcJUYM9Mx+[04}d7DRvddV:]?Јn==@#M&5[MT fU#EXFֱh1Fpϕ$nP綡m^&UU"EPLժ2Fƴ]!MǪS!cuGsy:Fd}ZY൴0MHt$`Vaj$CX4)1pxɲmhaXCJdJ;{G&"M̱wHSF8anr]0nrkp]HBx-ۤ*^U͍$kxJ~0a]]--k.(L2յ|~)I D'kiLp7EΫjkqU_mHueM~)+Q3`Z&a`]@Ҹx<3_&=vGz~(9w׮޲dE- 51<FGI{vhD s;0#%6),춏ߒPWW @%@Yb&Ѿ))vu.|>E!.Yq[vF 0gGod"}k8^ [Onbŀ[Dc"@Ǧ4SpibZ8k4tGę&va4c`$6)#Er] r53,"^ƽ1 ϡKhUʎ~׍|`-p{Χ.Y H 痋ˤ+@וگ6.ke2 MLIWA8~: T|^|8ºx-W%{(: |Gu9ex;VBTrTup'j: 3JFJ,r1 ^&oʵZm+N7 !Gz J%khO ,A'01,u͐6_mZb!n9'hbA#g%tU FFW'%V|x)4l5GӈZ>,Ua @Vݸ48` 5}֘v@NfJ>$s>߾VM6#¾(eC0jZ`2vhw$#jP'0 )4x-g,9 _L+7>ȍ y9{1 4H8@WՍM2 AиxޞFg8%`p<{z#VF+ kd B[yҨ:"aY0;$/) |j3LYlg VPIX&G0^,q|_Q#@#A wYᒎ]O)>ӈl9 Gp ;ZΡ)dx݇7Q1/Fl.F|6dyfeBYl1[2F; /FU*FI*}aQꕓ)3Ǥ BIfמ @4]s̛١阎d?sYarK)7v[Ӫ&&Ldtb֮OYK=Eiw\l#sў_<.|J#kܠYiL ݽI [.y+6X< IJq1q2R#:rC =AG2wJ& ~dQg2c)ha¢wYv#XV?>;6߯ZFzr1lVi2LG`Km-29/V֥&}WVI#m=[%0X/tLoum*QTjtHV過u9 %"-U H, Q@K7B# J[U{|`b(^-656OG5%5>Aws[ 0W%k@Jl/w ;UC =D6e:܈תvJ#8LAiFF7l\`.x#{">)()8Ϧ4&Zh,'lu+T-cT38춭rKFoIefi}|(L=H&MpD/@֧YizmڹSL8, W?@|T7r[\is- vi!sF czȦks3p`)k>xJr(߯qWn&J&jdgxJ UbEU9vHzkϜ|UZra"O}?{M8xj9[$PntHs4d|>oIn-LnnFGrsUlP8F 8iPbzGJ}?Y>[Ú\jW8?2R6@$QpOP'W9WId#[`Æ!h[Rm ϼ11-qa@FvS$޿U]9 |2l &rXᨚU&p$Qbd4.nxOPKΰ;lj| &2ekzJ%&dk=}ds,&bs)rSJ,Sb**ӯ72ڇ3okwlRncyJS @se-poBi`@ ˎR/Dz+Y[[FMTkD.rU%ƽ]FLrĘo~`)x@;*tdD* ȹhJq.9IJ=}um{@{}n51 ʖ Q/xsג?M2Ǿp+o|)nk$kۊmoϬ"rYj]]D =@= 1"f%-8M|CHJVJ?bl[!1?fU#aQHEuN2Q^W0~Я\;L ȑ}(t:J٭ɴԘML] 0ZDWbk0TwbOezLokX% FkLn%ve^uEYU~[xم J)lnc8_lyF;s[,qm}(dd2=Æbl%4i򁑵+!ᘔY5% #J# ޑ&[LG~Sz=r> ){ zD&M6Ƹ0"8@LF 4My,?A-HV7(̹qdga[cWrg+AnJ&rgߖbLDJ}N3i Jw t CH&jDU(F&}rybV#JMenIz JY0/"ɴA`μYʼn>񍸣>FJ ~,ZXV 'ĕ}2*[&%#1b8evLGё#wcUKO32NkJ՞+b)'ebBzՕўdaW뻪X )>[Lx&T 0eO #6QH޾Ԯ}m0CF:kG/fћ72dw ,sXx{bBަ43yz=AnrKyj1 =Yrk1L WVx#ahdd $~0 x4YAb9+ыH-z[ÆH]e8%^hOO,!zd)>V2X܎s)-r`FAϨ^oC2*a-jzlJR M{eEF#R%G-dř@h,ldZ4+ PdV$qG@hFߍ\cݮYH/2JG<̄۶u cjJ#l!:lV#;nd42U'ƛ%c'rLJoh>j0̥cnrdw|JSDvfD6Lj+AbFȎ۰׾?ph&{Y#ײWRS}xJMVkl bVW$p#F4YGnAVUy"Z^Y/AbmgUvpad6^yw}G|vn"FKkd &1"pVŜ-CV t0?ы]`$JU$D#ᎯFbމ0v9`2d ǮH-;YT%իDόԈ袧نUy:yaW̡vP2HPv܈sU1uй8]U06,0d kD6Z|1z dzZ\?Ej#@l& _Iv/utACUij &L#6ȦXEG#MWjI(7@+‘~6o gỦÎ"xE tԕ>c86Ua1qDe+j -ui}"|<=#Q[@nr$lF>29y+Wx2jq1UcV6Lfdh)#UkD $֪4HGU.fFh4Y[5]&r[0ZFʬ|(G酽qH2>3TW-&erP&ko5fۿڗ=1}@U&9:XO.=? [T&Frh_3yv!9}m_2#9Z²^ݔFo>dUՎRHsL*'#0lg L" {7gؿe41vP25UGnmʗwAL 52+JG|2L6.|S˜Ue,MR€hrkdU&~jOKC߆I($cPV&տ;KJ;e&MSvӆ9fq,~]˳R<ᵫAJ>&G#;jɴzѢ/Jx(dQi>Ld2|ݨ Z8@)k!F5χhWd娋ϊqb2-G "V}ͅ?B ,\]SlT k%3  2f3DkW㙧O^.%O&lhG>e 7-%O%@#`4SQ|Ԇ%0vf@I !è2gk# \٦M9foyd*mmQo AFۮEu䓀Un1d" Anx9ìհϨ);*?(ʹ\ͱ}xJڷM/?O- jcȆ5K 3Z]ѵ9>xq#N EbGJka/2zPTM,pgDzY ɪO@Ƴ7H=%s]# a"r&'Y Ruwh | UǴ dj ģ1뭺)ZȐ6iլr8}+|MN^6Q dκz|R?Qi󰹓4w$Ϟh&5[acw^޽yifu:}M hDbMHHa+Ubʪ)r[b䦴@f)/G.'Ma L]4UWjou=i̵k %2]idKTKL ^$Qinq&@MhǪ%%G"u92W2h>("7, W:7#U妷1ӏ4%}VuH&& 8w #3hPZ3^vu9*a`j L2ɖJUW% 0TV3&d9HGJ'e02`*w2$,?\uPo[U st蘧j WOS p2Lۍ#[J4d@lzZx)~2ʾL_9ECRJ ʼcV7@Uo#GsQ& ~46]̶.t %Dn :F>qivnDbX\8#>&L5y¦HAW8H SFjײ0׿(|S$:xA ݴb =kQK#Rtd# 2VJ[ȷty1Z`zagadb%2&Gm]k'nm~a7+簉ہLKwOnxdpCKjkE82W 3ĨƄ ,>u31FטV񀖔Sk$HI0anQ},~7bb."|"0YGjz}p^&2 y@9%m^hJduY{;]d]R#%7ԨoÞzBºD k*83U pT1|~Y8fUjJJR(Ed[iZ2[&Z5JEh.>4 `L^$fX es}LMUoFEx0>=g-0e?YHG_dDfe5*V-`t펽3p>K̄gI/xYJH&k$p+6"!W{~]v\['jh0iaʜI!HYkCtr;Eiw +h"s' Y)Z1Yt+#2Dv V;pGXde-r{^MUmm-Kk}Jzϰ^D WγѪHj`T7 m AV;_n\Q9>1|Yi2J٫teex4,4Fxgd՞b@Tz1)#vkV1z$NHʢ^i%]-I9l; jp?-阹Y̥l,rQlFRx JĘ+=i/h-4J[zVc*42R pY76CH?Ӣč^`K(3ٮmS4":QEXƜ_O19hPʰZ dvٿ͸g S:2Y,fK^UL˰&p&mt˗ %cA+Ӄ`Ύ@=W4(0[2FFU۱.h+J/gPX9RGYLEuɢ^@4ez] @Mࢪ\ >rAr31qn@21r)Q&[s-LD?YbJBI#ȇRVjLS^I g@j$d+IF(3l?RdUh-8-6pވk˜un4އDoG@`p+!{i0}1L4]W^9+-HL-;$g>b"U[ʮ]=jn+c6 J/Mܒa]tu5 'eC YY dp{XXu3M2<`yՂFS]JcQQikZ5`]&0em@d2FŤ^S^t$HTʬޑ[S <ٺ:VJC٠>?}--ɹd6'/1R['E$6T򁕈sh WKѥD'J07SQ􎁪(da5xUzaVyʎrvG> ŋ; ]dy6}(1UnCKbިvϽ限 GEYcf:!gV|tl#rеϬt8n6ϳjȐ4"C-5Pjz]aR9X)uZx_ R)~@IDATC4|2Ǒ)㋪p-cD2裩Lwø+MvӍ6 Td<6NcS"$P*1AxGR<9Rsw̰̙;7,߁G!7I ܱ.>E0^n212JO<O+u%h۪<\_띆F9*Uڕݶ8dUr3Rͫdg=I>3D%[Tn gB&}@]`J m:)JI0IL); -Ŗpߪ&J,dQXP{2QWUG%]H@}pP1筪 4 F%V^C׋d2O# +dH U5eTȭ7-յ?R5y"S)ThZ)d5ZҴ.s P5Uezہ2le˓^_V{ z[Wuh}R ŨvEFȢFz$@g /oOoD9 8H)8=^^w f)9p;WLPnsFUcvT㮧17yU:jqL:v֕)(1@ &-HU\̓Bn$Ƨ'+tMi:gA*7En1XvOFdbC q0M88 W\21 ~Oam 6{%Md'$,(1Z*k%1+%(NY 9^/m!Ya%ę̪"F憩7g'9nh$+|XpL2‘pa -qxEˑ8XUcBH JZ0ЕD[#FP&sPKGOXF8J4 U9f8^<1Σw1τY_Bx-՛*~wtU?iZz=AE둥ܒ.Ǝ,Yc]<_ -F'jre4#,MтqI,wTi;b&K}~|]@(>Tvd͠n#&s#:v̶j>JY吲p[ȤWɧz>u 849F;֛21((Õh`M?+#1i]k7]#\KN#rWU˦Ρ]oK%U;4r;4r BP`ZC #RbmtFhQ2\bLA#.Vm])fLhȶ?ǴL)2>GNEh%H \_"UBN l(cCە3'Mp<+bj/e22CV98k9Sze\/hgs^~/$]Je܈6;2n}=&@T|21K{2 E [OUeʎ|zJ xw5EWF/% y'f|ޙRh#!+ѸZ0iLЪc]? ~g7azʖ?plJ]J9Ei29Un"YwgQnQnbGE}fkẄ́ gזq[5)wϗ(}( Ьц<#`l2V(pvx 'Q>?@֦\:êf.d"},rGbxڃ p䓦] }ɢ5jkm-^vlt>2)@V{o|2tGI֒11e8%2F9&si&.ҧG<̐O!& #~br $RFd1H0hO +1yC5l{OlJpn0PCƧlw1R-pْi- EJuw,SeΪxJ-.}”ml11Y Lsu8Wsnc,Lܷamu' slx:otpl46 XL U1|C &h%An'MC#e䀯֏`uA]Y?٢m6; Vg ^/ z&FOQ]QU!Oʎux=[7]E* 0B&-j M>`] O z64QI@n>Zr }ϧ)LR҈UQB@:jvX\ƺ0F%# #a((}:}I֥9| Λ@b]W#vsS{sdkL$plcP4z4۪Y= 4zn Ue1)+- > gyg@-B9Saڑ@1d"R@njّfv:4f1H׻4c8dSW"[E45DY8tc 4W40&/ gg[a5V5P < 'X&S᙭ ֐QX*Mocp#DfI߶WrWjlh>l嬖3Y1Ød2'Ȱ<ɰX%V);½Mh2{CggPo#{%d kٔ L/;([(! jL~QZ.sӭc.ko [$Jn@4}Ű` K?C ɍc#b`@n6ej_{|Z`]YɎkObJe8里qr7q^q @ĤTr44Hp]E[^X:H1#Gdca.`As쎽 +#.٬R38媭a'j8LZ@Ѯ ӷʽ`-J-91_ĹUc?󖡉";jdU{#ˆ&j(tWjpv_nBW1P)t? J|xʘpG%J4P&T)@L#^7歚94y6j-%,݅-M;E>zLibLAhl&a# Z`Lvͪ*F 7#PygH UfRH-CI/+Xvߑ='1LIlV8@d; `hTa`vod)1Kl [r@)7dkaU>gR/6`(|jyGA?M[vxwSeyt5NF;  qM p☭",0<9Fld"2C6HL#}F[mU5}iIA)eȦ%JsJHAGLLdӑaxn"^;LF$]U;fBfki00eؙI*͓@8"LYՑ'F-^ޗ VSM&])1pGJ=M@4_RI[G gAٽ?7E&n koT1n+e,k,#QC];81p7??x^Ƒc>hcUJ+(sӥ ij̭L& +L|{&HJ֒?1M d*vV(*310&J#D 1W{FSw,0J[njosFkZiHQ8%!'@L\44lÍ&ֈ$vɐd{6X8G-4mTrCLL#ԅ =8")0iQΘ`J kh끌l[y”rQ سOb[I1$ӻ%; 6tzmȶځfXq+--(ѴU d.YW/^pN\Gh;d֨E$VLZHvZ0߿ jaj*,w$l]ٌz;6IxJhm fk`"(U%UeFIKᑵ C(7w sk4 1ݮx&ĎȊ?&7踏mB \ aSW56F+hZ J&"JR h?Jۖc;zldvk<}%46ǽ0dOuth"lSj"iJ)aYmU4971űdZro Hנ@b4%#W[3jn-Q6GaVkOcJ0{Wc =)exJh8vwJ g&Nl^Gz('f2صw̥#_eZxX#nn )鵘q0&}-]/OzUlc U??FN -zMkggFc1vlimBP1Z(ǡ G%6h|(|1@[v4."LtBJ *}8de+$;2 Æy 32#Vr~.=vbh0-h̑+?&kW}sF0[uZ0;_~a[Ƿ '#l:A>LVb4d>,РZv(mGCZRLlwdֺ. e L|KZ օ <Ex%/FB)~NVUVn<Яƥ*7wKY5(X;ap&4gߗwIȹ ?̯{"nvera&^?zڪdK߱%Yl^`j&rA&`gĎxoCXqep̄'M% 騅H&9WmF(9r(` OUbrJr@Wb@rhgVa9t |:}ٔ8{I@0)e{.J@ PT ,bH qUAZh88,K!8mJ>0e-xe{|/S #gG-j]mi&"c7(1^y@n))rzZ}8>* %A"O4Hz98j dڹɪ$NP~ɚ( -iL 4 ]GOPrzcG|ӌ&UjP-x K/34ECGq%P[`L!Vj4VhZ #v ΰ O_S V=UEgࠡ,a;d]۲ΥmZ]v܌x0&sf>^9>M`"o*@9g)@`J"dht UJ FV 8F6mVB֞X;6$RuGpMqS sA_4ͧTG7T^s +ij/94Ǎg",-mJ@& 0oaBuJx9C(g&>޹w 7WLr &Mm2GLCpQkWMf)uJL t΍vȰ0[U@PbȄ[??Mq2gF Y飯ųcYǴtAp7>2D+Wr=JƄPz<=:7r1.]L?c'hZ,$ęV 5 x#⑰,A&?^8w lg.0wm@yG8-,hХEW)-ׂMojsbJktW Ϥ)pGn]rX&*F{L_kvdHQ)͕4B1Z)2KC&rz9xyFX[#lk > U d_{&Ȫa<0L,&ϖwtd-sY#R"Wd141J+GLB51˱hneGwoV^qJ M\ P׈e_TaU ;,QsȊ [D=Q=^-Y OeGϬ.,3qL ?~ 6=}$br"MźJI2R6$Xtݗ&dūK1YYICSPm je1m F:GqVSߑE41ޱ1Yӈp^O9VwK[ e"ӫbȈ4tTb<zx-4J@&kMgFǪ9 rh"ktWh1M '<3q6gmB/땽}4 úd}9T%؆xÿiv_+JQ&Z Pwc(EU3p~:"*t w!)3`ygg&ʖ.45F`L;[VB#0 =̟X 'C GW{Rw4n4 sS<_n:h>97"[S:*.׋EõjDʘa0q>eD#:5ZLkAZVeDIhy4qV^_F{U6Ci[zbde-}Xf  %sMVjePeJ {ע@  ϛtU Yo"Tkuê)2qdLʘ}rkAO8ƌtT|kEVq/ÀN/SB_(ij=xdK ZeG-4gܐ&fN5g??F N8iX]mUڹrvLHRN{yLb0sْE-dbcz J 7o.;SlaUM{IrI)8(70r卮iP+ esϪeZX5q'PTNI]J%IwqB #tl.Rhe˹Ոtq18*MbU(8zF#}B%JzYU`HnHLo՗DZe%v)$%qGYV1gkC&!o@L0M 4%츖V%lJ<ѰD_x7J)"m=^pvZVj.K޶a-59]tԹ.QFUU}SxBy[ҷb]P2s{) iIUJe})i7R+-ݚl"7%C_D6˟$òqGiU$YHFbr#94N޸V])@irhd[ FЋ}[c >F ^2D-&cA4 5̼ o`DHiP~0xZ˽^P5Qi 9 (E&nWiWjnWc&l5&FP&}z 5#5mS#q;ϋ;&$H $8jpuI"pr ?W8Q#*08VazUٻY1F5OhJa:>AVW4[&}1}:6kHAf2FT" Ӕ&<@+Y%R[;] }m"h~Ww#4v񱻆iTEG@L)GA)X鶞^ ۵‘ U/12Es-cc`5*dpPi^c@ܐI TÆe6>vw YD֑,>rw ݥ04qxD]Mk[)5X)OL_Ώ86)? (T%~%ס $C9wK/Ԯ|x +ύ <7G ,6Wc7%FF`+)J rZz yRjȚܺԙzf[&\$ T^2P5H X?&44ْY`G|ܑk\J}anSb] ИEzR& 7"h Le`C<.Fg^c#Y;02>nOMd< @myZJP+ S5U>cKehle2U-ͯ,i"L |yx Ƶro*wx5gQ2FdQ)@,IZWވ-9..+R.f'bŤyq"z]cg(ځj*2%睈U2(/+-es2ٍ(KX!MzL#l4SՂ{dx>VBj[[ɀi1t#SD 3qT0a]&Zeh`Ta8QV-@ȶAӴ*{gEe}[21^; l sJ }Xk!ѱn|D,vTmɺY7W1dȹYX炁ٽmF ooD e&hxy9=@P&| :N|=N¼bL ,kwRk%f(g]q2P UKrJFp; ('55;ɱ ha.FO0q% JjzGU%"&Y)6edZd%*+G. G(:4\gnk!K >zijo4g'[ʎ|T(JXiq}ܔt|6{K)jS#F6ޞY7z'LȑL/X+JXs?V)U,'3#@N3%ңanz#d* a lM2@=tustt%UR L&ھj2ph:<5; {U2rC7AD^+%Ox. 7R` Xr\W1 2@[FixX ۹TR; +OđY]az~#48E4H (w)wplO-k +%) I%MB&7k/q #K~N1<5]mJaK?\ZR vzs+h7@]G|U-܆LlC1.%2#Oэ(1z "_ ,r3qۄ!,lzrW I9w>PZ#dĹMM6U9Ļ$RΛH  FUƷ*ct &6(2m6숗5.W{A4<8#톯T3"m/&r35ɄL:9'{O04qd}Oʐq%G&XWQ8JՎr|&Sɀ wl7U<ВMOA@ͧѭJ 2anJˎGjp,R䠑FޭѪ-){j?绒Wד ^u2"U&"R;ݡ5 =`bʎiʆ`݂U&9# ht#@ Q#~[o-@3 d=Q`g0"FZ^Lc7L7bgvzރn#@1q𞑿#^K9eUݫ 4 Z0d(M,B^ 2}hz(*O-jA)FxE< kJe鳚aƼɾdkilҞd}4LHl"$M2zcbv uS#I/ָ׳Xon{n 921Cū"Z DrәrX[z̛§w-"#oQʪƙK(l3fе֋+BP5sȄ^G&5di%,zgѸRi@]0yJ5 )H/7 Kze]άix;ӫaGAɐIkuECV#c"o|M1rk.²AVvIe 26l2zܺZ! M(cH-0&6B8H>T-pOʕ+aDǦ$hڕdHXH@ypօ@,`4R&"xGӉa{#LJpѪ䂲ksO=јZz%Sul^2LI UFׅU[@;qJLk,rhda@ T}ؔ{Q5t-@y0[gL(a 7:sq&U[C|d#$ܒ*mWO;0q 1`1h)SPƤS*_ pֈ/Yq(l%Y ɀT&*)4%LD)Y{~Ǟ)$p\n",h<㦯kmՖ٥U3t %[{#1h|S`2VLVS1ȇ,^'LP.7:eZ!%MYFpV47;ckZ' 1kh94 ̫NlEm A:}_RX_{62=T%2pWrW^,viH6̤M?Rםg<LNp-0M2UGm]nhV.ɜ ܤ|!BΥ^JmoP/~ 0ӫVjoUY!U͕#t U_ Ȭm2b`w0[ Tm̑H&)0`$~sşݫɉkZ&l%Sтqa)̶Օ (ӋJ1.1ɼq\9A> \?8+}sJ2Mn iI`_$LD (0yG2'@>+Hc4mn4w)g({Y1dE/ dkBC&-IP&enFMOĶxk zՎ i"R"t@3l( N_Ꮹn -I DF!Ҡvׇlt&pMH9-jNIueJ w8_X9Cn(bS-jG"o kأh0lr-!AhiX[3p0Tb"ib捣,4đUNI9F6i{mEб.uvD^Cπ e&Rʎ9 t\#Y{OtT#=]94miTklm-n+@hy #8zds9Rv3 UL^`FT@IDAT#}Z^pY2@|a ֫R$0?DHJ6q iJ⹱}|2,^z@cir&(zǹU#dhYا'#dEj6լBc@Wz2&}L6?fx9%~h"c4R ]ɔ?Ez@ ^C[,S"i\/RHKa`Mw[˜ɄrsilO @$Nu>JdmjlnVjJ9 E0 RU(1xd]]o }YJkϡw_^A&Q/vJ;L#:cdw|0vo JM_1[1Ro\z zGY;HpAJTa#8yJ8e//8>v&ʰF&-ݚ. %Jd "\Y@/R>pў4 }3*-; %㟟6ֿ_4L2w=+0߻TxJs֟܀-Ggh<,2x0R !%{ha%Ȝ;R"cҗ)SU¤C #UaaZ*A*5 )EeH>0`7ŷXu =FK]4]YӉ;6Ҙ3Rt;2ESH2YMzqX)Zt쉚Lv(nVP (U hqNJ6tb歁lC* s`UL U-(oQk.xsTRp& +x%R4 7A5ΐ|ē L$ 1-f:,5Repq3V]"e;'F2[sF 6=*^;>7 \c>=!ّڟ7 GZ8E6:U__*<(+PU ^)RQhH* 7KFֵvǽ^A+FsNr#RtǁĹ5qL6ZYTp r(; VPҋtumO߭));[48-׋܀Z"aJ2% .d$ۺרTr?#1eNrsoy: F@d{j-xcϲF^*QdkAsp.h: U)sHԨ;c'@UyCS"ې8$#+ݾs;@JM烡w型@y ěyZLώj΁jJ>pmΎkRJ kJu)ƪy+dmoͬd=ib<<0 &3`Z\AD1 V2>4z1>C>J-%Ƭ|`2G6˱k&&^vqNpo0}#Y GJԛJ3?PXueb6Uy$呀=J\V'FW WH #0ԂttdjZd֠@/) ̧}`nJ-\ 'UrJYmI >w_\ ҈l/zR2n9ı LD]zaJM Du C-a2<,@ jޔ`i\ӗFȷK]A֒PU)16rs$-*%C&BI 1YV¿tj@ G>uZN߶ ߯NoSi/}"JF(5mM1f] !;ʾ!#=FTaVXzO(P^-Acv_ T+u)w)J9s8K(=,hdZDJZkl\{ MXqezL9gǺTs @ Cu$.`nڅ.Ga@291@02Ak٬gLNC#Y F}A)6WH<V їCo2HOi:&(g8UgOS ]rgnEW|0"T}^Unh)G.κ7,[CCl- 6%ޱi6|b^gq|Ӛ嘹mR*Q28 _!;62Z[xLκZx} ڑH6FU#fP57 M_#+4ER-ȇ&棽 0J^E174f*䟬hhGӽ eELHпO_F]ܺ# o}&dmB#`;s@fb+L3f֨"kT՞943(kFSH; b.U4¢pҕ{x'0Ad+^"x XP8]&c\YT$-N#4aw.sU|ssi|{RO70"O19%+0̉#ed]a*YCbk()%s'#4)8尟&&NC#`iJUĐL/^# 5"QoTBW_e._( 3ar] Rf*Q?M{f2K Li8aU&C=X2=br-S տ֛Le^#>&7J)AV˞-vU&L0 2cddxy]YiK* zPjnx> GWGW !B xsH#f`b=$ 굞.& rżn?YTnW=BR fм5!N Vh0Q6:F]UKHJBgqFQZH e߮voώdTfoy;+& # E Uu`UiFl1R^ g߮Lr`BHӳiєJ2,~g J `U0C ,8a")L肀Y}+ՒɝsR&r-̛$t@ a.kO>H+ɍ 4Tqt+88d&zVu#o+Udo i.#]4lA s h9o"XK(g Zp @hN86,q"{kǂ[$۔̕9,+wcզ6eV,>J]>U- :KО@ZD_R, 'hkv5TeVu*MMGםv̳DIw+EQ{եϓϹ*&7GCF@/`퐭;l: $D2^ˋSf(֒zݚqSRk_e#".$,&@y ×'aF!(\r۔dFm-h/SmL!;zU<[>xLir@(ck[x37#vdgޒ 40ޜ1YJ՘3+9,5sJ۶0πv@4D1 k70?ضCgh.0J U#jXy'uLk?ttUX6h SĔFˎaRǍ[ bn Ŏ^s# OzA)"5L쟃o%=* #a\HJGJeRjY%g;ت/mȁObxLֈܒӻ2+A?P.i# JTZRxVW3FHYCI#88|Y#!H|Ȱ]$뛀Ԓ^O A@cibb Hc`}v2=Flz͢fq(n\pdׯK頳BwXnL)F'L&4F(5˭`%@:k8"2YHVIՀrp׳m,xwAPO$3LCוҒv%6ˑ56ę뭝A#{+G84 ejTQ`R{Z VvfZJTKoh_VB'#LfF w @PQrUߟ:]' `bIz2 &CJнc&cZ{s[R/̙RtdgV⌹_՗hsEo_8lUz%@ nxUoEZp޶ K%.3sğۂLl ,˹O{ZL! /s~Q 5; :S^VE}*r00C>Jvb|x9Ӎly!Ĕo+YP9 b EP*zJc 8fG&eJ gUF-2>F{,t5Vm$NgZWq(̑U)uqh>AX0#F2&"8+CET`!)# L| 49T.ZDLUz[ƛJ+ xq) p/.Tuu#4t%-VYGL&MgMn"0r.Z'CL} ^/\ P}6{Zv2]Mn] 7#VhO憕*པЮdU^JCsaz]L򄑲zc0axʳ؄}LibL`@SFTk9bS6y2}}{Y 4DKSn,rz%bJVr0qk隍@UgZQj=eծ %ɻr|)5Y 0E zPsQ:2{N چݔOJd*cD&Jwv̋"ڀA/zʪcĂLV^Ay= D[ #ܺA0#,1.p>64WKj~\3^JW +y ט87 5t){5+MDb&t5߽h3Q5UjzJzĄl-h3Lo oEעP 9\aNV #뽮mkt_ԘI;A$7+֎-f:fK$@K xE4h|֛5h2 r#AcVށm>]sgVq|JkR7kUIjQ҄-_=H|&,&/`JuJ^0F.%^>囯Ut@9˘̉ÍnCXAGgu#{DIGZ3]%G}G@V'&h vo&/,O~53oTݱ?֠dHGEFFfUZ{πmRyf&ɞszbEr(c\|d|/&'$^HCj$#2Oρ oLMIх#VYrw=<7Y$k~ 8wjw]hbe#(ꧽěv8D  zYɀWV$h֒F Vı!  gU vYu,@15Ԅj  gH0^̅px,J?s3HpxJM<%gUܔ5(Qjڻ]AUlPdp 5vJ톆0BK`|J@-pu L!E#x"sX-<(s'~*S&* eG#@ՐdbV@%UpS-Kzkq$:RK #)ez )t7 _$=>X~ lqL&>56$9̜Qe*Ȱ9Rïjtp0h)h(O>{F* >dJr#R4=|m5W}b`>dj@u&U1;Q>bvkn!E gw{Fhl8@/b(F ?J$N9$&zVUze3h:g~:OA$d06 4}qͭ*ww24R XFRFg-ygtYyaG~- sf o)b Ѫ>l|2 O@׮I-aUn0V۶)ɀzhICL-U3ّIߪ+FʦS9l -4UջXi[Y I&j WʿlVh 0)xv$3`nm.jF| 1\4%[2-@Z M)tmsLoDݪ"RjWRLLH|~^(Uss|ƴjbL@z]3DXU$O 1Z(vVM07Ыb"PԮP~:+Oa"gߝ+wq<+7?v@SJcF#,Zg 4ܑ ytx.Acz)^ϣ#>JLxC`eWB˜H8Y/ҰJNS5q+0% '\Ǚ-p 0۪jLZ4]ST ELf K]4sSUXv\jWA~zA#-~dx[Ǹ˞=MSBcʹiu9nh-E&7Ab*~S8#|F9+&>t4=N|1r4Z<#;vS2Fvl My^Xh0T /&pZtJmܪd7v\kǵ7*h&6+kٳ`rcfq'~ Lր U4 rlYlbۤ ;d5isΏf~`dkVChtǾr\Ldk=o#} 8#'Od|C3ܱ9j!PŬ Ɣlɐ Y=MH z s^,1rp4Zړ Hw\hg" x*P#CG@jKel$VoT2>mlr+Y˾vrHyH "]0 ZTu N "N+ǺvBK;-0C$mJ/QݫiD? 2XKJZzĞB.YQV1v [YoY4&<+ *y%XR1R&AI)4xzp&zkTm1#0F$Fȵ0&bZ(O)6?#4(q PYatyLV"q[~4jiUXtހi4:"[@Wn2A@Y>d5PNV/}xfKB*84fy5'ng# Sb8g>-CR_v1)uE&,G$#d {ڲ6 {tC3+QiE;W"Zx$ 90ݎ-0@lW M2-É;/+bJ099F [BnjFJYPVL{*O=WdpR>'mhJ/tp'·:A=~+mgGκ&ƤE2qr0u`@WƘz;BC@~&-zs<1C`+e[6rE,2F(ڷ-%Y8'6 L*Jkno.M#:lrxY)mVt oH *p2A>7kvc%Ɣ[ Fc׊^/@/RZ"[wS +cNs7PqL0&<ha&"瀌;2_p -6F3}(=B%+ 4rmsϹw˖! Ӈzm3Y+ GQz><ٱF–,d*Rf5H? Z,Az M  R 0B=؆W{f)2+LPvh4QA i:2TdHXT [  ӵ[yH뗕v"SD3=q Y蒫#uݓI>վ45j!F;p-DsN9~28qu+51 q<=`i]`7B. A@&XUzL>pr" |>dJY#tsW($D-J𕼾T"lZ*$BPVEC{"d.ϲ㕟c]6"Y4-ԥY`>+;jlp7*4;"ukjdLYaDb,#Y&SU͊h1Ϭ* KjW-җ)-FDT g|:MN~} u5BcCIJkEҒ ajX xv9$+o!ǺV:#"U*nB3ޑ^N?[ty[Hl\VH#X{hVzY FSx4+>e s0.r@Ug5l@ϋ3hJwL###EG* Ce7 Qaq'] O 3ikHDJXn" hp8MU9cŔFTEɔ2E1d0MϥYaYϓ^8ƨJh(ah10Ob ۭ+Ue#F‘m$&#&27bǞnj##n̹q `mhs.E3cLp&Y;\׏^nPz1nh|nUE>ĕzgJYL\nlpm?&JrxHCvS&_YaۄhuJMfU;6F+pC#+q@ksVEIFHbF!RjmshjS(J21o\It|dZp~2Wt=ѽ F,$6WwLYWud(02L a;/b0 uLj&sd e(Ft#zJ%L&(YeRϥO&j CWUn|AO);NTs>]D \c]W΄8LJ ~"̼h!&<3q$xŻqhgH^ʭ4|"7x2U$Y Uw)כ[)Qr+ ;xrM)՛AR˵%H_<3`ıgNck6IF5sުpݐ\)[p^e߀4Х8#ؒru|NAEF[&] -  ~]d|R8""7=¶r+ HV^nvd;b|0feH<["fNO?`4/L^Eu!WihɵsËFӨ:&nF3n.ro]бڰ!H"r u7 nbߏJ2[] 5 +`ȡ)]ѪϮO97d%bJld &OMx 8[>y]8\HW{x.Og\#zZdBe r")sK&4"| |H`Yq-ODhiIrJ AZh@֏H0k¹UoOH# wd!.Ud~*6Q\/1(G*fG0.6rPO6SQeYaV?Q&m6E,8gXox\Ha̳'#,zt. єCzgWV hΰv@dWrTJyO֞ 7Hf#")sk1@3w+HV)i*lvv#?uc"[w<|VjG9vΪa%s 1sp$TOx Mb11gTuq0P#LMKu%>yZzC`U|ιdwp5RqpU K51D65d5B 71YyCiG3̊L D9dltm-Sb!Vj0~kWr44 {#ٶ*kh[lOgP)9؜F 12U#rCJ2,Ǵd {X ˺k(uNjMg\)O4JQV<(pXȹ >Z#eb^ÈLQf?q ]-T2"j : E㾠pkg2YŜ@/'PnRz7]y:E-ڕ0a mYMpvZe& 'Cz%K0N $7Hz)#}:3]Z@D~Uᑰ&Z:6wC{1.YS#?- ݽ\S}WT׸# shyF: GUb@-#ˀ*sHR]Fzd;AR;ޏ.2>͐jOJ@501SRXVr@6+c#G2lE"%D-ȡg'9eJFo%AC>yMI܇3јF8G!nzed}dT˵#zxǞ=3$7GF~%Tچi ՒoF_KedQ}~WTG9[`nnSeG QԎڽU1Jv$Hon[9"@“Yb q-cH֬5NTSo4 Vr);jL#bW#L#rn&&ƳZ`-Me8F`sJi%;eO%MwLSfe$|!Mh V0)=BiPY%_- `:YŻ]5=dqn.rڋQr@f@w`.Ro@;؊mJmkV2`%UZH̫Q`rǼ֋q$в}瘠.B#hzۚ++E<}99#a1ֈ2 ځD U1r?AڹRSȐ^8ʻTkqP"8#Ø=%Rʆ c8KsNUI>mq؟dnIjȀ7N݀' s=Uܷ3nJ [{GЫr,ǔz1D&k /.E1\ܠkZ/xS0L]Jx&"b%ګJY P%mzG&9ㅣF @$#62@IDATxy 2D Q# )H<\&8(\7@dW w UheC0qZ+V".,lFSb|tyb,#T妫/#P)6ql X +p0LELfj'PbnOSt ?;퓹#騥jyyj!^KGXRˤQmazZD2|8PE cj,RppΔElL>s-}ܔqMLs;h0A#G6&3RJ>ϋ?H\ vH̳#hL 2|9 V)DbR6?pkh)H8t]Ȭ"@[c l+}-|aez&JX痾Y XPrO?pa!RcL҃?o`-w?+hܭud%az&#}M2%]"%m8ױjn#ISp70JhGneJ>`_m信j VĤ,Hk(=ggH%2<2+4rS0} gR#9S gC`4LCT\XHFe]U8s2G$6qӟ&d}m5D:j2enaZ8޶ 0hϔe-}%h@nyֳ(1[R`87ڱ Ldݚ!eH ԻوڎƐ1|kFVhtl: 1{4 ] 7$fU& H>ɖHH&- )?K)T@M< =J/w6 |[X>gBKL𜛋!_z?#e?$gu_g_Uc/vb~8I2=@C оOu:jb2H~Ňj tlʢzRmP+J2Q}?uU%ָRF& 2q4)eiO>4pՔbMPWJ>&cjg ;#9'(cTE% _\`haZEvCEhj|Vm gh!4ޠ)*]4v;v9ׅ ;dmU/xoM*8~Z92[d1 :0O CwhnJF숷؜11lLȶ`mȚ dm $zY[{pwF鵛%ƌ'K\^ѭ&10 XlAHJvμ=rX39Y L ose˼/3F#F<j;;vG %цp;$`몥gW"cb w/2+&l E6EfdFюƷzd=Xvl1U;jIOzx?}u/.?2zGMr{e]ӵsqW; +d77b5?ޑޗv2`)sk/lQIU'QCrVbgŻ_H΁A? OH{mIebr}T'=\f ^GU];+a֍(T Fyp$,€F072OX"H8MTGϼ&V}f.Ϥ X0$F;3qo֘&(-p^I/F A~]kjJ-L,4ОV=;C!mHwWL@&܈^L@6 .܆M7)Pr LHx|dǬVʧUa@"I!fs@ַՉ#r) :5vk>e24Z)c[2$z g>İh9`4j ϖc2ZO#K:(csSPgnF}j i>u*ꌼ-3,rs>+h+0 2#rr{bhÔ`\j:ShJ^o$S)Y&ֻJtltƮT;*=v̙T[R?&Ż;SL6+>ޞ([eun;c(X[;Jm4jQ Zm?VLhċN̟OZMiGFp)86L74|v22;)0l8k Ũ寧 4d=et a1+螙d#҅/b6qOF/`z!}__P [FSwq+|[e= lĮJ!71")a41{>vPg.#u1a*7AiTʁ U|2wyɶқwAC^ly qv#A@Uif[s%dmD1s H6FLdEC chꕍkϪ)xOzsԋb'Cj98 S\ H[V!4ۄILPx3Q^{Jد[6֋[iۦ)3ֻq>a>zQQ#"Uc(E7)cdLz 8="@Ϛ橄)kJ{GGґ_L^zu0WQHdӨ n{|:|@oŎަtUtl=GMALߔeI0EpJi002Po&rυ'ds;79rY-*`Ֆ|PӨ:ʖ&[ɧ*d@+;Xve3ts&{^GA1Hw[g%j4W ^cnʁL8}%LvkIIЭqkTFTj4dr1< #뚉^Ppn#őHf $()3g8vkL y&߼n%fhomd<}<.$k {c2r LjeP@I#B:!ۦFkܠ0}-azV;՛YK|Tˇ # >3wA%-`EvVTko#a9opg㷉er;]%[4R[1"~sGlB{9V]cґI,|%䆄y?#"݋ y.7^ tDӔIzEy]xȰ ߁gb$2Po]XSDoX/nώaЈKƧJysh+Up)h1sU-"-9+5mbu: TÍmЉT҂T wިe5fSP9ߤȺ R*)cz\ >HA0iߕ|*d22J@fK˜6E6#Ҕza؆dz;kiLd]xOzU1"%'k6d#?co_шe| h7XK%bؔɔ7:ӯ- qO/[Xu>ʇ@4wL4B/4``~v CmJy~Ѵ^C/h6#>GV%>1Z2^lڼ~{]CC,>3G@;iJs[7L&+9rӋT&xAT%.4zJ,i޿qˇU Pf5g '0lU*^M*>kX ɘOjoFӒ@vׅ߱O$2h[L8GVmR8 Xqm|uѨҸ0dSddy{eB5Arfo#P{=L{ .7BァRwɪ.y :ʎѬvKc/7d6x[ u#e RYdpzbӇAPAqKOeХQ3:wkC̑s5Z \A F.H^F0]ĵt,FϢŚJȔ#QS{M$3( (u_8'd|5Ϡ4^%G@ʰ#kJbz/׈L?1 l 0́ 9gHn Lv؈3~cjG6WHLFjA:Mq4-,UǬ1JWɄ#ilS6FsֹO' HWRѭ!'02+?z@I ІݼKa85A4VȎLR)"c*a0y+I̪y¹p3+^b=]w@`mjw̶Fnr[Zjy9$sD݂[GCɲ͓C->ulXV]I@]J2Lh[@Xg[Unz+9*qJ1rR:''5 s4#ZTTy~U1O@ذW=xcfQurنM̼ua?rߙhY3BEQoڬ<^b%O[bX4{4p(jI !FJ$v}|dJկ~A4+n gb^1 &fgލH 3~[ѝU҇JSZO-$%|&NJJxb;E+Fh+;Nɬ<H驙h.igV8ϙ>w]S:'$J0ެz{J%L]4-EKʂ^?xgWOQ뭽cFiU/ }a 2LcBK;I GbǞ[z9dbכ uTʧlnԱY.Y AApzY:ƗݴSXŒ]Pb8MlEiiq$5@^IPmhFUnkˎȜcDӱUmίqO) nmz%ĕ?&J'0R)G ( |CoCT-wjA597[Lʤg{N#>nɌoeےF$#b(1Ͻ;y990gҽ9W:*FqkLjvCڐmK45aD]BVڔHG0>vԭF 2>B,IyB߶QZrC vm#-KqspgUdp+e1:.b.C[y@u>@zL!Ëf <CJ`QZrvFZf8#[Wb۶0dtln;q?Jc-T{7DLl^ wdhR&vNp~1iR&"OnL^.J 8Y֔]4@G%GF*Ҫ@U𠀿3!zkgGkz aL¬T5leʐq9qz3o&R{ZiH&@tjpd[[]$3Ԣo~[g?a|zlc<]29"g$OCnD:"는8&ib8b(͵s(#CޜO]Mg§zڛq}Xko.Mĸ YWّ[Ra4bbksVm%Ǧ$s zё`/Mׂ!HF ; n(C]x +͓=K ,h4Ďd>M%]7:!/eD۱l3FQI8UvW^|U9+WJd ;iued8_;klu:)% =MLYMirwU[ i@ӽXϘUwc7㐍ӛvT_֞`oַ{]?73eiK}=P SN/q&a9s2 g+F.0TU^@ۦd,VU"1Ȕ&u8ۧa.hl ( I觔\A^8rJ9P; zhXո V|ǯoNvY}M3Mׇqxng9۪Y~eכ& sTbJ%;  baZ@n@[Y?.bD hALO6Y+>,Gjiij46\K,('u2gz.̦1 sn7U9öAN h㘶3#_+YYjȀZRFZhx9?!>KvivbF:0<'@{#2шl.H9 F6Bo|nn"f7; ]-3x2>îY[hS͹tu35O>$ZpOS"ǐ%, 4ݸPv0+BA2K71Qy;^aJ)pj/3AAZ5v)2q)2v/u==OQT ]^^kȎ 4Tƾm³M{ڳJ8Ɯ !4Ʒ̜ SIVuz_PY!8]K)A%W  >፣3Y]eZ|45gL\AA.<#2n-i" 7dipO KӴ$[ ^N 𣒮c|^O6Eΰn|8Dz0c@| ^:2,zetͪkhĴ//FZh2wEc$ UUYUw^LK5$P#i@K6#߹ߥnzw55$kGwFF#xnۘGc y^A>G'%F +e ʺvI9|O1C"lV/Xʂ,bh2'hzU|w ezݱ1x<1h1Y{Ȕr]@JaTb"l-UGoؠkyd-tn3uxY7>L7g#,o@&VCjnY yɇ'L m-$d"z5SjM1LyXdgg_ Ջ ;sdML[6q^ rվvC>7"\3ӻ` #?iKϏw6g%wl4&o ޭYH2pܺf>L1 1{F8%kIܸ~kvuq RfW [F)kW[&![G$ve)AJMtntU:% <e~kax5֕ c^I9~2u=Þ#r؈smcj _.ͦ`3pOJHA6t^0oO6s';.L#n7%~x{*1Ȫ\_3#+Χ­A߬*OEw3yn̿:l1ݝ9GV21#Lًm yV9?bd(A*MRCJJ}}sѴs_is[%֢ "{.R'LC1e]gP >?w͡F'öjnx`@ӟ J!M?~--;l#>gؒ4fAо=QKW{7|WLWv5+b(땑"/%%r!4/AJP+!s%}rl-z4le]Uٲdբ^J_U.pkFi`[RU5jIhݮU[II#%@z. _n_Ll\ #^{1M߶~Eߍ_j,L&J<`4- Cd8}l6k}ʾ{GovWچxJZvܺHz< AAO@c2t)!Fis]r_`Vrx-m vboW_MY5C-[ %%>z3i8v;&"@<}O&b!2XoGj/Vuef fU&P>~[;-|TP:M!3~I014דBƈ^FsϷؿw]KJJx &@n 7OL&mJB1K>+$&CdS<$WKF?pDP|cdAA~պxR$̄#1k4,\#YCUXh_K2oG`Pg$XH6א:,Ju8^%vA5: Ô 㘘I$%\U>FV(jrڑ]y-1\P}m"D׋wnj";Mv+˭9?,7^Y#Q|h@ *)J:á@<' \BRa6>pK#ݭ7%e# YٟT"Kq: CBZY,/r吘ܣߧjGDG5<|Mؐn]I/%M`e&5\PIʵ(:UhvxbgxY Ц>?!BPySeח qMN ͍-O{󳝻ͦ(g`vo6J!/^UV+v8 뛎B_+JG\IKډ[f̴ P$xG}^ )TMbx{#7Utɒ UٙK^ $+FJSeA 1&eݕѮ䯇 s-&Om[KބjWztzq}/F7vK%4hAmM+aF+)k)Ʃh hbxZkw`D,U9T*L6A LE6-hӟtFG}&DTpjp{wEFdᬾ]fh6hxB GQᔵԨy]wʂ 9Y~A֏MJ\JʝOmRS)QȾQKC16bYyjj6X En6/RHLB+XvX-= ZIJ$p 5po)`k{h|:ڵ)y$SIHyZ< HseR6 OV6bK Mʦ#l:z *OZYRJH,@R28jF^=}Im9 3}م ^;{ dMk)(OAm @bxŲφ^/_0%̹),j/!qk4rސ~YTu;(_JjR9ZbK'"/Ñ 1NuifjJ5ˡlJ)d`Z2)"jŝ,K:O3R@K$Hm/> AH:ʚvYeyL{ՁcKYs[4ȏ#B})xY,CYӫ|r2fd xxDPUkU)@A 5Kj)P$RFZO-MAApp R hܨblYZb$K-@„LfSYeC 4 RF oJp,I#`R5ZZL%ZM'@{^)&@0 1xśK[Jd5#yb5L #l-mͣ;)c_^]"p8cv݋?汄VS?C]-)9 ?U A&hGӱCdjeպD" uM(h#l˶)U14VNշ.?zO"nBU0'\@|ཀྵZU[1^׿ B5^5R[K!01m{D3RvZ|FܷQM.bʊnp&@c@dǁLD0yca.fL [^T %'5kR|jŖMY;Lt%@Yֲ  fuqp lD6j#U[+Kw}7[9k>Wy! ޱ7fd8 q:&W(ᯢQk߷ﳶ_Q >YP $@&ZލmDMJܨ eKק-"#Mhk*ʐr xͿTWe2XOj d*w+yek |&/WʶgCvۑkJp\/JQ&6J& X6-W4u B.TҲCHmpdR+d q-% 1 y&,:ܨu Y*5 (fuTҾ bRYJ,@.8ͮ 6$::Y=Bj#PI},)[6ύC>@ycw)s{ry9y)ѫmdw H=g !*AY=k#w =1Nd3L7bj;۔1dRPk))|!R''|cD<7=03BT*[{cLV Ii*nfDܣw>߿hIJ_@4 x4GМ&D,}D6Cc畄L@R,ArLMGZjVx~ 6+o7H;@8jMbnAG )K05A U)ԺSZo-!L4J b6nho,<R: to7ۨ-@zWV<&H-<A"3U5XL]vR;lhv$]ex9C#2) KjeE躈~9'Jt&u}&\JCeCil| {z ^fMИX}~RNS휛ڣ@;WFbPA ~YRuO_wR!nKT^`Y"Ħv'F@}H3YY !@hbW|MlUJUCd.eMy1,Hf$ 2R&?DV@SyFVUu d뮊㴌ѴZ1NxRkh]CȎYSEݔxM}br::FM{S-Z/S5w?V-~q%jQ݁1ן=d聯I2Ai1j-gGx)`ƫc|s#X-~[RK F("23ZA}"Z.<@/A3Q횢pJp5THb ,[GYHHӹ )@?v=Cm1KR$(V{Z?YvWo\5d5!b+lxA;jrZMNYS@K38&fk*ƹD6p 4<$bA\o]M/:GDZ<~2^6x3*M P9LGiK4/X=1@n^]ʹT}0dTeXK#uN@Q/ALOl Oپd|+_g< T(#pLwDaXg;k uگ!-b%uQlbm}^+w1XdYK fZ<gKh6"Nܽ{Pꕠll/z+/O:wswKǏj;_Jim5t  b}R l-; pKӢ^>^[.hZ{㸲@DJ@9&Bg&_SR&xh87>Q5lMYipFhxBߺ츶)鸅oHRYK|~FP@gZ 45텐N`˄ԂQ*oI -&ebW8Qǧ?qN SCu OT-@R{;sIRhA!vf74 ڤӒIe@Uyq* oźdQSx0S"&+(ke14}d]( z;ZkO!b{GRq6BD%fO@R@Ȫ~v=s}hUR4O^.u/fRh#o  *eboZb(H /մRF" 7ZPk)ִȖb|#RCuy:kY%+0Uz9@ycW55vo␪K?)Я2w'Y}k-OCKd D+sÉB)KkRf;L 0LydjRcB!8F^JPӦ:(6FiK* Gkncڧ)'P#m㯐Y%e -_@AeIe>࿋hxDj-rߟFHL ` KjoRm\` #ԅ+RN:p783-hN^:UU) poRp{n6| _oOek]; TbH}i#1̿r]&SO$Z w{O21Cc!Eo<%A _Ǖ0ܓw7>.z} 1a)T.ӗ?n`G'µ֔&o&,x@IDATR1B E]&ps: h7yLXKY3 LDf^rA T>qLj籂ekNS cF ٔ01Z,DV Gmaɶ)q ҇\-[W?K;'F̙`X`*qJL8يA[O[ {/{oJL*OC/ /~b)⫲;MaUeb)B8_\gR+o C0^"f8G' @Oƶ?zl ;aKtf0?|Fyi6I!avhk3m3~RhSl RzcJAX=v,zU G9x.)72|xZe[)쬌gY bF0 {*9S4FZ,[n1FKgM !RưdZ *sODō^Z!c4dڈe_=/M_{+Ju/X_, Ph0^%#ێ$A>'A`Z/!6R)DNbtdd9|O/KPkʤiH}|8Dx/Tn·BץNK-΋+,െh=I&+ -yq" /AǮK}K0y 4d8:!j\B%۹eG&2T^Tsi_ ^>  bfu`hkȀ[`ڗD,$5[SpTl+Oj:wfʑ{:9UwnԻrH{tl~%-ɶ} -|VJ^IF[ .|YAӢ!fq I MI41ּ8@4uLW%UJRƏT WWtA\!or`3?U)_j MRHS, mjzuGm/:]څY[^Q%(V% 9!. ZBʲc ^}3AZJ_@\a▥2bKUx)|OkhT~)G1XU[:q1=@| Jp0 ::ʲ* oGЩ䍧;?6IѴ(7$rpd;#(ilc+WW LuW${vg߷"~kxL@0ӫڠX't6? d11$P)h0Kd- @7@ 3{-@,gZ;^5āhT6cHqGxg"THZXO ߄Zhjjt񙁦t{OS9'5"JK\hgdn(kM \ | dRJLpV( avrRqe6\l +e%k!n`8DS䐍.1XϿr-X k#,q/+Tl+q}ۇfPŦi;! `T BnZڎ]! L!-π Xypf`+)𖓢 Τ%<&]ƀ qعnҕjܺ[HK*ԟ_l[TKv,uo dpU5ö㛇O~ ӟbx]f#(c#gT3Kٶ&5񔽣 ËVd])׬W.iƧ)7-qˎWZnez17OjQ5~J ( ɏVy8HJlTF?!D/q-ˢI++ϣ%lU" ~۲Tw2.rh~BGQ5ݟ!hbr@!nqP[.ʤ?@)KuW7ǒHDД@,mejh9eZ$ QkRixb43Z]DHM#|% 꾪1 +> bS7:YMV  hQ ⤚-~ ׆ɶD#[tXf˕9oBjP|'`Fk abT-Jm*9Zg8ВV~|SZ,DLUaµǏ md w?jox^!af(BQM0 Q2&"[LZB"鐅Dx4'F˜z\R4oi64Ǔ^gkK{>|4 zݵGa%û%Fi1~򮋧'r2@OOYoٲ k'5\ "(U,k+/Uł YWKjY,AS@f|0E|+ 9?؍[&̠hCӭMn‡#uk) l:Vml)~(Vd} By&&·He-0![ ;RB&1;PW'v~moxCRKjZ-!5xcRlT?{7{QŬ"_é*~&ݲrH8UA0Ñ b1-'(=cZ6@ Zr{W; u\J|-_׷y>z2ᎅ>)-la$'~nd-uh.a& ASIY+)TI/ŊiƷ HLYjS; Z)X6vY m8MY4U:Wi)/K9}x, xhvn[KW0/H׸l#CJa6%xYN9U,HGF@G.R4hyMqn{W㱢VSG t 38B~-m)PKx_-5ɄLq}cv<åGa}-в"DTMoJhm kɧfr|#) D8yKV feȼTRY㨂[" o 83!@o ~mo)u l-fq6>%]N7C0N)SRJy1ۮ Z>$̴ȪXRSkKAW]տ|8A^O9~Ӗj ! ?p"Kj 0k>(D7*~KY ,Aeo(hG(!պOci7ORB ~TRC׭ Z=."A"ƦczY:zwx4 Ianv ˗^Bozq]phV BWMйX2WGlZp^D6 <2qR8Dd"4{verdK |LbR@K`OMJR ҄@Qk*.?OO 9k$yRu ^P)l?t h6#Z&)v}LO? ?@؎F$#Qm׎XP6[ Yj?hmG|G!W Ǥo~|a4AL6kM gVpi{ydM(/|7I|a;xC[u4- lR.j(,,&*K)EF,r6ѐuQ.˪aDYxx4NB=ٮ-̒)b36gvpJ,V_%0UѱSU±#tJ&DLtd&Y )ZH%hTVSK.=% 'LgUA6F|!uK'[۾^tɺZ0e-k,1K<ElܭDP')qRb% jqI;L,eA{y]q'P{?eUPB͗?>ھ'e&bXJ)$w7"; 1+َԺc=T!/'.0?ծT(f8Ժ1R0 kͫ%e," p5:/owj V\J6\y[ɒ %G6ҩo)ʩe@K{/B+|R_SᶫMaPSe5k+I-ך N xj\Yt#3)>eEֹ(f3/%FxKǂ#^4r)UyG e:rulF'oR).T15CIa"dJpL3jVw!# ,5M"ib~AUjY,1̕9ʲ̝vh#m010ݖ] (t;5/ʍanhFeBpR|4ZLJ?KL1XKN̆it2p>ad b.D%[`v"M!X*(EbQyx BpZo&{!M4NA`2UJR>]/0 Dv@|M>⍥>&$ Ii|!2lrf<#^s|Xf._CZlR1}o  B-el!mDlˍ׽Ѳr8k(/>AU?5qL #h8I;uR[ plJ&Ra3Ь?G gY,$Q- pnTA݁>w'K]v lͯU5@J15=;8T՗4dZ"B JiQ5G, g@Y1f4jfF_.⬑CY 3|+y jW1繆1CCHZ~b5zҖpq`RNOC h0p1Oݣ3rkDr6EF/R ()lB,U%0"{G]0MEG#tujHW(ubZ-+l6~7LYzan^jKj_ OwBR$JI#$eS LBע,<1u!(vT|i O nD^-/f8R;ک4-I gvо6/k gN/<=5YQL\]Zƀ d wBxfΑ tn8FՅ!-$ZF70 7/Z}l/\kxMT- Ryu0Gi)i{;٪d$fUK;\ۑx%mTJ"~޴К6޴e#G6@$dq* Zq%Rnqx*RS`|/ZXy&k}/wn9g~m xA|3@DM-:**,&n5mhn)xb D8!+E:RL;AZd),wrYrY QR`AdžikRVO(7ꔫwp%M !HJ vb PψlGbUɦ\_qESִWg壒 TNYbmzԾ$ņK뀈y.fW㶣,E)f+|8153 K#Rk;4 j,5&٦M-` O!K͌f:se㛡mȟWU_wn LN ̚4,CsPB%y"e)Rd.q4]a!@q {sLRII;,Y1UT8,`R]tWK%[bԽ 4#n8CS`88%?x;#_K*dMR/m0Hf[^D̓2P,h~y,:A^` qL^9ZY3pb)K^h8l`4I_-|6=\M[2N^t;qH ZtH|Yjb )>0Gyx2D ; R%p.-(2-SIRa@+ɔe) Єw dYh2\j=~"7XS8o gCIHhLDLӧÈ@dY38'tI:׫a y^?^`vHLP x}v/w{t#Y`RbLY`)nT4I&D}B)[v[!CN!#ܷX#fǬlt2b1!_uTnu|g##P҅6{~{K0ډy 06%k#z*G T~ @.C2ϯWi6T+fԐrMmб[-q+$a@ב>eAR4;Z;Y7@pڝ%s _P`f.&9e)-_YrE-F 0\o,Vp,dSo2Bł|cG dFR͖f.GMJ)]b7i|XeA\Ne"/K 2"D|>hK!nf5CBpc4m%NSa;ClxQ&2xM_q4$B&$j(oU[j*ѱl MՄ@AӱByyZzM4[mm;aA1Ovʕ9~LVwJ;O Ꟃr ܎usGe3Arq.%"VKe!yWJ nS|RY -wbG 3}G(Ft! ?UN,+bt L5h];Ɔ0eSRz_],/sdy<B`vuW }=cV^WJd pd;>ljVF4A&Z0~I~~2N9X ؖx - d_S4%xKay(Zũi}/})@@<d1Y:TÈD4'j- #BPǖYIc6o5) >a]#<)`MyRZy^d1k*PDRkf8c`6%# :yF|.C,k-SE# Qp; Růڦ^iidk2AdqRj9~CvAU Y!+\ &l Δ(YD$Մ tMSR N#!4N_yC)'ےD̫jS<9f́-SSÉ T%`XK;jbNѐ.ϣ;'gOw:l[3`#BW~ )!\==lB`?s4OٽZץTbYI\- T1/}8ejm9dyp{MbJBxTerA)BT vp(MLy3\}*34&PπX_Ut |:8‰ۚHMX˕>{RhNkEC ?I!+L$~"pb)x<ɭR=SH)"*[++Q"%ɖXn HwCf#׷*xAi)1ŦB`"Z/)q&_^A&o]x/u?XmP Lkf#hp^J RP {}K6NOL3)+kWяo:S^LL ,UtZ[.2BȝC(ȐE5cH L9&2o_`3Z &CjaI!׈UҮ8eAbm3m`Dx1ADƱ'ez2 ].%h %Nf)Pkrq4 B3qnwN;S`b4^8fBGs^%,]-8 [RYdq8%4KA;7{BLA__5"(|cҤЍ7B@*j;Hh|)| ھICpeY#(,>;h~[FD/C!p8{-v;z}m;B0^Z`)__1VިĉpjW@1#f_Mjd#Ԉd%NyENZ2L|`+ 6C=v?LJ;꺻@w}؎x`S5&4 "1cT7R-A#cA;h@6i8&K0F41lJRRʉfy-6\^qFiy?D4X=r֖ \ L@׏p#2 ~?r8S晬 ➪ X-6jRJ(xGӿ;s!iWZ'"(rX۝ԅsxRDvTɆ#*mAӐgX ]@/0oq~-a/olD6 S(6= 㣉BtI!#`K45R S0x?PPT bz_LY]6xU Ί`e4 ,Td1`\*rRR l]AA8`F!SՄw8%|.1<M1, >m|؆ZtdbVUA^0j )MkDW.ȌZ_-kgD+ :F*>J]3 Y)PX< z5R;mm#=q!?ů_dUni~.<|0ٚ:B B,ChUf.B1~Zk 1ݥC(r)˵XHI/(f!VJ"ҀLk)5lYTY8˗)(`=ҞS3^E +'GEnW#ȄB&L*42d8BQY6ԻM&Q#K2z֔OΛF+1]$qD z({z }*a4U6AGl /5SUpsL-Mujd8P5P1Kj~{% 504IdcD ^BR~^-y/(GK2H 3)Xʳ_ġLMEBୗA`4qORsSyBB*DӏPE 5Ck P!%)ZU ZR83L"̈8g8Ied@}V1&_<N3-S&J0 ÆB:ḱ֧2NDHcц)?ц{ūzmKTq%TP꜉sX,Yxh %ory7E17 ɚ:SQ)aπhY>,# 4E0}`^;/dՀ\$: @JDCL91!,_ b衐3ӫE*_um;G @IDATʥHc D$eWKLߨO!nWF4/`FzȅO_I՘`G.Kr7q#gj S*VtLEDi8!I_GRp鲌*6r蔕)eS:Zļ2& MVHHHk *MhHi*eVCŴQz༨U>IcCȚY[RPfEG_~7߈L$+P9h&0[ژalui !NQNU7#6t#Dt(04QoNӺ}1zn$V_zn;(:iqkEY'mJϢqpT3EMє&JKKC05ӑN?) Fiz=j,\63A]eyk@-4Fsuk2qttLY~eݨN$aB@RLݡd!pL[6fUsDt8)?Z]4 "e8G5/[YWbrkǡeҩ%A Ok[ BQ ,9]/Fט6DWbJ>7c(]qb{+ձMB֊8pa wE* BJrtPo6$>D 2k[D,9ĩ{(S/E#t[ N+ג@%L<hqԲ [{4ǩєLŅ/ҍ:en$ 0UKUF nrEM;Ǭ7Y>t'm96J&8d',={DRXKE|L%UOWc*Qz s}4 IH&˷"49SJ&H@t`lm'*%|MZiFӌK4+}h\<8i@b @'%~8Sh9qpNH M q=\gir8 ۮ~l 1 dwЇ 5i*`Vڱ/!J3W㇎BvD,JViLu !1p \H Bj%,5%ZXB!%aP:rΫK Fa&)#հ7S(ZvɅ|W {oM**DS9c;4#hM:/q{l! hpF|]q 4').iAHu%E)6 ǔ>Mΐs`l N%XٽD%.t5xJy*M4_aT7֐vlp2vYrDéY_6ƑSu4#3yw74F,*i%FYR|6)})0ט?a9)PǢ,gBGWX53*AH쒮IJ8BMHȑE9U*Z2VQMr%. iB[D4 )j%4m'!nFc˩z@#SHߴҍ8z_fВ)e`O@}oO8 dǜG9GS-H0M"4'[5Ksb,BR;098QQSEJ7 aree%Sju^'iS_IKXALm 8m-RDFv@|5;Wl!/X/HPRBN-m;hڱ^'.?j)|YF{6͙[ߏ.S]qo4R '\{+6?{M k ܪSK0DhrIH/܊ZgU*J͊ĩZْ 9 ugHg _^ďAVnԆD!IˁOV +gH%@AG9_`7O)8oN*K_:'F:]# ;>ܙ# d!hF̚"38ʹ2_3|]C7ZBS DUʊP %&kp,`6"* ށӭ3D&8+ O:D=Eus%95b)C Yh-),d|NB1bf6ů&?j4 _6hZ3**x#D!;YimkyxpLsM;D4_nB'>dˁ=\/Z\Kع 3ථDj Y/&T1n(MƦe!̔vnMlJ+o4eCSӳJY)y" ;c[ #|і fd ί|_sȉѿH\kXk-mKdL8?Z>N Ȣ@SN 1%FHδF5 ʤ֒tS qZue 1S= S.ͨ_5`EG淜SP\锲Qt,LFFM %# ^"܎Gb8҉]GLH]Y!]/8M|^ )ueBpJ !/1ߔ}-ܷ%~Y-U' Ozgv}&%1qnBH!3M5&QU@S~4kMGN"f:8@SM'˙N˔G#'0ZQc#M!i*Bwvڋg߹Kd^ K@4%C\?|H}C$VZίNuU$22@ T1q*h*" [Ѽ!0dR {]{%YKdʐG,=S!>)'DVE9d|ꀔ[ldcKSi4>C0ubdk-QS" Hh*\X+8?}^qTzjHn8G/9v*v  %\'?N bk ^[fD^}lrNuLBO|OWĴMi[`~+uTJIA|U2D 1LmXA|)KKt6"?:qǜfфDYS%y, X׋6 Qv=3/LJQ&T.')4S9;1-CW.;v@,%b:FŔ˗+nFӪ,Ήo4DEF!xN4LE6 XZ5JG-#X?MۓDj 1]8ȜWx+ d>k0eQb=oYKG:;GvHjDq:lj19_mيNfjU_En41<.a95SwЇO5IUOǸ(*-$Ec|oyI}x$6-)ƕlm'-VmQbR@Vi{ ?@@Bs 1+eW}(!B픿Zr}?./d!1G/瘊R5\7 gf5RFQ055j.t"E#p)J`E22LbF)p&Bf]8M'X҄"p 0@|H4yyVm*%Drs3C@p3V/"&_gրmM:Bֺ8RZs=T/eq5'av+r&dq:]Q6%/[4/4Z#I_}iZy ƯsmY`QtQ?Ͻ.򶚎\cFsS:#4rpړl)Ĵ΍R9zSHQ|k dS&6U!/NTBL58L81!/F$$Ocm||cL!:4e@DGWJA (L)>B)H䫢BiJ$5<! M-}:d#Y|9b.= Je&SnJ$" ڮF7·lӊ !S#q g#"G ܾytASWk[_؊O)F)Tbt ?Ae}։w;i 䵹­ir;+#T= ZEv438l_t{G&N r%#đa!Yd C(6O8Ӻ5d-JXI8+$)q_ہҟZtIYi=5:',ތpV'BNl<>9V3ե2d('K/Z'|tM'_[2Lǥ\%ZF 4tl,DV!jHhTE\S#*Ɣֹ;GOʻ c.0N[9s ?A)!3rmNA'5o] Yf˯P09xcj6X:>CNd,2ͫT)WOA#sJs![b")&n$+t!BSXTV&B5|Z|;L c!/R6)&ZR qZ(O@(LgD-Sf|c -?DVbi!!^gvZGv^ŝϚ8R#9g r"9iBj%кl`8p,1NBzFPR`!rV(C/@\GUKq rg)B门JRN~rIqX+ⷘn}c܍B̴,N+sݹFpEtHLƚj;r-D@SiDRDIс0"(ȴS]N;C8?~VsӚnj)9e2ӤEyVYQz@"d|J+ĩsԕQHzRX|UYϧ,cc =\愱piCvxx?Sl?E.=h4T@#HM 5Q|FS#sT&'%sDq*Z-@V9Jâe*aԘ(܎q*$h8z3҄8Z+/e#Qfw0u4JY~j)Mc!"/ltJx'BʞV:azf6*>"|Ig"7dsDgć}sg[PZl(Ki(d/$V嚆d)Sb"\84ҴJ ;8RcT jX>&ƪKty!_f!T S-!H[,%/!\oL.-BƦ5VjIIDɯ=VVNR:,בݳ}VK)Tu,3EBpx]aBC/kjLV|d8xr,oK;8 Rp4F!32H8@i/QQLGHt,'AS"dL։>q‘M_j99h|i*'h &i"+,[E] hُEWN_Ϛ0u1@qklG#~)}<zEj'809s4@X!`n:Èk^THa־u|D#K\JJ&uU6;qJg-HJJr[?gH=b}S4٨~:|=\}}\>Dt;f+Loʑp lK9hu?f|bpl L-Ȓ80Y!r%nh"p2Wr֏cY!,5#(\#tNU߁BcsZ'B "@#/ܭDi7JkYр|[^4j+9)V( Lu!42Z!|iЏVFL%6]y g|fmrL;vw臔b7vثDhqLuRL) qiyxܺ{+/jiw3˳?ʬnMm ~:l(+)1ZՉDZ ?誑οk9LM!kOkEy!WE:Xo D`jZh`; d?d_7tXeazpc>P-ߎE0if8'ā9/4ꡬ=!dbVT:.+D#̝D4gSa*-ɩjjT SCE)/0:u#BE/ʩ )CsHR;WԺjqƳ/~-q'wBv 7ml𙨮خz( iNN9q}Kg! |S]MS)|C3>GtZȢ . "hbZ5l sFvTWT3mXvؔ)ZUc*T'}ޣ=~%g_+Mb gn紐z4&8GȞN`wӺjqgĥkh𝏯9{.߳ pAvCS!ֆ`REu iE9&cvRDKXD8R«kl@FNEVZ A“()Pqp- & X~N .Ui#K/4v%ZYRYĄ( O#/=(%*.W!&War@+Hs n}ˠWunRj?Z*[qLEv|m˿[U/.Y!NBM[ڇ^ X+ڢUQf35%&Fv,Y@SG@>羯7'ݦRO`DB%R4E gɖotX!kmݣuLM'M~KiTB:r\Wh~W[|e08C"X3Ze+)Ԑin/ F ٖڬ2MBu|!8>5pOi9@NLuV3 4Ss8_yPilmP˷BVtp=PZX{e[,LF`kU9U\Hd)@Gt 9dDӵwؿF`d\m;VH 1? >{ xU*jUKO6 uhhX>?Jx- nB "Z{4Ιi힣 mZ5*b麹B})T?q8;=4j8OnX6dUK7B<-.~޿Ϻ9ZJ kj?YzDHM!jLc|T7%hZd K㙌Q*|>NvAd~SHW8B¤-YiƑD~:@)X[H 3LmsBMcM1ʑU* XdS4SS?lөk)dXu*b1ݼs\TD [ )98#ҙ5ƙA!ͤmo4`yFsbtMKXh DFsWX FfTמ8Nݭ5vP.,jCW b* 'ࢁjI7R5>qqH qBȶ^VW5 Cv_ui<ہp4t 3w|'R-+ZIl m*V xk4򥤃L,8wU1,kr7vd5G*zBWn*뀣|#\̥5˭^Iu"&)`6u/tTWh|cT{mS o\KZWJb;k+1BN:|~h}(.mX T=S!v/h"M[p7kAMW}zzp)duMDZ')c`9Jm]u5] sZQwTWq_3 MHJW_'3KC{yT_fϾ\npR)s->o+] N}r[LIFuIViZCm&_.'+QI8Z5}xxdxRt ^Vgr?# nJYW,r8;U!p94R.lr)%Ƒ2?&^c1L8pdK6!EQZ^ Af@.S9gAMOD)X9&ǡ ._3RK_WҵG_S|)|!k9HDԥA) ̩DRt|(t(U1%EC2S]!9_nBW1Ͼtw@k1lO?ߔ,-RN'ZoğYƜ%.4 ωGϘp `)m,fh>Zk/$"Lȭ0FSqlbCW&#N>*@8P T Дaּid&J.1㳢n. Mq8D8*r ya7J$jE2SN,\NEu c:*VL-&#[)MC`p#P)J UJ̍Bp^cc^-Y!c:ISju(BlTֈ12"Q9)SڇrpMA u=L!CvNvj6Q,·B&(˭Qu _"r.8Á w1; [Gqv# v ={ 擇+"Yғ2@9BQH܈SbJ_-f0!h-V=b8A$~|y?$Zu̱LdMDI#f)D7?#0&i"[4qE-B)ÿ*1E.Ŕ%e*djHg`mo^{"[Ƭo5L=]Bro+aiaLӐ l9r[~)ӌS'BZ%&kD+D6cFm#sc(p)"Sk*QjVK~:ѹo3\Naɶ`AX-BuVz׆+Bi@ `Սk%+~pprǚEtY*ε&JOѭ9:tqB8ҧ 4DhR6@pĩp8U*J!+ h@|(G{NS5ޥ;X4YN6G" O\|Yc@8ԸCワ@)l +"fJvn|}EEjOHz E4tT݊|Ѧ:o~wsTISN1]!S`@65*B !N ϿݿwW4V \9̋,-6nTn-s#?[{(eS84mCѪDHb=JHE%ڐ|{GCt\w>9JxRE}B%]VF֎Һ6-ٟEi`%H)Z'x#F_4tojJhH%Qa*)KZ-" @=-\FGHZ*zF 49dJM4) xE*iC,ɺ 0Zu/bdS:Vh)]hd>vVIUK:'M"ՅeYcadt$)kB8keVn*7_Q؆gϵ'22!etg3{:K^40 ,!8~<@!7/{_?r)6xQp:!zn(q\%ɩ+d3qUa.76χS[G9,) '%OO6_LG)cugp"_jB=~QF#-NJH~js en*]\t{4_? >g=42S|c>\ xՙTe#q\&2|TG2̐c ښ+]_e$^"@"p L)WH&E,5R >FZu(O]SFhME!Ɩh3{wv}5n--j3eͭƪ.dܑDΑ‰7"wLm {?<_w|>i M[ZխQv߹0VhF%pJkEPķgM_&5͖5饵s8)#D~:YVT m0YB/vAK. :x :jmdu‘`[82f_ȸՙ xI$2|q@bp"p kG?wu'!M!S ٔbK)iKup,cj9!PߦUL+7*"e/G("O>g8)Mr;W,ͻ(HÜ6XBzZ-+,'.%HuY6oTcuF8s"é5ՕĘ)cYe:יִ'o'^T%BF|u9qr1Qă^?}E"Ryhj'WnpmKA)DX4C4&M6`vc+J"u:!-lo~i%ZϨPWNՅL@# :<+ޢ K$MЩq! o53)N hjl Pm@8v?kY,nl#J ?PruUJA _}NDrʕ!8UeS#3SoKT,-9BY[~u9B}c?=o{gc[fj;6rÁ+`J 4>μ|RoI2>9uʵ+7Ydi_RREW+@9|b~QwMZ4 lBZьˑ˗✴kP׻Oq}%v|uբ) ^?Vr,KWp~ |&5N}v I4J|0a%^JBW[r7tGQc19-L8D1nxlH͜8 DSΩ1D: PKRi,Y-8B`VNR&o~OMy_m-:az[êݴ&/fмo<:*YE~U̩=)e2FOPf2 ,2}ʅYQN ?ޟ8\nm )(T^{AQQGǗK)C:}a!exAof4[B﭅rsix\5v˯4ZmߡEh(ݟxF =lRDztqRD 4m3 |mfESi?F!nVĬFR ?nM:F>MU7XPiOځ:š3ڲ*80>Xrj9KǡNKsnxpLn)uY(JԟN@YQX34Sm[4 Y;( uVpd13#_>%[B $(xykn[pg7M&a@I#ۆ(~LMGU1MJUPv+>?М!zFFRʬFU"wOXJp/~D5/'wKoxB_-)UWrwA|ѤfK:SBƴѦՒ"|2#h4%$ UL)U7Ugi2C%8:(%2!ux?c}X􍦉9T;"L!F)%|HяO<*?-Umr#2Q#YFu&uq H}!E9jiq,5Ӛ,߁!1-EhZ௴DL S>A`g65󣹹c:z Ҏi f.uXk6B>j%jCE1 -p4 ,2{D+<YD2d]^:T!7Keut^WB! IZÕ.? ~%tC|!tڔvZ޵5xz}SKRS>AOwYL'F9L 9L91jhZ3]&p:@Q8B~rt8Hj1@~霚1MZ 1 ] KhbW Q[u`4%‘"L")GlN6B(M!IS×bT(AXL:0с0~)\Qrj _/!9g%UNkp{)r qLLiW~#`49A]vBF 鐂ddj۔ٺ5Rrx5BLVcǂOB5&o Q ۟iQQ%RhU,A]sEؿf97RΟ6\p|V@$Fk 1tujÙIЁ`De 'dPnR 'b,S!Z}^}(aL*+! w.I1nd3)I2C61။"B)p||gc܃d7Ӊ˺?y`~)65V^NsRZ$5:9s\;Էm@R"W]:ڒNT|Zo~Dv5JD 1mjb8uiZH'Լtw9@7M46(2Da j9HUئm=NSN+ODI; n48! Avo heD!BI /SƤNÇOV魷DosvH4B-U1>Z|fO匬]2V.qΎ\FDk F4kαF_V7I-U#H0Yx$sX|q+trw@[(8TARSaeV>n-66MSRH,ڊp{%&Rp'k4SVzwc{GҪ%◸8+ (\ FbLc)z)hگRBD P"0:!~`'req<~pY|WEr)J;' n? zUQ.6Opӏl*u˺KN/v⽆Y4*-nVm4cIZC(ʷ]8R@R.6[sKCꐚb \ !wa1'?]`jYF ^oO/rKlWRȘ8ғ2}?I^t!6dB@6Jl?$ N '?Z9՝JO[FS"ư)PhtQX&A!Ɓsjͱ04Mos>n!P"dRkic\+U0Э-iN IMtYTBDl1RJ!:?}[Zp A>:ObHJ:?r aR]+w%n4'$hrDL *)<1}*B4L?_(eQfjEs!z`фƻνsnVDXԀE1io4(LVb:BXGO4DZP1wߎvՊC!N֢64fqМ]·wq2h%K'4SRd9m ͒l :?BD!YaP92Z568VUݎDӏ%tx'6AR=td5Szi!|1})E(L U8BV Íhz̖e-ƎXpK6y+!~ # -sDKO!r9Ό!K Y&22~hFij!g;{n⪓Fp \@96,`FiUq34֦M0k.`FZMg)=Z;IjJBTÔ}AFVDcjL# #˄۽BM>۟&5!rc|j s* T)FqD5q{q*cxVy>>hAS`,ʷVbIi@>LzH Mj<4u ?AsͩbէIiU"DMAMʶ'N{|*]'ZU&n"0Y##tdMW~ej4JQf֟PSRa"pJI A68p22,Ќ@ |3TKZ8G}\|::OG9SBBF+B B3`%:ڀ<~}H|#AbMEMsN8G D!)hRuь,VqQŃ=(ν Z;POӞѴEKACȞ7kS"62j L Gv_zA5SО\EԤ.Zs_ߢVB[ U+m4-]"&>':Mo@IDAT9Oܝ{/ g@LFk 8ԀR淟eȌsE;*%֍@bl Ja!GTg)&! 1QbEL|Qvq!peƹ+~!(Y]C D#oDeGH@H Ëtz ݳ>Ϥu";G@ kGWϼMRiϬ+K)7: ݐ}/YoVWҁ,&)n(1\<CH " iZVcQJ::[gwe7zWJ)5dVW'ځ/Y hբJ)Y׽⃏i+:J,WCB54vviFSy:Vͱ<Nh -Zb?J^)?4qVrF3[dhL#:}S ZMGMRhUgݫaъ"qϊ᛾pR!P6 JzF`tiO6G¤JDHqDuR$$ou!ƶ#[o[?ܧl :tn+"n9LUԃ:(ekV(jU!c:."J1dTˈ Q çv9NiMA)ć}[nƖ0 qT"oʿj(Jd1!8Z@UT0M;D1Ke2f||Qd[oե`+1䏉_Kdj ׃tgC"Qؗ(H*kj[@\.J[;/h#Hi@ޤU7ńXDjߘɐ1pt*c3?,Q.r]=WW?\l65"ՒFʢD|"0 3ͷ/z#NLSvMZ@SPk3U(gN(3YV )8\CP|!,Nz'l1VБN8}u[idU;'+gTJi ?~C_WUn!Vsg@\d^SsJqNrl4VJoQeZi[Z/T Ҙr%ΆmYcir"t@$ؙĺGeuɉ/&>GH*5D؉H V 1w(9N^t-ӌS?NSoi@6Ĩrj䪞NJ4Tm֊v4/dFh=p,>Ϋ#B!a0q!˵AђW~W ۡDYĮ@x!8GF1q ʹjgJ+*7YjՆ)S40EUZ whՕFd]%[&aS >*Q4Iah9嚶EO81WXBQ[U'MR8ucBE4瞫JY˅׉6p|8tQc4OOʡB-ň4lKvUB:}rgtU7VDbBBL'p Z-OB`M}rI4 ^KD*M_D4;pׯTnKeP ȱR;+'r.WreVF|:9hk(ĒUs0LȘ|L*Nyo^ȞAreYl on} D_B?XQ91X6#2PԎ 5Wr<^|a9)4u͏]tDRd 9 46`6v^-K֍;_&e65b8n%Ta_oYL`_b."(@`)K,aP!~%R]ܙZ\@{rʹ)NjRKY:h@Buq 0+Ov` 绱!]/EP¾s'Ǐ?Pi@F%P,ÚV֭C-ś凚)**VBMP;Ggijo1f4%ljEץtvo-8N yOs+b6JuR0k08ZYlʖ0vqwQ`:&w> $ܒM0JYY'oU}m?}65 /$~Ȧ;ztv+*]);Ub7oo5HhxT+h#bYKUC? Ä3RDI@;nEBF NHRqXj|Y:lR.Nl`d!FRn?Ȧ 4.UUmH!)h@:M]X)KY>вr:hl x=T$_]CW{_r뒯Xh&b0;DRR| A`=3 /!k V"k7<&ZqP " D%/_`ıe D=Km)Y8o#Db4*xA0- JZ*x1˽r3Q@\9ψ}XG3k \|(yJM}h)&A!0F7!'S65N ^k'eYk|qAUJ01Abq^ 2oԔ(k@iqdӗc$H";_K_#ͫNST" x<~glwf]o)]ح<<)-)cF~NtA`aV֤`B̺mwx>Rb^-b;.lR؃BKGL`~AK0<iO—D!ݾJ偺5m)npǿ@&_8+G׵-sz=ܗ3=yiNmB{;Ԩ/KJ,AI-pZY'SJwCs38 -4%B"fJ0vś4n$Nԥvb×#tq ļ3:D4 Ɋ lYLˤ6/?e~:;47Ȼ^2tavmj[ =AK#U+ u'`ɔ{oMI( Ak/B!m2&FbF!@ B--{ZM^ZT55mO.@ǤJX9)%J_ [s?%^(nIݵ3y8T|OORV}uj{! t/@VUd1Bd1&ϼ{돱Z/E{c|jb4Zdئtbj0̆o*A4&Y4őC9\{c4YfTf,nc8U 2Ws=%uh,hmg@"&T+[7!>R5OcwSK d.ޞQth;)%!\L'; e,TɚA ˺ZbިI;vxKE`dy (4՛jq]-)(L"%hfZʲKU|x*yu,YjjHW"@b|"p&-;~uGzבTV MS$%yi ST1 x& #Jx T7T4 bRz"]*ڑ(bHSG a)$ iJw!@J h67.{xj#|οKWӈ%Ғ.àزj9>56@S4_/M:̀/F48^#/ߙŁ+E!IV'_̐BwjeS,K Y-p0-S}xRm3}UUa^8F iD,d9 9*Ԁo8c* u֠@,<,o  dfy'꘎.kJaU&g(4ZH_d-bR_ks;G;NGƌP 'uy9>}dqk<#Ҧr4`ߩ=wFrȆԽNH \0DI3A9wkE6?+Om#))7%k<[V#)d:L)Q@@};e!m "0BIXK__ )?C8/+jW@MY#۔g@TlK[~ V>AT #Glje[t0?$f fB: ڋODmdA]Թjk9*'U{$ڄ gxBRKJ\UL%8.F3GOypۉ9kSGKI5+-L]Mȗhd&fzU Ch 08%e-|槁w%N٥Ř*LT(frCD4!omjj8b&H_PQ!w{(N*6M_m[YlAt*SU\a"mٌZ85J͒TM t8ZGVJmdOWhOK%%$ FAcgk$§M⽇z!ԅTT@;A (wβm '%ftw>'&i TmA#8Tl*%XLNMRhl:q"|ʙ{'ܴ}L '(~lp";t:Iʉ#Ҩl ٨h[w>{kO!dt9 Ԣ >N<Џ? O;pg5AY)BTӇ3q#!≴Y̒!{VPǂDX[bBZ,E .pkܲJT Lu`j|vNR/1)yِZC4msZWÝ,&K^m/NAkC7bLEr[+./V 'U%%NE[J-gyHu,Dj LYN"pAAaH_~"h6Nǒ0-)[Ƒ!KlF8 RmY8@^68|]6Rw Mw 񛧽ӿ-+s}#)<2bI Vw, +db; dU5|"WLq.R seFI#/[̶inrUL/\3Kx[6 rj]dw޽~RJ!aAĹ'p|4a))3l`s(Vx_v@2|N?o%@U!|ڬoJ3}r>suKY1ԺXZ,4SdqBx֝ Hu<_hpup]82ۅ-[!vRxEH!]{qCjKE֎T)4:T6:Pe:Jpx`|9|#$hL0 * نlSb-U|h&7?$nB}%eANU0Rۑ )V!Lwyߙ֜8`! cϞvDlmDU105U9eqgL('n /tX A/xq; ґe{ɯkj1|+mkI]f,gf|gk#bpO4ud鈛8Y\GA[~7&FQSHϿw~'Pn4R c7F~V14!k*pl٥"!bM+1&ƚ$a15}bWՃf46qE(vydy KQS X_=c P ʒl XS#*@@v*ʻ;?j6]Ӑ1\V-TY!NX*'4g)K{LVV>#C PIz8}/;S ǃwY7 cDPEY#Ubٖ}yy3౫ӲA1ijHۑm]׫Q irLoNBSU؁ 4j8ۻuێ*)OؗZ/u@gbY1Mj<^͉ynwCHZ}2d]N-BLZт8P' &+l0ߧcw8 K’WpRRѤ8M.Uqjk!Nq)t([*6ʁb7'5WBHj)Xf~ceRO _y5el]A$ZԥClxOAԓJ-QBi-kF)8H˺S3*H)g~!^Fdh@(^,)HW,A{D(POo \ӈߜ lD CN8oPBߏ? ).eM|uſa^_b/7˧FtLU+6I;Rf @|5y ?O?&1&+Uv@˼i*lL!(GdN;d!%|@K7>֖/ _$07@ >3"=}xW+48]o řT$lNoP%?aeן+|5J!߲A߶)(NCTv> 0N:4cEwٚv z))n;M". HC\ )d oڵ^l/l]G+O#$2e:%>C_W|7JGChobZ/p7yK:Iwg ւqJ^\Rf{tc4C%AsOvGsκQRPf iIq2sb#Ӂ\s[:/Xɪ&6ZZ⻁ɿMIy1lAҒlZUm "n nfq9t}wI Z v1ژX %=p^~n]_d n)fScfpe4xA]ttxUIgSem>@:j<q ďRax=~Q n@{iemć}Y:mL$S׫0l1q٘|d>hm_%ٯW._ R:)RBI$ZdR8+vD#abR}hY_aUxD0#E!,WZ=!+%\|"MpDAߞj^b2_#"DSu@m-Z iʣ D\{S pgkf┛F8RTbHHuuJK@=AhBl`qAke F QswmG+*p0q΄XRȖ6xsvTRuǷnS.}_َ.y$YJ( o;Cn/1 Fzu8bYng@v ^xxbq4B(,%TUh)Δ;{ypϠau)#oHUŮ>T#@++*޲KDUA% l&kcUǿp_V'YFV#%p|jm^ ԺX*z>a|t 57a_ܴbAvg`)e)$a-XQx2}l%mHH ;XQQ(&=~_)>{3<1sRcЄ;{ 94ۻX [khKWq>oqK^#]p+EX-ٞ^~_H_y?vxjw͖,Cu, t_-c߻rg}iR FMo<30K)LKr+D{Rl}{ JݮzozB+)ƺegaÕ/eS-\nqȧハ-ٙ㺇1Py8cD(04A1 MŸMU)ZLx`ةeٻ%C qN {y<iDDZ to@A m@\-,b #cMh0S Sˌo wLBfԂb}udLJ'goJ$M):64R \G,rWP,MgFVƃ3RHG39D!!1)@Eo$L'®TWV0BM:y5v賿rMtR_^ѨX97 n)oZ^'_yМeN[,;ac QJ5y'DŽhtRbi k*` ͆#-)lNsIMac@e ӊHMcLȓT1yYHֺ̲Ѯ%PRKa*UI}ԋHC>R#3Aؤm-DURUi ͫD)E?} *؄#^ 7b)f$dhMS[zRovͷHS3C3 <]] DŽDnGm$Ĵ|ii*lNv*[%))OzF'iNtwpqKXv\{h q8tԤK ?3 '&M˯c(ٜ;7`<0 mOK7H. 3hQl**OCvpN \S/ +yn"´NҨu8)`»IY/!?tMB ^TYLq #u՝ ZR)X-|K.!T[*@K`VRz-G;_ʹT,`KjI[(%SK'Θh1=֟1y_i&H Ƥ̙FdL^_}y$JxGOdA۩eja:ZRFIjyp G{n"S#w r4Xä`j16ȞZ0%/-)d0Z[6%|3t'OfYO}ƗNZ"[' (On|dé^;}S# D1q∇u&DX>{LSbL7.4B"WYQ6*m`MS[[e-d 6qȶliOT奘Mm.Amj1_ Pjd3uKJ!kϔfX`dtHYw|tzKm4 `!`@U18ƶ<3]w!0%8j_)l6bʦJSqBˬ{G:ӿwtg'xW|7g;q %A!mf3 ɛAMɤ~;~?qԋOw+ '6ޖj:O>{xIehm'HSY:RMe9p4{cN9_mwc[v!b !:Һ`S͉˺>}_qJ i,h_z1)+6_( L #(,$6Cp,Ǽ P5kb;X?Y> vva-]~uP;A`}VUggR<&\ynz-)ޕA +)DBY nB?r}Z)0 q>g*jZ hJpH1oUIyO{e߇o`YdԈKm%3 $|?y &*c:zj8Z`)vh*KU,qw73*avۯ{dRZEf@%e_Rpޒ95|{_ouD5_*`4UXzɡV&n}Z |;AjfMg|7nW:Yc4\FZ lLqчe_Rmde 1MTTY֭V;|)CkJa{Zv޿-f⤞ݥ/^G^&֒LaA}7ؿ'G?I5.h6Y~4BU |)7\mf4qgA O\q很P4F-d f')nKu`)^p㙇QK|%[ 7y}IJ(jB$[ ,%efÑ,xܑr6W1r`dLe֒"0(捪WFێ%3k?QeELSiYSHy:Fҗku.C QfJA2J␯| &1j bR4eq1,4ӨB$Pw,12xELM, -B^yx[vCZSVա#hĽ.M^pq~=Lc-($ dӝ|MYԫ8Z8`낷M;f.=aŖtK;LJ x14~>fxƦQudUĹ;~{I@W.ˊyKWRg-33HU8k GSsI*@,!)  kqUwGR@3R'p34 Ĝ:6Mg7~ !lSt:y Tvq\&8]QBĪ[V p>-8ij5j CGmMy8H]nA'nfdaz+U0q S 1އ;fS.45m8SvY oٿ1Q3$K`wM,rb t+h ]8NOo&W/&`$ɺ:pH 6!si#"d7l(p!)9bK*oVFp3zwaU#ÿU+o:I:FE.e W3O;(hq|ߏ'~7gqTŤf9e-Dۈ-4bfȦ,Zo)޺*T ұS d 2j ޳Lʒ8e1PSw"4xGmb&KgrKFT{x{yVBbHnuo9\EQUˆ[2)n/ot+ { lx4FDʉ)i@JGԷgeLf"0x^(JYn#p h kRV% 3d1pԔ J!hiXLcEe,r5D4RJdȽ+[nhbA(+TZ"t@ti{ -'YF^jmɶk5IK-j cnSʥ,ã) d<~P_'ՋO')^;L UayLOgO޹ _-T O`MKɜR^in.1H `R+IEW{䆱 į ~ MIЖ I D*l<}Q[ ^8NBg\ G7X"SLֲ.}$( 1+ `֮N|ah#mmo3N@U`]wO?yhr|ux7p)1'.h 5t¤ڋS`yc3K(/τb`!V G9bV8ܲkQC;6H =WXq`w,C7ӗo;dyO,K9=L:;ny=U;4H<1UISզ'[GK 2 Ù4!{{R K5*˲CJ['iu@DkVLq!=-+ugp}wfj̏חQGC_dַBxL7}JVK?QwD6Wx;jfB.#R@ށ/E5b ֜G׎-[^2,ܗ}3ZR tѤRK,0U:xYK8*iJ :K āe&råWcZ}hTqTK{ *-OFLU.F`s[?RL͸ Ȼ̔{TQenx)gnJOZCA,)&%ɳZ ƾ/+LGqt-cVScu/Epn2LJ2Ci)V[E3OmKO+zU2 ~ d4鄔5+Q^6{ҷߪRvD ݯW (/+U n#X"گFC >fBYӋavNbvQL y3/!L BM;J'czQ0[e䲝/}h~?0/0?^@2M9R KQoFmVeZK),qK7{XmY{q`֑U( DZ3%+\Anv SSn4^goR*Ko OڬZSI-wtxAMTu3H3J%fɻ)2%o㻦:q"Gq`Jy@k'zun @6KaЫ&jXRfCHB.uf)B'RZrym z JjLwU)$Ԝ'Wd}fg\(+gY c>OwUpL d %nqږŏ`)='dI-yȲ0)7$}+)`#ݽot"__~SyF$s>-PX\@62| jF7IvPφfc3w!faeō%@yL%ȀC?xH5nf|c@,4]|bz$U94-t5 ~vh㉛%R 4Ex~ŎLPm>M٨tbޫΨfv F2M i+/u\J ]jvԾHQ4v:& Ӑ0xu&*L%ϦI m#R 2YwY)"<eItvC@}+2v ɻ]dnЏO14wƭZ݄r0/ ֮f<4B Y81u1I偺+TKPgR  f6ިmH/Æԅ)ݾ dTߴx &@cF0#&!qt]Ve$Bn31A-1.J($Xy:cnxA1Ύ7XCM̢)- -?=TCb<;!k_:Z?t"]׌;}6^ "K)g\ī!@np|.,M"V;*@8~hd.:^pZH} (76v|"-ysu:_(i#}ӊW]TMI£-$ oGvv`I ]ٙ(T!ip1J.D3G>&[#΋' Dպo۽l(gjMbIiek*Z R 1e 2A!ZRw^ꥣmG0 [6\@X f~ k-HNV!1{t kStpծ*~Զ !qCkMGLQH!b6OD֩Bx<#v=pu@q;^/W*Y^,NB@Q`7-3uMR;HBs?LJ ,\#Ud^4`ijݲb@W\R{\!n;ٴ>Ư;'cjm뜥0K [kkR޷x17fiEMK!SpE. fT«r:a Llh wte &4 Q)1,ّ5RI HS ӷ֥ {Aةmx18fo񯞏W5r7"ܒ v2Uc ;+~9rꓗ橊+`3@ L:"\PVr˄v@*JL_dH`[h5!,1;O!KD@jL%W 4)-S&1rLB)w0d-Si MdG-o 4e4>P) #DgnXj+DҩQ{QhIm毤QDPӶD5AH㿫jK` iz%kbeTr[ }8sx|MR?wL=tb`p9زW" FGK$ۃіj/t"S0['.ϓMM-.5*K7ﵗAZ2$[V(F) x`b,YRv~abUĿwGfpv֐4>mY2K` (hӇCYeV/cH ;HK*PyIu:U^/[B#BVpUVw3+,M)8eoxz# M(YIf'*_IJ>>qx.GhZWUw)xFF{%H!Y{LyYd,bck*;_ܑ" G 3-wn-k:8epԎ7@`rʺ Tj_GJ-T"ԔȲ ZV!ee/3ĩr*qsG: ?/eD ^eIi mB7]Y',P -H~j955I8d&<вITf#o&\Dj yHV:UfS7.m A5J! p -3MޒwXjR"v5C) TqB,߭M!dZ*UۄLeYRvdkŔ@jꐂYmCFP  'CK ;j5ъ !&)4Aet,5V|qU#YJ *ZDhu˺ tZʒE05 Dm4fVSYq,!b8_SbA_ljFY;dA;E@N0T (7Rf&R|@njq萅t&%Mަ{R*Z[nh@LNlj"-;״@K1< "lUARkbASU,@JP_ Nx83 XS]l݁jG=)젦& b8(:AّӗE?jNZ5 6]qrQ-1 ȼe|.ęMP\@i X)A%^s{o|D8SxUkZGʕS>?YHŵeRފ"K9KDDۖ)7 D <A;KoΖZd+Ij/6('.=(-*!if,R-qz1wǴTR#B&rl RJZ""1!RDd)T뎯;mYv \w}+4=)L.7YRW4h\ &.副QL#%)x+/e)Dyc"QI{̧au\ǩb1qR턓BxDj $ aS&B3L!:X8I L"T7C;d#C٪3e\Ma X>@KU1Vz-YAT7b%—GtSDK}y炥3P#E$P<`bYjȲ%o0^#> '+TːXS JDIB X[6p@c& _##l--Gg M-eŬij,*łSp+)s3-#0LY !Gp8%&B0^&0tψY]G 盇H0L0&V\RydU ,{&C<4N|y%Ry|A|.@IHގ3Y|˘BljVGR yAD*OşҎ,յ_dmU=f4 S]yG0~ B$kٱ!,Z-6Gfbʍ*R(` o"h)L\c^k>?dlTuPʹmX >ӗII%6AKbA".Ъ xqxU)kÉxSǁר*LGv:@V ՖIdZ38Xe2u&30$%bԀ,@G1so%/~d*@y]̀cV;Bç3xD؇\KY ;=%<\9<3Z<W>{ PaDlYóq|j!Bj'Tjįq~c/Uc@BKU^,? ڧ͈]W mPR-`=+W"kX;7!Rs[wckniS{'!߯ 'ZU{wKhtL}P5QrVK>㬘 cqv]5[9@|'J#V}/>pRjCJn82r`%RaC&Eɿkq$8pb '3@~?50t!MVh =Y9 7Gnm#ҫvĿxJeZc|΄P3RsYupd'L ؒ/1g 2h<#cK-kW3]'<2E%I?co(#=g MA'c2J=BVb__ h^J &d0c T0gJUҨ *@?^jW~&zH*Cgq 983c(E{#`9V^LskJG< |0{n rP cD#-[q39t 7.؆3'ϕ^l Q4v|혬=cd;wYz z>@bG#,T9LF,dZDaX;r߫dZ5<6F%UcUD1i4z*HJ>tIhwP&ӆp AV}!*z1 P-  ڛն}.-Tz3ǧw bﱉ w$TͶ%] =.p>l0)6#~&!oEd[)Sj&leU4&2e6B/F$0.G澩. k<Ũ GiMbdʺD%-;LD؞k!GXI"@J=E?1&=8XC\WĜbn6h -4%@+тp J!`l&@l L.d\ Vmt94S-ӱasR?HmcڰϨqJ}-SPb֘7-'N&ځ{6(^CkľJ9܍x"KUݫRACQ\cd>2FYD #&T"gXVg WeBh.gUdr!%U^1c )Rx?[-)(=D|UDZq3Uu)J)Uz`T-~lhWx1ra̅jw Ip u ճz\VJ0^T4OGkھcrV kcxbHYCS/b=l= Ar2 +l9`T*,%JRYib%0}K⻩YJyUʳ2CCL\1t <"xzS۪jwKd>\on `ޒ2Zcc`w3:h"H:PU+!a`ZYW}dYaψ#qMTBb86Kx9ZMi)ZF) N̪#(+!eg:*$HGkrp4Wu%"*&RV M\NRfuw8~qÄF f֖iY% dJZoZDd 3FJaz9 kHtLdvU֭{[FB R*%R CeLڪnTάbhty;iJ͊Ęe*+Ven eGE֒pZm?}|"albS)#uyJ#dTM鸭Jue2>e}ZXoSk V%_t2*,NOp88 |].Ȱ)JpΰhI HbPI19PFZvVb;#E|S7ON#҇XN*X4UmP#W2HOcwUKF: a((12VME$ "+ GXeᔕU;C>kW`J/ }.Sbd0`@Vru P$|0β+g 2UQ;j7b[Uv+;IVz.(U<9b*#~sU(u$K)bJh.@ *s^R$;m+1YF^ϭ<12sg zJHνH|Fg8.;LS*cLJ4 _ 姥]8i x|^ySsw97Ms@K<+V-@ & zUuv-RFw6%L7\X蕑E9 `Llp[ e#NϟC S)]ZXu7v|bd]ϧ2˦ F##3qq@oKSV#hwJLeNv}?ZΪ)Бqk64Y/E/0JV(FhˀR0A:v4')?C3!1^*C(w zvL.VĔ0jsm" Jp@|25#o#= (ͱuJ&n=7*C蚑H\.|&bvV{L95CCא2fUףz bՆvUxbd7Ho= _p}KLzxdw|vh=S|}Y"k7 q|K5%u%n.GXd2r/Ov;;5NJ#ĆrΪo4b/dq;ΆĎP*f;LY T/~#lXfzύ@0T҄4a%kn-iL9I& 0?Czrk[,/@?^`IdBl >\{X =`֎q=<:V7B+Zrowm(p?cnUnDΰ{!s1\>E\+xJX7TaF7b;H&kQ>㴐9"F~m2嬸 UAv,Ew6y$jiZh_8\j'悔Vk#3OdAFcKuh ;LRM 1aKR)".g@^hUdȐPSG_R{:FFD.@q"@:Fgmls-Tu)5fϺ^-.ߥbdJL7oed#ԍ=%, :zbó 1 CFMx"[=gJ R( _uk(Mis2sUJN;TUg(Ziǔ0f=2-G(젴.z11 I1zeU.pSC݋,,Rjy2g|ȟ[LXuJF'Ћ٪HV͊@.hJ|U# dAƪ#):A,-%@֠r2R{ 5iD0Rv4Bbd YKs31%FDb"Фo(/)hվ3oLn 80lCz@ick |^FV%'Y,r辆d*f d]^ѣG&~^8;s:Yܖgo b@]ڕ`|Aȭ?0he>~-ni 2ffy)#&3EFI:9n 1q;E09|rWrkxǺla Jdg *DwTuQU;F&hb%$c+@O<^U# r.OMn-X]1g 6tR}@SDtH#ØxQ 4w-~UJ2L0W"wYkV"qA1`XD(3bŪnU˙fi4w,(E1}u~rx$K2|Ep]׳$!YsVEpJZjtG o Ji?3T1D -ҧ̪G'(Qr_nZ›{LW?ّ^P2f{FJjUE%]ZFpb$C3>]ERܕkp>N]F8'M777cz@XWHz Ld ݕ-,%ac#1b]xVqR[}`9g#E]3Hp;,jd_'=?ѹH4+d4>4 ο^mE eأӿSvMQE6 ɖoN #LziDw׈$원}D ȢmeX{kb i!;j˒jL V-YUwi"*-IT&jD-C87י bj32V"WFݿlR iܖFimF`3 ^oQ)#jLhxeG}ݝ^J#ȦUyf% bV4Y9ªWvp$Vmtb<%ڗyKc ن߉ڹ.G/I-ȋ+2ޞ$+D$1ebt$@&bE k̛E8GXz8UaH @0F#n ^H# i'rFN J/3aKVhhb_6Uyj2Z\L^اA 8YSަGt!)7:>Jid|8VHf7[%@ ޸v9czz3lU+Ջľ JFz 4j#*`-VcJ-x43#`2<[@r4Q@6и}2i%L7μoniW[5H.}v5UdW9D'I$sA#Ųojs{"p P@ T鬁*Qc ?>CEuz )Fb)c@}'6~ko4HzAJIoEC R&s9;@$ kr%tlJ2c\߹F5LPvĘ9s3]z-+%qnl7M$v4eN&*ȡv95` +v1/5=m3w^Sr䳭Fh &Dj]xLS6±, u ώVzU8jFhd.|G֠] ClĦ#WGA2DŽ}ڭв ĿXd MDc' %r !n&'֋O|g+ٶ(kC]_ ֬;FҜe+ɘ"e}oĭX?(E1kW}ߏ"%f]9J[h}-]h8HH]&mBn/h4]9[0o7-T&ldp=f4akdbx;̖&Rj$ |6+RnD4!vZ-{Lh0hFGGuEʎV II6itk(!y:fk_*kME-Z@0A^ڄOWV9YƊ@8 GUc/(1ڸ{' ؓ9t)U-=wTBʪ]I˴ܔ29={$6 }iC2eY9x|7Zs|vJuz)}1 X5h! ;' Rpǜ_@o6Fd[##z3Ʊ*wBU2̕?hџoW2JSdP&Jr4xa"9R#cJ@;fhxd.ՒR.;hi=i&VV sHTm4;];CQ҅ɟޔ޶&4 `3(¹%o`3Ȟy| &C Y#drȄP5@@RjHn 杛p5LD 07]GoZdd+, z-+RoU-w),ǐ) sV;Duй}!NέQ˻ MFGU>Yɘ>ԖSxMj1յj:.BpXHd<}@{ղoÓ8%ȪZzd ppwLUA۾Km[zUYo("buܚU륱[oh00ƪ/TUٶ2]2轕/5!M,,}K1pohJ}p,$2GQu-+鴆YjA>^5d=YY9U[4HAL67%Z81J2 !XL}ߓJ٪[ޑVkf`0ܞj!PMɡUd8'V#jՒ^G X #/B@ OGCwK}jl2=#zn]o{˵YSҢ׺iU}[ $:#o^X(DA)fG9YGdxHh4Yv8c8e e&3[%v0]31R ׻S;/s 9aZfŇFl pjB@ۑm=%uj]6??$[ԛ}^HiɞHGUGx4bf"s6]d!=&O~Cu[iuz#EpS$M )ȄK ~FW7htGUT+;bJ5FM鎬Ykend` lJ-e̎@5nyʔ selx|;v%x!w3߯3&Mբ}'ȯ|.cZ"몑۔ؿi8& ! qH~}6[c0".V1@_]׬YѷdүqDv#L6=%XYx0(.$1[#cfؠ[yЗn "MY? اj>TJiQRuO +#SbڡH<Ȇ$Ó'”] 4Kvd(4ҧτCBITXU㘹ԭ+iQ4H_(`+g=Z̤@IDAT_Ǫԕ\(]lCߣl|?uyG]d O#PAja .vJ2URc)W*i-׸czx%jC%|_4q>z+0rCB/eo\-%WXwPjJUX^p1Zz+?L)XM=GUbGb`>+|7RŴj;D7i>HG@hTG1롊"x;d眏,™~>4]}1oQѢ瑮1g& *"VYa UہO=sxST4natd0!p `ZİEY *3h\ւ[# C%nsn 3GfUV[ݪ.%[V b4Jɭ*q `D͕)וh8#v;>l3lyL 4 9MSs4:#֛Zq-)& "#uTzdr]Oi0Pj8Olz a7"ɜ2!hZ9siϊ.F_|jz;4|DGL L? J-&h #f\IFIЈY ,XPpSg͚'3،4Ԯ/#21Ľ U1m07@Ua>c|S9H[2U4&hD .\{VdhJLV RZrNp/q>ЎY׻cnmӈ&]*L-\x=[LV96G6}wA*9Vbj8 XHD)wP.VՕfԫEiS00ݱH8G%O90[#eX ^ΚOX8!~3I_ovmYUߌkh|&75,d1w9SbxBW@ӄP JU-FdxPu)%͹yV"WfbU3.m#e2L-ϭ J94a2ڵ6OeߜnTvh`.ϕώAxzy&)+P*G;QNO^ %E$)ihKAiD` qlId@ 4 GL9O>[ S@k)_2 rK1YdTR|ԕ͠MR;ŐMO)Z_٦qi< 1(U"\nhczG;Sd>:m@wK 7@܊Y_pL0"q2<7;"*LX$CQ@;ph%}րT] 699"ɐ;2 euT NC}61C-1L@z=F;6M<՞Jyɦoۙ;*ɺ3'S7voV-(|t6S`0`n.R]c jr>l&j v00Q ]eUr+,@ e-eU6ZkysUVٚRe&  &ĪJ<Uňz+Ed6lt&6Jw $(SNFCm 0] ~ G 1=n WzB5%߀uW M-Ejns; Twg|*9 KVv*6(2ee17*7~ ڧONFJ0D rfXk'Ρ3>4->xLL,.qi1M:rhSVȉ8V1& -P Ш->qjᦳe4*dBld8"ab<Y5t5d#,M*O1ret[<=HzhOUwNj 52Q-`ARR@5[<{qen^%4W"˘NzgYs)=XP:BUh9os/-RʿDwñV *q#YCC#fy*B;%>4pxs,څ࿉GgәI߄>2R Z&r>^ f^ŌdsMkL'7ʰ,ȚVbnJu5XR.ϐo^"ڎʎFjn b]l%A0)C,_ntwW ҈nAC2dSMڇ#l0@>@ :n d/X;&D"qHF|]\ڙGdR!Ϊ}╔DSy"9O4^I 3o\)c2UJ8TA-9hPYK<픋@t4TK82 MO^{uapN)=FLd&H%I01d ˳'o:ڰ[w/jX{^X/A--LF]L<G/PN 4>%hL*x)@#CȜS4rbf ADn1|,c`Ȉaуڑ@ +R9-q1{3O>BɛtYʮ@֘?1##P^RJQz@T^&Î5DJY4 "Fu 'E*i>b0|,B 0rl~*3db5'Rvպ84k>- M0q<{\9A][ ϓ>d ~aA@F#g (!kR&#tYgq$`R'-w;nYJLdǺoKL5V9m,רּ0uGv HHitݝ_=| / =~fR )Y3Re{OQ]"·\6BoKUƫ~tU(fePkDўhza 5)` gA @:cl1ɯ-a>4|`Vo+_05ao;ԢdSinkf p$DalzOSAIZ|7 &ӯݔ٪ui̭5(-7z +b]xcx'N#~6bd44K6%=LP@n.J9=F27. ] rƈZ҄kQ!0UX =d@A:bjwA=Mu%l%44R\8P )kP2%#(OŴ lVS:dpkP,A|ڍ&YYD {ga\WS50>6=%Qbְ! v9鿡_ /% $LmE$魝fxYjVbڧh4*?i`#lMO%ВvLfX?: G4L`S|_Xы=&^; U;B!烔EΉd5ECoV3c.q-".U-E[߷)9z>v݀9- ZhL0"QWXv$ e˱ՙwl5 oʆVfEl ^S3<}n]"ό143RdW(152rCn%-"FVN)Fȓx srZ $ 82IQF9!1zvOP柭#8pl2A%4xULnmR Sf.5 U1dtzU5=lۦ ) (ɢ5iRWn|dJ]RQT0A&"ɺK` onU@9TF#ćkI$ |^[hLߞ$6 m1Acvd^K#$nG +#7N-3@Ð{Uh*GvdES{FzJ?sergE L)rG^U kiNj X1qMT.7F/Qc(3Ss}'!IbՔJ{C mpd[Ղ1H)/*%d4.≸u}߷r:vh4BUv 0 OK +QLH8pGomps],+ ڶ˧2 OO0o{+ȁ^%GbZ9'LAptI5qLǺ?[Y>vZr'K4Sh|c[QÞZF2rl4,"ύHC Tv&ȪvXII?eb]33[#Iᨤnaؓض`zhX KsICc#C@#_3p `Zӏ̖&!J̶L3ȧߌ4%R>݂ |d&n2ю lj (#FW`k/0c#ʎp_HI]GNc؇'h@|d\m(FoJ) $բTT 8Ar۱S໎j@ eJ0oF0"_nF{|g۶|& % (ݦ3ZKkt)v$YpX AV8(p˪ U[Q@f*GQIp}!lP‹}L0S\Qhk`L-Pqp& ,Eȶ"k|ܐWFL)'1_4ֻ+|2'.B+uh'sD#ӟ?bjouWIfÀ iw,d.gӆ-OX MU#xVo|2dYWRjh9qXK#Pa6lkP d@%$qvVcVL8G/^晴Ю 상Y@Z˽uOFf ,S;R"d;lޑgflhJnƿ0n+Pȹl 1L#:Vb%x]d΁!0v̇?_KhLm&z"oY4lz3Wj OdFXX*1A^c Z*ɅEG Uma]mYU8P1x>/ s?)+v7(UB)71%g>R#db8/[d}8 {J7] )R`>Yx.s7T¼& d+[;Y&2Ǎ3Tyf*$MGn &@jɹϸ dx(>I˾14)yGVkgbVG/<1ŀAmleJ0@`)R㦯1 Y[t2QU=;"h!nt\N&SdDG) XK1&e$gHpkWHI,-+؇BT"Jptǰ\duߧ6 @QW)i&ƷoQV1 x(珏z -@v)Xһb|JY/8_F| 4Eʎd"S)@ f+@y|)a`GW)څ?d[db ݎFln\ؽcLzj2}FGG9.WGr.~xKT=: W>n4]l;®9 IQ$HMT#}az2-"[Yb|wzhkKQ4 )x}v8Maշy([@NOVdEQv& @vk2v{Fni:6v-4D@ڲ*UMċw@ P*Ocj>}+UwَrnMoQu/pL7=9+zt M^v$1s$HvMW@59Jph` rJtl%ʵ`#RKLДU'xfB6Nd"kTu2M{*uͷv:7nn{KNl .aj~EWV*9ʙ2FU7#$v|.kAN Ǫ2wUhO-v/3Pjx#4F<}Upex2`TV gdK.b"1b-R9ssTURҪrm4d%}"̳i`i,czyb;( z1]O )m zْ,xJ <8Uc!^.nnW ح4Z0j[q4ů`$^<0@)410gK:ȾJ@  6{*Eɇ 62%eqLJLtp]JM29һNʾ%ƭƮ YkrmNχ!\;AxU}8,԰ ;R:RM׋'hȳQuUd#lah@Cb@ o= k +5v|0Τ7[&SoǓǹF7 #d;㳥(9+bJ1IHb9\-w#e- n:xVMU'6'%FraGL/z+og1MF,ĵ?NOVy*dK[+ə~j}l<)Y]/SIVrL8YorAS.#u['Ȥא`J>=@-}+bsEZ˺cp#޾ô^ y5Flx]; A% D#&@8@F(W"MggQ; T*ݗOYfŷmKvlb]iļ$.ųwC$B U*φ2Q#k7=q@J0}bRՓ6[ą)R퀣pĊ!>2h@UD eƷ+])+Y9[#"|")w&OGUz ?NyĂcC,7)Y-|ZT@kh]2oY7b~{b9cU-]Ld.Z#H9Uvzkg.0|2U1w[p/IuZYiWpW%8tg0 d$&P5%6!'Q}3waބgJ(7B2s]0R!Fci(ajY;Agգό3M#qglQM߃#16T8m@nkR4r1Maۏ\UNK8ʘ1>q Y>E_f2Xr]|(HG~ζ!cR+Jl]ޑ(2n}|N4->&*P#”E&rSmHG1Jemz{GnFK^nh]`5xbCHdž: |`p%$F\Gnxb]8 ]MaՔ!>`C&7T4 .4v晔 ]}}T ,2?L02OG,9,+}QRJSUI\BS\*>ssxw |̇C6C j]HVҲݚXFYż+2fԯ}㭂/˷Qt)aJGH-xё88)ei7bJ*%+dLMϼ&K;md™] h 2YF iZ#e-2b/YK%KcQ5vCv,|-?3Zȼldcijz ]2&YJB#F kdb%1Y^1ra|F8X#0ISO D#x`|0TmK!F6ryrstYzG@r%矞,0aXH`ql%@(o(-G`tY w񲮪 g z߫ 08ɐ`_BGU ӯw b] pΥL'Zȇs^ I`Fj{c`jw(YJcĦ+ԂI̸Cua# 6d߆U1=ek(%0 j:JTڐVt~rx/Dh n]XUgk EU4 A @Y #>LlF[$Adn(@lt+7PFg*&,<yk3@pwA΢w=,z]} O_6KcMl:_W $&JaJp&o"R&y#4DkĴmU ƥ,g/R=& b6{.ҳ_{VXFyFihȎ1dv%6;g((ҋo_.c;W0OHpdJ-~!D2JAQU &0 @Jp{4mzm>Veꢌ ؓX_Ovv)g [S3AuƑ-F8$sM 'jdQ]JrUsI%츪Uk0[ƽV%5n]H (!9J_=p~6GO&6e;#1+Y4TȪGi@d U%= ̵$hPS61-e%F 8ZCԻ}6g<F)X c@fJ<+ٔ"d&1[ureǺ4Nc*e>ܱoh?m=r=MxK9%=ikNJƑ/Ւa ?L),٬y:jH2l۔}g[oXL>87^cc~U[@hJˉJM,#,Pm@ Suy&?s7mȢ[G-i9`ڶ rFV&Z6ȑ kT) "%hRǾ$ہQn"ެ&Sjzb%Ah! n2I,U)1AtѺf<2ZcպFԒ͕-7&kkpkGΡ|Z&";v+ 5"E}D'bPV7Ͱtϸ 4p1aJUBI5UEz|:"מ?qҾmJyrFɿk"9+KPz3#a7%e&jߔ[!FU PfMIS#oid!AbPj郆<%lze{(&@vJL-Q{XjdJV"9@dX=R$;4e1 {U%nmvX[dZÄn GKg%y䩤Q)lfG: ..⿜9h7}XG[*&vN!d[itnjOwqX<17^#c0@O =#>L,0d*E[YI3L#y_7PFJJ01j)a-pu~H@4 fXKLFDRӈRp%xnHU7LX#Gq#-O)׫UI5e@ZHϼF,AַŰ9PGұH=7?WgUA&>7Gh 8A-V:cl∾vp~wcLE 1 S%#M'eÿkeÜ".0r>xgY&F{A~/[@Kk%k В8Fvە{a)sf9#ɀٲDn'&hægCG9%xzۡF< MdL#%MZs~i=H@^|Qa$7Xܮ9E]٪Vj]OGjX~=i2's$ bQJU1gS)qL5}fEtlְ#l Orj߬X;Ĵr&8^Gn~;ۍ,/nTU*&,hU!hnJZZ^jg@I|"sSi.Eb9t4*0A]|~ @e>ɀb|0 ɭN%6 xm2wI`PWRMPGv4n-$N}̇J#H^nU188H # H&‘㭀p  5vSU%< rN,G'|P:]I֮2\~cX C< U;kA>] Ύrᆶ#Puľ}hPU^")"Wrd2oGhPww^|[ [D uT p;9Tife:{Y0ptYsT*^1*CbdSʬT9pJzr|HDo.F+ah#YSnj"=@֪Q`~hIn.Li*bԪ]G&YUHr ܐEGHXHܠg#TUX1|0F8lJk i c h`FL| VdLڹ 8e&+BQƱޘ}T1oȏ #1=MkaTEĵT}W H,8h؊m,)eU^$sJ9Vei&Iș+?~2a#܇1aZ^ձG]nI>ML.|3L9C%|xѽfFny]b2>97kVu U$KU)9OTܾ3zTG^4_H]nFSh@bJRKUb$Mx>QU~׺kjs8G};ت@jI&p/!pd%sp#0UzX&P piRʂ7z 4kC)  Lj|2@aUhI&$shxّ8GϤ)2J4>HRE'-}#d߿ V [o- Hcd=~n} zCi{q<@[R--7hx.R鍓H&gN w䟉]cP[2}́FspD9807֐a4 i:L +ᑲA[,z> mCHLrv->PJ#: VpVz4 G98n2rf]dzXAh$+-Fh`x+$5I%[dzOm%`΢v wU95v 4,RFV8!'A;vPg`0 .F\ a vd}f=*CAF]clP;0}ER2W#JdUy:4BhĕYF2NO)B0'SFf Y)˝7)HSd H2&ux,׫Vﭔ͵2fa/90[n'=[}.dNmG/ԧϰ-ӇCٶ= !aݥÂ#}QO'FKbUv`H$ i8HqXG† bxd=^#co옘 G+e"1t"8s5؍7nC/)֘H_ \{o{af@ wnkVUO`>ɠ@)vI ς#s=컕Xӱ;T% d1ʑ|(`n$&v_K`GmA?1!?KAfam቙DUO}T 4QVʿ0Yz7S"Um F2a%JAnr$˓QU#e@Kć @{Vl!,*=RIU@fh9)+w|d. 1MȮc Jo3Lݭ&*96] SF d[5d/eWSY*g$i0z‡@̐ :Q E^zS7n 7XԮF]--m"3o/9Z5e&U!mU7'n^&$΂paGiLpO3>$*9aAݏkv.nٶc+))S;1f. H!R(Ù+WkAtWJܔ@hebr-&FS0izv q9@D `4 a%dZRjm\I;pR<+-g G&4^@IDATf͍I aH3EwD[XMo GB4J@♟{2Jp}˨*1iA WF*yi0ʳu{ F CJ_b( iTExiio+ a/k`J |?c;j_n^ #VM dq(s&_U|]C|zFn52'n4@)($Lt!M" ǯIo.b2RILl4nL4O>)sS!rJus[&g6DLdVu}X=F@>r]'' "-²h7`٧#ʎ鼟veWMH]d1rQ &RK5'O|s30Y%>5l庪 -Z[kmIQ&!A8O/ +pL}ab< Zg-3_&Mz|ITBZ) A4JHjXePS\m+agdzitq0 sƧ &^O#LW}D2jT"ZYYR#] rb*a2J"9T#ܱyٱ=sƩ?MUd2v飯7\5lF~[!R[D&znc3e|\9 _2^d3SX#a'RI7G.\whD{#kR0eemt<‘QPh¿^Ԭ`̇U MQB0q)#`[JÓFWi2mPFi1IJ%1#2g ܽ'jln#x οq ȢC; Ȉ!=%&:;6VJYao(7 M~0Qcl#Șwe,&szݍ Pꌼi3wy --ۆۄ7I5n7$1181C]i ОCdzҕ|Ǡ2 ghY w 4<(J6!sk@˽C7 ;.  5X.@XN1es|}j$h 0Y@etLÔ#09_p3 B&dO8e?}dܫ 􎪗>jnQ?L&4M-N@z t)jvSzg9)H>yj1#%{|LkH24U4ܔezyi"CU8"l*l724Y%e01*:vbb@IvX{_rgƴ#̝hvJpO[Y/0#R4OUYJ)e/a7 3x \=#XݪѻwYƗOo5iڡL٠UD FV2JN"4 5dJ副*vN)S5y{_J^վ!F4WPummG61 kdN1;*u5YJ<+C6opZ+Sb((4uz%6ޑ@0=~n-tXcs1ܐI@ ~MG־FG#tݱR*9G//yeÓs7C|!PU\ ,VaPEcFgaʪP9$cJaŁfIs>IW㜵trY9 ZL(wmwzxL& ^q|nhQ^LUlF'@ wAJLxd3lVkUC̹T m5Ժ@" ȷ>x9lj6[ S& E]%ӄt)a펾U酉 `-FӔFz(wdX Y6S5hׯ13^sch UreDmʭ[W ř2K&oHYm h4ngqU2q7=evDnaث,r<'ݥ}3vaߐdie2LaVG3k,H-ݱ妴L]yWu_Iӈ9׾F.Xw˵0琕$%N8c\Y0"[<sKgTaJJ@ 4w>/ZY2l1l%i]0 AnXcpGULS..- *$ ['Fx^#RN d Tob$}-ެUkwTu/Dcm4'9dU] 88!h4p~B%<[]nDCwYq/%3!sPbVtT]# €2n2%&7LU ,Ie΢X޸&ƨeYY%[4!Su{. В?SR;2A1T8WǬ)fy|659eeޑ 8O(R%A)R*W[Vx/l-̿$W^i/a&d0P1Fh[ OCwKv޳{QEg8&1}ā >P|5ʕ& G%L,L,ǖ'e&U13- ~x-J'h ?-'k=c2,7(sk-5R Ur4ȷ>4@Fx6 3RͧMSjOP)7U6:,BIf+n jJLJ,@-L uI[8.)&0aʅHG|z蹟!Wz $x'HJH$2,'T2|gE$DG 'vRօw׫yUuYYō .cbZ#^ ob43%ޗJjS0]VA5Eq}K z}ܮY^0.hVsVr~tig}J&¢vGa\ɞ1 HmWWYqY2KlUǬʪPd(&idу wq%]ځ%jzB![sWh Rp%zU}x(;ua4fHq6 &C ̐RnvhmJM)!vhxr$ęhqTu_W`N7)WEI&`VJUS2"F훪 dyߎs]/S.< }j+89z8 ([ӕD%LVx qF`:6N Fe>8zwv(ZFjg%0+?o2adddJ9כ AkG]<ەfw,pkOu-C >~0ɔ(c GJVkZD$庐YO>Rb!0'%F8^FC:e&j%,}OpQZ)ȂͭԬOXHW142YodړQvqG)M$kW/ Pa^U MAkr@"[_Luf7YBP {n6O0:qo. u9f0N\tb-"畺ў{@IR_)5]u<ߺfتH@AUݮa2Uc~4#Kiiۖ<w^Ic[ڷc=3yfKXR)g ؑ9p/FtVr2X{W 몑3T9AWz~q ß1Rz~pA&ȳ#Y71ٓ#`*mA;#uU%)Jdm;{L[LGHG?-6]Sj0);2` ߫kF?|" E2UP84Ջy&b}.ޙ8}+%E dHߡxv>ߌ"#Ò`oGH]Ws&iRnISb4<9g۬ct5J ǭPDād3aP9ލ[)y"2 İ~7:|˔42ԋdUfJܐ0۔m;Ἴ.2pnݔ2[)ٱdF$*1$5JĢ %KMIJ}b:j,'Pr1Ysb4 1:-sU2V|%G a &-ihDn`Ȉzt} ]Q:HQ/PWd9oĭݒd盠?cӈ3Mo>#ʶ[k*i:YI 0j;OAhIJdx`LJVpGVidrLʳ{@L79. " ›UY5YΕULql;Yc]io[;`w +G2|!R&hl㳪8[kUZd"O]݈0o~`S%"+ɪYU1@$ê2޶pǀ-C-S|:[i^Ԩ%ѳ1 4b#: SU׎9pGVe{\vKb]UFk ^Y8 pT_IVa8MG҇hAM,Ϲm˻^fB evhUX$`Ҟș;"P @0D,b UhK_55P˞Nl R;r.G-x3a.jaЈZRƘ~訚QFÎ_}3׸;vGsENlI(3&UzMQsnd2Lip)3 LOt|.G<+vm4;5bփsv$M`[q;SO#1J,nU-r>,v|Ǿ -&H#ǀޮH䬀ݔ22O@ $:ʘ0%|fT30?PF}=e"H 7,7&RcJ{qL8ewވ3uELMVk)kQ8$?rkQ!FP&s{֞ J)U`_UmJZf"ȢdFFDf[&PE8%k$4-<@z̤x-xgwN`}"H-e?5T87#'ڇ S9;>M?eDn& 6H&܈hzuu0^PyeEo4&h|q1&5ZyVMj%~Ϋֲ&Es&ʯM =4_G)|{4;d2ɿc>&qM7 Ls^o?*V^8`# J _Ob.&&G RP;2YuuHJ 7xyM>d MeʕvX靈nOUp_?l9PU3~c5S(Ɂ ' E SLHhGezj?_B)BF7_KX2)зaH8JGQIš^@c%b+bU2vO])eJU0g 9׈!/H.0+Uu 49nerh)uj)s3G:*EJ=Ȕ[mn5|@dh)CF3I{LD>n-Dngi"/6%60+yurF(+ǑM4:(a$x U*(mߒȱ)u54 .G %g4(ЋYHA!PL֟dH ]3p`ɧiV2Y4l0&4^ `e'>rMU^%]A͒_[0Hn U7)r 0pz#+(ݥVݎ&?k(u$ !2H(Q(F#c9:*VUc$g[2߬LBv@ 7L]r-wh(`j"dZ^0+ނ? xZcn-Fh ^HI3 ЈSqȰ^C-/F06RnuĪp>sץ\c|YSdFh@zp2NYCsRXӄ3/=r_ #54(+UXM\:x&_Gim kPJǖHw\UD@5t5ƴLFH݂XBB2M棅%Q&.7S8 M]o5s|ap@> +ȖOJ>?(ydH@N/'Mnxʞ L{6^qla/dAU/'^$%FIX;Fx`a  󹭟1=ASk JS{UeAGkYAzJ-S~ )2/Gօ6NIK %-*`O`&@@1%bU;f}u) ^2mV ׂ753m Uc:fMo"9ۊngMY/^5aX&шl1%O$ ؿHͭmǍ'Ӣ,zVo1R^#)Z#ϪrE>2&E`Vz z.RI127ޒaHޛz"IIx:w gB#"~Y`S`Rm2qLs2TOGqd do n0@7ĤO5ek_2 3xc`@#C$ 㑎$XY}V2=~r4]^oL%X(1,'>/ %<dVІEƜcVrS!wCJio6QmXnk^-Pt= ;RW|w-YW3 0n=vT] BdK6a)ĎeJGD|2;伭q$H~qbcs@:&k3AՔxj)9ݒaRU-c!hRu5-R%k7Ts5p/p,4 Qn4cVVˆ6Fƽ^Qщ f]OLbɢȞݬfeh;٣oMwɭ5qJpۧ+lgH2RY92ш"w宀!*M$n#Z^TCYf>`%d[Gdw &+31ߋ1d0P2Ah0»b$YʪضpG&ԂV\/OIPF/ײT,K|[i0lmVʓRzJH$p|02c7WC)ߗ1HIq0[JiG2Ce2q|~dkF8e(Fw>k#~-1 R  rzs J5Zhe< (D9e5>Qm`dV)qB  ȅ4khG  eP12~G 9e<1_Hc|lgؔahz2ah@PpIl#`LbΖQQ: yKVWyf%`taQt>Z㌿dwȐU@ܑ2,,bnM" 3>M] R/+!㪚5[j[#^ ۖ;*9h䉀[ s1@s['vM`a $@֠RKh([%fk0T pUAIlrkLc.%dFk(3gY;}s7w߾Ug"Md}t7V%?)Fa;ؒŶ0Z{R` {%; aVuS1iX.>ݥ,hĴg%7Zܔ4Y24@kp.H)LQmЋJΏ7XNGr 7.@ccJo(XuO|IJuj8ޑL/[4+2U ?[< [o e]镄bOtJd -MkIFfHJ3D R* Ҳe&d.e H12QՈx6wՖɧ?*^AJH U12z3wd_@)XKdNW&dM9a jL&sJdMv)2Q вvs&fL)_/!SJRJlOGzxYq",'+߻'s1kw$3w\&+#Ea.cڄ?$hS2QzRo 2y@C@9ꢷ C0Ȃ̶d ېvn9n:P4}@U?js ǖ$`E06+7##4vby>!LȶA|]?'6|AJi5"P#,2ye2n\- I&w~x6& dbkO/G6VI% Ld;sTaֈ FkTM4'L=e1P-g{UAazy XK:j+% Pz\֒UBv$.6edXWsB/ <%YY5?2Rp(Rph.p Sj|%]vRb92=eV4d0F _MlxVcW3vM@92JkWHT .M$fe:cxaL h3T A6"ϺӨʛU;V;7#fW. ^0B(ȖFBH㘕Q)7<3Ɛe0jtIis<)EG4Wna%$AWN·IKDa C0MJM>e/R C~EJq [PY߸Fɪ:"U 56@XC @b#OtUU\c|fiPxAFV|DL&LSx^2D:7J4`/g"j!.`9ˁ dV0#7P2$I$* `@؜@ Q(DN N\Ofc}7shh\h7ZU-90Alk4+rTKJ}"mU;nUŋ*H1x11%CE=.kG {c@;k$ˤod#"˦ `i HO8F3 7 "SDb@C+9)gC4%Cyf𵛥PQLYc"{A|%_1ęlɟoW$n}=R*[4H6űܺJ}ĭH 6zM|} dz5 Y.Bf=4{v (gG1F%YR a<=5829h5ؿ*I,Q] ``dHW BYuЋȐsJUα 2[CULR2T10AyRǣ0H󐭮MV%.e7>4'ѽZ)fb4J1ƵOs#.3^&wR%//^e@yACʷCBfh+peʉ2 %L|Mi=GhLG2Adw4Hd,"{z ā iB R@#nDҾKVcqTϼ54j#iL*97g; 6 -gFZ+ ^Hc$dەն̳Ƭ ߢĊ #il+i=2HL p8•:UR|5k'3ZD# ȵ#d€'#H2#Mx Md Ȏ[)R 5mI#TSc-UFNJ}ݺ+|< gJFKCP* yr,61pFࢉ2t'Ù'cnu>AdGuTv c@Uz;VIP* .}~\6.cOcL([b2&K)if]obX6&>Y_NCP )Fdi v*OꊩW -H]Li(u%m:Ogtw{fmolm+#U}iŽ+a,hmg"S 6foF v|_*6402)U[ +kl ^; ( S }0涛AJdb{@5.bmb 8>oՙ*o h7Ʃ>,%w.2FP" ܚaՈ2f[M@ M12 dWJ 5EL>J3>skHJ-nTFHl^q nooGoU ]5g}=]ȷɤnFJLQlbȀ^ny>5]h+sHO#gҝ;sϹrL#b8vYPfHb{" N]) +82̹4~2.XKb2I&e&sޟ+|Ϙai' rLm5j]JЫn%JǾ4p% SeϞLW[l~w |Fv ``A ʆ&۬Y#w^+Erz,dAo]Kܔ0j֘RUY'nQ <ٱ[ idHx{i$CP`iU3}Tjș Pm&=]]uO-&kriK^ޞ31YcQO8ߌQ)Ak{]az#Mt0ĀSպR1ʞh&D#s ``U]@W5Q)vPc=@IDATUMLL;GƩ6GEV{1@dOIyLLOt9lJ}'$V@J4=̑4x>w"R{/V{x{I}Lrjl0ȔD0ML9}; 1 RqUnJaGy &hP> ]h WSE:dXUe 𕈑@eGUWF搘!}D[&iF&ĖqT%7.LjVg21 3E>wz5ʍDϤc{i^z#Yu6H%IHc +yCexMͲ ;#0Lh]40_U%U-ϳ&&墮eJ-J'O-C* 2GUX q+3-CkPb[KC0#LTE<r|hTrF&۪k՞`"AC |>׆yo7tהּ)"5M1 Zl crẐ4ޞVc_꼲s&1ǷRcرNϳ.$Y1,Zf,|G@l")6inG[ &.8,Iov[ 2ebU+ 0~MS#qlaGFyWh~*93AVe4Y#aDkcz de[^t aid"yY#ql 3EA MY5E0df/d9eh|f E)6er79=ApLIp z88gMx{Q /bd _ܥ+@6=J60Ld&\oĢ'Ro5YUp@@'C&ه c吔KX xGn.%K$'m3`H}2wlc@-kGx"V^CZT2̄l{ח{Zk6K `([aC[/ZF v$n-C 4]; r+$֨ϟL$+FHhLR ٚMH'@'dDCyGT"zeE)#)dH8@s)mݵ(I_J sxE{X1~Cۤ7v|Pc1Qnm Ԙ.\W^z3]^88^ڊaܙ';lnVi2 sGrz=c T{ko1GbE [FO F'(Bw\AqJ6Vʰ̤YkjCifabu" V]2ȖJ"q-}$.HQVx1xAS٠ܐ= M-2AhJ0>J 0E8Æu]'QNh9mΪvS>ZY0@tlsd[)IU9(cԬMF&ˠfaH^lP:jI)S"H07^|1XR֕g-0b#4:*aH&]S qJx % ϊck-ArI-*;"}.m(%b‡ۥd]k_KL.<˔JD{ӭDj.o.+',Q$gYJ|.נOɪb{~C`"#yO| 8ڛ߀ +5gQcJS9I3W^^ї8O14pL=eyfp"v}$ĪfUz2L6=,3sȪZ);TWХLbI%X)it{r67b 6(鞋tyb2_F.B#g7r$+t9d-Q0a2 0rFιqrڧ6c>?9sth8L4i^mYUcXc #{%{MbLD cZ@.Ta;fU1|<إ`42[M1R' 2=E|yђ ըKȭQor|g\\sd71,c0|Zm``L0}|jeEn%92)MI ;z1e<}|7i,e,ǮI?/^K d}:ڄIӕWо#c2&"P"=@j2+dֆ$@YWޡF@ʺ9Ƥit# `@;  "٦E/߻e2}{1&Oc1^ۡknuWcuC&67\d$3e mU-Lda5t9'w4#QfBG.x />Ӫ\ISc&)HXH1"% (]H&v<.w& xFx_ hɜ??وI0RmdqFtMĴ䬸>^ )0D<ͮDK]gSd]+hVmfa]u9 1ae0'Drxx8u5j셑< zU<25dȍ> GF(ݍȄ)|=ϙgHd7)u6hkdE č 1q|yM[ _ɬlnU-kr;(g=r0E0U #UBט |v4WoX&kP#eY4@2! s2CjOe:n%3;< J te Ӱii>A{d-jo( w?(+4ASTMj^adk;?ud9kɜr&[uLA6)FL>,.@-"`$G.K㹚鍦jlZ[$6 )]DA݅U ǜ2V<%#,hHȔʘvZ)ځ.$3̡U uCU=K-z̼Zz2$& R*MA\c %*-LD4Lcc E6ed $^UaN{|ep-9lɸcKlvjw>+ǨnSXq w.[}@:-dezSG@#ix%Snab_Wc>d2 k8A f5PfvǑѯ9[ d)۰1FWrWjUC6TUG R gC-Im`O"X@Pʍ9U€{4LoIlr &팄_,s'mc%eH\@PLj v laRGcL&Jr[ɵ$ܑ,h|gnr Nnϖ/>NWFЛ-r!F nhkp^o]̖FlPS,27 n\x] ~Wks\n SjzCq"M&2xgL`]M16To(^*vUSkvmTd5S^zMGc81&YdBt4dn$]Z¥?[R ԕ`x 1AږgLK z1}R5zwMU"#ư' \-x6D`PnUk]]SuObպrdZFoU^dM}l#Y-zF0I?0KiJG"@:u92P5YlYg{Yd0J`lJ|vME ", =,Rt[\I{hq#0L9ܙ WV-lï]Ľ$(H{ZFMl=EG2 '=[qkޱuʎ~eM_WJKi᠋@iG*ZU$b@:0Z.`2OyJ ͪc ?7LxLeL |^1^Ȝid ngV+qr47@`" j[-ぎ䘃ݬѱܳ4?]Ѫ ݶA&2~<5oOSaR{߹Ll9.Fh,L t0l[FFʍ\d&T_FyNf` Ȧ[lJ$tk(xJmǨ xP)[Ʊ5X>܈5zs{K[b uh%$AHLY [&.wφ2)]H\G ЋCffiEJ]q*' eSj Gc#jQbb _eXQoq)EoO9R9ӓª eV0  Qhk*ܮFmDW糖* jp(2U|8WOذ!̻vK?X2H#s#0[>Rw*gdL(,@ XY5QU %Z#FPE R#Y4dG7O 1bc2zU}p6RP-HzxU<̡gI*צRN.x@Dl|~Pf~>B T\Uc0"̶*f#c Z8#L|dt%@5R#Fι_8 ߈9 RM[CI"D F7E+բqnFYõ4{[ZL \>#iVI}|@]OVa#$eU˕9C?ض0x]ر+(`*˔D/@.#}XV"uGX8kL3C<5 RlDnV-߭ /FcZ}x J6뷰<Ɣ R2hަw&[lz #/Lh:p%&OWxbḻuihڮ3l:H]5vJ@K}9(YM8٩ 3 U[|e1;!qMKsU&@67'Z0`FИF 8ʪi?CΙ'p"a;#e{Hq$ĘB/Dm.nnazltJ\>ݥA sYC[44 断54}oО;;sИU%_k|%lVnmĪC&mmE[tp 2S9R;vp)m<X$nU [i4kCS>/Ye&db}FO&,؞HUĽ쎞(:RW;뭽~A\#Ȑ ĶCS{_ .=\6Q#AnT,b*֮J!J].-)b>7)tT"f̙qDд0A# [h ȟj!Q'f{#,/n s_PnlJoCL&aU{ kKV1'本}vM1d&Ԓ9WȺv4W҃ #g-1@߹ɀ[FId =]R(7NC2YJdܬ^2Ȑ?>HI#`* ;8ܯB륗kg6oj;1xuNVexʾRXn5B&pk繮Z@-J10A!B>b%̞1`}T$ 9W@ck+Ȫjo$V hPF)|,SO]N0ֈ|Ll zf-D^BI pL6FJsAY',:zNZz=Wwנl-^̏m%ٷ\vJhDxXc8%FHbX5ꝸR.؏MUY5`I]%i0 i1LoJ=T>4JxVߛw}XƑRÙkF %= 0fV폴IzZ0z={,hLO3J)a]J֠8dCdJx>,2°UkWJʷ3rq|+YFd!<7Os/5=  Z.ܬĀLP洞 : ͪ Cb͢)1 X1gY2HU"mB6İqZ8`zn-6@{Ȧ8ʔ<`Y`6IҪb]@LSj:*X F6TYc) xZbFa  Fb)1J}~U)H݂3F`b%ZFDa25rZ|8XE_7i 0^ˆiA) ܺ-%M-@$x ͲF)[&2yV4}+s'=LΜRGJ@z/!CJ!Ops%=^؊RuШ#29#0 j-h( яdHbcת-^@"7hD4s֛X/[^lcC Tg7ӱf@K}T~/[|#ΧM-M)4_EgUHEZڑ:E.J :cO #;8ؤа2V @ D-ZdTJ % `XiWڕhТs+, d-i: F+g< <)#YvA-@S2} 6aG2)Gjy-O/&>8Р@Y 4ZQ? [@W94 dG]wD  -}3n94O-%ǖ_W$ Uw: 04ez 9|:4zٷE/A-A}[@$𷇞@x_Ƨǃԛ22ت-q@I9)i6OIwJ2^5;"k}yzU4F@(k$x#Ȫ"TȆcuх1-˜1߿dmncqmV'(ڹј|___<5츹4.Y`>!E)i&Z^ ?[<1a12؈mŁ ȁ57T Hx:2%RO&f9`V+{%%|=F7e ^IOg{Z) 2]h͙"KX~OW.m1g- x@ ڥ*51_ {XXI"Ļ#SE;ʦFǓvlF8deΰ)erN ڛ,6 mr^IdΰmsdMυ)-04<1@ j%L8a? 7 0r?=LKu7l-0a&‘K3̪[ ;(1rQ >.h$@TG>l壥 1U1s4f{."Ӌ@κ`F|R◤_l ݥ)"w4#V(ZiA٣6.WJsT ]J)iĉ{wQ _ux %GnަUR]ᲞU)TrTVsJ.|bh=Jrm2w;s5GT]Jk@is% Y7WMl/$ùG( H`rFݱ7ϊ,e RM%!LCU}_BiP1DEMJ?w!d` . 8% fd& +$R4O3,6M;)Ow(7@ \PnnikDZA(CC/d++FPaa}sd-m,5`9#}s58E$\ #tB[F!jSVc!= c[e1ڑߏCb4 L=K4m x zcWgȽCcJG&2bhgU̱ Z||4ћL<){=z5™g{ %GwتkO5M=:+V4xXtS4Hqbpplsղua8G/@hğ h|6d2Lɪv7Q4dV$Uu% 8^nJW( 3i es4Mgko"(o+ (ezl4m($J-\U(=>L & ,`%F>s̪.o$&ngW@sU sRE&c&n4FW10fƞ.v|1[E i_\vYz/ rNbz0=V b\&>djXK]-Doq psl4қ#ElaedDK]w'[e>" ȂrtkTɐc\2< k֞ Y/(aMITNю>Z5* @Miz1OqTD ]8FɫqTMp@k^N/ͻ<>Lb㚒QVELv$[ Ir!L5` ϝCeNP̶Bz@c/Pؒ=,Oz7)&ӕg`4ܥeLnKPW ]ن34Mz5+i`OzJd}1M4rkKpKr hCdWvQ0bc\3)c <`.,V]#ޱJ] PSc$xB﨑g@S8CdYrSL)e* 56"C<@YK+8W^cu)\x \2H-odo{M9}bęgҬ3 R__EXDEڅ.y9g:,OO)fڕ(l3G9M0 zZrG PMZT{_$ F8%O?P(L\*F O,L`ڡer}OSIWJnZp`5fl%F3YsW!T.h/VN(Æv%k!0Hm9\{,fmaG?#׋Qrd}:zsЛD; B.AkLDFz9x)M@*svLa2z);koFMؗVI#eV@X)&sL&Sb,2? *arK`z+:b>a2&J=e+r;SGy>5[D"edv9]4;6ڱ(+6k8Y$g&#>"rseJ4ű U)E2+ H8TxdJy{֨]șl6W& X#z@ .nږ,Uz?6!J)"CzM0Rphb4-74YxL3JRMRc|!e̋)26z:HYif=& Ɛ)JL%10@LWJ@ɭJ%G:JM #ǩ%1)րe$7&Z}{4җ$F9|ji=2^nj˪cG&|%d;T9!b4LY[4T'[Xd =]>9T?+$nE@D/*es;>ߤ6&uXZh4f.;Ҭ==bajoF8ur'F#\pN2YJ/`:֨ϪF 'cHJZ*Y2݈8O@#e]2eiL!+:֘,^ DY57 P!EMDSr蕀$ >M|[5 OSDXi=BF^ư<@ k1O#j}:rY!)9+ XR e2ѱq!C%͚i14즎]daz'д3fs) s^6C1dM8瓸֟Xyvdp (pʭg(&hۖ k?qrQRch0hLNU-? ^ޣ"έZjF3'#T, <ґLo?Jwìja+&pI4LlU2 #a!&R2}0pT] W`[m\d7B6av}|L2Weoę#19cڼ0@0DCh62A)Dο0RKyC1||\7#Sm甘]!v8Y%Y);Z٢L^9̇cc}hUk1' }dth%3)#[=`ݤ=1YLU&:}aé&XJYp-n:ˆ1BUUE ~.k1 Af‰EJ Lq&1|)X+ 5"^hi+6j x"A?#@d}q9hs7ʤU&M Y? zk7eZX)|b"P`,4}%<Vpȭ=WILBtRo:=A@׽c#r7 )QѨ=B7:F߿L!0QhCKz 5ԌmFe@2)ȶ#~ZHU99V]~k\{>a݄Ʒ %;訴 >Z@)rgsU#yGia@ι2Wf1FH,+4JJyVK\H@j1A#to|>&UCHdvx[$`QuaKSVۅtoK^cUTVt~B#PrG֮䗅J[8"n+|Ujl gљ>Ւ`kSOEz9qٸzˆj'v ;ڟ2Z3}uMWk DYE+05v#&ض'Eid40^hvw #{Q`?lv H!4Y@X;@ k wm%VQ4ITʭ f.z2 hn񓘐!]?у(ٓFMƻ ȭToJ|H@Fflm(HJß'/M TĀ^ɺזIS }sk,25Z@n&'7V0R1L)1Rulyz.![H=\`Ȕp7vuM--i7(zB7r bf;VܱkvsT#$y;i7؞e^ h6,${LiVқyF7Ts Z@K!ꮺ k$vijmʖi" +wM yʼRёP҆oLmD&ԅI.w'O-'o[gTz- ~5n7'.WՂ/ǎ1&6-FCzp8 UY5Rz^;Oz6; z-SW#5Qn\vu!qS1M7>ѲY/wħX HJ&tJ.KJT( 9#8hɤ'0Ywdz)muC%qH\>>)(J-l(!`ZDJJ4-Y \H$n ^3=P >qnEɶhG;רK8* oR#4:k,f& #aa]M?F#X [<1FOQ'ۑ֑5z+ ,ˌj AJU o4C/"[7^j4.w`5ʦo4LR:RmDJ#^䏇Ⱥfk8"?GA^xD/?k%n jW-(`)"Ŝ I$StMX :@V3)s!g2>@jL0o*I@eN}i֒>U=1J8)>UJzFSx"Ya7P:^#&LCi/ت:R:r Fݶv--&JF1`whYo0M; g]@{-Os[XFF%8ޑQoVHڬ2׎$S+5EW@wI3 禚!`>[54 #mB@t *<7 +шQ·FW1O6G:Atq,d+8g+ÎF#|]?WPaR@VW*#IH) @W*Ejad[Gνt~ɠ1ͪ.� gDfĦt 4y *9V3&%4>|0dGhD扜yk`^Ozצɜm:zɪ&EXo Bt(V&avHL os&{V% m6 RJc3S g*IDAT!z$vn&hI2dDY04ƈ@s‚^ƜNS w) dA 5҈F R1zÎZcN,t! ]ɔ0 cH=5ۛ8 Nc<;.+5=}TG4JGY8+Y)eYh_/PDʘv7Qv57hlIvn5X𕐢?Ur߬p6[U}XnI *)5/swJbz4beK e7 kJHs? T5Xsz^ T h @UZL=1,gȢOlDV@oZ2@#rCעm}7ULnGn4m|>MWj \EOᯓİ)*,%&&b|dx(b}uTqQ^DHjt/ЇZOV|4Z6i*^̜!,>&H9+CAP mbS#)k;CCuc#0arGpL&{Ȧ"ZSd{xцLZTc&cZ͕IPIV/߯~!Ԩג>/ ǘHO8J4xWc `UJXnpQ.@PfBIS6EHkkGw̥1ruz0O RXhDV=*.Hַ`UURb!h%/RdZ4MLjr69FJ WMUBb(-]Fɶ=Z p} 8ո풬v]F s sR}v YviX ~‘Y$l4=CCw+!E Ȕrrpϙؑ&ܬvHҠH*rv7N4kOMLa921m+gyC b`0 UefHUw4A haNfi-COJU)!j`JL$YG-b49ro/F4 gCϭ=A&m{;. D>4&*!u럯x#v$ ob@I lka~BLȄjCUR;2FDGϟҀ#c^LVd J }JH|1C+JA_|3Wh CE {`hs;&mjK6.|\.?PU%P( #dK %ّ'}v 2\gg۞v|] ;$Vm#R@d;``di0k!kl-QcWVr @ޕm #Y탌{Kwi=9gE0O4@SQe.J}4nǝH/3L3z~:+P,jelYW`ǰ5VTޙ;>+cazUh HBb%d?*>v J4|M)4z#14HZ2Mh`Y/ =l0}UJ!zJdWfNpmۼ?'홳wqUKZɲwY}PbdgTt琲4H?SNL@K."0nazL]!5*[ Dʺ+}kCd!yJ`߆ϵ^ Ȃ[i N;Aks%P2&J4'FrEdGFXOx%An gdx]45Ƽ欴c ce4|)ۖґR1lr1@[MI LoϟQF p$8Ұ}g'1@n`3\P Ρj/S9 rk +0^;bnמVzP?0f_F[OŚUyF*sh%.%akbd@,(tN< WQH^UՏ?{ZĞYiMwrd+ɺT-S{1qScHGA |\$o"CpVRX+@0d8c8i`֙ކ9 {s-pVo&BIKP{ğfFU!YZ*=%+]P#S\K;LRV# IF8ƴ^&CX#=F1rwdl[QUiR(%#pE[? -"d+0J6 ]c+jW1L*c5›Ŕd^0eJ*ZYq'2MݷҕyfhoJKv$ 6L/%1]Qd^Mڧ^([FVA &nDhb{^͒-\:}:Mя otڟ31,Ѻ`2&]^5M׿[*&mЖpEWB@U bp"(޾9A%EZ{悔oCUi21t +c1%dJE2klO>z90}2}U97r*J2ޔ``UzIgVz۪Ɣ]k8v]0 GGE#+ QhIC(u_YIVwz|>JU%#VWXv9.ϡ,[CyxUrYFmk'F6=˦ضRlU:M;@TC/T_.N)7ܒ˪I  H\q4ۏn*h(б^VmÕ `[$2 0@YL旂%>6| 0N)|L0[)aEw"W҂}/=|GzQTlsrS|z[C2M2ūJ O<70И5vq i`L] PT6aULkQDdHޗ!ܥ5^iZ`"r[xn&áq+/vC :V򀁦z'C cR4]U8&̉;vS⪕0ƪډ0]DZvnHOǪZLv@htqwl jGz&R!H'+0iZvi꒛Eُ8) :-uǬyiJUËLUn4Jf\|܂PDU)i*iD'%UGxw XI0YK!>?LczHǝMCdʔJC+^`'#[I2FINA?|,t%iA+-WpoӬh2H=@vte0YvP$Gdxf:6diVJHXfW]#R&1C`D)[8v82A&rU䟸G_C#taj_M%zS ;$u̚>Rt1)ȉzĆ:#52VJ)UM3{Jp߫|~_VYM[E#0ȶRct[3Ҩڼ.|9;wax&}h;X @v t(g mϪhe.OoU Y W.#b$g޷X1?vf}{*O9R0ԻqU5Q24ǟL^OO,oCmz4v%2XI{!OE[$}>MjUyqxzjɪWb߮B&kO{YCIx%zǘ<1ܷ",Jڭ^9=fϥQJrc12%w$[ C'R 5ʰ^r94dp_ǵ!dd8c Mij9w7- ]2h@b8p4͑XVt}lbU.gX lwӧk-,d#UփP2*3减c,tuGGOOIV-:(Z ʁlT5:a1Qnf9Rڑd^?FM:DcU)>:?Kߏ:ebG%Z% d"d %k1ʪ(-+ :VL8H٬Cf) =@&s&H$hY/ #uQfΙLͳŲmeV=1u;!2[]*(ʆjr9<ȡp;XCnз6Pis% URϒh,S %´j%o%]p+tlv˰ܘ$RVH76_5t*FhT4Ȝ)D-kCO9ЕF(sZj:1hR4\\,"vU'Z{rE]s&|zGsNϟom \lha?g2Q1;Q@O-T[ bI/s3 BjLYϿ gmA(R6ƧoĬ[]\CyVQ/k9cnEnݙ9 zz2 H8gd+{^#sUGrԠ1V37XhɔD8^#c,LO}FDn>u-HֳYݮZ1 q$qڜr#n@P LIJhOa%QK^+#`z0GE%-dHP#G(y#V);(91}e<0}mt'sV|s&Oznу8:?ƵXS=#ZGG}1=vZ G|U[p&p|>&uT%XA2zaJݼ.JgbJmGzGyv(#0lC zИ0ȳQL )kpPraL_JGRޱLد3ze6VF#mQM:͙#[@T $H'CӛU+m%L]ݮBr 6^T`j(]?+@)s  1ܛG%8|ѿ&4E6Ymk% my-a͊φ"a/J(=f/i5Ooߒ54b|"{)|0=J`z%GeX*OUkP6n*Ir R&OGJ2ɲGWpJFpSs(۹ގO=BU7HIbw2YazFv|`VzWPiv{otٳ.%aB)]Wij4qn=b2&`M{k0m Χ<珡Ab$K3i`- `2Q 3WBNov@-F&FMJ.dpM`%̑)U412OO#׈/єn a$PF)vbPnʟ#UBdG'H >e~m*\mAfN2!^'C dJbEU]0dp vj|x)-d:/7S+8PZ>d݅JrΪzFձ*1, |ܪӈ-6a?|f_ #a7= ۾o-XW9}>4{a3|tJ gv݈HP#eؾxzS/,׮ dZ:jtGbk[@@ĵocFH39GB>J|QA;c}dbȍ>V)i~{c-&H SKw/g^A#j)sZ< (%p21EsedvM9_Tzc#kvdM`@c}{0IE#,"5x9r2}w,+1eb< O1^K߃joJgYͰUFneoJb$M_ljlP0W$X e}$O)3ϙ& .u4H%]ZƓV"-V'6CU)`de]~ko"ҬJ1y{ .LUi/ZOiA\Wb9oZ{ u >MU]HJnW˶ fA9q%KϾ<%6A6^I3YG,ʵdd2[9Ph" &-S;u|񬡊O#̪㨋[W!SNM-PUn "rm$m澔JliIX;^8^N_cJzk%(U-0J)5²mMh04~͒ ]Hz0^#3{v##ah4ES) JU%8j7dfbRI)])WgFXki ưl> KH `/ <95/I?z[ +UJoDWkhl eG][GؐL]4'qS -MkUʜB E+y j)aFX%+q펲P%:,LO&oGh7vL&-cK|24h̐Ciq4S_MC'䃗-ҙ'L"; ]N,GivCXZd47x}qHz>m2^]KꪑxeqWJ|E|?|ÍحֻM^f T  3'Z֏@AZQ^hM _>Y[3;86KUǠ1JxY)1N#%6.ۉ f>-prh*.[ö2zop [61\?/UR-ƈ+5Q XYUv+uu\62PK*~uh5fB.FJ 4Hcr%&0پGMX@TQYa2OY UY)Pdk4jLsVW"drER:(J1GPzPV̰AH`|eLh47naCeG;еRﮒo3`%c pΎ.EWPd<+;1j$hDG %[A6 v/P>YՔʍQu*uZd$@ 1deG/ԆHSH&EʢU#5"$#grJU Z =R;圏]On e9vv}`A#e̕@-!zqiZI h 07f#2A-@r{ %97AoOrr|2nӐ ){ͬbq[A֕ ?Rr^ezsFc5O9֥Q4t8eY缕0*[zVJEsہ@$ӻҫ(nj O>#C -66gle'FdJet+5]{IA[h[Iꗔ+;U- [["eWjIn|g[%|MȪ1HY>r,RP%8CYUCvpQIHóUzxX <}.L D@[ L܈Ua%.I#a2CCwR-oJ3t Xlgi M@fޞd}ͺ;}ʦK IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/hello.tif0000644000175100001660000323466614776170045024760 0ustar runnerdockerII*+ 6O ?!@XcbPG-}Ā1`49HcQM#?Q /?%O0[3}NbXr^KbG|f95jQB5':kVF&@M/)[U%P,bg(}%ٌ*ƞ;z[$;S@mQF-q'WkYGARʣY5?볱#mMcͦ=1D#϶>9XXu%Mugk kxf1HCdXx ?[e ֈ1)[4-{H RɾR':#KZIcL0V@KȁD3蚶 q0l-$t$2THR4+R CԴ,sF55$Pt6KRt9-Bv8ؠk6rGڔrnDp*$!Jgq"Y_~hBn׳!d2Dpb|~sEԄJjlY/W@鯣xw{2$нSYe dݒ+-24 D:6uy%rwim~ި#{N'.|t%g{ !V bqxʃfb|@v&O%cd`#86Kl_*NBBz?N\:t~.YJV|3xfZ 6An8(@)X,|8+U]DdE:ppU H*D2̥+(젷^DȪD2h$",h,. &2bZ,뚲hjPjKh(pE zōjn)" a7 lnnHLj"zɎqN01,\O',BӁsB-1vr.“Nfijr?B9޹E"-+TJ8,1EXL~`-̫O6+&mD f #r',2*M,J_J8PF%Of4,Jtoh4<(b=QȕR0tN/LM1.*+p&% $O@ *2)48;dȅ: OhD.h}F˧L'(fb%J Ղ(<~q$2Z#R6LCP mJ@#IO STh'&c]zlQ" M'Gj\~N6{FUgbr ]0n"G2#:c A6c#%d]L=Xc3O3嚡&_Vz'Z4fQ+C164491R`Gg5Q6)+~漂gLO (6kk)K%,ZԔrSI Tֲ\jM{C'6ṟ%#v)ڪg,o2_ODbϡ% *6ƗFjfEuumKHm̂d\m2zTb.,\MzLq&7f!lC$LUT/Arws? ì.dE6r%j1mk2z 0X*jF%Gz%0g\ Rǜ]5 @)[9,"TD5bLj9QW,ʭ L3+Ot܏kФ!2,+0[QB.hhΏ2TS$"3CG<$1ua P zXc,[fEV*^{b@u1lb.y]jM`p&*zwE `IeiC>L1_Lb'1M8Qdb_;} ֐jZ\uZނKz ^A $P2,`ER.h'ǏX,2T4Q"wL6lV nO3-ofKʋ9) z"~ H'EFsXfJ !b0>>M3>OOWy%XavS[eƧ+6JINr("$šob Hl`3n.vP+\(_x!6.² %$V%E:dX$~9_'XZ)*=Y;vp \*tAq?WWw-~Ǩ L-4FA? 'J '68 :GNvR旞,|+(wx2d.T(uq~7 t@ C;x%1|Ӯb9,퐱Ws"#3QGVӯAyq9IhJQ\]h|aiDq-ŗtV$6h,qP:NLjUX礐( ѫO$[gdM|c,RFT\=pN>uAGk{Cm* mE4NGaZUmuGӭr01YWdJE}FG f\=`>  2sW"rn#~Yh6x Sk.ƤG[ܽO4aUl+!Ee9FDKepد˚;rOVSahTƨ#p\N#mv>Pc:aeVĐy$g ћɖTGd~艔$ݓ\ZV`mh+U!u%L)a{m|1zmaspFBt<.\ȧ do@ i=-f+V g>XEjroT29rofTZH$ȬBh%hi'&tWn |SU@:b8Vw)o"\,c,'x) hpEWۅVj('t\Tb8 h%T}eS5Qw"\+Q PnE4 ך"ӕ= . I+/ I"ͳjY< ujb,^c[6 o}[3jE@Jl\\>"%3GT?+j?5K`Pq}=u(.Lx   A)E +G8Ca` -KD5%r\KD:W&eozTS@,RJ15n(O$h&Kdrh!ןQ4G1އ*Fw(f gɥs)O8d3o^Wh!Hsәl!)fѹ\[K9핟[b4v YBk;+mp8-]FC\gP-($$ҟdRWƎnqe"2c:: k # /h3h¡P>nB 0O\dJVi zA,4)  Ȃrn%2\\̄ !;Oܸ%p"1*Q(؀ \>jpkPs.s4$Fhc &2BI9iv5LICŒj#T.>4 BKdC+b蟪Dc J:s}sSDTȻo&5 =:x 58L.s7hz`JLF)ri *3:~ O*ֹ7PƮuDa)2t2Q01GU`RSI,A(P2#S4B"6=[WL;m 3D~4.x$-ZD"|IiN%lrGfwl)S)Y)MDLx"vsAk J*Zf` b;b ZUWJ`DD:` oe  VlO ,? Ni9R P'G澄S̠;@Z.I:J\hm<BMC66Γ"5Y%`Il*؎xHkb! K2A<;= :W` <-ِr lAWN Py*9øj>'UPHb>D|(u ]'|k)ȂF|w)p&$܅ ٺA 5]x2s7*̹x :LM32u9L?#.ÔAM*_ؘsp(d(bVMKpNr9?摻geYho "&l?Z')pDiomFkI !` Qx0VǨ%.~3D)PXz0ESV9 *5d 4P U - 1%J 1#j`g?|l` lŕΐ4>JFRj6JnZ_έ2lȖG̋YJD"XC#F҃C1A$x=3q`[d d}0 rD](dBI$9k C'EC7QCB0s@g`{?*o<|}c[cd*TD;"<G?`׼r0%!˓0g͖!\:8G{kpH {{Q:D)/ d2@fD!tʼri2~Zqg0"YI1jK.Zmmّud ́B6S&{~;dgk*bB4&0|\CgrR&UM&qcU9jAV.n) YB暤W%VO9]A'32 +}Ψd~dCCuׄvˮ5FFQ{DJ |6HɼD̪0# a? cziD+̈바X| 3z #m8 *k^!'k# ;bc3x '-r.) 0،Ɉ,S(0 ):(*9;5Hb;Bz"D"eQ`J j 2w #!P T3'"`3#kU:I͐r`'9+`4y-#AₙXe/ɭ4r Cځ=c9$딨K7 ;`8>ӛcLЮ2Dj.4ʻ :0s"-*mr+[ 5KBj`{?: .I@,SX"Rf3Fq`DŽІ9$ .*x K󾋛؏z0XӇ="9@` xzz 1S;;zd6( 7p}xFR BF.P}:©Ɏi z+K߾ۦۍKl6?z,X2a)#+Ϊ+F饼 &,{ޘJhq੉C ԽˑHZ΢G98,7q ".lq!A QMK$',ɱ.e<8ƶɯ4T>LĂś'"bTې @l >|VA .AO;샢?+]P#S6am+l,vX -8q $s#|d܀1ª`%J skLN:Q)lҞdO#`"%sNBL_Zl8bzM7=s5|!d-.;dǡ_ӨLdJQ"JIh -ӡ ZF_kRuYn&9COj84 TZSMf64f{KzM`]_( B+Q⠐|#ueߘ~Oϟ Vv,\/XjX$Yd09k=&!ʪ:y`s%tGB bgXq̑Sh95X@a|c8k]`QCMej-53tEȻV,<2= :#_ωr )$搓$v!>v(Dމ!َB >h c5"'塸ա6 @eӸե̛{scNdWقZ\VM6-͚a -OZLe4J~ Y'l= m4Zp ~fnw,91b&KQj\SvDn~ ㎔kFIKpbnQ&TmE- %dKFSӓD>3U %WJ =g/ڬ\z|!^]bbd́ 'iS:yJV2g!i~=EPn|a6!.4N)ɜ^oVIftdRsdBXqwDHRhyϲw jqi5R;Qޚ:Ncߜ7fXw61>C*? (D$ _%E@qwdD!`?aU Kc $38M*gpC@0Du!2rY T3ɜC(מzv BpsB@U ZG9GLoODηL[Pt Nbq5:a5(nU#wB^?Ƕ_Xܶ΢5"!4d:^R3,#;׌Hx𖷆Y!D5 ·EK7񹌆J+gӱTĢ|h8ףkJ=>åAk|}'"6% A-: lpi:m*T$1N"&(QñLR8Z'1򲠊r'4c- >gPI+M>KHCc;˺ ;{b{6`R)cj3n ԕMT4*5'@ΨH;zTϫ  [@T]+W'6F|v]"N z(Q Z""øX&vu~ԉ"Uݱ1bǀ ևs þB-lvQCKJh]7,4WXSHïm!$T҂21C~MWi}t'i}> b&_D@8u9 +#.# H@EZ:JnS!ܷ-es@n{&BkZ8=hܛnl,7u?oO]E(q2#@i܄f8ܭlѪ348jQ-{b3ien8taH]>Rqàg}. 6t넃l]hK2YVC&a*&.}NA phdq|<.tACc-93BYbPt.h!yiy|e= RI@*c *[ (`YICPvLDBI|P,1B؉"Xb2 ^DB܌.n'H0!2LT7NnLyu.\f~tW 6FjcU c@#B%:"1Hedq`BbjlO&::@EfkVGAzvjZc#؂!>y Ѿ7RӨOrx`HRƑM|wh.a@՝j.jsU ur6&JT& mPL.X*Jc2Ŕpދі-91C4`O]ƶebbfm lfؔBTEm|wi}R(@ J."0B:5͎91 nOT/ infKTf/NIWv-).=!,BSQO_؈.$,;mI QlfMMlE>Xj0L'm cD@')]RQv:q5+4Q4LyD꦳-1Z'iӴ1'|nP[o'$%d!L0nPB2kւw'9j0)9.nB#H:m]qJ !Q)%WTzbĻE\ Jm?չf=?'QHC |ԵjZɻϽ1 VDurNq(/h*+I0 *ZqRҎPp<D$-'Tu9hi _HLHg3DѠ ;t 2p Gvg)P:e:OXpN0䚂!ŢC$LL kn,z!tyKD+ 80"K)lI#tEoZЎ~JVje). d)M!q,pVi-(Imd0r0!f[ @4Bfp)JLMܦ]$:)^t% |L %5&sT]rpT>8DC!$̨,op!$-ܒ~,8s%I3ˢ#2G1zlVSd&le|҂l ܞhBBO2gENd62t`O@+足@) EjEGR*0N>_kSuec4pi(=ٯz#8;; o0r84vJR'|TS25 NFi">6RiGB4.R<2B$0025 tSѪ@ &|R(HBfW+P:t.޸qUPP'1On~' E)e17(Zu`G W"Q ܬLI g֮8]b4 rJb2'U)"␱3Gxs1>8xC`2G6c2hV)R2J9_ EWUH`H|m?!t@&g!/W H4bq`sTB((Ug6$鬟jV)$%&pB5:D¸T !̤FZo'j4kEg>Fd)UAbRPoG6!`8K?ġ;Us?۬Ubk([3Fq >̱iRXD 5*@)7tRλdk. 40TD.q.?NBȄEԺ%#5TnMHR!3)cN Ҟ%UJJ*F. r%Ra ;11m~#BI+v* NLjQ"Ksw qj"|1mr- *P 6v229k"Xꃎ!j3P{BTl|v*uD9%(J4lMGU[)s,SWqg1 JS"R zy*ze%wExԪzo$#tǨ(Vwnth5v?(v ݔ,MH?HJ~(#,S"G*BH +Υ Ln2^J&3(Hcw {{ k 텦s:ʯrPJ"sF[DHx@~ux\,0za)+x``rl,Ty= ?e4>ʋNKy'0Ubj82eq,vVKX!~$ETΊ"kŖ$Nc%LL}Bb ETYl@ڄn βr Ci:5*T=QN$?ګ*v-blqȝɸ7 Q|MҌ1e8s=gKJ\؂Q0b0KtᒩF^ܴdv?G ^4[c/av4W@ z:{9I@cOa/`O:l"]j1&!dWf.6>Ԫ<-*.z#QvLg-93EJ$Bw^F 'j+Db]a{gƙ #pL!?.ya!2Yh]^JJb$w_4&Rvؤ`xd*:]"sªQ&$lH#MA VNJTbm58TmtYu j}RY C*:\RhUKv/>ir <(~y&::̯1"(nD$JZ^uJZ`Hr<ߥxWȥH[.9D"z-B2Y?eJMm(7)6,} s$,`J#LpܒlE$!~fYO#-X89vJ|+ TA|)U2e/ݲ!kё![6> &VMQǁmyϱ]Dd.ۛR\J v,9$/̓AҺ0 _IGŋN=3mCajY%D ?$J$"RV\Kc9%SSklk\AqYsMG<@!\~0ma5fժ3:$>mT;tb#9]0ҼulI>Vv5'^R:[Ox$]`uNVڑ#T!2NȘTY,h1ryØܞOkТhrڭm,*<<\2I#m^"`7|e. ?gj4˫8ZM++&v'm 9jTbWXv JzE'Ɣ='8Ѿ1s z%"B˩v_x72RUbenYGT;Dz<A}Xq(v9aؠLS4s=~󝊩!%/sZ(&_K x (*j:.g8-aQcac\ r@Bϝ܉ȹ 2ԏk٪;{q07`ſ{(i׉ɷ< B$/ټ-AiRX/39T[ R<ɠx<)&K1 )$ B+QG9jJ(IB3. 0B:B =Dӏ83B9<rC21ڗ5)ã8~ȱp͈jZ5c7#"$yᬪ,;cH%%6:8IRzL#LB5c9$6B,9GE6 L#BxS( )'P oATIq272L./ɓ2hԻ*F4 cyt39q 12Ϥp ݬ{S~4%SO\" X2&RIMi0}5"@DZ*j-0dP]p s ri$ѐ:\ۨ 0l3B5#lsw5W@|߾O*2?Hw4<Ὺ< Qs>: cF~ 7*͖Ř*̸HВ+ SMBA) qR$O!?ؤٻ ""=^024P~˷<- %7Xi /Ú)ZaH[Щ!*H9"ܚA& {TTC̚?[e5P,Ѷq4vR*A+p׳B8ZZYSE!l$LM!E(Y30"ŒDOU֨Ծp]Ëw˄Ox}*18 '%+r%Pd:]0s^ٵ>ǫ4Cٯ f4JHѶ (1)Et:!QB,:VC>b/̜!،H)!!K0TNdɔ3'$Yڗ6 W:|I-&bN9U7K7A؈Ϸe?MԚ"R ~}.{x"܈ қX'Sѩ 9%Tm̕$, T݌$ 3#[=ҩ<4,`zNlJe+Z:hՔCۓ9uZZ`?V+@2˳H㖖3`͝^A/#mb-Bi-T u5 4c!.vFּY q ء[I<-L<37&П-xdE<X55@U-RJ9 I"% Fd`17c:`lY|%<-IGu*0=7vch9%<< Ͱ)Ӝ TcRYB>NbXaجRU]G78s%aGXSTD9Z,6Rp~&Ӂ)4 LJ`tb#1Î$)p̌}a)U~ɏ-EF}Z*B<&,`T.('4%X2‡HdBݎ!FUr^O[6m̪0V9*r 2N=(j\RزRQ%﷩kRIsٶN(X)orLU:$)L6QV+3M%5j˒MfbI01~_ ..v?OSZE?HuaEį2N¨6z~N `™dȄ IbE0~,1}a)2Z >/\MBX[m9,T2al#>GX"4,K$) ֋Dxxj_̜.$e!ic XX277Q)p(2ۅZ6m0FÛ;}A-K>#!3ʚZ$+jl/%lxaL.łJ|PUŤlm3a Xʆ[fx{pv= Sۧ[^ȋA>MPRU>-um;N,_V$Ǟ \D@W\) ̀Oؽ`Ӗ_ݐ嘏jh!ڽD#+(ȅS4=T"G Ǧ4ɺm-|dd/%zj)J'{/tZXV|) 1 [5KP;Eln, ׮DG,J@cyS^}:YQs }!u؟NKZzurnƻ7Ý#Q<7 o)lY&ꊀouHڻ!XRU?_(#~ @`"Q7V-EoXEa@,,Q܎>~LaR9Tq8c'ɬb1dqhT{7>i(kULƫ=U? K$ud!Sj G` j% )R8u/c+`i4/ebk/OrK;^hłq1+",P3Jkd?@SݘAC&po+KC beS*rld}aP7{iX X@ m{DHF J&- 2"<*0?(.(FP'Ï!H?˄j%JzJJ&̚Gz `~ D\?cRlJ)9 :*kj%Oz^(^"ichL$*Y9"b0%4ȂIzRAõ-R $3rX$kU0-ŝFbVp* "TʇVnDh6*D Uyl%i"m{g)X|Ԫv-i*Z"9^cj &) LҪP ;I~Ϋs'6]]KJ.)*nȟ ד7vV;ӀY]ĈE.Њ@*_(!@ g9tWVvʍ({-bG B}U 6e)`ַ9Fg^%E?A)ð}Z˴*Uh%;22${N]xk5cUZGЛ+yVW γwo_f mhҨVr"rm 8<֖I9^eSqbdA6Wfufw\Hs4=vx(U"k=&槴q[qm?cX +Yel\BX9Dȱ7$nf;5A |ʽFN䨢nQ̚* V '%Μ펰}n$!v 0ӄN{a㕗; `b8Cj*B8ȓ[R T8B,.$J_H ]j, 0rG/tB0&Xk0 TH%o .k|H /sv""fީަ/D5G_VTн zZN^$Z7Jj&C/ddXClFwfVbX閑<&&NnaB$Τ2',ܮPh[bK`jɊxq L αxR,̛FcЌɊi%܉Iw'!ƩD&`NTQ"\2ژY"!ڊ*w[ĉ@c0jf/h-6&"eWDqڅ-b,5%JklCXFMvW w'. b]ˍ!L$rpCOqd2ܱ @ɤ/$Y %`',jZ-ì%AMCxUcܲFPQ &l%zeI(!b1u%k6%Q[3`ms>V݋W2EE0&B'(iIN܀ɚn@'m[C*c0o $Nm0QM' /nCT%~{)XHPs"5IF% ^.(|L},ts= [I v!M0,DkrlF$,zC"s=+eB T' )T5[ (-I0F µ PkruT{klY)Vk>ZM.bjvJ l /@&)3Nj}D( I4#3,yO-5'rGIn5F 2.&O=sL5z0,?:NOk&*]2DuDȉlRXО!"oP N, "FqtI+0$dY!ǘpoKdF'Sҋ{6nFrs2 91MO|0oDnn%CT/TjEJ"W\PSHYJ:t=+zeŭ',} hj3@«ZBQҊY^.&첐g'ز8ujC&Ni{ SK*epeW\ 2sGN%U&yc$m0O䄴bkV r%JS qMi 5Gv/BM{!wI|Xqȼ TX* 1n"Pjϲgh2ίGXpV=wҒTySiG(^}/l+]-fG0I1|o_S-Ɲy7ڢ-}bC?2%M32jy %)1q1uO6/']m!By0t^=DF]@#*uiTAW"نzGej0)E`i Ѻ;/e"g'_%~X{TۍjxfȨm{sc 6Ȇ$3otdBY6X(2ĆXs&W] !D ADUi|Vb$F%Vv"$3OuX(VɃ@PWl5PTZ½Aō/pGnלW CN &D|et=;$9l`1=1ֳmf(m] ק/JGX1fj;g @"FE'Q{yַ_EjM IRs.@lj{V DܩxV@Bodry'+YA]JWCp))&D> m&4_j/SFwxEh5Ӳ+J&S>V8Nk9L$F Cxܛb҄.HI B22k"T g2h{*.dPx5،җU)(9. 'bcRxObb!^ *41(:o bmv; 5/OgQZ1cnh'rtUu+a:@2bϛ ۮ%$dZpQ}ltgܙ=svm&{nRz @汼\ u?6Teãcy%/KYӑXQ, 1L #!OuH'wiQԏ!9nɊNҙ=y-;m.z0΂bPa?!W/J5HJ˼=,k]0ayeѾ`&0hĂ NC$`sg1MS+Iw >e3;)׎E]"sJ/t6z11cO'TV V,­B>+ sꫨ$aqTUr?dΪ[h 0 \W E:fq%{1R֖Ys(Ӌmʙ2yqvM7d3{$13E#D# AT( >D0x*1 zD%Ġ  5 LO(s$B? ZS?>TUgP6\w1z~~=z hvgd&fYOuzb!RGD,VPG1{! hž 32$HfФ l<(J~*HJ~><$HRAL{4+tDL2$jٶۖ:SZ-Ф8 P,"< KR+2 #T2rLY=J "?G)L}*z6;# *ǵ,?6j{td`).:1OxLm 㞭3c2r& uhMh%CL,L5?'WZ5%9ȀA9m}d\w/1˜D"Ź$hQV Rnʫ_$-Q%rDDRvefR<8u(#æ^!Q ĂҿRQ}bHvKJ9Nь:Kmqȓn~Nv l/i:Z!+8)GgN!htSUŏsV{SU_ D逩@ë7$,Ub %47$ 1!SM*<-KS:6S*VPGPwbvƏttɁhUHUXHjYg3*ůN%um%vaJt׼o{8p#}ƥ38gKRlO|iv$+ȉSV .dd(43wna*NE ]0==4ӱNuط+HTUL6]&֢l+f֙Xi\K$H}At ʩvS`┣Ȼ!L6'V/( L?lG+EF-U Um(Ǝ[Zv\qJ JRIJtSV"<5V:@eU-U gZfap$"')l}Oe$5H_ 9F3z N" l[6qvNk~%B6oJ1ٓS؟0Ev`Ĭm!_ (XiyXxI&r@ H4/.6U%UV+"7ł$jg؉4>вKtF{ϧhB _7 #ңzR /Ҽi$ڍ1a92˞j7#(a0*J#ISR H:FJH4h}**XZ,J72 =ɉ<"4Xí \ɏ"ك3C[o謓8 083q9ҁD2ʐ ;pK4Tڭ/7, +jوD{sɫUAF"2%,H ؖ<) q9Z䚙1IQ 4Ȉ=@S8!>:DgiJ4D33J?>q$*/ʊ"C*i#ǗӶǍp,JSS258A,${%62jXqH23ֹsYH j bm!3Idj8CTU)z0ăd>.<!ɶ04 +Dr;/IKKֈB b)3YDi D(Jcf[zDDK|1)yQ((;긠e ;踤xO (isH34E,FAʑ5T,о荐J";!az ?2D~:J?P3CJ?3x{%ٰ!3qHbk?栙( Li[̻, (BߣYd'K\)<,1zuKB+AAO1tr­񽤸z ,NK8cB8zղ \Ѳm+1YL,<};ˢr1J4+;s U3(N2ݘQ=DZR+:O l7T56Phؐy S4I&XjID*5cOc]J(2Ʊu3/t VtʫPy_($F <&v.}6b44A5L҃/mtFY.J `يGed)aJA44- TEB3I7\uCȬL#!XQػt!L s+ER;\͌9HE JgAĴtۍ } M!#`;\'R1Cx;+ɡJh|W;"-˲Uj5jʜޱK;$?+.QSɟ`6M5X_SަԖSБüY[ɀ6 t ;̜2r'=scAX<g̒ğq;^z΄ q%i UŸV XX;iۍՈW.&A[̱c宜!vJ+  NVۢ&[6!ɸӿXgIHfH9p1Qgs̺B+apVJP[΃8RfRqki_d0$-|,ln<$ڲ7A^91d8̱/ 뉐'-UbTC2s, 'uG<#Zt.Tt#%á i yƦƜE( kNL 6Έa;ZU/ǞУ<ڼ|:Ѓ R}ԍ ~,01#$*\ǭ~hB3u/Vnlm EUꢘgyY))X/CX=+\;fkj4f?mM ͋pn;TogM׏XoI-IWG -!-}oDLN-E 5UR|*Hj!wLo;dC d۪.se#/i?U=K3/.ܹl(d?-HVy9K/8U&+yv~K gpСo޶vk)*׬X`Z=#]ZW_.cgA`0~ I[Id9%F?d^/U +򦻏j@ {7rbVgƨ VAͥT^%5NJpM~WH*y282dE}x}5n;Ep.lIYBD,Biq7 5z#(e8F!i"x]$!V>:[{v :C]ē8\ Aam"UIk^(x’̥eBLᓲ Y+!wMKKB$Np@ `#e9w@1PDz[QNfnA J0bDlV )V -Len`lN̼zuDXrC[;еbS t e4$&EsdPAe§Km7BنvιE QQ"h9zrTƇh5xx4 N95YE)ʴ!nOT 'r?V eNm -h3p71%Ĩ| Eutm=qbO pB֘l`fO3H%L.-NTja/i3u3} "% .j)J.%QUҫ#:KL݊rOR)ŸNS4o6I35--Ut  H-Q+1k5 6ȫ>m(PCy1huŧ.o/\g%8v mSx=h\qEm yYgcDƪ8Uސ~$ !RzB2v\oK|"RM)]8miέ֙Y,Jhdٝ&懶,D~9FfJM/QIw]1K wcRsOp©Hf?(?xWTv񉏑P%&u[R׊$^D8UVji;Nd!(w.r7,u(DcKfmV>ûl&FGwhK XƇqG"$/| rjX{IM#1}mYՂkZ#0Y$bItB0>bK7+fs!b6ŠֳsS SeDѥyN\G n'Lʖ.Ë[[oNh]a{")$O QZcq,OVُ;fEHˉ/g {"xZ>Zrp,=.o"^K2RA򻴊גbbNP]xXG8fBNRHhu0ETvc/BOpʦt E4, @C6sCxOXhfV !iHhVJh]kX/W̢ RI9#HkPndS!ɤяʒ#n'hpeNYjg`7J7<€Ȼ..Վr5G-Ȣ`i p]if*ⲧ0ndGDmiΪ4vtCz䰎pB 4 4>'!_N訟&WΦT(䅪6n b 4NDEGQJkjX&0F DSpHZoB:6j(x9BNsPJJ.^'abnk"f2qPemO  l> *Ib"'Hf)j*cBs s`^'ldžHl/JL}'Mȶ*|K Brvy4f~g9ROC fdja%~|MRчFD(M,# rd< *|ʒ_D+rl|]iWGwGr৮~G  D2 "6ǜP;NhhϏ.h%Zd3#0b"H2. Lj 2ňzoP*Dn'LɋMp~RİE$sYRlqVA 2\fldGҀ9zOh+&.KioRO‡Qp(Xl>^Khs(SCƌPj(tho*J"++qĽ/X/ $?ID/jO4؁ g#L(PhdNS#BmIEkql2z"vꦭ$N^Ϩiъ#΃@&)1v AIpT|I,T^H49E\-',ℛ@j[tM @DMJJu?u{+K6Nw'$I8`v/)I[vS2% )ah2⬈ҬOmt^G\b OrΤlƑa[(.9 BN*Wqk` 5AP tXYYTE6k64f o-g!Y~#ӧ ‘No#Js\7 pPtt": r"?6HԭS4"jdNUy)0gI/!fh(T@vRl*",}V '*_nRFkZG0w̺Ɏ*zО!3sr,'cfn J'vX#/]Sij$L'*L(o'tҁOj_Gh/1>(`]heV60/uEn!.ԥnT76p\&G+/8&oޮ4"*0J(6w4!g >$jRjh cUit^skFd!px(x,h4'9fF/lF~[X'ch6( Pj GˇLO/Jg}^kSwa|tvQO1w T!6ńw訟2pɚ&rCGE<k㩥xaJݓuHBnE㝏v⤡ "ݫsu˜xö z=\UH4/|r5%֏[8I)j7sYM\e%Ym-煒WKS'2~b/CLuqýT3gk r*[ U׸&xA)n Ф4Ev!Az3`t$tiɾ67P.=o)B᪲ѻuxb~?(0!`)D߱X:&>c,}!?$ >%&F"RNG?% =D%4N>Igܨ!}C@9B/3J" VwZS1"?M氉5VmHvN}^R rP$"#Exp :G?V@UX&!;@lZS442-NڤP@VwBYD!7PqpۜM(F:-ФrM;EjN괘;q]* xo\Ӂ`U_#ζ$s<)2"5lFР{~"l6I{0 #:)J Ф8!PC%A*įƁ"kz4:LL>lZ*$tI|(4 2*0:* Qr,ݾM8bA$~ #N#~iLGhD"EjJNw'0 L;T;:"~$J"q 0H+rjt)7BI#RZ*P TIڜT#ML$ O WvM%.4 YJ2PܬP[V5W).$($w+.(NeCURSNZdcSV#߻󥃊A+u\/b %v?3=9 j vyY3Ƕ Z>?S??!:JvځzaNpQy%dzH* tA1G"4d0Nb<Ғ~'˨6߱ʆZw@Rn9^(Ϊ@_vlF[J R=5֟e]nK+'/sWS+[fA:xk._XJNce7k9*x(RTBw,dLt$) $7`>C O܁(#q-d(׀C*dghHҮqDB4?xܾ8O "TM&kقt]!x5y",O.`@uФ lĤ8yxc?FҒ|RaܰN6fk"nss/}ސe,9ѢX g͔`LQh䁛%ZXm> ]=B}grjϬTQB D'[!$,FVL]%FL̥'P aZhe=  ĘxV-}oc)#U]WMWM~6uy6hn#G+aU])Fg&e7\A9hÅ#H5G ݩ.ܒvEiB4btdO{97;QIT0l%B(¸gZjڂpHΕ&y*vwR+hrԤF#dhGEg/FB0 \2GR2q(Ut9Z8Wph*Ux&< ;ڟ: oVZYEEBl JKziI[*BnG\o󲴤䢒p>EXJjl-xQ\6p/'i#U]^JlW$8)Gw l(\k|EJg9U5Z vXo%Rjϖ,9\YGƄEm>J Ÿ>SF( S Bߙ떟Zeb٦T4ъ2`1 ۇ"DcO2; Q55кXﱺY ns8}= 7iL$?3 wƧ3 @z? !l# kۙZ-{h~@9U 2_R RXf7|%A:o40|t&)8D81gY=2@9)e)+ S~-$=//}3Ecw3AzŻ-}-;O7CVtc (M7*BK#˔K$@Qg(@%'=N B p$+JC紋D8⸁*s@)"2H1s- żLB-ȼp=*q9Z1Fб8{lWpSJH虴؎,HzKip/7 |6?"LY R-d<gZU>l c [m[GP'K3.I<(JIO$'u3 J3ƮȂګ@MTI!gȜԟ2-sh:ȵPy(K:Gb4c FM)K4! M%DÊ KBc*HU$ˬsVs#B:)֘`$8|x LA($ #lC2La  ԙzLz3ϥɰY1Mӥ2&JJ9A"&GT,ƕQ%#ᤉylCX. H 9{6+þȨ |@4i7;p. AO"(tJuDy$ ٭N@|!ꥨDBB <1@ ԬZ J:(1].GͤTcخ#u:o)$ "UOyˇ] {B1y9+:0Ѥ47"GM*YoL"xA0 |z"$w?^SKr.\Hɟ *W4PK"NDS r. 5˖$Wn]O`C;  TR<:$ 4VjZA8K΂MAyBY0b\`X젷\겁b*GzyXI=>>t$F<`0SJ4͵jLY}WPD[s L{lUcPj7T~M؅ )ڝ8ݫ+謰0*9B{ZqA#QQ=\hKbKb³B#y="ſ]N;D)%ѭʭJPбǨ}:;+*Xپ4/7GF)4%pңo`rc+l]F>H;׾yKOA7}C ݣ-݉mBHF%sE>_D9-,|ߴ9}KpbbO=QXӼ#TM"2ӷ역kEMb} =XLVXx㱾(IjTX}Tj-!^KFHG+_}7]j  ԛ8ILm>9 Īr@U6XP3ģXL^=_)V5,Hx[ DdM"U IT;rbFz?mo@ZyVW3E%WC`VbyY@$Ac r&>Qa,ۏ&(ٮ,1UAXf AkGCnd=aET7(;0V͡XQBN4AE,?ПX 3=eU^e͈iۋ3仔G#\k9z="كx@ E.|N*UYVeӪ (ܢkA LL40gV%dXg@"F;M`\_I$t<Rx%V Vŵtv'9 -]܆^]_AS_셦LSH!s ॊKl0͡YhtFSVXˋJGAU+b0R(].٦HNoX|. pP ن_VSmD /O>ni) 6_ kY\UNJa$A侎.7RE!B&tb`0G&9>mL3@-դٌn- `R4I%W#5E m9X1y3ԑNB,Y?PP!G[TVO.]WlLJF+$pOϨJ2*6ȡ.8(T]]t41j=o3J֠בڟ)EasO#hѓv卵,B|$a c0f(Ɋ(yRFyr g^d+Ipx|^\u?sV}^83^rJzhQ MΨk L}щwnuRH#)<[y'dPv#v'Hߡ=&dkm%R. VYzΐr-54t\% `KI@yva:8?ȍ; iP,^uu~UYne%{1}ܣϊ.|ZBa\?G\tŏu{L_-u,LXJxAuZT_f"S%RM N\A1d9JߓFdGV2jbFm]^V fx?(  >!P@ "@-?X9a@:3~Ϲdp ʥx,}'SY@|KDq!"y%3MaϪf gxdR!%)(C$qJE2)5סLHR+ԩqRIE"!׫Ԩn9d#7bU8$[w]pWP#0R%GիMa_m@9#^7Q 6ukX(w؆;!^_>>idC62Itϴ4*8WJSR %!{u@Ъ ? 3Z-lH3]uZ㘯NQi*1vݍ#kyII-i^APm"%HG@3%YDd n\r\mϹ&UèpmCL]07N{ϵQ&ϱW^iJ\Jn"Vp(Q-Dm(Ik.%`Iu?"ͻMaxm +ٮv]1A6bY~G꽽K6#h{; n' x[d 徱bP9\!?ō_ "]Ll"/+3]{K,5"R!H#N!.]$F |$e2~93O #gnqX41Q)MYp#0~ACH-Y"dThɅ0?wVn~)$V_ `CȎiwJn'xYZ09#֡Zj~8EBN3nJBe X"tcW'QCd9>dp%!EI*V0G oeRW"-jy?C&_R~El$YPRnK Tc<;fEA,~aQ*(5D0'ؗZdi)7S\GC#*RY7fsڎD+)mp(ĶH2MTiuD6CI"<= emȆVJth]e?FTC(y`%ɋ2fYZ\Dew]Q9wdAVP޶:nJ\ U̩C).`! MY`:J{Y1`ӆ!eVCDT'EbԤBzD7PZc,e'Ʊ"K12F`Ǎ  h-,>&v( Q%Èx_K'} !Dc|Nìx0jܠ~'2o1؀VkaS?eQNf+90LbžR`FU:̯6yV^D-"j+4+)&'/vΎLMxžu62`qrj& vY cTލc-+lND26n.TWUgvk-4kJ[ ]Mt "zRRv|ӕ+3r[lL[S4SH?RC *HFj[KoyϽ)ԟOw>Nҟ] l16T}0*5ݱ90Y7 L*>CO |;>VonI`xmiKX\*_(g撵G>G?0(B EagP懢L9r g#ާKcTL!ؘ2쎌zX Y3j` Ƥf|-UgUkir8V¶ NmH(sVlN(02r` c˨uؼM6`+C<" |n7[!-0޽)"ڃ,0ĤRO|{nJL$nPĦG g0~'cCG5&h .Ly) "|s/8}Ϻ$po`xKPi9MdlPΎK-%Fэ,3<>fjJbGPbD>kNsG0JƋ&Hp%|"kGL\k8~O>Q礡fx~+޳>cQ~΢: PhÜ!X&P. Q j6moo@8S@?Nk O~b@ewl4aRf,6qG mڽe2SlC?J H8d3m.tp :)t8?N$nn0 O. 2.  pрLO'ˆ±NycXOT pSҒӡ;aJ`,d;"̠RJS R jr'Jf5 jt VcJhƱ\]HcHi_K:唚.B*La>}a;΋`$ȣm>R6}>QO GKY<= xFlh],gO01eCZ")t0sRȿ"A(QNSWG3jM;Jͱ-+e,]G BQ KDT'$T36MԹ˜)">@B%pEBdMO4C1l`𻤐QDv)&D)x{gI$1:XQ3&Wuƒ#er`eJEH?R1 ,4hx0" n8΃}S\T(o0a!1G Q>r10H8O cM`Ш,:K"xu5d190}bvHR ֖3O J*6u_2?W$?(I)Ȯ#s+; :(.X`njD|3lhvR1B%QOIt~PgM8F%<4цjHfOv#0bua.ȃ'W%VU+X@ ě)N,KZ x,MH,wk 7dK5' 0Ύ)_cWc%)rCXcCnI4N3~"Up; wEnS07Ma,"Wfs0ȴWx 8Xe{q!FՓLL̫8uo摯)S1ln- e.NEkN10ڱQ,٪>o|34ԍs JՍ4tx#&NvyelD)i>%ooyǛ)P~vI0ŗFՊx*ҭ2Al/.ot1 ˑGNs,uuuT)׏+ cwTJV6nN10 ElMO砫fr^HhCH5Ndp7[^M>Ip8tw~ ԤDz) HwbL6nܹg0JOSWu:- LoQ"Q3(]Z[vPu',B) xF'/ȹ86R1axMh#>VQ7+PTp7!u)CF<+3Q)HyoWJ SG 22 JH~L(TLkTjDNL~9o B?s&' p,VdƤdyb[sEf' ymgĤU,dv(bPL]9DykDf@ajjU>Jbu (lj"1z&&ZBφ f8 cP D"94J]/[`lUELĊT}ĕM1- 1}RMp a%>y{5spћTIa^VP&<2:&mW4Z`gYrͲZ8ڎ-,Х"]0+ꨟ#JeN.[̼ީ&6b`{&4E$%ъ}~ޢ%!c* ) { V_}h \OSQk=1;vܵSh\FkR Z,g삺X'")o abcX`:E٫Z!6)dq!(hohzǚ|+)s9R  7- "%?#9 )I $ -#ِ)߳y$eY-EQR*8$2Gs(TB!jҹ*H!*+WؠDL"S' cebO̮9]qWܦ`ǣ̴NXN'5pW^^Ȕ}\]q>C_@vgdU܊ŇL>mAf[Lܧ_W+.)k2//D*Z()f(# x(#\1L1P> e >c/{-* u I>+ʚ(\ɯBݳ5=U38ɒ = SP;;` KlQ@*MiZN|• 5g42P"*&I]91/*0OC۪gX *UNŐԮO}B"K3wrBj'΂VDQ;\55A}\SXL7=IE@j@Se(~3rԌH(XwbycoF3*yK_"=samU҂XͲ: *bI~UTZ}JFyj( "QXɈ)q:ynxkpYI>{n:M1FY<9-oķbD(0z&wK`^+.pC+"|S#C]z-ȞR+$ߡ<1 ?}n}T{JD0RGBɼ1O#@2]wdqRѮxl0q-]7F"@iJ(R1#(9h%sd)#yLHI,D&0REa[t/ ( H.&5c3/0$=\V@W%ӧUi@3)UnX UWWlrh#(|T?Q$dV&;Wy1 @ө7(Ȫ5HENK͢}_ִmɵW3Y:٢R{5h~}C2rPBBr̝QAvj^HkGF7z J)j.vpd.?QJяY\P \k|@kM>!Twz-Xų9CG&-rҠ Wo 7Vuf9~%)sc+\ Ҝddxt8S8muq$=ZJ*E*]Y|F6p=xWbi][37/dyeWpQ>2`B [ >;L3D¤YF+'; +hUlF,>[Z1Quta$BOv3N5F3JߝK0IAs%1f`5Ἥԝ59|o]Y X: {vDPaPD}\ŇԐ P-] z|hʘЏ/O&ܓ[ ]x{yf5ήtǿU m @7%b!,Os_@oDd#déZxHZz(k &a3utyMxJEc[_{a\1GB&c@ڙeqR@;䑾>=-?&ﰔJM$ũEDBhQM5)l1RIw5`Ǖ]bl\^?DsT ZVd|}ݺҵHkB+=!9[nPk(#+JTL^59ޓr(<۫Lbkm+K9TNT O}D5x4w'~#{C{t37$3B=ӕ'yW}@?=qs :#8ҢY<*J۠(c.>6 7Kĕh&"&ùp r°)E>3p~;g+)s(~@ܠ{:ң08S[* 0t) (Pkt XkXǖJ|pʴJ{A C(R)"ɧLI yR֭R̕ں;16*F*ss缻J | #bǢ˥RH})簱1=``t5j;( ̠ #A8L}㕐*47:(9.q&bhq/q!˳r11/j3u&:EAAH "G؞" ŵ Gh܎\ 7i1 ͈`t 1FJ@G:k9따a>A0aǬF[W8:هH Z&>@<;!:T2k < sI9@ DK;PS$0~@:s= 5a 3-+jA2T)3 D5hq05)|✪#I6+`>ɒ`LW4~9Sru 4A);@rOl2'4+%mË\?ֶ1Z;4 ̓ ,8`>_yD|MJXj0vZiTLΔ6¢ r5,;amL6S$F 13{F4SҔ!|"`4_=] 3.] r<;;%̂M3ǻaPlﭔʢL72Z!&7K/g{dڙ"SYÆIһ44,,:@%4{JM+.YjлKRrroȍ|\/ƁʕyUȧZ0c,2ŖSb51S/-f=vQU[\DNEs ijW*h夰}:?b̛ u+[$Q |&-+ۮLu.zف``bʹW "eMҸB[EHĮWJ ;:MbX 7W]-4dƵ[Y%:MbI0E|lT9fZﴛYu@kV0Q|B ϋ+ 29L:qѾ-֓ю&((0 8ዯV2%վk.sK)|@F\@SWbSYu)?R-ZETaXZ\ SJ^2Ij4d9$ yt: 1kYNf: MjL,Q*+`~: =p,M=̬벌=U֏ 1D'ͤ LG8ܪ}]AdW*^]L/HOrɒ<F&8IsK >r>BMe/KDR]eٓI:q])50TA_TLB:$[b I|GW_+=1 *4h+6mr[iB& S{spŽҴV0ذPy?oE`;CT+g{p4>AejM':Ihdtjv-d`><=jO4BQ5easZv+r&ۈâb4uIgtވERXbViĢ)ٳs5v28-)z+'4X(|"ZFB[@@~w}Y-R,&2۴+bԭ6-tM vTh :B̙zhxDh4+.d3*6,\h hP} ΄QRдcÓ~C G6vPa!g ېЍ#z'DmwG滼G*& jp9b寷"~"6F ,Sxz9$7;b=yW41$'f'.W(e~7 axD jp-[ֱ--gW& u ޵JǥΕϜq(@SNgixԹMe5L؈A`@+CapE`$fB<~?dp "¢$3cҹ32F`7 Ncp "M@F*9 AhPHtM+dD_GX(x4 WGQ&o06s+aa(=kbf \+Pݜ%7x&v7lE'pS7k9ȡS] Ęx A*/.ۇP&tTquUkd J n+ ԹMޤ1,J~%o 61 C:!ʚrAʀ  i*M5ip,L+qèr!(C~8R #30O l'l41J (7٢?I3QI#6,f r,M̀,,Lk_O QGD-bF/}P&j|k1$UW*kΞ͸ r &#9#ѐñE!D=_%r IQV+ p> 0M0λ$Ψ V T<2*أzF謭Hu|*`VhՒ}o t[ $K2O,$zjH p;$"g)&<wfvuVPfOZ/Y缼/ZumW{=8t:C #ϭU{a͘:_tp`Qbp\yֈbf*pj@fk,# ^╝.9 n w8=k JhV^-4zM "C"  4>}C+/RKCXbDιd5b6$S ["nA*o4IcD2[FcK8˩>mϙ톐 /M:J50SAtJGn1p()AL##4Ԅ!8*ԩfykA¸ZA%0n&$7keZ9 AdH8y6e`[ s؞XQuU3~(= |IR0I"?0t +fE~,$Ħe9$K{E0 uin`b"D+N䨧"vxe$PEĽ6![S,lNY}ND M7NjPiGYZ J) JQ 5jJ<3v*uqIZ]VΘ#R$?1G.lLg#>yu>wCbQr 8RGy-pT&RfO|UT.yж7N 7DLOdJ.!̳v0"7 ._ P8$: cܢo%نrTsz*ư5󖶢ؓJ"k [s$)u=|bTX}*c 8(*f'(Jv)?D^H#5sfe&y 8TUwe$G4F*XbyZKW1N MUUa/$_(BkX'J 4[uWO!D뛉RߓxH,nlC2#9n a(@e{3sXe)9RzCIKC81ȁcl3Ti` zwt*Ϲ鬚rd5t!OG}-l\[h} }4Lj'0Ip ~:IuW7l1"8j>PO-<)R+0fX[rJI"hZTBu&WOй<}D5{"->Rd9k'.6_{k'8xbU*%m^IsH6 D5 *0./\dۛT6:?R#-i/ +nsҖ]ueDŽFL#% gОY!O( ֫ܝր [ԏf\6oJ;2Mx |pbgXȵz| RxIY6`Ox  O` B,#PXĢ5'IeW)H$޳$9hO$zG A(0UYzO%bx_}d܌gH(83DZlr]+"TGԞ%OG'H91 {"UbX-VE$;$sa%TS7E11:~)%7Yj5؀ppo0r|jK|WN{3~ԞϜ?H)c5%Gt#l8(<)/@2)F#*1IM (  ཎJAK#0l̀+ PR@;LD$ʉ QBﴰ(rK⚦{ٸ/{g"QzƏ&$mi&{:0T /f"qmF͂b۴JS8{),*$B;P %svHHo )B 8pl0K#ʍ=OP"N h$1CXHd),=G{IAQĔM|ޒWI#}uO *PV, !DXbU,+&l? #4{ l}/"WHZ(827B?]#0?I:?dF 7R$(FJbDE$],J}y .h@vM2$@ȗdC@:^Eqd2G"nw՝FiYvL0Q$Uoȁ A\FUS0@331ktŤLN5rx'Z t2JqH*5(|Tep~}7tI@`!t@$JF q^SH*tNT8Q1D8ySmʙ)c0BC RSŽ4#y@q&-.2؏d!3PK!/Z 5C,Ub$[9?B$jbV f@RoG|g,:U H4vPGcf3v<=jy3Wvo!e%'\Lܭ$l~гm) /n?ckbdUJ3}H.+iKU|| #˵ћ $CYN٩D,TIojIaŽ 'AA9 ;P4ajD}i5B،{R#”dD'dQ|(+5*44Q4j[0?hV*PQDPL F${Y7&߃ઝ4w)3*͐d="FH\?Pg:˶XPbd&C{vr3{Up,KXFI0'_~تp͊5Hވb 81?q<7e"5B%b=N,QfiĖ|:JS{+|;bS5a)XrF,`g4ꕜ~=)cl\*irjɈxa-:dljHؗ4o$ƟIMWu{@0uЉWeiA:M f9:󜽷Rx|B׬o|Bgn&2(8DxO1*n(% i+8 H8"̈kKA0fRIɚfӤ4 cDqnTMr E(pT\à TeĔK^ib,fg]0+w HCOj\e~Ȍͧ&"׏2xڞF؂BnALw07f"N؂hH ov<ˆrφE̼ .a.T%mgɄ4%Kk41(ŴJoVRHт1ffFmUR,ݍ ?g`X` ;NrDFLj1$L(v).hct[e*r/ in+Up4HJc1%1ְTE$ȫOR Λ;Dcxoo@&}h} O CčkRhѽ1E?c[A+r>\N`)*i4o,0PUH(6n\":Ge +c1y^H"yXB!l5t!vh-TO!a \L&Hܗ!0oPFhp>/۲0ӲO"6<N ɲ;Of dmH!pe 욀) "NmĔI,5(R%VHgz` :O^Rf3>Ovˊ|PjrRPKcCc%64%HB#Z ެT4FHW(x$D)4̴2a,==So9^WI^cPu+ Soʿ{SNbZ!>Qm恑5%qP12" MΔI:Wj:mp`k&%pO\R 5plRoR#lhklf' s ǀ –? 4v x&N)\>ӲG4eԐ8q˘ NYCČ 5/5Vf@K + bV'brR7Ii&ԋ(a׃y5 pnC/2N)Urm 2Kwgsv$H5Y*KT@#Fw2^R8+YWU xO#[dKONj4az CP78dg)қr؛5Y1Wv06pzxV",Z`OV %z[#{nWl$ƙw5Ĥ m2W4= $&"϶06nY2*I3bJ%wYuopkKQp|0QڪoHa1b7@\LmWӊ6utx1@jJ(uU:BV{V<ڋ5K/WM =w[EifG/~JğMNdfa67f2 L,C/t >-F @2 <X$w,YoTiXkj=S 8xM}rI4$9Xf2`zxJ` Br0qm+3mKj%V\Yeo 71_p;6UW JhK[5m N@S8M)et0(TZ,hMѯehհE)?S'HBdrWn)iP_W{~=K ^~aO: P%tKt;K|| 7>G2ER 苪,*ijK " Uiym1B&3#`QmX I=3JB{ϒX̯%\13o>%t~ЁBVG顧0iJ&&t[U"h" =HPb#(D1E@ IHܮ) $X|Ms07"}2(T)$I rJHS 'Q(#{?pܺ gՀ $Tb`-*!c_+"c/Njknbmc9TSEW u}oH[ W$`4ǐУxk7)%(uD.H?;׹?4oKl .࿢]|}}ЮpI}>M森@GN$ 򦬣$ 5L2%.#m }6㢍z,(SBH(KꞩEK ,(贜+(d>52ޟ\Oo E`blsY>>Hs7JEA~B*PR !ReW{xix(cr 524X "mAT>i)i,2tlL<6XLKQ#(y57 ͂Dy:|Ad[$JA UjM]›@FiQ+%6(͘(Hlj [af FQO ;欃3ѕV !]S؀}:LM\~Z ? }S)BaزMJr)!-'Ehb鱇9")Q%'iCTSc[#pMϻDDƵ(YEZ D |p6f JX-Z,1@C2}ÒC'|-sKtJRVg@Aːm&KY=/*Vr%]Ce-K);C aBɆ"" QEq p@j~SVGOJ2 Id%/ڇb E0Xdm:V$hQ,͍h8Xr k5\A4Q4ELtI*9j(Iks&JA VdvLFzx .M.`F^1>$qkB6f5q@4do )zIHJԟqӓFϧ&! [Ga攕iP]DjS [Cf2RH\7 ki9N5hs1 ,oz)ۇ-3U!m | UBR{ʷ f(tB³YgAx:YN H? OK3!ǽeo/R۟zퟌC*e_ju_&ck;4A:'~6jipPkw./V79pK7NM‘tя>./^petZQo1SsfJ NHYO"RiXHXuM*zR0e;(l(t5Z$L.893=&/>!QE%$]d-SŇBL1}roނk~N8}{rMon oDWr|>C'2S@U$r E(-ꎻ6?X͍DQaW]~̑cG%rFޛy_D0 a, ̓$r88}5[J&K"l z8ϓމ0,YA12?UBTѨ>:qE 94p}xH0tMApѿm@yݟ5_#` '6:`Q]-Sؾh>%>MLR&[?Zf=t]KC]+2@RΫb 2ى<#j4B|;4C9) ;A]0:<ʱ*HW+0[ ŧ(͑>= ]Aůl2"}q;ĺ28(J9OTtt6MFjѳy +@X1bu$1 8-&I1QK<+,T/{^O% X'"hDx&ؖQ%8J@ -$N?EeEh|"LQ T:}na`ec===HZfaG2_1x-T@"bȄ]=S ut|Cʸ5̨~OZ5!'Ch}9? E d7}d8&SPv1;s"'SW*jHC}.e,)=RHn?~[icXWke5'u9 6\5sNu>~;>70B@?:!~͝,Wd Rajg *U{N;VEi*NB@If+y8}+%M:\\vP쀚cet[W{nO~!RWq 8kz^CZ6>ۨ>@Ժ̯ vYl9ڝ* t.R'=RXF2@vRYGsr)0f.5 /p e*62 )=#xCaiZv[ :g=#X%-ċSeyQ z"E9r$:9ֵ(*gIڹgwP QA\W.~&X x]Rk>^J ,c/w-vՏL\Vt A_w$ C`X1x{5c#}cWC |Kdi #_4Ob3HCgPxrh):'$F9'M@9k#X"ͦ4_Vm A반4Ub5W~PZb9i|(p{+{,R1i frp=1Pl2=0G̡iGGCb3mJ`wrd;)=l-;ixO. doZnco)4Sqh(:0?+ 12, څ:N: <@~i ClbǸnB *ø*HlGnoPI jxQBZ%`) J@\Kd*B`C+L(S*oP#h,3sq"-JZɁJP*d&*C";LtoN4rF+oIμ0*Ϯ>/UbL-##l%0"+n+ʩ  *WZ<)ѴȬ @ҳX+#Ν8u,\N@"+YG(J+0@O}CQFE1(T #/jiRRT 亴:ʇ6K!u+!2f(ZH:ta19M=,L셁{|haۦNlO]7x>kRkN/ю)MT~'7[D>5.o`$S׊31::5hƛܰwJ#BNA Gk?~HZ:,Bت1]俷tPVJa!q?qLIf QE.>FBLO R7JNZrTM[IJXLcRudyl2ne hKHs$hJˋZ~rNRjR犓 g :d  ua֕m iDѹQ8M9u Cp Ms 2gt kAۚ_jE32!Uk1~Zˣi /sUDZiА-⤣9#)bˆ{zDʩvt-ݟw4DڕYlP|!I c=2xdZAnY2IirmR:u|)<љ!M5b/2,A0*;or8&>q4%*f@=b*}->K)^'9g{P۲ T`L:gqBehkc6MxTj!!*%SRiIol#4\8Ck2g ^PRĔtIigI|gZ[,LtmlMiB )e.NH=st!$XA&c ֥YY\ <HjdUT4:>0|-Ώ̉ݲsed&Au8$ff=R\@MjS)q`%I'PwDAF][2Ll^y0qlݴlKƋ6Ώv/1ެ3 *{aLUؖMDq' |!w?UTN¶X*i.|IQ LSOނߕ+@6~D,r1R*7d*V؆z"F*MzMi8&.ࠨ62nM2R9e%&R``X>fbO&Sə\W}$hc&!Xn?Ic?Is v4}Vl`=$m@_=b{oh}PJQir Bf) tU[#%UzL);EخHwp,rg.`=: CGY QN[iǥpzH}`/B@4z=Idw]Kg,veU{XX.[RsMC%kjuw]};FT=;HqܶUd6EyWáy#[9zvdYN葼֫J }ACw{uBF)oc\ AeN km9tB\5_P$}>.u2jJӗ=|d qr)6 7򢔕3ywU*U)Z::zMw$>n~DbN.KLbj6Dee)rF ƽ` nF>jKRˊIP&"I*P cMeXf2p~n f_I2(P)d9dJNHOl xK& v&ُ>Z-'t*K(IT$#Hתs.b9,1 OfZ.2e: B-glI]PppFE%$R0g?N>kcF&$&jkmr Læn0'z+ v,fZGFbQk:'RĪx"F)ȼNK-zm$b0n*,*h, hM4tJZ- m1 ",' B#M4F$tQ%N^L J8Uh))A qi .3&"#j W(dF0"H,"lrO2)6 >#i% PI2EohcҪ.Ry.eco1*L%%jqȫ-vc.L̆m BVya: Fz6#S 2q7@$&O2QP1:i|(8h&Fsi7gglgL.6/$ >qO,.1e^Zj(]8&lc6r0!> 8ΥŊ!!2> )9btyh-͔#OQQ.j\mhd lR@: G"ԮX|gmBЏ`B҈2I $HOHI@f~}r7Z2=Al nk| @yPO8Fz1Ƅ"͓@),&Z6.G!6D>gbM@X»R35U0 '2|8 |)jpXZP"=$()-S()MN (=3WLJ(&g VA)n\~iG4?'j% +>cdTe/ĪǤdp<- Dhk>Z.g RnI3BSfu4P+.e}F"!(f) -A+>YbTpSE%OL԰tlI^4ӑd QC2&KFK5#bm9S6 B6OިTq~cRecbЭ2S 2#ndN}*I97 @54m C"?4eq=v,e%(H]IT<ߏ̕2h[685P3K# l IDis(+|yw(L4YXu#Rg%'qUkY"[V5P KBbu9S'2 S̍/q)b1ގ?ywVk kIz#,B,QR`NY|p" 0Ej6A)59QeQ2of@s*ktD31THjKj9p,ܤ"$JZQ%kE.&,NX{l.s&SV%fWuR6a֦8zX1 Fͣiz68+ B1Be\){w+z9m؆,\eSm%mÊH߰et|6&'ī)( ,h4-1c`#UU&!Qqg+|:kw@fc7-RX&@ TVK}eǰK'8pgy~QB"cFz\%g2u'-=ZpRXbq2)`(E TMDƗ:"!-S8ݒM >BVSFO_vޡ[,rxm7W_>xXwxYIsP  B<D`^8*D@QX+)?c?#2_,q UA˧P̒JO 6O!rI%e.fGeiYfYF V2b0 J^P6H6Ic>^7cnT۴)?} aLG#pjtYMUb1lspm_a${X#16,t;,^_Md=Os#z}=n{\sb>2 2*z#b|K.[^7\9N -jH*j7.) "*ʨ3[`!{4ǏT.Rd7 _6((΂HȊθ3:^'6"T |D z lU*JI@#B  *X̨"_S%z2֧dF 諠E D<'SЦR7llHCBJ m 9x'ѳzq 1qÙSau vj&j~aΈàTQE~Qw &|e:?%(-m(`2s.BG6).q0w {xVG8@e@+Ƃ, }6zXm:-uX. S< KO޷b<FS ZXn.!Ni!\yhNͳэ/tE]ē9B6j~uSw;'kB{~JCB& ".r&"?Mǀ݉pVHc&[M "^!}Ѡ.xZmlYMB t9 O9|C.@]٘.Y L:@{@ё5XBQ,bi@]/}"|R$?cehYͦsK!?t&MieLD#6ֻZ>G֞ h%b;}`w<+A % "*@F\ #Hp)iH1q"D1.SRWI;rp I~ (bZ0(Թ,+dW^}TǗ$X&X6;^{{).(ڤX!9^GIX ÛfiߙK / +P@_+d 17PLRr.h34`m>i Xj0 <\PTsG2%ʒ#i"0}.P[pvHR\r0^]<$>KwQ}]oPf2 j5  p fe%VZ`B߮ -d /\v):VĘ$VZ!':rCV".bG/2D9'5whAQͪ+#nt@tu_6(qW"MAAxGyij9nF\0uZ02/4mAYL;u):+a"8h;ikPX~> T"4{wAmBwzI0u\&l ٞ&L/İTDmXOj#N",^|[Pǥeј@C}҂ºјgC+4b!|E̦y%8Ϛ `=RQh0&I~euB.]#kQ-$V3:%C.e dFE ¯Cpjm=6SkHBjbπ&`WdQg^Zvd MW!Fe "䚸J>6J_=3*zBe-F{kЭ :i#?hmCD%8 B=CW?KZ> `B~ou_ >i9߶/%)BfsZ[!2𔄶3/qY))Dq'3c-ZѸحZlINIf7G0 H=G1TLeڽ.p#.3\e}E߯'iۊ=BVpJ»x.I4@-"ȴ>j^+/ R[zw(fNs4f>176mM Jʂ<_iO nɢS}lJƏPbU,kȈc9j#j#+³/y9A30 k #|?T9òl5sW4> |98z8i8{ z2Jz aª/y !} :>H;)8RjS#Фio5C`I1p"."Avd9"#8$i0d, s!3d:74)kIvb 9AZ1b@;A$ɼ֋c—-qW/#b/!zWzŪ;:0-;`$k'&6ѱ*D/ӣ2 l" 2G[vH^Ʉ1#cI 龌ž3HaBW&Clǵ S>R xn#|4)# Z B;8w@(Ӎ;B &d!2Cs ; D:Ê+˽lIsA=wcC쏊J!hM-\S|p~ܘDڊzw bB|#S,plҦd 0 K}4kZ>J+iD/Zѥ{L| "˼ZClK S= + /ۛCa9R0ArjdH,<WJe*oΔ|BĽ- pJh%Oh=KF" dyǚh48-&I=m>/7 k!x50RRΈ8Bm+n B IJ9P ,q|ˮ!,Ș+|ʪ:H*$=O7RÍ?ŭ@~i3l39ƪCMIxNܶOW%Q?!SodB12ZIq {>S%|-$"t9"Z2|<5wC≜=q߈yL'HNqqy>trR8ˡƣ" Q}N 5W54سP8⪓6쐀 sXDz@-]<3Oy#}2{3 A) "9-/:I 'PT=**{, SAP89Kw찰"7LV*rMpHu$EMõ 1YMɲ#z[` s#bXRBY^Ǥ;SKDsS2ö~tD3rŜכ hѐ|R~xZБ]3i>E] hDG\2" >>-aH-ID7ĀנpA}hPQ2UY`vZ|)1 $2Ʈ:8lEa"ĆLʬ\\G@.: #($|yY6,>`}W$ֲ-+Z$ PfSIW=F% x>T31ތNӒ VPIcdb4I{E݋XD/3$kn.zlгb&-_ 02M <*@9]& "ҿ3V|vE_*"%Û T:sa<$lv O!E\+~#,k)j\$8c>և78OkMBf:슰 @ۺ?CD;~`Y5" Tpb6 ]$qؙ{%}<6-9^GތṔf+ M'Lcx'XAɬPқʝM+rE]3 b)>2k'R>9hsXU1Q/4'ADT2{"\KaIZl8*RQ 92B-[ZX)r+ eֵXA] 7TBWP$rP_-WC*!ֵ泪<&Rc/J&-ȡr;x}y8drȪ%M`۬s/b`x s~ڪKC>3$JLsoLueP_;4{RxGè6>T VF0ccPX n7!), f@V(bbK*E\ɛ3,ȱ*>Ž+_Mbkٖ(^UJkM|&X^] o['ot8a W6 I8AVLqQ zW8gj3EzDI#om4p3<4&gZA"5u,Ƃ&gMeqސ"+v6{HkLp9͚Hb@f'/D&lB=oA72CSʫYA4IJ6N褜/H¨sRHt\+C HcN  N]B(Z ihu!|F.v#t̊0OL9fc.T-5?_5Z v5CyÍL∆ {8ߨwEf_:K2+^>ɲ"̔eJ=HjF:I[Ϥ}bRpD%HC6$E?^IA"F$#2Hc B*Nep܈#hoP7go.(FSz"Эl#4Ѝio2 ihyCB A=#^'ZAa?> " &b<%(ѡǢGM0UY'tN)B۞VB؅OW4.] X-$B` .?Ґ5%H$UDɮ;IrLF- <&I:MMubm(,ݡ#j-$7tH%:5tN.}ۏkxԏ"-2lh4-ƚ?R:s=T zf?Ddr<|ڧMk5#)G׹RVRHdw?3Gƹ%OH,TCqoYD$K~)XMOBaȺ\ ,(-+=n͚:̳YYhRJ6rpKJm-&N5X@؆%V.˥F6GL{U@F-kI:6E.i$HS\<X<4T?VAE޳ۡhlgw\JI)(Pif>}Sl#4.,˳e:' " N#/vF)JP; لhкɡ@4x2%ޘT\Vd} `Gw¹_KmTOWnG'7^X5, ?<ql:\1/6S2%V@ }[9h/FX##F?ܹ٘v,K+)JSPQ(Zʚy06Zz. l|{[GZ3_>GVF)U#;T™A@t RS3Z RK+ EYgCciCX1wkTGLn<{O 7haUF8 ETe`[\vqd[-,]瘳85io>3*Hr,QX^H?1d'+I֒&p|+ ߊE:gX#/Sk04@ سf?mi/Qpln9"#KĉmdܹSI6U;;q5}ly <\*|E4S*T3jɚڴ] 7̪ҦE8w[1PȒ3(̫h|?6 0Β9K6'to*"KTCNq-$hmhOXCfb,&\'NJ$l:-DC$㌪(!M{" PklԌin)rc ҊˬoFsFHQ|`*)I&OΚ .g&OD8T;MbB*˴M}.lM'40ObnZ N.~r)ҧdTf DXL" NR-5pl] d%fmfиI܉PnƑd$GBe͍HGF pp$&#螈` NbE""C>fB24FtXHrk}FnZ,=N2]-@f +~vʼ0m* ne#KG"D<3BDe*D#![zo)'H)C.)n)1&Q!Ezs>q f>-Qi-pv4 īd" ʜs0lNtp IiL'3Er Kxˀn7n#lp2OLF Q#FJPJ`Q-GokA'FEftj$@p+.0jhgVfhˎ1đE;%p04m )MrnĚ<3H [\4°| kXL'%'᭪ NTr  N&Ѵ!4+i9 Hlʊ`af-H7%VjjI ph0Ou†Ft1*>#gR&O" !ʜb5UoK?Zd?6I*45QHT&X$Ȩ.%r/2F8aIi-PPlO2QC3ͅĄjԅ,9OG]Rxd.pquli ʁ&u!%)u6)ĐcE5PvO| 52”]K<#d5p·w\f킭55;*lM܉.,VVn(WO]ds`QkUJՔ㓺4O8uQ1]+VBOhs4`vRD '-` - GcsL6U$ń0v3Q+TfS R}W fNg1O< ޠPF6f#M %]:Jrrp- ._hp\6SG̕ WX?čim@/ȦU0B=MJ>Ҝe zQ+ȝE $ptQ;$VM,p؃rI@ϱ;LZ.um RWR;Xzzi{"҂!HMb 0aw'{tc7;)z|e+h'hYW-_m#&ڊ( #%e nF%2gu-q{VG~/ [(ЫU-Gv[{ 'E|xgF"\/,H88Z9^VYF|Q5H"L]TR#NmSD\lL,p2Qԇ5) /$0؅4I=^VϸǯV׬8H+U!oL {〢zGφEBCDr,p#|=CMX1\@y0 HMvl!FkJcJA(CƎKO+ݣ|dr  8S="x(@ϸ:G*H?%ITD#4eXtEr@TR>p 7AuNZQ(e*IM&/$/Y @Nb@z%GS% }H0j١ԩmv-LX d% -sJ׮ _ V@xE9C4\R*=&MR-RgEGJ<5t!O*Q<A?D &-S'2hb#\)K "RϾI ? JȲ>tH b& @jT":nT #ڕ")l Įв( 1,P-tt;4)S)jrL'*#TO* =!;?s: J'+ 2R0DSjêd6J5$λlj{I:H`(Y#Mt Ć<`-3Ȣ]8)RY|SgB:7g]ITFBHje':q~Qh5E:R R] "ZتE3 (UCyЬ6HSB! ΡKZQKxJ%ohg\u]!dҪC҉%dK+4N l\en (q`KьLPꔜ#1^g'0O iNosp1R{k.k< 8)M\ۣ5/34\C˹5ni)ܣ+mkao6Kݒ3Z K?٣Y }gfeB(R~2R~BŸJ-wXzg>&HRfQbNJ;TOInb(`Vm㹕S@g.+YRdWH+bH ϻBVp/"P7fˉ(5.x0?;!y>rfd:n_#ܦz(f#i)eL E3PGɪHqeBtl_/IXu sb\#IEf #Gi^$)"]Df dKu;E 9pЁu#fT2jJ Ѓ = 69`0K-GC KMrPeMy0WӳlN%JS"QbJ0S<6LdƇ* ,Cq$J MWRXV˳ E(R(g3l֕bEJ󚭾jF4Ir F"(,*~aJf`ȋ&Pw%L}f>zWWE de(4SL&5E_jbjB 6W *Ihr&kt,r>sVУHQˋ}HC!!|SnxFVT T3cbed{$f”fDN("1lYHTHUШ@@RހIXpŪyJH.3PADڨY/ʐd\Zn&TZlkvӅIU09@I^]<E *Id`*P R/އ9\F?^bVl<2 JrĊԼ_V%QV6u'Y̑EuRpmT7LQV+W sJVv!\f>ZT5z.Y tkc`'[ k 8Ր#$V'{Xw]G~q ]Uݔ":/B{G.H~KqT %W ݗ:PI$ Ys!UF_mLPI!ҜGIcc{V̺0쌬oƣA˰mdbYBne{yhJ|]ҙ$,[|vp{?T5drTE_IЫ:(#ń6C=OG:>ЦnTU*8۵gC0S-sJV(͒ atl{Cò;֚FR7*b$O±7w +ʏ赯 V빻Y\P&=f٭HAWq$@ ".7 h,Rt kLK<`0s 9|%ЀBѩx1sK Kp6kh1m7H#jv~1>;"*RQ8$CQ# [i@22ж?$k X'YZ+/BV@/r(X;B@чۛ;=%5#};4ÎE pZb:$ '5!h~0S"NòM!3A; -4!sgqCQ b?yw,:S}b*c^T.1B 1I|yȋ0@F*"j@,lr@\Y:2" zK#>T#K+ $[rr+`+=2B8)B1QDH#jbT8LRu!1T'K$hyF\Il /4w$*#I-pë'IT%ۥ̯.@#hmO6Ă9j@ɠ΂,< "S&䂮LGpRN {g$ė/9|8E@ES {Q*qmК GcJj 3Ƃ4+و8Qqԑ#$O3!%8N3O ɣI8$G$3 C  O-5a?}8 +( %kPXT6a:֦i* ?4,Ȓ3DEaf#/ /dGzY܀NZހ$6?|GM|',I|Bb"Ϩ*Ύ/2*8~(F|2BV l3D@+lk B0)H#\CI!Hx i (@3);/D?D:j r, LlDM3bEyx;}B1AB\J$ɻ+(EᬥDI?R/}{iR+שvI1!7(sEiKVz a5(/TТS"٘~D@62ùp30T t-Brj}1ƌ2R@,ymՄڌ9t )[Л} Fr r/} :YyX|*/5D4"\I|\1K\Ȇ2Z:AL?KYl^1p#JI>n 2/^˦LxTVH +bhO];0<,(8@CVU b !qތlDE`Ul ,ZMT&'"jã]>oa= q;X̡ #t- :.V `Ss"F;w@mABEkLp1ºY9K1Y-1R~3`^++ݴ+I⯙ (3b`^}3]MZcR6Q ByUYFΘ+ ' pCkBp2*G;Ie5iea<ڣň^)݊[Tb`l)L)!a|XÉ:i]((e]BW4z^q$>3_pj .[fL!t&#mF:4gX&Bۢ2z縄90=Hd%QCI({ ^,Q=\][1jIiS4k7]Z7:Ġi ..*?+<IU ܞI^%ܽRۗ-xVlډ5}Br CՉD/#)i눥 i>FdYFTE H}$2I}W\t&f'Pm15%n8bqg!sN BO94*)rW3y4F`JQ0R:4Y[jڛ)!0‡LFo0luҨɋT_vTt6Z<48+X 1\Uf/ :W߯ާBuUPX'X2)mHc'9.Np!*.쫸!]+>Bpp |\F]v!ݑ:*cJHZBfN<'K$aCu *@3 N[r>#j2) " B:Хj22Հ(Bx+~ӁK\+ nyQɭTzȐȂB`x~2#Hbrȑ*x|Κ-I҄?|$%Ks*,$-hy ugH9iY&{%6Kd 7049]g[cZbDsJ(regУdE%C[=6VWJqA7L!\V:j)83c 2U'\zMj8 j N p=6CD0OJ!WY?}G$ĵ o~taN=C-Pu sf ?@0fPD _\vB&*Vq֊$5kD*"!A`\O,̹Y*a7-AO65 \` %ǵ2y7}xw_Ra$ؤGbA40G %Vy3l\  PEGP\$(-$tK%ޣ"eܝ_rwwŒH^FS?&aGX/xQ{,]) <1wLjL^ ,HOG-(=iELb`ThO%h_+j,$G٦ vO=&/9+R Ƃ,@ԛM9<'^RM=XdyM\8 0w7;Ei5t8zcEttcQ=e XcKmxAf I 6=HDEw| XF ʪQX"9#&)}YV6e*]宻Y*b1m&$H9"v\KP D~92RE#݄71Q4xM"ri?pMUwjވK@,B6 φHHGz?D CcM-i\)tE{Izy}*\PqojfJo8BseE;Xpl.|"DTto=(Yԧ1Bz<3>KsffvP}Ɲi$uU-rIQJP'I^W(&y?Q♑19 dkr.U+(U8Œhx7 JNYdR"߄@4l؀+Br@_>r_IX.>٭g!Uah0.nXXn:H=Sw܂#_o]=rbJ|_{542՟;ҭJ%d+E,\sàJy nY1WwU$3sR27{&p\tɱQIo ,H(>i ku-Umt}wv0e9~9B証Lt폹#4qEɳ,A1!/iۮHGKT]5w)8VJmM S1LDUy0z?V}( T|Uځ\8SmzDmU3lw̜p)jb,xZF) ! ╇-kF'C=Bjap- hobLG\,dcL i=(^B$ǀ(: ɫDeLk VH48$%vvoK -RFo f6Ȑ MօԘcH1Œ>DJ|-D#8I%cX XDV(lAdK^mdj>"Ϡl]P/H۪}xnM6QJ!X2GH@mhp\JLH|KuA*r6NBzNmIEV'$^EC`V,<Km9k`1lIQh6)zK&EƠ `ɽja#p$090wԏ8_b&"ň(ɸyV )#Mf1f/mvq'1 /z6 $˥6*%k/٦'"~B\J(Tvᤶ.wl v l&׍H~LFu '@n6/:qk0KTo2rUg \kNH$ s&CA90Lק|b|X"~-?b$EJҕHj>KF1cP"O1ͮnn6 >r93 a0y""j14|dFy1'(֥>J{1O@PsR5Y038):L2$'JJQСX&k bS: 2 S dw l!cxp~jExnTC?u9i+蟦l,l >P'i,%/Rg `:tF7b F,h"H|E,GEA$x #F?5r()6OHS=M!)"2>M2-Lzb6$xَr"g>¼ ]Y[H xnxjfsǯ5\+<l-ѹM}k%oN)+*IXxg 3P Lz)S J4|\2d)PQp'0bK)>Pn&'kK\+aH'蛅Lm tTqC -J1p$ y5>U<N?oԝ4dRb@f:pF/]~IUMI !Ncxk)*m*UƉ KG,v3ȷs+^DɸIskRƐq""K/.3Ev"U"Oxm 8CRzxN}z 瀎\DBM?VDVE.aA SXH3q6gzow'ɖC\O2guX`w}y 4qZu]d&"6^_-y݆ldKWӋ,n}fD豔2ҞT/RD"$P "fKsDƊ76—I{Pp2}UKAGoyH(tzḗ:P%7+p8T)tT\0dRQKI0,1і}ta Ӱ1jljDuDLGff vS-h-4.Q8Öz$d~xg3GRp8sAON`nov2&.CTL.56w0p!Ƣ R1 !yR2'5t8D},Ηr8l}~BcVl㓚jܱPwcQm+kI.(ц^ȵT}eqܰآwȁ9bJb:"r}}Jyciy׸hŎGkFLƌA6}vgQІ5{.~/`z}aebxKIckE%xc#1=L 6W'cNmÓ5V280<눈(fდ֢NO >> "V% = z 9ƨXfY@+(e^mG*cWS\[Cn$4*`ET#jI?<44 t٘p_~_Bf*iȔY&Ys,L\\U89nZAa0mz#ĒX$57srRPYm 3?!b(P 㐇@ۑG( Fl L#,6|N,A >a &JL$x YiqXRCe`=m%DUB $Y]NWi)J-Ql4"RZmT 5PF#i6J P31h s u[N f E!-TBEZV+7'+0ުI.^w7~wU{#={ CZ(3:@5R$=" # SK RƂ/ì*$dO @ DV* B}2ڣ(?C"GЫ!R  $#,*\ J-#LL "*B80$j$Q,`\o=(<F K! ·&&JBDk׸T ~ʫ'v|>BV210ʤX`1`@w/*U Q68!]TpAvViݎܟ+Si솋aKlDL|`HT{ȄbDp=+#D~Jps\/zJȴ)`&IBaLZ{N6-dZ27T/;֢0|@kpbVײp nʂ*ƁgG}7E֎m(ӀÔN[I9 W*zm7~4 [shܾP^KUT#0s^]*o R-J;ݗ >JvCEdI!74fٲ=ಣ& =_ )p!iT LC7n]:(ˆZ'W?Ʀ۳xP U0|k#kΡTȿ*!E𭾶r4 Ӈ|i&X.Hz= 2*ᶲ GQf%"z]ITHVV5I,~EZ+CT yP[CټJwHkaG|ܪ~h=Sz G,y[Md#s+# Oܳ,S" ? |Wt6гth=dl xN-ܙPB{QX,=$VS h[T.VTtZ&-@08 :-5FGV5a葃8V3HUZGz+4,t2>IR!a eh̭sХ9#.> b?s*/a$ɩ9 3iJh̪i%xAKiU @9y0LD\>JJg&ٛTzaimG:wD0qn6 Ve!ZpYC)J%@- AGoMb[^JB 9%n0DE %RQzm⹀<'JddjoI>8T+wgsk2MLt.9%4T*y3Osi:%nJ'k M̀x~SCtCşѼUsI׾$[fc"=8t(JաT4O3ZrdufW0S-D$Ev:pMz!N8rREZ:ءTMgM޷9J9g.?4DA84[6WJ[ƥiM=W8 Tw8 - [Fiea^AtDvzǘ(aY;k٠,i& aS>S=i Jh.vi;'CY|޲ |$ bV($"QFKA1r=$L2孈oHaZ R 0x}cE&1^!˿\ zB5)x̄$Fˉ'{ x= kש-3:*ZW+dbj))+j,'  *꘡}:ZNjEJ[#0B#6r6S֥Hڡ4:-4#ۅ d|Ia'I2ʼ EEh)H7Yɠ0Bv2/1B"|; *)̢ >1?{ĉ1rPSksX?Y:z"LبȬ0RK1@O)>,tC{/5뮒YD!մP (y*cY" L)&sW4` EHI]@q"H:(9LFDQ,C@IP| ƺt'> Q@} 4%G'KE Ox4Q+8~I8P*ɺƸ˜!R<(lD?C#ȇ:K  )\#,L<Ē(䷙ܖ2,2QJ唣#<ɿI6͛ )pKJ O0l?I";M=4Œ#_1 +P|#ta6] $FA)bkG-7 >EyjH:}g ŭ76:OҞ I@|%0 =iIe4Ѵ ꨪdAQ)xLl~H i٠XxE° iЉMPH7ۃ yZ։>sbiS*)SP-2Yg 7auȢLBH+5"sO݈j4/O: }'ݡJelZ\rª{üX(,ݧ;Օ[4ܽ\չ,6Zkíǥ9IdH׋>W7WxHp<0uĨ2ؽH*"'ozǨ+3ș~L#[*Ɗ<{Sd>%1N )*4C@ $g[V44,GH)2Ȩ ,Q3_-IE%ЎIp-6C?`H;W[cZ::$)۰D)̀(RӑC]kGv,*IwAt^Iag 4YZ/^+ɩB#UH k_. ;M B2W(+]2->QbF9X-MD> ?,^+؈ ͮ(>["gרEl^a񟽆4/4XsgOЅ)F^ ~M$[ɠeZ=b~7$k*W馣#1T#Q],2賥- b 퐔v!5\( YAG4$DFfAnoi[FX}e|äX +!h ]]8&q7r* '8h R GO5 c')j"V|Nԍ#W+*&$]}!9]ЃDLՐ21Ƚ'6:3 [ܕ XZd!FͪP(vX_mfp=~sӸP=RY]fj ڹ5Rp; *' Va'S㤌y}[3˱gD3\e8+V1yaR7Ŧܔ)B>_HGV<8`jV㢃fHI=vCX>UB*es^==-AR|5V<͠og%ݠ>m63 N0 ȫ MVlojd"*9ȹgC , }8r&?!U}*5VnjENDHbBK"kn^ ^~iA^VM%W2gig/qZ ;ȚֱXsvfpN7NjηNƒQ}: ،6lAB 3Ľt2RԍzN E0ϲL9/79 ̔5AtJ3ŎfNY?~y[C3Hmay )zM4^/n5⎥ArqpV]4abT'KisnE;p3f&?w%4p=Y#7/0MMakdں0q9ן5i; I,"w}02X3mրxEvE/ި @# B`@5_q7V { 28\.Cd`LUBb 8\ 7I2x3fK8LRa3&㳨DO S9uv+'#Y:+YZD"}\fi`9SLɔ%k a(,14D?08(z+6#R:>Ѣ+K¤tc;VǠFH6iR%jsb X{A)MTFʳ";FSLV0##8-KC;NS ~XQUxS"ut 2UJRx0^RG3꘹C nHY9#JrgLV++f;Y<~w+rR/sO"0)p-8WnVn5w$J)Hꆽ0z|3UO5ɻ l\yW/B6&RWk W,(zS"]-eգ|;fZe3AxS @qֆV1{?GSLEy:ҟ KJSh]!o#^jPG-F6?=eu>S isM,ה O%ۓr:3zA`6toR&I2uz!"oYA#ziVk"g<4KtBPY-%hX4M?1y@h졪ge,ͨ71%V1a$L,d6R"f^ɜ\*)?[V.Rۣh̄I[80E6զC4 3+%!K$:r2Ƞ%(>=X̆>R}m<)Rze]H!=+$f7ٌ{HRc#iUR9Ϲ7F3#MJ1:cޘ\5q*̠ȫ-:ը))]5PEiZɅ5Kz=}D9&ƊcX,.hz0]B2%p*IMT""رDqCK-3^jd4vhQˁqVQFC{='"ٓE<ڄ^haCDZީ{ϔ&Ge`wd nAW,k8.z>YY(4,Dya*x(-Ǯ,6ф iW&1=ֹ'SB(I%.\+h)>cp&2:($fw.;2n$jl,l(YeKgq4ܲ2k;eRIXE!-\[Tm}l(wD_%4&qGT svLGTaw:x"J 瘬W"Ky0wJ{kK6u=C32`. h[Hqɳ`_wF\'QySö_4Iݦ\|"wo 8ddW[#~r|+5z7,2OPDFN4dZVClTׄՔ<~.(IܭvnϞuI Sŝ#:|-e}( ~Q#tR⹬S|P-}`El~TY? lػV rmS#̕Qy,V;#.>fVIxۯT5@'8  \K33um`MoSrD.0}Cs=," du/,-rq~.+>d!t*uEr&j\ Ҏ$wBN'/|KgBV06CHlHX! dfZ*\R.pl-lD"fZ!x/>20҃nX|BI,B>l8c H\okl /.Qo-g (">K\D$ּnyz%hFvb ,%m.)ZqrHMmHT"B!,$Z-EҘع rBg!BM 1MfZQ}nr~,V h)ceɉ , .-oƍE8hLjad& [zxBn~ˉ 4ֺe "p"lodfԼl#_p-@*(./p1!V攧e\\ahvqXV̤lerZrؕd[Ov"F,4()8T,!<qT-`_.A91jz) \F 5CIi|@ KE_$SZg3Ҽ2 q%4\lwA-{ebrꬣmsPB`M:ȩDܹ!4=*2 TW3I t- nD E0%)nآp1?#)WM* 6k˜rꊈ %*c=I*F#3V(tV@!S2@EL&en$+Qp#aUem$QVhHfjqv lM)@5xkCK OƊWL:t4?ϊT>-4<%՞rVnsK8bsjs#Dr^zI44 6\3pbǫU/$h{b a !?ؠ+-&,3ԜDϬo}DbAΓDH-"tShsHFrR@GeG0غ\0QAxZC^(NrVN(['La*Lmn+MZPM>&o6 r n5oOXڔLd 4׎fĬH^T?." kȃT !)S"Ќb]OCjJrHΐl.k~6jnf'\L-KQ֒-rmF6trsrK~TuOFw]Nn UMMl(z0NE$L5K3@bWTO6]A(N4VJz ?W#e) >=8FLl GBq@wXB| +*HcBgGva،򔮴(0g7~8)Sct$D&$X.&sT&P}1`zg<#5߇\`-{j tPf+XpvsՆWr4Î)€4u?T6YHG2n ~(#qO b,xrtnE|kS <5QTXӭQth/-BؤPD~nd{ (0mr<\(n͢ XY2N-.K=i#;HaOِ;9@:_j{5c.g>9B٪[rqx=m9vl`x[3KO_f&uN." U~3o8DY)$6GLiD?(|0n7Ww:cFe9Ɩ\#<"=c #BSDzك29`5TbԂw&,, - bNj.zz9u9\(FlzcvOKZjH@;wR(M//4g(y85L9! HZWjw/$%5^Uq qL^[@ 6l>k֩FN6BtJqVtXvFqݯpJ#O,ܱ@RVVCbQggdcMPPڂԫz OԕF1j\uexDJDYNsӼKhd MɢҦ(I@H̾;Gi^_r+4IlQ38vQ܆640kjo>5%4T[B.m304my,.nsc=*¶A(Ͳ\CccGYUl7}U Nϊ1B>]An-s!Mjx =ҐB-`iI oH aQK_t?Swo[I9WoJ@2pS<7Xg~*Ԙ'j{_b(͢ˋI]z_/i`#**N-X{n, n0ol2?r`s3Ҷ7)F/8҃e.l3etԧY/͌hz 3{lS4G 9G G-%oKPB~^^ ƛ1tlmbR"tFrR/tMc*U"q}4k`y,/SUav?u'?[55{W N03@潪H' #t7W&\Ɣ?j?Aă8;w2Nn͢;E4,{)#w%ƫ{'V /E1Z|~~{aFF 'fRpNdZOFi$8;s~P9!̧(<כֿg$,SBh< C!"SE,6)!# fd#BB"22C@G *ZJcɀ.PӻǸo#R XH3qD^:ਉRKn*⯵)z|Lj:%"*66޶̣!3Ǭk %5.7B &("II!JHzJA$|Ԃ#z'h{RJ>HzhK`BvGQJ 1 %~Q)MbMoA4LH{iPe{lFC<)+rV[P=UsJR̲$0וm#0I G6mP)t>TL} wU2Oh:e - ] ls | CKEh,6Z^ho…i.TZCE7"|O:F&I8IyJȈqD'iBs_ -h!:rͥ7}h'0?׊Zs/2:UȻO`mAͺ웎[uk*%ܕ#TJap ܳ` wZ'UufP T )o#7")HPv?C {O= tqFji 5`yף=n=&|r.>&"T C3!<>řFȝS ! ~9NM)-"dPF J? ȕ]vllE]T.V:)!P(=YZrtR)EDIz&ƢOdi-R(MiDeiO5c o~,`U<,v+%ܡ  0TOI]N,VR, 36!wBY@!7b (zC@v3Q7J9U)RYB5C\Z4B?zNpQW,?GRJ$`FLYy1yBcΦX]+SmΏ2 /\Uź&% &b}Ȼ5G멢$z7zD tP+edti,Eֹj@$&(c x۷ J-Q%rk'ڕ-s3˘pk~_K}V4a2eHv .ʵ1t_9<݋e RI/$}DGw9(.*|$7h(XpDZxt]:~~ Ɵ (~m5,v^,מdۅK IܒKz jkymw/ !ANxqmbaw1 ` IQw~e)n6Q@z, ڗ("4hZ>yys+PaHZY:h!B$w-qT?X?DH#B(R* щSyY_4IXb!f r`_cl3 @0JP| T Ф B='d ؝Kb  1X943 >Yc|sѺN#R#@)7Sd0Cʵ)*#9ʴJff[@{4Z:kF0e_T37)@HJ[&)~fԽ$$:2 )c5X~lH|D9m-9l2j4.[w*2B2 $+@CkC Kɸ$*&HI51>[89I1YZ@ޛ1Z1- &pz JBZSc3T *D J<dFO$\D|+kHT"i-2 5u$ JJ]RB)wsj ,\9(J 4ģDojEZ#B@}ȑԠ`/kmL ZB3+S k$)ګHĔ| 0YA|Bs'XBi>C KB| jflK4"ҋ z?zxC ,$J n@Is-BY)t" ӳsrZˢJiĶ6[ .ət4% 0B(K|4lбYCT]~4 >̵քƯS-螶W9r AFl&mm̤H4%90~ʹJ+̱tQb#{H4l.[.JM # ?_& 4|"5$FTeraFma ‘';r5ҟʳIm|g6:+ Ha a9w`ԫKIL3J :a:ن4ĚaaOb%f8.;4c:ێ_3-ELW`G Lm1F %447 UӮ +Wɷ#PkW`(= DFg+ݤ[aLރ`صbʌ* (R~@feJj׮Y-;?\fh4 >CmGt$eY -Ό` j*әݳXI(;#9<rD>^^s 1UDbV%SC N @UI)a9dAA[B_pϠGW$-.: D46˽ 0 3&j2ڶ++4ŵ6EuC/[ bc]0.Sğ Y ĈYJ <9U-Z.h;ls}րEU-Сq ip&/pPpWH\ SSa'pq6ۭ&MQ2r>o@re圭"yEskXم$ _4չt_<3e&1 $uˏվ`EӉmk"XOL & bO`}8Pa+It^1Y,+Ұ/$m䜩>8ޒMz4J rzJ !Rb6Y$JARvn%{ rMhkMTgedavroE&u0cd dO IȀC~޽`^֓LPq}~cD/9DB4])sF?Ω5Pl0Qs \k1B"Z1uD06)^qPðaJ4.|loUɽKO3BaG2hg4#)tuIzvSF%r|2 U4LgI0wy9E;n0"/ JO( Һ Tsm^ z\3aO@pX B`(-}a`8MA4z h ~@jEٔW`ѩ4=$Gpw2 GҘԼ R~M $.@Jꏙ]< [/kW\Bj*nS)m~k~gQ 4.TW($ >yHaLJ'&&185sJ6l$7I2Ϩt+IƴOk˛\ܚMN|$ i0O7ɫ~jzmPG~zm~`LR #X+SR$:&(8IZ LH7/ͫP8ҧx;(Mdü%+뮅#N#kO 4&ZzI30ԠA H#=4@ػr*Po7 N v;G<9Ht3 P)'%DH BVϓh&%̣US2X ?4W-O Z71L)2ӷ'3\BꒆiK Y ."0+RHz^Jg@V"orZ#Fh^ |H,0%("kU`괮H\lJ?(~3+tI6$LҀUFTG̪$^:JH̤ػtS+\J#{j~@&g9AW9a촓\"߄$| %;;ZS69$ ƪ4栜3AL: 0hVw=+0=| :_W@5ݎ1UDVҧ#K>d pkDDs3G0'[R 2fb"sIKm-ز>k7*oLdGbByRߒq*`d@̏4 %H%r @C*LʡjKH#ST`gKQf$@#!R Qۨ3N?:"\)jeIf[ik)RY"%?)(Dp(O=Fj\B"X{YQL`$VN2?(%ԧ㉶\/ٌYh &D%\8D2 GOaEUXMTa+Uh.WU<%ľidEdANzU^\ſ򶣩 (ETH89>HI"E!Y@3KX*Hl8nC\,Tʈ9R|d4 >@BZ fOڪɓ35c,rߔ81ť mq*J&f1ʥTK)];xI?cNoiRFFMqL4a @ mփE[nӿJy_BBL0|f9mxVZȫ 5Zl]as@zu(rԃ[-U k h<57IWϜ%9;#ɯF9a sb#*Y\`t@%*2brR %@ ]tۃS< IA5>lmj;l|T/DghT9y_@Ϛ JbCcA qk~bxnE.rAn]'('ȼօ=(RƳ/uʖP)J&|nT >(d9ȼt@嵩R=4!ֵʅ#rPEѶ`-[t Π΀ t}M3Qi )2N[0U} ֙5~ij#66+uXf-lv!84BBFU<-1~nܿ)oٌlȄT2u,L&N G F2hT7 ||eK4NޫbھZrh3`" |6F€洇OpңgH([Ij7s0_"'4ϼ &P-15 -]c3ܚFgQp@>qZ.w*TU%~8Ln<}kT՗:RPǗ~o7 biYΓFGaUoBN쀂+D2U@=tЩr@[9t@ d5\QM-W)@Ŗi>l\T A053IĄ !RJ6#nC%hn$GI>Æc09RGH,mjкv;:j×utI<2=GHdJKɓfuHna 0ѻ| ,.P~ĝa%B׊Yc-iȐڱOS5.B-mYHMa(n ?%jdžB{EcKxq9ȟJ`<55Ҙfѡpj"&PhѵTp[0<g0xKB@E%کjP}%YЇcJ~G1 *"D!L"jk"ꏰ֢]伐:oj88$zK'G-l)cL&6j'+H/O>" _4q:j˗ge}KP&e5[r.N##)k5bƌ%(chL>`o!;bUXrl~2ydD8~ "J.(?(F4q!O nd7X:A2X:B\YKd.m)=1)5bUP ic KUw hWZIfMafQ4p (hu#hvde9SCPD1*ryxBe D;ʀPKKjEcd(.XVHc8~ؕ[UC2DIӫ\Ty.rqq`b碄߼ 5U*ǎaCR6[B4jXT2Mjbc[U9];wX^|51k\[`?S_"*Z< }Y%VRnbV&hͤݔ8Ə۽N{htB210:5NۣEg՜#t B}bʭiUkIˈevlEw̥{L<5Z wxJrPhZo^;Ӳ#M3fyܜI_ewqq;cJE^ygsu1HUٱLg䈙L7 †XqQZ4hژik]t=?b6jk:挹L j@cGx:G{K?۶JϚK3k0j꡽rTDuS(#m3 !,ufua鶎|@2VǢ]a xQt[czZكjdbz*H\i.,@^'*8l4XM|xe %^ u ߠ pHfĪc͊܊\av6'@e  BFR<ԀfXcJ܇,.Lb\0aN'Ð!1(U؞ Şj2hM:h/"imQC{N!˞"XRc)IbjtD"@ 'HPJ,hBcF #*d"8,#p?D&mB $[K =\)*(l6x"+\-F {-OЌ K!ƃ"8bG!|j)bPHN0jhd`JY6$}8fN)qȂ y1B`Īc-BģtՆά3J9l`o #Ҙ %z7 on ,L\جVHԏd$,)Be bmk>b0"1*g&FdNS6vv$`lԅK(z-&-L.6I 0Be "B(ɴ:9HpޘZdSG"'(4lPCcG6 0#H,? "gqP6hK&Fnp9/CΕ"vRl*F""rC8Ar4lxoL2} Ƒq!PA; ` GZe+ Gg"3ڔvɌv%hd/?4GӢ%1k\-m(jH_<0 g lss˭75!4/);5 7 2FD# HPHp©#CBʀY'bLf""]#0Zo9 XV4UB\7C9 pb'9Eq8eJrJK~4N3t0^E6o蓴YuSZak[C9%FpV2(ju"UJ-!CmЇ_O[D3l< (?u[4'>B7-UWN\u' @{ JSARc^%*Ғsif5k  /!zS9jDM$1-_uS! {6nM$)pfVfdžp:Tb"A`x|>P/)*榝%\VjN"fJ^46u&HZjC91[ꈪ'٧77|b3Bdqh?FfvuP&Wo` p2eClP#Ӈ=w&\9У0c:2sKV'c&aukuRe  伤 bZ1(Qԁpwg QMspiP'<~"v. Pii.jI&#UflX񉾲&OZGP&:efaGxYPkH< hڨ|ւъ_"Z :978LKHan( |smKeeBҤL!PP) *N\Tƫ6*,+)9%[L[ى=a>0R'o#X䠛 aI4玚%{K9)X|Ҹjl6HŃ,F Um\|W:;gʙ0N"z<.fV!f*{wXi32o&BGtHg=]o(78g`r>)Iz"әe(ZEKCu Hl =77ٺ)n?2s#sC([PBt|Y R)l *BHaՋS7#j)}Ic.vb;MR*qb*o_VZ16y& d';}|p` L,~nsVimG]GZl9wB+'K']Զf-Q*֣[- \ևq)|oݡv8.c]a>{k)Cna5,> .ew[zf AP @p0 ~8cr)b`$I igGܬHf%1ΣP(0N9U|*B%ӁR9!ןϫTq_;v @:Bߤbj}Y\ౚS p+SEU+G'iy0#0$wr 렗HRtNFk5ኂܪhJG/:=']ҧ΁+5يO2 %bReV(;>.7 "ʺ0辀 6R h¢(ƿJ8颌 @pȽ *548.{1Ҡ0'KCl" K 3(l*.!{NnH(MDy+!hd"]#L$Nh'3eIZ,9Ln2%NKr'ԑGv<62D;U)bL:ӈdk؈uJ#Ybu**V3pۀ8hb9m "XTP T,˂ư֚VdСSŭUX ˨C{ ʵYwZh"TmS^R.T%^UCL٧ p)Tvi!)8Wp7 n"ʝN!(Cr *-*yn[>\}@OY/NXT0VǘK%r_!/hq5B@%35Z5Ԑ*!5׷HThk KGX^5O]vpx;㎵I\CRuF̊1:h "8lLv"g+b7~@"v6Eұ+z-U&J͐Ճ 9ZJ/͹.@} tRHrL}çeDT?-jv`RAnYXb&z z|^q]LE[ld(2oBDTK*Erʐ\1"Oq3ބ)A,KvC'DJP y\qiM)b(!:ꕪJ'GU.%αt2~$yK *qyNB7e,,rV3dp'mFEiQbTb#* ~G ' ǕR$#njR9{ ⚜txsI!PT?3TCm(0~bmKSx1dz+Hcc%\Tb*EdM!hmTUSUSӨr:TteÌqeiG^~& b~q?#ekнsXO+}VGf.Z'*IXA:lC[9,z,J 6;38}⟻;m([QȌ5J ,@ß$6CIN1':P}$3j{015b(~"CDRP9`9H5I{+' t돪V qŹ㨱=3T"F5I0<:{pN*Rpk)/'!W)Sv DI9뉥SLyAP wElګ:c۶R1w 2Z  !Z;Elk ҉3 [x43J%/,_i ɳB$0D#+p +1qjF)ʜG@ *b$LCK@ T470[BRmAI3IJNSZ3Z72*><,쿸Hj7D/A37=CTx RRN7$[IŪ꥔6!G Q b٩H0rJ;&ѧdLE580@3Kް"i" @ʿ+ܟ?| dj ӊY 4 ˔s6@jPD F*P* t[{߈FHR-׸ا.Z5L,[[੻R$XDW:z3AR8DK5z (2TN(㏐[*I8,P98%rb|CY@_"= GS- z*ѩ-ը;w)TҼK#W4P,B=-3´̟9% `KL 5MMН`2 ]Mv#%u.Z(FD+ND{ WSUdC="aʊ+p~@;3kgLhXͰS٣:Ws{ݣ472 *3G_V W%lDkN<^1B?DD"?HKj KCc͕!$=)&jYvcc8l9\5#Lɗca袉_7i㽮"_ٯ]=Z6Mҡ㮈mׄ'03 >s[V?$ÌUj0s`=pjk}CTC Q %)ZTb!A581|sk>$B^W蜎n@ V(½36 !Is V_"ͳ˷ 9f>^6jH8#R L$˞;2P 1~j$ެD3 {]1ghrHLTK-]8sWEFBΣ = Sy;#žFټ6r_6r,0i2?#ܰfk+9tVFji tܺuIC>Rh/v9vÒ})zF8chٸ3k^2,E 1>~;A05-e~.@햵3:o+Q !SCHE!VZezwB+=&cj>9A_Ev8rip7bI2$ȶ6~„ڹ~[{\7VX8W<S>;QCl*i:O5:37CG#}<2lIv%d&eޠMILђ s'Q j3k"֠Qa>7{-p\ +@w^Gj( 3GYs/;v.jXqJ³KF2[}0rkJ)>$RPWnp"*Gr?wp鱳ȽnSrL݀D _gNj pӧt-7IjrY&&r0Nj*{q8ވ^XѶ<՚I0m{=Dc U1흝$L(JfQ kpj3^+?!%z|S>ފe;6LB;w) 3cUW˂L1=/t jdd5h-$c*#Vnk-zr~eH-p+7^'?\ }>?o ٶ({ ^ HC!Ч8bGJ1~Gb) EHdH%3JcĊ)8~ŀChv12O~@Hy 1Vd491.Sx~L&)dn}th0 II E"Vmj 0c !>E'D)p %| YbSY'MMIpj$J}WHUΥW74:MJ|=4o'I9%$j5ӖTW7&F֫RIJN%)60zO*bܢ`t(EV4kHr˲w{cNV4wY%\~SvEQ9 ՒbU$9B@[iUH)e2zY(JB AD,&PՁN`5D_ֲlN$0VsH4%CH=%sXɂ @zIy&|J,6v]8l#9l ٬%P$2; I+1Ηca-;eu0v`,{1֠YOij7?Am@X- ySoU[].&TG+(۵2jw0ԭY]YX_kv=cϽƷNgAXMMFJE\rǩn@ >P*3hM܉͉ZBIwūLҋ¨j%\!-HCX=PʎL&ܡ!8e܃ @J.2i,T.bRoFe}&H++EFb motuL$4R;CX}e,xvJHFjJ֪r $pP+*l MPm=˄SǢDf/:*zOEz69bBpV,R,M~R xfTb>(2 D ;gEB~<̿ _.F~,wL0\' nZ6)b@=-G qҁ$x.쪀dEnJ ` Ql I خ;":MNφC Tx'xr&NF)RPqPs \PE{m,¨zO|"+Ѳ} i=o.͖egt/f2BҺT* P%Mz0&b-`-n.p &n%FwRTy&Pn# |fٍ󣬐,Mj֑ 2$Q rľex>,G+$=.(6O%L_N PJ.$tU*ˆ33!2x Ib R xi䗪ۂΟ"&ϧ2IOp*oD e ˪}ϙ(ݫ@;RaLn$?n(/xNN',! pbD.P{& o'=>F$l Mν0'JW2 ď4,ADDS)/F#[o:/,/ni;s}3hN60C뜽nHN`O"p"Dn/jQȾXSuQC)Ϋ@4g+e#XI o:g!7BEOb@ILdž CbU ;q cY,= o "j|n&͑8RGl!>mjz<eZe2bc4$nЧ/жA3.F14@4l@.FZN&I=TJ \WGG=Bbf*<ZP4J#"o5N.$Ab-O, Bbx@wMOoj+V1RL@MN5p6;NWW6QeS vdrJG|&F4H31N)I Jʔ88Q~VTFg`fTwf"xmatOЩsЄ d|އpbz,p4K|eD -,5`FwQhą5? $>F P%M:HupF*~l}EP~t:6'evsm$2klAwq]aK};"ĪNGь*(=Wni[ e0" ]ic+f2(.x40\x2ZfufĝvQX9LrCm@`T}#D҂Px; A_n0{P+TjG"[z^Ӗ3GfVsBpwNP/d$ᵥIMXY6R_n,ljMcVMh+8{ _L0'MOKf줓o o2G#SV󐕦+")MO(hWY.cf+ !2HOw;O0q;DZ<;OfI/9 Lض(D( 5Jf+xPo0JEtzbN/ l$ŒYEmgS!y S&А7NQS- JU60s(mƷ!$A*!'W!ve/%#Z|k*0y@M8\kERրڪ.@*p5;<'Ckҏ˾ HS*9'cUʬIyQ̿sA4Yֵ' 5F36Ͼn9~/RR9"bKe0~g!i y~H7}DNίyYu$(-Qۉ 6hT#HKFx<͵1o7gh$j9dRNaa Mm(*W;!^OW0*B跋̃+($쥻Qm dm/ji]iqK=WQ%7/=f 3LuķdHK$[`4#Em-)ck&C.FS/W6;U-~ذ6oy _ gd9V-EUX)/pe<# 5dNK9z!p^SS5>ihSͭшFH5:bzFo 5rڽYS %6$T4s-7.3.PuS 01TEU񹰠wyi4D 햓B' f60]z~$b0xڅ)ӻK:AGޡ-MOHQא;=2r:3բ[`(V(S\vj1ÒcdOe''޽gx$L2"b? 3@Op b80B`2Y4)PM&?Kg"M Eq̾ %QLiDH$:{0; TiW5tiίZ36qIPʤk ^@YpѰs Dfb3A3]4_5߰U2$H+Z+8n7I5ɛ&48?霮o3nGwy:EުSDIz0Vc3}~`;sr(!IA/""Z ?pھ+NԠZj3s=g(qc%*TI"4.Jç|I-V/胡 "LGu?rH®Ϊ_00&րsH4E7K)D|3s 1* ᤱR ʱ/9%+}T 0 @#ɺNgBR~iER̡р T+6RXRbPlĒPzΜ5D8$[IҜ˝e 36(wU#+^ݦ뷭 m-`]"}AASC B]b,n[#}ՉZ ZqN+t43cl| S #(bA#*DT:1J[gi &b!_HVI($dUEH5\~UՌ$Tg=j,U:\&|wp Z)Ј(4J>ͭ&f+w-!ww^״{S0Չz ^´«ևW|2," d%-Gʘ|ԃ!3[&)irBqD3@?m3~c|%3 ; tI"qxa$p@$YK<-G ceĕ9$ʝD3BX=͟=y '̾H4iyDu@ {b̲*P@S[)/љ$q܈B9cJpǂVg!:2?LY)#< B?+Z2xP*>SA*@|!-II+_(8UB .4$G \!*kp"xmʍn+)r'G.hI57:Dbe2kq?fI[ܩhnUz4Ƞi$uyY&?>p(vKlsM1f 4^+(T=]J$@&rt،uP4M{z&{\Y6$V(G7KZIFgXL:hk1-ģ:)nt @ie&ddBNC@, /hr)_`Eii$ ֕cl(;iQEra4OBO)p a R#B +eS#8([4~r},M1G,֊OAoEZe2 J̥죭S<-uN+0Mhn83@*Qƞ'7Cg,.s~0oETKY[a&%,i!bm2C]8BmXo^cvu&%ufa-?Szx ySdYpvQ)α:sAc eIkzr,}i{֛|h6+*!0qﮕdH 13YMT y;g9djh㭔ԘV?` jj{z[: 㜀1~h"*S:4BB*zKSii%󐊛ҭ8z "Rh4))5e/1 # @g"r9pJf:Sa'Z1#;-0a7õx b(1zh# Y=@7 !-;D=u  𗇜L0X$Ȅ3ϊ&4#j=&7ɺ69Y0 eżZcYYC` Q>//Г[c 3H AF* P$iqP=gᇏlG`Zss {$9k(Ai* \V0Ѓ)϶h@#0} O3)ٌqIS/)t8-n )7#Z(3AS0 ZrW۽B<2U B 7ܩ9u@ٝJȱ:Ӎ$L=8،EloAt! B <Ia!q"Wy5ƪp>b|G4b|?#5>T K c=?7v:4 88(6}4[Ì$P7)7X؋+{"0 Gc߱o.U dBɇs)<>qk.M.)@b:8* ܀Cw:"B 95= L;cĩ=Z":4rACiM@Ƥ #J Zb**"gʅ-βQ <*$˔ѫ+:@$ [2҅6bbcnȟcC SK h7#j _TN{>|,Fꖕ# 5GGr8;NlFQ"2HZS*;.OчR#]5 ]5R$83{=e9H̼3 (}?XR`/M=F)Ak7-0A[!ȋeL#L;Hȼ*= liíH 8z 2B\{8-QR%'jFAWr4 \*|jC9rz ױLBHT:y +/ǥ\[M1M\ D@R)]癃*u7H:Ù$ P@E}l4)V?Y2C'ژY ͌h@ վxm:iF C2oJ5`',rJ4UJU2pp!H8jk.#@cX6h0> O APG @18- ?@@c`,Er)/Kߑ@T7H8TRuT9W@q,vKr8*ShR0_3*B/e _f:Lʓdo2O 8:N3N6F}$0,9(QNvew=VXf%2@9I5͜*Dr =Fe Y`ՙ| c~ߓ̬[SG8ܗ}2"Fy. 6bZJ%6(Ji*(ۀ/렏[*9Vr#ީ/LX'e+M O3;萯s i+ 2 1Ũr0G` ;jzM0!*&ΔIJl#+~LQ*#3r\e7|6^Qu>26\!!%fJZ;hV^0 XEfh&N7P*aE$EۋDwTA/V@\ۉt!HiUX_Sq(CHE8ҹ^ZŠؐ2>8'Jܦ1#I̲/ #*BB#HA8 #q$a*n E ZiYj sQ,$Y ̂9(UZ}ژJ$,4 _ |GCjThHyAFM*QƒX{}"~}Cן_j0|Y>9tVza럱DPQ@2 ^5<%X:AFv"XR,J# PEu%@~ p 3I yBx˴PԵqtUn.Ha'N`ʲHŰf <[Ѳe1Q.@\8UYHw\`cL"_!#YB&P # ŌC "'Ѱ[>HScUaCtѠ"جQ8#J`f gZwCk ![ʞ|;$\Ef0B -%ϙ-~fG^_lիY#{(BPQtfH|٘I r\֋ CM@fUϟ 5i@09Ѧ޶0/wX \"-7%e,[fVGz^95և#-o v5SW r%+>SttΚ}Q!b9̼Z:oƓC8F(U?;聶|`ei0cfF{17i-<sK:QiN׻51M' U.  ڠ$(W]cF:DT^]lH &'k챮܊DEE4Ȳ,GG┙Y"ܩ EfϰK 0"j';Āk~ÎƎg^Ȧ ?ˎ.ƴHJfwe,q k#fz 1Պ.`Hq  ZbTL$lO OƎ,-a+E q*Ǩ; & Te-K4ZlЖ ITKd(PLHe#ֵrO )RKiXEpaER^SDtV+;!V ~Eh(щ4Ĭz24"Q)|4 #8l1d;hC@?1 ,`YnHCTcho?2pn^)idǢ6l,/f0phnlr"l4%\ohpCH]cLȲ"A$mĊlDJQĝ*FڻM_#HK%]Ǹ\GV@&^Ċ7. !NpQ.-X?y626E#H;Tg&A) 8^8jyku+c&D!Rkĝ3NҜE |'2*v6Sr_3p@`HT?2/딆˳'\#LP(SRH1zJJ`fvSp+ZTn0b? u~DZ/'n\ exk~U*eLo$\} s (/#s7m9isy#k$P7 $Bd`EsEi~JpW3F&\>pJܚK{p>GtFRw# m>1s#R:b]vR*澴X6MxT\H3BO<~yk9G0$V' Fh 4t L7V*& %`۫`iJ1-Su"0q,nJgO^Ad0 E̫]$ZSD>ЮHpL$[[z6N b&kI)J+ˤVoT+Y`j Hk5.AU9E,->3d\-spO?;*xRBϲ;Bf`l_+W$-Bn?H⻈y..K0bD6U[ܡUQR2boP/"SFh; ~>L+\3q`CL#Idm(oӆe]f1v6. ʂnf6TP O@l>g2Ocfm :W*KȤH6fͱ-Qk!HhufOFn2gLL,P ONuCj HKT+_pڧIcY xaTzbIFMs+DDߏlPJ'bf֋lP!H/饃-WoǨnշ Hq&j tRk`gr;PE%n6$C%#+N}g.pQ hyksu9' Ix2xo\dzI VJw3?S(GKkAeEv7*b)ma"mK-rGQǒt7֚3G t%a8(& ;!ekjzXB8xp~+P-àF")Ų&J0owI3jܺX7nJqH]wqF>gN@x߹8y}zИc5Z+w:G0fkZ#KKAuL\PY3kD-+)99xB<ɗJ^U<[+€m0i1m (F}k ET1YT".<x*YpglZ1kP&F 3<̟U2r0\@ՂXV$qGk*SY'&y-%օƿQ\veNe[ŃRѱni4Jntż*TUv,UR= $֕ K+#!߸!qˍ6;OHu#?_51Rba]xMK]->6|ued{g6]'qCܼfR(]n]৓@N/+Bw>d]%E8)^WC聺G.Z{ RƚZ1)k=5 9NNHf]9nm1ݎw<׫'8xE=rixG ^ޚ%](b&#J`cL%4U޺0![L9O%6b"d Xqэ\[g9o$=Rb+3#T$=j;8*0H{M$ ATAOȐ)"hc8>Iß!(D"O5D!S8+MG AT}Oe`j[R\2@`&ͨ9DZbI@Uq{]Yt-8/`)4*Q D"!3LU-rMvXU;<E1x,c}?u}-~3)Ҋ>_1jrTBb&өW,ZMp9̂}ğI>Fi6ä^MBrH|M1rlS~ɲL{kt%zɊց V"I 9>!@D: 㾊&hbbƿK=G3h*g% C Or)LkȎ :b'ɛBg+'ˢb F$*i\nғ"ˣ3֛Kqf^Ό<,2 ΩҿzV&Bg+ <` SLLj,M & >.;6 PH~[ -J5j%Im%F X 'Ѓ Yl%iT|lo֎ ;FBWѻ5P6" o -XI*@2]Z`4YZ*)E-c`87%@"ͨG"RSr<&/z>fkt/ϊP]-A {6io9yׄ,~Zv;ZA݇GȒŞ3KKjR2ѵlxYl5]f^Mun+7 JkDlmOYrTn%>ʅFsbW,DxxJ3&2d=R:A B2hG*vG,Cv՚G?Zcz2ɓvX6lNL$ W\MR%A.ڟtr}f!Zi!62r 2Z9#V<e ͥԶ*j.ܧ!(xq)z4~ ]{=xn"RBR At2HHl<;27dL~0"M+%FfTɝp mɥ',I $+-WryF{tYx3N.QhuTδj}#'zO zwrl1ª^[ #z'5lOvuș!"[D^dZ5)B폊<:kp4&8N 5&D08cU5kiCZx\ø:t/{H~́ [6w\8"IS$16-^J~Kd]*h:B:+ɩB&˂Q3ɰ8 3+.A- >dl@=6!#9)P~܉>q0|.h 1{z-Y'B pשJƫ| !2&Kh 9-qi+_>HH<5S;r(0<>.8Bpn 1[dCa)#)ӊ#* JCY h@+aR ɭ+ ?SȌiܾQ**^%HҚ2!.JJ %Ֆ98 !ϵө[@3'Ect9vI:"A?Y, /ci$k8Xȷ!:`TK)+[:2iHƵA"bT @I WZ!A#YblJ3 WIę,&?8YP.B r;-鈮xia;X&޼h918!rF|+8GōCdJ;,3?a(C( lg7  ͕@z~;-ks2KTDŹ[PF$Ka>98XԌّd-2例LG@.auBp❓ê\S8sa?w$Aތx$ eiͲ&5q8ۮ.ӭ0AJâ5HQ:Q̈́hٻt ;W @S .B-dwҌ *Q(#=3oDۜi:3$4~J&A!p!ͳNPc':%< ѩ0RLԇ(rN@;(H p)$rx+!h94"a-;[?Ă8⛶fOP̂͡>FnÇFdN0fԌj Xϣӽ#T$Ū@) Q}DuY Ur2 tAPY!q<!D(k-)`Vc< E`HTXLVh\['t8Ny3:i=R"8}q?*=Ƀ¸i6*#H||W|#}tSþ*e3 L!)(=xR>Du\7^8;dh8\ ӕ&% 1LZ+򦲔rP ͂s K-%G@Լ;d]Y~?Ћ!KLqZiTj|?,Ԏ:**ۇܬCXYR1;[R)1޲! MǑGJxXÿQt76PH:GA抐R5N1\ YC=HG-t*XU4TȟjT^ۓ |FF9uj9JhKHl\t0r}J5~ D8剬T)#Ӧ z` , ГI:=}l?RW2"-ڛ 3bY6Kře'C0*]4;x%-!ְX3IᢦR2d}-%RRç;uT L`W:ġ-^TxB[ ; q]OٔU",96hLt&AIѤ. ~u |DFT-[cnM^^ E>[k^^(̀hh_Q\ }&h-,%pb#ʛ8+<Ֆ~9r8(t뷓9@t؜>$ia銍"h4?ǓjņNY.X k%f6j{9e t ՄwtU< i}%T/Rȡ!*j5sTP1}]S&V}DdBͫ5hDѿm6ݲA ÅXV!ڤ @"bt PU0.7 [(_vrFb޽:~ Cwd'dgF"+KRʼn.HehFSKӨfE./ ܺbEe*ϣD}٪\rk taC\ R.Dl%X}g`pWBEBwf?#<$yDeHILG`ʦ̒I6dP9U9H#ޤ >pDQ[g"IL!9);J8e @0Z2)V}JJ Fá` X6{9I)U6^@/ ?Pˀ)BRm_ 'm-&=]o'-Nmߴ/kқl6q̳wuYSKD3!YͲ͚ Ԟ>z >l/\$ 4: "f02C<(TH~$b/Rѧc>l J= 1Қ$Q52:7$pܵ lϊ,Hd"7c$K?˓͊Ą%jn.@BnښHFJܾ*Z"P5I, SK7!3ći(*=. xۢi.̨.5ʦױ[05SC ]ү4[ UD7GH˶Cn[\~I% iz]!&wT<} "O\ aODɶjV8bVotyTvWz9Xkm*hri4>lB$$Y$53Mp=2J)U@l~B%N &iNUKOML>iLʔBgYXA5(&z#sE$ՙ EGži۽xM^ub G ݒ'2J}UՑ(R{m Źl+}WQ}GVHVJ}K_ Ơ"sz'T@}J].@#D J8jG֒pqH_k 0Bsp=PAςQ#QJ(: Ȩz|d)63bTh+YPrC@Lf SiuD>] tvCK 0@ϊ`/,(ۑn,;$Z)Yi50"6}CvfQH(Xc9fcD[OFE#,)G'[TH\,HR|܊ pG&5r"S 6&g>HB21_&m u*t&Sex#mٔLldB>$T,ᙓN{FASa3q"BfOx=Ƥ.z:9VAG֒4$_=&eaPg!p 2VTE=Eo(|>K5kB4i | Ɩ%" rL5{$T+6}22sS9XslLr+j͖ gf]nG4h_oO98\Dh!cɖ0Hbn'>%ɠ@1F w̖ PLmF[Q:R@%I&Hē#d+{zIAmjZ6,A݋TO8]LsyAC#N)FDž !H U:rj%3)Yb8wn# J^VoqzLƚ~LUu.V/$f,dG+g`ɺ_"|mWx1ȥ廚>f`t*Y}abW5}.UL7<[?jIwƕrSLnhZ-4J VyxdP2/GS!xyl)Ͻ?l5 ŸƦŤip3 y?b5vjU&kY+BhW|Lρ!薛`)lYOII>e`1ť xb@*J9U ~yMV7;D0YsHQ:/}LJ_-_)dCRWL(eb/Z+q3ge525ISN7ҒUQno4]X{RjN1`o3u*`QܻѼfc:V^(PT>] D$^ T$t'%_DrUB٧wjvV]SRƉ yftZ 超r:k%:dN*Sb%S"trZЏM_Q}fzY:#>\Sf|PG>_q]fG"d *R~ $-.]PK fD'jZVeZ[Ub^E_/cJM2pۦ<mfP dǭSk`/ N"hhF/ɘ!'/"* J9JZ0U ^ɨFL G&eu{P ܱN  Ő6J*F&nJH_t8ޥ}T1%='I/l|k Xc.fzf\gِ3Ժ\Ą%Q꽴N k$|T2,yB&2N&WC`L67R9@DV"bpڌ2!E;iO|M:QJfQg 4:bYU9QH3J" r2d\8@BmE%ažJ9#k-Q[< v7)}mvqgշBr8x/hqP2BR6c6~v*PN TAotG: 6(H)%I= qk鎄ՔfȨL!FM6+k YicxD-_VM9=HXXO+TdnK)l̞#:F4ӷ!VgYnhsDK)>u|8T`̎U"Z&qi0oF_+lڑ=tI{ :Jc)쿊ă7fY x0`&QDzrT@NwohBL+$N\To-.g3ƋF Qd+P 4( K˂n9Bܕ"lM_ԂϏV@ain#5UJn-{]Q9Gp-~y cu.㶁lڶKbU:/:[,eHը W#ez|8=E5!m*ۤoж.tw&u,̤:¹;;{Ÿ_`scK֊d /i(19<2\7 ?,|4.J:LKD|"Jx}<<GD_.fej9䂶=wӸx5JB۵;9pC'yDDn- Zfg"|"d"% CewJonpy:8iǨ ~J!M8?)Z\v ,B (0a@{DXl?OQ }6? Gqbe9F rjmF(pk4δbK.p*f.l]C0 VD rU&ǼN614{%˭O0̀ W#nQ_юsKo+> :,i;hzU% lҀ ]z޳M=`4N *р+c}h"*8*S#ۧo1HN*H%$ 3n"J쐞:c&3Bs™L ,!&{@$䣳D.bJ)SHr9n‡#: j~\,>τzUr4G!Tנ>O\R" ß FsԣK,}W :oh Jt5JPz2ү̻Y!T9NdR Ͷs>'*ZH-JXDd#jŴbU&MX*&.hI{4MgM쫁T c"2M0Sn%H)4b&]8:Mɚ#SBKM:Sg̮KeGhm2i1 I>;LETݜK}*3F2͈Y YY!Jp' ]!V¡ d:0 J+-O눟ߋ_LI:*SE* ޣ\E7rA/2P4Rp53) \mư8u+- <*Yg5i1 w QѡSVs; ~I2%ET+r!U uzZ'iU]v *hچ2!rݡQ1Jom.> DEVNA|!,𢢠(D4Y!nAC,ՠ`}uSh0mye Sx;&G`RW39&J+cBœ2Ca,]5#m Yg6KvL4̍$7%a$|jq#*J9kA;r9ϼC?KP3"Qa{ #GEd3aiɕebsЃ=V[-h7D4!y}$C^ǣ( I[M<6 t2"JG1:x(}B](d=9oM8B:<ѠgEaE-XtDh0rIHN$)’FdiT.Y, 4:foD*S KTd UEP.6J)d&~3zy ee2*4&%QQ7@ܩcP+Q_CX+:ӧ3,L˟BFE_4ny8G*1'H vj]u98# U%ϽA_)VSʄ# i ȰO ŧ-=t,}2ȵ?{Vk&ע^Gìi.E]:hu2/4i>1DS +{Xz; .+?*\/*ISMNS[t!@MŢ]U1g~ ;ʛ %y =Ԙu*ߴ*jBvu4 2/®`Jz*az߮p+^й$~v ~h]5mN:BPՌYM|چ1vD;;?HfcPx/JRޭja`DS񗜇?^!X?fX2{ʙU RULJy> >}p쇚lz}}FH\ԥ6edx(PAŽW 6~ͯc(#W&WBQLd'{UU.:ռ]9&/oa=cPiD5aظQU Ot~7|ž*,$e:)Xd3*}&ge*»PtPc2X%1vU]E*)*j>f71ҕ4[\nW:FL n߲ڄаnSAW_>j1y*6q2a>ʹZ<֡g" 3jp ::9˓"q1)+3R.{"°:ȱ*K=[7,rkP&([*;9\1ay/*P~ъ7r$Ka*:)?PX;=Kkrf'/1 r4͞;,=T6ɩbʏ]q4!>73-aͽ ɌO;+л zĀ8 U4@ۗ3/.,8B&iWc6aʳ՝_Cl3s!ؠyT@}j] L:XES@0@M& ͉ƓDٝC'ꥒ  =Z}9Y8Z$0&G!0D1CT(/)P(/s"z5\P 8xJ Y11*9kQ3HB[8B+c#RԨR\+#4\61 [C,z< BB:#Y㝂ǖXv'A:A6G({-ĚX+Ʀr˲<*JS@QXL-Ê59jYlRpT8؟;d4vÊ'AZ.[Bϥ\񃴂(aΞgt0 տə0z#ΛXPâui sJaq !> ˊP cԿJAa~EtnO<< 71䵻J ׳DeTQ:0LøQ)/H̏&$K\5E@YC2be,ڰSlݕBAR yQ}dq T#N쯗z/ Lp0M'L̠8;%,h7A8L1^pԔqPQKbK:s>tϠ̷XdOv`5(mџWbY0<OOaT*J SV VۨdrFs:C>Am4t! ~3m%i8 Hp5\E SC 3z .:tXNYpNkY<-Zn!*UJۙl͌7 Ga51 1lWq1sc7egr)5X ؒa9(L EN4D$9>9 Q4 ](Jc&$]Qs-R@M,3i# S#\L[W:Uұs 6˝5}7F, llI]I7 5/ G Z3Ns(Jw.yL`ԩ'4УE I}\bBTg)*M+h<.Aݱ-1x}/@Y=VQD4 øPvA ԇԈAa`[cQ] Hl#UȼIR pV.RF<$ZE)vٻP`-|k76m.zŜY~XrϗNܽީuicg[ω읩)Ҭ8zU9nǼ᳹o*E@?$ -J}K`$f_aUڎ54 ˄'؃@`^oĢ3MqS4=bOݵ$>WcCp]Pޘ~, )وЪOx+`{'%[,/ Uٱ"gՑNH-"n1 0;c9Y 3I'3=\/0EVdͽtT=BMT/=FCXu?Z$zLy2ڀ6&,pvs:Stu3\#4;CD 1xb3ZKIn\/2EyUjw"*Xs0 *IZMO& ?"5RW. Ћzk<0SFUiO4?G4zWZ*~qGm6)=͛gܵǕ@T4֘}V: I)2Eg|N-bz~=\;\,,`lgGE"y9t]q^1/}Zwf.J}w (j|C+3FyMQбH;!]AR~ C=ldNgaBiVu zG'7<}F)h{也sG}ܥ8I Q`T\ot0?M ɀ /bo? F$3S}!=GLh39< OzAU:x$3:LTPh/ "GL&r\ ?#\"cBWȅ11ө8ZƟ ) Gr6gUps9Ahﯪ@4̿;K!Ŵe@,%n'qgWn "t w~j9WfъQ}{ٙ=e>WxH?{ܸn^/IS"ȴ3,&0S8[=iED 5'XAZkTTOfbZ" %01BAIdl, "r?/s(b$P>l?L|O[+ l^/'$ ^{i$؁IO=ࠊN4,O &,z0DU~(|:#jZV|"<MSVTe<,P L>TBH0=2I3T!NsO73XJ/0w_7.9zxr FxK(]+kSZ)2BDC5b7LdAXPCͣLDɐ<e(!X%4hai_ʅȻQs"i1Jxwq}o(}.ꡄ*Hjjxf׆w?!ci\mb ǨAH3ܜ 7q`amM@qX9^s)Y[^g'xf#l ]ǩBȼX `I$F2J EsUN[h\ (ԃ< <5Lrw2'{FFGSQ=&2; #MKe;@ي{T|}[(]d D5(䗌EʥKUG3[]B{+xkgnfK93F| ڔf"fϱ>A!wa"R$͉Im023ӒH9K'iAf"<θ*:R$O@o#ᗀ#'(#%P[¬embj"vQLZ6l옞,:JB:)D[aT_J:ھz5H *}٫/LdFX/ + O#FKlIvUF[%<2d]QKI lxg#@i=CL:3VtRMXiռRW$WN}RqdyE(vn0ϋ /_9)odE`$<x]SNwՂH']eТ׃5ev`&{(-"īN?Ke;DsJ 2i8>Uu2|vPڸ4e%%k %J?Ҧzn3+n4J&^W}}X 5a/W~)O*v[2$~ɒBT0/ށkFgQńj jDx"g#O4J \Sx >I@!:ft3J@%*]aJİah)!`R.:YjZJmK&zH2m{ƙE~CNvem!,P ~b#2IO2O<B,"T ޽6 *cQU!evxBɐhd\Uk'KP,F,֘FӯyP @ Wm YƂ%voZ#&,&x*#ȗ ϯlNȕjH08iwouE+O֒l1D_m̌BBK4,cm< xm (+z|i.[p2 ! ͋laflB8~PB,QiVp?""M!Х*4DNl&:‰lH1rm\PBT *Nl[-NKد(ZLTw.g2 wO&I mz膍 dodxqnd&̑2EfN.ds({䞰 "O'lQLd 0pGI.i%53M-fj>/ئ܇r3:j* ()/MÓr .q-w'2PDD/%%PHJj箙jvSnkRKwk. G)w-N*k-J 0 0A$ʶMl,e$ʎKs^d$QmILίD$$ѭB"rGBQl{4H*HT)Tm❫ jJvf>H̐G@вIn+g+CY*NeX8 A6vLʉGnE+PLo (42OHmhO&(()bom%2F4qIJе,:QL4Q#.)&9GR{"ZK'}&(@dtFwa8$O|AmW(!J~/,P|K6F#[Ve0G@'T i')OeA)5 V?1abj4 dtDAdx'$dZI6Oow160֔(8F>/&+GKwXVVȚ2"ťhqKY΅VbVՖς1{)SR*%rfQ ibI N?w1ΒsoT({wx"pȬTמ%pltEKu| /%A3_̹Ezs2v[όlv gψB*fNj,"Um9{JJFBs(!ᵞe#khLB^xiA8y4AS ^S>2YYrAO3M%3OVP+!D'C 77&g&TG"}:19$((lТC1qE%BV# xEtޮEV$tAeJul` 9*2ghjtmyWO4h1%\FR` = J4y ڶ/)CUxiRZJe0Q7ZB1a &ld2#KB?*(W`YJ'xU!D5$76` 3wT>AQX^Зi_ !:&2r8VmFє\IUĚCs/dYT|aVjD'%,iQ{wFȯt9%2o^*[Ps3%ͫwfϚ?.%o3?9Ճ*7/Et8FJֳÓ?B[De U ]b3fy2_ JNde#$&t6|8R+N248)E+yMxrvp_m*yMB[c2Z0zu 맲W B-eAStViIa v$y>Y,+GJ(rkגm rV~Uozz.,"aeb5}@*ӓq&NkJ %Ux晆um&xurw IYк AmDZ_ hoʘ3mcCr4CG{eF&RR5߅[Zt*Zz8v}.*Ոk!}t̘`ۯgy 1vV=g GtHSEk9rMZ, A6Y$#SCn&zg`eIa B)8)eA],C 8V@D (> bhB ß7dh -Q7 'g=eI|BgJn}H!R *O(1$) E+Ot*(Iv=^O0IX5^A`{dB`Tn;u[XL 7Ht0^Ų9k e ")WŰgg:)AxRh ;3$i*?CMZ-6HoٝO ʂ">ȣ~3IN802)zxB(7 İ *Ƕp̐>g3$$Z#blOjvJsqHw)-)#dE$. l0Q͑&!Oө-L*ˌAF2)Bsȉ6p[Ye"C<$=n ChmTӈ(ͭT(cvHɤV>3"Β2Z^*9LR(ZbDfM#H8%8ⷨGlt-|TFvep4 p_sQ6&"Ple,pR2չj 9B)P5gFc7C]vPip=UN>APU+sZF˖P'y p,sN~r-JڧU| ,s?A$.:_á0˔g%΁6Bn'Fau 2Qp ؽ?Ȕ 1Yvc}-UMMQǺ1LY[9>:'! ,"$FU{\T+U|L װ#%; 2DBY ;&/ HT=G(!;Z}M}wqGcV3ZWơk$E\!:Uk*$|Pbgg=ˬ14ۇ Vnks->#](:RdQO;'=N# g|,{d1'Œ~Qݯm]KZY|RFSHC*< C*jHÇxl*Y}GShN7<xi LKrj48@#RfZJ"6 Pqe6+;5'Hu#8$K+U}HDj6};%2|즜?eaz< FʴsvT|U9$~RRyL32AY~u j:Eb|@ҟ:ƍ#H,Eynqmz+GuN5-9rBB+T90ֺ5.CBEa0F JcrGi*lIjun5k#3~1smս3\CuNV3x=UӮEbUVQ5'd}*(4w#SX4UT<AվtF1z:$eϭo{"eMcxYMHK nvR?USE"ۤvQ7Qjt"ܬxˀ, kr*pPײdr}esmemd\8∢6:GQ@.Jd*`NHdŚKX=TPg̨e!g:ns]V ;k#$ 7P 1p*"}Za<Ѷ4Q2˩yAQR7+5 ,;5ԴS۳B `A3i:k6ʣ_E53 Nj5c}2i6}_A`r,r*.̌ј #A")?:$;ZG3(ñ>'I,$YѝK=nb~i'ٛ"CIp"]áv# 2W48 3.Pa+5pH-,DRМt5<3[x[ %Z]>/l (TB0>`0e0J#Q׎#dh+:Oѐw>RK SY.4)8x}ڨ:7z. Y˭"c)ų(?7Z9eG~ 1RPsއȯA <28Ks/8<2CQ-{|{s3ȫJn< ]G)X-E8ِģ14T I u/h9;´wdj( \aHȓ_G0?e,d_@ Zj'į;E*\75$_b! %(*q5;("9LW3Kִ,oL 2'=DG s(b=C;xD#F0S.˝tEK%R_d?ҹ/ݣ{_A+Ūm䧧-I_K4+Ky9T&ϰ}Q@G؉,/A0)iMh%h!:R l?1öPK8ۅ",c.-/CN>':ѢK#$yĐKUD*;<ʫ.E}ڙ'GE0+SS4, Ľ´˿ EVReNZ'eN#UTCJU@88tvZ e")*$T 23kC0LN,@ E$L4%]W6ç}!vՈdq=-LzRI@()m*,OKa 'ꖮ&<058Nq/kI%ed=H="̕T+%܁[SƇa;˘3eHP9M{[ߢq%kC{zb/4Whd=! +FbAӄk/JV6ľ*$l@\/ൢF̿"͕;}7tjAIv=Y[,5TK>'d;u[jl;vP$Sc#Pn~Y|px.d&u@⑋jAO7DŽ-DIJqFkd;-)!d$1ʆ#9 Ȝ;G ڟO=oisAi"4y B!. -4Ŧ ˼%:C!r#/ /Zv?_|lBA#')cN#,$NBdH's+YBJS:] W8Qt;{pqɭ5џROCb暏 g^uɫWbCuUPTi{\Ɗ :)%Ga=:$f5mCCP(+g@9%h؄N"QM)tNqhw$LLb|WgʝFacqks-q|?4}_r\/~^]˾p[ڌ d`K*R,Y:]GJ/Wdv#<5P}Ouh$Bk]/G-G%%ST-APm ?Pj`i93ѢQrCMD~Q:=Ѩ- {]eq,j9-Q(*!\`~5KpO^')!Er95YbHX` *QNZh=xkXyζ8-* !j]؍Hg X9/E^?:fW=Bj֘C5p"42Kri?i,LVgPMOi}˓ ~ՍЈI蓅^+5J֏*$c-6S*|fʯ7OZUj?ZyZ肮%h (uʍ*[(X3 / >bPm#*W8l7H-%y%SILr$B&+h\ `2TfI٨sDު7cO' HNI(BW[W'dK6ZK~Y _:]FngAE&LJ5D ar ՞VOA$4 cy$XE56Ȓ?*o-.WLcT<3d`jLT㓚T$*ٵB\vWwEࡉm*[ "f]!ι=yG)hPU,MJZ*b%kiy$SGբTlS涨8wt!́5sʚ*cZ*I z C&XbT9"ZtJ#)ְ5%&tWH<&omo[Y151 [t)D)i "K} Wjm dʻ# 86ۼy$j29ʷ >'nH.lYqwK[-#Od 3J<<C\@5vᵔ),=O!GaD|Xخ'ЮUNT,vi+ blMvq$B]ْU8"Er򬚑hTLBqPa.)R6O  !OcQ7V av c$!eQ~'$~fODa |蔚Pe@YD5&*Do?VjQ*2&O$/ K#vGaCw8u lCwkJ.9724tv("xtj2P9ŲJ#arbqy a>7/Kt ^3J"| `e_,V9Ipd1f2p-7L|^Je8xDJQ&Kb%U#z=.X B>6+C@+29r$ C<&=., 7h<߹N+廯N^Lrt& ޟrH"Vb?hܒIqC%\0&<2[#/ D$34"&sB!D!QXGƒ"J͊:%8Q#/J >#<ԎC>ɔhW1-ʲI̶~X._Iq(rC603 `@5_1S^6(.ت+7Cܐ@V]zάlAe kba{v턆-] H+b^-"c X] .b/;M4TpH9<,T.|~B3(9`(9\/5ƫ@~* U)9jqHpqrEځdw~)ϯTER?f"q[\SJDT}hGl^39RjūB\#*t<5 aelw(EKC?8FR X+XFf!A;GY!tM>1:`iQ&1T|uq{4]d|%O9T{u8Z?`1( zB䧖hKmnM zor`ˣdUpShX̡h^xqVelÓyuU)h\ @zZZ>7TG-eb~9Hk%ͮ#҈eT5ti?j6lGw%H pkS4VFٚ7 NlKeW/SPѫ>,iʤe+6a|NڌZԙrޱEU .MDB,ZlU%}@Tg|h` "#;k@hQ&_0&vW[2z|ЊY)Ym:gRP9]nKZ4 ciiS#ڥq8-&F^ݒ_?[ n W۾pخc㚭_>n%uI O0 emcp.#Qd/qQ-߾qxvay<9jcxah}hmaDn/hSbmky3%RfBkbX:fZ<@RB'+Zc^5EQgZm $%bj ylert %,*B LP@ΤbYnGOE++@u;oP"/УgDofڠX¬w ȳInDCm"D]"6bv]0l鬹nf+/踺DY \Xp͢,iHHdjqh0Ƕ&p%M'>+H;'-ɩhƦ0E-wʎ>fGBj*2YQ>Ǯ/ؗ.tj@ꩼj憘n*XFY|,`*MyLaEbrLJKqCkVʪIHܒHFq1޲b$HDIe$ 0$(*x)m]f+hNx%F(6-> -%%o')L b''Ь**ͫdl9Y(qpI~&Ho%bT^q )pO*ҢV@ "~#b.nd#-j6/&`h,^/K!q~WpђIw+Um(R rR{ hψp.$:Ѿ)ɰ:+F֘pynXU"*ȹpm/ 4Qy;)ĵX#i+0Uΐde|jKl!62( i 8j`Cɱ6!S&cQĚ:S2m?YQI"w ecv#Yw6*@JƬv\ܙ\8T^+\[3; 27ǯtEbMBZyΏ=V q m5%"7vה}8~aI3f-UTPItQrP#<2rE DIjiH ɥZXYl#Yҝe^aLYĄm5 _%㌎E4o̿m,׊0rqPzB~3!18mjn;<YOf43#7GE| 構֕yd#q-1byі&oР|[Py^݃5i+ǫz*hS-WG[n0#cTI(8{|"Jk7E/Me3BC-!Տٹqҵ.qھ:i"kae)o5a4mEv&t5< Ӻ MuS(ҝŢGdlɪ%9jXXm+BPO`Y!y(}'U0?ez8t,A!Th,fG$A5.:iA)pfaSOdl3nU ҨzuN|clUb WD.vu6K:2!4sa|RuH^ 2j_6iŖ q^34j7G˥tqV&A6:1A_牍xќ.Y0=#0+5S@*2󷋲\k%ic#)~ {Drʥ˒@rh$Nbע=h)!4MԄ 2t"ڂ,@ Ҝ0{@*DrJ9Cʪ#Fi|(γ\.ɂ]Ol>?NA`B;t%h ʥIa.!2\#zL*K.fL'񶙖zXWK;~JzaW9/l)ti9;%V~η~Delz!8{H ZW"O$2X&BpG& 3d$$XcQ$Ԫ boi31x}`:fiݱ,N QOa&?ԺLJZ6f_aV#z(µ~"=22܃ H(MC[;<"iQ"MvߣNJջž Ȃpx ZkK\ EBS+۹$'v(VziE7%h ?crNk/B s! %4 1%:j]^/O6EHzdX{ =MAsWçĸlIGxݣFA*x m"DX튣鹟<񱂔wÄ$qDMFg,_fN() y&O4p 6&?jXr%1xlQ5Re3'6 14䅕V[+]XUb$h&C!KH:T䒈j$C=JJ S<#iK)M*0ꑣI@:yQd,8M*f} ZUC"hc(:+'%2L͊FRş4hHڹujVK@ z;I Xela/PBp84Xp* ß% 6#@I5S1&@R[{rƽr߾2;FR"-12X}&BgT4>& ;U  -zmz)˳5XK@̽[!f#F)) q|ڙ( 2( 2(?x>@r59q5ؾ ()+˱1㣊<9 @z=;2rdSHK43 J|CZ;%?[TJV/jr| ԛ{#r6X!%ǻ3(?!Nh5AKT;y{6"6:%\3UIP(<<. ú܍GQ9Ćx@*ؗ 000SȹᗹD  {=Ԏ1ȴe)tʌBTG<+vϩ]3î&SܻQri&.:r 0s871|#ݴB4$L q#=q010CHa/4x}ʞʰIlȾ+̪JH+ !s %:d-*K(K?x O6?46DOH(ECPlUh7#ADEeɄ-y182Ѳ :i5LJz0Ją(z@LI!O;+(WuE:Gbӓ،֓<T, |J@6Jv*ȋWK%Kf#4۩Fz?.#kAcH\˫x$d*խP'49 z)xeBK2\4=#ADHU1CurJ(*S3J"P}*q#ЁM,S)ݘc7L-Rk̈ͮ*UӁMM){$AyuOۿ6K pR[C{1ZWEh D~ȠI@y̿g ːMOyV]A\"6` MNJ͈뻮9E# dDVX`{ 1 Ìt]\ZuQkb.&(E)$̩ctn4XIdR%;T:TD]{7_DxT RR36M1RĊES7(8 %Z3] PϩuI;zqW!!+ hBMkVVeT}#5@徳9NTg9z7YMFzX%+SZE؃Äͻ#;(8Ud(O {r>',],8&ąF{5 u^rGLHLZSE-VŬJc٬NgZ 5 Ђ{3m.,PkbHp~ElSWYc8/zg *"@CrD|N!ygUUc9V;"d錅'K`1T8P *(D|CT,8T'$04zUa#d<v@ ZC4B.5Tz6Lp yjj{'" ̪av.K^$87Z(#8qɦPq&R["EM&'oQ$jY ٿ"$Hg`dbRuՃ@aIs6O*'}QߴSY9M)}Ql!eܸC.+4;4,.|8j^Y7̢ؤݪ h|ѫ3Ln. #.7]\zw![H}"eK9 ēމ 6iԫ{_̸-[ҫLAcH&,5@\9([XO@-ᄡR':}ucUC?2X]SoHR֦)e\m|jqrZea?K,=;4xZboơ?[h^[;A`V1L2 4f6\eu)؈#$7}<3@[_{Ur4˷Y'7eL0jUPB54O>TB 0&  -:#yM| 2o|; "/7w%,]8 Z Y}4TO^}O$y޻ڴ Uv -R4"ph42F42ApFG.3 M9ޕB G@}Ji#c2:4 W3k[kPEk>NKtjfa{`( Ocb\ &όb}9ïҘg_*Mxó.MƀsξMR86$XV'2ib3llRo]d;9tist3H]'|A#@x^}t{_-."i ʲ뒞8ɺr%ʰ I˔ڡ*S L"⌤3&"&\:1 A6D ㎻; 2*i 2m#!Bm®J-Z/@ `$h|(8)Ġ(ͺ>A+{H/GDJ2kgPr>1J\4p;Jʡ!TS1ɳ؉*KHZy52 24 H{~"?^GLÒ&5 BB;ưRgԮ:H/^* oId~ӣQ'@DНlSe4$%] ; <3G86 -G; mCfLJ)>9hxN ~]&cm1~O 4k;xs5ͬٱ?Xa"x *;# -"FOhGU9Ӊ; ~X3olvM:\SIݓ> i(-}2d"Ld&߉ 3^[13F Oz~|*3 $ܔ:}6_/RxI d 2`h 2@T]_RxRi]&h&p#q1'kU3auVZ 4iD z^}5Ƶ& 7ӴD1bF:QU*4X_ B|CkY ؀ɖ/(| 2T2+k4Vd̹BLi_xZW[S38B!9*t dHz@*C'G"ɂ_q0-J<y@^[]),Po˒C:H`"&$CgVR^Md2 xc -jm?͸uesdcƜF8NN<ckKw\5W+wsE;34ڛH5_V(SP*툤҃PLX! S_M`♂c͒L#E%`)t3(j MD.b:j#NCGTʤB,*Ȫ4 MH[L . Y8i$}|F6X9Yp&}g3hq,Xv#x7x4HZ#.5i)-c6(AH*B){ %]jj@H!z^ m^klg+>lAۊgdT\Jw`S_G0Ѧl LG| D6L /TI-!i6H "Q] _.sސH`vHWwVMQᕸci5o\qKW~H\9Bкz`a(?#Zǩ0'$͏-YC my`KxGJ2lun5$ j ٝ\th/R n+]xΥHj\{a*ыՂ'Ga!4lVs>jA9_6[ S8[jWR?Y ƙh#񝶤l[\DTp~c(¬ g=hUu*@aPt26G Q \!/ 8Q{2M)|~9+R^r>kR+M7}It<V;6*:}@-ڕs.t:buvз~ ˵Ya1yy=>@C6-1yÃ{<-[CMz7R?r6Xݦ5ƙ6>Tˬ?rs qgƒv Q'ݽS(hpLo&shL !(J]4˸J(eLh->@Dd<(C/&6DrޮEJI|&VDZ"hDxV]vJD,vV '!>{&rJmvJYdPP3Q .>ʄc.p@XoP*Pxق|fX:c# a |ΠϑAqVjd Pq fx' m ^rͲJ%_M * =t& aG z_JLqpLYr..𨣯bjwM 1 &b>e#w"h,:bxٌPnvn=`; bD#02 lBy "߈H /p#p(s(-βoKjb.DZ+LzK )H( xQj~$)Lfˋ?P"KFQ-`@gF&?pRY*6JV*.*-Ox5h3>!o96ʄ4nF~P}dcG2F.nI*qw`1JI@ M ACI . <μǤ3 %< ;I~هDGHqҸQ:ɛ:PBtrBmuQb10]@.e}t2qY+иigh/).iǨnp @gs2fC)vg 'p*ځ0o˫)oc P^lޥ&1/PnVѫF&Fˀ4_O@O'@(֨<(d(1UDD*sLL;>Va6 ~T^{":*M+"(? J "vRq&tsK€eH= YX-kJ+ j,FV_4e€R jlO"5񦫰ve"s0B 8MZC".!BiLHml)$LO.8mbfkc>qbUU+'>e0x ʓs"@ !c`-`ɌJ)h@^nV8-x " kWb2PXD`} I hyS&v(0|{(6͈F:뭑8of.2Rϕ1)` LtjʃLotq4tىU* % ʰ1a,h?7T_Dtud{!jrVWDen[1,4uh'x%rӄN5{O{Lﱍ&b2eVLYzLcH9doP >Ё5הL S:MCo#;o!tq '9YtDQ@'+5a νrNlyBV2uk eKRs'tfv6\yuY7f#*8F'fm}%$ RgV|uu$GoȑUgVHZe Q MBqgI$$&\o΍Jn.92y^=- EVnq3ۆGQ}0oνiCgMQ; J5\26m4e;Lh9u%Y ,y6m0o,mCdǹ.90+dOM.5֥[(Ԣ٪>MS:^ #;5$53^u9=| T50`3Rqt&6Pe|;`Ur:]Oإ1IӼK-uN-,n_396p |1AO*P  >'EY.Q Cp%r1 )w{|&Qy=)ƃ׳c]糌ұ>l% ?U! 5|CF A?bd'b>i5]IcXjNX5VDE)/%w;AQ1F*0djZh]fG^*ܖ56ʳ=qםp+a-lYލ3֩l~ZgQ ]pxSunʀ1-¯aG\H& `ī l[Q?ռU2z{ ے+¾@HIޡJ: () !,ZЪ@bCnB@ @. ?铮'pZMj[KR0 }24#k L-0 I$,(((:48@D@NDɫz@3ʊгNxбˈ$$+3IKsb2h#3$!.E21#DB)"pCԝ`')8KOH]R-,4+ PԧL#z+Џb6T5cS(*3G |^‚7M}(π$(=6 L`(7{ͧȏ$Ru:4h&u].Rvۨ8%u]@@Tt~Kk$١։H9F9H&m0>V=dy}osHy?uЦ[6(Չ&]jKVih6e[9)/la+ }mk=dQŦO*I({a13\~.!֒$il໥֜P3Cτ>\㎑o૤s;^'a_8dy>$ڑJFpg4f |D).B 4CYXsܰyyk`]?b2q4vii䒡*Nl6CEM' Ajs&D\g͖%FDȵ X̔wrD ѓ{;R1!Ed>dA\\?ܫUP]&$:(18B+4H#HaO$c-T5S7rYJ ׈)5&w#xK z Sy֬<IKD׎p*755 BKEyv[λ4YG^:pUV60:=#ͿQ :Q!DfE 5ߚ"A&E*hf[2%$zѽ *(7+{!i}w T~ɕ9;_lnQWTAEufʪ1iv5O鋨k"{|?pAѮW玊0UV7]Stez#.L̋܌ !F׆ހ}ܺ"5uN"oR-Bv`byl0ܵ\ *Hkڴ0~5[AN G2A<}nD6WW\>hD]v*{ZPQ(^g HOpY~kۤFFVM.g<\+vN WFv3B r]#o={ 3K{'g&V|yAS` QrQy&r&C/\]W3fmps2Dvl$~-\5auFxKaCH{7n+/ӛʚ+iH)se3+)7XQ/b ő}iF85c+[}d}12"˩g.KL@a0 60[s#X$ d#by#3y8zq(1s!_>$C , <`AH;ˬ+1f 1 :04; }:;)xr?t/ :e/b8I›#@$>R6|D%8~Y|# ZZ4(b}@~H@͏jz(9R!Ͱ2R4څBS!"(ҭ"I "1 8D{d"58}>(o2DD;=ĒId &c*4Cx 'ڱԲF:tc  r#13!I̐ЌQ]8ʷ$7)!8Qͳ1(؁7 c[H Z}*Q쬄.@',|+$ػhb^Y)i6cK3{Jy8 s1."ӊJ<sn0HLAF)<#p i)پ*$FJe3E=4ͼj)$1E+O 2:zY8O)Bt! N1H,! fJb%iNy 8Qqh:ầ b4X1|# <{qB1߀jt4 | 3Ģ"[5NX6 DBpѩ΍5K6;,P Q3ЈWbF2"{ k32C<۪E>#aeBE8|r|`S iZ8,l ,]ٽ㯱.""+?"YF#2;E # Zh`?01Ⱐ=l8Tc^ڋ)_V/ z70:4Uz„O8ǡ__u9TI5j4ٴMAFi1kIIQPL1##Y mCF5B D\ORMR˯!nn!BƊIB:"6+#r_Qs1n>)OZ^۶=w]uTfpuz'УwU $q0d4{gZ_Z Dl==8Eyٷ|TiBa?f+,ef=ü##TC5f}ҝر۫^K2qc9+?"_<9M!5:m<`h`.=GH[n2-4͂8$ ;Vxӕll-6״lM_]["Y̕U Kd+FBcNE_>QԜKF#eNyT<:%3>.ZiiL0qۄ7Bq$ۄp} J4䆀 ;iТS(czFT-^ټR 6^ނnň223TfX2(B. fF=wj0Ia,e̸#ƴ_bn_󽦚j#wo dP<ۂv»crh_ss 9ND~yw{0]ғ$u54.mE>Y^.dd=z>p{`-EaأCIt[5o^w(:o(÷ŷ_V^{u"\D9{5(>v2\ݺq}_>֔ryO44zɹ (E3M[,!ME]LLjڦeltfU2bf]zX>@h# A@d ?@(AFcQ=r9M $`8P](>@cğҹfg3@9pQ+?'Ru&u>S 5,1IDZc(^5O{3('TZB3rᓘ"Q أhW(C$iT-ŢҌ=P Z%eQs sQI5gIG/W$rLķ/I60;6f4Cy$V!%~NDj!N;\"Hr,2\¥ϫF*Š5h!QclţHzD \94<mn2HR2Fz) jF/LK"$s";,B -ϣ (B@*HBg,$42@o 'IO~/3D9hd\${~˲:%+4;+H<Ç  L+#5)>1#U&p!/"Sг*΀o"fI]*LސTRe>z'T~(mQ(b(t%tKHX M"3-B2<*\kLC12L@)emzV <\ł{& &~ƶL6%TU_Led#~.f"fn[ G6tm*$fj bvd<8 fdm! 7evo揧>\lv)gSDntQk~%˨jR*kD,>j@ L֨E@:NdhO)"semVVNfp*8L .J%A 쀈ף.(spؤqNr, FS䵦V&$<"k.e{ 1 g̰ҁm%$e$=F{+q#.p-D,"t&а,fq!f13RozH (FijЛ9xnEæSfj stO0WzXnH'<+ cO"\ϭc_ IN %;~ʥr$PKo`<eK!)$<0dss 7s5e P%\el+q>$\CnIt&)i*,nĒů "Qvn(RI7N|Qq#Ixq^Lu#o" m2VckH nN pSIJtEs<ғp;wG%k-~׋R- c24"`=~O&MӚ#jp|Z0sT0SGFbp)aCPE@d @XҮDȂ/څTFhN%KOzHd6o!̢##3ΪPDE0 q1R q 1DR{fUtq|O#fQY!4\;9IpWu/\Z8t)Dٖ 6}Ō'2^+Lj"hSCVIzbŕ5X[n oWLToa'?Xg$iȻ «M-xiұL|e% Vp,b䛆gg=(6w`NҠ յZvy4kg_Nyyp` s#q&u.vf^l;.3Fe:s g#)5sw7r 7<1Qrc5)]1x>u0p3rYb=-PY=fW_<2`8B$ȡGnfLߵEI<ybs']{I03})UgVGY|Լۗn2"lV[_e}uE$p9BE١BX9'VD`u"%tfR;:Ls]);e⇟NL4({ڛdSmԹ"aWTB=m9 g-:W/C2a-*בQTȋ^ء%,V>ɿαɽ3OUV/蠕y,"CDNF␫>yor̦sz`.;+)mTShCp}=/7N B5sy|oV{ cV/| 6t r/o.Ls-Pއ"4rJ0ӱr*%mZL|!\B(*h0< ~(","j>,!z쵰 b>O*-ZƱg!ZRQW@ (3Q'LK=GO" uK /IlZ"R4ru&ֳ6tkMKJ1QW;:ЂVq.R^]" y^Zim4L;JĻzTƭ۾ѳn6%jV@=$HF1%"K_9HE>iVd#t߀/3p[<'\KU1-"Z](m6J},|Xd pM#\h5DAp](\B$A:5e@Oha0'~Lj4؏"nB:ʽ3]ꈡ&ìU IG2wx¦ˈAdjTsVo%d\ѧk`TZig\`/~JfrJnѵ\KskHBߔ$YF։TMzp5zO]'pW+J/o)nZo:Bs'cL'Q EEH8B@VJrډ?b/:Zw.+ z;X\*FF!@B[x'r}CD:s*ow2]#'V@vIeu&Bm["+n\zFmJ֓ri-u=\-Vˀεmc#  ;<(f!yNe9e}1&"u Nk[ Ŕao4ߖ>&Az\.֧ d`J`HTP1c9߇v3ȉ.^A;s>WΓ^xw'!w_YIZwcۗjj 3bd9[z6R-=2P `%h.oc,b%ؗ&"#kmi&q‹ 0oA@aɻ͸+Cۊ{u2z2%4+rZÿ2U-k J<'1j;7(t!D1sAB" 9` }̽AIRKBF[ `?09j릘ַY [`iG89^r {I6H%$-q X )04J&y+u<%&4IH1:i;AJ JU4 j:Й02[(YY*& ٩BZE0tV@FY׎:7UGˉzêRr&#":yr- [)ʛk&l@|6HA߼k@ D :Hĉ<꼶㐜1.j8ɼ R簊Q-:܈.A*E+?(1rxBm"* sEXئ:RkC!ir.i;bJh5Bd>j# "Lj>Dæ*7Y*(,×93?*G:20*\7z%!*t.?p$)ɂC 5{}C2iI T?*(9>Q4bZ-CZ& ="pt:Q[x4ݥ =;Kb]GJH)#),<ᆫ̸٢Z! ǰED 6L[ę]ƣȈ:zp3I<@H/L/xfRx’Q;0 Cʹwj%P,:;TS v#(qs@=2 kɚ̎7cJ=f#I,Щ+lSRW9P1;A#)DP( hxYl+OS3-äyVAPN\Ĭ{& SֳԈ i^xFqR ,Fx́]jX<,%}])SӨN!,#ZjWFb(k>т:[UMtmx=)&u)QTID{xM` G1~8ZZ\E3ϣ8 2@![~q<*cQa0+wP:K"?tz>|T83ٜ+鸪 fB%E%c9SxKB*uĿ#m]}^=* tC=YH EĚyBLVSވ&EBn 27jGe"I2Ӫz̮;4%s?6-[U\%$󐬺4ь->_q דZ1烻z?nnTX/MδV q!5 T""Rеμ&8Y>Yc-A`@f\8U5q]PKD RGD}sb{Ϡӄ9FJ&rϚO@1ZJ~edr,[>FR1ahuIN);읳&}|Zڐg pX{m͊b%,d-Dɗaչi hbÄF(*.:~/k&2a8J]%h"+3Βi8YE#~T{SheZF+gP-cb-:5e[.iQ!(r9pq&dġ!,+bl`¸'/l'OltU޷H} bMQbL S)QB^UΏ3O8^$sx~$%㙯E݈ AkR8!⓶d,$-HaRAo}'?Qu6Ik5f)˚̈UsUXT]b-Ehi9E~^ zNQB{mX l`9ExXM^ځ[ fwQ)E;%V,@X bw.}0ϭ;?ʰI1V/@z,g&ņYuXևhF|Aw$k1s%:=BZ3P&1:!.BP*2{AR%8`44:4 (O/꺸 #R>g$,rY73c6җk.ƹ)|#ϫlH|Xn8` 9dS삥w}ӗLS5.Xh䉘tZ6Z씔C ')q|^{LV+0rflK-'8cZ4Buo$6iz!|(+$cOcnpڛ؅2cHCϪ+[dn>g6oH ^$xPQAJOB X_n"%%6wS<rS+|.Z\MI6{:6yCsC88䐞PnTi)~BfMu^˰1H-Y3J^,\L7.= dSNr:0yeɈBB@ d$AR":Ol|]f[ h??]a%0xH)(ϦrIKsFHVXS1=7i@5NFZ(դ9 -.R`՘D'czly4 83]#qYX("{KHu]h%WWׅkƑ^|Mc>J"wTۚ Pek+T{d>VuI؉nnMM+Z11F6(PU*w? =ZLaܯ礁VLw碲&sXBl-P\,c[Z)B! EJo5zJZV .JC)؜v"\餲M)7/ K!&cAhٴ.]5M5=>%\ 7~ӸJ&"6wqxc0u@6JK&ȝMExbeB'.%w8m/1d&V¿%!6!-DSk6Y 6Oh6rץ3C,Jx6e9gqL<$[dp ՝`>%=_}.nv]wC% /C+(u')& oK=d^;%m՘P)4vO qTn+E% NSdX@#+NQJY sO3ȵ,:Z?E}?JCی6{ Zfv[czXU|$뼐_ ^|ݑ4$$ $FIc,RZ+%nZq<}`ضw٬(ӹAd ;XO%1~%blkg C 9:৤S7 ,ϰT˕ÎAFc6NǧrWOEk̄J<+ɂHgM)U.ݱ{0*)kt#o~ -ˮHg5φ8"l2Zb~J /HHLܝB0R)v~006ll %~L@lhW"V&1G`:Ȫ:ZB|NΐPTWocRԽzm&iƼMoBR: l4x"M vPT)b^Mb>oJơFV(h[Ez(kro֐eqN(f)~n dn"QL: o.ڈ`UgT(!%Dǎ. l oՅ.kt_O,HkboK!fNs6dVi2ڪ^d#nSB $'}*kL bbI&h!i'&DGdGFfǑGhT,$A)O9".qMlRGB̦BL,J~ΗͨO\P(">NV@?*doQI &]DB4(Ԉ2*~$\% Lˊ,g-gT.=0if'.u|}m?x#.t6Tr/t^.! nb1MJp<"꫏#mT&~kunPVf>I?1W)LBP&-R0o'(*Jf Dg r1s@y#DH(/Gh7$Rlۅl9rY tusD;VoME-b!Dpzli)=Җ  u/LWWU @mQHbsUxz)kL\ I3D)s3%,r "fN3 dxPxBggiHn(,BfT7RSj/Pop!^'>(ϴĥВӎ[af!JEWg#E/g Fr6cʜB䧧>yFbD;;5tkPU^!t7$8_ʵRI1*mN*؋)sU7yI+JU)֐:|("mCn!mgmq`(}p+sr}sn N@5W#HR4Mzt 6Rb2ܕ66u,NF+G%KG4=;mem(ʸol3!a|L EE=8p3oSԸOYV1L'GT TPo6p!ŸWd~;P:Pӑ[Vc L7D0*n (WPt l,*B &!%(sEɨV%Ro"䂨E.a:  e?hPοFz䬖qEp7VN7w~`upq&gv)v=K">Edm$_J#ُaomQɆKc)?oJ")<'GV$W|eqcI9&F4K5`UO#F"h9 BiR2Y8*}noH<aCdF4HDjXlsٲQ^"ɢA*>xo"HmSP+v~+ev/Q`_hb!_`Ӓn&d_n9w0`8i6tJ% kt.Cd]~y#B#Ϟ Q'^z;4Lgp"GNz:ڲ8u9hgsfd,kXӔ L W c=g)΀y՞$!'+qTlMl(k?&˹JCNp(:&?tlEf` d5PheJ2I/RҦwќdUJ?BfEJJY;,IvGulܪ)s65DωVE'ҰR9BV6?X֗s'j)aDX dnY؟*驿Ĉ>T]7 礨ȑE 7Mmngc$N(?e9[Gdצq+ (!0Oi'կUyxb/-x.OB/}_%΍;u{5{faX:H='ZSyf(QO N[>8.\=2q6 M'To.ȳmȇBhmBGښץZuܑB(5 [ے=?@\jm,K }YI}8kׄ!ׇhbz!x|){J~`,}Ku9!hDbɚZG1t)yPjem[gJ6wZ]w+14U01?Cx{=]C:5ĖȘmj(Su[ykbܳ.|2U"m o[J=4@7Q|B"""Hi!-xcZ%9oE;f]}lZ"F:jVpѕOus0MUу}!p6R UC^vN(>>xOi tEq˅Th<ܚoU]l{>"q(C"9R$#4ՁQqu`9&FQoX"=-%AUB#2j"7*]N.bftͻ&rwHH/<!sf,ulp p(8?4 BP<DV0?4~+>4)JPVD2E"b(Jr(<+C1Y>It8nc:ɢG~L>, <fPiڣLg\)$T9f3wuo/tnMb1نCYFEwiPIv6[0x7d|gat.m&̀&ӽ;.BQtcLcMe;p-vIˀtx5Z==^9Eڇwߞ#Aݠš(; NHh"}(/z&.޽#/ ɳ?` Db&؈* &4ȓd39J6Kr\ȴ46#1T?+Ʈ!B(l l.2+$Z~ՀDΈ2DD#rs43~*)5N”b(=<*j f3 8H".@*u6jbxJgT,FlrUhQehX20VsM#J[o75h=Ӹ r H|c(ww;^çw/pjXGEO̍p;+I&0C1%h.VCHcT522cs(KcwdmdM#(P)JÞcs?- ܖ"JÈꆪg9=,5n ~D>kTn2XR ~ttVU@v=ve+F)$Etr0nml&"6p!D;>*cOEKsٍlM/sfgR0fu oVwæ0z9k Nz{ o柚ŧ5)xC8 S'a H(xI cLu?r,ٕs4)y$IK3 չK$Zg?Rx@~.EP$fl$BUF܃ŧ&NN"%!fm~hr)_wgGN9be)JK4U#Qܛfbl H)]x(5*1M&㜎l9W]M,%|zr/qJTL\^&g9/v6LGB2NmuK#gZr1IlK!ֈ\p^ $EI5lfňpZ|6@2[^NTHoIBw.R6XlVc R|۔:t, 0KM&/,HTrS{S?gZ\ɋN(>hʤUJл,ZtN{]}\ź<,Y42>Dܷiz{ʜ0uz>ػK"ljRP@&?06FRk(8FKIli J6uFXuK%G؉\d gp!FG|xG=76h/ϱ2g όJz &Ĕp$H1RDM2sPy+,)Hzͷhtw[\ZWfP=Nb!;TPIP$ZʑY=;t+[Ғ7mKY ! cdHT;4lpnI%eƪe_G9seSW)\TE9>G'`׸#ŋu\@JqB8huj;9>?l*hUs  ݲ>߱:bI?U \j<ͣq([T]?$%Z,%+ITߥ|,J: 5Xgc͝'X)I@U%Ð,(yA۝蝍+I"Y JI.[-.+yؼs4P~3i 56B<돪b ʓcMɍ9;Mj)8ևj0j+ ak?9ꘗ1:##B\%%k8 "5ȳ$P/9_jzO')y$%=>Z+&2c ;8?.:d;襷A#A+;>ޏ{.ĸرZGLDF8El L/ Ԯ<62Ii湠9S}1 yx㕫yNh۵Ppis#=X6Q('L\EԀ/bY)(‚SY?ǢZy*4᜺^rA*Xj$w]+ 4C$;+sDW6} G2M0h8 *?l1t |p41ȬI ,2"}}s0A=a63QAd+f4ǒ\rWR!%*iÎyϒBpCX F̱=$eU!K&4zrkDFBBn'%@ʁd-86t5̯b,t\ YE${HBۼ89}[yE[Cl{+}z /X8$[A[N=5ڨ?#J!"\qwֈ:aˣHR< }S' y?1uFLxẅ́9?AYUSPә90(DzȖCb>C}S%K%@+? 눦ųSKר> RTF2f-TDҎulB6C+"BOIk,5V028JUtƻlW­JU' yEӑ4py K0[P 1=9k9 17ĝ< 05 Y#l J%BL`ۆ壱8`dR$r>DTj9@ZmTSVGaIʯ;cSq3@#;Z^9D%VAZ(JLM4%2j%wtbaKCy/\BR+2#eڌ)M8;R!r68۸}$)e2SuStU(ѽG1^bq͝B 5}ZHA,-O\WڲP]ܛ@:˹D*i=ͪГRSs}WEKbѴx„CԧR u>!\LPIL:q\$xH(68ƝM=2O˄Ev|y ]Cc؇@~0k R- Wu~R҂ +t 0íԺMZb 5βRN$6 Srk_0U7dT1]tmYC1CZ gO,M COP ,ZSs5 [=C .g;Eݺ |=A`W1E(ٖD 46;<̯"4ܾ0=w3 !D|qFFQVbn\\Y4` ȹa-\BRCOlUTF9Û1YNHU7@f`Ce<~:1aUa ULp~Q8Bwӑ@ {ZɃg&mKak[ueTbp& 4`r9"3hzr kҗ?Vc8, V, V"_[޴"ID/ӒcWT 6d?znL_p!{P@{Ym_K%OTP^1בϢ=C Pϭͻ~Ofh-kRѥLZ.tLZWO-&Er_C`Ap>ʋM9: 4jjF-FbMxYQL4KfaL:E%bq4@5o#΂ε9o8L&(^e=##l"*u&yW\/̇˘WW۾-ytveXfո|;S.]ԸE`!(+Rf+Lds{tlνɤS퍯CﶶO.-~Ca@/$ a@8cD_0$U#@(M# z= CpgĶ"9TH`hL(?AI "mAI#Rc!>59=}B4c?bsjUI'LeSbAVb=C$qsYePi4NF#Ҩ|\cX*1ƙazLgK(+]XYoL31m~JU_Xi[@b֪4]]TK_"jUq{u Gpרy{=ήrF8jlHþ0hH4䐻J^|@ T# SCQԭ8 0+PB HVO`CB5<DJ G]![]DpHV&qgfOڒ6*J,)/0G) Z[@Ak3hiO1~~+"%4^ɼ"F+p2*xC 12f$%yQC`ID`uS7BE!~0*[N"rTUT''>M(gr#Lh,%&ɖ*&HLF KQ К1wHbc/ʚ/Θ8ąY*?Ѥl#_!J*ʗJB0;H~N0IwyAG<8j!"h]mܵ`#b_,J? U!Q:\v5"5YBgQ~q@]s%MbW\\#=wRyӘ:1+ 0tqYkt+{,rK #H X,}&avߜYg&w/}i2QX&.6D/ Q sAgkئgh ycwwp a")t$4tkTC+x27;2.p"/9?_x^Y $[kc;uCD(J^=q!5!OgFt^4@n,ѐ A83M y>tffm8iZFfrϨ(B j놎l D@!A&hZCd@ lӬ Gvl `PFn+8Ѝ@Vl¦c8b, $ij^^Xl!V8% G Hpli򒍮,,Zⴊ%fid, dph*4ۂp쫚D`e \`UJŊ(fа@mtL'I@&! )Z (&A Z$2׈C^M6D_h:o%Ƃhjqlk6иiăeN.en\ToJj6N.nc8#p݌ƭ c CO T@!!c(t.vid̂[h% @q"LM#q[MJo/)ɥ'x8, ^(~ J1Q.C±0p4chZvnq'邪p2I^-O cz .D+H^ 'lx\-PPfy# fD0Ƌ2 $IL$h Kh°!ī)[0h*lHɪvmvU@JcNU 4.M.V[~L 0hg$F8Ȟ}‰/ p.O,Ȣfb5 $bq' /d?k-@w+TF4 2.GFK>;Nxޫ3" } MpDp(3id!h 7E^ RX<`HeFNJrlN:)$.C 7rMl$@&f X:m|!>MtP(>nKjZ3$n03:04$k/~3Ok<ˮn@]p,**ZPdKRbpp,(n%fTpg 7M9 %MMSf(b$iK* tASs*A~IMօpމR)!,#XDbB5@Cx4էOG3Jn/NI-Tp`͐=)>HErfO&LNyk F(W#jH½ǒ d M9Mzk@BO*vJe ;PnbNKm"_JZUoܩwMbM5Vx_𧠍V,Lb"+zvPq>$ ' 0f Slp94NP5L܄C+A Io SN (g[YShWMH1r`0 ""+JEPB Jqa[lERr[KXc/cD2b!w64,IW4 }R5NU*i:O׳NCtrtW7~,@3"mA!`rEn;PcO)ZgPv1#Qu>Ot-)fd# e"-tf\r8KJbSqV.e's` NL pH[X6fJBtL%Sw~-_7<mOM$Θ"qdշk\lS hO)Qu w rҼGJ1SzyxaCԞ{'Xn1 PT~rv$ج-F&JP^J4,Lvr76 C(PAϋbZO1btLEטF(,ĸ#$9YxD4EVN|ȋ5Vrg/uq$$ 7!k&[ Gs`mSxx3z?Re+DM(֭ L*͎+X3u3)~@;ur &Mc;Vl"&#'{逐D+0rTlED0t]d`~kIS0ɍ~2r72?s(w)h/)3wX(Ym "4&uhO`J) t,d򪡙4Ẕ4r]k73{w0 hݐ$q>m}p#`nrW*vd՚+/E%tz @n;:%`N`0~•yZV%8?"k| .Byax*9;9j >4-$Rlc‰4eZ$6te6anw[3!3oI;[Lg@%愹}\sf$Mu;VqC$&g*7?IQ%9yJʲVA$6pO\cI1/ |H[ 2;P#pD%.4Xj<>V%Gzwv7c;,7u;ዓ"OK ɴ?h;>C0cr2 ՜;B^0CTM|-rԝ|wT/4# G uTAӋ)M.Ef~ p8Xr3u3ͨӢ'rcBI 7upS,7\oGzK +w'Qp >$kj}ipeؼ>D)P&tg'=rK S̮.u:,rk!7硴&3ew@mxqwrRZp$:.W֫6\-`l2ⴶ<(u _\H N-rLur1;At=kM|+Q,%r"ZM ?OmS'$Z[|",К-`Q#4 =J9/B'{9!8PBo (Eߑ8E#/ȓ ?e@$->Y #鼎)#O3f}&Q9xBM$3I9Tb!TϚ8!}WUhUM_O␇P] T%Hf49N1֟q (oTqI( HiQL14Rr$xxUmI{byj"|iɤt̶o˖qZg{u\Kz2f';> &O 䥲?~mY:$`#.h%l;$))[.j걿IBOtk{ CiB!Hꐮ.I>j(dlǀ50ؠ',6,̿ NMPXhW61 V:tɌ H)D%k$oOi}weCNo:DןV'߫QlV&Sץ#2/Ȗ~x =FY wVvDkYwl]]R55+2//z&]`#(+^"i1Bh"GpQ [!9+`D+Ow``&z3 `|`4X \BzCM}9"/|/s!By֑QrF0t,YT1m,װrS! T2⎆@l0۰F"[c!+.]ZlYeEBbj2*2$@ո] rrqwߠ b.Q!/4|}K*p<s Yx98+C N34B)wpR$b &o+BhX]08&)yka48HtoEdO!"+'$~gЂH~}%4!\ { ֪I{Qek"B9ЧfD1m2ȊM1.%9 W*?_]p(a4SO o9cuD&e>CZbTzeQ1%HG=ur o+&=JdOp(66ˏhέxlXpgYQ4 N3%_c@jGkg",5T޶*H$fW,@r?@lw Q>]}3>7_BV2:YF/p BIFYmڹkjZg7*%.{R͉kTM$R{jM1_1P;^@&v>m7NQ-I0ހ [V:k[wp-15u2.hl >ʄ[ÞKsx{@d--3 6o}rHf[K#A<:61$6G7/{mf+5K=XI\en|t*$)eNC".Nbj&V>GI3M8M-$MjTte`B\/_]*c1 ָfK6e2,I V&uig@@k>V7\ÙGZԙ]3n~2HV|Zc>ƴ\+X>c;t? Jg|ib*N9_} K?7H&#*(Νh(!"Ǻ+t0, n/ճ:˓!XRQ7+t3*;7j>3*6=~FCuYZFr"jIfA4#(Li W|oו^Q?A(q߈5uWI$SӉN+؁CDr\A9 0(4 ΂Sӳp>9Z>$6LY D#- 9u6ECs4:V]XWh!x>15+t; m !sy/ኢ 6+cK(z,x(o[K0]R1JPysW*I-[]5*!lHHF҅>Џ5iB$6[ԤܥJ蟲 Dה#R,(:ǜԈXUjɉmP)űXHDC?3Q.-qҹXHɠANt003C8G5 B_P֞!ƕW%xښN)@jU VD͌lW}F@G3EQ֧'Mm)?sZK0P-WlWĎ"&ͥ G365 Lm[XH|1+bQ<ӒO"Y2hI喟J=/"!ts.}Y҃F!9T 8H)J2'*yP-PE lJ} Y\F./BR!Ôţ 󯰱Z 5TU*G fB5+1:Rs7u+נMjCL;3V‚* a+yMKt [FBCI: G-Xb\҈#RLxeewY7S?hTl\c#fY"dY:Xӈ#x!q?jjW ΫE7}=MڄN\É^'*cNH%nA;|Q˯d(r3 B٥64*ñvQBp̚[\cwW62ӯUe#X@q]x|̞i* 7 k l(g2I)ˉ)gK.vbQ '&|#0.zzH%(U؜PE:YAGaT".GcE, }gF(IY3VS2_ 5e Ҫ@*&J'] sbڇI:~%Y4>;+B?|B[ |(1.]^u5~qD5x@&Ci]QI7KnG[i+=Z pITT9Zpkc =`Jѹ(nV極&Zj"Lq/z7/24~rp?izԨ4DBQ6.{e+KeqE5mqˬz2N+H֤,jeN14pc2 &5BIXJoA [yb7VyI3_XWLB-w^Va')W F[0+7Vv¤͜<Ї^|six\ [ }̛r3ʩ#FjGnf=GX!WvT6j ^*ռV)a/WFltG]ejKpmftc=^ؑ9ӋWwWt ^ KW}0 0̘R!]nU^v3yӼ9[GVfK5T$,(! GHm")g, 2Z:Cy-JJIIdB?Sqwօet/'p/(Yi, wb-ǹej_z]LyǽuIDP76&҇Xy.{ \$`y~Mw2T`l%'Pӌc~x۬Dj? XD$ |C@pE@Qp$d~cѐ$l}a`3KcCxwkpMV鮦~!n4ŶqkTb`}zVԡua"MK-Ӈ}"!ՠVK>HLa >$Uo}+ς혅*IwAQ$FAF}т/a`rqUDDR~hg%c]^yď䬤N<37v# ZH,4vܧ|ODCm Iq$o!JԲhZ^դ3ًÀz!RjZ Rzd`Ty.`T8I@,A$TW,ZPƤ^Aj\N[M>9hZ=p)=)[vh \ $@H҂ q"i 6O$ ?PW6 Da@V"|@t @28{e@ S6#L PZx4ކ F_49^#­^OV̤whTNdYRr #-W/0x#*I옩$i4Ϊ "BX+S֪n:&<ɟ$i;=#lѱJ\ȒIHPq$l[72(0&;j)&tĥ&m S('&֑K=T/Aꫬ2`QU?nނK<[R .pԏ !h#:C2`',SG ̇ʖ;Yj>2),Iv^ H4,Z Ȫu /천k=f>ZRr0(pNg.dH-'o`dggrβ!ͳvj(ta FӖ,u#|I|~b-{|;Mz6 ,|`&Y2~J [[ۇr<I|[gȚɴH.g#`VV!(9C { XJ_Q߁RJ\xm~Gț#q]{]BJYPR+66d\INǖ{wl2uAYJ}#܍Sf BoOkԥ"\J8ev?NQ]3꒟YD[!.T -Cf*+eD#7Hr:!)v|i%jp43YhP\Gbۈl#9(͇Ap%dщ9Cu$N5T$OE4h =b:DS0ő7jZ1D5<T+V;3PE *ifleSdTavlo@l݈sKlƧe)IJ{[ʡښpF$!6mEBUI@?Y 3D~X "5L)A[uKjb{N55V$q>R'!=oY91>>2o?̵d(g~s5SP)̦=Ϥh?7\]7qJ;^e1)fh y'(j[eQU9[m˝5jȼQy q(NuTRle=5K}e }+U""1ɶ›S 6#ItkTd kg |"=0:6KquC,*iD9$;NDuP_FVsRobz9E ]TݗY<{Dґ)|F]#$erG&WLGhc=ov}{uo`FKN%,Aqtk> _Ӊ۩1\5>^FȺW}> Sҿ8iՠnYe,nc:M6qU+g7txmg:Q,2VbUmwGEڴ|@8O)YD.<* ꘍ҢbJ ǐ.̂S?bȈ$@Kˊ2-jgz݈0$ĥ jȃnniFC(Y1%WJ3F lF>Lh\&P@x*.u#lnNDа'@HpINl6ʪ:M*M"0I `Z"Rʊ +b+!@jh>H,\+8Z JR dʞOiMJ]ep1 b٪1`Hg68":eЧ&.^=DLԜ)M̜G&5ŏ>qd.&O$"EebT=Oe&&ˠ~[n2t^nCJ紽W d 1 /5FL@<e슘U!ED!jf!Q(Oh^`b5=j,BFr=Ѫq*J#(i*?m ||t h"ʬ8A!fI`eh` γJO)yz$#.eϲ=0$lgp>)@7jʣ1A0p#$_  HVcXyLp,#=ƛGPD 3N4-(JOVMJ|24nҶR>R.~ sa0:heI+K΍Í# VcZtg'OTމrg ʟ]EG.ȳ;'WV`J@C Of#R$º˖Bz̴҄f9kR2[?e$&e Epܮ f%CV)Os *)82Ig45 T"#M71s2^:R~!  6!*pM%p$tHǏ ,lg7Mnc 4L m"*E8 jb4l>&w~a:S6ώGJSҿT Z` *e!Q Nx/ tE*P}(|#41iLp# L| \ѵ j4 L2I$&2 i- S2 E9U}'#+蒱Γ?y ΔU>73b`A`·9j%r''S& +\i)n#?Aq%qf.1G=,bf6'4R$xvAGu+$D ȯ*9jo2L (ö:RTQ!W 6\ #>5O>4*bO30r&lϱ:(IukS\5 *},Mn7n莃 1ZF$)a9 3S/[YŝMzLXɂeT'CY]ʄagKD1>`STejB'c}Rsژ>z^"8\$?(zhiRx Wj_,)H{aR$bSP#Ht%0"v}!/ OZY/ܸ'DBR| m'>UBU* sp#xABmtY4kTE7@!9 '\ABbt"ې}s`2Loxf˕V:%+~29b$ mY)tnaU,u/4[ĥhM?ncm IUnj!X-L[pRjuA/BjbꮰN,X#,?`C|MD Vu2)jױYe-†&vN* nJz'#tf9]&%(Y#ȭZPhR[' 胩YnɎO*"jb32>2b蓇7H1ِWϋQa-'KCftѷ8ܨpϩ*啱"k A.4.qgWG5ka=RƩmsvVZ&/Yx:[i?",IeK뱠10T"Y2`.#ܬj\' 7[ټٺylTf7 ʧh>MA/6eυ%N"?w igUI8'nlPu LxVlVAU#g{Љ|ůb]< )kUݷfԧ{]-qC:HR^4O{\%!?lދfjE[IhxkNbx#_kYR0"棟.׎F-IDeU=)BU%E?)Rܲ&yʜb6@HtNVt) ݿM6L ?TCQ(!R$$X %E!$%"}f,%!p( EQEc 1L+JLe0y8&5Xt:[K df ϫ~A!ϫՖB"ȥBED_8Jt&2mS!8eVe3o GjťJ Rc.<\FŤKHe_nYsd ͳ`kGZp0*b=]<( ͫ{'PNȸQN2O &-ʮ0p"&v 5;2R ! :HBhc|P2В\/ɂx 2J (Ү0B й ⋿X)RF` $)r,ǠJ,/)颔;-h0+$r&9"xT< ~sJ*)TSB~ӛT>Ҡ#-7ICI}ZFisJQhGT3fTL%K L=%\Z>hv) -pAҥʝ+ҘI6ܯT4{*nd;KOŸDVK^vOKT6 g tT<@[tkr;Ÿ}7(&M_0\TKժ ,?bQI\l+YJe8߀ِfHU3d*ܥ^;*Ee6u=4TɓlW=y,j$IvGpğwÔ&Isr|rd1⮾k5r!7*:"~t I4'$ʢK˟ Zä얎JVuLXt wVo;:M8L(AaHPNr=#b@ =*H Q]: S^!x6(+ۿÌSI xݔ\xYmO9ҾCZAn0 9 >I\]T6D}E 07&#ƅۢ6ہF: ,/?ʁLF$ꞨEii$Qɲe jz֞Ni_왛Lb~-8)Xq*V҄lV;6bҋ'dKQL-"N H2Af|,TȌj!`YG yCD2Jڦ*MEfC ${@ -X%~KGq9LK3-G?3,}%\ÜP!Cb`\S "i$4ie` BU 2׳+rZ\t{e6NbHIScYlUx 6De1O`Ulu:rϙ' BS"Ω2ˌCOF:}RI \ҝL%>]koYX̣rzI3*_k_]hQS·F:\ij=uuR&0#_h1 *k2rB(K)BRWi$ΨӽSX$ڨZ`T,tck}[${Ĺ2T%uTdƯcvBZɂ\E4-Jo*`\Y;[JEIZǧ7EbShq&A U4zc%BQ$T'e$tP}UzR1[qn 9d瞊T򲤝BH%v7h&bm=Nk:d $sVK=q"9*>_,dMfQ.g2L -l@nU;4p5١CڡuY@Żs%-3lJ#nWUZrR$Pܝ6?bP4' HC\ dZ>iuI._ Ue\+SCMYS/(u&p<`NZ 3mzrH(4Z,7}R1EU| #_2!tҪoLwڣ_ xyilnT}~dʚfH7h76|LIxZu[Kޝe="l{ā!YѦ3Gzj/A`h83↜&j'&>#EPk=ə.xeY4 #j:E5rZ*Xn'"88QU[@>vݩ,ù?:=3>4L͂<]ExQlΡ୓::NZ NH򹕞 jΝQu2h w@JL%h+P-d3#]4U]0VV$5oSuH֤:UBufQ)حvY) < æc{q#E7QVIQ+MGv$_hFnN`8 nrӺj<egX-Vi1UbE)-0IRCr`aL^QrJpSNc~>: *֝>z-i0 p)`-LRQ t"j{VbiGɚdl]ud}z{E_uϽNTخ`?5D#TR%CXݼ$E=GpS_ 1 ( qo| P#$'ˤ#^=4##$"S՚z\saIl JY;p۶н2W?}3;;_E\\ Q½3CYT0\᲻^JеX-A2h4#$6̉ஞ{ 0sAVl;x7j4^fKx=Z6xjzQa>^/܎@A3g* :Kۤ6h?nY ,r5*SI,7ΝlZI֙i#ff H4i|PV\rCV&***M ]YZhC""yDfW, o_Yc@(ؑLs҈)hF:֠ˤ&OJ.&::$oO Q˛t.jl@r& .*[{RIde9!"Be#+j{)&G 86 s8Hz蠓c)h݀ \C3l\LL 46 ,&@= NMJʖ#\"q `Gd蜂$TlIU,V[4W(J+jL-=DEtCE˨M8 \9$"ʬ#+^61$m9WȂz:U7ЪP&ePʎ}PhKhbe%'4JڴL zUli(GQV;;3ةWٗ.!_lxdv2wɜǕƗ]E1˙c#M/+.&D6 DVXXԣ=ƭ\S$N 6q!i{І@e+XpC$pc*M?N=KU\SN "EHZփfz xpurW9!cTnIWiK]}'`֑"uf#մUKh5uOX$PU !48B! q//jǭ" osnۑ u?aznquveϞxx5RJe+!YtYG_'t"MM% M'gD5 \cEK3)")bq8NE#Yrԛ R09gKyϋmߦhf:$ZrFuPwH"On5=ka}kx4E. O BmrvVyUX1l7 g禴!|42._P8 ͼ2Wa{fܯfKy\}Y[.o4?+bbLj݋°c" L4P%> \id؛N☃p0FCoξX!:w,{n=*nmC0(m\؃ $fN ofaB)HνZ(DMZ*'oB\g?)j(,> bGZP o&nH iֺ1C!@/tl|\lCp3׭m'M],Z-P-} *QGRJ4HZ/ w>s,,FEpZ/r"-TivƲv.HR %/>8G2M0φHM$qHd̸.*/Ύ2>Y^txྋ#OD9orNk3,Gn*J2Kg,1^̰ BGTNR.,xL)lb/18b'8#U \`3R+Echw10m#2tgin C"2%*Q#䫯=E)dcdQx!:Q0N{}a R"H{"#%,f$'-R@II fxW]% DB;l'" 7,Z/huFͣK"&UzR粖,xb+uNIAuN`jIRV/Pm.mj<ÎdcIku?h`4=Rk9o\>ˋ&t5wHH{OyTrEקeJ*Vl}5 RYi4U-tdbUOTfFH|v:Ai+T6tODYr-P"lJvJS2:eQUU۷Mpu2ٌI6Gb:P= 9{%oE.8sOhW qo!j@b\)&u ˛X4Gdn\T b_cxsPO!|xk;e8tj>!d?B1]fP8eqDƟiFȸlXNqs]pxڷyP=sF1@VϘ6i>UL0I ؿ.ص#fۥfXRqzj8roBy$u)fz\8:|%KݼJJuscߥb=֎f֭^mWv"Ȧ-HI477$*-S76VmqX|B$K5IEM&I#1]XEMGoG%өniTQvn GE'p/a*|%KEiaQ-l\!Qce4M5ψL4Maa_ E; 1h$lByk(! :p!+V~ (茾" d#m(mR$D,DR,ߠ!LtDAT64P$L$2:С N.G(0R.B("\ HqZ,r!H1Ѫ\O-Mb}H4=hrmܙ  k*F ڏ7tH/U #Qϓr6odxʀp } *:uO‘1&y<,@6I3K,IM 7@>;R("#zX%<ȅFzAp*9u5B ,8S?R<6I ͑.4)`O{A3+v] C.ArEGcSMUd3hRd?mijbw91Ҭe2ܙe`ʷzz@ﵚ\=$"e2Q_j4G""e'XUxqM,%WBTtܶ9@Wn]I3HMWEqrSɷej,1+ _붔VW6kRp3 _z$:oI\$("X#BM-y;i;wtE1svd6mli90s["uǢÀJ 3-0@RjҖzx 5RB?c\m&أZe-ФߓJ0$gi8gϙHN!:cnrjᢪqZDPwV42vM.8@4 lGN?kėY')O*MI#UmG١1$CcQL55b|NƼ? ts%5&KfmtHSy7mvÀa.\iL)fb;)Y_'6&Q)(w}K[mQ$sP}%#H!.ȜcϬ,rAˋ`7f%W•s1|DDz O[R$ c:bU Uо,-RDT/K[rUS cܬt:W8Bhuxq^wCu}1̷EK;oTU2D"md n0et1@ݱNh`>Tڼk*thCk^+T4dZ|\Tz(ʼ5~N֤RӤ+ ݔOrf"syЌӧHQkڥysb%][U]w7ճaXy[1g0|>h$bR_Q%  0I21B𳋰'؟&ZH q c,;,.qM*)ꕥ)1p3ٺC88ݎ݌7KD+.t[±iR {E(~jٕ@;rh44,B:1&J :&p+3y:[8C["I2|%:B;9+)[ð>d:U0'2a!D1w{5.M +T=)p:75L3z:sE>?a*mGpP]%.6 d0Be"Ҋٔ3C !T1k?/迤-*-xbp ZyvS@rsYH!+|ࡦɈaiC@:iDl+?"ޠ;EZ1i!(:ؚ%$J sH :#-$OóԢ(b0(x,4/TR!<7\"K19w+E7-'+bB'mYLұم'CKٺ &:xStnLؓ,ƣ s"!l55N"#m<#Q<XH>0(WDiDڂ;MH" ~ iEKw;ʇcQ8R]:D Qt;ٌON C~=  GOܰI•aK: LmNB#)𯻑m{iD:cD6ab<zARJ D,kc7lN iR_0lIF4) a1#LRAESrH\AkúH-RII3!M#=G)y"e $cT'tRlS QNK- Q8CCٔjʼn-Ӟlcd 9 -!ЯH' "4h' L+j֍q.R=I)؅GpmFD4D IS4?rؑP=h c (fp̀Ien:^+;F ti:'CEBIiTBet44USs]0*M0)28d*a tV1\-9Eai/ ˡ$ V" D`=C ݸ22$( 8BKM"ZJ/:{@z/)ٹ o-ծjɜ%ݝBRj٩؈uRL[!'Eg_%aʐH])U)50= _C?ɻ{zyVЊ0Ƈ :6s!]R;=[(<)|ŕ -HNOѴѢ N<%d4aB @݅ &C;\##D!:YaY8hY:]Ȕ :0?%>"Z#Uܺkt-"1 3u"*Dc/YɑޣWDmL:G)ފb# (}<7@5c%hgI3 ģ%E :ϜSC[CT .T<\\,=ɦ/FqYlE:aMLY3Maf@\[}'꘢L\N N;yC-<wV!C-.X>^G(&ݝ:&x8r'UZ^dN[?E@^d5} }-y%Є6#`lL"%1ل0'rsQè;,-)ANKS|D̰QBbUZRg?@ʃDaIK| P$ g;m4#P)6(~4T1f+KvE}m.6$R-Xa"MH#` (m}Im6E=/;IbL(bUEa "M# ]kL\2* +MeKR SIC3&ljSlV˚<'q&lNdTdึ|}ҮAe0f;J5jX-\$#d%5Nҕw[ scjϯA*IY.d6R m*iɧu 5ݍ>/Iȗ rm@3uԖE"ܱʘbŜmcӘ94F‡]'=}Zs-AH0fn80H֨g|@$p8MFQ\yIOJPhI>㻔Fm*8ВO$(++prVhhqN3pB^(Y7މpW԰cv|*]s#6b IJHul2u=jrWFnB6q(ΰ;e􅾋̓$1ؠ|6Qml׉P2/6C]{ӔKT ,N'^ٺ-l~[ #M]20&ay*'(o }'\h*PAR89Y Ew܋}c??P`Cq'^ehk_Z?\ I-"֦NCndaf$*iVH~j dk?ka+,^UhfӨ;3̰æI 0oym+.F%vn;ʬG{c <^VR/4KK%xHo<|h֦iQr=]TKfպ[+:Yv^Of.m;#R꧂ !1SLhVBK wTV0RғV|S0K:t'hQ" @LX>uG %UŞq޳LK.UnRV#VMw^yu92!|oRTD>P^ I"Sޝ7뀰xRfJO U: GӝqZ:dJ߶|k5m8eB$LSٻVD"i0Ac@l-5k_!\CM`@[dȖu1wHm(ƒhfx'٬N..'+'_vu:`D=)) OyO6Q +ʓ}qr{5KuգLܔ?pь|YI8VeOmX& ؅ӏz*i,/k "`&XNFZ? *+\ڝz 0x ioD0VMˊq(zt:' "LɈP4:KٰgWjDa!kFfQJԆE#6cz i2o2G.:Nj:Z"`N"'+ј*<ƎtE+)Y,,$L8[ H &3a(dDP*/ @k!Eвp6o&R;&l~'jV1/ **"l&,dMLd;<7;221)g(!,QoQpNbr~|ֲO:`; 0ʉVdxCDd"p*nCcOP;+*D"(xA~vG1њ|e,kdL%StThC^>ZHV .6bXBd,fn]e. Qospr,uD7~>\l8$KplQlru3L'l`4 BORT~àB/ ' SHDD LIO"H: QRLoRQ-45C=5&$Fc[O5kb^c B(opuΪ=29KL"(B~#s(b܃tԢcfed%,8.Bq"uMoshyڝ!NKO-P(:D,/P 8zB139M ?R.F nTL0ʈUP pJ~ ~Iile{Ae%JqLxt~5.$ 2< p׍|r%MZme}brk;O踣Vb lF={/fTU^(b0;5&+L*)oRR&?ķ;6pU(Lp/# ,qnR|Kk,V:da1HS>8giuM vIo""8I^6!AmLД+cI;e`TL5PtTr!M~9Bp.^N(_,#ͮ)S&09comIH(PVȀVmLeՇ&HR&م1PIkѠ4BxDW]gWp'9 $Õc z p>e="IƑJ1b6 =Յ+dt~ po՚JOeF䠴OTn*5)a38'ab5m5\bi$8)) LihW'1jq"h[cfb.9B[jh6b ,O xa8r y-"ŨUCp!67 !40Հ<:73^!C&):(.YL|N^9Z+/&# ܍clhDNZ}1?5xhD} ,CGɘh)qh5sXM. }/[28pXit'ⲑybVi+nR5~Y#AZJKɼέQte-j"`H(㠪IB-/+'v2HW*'Wa#V ڟ%2 J,yhM&es(@/%GKT"95.0bFSkGZJol_xۓ16u=sH*uRXֹMLהּoz9i DfceCXOu=}I' " i#cꁯXM-ѳ*򹧭L򷬼nhb{i }Ϋ9wLc ZC I.f$B[XR5k\Zޙ ~v] =Oc^N&4{4ێ8Q~a,a"~1Gb?8$r$?lS#N푧Z.@1*%Frg8ߋW)XZ$)L95e~-a-MM Rtiu) <_cD$.eZ,|i=T>MQk8ӜiiX2%8J4Phj:d90TqOv G)5yKj<&p5exq C,y#xR#f<*Vگ6iNOh.1h.NRI"_657^0Rj 0)/%Sm61Nb.jI\×<lbEY$j|Y#pZx"9!:ܴT(oHOd>qA`CHJ@Q%Ztscgؿn7o[ r\V"^X `0;% ,Kzh$30>jM QX쪹"4?sGl˜_z|ʗVjҁJzkS"ܒV^z`Voq?Lɡ `mxJ2!u\$bh0 x 6~WY gW)]'%̎t"2 ۸%Dɡ/#5aVeOVscŢA2#R^)AԪ?tJuY;~[zZ d4)ƒD 2;$BtɲQC9 ]1̭!:ܮI`H'cpb.2 raQRD>HWv#G!曷z7,ݯ6^'ˆLl/,e&YW#H\D3ߜ-ԃ6CST\q$4m<{o0Xxz )!#YZpp3JD؊Jn)7jxjNPZYe PGBIz*%"p;lL)ئGuVOCFsIuR Hċ~TTVGAHu\v^k9%˸EIzHAZ P9=~KDEP d֞ H;ƗȏڻtZۄ?gߤKM, 9SzKr{뙩NPVdM')&'U>Tr4S4ws[8\r#1[Ф+6c"m5Tu1Fh 1wv(K۶3 Oq󦭑8,RK Ƹ` kjZ=IݾUqv@5~k$_l€-x(ʙI $l?*C ٥BǙŖ^E4U6WKTq ̫[uC^ƿm'qͨqk2/# e&\Z CpoA> o:}Q1 'PhM!qȣbK(e. 7ȉ='6dja-팀}=@*{tpB%+'HLW nWx|&IӺg4i].~<{D<ay`)HicfXp`:jwsj>8#25\ B|¶Z랺 -#,1C9 z+5= / D B i:4ȅʌ*D$U9:ǿij=c Y`78 '񌒼@Qf0۽ј&[ 2) 1x0ys:K3;S'{eBq4Q#9brJ [2AЊDDc"[" =\8B_ NJח(';s93EVGTl|[>DܟQVы?:$shGY1b,p%v3**r PLۡ"4<[]Bl݁Z۞2#դ[Ke4M8p2ۋO2d/bZ+ԷbKѝRiW&C[U%DLs'vމqՃa Gc bRtP GUĵK{#(BxKSC, 6U-4Y]ҾͳK^ >g7*U%a'2cm ~C+h?œ+4ՎЍN<'Yeb75'"!왪k[D[N4q3bUIz:~lٰ)A JF :; ֤ Jc!B )@.!`mmS'. /(oC]cee N>p²O5BH?jY%% %7~""!yRnI+/MN116VBm1?;S$(Hɡ7TmdMy0. lمH4&na5J` M\+$7+Mga;$ 4VU t*i2$j>]1ru=" ,~h} I*eRYT"]1DG wɟe[3}7gFޚk~xBQ634FA!fN9 d=q<'wOH3Λ%N]ӕn% GmIID-q2RJ/ǒ73spvvlI8tTC"Kl"b%kC֕,ՈZZ#6k-{!^zxdDX_.([X$oh0}G:Cko雬E]5xzCns`Dϸ8GC#I Ia9D2"Q@ 3DpT5,_`<1CL,5 }Si(F?Q*T KbP"? iD*w"?Slb zD+D"UYD*1fƧ ލ"@PR u|gm0h2|B0+2_aShM40cXe'KLn m ev.c(T0XĶvpm+x9]-w3Y~pQ,DߤK!8ӟZ6z $ ث3i^:NB}DPAL[ jȒ@ vFN$ ;),PCC@"0+s$ L?>&#"KhKN<ǰa4l$V1,(.1.hDڀg *b J.(?,R!7*XPuW"[68$|I|>نb帢8?gh >/ NN F̱|З`ݵNHsH~뺶uހDj)mlb> MùʪȢJ1EhsoF NW%}s\cJK#ꦻ|O:Co`ȯv&21 ޮTc'KHԊ퓢qT.u4]"l8 rD!h!4Ȣ~*e׳hD%)A"o' '|[!^й7\ g(I,`2""6D]ԭbJp=8w~b L!zU`s!=N]?LT?<]LQ?r@U3\@$Tb@5'K\tEt'kq &UOWJU,ol*gH4v7niqzY)"P:d=NipP~+>2#*%LX2YK;)bU!"ԥEYC6T%i,g8ȿ+e;03E+C$ lГE (iLK"J &kɩXB[;i~`K(组<2ds:h*M8eAU1`"~?+M,8Mr$ّ:>(@1 rLL)2ɨH!FKdCv*'U vv)"ÿ9誾Z9LMa(H"V=mY޳=%Gr' KTKA*KYdrBiHp=_^ِp^4iA|!2; 00K\uX'YddP:76OB~EgjjϤFm8FlGbX4C ۩k]"tQ ^TleGQǍK!qh{5ءSuq>Si,a@'%QALT-jEn %PqBd­!'/JFj]U>%d2 tT*[xrx(T>>?7V߫tB3@ĠY Rၫoې)"f>MҗTvo,#.;76cm'Zq92|S{1D *FSj3cjxYT0& FW azAQdc<1qv&[Ԝ5-L)]@=!D'9zc/C$Q-Z(Zrxnܮ?**L;WP.l֎sd$Q=m*\)h5JZb:`5UՂ b-[VE zs?ɰ?I!sf.Ulc(l)SH1Vn. H Mg,001*onHәC4oXLiH1ɼjmsX'c(L%*#U`ȤWW<"BYDt̡J̘vUM-aRl*I\7sx5B廥%#{E#Nxǂgffvg:MIĎn*VBavLG~X Or^j>BH,LHDTb@VHChzM:Ć$#%v*M,0*09z{~ Hܨ~<.HH@I[ sj$?J0,_eBSMJLh e$qiԭFbĄฦj` xmp%D:Iw HjfoQHk^I83CfT XfŽ:t"Hд"Vujf.E`4Kڑ螭p"oR9*lnG&gg*ŀ\0Vr>; hhDf(&vj vnP4_y dppKƢFO9ɜgcH bJe" jh/M$""Vq#gXD֫%D$TNpP+ *NjV*>u *B]\Nn)!D!ExfP%y~j( o2-XdL$ "Hnqn'ss *5ilΎ6FF據1Z+ kGps3P^FcEw( #hWi'3#3v4M&Ŏ_$Ϊ}ȮܦhgRQ5k8O12&@E@d@CeBā$Plqg zk(*H.C& 'Qq;@?L)4M;u<.h QU$QJK}R }af8%VRC&gorg&evfo-jf, `--<%d~DO;ZN*.M2F0LK.;BY!.Bح[GN4d%ZjZ?~f--*6^0bHFFBt!CIn-Pii⋈Ca sW, r35P*Wu=H[bo\T5 za NGܰr;kPpٲ4UVr#JTWe Hl8&ȞOQSSk11lsA4V6S_ezN//8qgJ`zLR.` %}sv[t%I$A479h=cH3uBC|+"'jJֈ9< [xʂQnmB*Eh8!8"|qT zbg/d5o@JEMq%u'-3%3\yp:AMuү*%v>QvQdMq I$ hm/)nLq!K.gCM)XVrة c:!1ַh'%Lhy2.A* )j|L$]"{xIO6SZNB!SU fEQo Ik v2﵄^QwBj"q+Xm 27V eu5oαB9/ C25ҹUiCj0""@tC0iBJ xd̰Ua<pRB 3D21G^QȮkjlge]'1cxd%b1&yLPxӍxrOoqcSkfb:е?󮋌O`5>?WF';e1& %C*Hc|Lk'l$?a%01Jŏb)X~R%ў Hi9X5wiɑ9[8\9`j]Î3@vZ!#TAl[VŘ(i(JBQyQ5ȱL-LGsQѻ(sY%+g.// z2a[ i:y {KVxa~$߳K"h##[?_hng_!=y2!1FST79räb,򹹸THp Gx9y FM(N&1;ܳ^_*1]Yxd/[<bai(ܷk:эGm'{^FI[{6zO@wa"۪,b onɌ ]. tJ?(0a'0?b'1 #0 !?4?HHMLsW9$qȄZ-pX48I|RԾ9&`:yD)YaE#R94jgݾX_2h5aR;@@B5]$)- G/`̈U'Jahu3  Uإk@: A $إ^.hd8ɀ.MYWc2h u//=>l'mz#K;|+hc9Ț(&S $j^60>r%*B%  3"Nn?Lzр*~!(k&zKc+Ekz䙭(JbB0 2L+S~  9M#V3.#";B 0,5ݷD8 8-i]ES(HND@h3,.\2W$΃2RY(8R,"T 5{)n(l$?N]HMJjoUH&8t?}?2sRG5(? g:KJ%ܷxAn-JF,$e9f0 }VQ#ᐸ4T⢈_0 Xjٴ7?C9I"?x,GsY6iE`*P@)eX9y){"5a^K-7+diBpE;뵀#eHn1k .B5PT'H,sED B%3jư*y@P+6{ [\-&I6`˝"0aN^\cp?L٣v7DMYO\؝bkekq!4> cfƪ"ɑ٢8 $3򦇇&l>R=fY # b؜ xֆUikh(eO"X#YZI$n&~b2͔0[;+TJ)!4\H.6j*v8ӺHrQ6'š)X &DA LCd=|)\V|aҀ8~;XtF=zd’k!5r%>akő/zs,Db ؑ?Arz(u0$uRqr/5ۆ-)݂8c'bRRm쌬’nr)% F"ϰE?u(؎7<@ҬtSw'jSp$B|&oOr>]qH$5Gd%lDG[̨3y4G̩MoH(8f"}ն&RP|Ǭ+"4%%4ɝJoUzq-3 0*huryҌ2+p`S#+S $EE..BnÑDi7 ʂm?E%w1*8\tGFmE=` ȕIOW7@%f.dB7p*30w#3fqWDX˨oj(rf[BFGI k5tO3Kd޼,&sq9Й:q )CtQid-N{3:;G lb5,$?PM4wdH[T05VVz,W0~x5bB={5ہYԀ,ʠ 5J< InSVWEի;E)&6aATb+κڄFĆ`~+)?Si=` kgMɠ}H sY5qvgD& \Z{:g%pv}5Kd(3rc%vg {!in[0$þaln%$rMrsv=v(z oN 2i+S淒*ۘMֵFLIњ:_2y 5395-}aEv#x~1mSMYOd` m'Iz`iw3\ t8gE:F 'G3"-">B~#KkDv=ƐLS9}',.Ț9J!9d**Cr;_q)* j%(8/7c! D9"r?Þ𚋠4?R3Uax9G:|,Yt5< F 9%($8#=L Cz?6S'"H`.̯u:.J#r*46ĀZZ7N3}>J*{6D.B))Y=&Y # 84| )S47,2*e} df5J,^A%*9 \< .b "q4n yG0ئǐ'CݱȋEAtUB543Pӆǧ,}跔D#B+vB{@G3M4Tɦ)zJ59B:/sD";Ѝ2p-Y;K 2\71#ú! xb?KIFuTw4D1ĻS3Y)ۧ̓"- D"SL9 *4*ˌ" I )Ƶ:~Q[AIjMoA(}E##*e+,D3 ` 8mKy:[םK {Mt²&-(,$21v|(sT?ԅ+iZ4Z0 |P(&)P|2!0A%`En;## yү_99ôϫ p, D9z8Rs#bH5#! 6JwYY " =٬4d YА;6uZtћl'Q꺒£F1\)喱ӖLs'AM@\WcDLkgci9fKSߥaKC/MRm,ԇVc< NSr&*NE+dTF F3ZWEmE (T!ɺ=ac #7ETP+]=)T*35S ՛NܔUE$%VMr",7^2&D;*bQ=K: $[<=mߚp+w;GF3N)oL-#ѭ20@l5(+c_,2@G;ω:MN>ZX;t-/h9e(f .^JUU;S_Oܞ5!]!AyƼ-X*K-&a[ M&KIg17ڸLFD~"21~!ѣ%, ]r2_u #CI6󄢩~9uuDņ[}$m՜h~k LC\zhn#;[bxcY1.Jh>,*6X}H)R;-VRv[yK]N<0ʹA-]lcU_.5h,fIܙՎ^|~%ľ^9>Sf<;1sHo>k<NY]-: 44. S~ԋ<Tss S\yLmCE0=1Hci &? G*9*扎m 2j{bY!INrH;Eu&a^>0g~z}q 9zES{I= (KCnR@gTmÏy2quظG6޴Ф* =My[&0_9jM:`Xר,}pE׈DףG$j`"C_5'kC6r7sm`6 3c4B6/n_W~;F-]B /ggQIS5cCYP$k;<#rڇ 7"McB0y2s?mtĜ3/m&UNCb "[YWkVRx*zk/sMBe7ylzS7+}nBx{ԺG가?`@  OdBȣ,C Cg/?!@8~%$0W!GSM Ϻ$JkԺ#y+|A58vI$Kg` $tyM¬i]Z-Sc{6f$_;X]V X4ynZ@sشֹ^O[BMdQ PyZ 2ϡIzS$A^bw|cqtשg7MG+l QNr4Vs_"\J$ҙLUħ(Iڢ|R𾈢k зMpƢ̓ܢ8+"p:g$B(`K20D//O ۲:b ⼬PϠP@mjI¦v$1%/hS,(/Ƴr@2w@⏧Iz*K6 [")ȭ+RG ! 1"'iPE3$;J%8GQ# D<K >uI_E* ` <.‡'JB*<)MVWk+X(! MW,-,?Z-ѩ \\ RVQ."9%jnIڛmH)b)(LIXsLv%sZ>6ɇ5p޶=#)Vu!ͶbW@icHCn+yYҢRţ79%hc㔧mt>"x[len;[(2~8D:FB4^p@o`[03H%{([}uTo'.'| $)^YO >HGJ:k@ ~_+kYw$Y,,IͰrl'~Z(Sܩg"xLh﫚mLIL~5h}NY~9`9 8f?U=D$I ^J9<5T?XEig璭S|-EF6aJXa˹9R-$mĤfHcr#rFIP<@ޓ" ŒTL#M+xBhBD+#`a] P0 ƧK~9) JNy;WJ!WmL|QP5®B++ xHMOma٨yV|WRFH@kq+%%  )N4ҽ&ȁ'K6343Ʌ0uԭBS4<3Ju >,t tCP~9@aa2IFY?Z$8²em9ތZp)Q (::*_Mx+^1li|!^O ֗̃3`O)QR?Lg`}G5 8f1F=@K\(jCD lҮTblTRB!mL" ߀ >;hxnfM䖋 "v%c^)[g3fs%cGɝ JIp8~ŔSeM`q R9ߡM̺(i ̻z=J,A'?`fzQ'[ m;0(F\-9͂b 2ݐXQZŃiJ(2i̅fy*  hA ٌZ[OEL)9KAZ}ѭ[NHqgZSlvŸzjFBf+-n 39S?nTasZU쩽ʸSC>atNt)aZASS@x'K՝uqi~/:8g30O"܆,U`}:\+4ә4dA!Zy8[V%mu.¶DCWRnimmk7))O=!J~XHoZ7 S N:I`LFIj9i15]%1J@tzp$xjCs)٨จLDJ\—@'|$~%޹g5jhɪL@{%# UqˇL߰pw ʊOcI5>1VFJOWHjGnҷW6NU^h3xR)^/mP:cE&{b%$QX?"仴;$g8)<8Y*kn[\M̒Ki[o}]3E&.wr0kuۂ5i=뺏Q,p$]R5sL8gTw.N:b4 qKO~ ud>Xiv'tFͻ!R7O"'e>j|VRHO6 9 #t*_9^!E|N0*SUnO*:1S ڲ8F(MsW$W/Jqijn;C$gпBlXMc;I{$q(2248)kp:zH"JaU*Fqivjo$<<,w(qVsr %Zmm'ogA#$zUO`%!W/xB$Y (d&pڍbE'VLGUJPS AM btIĆRI!-LHjL\25.DNR9 .GU1Xݳ)|SO#-^ư~ʵE̺oL!dVO2n$(B7,G a&_]_JՊKG̠ Lmleb-%0J.2RBblY#,dt_F) Όxϗ9 氯MP$e$Cdw u+QKp:[+@@CB:#2b ,LĐ*qs!26f1RQ4@X<+"ar [K**6r|hWrp+(L4T s.Y]ddFg H0=hUeZ{Z^m@`}_΄\! ?eqT #dTGSH2 XO.bHDb6;fFrgQ|\pl4xɇ4 [%+8딻|#[f^rsNVsx)IFόKdcLBMb%E\LWL-vZfkoQT00{DM>ݲ3#r@gՆgw3Ֆ:;Ӥ*NnΤcIwz%|e W7x-kT'f(ݰNA,t` D0(c(XpJTB6xen^_ZW'(ؐݨ!N׀Ǯu{KaOf/Q`kl&S&Il*Vs8id+*ZCx| i]K*pX"kSrL$ ^ #nȚ3 UԗV~qMt_c .2(=  "pfg3pgB+8 * lSBy-L*?"g1蹀0U[gR-%Hv"džfY!G̙'csohwE"8x059s_v\){(mqq6`ΈDשdmàkH)q C̰$[#o!i97XM,q Ij4XZS-ިW6S$gK Rv?jE=ת3n)Vfh0.Gn\ÆMiD.)kRsLσ0*P"$&C!{!,/FHO8=[[DldAH4噌< dՀκB͎d$fk:81K+CzLQ1AW:ߕՅK/LKVRXGˆ ZscɣS&Rer骳."" wS\kGO:*oAR>$%5I-"ɆK/NǕb B ̳T E)!KrR5̏$0z{|ϑ2IB N &"_y<#kfq<5PT*/d뺫wzQ%O P{5h½#A{؁ Mk+jbW#֏J[Fd;aӚqMihMAG> +Qw~ $pWޜ1"(p2zh0FHjbvf1I^FW?bA0pd/˕)'TC!ɡc1StJ\lrP-1k0<.\a'LU?s\K7ڨ͞;Pu%D%p/٢$?]ģY/;us!Ԯ*<L/&\h)c!c- iGbr @XS?b)"@$"CŤYhKP AEp@|Ӻ$-€D"3D3i",T&`UD1A@Xb֘vGP'rA!%:!@vsP#9ȢqK@ )SJk;A!tڭi=;vi m;@(3@*%Ox׀:sN kj& R;;Q,5H|>+*#8ـI: #pS ;O(i8G&2B` I xӡK%! @($Z b:P!df'l՟.3h܅APR,0 `'$<''"*胈*\M3+rA$ORd4wI7 @O#:: ̻U$T`$=˾Pñ'YiRd7&OTl:7N Q660KGol?/]mHN)5veT4k2θ !]ZyUuqe"Li"eZƍ-ڐ9oꠕbn(DOgƸꙀB[;Cډ@ d]LK@*-CxXΫ4Ht#[ηQ`ȓChd)BiSio?gJ`qbq4n:2uv ' g[~*6Il\וweuߤ#9MzM!Tx%W0:FQaIL5\wA4D~ F °DL49BHSk?/d< B*LSI̩z~9?o\d e ^3We* iX$UZn$'" J>(do#S~,-ụQAp=͑F ?!I輞tm x^(jH%`PɢXGUhR)zF#g@,0ARul]叐(R'5IȱHq ,"OդлL@W!m~IbkdVZ7Pj*9kCGIDe5`i]7( 9G_I~^FXDAKxK6+Zy;&ѐkuNE=*%7gYz4f.c *6>)!͚\Jb9nN@䔩Y]nⴕ] BQ4?t+cv#JXfiRBIہUӹ4@-L9DCЋP *U~UH#O7oT9% X ("5;J^Z= 0V 3gm,8@[ʙHa꓅6ʌє,ȥfbm*vkPK: H"XQWH6$75_AgE>O}IfAuu(?DEzpT*ATveW.(*cnq.R6][#Y̠]ջ"SK`y EHM`]RxV >b(M$E8ʑk+r]1⪚LJ9WΈ*l^b}:H68* \an+Ɵ7W`рaܕsm5[e{Ɔ%[:CBj^*$/9y!-"XmUGIb-%йiNѨJ٢G5(2N!P"M*,xK˧sKjYCN:Wj{_$.ز+ x0=sԖY,hE)!ib-ŘFe!Y]j- !tƮ,ն _՗#m~e[# p4=>曺f we@rxԤD;A8<F4nLy}\0`j6M**lV?jdψH=I{K㊩P)*Af1'\r)ʺ?5vmuiw)0IMsO nFZױb~ b \"_1lTDTۢ4wL{ӝJ&ϡ=#Srƾ#PL*ٿ ,X#R5і[]id * pY믫s 0,j>Q}|[#X/Ѵkͥ @4b 9;hX55@zr@Z8ӹ9âW  )53/7Jj qci:,"* *q{|?qoq p}A"(ڋ:dHS5)}(.*%=%7Jҏ^3Z@*bEĖ[1!dSBsˑ$?-(ѓ㢹w.˼[B8t?cC !WAu1@*Hz9ď ,iQ/JTz􈙫rz* ɞ <6" L#꯼)9v*bD +C/4;L; /r)Jk̬P)es)뵟ºD7餦/t=6#D# @s Y|Sɾ9#0T,S]*:EfvRB㲒>;<4^@%7sfdD:]1q&eX;JjL=lSKjOm2)l]e6_A.uҭ` 3[tS88+҃s?N 2!7K QTV`֞"|(^Pՙ;8ۇ"c /]%>5+"GFYM† {K`ĵʖz߄}KtO1=SϽsVu1"l2~.b]aZI!6@JFE8-fף@V5bƪ i>pJ:>dNNe#E"Ai+U`¢b,\FTމX!na[^؁mKX2Ҙѩ"]-^\V+G:BD+%IΜ))M$\ľlʚ#}UxK"Xzǁ,P}6~Lt;syZpqUI ~ӷpoqp 2yE 2⠎3y?*b ͋8}=%< qv޲k+:leh;;kS+em4IvUd2WM fĔeGv+򚼥٣4SAIs>(kD+jAkܷH*q"Ă5$7A fS MUi \X")9 i5%bwvfB35"@+%15]umڅ.Y9aǁ8=mKP9lE" .dU_GV<0^Džo?l,2 `X.D RL.8Ipf4:}0qRASbG˝x#TDV--c+ m}Pn1WdIk(WHfOrVƏIBRyYn6r` l9z:,-=aWG.5 J϶ $702j@H&ytoNk/O{M1Fg&i"yA\&"Dv7JM7 `@&@ $DOBE0 7C2pUKeȤq.⑇ 2NS)eD$ZCڕPg,q@Iyl}Waw݆_RJ1TEV.+D'US@IDy$C 3Q(:-PYqG%\CQh3e:ȠWJR{ qܥ\4RlQ;LGOK(G#Bږ ۳≾>\LcIJdت ;Љ?¾حš0h 8m+-92:̭>`"["P N vLb1O.'ݭ"')S" ̄m,nOl#ZA"N ^"3p)؎J'Y2?"> 9>H($¯>t" 4?s.“dtGQ:y9 4>˰H4st=IB6+);[~CVM,h}pCxS3'Np2)M8}ϩGm"&VwVœrȴ?)Ss"8* <]k$ Xc-(,Ҏbz8*U̯ô!Uؠ ~I=u(5L"dJq/ӰXmݫQ-iwvڠ\qʤ# V a$&^7CmfxI3v2* q!# 2 (L[L'⡇Ђ"$-WNOՍG?vRit*9>ޕ}f1;:1#'C.6?h@Œs(&dHrtEo;l"n]gi2?vt`|ݭ)dd#*':Gd" +p kL/d8diPJ0B Y#[gũ\zF!]>Y*ybsX'mzN!d\lDl0SNM4c9IeÖVM! [o2 ڀi%ў5(t{HB=*Ԑd p,1Ɠr|MIS}F2>, ڞc<p!LE4mVݧv<1"T%*5@# B_а6 ?b@H -0g=CO M|J@Ҹ >Q`:9F2GB4LSI 4FS69 ?#RTWCU=Q 5 ?b' 4ƁWK@WcQ BFռ`9cS$BaO:C9 Za0MN)QB$I\q!6!r\tB#49Q>lKeuiƣRضĴeHF˗r٤&8깫;ӟʊ؊1,+(k H?Cb3!- k*čj $éB4@#OzRG1jt?0 R4á-$@ 묪! 2:F&L̲NGjz$ " ℩3Y1=:飣*̠>3(ߴxMdףrʸx)H0$:Gi;BC|(򢩣kZ %]LȕtkHњ)9P#2Ҳ5x sb0(KKΨhGx-*$ZnMm#ה1BdX :4VȴbKw3O؀> 5D9HlL=2YuކOκ3q Sk^j%jU)%/c*)`C` w$uWn(~6"$bsd4¤xW(R8ϵlJk}Quۅ6JT\)5dVO--5@bN}{45C%jļCL}BJq$X ڧڥ!L4`~٢LtWG)Vln1Q7NA'dI01#kn;U!Q=ʍ<dէ9(IX:[lґo*%:*.~RxLLmrLuk貝z [ZSz>`:,ߟ#&d08t_j&IKqT5$fxdZ2H?Q >  zG$`1< 0]ý!o2IcYݬC&$UĔ_)IgODP箓 ,&U A*Eq˜(CR+o gFȒ"Ɔ ,I<{`/HW,լ*1tdʄ$(HVl7K@$YzQ+\Ctv^QUaS6jn%q$xDI*JX{]CX{%V>ĉդ.ZIh!ڗmvaN7 HxS;[F4A[Xan Ա8e2#y~`Ms^ϰʥi4'=JUٗt}imz)w>Kaͽ?J[at -/_9dEu" Qe|Jf8]J@K?y~$Vh!'>x5m Ŝ2F]gDDbey"0ĝ+g0Ϲx,~ P[8T{|_ Rb,u@ՒOڡeSO6+ڦ@.Í/s豍dj#OZA;!sXGxqFӈin)X].bж!v֠ nR:DgBCsꪳWXa v؊O;iznX6Yb3G^GjY$y79ZBnGF-*P,rNGȕbI'Mx16Un:lj(/f)x\U }̄(85OH8p {8X-_X]eݧ^'̤I'VC^wIJyZ^ΌnkԷ۩[^fbB"4.mB>+[ipjikpVT[)-"L$5|| |ur 7c;^\rt#JcG1ef{zT{q9D8)%}!v}RÂR/W&[AعY:i)=0ĹPĶ.ҹ^6H|`"t̫@P4Ϻ .«Čbhȕ|X/1(+hҫ[ϸHd.(M)< fbLw-\jy t+,GRiZ'J{ԩrr!Z߬0:z̺"!뀪2| G,po[¢hd@p)Q2E%옔NƁC/ŜQ"zIFR*q*&8dZϲ''bHDu|z )N,*&P ~lF+, 0&{. lA'P/>P(dqZ,ݢ8s r#2ȿK%"@8У*L:+*,6!*t&R f>/~o2ZHݫˋta^!Yo|QKG*N8p 24R^,xre8hʈ2t>^m(*ӫcgީ\}pBoQ1BPa*WXPǫТ@.]<oH4ԴSI,!6X|"dЪXWH.o̳ Т&YFnIjʭRϲG5B;8j'RK+i'0bUSQ7nFZ1bLݲ!? 0$N{AIvSjpY*BU=TfDER!cԩi ߨx fzI.8I4,4DRЦ؉`AhjVѪ-:|vv[ĹdnE?Ÿjن#ʎ*'k줽k H 4{E9m KhL#LLKl9t2!vee(謏-X"W\d3 UR X0AEp@+vN3k'F#8`.}X;cBYV&#B|D1D4p&8kIu\jPH.u XdF͗yr|! KpsedbF0ypw*R` f*WP-ydb|VŶt/(It? MhC2WYfق5SqhO<#:G ̸5$Y` x)Lhx:m-a{G]ǰchd(!+Vr+N#IW6H&"dR1>$fa)zD.CchGXⷚ{X҅=.mH&i̪>TJ"`b4ݢrj :i 6as%U\Wvə4K:sDBTr8VF4Ӕ]$ y8A7T>0p|=QСGW'r{ԧJߧſ>T$+h+7`o62tn{ 6>(?z3`/{6(Sf>Z z%lҎ 4av>t|[tcʭiݢ )= 1F넁5J$,KQkZ]lfkLňz I!eV%[jJg|wی8m"SFZ+r3Vn#t<T+Gv09L= y|_XUIrWza*qA\+$"ޗ%)vhRYM@;WKb1/{VHL's ӻ]:&Kh$ϓ b $F5R\8QKB%b-j N1ZZ~Ά 8 AOT  |$M?ak9qNH}Iz&A)'=w2h8l=Np!-ja\H%JȪ`xElZPЊD '}F`{cUY|Yz.2")fc-q\W/ S\6Ts_`9n^ q°Ro֗O _2 I͠k|{ =7i(?j&.:\<%<(4 + p KP.2ؤA*.?nBaH#3%Z("R.)J' * Il"J l!*jD+t Pp 0 $,[> "D!I#&)"|`Y1 .ďRhT'10oM)ʮ+$=S\@"2b8\ LgA$LM֠-6;3\֠TRP\㠓˲ K֒DVE&(E?q*"FN[i7 .5,RDQ / N똝.w*mru^/"z.byꝡTfMsbh)Mů6 '@615hUĎ~b'.܁ E;+.jil^k$\2$ANTNWn"ӳJ,7VS켰VO4>H%6(i6W҄]Z< in="?t,^h&3nbl 䟕"&qiz E[Ѧ(`?5X 8$eSUk+Wo}amNĴ?"pGFL%BH{$1TQj.{n/෈ !ҾHJzB5fB9"3Wc Z"h^rQ/BbH,L!b@$nOF=.zQdDTVNnԛjU^1m)ih}.c >]bGքk}cȆ،eZEبIelyfR,oTH$nrxk@ x }#U@(̓HTU,h.Gx8͔"#x$ ]xxG|胅&2S.$qJ%/YüWs سjS큨 W!>tڼPtlgᙫPQOy{"OM4Dőf1P1)@H4Y{.KOͩ]i!Ua4xN>V?…t':g"e%FeZxujnkZe*.EIIDWy/$ SF|0JbX j!GSDmY'5=n$DB)xkr[gl$1f pǗU| -Ki=@#1jm' "f);cȡY!g\[kM;n%޼0_TT11'(}<eH} z"ٜJIw$rfHzHK x.5 0GHgX̶BvqLׅb 0#p3d:l5!)*ICZRT 71yOˀyAl$sDfqE ũ`fw'4KD |F(>-r[U0lm<CMbDy0ɾ9x_LX}g2C3]NTX+l^9XkO/مӦ` ugS+НNz`& W0Em\ůsJ3eƬf]V.sFb*pߖ#z ldjQ 9R]92pL֗3W7MƴA& lm>DNT}4>'rsѴDvly5%v.NH6I:$$$yQeʻI7OSo3t!,/ZT#*D^i/izzX1_/x 3*1ЮF^wѕ>tϵy(@4-^E!<W*" $LꭱBeď]=3hM zQ{::2[b&,ddb~VB-&m}s439x`qF I&a〟{[(   318qs`[1iĩKғ~6+$^~&*lrw-*Ç JZ+|($ ¹-) ʑZ#-ųC0q.Rp*0p >4g{r%322-sM;?ґ!awr*c8I Lў𓠈D"ȶȢ>!w)#C C8{49E%N4A]DZ##'sx*\eBҘz)d01@SZ#ca)5(C×ȋb#lVv=BFp;$cC>FYB YA۷H(:j )$i쳑%yT kJ` "ܷBhCk:s-* Q*%:Ǟ=3:+<23"I;IPDKC4x%z64 _:H$a𮼓~8ڵO =#9#I=AHijšEiս쮩8d#l&+ MZFFL-*B(s`cD4~}#8 3<պ uL"Na ?4Xxi)-Y2/1+n˵*k8s#IcJ j-<$N? "kA Mt- )M?4# 9lθzs0l,IJ ㋊G=QiA,4L2/TFѓR@Ҥ-Ga(`aӚ|«#+>+̎ڒJ0l+ËRa^̬kRL&D dmJ3JȘ *4>Ŵ`6T}_$T^򈰙=Ld'i 4E!z/!"ڣ!CS; 4y0)B:o8h07b*;PXZ; J@H$p/#jl IVCa2L;("HeRS G !좒zD-jj&=ʿ0IQ> @rN!8)̺`*<%d\=1'@g²ҹlGK4OLf0ȴ_+=ȤO!:EUS͋{ O)0J{9{#=ZX#H$E[:HTl7"cxl K ZWLթ;Ot"A0495*D$]|aH] b@;8d?k;*Sݓ3IrE< / E:TˡS`K3(Te@\_t."<>ӹТlꉀE)‹8WC\8G!3-U9LjW~#󝊮Zhڅ4(}Y+KYH+c dKDu ,'$ ֻ\%?9cA~񧸈*2w+[ P lUElJ9ZPmbk޳X:a( 0ɘZt<2һ_>X0b6" K3ˉM=35ZA=Л"M4J ($usød]` "a*g};BH:c¼#fa W*Ab"5 ưؘک$ƈg[mY0}yw<0d( e ΤT{i,Mf0hI&|wG*hE<~. uF4 l@M3wa'*FkD}dA >F5>pYksE3ByRA?gfF/mO l*!Jݣ lxG8sgR4 #RF4ֹ(4t;iQdYB˓e*Geʙ]8|f[lLuUZ5Ԫ܃0 # 3i_&: !kP`\}ܘƉs_\665fhJWI.j0>H'%! e7JumNh5 FSًl1w4F.ҎDvdvTepǟBIܬzF3 L_XN8J$Z$BMct`CiKEr~LݴBAJ63si0 \S @iN駮0GȄm,XN͑,\w! Ū /bㆼ5F[o#cʢxҳcWKRӤT?ml@}:MIY5c&ͣ2gKL6Р; f6879z+~iTnJE5LO7h1^KQkSuMsm:&.}E3DYqqH4s֕u@~߭HƿO̜M&h4!#gF)T_oZƊNɴԀQARt٨"!hjp D$ PL$`4e|bE'D_39$ Me)%7Ph'^/G&$G2H F@٭z.EQy&wšrؼΡ*l n<.y!Zn &3Dy2,"%JEk:-`0L {qA|-TʋtAKf)nPhm6`݋Su`pHMJki *j )ZL(kڤ0f&zK4"!#iz.#p,*P"52i"I=aE&mlӟ+*O3&% L[!nfj4BgÈ@0 (~i{ ΠҢ2ANԺ|KI9 VB$|♞{$ RRr^y0Phj$34k=4=N0H$o]&).ꧠz$T+ȦPHѵ'2!}ɚũF5%0-eU*F NM>7`B@JN)KMꅺ(A[$2暥n83MW]=Zo(6Yda >'xT!L->Α@jm|3*4JRh9WACZ4dML\:'HVKl68,0(n&1ObEk%+@T P)o!l0h̽,G 7KcoHg|$mѰǰ^L!"mtmrWOABm .qmZ`lӿI|5!qIOJz$!eYfFYO$̹Ra1 xl?H8l0p>i6$`׃R[})-2t?C\)Q BK)*D2CX$3$Vn\;<4*BbeibN 5Q"@Q{BIY5oQ@9#M񙍰H`j,7(`}1%7̕NlF3#nX"`Y\U JB )-%mF6z#,O]%#@7"uXkęޔ?H09CXc).kjB#8I MYR"7mM'Es)FA0A'*7ϵĉ5SԍȐa l߶6aJnB62]rux9> Ծ Β_%nE'd$l u]TUYO}1F)2eg4tHD+o)ѓ2#Ϝc$ KF)ęXڂf)>G0BFA0\/j)2ڒB0ŽrWN&FCUf*^$[BtRQOSX׃EмdE1.Ƣ" LȯD[Hv^k0)[צJ O'+E# "QIkfнj+US)::B$vO6p9G2&u= ?vz"F  3#T)ZQ aԞ?lOv})mU9SQ3Sʸ~[Dʞk!pdfK웾2[\Mo 8kKOXQ{q:=,} r(SiS$1s0M]NU%duՕݎ(اEuk)lH>>)ÿM}c VA{Ԉ(Ӈ"~qS鹳/T)ƟK/] lyś5&_}e[!.v".oFE#B(diڗ$Z5NC2z *jJE-(Ll6.x65PΎ2h(nkpjx%NS8%%9^fwi O qjͩ*@obkxd $E𧊐ax\h = iJrFV}%i2ũyc._  .kX0.g?A!->iIyK?jc.m.* S(% nTB'M*l`NP (z~,H,+ z4x N M).\He *eM/t.\+Cv8E" @9 +fPT̠ z2-= *"Nj`N8"FwEGZui27nb/#r Ѐԑ$Mчb%2j/d,n"ޡn*Lpknn$:Őg`1X' GN)xpdߢ2:'xB"(,) J*fP0Lhs,b.QДA #vֵhr&#(琐.llF{oo:פN cb$RpgK)ZF+)?Hހ.rkdB%Ę%p $Ml7G k0hmFh/OxEkaL0 +un y;~o0m+ x9J+,˶@c:]K!;x>iP}}|u"R.vlwb;*L 8mL by (M^{D2S jQ|C #"Vo=MR/.tgCfEsM,!0&1C$ Z!O&βtj (x1c.1&?'?W!: XdBمuLL"~7G EZϋtĠ2- D&5'hJ&3!oV4Ux ¿g NHI)&n"'"M#b6TIG^LM (S`v4#v,jfKO@ mW5Vԏet"veNFI7N:g,[MXh+TH nʀ.N`&n }jbg/5F>dE+P/ "09(]<` 9TsU#Ҡ ^A!Tg]!ROpL1Nbso_.t톝Y}V3.2  yo,fp BTu{j"1b(E8Wjj,^ (0.#.k( -8"N7y}p YVˋRX='V.h2dm![7BHoW)nة5cxjOn ]C2JƕԶu!&sn;nE=;yNWN&n%` HC-nkX}@ՙS :7đIG}Aq.ഭfW}^Ldǭ3equtaqUj;ջvxy2pkxϔnFWs&(۪?Py4lLghSfL,IdJ}N>2{8=fi2P9QrBSe)R}BRq.YCgt.K m/q 5l|ѥqoUhpdbXw^HDs)$k1BE :ȉymB;#Q3**M,p&M"H8faH:zy殴,ԵL7DROw]T;LE~fV%'Z*lm""1E2s]&Y  VvuuF7PN}㸡h Nv0AcEYfťOW Hn$uKhmU2>^Fn9k7V.+Q+ *u:wH *Qj|j} lva0d<k03@$e/a\psfVWu w[{MՊyV&[ӔO݇b`do[ R|Vz7+25hG{VOYvy2Yw-St@ FpBXZ1BVa D,&Kz 7YO_BXJKÎXT>#멐A͓0BFK'[mpg] ũ!7,:,8;MT$w/j|DlZYRҦr i&ݴe9Zr$K+BY"GWrpKvs3 x %3%7A"nDLjtf(G̅~+^!H\Qy!~EZ;(u !cZL:Gh*nj `( B5!zD鼎Ɠ]yBZ*3qh1ލ"h=2QS\;% R+- ~T#:2*2bbU P.sy}`6k3Lo|o=BEZ:$AZY!ɧϥrRu+ pfB0W B;qX #P pF8-$H1H#Y_J%d6n=蒈hJ琙IJ%u)$n9BZ<~8GrI}ZJjE( 7ťyN +R$\F=jI+R>y\%UI-]?ш~2l%d.pظ(ANH[q+֍ IDZM %u$I*5~IheԂs_k ne2 PZ@J Тlj"(,W 4m\&ȔL# jP |: S셱-Z C8 "H TקnZDV 47,CI,PJϩHܤ- z.EZH,+K'{".rP>0I4 , pҥ/i=*8b^!-J/3+5i!&Cre7,%X7 ,YO;/ 2J`m-UNgqмy C&lLFx1ԤBH:kQ>v%s ԓ ERsfxSD@ ? y(󠌽ĶE &!i[I٦sI&}tU# n@l݅wU*73;"Ev9&«sR~! VXC|(mڳo[w̱L?:FP<թ#D:zgd)[-s;JslWe9x7B``Y6׬#>r1p `_&fnbk}v4$B|ow t `'ݚ=Ӊe~xLXA t>.:x/(Y\K5iYsgԹ\xaОdLDێH NS4Mw474k[W EQ*9!D;5-?Q;AaZ%#8p$'cz@r&)):3ȸhD,:&P.=y U qz05A5/}I&,He ؞)>Hp&*%"sԈ2i.7CbY}z(Z8y8ɍ\/SO%HnDh,޸[ 3[ )j,`z° <"pz'2t) -DX讻?y\yԝ3A3'hG8-za,';+k,~+"@clxld|!:bL:`L(-R<1<3SD@/[.ȣYA~CȅB$׶zz4İBz~1 ;KH.kPL밨юY# 1ŸL؉I1\ $PP{8/KC/IЌ o8e?1]1(dt,λ!R!⩛b#x3'A"MA$”QٳHJHѻr>]O @MCBy4bM .+0ʳP]Nsרɞ9=Pq'J Pp幛8 \>!#j2>s(SӺcFNP:qԛ&*35B,1ǢyQAL {9%M„Uk :+6><kHS*aGG☼Si XH8#Bɪ6I bZ9 T:4gWq{ԢЋ0ۋ@)"CM;3~"9*ờ2)Z!sO9NY7ZKO>I F`(;Alţ$ C;%Vj;Ӷ[4=Z &Ui=ݑR[J} %]{*{a/ U$[J@Y8!+߭1,Nj>1=PKFK۠cqDЌMJ]6zk0F91tDq$K`v1\\;\6љZeƱf7[&YcbQ[]L P~N`JuPiU<>Ū .@}Uf!Fu-@ SZ=V-߮%Kdn$el ?HY 1_ɊJԫf2Tʥfer`[hsr*nӬ3=԰dB6 yMF 0;uRsUk@HL/U=/ڃ1F*G k5%݅ A0PJ&ya³=jdY†ǐ}օ_l $<,\oME:Fԫō:YHAߌ_RR? 6s6t=$&UPlr|Dk"g 3M5nUyXk- 6U pqRSl=iՕ=!:-jMU,ŋRC!]hL?/7x|=XܽMgFda 5u,dKլC|ttx q9Sл|*X7+8 aD޲nPx]DdWONl>\y(|0F {c"mt;]w2k>X^lKis_Jά1Ĩ}S&[Cnjh` vGr]9GpʋFy`u~1>aLpal-RFQ[=T?0SRXUT6`Bޞ,hv(4WJasN BlzBMcU1کjֽ{:EWF v}ȼiRȬwCc\[%NS<ҿf0I|ONCX^P P0_0$6bPH, ?#PpZ/ %$$P(1JriL"%~a$iJ3،PBhT WQ/ٌPki2JA6[_L`kU O's9 ٣_}c|f%r`cJ\` G0&r9z%r jG {k:4J9tG$_#縓Ǝ1DwL/JSpZ% M(]^l^S(6jlm* s2"({hJ@):Cdc^ ?⼫i.ډ %D$;x "΁EQb"-cF(#1 5jK+l~j҂Jl@Z1΂B> =HBkލ11m O $ c2B0Og0֭*Bɂ(8~ Lⶎ,*.JqS%oY=3SG$VMVPF=RS03KNL-QJ#J ܞ{^*ZP>1:2)T9<D(ΫcPhɴj"j^trF'6XJ_hDJ=!2\YݠX@]>K|z,>щ ۫ I-28H_뢽/^ԅn >홡L`XpеP6byBop;@ۃ"/N9F/D\lg}8!w D1Ꜥ8W31fA#R^~(k@ Ѧvz?A$ۥJzwS "^ÛɮF }|)eCiN(Sqm5qݒH UrtJ!_F` )vҪaP1bΗAFD0]! ɹWH@g!τ0 Uz'HDrl%ũWbH9c?lmفJ(4WbTodh@GiOEErHv# (]MYgBAȔs,0vWplH}#,+pP¶RCދvK2U(B` 4_ '؞v9$|ƠI/%29phXEΖiҎvq1rHFg)ĘRɜz$bN-b LR/&'QPL3-BV3aK'!<2yb{Il8 Hd˩T)hf)"WD* )3ZW\OgTcSQUQԳ|Pm83'U}3ޟԤhv|^Hm e(>WcJ)B.[}>HRmQKMvUT241؎ݭ5jp5F4>` ˡf(.:5 mHRIa+Z/AX6WRC^ٌ.ru]^aڒQ%9#PK'%j`pAi^Ms^(+;N;ܨ&Ybi.ե&*"G0B}ShcF{ ,{ѓ\#rY8w)%%ĀgdXn &mY[y\9At]DgS3m%*Y20[,+[Ur&!ۂi!l?-h>$ ^54l7ep[_s$198YacIH *MLeR@ dro|WaZ͖@l+>RMQ:[\R^)y Zߜf97s]7/PpH=hOE\er4oy $}mKHYt_ 4 #Zַ0#f`bies&lH٣I>}]tn:êA#c&hu_;a,D?=c6S]R{`Sdו:wb*Ӿc[s ?E +Rrj$@Tv T3G\=+=>wP8j3^z!8_?H= ˛7Bl,?KKd}hU%婻S!k})eU^ho3o>:'ŝNl?^!׸di?k®'omm :g&Gj4awsc_@7Lsf/>QRBD`&&1ǂW,bÎR"΀:Lx0|8 U (&@X'd~zY 04dȴ$1.Ϧޢd m^]Ƭ"몚!prMhJNYD"#֏bx @(F)T$-Bv8."4lĚbO(piQK}(pbdːU` y 2an8840nOH k!q]%QC)H6@B',搯! X炑 E/-٨8P%Uࢯ*e08тbdDxP^+m%vR : 4ԉIoHbfNbS -@ 0 (Gqc-ldl1E{9#LG2kW9vy2neo=Ń. ==!6=ル7+ܦqR묶ޓȴJ(䳥zEH٬&#@.xax8f.PsJaǥyX\=3ՌmT]ŗ3(Sfs8\a/uQ扎v&ӐEc7+b9Ʈ #GץՊb܆XrhD~ce:;D ֳd1*kMd5H&"fO3Ī +N\s< [X<&d8w\ԽiE ;"[#p&t,خ'/_-Pԝ'άR3Rtb P!Ov#r4ũ%?Rȉ?IX]d7Ҏ;6TR*EBrKLFTUM)z4`t4MIdh^:~RSEA"n7,HG #Z,zB L{ZtvIZh~Ԝ!!5@xEC-%-T3 nƟOͿ6aχUOmS1rHŶ4$+\eU^5)E AXo3+7{ |ٲC`#W7s-itH4x>ӪB;vݹ9+ˈ9֫s8Yv =WK:hI<e!$ڈ/E&Xpϔ7ņW v S?c}D'#j/3ҀFTIC$|A%iIo1$H-B&F iE-EPt8'm14#uzM*[ѫuȵLxW%8+&joS" ]BbW } )B$Ia`21(?ȿ'?_+rY$*R ?$P+}9F\?V ~ш[^Ju2B$L1W)$uB½vڭ*Db ឰ2𭸺f+Sr 4$}WN"m.\VR?iQ52K6l"%ҝFuE3^3=2TOMȮ:zqXjQD<žzez`D]rqIiqHE6rM a=u $,s-xgN"M221_ t,ͼ` mOm6lI ۿc?x4YS5("I3+k{n}HlkGi$ؽfK%L>\a_~UO?Kfrvܧ4~KnL D^0iusHa>|٪tHsR]ZLM%"P6%:dg^ՇfDԞ3Ry(:WQMȽ_~(eʢ@:IԾɸlN$,}~w}&|3@+ Ah䌪=z@R*/d 'H7$ 48J)a@@ "+LR+F2^& [pœ`+ݝf{ѬٱU$;ˉ3l>0.Rؤz7="(?ج?RA*82ʗ1.6 +c('2팻8cX80T<$?y +9ȍ Ș;\(0ajt @@KQ7s"1 3˒=?*#*lb8C,3Y\t51 |neKG $f). +KE LJĩhiơ龳z6"}16&!""uDcP3ds AzyҘˡ ;Ʋsj ac\_R #›s)1,2x)1A ,@7Xlʘ6~L$C& # ~t Y ·4TJHL*;Vb:2}"JaqԆȩW=b A鉻LȬ L*|^d*z5 $}C<3}`交5KRB솭%C?6M;35(AȼOmb|2oTS9% ;y ƒ44:*6z$E`H蕻tǔp zE[$=~ ,P7BH(,KI'`ن*4}gS!{͊Hl~ 2+y#`SJ{gPx z)&0?. 5MJTI3r(?8B",c>{`/`CJ02+G=MR =eZUqi`Q:-Zj%u,DBP5TЀ <=H+󼲁T\a=Q۶IC`=,B}4ߓ+Gʝ>L*cQ4=mNCP~N\T4:6gZ"*"eܵZt2MI*/c׽UU#_$_tE4UMb"$M -_ߢ(f=C+Gdv8ӣ]a{X^H=%C[:˫%י4f28"]cZy$D+`hiv_,3ɃfZ:N ^T [Sڑ3ŶqKIjH4.65L?5Gzd@Afiw׻䞕0$:0!U19ݖ&.!Ȉ'i3\㉾5NjTF,v5)ZLzvefY`J#xK%촰5VI, }x8] NV2-A^DyE 5k4k]6vSǡ̐ըmwT=Cܯ\˹8. TdD,zvFbXjW-QbR~-sI[`2]n46h"o jׅȘ x>eNNH"?K )WڰRf&Y<1{ 簝I°>ֈ{ o)CiV^x'ٹ0x.kI.dCVB fҔd#3J"ld!?FQ sc23s%MvLJ(DN¤j;M 1HIK|`ndRw CKi%MW8x :j$?`nWȇ7N/p_skÈEW8X^>w? dL.bv5)"F4AE^8Urr1<Ӏ;`%XFĕ{bT@^oDeN8u *;LgO((SpͭR[]r\O#lq9א~@:ًț/" ʏ)ע_+["h,XXUPe PvqxLsܕ(5t3tiX|jv}pv'ܺ;-ep~|{`:7`==^S'ն wk@px _D"{ppEGd'TI$ v] rd;N$F,CgHl6;5Ag9$, =jD*6 8*}"tth%sY*X#vS\dHEXT&ugxf#(YCs%Z_H;e`sdJ$$x.3;kdR`>7.[7QhR/GE3:oR؞>ODT;N@П P+ Hd|`Nz'@,#t&"mV`:Q :ߥ"ڈk"!93sJCjh#LCp飪hQ%,R5 j%;;bͲ 6T4.32i@Tu*KR7"lW/LN>ͲpP}N,6'%HoqqQM2A1D q}1ݙ7XVJ~e9R>!)I~љMŦ]lsU l`3>w Ozާ*>lǕ'N]Øb BZ {j2DIM&Y*U9Ṋ1:Do(2b?bdqo"'PAK!l85Vɛݪ22ΎX2'Kis+%lBSi(; "E18Ӣ`C$_溭b/Ywv&iт", kPc&q(|E>=Fkɖ:rLukv njg=>I_m2dUmGNVږ@+?!c\"6R<@2o<2:N -pWVCZƬBXP>_5_,YEMእ2Q1ջPdۅĜӌ4c<$d1C4Ю$o)`g $_5V,SuH?תDӶX/1j{p>09ѰqRi,6FgRO.1Dؗ{IBK:D&ҧ\O,j"_o&;,<5jJ|CP5:Riɤ+gJIR"I5m`_>J!Ԕ<$fʹY ՆoZqG8-;Q,.) w +GtǫgzG⤮"U\-qB{F\;}7鵲ssڼiW%6%];׽WջN1.g:2̝: `ugc'="ջ#aѪJE*Zdmv LT'LAC6Dp6#e )$’Nz_p.-D):q(DnoālWMaq  <'qBEѭ(1' $z[hn, 䚧""/I^46JE)~C}",n>CO'zg:i~P# ;E h/ teMjq@-,dRg #~ݢ&Bg֢nQb,T#/H&@ѷ(r̦ IxL"k/Ȅj4E 7Ր~+VS|Xvöڨ^*4h̲bj&:ƦX6Q\pLz. nsTSF *AGt-J jL Pr~(Ѧe ɧψ᪐4HNGZ.Iz|F7:gHSfT3RS2>{PȈ8֣,m!#3onƧrlEt4P;~R] fjc窻>NM`3.02gD~Is)k6˾އt\*[+\ĉ2Sb KB.B #V.&H/ CB(jcjҲkGȏQd:sI*l|I رd_i?@9(0- 926Ѳ耉B,.묮|iA%"CƚkWL0r‡(=S-ێhp"ii)haH}0L̦ZKPSrr^:-wF 0F1TI+1S%?."Ml[e,$$ҐOkG r"-M.QOz*EO/kKhƘdr3tib5C*⸮"r$7Oh~8q*6pb4gMtaN'WX oq)jV6CkV SAQpqnuJz"egD:glsu@71 lI0Ozh0z&vE.2pJXgG6NU+>ΏdM#\6Q##B`2LVcn¤}2p3 iWȌ@?8nD4*m'}Tml1zo.$H0uГ8f1d(;>?[m$N#JH!|)(ѩ^Y,ػw Kj2B]n!ˎƻ*@+R\ƥCU8bZ#BgWX:xvwy-_"mXfJup 7HA\Hd>@.(enF9jԤ'F+z!hvX*Q;,[t.Hٯ .u؈ 1($ICg&.Cuכy40oİM}djR?>8:^TE0;P2ry8<_l bV- H#u:j "(%qrS?$;䱡:GpcimwcmY'Kh5Ak딊/>'kee AlTi5>y['[ fe2a!qx <;fqBU6 6u2zD{0 +Tm @aac7RxM VqoȱbY&;~lHAj+\Їu%Dh6V^픠?O{JKBC<&;r%秊6sg 0ۨ1=&du.i3hR˓;Vni8Tnb),0pMC"CI)F߃;3oR'td-w?2|p23+r_C9r%V|!Ř`P{u1 "_@IL8dHS·lBU\S <.rvP4B突hQ#;;䎽Bj`7'?fHۡʟXhr0>kԏmIE駫Gglb©xnoܡ,? n[dK}Y{z${|"]qgZ3Hri}oļ_nYp2:>ܗ2~ '71l}nz"՟Z帺)M#4r#.݃&mjh~ale]ˌ苯N6퇹LI\܏RW%77~% w2>$Vz kO./j2^U&Yp'馱ا]3O4T w86{i%ؼ}ځWN14D6;Ag\JM76 >3@t* C"H1~ F8>؄vLf38@q5hI:Nq F%2BSE!SLAYFGB>J,HW4K[.B@DcaI<Ge4Kd" TD~cKWPv{/J$SLd1 P"CK.KͦZ(0 #o+DHL$0D?&8)*t*xJg R}AP3ؗ!MBR̡339``GL/Lx,}~߲r%*fC4~Z$~tZޟ- *QѤ;J}e` _˓NH6Z!bS4 Pt򗢬J?RNWYcJI 3Fp2fM`4eӉP (!JԷq&({`,`)H Xpٹ!TTks Kw=ۘ\iAV;4\jq":@g\C=LDл9 n~Iz^u5YAVbwMH2_{&?!eHgMp#>GA Y4Gj?8 jT ExۙKKT\v\ Au}QB}Ѥ&%qsD4 DOѦB6UȑOk)MFcvH1KrҤVN&YA ,ɿaQZ VzD:&(+YmN@q6(rYY9 C7Ɋ kRhcj;kĮ)}OMUޝ/(PK}Ҽ<)8[* tN+h4 B-TGTe;#m{jTFv,%1mm8NOa3bGfUAlTIaԒβFnP&d [#8CD~%Xhh5z;=ɌG`;XX20~X ZXN~j48wLzdM1e =yW,yKFJQd,G} S4SƈC."&jeR>:R yƮr h^' \SdIg5HղC+DY8 Mu vMfub5\)vby(D :31Z#w2@Yى5MWCGQ1iX$/Cɂ625fE6 هlpB$hrUf+b̕ih; g4{S @`X#̂(p+i KwY̭֕裨RzX%뉏j'זkR㭦@S֠줳)Pޝd}at Z[H+)C8)<.y?:9QҜ!з؆$8׋38%PJ9嬨I#2ڄj(3K(ӫoO2 \aqK.zaIS!{1|/I+4>/k8kym+)3sS ) /*ÜΙy;%Q|9'Y;9 S$s^ d[ ˾[ո)lZ!c&004b T8e5*۔3CH؆! 7oCt:q+A䥚w7@H2=5GI㌻PF5ZeîП*)tCsA7;+*K*Ecb6IG֫⤕8+Cc8"ɬY/ޝQ5ʦ(a@쌏3j:eZfMj&\MY!|0=4#,ྦLNqA >7;,AжJ1 K\@(&F %"ΤKX?˹ ),}!{▭9;Λv &a*D/4R\f5L&C? ZנѽR ɤ;TiLsyGM|#.;)ҫ|Ϥ qD{׀*"qJQ 4Jˌ?hQ7HP|N,K3\G,E|2I_-+\H=.D״Dw{z[϶}4B1ݛII*B5+yp}4/G {' 3+YM-2㟳[|ָ3S2„N̥YF2C3Z0Y|լ\=Eر<1$IPC'Qし|2}1 |l @yIݵE#k[|elI1ރ2*` טܙ 7I5$iE# D4 AkD,!~}*+DsЎ-y'6 *Ƴ53"Η !0=b֙ݟ81w $յʡK"-QR}Q#P5hܸ9{ˑc~$9_@=0{DqMTHCܼ oR t쬦%bBV5JLj.+<7M+B`]2=*͜`YeZd.\ (Y<]=GV " ȼ'db%4 8U)IaM弬.bӬ:[h|+4فbtXOn" b$5T9Xʀq, }/8}&9;:VFӥ^@mzLǢ`aNA$X|u A^[S_[̰,TD.u؋.\>ܘa62: ΈVAP8.˲-=2 ZQ=@nN08-ZzڕDq68Z9 i!c` U5.Vݟ|p01@ ,fir_.Mm6*:5<|"h2^f\ =`iZzꈤrl̨RSG=㽛`ZV]S^CFs;U`{_`Iz~ESƀ$Ŝio) k"%XZcT>h.堢l"LZo,6 Ảdn=`ҤF J܋4~j?jY= ;m$ 9\ Hmp^~ɛ V yjZa^{]7nXX |MFW jՇ !geo:W.!+ϙ` }Γ'J;44]R|$%I|t@s#Xʊ' ED/ _uO|\5z>c<< ؟n qbN@: "Cg$:MS n~W n̺g}\1ʴC)Q͎\ŅI~ɠ;'0f->UN%m%9?+ٳ GnͳC*%kYϴ6Ia܌+Aێ9'h7>Cȼ+~NӠX?+B6%xQ"7|16 30!tMoJ[/qZ,${w(|t?;<" D{3|0JF*:>##3~J0:CM-0ַhBl Bڣ:Jd@H"ȥlB:̊p JrMHĆ-R>Dª12d$nJ[ 7 J[`6SI?gSHhth翓27<|< #Jj'SNKH7m'')R`Eltڨ2k&U:.تRG/%p$WA"#o{<T)T LB#Qv WMH\ʸw7v{"]4X,8:ܕ)@ j,'l$C6ηܬtal:J?2d5vd]GٌwH`> =JP)F.NqGG@5,wT$r.*c"!/c lJIJ6XbtJ#\7xSdY+b;Bz IM ZCxqϿwNEX2L8bw^5F l EH"WL a vACNmO&ўIw5җ_fھeD:t6%Hd#Gh8Z 1M'(RH{dLj=NFKi gSJ p~ 9A qr!HWVHT,u'IņHNH=kyi&:ZT(S} XDu|Ƒda+ TӶU$Wᮭni4M)gg-N-mv>+gJRS!o"'kͤewd:?aGhu+'Dt#f@$fv*CKK$Y5& D!P¥7 fƪ-xZAdzɬ8 b5dT @]=u%)RcGhHQu!NHR IH,u萭\)_zG_k(%Jzz3~.~ZA"3Fgy}0d(IӴUU> E-i{hYлH>BRZ]UKfD0%Y'AuoUߘȀ%7;,7FgG@D VWDGL惘+ x- Fk#bR{" #H1>g <#hbu":'!>ȉq".:BSB">#d f(\',mjc?B.Hy+@׭D VPK İMrQ&j i 8`!L lPUk ^mAymKGhP:v'֏ 0mBRqgW 'GWN_"dCgAi-1,q1XRӁzLk8TH5*w Ǡ.n$N:`D:j"-| R8LN mmt#PIJiRA)2tE)޽ÉOflԗO ¸+_eHn/MM6Nj0ou骢x|%? +` ua7N]͘u2r+"]È ҇)؋JjH_P.Y*/,p0DPMsQI laQ3J)kDf1PGܫFK-A1/1RB0B*)0C"B_kHfM$hrN8W3f)7ZZ%.X1Ϝ(Omq$g/`oæ붴= n++PCj"e:W-8sPcR%mTr&0BLӎJ} >ϣf+-]#"먊CCD0v!BL1"&BFg0jr*"n:#,H@u%+B ܺ&0M*MK?sR;)Jx T(U%a i,I7k#r;Y v%U"n UL`6P[$2EI|#wKȤ$:2ͅg5B : omʦܢ*9>SVːhIL0c**rN? |RcM(w3zˇq2PkPq#f%i_k&C%y5VmNRgB:M ZY<,z}WlUs ޓmf/HMk++i|0`ȬjEm$v~CLjUmflPv@.FZOT(,"/GlAT#t$O0ӤF4 ˥o g0m :k3*AHkqYKO.= @* R0sRobRӒ]9s8 y;j֙)(Er!+GElJikWQ.790pY3mNhdZKRT.C9rx6.Uv;vIyOb i `!R}BDU+|8/X\VJD~ nl–Kh.DwRQ`M}(7|̐U7͊GBܒ:J,d(X+Q뫏S*C&V0 q*7ྲ R ,zlGoPαFC(Gqxv %u*-:Ru,HVڵ <R$-O_ )]_xBd;jN׉;t"g?rs(m TSa/+a\Cz1Sm@۸dD _cG]Wv Qu"R]\ &}jB. "3Ԑ%z2\ Jԩ/֢Mx]ꡱwxDu{3P{>l9Wako4k':Zy `Π(:"{3.<8.h?%P^vZ}MFh!VA1 @0/rLn=YY7Pˏ~ u7a}OYv&9UmAYeI'](xy2`HGȗ|m=5_$]guϿCO`+`:YPGFL[ZŤ;wH  A. bXMDذd)%Ir2@3\3Hٳ[lQӘd[ENj lJn Dh̾H(q`"F$(l }a< tN-ahn'}G_q:5.u"٫zԂ \9idWUĀY3cрi,2H!jF sR/O9m"eb:n* 7౹1,* VRDY((Fz?IɆ+g)1Q dPQ>$͇۽iUk+90Y槗K+"^9NnL:W2~bM (P m _̡\+lb =]"8p>SVgA #uwcfF#y;T+,&@-!A efpE4Knz.ITÀe$(@BO! ƥUyQtt UӪK*҄h]G%7Is21%J\T޸ Mω i "/& OKtUe4cxKF YuX ^ .shat*kR w4VO ޔR= -53󃁮~`N&&xk }*!S_d=D<_c "K bgJ)]HX*ד*UY}z'7F3هiթo;EF+q\{-'ILYT oFbD-Aa.PZ)z4clK:Ѓ @(ۤ ȸ3>b,ҸlƜs%I򿼓:5S$(ܬmY)$?8Jh:I6;eB q< ;&`: "K$`۸8T (+ʥ:@ 9(bBd)Ԑ81"FS)s۶TB8#1:(/H3V3 >3AEQ,B]5DKDP)$205Ș[_89׀97KK@M=d 9=J供dWֽ:  37Ɉ|,;+ڧ8;{ 4 Ē6 S>T Z\#+ *nFs K*+—LHI€: )<e" :T%8),:sAŗ1L d4@\/@;H(};w)rԭQZ,d%C؀8b9UỈ+`3*z8LQT8}X.\ľrǤlƍ{v ="& $G9 Ɛu+V&^$E57N p-4$ +u"& & "RB|B"CsR"z;3(J!s$C47:V%Eup [JX%) Ҝ?aW,H}6(8,ŋ< R?Lew75b*UT @&Ű X5с:di<Y6*=EAۮy$ѢZB(jjL?Qx(s:yk~}N@;}PNoD.Co,b7]$RAwZD `E|E>эX02!`h㖼ZOv~'q`=HnռhI9[NbݝK.L]j{.I߲ aٌZdi ~*e$@Hk\t:0qч[`TV"LuZ?l_8,/%9qZʰ`]&k3˶#˞c;%P>7ԃOQ %@[Ӟ:8;^5/D^ dJZL-ð::8læq%[^kpjC84OC./A~񰜨~?^pmvMuF($*ɗ6Ƥ#PVm%@% cu- P blWBbgSTHCAAT % TwhsNuèorԿ?Sh2D5:|MzCvw$Mϊ[]-v5OtGMkU J3[<$9/ *@۳KˑgKZ%zn`&8kw-vhe 50}uLA@p% ~a F@0(Acb-c7I 8$b1)?P(|Z_ Agr% o 1 Wd4q+E*Ʉ:E3D38busDR"q *gխ%Ls&Ȥ7CLbR ǽ&K6@xHOڲ*04A 3nSL :/h136*!3 BCJr)Fҟnv02 ۀN:)c0rJ*!jF! !l?4+4$M5˴ˎ#4N<+4B)H M((π+j4P.OMIc^" 1T$$B8E25 CU'Xt3Z H³vGOV8UR+B ̊,B6k:sAeWb-' "thVh&K:K`~%5ԇ;fp seZex̎LkX}ȳ%fV{RT؝K2 D?"-]춳%+zIh̓dn,b`ri Iw WI;e2AϞKԍ?w~(0tȂ̏V (KR=Y~騿D>-N<ҹl<.Ch&Rd~BEӇf0 ["ި~}~>3`kEiZd[gu41%:,:ݑlTrPm17gRvE xV)vcP=}Ic2mR!P LB*LX@I88JyggC䒊rPvQX%^D ](/fgHB WXǁ3xmП.N|{e ?֮LKbunW;cM/tȥr)"F%عŕIo`)\xb 9̀4upAst8J~ tY)8: dx$U΍ $Y"4]DfJ="6Ÿ2Y7zIi9JB 5wBK\RWRR -#Ex$lgL5xӖ2p#ʼnG+V&QXA*B"D0N T`i+VqOV@Lc=?}I'2S1'ZW`-h7gW4LSNykm͖̞ KgNX:,Vٍr2̧ _,”>HarZպ?;PZGU܌Fc(n>؟?sz4RʄQ-fjņ'MkHjU]`JBZ˭G&h,{^ qDЇ_HxgAIӮxfژp Z` uv*.FQHb&׺\Fj@%dt=Z?ct..Y--bro5/$\?n=p4w:iR Gޕ6pf^J˅st='ŷ9IF{D1}zYؓ uND3E2B!_)&TP/dwXQq2k^J+Bj"gOZ!{.V| ٽ1k oyZ>[t8vET\S!p<1JVufĹfX/ xi,RR7~$my1\Yf:{ِ. znF` ɞʕ{ oz]utرFF]S^rk)zTxBFɵ!1 V~j Zw6H״R #F)+4,͊@.E$cTT;W^Ni8O5-:!z-qų&Dڧ*XQJоuQm`lh?n~~ KmZ¶^jj_4Iw4 |ҟd^hi'XcN(־(ԩfpHih(N++֣j&z$+VT+Xu l"LA!#I8I(F\ F:h|I%˦eL:o-φ4N6"pAixAJ 6M8$HD"̏laFf%D]tQcI.R*p dG JIJ J8_ LfErV60 nꊇh(dBMFbjTP'rƲ6I\/D0z$ĵrJ8v'X?j~dE<  ,غŬ$fKѦJE AqP ŶW փ$Jl |'d2RzOPZ扏0"0= `Qm <'Fo,.*0V$Ji&hc׍ l `ID"4 PJײuGB@8Y4KN J%hQD" ɠQ$)j m:Kr!P(3*ՉpğoNCA#hxJdPc)34|,Ŷ;J+"E$) x۱zq$N;%IfMr ¨&1L&f*Ί/KMɮ $7B n'en `ց-bv^&n&l 0]>F#Kf@2@F':2#+3Z4Ԭ*zlSH93€4&$5$ I/c<'/Q,I,2vfc`$K>%.+-+][rjZG K6j:rЄiJ,6'gupP$"2Bs^sqYd$:4@H r*hYN*/FIWpV&ѤW8B]YiM96K[o,^ \l/uK(# 44uAbk[oJu޶zsu2:]p!D\&99Lҹ'Nbol@VDT&Ѭ/w^qh}!nlKVf+ѯ RM,((Pt(;FkU?"7W=l*:tf;^]ܘ2f^~]u'hbǂcD)s-z$Z%בI öAyCs'4(A*S4rC+)zqLfO4XZd!yuu6dJ$k ]X3;kO~D+;N~ s̙Fwh:w='E4ZB8:)vij#e[3j!JO&#d6q^Phw {qF <+t%m\~'vbK4!g89[ E7n'Ea NI%߱0L-dRWi | Iy9AqbQBg Cc0̵K8EIWkT!>Ev 4H4LFOQb;Dpb~7 J1@ Z7Na4 ǀ+Y##GF;T#7|{Aȳ'6oz EF}C\*1ی@rG#sOnҪ 4HZ.*Pb Kk$N@㿭S(: V: 4˲=Zx OD-+.P<&Ъ';"%8 ң4z<)J!+k?)?kcK@ʖj 9v+̱|:M"HM~2 B< 9Q] Jܞ%IZPChlأ}? .ɪz,π 9B(4 e+z/X16\$-Dl[QemSrIȈ%F@p FXE.!0:ޓ# ;R]j7 i H^_6A34(24WExL#<6h[ɣ3["b~4oD~%7W!iXH&Ylؘ""ISݸ8j'J@26"zFhS[ND Ԉ [&WdWA@ _cwAx\qg ^=71Lh'|Qͱ!+X4D|cYI{`_!˹Bԥ,|.BLrOZ~A'Ԩ}41=yݗRԺb )g*5 ?1!-!ȩ""ōd3bZOfM[vdQl'\RR8BD@ @48۪mE hZ2k>2/3/]N[JEU 'wNMNQ&fVQx% Hi] 78F4 e mR%Cz8 2=eb| k0!,eqHP\$6jȑ|reFfIT@$%(򯨰d$8iH3J=Ä pb 3I! XsBbBgؔAs5bLu6Ùy;ISMx+>DA /aIv\K$Oj%E&bqF 5JdJP/L4K1QI ӷ fNd.'Kf%}L"ك"rBY O$̺Ŷ 0'%Y3p~DV;<`A,BS|7ϬD5,M$Eֈsz9^4k{dřbќ?BdrhyÏՎz LgD.Ů0c"!MMʬ?C4zT'!#!v ҙIcwP(ZI~kI𔳐6av*q+۬xK?M Ll$\mO&?յc{ǀ}Z4kOv>MGɑﴪ%:A9جM|qy-Nkk}#xsB+gԦ摼iLK9NCĕiXvZ0tk҉ђdeCqŔ2]ɆeufB:mpIi2J>j@d%1M"ȫ&ݔa6*ސf>19lm8r)$eW~HM%aNI2YOc%T;E̺mH*\[W-@ML4#3AE*cYrav=ioA2U`Cx*ms(!VD> >_$ g#ƐBF֩%M=|&#d pSJjOBǯ Xj ~ITJǘ(d:h&#tӚdr?NmJ L\Bb}ѷR?o\eO7_eXI eȞm5K;>#~Ԩ YӒ-Ity46Rw_Zv2٭q%7e{8gۣRHx5Wʙ-a+oĞbsX9ŏL }I'8#" "S +٘>as%3h,5 *9+4:\P V HBPHɪ (?9D1;k>"ArKL6;ʳzԙ; 7`!nA.S }  &0 4C8;kQ;ʝ@?8W7/ ್&Ѫw 2LBc=R;y ѕ#,Xؽ43}/9ǜx.̳BDf !+M˧9 ˵L92!Z" u0!dv:3A:*&}!{. f/ZoAll.x&ɑli"sYs )`²"J||e3n4?RyzD6 20>Q" u)ER21+TfR0қp$u1*Y$D!\:t48 4(HN9ĀȢ a~br0“k|k]Ì{:/:Ȅ2[>7laD|HȒ1Dó>Q52KYD lxML\ VWzA$5?=OcO8*l<FGHklCԉ-k$Li)쉼6H)(њ(ܡZ08I9M|>ԠY?(${b(pnPڸ<ο$Z9!$1.ܪ1µ9N}` RCx F,Kx}=r9rLx4@ҎzPyeY-$D9;tL{Ca J[bۦJ㵢ܓ:V,qa`њJESA "Ll2:_9$`=h~$Ĩ [:k)D@&˻A[t>SsTg $5R.e|Ԝ$Ҝ-c.ε+mMP@ZSE0|' dIQtlJO%dգZS%q;.DНQCJa2[458PCs"b4Ȓ QبӁ (JH+n;ѠѤ 8kBg@=AOSK`O|<8l %b.Λxe̙KČ5K%!M|Gsҫ$0-*=9˭YHN%DRͤFWJVQ6@XYm UԻF5hӘAi'A|B,u5n>)d*-)FTY:x4XZ2(S8(?^/a䎊[jV8%5 [Udu*}cNGRw\ĔY2QI'+D.߈=M!D]p1"{бܻ]HQp OFTӰ׎y+wB@TuX0Ex6 d8sJCx;I鎍I0m}VKw)|HFiZC)a)6./M<@~RӖKjl̤6Խ!\Y(ΜdV `r-Y> Y!@؁R[_}M`\e7}JA b$ l2A=Ɖ@Mc]ʹiֲf k 1l ιѤ>:9ZKV\K.=W-פ@>N^|GS 1'k]I"\X5$Wu dIcSPa|?y 0R;.}J*6=Xթ)5X>2j: jyKUd14B_hQw6 ƲI ycތ(Ѹ)Z#6Rj8P jTQUnOsaWb.R¬ }aw` \'+$;St'EXb}d)[!б)EJrwϗlO&{uЎknC9kI>.4Aܣܬv'nS-NC Y*Lңa4_k2Lu([꼥/t5MS6:)U>EF4À)R#ۛT EVEFE96W3qCۯQ yG;Oj' =,y&]Z/ EȞgto#{sz6 2@.hkӖ &^m#Dʚ&DN|!=Հt%R<u"]27kPl'69X|kp~s 1 A_Pp $ _X E@wf*z`HFCߒxl  ~a04Z}e0867#bn2 Dcrw~<Ң+Tڮ>+js8cʨ3:\GrTR(s0.s -Bcmb(tj+}a4u`Հ̎h Lnu {O|a;o9G\"gcBxHɜF?cdZl,F{{vnllwϲ *hz>%L\Af#,B ;{n* 2\ D7(nFܣ+!R z4odj SF8G(̄?Ӣ[Y.jlrP )4r:6Y'!fU׍Ubgu7ώȌ&RJ{7#u8 9>;5"UPvlc= SmE: b,‚RAi3[R#j%L|̚SlYA+e6HHb3&3n\"c@h\A`_TǶR Rv*/R[ 8DEВ]1X%1$ q1#pygoGTBsOC`+ml }+UB50!B\fH~zn@Bo&gRB.Wq7t]nb`"Y%)kU 3jړ0*ҜhsLkh,۰l䒀lJV=e 9f;oWaLT)}f:KSg5\df~Gdvc`LUNfMI Q~1&?6T t}W0 yLk#d'SBc/T€euFvT$8K0XY7<yju+T%fUDAݚ 'c7d7@?Hm6MɂMg1؇컊G۲IM^NI6)LlN) LC}Zi87R̞cCѱ" Ŀ"T\1udޜ5 {帵Ť4Qh,]طA|d>X-sûL +VH6X4SfLᆕI|!;ٞEaZ+ X4sKBŕEj+>7]wySUN/nfv1=Hꅣ|ljaF^B|F̧F,L>>aNpLkb>O,*" "b&E{&PhF Ԥ *r:Ìfm!n(eBC&N2/+أ"ΩLKLj b?,BFB`Ee L>iR,g!B'2(]'jR8NB{Y0Bdn'z`r$33!*J²a K9a) #>S)sl"q=G4SroQt⬘zKjg,(rnt1MfY*I#NE6K9co2rPspz&@ƾpo2,+3\I$n!1"jھxF:p<{aW3q>k)G,^-:FnP*!e+WnjHJoZح|e6nǮU#CFT).œ56'?@,t,82P6x 15_: s:<Ua6Ȟ?XZ^ 4,whԁp]ƑÃF.{QGNq'0Cla0q5CJVp#纑Adw|ʤ8m9v,X;vjW#UrJZ]c0'6_9ڝKl4N͕%.T;j%QE-/1ǮXD38ƻiWSCllY\kTu]TDxyK7B"NoE%ل,#Rks_ì}HmȎ _B6i\BV 'ƦHJa :M"egDNYok#{ߎbEbݽ0͔4"Sj @SO؎č/b;ԕ$%8Kĭ~M wsM).7PJ;Ʉs MYZ $w|lfc̘dc5D`N\-T[O& u+T"6㯸Z5ǩBiI%SbYOS1`.Np+ |ʊX"7G˼}Y_c"-*JpZ~|e?(0B>^`X@?$XQ~hd $< }N&ӉZ@\&1G(hm>4E6>/ G9 P35q(&zxйt.M С BaLkDRqwqL-EeFifmrŴsGμBlgG ǀGDˀfWGC7Q7QZpgeA7}ؗx44f8^moP˃<8|@p4p)A7k`"&b& j5 D=o#6q;:/CɢhH6Zp:1J@ n{o'J޳|p; lxK.?(04rCk4>RH.,cjΩR;nl'&""Y83I$K4z6"{K4&u[-4D(?Nҝ;2Hl ʪ4B#rԊ󰔯T  2f6 LRBfs[*. {eWC3.Zi"8:*jQ5,ʧ ܨW(?[aXE#WZtL25y$#{H`ck. ~Z*}>C9cY"b"Sc&K4oΘxul{K \6\ $C4kmQ/CP>ёy\Mr쑊qef A`_6C[XwG S:\~Ɩ,TKU4b29ě8Dr!0+cx|Vs˂Y˴!9r韹.X[ټ$[$O;q>ȶg̮`PZlD@7FI RJfZ+R%ǮlKl#}:|? Yp]>f`$},"ryY"ZF1 mZ| 9UaLJl8;F.Ó8p8(HF 4hԄA% “ dPMwf2XuZ8tc8R&a7զs΋qtx>H `?-Q´JlpDF񆓬$w6PTTJ@M J7jĶ 8)*E HĶDxtc\J.B`h~ G:ZG,Gٵ~NtUϣ\%LLzc]cvZGPm(jZMGe? A 2j6Lj2>izQ+9mE6!+•(J 38P@}kQ*Ӹ3%@׻r-}V$Caa]ݯb78=ɥ3( p}p:^TIFAD{Nݜϙ!&1٩[3+T+!QazȌ3ݬ,i#JEa։!>()ayCi#6R դLOⴳO;ߎ 3̀ Px⴯({I*K~(t%99 JJ<|W1j M  9c25 +<8ak,k !iFy.48.!- ųgŸ/ 16_%`tUÀ᧓..!>-x,,2Dk/Y$閟r a1Ɗ0 ,${Qib%T( BbAw$ +"cC6n9.aZtd $BB܀D"x8 d˽13Ѕsc>’[C3\«!0[ Ǣ"$;ljH]'>¤H~ˌ%l2cNJSI |D' YJ;8k-v7(%ɾޤ?@~'2k,Ȣ5F*})-ܓ6k<{QpΤiFӍٷ-Q=Hlgր!H\æNKؐ1V[3a3ըt0069BD3XFlQoȜr˂Oc9}9;2CPp2ܜ$P;#I|s)J7DS [:R>~8 @D9t/"PF/#C" chT:z"adʮl! +OⲚ"q$wRʊ> ,,hJ)F:؞->hM~ ܧ`4RSD <ݩB_K G!^MR3VW+P۟Mu1'~=۟ӄi$+H,=xѕVtPCb-;Sm&C1X\[߲K ϫ>xGC:ȜBDAQkXTd6D9 ԝQ ; ̓ ӵI5AB"ӫ{aD)|"# B92b %R5UpIr7, ʐ&(RmG6}me#~;:@+D%P<1Kݠ@I0 # #9,$%X+c3Iϵ;.vE<ٯZD;ë25O@%6WP}UNe[a\&TYDF| % LMlETH} qU;$X'/88ۥ@ U5{TQJ9J1!̚%38bd;q¦z?`0L џD%E\QdQX`4{2ޕЊ=O=82j5^DSO^.8"RUJ@.jCS/lZi_ǐ,рRUj<^1 N/$WUa%e딪3W1}Sގ 3G;ۊWUYZcHokBSUGL^zx%&5Ҥєάxm#F 3!C+q-@߃/0)訶vjI[m@vWwRBdaK]a=p3QDz{Agr%CV[蘁zS@aLޫ8e;Iil븼fRF@׽n3PXAm{2U,-Y!-ԛ]1=.DQƬΨ=!ePI19Mkz$@tĝקLj|iCAIm: H $ 5;)DhʽɋP"ٚ iȁj-٧u wDa|X "hH٘(~g˼\TF'汈yФyƴ@ M*"`#b~\mЕHL8IdjOK!+aT؆$@*E9܌,RL$XYNJ'F٪ِXf= -NU2+UXY1H6T60nUB0ސj()nKkw8S9þg>zG^Gd* aiN\L͗e7{a {lhT~ X!сߎDGhIeN.םO`d0t-` z~5 cKOsųī4gx`'DX7S>\*;4S[HE4?Po [B =DFozPļi,"A>tLD-+u׻16$D1\i^N;7euNGs|m5ޱa`pQ('0  md6HTybbwVdH 5I8#.:0aOd4 Da ,E#@v5 !7tI G̶UR$HcRY 0,I ɤi460T$!RHR Q`,igHLGCdӸ>NԒ\R$PH >VzvCa@$j>G4HNJs$ HlKuBԤhŶih3& dЛMmOƀo>MSSߵ& a䒻N]*RIx|SipwYc3Hd鴛#G*z< 'rL7jzț@ "K$+2?(.0?H+5(;z#P2 -*08o#J|b+#-* Đ(K~3`~&"":9" *{s: $~Mgg*[п@VNh(m #DOrLHzz> &~#Q(OBȟD]5@a*H"6Y(P@MS*P#mll⤐3 mdi KN)U+4 LީAl]7(5{=S = )lW.8(,w i @G1/v:Bg'lg^ D 謉$,|;rb0 wc2̷܄5y$gj`DZ+D~y\ЋR(goBҲeUPs1+ϱ<9MYJ/ɝA7=Mnܛs ն6A}w]dA0gnX^YQI6$t由m ~ŗ([V4hsX9?\ɷoYoU &'\ 'DMJ4M)>;fx?@( 13.,0FMDPdR&z\9ez2|ͥ !wem@Y>E߯%PCδ'uEv ţ-׷Jzq 5(8U5 6DV l?.$2lsQ.HíS&~>]xO$:}12io1۱gzTv lj Ym˰=ZU)yqB)"?u.ʅ:6rYkǸxC` |#yl psF`< vMJuLɮKd#ꅻBτ [3 %hSCΉo$lbl`h9CxʆLZiVG:DѰD%kŽn&v)B5ǽX&Uniw0%gpcڈxgy ( @Uڼwr]sE,{;53c&X>6bdPR"?"1I:ʙں[ 󣥋qiiSu^gS;?aIaL9 vhK#LRȐFκ;pz(2n{u^$y\.p(;M8!e{X<[vL+9]M!;Vypђ*uamD$eHa+xE@ohjB|oa#2҅h]koT ТƺsMyL9/zL氻gΜІd ZdT)Ů'ZFv^ɫHʒBB1*\̆$P̉O "roAZp-zdg kβl x/ 1imľU`$KPA$JPv`Cmkv,V1N¬*' ɨ!$vff(q~&H:&gff$FXbm# Wj"2?(p O~=qG&$eJC"f'堣tD\2̚@\i}vllrOH\=+ZnzF@۲m_o b L".Al Fp,ʭb @E.I!$}&w &fj`]gXIK51~tPy3o ['"h")aR/0F#bVo|rVO&Ȉ{ o#NSq0OcB7[$&"Z>s֤{B*sCOL̖ %l"#]1oFؾ+;M;!0PA3uRBczs !@ QGx+a֊w58V4/R^8U/o)/M<h~#]+~;5 ppo,E $Q҃5D9T!9r3(֡b%~gZ)m~!N*$wuZʐT,T2qde)(8j#yA2wώ˖(1#~AW# Twn@Vȧp@wFrvVY5Ge̥4Was7;nSsI3n. vd A?u1*O 2x(6W\.'[\Ŗ9]gn bn5Ur2K }'eS,E\`8B̦Ax4kւ̅& w3Puq9nI紁v"d W!wx[$ 94*5KmMBesKb4LdnOI)qj+O0#b{WX Ӟ11zɯϷ!ػxYO0ϼZ۬vYy,ȷ=[ƃX8HDD(qֱ`e:[XG.@J!$RNG].f pn4X)A\Tap[lr"j%ؐ1-Y92ZV0FV#W.&?a up^n) OB( x28xgw5DmסY+r{@ NoL,ulR xt|Kڙj͟|5=)$-$<3c7^yE;#&fyA<P'pRALw&l#(ۯϽ% qxsu~fRA,^/6% I؇g]u12cN|f)^ų>&.e +MCոo4FmdПRK@ "is%/ ;7|2@z{3 _4ԥC<,p`x~Q6T0Fœ2lTgCq%c#_dsN*!EJ>$0mf$uzzv"s58S0@ 7ս>l&:; W5#>R2O G$켏(x2Wk:- kpVVP峙@pL(:8a$']n_=kcA7 #WsЯ lORY5/t,Uv19(M+UZvu̾s< >HSG:(D n3c1%Tw;G3xܺY,!@H$BR0=>hXK!R]?GZ4RKAf6K:X 8HTfpr#ƭV>)]"xe gE*Y3Ħ)N2=蕜vM4ʩx'"]+;pY,RX`Eka|g.ywV. N . O- F|~*dɂ(7ԟjbisJӡȒb P!`9d#,ڀ1h2Cm7(:ݻh"XTK9" @\4'-|b RBrᤳ;Hk(C+VD$(*zD>ɡSNjR0N EirBpH Z˩p "Bʣ8+/7"6A!D,">Hw)έ%##FJ@P?Ux $Q K $Fԍ\ZLK+*D/2n0=gbUQ$dJ{.22aV#>]HkJ" 8 *:h"  78'\+HݰΖnfH'5~%!yehۤ~~;>ɑRݶu\[jLh[(߀X<~.qִՁ[;p]hs)r)~׽1g—V)dJy9\dg3v0 ޹Ās|z]._~"J+i@n/mr5H Nmܑ]*NmQ3')AսBZB  OEBIJФK!J7$IasM"R;I2UQnKmHάLJ)i]Mㄣ;z8lDM!0' R ~-C̷*'U=Ԯzb3o$$xZJiPR:Q\e.An%[{!A(ε drVֻ qpg?T~̉!MҜ<'DW}\ogJ|p!:)sEHSR+`NYJjN5)e"'Fu2sK)r]nĥL' XqB$i S|)c䊔`RV:RhE'Yp1^s3cVdSp%*g(Di}FTE [%E1dVA`@%r*d)ǘN-Nj!Lڬ#ZO4"|AdP}* .IT|c@<K#W#;PZ} ^XƠ~EIuhiYGӹ"]Є9H~jе"M:}U#dóV?ه2@NGDG?J`4s̎k<N5P[nG:$? qWTe2IZ$OQ &{ K+MM~Cy2Ͱ976'#%:;I Zʺ"DH>ґ y+K$|/C#.q :l ; ){}(?"!@;북:/A`5{æh0dO$B= ;b6t z Eó .x'q5h&A2 #7ٴB bs`3Qy#%ôP̼"+ %{lʼ1#SzQY|: U,61g "aSʾ,Y|Hg@{=H*FjbltԎ9aʢĠIr58 ӓɺ>3 +TK0 JɈb ˯L<@;6CqE1#آ".G@_?"A/[1 ?ˤ0ځ&eB !g]5 9A# .xގťtZd:HQؑ3$xОtkFŧDbҳ\ZiƱd|KU͠Yi;mc~lEl {y![B1' **9o+|K“>m\*ʼLˍ|¦^|LAxn6:`Lڬ *b$\`ԪUղQ81^o])[l>1TS53/ 7<dLFet:BP^9$wSeӃseUL] SgݮMu:y|bXlX=ޚhiU0ʼ4TJgͦ{0egDUqgk>e&x ,%1JqD͑R]<8ƻ$"nQg2_tŻ*Hj,3rHKYCv^%eBO'Rc }uL&p7{~oINlx<>yhd?DŸ$D EaCC!dz!DciD*# _e8~3#'Jx4F;)FY-Lܪ 7eT2A+4!f?GWy4>k5Kc3F5>iW ¯q\2M|޿w}Q b,lh}D@juS]n:+XDpC}0=(ְ ~_ѦY"j eIlC#:/ǀDC>Pl[#UR#hj4#28l8* KK*j:i{F.8ǜX%n`4h>k@";(ғ !m:',B hb*,"MID"*ʲB!(,B)>@+7@9/'~/L骬0À!J¾ڀj2Pn8ωd&+ M"'D͋ GxCcВf٠K;m4W!df*82W/rQ8#Ȩ >[`"T2 5_BZV_$ Ѫ~H<X[˂O`׃pHokQS+dN4y6Sj7hjkG ˓d#hCiCxVtv}ӁmT朝@|~A(yH~8 #e@;Xi .EZRR"aZ,`ΐjA5dԫH.p,?a+Y9PhCvB7-' 4QIR[,>F^c>DTA \[_h"cȈpA8#(h&Kܡ1paFW*UʤR.pxawa C0 CUy2h`FD0qrǀc= ZY6'G_Z@dlQ^r88TqYro<"*/L'p=cB*-# 0Ƶ %& {k3x6V$UoINtDh6XZZy>hэ/ʔ=dԢ֯6.I4s3j1&*I\X) Q Љ8JACqrGR,{2M)se0|ϙy_zV :OQՏĸ*Vk(bg|ws-hS|Q'쉝0e,^#쌦&:%Rsb<`R%A̓Ư(*έjF4lUg]xGhZ<@clNzq?. Zc ϶:]Nea[}ӚT _:x#\p_JASu*8ECc+:$|бQUg @h/}Dޖ)TDJ>X"ݼ/kqTKؼ‘H#OwKzϑQXp˸pz*٩r^g!!B5x8&] R>?lnNҙ3Pѳ#E|HKA΀l fFyj>%Eވܱ̰8’l*aFБ2#&㐊߈9ZQwZS# y^*%Btdg/8gX!T~]Z-` E6ʽwYvHqɒY)O6OQђ\ -Q4NvsbJԻqGw3x#rDw1&ŎjL# nꁍ;Rwim~S((vJuxO-OyT&?җ}]?_YͧwPQ|uYm- - Tr7/(: <gn *~]`'+Qlj%\؉#q5-g L#d8!jk]9e`43^ 脶(gܯj@$JdfWi#boD¢yN3L}#2+ ,0TD x`  S?C'$9Fbs9B&N#@M5LU'%;9L1گLKQ9r'cG|Bz!OĒΆK8-Ѓh-j ڛQֳjT>% 8 v4DѴr> i|mЦ$m 5Oo䳋0 Nl.oA8rTZ*8:0TNB|<²F,3jO2S *-Q[+;N@_JJQm*t3L\;5}Al[\Y}Tc+Lc LoP0|h5PY`ս(tR`U(Y19cb&A${;ȠY3J_BB50dуR"52sK Q#X ̾m0 |{XYW21[/k@4lW|P*4I((%Ώ;̍`)gԌҤ_A)3RQ3 s BY 'Ni.L2Cj T-oK3c$oI# a 1jU|: J'ODSS Q-|7[A .팯]OZGie I(krz"OZTq(P|Cy6Js0 0LZȢ DɜhF .޷D5)'Mjj!N 3ra8f!3WlJ,+ŁtK3j&b9RU3:JSlFv&,(Q\w`]pVg_9dJw)(fgT$dXXRjꀙ%76Q|mXTl?OAx BU ?1ҿFikcsd(hr|h(4isXrqgjOݏd_Ihdӧ0c9YgjUlU'gDif sFp}Kf^ц@8:u]v` /Vϫ$p^k^W&A"j /]X’hk̻kLԹhW|9u(M]ʏzM8o !]mSlT9C8alI_Հ=p)jN$)p'EY ʊE $. "j!b#%6̿kqZ0Jo[FX߄:l(ZHzK`$ vgԏSVYSU_OA#ɨFp6%d|_b_ٯPrrZW½>m])lJz54 e EdY@̼xN$^S#&1V^}.Q(S,w!tgw%?À;Ōв#]S2TzNv Cf5h6hfl >)`'{ 4ntzc|;%)j7Oƀ'VK~;Xf5pɷS~6Z~̐$3C`[ѠTptwŁ҅DVϖϹ [+CG>!uɏ68]C_ļ8P;yvU`o @{`XTz912#.]*ˁѹN(m;M#hp[e[9X0P3av`r<ҵ+_q[Ƕ*ʺw+m vM5zvٵJq|$~(v;g1P6X##˜~L;uy1?;^p_$߰ Vr0\8dAϕeP%;4_49XI"){g“5QJpScXj(fPZ66ߋUq̻uz*X[^k=^Sݮ $1:mEJq[l~wQyYʝ #4lʮΦ|i.c3z %E:|/YA V\$&D5RS';8CYUhx,?wIq͔^tG<3BCW^&~A H䑐 AC$>1Kd' 9"\H@܂[- zu =N@Ϫ&OTV? "[7 )yT.7&i9^IaP%-՟V:UGXHX+!q'JcfIgfR׶Ie!Yn_2ҫfa20V?rثzG);sˎ]!Yi$oS)uw~`V9GYH:ާ:v$w莽Mj*<>%K* ҙbN߼ ;| ʱnBl)9?b|&`CT z`*64L#q#n3ԅ1EhzODfټ3ҚnB2%\^~$ z/g>¯ PMޟ!IR2\#)i!R#(BO FN򤒏18QPJ0,r,s|-o64DUGb ➨ݬQ[TЖ6[m X.dFzUL2Y3E]T**Q55!# EK*Ü,!4PH 8tdudWq"VeK/+[7# `g$0jا@`,D$Yj"UP 5ѫ'y B|e֨ #$ g;c=4b'/NE؇W#l/hG/Ĥ V%SmNYCij8Ԍ"oc |.MнQe'5Dx2xI[*7sr Eo)\n9YH^F3(!j#ԕjw59~m\2@  ,m0#'QmJ+ol#pRd,<}҈$t\Õ$)!$Ϻ%$nd?0CP#a')@"m|zH~X{-Y`ΈV!B Ab755@ڃ-MHBy Ͷ'g'r6YTvFO-a+6Scec Ji@IJRb;Xι5E0UtNR_`3#pkUPьgȡ>14Jvy |\rӜ$]u'ס PmIΣ8SaY]]U2٭(Ȍ+f'X"0\1 trE%;E ƃC98kQa!8Le$M/'';]z%gGDa/ZC|C,$\&2c2ʏ}Y0}!\x~RS-.'H=P.Š@4;f} wOHDePH>"UdNU/N ьEJĨS.ԩd"EORvBq.€HQMȥ5U BOP)E)h~@oL# W{< P1{Ciҏvډp51J]^\POeg(˽= m(čo@]izȱ/oqFLzP@ !"*10ռׇ WmҸUzqcj̄-%Y 9XC"&_W 0'i7،z,QU[E!=0E_+:4TTLrfRFq//I)g7(|ԛp3?# 4 UP[y3nO ڙmù}dƌgpyӥ"͉̔s]Pm%$p]ڑ!mx MWר!#H+S++vrۤ@!Y*pg`XʄT3D}^'4ѕ7g [Mp)B'<G'%B,kTRt/_<ҪN(k(ҩT3J V`ȝw[ + az'DwI9rC8jgLcX5xVV]%ˢa5;k ʔ] L)|-if[kKctz/1fT5v(m#3 Un.'S+ɵ7.֟Ȼv_7}(JZ;""ڽ"ZcC{vE6,+rmb6,yEWtշEniNnM>֋"'x („ GƂKAGHQ%C72Q:c1;(7T-ܒ1돳HJkq>)ȩ+(s< [앻)tk5(,?AC (iN$&kz-s˺x,pI?(aBNs%Z7A3N|qr'SAx:4[L*98´:}ѠH,ՉDq!lð8HǑQ+F;1C}&s}:$)<#+KbjIcEc%:צR>CL"D:rn6YP 1E7[rYm)R d +P 2Jjcmr>׳LzrAT JDa e).AtOJz?rUYYj:WJ,H խ<3PB[MȧfGXR04*6K]MZ4ADZ?f=dΡ$A^LfPټ2~iX6 HԥA,G#E˼؏ 3?HT74qTO=]*lֹMT`FUL{[M$[{jʐ}I0~iuHȊЮbA]}6\\f9J"[c)u,z.NMk"?A[`;kc}G5Ě52su܌QyA<؍.9ɬP{U$fuVm3ሼ!QiPV[}EG6IIU tDJ@?>L9Ԋ@Zݭ79T10RXB氃Md)%T}8Xֱ~23PѸƆI4+LgA;)ˉ $om\e9@񚲡^KJZ1^YTԩε:\n(>DI^¸e laMJ\֙h)M_6vG]LТ; \q%z>5׻dԂ\phhr& @13g' 0L}C6-26;q% l zN3{E7n.MΠܷFoCU\NR0H׫X5$2NCU7M:Ix,2>F`ZW5|Uμʲ'[94^D0@mhXѸQORmyS AY3 `>0EXtwfCYU`OeuT2\<6³pth5 nȖ\k$A*Z V "d CS \ <ڣ$?j7Cwj TaLmqoȏ%ӉT=ԉ,CUEev ꔇeQ4~)Ts'zEo$nP9~zHr}U$3|g><%>O[eNmGnx:)Ax}7*BNeRDw+0C C!N sahiw:dCQ6 4{?|}>|ٺrdlf8ؽDU6fN&Q?Qɍ s(nbb COB?& 1cXfSR1>@  ~_з4_8k oF3#1Mɤ1PDLB_$mD&(F72hM5OA2\6I%ͧY lɫM=$pH }VNkKVV?m63wEd:y@ "qʊ#>Κ87mpܺj)*)A35m;j 6DP˂Q .c,BϚ`, .; 1R 4+&*(2d&Ǽ%Hϼ  ! lE *| m ,d%;~})0*s3>Fo^!*khSðH3RN(L{~ԭ"@Z%к""N Z+:,b+ŋK U43ͻt#G>1A:2Hӵ /ZK|43cNMt~SDG:d#k|V@MqC\IujUm<+'!+֑ןӰSB4crH4/CeGKGѩ,3 uY"kBBue/5 :8~=//#P&kVo+z9bK\bv U0 eP6z4g`dzonҳz.` ˀ["+@_)LC'bJJZԂSؘ6[>`\#T@ƐU8kTe[ν7$91g%ɗj&&1/6]4h8OVkv0aDɑKc%~uq1/WDM?QY}!d"i=+5&Y%&2;5]om+cZL!j ҍLIn.H>擩ryό;tEC3P}c} ct4%uM %g e }HX5).t8Tӣw!If0n#fS+Yn.{0&?35CB;~It@D"$%j߳ - *-2l!: ?4ʌ‰"G0F\#u̇01=D1=Vɫ{(j<S &LC H*A|Xp!TfL6O7WII%X1x/$"E"{}?"En\+:!~_DQ2E-Oybjt _ڳo@] Ռ\,mPM*T x>jÜ-W~Gԣij W=A ~A0\[,˛iDg吶q`2vycUy;6ֺ*=;~g4Oc~UcI 0zj)ȅV**|)(\&KTͣ o¯&~zTEu=_6#bJ6 t=pOm btMvRo-g D/ẦUF桷ɍ-ǒp^M^Ϻ"m? #CʐW8HEcVT)d [n;dI1HO"Y,-=S\i&|wcN3G8qCީ!*II2'`^>֫hvDzCmOYA'IMW@?ztsZkm1u@'}fA*hPߴPj^\8p Ȍ(ΨW b /RUEdNΚHHꢒZ.bɾP҈1M4}ꐐtC. $Ŷ hb &)Z3p8Ri``nB d~l8݈$"zO F`e k&݉`DoXuGl \Ȍ$Oz*愶k:,);a L i/)'Ω^iHB"+B c 0ko(ŒY@qCj-NRPV!pPܖW uP$BW Mӄ4fC` )!d *08d *EcNio8$̠=`y  vҍ/0fw'!H)q"h]>wD88{3z0d. Q\܍ވ\Lh)M*"|M!؊6Di2e(kip^2lP`@j Fb'-"hl2L: ;pJ=QR)A0*^ 5%jң4K1N<A.m'j:MΌ+gBd$2fnnԮDU/!7&\0L%*Z,R jGdMp Dw (̣1Υ&Q`I WC01%sʂ-,H̀a6T W ҂sCh%GZpDi3JBgoh,p&bl`3'UC#O G)pI* Hr4MJX3` ~hąXLRD|8h&B:b3-@`G1F8na'p3fp Eo,cގLJBh8/[:G",лEd'!3!4/Gbh99Ebi05DIR4f?MZNU Q?䭂-R,9 A'Bt3`$5@/)'WϫJ .VJ=#u5mW8 .gEA8Q@&Q$;/R"1 RM@S?WY/tO&ae*4pWnFdc1XVJgj ΃rݔ+E, "[SG#q*/Z*F 4) H҈KN|‰Dvu݂7Oz7m!j^D J^Cs35@4|Vp.r"pNc3mZX-C*LpY(j6mF԰Uj֬O}A,ubDj̠ԤSPLd1!Bp ;NRF2-u`pDu ) [e3 qCjb3/M5Tn 3OgdS8a0ߏ+V"s,'"oLUU6C7xhnM>(YOwT dM snC0=Lг8p0&F'3S!Gb U)4&|is'4'$"v'oxN铜t)L9˺e"d\wfd[8")T|ذO𖌕UBfGZKq'@K_# @ \먓 ИcNblSA6KsՏ0}*^I2lrGwLs-@&dLlQq LЧeuYrOW wD@6/0PTc["`0@Z(/R&~=UwhdtA7zmnaˋ2P\q@W2wPcNR lZ!>T`3fx3gUQ+Iv@׈Ǔp!᳢5ʾXavxxS>6dqlHJ=DG1s.+9o.D7 (Wi@pzwpsF^L:#׹drzظvl.*FNHՍQK(pe"C1䶕73qaa@Kuд.(R, [gЋtUAZVU_Yh"1xAYN~$UY !g;vFJ4n?#m"'|37Y"oxѪ&U1v@gHJ[pg>}]$ O :hVqbq'i]&6 ŋ!MVSeo4XբV/FO9{ެwb| $KǸҊ9U9g H]15N0l9r" xB)iOX&Ҫ"44 b&bۢ` WY T6Ǝ#V_?[᠐l(|(`VpuH'fBnڤlTǦ0ƭbM֓̔w[5,ؚTCJz1BҺXW䷍4_3wZ״N9Zhg:7O/B Xs+wpЏ$u/4/9-*08}Ifu( NRh2Vcd}Kʪ{H}+ʎ2`'a\QY"'d-J( NL{JX]dCQd,p:g+M uI1bpbھq:R=!ScLtd]~abZ$ӧ[3j d uF-D3;QxY@s{UzPL^2JC~t"+~9)6JJi'{vaǤ9f&1yik 9"j{'ufpUb|_S aT "(@C9C@(YD# I dC#QI 2yOPgF0. HtFá*̢{)*u>w Fp=^7Z(0j$2S 6. "RJ[̠P\I'Q9*wlsJĩI"wou熣x m> Z(WA W`0\HEʵ{bSJ;&6vGV ~+B͜yYvLקpI^ފM,]%x:I1A[.pˠ Z,WOMP_0lMĄ`y8H(49̘@iTޛu{`eSE䚂n g1pNJaf(3z}47̋;d|FY %Z]3 s -]J b8`G.넁7r\$pOYj@i;@#GDJnthEG5PtI.0-%p_ ':c{Cfcqѓw-)EuwE1>PgGnltH Js蕳2 c@B3fפ<} :J5\ebzm&V!Kn"̇=TU]eȫS"_B}6ǫ˹nݲR5 & C9Q!ĥ=rCƒ,_%9 ;a>j*lC@čv3)C>H#Sx9)%!R挫ӄViȬLD0Lt۹DKcԕ1Pc;qlq*I!vo"Q(.ڞyXPGc,s ,LCr׊Dy\`.3= vu>&)DTX君6+"j7X*i'AK d 1pd€ j6H$q"U=$i,ryE2~آ5yeQt@- fX ōV?V1sV*B{.Z)U4aיBY#l͝/ƞ] C&F7m:-,>uDC9(L݁LL} p B)k4 Cd8^<߽]F.q9BFv$:u! UWXDwD3 u:-xD!oLÑZ6 sQY2ôA !h*jiK(NDuAhjgH6Ʊ1>U,TϋrY37@!w@8bxdow kmtnjk7/%,C/%U?A\΅V6~YLςpq+״۽C zAy-W" i#QK̗s "{BS]Q^XAgLcYѲmגT*~},SesRiKder㓩/AߖJB!$ȟ{qLX>ydQiu72=N[Ґ_i PQqުRNy+xs ֱ h= ['2 \'944,W&Mc𥎼 5a! K<ɠ2qя W0)ZID {HB6%8 BrL Դ 0& 9SB Y [̽ Ay) h*`-EK׽D69j1K)Ǐ~K,b$D7wR@B:($5cE*ŢpLd5|$Z!yD<@v>qV 6JM8΋[τxn#ɿ; sŘc%;KY0, Q4qM #)pbο*ZZ50MC˴ʺj.BHrCEQ-(őK@K  WlѲ(SY9 Zi618>A `26Br zu#ȆPQB5l6M tzBCTҵ#Lh'hL*?ӰӽT<4_{ihU=QLH48= % 5WKȁ3R+KAp:AJ$,yJ2ڔȢU ɡ=0ө1D|d ݸ8tIXĴUɠYH4ʅDU%@UV0WCLppDYYtU԰ѳ96+&L1MK[l6 rS݀-0٩iPidY2@͉ ZEB1ۂKRiAJDU>2+c,ԕRze x:0!):X-BD <\ӭC|z9!-\]>p ""30Y 5#%L!tq$,LVH.Ȓ@3&=$P4$1 $[tI*(\Y6Ymzb\pYaVj&zq]ܤVD2kN0~V鑚Bb+p:A=Pa][=AeƩ -ڪbV a a>2?섧mȬ gSA^ב^'k+ݻL42+7 bH]j^\&kE=7fSR{0:`4Հ?c3>3{U:+][͸8;g֪< ̫RP .ewXIˁS<Ͽf! q2-ZQAz+=)T3[&lUWŻX|}agg$ ЈHs\fRuDOa09&,p<bC-,#L5IɏҠ؂YJal"6L[kҽ0a !{)BX&kti!Cj3wꅣ*! R A;1CϵIHOKn0K3Wd{+8yd+ coVWKDN`鋜[4Cb4U06I0m65}Gys LSʤ\<[`t''mnW2$lM)FP2Bdn-..e!Z kr̜)6 -)=8G0nW[3GVi,ɨ9V_}k.W"=GQ6nǂGҴ ;fƣ5yL<fN Z9r v?NOlIblfiEqI@.H}v2DkKQD>x#41Lj8L&1""7V3㤴迄}͏+1A? {ֈ&0l&ihwHƉ 3lRg4?rr KG|%\qI*{L=d }W@HZ9>o: cIgjv|c?{hl_]cpD[ VA=LFWc!Qn.Au B.!)<%ͺػ4:|0)r5`@$ PW4 aV F_vHc * 8?%e38 m'x,s9L+dr9fO%(xA$ UfhA($+SSP-q h '֬KB d_Qڍ6>sG';Tj|s!$zLvKfgp͐F|j: 6R7soj|2?!_7X ʌm&xnLG+p&ʊVȪj4+~=N|Bd$1/H@:i:٫ɢ Pբ궪(*&$*ߤk`Gʈ!*r +ҟ#ʠ) zˍ k6̣º+b67TTla",rŏB蠑F:ʭZ)ZK KQQ|3ڈ ˭SGZ`-ESJ7 q3ZMR$k0AHgW)g*;3-aϬASq5z\9MLl46W@@H j%pR߸'#ʌ #(I-N/RSf( c> -$/ˌ~jO8KRkFC6Q D0=]@ڶ6H[ kڂWF|ZUZG'꿉d< }Z6?3 M|EĂvh#"A|J:ƒ4ܫ&UD}IS1 쐸fZ{rK$IUy`"_۬)1&fDR[~~e-U('# !M0m(#sE [$#o''*mg9:Pj|5â!*4x}j"Jz8#fd_xl1p4S GhovׁdO$9u]KB I<+ -D-̙xs4dzZӾ"o(ȅ+r!*j%!ZNi& Ȓt2-iȓ[kH#6wm; KIS4[0b:F6]rrRR\8h5 mc$}F@W{8RSj((iK$B+0R_0DDѥjRx5\HP*Ĉz#:U0q$01cj~TK*-YbmFTU%mlV4&rpaL!R%98iAf>Xo,Om6e (25xVaLFB$B*<cy-HnfĎ쮫"|nyH_ܥ[77~{Hs&"v㕵҃O( g D`ZrB%DӨA4ڂ_)*yg$jQly-Dyf>bQ U}WbN(VκHЇX^ dUIFSX%ߍ܃2XKΉ|N"Md&'  l{Wb22)3v3vw.3B<&s1su]ugW6PH9ɹ2Rfo8fv9?ɢ*5%VC;E3fnTϓ!FyDM2y#>iр%ES{+}[sEYODeLW 7B%7Oz-Lʾ#{e ZSI3Wa@&k6Zt“䞆q4_-=%[d[r.XLA뮰sml#]Awz fh!JhpҞ" fԘ-ۓ„rw$1#O$Kʗ(!W SS= –O V]$M"#>܌ FEQ2+"Lu,zjIF4dB>7ZK%4Bl"i~$l;"ɡ%jC],D 3-T Lf»1q'iOpf>ct['O&JI3X㩛Udk:46EN iCVZҰ0DT%c&Dn5ȁ\I9 NmaO?Ф$舊(DMk }RLfOl.=А|[s .ƕꑐxDl.gry]H"C?Ds XkR-˝<s*7/c@ReF]) Vc*Dw+HT #pE9VZN.F/e&s.֏,=Sb($lRSOZ# nLh /.8 U$7Y3)->XE< 0$qB J9cnaepxi!S"l`1,":u>L֢nm(ÅMB{U~rHwVPs*ա$D7`orLLo^2ǻz/"-JV* z*$de2~uq(׶v\6;31pŪ1g `rM1w-z6¡Ӳ75+ ?:cbabOkcQq2lMJ!cV&-VDUfdjP K%bA5͢O~J%@ O蚼F%x7! Dכ}2~4YPj*vAFV+u5O;I(]TtA! N ic?5_%,l !e+__ƞJ)npɌ7ܢ224>QIpno-(ne؛ԓ'5hydP D7Cju„eMs։u*0>ГLK `Xɢr($,9n#Y7AvD MԽÜ+dS=7 0rSs+E6j9O6oUM6 !,˧qX-y *blˆC+*(x(iPmWUÃѱ[XҀpfEJsꐊ&`F>hu(w}3"Z]uj纖a溑xX6Lt=sX7ſ3IЏ}P8O V4 L&2$ƊTelTÖͅLuݑ;b0ˇhn 9=jؙKtRV[\rQrup4 ..21O?x3L}R^DA̗9Z)lUw+-Vj i$ʛ?+?w4Fsayd׼%4ΚISZhsN=wg]ϩlV]o>H8oUhc ?|N;4#DA}:t5 =&Uur6rձ0ܲ+^V+$ڗI$|b7+26Zj4sK?t4ky 7^xvƏ-{ehEDhÍ*qˆ NU= =zu靳)E-TK OBU'3SR3-3&  aT"{@N 1xd6~Dq#"FOF;M`4=A0i* Ҩ,$I$FPDfHY1W՚d a"Fb(TQXThc&Ez+i=(#8V rܫVNcP}`QFnc+kuh&J"32\B/of[.J}25=|g0lMJ8| J$՞,} 1tkP\ݛ 6JFUXg*`D2Wb"E@mtFrL$s$R|̡I24? 4'ꊣ=D+O A[8ʃ0Pr\PGFq 9G` PPĆjB٦ZOiEY )#1aw>jt+)UHܫOt:5`V4TJn`+}֑2}l(!f~f?tL%퍯!)Gg4g3g|]:] DxxEpϡ03INHd"ZCSkT*jE.ɇT`%˒ T+K 7VZC׀ɾb%na lo?hS=މαTb`|zE9 ~G;IEGlJCj YZj҆)(AIgءs Rf MuR-OskY7`4L2$Q=$]GʡlRˋ&lu*ƌBo D4RzO/i6`$ dĨB{kj $`?ylHT HBnYL/"E*`҇kq;vbY`6@NTʈ+!!gydY~'LMf}Ԁ ٟBP ^QVq],`)1G+O.blP-tէ4\Q r5=ϜO&nI,LRK[K1i-jY*5 zY97 g.8p[ $bYl)ƐH"EO'x? ;X>stI6jn9;2fתnI=cIDikF&@<ApהLuZ`B6k`SNwQ#> 1Xe)RUznKs<Ѵ'\,x5V B*|\}!0ʕ Ds#6c(Oé0vˡ"tYr@)*XI%l=\bNb=Me&$t;'!W0UBċr;,?gg]O{V$^`8pp kq*dtUr4H{92W6Msq<)HFNl|Mg9zޒkB bbT=FoGg=+kYk.3<|KF5ZF铿z{.=(ŀ@? sr 8r&#!k@N! a -!9j[$n q"iR+•@w< Κ#J%!A_ ȱB@;"QG,lI3Bro7 I/bUxG2H͞+jѼqJxIIŸ "Ʋk0EMAJs٥ES s?U+;j3$:A!:NCL{) Cu-`浣''~zl%B7:ds2&DET@GQl'ݐ/>+ s蝽C:-+F:?RJdUwʈ|%J *򭻕( e+2ߦRJӊw"%$"eRZ2LX+IƓE|$Ȥ<9_@J3[֪Ȭt -WtKn|,buH\TKCRtEV+ܸ&ֹ"";V+YG5fQ=iݞ**5('Js(*2Dzo%I[9)N@u9Z-e/K+@aD51*K0rHsfTk kAI!@xD 7U؏*B%S0ܣ2H,vA=[-EIĥϪ|LpdLK;Au눀#x[P}"?9A0UY3,Z !t3{ +I9ytPQ5=UUt6u]U[/M:uEJ_dҪfA38|# P̬1EHDr ^ aC܍ ]!IJ?d8`=A@5A<<մbZ7XYd`5wɓDjBP"A,L(ˢX-!5KR͏ȤK$fT +yJ!H#~)B@2oW1 jy,rt]<@8%4CU@VL?)TTDB62qcR ;%F,GX&S(F +ML? &\_Z*4ZkK틑3"5]P{т:.ߝэ`EF]8=5=#GPYaP %X+ᵀ*ja1bXULCs!-WAGH8MKi2;f; <6 ۜT$|9J '6VG3RZ]S\ЄN>Vjب #ՃpaՄE6kD)2k2j!2|g2s*dK137(u4Ӕ`u2sicۢ=۠xa./ϝboʲ2*ݜAM3{Ƃ\mn\Rÿ[4䒋miSQaL0vc'MMRP&SQXԅaC:<$%61͒y61k:ZiRWC9CP6ϙuc`>E*Ns[&RƘn6BGiYޅ GܙjcYu1,SvsϹj  5fh{Z'X[j\z*dZdPdГOcYRIBwϞ Fuve,^Txɟ4JtyȆT |[#c3d ˭)RdNɭL[!H$$%pfТ+ޛ^lQ6q& &!Eη+e Ҋ1)cFB9BP&ASMf`N`CJ hL9ʊƓHrjhlީ>t[@( {lsc ^ T+j;e*&ͱܛ2ר5l95pЯ*c)[<-!6|AR*ع$.c ^ RQq&: &梔Urc! Eq`tiʽ<7Œy^wIy xRH?S$1//z&k}{A1bϝD][ȍB*&Ҏa aϮgbaЫ}{Tw2nnT'/Fw!R^Xjl'(RS2]69˜\%J)e#k+eI [I?(D& @D ax[5a0"`'qx|2e-IxDNCS~Cy<.FJepI.NB^yV_U:2Jhp$4K5"D4 qW$t_}]''ca7G͞!~JnIқ )%Tl+)jʢ|vy ƀi0mVfv:@(e-Zͺ~׀}G itR&~-MaNGNXGr-# 벊m"tbOA 좲(A<٦JK 7?J#衵{jkrθAH)ԡG봊?2sp0 ;)ф3#-(ȘBch8:+.pjQ9K$@+n ) 4rˍ<ҊHJ(J0MLK&ɫ4B)GE$ 52?T/R&Fnqӷ">m*iEMI*Χlk) Q'򲬤s&\G$#(v;hMԈobHV$wˈNO%鋶0 2(PwɱzfC!E-R#y:+lCֽOok)(>0AŖ4-ӝhe %-Y Z4gM&3&~'Or Qk_o*9>zIh/3Uk<}GU2C`^D$pHZ.ư{pl'ӈ\Nv?G;oA)Kr9n6H#N4;~@#OME%$JX&IcC 4C8@bG{"%nB!"˲8ewzLȱ Ar]%F]ΒY*1!6ڽ5^qcC>dN$|?ZIG.ʹbdl dP'C7#L+tT(z2X.ja)u}p]N%Y-ΪY}O1Ь\C#޵e\6s~c1@#teQW=ؔ&DX<| L4$2t>0c#81VdN9+~E?qz&WPqbOT&I F(߆D~5fPHLV1ilȉ$  OL- P$veobjI}iB).GL"itFh`HJ2(J titHf޹DBx2".2Iѐ4d) Bid.S:JT&2ꂄхNoP*qfZ:-4ncWC!ޒϒqoB()%F~iNITzɦ'@Ҥ*0킎e.jt n&N V6bJf"g. õ{/0/:f eaK `T߄M/3`Q2У1:rvJK'5;m t$;IT̋`zg)p ;6wIzC` \f@)Dzǭ) .Yn2jL`k=HzFsP3:b"iZ/ k1.?LNR0lzVy.ť`&Gw[-9ByHNhy.dhIz''I,tXd ̎RC:!)4;( >+ '; "&t6-D?F|RH! >|zkءs)3KS2ތ0EpbFd :iBi_2R$.Z H@u f6GFe=)gV5<R+'=)!6aN{2`"UjNT 7dUFjlr+vzs5SjN&d:jsfHigNI-p(H%lK Ղx{p¿6qol`)kԴ2FCH:v!qr }2 k3`C'C OxB/a$$-;h/?պbD~x2Ȉ>HGXz$9|#g=j>)DaoNy=G aIL:L2ܤ\+!*3)}b% ĩFS"jn zwmFQvÍ 3ܔ%]DFj]>۸xz|7'8s`h02!(t0C ^$_~:?3E$0@,&I"|epd/&9\ Q)TO J P%9$a@؟utf!`PɄf]]YTb%Sjq+D'Q*}lߡG;n[-v+l!HNFsKf /tOu7S5C#ӱ8ia UW@g3sa!wy_j1O!/2(kb`kB*j" "퓆3@:lID}E $;*/bu:*-*މF(ʇBJcbƑ+j@Ơ"p( &>ihS:= |=0ۺ)<) K={ NqM)DMG!z~b{خG' 2 ͒z>tCnQ+/M%,t/B`S!Oe<#|WvhxGkoKq+JՃBn*{U"@ړ"3c@0\׀ w*{o"M:LXI9Oie= PRW)r:L5{t}S@&@BwA47E;tAS`Fu5F?tUmŢ}ѓwIC!w)-7]՜ԞK RRBhD1L ̡O[,Ǹܾ(JUOբY؇4|++`^kfsĐ{lDQc Kw0HYto/T:٩dC@$fOs|&2!>PC^ Js&wۑlX㑘F^.u&dK Jn 3m \Jboצ4DM8Y].fQBh(esR6>1>{kGɎ ۤNzLB٠vq,&>5mU#,chOdmG^v]RàU 7.R>NtO*M!6d)I ݛ$㖣 ZE1H&i3Cs-4m0Qf/NcaM!r+Iۋ$ʕsAѲl [=i/V PkA?H36ۃD00@ٸȱ"ӯ7dP xD(ZCKsLE- ?[f#Ku8nXOs~ūL.M7 TI,@ [Hm *|i*gdsٚ"8v˟ڂ23 pYR k Xq]Ũ&l2g7 S:4kK%ǴzJ~eHs5Qy+{PWPDέeҴ8V/vf/JˢQNo E$w;-LW409'zGlڬV":  ȕj/k-#hCsSnv W¨$p'#gVwQCK/al^Qy0˖~i4,oV*@ڮ3۷ܤUSGJe剶c t6̔SCCIMc"*˳6szh`rnѱ 3O4GxuV'jضu9>VY7kia-fݶ:OZHܳ,G%,y=٣^*>#* K^ii|l6(?/:]_<3:{ ^Ļ$؟F>^'u䊼@$A V <)FM$ b҇9eϗsPlw)M+j<7C#sӱXblمe q I\.=W|ӤSf57ј*l /r$z{Jq(K5NV qՙqVk}  6;$Ѽb>) s]9 kX%}a["? Qi5P }8Z7'#ض[%=#8\0®1Żs<>8۶I:3$!C9C% 27ӠZ31 53+Q*JZ 821TItSy"a~G.SU?{ A; (7[:)X'ax1s/ 5"J3");À-2ǧQsK"8!?.*w/xdc h}J &SF2A0fzC#xZ?HӼGP{T 4#3H1 LFsͼk! H8P[y/Z<0Ǯx-T) 0Ѷ(TI,_%) o:"*禘Fi ٪ӿcy>ܕ5a`,L :oBvIȹ8 e6BBˏL,!,:ޜ~&[Z"KK$1%@Q2*X.K=D@Dr*K\8xK|.!3܇ѝ# *=7, s,J<CaH"e>ټ53 "* Gc5 +H/*#bϪ4̓ {qC,a{aL*v7DTÇOA߮2gIl.?73V;M)LDq69G>kU͔F;IJzrK p/z€.s+9z9ʻUX?A?3-/ 8µ4 +s!Ph@R+$\$aoX/ۭȏR qIiūݔ'{{=R<*ZH&SI:zHdA:>#)Uƅc)̠|i N˱RʙP |դ¸!i3h EA $"*r%UȈJІRӞ,gP. 3w)bI/m4K]R(;@*#5AITրC z~(YVUC:+Ƕ.5n,?1#39WǙ ;L03эDQ* JS8mDک]31.dy);H}vIDP=x}!|K\ոax!? [JY@(Fj!S1|$= U3s# {z``͹pS *Rۺ*$]g'x[\erQ9+)+B*i+y_?}FM"U)eـI(ؔD 3lǽ#Ҹ)Ѕ\sU]Yɋ[%2G@-E"zE`=i܏`-#kⴕDXk<$- /cUQΩmK^R)d=RNb)YJyC:1{&rAtФ;!ɪ-C4݌P+U5sF$({h>IYDBA`-^% ҄ZLqo] >.0ќ.FlKI[La3UJl>0#WreESeKI%43O{E%3s H_t=%L8^ Sצ5}ѝFz pϫ^C+P eɣDa[]z45) !W$Hf>X-RgA %[^al.?B$Y̡ *V} >fJ$O#u -e$$3n-%dc@ڋ206A`]Ƞ.#aLh,=')X-wrޝ%b9\u`leisϙ$F̂G۲?haxEQ!ܛ~D`(|3&)62j"b @d+8;#"{c|VԐ|f5(γpe>?>Pm&Cfi1,sE!^VNiɰ)i ^gF ;W]IJޤ̃!2Y9ҚvK?2HyoAzO%<? [`b4%2P3yYEI).gXF S!p,*PTIk3)zy.ÀRX,$$(Q!^K>Lx]e^1(bY~k<VF|!7QZ= OPX9f<6,yeH5I)),y,4^"⨇"S@iɱ^.ALlEq^@cmi1jF^6)O^ BD(0+[Vc%M˗ U*&39ʐJ}VfJK#SMl\'eCT 6VPM^Rl= g.-~t~h0V;BMK ~ޢpYf=>c('_2MzLf\6M#K3ƲZ[ ot{Za<,3cF /Ȫ-o%k,a:Qqvb"Ie־_db}pr"O˾*. ^gݱI=Gij093%bj BΣ>xeS ]{qMISrn] 'F6[&ms6=FݰG@e<5IH 2$mYB4xwi Ljg̹–+0J}XtiNE/Nd@ZB &Sⶱʴsh0:Ck"lY |l&ح^fZFKPcvB@&#d^+Egwn@v>i\B'iȻfkj0*MX@$WJzwOZ*Dl #* N[>?Px-j %KDg-̜ |V"! K+06/5Ǝ`fǔp*X\ZJԻ N dT*%$,p1JZHT㰉 fT洛1~d0  njM풫y>pD d1[n} cLgyhdR"Hq6oE*f̞*p9wk)PZQũHB*(c*"+1x#P&pA'%CNukFCKk(^?N2+6b% HNFd)&ZIMԾ"A FLYvEL0M PͰ2n.N'"ds pJ -z~KrZ!OCQ -%)l\ FRҬvDPg&D,8 Ց4RhqlC#0檌NeJU( vDR U%|d7.L&&iO,!xPQAgF&/҆E1i"܂ "CP3Z 6İcoF "h_4i$sޭ  Άĕ8Ͼk1r*,llx.,3tpC :BK r4%0@S'0HR #C~)Cb%wK!BB 8lj@'6#FΨ UF|L+f>4z% ć$~ g^OoH#?_FPOok@SKs)%u9ښbF-0~.q ՃX 7W0u RR>UpBK JZ:;5EhS.0%!Y-_E//2O;.F'%TT ZPnKMM)0:1)ݯaӳ"hcuf)ⓣ3ĴqViIPt}L S)I*J\#AV_,YUi87UՌnPƲіJr*>Te[S%Lu(b7rk.YUBdEs cNԐǗID7O59c 'epe$tEeAܑޥ{T-^I5 G&[/\h@C E#0q,:LȇEԧQwBFgMuAq%qIrv#!PګOqPtF 5(In?<$ʳ LYEIJM Ȑn1<2r^ڪZHQ6Z"6h&RJ5t> (HP.F1Ο.W1ί^%ůN>4,?vh"ISJ,PDv Q*)l4Fga3duw pW#&)IJTdH"G*KXk? vb#1r$t95+2?Ueϊ#+[U?$>2,% MS-Qk 8el _Hʛ ,X_'$\Xxf f,퍫 m_ ,ܣ4$''Qw  3VϺvD\ŘV"AHbUvWJ8KUA{+kDHg &G9Kk,{"ҍIBxCQbNB@vk.dwI)uB(噃c䌗d4E˘A>u.jRQ;" iCՁod_0dV=)BϽifq\r`귙tg!}wkOol_m!>u r4䎠/E:lE{vPmUʐ3P$ЍHGjgeb+$z,s658M!<WL<9eZ:g*]h՝Gwbc4zK6]h9 lj*jf:="C01ȋf|d}'zt уahg" g*cΜo: } v}hWy7qmqD@5QATgRڛ@'qy6.U6v[qhF'Ji+# .i! Q~;gvWR;(ióV&>r?ة-UkRXL+cA [c>"j8zCK]pٕNτ_Q%liwi%Vb;˽ssן ]V*:,bnxgesPU7i] h0:8on@:4Y5DF]x?%1^#y됋`(_2U?<שfT- ݮY >XF7=y%m /0y#e|&Yv:U tP=1M[ݤ/n4`g:v-dA;[yL]Y Pq Xuo7֏h$n(R.;rP+E(Us 1"gIENFR-dUv];gKޡapnzyFߖ1{6|~EQ^3< x\"1烀OſA Tg?& h 8SB`!@,UǢQĎ?!IT9'diEa0 A_4 ,AP"|G(t>}5 Me9PY\G*V47OC%y:5*3}h8Ip0I< a[j%oWBW͢}'e-m㘧!c TmSj[d76"7/HY ҈na;}8FۥٹT+!2t'B%(o6K$PC@۟;)P:׿@J"J.h*X|o /R$lMoDL;NXGH;=̣%8E@B̏-.)"S)=R*9|n7:L1lϊI:LNTpéݫS/!${•1Ǻ f:s; J|ĕ4M2襁3tBK0$̴,U.30~T`*K%/!*ʼJSS&ZϴbDlԋ+ ׀85==)1G4LEaOdMqDjBTUe awNNԙ7oL[Ѱd#H"JN#V25hGXN;h kx:\qQ/^v~Jj&%q*\b$iFx vhGͶ젗^#[!rOk]W/ʺŧ-Ib@V܀%N~v)]%.E"y 21g[*X U\0 |P$8'^/y5 D;1ҏc؜tL  du 3FP!GˡdŕJPRb{ (D-FgS"8H-(d WS)0-'p(5+gM%5AIQGev,CQ!f$EÓ*γC#ʉ@?t*T_ӈ0"9i)K"ҿvr6I:٘qB"X}I>2*Lh%g -6PyaȖz8h%LA thM<4P NTfkQ3a֓2Ä/b2J%f[enVL0 a~ΑDlՍˈґDP+1L\I0A8(MSҳF󛕯2S;3lΚ! V1>CS^ԕ{X#2=w]-C,6YKxDAޕnڪ0[U@ ijtG;^t!Hy]FTcDhXVBG N%Y%ɵIxț9x)Z s9 ), ƗՉFz_Wz4Ip "r>çy&~ jO-;HE5?ls]J5rI@3tЅ< A.Aq:V:A|W,<Ξ0̾.b 19p{]'#VvkD9 `2a/*Y>9&5HbqбvF5Et-̡)֔e{ysKkJdwrC G cC㷝;Z③ɅJ /GZOs=u9ΧNo}CX{>Z"1+]H_crNIYJKo/2:C<#m[,6ka-e ^:#W ?"36##!̬\SĴ;/*(7:Cgr[~ C ,L =|S?<D{6Z'hѦp[<t2G<)`9ÿS *+{J-- 4B!$@*C %7N@3kGʾ 3!:ِX|2=bS$}i>p> :P|!`|f R%~XJ{( jq4>8|` x \!91F5XyFYKԗ8i x3&4&tZas& >1BˤCtE6 ~9[dCd[B#Θ}`NʪD GzMa9{ĥ0FE#Z)k*; sZ1[$77LȬl 4)e!8;}(BKİ&(۳ ߭;mtZA61٩C@ҍ3qCI]X;AV ;Cb" ) %-ZN:29"""'A >9tE%2G6thA (tZr/]#<7&:|tAs K;t|$O-C E],1#MJBHo =<% H}pD bK )9|T "JaNN9E,VH6KB73*WC/ēESZHsD$^?c](iokYL52j"4 3sd%lQmz BZ*|dՓ67N#,45j;Scߖ=2Տss(0M$Ia8R W|β2XԘ}JۜI1#2%X̋NDU{4B[NdnA;E-X'qP/ʳ:"sC tSãȸFϵAz43JaBM;Q?R51<5γ^;ϼ[4ё@8y4l ]-a+ﺄĔ-Oɬ_6'>Ԯ$W:4ёUR3RRz'҄)st&: {L4-$/<8ʚN Y!}$7c',jH!@K¹`s2Eٹ,{+ZRcCU7mE=H}sH[?Zf=D,rޤHK=ZڦS 203d|͓tT^] 2U*SFϡ=D! !H#9~a$:N# }3֣Bi]"5E9[b3@tR,;[[֒f2\Lzc5=Ѧ(3;𑛱[u5e39Pci6Pedk*Il("\E(ٜYSUA7mZ A*&y EMoUK芷d[Q 4F8Q. d*OϪ$&~_N_3ޒ`I ,)jl>LRbvE2G}-D ljR:\ MbZS 'F~MNnC`/}Zk9!Q5y,R#9aJ&&AMu)ڝ ևb -)k  <7 zO~k)~岾ESK,.~eMc܂iL^L3&=¨DđKm$gVq(Iɝt%24ߍFSz^&3Jmylۥ"3v~+۟qlreӳ@H7[ha{d8ȟH7a?9n7?/4Gb;8ƌr4[#oLH.bS= d9.>NgU?msZ U$k^UFE 4~2՘r3g%u(x[/A`O)B'AP\{ẼͯE  eԤA+`EK7γ%Uѥ.ėhJbUϷ6]+a(_K"ufz8Y)A$!j)B{y$m \>ƾ#"'+-VqI^嵍H}: "r]|TU!M|l)X;_j%kǿH\a[5. e1W݀|0#wrzLS8S]*y/.æS6j}mluehp`td0m.EdZ od+G1GptVaFshUѳ{cZLxA`g&B(%?"8 =cqїܦ `r(4Y"JgqN$Qd)C@)R3)d7SYd&U8HYl;@ X`ӈP)}!fRb)2K.l8"P5paS*!R@2T`W E8?v\Z`0f[mq\Nژ \D-tgg4S`JeO"psYn:֪ߏܿ"B@ٶ򦳴 z=b$K@p hX7h0hI)>l:Rcj렯<" T(K!2ʹ릜@+K2 :0s ˧΂ŰrȢ E )ͫ3ݣ)J(,̲5EBR%Xh)Lюrr dحriTʱ(JP ά$bđ2#+U"D#̾T W)= C{ nFY@(o䕦M/gNGJ 6zݶ&x0ʍJj-a|@,&VlG@xV' dQ豔zH5܄?y XF.-Ӈho=ٚxޅ1b-Z6桰{j%`iwer6By;}u:ckՙ'ȏ|I)ـ}LW &/ ϩ#m7mX"D)B3D$RIf"@*17s@2$H7p`5 ybiH3RJ@~p2xlZP0=FBٞ\ 2 AM QGD6:"s@g~.zA;'bZ[/(doIQ$*_8(4FVvG*!Gd^;kΚi:!|-KGG*qr6x):Cv.zO$E$," nDDz!L|"*_:)voT+\3]GH8Vu2(eFil%.ެ34T18>R~踁H#1ed@Eȹ!xs.9P@$[W!aȕ7|V%RirB9)(B tn*_͡u[Kk>aX Jb3_[@+aT927s- k/k>Azv2c&XFU!B5 h*st Qݼ79_e|رjHY/BQuk*Luj׳wȔN}֣'GT˜gv,<2?*U!̚xXɺFYI"}nf^ki5t I͔|c 4t$͈ua1>!=PWImT m"ǹL}zHy_]v{y y?p<HyN\ZxreVi~M|ro{8LDopKvrTg\˼ $ɖj!MH^kn"Rm` 㦡.4K? ;˞.~D!Ih 3Bp)6zdRڜ鮉Dԥn'2 N0D# 'dBbkfNvUpj ИB ̈́s ֐Х"Ѕ@ &(xCVkp{GHE%0ض 61 Yʠ6.݆bkogh m:-$!/g@ HObԈDPAdl F_ HFMfw@ (b vɠ )P%%ުξ+M{2[krH&(Mq:T *XW,oͣ<(<쯛F'rI[DgW{ %L(d:4PQVNk0 ʐgǟSDgLnœ{Wȹ Dz8R1l*zk 賑"Dhd.cW4U'!@Ύ{F%2Fo>+G!?l #0-dCdC$^vr2$,>` YNC . (}:lʷ3,,T R%rbh]/=tN3L'" tK%>sg :wg?Tn`҈ăf/ ^i$aR|FW+HR""~Nq,Eb̾ ?NuJ|Q6* ꣩N'*7kie0iT~ڂn)- 2\Y0!w3zDz`M65u( #tRx&,lBlu;Ja1'YlX*TJ.Oq^2(mb֋wVD.U)ԤH*l/j$$"öc'n.A)X0wrl(msSHq2Sxb) d]HD~}((t=2B -;fGDZFcjGN]r0!]V8͊ȭek{#h:}UǴg3ٱuz&P!ӾqFKtr[u % vfSG?άFI?pG 'N- ~na[~l#iD>Oyr&FmN=LipMKM;>`WbV$y0v.Β_7U1i&~xy%7EdKv](_P9Orf>!D*٤2&KBP B!p! DoCaшh@"IGQD1ϨDRLDJ0I! LE7I(OIQѠtXRMIxd2£ b%Ns$UXI&YĢZWtJA8ۃ-1R!fF~ `rj i5A E ZXt#7tR63p)` IOPx?w-g ]H+pcU?R5|6| i2$${Nf? NӹmkBH6s ~s+*5ʮD(t )  6l;jZښ@1hc*" ^<|8¸hH$xDZ'J8ģD@6ћ&ȀOs$0 *:sZ(PBK*< ܂<2(hP #(<҅C4T|BBSoͫxF TDULEmVOKBɧhS6<4 Z N:HWOg5xE wLFu"$Kb0=(@- {L >]Xު.>OqKuWKr[QS3[R 3Ot6RQ٪^-?"yڄtck`zQ8[m䕣K(j\Ђsc{jABo5kJi̓\j,RH>6=iMɇlmX3gNͤҜWTeZyLm=}s3cD+Ob7v{ wU"IjbcÌIcr޸^" pϱWT`޹Fՙ*s.;>?I8fzsf]o8bbw9 G{ 5$"F.)0\Fz"9ᷬeK>d9$r,ft$q#z qjG\m/i6?S`d7" !,F2 22aoz?s"[\̎" +!=sbSy:IpɌâgƱo7']%"nىj6ֱ֪y]x0 *3r &.DȱdL7yWLO3We cJܖc4(=dMYSh`;]nv/0]}$eH"LЦ0ZD> ""Ldd%nbS*[|3 ?݋HBL12VuakOLmGŽ_xEؤ9̖G( )T~Ht: Jpʙ4vj5&U z1q%S !P*d]եdzDHUJQt^|>mdK`d-,ѴVcC N/N%gR !|>\.ָ5+Uf)֕YljEddDMF23&k>„H;4.dbMEȝЌhvXVq:d=Т%v [HfAe*]Py?{WLGƓjY.$c[ dKSWJ"t]~Y}tWJ3.i݃j[!U+μ>؞oP4[)TYg[6=/!-\ [@['ҚMLGfTfdZȏ<LUgʯ"`_Xʋ5ˤkpIHkH[!ӏS ~)r->u_e1\U.F_DXN1N*< &/U۩<<튤՜i?8oKLT~J}9@70YtaGtoF |)5)޴^c/b2\s[O<.*Kj>_G}6rI p7D%-_ZWmMՊe߹D3`H 8%匬:5:q%zK[~:ITyEY3"5 or$ +e(Ix9dEÈm>>3ODꄤEBhLm֔*n1:T1ɲ;׮)h,# P~> ž1Ea1>R$+ ޕRNyC$-Z;H267?7szs0i6l zݹ2$1R4<ڋ& C6KJ 4!\%_ .(0<#/, *Av3Ĕ~+ 73!,=˟*BI![ Ɗkf@CN`)l0KBiB!UC2Kxȶ8Q2ޒr3?!" 2x]#ӕB[ H(ȃC80" (4A&98gG{Y὘c kK3ԩň@8@w<~x ض9K919A{A5ĸHcQr!*Jkַ1<T>1r˻#[F3͇Ƭ:Kw& (I1 92hӰ=("+$bL 8g7Z1*yJ; .Kz_1 9k!4'Cى#lJ ; 6wĬ!C43t$6+cG(U j].‘Ǹ~ 2r*!qk($BA.C bҵYCL -~LXB|˜svRb1!黑"O J50SsӸL1X-īZVbMHb֨3TpT B+0ڄ;ɹ>] 9.k)Ja}㰎z1U$H}'3y:l94:CQa&ѲD9"a֌5ޕa8۰ZaÛ7 yl:T}qe1 ֣,\ϼH4@ZQDt:3%8͘l8+ռJ?Ut֧5T^a  p~Rrps/$):=!4pCa;-ght1s:רH!̢oH +}Q)**%/\k,h!+][FU-7K3\ -WfT*w]*^ٖ%&&RAҠ4J8˸c<+A>kZ*ݚSX~E Ruխ":ǵ5̌8\]XЍ=&*_YOcd]E#59fLrCkm/02"F?BөFnl82 f=Ξ*iήN<&"qg՞`p}hZaҳ =ֱ7N* b̏,\h\0S&K߹]-6tΓEL [욬6ckk }}AەO'Gά4慶ȊY"ajK95v \$OzfL xP5~+yޗ7Nk)'||PXD(dG?4x=Pv4_Rq>}&֢61Tr30'νÍyJ%a)TSb фP4Ԑ* Rg˘wD虘H~Ɛ|.y5bfQe5)ägvȲnJ$HV/Oc8ޥG[>XBIIJ<8CWeVAċG5p?B^(#]syn!T#1"ĮV?vPOo"49{V=Ll!oA(Pi iCFѶ`'Ev">shx5V B8>4e,i)ֈF_A !lXК_zryk,[qھaFEBJm4~,VtX-k8AOk'nW=Cv.:jm> =NR ?*!3gİ2(̵ˋ[.MWqϛc;;'u#͝Y2pڞވ1i|ݒ7H!nolAnm)ڇT?@$` .bP'8CvAvLDbd20K2@,#H8}?I7Kg6̠i M? P452 &{ }(&_M}>oT?2i[ I]`,-pQ  EPL d\?Հ$2r";ER%ǃlpHEgdPzz|=3׽OOSae~! IlQW..ž="'oB:. Æ; zL!Ď LC#J~;훎4HŨ:%PáF/;$e>i{'dG'ȍLƠh9@ "-J5 G7HJg^*'ȣB$/'l"_=H+ L[##):hrԮ @.# $Ҍ)dAT$䣪2Mh<('HItVCg~S;`MN)}1D# 3.@FgjZ^V$8 C2&Eq>HW '(fssX+ڷi ^:R$W/3}lӣ)>"ڎ}&5k0NGW %)ݸpZ H>B@})ƃKMLFX܍Tdp+l"9(|R"W `U7LDVbQk\MKF*Yz'0و *<7&x$I@DcKP |;3!b$g ?] N%$VgsN24WRR/F$30ROvl$TAk~$DTbO){GTR\?D:ή}t=G@ A &Dh\422"zK$&G[ISZR!zwԙ 1[;SA1T- cc !~H +-$ LP8A=&®nDP=dof01#i g:~z%$E UܦC;!l)W2@iLK&%\tȩ<g2JdQӀnP(;iB2Q:|a,}fgL:>q0Z,Yz66ðK#R=vV2qѽ'`hk띧ߔR`?Wg8">ۣ78/;ilpA\CD[!|W'&{}3+@ ߤE\sO[4D=UW"|_nhvD`n~&a:+,?pɫ~`Mj|-nˈ)@D+ @KhjgLtK0i!4#d fozX L0=afLLO :02툈 @"7"~ɪn@I&#JfoNl lʒ:̫(A/rGm(p\ev"мͪgM.f#RPyƀ#O>b|LHFi 8bHljsBJI:b7̧t"h" pi(ƂP|P7/& /r,LJvQ(tɜ~p̚zDuN##a,qqN{M&xpbzx". Z{`U /Gz8X"L:Z*I11xHPʇhj`@jdoP _Nj2-IfB)R{/m "17,5 ԥ) #pXz]q}T12*`I*vRiDkBh/Im!txMpP 0)dBeQi'mNb_dok$M+$ _+›CA|fd\Ag*nϱ D(m#1vr$\9ޅOr ܰcbZ:- ,)vˊ`pf2M+Щ"\b4,BZ<-I9Fxh" ,ԕͩLA&I⒦j'ðxܓkV"Ƈ/ΣD*t`'G> .ftL('f>,/L ͼ0B.<m^hH&I,HKDL tͮ"I/jJŃ4; q(h~hn\b#In(J V7i+D"!8 0ky 9O('DGk3jڀ#sW3h 4kne/C9 Bj0:/_I ._L3l¶|nK !´qlElO(q.µ Z#𠭼Y*A4(p*3fPccCh"+"t,a үHan{2'PG )//-:.7i1$d21@̔%fTL_B(i3eq"U~uR#3Y4TiN-H-OOд'TN*sO k'%̼` KTvr|3HQ t{8KpxƔuM@̽:JUh)l/<30}6 w Pa ^N4jfv/8vvd5*lN VuCR]."FEhC]k#k4u{v`̚$$ɾB>KԥV &@bM~7s"EhtS[st)VpԺ4e֍.Hovlz\m[h썗8Og7sOM4"^125-{gקc0g-܍kRjRbK&F7[v%TRDU;iiCA R:6Е3I-U{>up73GNJ-*¡pzKXR #.N-`/Ƽ&{A*lFsQbC'jRNR/l]M,VKd.|T5* ,Œ${yt6-JQ4rC'8mPwj(k90ft\I) U''qO˝-nx̼A/r}L`o4Z(#iY1ށ m3+ (?RW\0SDwm:0Ȃʆ93u('R?HϕJ^52'DflŢ5̶ׇ7NTL{m/˓/V/N_c`jzLVwN|tPno@ꉍzgp@+̇\N~RpWh!#vW: htXt8"0~'|Fhe46K5$ñ刍.|[R|az[!DZ7s|vyQ'u2öbAy2RviH~Dgw7`̙Zѻ1VIepYi֭"]vD4hП/(j0:'F&dKKkwߣp79B.CTYYNjT+<79[9 ''kF#nBa:سgj9J^!ɩ2 E5f$45nq)V9TN5w'ہ]Q;S.LWTGh͖N3^ mK{1I k'wQRu\*`pQ䗶A"Ԓ(Z2捇`(Nl["PM'DT30 ](OH/7Ph `8WVgqȖq&grsO|IٚKjЖtYN۾9CΡy/4ذй"0CȦ\CNbMLxrvX Ē`z"ubw\u}|JkUU3ӹ|R#q ;Ke"!>=:7bwGwd60-0uvh.X¯#i->]bCUrӕ8$!BO%(Ru5*֑Y :)J OPV3 vF&Ccg6:X Jj!Cr U9F2D$9i:è :Z֚7.,T:pm/(v~T|<+2*5"Ku;r6SCI2‚HrŪAEV+n!{?&L&AdS55ޮ I/"_/j3C@S2u4 H:T)Kg&x+jL*m0bq[Jr4>N o[FZ~6 p 7cVp4ېi پw nEv3ʥh,"w\z}1XRIe@ I.%Ld1p<+` 2TeDL=z+ w.{MCd(wL *rB"$| HK4`[9JIcHPrhiّ<,l*Dߛ3b+*BV73NFaʃg,ye䪗[zreB34V9 :UKMe1^?I8P 2wri$;B Tk2wՒ?`v29 kRibi*H-q˛D^-.Ln1 0cUHS ?h(\z&:NC*hHYRYu0OH{RxĈBfUxٕr0^`xM +LXj 1`yR-k#V N}՝pc/y7*@s޻AIQ߳'+b+eKV]Ԫ"5˫-ܼ_B 5Mo ƪ[N%hXAI'bo$.Lsz+r"殃AU= .M@%6SVMKMRT\EklU4ٔ8 ʆ˩񏑑+5|ytkV#Y"778 xSXr "lXvUn0d0 r{ĭi2;i^8m4e.io%M ʼi|j;\KU1A?V?e\Su}$%'ްF-/\9lMɲ4޶ױF-ya@ CPj4OB Wr].#\@(y5#ҥ٩KM1^GdpX35C&fi_auZs{=(㉵Bc-- "Z6tNgݎ$g'?ܡ >=I{$^H:43T6u\NŲI4AR4:UmPnŽfex :ނs;a*cKׇ,Нa^W8f$$)Y9.KwaqP[JﭒgתꂨCo1k^^Ƀ{u&8{Yi#Aҟ3&B*;#Ὰ #&3II8}y:@ =;ټx1H "3t.j ꦞȧU:0"|8>HKՀ#).+S4|(hJ SW YqC SA )+ ,80d$ ҈[c8@8-,꥘z9ыī {I3!0kA׋ݟ2ƫA B̹}!\%#;4d@<ئ75잱[;s}?KF%BO +4o8OdZ\ 8E 8>|CB@QEQp~Ҕa8+Le̒߹Y"كG}kK LM4E` yJiμ7 !KX[bu87s A& eUH$qL ːQqP }3lƀ##+c9aHrFc(ǻ;&qЅ[1QH}G84B=ݢr;) E$ 5S"J&ܢSV[-ME|+8ٕh*J$1Җ!r3IkZ軰gHZjU>KEn-hbbshFs>E\NG3OѭfȺZx ӍDaV>}dWL&/kzpSxj1";]-hc|1S2Ґ(H\-HO5X^ˬ̡![A^@/[_\6hEIn‹MkjITq;&"U o ͬ+}yiimփBqfiؔ_=Ap;䩷([ OL"kj͟6ApvAј`#LMe,nB =WX~|k_k ˞:Ӆ,҅4Y/k7ڶ({,d@U]:+*?N]^9MCHtjj/„ 1>9RVu!5O.D8nSV"/9ZLMT%P ښ/05%45Htv8҈JCsez;?,䍛3Mz\8]B jyK)jllq̕&D[xJ @UT-i8>@JŶ#J!Xk)@-d0ݚ65ʼ*lviT&GtxE x sK0$F5O  aO`  bP`- "I$QDB$ ,bA?Y%b2MLbX H&YK6B58nH)lLᕹt:)DZ*! #i]Icb f1R_mX8)i&p213LO_D~?LuiSCiS~&n{g5Ex$Ck:sꮲuQ[qd?0I.fa`|N HD$v2C>ʪl HJZ@m&;1 ?  c $2bﰰ﨩SX -у8I3*GH"@kS$QLkS⺩(!fȎԂB)Ȇ:z[oc"0ԚǠ@.d;4*.CxN@EL+s"T., L#Ps)Voc?H -bJmr1aQ&h󮭤qng(ϪD[(j$?*'-(3]f2X쑂^` mz<0+2 "y3rl),[#Ƿs$J2[cd,֠EcR7rIJ("J1[R{FE" sg!䘊E: e#UMغ Qjzq#KjĶ(=SȂ=h[xBA-?(5FoKTg]Rd)HڟCsW4%:>B92 CΌgϤWOfgOr.dXFWX~"sO/ $H\.3'*bбNc#`NzHU0maȧfQ>Ω wJ$&.@!B",‰&#b"*2Hz0ȉ!DRWLؠ8ň^QlgH+ .Tو|`E.n<͎,-լ" @nl6I!E/CVG`datM$^zDǵvC iK,7C4xiL!iGpwVc1jD{ќDtC`# ^RmZr>.Q>p ZSpS5/w7p +9:C 9oQHJpsХ!*=&0{9Z(9q +4s3D'\yJ2tBJI7iʁ=(vT!~yԙ'_NM܌4e<ʬoX I9G'l8QQ7(j>/܌ 6Hr궕6SȳrL"_c~㤙P:cvd&x޿A7hDudJMbCk3U~\m;0T62ɨCeCZUV6m&`)~ 4AJfRm0[wMEU%_r)iQW=C2X+NV.Kj졤Gd<-4" VDZۗ[H_܌U$=sO||q6s9!u_8,(Ii`j=kE+끟CSOdFIW Xa|57"iB,D"IM}Hb2;GƦ }!'y{O< fm?1PJH|;j 46+d$1L#n{BrIFr%tr'iAڭ̲M8~O]5mTh*!n(6/[j?n5~Q6㌲@q@EbL`.s. J:j% f̡ 2LW x ,($M" B7o!Pҥ2@ #1KR/6"@RОb/ 2" X6J f"A¤*jxcior/RzoVu.:!閸1SbA)n❅,9c*.1j;hE-+'yf!˯jRq2 l"H߭xp ,d) ]3Z̍Ќ-I> 1ͪC5-Ыc XznGD.h5Ę$g=G"$ Q*͹4*f+('lxrR"<#!C-2橪2j]-Lƴ"$D~Qò(N)5$<Hf-3(q\x$'%έ:t34`)¤l9%,g'Z{ һ(tJiHn֗Òr{Z2Mh (u"䈹۸<UyLJvT NYa|! Wܕ lwbQk6q=ύHnahfI1TAwiMe/8BҖ%<`M6Qt!J83{wB5ۧ<bGT+am@t:i^@ =rmBY!} yû׬T4CO̬ϟFv:4\[#Q^p70ΘSܖ<84]^>ӉwM?"p?M/zj2 4P1tanbw46;x~9+,>`8ߪ#빧^M5?sV^?*xWҫQ9FN=B 3`^ S?$Dqn`d }I䰠 -)(i1) NcaHnOSpU/ϥU*բRX9VaQ*BoGjr~Kϣd褐;h&27 Lju _/@ Iu+CbZ;>/7#wwT ¦[ Q;!-p|?2 >ޜo>GeX TC1䴹o` &(&(ixÑ:2MpԸ-LJb)7B*n{"D{KS(l.ɩs`##nJ7k#q,ԟ(SåJ ƨ2 " h:ŦCPII|>u . 'u%TAUnT8Cnc#;\+qЧȢ|!I+HyO:,U*ZU6P [R"O\6>j;EH(}W` Uꦞ*vؒ9e ;ZC/g2ȩc'%O -9M(&-6|tɺoXg%#;-]Z ınqo>*kj91X]7{/ V;yKC^7\yC]^slY32D{vۀx&'bӨ$)Հ0W2gkSL0c%S6Jd1 ,)9aB`q-,܇KuAES"d".=o/>$E $,4  dMP2RߗUm؏QKsH1w?'ތ` #%] =7 6Ytn %gԕL١w=nfX %Lw7V0d:€>N|`NUWDq)bC1/1Erd#ZȃVYM P:7xL/B(4 \YzD"]fBF'P:bUY= >_qpȷv1h%L2 i2FA2Ɂ'n^.9?"~&.ExC`%u[Tr{rVhi^< B+u@ͣnT)X:KF= }%P9z'L"9@*_@4#'AU-Mk#^\K3Eh,A !VN <H5VPfz'Pnlr_(1,gLy@ݦ*.=Vm]t[E/t\q|RbIihFkXۚqU.iHR64NlC1,mhqn- y`g6fFĐ8u2 &%\OO6V]&SgGS꟧k7 q0xnb$Fi$$ ViNcqZ.H^E 8(bƓz'egOc$[uX eP9H&+uYAX d7HKchm ^V[>/1\#yTщydn6I(0"QEԈQ%Jr(b-&N跷 ݿ3Ge푋0g֛>x{/# E$Z8t!mvJH5k Қq1)QSRgE^]0BW(HFZmg^|apSJ?>V1t!܊^}jFmyw}}Be>&l #}i$%ԉg<|T˴w{7lFX~DdWb ݷ}L[E*_dWVN?V_s!{'^-\]};` eS2@b%Ҕ3BouN` eyδBD.47Ep 6_Ƃ;`R*qsܾ2`u%J0:d yY}찃?Q(I 9˯ `nja+d$X /(jld$PCA)-G89[?9#rE=;<똽|"'{ر,}3/;>2SFEGc{1ʬC{/$R~ AO㏕BS%B!*+E*N©2~X .2? C.@FPJ59?IEPLw;#&7 BV1W:Ⲟ e,1 yh{Ԕ$QCZAC:yce2>!X〉j -8!H5*I*$(sOK ÂӼ]o:̵'H3o ~7`[VEExY+b1??t)wq[IL(4`Ȑh5:|/{qA 'V96(HZ n1ͭ.s"?;@?ٞ,NJ 6+D(5:(XL0)LmGd]0i Ϩ. D_ b>\R7"~1b92F I;s4 8KH89M>K{c4kQ9{NS BjHѷ'MHrs& <)C)BL JA+ 1с$d1(OÒC)ѼL'^ecg?G:pjF2#9b @/Qp,!C{Ү̋Ae8+1vG6TmS=z$RQŮydL;0* űN>il+S;T+%0(IXQ^@4)G(7/{{P(K82"V8;.64/ ($-A=Il7"ZJY{V dK+ر( ab:H# &AWu. ;7ԂR$(U;,Nd~RA]&[itFz2u$ G8@D(`ʊXQ3AO\ڋ%؟ Yp}M%9!^)C>I ؅OUiՑKKSՋ9+NBdA][-ԁ)}I]K9.Z@JvH!t#`|Vڗ,ȳ>ْ:ͫ="8E t]5n9$LN)o0%әXa"}D 9fѕ_PCS! uC}z3{F/]JۜBD 2KW@ޕ"{N2<7׸}-:юFM%`8"QEt>-"2CieHqI#%y9ħf"F,NȣD99SqRl^>.^㔓DL2f2TUq3Z>v357W~ZDޝyfb]C+? Ҟb"HE|aϸwy;jn_ t^2O"Kz, Ti/s_a^yQ7e$"=M?8?fJFܑyܱ~g%*F?3&ވnc ̷k9؈rYvD +?SEb101ч*C2x#+?10BoĞtcF%tp.N :DfD5U+xdb[.H><$p9铪%#An)L;`0):FzVIB'OJW* \MMoC5KGG MSĸZGi4 BS&= tMGBc)n8@,om\DJG#XvM[gWYNS=Sk鴪T-zIYS:nגl؟G#%C^ j(}Wr^2]tq/8ML@fv#s9š⸐(KU3B- w d5،\K@Cu/~9d)\3ҨPRtM%.H~& |L7!7lģ:I\FĝP*Ọ3ʃ)zþWCVZb'jv"BHoǀuQwL DD-SCu3|IX=UORP;* #- ҏN Dוn/FKB UDJTy'Jh8DlrIM)H&D?N ܟk *uihúIƽr$?;Iir{NPEFe sm'fiQ!BF1eo *O|A?@]bPV?6Hی7w.֕@q#) RB0$C@cE*.T $X1=mٿ[K$Du 4^!𪆾+ii1&n݂Mj2Yfz!*Qĥ-ON0(7&V 4kqh aC_tۿV~2F}C ?V\DUdGFǠX|{ÿ8P|7̞˖J#yEh*(T&1%DeeRXe Cm` l :tq,Qj-0*Vli줸#':S蚄XM%zs,LkJc: K#{3s&l 25Ps1a ZNp*'70d<35"T "mvOO1*XTל WG ӐEQrIWya-n҄KQ~|\KX7 wbJy*NJXS/БUt'ec%#x0~+:b@F\G5L8usRz۲$)֙h0>Ֆ!쪧Mͻz뾰Bç, GmH`Kxp-fd"(eJgj miX"gtJ" N)$7+z*HY THX$q./m0Zh2(ꧧĠ>;Q>PH܆ܦ mm!xEt,jІnb`J򧮮i!B֒0te\Ln9w#V^&u,t0f7P#? P& ndAN2D>*GNG(!3`SN,SZΤq kyM8M EGuK  N7Q1腑${ f!Ėozvf&{DJ+.-kآ(хc`ق)4&P# bnu.Hm< WޗvKw?kW \",&pFBTBdWr^`xXbo~qfmkѕ$;G S_7$7X{5\4n!U2PՊAp$C gMolKs8O*;BKnܰcM-^zy$۔"+rĎn1ȔGF@B~8(U7C "SK.C"줹Tj< G"m\P}͌dH t9LUt<܃q,~xwz]j<1wqf,nK~5f DKgXu "\-j[~*Mkޠi,{@R$F@?&,%Ķ1i}JE^R/>#Т}6 Nܚ'f~M4'.t '0 tZJi%LTd;(<[*O"]٬!FJ*B'ۘ6"8͛Lɝjb AglJ;4p '~rdެb$LSHڒFPv0z=v#,a9M"jQ"pNӲt!P`UYK4hG]SLZG#S@M@+@!KmB_XTLFvMיC?Ll숒SNImI3 /& ,ADJO%k H/!i&F!;>:r@ HVq(P'̹"w, ɻQ"1ٟUۙfM\1vjOW~=%9A i]p)I•F鼩 ("G"u+fúaX@ 弡#Ur"2D4ܮiLrv*<#vXX5"D&7p[!G:g̸5"̀nDSHHfgT{h2F QR$5|\.H8tʵ4Js \䵊/n&DTo1?)gLvFFz}c)4 \WAF#kESWrݏQ'v`z nupCXAW@#y]HGk0M1*nHЬBp<);Gō`4TSk<Р~L-] cH%Ew;}k1 Z z5Hɘ̀kfm4Zu]trT $I "-$lI%|ldɑ^Bh8K}Ffk۝+M(JY[$ou{caURT?%ŁP#|i<ҏ=o|^ع3ӖE[f4|+LD9{<1uu;@82L~ބye!4ߡgnH[ސAr_rzGQIpB]ϱHyD.mXh ˏʛW^=qP\gٿHvB _g1=$Z##g&2.j|/s!Tcfe k`w).\'λ&[B bG.VflKg2~|O3̇> s銌R72~2'//CC2B ;sq,: 320++8O1|@%12 7 &jA ȉk!_Z#j"$""o.)! sh}$@y{H ?2RÐ?gtk)A =@4 RC҈">9Z P4;%buB*s9}rЃ- 6k&)#Й20I Yiz.1v2 :B8}2L>L ''4Q8e9 ³vk!9 5qXCT9x6骘@4Ea?2|H+!Yl3i3/.E!i+զ34@!1iH'a/4B IkZC7{ =w{2qAib>;I#/Y@+KLnC;DCHC۟0th'C IAS* w$ #3 43x?L Q2𹎤P3FCY4Qʜs4~Ȃ42/Js Krix(K'Z" *[Ω 1@,q"2mg̢vǒOhY*C\Ǭi.V!ʩ,*,йĽs%#AF1Y>I2ڹ'!4L cx+\B뽙jާi 2:)]LN1U/˹?ZNE,1 s|*زRF(%P3 '&."4cIP+(4 +I3*r=+ Q7x΄`Ѻ˛Qh! 2ܥΔM441r$|4Bt~DᯍI<TQ㾊bm>s*!ߗ\FDYj8Zۉ"A5|t !z_*,f)<ċq !qe"g3A~F:mDs:nRZ Ďq&ck *kJseb}n4 -P qe:u'3Mq=SV13px9[,E#1BK 5ПɢMbJU$jHg< ]X! 4$GMvrljK-鍷*LGZaQ"G?BZCVKt ,3hj5ø1L 2YԬɸS#<\EZ,\QMɘ2Ky"oUR761[~E?LU*Brܳ!EdMt8h3؛С NɺȀErE]38\H/('M֓@ژB y9Dv\Q#OK!BUʘyN-\fQ&u_,؄ jBS`_< V+cc-ʢ+!Vu|Cv"ŰvWZ8 ΩB -Hb3/J ze3\I]Wڀ[h1^ 0\t j߼f~ $*Nd1`kSEkqս.U}>ij5 o[ѓw..%./X` #L]\%)աIʜ1!Q,PuSAZO~^˓Hxq30Fޕ&œ~u51#aSX8D4g/TmΒvx5R\R1[`4E(թˣy/_GY߬*2|1:2bȥffs|?3LXR#;V\OH] ;&4}tq]Dk\LL0iFp&`*ջ¬ឪǜ̊PxmHdz#uhzi־e*k@yYֵL)h$#YŔSNTvD 08b1#QIÐUUNƟՖ~$y!IJ^\k/ <ū i0R:P:V/}'69re=4 AMD!j[&{R!fvD;6oTW֡2XE[ObC-:[?O#舺5T3n"<;?O]zYHI}E}SL4f)`ʜۯ+yV9vB=h΅%\12Kk}`FijNjQ"ԝ1EJL-AЍZB_Tu,\~G=sr0[ُX,2C`$bmS[j1ߴC#Њlz8!R ؑ磳ޛq|˿7XJ..ugV{rK`K4S mH\4f4$Nw4c7tvPK󽑾$34Z7P f;RUt'/hKt%$TQ.um#F&CSr/ qS2eh4 $V!Pw+~=L _ Nu|A;4~J*|`ju}v ||cw@Tz@gF) O A` D_8t2Q(<$PDd:S~oS R,OC"0LV AL@iáRxeV /I=F^:fXD6?C&rB$*ku$F#<ՀSΉ&C/MiuܦFè^ݤQ'Sn0i& 5ߺYc#5;tfNkp\FL=&e&z 3ѿz ue.f("贮-\)KJP ӤHcJ'RHt&.CP3Z z@B& 䉷 2 ±J(8 ؙ)JJB C 0NsG`ҹA/΢4Sx*2g䥼'*(r.8ϊc!'K?h#J# t-`ԥm4?Oc[(aQu ܠ3 O: DE0c.~MPAAG" UM-O$ZޡV(S8[(u7h '5A%$KS:raOE>Ŵ }x }_i+z2 ;=b,cJfΧ"J$DG $b2TUX+B%sepވPJ0)jF3NGޡмMHTWˑjfwP\wNBK$NKEj>Pֽn:5㓤2!Zɗl]=Ƽ7ck/W ؀M+˶MUɬi*^J J7H{L46dB eW]kc@@@T2" p+r j+($l3r -h"VLBiNÂf@ZhtJs<&q1K.y]I@;7b-W20 O!,%DՓ0p⡲@iGAUA dXD i0~Rɩ ՜x|K0o_kab"~3ꩆT+TmQiR4 -GuoDYjff*#& 9GՄ;3^KD 6>Hm=r$IQ.PH& iLޏ$ ܈Q.0kiAL[R^R}"4^|ADDޢ:*]rÙМ.j%>̚En*D/v,d)xIɪ~D y)dO$Jd\Tʰ~LHq0~2~WJ!{H%1JP@S] umRfi'YCښP}M"`ՠNb׹-!5-gG8O0NܑS@imvvX[g%%&{"n?>̙ ;]mCO)TtkJ6&mU_1 76O(dIh!EsU0~Q }8*r" {RT˹윖erLD穲ZD\ gxؗ7h$-y4T~|Lk5;;5;Co`6K .ޅsr9Zd#"kHP:D V[d1TҿgI_hidCƗ\d1g>vgv覝t4kR#|SgZumWZ{(Z(ͮ_. S5 EXu3&d|[ޑ)R"ߑ;-,(M+JJ٥#t_֓ZI \AjlF־E^<jaֶw̄jvh ݍgu)]l>2g}ۥ a6 7HKtg} c&e\^mn]gť>v,p'nZ‚&իq_qirûA@!^z!,bgDf)5Iu.ņh%ږ7%{oA֕cO "rٹxW&'N2^W@SPMUFk,z&o` pUƁPn1PmŲ_cK>=0\EV{iCT̈eTPbԹɒ9Fg)"ZbJ F %,%,0ֆng*&&SWJF0Ï8tl0H>,&D$A4 PpTNWE>!$%8KFCM3^*ofd_JbRvib(Kl0@K<'nڤn÷ (#-&$㺮N$."1 JMbL茧dJFI QJ &j$$M8# TcFJRTK JB@Ƹetug'RERRrIʶIӬp8)mHB vo,Kd$! .ti0L GpM"$oc@pQ0m@coȠO 1,0,|KHՉl}xnk ߯k"`pO |fo +p@&PnΎ_`^E궠nI.lЗo!I1.@?~jC A!%P*I^&0fƲFdP&2c$/^# o1FhɸpQN$ ( jJjuJgrBNd/j鲓*͔0)l&LFw3$KÄm,mf2 ,i '(ң˸ђ?D.ilhHhē8MpP[ S0Ot} cmuX?IԣDItXt]6-}R- ABL !LE* Ѵ6$EuI4*-*>% ]/E iQV7n0:/izmL71Nfx`o\O(|jӴ1F E>|r_BFɎ-*-5D/ okMl)m TɅ&nಅH&,%,eXâ-u7t0%3r=vpDHBkETֆWI JYIlo,E%K&7vP(և^F3$6`pڣҭ&ut x&M-^2SRb.apKɨɤ"OFm6ߍL8VIWb0K+lfԇ^?LucFJACT\f$j"_Zl겓 0JE?VL0Y5f.̣ WOYwfI{o*`yoC /)wcES 74.BJXM@#RPө ǼflDG$$P^$tٕtq;p4XA+L2=ذ*UnӧQkrkDڍ uMK[eB9Ȁ:q4@&eu]Zq| y ]l-ODˀKI<LQқ,VPՙ}_d1[ӄԾڷ%xt}`Z)9 jMm#s.6f55>2ΪZK #hzҦ[=-an~~G]6P0^1r-wk%(OӊU^X`,oz9ks;{w_ 8HxU)/|E=b<֓MYp/z_a ?X35,NNJM(/u.#tHi <;ک ?P B'8#,lAg%)+S'#A5Lf1$!KS4J.].H(JEEwVsWl p FdT@W{PXv 6;"6f[,;dXI\W,uXe Jeogh*f+&>'w#%+Z+RV*ƪi8Ú,*b⢎,l %.+R F,E=@H.ƒ8 ;ƅ5gR`SU: n$;Q,q+)h#(2((MAus2uEQk`]"QΔQwi6U|l%q /J _ iY Ӌփ7|`9*YUeb=88׶ބb@RgvlMG fi{PV[$3ҬBkrDlR;xQ?yf9MPXhv$jTj9.srH Rx?L"]d 9/Z6΁1šoƣò:3m_p|<]m CSJGX{o?r=^ 584$l$V^1zyc} 4u(8wz1,6` G܌!nl #D`Biĸ@8zN0RK֑h,/ a -dԇ5tgQD03r"H[@JYi|6?Rb UoaJIA 'A@#vPFb #-3Q Q~Ch_j?ZzG(ahud9 4K!͘~Ǣ(&(Ȧ|,qbc:8j$A-2ӊ.B6ݬE 斠#ځ4Dՙ.[Py/D ?,ѡaČ'-8&pHZ0H@P`fVe\ۑVT zAZaGԴ0Hꑶ?C,8lw?%cm"oT<ɩZڒӖʤ}1RB쵔 wC NR *m?;^Ї`\ vVOǧd\n60H!# :WYתb??I24>61'dG3Q} yi˙SPC֒v/4 )uZ$6]wEt|-E|DFQj![d) ?ARES!F= ś9ptFȧ?1d:#G,i+0d|9ҟo_? 4Uyh҆1$L%_͍5B$ĢJ$b84>V3G| ̎>Ǿy%L)똓0*嚊,XZAիIM1gQ..ՖN%j4J{-& #ui' }Iڳ',(yB*H;y,7.902QZg#JIՈ lÌ+; "qX$ <{41+K~5ۡ3Ah"u'Aأ;$.sb#}a04I4%1Cދ"9^.E!24@*JE910Il?)\)а~3¥XPW/:F-A q7=d%2SfY IA=-z$"P'a}ڛx9 @ &D acbKkTP%0!3Bh-ȣDPcTC:$tiH!i3z!t5b0Kelc0ÇJ@ X;3sG#zJ3 L+AC$0*[TsGrT-}(:$KDh?=<øȰ ü K#Ͷ762h8 F9FY𒤀,5ҏPy.H 3si}O8C'3 ;Šsͨ %-%BC3x@͛S(TF$-Q{MNTK?atCٱy}#0l;|t1 r`0X,s.8k ;E&FɂUfL b5:IR1Ӕ@ 15Db4G%쳫u_>ȍA醓R*9Cjt 3OXrדמ| <%tt|!3 @=69 JJY3kHx4%x+TDY[C(| @(<⨀<A% pV̨!L}Xț:re?0.^|:kGĺ!9r# Mؗ:y2i?<3,{QW>-"ASkx.I Zd[6 M80ʌ5ܚ@ +N蘡E: sC<\]Px ,R]PˁѻAg/Nd$'%qH~ K]ڬ`& >"UmK06&ͅ9U)RiQcĆ[/݇9#?@Z@%CH|8{2u~ %1p =9+(PZk cb  >.`|ԙ~fc1^e?Y@q Dd$ L2 ^ӱC5<3؁2F,@2nuu`Ub2%3> $7l+J>-ۻF!Y^yړ4>=W1 0Q4 ]l#dŊO:bPd UUb5*yKXQO (,kb^yMg91<\}V6ˍ("O"y8inEM4bC`y ^ȃ\M3ξv 'b d4NCm&lbc >ÿ.4XX iD-`LKM D2k|ޙkJ9HeVZh{E\e7ZARN)8I ͕a} 2*64|aivbA=m0 elK^  ]j9NI&\M&,aV[ `&A?YKd.Qx ^`h}:J*#a_Cy2z>l7Mj %[jSM6 Y=U%S>OME.sI̽ M`^D =ڛ9FӺ,"&wX0 y 'YM2C;V Kq~JI cBl <:5-7q~-e;AjVAvޔټG)䴁ar>_;s?tq4J7LJ<|(g?~:dw<f%3"l Q] N1mxgo< Nˌ٤Xo=A ïoNkBOp8|DpK)i)̐^׆-Yi5dRD;C[}wp֡Tx4VBX.^K'QJ#ش,?St<E3Atn)kaH*.sF;<6;EܞRQlۤ7z_.VIb4X', ɩ)[~#DH:{j5ZB*b* Pq ~Ǵ`jn q`{+>mR܍?m ?)\3a.F2ȜC %<%J쉿 &(% {O IlЪ)c.) -Hܢl*:$=1PI+qI, KqE R#\J/ɷmG<{u:>cfvR ZeS&V{srg2NH]SIx`宕10ǷrW(`""R]]t?MK5.K:Ua8e TOzSY Bzܝ.T9Z-xX sxæL!pK\źK4kώI& 8KܒZ杦Dɣ[Q+)Uq $qM%Xx!=E`A`,6t ّd~t %Ẩ/Xέ[H$Wi˄vBy%uZYDHQ,:ԛYEZKl̀$ZSe>@G] VAi5 *+|LdPSg90~1%b;#t m:G⨋d)ub4WQ`aoQFY+ ԗڑ>@:pVC $R<}J 9Y 6>3<,gG_IIG`ܒ8'jwsYZ1aJt"2_U.exJqqs+((+8 %a(w 2LJH 8n_hT &%V"Vze#J["D\̰"UL,JJfËn EVi!ˎ<ȧ V gX=̬_M|fƦIZjFl/yhCR⪩h l L Sk䨎!& #/l6ӅDŠPw/:tDLol~-"P7.Z-(& ( ``b`m:H败꠿""(A ی`JbG`*awcޑYQ%9 J ubqJzTjQ^PoRiθTǞ&.kxkJhʣQ ! "·΃oe lVxQf"v-` bSmB_oFyCvDL+hy:&tu&Mr_Cw#x"^#I$RJъqn@"^v) ܷ" jNXiŋ.ƚcZb ck3 ̈ 쮶rXHgU-n2  "+:"..oKow4`]c"xV;=/]jZ6 J"ǢO3yO! ȵiL`X%QL†2̊'g xi 1 +AyDJjPU Lڸ9 NVk!/s@P< ܴ~!z0Ud&i"srd7/4G" p=,4DEn-D̚q3@OfL 5oꤓSgpJd@gH^;4}U1@6!6iN92J0X޶1Irv#v`&gS<;RW)f ]M*i K#jo6#*^.uP*q-t'USYh,Rū" (mN۪3m!'oB&D+$e$&dVX#](d kNQ@+Q*uLK^eG*i \PB b~KD, jή:>UDDnUhzIIU7Yo!t,>t֢&T6ӶXvk%i$M@euϹOԫnf3"uDhZ#I$]5:(fo4v< 3 O3N/w6"MEO0Ⱦ'T.OR9eC6 zodW6 t]CNMz]4%#tPF>w P{nT.K+?3䢨 ڂ5d`7R0yugkEe@ŬHNiZ#&J. Yn+Rk;.z,,t2TYUK cFLh/M> RkOoBحT@Ks:Udd,]kiHouHDžlc gur[,TS wcX7bX*&pwVsuk^MRXrւ$@`Z[aDAbBDĬL.4,QBDXRԔ #MH-u ug%@vCgդEiUgXO@6;BLlZ_s慦MY5eIxXCCI:4O6#PBjl& RK.m0hNA-2iϟ!%P@.hK9Jsjk"jK m K{O u TEl~߇|Z<Ȩ?{*"ipuOZ!(5НI^e3t+N۾^<V(".,Ba-sn1ز1?nnx;(]}͕֘FS kjb$+_ß' Va ։}Ana*gTP y.({ն95Ă?4 BPp BXT FT~ aQ4)?%(d6@KpFxT)~ȡЧI&X4:GPQ% O!i$#rYi@h"pS_ c«u{Z_SyZBЁXL0s1B$7/b5Zu"rvik`حJ1WvX(0fcΆp* nn4,%1nkߗœ[kG`P ֬|Ȭ0=󈆴kҧLN$G/cr&2*П&`h./3 Dc$rⱱ)KDn Gp Ũs*t#(A6=j-i*ɤ +q JS%o )Q[GKpKId$213 <ۛ4< D(Bi>z1T#pTM'FL2! /"L%M3TM$86߀*h-3 0̪ 'Kw2 Ll/93Z 2$iLL$g8 J(} a6@ TLl,%+h ůUOMhZE8J 3THo (EeuϻH~ g7V@(!KWo3djU GR֮h@Pz,m mdQڙI_@W=ِ? ȕ: 2i}Q0'(#\8 Q>2Y(>/}!E-, ?.ٽXi4[gT0C3`r P[PD&!1.e !VI؂ʦlXs&8D*#1AdK6cfq:'(5p!9_٠̷p)y{;8Bn\4^C(jRdM"Gq$h \0e@GY;tUX˘j&S=ȺM۴8Gh\hA dn&zN~B{*5yt 8*[0 h2JgҠ#"OQ^RkQ܍KPS&CTEvVaX'ݺd?Y9|U_9e.CV*(6}}S禅^])(bvD% %>zg*"Nۧ=ܟj 4ap(-iythW8$w2!0vTS-Y߅Zc-8)X>wPgs N MNH˧x3ܠ!9'X}@C:q QJ0'm pUQm2̊I qa.1(]$bj-y4bX2ەJmq,b/d-80Bd =Νf'yr~F 7#Ujl,s&^g>Ɔ L h*D5zI\ܤHU yLm AƔ)`BUMkCĀX)'EFd ǟ֭f1)4oqo[/&*dKTEyXR>GKzMt@<].tEaSG 7'A ogJh@$<$O{m :^4MpBLnV][szu>nکw:+,{m] <6"=@n 1,EdN47}M+g wrQ7r =P+(N*{3!r ?J9[ {Ț2 3z 2 !&-K17* ;4 Sp=Ήl5 2">"Q8*ʗ J̊/% {!ⳏ06 1ը#a2, ;\)Xd,ljs܊IJїAB2 $X+p~-#zxP/{i nXIs·:< J1 ώL+vkY ȸM2txӒ&) 1iG"k{0Tʸ?q6B@?c4_铪) >+Kkv dc;]do3$bЉ$ 60p2"@֊H=2|C_sMcn/)g>`gRITQ:JOPA5|X}O ;1 =g(r/RÉxȎ>5eL[RꧨA ԰.O/*b (UӅEP9 cSNALB}U0D?QK* X Q>dqNXlIDÚ%ləA0-!青KP+H Щ@{@ s=JȪ2Kǥ^05G: **i5<)X5HQLFE@Eݽ7@}aCQHyRYSI!V͈k}ț:Ȝ[8̈:\Ql8}d)x<'mPa YdÛ1 S՝+FE_:25#:A߰i./+5<]<:nlґݲ+>[1U(RK}׳`#ȝۓA&K9SsEyVPړMs0`%IVW =2B8A9?C1aE)4 @"/:K|5d7&^$=4+@tCޑ9ߪ*4BID!.$J&R ԭ# ! ^ 9X eHTEj+m q.#Ei[Ɛ@`Q_yLh.j*@20/j"D9OK1kzb eY8̖͊œ}}=T'974VP!•/A[8k@j("sCɭ4u1CbDנ!nք9fΨ.*]Yuɻ; J:Ӹ f0;tZCaG>bM|+ 069G/ =ݴܞ% !l?Q6Xׁ]I<djR\{LGjs椑GB+jO K*l{(gڳBK aK<9d3Nl(M^W K.~^mc"d٨( ~ eBW&lUW)aAn*ֲ @2II|| UUb*bcKݩh\8u~*<+{NW: \ C3Se}l~ Ҕ`ruE ~2?[3˖|j VeXe#f#@¤FwBs۷rP@VMLZqAlAn5 lO0ƎD%NljB9R3\DRIAnQ67*r6z|&ljflQdOKhfhH2`m^W@o|o_ Qճ)Eź>l8&N.΋4ecDڴ4l$hd)O04jܬl߰A:퐐|5]{h0{?g&h8. 9|X7~ZX6up\oܐ9(eV1\j,4Fl aM<%dk垯X.Ǖ?lJkDUۚ>d r=k주JKTT>:xa n{R߶ŻfP݋?2xS1z.1]=\õ`=]'osSLj06$k sm_;u%?c,,ZOR$ `6e'R沪,L,ཬ &_D$Na96D KaHW#( V6lCGE|&{hU1 >I r~f>_ (  ?!Od4a$T q !<Fa9d/L@qm(C_D}aQH0ƑLBR̎M?Dj0EHJP&m5JC$ӷN 1®`: F OV|DcVHG1_)6Ldƶ?ͩ vs!A68jMQan[FG^T1ɣKCIqdwG6=6DϖsZq^1L,:i5k4˲{B  cLע040M03'k"6;hPZ25/r) T﯎jvm/ˬ:){؈")$DCH<+R{4n(L 6ʲĢdBցt*=2++/d>{HDb) eK??T-HhD v r.&՚fl|K?IU /i|~h>%v.:7T ͅI3~\,\(4SЁ EG3. =v1nBYmeڇka %3C"N%L-Bv 9ͦ#o=hUG6cҥH^YNB Aq({r8T"j?MfmFCk*_ . YwZwԲP%]=|(Ģ Rpޫۮr$lRU<)YX[␛aY&#a˴臽~*8 P;4}J?lqc8I}v,M E, 䢴s#'z@#v4px81aQe),#rM d@+tFpSOfa%)lG¹Hŋb),S!I]넭]s)`p̉,~ZRݩZaJN>K7gk X /#~'X TȺ'Y*݃0Kpm# ?>bӄ1L b2f]JfZbx:ȒqΚFUi:%3]øg^ x9nà;/5J}lhzpL'u~!]ZYdTϲKMPoGy/qER~*&Y/c[KnT!F v=.+#$"Oi-il*)f>*c^4m ]ބD+n}Ϟ5no[w]81 O8@xԭLrsOjrqj0kkr9C]c[ŃTM.S j#/mP5jx/62]('piw<%AR4{ʍD %R|GWAuk?J&@ ېaR~b ӫ 5Q9F @#M,&yy+fSRHo2;so,-`\YxgEhȬ4 fdv2Z42 Rb񂀳S\6ūw^nSJ$ze)+ <6lK lwBH )<qmbvF CM`B6$g.A &0F/HK"Π|WbTlG/J lAlFx(#LV";n\I:!m xfJ m QGп-J⢨xM} BYl2ȧ & $gJGhJf~T̨x$fuc 0v@e m1LM.ꔈ`cL!KζDIt8OBE` |எBc RwMz.%lc!`&!z$,(Fe攩РD%b!#9|)i8|q,B^4P)/'ZK. ʆ"PH|s_Nn/|B"/ Šh"(d 2LXma>C[ 3 FV"bvH3+O|B۠ YlA^m\p$Y&MCE pD y; n\d9m)M} %^yꌫ4V/zQ"dňB^Ud#),XObl<' ~CO/|o& ɻ'ʝ&1 tJ)ȡbgvfBN"f.Q2JpM- kȣhX.&ы=E *4j O$0<[jЇ#5އŗ(CDϖ%#ܲg.R R's@nKb#Mb,Pe, ʾJsEBtFkvX 2&^ ,oLϫC,.9"}eؐQ%(/ t 0T#+$)6Phe伄 u*(*6Kvj4 JC;dGIH Wl* ,%Aj|`AAtbnjCL|g.#鈿gNY_ "8R16N. Hfq3RPP5>F]KK(M"tnrM5*S@ Kҷ&5qa$KO= ،'M*0P.zF(˓N[J d*k12 n#b3U"_JWs(\E!Ny.Π1qKl`jήP&$. l!̵gTlTcN-E'-6l>m&%3Hr$^&儀,rXCd7<-:F~3YsIcs'E<ΪGHΓgHeN m`C,d 6` @ 'qb)KAHnAJ TDBL+Dl @NoIURf$vQL\%];Gڬ#vGPڿ/ a ȯ/Ȭ&L(mc&(nȆ~9}hDkYi!V"v_14i8R|"/ # cpG K 5l Mx$3IMx<aDj9h"OXAOPf_245L :i[Vr)^pc _I2F `, wzp.3^iGId#8XJa-ήpUR"h}>q7qq#E3mm_rX o }kU3=MyL'?bp.$XԘO=ٌ6G4XLȨl !33FA4]?T' 8L CbMH OK.8Jl'I|-m+Ghr?iS9nGX&w`0ƜF*z+tl#,⢋F#SP34[V+a2Y~)%KaxMqĮ7~1.I=[0\,RPP;¿)(8ަjJp=:7 )P%;^,@e&5Mb2SA.TOW.!t@4\5n*'P@0*rZ"vB| BQQKUbHRmR||{J*,3J21j!ibx3ڮR4և.,!&]ɿzO"C4A |rI/)4**6iRc7Ro* g5!)0#ZcLִ@bW;38 N+W/'4ZּvJs!BW0L1;BІDr^JPH=;jb z#hRypǿ)OGd nѭ*f+#)xǖ=6,#Q+x, Ar .Q:*b8.88a&Ai@3A =bvZ YMeUCufGiǟd=5g]qe;t"YG^\͂/Ɣa?(e8(3[Wƅ3w\\9Z:r  T ~+GnD_wE @p HR \E$Aa2L*{3rM.ARzԂA`okȣ19͢[*'@BfRO@Ztn5TQ8*@>r)jK@Z|OAR̚qx°9,a"sD ހwGҏ&g'TGp9}/} w΢5I\fcl7vh1C0,zfծJzq (;¦i|$OПL Գn:0 #1#n.0[NhzJ I.GAhRo š1Z. G郔,7 kNsCD?3HK+P"~ II 輨LݢpjTB~2h+72>.,)j|MkL.j[3X6jl$kB0}hjhjHaf_oZE$MJ[6ۈ|d/>$a.*_|%p7ըśÁHH@3mO>.s:H7_!X uwpY3-/b""fЙJAW gq1([~)T9K77v6%@!SnNe21_+%iE)O!<@f|JWÀ ؒEM^4[t2 IYfD-2 ¾^Eɐ)(G L'E%<ғ>ysS!&@^d@JX".GpI#T!#.kq@ D%hkI@9t$)]#QhRQoca1-C.En]Ls|Р jl+<8C* ͝MhjJBRpH*0QCit-B*BFr* 3h`k;qp+$V/p~KN4 R[9:wKjA̋9OX/Nt]OXN%!<55zG|QRR@vS*:T!Z36+K<2ď9QE_i(~iҖ13|>h+jp ]?+S%CR+K#  eزP Yl%1d?[70N]˘J .=PBQ])ct2[صVs)ұ;VG& )ނ1M:ƄZ1{与ԅbk3ɿ57].NšL#,\@YoSzEr1o>ǮmA:X=[A~]Vqe*cp~!ɚb`ݱy/ X-S0zD08ѨM05s \ܽg5ZG}3xUT=dW"HBc5$--Kwbs1=oprM20l$"8%^P zHvK.ބ$ɴ6!wQcD8~^ElYae:{쨧amen#f`ypriT5=3"0T2I89^Ɛ "[]S!-,rȹ#!RS*눰88Z:T125}\݉\ABEs8r|!9oZLTrl/-ٞE@7]D%,i!T®XLLN'C! = OP I4Ҁ p؃p6=ФgC*c-z*ɪNQx3>K20ZM#\& >LُNỹ&Rܠ 1J8QzFþ-*k41P}>=@*l j >3j 0y-$(RX} Y /ZVZ4H5PN z94z[5Ρ-X-BDS@ߜB5> cׇIt@(t,Ft/ѺTdQ ]gQ ݌*95L]X/2SO )92lA5I'3% $%Ԭ4T(C2̫"sOR ߋp(㞵 ڙ tֺ!Ls/x ݂HSqŬ $3 tŰD98LPCVAQ1M}mPȝe" ZY:@iٲZH*Ls|9Sڬ2N%+ԩP<*B.%ꠅ9-d`ܛ}@eھ/$O-~g'6D\ hPD*T[;H4E6.] 8N*[KTf}.wGǂ?HȊ%ō]SǢ`<5a@̮]ߐ[tGڱٲ6SvXLr-q:;BVb!^<"P:6ש H-£31fO N: *ɅՠZ"#}ܽnm $.jus5N>_F.Yܣn!bkbJ)ލI:C-i'Y.f|!=M'}>X9zϭ[=H5rU]ȬODKԮb!햺DTT 5v`ͨ1$311:Jc;2b^D&҈0e,$n6K:RUAA]"E0#]|PaCYD?cMIaRso&3=-u*ZҪf*m) G E:H<\߇Ѻ 60̱KPv̗|3ys:$kZ|wK}*zPua x `jmsm9ZYZJ3vV1:P`)\e`k+,_>)cF.XY \ERusa-\lUq2cΟܦ, m-@87-e9?@6o<)KcD[j)£\D/p,% FpؐsKkBGZ5Zg_ȚA&g:T;r@ek:J8B(r9}6x(jG>!Z-v/r~jRJiZjq >8UC E҈`X@A/1(5 tJOD8+D(0e,Y(MgyDJK%d MiYQ0ڥJW.F,Ro+VՖq2$+=H$@ ɩ*DR(Drr(;Th%x#>y&4@@D(񤎔7H\RMX"Ѽ.5RN'ДYI:{Wʹe?i#*~Nt)mX>4>s8 ~C$(3H:p\pKrNt\t;1P;x+G!& P"r] )BH~@Ṵ@i~6"/Ȝ=P{ڝH brB#|# HTڥM``Ii)̀uL"+T.W}[ Jo~X%6< ;ix+%VVڶ:}D0džX` NlaV+6V(@+>ZH;cGungXd~Tb٧Ch}NH"& J1RB J?2ic#bټ 3:2סMCfŻI4(DHA ""Q 4i=d1Hd*, ٥(܇"?Rt-+J{@bU8 s,mCҍa!2Mp%Qܯ S"ogQݯ3<1U`˒Ƹ}Sn͚ln'ƄKBxcj}ơh;-jG]2hȌZfgʨS8HBi i*%ƬTo"{*2+MIF'Bn-Bnh`U~ʡ< ~A[k͓Œ5qW^0dAÕ8؝X~{}\l~>Z_57w͠ pf 刎{]a RdcSsǓ11gHg_Gqu$ 10n `ߊQ5-fжq^ׅ2BUA0Ł0߀&otYѓGPڱz\ M+A| #2zGȨʢxڛM 7|r-U r2DNLKż7e ׋;BAo~D=J *S!<ẗ)Q-$PaZ:lA,o ?(,eGT=8:YY5j5I~co '6\c]m e#&$w$)oYԒR6VDLb]lAt)>'2T+$ΡN~Za &e=χGrrP K֒xƞ)eTMdKM* bFPAP^~R5^ݱt5,j2 MmP8FO:3 atُ,gBR{͙-<RmxD$866R+_$e m]2P1yY ڃYdA^xG)]"6a5*DgSD28Q&Q"j| S+Gf̱-+Lsn3G^gnQxi(LD޲$5Dug:P{7Q(!΃άYDb 6{0mȥ2o%c$ l1斀HFڅXk`lCԡ?FɨW8LTVҲy~0NIHN>2 `MPmpߧ|ۋL+!x)Y *dt\h QLpA¬ _ymg ^1qڀW[ZI QBJx45)hC]]Ϊ6"}ڦmy)?Kx(dD ߜ>h XO1OHa'yvϖB GR<,%(\%#!>>yM%HtbJUU^ybRn9,WD UW0S@}L貕fqhXu~تs+fW рdC$!M焠ɢcHܔZ>1V}ǞUK &h[KʤJ&srVxK^*=K!:Dڇ}m <7*¹ u).G#FtOV1&&Zhl#->*v^fL) XEi,`,ro=" 4gB+l(m(],B<#*@B8#H} U@eEkAt'vB6Ç,*Kқ<T(j7 <ܲ$i<Ka/\˴fuhB:PTkJr/B뇶L$/iXՊ0H:Xtf&.ryBv#'PyH ̐HT0pE >haEOaGJt!C~@{"jkob0o@ #Ș18LLnUVN.&R e FIrb)+P/ہ1~+RB}J*R` eFj*xtaJo}lFVG]D|E=1nFq!LĢ^V͔rd,7Ɩ02!jS|gQO!Ѥ8foCt  CP8IHC !Cc38K)kI̡-ҨM$gP^&T280.phԯWr"]1Y14V! |nEFB 1Pz \/4Q`o/+-+3]pod5b"ljOzK~&MDB,BaZ^&)?f11FF:~!P YƏlrbKEeT)¨Ӓ@bQD 4Jk ҔѓC} 8,H̟r.pk"dv$",$ؚȍJY#&>ɨs^(hok8ڒAIucop.wwV~(Ss\1J"hTqC-/:LhEQMZR|eU봊iD0j }Sg:s0ZL, ,q3K$kfER {o|Le84b(.Q),^0fl#-GӴbxz_FY'FMR;&b:@5R͈mMbH> aǣ-< J^0032xHyl *tB(WJ_ 1f,ږm"fh8aK]-W0ޓhmY &QJ='tjZK`J8LǭM"W]j-,4mse c` s5]hH  no4 PGiki"7>2ʨ|I+Y nhT-'3WET#rb,!H UBUWtsT$'lJqAFa'^afuWJpStmȔAC*RM##u%&iqe,sIHW1AL7$)2nvW8yM]rei :,` K슏Qbo _N opD9 *obԞ5)Skvo(҇VDNdsW,Mضi8,Wʘu"ʘ YjNɞb 7д4Yb^.yif^oJ ؒ'I͛)5~x[R"BL6ߧVNQAj_o1 tP5y,L EG z$ S2 qJ BSdkcz@*yVՌYmptc.K/& l)q(t`hd,[f 4 /U>q8gu\h-^2j.0hйqh8o H:Z潬¤0b.Qù[9o8t#s+YۀʄhFRf 5j oponWq3ZBPNwty͹9lگeJ<6Y~< T)Uy Kj萫 EFm50b۾9W, ѕZYbOhm"rG87o[1-[r] <|zPVBbQѥۨsfs GX"t)zU-\q^nD5vaL%.kǼ{r#٣xV'HLewk^9~~'${gwd/}<֫Eeu{qlyk9Რ6|Fg.Kኢn,úe.JeYgJMT纽6A.&*/B:m'{wɇʹBgB1嬙xkȹQE-~kYu'pF`5?GFgq0$vSD4;sBY mSU,l%wb *) h\=r^Buө U`6c0֊]eM*ID h'^ d[5h䫰9MhQUĽ;gɟr]ui7Cܥ~UqSܛXuUC:Q=-Qm*#5 un:mٰG zp (8tM IS<ԯ…W\ ?P B ) E"(  hII@TB)hhy/A"@ E>hJ;D|nAtAM>,(%S̡QشD-P{?PiP*Y FhՠQi|[xQgN}N;vT0$.UvcMkd7-_Z`R{yJU?L2[Hm}s `Ytv)Gpj;wQcrIBA]RR4}Zbn`Y_BI58k&Ӈ I.+p AW.n>~*` ;*0=mjUQʆ;b+iK?H=4C]K*ѫ=CpJ$z ;B.jz,l ڙ17Axp[Vٌa|+5 # ۤZc[ñ0;nЈc7!yE;L R1!7pXA8 q=03@k80 _;9ΙX 6 u84#E"=pT >V)jB( i^9ۦ VrE=[' GzȒ!#`>μ`'8֠(*$ @%w/y.cЛ!Q *L-J?+ LEPɋHj+AyE5t>4%l$#8y(Fѣ0c"P 'l2yK|-*g3 0@BpD,T< lK0 ˫(l.!<ЫIKw)鲻( t8'(F ) D'@$Do,)7 iB}F L Z$ȌJ-;<׫*P!z>tZKPq@(d@xJ8K讙šϺA(2> *Bk4ه)ȋmi(<^\= Pذ>X /ik* mBP㑋/A 8Äk-AS + QY )ʌ# 2 HO0s$Z,+#ӃD y}kƴ)xL:R,Y 4"h8˔QXݠ2UjzKNc[(S;H1$M8cBBL[0ԭ O:=]5qًI=UPRׄ>K̓qM9p12yĺV΁ܶ”$Y[P5{KP95c7)iM%c=1ӡY$%{X3㘊8A] OaJ4sYhT9}id œ,-,[C}XST rDGZš—J#F @U[p* ˘ȟ([} }.24B-E-)w c:Q؄3de<8 ΊZ*ؗ{KZ¤(AW}$ B;9攵 y+OH br!yQEǭ ֪2@HV׼*dѢLXB%&ŋF)xAJ64mBrK@IByX4V2,1OeOb p п]( ]ɷ:;|yB,z\KZD!D T^Ә~ſ |PI;=Vk,Xlw utv(!JABi]A=̜I .2Uc((6ċZ.n+&\U.6K?AKmTBԃ С6!x$%HۀΉ-HB=Wzݢ>5Gdq yd(PK- ̰Wd$;嗢Cfb-=; (m'/g*bE tT-!u& @ۚkNSfF;F''>I6%B *՟t ǦҦ[c ɖC +5g9CׁK\hК B>y~n2?WX"V u;}UC-mZ6tI׉DQy` E.aS1է5)We v qP:pf؁ JPۖeºJ2ӀDoBХt#dc3H^;F[jeཧ- @~55¦M+A2AQbm5Έk 3'kC𱗲BpFm)-Mxj*4!<|ɰCpEΫWץq< n&J`C=cݤ2A}_ܡ/ 8 gʞŏ]:8<:eX2~1ctJ#DݐR/Aȉ-j+`$@zPS]S_GC[Qm!u>N3}9~O-49Ri{]aZ2u4&e81@u%{͇kLEUӺ63WRL!9Z,* @p@4T@O(akkM;EB*K-b45]zs-B4 vF`닷3)`Sʣ&tA=#]T+m$ݶڝ'g}Wr T&R,5=u=cRge4Vc+=`-xܴ'us'eU/J*~#f,̘6>ƻ87 2zM N*zPZ8e'|̥!)=v+J&F?ty[ ҠtG, -~YMKL#el&z/A`D  !P؄!aqxB?cyBryDMKa$f҇E$N㓗ܒI*fR$E>xdF+JPEB3[Rڜ6I O*8l(k{[fi "I U{fU:rHQTU |@0AaX6ZcSR &*Xe2Ё15(Lxm kql gy[ J3ٌ(zҭO+cg#*- ԉDg\e|#z&ҒIik=P2ژ@Jܨn@q7&}.;Z( QJ*q͉"hIi$O| Ul[gEѐbH+Z ''pZӹabe\tɵj/zjecvپy {#M&DJkFhcn⫶&otf ;Hzkl)& >LPIrƞ\ (쨧*HXrb) 2Lʖi聇/H$賃qY(">̲L(m bքh̠.vbB.ЎX#(T Z(H|b0 2IL*"!I(x@ա͐EcDЪ~%L#̰}>aZHlc tl?p*3&`q4xr0OmhI{ C ^%Kzfbhn6diŠ50} izld-hÁO_ PCTHtUZG Ѓ`Nj N06P_'REIK$xbH~*=Cm" :Vqn0x`7B'J"Ƌ'#RB Bi,)d}N* L~ N*?gch/n,ѯ#motOq/` mƪ3((%HzSΫBs"#"gCd`f(0pL{E2%kP~nKNLW#[ -Y"h/Gj r شK($ؓI *%x)CT7cBW6351zoO=`+ ΀ >HlL%d3ZYg*r憿%ORT-eEV E 4+UUv/&LKBT\5fS@ 8S..v!:)Jk)B\5\ODn^*vGN@.RWQWv[3 Qo3F6[]TiM*O auGU <(rҮ 2&s,aFTG6_ubc"m)3z A:(n}ebj$РJ2 iE,֟d ։l`VfoM0*p7a#r/hk "\$nJWs0zirbVi7GsKv!}|e`PNld5PkT-#mJPb#*J"BrHu-cV7IHv5gNRmf bgg_ >BO6%cXx,0 qIfseT5@6y7ٓq?/܏;H.p=#,!Pqf(LĜ狘RЕcA1N,7ONTVkezͷh9JDyΠd'D:*xX$6oU%$*@R4) 4M-<-yhQS#L[ ]tNX]m _aE`WRHg>wƄԐ6⡐éڣ (sfRrc"gy o=6Gv.- Vm_[5U_P:&}`RCܭʝV_wwrSm ظ;VjE%iQ.QxX*R%+彸W683ۋSQZ&:,L.JfS~E0-4omRѡN-i(%-O7*aa~ĤPdC3q삄&aXKwCZ WT}^[Oパ!eI8fxA,ޠi]?^˼[T]Iu"frB̂AB~?0 Ap C!g1#D|GdRP 2>ERP,=d9aϸwYKK紉H ;'WE?A+LGlZl5%ǡ[Pgwȅ-=pT1@L[DӀ6Brf"JT*%,fhhOYl%} 3/[52;V9/ِ3ŽbfhgɗʧشrQ5vΐWH]rκD "sD{냺z;@Bڞ:hrJZr(!*1)l2h#c:́ 8bEN9/8H,mM~g[Ty !-[+|RwD]&@q~79uɰ}ǢAS1CH@@H&~t}_M8AYڠ L>|C7HW]9񥲱D0U-ƤoOMŶ;ZLC]p#\ip"cmpH+r_IRQ ىK=JD#%O(&m,Uwej?Q$D#GA֓蜩E;maH&Qϓi3d -yH^UIu7lTIPƣ4T!FYgJ&ssB"鉂T8%dcw1,9'61sI#'=?=!?vlF2dԔAW DMN`+[nI4ŵwOGlFЁ//1˧n&Kl#Kd͜6zaϻt䚙M GL&2.cD  HIzT]~Fi)AhͭY_RؕZ*W(Ɇdt&Gw eADtlhNڮr.>'}zY[F3~2i# LF=TJ6dX_*D XL/.?HI،g\*5ѳѱ.tn .JcT{X/ajX&e&ZBͦ32F:-aouF(nG9 M ~2.!ǽEˠ**PG,fum|BJ Sl3iCūWwXQz8{Q!$)a0 WU~,:D&vkYϕr% T"24+ 󙵛1*6IT+z#?J @5;3(~1(((AuC;4䢠H3&%A\KDbe4c#>x'` 2L< 'l/ꪻt(1ÉjW$+a3 'ňs o[+2K1+B3 abZ2Pla9Zx_ '2=)B WByӥҕ3Y%D=T"@ aa SRW), K [J~CBN귣L|RZ-+@%[-4Ŋi%*07`}ʟ4>J_`fL/z -4M s4Cf c[j S a_)sq &83A#A|iJt8Dj= Q P\$I ˆ; ЍN¼9ܵHCI U(85|OWDR7 >xϲQ钴,*9.@굣 (< 8R[) Ό N%K.$<D|2u3lR CtAd~ǰހnbKU=;8Xl*iUDDI=4QTJPrV(͹l=Y2n904D: 2|o\88w6 )" e~aeNdTz:6HHHEkXŕI W4MU- ,b,+ɾSb|΃Ff#6k 7169KP8Ƙ39"ZRL'DS)m?Y8'SNn~ȳz"_j6r˝x|Sz.5R{6#>0pB/gャ5b7`ZHjHYC;^(BdL cs0uó{'Ah/<1~+1ugbT65ro-? dEX]xa\C ܀,ɝҤ9m+-8EŶÁyr 3]sOU1(HR(')#CzBީ;3rnN^<91"0(Jw`R'5(kJK]@BhKM9ZG 7ϛ`n#:,b^4% hP"EN8uEF}x ",0^' c:^+[4^fؗrV6BJa}B췚¯u^[UǶ{A&.hM<a y,ly$Ym;5%`ްj>@8# A`" ~PF@1 O$l?@Ҹ]Gbm&L~M b4vSD¦:TEd+DL꒚MuA$2?#&rka&c9sSTFR*)He簉hLܮ<䤘$΅ c-df@4<"Sĥ39~;Hg'&'R! Br-C YA_Mc1XTܢ)D?yw{#* @f|A r" L#"#:"0e =) >gdω6KH((hO#d# j6Eň-4*! SȪOH|Ңh=<ڄ?r O0"AN(d&m ݢľUkhéZa#`*JC4TS]ɀ+ WΈ"4h!,ĕ +$+%(l HC Ƒ<d_MB%(2aB/؆,?tbyB~p%Dp lpPjMC %me"PbE8%օB:V~^Wlr:Ԍ48 +)nI0 mE04Ѐ) D Vjh(78%@ _f/q&@}M( O3HE:nuSktn>KޙnU#8=\i$Iݹ{}4hw"a2i"hb,""}Z$:Wp)rEfzK2/v].ޓ#d|?\+D,q8]L?'HNgyq.Dj*F$?7ŀD}a2 ێ K γvNhMIxa~mӺXFg ~ė,%dF^0Ɯ~;x^O|-6 b}]G}DJجE/‚ q>C[#HcUˈ1TѺ:y̐ ՀT\re9*šThNPx6xJy%я>✤w*2k\.D(hAc^-OteC Ycq'$f{nbK٪DH`,3jQŰ?AXh5D6$2/g J+)+5pT͊9K ~?XO2 ]wГ|Ǭt4 -f``_Vc7/2ݔ;`x A<*`EAR.$~aw~I Myr6)zXTI]"]TlHb1-g1&N^$FYD+v8B'GolU1muyE{*x +?L[UI?%ge֡!Pe-i Wm?$X?PG6,H>~8Vͥl'VtT3>&h=]sw;Jkp$+NG LxHlFJ #q F9!E`ҭ [V7!J̡+dcP '͚'S Fk xUa [`QBE%rV׭6P+Zrºʲd@%h18ȫOtRe$gHJrU<$B>پؐl68I(I( (xw 8}EȺ/]x?[v&G0{iݡ5*qɘrB W^Wyݱ" U*G˹dof%ʞјUmmZBg6{Β!Չ7~9fI{ ByRעNM_;0?IS~lOA3h-c߈%z3Y,۩(l6*CM9Őؗԁ~.3>2a־ \CEF#"N*xI dv ^>Z$+Dv!2MթH6U^pBd0`w0"6ل(n6:#*8#nKvŌcig>K!"È/͂$̠ Dyhޒf_(l"H/@XRf6HXiúlN$DPDmJ "#U#Ohdh:gڂ&ahzHs8u` N*쒞N;L €:0ɾDk c۰R)**xTh)ƴ9P $˂\TB`ZGgmgޭ:.dkFdx,/ ffd^hΞW#:Nt DzD^F͊xsqjp·;,sg0ʬi0.lGp d*pLЈJL^2hnL߉LBz{gUލXDVڗ6$G ,zH?b^ i4\u,r#-Т|k`ڽ%|x<ƿ-&EL`33,cϨẉ2D;+R`#eyŌ(kkO%n2.}0O JхۋI0J<23ᩓ"$ĥ[IRJMN~( Vdg"fj%@* * }O.!SG#z(谾BD݇XU((IDfnR{sA)$r3 C`EB 8"nU!BNl!J ,!\qd…^GI,EBn.pp\^FjORdR?r)Ah%G8EB`ҩ{M)aKPiz|0.ah4r Fo E _hXI skC(GmܖlgQ {D-{1iŭ TmjxьzQ[Ϣr9TǷ-rV<tB2p!;S*T +t#tOp`/U8vElq^#*edb쓤bbSZ )ߒɦE˪El` {(h%*tVJܦLHsR;5 %'htڋ܋}m l&2  a^;L_u܋q_fJGuddpSH VmB]g\Bl-𵨜}JπC:35)L:*TgGtMby,Dď Gp[586CcrPm-¨4n4.'RbВrZNEMaofw:j;D%h dR08EE{%^HG[Vokr;J̍Ve"Lτt7uVe:B #ÿS-nkРCT6/Z}㾑ܺidJ:n\6gOn? rbPu֭0r]Wn< tn *#*>x e|C |Vdσ9ltvX >#6txwIk& yO̫W వZBy>t+9sTy̮a fhOI8]y0A jAQE5m"gnmEp͗ }EԑN{*`xg%`zn b(70ce!c`dC*ōҊoy,NorqAc-W䀹MkiOq.Ҭ9%ף)!(!G{-5;cxY n9+S5Ӎ~c{uc%;+ϙOtrUtT CP췤͏eWcwAK_7u:ᐥ $z;/ yvNbC~[9mfdSOB"U~*X6ԜbL^3~3QZP3WuXo?p%Y"Vrf!TPRx-V_Y{t{l$v#uqbl g[4V'{ zx&رD*Yk m{ #iF `SXuu"\ћ 랍iu,1`N~LII(]]cdT xCс *ۣ14E@R{(IѹɹB8ѱR@NfDx6bR .*X;,aSŢ9+nZ&gFuցӬ&}Ze/^[d_RO&\w#?66 CG:+ Sly|BOkJYc6F$T%!{=I&(*՜i38V]d{/ ȯ=KҴ' ܚݐO{ǻmBPX7/&"XmPYPV'w7E["k\㹉,_u'Z;;lxQu.W':yFXQ6J[cljq ͑P#<чlw^.J *&w;(N@7^Ժ0!7֊_mbC Eܥb !,J!o챑e%x*D/I=nپ 1a 2^Q~mcTwzf?|M"d"KB7z@ aai5sO ՇqHfٖcu2 \ E1"JGkP_Tqʟj{zvt#{YՌZ & {AА, ߱L>|{FOMlshnM_UT_pʆsIK \BcJt ,m$́C!'i ;[ #4&ĈI,g䍡c]E -`P)"dAs]2RE\Ԛ#i#Io)&ĢH[3.V)q!)`n!\KR%HM;Y>E⏛S? p i$GO^AAxփ#͜N)-X$:錂oԨ!eVJS̹oF)aM"9E7Tݻێ2iʾ@^*u (9+% ~e kzx6m4*Ф{UE?sAÏ- vDԯEQ!65ʲ&sO\M( =̨ZQʾdA~z{Fys.N@oQEYT#"32KyZC _aT=b[>>6ot&a"zCx\l\!*$%67Pɓj^,*Բj "T͈$:Dfr4H4V Gk)&| OH΄%MRD o%*fHrT:0w$ !+0vu&=,:eUJ>dyZZEͳhFrӚQP'u>8BAmJYfI2sZ yeM`'] kK. @wm& NX]CF=3*!E 9%8NܠRx$+Lbsbd.e?RK~+>n@48}ME+ל7V-*{\WUPȻnOBZ02hJ ]v 9wZa${.ޏh OMdyN8nqMٵ3}'A5-T[`?rn2x8 i=(*5Y8+"F :co@ (tB<)@)"J&(ڞӀ:$cPAJ߿ʦ1 M5 c{l}'p-2-+ (ٺSKx9[) x$ :,),Z ;8AR++/Y. < n:' XDݲ(ڟTBھ4 )8.S10KB+{h}7 -8G;y<9F2!pSرќaR)6#?-}s48 4K9;OY% m]Dk*2űOFC!n(;ȕ;7} s`G:,)G35ѿ05 "—0#Hyh<45#,܄"T)Dx*N9BvTB+T5aA~C?)d?C8eIzx 7H.E!$D}c G>I&h tO mcAg1'3݈IY2:19 =?K T!ڹ6#ndQL:1KAk8tpL25~Lz0rӊ𝚜mCN8Lw죣 M|eIJBWq;jBV,͞nj1S "St1I6m3:r[$8 YaYepnݒң=8_%aOyG!4r ?ڬG *W) ipH@sQV*Ri/}dxbRā[]0Ax "; a:oqML X?%c ☈h&shGB{, iK.4+iB._9jl*ScƠ<}u"ubUa 7$mI P<?ãAu9GpdI,t]Γd`}\jゞB C$yL2M ¢OP4TGu߫bM.4ds[dyK;EmVUأW9SdCDt81U;k/,wJ(%i$ EJ'ȈCJKK3_up^"OɝB ǣ9}]5@Us<[`ƌ)kE>W4Ed^;eq,QHSڦut_թ$ 3:9ruOQS T[;8Û\5)jmT`tBʧORYi5dz10羖fڠ0$JG=I+OVEJt@UlA52>;&}*%޳3#nH%Gɋ*; kكo\&@=crA1UG/8]PAs^ag~78]MLުS4sqRV]x1 ,=dc#]>g4h;WEI6QPzu]|-\V@?2>[8l*>J8Hk6oKxW+hC1 PYE{M[D~ 4!>o?%np2u-X9ș`En Rp|Ke/TZA( 2`4@5~srQ\f5`.&YW,~jm jUv:߄ +[Z O~b?]ARf N1XjvȂ<5o}6L R%,n=N-n5q ES3.TIpO%Hd-<#vz r83j@J+6Z`;Kb5/*A=J hu&4Okx o+xZy M_3њ)ѪELʀٻa;qu`\=lm]J%MڕW9Ys7p"5k)wBeś3:&^au4r(.ӥla,4Rm0wmOk!ܰ CA0`1OeGa׼#E !+EH/K&xJs Qx:/á*D2)S_Ffp$| [~WgPi @kCKE+`VƦbT#1šSښx~Mi/a ='[{o> B2iw8 Q*ЬUf?4(U?#y%]pS_ay>x[ 8vW?Z|~%)M: 蓬p,*'?́,l*%kJ%BĸnJ!XY&-L? B 3=!*) Ȁ zIT>k%㠺!IN&/ҴΣ]0 dIr̪3 +b+d/;dHܤO% @)# Js v!kJIQ=&),ʐ 'SS7J2+.sPzRx KJgL*l8y52|-.+r̲wi B_-Xݣ&k#sg!,S_È {ƽ` !Hd,z$"e E` _҂SD-'uM0':MM~(AFrxc%+P|"\tO"%1D/sߤʪ63#(OY}QgԸHGx鍍bD7|'w^Ud|᫑[0&trln=3g[CM;/ 7sMnR(+Ae$g-y@^@ݰ0fh=r4F:ZEؤf /:6bK%-H RS)լ҃M\R} 3̝8D:NO6 qRH4Y#nH 2Dvi5C ՞[2Ut0 "s >玚 9y10f䖙Mp]~b)grJn8D l0LÞ' 8d@:uhDIբ@1y~b? I~ QHfv{dTM';rP ;ٌF7۔] aVE,qv`HRފ:LXJe# q %؜Cƺ`k!!Qy+T&.y̏p͙C4#ehqX԰0Y+Q>wz>u耤a:KZG0CkS]ʲTWqaHNJCqV?Yl lQärm]J"YqJJG۲vT\!d-UQ#X]F [)J;xJ zad5dڡ-Ol\eeWC_˄BGo6F- qcQ?ԕ\d.pJ3smRrs)A!U4 |b˖*j"-1) umqⷋWOe'Q<rINíE q5Tx ea$obys`(d24 % $(g?Y))+ n&muS8ʼn.m XLOJN!S. VZ]5Ø:=MޞuaQRdg2_`2B'R Ol_Y=E%)drqMvJ_u)c2h9s,K8k_v50cu2j13cXQ9Rt"CπBRu@*7!j38/crXSHuRCWS]5v#C"a4ɥkMzPs]C{tMgdG ]Ca5d\Z>$nrH}.pqt;gj%P!\LN "\Ab  4' q~1wo c+`ZITh+6&.p{B6QV>gRb$(l\oKGvCD%B !\ɪ *vFtDt".R Tj&- 8kLK]#"(Ҭe54R\N}BsrNJLzbcN%dpc+yX#Dd<υ̌@Ym^ILPfO*pi*">yG|skՋE<#R"%2,LFtPlDV9Ala]`%mAf?Ih-;%bPaSTPmC :]aG!"VG0tJ13/N HO*"Diz6!o>"X1R&,2;a.!VɣKnԁ\4ecϢ&†fohUk^rWlJxibODp qƝjؘl^e $uHaiTu"jMiaet2Fq:$6 {I*)0NF֍ GkNKrrx 60=g >QƄkeHZHVwD'&χX5U)" T>ꖦ&Shgz`arZ@dL'JG UE%4cS$ Q`m*P)4E6czMDVb֍gzh%·K錹CUOGx2)=k%c#MME -=ZnDE/Vi: SDе"h ק PM_DEJ2zt.}$Ni4HZHtatX向[t,ئX!øm)|!F 2AeQ;L4ԨnMAn!MV-V~C֢K :`Y!*pǔΐh7%wIKM0cML;<VW!3C/1K1uOG )>^_7C7l5Qu)ɫAzN7`ZtY!s`n#fO&s)mнI+gI)]`>{\)#Vx~ȀN^ Fgő'D >iӼVg9H'Rn00-k =cG;@:̙k̪)70Ap/,8I(D^OHZX+hu82l9eWez V̹ b(cŭ$1`N JJoY|F;ypc?3ʅiQdh0O5Կ}z(j3򆯘WtnX[K[~ X0?>DqX Al^9dCY >/Lb0 49NǴ[xl9}R)#Q4 #)R')#Diϛ5 &Vag"/-I#5djN@ؼfcU4kMDqT%`њ !1Lʋ3WK^ 墺P 5[[5"#iҥ9"H3ƄrF1T ίDm Cl- uu/3D^vG%K.% fXAZh{t)P@%P =("q*+GbH8G D1֨ڠqkƖ ^()i$WN NM= Lp#:$jO ><CS|F#kQ+-#.-'Ϝ<*9Q- B2kh(ΰp 2B.R_a-Ⱥ(O=2%&),\*R*.F !IAѽy u@gi^̫T*h0h 5 ӕHRxWpQӀ[{P%/ 0XX,XUӑ<*[AIf (;0XaO!.!`yy&FIj&e[n@F#>)CJRc0BNzke2@)8d)4H;,2Z{J #X\Ϊf(P9neU2c6_{FE9Lf?!`U1;yA+\0'.YB W"<1[ieG5&V3kB[`VQ6TX<x1O)#MB"Q"&Qw "(ֹzKfѭ\nA(Ȉ@!S ߬F"n-ӀYӚԖ!BPʄPgP(C@2NWdZ9§DmbGRCJ90 *)oӡJrWnEvCVWBPH;?J[,x=f2^ ۙHnsX r&YX*=1*3OmYnTz=qVl1% G toO̩)"\eܣ˟wa=-`1P+ֽ:aI#y9 8_gFR̗B4Tx߇]>{UR9sDVBCU}TduWeγ?Fx̊nBh) E3j2&)*A^@{ZOT%A+z- ^4.M5E(pn1g!WZ Mqi~ٗP9d(x䑹HRB:"Ft.ٚ];lU9 fo5͑]-leILwL[e^,>tI Kh\EBp{65RXvڹd8p߫PC7ơO@iI 5„rI}eb̈C(?JKƕU7jkNb,E[b@ 'yD{jQ]iZ6P`Dd5}2U3KZ,% ')L4NCijo ɑ\VW`RC)CǪ'HW2r#RgE:xr`ho9c'/*<3BX&//)0yՀIS%Kι9j,AX: )8k.ŭ Ay/xs);h4zEY2Ye#K%*0żSGA2qdA'p'B.pkSi 3Ary{@nD#(V 2(!sWvSz3pě9ytD0?%*局29N7G,˼/Cû)$ڱ qʿK'}#Rt%ǀC# pD'|'AEhk-ꈪ _([4BDQ$1Fdka*X~G`;s'6b{ s\#D\`3@sT9,{;:Ľ1][` 3$#3;cROCZI "S1`<,TrylA9}ik$aQL!ۊA:;$ 9Ji޻DtFL@6 C8.1G䠒%\3#(b4\ ¬"3F̑;B"J$⣡Ƒ??jxً2@9A9L|-hƠD= N!]#ȇ480 A6%6@Y۲(2% bt;8G3B ù#Q>XtRw0? ( rJ2*AA#HP9ЛK87;@d/C}0@].@PvTa:1TRy+jOtQ'!DЌ˲ZA4:T/A3@CjTEZT|6j;6(Z:Hb{J Q%xuaK܇kF 0 c²|t-Դ  1{Cej>`ɴ,KgT7èX l! ?EGRKԴ ,xr&:@>3c<0säk؝ KiUε-Gq,S%(2l:MAr>7hN MJT8)-5¦ ؜;: s' z'p6C!͔~ #"S` SBZWOt4[#cҲq 9ZML&H$R(e4y5MIY?꾩Ms?iFx5+hO3 =x LHĥ5<$UC0ΔZLah$ݲSؙGѣ!FypOS2nT(Uz)d%ߜjPJS#yEA,5R/C ©;2_Z u'S3yb^lR)gћQ",+Mj`}+;:Б134'Ks\Ҁs?LUc .BQKɧu`-Xe$ %85296P{ADa4ME`JNC#]ԇEX ӝӊk*(lՕ0`XE#4nAz++8bѧU]@ȴI\#&:ESXc,AG,DصY# {-zʝ jf[)#NszWe653PbcDՀݹpm(՞64(9e&>B"63~Բbj:[}dcLE۳^9lm95𜊐쪗bm}=en5!;Hffak˖4r+oΚ <o>2S}Y*l:€̬1[COaୌ#dY;`Tld}GlP6.5i[Abn(D㇎C2@2B>ϛbAq;j}:h* :fm2: _l*iCRO.i2d9}X֬tkT94 rnF8<`1Q 0 n"A;}~nDMӔ~ɧ1cG~n\mՆ[-Nh0SƱG־,jn2Av򚑕kAsX'F!ZJ8iDلpMاM y%:}Ae.[,E3}N6VIJq5 < ,#fv=IVU <>&if4/nb 3QVbCg`yݽp؛NvktQ;e9bףNBWNp2 FU@}o9L°:ߌIZ.sk7+m0:;Zt(=3N4eAi$q2sTjηYQ-Qf1Mט16]gXצNH.x -ͻlI@טbB/n! &Dpdm' +-+q: ^e< MIrplH6Fوk%޶W,^Xc.ntuR4Yt$@ $zHeRi#\L^9s' !QT?N ,F "1O7DjPhU GK= 5#l k6'\ki& 8SAkJGq}C)X>l  'Si,cMfx6="|^mGS]v C2`,TV5wuR ƒQ&lv @iH#@U$>&9ݥBH.*C(? :6:&& ҢPX+$=hޟ*H?k| PȚ%z<2Q +l~-tǍ ((!6:;Itp5!7:E\'-{08;* kCmL".[ IGbפOSF: OhS?30`2-3s|Bs@Jȗ"ilX m|΋Z=$PJN(z<.C#D"&:ӕE*0̄U*1}a6j3 +QS7KT+N2E&*NE˜`CƶH*n3.)DUtȆy)75Awƭz3P\wBDTbN\5( k*k!)+9z:@$B.Z OmՅ}O53X4q "i\\Uթ@s]]KC6Dnѕ%h(;T@ jOͭiBΟ=@cPM!b3b%/- ;YY&r2:ϝkΟѩw8-ttӼ3;RTVBHUND X ! ɰ pJeɍrؒ€vQ7c2-oe*qȲG&Q$=- 4,D=g]6 F\p&b !aGw)Ԕr"tQȠۜ)Y%#) SӲGϬ~2(ZSorbHb'@ h15a( Ȟ׳Gq/ S(I!KGx"DRJUZpx2 z 6Qj9l$6QQX7+*Hz7 :N)kF\pMw sdEI9Dt~E8!}t5GȑcDk(:yJ ~]|T E)%6o{$ i(~CBrZP,t[;-+ %s~zJTJO8HƀJyfU-8h3+ˑM2&T&0>[(d`̜ lPwZ)d ryPDjM _Z§ee+Jig^Fć4V(M7v49)}b"8$h\^wMx/+gD0Sa:GR?¤ھHQD^#t,ԭ9a|O'9<3wa*” `SI,,y Ȧ;ㅚQqNURMl%B@On"LLǦ_k OhCRT6i~Ȍ69]'Oբy >&uT(\c+DKcZ-, ! M]):!^|^IݪS1̔t:k tR9/o.ʗ:_f`a@'E,+xdx3Cd{LBо&>FNA1gmkfQk{x.hd TYyHQW A"bz_hw 8Ỏ>V0*Tˤs'TW@ţڑwwu}ZʽXv灸#(EPx:%*JOX}d~jW\yZܻmRg" cX|`ѣ\'k"&P/.1r =đw9;#+`5&` l!c+Pk )"޾Iɥeܧzppӧ8P\g4\i'|KP1V $?^`CU>6bAez.$Lm}V+Q*JUV*~ Io6"m`b\\x!ʄf ri`'$!2L^|Q.*dbKIS 1?InB|ŧ2BQtS@4 UC0! P"|e= Orw&[=ICqZuDR݆d3)L" MQ%#3ν~v|PQHhUȷQ2UI|Tcr6K0IVÔRV UMƐR2wvڎ7LgCXX̋VhIe4 TSKV $dn9f.tb d*le iB^B.xxKjt}Mn DxkKD@sLGoJJ8p_l Q) 8 7r+ rof䵹dyRR@/F7&y "2Jfp*R n"H& 4\tx,$}lc6)oZIIe(g*S fXcEz{ hXߐ_lIaTZNq ƂD.VNNB;lS) 㧼~j&:/6vWSBTO$$֐B%}6`pθoSruLCh8c#*_ڸ Y|l8T6CT?]k[s7cҥN􏔫=1TN_66.s OQoB3g!?#l##8\#^#ѡⵋ1P[Y7}vp3l5Vێ׏BV6ܐFuƋ$yV`d<hPPXaC>q,$ jgwezoZ4΀Fr4j{ +Sgl_J#X⋰vdkhZ-+_"YJp=LV!JG."SEyu8ZϜпRIj#}ܩ.8Z4DfrX&3\('reŖo/β~_uK@г&!VK{FgEAx@⑤~D@k((2I{Ծ# _AB-RMKQ@45QHt9J) ,JpnQ,)`RTZF(JO!ҨΙr\ Q%2Wq E) eNyV1R ڀY` Cht,SzZqS`89C%YI!^ ȀS|KMu42Gvy*[{X)m@}XA) R!T"Ct.b %Nt&c ;cpd ;E æ(j\!5h4%L~*:E(2%9 b+B߭|?9`%o%$^٠ŽzJ<)"M ;1:=QÚ+S )O3(r343 Kό SPx@ lMN;E!6P)}(H2>M܃(o+þ&Ǡ/TKb3=+.TxO ˥+SD$#-C|72^{bnȌ@w7!"\wV'?yЭZg AQRX0fJ[P/QCJ(6Ae '*HuUP7.R(f1w]{Kiص09uhBT{{Qպc- RCZcS܁be˂ZSX\_9usbE`IQč4L4JT?zs:;nxI3 bu*$+G܊Ҹd[%YG=j[V;w[fO?cjC(gi)čE/?#Yv\SxA;qU ׵8xys#* PHZ!i [տ;(iE2JLnE)Lѱ\:[6Oi]>,Ȉ7Rf?VNW"S3vɺ0I"ʓ#~/6]OZL/hYԣx&XJ2X% G|)=;NS<թ_R#g0YW6l~OPw[нJQn^pe1EW`'_:KAHr(bp! Rj64Jtlus1 $Ew]O4 Z#n" "9 +Ih;@-;rc0ȩ^mSy th—' .D~}4P6iP%"U0 _4c[94?UUuQ]B+%7DZ?W(ʡy'BY!,7Zy(N3wQ[iea=!z_1vҳʲf&[ (2wک rLަ1ޫwby$ ܡo1S1vaȵ}Fr6_1Dhwc"#\BOfDF^FD]uzXm\h/a^GxJ+m^cǫtLv۷t;󗝮1ZI豝<Оdtӓ!ɝ_5܍)jN>@_^*;+Odh߂L6_WYP!|;godlFPtGP ,.yDw;kmَ[E,ԫt|j޶ \0 v%bԓ=Dt_޳.e^wb|@W1 "27@"[ Q  .2[效ɡ 1K JϾ ~ ѫ"j=cSj&` aP-^= @+Q;!5p$ ڸB|!ѓ$(!<9"!}jc 9לr93A,CCJzp1[9> O1~ ;JiI%D 1$ -N'ޗ}5-6& r'DKPZahĩaĭ4@  b>5ۧ$e!e\y6 >OIx+HRL-=겈#Ot@d'-ђB ?7{[a@tT2Vѵ{Ulj d>M:[ԧXGJJX * &9[dBE@On2 4]FVFFkMMͪ)bAx dCzfthJ/QB..^~O:5B0DL<]hPl`RB- #ݻ_Cl(\o=dۑu-0[L I*IHdمj| p+| *ȃI / ^"8[PEDT~hX/#)õ)9V⤒ļ3ۈ9Mú]Ź/ʉYZ6,zO{ӷZ)sLbZ*Pa+؂KK.5\ֽh-ff'&}gԙ,ɚT$SW)bTmӓW嵺Tswy~>>Wྠ+cD_ V&N0f,+j\^ ^վRڣ*o t5ۚ^V؛ش炌PkʱtbsoIEP₻  )|(u֜qiPel_X/㚔KW"we){/ )մE{ 3FR5PĚx( LÉg~HVyjE]2l]l &Φ8ԉbIPxCJY[_bq.,V<]ĶT,+Z뀫P} CcU4yKMVEW1CpY;d<م:;AKP[h4}=g$VEŵձ$+PC`}Mm jdPWKYHx[},!+ȋgj2rjBvx]j'Wu޾Si𻿒(КvW=]T]U[ȮV)!r=q-=tɪ?IKY f~Nꑪ$kW!Ri.>`v٥v tv);G勪~-^EN7A\)xRL-/d=GMK|^(fqKL:;vNnlFXDz*1tEsoSJO3=ƪam5'?Me7.](-)TPF֋.jT`7$ C_,Eа4 F Ѩ{-#hr1Hc@yP 3A_3yT. Cigb< 3h,1A&+Yp8$!F7{ErJ*94N"b/٨ᓠۣ؋5fQS!F$yjpQcd,cR;U7CAp;mngG%7mAF&#|r7HLըAJ  Ć9ٴkhz _?DPYWB!1p4wc0] WJph$p%r5Р͂ʭȭ! Bɀ^ +DbVs XJJ'fiɀpZ+ ,>,Y bˇSrW;-W+= cرQ%CGr?h-?Ng3_4hϏNXcHIJЪj@(L2!fז]>& eJ57QS1[M>W;*^je:=7]s*,&X~b"{*䎬! Tԭ [8bem6Ev-l($fQ4ڗV)ݿ[&맺7"%Z9;F5=.W[ހȵ;~ى*M(E- +)DQ.LWu@:ajCfYmM\GP/)&TYcf +pD\CgXK0D/påPg1EPII:p.9=fmX+#$)^gz;OOc}&FqTJI,u3X)[J*\Ik%pXK,+̎/b%c'AjfD0XeQ S [ "b |X( \-sӈy^媘 vxB2 Ev@ {[V` |II?Vqjԋლ5UB5`r*4HjRyem)kͭq^r7NU ʹC`aa\M?p3 $.Qv&ڝ@MB64JzI+Uq쌌!o,S\eE4lιk#08})AܦieKqL], '$PLm%Ztg3Fr0> Bl+ -hM{`>/j+ he9vS$(%^ +D'/Be<kܕPw%bXwM k 3(ɎgڍiUlJ1:=`i:1B8;E.{>  -FBR}=+MRЛLWXegs9>LpAX:B6XqlZbA~UT}6JΖuϘr҇9.#)y;R0j F03H%.-Yc`E(+ϻAN&>4g!P~=y'yXE>uQZ~GŏKuUOHê^(Npc/\;Ǹ bLhY2b[l̤# ͋>(!lLŎ2H P̸[bVMo[arE&[>b\Z'K<<\+N9 n⥾!eI v,[g$3.qbnMOe:<4Kb ^pBkރ$V3ς{͞l@t"(> &Q>LHAޭP͌ Bƞp|t(ndܯ'{ *H>B PvRA Qo,lk2o?d'c4u2J@BY͟*ŰS,ү 㧔/)v}tq! rwvZV(*m mI6%Qr,Rg6k+vI@OQZ4ŦH@f`'oj1*X&+BL璇L1}rĎ2B&^|e]!h5"$rR77s `ea; sRO6p: tOD|O͐|h2Վ_8oR,*>AM#SFƮ˔8,BF+.ځ!XތEp r3bbzˑTI22'" q/P /2Gԧ@eڀEޱ:KW R2H)S;c^JP6JeFLqO( rD-FLȊ2RMSF3vsf=wdfR,x mVt >%r ,Р-]礮f@lRc̑9 MC͈j;Ug *GE)^GDbS46g NuXnȐ'oBG M,FjzUgB!SA-SP #XQZc1i;@]*3<ϴ;)A%\zAetTICS)- tԑQK0O.15b8)*4Vv'ԺUEE` Fl fn掄^oiGWGmSԳDLB8P]z!DzʇՁ[)RnHT//+0!FӅ}w>IawhC)(DRfq.fӎS}7fvhQl+R(tqCe]*1ь$*w&f-~rL.TK+#,>"j Wpk&@W]x/nc1[+ce]uu@ MqL2V&1g@j-kpYqxae90( kƉ"s{jd&,S#V7s1eZB+¼46JI5X|G)p@$wgGU5y58пxal87(N7fj*8%h$f*9'$ZvI' q!bɓQZbZqI$< ^@D4Д׉b嶸36CB$|0TlC\T"0jm\M|]bjk5/7@JQ$*3qZMudV4Qb fX{ѝIz%v.[̜^X>B?3FM6 hv<%OdhE'[5Ӏ g{ݷ񁫜eDRrPR*$ԊԂzPBzP:"S37OآLЪ1nz&uŜ<̈́k9Nb]Drd{ nn9H#, aw*_%'$>C%F֛1<44 Ny{Gڤ Wk!o1Yȍ*p$"p%$ 1_89جq>Ym1k gBf;̘:[C7% unS*7kU^}O`A촠umV!$Jk4j$nY!6n- h͖0ݼvCAP'iàrrYuɯQ }[oVĞQ@a7rVV v]\czQI\L ikѸC+=baGDՊCtK]MCIvٛ!wHpcN A! Q@(?c@  B %?% 19(~C_ϙ.y}Gq5͡s8+$1RLT#5!ejB,ϺڷN#иՎ)6B.0X}aqz%aXԤM !US^ Oƨ5H}(i 6"chE+@zne2)ϳM<ʑA1/ q3UimLj}ݙ`QF^ܢ*ͧ瓱04)R6ָ8  &K2 O?h6l1$s4Ǭ 񢨳М;0DG!ۢKHAO PQ{fdJpKZ"Y[RfR=1*&)ʬ9q"0 G"p4`# R$ʧI&tP72H'Nd*I0*Qk7KT)_I$QDHH 6~ F:qX-I14f03X?qms ɵu}KX#HmW6c Ivth|C6qa.%^0J3)<ށ\Pݸ_Au*0leIՙ5S]PD":V2`"гWsc]39}SG`5tA,~jL5{:Da GD-EWMo' KR޹c9BI NK;{O 363}[kJ[ǸU3*b/ Kx67(.'r#\k;!9Kz^GδmV/jgJ'ڿomU5,~d,ԄDVM;(K1D"j milRMcUʾð˺P&DrA-Gr"ҝV*j$1^(e&*ڷ_]8! j=rA"^z3 66PI.5ڭ(V?!HtՓt.ZGA# l hȦ%԰IX]#`OLH$A\dE@VIOPր@1.d av$`CPBHK8HCM4;"|Լa3e!L&D&Daz]#d~!IZdcezĖ9]BI-8A>$"̪IR ʊn?I5ŐL4Jcǝ{/*䊌qT[L:ɥ/:aU6+aaFjUf]T=/\-R4fp-@LKV+9 %|Vq-0YJS04jMq k O \+v$1V'gqq՜i^Xknk4nv4-sS6!9M 56 ȭ+mQ^C`\QI|TRp JEAGѨvOڣTuj6U B/8|g^D, ^(᱈o͈AU6d23 JYL>G7,A0! ,[.9 $ՍjGe?xsl0O@KGg8A#FU5BYFu@IEM=1jjvw>\$ݒk:պV7V'ƞ+%pE44g\YOKa Q֨1&nA U3z.%.zWDfxq҉/~B9tj+͢[_F,2e2 Q {+f>#s`=Ƥfظ2PATsRPαFЋDs J3^fpaƾY'~(~qn\jz,MGs~Ygfapch2:>!Wև>XCLozM9i=Z! >VII)N_⦎DSXƓ-rɊ0*௒M*kʢ$C/jM& }# c]m\#=L<(/CZ<{A1,yڢ+jk2 'щCV b#/+Kb1#K/8 Bz Ä R:Y"3t<$9GA=kǙ}.̻:ҊbCԼHء=1UK-(-CqL~ I.RcT!Cy"HV:q:.F l%2B,?ԣ;34U@(@3Ê4D0ڔ,Oҏ{i:}sSrMLC $IA*̫M?TO,<dRc%;LMuȾXs0QrH,0b++3IǼLZT|}|eEH7U4@<*|ܬ {Bܷ2]EU!=9qH*.PC Ȏ /` :TS[6Ъq> ITRTׅé:bT-~$8Vå x ΍B 3] tL$R>ziZDQْ: ؽc&؂9{KẀXnK[Y#JV*Cm[823HKE5 gJ^VZzUY s,W<*@ Vݤl[,[ 帱=ŇQz4Kܪ55/2+eV.`LXruBpWJTC Ms{l9oV(  5-&Kh|]Vx `R.mVPd"._^( ScDMcm*|JKFB9,:Q]AmټN8<]R͠]٭KF5Q~Mē#td$0]ñau\($v%u++- *vc=bFyU WuR=d[8S*J~ L :R}>S@,K@J>nK&jRZRC *u4 ,ߌ?3-ZL%4 ΢#-i%bkvWkOi-I=%ROqTZTJ.j! ڨUVUg"ث^#Dz8UܳsJ Lb-yyQƶJ6*W1V]\+ 6m>|6:VՄjp6ړgU֐#Ztn3:%ՠ!#GZ8]O"leb;tnj 9Ľ|Q(>[^C"L@QMb ωgգ:;EĖvwCeb@j-cK 9168JCC;%&:"X|;my*vdi.4xu/4IddDspSR03H/wGLGTd`qb9dLu.?\ ]? *gV+4mW:T1ZG#KacrR![Nounw xu'sugY5![Xl\x]B"Յo;Q? P0iGV`Tr$DHDbk];RZjNko&cL_ZiWadnG¸V^yįʿ hbUN%#|T/W'.%czLs@gQ 6nTL˫Wn -JeKE}J>FHp:Gd63,~E`j9i_hˎIANZT2X(cxt t &ˠv(Q {7\*/Q1Km;VL,!ډ[~;?(D ?!ȃ$C05BQG _rp$-'}¡@iAxEBE6 Id$ wFMx [ViM KuI<a+d. C$W{]b+H '-QPk6!TyzڥmDm̵׉ Tg3Nb{—,Πwf;#@j]9(6 0n{]RtۭG6ƗbJ4.P.#.ɯ 4ir!JZ⟴o",(Ң@X"P6/V2(4i$-N$<3Zl'gIH5kg i^AW@̓2' # I9F%5*%/.I<%R4 J?`!\CRr̢!ڎ;DrUπARBϥ/˼mFɰ1C zDK'UV]S9zW.LmzN|Dȵ`MU@v EU|丶DX{R炣J^9D)ժ(# X0"Y45e '*CoZ*n:u?~T AITp5Oj % 4hVoݏO@SDSG⽨Jڗ#!ˋ=ߥ G)wiY @4JS9K*w O'$qhuqy%Sp9;\DqKYe$y7}t+3%"Nfo`9=e[g?T:t#@`OCTBO@vZd?! 6"N>!ܑ=DwQ[t OBV\xUc1Fjd%IJ`M2c ԢrgBkT&}$*8Ԃt'Y?DT[iXɔ'aæ"dQ%kZȱ%dc#:(v:b2Ԅ vBS$ ft,Xݑ)z 0Yv@ZB(~sӝ$FFbԛNW1N G=bX5d3C7a~KfD8$]R%٦̒x$Es[pJ"`%Q}hIJ!T@>"ͺh! vE9KɄ`OK5e%ҳ ^*? լ~|bp(NDIH<K^_TbIw8ꐩRPMv2$>^zb=AlLרQQ!E!qa39W \z=JsY.S2hsK^l?= @u=Xѩ$ gޙ5O*$2Jj4ja<&l<-ݺQhdlŀȰH#+n'Ҡ ^DeOSt s:b]1?YkׅE? ~4}!0KtJehHʻ^G5H9 [Tn,a1 ?F (6'%Dh` l}Ն7Up*&%kli2&AOGiWm#º-2|4p3< |g9DVAjpZC q9 Ň~oחQ̫Wi єg׎5pG_%>CAjн:YQYDUZ2Z$bI&Hf ̿[.钲;-tK ͭMiDjPK,YMCxܛs"2R 27bB(P{2Ric%R)Ӌ-ތxƒjYZQ&uʸ/9kd9ߌeqcz^VEbQY pk]jursH!sIFb*dH&G)ڬQnʸF혛3 "S|}3$nHw a7 Ε- <% ڝÑ*=h@<`NoaS&?pQ)owzj83lx{7 ,:sG[;!7"q?q{@VU`T#l t=*(} J 3oBW6:5byK]\2 9CK!fxGGL?On&blo2L$Cr"${Ԋ5vRWVnE숾S>j+KXWg*(DH$$c0O+ʔuCp^Po"%,EJLp pcx.ΰp aB$$$WpRp Dʢl zoƜi@NE.ƣgK..n#Ī$A@EKr*2brpl '"+Ͱng DShVLC(&LOF.a ԏv٨ .*tΙDF,(j%lƼBO(rRtJ6kPp0l `)+篈d禜6 $L!E\kR f{ hZL&KgO$`q~Tl4PQMHZdq#Qj #($NlRlmIgw$ &ZXni$+z 켗$jZFp.rMC,EЃ+ {jkS-.nv?%XM͸(i2(>ܹ"%1 *I *x:#'R'8S3T' %K+ 6-X@PH`kO" >& R%!.ΖAP gvhT%Lb)LPɰ㜓j):$r3v@`⢖/z\O!Mͣ?F> R3e!dr+Vb~Bp""- Br0q=dt*v^m#Lqc bO"R!S̸OkD(ƅ"}F6V8\t0ҍ-Bpr lж%_м̘IJ@K~bDƲJE5h 2L1$~:B$g8H-=4 xoRR(cn=I$,Hz  ήH5_g:h(%XO2e*t贕bjuQ{)ŽM$)DJ,{xQ: J$NRu*& ,@ !Oq "4zgHέ4DP8\#LG`<\Ym$2I*NW@mavg(P52u$eD)ABݱJD;%1Oq.I!͂p<IMN\ꆢMiS1ƥvΚ jgKsl$%0: WlgALB#EE K!BL IJl!Rq nWRRx p<,\"p-4MƒsTt=ϳY^2 dUsd  ǐ'*fnvD {Xr?zEqHrm*T0:g@"IdQ(J)bC" χ'@o'e=R䀜"Yt0ֲRG2xdGAE1prVxL&_'ゕ,hT;qF~cd8%{5…)LGB}eCZnwPI%uF"kzLwmAAfn0>}Y씁K +v8LTĜل0e yJ/b4ke$5IXcdF1Er&V:r>^<&6Pa#a;Y~^%Ϋo9+[? Pd %1INEjwF%z[+bq ?W|HWNN %s@̉=ح@'L7/LwZr@p&0oBGNƏbEwfu6 }4w@1'Bf0{A]M{7_|ʦ'13_ J빇MdeW?:a 3*wzq C6yݣ<#<ש{ ͖Li\*dC+$co@/ [*oD̶HbDm+yWTtb-{4^}n*}~$;a4 ^0 ~#~x3dC(FYPPB^ ͮBK '`VPGBK[t2{[JNՍ̛sbTgA2zaL wO'uύ?o' :ԉ¯5M%\l)EGz]J|Ǚs]1SSIbY/ώHls| m)_u5p4QK6ɜ"et]O_ҹa@ڗSr {:7x %ˢ a}i:b? P P$= 8\*c@G@gK 叹tr`"p ,L咸\V\M`\Na*Ǧ8$Q?q]VX]AdHd6mLR5\0'Ʉl";EiPkq9=[q:_rcX*/)0b;xG!uLV?-a BeZ3`zN":4 AZԂ=o/;FcYA{On}v5\=O#i((%oߣJ"'` j@-fnk"põ «8-\H*˴$ LjzX˃%oڟ|; Zp<25Hk~P#Ő",K}"<"O>%h+D2D0;w!2#ЩLI@M]'N8;L#M>2,!9!2 (02ا Tlب.n;3)*MMLɑ Zg /.TJ w0p|YN7^/$X җ.,m(2|z~'zFL03=;v+aB]PO ǨN8-c .K`=yzLߧ Ç+;뜢2cR]M zb^(yLԉ#mFLӭs/, $Oi"0AxnTP0 I&'!r*AoL4 $U'"(*`lDNgRc[|*Mb* q}v[lM 6gm\dt* $D>/V-GKr@sH;HZ/*8 +8VВOTiw]pțN/X VMlAAaSM=GR$yB9+S~Sn$iً5x:8],UZ}K<z.aeSq04b0F>gf@}@ <Ӟ7w㊍omi #@Ahp5ȼc*kAy:9zG×Z[ #JrsxV [SGHI  ͋.YBYϢ_BM-I,}Y:a0JLWKfhɢ&""n$2JHEP ܜ4_JoAޜ'̐DiUdqXC %^&DI:*;^(y-ʏݚji,3-!tjT#%%M ( PUԐhTiDY,?jL޴GLkE@AZtCv=]@6=5lpkXvb]H3 'B2 䔒 WdT1VCY"Tj|;:|eZRtGiLxGFB̚BD+?Fةa4dˡh&|Af#7"eQVq XYqTfˆYʹă}{bC'+J)2!R;^eQL]1} ީteʘ-V OuriEOD̎|5 ,e WgyըI# eAT(y'W0)A#N% :ɢehRu^&IaÜV MgjBp(48KN5 ((&sn!u5 Vmyջ'ezps/^OwmD#lz'MZT[SřIcT"D*2|@zr<1vH| oX}P˹-Ҭ"[ e]u܋XoDh0VK)CChe2N1$lb,ZT9tƟ1y|vy3byF'4ԘW Wh}F-ib-OhMX AP PV~LvM6h-ULg!ߝZ\ c8խyo*Jкs 8[j]Y b1~8Pyp`{q5 20X렲fmBx)}1 c qĖpߟq|%j7)ꢡ).n7 j1>Jӵ걦8% r y膗# j׫A4kO"K 43@c:8+9( ߀t+05n%l":0-(ӹ@~YD'٘; # 2*+B<7&/Kw2s*ٳxzK-A4 Q4@,2'9=\6h0 :&> +p~#,jT QP9/>bJĔ{p.7n;J>)ô[7T,TF%TfȢ6רR CYL괿1>{.;5&DÀ& Yxq7DCӷ( D[]*20&[Š &+'q <7RtY5!/y)3B˜5&@.c|C$Ƿ9g* [Јሉ*1(Ӎa~= c]"/DЙY6 MI:̒DKِI:DXD(IH~,̘@װR6W_8zPi2<̠J,G*N39:)i;t?7J3͊$3b97T~/a(} -Fx$J t#)F:LpPyͲuNcG:ϟ)@үsR<>8z~,h<)DkߚB>SZσ> z2B : SzkZ"},{e?a[5;U "zD14J26䶇ۅѣ<1Y@C| &Nm4healU1I%O44wGD;B}M}I}좕 LqSLM18õ!:q3}k$ɣr+qT5yǺYN@ˌ5iE6:{[b#73Tz:*|1xH(iS*THǶP$Z(ʄ2گ!5Je+3'1x!ȁ -*51yM8}F$ L}jKz;. jK,KGN$2L&(/$oA:*%d(xকN9|B(͒|g&%=PX %CT SYt* wFV|K/+I1+: TZ"ʝN5UGh]5=FD# 7 !:Kk0J2\#݃YFT643@ͷ):I* 1 Bڠ5©1X%Z4K~XR\ϖQIӐy5eI1<]U]5#td[QsOm)IX¾q\\e%s W*ݭ[̒B1#73mV -l3QEIB) ™DEl?<S3"۪һ=ӷ b^EZ+ ͈C>9(*il⹙NpX1:L',ҍ [¸B)%ڀ6;< 2&JbL][ J+ hLÛ`@a,N6S65֒EC1AZ-# /[h*iGQeC"Z2+UH 'B]œTܿ튿uI)bq+% ᭬\Lu3g(&r}C24(לf^=îM3"lkIxER#zs.ֲ2: J[j 3~Y*`Tyʓ#xQT>\N:݊!6=@ ɴZvɂ\2!:5c]P&eD*4_1-j}Pq=qya$v{S* {3~{ʡy($?Ȅ?f14D[:vR)Si8hW i`Z)_VCo<yD>9)6ߩۿ܊ ɤJA^'+[> ?`.v">$L'"RaY%u;C4ĭ' ֝&&JW.,7OX[\;ⶸ n'g]L-zd?FQ-c[oW5gx=0 ?:vfʜU@"O_1B^CQClKo.ӋYyRC[h[(A%6\=TsI8Ϊc c2st g. [*r9ª\"5]DeCk{/٤pab#ِ9dQ64H,6?X|+Ft FT;$@NY+SHO7Zq:Gd]͚$ >Mȶ+riUF!@a`ѳ[۴򖈝wX:ߊ%L@ޏ袓0f|=tu3]W1 [=(;ߒV^XA4f8/gt,U Qqg3w |iu ~X#\6w"ɖ~%*ޅD& /G,lI&(}}"Þ+MZ1RqzjӈAu؀ P7 ~B@P4 _7VcPp(=R<B_9<*b<'7Id O$d8qFO8@]HJU KtX&@(i[z e@k+g` uWء[dz V9yL*ߟb{kw'/K,{*GW '^oEa9NO0˦'@3~,>/濢h.-t̀'Pot '4N`D>oD!mP6Ȫi/kഠM>.|D ▁mz3*ȗD@JB0ˆ:Xӷq'R&IrAJp@hX4cBnؠ @:H);$C(< P RT)4K: 5t*rJ%A/#3R{ 9,ʉKB/˯L"!i^J/R*h-"+r@l)ʏ(]TĠ #2 @4%(^-cIP/~&5kDR6!I`IssKo@4T<DZPjyc(@̧\.)}MQ$#(ԽdiKmPCRέ4m*ջ,=f;UKvZ"D̫!NnQvQ/yb툒'KH[};T/egS񭍝JۂO}<}UlKO4Ο³`Nۆۧ~وohmizM(_"{0C %uQ´LuUM>Ίqؚ/`t}r;?PrDZnxvye* ̃Bzs%{'=fNRiSnj@9[h?Ӫ)|VOfJ+Yڃ(77]L< 4TS: !"^+4~;RnJnvP &X.Q $ |u#)G q=LDaךͅQ^8,>il+ DɵkTzm`~Rd "gk8xVyd) (,#7em:RnV8;6TϡB9[bUAҷnUmmgcr-҉e4Za U$4WBaa7zT)$Dn|xxDr+h^P"r9Y8 lhI>uOۣHv{q=ǘz „H`ێp&S*"vJdp,YLDz9W2oeŐ3Ӭ3B \@,f\cN VuVy+lZØ,t=N="BGӷ9킊$!l+!+j18UNEj^,T*p:{V"T:jUe}@"m[seuG8+BXGIv|"ݺIVT'Xakw[vcX:k٨mU0=#HR K̘bHN knsU}_^f.ݗSg ռbE~(Îa!TͬA̓i8FOM88fV<_,2FxE @pUjA.L .Dp? ϛ&gĭg(UiCBV-iGxDk:sYHOuKN,4+|pb R' ] z6i&0Uљ,] F͗UciG_H(YbZӷ]$?4XqcƜ IrJmeq8@3O(٣[MB<9R4Z;(dB>V!EMGzW 4;*u\mAͻGYƵ4*X͌H/v'h.yZnbW$sczmqV2UtwԤ,R>'g-c' j.ꏍv+,f.f N+a* +e"IBA.Ba* (J$\Rt $jBgbb䐶tO'tӣ\"*K*,B$ut)g?R.*=҃U&Ï B fP=@i $0|BՏN] ٧~b"|)UidEɴ` ANJ?X>I h6fN}g.f1$@} >Pkh:y&,݁8Gjh %B8~b(Œ > Hg/DKqp`nal<,JJ kj""Kl  b! ,?j#%V /(YfRPox HQfRx.K* 4ʩ־0QU%b0`R(fM$cb*"K$v*XϜhڮ^$F,hhb &/\(ܱ P".~`db'!@Ufx#Ra/tz !%~nz ,`Cn-$dLJ.ƣʼ<0S$p0P-+  IFfK5 )D -!HL tp G$H+ȝ³b!,#DR3Dg)1p m% ̩?3t&ވL"+1 M1.\Nɜn6rvfΔ*d\AO|pSfA TBC|ʊ 9qrM3=! /Q'@@f]\IGGl(#EEdQ5f"N28L%60 *TXl( '׭LԊO3Mlp) NJ j9Mс>.0|0 MSNʒhR@RK3NcnE e Dd)Nzf- b*uIS+"*Y笄nGvJwPPD<4/nCTs.R<+d79r3-U.@a[UCd #)0a tqKM# pΏ¨0Èt(FH13wrlaj[P~j8E^\ô@*% wHhl*j@ Vj ǭLS?ng6 =6S{4ncP  Y/qx49.JOSK NUwt5I[XXd ?kZPDq౷n9e-4̴x/Љ) "M} C'-SHQG;32LBNpdȱNK3 :& E.L~"L5D2 Y$6H@""JHՌV)7P2А&mܬ9LoYHl=hb2֠Gi{$Mr/X]v]HCzUh=RcZR~GbWEso:Ц,$؞F7S}P$d':ˈU{qYa8fo7@6d#KhELvz:֯VQ`%HvibgN#Me8iJ-v;nWSh^#/Г >$4} jɢS)215g+r&kלԌ>͵j#L)K]#Wzs;xPhaʟ`ԍ1&,Q) =[\%V\3'W'rrRgGn3,2"!ʑ<OG!PD"~]&8n?id г]lSN$0JyԪj) ]?I*gU2XqP#SuD(Zh= Oy& C+.gR녃IFeՉT~$e~ȹD)TEo:ŒdVdN A]1+4BU$ve)bȽCm J D12euҊa-+GRIOiE5I),E)?Ϥ+5SWh- (Xޮ&rRU("~NA>}65Py_uGpUcav9000*uZ4sأ  dGÝZKTJGmIYQ~.Q]J.UdXGX]kKݾ?=4tSSeM$M#L;GϜ]ڶi"JP˶CHk-oPTiv#r-i+PR5f ru#Ɯs2RT+W9س'q)ꁮɗ!WnѴ_)(6W3rdAWmXkb8:N4uŸ(Qf[^h"C "n;++rBSc!X=A|~p)DEvբj bI`>&D-Y0pTP8@KN":gBp[-\y-zm}WMK ^}BFNjnUO)WA ]*ڔhwB{W8sΫr 4)R%z~RA$u3^l+;vB=#-̾$Yvpiq;FT*HmXI1BaԺQerbvӾ~&]3<:Ν蕛H5%x|# {{8Q#-9!!#SI;{Pa(.5㲜Q3Ⱥ@13 !C)k ='ܱX R:R / ,cۿr 9|#:G0 (4㴎b@&CⶁI1`>ێ9X#0})_⛇!:6{,0aR:*D0I^"m:'<2~){=ұ@P9kCIW$͸:h/ɱðÄ3 kpXA[:jsCfˀ1Ah%~[J C ssYk/X2B6_@}8‡0ɣ&Z{6k"$3G{NrG%D9(a:/`;$9 % %i,J ? (K7{dv=CX skDj2"U(~*n`$k0K'نa3E|Qݻԕ?!sh}#!N1 2<Z 2˸M;; {Ã@˔kHA491!T-t (tlw3/1!JP0a Kz'#š\N!!U%EBA;z*A:HT< V19 p|BP3Erͱ3*u 1ūĺH0`4t+C,Я>N{!ADC¸|K|: *9#d+0T, DysAb"3z5ʸk$ubUǔ1:+Q}53 躺%q5MD1 MY`FE?XťP.P?8q?Ĥˏ5*.2%3 7 7K"~GS2[JЂ;-U>&;IPfQ#\ʃ9 ZՎtx{m=!"),B`3ˡ0{@thV5â;EQ|!1l%x_ZOJځM?3TtJC("[ʎhI<%l9OV*`Ŋ 1JD O|?i;D]RXA ,u\|=1d#/*Ry[lT)Rsu5R¨`yr_}2ɵI1Y1!r!3ll &p˒]c1bRD4|fIycB-;[6<1a,1;S該MNEaR\FAlCLذ؈{VAR;oV=E8%FZJk&zɹ';mWOyM-140R$5\ ձW5lM,Λ~e8L3'ƽAꜚc 8aɥƉ9:Xc[qiHG'lr[wG* *L. _B.{O0 Vd$gO;Lۙnu b6`ɱQe,A,Kѳcf5'Bk_pJ&c,11ƽfvAiAo&Q=)P?%q(VP2QĺnO&~Sl)I } #~,--CƽfUCD} ҭf;,msH[Ű@b`, VG1MQg]M JN1L Z,8L<0*O"$n1s α]wAkЈփؚRjg1q yí9 --("']ͨ(b[_R[*}V,r":ѫF':O":9@G#5U%I-~k X'h,ﳊL!8W+-Îjqt#GzH覻$ūbH"G8]FԆCXX$` 3Gڬ$1!̓0*Jmj,BMހ%.R+*, S.1gΊKڝ#8 t`<$ !:Ei*) $`#A2čDԗ+,0)8Gi=8K>"Į޳4>0rD̛&lcP rA TyZEDUR+ SB?)phjՕBQ*b@ڙNP%.[CKhqzt"0XxB)2hס kM+΁?1bWʄX(ø-U? W<|]lKcJ:؀C''iOdS`27q(twc,ɕbG*8z?j3LnH?Ӡ#~ LR2vǞطrG][谔1  ̨֚$yx({sp Z42 `JZ Z?3y=k+#PS$!tkUMMJNKH>Jb2s[<{J~c&%N|& PEշfnR{c]VTU9$ѡ#$iꤷ6P2Y{DU(LS8tv#dyGa#rEzK;x(WsT-T' oh0HS[ZG!]Nm'yPJk3,%>d?H?icm6AZRN7+% }`}DzĈDe콚I,I{ yԑ|$af$!-k.љ ]/bVz8氨-3Ȅ*P45O)Y,X#E2IVYEjqB/g.ALH@r5S٥3&jH1TToU(iˇ->Lߺ?#sX :x`_XID)uϹK M*Jnԡ6`er))RT6֟bh/QR3ZA^G5)g#|ThP[N mx *z["z\=) ,E`!U[lX[ pRN)[; NZׇ9Im7IId(I~SW6!=UbE':sX?"Gւ泭I'S6xw L@ n)E Nd)lG{>OfO,魰BdS/h8We+VTQ<\EO's#’fc+j^DJJC!TUX)78BK6Fy&-d㬀>Y Wqd.>Pr7 m4|==q2Ma r0 $g`/oE]αG%67O{bq;7K|6)K;˺;bbloQuKUpCT}V $Jz9r<ħGgayz1mU;{$Qڷ^V[O'y:Ri.44=<܄M()MԘ~J w {WpǑ<+Kޥ$C:7.n3;Cu0e ,H?\@ ĵcAH<խ`܉џ!Pif`;vYxGT'(ceJLT8{p3}+209I'̝6sz׎OFg --K2uY7r.MʵkW4. Q[rV'be + zQPz@ z5 X,NJk\)b+DDo7lJ7e8#JPʊ>$CN",I\YIHNܣvcDԔm*@*B4-1#޾lͦ,~T>N*,Jx|(iEiwPfU`fjnyGvlDnąFH{P*0sƞ"MRbd&V- 4Ǧr+!Wv̎ˣPPf>P*0$hJ ojG+zMi$Ǩ-, n ej F ?DrPf1&3h~ZF C4Ȯ-Ȣ#@ UNL#FfWgZ,rPmlDrRItNHD7>qUR%آz F(J,g, A$Ħ,nJ 0H{n2̡IgՆ_rh^hJĬȸ](O7') F Dz>F_bP+˒3xx"I0*΋/$ӝ1^߃R*,ń.` P3Od<8Wr>J㼘 dXOr)IxtK׆:'Vu׌d$t[!tG%CIA&R}:Q<}QO.)S&ub8@kZr)g#j/PePz3PT.μ~d+|Jq4׏@o4.o$\4PiAt6R @JoB~pg-oMW83!G" 3%c`12ffvcz-$P*j1551젖t[@g%<ǒ"9b":&eFҧL*"umF Rf#ɂSQ 0G쒄dDf8bEfo"D!FEJnf1tĞ)r|rp2)SVU|u-58ll->:PZ[1Z5jɔK:ܧ"1N( .xUq2L)RL@3 :F b w=sT@ GTelp>!d>c@Ob%$elYk1>$`NG.YgגRJPz~l/-46GeO Ӳ,O*2%g> r kdG̴?0-DWjO ܵg<[idOmRe fj,`AT.Τ*&\A%,eBQ+j!Ǝ2DfW> ,k<ɺ0g$rRfjgh `2̐qc_F} ec̜"Q)4t0aƨ),!XoѰъq*cf(85tf/u0)/I)`!IyS[dd"iQԱ ?v Aǣ_#^5fYfјANJc J3/D l'EO#8ϑwdl*"(sJg+Įʉ&}U/E#t8VKplgَlULsO2]GъV<#˅Nǰܴ 53/PRWQ#V)}NլɉoPpLxs< leLԃV,.&8pOanJ%AG,pDr 1n1-g o)fimZeo4D3~wvdS+1l;O?zl.cLpu2@|mqx@noDk%m{5 `\a%PP-yʹU2FCAzsfTwZ8XLܶ8$Vrv֍o3 K.O{VfЎW%?w~_ QU9Zkoh}m'irqɐ%Xu'7tj8BRz;cf=wٍ9IcmDjiҘ33J/geJOVrCq974ʮAvZZ4[c~$X*Ů'P-%jҼm/@VJnxX,xH%-"2% |J7yk5]hg R+J5dvkDw!8`cFQpi'vɛ%Y?-@ϭفAcJf'ux^DG8#$5Q>G<}GWv1&툆m485VCjRx˱Ճml@5(O/edٗpwyznVlO}lQl ,Ps+1b-˹1+,K'e!V!VaA jfỰkg8b%f:FR䤜B M:[57n1%Rp oxg،P0 A[dG(DPDG.W׏,XI앑È4RmXZ܏{3yF -$ Ԃ5>9h _.e:, zXDCJu/̢h4.y;٦795[<QRC"'#U8ur2v}Kbs,W+&AՔթæ%fMuIa)ܨ"z;M@Rۦ(w/\GZ^p*$;N,V!ʼnB u d0)<&7Ù `rԡ ٦Ti!2rY {kݗg4y RX֠03~(j#J?Bo[b+*a(C¿Id83 8Jz"Ϻҳ6N B-"cV3 (kL{)2%OP>8pqQ/[ CP3kHH2,0$L.7j_&6O~N,9-Eo8Iv)+<&ʜhDիbLs0+IHE7CO{Т,H2IIvGiA ~xG6UX0ɖҡL{ˍН4mF:zl ClU,U[rUsJ^C pMԕT^U 0%Amt⾽LU8>l`x#4hr֠9?^{44 ݙKr7UmuY¡Lu*^ڄ/OHlx_htTwE&`1W[$Vڝ)lðz$j)'~ԗ^b?!Em&u ZIpiRh@cH 5[ֶH(IE=p18=jߠV[N+U9հ͓6*iG?Q!S4gϐ\N%FWׁc 1r!N$d|^p}3>:!7$HKKOd&:sDV1znfFb&z=o^B*? Byx<#c;sĢgd]>Q;Mn%K 犄7vnn|Vנs}-؏W0ُKW:8n6V') ;.1v7Ɖ[&KC;lR?V) _+ekS@+әf2iI1+-n7>a6K& W8–گLm+8qfHkFXͥXN *f9<͕Yp@s"Kc~T@#/NT ; NBGCf!T&ݫN2tVzP\ Dt36Gm8cJ~ 3MD;6zr>mj~s+1'ZlKWVV{@k'NY UpLuwM!% ..1\DuRYj(%#+~X>%؏%NENISXש %vwh&꫒Szf* xK1h-ژ,^\j87*kHn_{=|`Hu^ M]&nmD 홏A%f!X_J+ETmAf^,܅}0͔A(7lBUrl!y=WddL`*84>Xf;ktX~{<1 =vyPw Բ$E܂CIt:`x.yܩvWGu07, i$}QU|q&dBD* yKadǯiqƚ:] T陃P,S'ڹqfq@E8ZIULIK{QynF8ҹO2l%Xbym"`(Fz8H_ﱴݕvQ. ñx(=3~fj9f5s, s,Ex6.!Y̅лrp YcBf|z"oMfA2⺄VS4n¯ְUIi a׃jPʒd`oyt|C{@Yh=ϩl9#sP:>SR4/ҸLoi6>Te-x,hv[#9lJde+#%jul)ZGi(|}} dMޥwxi8(?aA=r񨨢?!7@R%!!+  8%2b:7iA ?{:9R?C2B2 d!a(SI-D6ʞZexf4 +،L.=s_3ڜAp1s*X?{A ;ŀy![x1Y AXۈn "Cfc68lC^3,7,X5l1y) $HZ`6=[ @YŃ؜y@y T *Qŧm@BW+yK CdmSY(35c쿈;0 ?\lA{CqT^i& rBfCݣƃ>="J[*#Ht4+F #$3:<'! 9@ƣd}Ȅ/lw90#rq ǝCۇ2$>C".j<;7Aj/ e+(? k1}P3[<ԭ3/ '9I41ͺ#!w;A*h9ĮG9([G ZƄL=Hdןx#(Q8$S 'AF6 9+NKK2piI+J1x'rӋ÷%l#rDЗʀ~Lٺ=X3$L(DV*K,Щ*9L%(kob}ʬ)i,aGQc&-"AR>F 8% c;I~Ԑ1ۛ0@(("<k@4T)6aS\JR))9#\H\Ι| SL!BwOboFDK\w0zu:(:U9RÃ+"/T͐|A16ql3wRwN/koEĒA~?,LlDH 0-Oy8;:R `Dk# Z`.+ ˤ_2\4Ő-Ř@^sƜ ?OECE۔I ,U3\<eDr:ժbQTr I,z$IԔT`;l: <়\ڂ,vԑݏ*=:thMqI&9Q*.&8Y3u88)8"9#)1D};'.C9R B8pZX-R21 ;Fs>C(lGq@9٠M!JI(lAAX|1s BCS:ҟvz øp#8}=x6€-m@ 5=5bDZv;ŞG17q5١!1Tq.[8 1Q3sZh|CUUҬҊ , ӕ?+)BpZ[`*IX3r8U9RqȎVrQ~U14oE V3ڪH%[ҝb&컻XRT% .}9F5=w69ɉZ1?ܸɥ /JDۛ$Q01q$d훣EݥI )3fJ}vۀ}ᩉR! ;,0+?<%\.ݟN2@`V56ɎJcMդAGlJ1>QݮVq}#y#~T^^8'mRT`hΕ}قXe2Zw>4 =Y37]ˤ9,3iU$PE&8jmRk#+9=O>mÛM^E]OъMPDi$$x:)*앰b3Ѹ%Ηˤ =yoyjG[ +n퓚OĖ짖ְPK?hE](&/B+,WPtk)gH(+-FeOm`<Щo*a^$~ pK`FC9a,8'HvZg%!̺avuGAܚܻN^k$H?'ҁ^S2Bps_Lëf4ld$qk5Nm̟dw> TNkٺ79K69۶j/F6K#뀏?9 KqF (#^d!M$F0Nۼ!vyl>nfٌī_uEQ8N i]u *t M}†Q@F:= 4fHQۻ<%- HL󄞘og7ek'yT.põd£}Q jvK̖] Jq=F{iXD9or^I4"p6)cv@y`t6#Lr+IdcXuԼ@@G22I%(Ѕo'31#o2GeOz`_16JR7>ioN|'|rEJY_1_\@)+\4yHI ^\x|cTsbŵ"? @# A `P',DQH }H`M¢T/L@2R5+ei?O+Qt)6Q";Mȴ~TXdvG_4 aĨSH| wGPnzPS_+@@ldW^+K(֫ ?4E:E-OMgDKY.Z޿s:{E?y2޲wnl qQ-+?(UjJC$ϸQ4? \>âV!K֊6 C+9S*7hS(&(V׬ M (hW/3쎩J(:@d|=i֍!J_"B:4`:>C-1´:ݤ3rI T)|qdޡN5d"r! (JtI4RGӂL}iݥrINQO"ɢc/ ۈi4D:Y*7 ^ݞ9`^ OPNk>{"Q}0'6 ii9+SF}/`Pgd(2QSI6Zbݥ,Ӱ ' BPyJҊgj +wUNRr>.ԢYfJ>.{Sƪ[0U~8uh5u}D'1jlo2,%EK쎈=p.&/\OhN [chv8[ݛ5ЫdEG"OLU)ANojR)X'B^Y^:^".iYkLGc֕X|f'u&Ď# ހg~{zKljh|OYf% Y`T!5uD:#&,ӺOD Ёfp{#q΀9]/c"%,@A (ȄVOd aq,΢leir_%#Y4XjLQw]+ɞĝ-S t"# 2=V$Z7DhOg/ [,cWpDQ`@4GA#lvEF*S+elIP; h@ewe5 (Oc鞃"CZ zƮ MӥD@RAUKv 4p4͝c8Q]~Mg {WE1dG3Ù}(x|er5UgkĦc%4}+.֪u=Rf' 2ʼnM{fC85<ƙxd;5&n}LT"'C]̭mS n*rh ,d mѝQJ3j?VI*@!qƎ/qhk\H i+A؜;Xi02M  Hlk4MwB`ܐmV#u}RsFfa 9zɔc20Wzkę4k_ ]hyhiO DhbiMx^V?bR1S50jƬ; _1ν5Y-PQILmbBg+G FqȫK#s2:v[7 $֗#lo*z2)qUhW&ۂ?!= 'ĵ$gh#L5rBߣ{s[4t n/뇘fXF BNr-R7)_S:?vM95/<**.{ݫY^EY*dd `-fj.O|rsOpG\QQajW|6]yB$yrQ,IܗZFZ;rѐi8rAX U!L%fyl|`}0]eHS3d m3SdmF|Vf;A!ojM@yT ;@b^ 0 ķڱAP >gZ a&)w@Hq<ڷ.EC4u4%ѹυ"S)L 5xM{`=P~ hL\zmbvㄐFWܩtl%cjZ7?*bi*fЮOy7&tE^e }ܽBewoĚmp@ h RwH bDi%0.b+DYf`j򳢪ko)!b$_,Lɣ_R h2UE NhlQnf&bBIRL*/IFMia"hD+m"P Vf03z"Lo!F**-ZV@~p\$֕^9+БHBP} L.ІNĀ&L-8_dBxmLQiǨVn,I_c:)p(Q*1$l2(-Be@ DoiB.:#UB Ϻ Pj'iZ@Q-< PrPέV”ǢKplĕg+<,ho$gJǤQiʯ%..7 2ڈ  g `KVg8D+G|HP [fp@Σص4q1 fК"Ɠ6omʈ+&vw *"PkPTR_kD+ο%S]0` #FOd(r$%< V$-Zbf $",D\?H +Fƒ &4p\2)DnNRL&eͪ%V_Ϯ)d n24گq$op.g @&' Q$l,S,؎tÎ$iHҍ-v$/5e?'ULf 370^$$ (J_ji&$;dЊNp@R*Peb` .Y&C@}$ZlfXB#G -#$K TC%?2d9Ò& 'ʎě1ה-(4uLvE-&.StRfܔe7a)֜2X)1$"b5O1ș;#)i4 !L\Pnhll+Q%.O%i% LA#^~iZ% IЮ$ F*rԎ"oN)T˰B5*'y1Bb$b%̵R^ǫ)!WNL9L\S)Gt-%CczddFR4۵GK,%Մe1T%$b-pGD2v:cYZj4!T 8%=4.'0/1soF^>$fJ`4mu-acYCIde5i-\6EW-ZfD,n"h}FiiUvFB(wI.vA.*K-sW85`$&c^SvZ ON,XE(Óa'o-.>6IK4ehtqv`W<.Z,Hy ITqjNQCX>60R[lviq); F8,QD/ml&el*s"v2ʼnizSA7HC~їqT'A(BloolX%5gM|m#Q5CKp[1r[;Wt!s*lKi {&N,+~8vXbF -`pƌKm:$ӡRHFzVXZWj"UɷRy%u Un$ 'Lv5RMo#V8o7dҸ2չ.pP \+\3dY^ ^iA/y!wEU(2|)SzMd&Q$@4Od2 Ǫ=pV<J*Z0Ǒ5ʾ]=vJڷlhIFZLa)NX޵@Yx4ws>e1iYفr&U' ExɊ1ՒK[8  #}*ڿ"xYEذBg'Ҩ4(ȓ2:No햇 n&*ZcDv{l!Gsqtخn:PٚmhVMA2Y#YtiuKcqQbp<sU,ba4Ia'ss嵢(B<-Q"c@klBF2\2ݛ͆?ҮlіsG%tCʹܹYe$ȳ$L_@p>! "^Gnv*I޳by;P"-8sٍ-n]EYzV V۟X, >aHP?b(A9F! ~Ɵ$zğq 10ӐLC&Hd1@4pJR4C3A#IQ$2J\ $Ĩ:n}YX $A8%vF$XMYSDcdVfUD{\=E|7Ϛ&ΉR0)C7+i6o{̛#yj#=.֘AkB$hʭ8U6*"zH˪븮9m*L>g\&qp3+;I K RCh3L(0Ǡ Lɯ[>:܆HA4#!l%OJ[6JSlX%IL$24D*GQ''@s$"5Sq=H Lki3:hďZZ`HD;绨GG=Y< ͪa@K"ڻ(Jw$+:58`HoHņPdHt:֢'&RԞp4N͇f~\X˅^"EkNi`dv2I&9kIDqDlI"s]ir2fR"ɂ66f:iG NT|;?":AHL<q3jO&Q# 9萨䦒VI%' L #u#0GS~*8-hL}!reX7mniSBdSGD1W>RE鐧axƪh\d"SԑK$uɉCnkr"R΋zh  F?L~o1ܺ "_b=Lli =V ov 0$r7.m>T'֜f)K7^CC$ :d q@⤙n(ԮzR l3*b&I5;#% HZJU6r*mM ! R;Ħ$MjE#ygK~Vr,@cr?|a%u3 &h"D,XWԌ FIE J2J^R$%X!5dJ0lR!T( #UGjV ]F4 B5S@$z; ^*O'`\'J4eIve EdI -kIfƹ|p9UvDȢbEk( 37g~v4rYa?%MR56nd lHblpnp1" wzG0(̡kPtӣIwk;1<:P?-?)͋:*^?Ʊ ?,m9v?٠>'yOE=,d:-~R܁/jٻjoDEV#Y F)w%gBaQ&g3݉WؖA$2p獥?ş;@H?!,5VRdQD*Zr3dq2W輨l:~(e-I18a,K{Lx *h# #nTi w\lrdgk3ד!;ya3Vb@uE̾!Ӱ9+!!A:}h5 "q372-9м~"2iA#x./c , C$6{Sn ;m b+?bȶȌKbY&KN8[٦:7yHóûN P& )aˆ4! +ĴX) ;bҝq4YϤ;6 4t[XaI9!"BZ086lZ``cXj. @;֠+1dQT6-c;%$zk|8Ь[ZG `9P3,~ ((|FkRGh RJe(P?('L\Rc%`ָG|MG$/#L@*73",%27)-=BA3 F|8SGZG#BS55-*@{i?lC??A3,yjKI\ ˥8qv9t*C?1Rb.ե)Ơ49՜7jSǐ$ ȎZ, lNojX3A!!'Gaé2;b귈ĉtBK'[+LS/ ULY@L6y˧) , di 9SKXq2Eꔄ.€&F"s0Ē蟢֫*J!2:.BK|`~JE9ӖH3Bes!D7v )ДzӊLPh#AYi `Ж?#,RɲA,1$QR*LSB*2$Xw2B߸֛hsQnLXD9S ;@)َj zn鏝-r ]uxW㈍9H6MBPyEgı{!63`J bmDFj|4P3ĥHdTlD}oʥԱAF: MnRׄHdy*0aF3wV܅ɜZaj.ר [=ebO̽S΃*HZTE$&)R6U I;܌9o%DO9%G=ޙ9$N:=Tk"873Gd%! >-[(D3 ϙjΝvsv*ᓍ! Ӿ޳ȭ9<\ڒL& E:YBȃ'0X*e4^Z3dՠjMtIJ3`*%UӱoI}|a܋Ր+(*Ja )6|{t 5{ͬ?bң Pij ( 4XGHC,1Ӥ2y܄{ƋAva٪Z* }@eWS="ƧZRCTͽaP ,4'+ERv}H8Z! "2ߏՀ :*,28Pˈ'[,b_/p}U;/콒+<ӉНE4|,"Ô$$/ɦR-L0 C1J$9=K\{1Za1&Z6a̛ Pӛ[8Ƥ $Q!U=\-t\7R3)>@ :ȴ搜iiI,!"j NNfU7}{wS$$hYIk"?Ķ6j{St,SLa qN#+< 8TR*Mofp*WP=S=hٮaQdD.Z~ }`D{7.6N*)Tw-wV➐} <^~iŋ{kg c 2PԪ9)N̝X+<9{kgϜE? N픻YO٫bLc\_ %2N~kR^^;❚`MHS1paHpZXom}o'{%eTkwӫ`C :\!_Fwx4؅Pza6"g˻%۟tk\{){3JV KIoXӷqq nޒo=uĦZNG+Rd>tlxIX`)f᪠kH}@n̢~S&ijRos-4 A>&:}Y̯* Q\l_fiy<][qn}jYwB-h5F{oq/%,^b%rN1Xʉ*zO8eap&{ (D @d5~@QpfE(0&I_$CKd0n%F,2rY=a@C_TPaXl[{WhzCM*"Qagrh$nnӸǥ oye'"m7';Cc:7!9.:zG!l76UbiW/ir H p"0%lo%Edz%俼 z bn29ꛘ# h6 O  !@Xd!C8p,E (u"45}R05LeOzA %} F8Q0ãM6G!eP5 Wit9 rF3]Ѡ䆋@ٜC 8tvHq  X24K{do:0O1htkH@T:\gRHqIV#g4=}ujhnnc8Hp1f[J5ҬڋilBo\L~#DV,/#hVDZ.MhzmqVXeH$rfD2:_4UK/]ijХw3\,$@C;ԨnvE RĿ"~ [ڂ]:[f:"F*,+U[|I: fmIˣzwΎ?u-KڽΔV{j".ؘC[{ЍtV[홴 "$/R:ѩg]E\k"=a#hF)D?wyE"eBT⥉xJHL6bA#LҚt:- eڌ!#j%I ײ!h ya4Ju(N*&'&]ªq3\Ǩ"bVSN?b -G$zx*E6LNLT^#'cKfh-RCwW%8=F,!:vgt:tgy^ 9F&*=kL8ĵ05Sr]Zr 5?#Ɋ)D$Hao}N&N4m8Oʋ4.M$$KOor#_V&$q2rGqBE^)?RővH` \2LCBsH\96/LUtDC0*JSMPW6ЪN)ԥvLTvJBW<>~QY:S+qZ5\Lޗ&r;1Q22ZQQXPhTR_88kRiu*upԏ3Н VpCI*h4ֺVo0LfW:H3/ ˌV2L[n]ƤEsYnfu7SkQjBZ"B$]:f(rh3\s 7,! ȱU`ZԲ:^b&)/s;D(Ow^6KЏJP0 ƍweoc;whO{)mdg;e` ;Ȓ*,U(dp9ɻ9=Knc冄u]dˑo"$aDh>|ES9,2JɩuQr7 Pqz#{r+ uC#D(b`ȶYШBe#$@nl]t>1*%%;t/Иr`1mUe!˩Y!F $/rZ׹qY!'bynNxw!x~)UJ(MDUoh~N-m:RUpH)aL-vc5:C/2S)=IN5T]JJl7Ngd"1ҨZ <7=+B'D5. seќ=?um^rT,M#$`ƀ,RwU?i/4_KH7Rc^+VSZ͘&z i4ՓЫ \{䅟~-eW8c>+TrVikgE.MЬWsF<ì੔$n ތ wLo;VĚ4Ϯ#ฬEƊ~M#ViޡX/dh(W'᱔ӗ6pRЁ/FY00SNyFGˠ`ҀS'(H!LlkKnnJ-9©&1}(8`"QA (33< R8G!HVn0m[OJO`UAr(3Hm5ICQAc&)hTVbM(B06ZD403HP3)+#/ , 9Ot{^{fQg_L!VШ;"4dCQRUHr+KϯB~p#N8DQ-?&jaJ ]]cچ,HUbEQ2-a&hR[r*#sdswm11Ag'V1h"MS; WkBFBgwcQl*DUTd3 2{mq$3t9XJ0n>mAXS4Q[)57'lt7QjKnbM8Y fd-I'k5RPq;DJ;?YҮO~t&Mgoidbi[3@ĤP"y$o**v_hi=j>7VqH;!v# %K"(_'rЮ8P2=ˬ*Xj.kRmvoO#3DX]kPē/xRuu š.+4r^֢kXxy3.ASnu>\=+ଏ{tncXV3kըԂDx4hxMJ~:tUbW2JSטU1'Nss 3Jr RL9x%-Dc>14.9&S̯.)VX䄛*߇yCNϏu7'<ЉCu$ =UmWf#sI r1~OO+ok) '9$ !1wD/ɔЗKnCPP'Sτ>0e Cbbė{9W+89Zk=fpRś Yqٕk C1ʺfqS7U@XLjFv7Q-9d L% ȻAE3yzCWo.&>emCP$&uU|1V-ׄB׺OQ J\SF;/HCXo)ڦQ>oUס[*V+5N57<> [$d}jW0bt'ZOU"(9kO=T350ZQmxBq>dԡ,R6VtHqHIzIy>mMXb{xQiL"4)A$/a ʏ%E,AKΒk!+*0|O/ 2}6M͹75JFnQBWZ\ܽD59oVCV.E.+|K[ߠj\ :^:z3N #5p$(چ&{z?ʶ#ڨ̓+β!i|`Qr8hC&!(j^D \vM|x# J|-H6HzD°6zf̺hRE'hJs08̃a5|4(4 . >JtH Jq vh#K>HD!@HMQ:~)6s4joՌN4HS첽Ă(tRP/eS Qđ5A$ ҁU 23=H,#O`)Mmv~U=e;\]Mt2/5p!#R:+П4ʠ bu}#%>/ tYݑf$wu-I ]P]6aG7Ul%[ >iM^/cMyE)OUOn}+@UF8 …UxGp/?o80[ ^*臷}~ |zsjSe3gnj*Zpj}ZկX\XW y2s=+rUx9}Ҁvί3$S.lˀeWue.L W_dҡ\uhvc|X w4[b F 8ֶjQJLqEtb4CQS#)%Y7l 1fUnE=4$N$iЙ`CίhIBp8x6aNc+'(Zkru?Rbsy9%͜T!N :cyy$ jXYN}"P G|_Qpˎh = M,3tNcfVgB^⤒R5TV@xq :5BE4c8DbM1rf6X?P@gL1l׫E5o$*$IRC|X`k\%A|\YfG=uz, /PkvSN'O PK眢;~ P*>@}8C:D5*e"ʡ^">=z XE<1_ ^*V8OaY8d#7t4e햞k[Vu?d;{wOerXM缍^4v-5ҙ˙.Kٖoϻ>c"v Pi{t\<|I5]b|WbDduvYvinU dvdǼ7kl^7|!?)""!"xߦq\&/b̚AQ [OXq l=R0kAЅY M0K2Ò آKB.tD"ٳKa4kDEK:`ٴ681k!ܒ84!6./̻%3% UI4o͔2,*4pcH(F)bV(QjzJДp?Eۀ?4O,Pw";̒B B]l"e RTg.NJa)VZs^b< ȅqFEGxAV 3{OEyQ6421܃=-a5DDmyD<{@:JtUũ›lW?09Հژ6*Qx+s'3J[{VQ@8[C|M&caZe1YL(D2, sE$Qi7W;C[= ;N-eW\c4Sԓ];SG+ j}ʵY͜9:Sl}ٜ1$2>;]?LՔL HmiN޸z',\~\:7䮼3h_=ɖ] ^:Z\i80s s7Y"љn e^ls#4: ʬcMQQ3_ H"+\ $W$+U$D>at6ո ZC adDOȾ1aS m-v`*>@#_u; ͋ V" pu(޼V0˰:TA.#hp2Dlpcݶ;PՊ-[H&ۖK? a { Z e=be=-jʸ+v)Y;k$th5"TNNi#)b\|V h50;АIlY*}L.@?Dښv EEi]a]{@LĆ8#oQ%ü]95j(AB%Y^4UM W3hٖۛûZ.yfҮKu :ZD#9еsOМ(+Fl} Q?TI:F/kPd`^HNTXuFl0/6mcE0aٵX&˼M93&Ni#eHZ3}oXGxu[:Qb|;Į 8)i_mph&v:)PH(Td֊u9ecI^\e]*:6 v{`4U#RźŃ‰>_K|7HmuXjcHǴ=5{qg!@Xh;1hzU"# ܢmMv7@qx vgWRJ«/$_b6r9&rUrl=᲌̣(`ӈC]b!]d+RIPg+Oӏz aEgL{HΓiP_MTqXx2E}3XS*utW7ES7 4UI,4ZXRȮ7#` +\|ЋQHGhiܕX`p6RG"|XoZ5 'Q@m8~8TIKHP}l6iś¼pH1wap) $E޼(H%X/VD0dU|ɁR6E2Z ȑ(Bs]931 X"Ec߅<x,4d `5n<@x|(H3ё8ph Kml㆙sU#/*9DH4N$Vj\bS̠C. tp$Gga83q[HI1!:fe `#>$aLY-if1#O3ӓ$ [zZHd1AE %*<)4Y&H `=*$Ff2"/Q' H <}Gw ] O m-zs}-O@'ӫ&eBX^1^FQٺ7~49Xlfpd"_*1"3h _ZƎ52kG$ GVYI#h(GH$b4? kzw8E\i 8!!)ЙZ@[Z \_YZ͢Yѷ*8ojo`:*z%aUR\&<_%r/Wkx Ye"~ibz{U;1U)zKskfK&1c`=0\Ȑ~ޚ(ghde'j1Q윴^JQll*:cjo86~i_ `ǽƩ3 SZmwZ/zGA 0鷶;[rI#e&y,YcD5[7 !%=#:UY ;I9k˖5Ӓ`h2k@!zYZr8GxseԟI3W;j"f>6."& s%BLrp2F pޮodr&!&%*J-+)B"G$KĆvM p"xn_0 2Qr- .;>^.d".s.uihI̓.ޤRs` %OV(CB4BbD8:(`wD!j&Ro,t-42l~/ҷEi3TV\xB$(&L -(PDh2;jx3pOuL'GK00./ɮ8O"L*)pS!*D#ј!#{O"oE hdo9J\*` ď4Q` 4S)6+\.P^`( Ц+9PO-2II Gh:Soa+2m[ oPHT0HnXo/+r_CS.ӷJ]uJt>S3+fK2g.c6x礀 K%+(TB(@[%Hi*~s3jTʃ?DHItKhQPK#3(3,$8 jFr.psMc2mDQGpkus%#rD$f#6B.e5@`4cB:HSJȰE,C!2t&U}bSk̰i1I7,S.ۓ`Ԙ#@#t FB0USlgW F8UFJu2o=JH[b#CcP{LRp27X` #$LAtP;4-QX?Iuk}Mn*dvQ0iʓ S-`"uFN#>NF\4ܸHJp6D4 YzlCN2?Vc/!.Gn Vo-䏞#Sig.'fLܔLOJ8f,` NgS4Y0M5 >mp/V6Q5CuL4 0sqUꂁl_8Vj;׺nWhMw^d w.A;6OULףx^a *g>h>*ktP`"t4JvMk(@-OBWoB*7D6Qc%ϵob +H/EsMNqF3cpN&I )4PsY6%І$mkd*vB3xo5> 9^T٦fa5Qedh!2RR\ncٳl?7ԣ[L_BG L~E;HtrcJ &9Dup#xZ.CX\3sf -R"sn+AR\lC~gא P٣2Qjm/"]TNJY|*mAO/Hc"Mq5CVŚ7L?K(lxgTh`tV #AP2-CqHǏ^؇HŒ]:p6q9Lilw FB\q㑆IbWa:2Ae܊-Xy*nªkQBf{SoOT3!Ji9MM2xqWr4 Gi(gI[y _x";4o3r#`/5 0ZqMvupFQ+U0Ovn%$ 0daCVN6*v#:i cC6:ٞTĖTSǀyU3.HEĄyZRi,>C@B){n'Na@"_ r;NhVICö eƙVImQuTJ-Q*gw $B;D ^͘me ux#l-nM_`/)M"J`k,Xg Y1XQZ] pI$V]ť %#Oz)LB}h'5H٥|;( E;uf븍kAs ˔NH)ѻrefޑ voEp0T̅ByY{ E'z#iV2q˗ i˲z7s4tɖ|S Fb{.PFYr{iN*D`(3! >~P6C0ش342Db>$a9g Dn00i‘ j"9@c;2<Ϊlj+2B섶hT@#o B42^2ʪ*z T6'ϓXۭ>.¡(ܟ3O=T`n+S7 G2d|Ⱥ懩Q$܋k)! ϐ##cHC1.ï,N*.+-Jq'(r䪩"TԐ޳P-v!K?=t&۽$A<ж ⛭z }:JDX) 7_N1=R͐M \;"2^ZHɵ3G'3ydO !,҈$RRТ_ NHB 昺7wx"-!n~xS3v&w&)ϝd?l*4Y3V&Oq}P&M]b%t*l(V3*mHt )V STuscT,48&#dJ3R7[UHFe"tUIN}A'"K>AF[Ț!$##rԠb$&`U,l?cN!6=1?j%pQWeȦ<>mQu xKw!sBB+c cMQ`q_rx CzQxnԒ@G aQ2SJ.8EI KF'Ba\QLL@| ;,qɬm\n!*r85u攥@D9H ͵PE['W=+ Re5dXx8EJڏ $AW. t ECQ2U2E'|(pՖPxґh R%Ft caB]gNoqFSD٧ƆIidy^u5 HaJ+ )3 سR {!? iFzcFasнH$Ҝhqe׷F.ڿ˴ Ck\{!J/Fg)Fޤ|FV?%lĂ &'^MfϪA-W%"6HS>Tޓ)1yD7)Q:DU2$U4;4t@ 6ﭠ*CYqԃH'oJ6;拉vA-S5;JA"(6j pdUyXzEJ;"ɯ2}(pVG>m{+䛧L H Z\̉HT)*qdP>8s 0vBކU$22[\qgŊ1@#CaxjvH0]DnwuP•Ey)ę +6g W ^_]'^7ۧIUu*V-_U!V*<E?yqzKJmifPv}SY;Lczz*iBNȻ\RX?yyR606'"aNzf|8ǯo=ML7ǏW>|o8J2ұ_G 3k2J*ф2a)Q+Гs/:~X٬ =ɥA-:? )b,_xٟ>(uñ`6}2 H"I.ў/:/4An:98ȗ#9"('b rbႭ4z-b4MC32e: /KO4m({y( 0aO1A9AE2?Ra)(< -3 N1 $1,%%a #janb KlЊ{;Bj1?AbHS , {"*C+봠 kmr&l8K<|G"d,$+I c !Fʼ "XV#/jq !AlLC? !+v+ H5`'ê4t43ZK{C!~B@- x933C$I#-1 `(x) 8*L9p@F M8=# ހ#~ݫ3R2d?a˸$2Q#>$SH hjϑ2N(TG4T4%</%&cB"ADA o c0Ս*\L yD-MP}8ܖ,\H@RB(e*i# r! oѱ)U,@Š:Lt5?eyDLk35ˈ+UTWT5Y(ttwLi_E߯ɹY>Sh4"KK/wJaPĥ4e!_ V#R_ +EF} e<)%~4 Eم(0vH:0ˍ`n,_$)Fޣg3@,!SN؟bV ("BQ$Ẏigxo9G˘v5wfu!K)|-K#ex-oX !hmfWNq[͉ GQ7G#s;iNA?$K]ћ|].ko\j_AW{>GmpzĆeF-y2=R3(/{A '-7XT*WG\0z~']duR({Gz$ƥ'rl\ Rg%@0$~B`G40VapFdOM%H1T9e<9%G"2O<c$&ESh|OI[U7V9D@UbO$.Zzk@M/.ʨ#9 PK .=,eUWrK2pBo g fk zwVMZŞazlkUz$*Ln+|j NiGPIkW"w ru1/.b1c(A]3Uz%:bk"'ֽ(:躘c$k Lc䑤;T;',(BIΕ/ r;Sr*"񢰭,.pr<"0\4H"!.Zǰ5`ɉ&:AϳT.°HB;IF%R$ 6j"8L2T[L`[Td67L2KCȫ EQ}*ک Mϑ22mTMT(MDd~Ԁ/-؎b/ ,4 \aGs+٭jb";дȹ"p{EwSⲮc t7ndG0u!u# _F#U6~؂=cpl^A: =[jTwaWTRFe$f7r!)*OxT0K-~tjVFO KT*@}'0[`̋ 0Xܺm)<;݉) ? C{Bb90caS+J:#iw˵A;AHnĨ8וOMeZ_b+ی ]#j7}tDKםqV _Ȭ?LfXHAe+A9̛bLfH"5VPW0+Eв3sI+uEt<.{T+o%wPW8qp˫1CSl)L;S(!6G< >6ly䪔P/$Qa$I@̓\ Q&LFO6iSi z v[ lMmԣ_!D xZ~EU1l{<*x:(*QE45)$5]jScZB͛sB#an4\rT.D<'5WrA߬14T҂٬D%(5X5$㶈dfUh,MdfJ JZnPRr"?a8'C_C_h1VM|Tu@k(BJKnL=8,P<4ŞBY p=([ pܪfaqs-!#shڄVK\sSANnH e IUy29Sꀑ"Y\- fل LZ\G/|690Yzc6jDUZY),6U)&r{ƜV گmp%i@Olq=<)7k%,%v^(ޭ6汘pQW ]~ K@$S7ϬUy#S7t'ErȽܫk^놆*ݯ^{ıh/_bVh~d'.`3TiM3w5_Ф1lW*:djﲶQ_u\ވ~+dئǐHy^dLAn}f,[,)ƀr%4%M'Ab0LAeL.*p!jKF!^p.ТDui,Ck^ f@l'vmbڎ@Ѣ ygZ *kr#z:ӆFd"# @fįLO(. "2"J&x,ҧ(WR"|0.(:BNAmž<L r&!' vfEf G@Cd,C_,Ljpw ),`$̺LH8EVzʢpCpE_.Ҋgz2.pahSZ'e(f;\j2ۯ9α' LLs"t"iAd1;!j.dȖ@ndQ(t4* +u+?az>7u#n4F>BF {i$J$aXQCh"Ho"B1jz&N0دׅHl<$3v *qpI#-kRJL)ԭi ht?Tk^j[BWph!;4n67P)3bQkj8*J)-glx%Reb W:ŦIVg1EЏ 2=#3Vmo8 G+nS _WLr9we-fSa$7RwrWo_mia Mg6Iحk2: T+$!̓&@]M.{jkⰶhuGA7*㤗SIJ3%iFg 9ܓFDJ|صjVL[,ViB7,(rn9\zdAT@ \ls4 -IY{vv*.Yå.#2$#raj$λRH˴Y<f(k.lhMr6*p!B`?fқ|Gb̀-!/TReԨ{ƫL7OIerweަGE6С/)KӕʻQiIs7wkai{$dBH4]**C/li CڀK (2*QʟprEYF;2qQyzg$i=2 E zeh <$gV"h#slmf5Vdm]UB HNXq}B3!(:H7-evmB̲6lJTi^gsSUO ڑ>~J#=iI U4[-QrKza\R"uq 8n ?:BX>63`H$cxeLZTWȪgfnE7:8B˸"hZ:\S+J@͟`6/,G:klf\ \C*̷A T\ϒ k9 aE ӳ\с[ ATX![D+O7DlĿ]k@& [1,*z\SgL՘#b E;zzraۓ2C{ŴmXnaUgAWiMhB8KH`3nӨh=Y1˛TI>A>oKK6H˪7G Ry4Ch:gs"ěe,^;5 h͂kkeRgÎ_eɓ"O G%Y~^ 圑Zb_hn[Ȏ`%fwݔm >7g8DT$釰v(j%u7esjRLDlky Ma1lj4ҵI1O rB:A_+U\F$"ī^kS)1Lo]Y~iu&P ?޶J62ҩ:4. (|:;1 22o7/!Fau'0Zw3Kٗh Pzj"}[-93's^?%/Bs#x"&6#)w ' I7":(#C,+76 7>tCz0`|Pˤ;r(2qn9ه`>′ ܥ<2$[t,-k! k ΩaX~#P:/4} ;3>;S$42K+ /pٕKs@ 퇇lY~Tp#@B˟PY}8)үP_$B0D)?56bT:<ۯYyۚIyy!-|8V5$ˑn(i?ɿxAZ7[2U|Fa}щ2)wRڏAJKd8@VThHW=}<֝彙\ɣV #ʸܪṁDyF< ݟ:Ē?U){Sm9OYWlyV{7՚{1ٙr_d6V^ܣo^%ν(]r ܾTƲ?J2Q" 2ѢWSc7DP ?%TdHc΂)2rO&PX 1pCE } ٴ9`] XѨL m:RxF3_u0In+K=| ^$Bc`K`"(ML# ){RƮ)2*&@8,#uck ˕8:\+s_8:0]P,CND"-[-QkѯU A@V+uThU+{i2jݴ29Ð oS!"E%IGr ɻI@m{Rja1VPκlˋ1N8զcYV] H˜`}-C D8}9UOƣЫ(}-P,hBؗl(M/øtEy!K4b(i!2I0Q!=-H@SšŰ9[z̺-:?931-Xfke9i~PgcR,1 Q-RWǯaØ !n.E]Fo eM$3h%g!,ĕJQGm[Э>[8\F ?UҶE&ܫ>jYp}9I֕RljZԫb)ΌZr GYMᰔ>ɍؗmc$,ݝ_8M>vMmN;.?qPӱVЉTVA% 4~thh0W WꖥӵO kf%Zdm7e?ĕe^r`𞼩1^W4p|3RCխBS:r~zΩ+!' YȠUooc\+#FnYMk`3p%vXKdpОnAMNML\ehuW rį%\bZB!l55); eq ,s@ʢ;< XɢH> GB\bܪwFh/$?K&j,ɦJTG S#P*,#N$#PhF*ct$ !. `L’>S|$ d~G4H ;`hS0QdO4'kQ#Lj'#G2)TtPz@Ui"ʪd4m`Π"L=u>ͿGVʰK%9'm<( ,}o6RBit T re0),$U0ObKS  $uǴ\Am ҈HD=rt#ɇQMעCp4cN2,IG, ~W"^|KM W*v0ʫ^2he'8QrSG\+,Bw%*U yĤҭ0݀P-䖼~"s:r"4&xr|ZZ *MJUEqn-RIÀis쐨ۺ6(J Ot j(ogtIMq1LRZ"l?}|4ꤑE Jn2UK܈OZ H,9) IG;ߝI%Me~RbSA/M"Sp!7bd,N:`"Gzz LztBhYP"1'촃l$M4Bó$$h*=R,bDveWZ0$X^wѬ}HLQ?(RHDqFsYk0':sD&#?YASH&KI&RؑqTߒsNi@*T$d^&#;DbrH@&Lzk*zQlc׷"dݥªDSĉSL~SUgU(OиJjLˆ=%( e88= 1DtK7sņcEjCԼPL]ĉU3qJub)2ZI)cj55$\rT%v@ >&7;e0bjU`3J{DEfud/;17!Kx~o=5PGQQ}`zQLH6ɶtt@>(i)\!*a)Y&0nc'B9Y XB `DbA*{G2TP'ѳ /%UGMzɯ!.Eo"tѱsNsas.<4VGrLEt1rˬ>Ƀ O!{rА`BnhBh =X{ײ(SK×M}dp˝;< jf R*Kv5}=3.hźVgNjf~§呯GGydpQ=n3%hশC%&)JT|)z.u!?db':d9"&*\S $!*lxa#3>@_NKYᇢJ p䭗a{SEUWڽpN텡_!=KFǵum1MMAޠ1um'4Fg^EO8w^Pn <5iΜmqn1&.RP К n?c@J:F"|,UG> c,A;Pn7-c\,pH2|B n\Bz(pJ)?.y!lJz.r'̹s.lo.R'HG]NG"̦0 ޙ #q6Y\Mp {Ɗ(4:HU\Pw&10Pk6:F!JGn|l?lA8"h~9"ڎoN89E(ls2T$bDȑAm܎SDT@,~f13Yer@]NAf$n';WlZ, +XnpļIC&9ʺL Yl>!P\0Gt~ZwOo4`Ri`CEl0쓡:/!"o$M#m0QrDn/ #IC40գC@uZra;\R;U:\PVI6:,ڕ Sq0[=lPqBp$wtqr}/KiZBe~P(|n4!H=hI7wu;bߌ?nnN, lFqhIlu7o`WE~Q {~E nB|5ap:snx,Xk rDB_qGgr ot)8D<ʆ׫8Pu3F>uL!\2Rg\'Tʍj n$rI'WYpE, [% NcmD2ȣBUorgظ .Xy -XuZRIn@_ ,0N``I] "QQm52z#^y&G",qE*ҞL5/hM |b{A@2I:SuJ1SzO{iɇhSX:H0U`stg v{X!gJZOMA4qx%4$ecYt4g q̑ rIB59zks`׌wbw6$_y`! I š e^l ]Blw2l#<*ȶ"&C["& `ȝXب!]+h&Dzk$yeQΑMm4ӿGI"A %[J1յ^|sZiMjӥCߐN뚨13-ɪG,ba|oYI $ ~FGug=js!Xx4*(] kvTrtv3Nę }0*faz7LG{{)iS2/҈#WZ 7p=5YVFʧr"LߚfMeJ@h>Ẑ%T|xX߱p4XIN#~{rQ> #PxtG-սmɴ")!bP"5M{k4Vx%0FRZF_L LԚUv8&a͔Ok1HvQpD2N \mp3XHF#lo U|#ӱ Gj{*eĘDoaru0eVn]m-TS9{@+m L\}9~nS<7dcZ-]\$-$T훏gG̺poXxqa7Zr"=] /O~%'?ZpqQj Q4yzEC{sx(D7;{s눸\?z%P}o+k׼p '2?u (JJբb?4 A>B0\ a#A HJIr03aCPLBST`LD%锊g36ґ2hSɋ) a.R#h0, "d=伋Y #*D |^);!~,m*$֓IqF5ڃ%c;-1JjT%a0h:С,IdhϠGZ<{ TrDpݙ>1 MYnkH_:G3 XIi(h*鱲=@uY>i4}7,GƏғ(&GQ.Y 3M>ddzvpymG׈']bS26O2<^$":Ÿ,)ƺHȡXm,U\ ] ^gm:d h4z˔ .h^J+$3k4TCsM3SB_PVtei<'LOL[E]Ybo5NK,mݗ@wq ԃCf{ٛp0[^%&]Z+]+mA_H.@آ" `~Ũj]d.IrzGٔ $V^VOp?k ΣҺ4b9X]X%SGCP {2`ITlP6b@mj$FX#VB/2vQ6zH(Em.R"$gg ZDQvMHhf"G^߅ֲZXQJ9\Ĵ'h $lrrtxTt@$Y'u}ŗ-*#"JPoUf~ 4fZ^Ah}CՒg26F,OmU4'54qm\G}Zgc\*\qէEb+AWաwjԯەS5mFIQB G`MRLYnyABEW#&<>ux-'chHYO,0sw݆P6e d8:f9P W C}G4Hm徒p$NOd*zL4NmCTlULf5*cjVA2Pm<=,# G XYVݑ"]aXYtq:A0W)9mXWSeXTw$> \aSp֑n^F'+1;bvTSU#ePrqt}wbkk|b1tgH.y)M2;R.ܠ%ڃ&#vȉ䩔QY$M0 r,"!y0HɈ3^n'@9s3~#/6u}bz>O퐬m.8MȧlhM.1 -hb&!Ĥ X68+v #BU=c:cT7 rB]  ޻)7 g(&㩏پS:6a4$QC՟9R%»kUBڄ#:$ʥ?+0ؼy 3Ox:ZRGCݠ3C8|kSoIRVè+w"#?iM켂 S@"َ 8:S;2=U@ayğ"4>l J&v+J!W <}5*ś(~/S2'q-F 3C=Z =уU!; 7="z ƴ#3J| zl\J:!m)E:+$o?:|q YQ"BڇNsp*CymŸ} |NLV- A ԛA R<~ dDO%@<B? As(C(tEd2$10T U ,?Ю2ds>.d;Tɫx2 wiJ-U@E,T}P Ӊ{I ͜EQi? q6/NβQM {~EɛP?ҷ ]غ!r (kA}ZrѲIeHwX8ѝ#ѽw!3?@׎j٫p6cԬyhωaU ʙyJ 2)jy"LDcP;6NL,t\(̜$ȞF(Q4}_X Ƞ͋-V%; A |Z%FJ]ф #ˤ< b{L )Z5WhOt4?̃R13]NQa"-] dh@>4 v! p ʠ4ۍ ߵVOP|G'agJ C%8}{#"8Od߉, |Xb5Hٱy֭G5SV_FF`E; 8x٨}?Hdݡ(e`פ^*QZJݏ7i{aXL6'VQT,.7ԥE^ѳ}"u4U,_3gLbeMr= {%2IMB6`91$G(]b~-E++ Eg>m*fi/niVKn\^7Ő?Ldl 4L;^y`8!.^쳂ruה9{f9$CR*2/N[ӾܢԾFmJD%xlhЩMK@"gm{Æ1KW3.uHUL :,N|Ye#̲nmƙޙ4gA(E2?\zOCqfܐyx11qOU3NtfkQyovl&Ӽ)쪓EmPYdc@ i* ̡#Ş%;J8^z\vlk:DFU1%N#]pd^`Jڀ&3ō| bۂy𔶪#܄&diÂ|%w,~\#Y,BA cΪP4u@}cJDA8s#+`Z!}/@?: աv'+`a6H_IMFUD6e *( YETtV>v(Nf~%]vț3F6E(u:YSK.%_1FrT~/2Qbрjs>Oc_;@~Kzed |:@`],ɞے#(&T)bY6 gSdɛlkvzJ L{0Bb(!#^{~!ҍVۢtn(ҝ=Pj4W\;a5ea&gϰBbiɈj??iОɿ^pAxD@#f2ʃhQG7cȓʼno!<˷4? `H"Q^"*V+Ѕ!?Wh?`@# !P"PV$E@O=|Hc$'{dt^K%À8B~NcX4j/7͠S$.`ZM*g)&N_Ev8#QN!FQ/{KC6SkU6eKŢU-/b&)j2* ?VlJ5,IsP:-OAp63BEI&=,,+ƴS\jK0^@G~ϚG` m cusKց 窴2.( n$:5 *Һ>-R90Ȕ& J1`˸JJ,L)9g⦋Or ꋼ$Ҵ7 ùw)%).J h⦊""68Ȓ>IF~oHVF:)q=An<&<3 L")Ͻ$('hdV*Fҿ[5(sN JЂ2:6 ` sW(ʜ(N~۬MXAD5JJ]*ˠy+QM+>*Mdֲp/lˉ, _/٘_>` R"d/Q#[SHD.%J(Bn[ >Yc P}p%-c[~7vRH~Ҋ\_{tf\;2ȓAL hc;=PlB}H˜Os .t/}i!* /UƛQ+; FSQf=Σ;g Y`8l<!ڳ$d^S\;Η&8Q\TW'=njn;N؀J@~wh&($ȃ$\zU|B-4I)kO37&1N!ZJ='NkER4X8L~jy+.*A򗩇-o)S ߚe sVx!|y-r2bIcY룧OF!U,)QZL'Z|Ui 20Uϐ#@QboxDbs♅-Xs$*%H0EA`5lFWB$Κ=ҚLDʩ$Tr C-j/5t9X\ځ/W/RweVy:S6Z10 TN.Kߑbԉ$w΅>|#Qeq4:l@tإ^IC3[ľwNߐJNI͠ :X? p(U)QcB%M%X5wZJ"bIQ JH5L zKJ7p6JM)墧rW t͙S)WF Mt2/T]_d:2Tmen/)=9LL3UUABaQ&b*KOvs* k.at"Q r")jva$Ղ"<].6r~my7RA9k=-P,`RDJZ!JZ2ui [z03+]QĦG!r ʈ#GۣWeo4$c8%!E'Ύf×՗VIQ2&U+H^oF%y,Zւ=_#ךր[Y(Kx&TO,. ل6ԙ눂vpx-*?c)+3]Yt8I]dkM5xХ2ZicN8ˌhKUIHc :d"ą6'*S!;T+d pqw21hMmp#SuǶrUD/ WMwNIQdM3cxPq_jǂBb$$9@5fJ"@rHRqܵ[/5ݡũ \5bsu ]HRv 1QG[#GEz6mpG`00c]`V,k%|ՙ`&Z'j{TvT]D9[gX("RIJW 7cL{ƽ~uYzB8.YdNT<]!GcECr ~iW?اz^eGо$ yfd{ p|RfchflfTE2$p$mtÁ輬P>"즼N^i^|x<ɔNj& :˨dbfIC/G[m=2nti8eGd0%|u!Bf⾞#fr$,DfyB$|m(l B*fG6\g|#D.rMB0/˩bpj̨b0eҺ bri-~66n%tdSh*tDeY> ,CnP.2&+kH"< ۰J|n謭Jq,&n(`&)(z@bH-dRPBخd΃!mld0JoM Ċqoֹcbd1*Q.].20M04t 9'N`'*q*d 觪~"$h$xz"" )Cfi}SBXXHF 6=+>1. 6b0g쒰's:䂹O?́8i * ΂v0R%T 2krZN),G)P#&onhsV<M&Krp^΄ZJKfHEjs TZ.ʐ ܒt<` *B"a'2BTmbH/<ꢽj  Zr5gnj-8m`c)l m/0~LэI'T+"R5b#F *$E>NDKNnJֳ _"_=f!- W30"\lVR3\IA8! F= 6n:3@#-n3 yGUD]J+Rcm_rS ԳgM *eʈ-+>%AЭ55T1w(yBbI3PAS\c']O 5_MXo~oq%se$7#]}00(մOuK#@-l\T;E: 21 Qxs >NSBh[VvZ8&.0V9QL:r5Z[ ; &5(4?~i-S\\*Rc^A7e_F TDR<#X֝gTLF%*^BOg$CӘ5 r.P}8] aP  "0P~GѠIF! F$TZ-$(aiE"J<:I!I$St' OLJ->liE"@T.TR;uMbS$ev_D(0uf&'shf Y3}_R̒-gv`|bH%]ԊF#\l(2%ȫ6?=7O^ IE}O@9+IZ1޿hK< !bog;֍(0޵ς۲m3h(/r(ޮm M"2vޫ)+Nt_dJ@1:rl #JP2$Ic*=Z$" %3R)!,3! a.3i6H~T +ˢ<~2@Dɑ( %a Nzd+FL`Jۯ}Rd _y43hP8 XFG6 &8LmAA:OZ?˫ިq-! 箱\Og ݧouHF#X8!YJՎf-lwn9Ϛ/{ݾ!ٔ?4p$67I{y8eGE\rD;j[!)Bv`D=cj n!GP34"e?p2P)91z(r`.eK,# T]TaT "N0_[mn嗮N a_$ (.ȱơ໕5 _eOQۨ!G?s hD _danHvYo@$rg"@$!P0A )>'T:xK @[in'aM F?8ORMredHAk-.Ha$t9Locdb|xބ@}sHҊWuɉ.w jZ"]NUʙ4Ga< mMYAu"]dj˨]!vj;E;U=o2վ2Z2g YY&Zd^[ԆaTiLXo2Y^\TmqHW`sI9{Uⱉ+QdQW!;WЪebؒf9}\TUCMAS8KvV.ZD#dW5U:F&" h LGOr>T+Zj}zD׾<0c:8ݖ>{/ -.iNQ"gZ _bn/fGve{( ً4뾉21A&ʧJf uQ5&@@u !T8j蟛xWiT'49w"&sueJ$F/ƉY\J]-[-7.=ӎ{J+y$X:<'W-G{V F"yOoKYe) itFFKޒ+\7ꫦF e8BIЅ, &گ1)*tMB,`Dے$Q,r2O*<#%1Ռh we4[>8C:g*ޔtDKd"p&r4u=ܕXVWVGh$C- +B| ƈrq$Q]#q#=r%M9*ڵ~,]+j,치;0>[Mԇz]msS1˴Lž1v{2|D'&' +Չe6 Z18QYNOgZC(R2؏c{9Ḧ́2qvw6xf‹Ou쓂)ܽM n j6 ,V|s拒΍H2H^Q2f\t6 ^;r!ƝG(  n 3R(6bJн< a]7A2ޮ+8#N-BK88+ n ~/K1S%X35j0ͤcP b[ s9= a8ؗ@I{r7zqJ7ɟ-"a&,8C6Jgۄ*8#yi0lǓT$P# 5skh2ܐ\_s.32̣(ǚ x}1IZDrz*#vǣH3J`-js&=#c*"%1j JJ"&#(k*.E@=7S ;а/LCbRQ"ܗ y [>R |Hʲb8!1t B`0ڨV̑czAߘ$vl3<}G  ˊ یZ L6qK*H6Q(-IvB{p6O47p:!뎡%Tl"ɷr,,;DP}I= x*L|xos8<:E. `0îr!ΒnK~:#xJu6 <>NI5(ˏ>)scr! 5{t¤(Ỳ( wLe(2pڡ- cyRQMY? )+44zM(=)R- T<&?XD 09/C Yt|!m,¬0% q kչ_0q iMT;ͪz-6"1/ 8ǛcH9np@a&LKu7I ňIE[:c3EC潣N{N](ڠG^ @ѬĜ{K=b%}1Dzk,S`Kϒ>4^qLfX1*JJ`=F BWPLJj^D[~,!8T(GϲFLʪ8TLP^+YWTDmJz۶5fY2!A+FNhZtI ڻWR!5IW=cmf.!Ľ )xъ3|c˓5&TF3Bۮ3 ,18”`,>7L/t5/Ķ:c493ۤ%PdU"c㕲,:!M]!G7eB_ XJC-USM| =NXf`fVf^H Ͳ@f6~(9L|ՊSJH)qC1W)i&*~>O- 3g55%č+^{1|m-:6L/L+éٸ}+#j n 42Um s?+\eY)9^t(m#<afb F ӹpdе D.fʝd)(+ G+H}˘Ѳ`uiG#bj?˭P,Zö &/ Į6,pIM˭LN`^sg Yt47EkIE6aRՋ.>⣚~9Y m!\#] cos,>|=ki\d?ʪEIR =ӺcLS;7"uf]}Zl޳71B|'R CfaqFptc iVv@ jJ!j! ֙O\6U䅖 ;W5 B~o*IJa4N-h2jQILLK*dEV/dm /9e+M{"uSnNU&> =V_;<ݏ-fㆧh*=ue[ CM5t:a pVq*Z WlWo*4 mv RuqLF}-8ҽs\SwI[P\րa vG%~Le'SRܷv>-P'0MxIcJC04̕aL˥(b;'a;%7^ <8##{UR97<̴w4;=2v#(<:S`5_3nDu G{RlƎblqܹ|aI]ܵT d茮bk³tJm6 Uz n!v2U^ FuRj{JȠoU.|{)6ejˮ:LNAckb ~5ktO[ɾs?@Ca@( C! $f)BkH9D@@` T}&Љ|K-oUbRa(C4}ӢX [PbSUPc>,kD5U U".IUfUI D"}#i fY$}UMڦ {HaW3UY=՘|C 4Ш4S(L6D`S)se"#¯C(?jsI ? |Ky,y}`j6**ob?k8^'X@ *)&ƠÏ*1#T [l Ί%,A&ç!MhAM&N%,J.R0ǻH뮊j ¨跲ijdO꺴T'6O# ?@(d b@~šH >QMIdf@iA7f@ZLEPIaK#TR!.N5nNjC#OQ?2'b~JsLR MpZ;Z1M'r5:?08}&BX+KH]!VYB1M`fXUtȘ-tf a7R4b!$?-,#\T_Np^KFw^;rE*^\0ꯎ* 3"D %f~1h2',|jL3Bz$D*4+8 3A ~%ꭑ8ɵ5o Ҷ+`ѩ )ɻ>7hڐ|K P0.;K`7ˇ4-BY"4ћC "R,I3Nh9贼>i)Jkd; KؽJw hQ>h64$dc&/Wd #xLoH=CGœKGPaWbî!H4iQ&JHR9rCc١0XnSG!u)itbmZ 64|o 4(x]&}p#Eze'X !Vi5osB$d|(T,Sq鬵k-$0Z\;khEM~3!^'1$Zk>""pV#Z̢:Xu^аrHL WrZ$Q8XI$!:nىdHؘEлFW_# ȷ3+T/(nЙI"=)Xoy˚T#ӈBD՟{ ӵi7Ri? Dȶj+ċ#1dh|-G[Ľ@Ӎo;KũXܺ }p&.yuZ}dbjf:6>VR_tRoab&4RG2_RӥGhHG.b^ `/h3^9,'Ȼ$#KإtwC ,]}eh]k[-7ҪVN߫ q6ulU:h]n8_$.e3JNđȚ}?K֙Tս3tN9su.JZm DJ>&<#-A|ϣzo:(iz`ʢQ./b8 *VbO&伜ަ|j n{ǂ"Bh}Nz8\!: .# nAFAFb1V BPF$hjNE8Hvyn6ZIL_duίJʩ0bdJHОJ;$B阝6Fc+"F؎Bx j!JTRÃ.=l"@=Tk>^Ro8Jp"įӯ1,GRpeP"'!.Lb; KGԵmn_̆͢m%")v*"$@`P:e5 $- \(T:0(`K;q쾀N&ZdT[m˦)쭰L8T0@Zm$j)ʥM*h6&EHҬoJ ̔Қ0 6DZeΒpHFg$(` "~i NH߰ZEX,i :гlZoέ*3L4jec~߅pmD(cB *2'0Kω*0կ*. (,NcRrdj Њl~.eq-4M! B~'!H \r$n=%0M&2v㦽qlmbsn5\吺v Чxfh0fԯ5 kbM;t3Cli6v b%rIiqΎ>ĸ`5B5Ұ&ZuR_h̤>/WKmnMRAbd"}bMY&E`Z_O͎ǾpQ,SDoCvT ӱHf J,,! Xxסד_QX A#w#A-`yxT7e+J;fW> r+@_/pED=)-X'"C0 lq$p qP Xes1q:&*i0UXu9|& Gm&5G\2Ui@ Ot!.M=@ wqmoG),JBKA]a³Lmm #U S#"6 bV,1rjLAËVmTTS.C *ObV}9,z(XVljbT`v&#/v..Ou.>'7+)u;s8CvH/Eq;*('x-T-y7DӖ9! n x*A#®Dr1K{N*@@Bf싂V2jx/Nh^ u bNcUƦ _fB}7*\y کj&7/#e(HZϳ}PYsv(S(lzO iUPP"D/RN'ԀÚVK7N(nrdl>"~m3&ydOVmK"3 BE(WڹhV ;C@v^F\xe{лF rFNO1t0L7A%}Dn !\X;x*eZȋQunsL.P`0ʲX` 4l R$T33 3Ȏ&h&SZY7˯j*(W-t*DdQʃJtG+F?i8dMO UW\05ЭϏHr'R % '5xL$`0'RɨN#}8JU^J9bv&f]([{<\2.fPWH1+JECqÜ(_eW`sP<T,ư!X:xHë/ I]LA9kh8|S0uxb [C7R z' vy#G&n_Ey7/˞5n ';v7uIgAJ`<BԡX8;EupMB8O((*zS[hBP#ש6֪YбWA|hW3Q%Q`E:ȻeέO-bqyPy[HʦMDфh#8n~¶3\+svh%$H |7M$_oso.㗉cYv>1.;mlXh\LEW H?!4. ~ " $&0})&D6+~8Ԗa5Ga18Xm0bp+;ȍK)bD6]J޵UnB &NM%2(j|٬zcN]N3X.L!NOMdZiu]%*N-ajVR-8g֮ N#CjO.n<*t6kMjׅ%&Ʉw xT}?)Ci}N/9#40;,O01LJb޼3i2ɠR#|/h{NJ$"0v9&EHhA DHJ-;7Ⱥ05 |ImR/3 8MVhj42"gv 3D('"il{ 6(kl}3b!)?9C@Α0 Bj :2Ok/ lh#z0r2 H!jbFT ~A#l䆁5n[0!F-?Mf)|g2g 8€kB/% 9])ɮ%\ dr4 f뷐P#SQ).֯g}ӨNS_1+K(0^Kg*΅y8sUKhh`Z-P'녉8$.DAIw`(~e(5g 43se#] Yc;fQdi"/єcTTȢU"tR"cJ'8>~7ngdpywxﺇOeo)^/=-3Dو=ey& 9'rRJ̸ zcnfv)f$ Q*50Fϋ3|+Ҝk/\4) rҁT!GV4 az!Jк C&Gk%RdM}^6H~JPYfr:~dB>%f,+XV9]u:!d5:&"8 )HCQ;6#!jȊ[iKq ȑ7~bNf,ao$~4Y>#i5uUg &_7fD:sܮ>4i. kY(@k>Ju&4!K $GR.Q9Ri "Jf{)^Ax+qJ:& B3c[-bkea2s-x.<I@B@u[b+G2H#0cԴW@$ "J.)ޞT4}&CcUZDԙ PE!MSRNMsG) sc qP 񍩰.b ( NiQ3='aw-DfLiJ(Hš=fdfg#n*ee*lفY>/5[Tpu~G`[&e2%!e94b4t3"*i ֨g@6LW2v} ۗ1`!I*`) 9#|}qAGj <’w [T-HF si9>e$"+"4ƭaTy~6jKqVök\z!Z@>`uPEq`1[>d,Rj\qz6adC푭1>hԊ$u%=*ة##Jh;%OL 4GB@JagSe2-@qx;mNYe-GjF͑nP5§NNu/fj5[OP }*Uv u_=u޶2 lguIvLWBP-]0I"ܯ=YJ9~5Å2:Ѣ<IB K?/"'k)Y1xqĤx9J`0J/ +|{1A+ ʣ 2,(3 ͉pәA|X8C[ӓ z-kɾ '{J/6 r>0d"-"fl1Hzy>О1s`n(/B(3ˆ݋- ھ +# !i;@G":1 3><(0KHDD ›t 2o{=c. ՛H"4ȑa[Hi6<E:+CZG r61)9N7+cQ0ӦJ9t z\=[~E#:#raFKi>- r<!py1rR)/aƘğt{Ae,<"꠱2 +9# L 5rtt! 5>8ch )++!&IQ ¨h0Iڶ%sp66 ~2a኱GKieY@ȒuMsx[EwCس2S:Jٗ=S`q Ήv9rbK㤑B#LZd]AS}\F "i͝I'Q~Q 8im72p!Ēdjk@AU04iy\[@2@[tUOt~OK1"0mSZrU!a +ͣFñ qM=U xJ=;+\!ZPMKAl&B{A:aZDʖkӦa7~ЪK8݊XiRE4DJج.!H|/;< L*K?Oc#9M(4ɲDJѦJeY yLO(Mn6)KL9׶3 Lڡ)X"m!3W L5;X2)͵ ;%ѕZ˄ DCC]f+qƴ _<[ѽLT$Z[#jʽ]`KCRR^MMQT$AjsՉ^!R*BeW.۲03"MPIJ&!xͣ%4a;Hwͻ(Sk? RpP}% L#!i;)6?dB53+X I jULF 0΁\ ^̼'ҠF 3 0IEeDK{>`,ЍO B%P)0 82;JNvrNS;T,!Z{ c#z:#Fyʗ^?&؞5}ZbDW_#H ʩQ٫*:x,6p[#r:b5b:86Y#[u4\}Vu`mʶk0xfǬNY XkZȻꫡ-HF;iucp" `d_J1;5gɳ6l /Lx%*Gca.wk>J os2e!HlCSe..4Eִ͛zZ,F23Ti 8/{=@g:fh?k&A%4LK>Ы%*~G-N1f&- $T F~XU8Ike/=sfsb2,' k];݈{"lkpmL;D^}м\ 3C X~Y n)n0JD[JsӄbJ[FI'DDQrQ#U#Pc X嚚tЄcp|f岙D^[ Ny\c,!6c(6 ):`Ya;Jfc̎1-ԥ֒qnF3 ń 5ls"XEx=5e T֋.rD$M\cObhz?J3o:,d)X0cN ð㵄R#+I\Ib*/gȩ4 H^Zk6r;$9RE B9KoӲި>p2 ]Y sz-7wsaЛ| P(!#&x)[¹A=:AUq\XC_pF$AxS@DC$DP }K@TLIxȀ(@eʥ2H#4= UdO(e*GT%1ImAWFS%Vs STz2*Gp9ed̃ 0G%>Q!R 3X[RJ-ydA}h&r#c`(?$VQڧ2gGzTJdb(m$}9xX%-ҪXxbs@Q{j4HS9N?{0&J0͉T!22=+2P'*<,Mԋ*NBv 01h1;K8&@Ȣ2 T&Ibpj I˔ DBB j w5)L4HjЀ2"K,ǼKҠK%@B4a!/Iz!qK!̋|TQ*SʕL>s#CV/\ @K:V^ ^(6bE6 [?袏-L ŊB g!S#R`$֟탶"J z :}ju}m!ZL3܆1$dC."Ѭ' E) F?u ʷ)18$0JMYQ(:"Q#5Wݓ+Ň՟O2r+3CG%AlًVC}Ð&LsNŦZBeH*¥s7-Ux31 /k˶#[Pth:あn[ㅮIg d Zi,maa lRtECRFL4B#s#$q]ћ)F9WTU.! KV=~"v[Ssi2eh{->6x\\DIzQxm退R s$uux&C N化BH-Gf1H|2Qp2wP\Asf#:& 3Рauu='(x_nCכ8>9QQ8aA93"B R[܇ȣ{-~0dx@1-F)-GުGQ!$M&u9;hN!G +MSHBȂ4Ԉ`R}B̺%R#&$n)fA&[*PI֬;. JsrE`DoFUWfu` zٛdYNtĒֲȇ伨ERE0.꘰Os#2#`4!3S<71}b! |0hҘh)%*[9G2ziS~VeD` $p=DÒE)FK$Ɋ niQ)y,$ϡdɦ+jK(H+F: HT |dG:mQCϹC Ja_W$r(6|I l12;nR(q銤K+|8T'MrOBO5RlّJQ*A~K9(n*|D_$V V%; X<ɛAUWY|#wU})"Y2Q@JQɊkY EQ,JZH}[F+elC$Gfw7ANts #\֠]>-9Fn #.FS-oZT*? 4>s{N5c.f Co 5gx1hs; L֡uPd X[G=Wx }^pМQ5rXI DIۖDbSnrHmp$8KI!vœw6ݰZVA\E.nBɳB\t@<1Nv**ٜp6hYˮCZT@\7쥪ݻ)U< o)}`!f"P Ç!f$n"d$Ų=eVNͶ*k"m:VkE[p #@L@/dre,8!Lzo ji!Tr'b$P(ͪ4bdơ :(I?DP㊿* ̤fL,0N Pq"s|S DPKʋ‚ʼn[϶!g쇆j&UmŚUC%b̀:mk ~`KHpL:Tȴ# |P_i28 ju9Hh}/]H@a"Bϋ/4W˸-J"- Y䛇$Ta%6ĵ pc; nT[":l,ňkFxm#Ogկ;1Rrޑ& *͑- %^=#m@/u{Ȧ4?\1ZM k. ktn .I8P^\j&(~DF$hWLӭd b.դ03.*A` <͟%34ˬJy ,LnKiA,܋iŲ'6 4<}^O.b,c}/I8322.Z 6@2~'1F[ Y45-H%Gd[ĴBWS@SowNi',3 =spQ^Er"SMY)6|v72uWJF.E3'SBIyu~\$bHsC0iM |\maj" k(($kU5)'4L:PUh *,BeyJ>HgfnO=Ƅ&?-/XѴ2 ÷Cn_Qm`=-vB^^caBi NT}\W >47b@T-y=b%BdVsfUФ(% O=5ڑ39:q1Lj7GR3n ^e5;_ECړ+b-ETΩ`R&4sUa*ZE_JM;ȧ^_Ž !iF̋dBUBeA]VpG%hB6]D놂 ..%P ] {u~/aӞye0V5$0םS1Y҈"H?rօU{xf\>y|DhpjBn̘娎v_hJJ5`3:A r ЪiLPŠmn{Tz1gKN\#M .TX#.$C` ^E^7Ei.I_; dGq#t:3x Y(X5/ cuC S'zZ%\*P55Ieli F` sc6(!'Y5z:tERb O`eH;@tvP661lxTg A kY5rR'C̞k/[ :S\CEç^XZ|Yx[%$Yc &ح ]ʲl(:Ž񝳂;} Jh-bxq(e3UЍ]"Ӑx$vC0+yP sMۢ3vw"KS%`̴/fyx^Å}p{;bl @o7P3 8kbC0jV+#J+*N+0AXыP2sC?U!oF ) nԄ)@í0XL=ʝ,m3h:x SlRe5;ju{ZgY5q(&]^ x.v:SN<|t&8t2( U8ݚHw4UTU ּ"dAXnĉݛP-OU0Sf)JzrP%\;vI_CeX-|'zj66PE 0 A/p b1 }@H9CRY Jp 1šy-(K|@`/$6%}b O4G~( ExVXBIE/eY!TJD2W I >1`> UnHd;HglSܬ1CLc*P%[/7åJ*1$QAxFqw@OeXxmoъ@O'{^Ihch!b:` #k*ʻbd=CNN1 2N+c3v1 Tq0iT(zK)#+ $CDm%S]/T%RJU+*Vb*8EI/hUDKhD=m%JP]v8ʀtJ< q!$WݾMZ6;֧+2)JR $ V.7*/[K%4Գ>z`MsRvkuq(nnۋdHZSʺ.[5H9DDD*WV)# 2 H+8mHM{#,uHso]auƛV֢@6~NZcwH9g)k˦qKMJ]'ߗRR.5"a*n"yKqZگS=_mqJQbs]p)ȓxH" +xSݯ7Fxs0iSXS!z&)s-j PHײ#GbLLeGG_m$ UZ*84NZZG"1ǫwz5?Mro}E@YljHuJH$v!TaC|ӝ#6vL.u+[Ut=;AHqjkTy# h:IGGG"y $O( >85)gPYn$RJc ,&6Pi&f옘'CJ=*\EcJQTKh69+q)>@;ZX/M#19c= ے,ʡm1y"SILESq | ~izy*mBd 37+3JQgJ$X R͒bHyD(s|IByLD05,2q2IQB'H!QD" MoPymhԏֱ`KPRJ ( 咳$CJ ,0qIڪhP_S[z=Qda_Hsm ݬcen|u ]&3|t]id6b/Vin1W"_1b[_z/k=SYK,H(ˑx6A-HcT6k˧zg)*}dėsWe6;%KowM~ӎs4󾹒 (.>' +['VA; 94L:K/8< -C#}4Z\=4k({\X|[ēSֵb2'D4q( &ًKѷؓX?Q/ "rݮAj ؞#< CT֭-0תp2moY =3*04j\AP!? @ tE0;#hӾ'9YHCР;";c:l !ݱ%ȵEqŖS?!0*%6Ii Tq@Ԉ6)G2"X x~(fSH û a瑂1VH|d36Q@9isB43s"B,C\Y5ͣҴ! h #t,1Òݛ軜KEq43p4Tj!ǂ%6ZZN89"@~XӖ4<̈KsC{ ې+8jL1[мЭ9nQPL;s秒ݢ|z*:5j )7Il;II!ZL1HD{2 )E-?H"Jql#uϰ~mD`5ډҚۨܶCbJw&0H63Ԯlk# Lbë  Sc۲%9NB|x)"C1N4}B$ƻ7hY"ޤ: z1K|u,:+4 CLQ(3È#;9-T) 񇑻9y {܇̺ïQt> Y33hcG;ù"jR af R1A>M 3kkϮ 1+9J+YĨ/sHYEB1܈ BאH~ N4 ڴH5T?;D=@QM>OvQ/LEgŤOt3@dƭb 49 A;,P2XI 2䴞RZwRGmx,|i.#֐SNd҉!-S*hJڍ)S"E6OՎMݩNmYH߈!ɍ̳>ِTDsAKݳL23P}RtZ9(#U[Abje""st`; +5mD1JC\v51\E @k@+V٣", r^\1A]E1LJ f׼ #i\+/rW<Qe #T*^0X }Ae."*hѓKBݹ/P.}=5a?2AX5|H\)AlfO{=9]=ԗB{-\- ,ĮE3Rmᛔ14A+Fۤ&E@`4:P"\"}‹MXQ0{/_mv<,tL?N.]d WA4F~E4 芭Bh8 C-Ҽ;(Cͤ%q>Ce aA#Vh{h(inPKX,-"t\_Qs@SBgũjtnr/o:a?6m ixwJWXmzDڤtP./VcgƬ?j; N|3ErB8l-B-;,kB/X*l%(1}vxw㫏 Ď\$k>Ai|(}] vm%wܩ m6'fniqNPòf\@O# PgV- ȴ^C!2'FPhĞ "1g' EoD}SPM_4&FҢy\) ¢4'-L:d}=QUtL oDmX#}^k (Ny}R6 aόdN1FT5*7`)xE͡;פ*KemgEfǗ=0C.tFI_t 6jK{T&(S *:ڳҳ5 +p&Hb "lF!Ph‡&( Ȫ ,56"Κ,lPlȪ2227,Mj!!D-sbL(#ԺR$=G숲3-&.m{=e'p<<3ր'ɂo;5H:+Ҏ"2" 5s Sd1FhN%E-PtlOA8n'I)n+dSo_ aCR@*Uaqpm{M 550j\P));*ӂim&~pU*+//Q鵰{!~pqc!AeG礟ۢIܘjˬB {۽-(DyB+n]t<@0 .[+yZ\E1$PvrwY׭h _iҼE(Vum2>po6z_Kh d)\ЕbA"]@G@#"7b]^%uǶ  MeyE`#[*y I+:A' YP}~!RN"qfvzPf\ז"#"4$ OvOeFB]kajbS$鐅8vk*lh񪲑_+ @qu9 \Fz@"Ǝ&%T 5A|c,n@;"bY e QuZP/Ǵ"ᖾخMKG! j!" I0 "Boܣ&H,,+sY\YG:w}'e+3:"~ 7y0EE)TꄴYs!k_tDYcmS!Xڛ_8h`Y 7ӣլXD9]\'o[0ΡVȆ>w4S{Leb?wU瑷qp Ө>O$rf/+k c㦇Gv1g=anV 55(-n5^#?n-jnCclu|TvS8a S2( ŠgѝʀN丌a[˳ʽ+Z#l抱Bd E݅(N|zn,J@/#2nGuab%a6+*O!׎֫V$ "$knLIH(Eq/Pxxrk@G,JlFe "t*/rnˀ$b%lf@"H"# XPAMcFԭlyahk.kJ~CB2vnm h'oCNV"jtetNx6PNA(P0ȁB0 tjcE ?jŌ,fn,VЂ!p+ Y+#EAI>墲$BB麴@Kd ԣ=C.g+%VFB2NqE i~pˮ2QpHuBP"=QHb:Ir~Xb=Q)q?#1 D= fn3P&2p,ީ#no RŒe\~C"=#hlP@j 1"&)LB"tUľ¶(gA^XBAt͝'u ))F7oR h.a5(ro-*u*elS)'dXuiJCy$Hj_%QQ_4ɼEW4}sR$A0+QJD"nd&2/8aJ/!vAeB/\\LwIhY.R rк D%:8p"Ψ.%ōN D@f˔R>snN8 "H~Qdʠ't +lJl̈`^uq="*~IEPfTTpl2ܫ=JQF;gfįZ@fB@ dоB asA^rMD@Far:yZ&*ɶ0Q#r;AUR):Bm7ǞD*Whŭ2 `Fh|Ox|VYTl,γ +m@9g):DW*jSCUc,F"50p4_&:m ~S@#jސYq稄?t_[ `Aa,,w\EqWRLC!grU^.k=` p` '<O7FZ@p=HRF@9B&:TtYw L "T7"p.فEb-- +\u%v3$ I抑Ψ(ҡ al+rhu>AR;ɿVXOK$%7hYg_/lξ3G":%_'@5|vHρǟ8P4!F XiiP#x펠\N!W6 h.QT2Co3B]sV@\I7S4gyG6vi毶q7F_T$Xٚ@ tֈP@t_ _H:c%b(F˜ʑu} Vu݀-aBL;Q6#0 #AVÚ~ZaiKQBI8 TJ˔$TT<6T7`x*[$)Q@b@V|.n'v3ޞQ!ekG TGc'(gN ELP#aXdgռu` | WFw  J Gix!7NBwe>_6tF9#P+s CzQ惑2%sF<ڝG}`C"rlj:Ha{&L.$VXV"kjAܛZcu'pD&k6ˆv>ZJ<{3lGb|PY-KOM3,5 >o*3}xBM}BlF`l)R:xx2cz# W-#;@Bk-G6bA0y3 -Db84;uc"|߰2d8MC^5tU¸ah=\b27-),]džlL*Ѳ2!U$aoG@њkॎ9pG|3i̥p`U+fA]8,2,1}-o[#E|.GL7д+3]Xqyd 4$r7b[T@!%Ow2k8#@yP5}=.#_;v`*ZXP!XFrŹB#h~Y2u#*n-WB~8XaYY?kO~2 ٕ=g Y,y-:k7H^5)(wݙ~6}VN%ɞIЎ6j"K@R!;LӉrJ)$z>&n{> o!V >!`"?L?aQ8 9DI!A9TF#"RiF4 G()MEʩ8EuQ}¥huh#ɰeNEvE D** DUɥ^qU"]n1zLA. ~bV{;Z j4:A-IE>4LƀBF2P"}++~;0pg._<#Vm !Kʊ.oPP"-Ȱk )* Cɨ҉9# J x4t dvɐ:AjҕM"8` dl'"E=4c&< zKc=> JQtbK)u[@̹ :~-, Sr&T9iU+ۺLR-k'SnɹtJ]?)CʐuZL.UvMbgB<6̬R֨@29OZP"5X BBx(sQʂ* CjLSBX$ .:D[=8֢'.V̚.F9ĉR8tnPig+gdT4jmuz?nRߩS\.`Bĵ!l/ku 2Au*P*E( ΈtX#ʨk'&ɏrnI7 pn,׋SZ%Ǽ>ܩ:_7TI(Pku?Q19b? kxBۓmxCw %HrVPA=B9c]xN-޵eKCAh^  Ï9} /bb_ $ux >:BvP>8)'i.Bi,V&bQ/x)E8p 7$P$kVr&!hX[V} 85Rƅs Ƹ c {Yb!cT.' #8.;w2ɤ$U AӑH9XԝOڜc7+$\#g]qMv%H@$Z]l#)lHO "ux:?+ <%};m&#wvtAQҐb' dk9)!|ch;WZmM6*^=۹l'knrR tąfZe:#6aw}|B\H&*u4ǭ8~)L )Sܢ̕8i&}2f$E2( Nu~:#7~rl1V%@+^eݸDxb6H")5l?$MhJT Au2MvVQWmLH|ôH{kRh(rRjKaɑ9Cvq>ʸc-B0 7'/[.j֨:Zac[Q"Yxˀy92?ȋC|B?|{x~)2><;z┃;>B2)Q!>?7 @9˪5:B0c38*3@='=#Y-z=' 5[8/ 1ZUs6csE *Bc@⻸a–# 5(rǙ M> n4d|p"\? iۈ#5.H2r)aCL !kxtj+¥ *U:y3#ºOHsȻfD²'>SHxa&B78:c!$|Gl]qG,/ظd20錧Uw֫,4E `ZÌI<Ytm1:9qG!kC"P:P~i)7qSL@%0 Ԁx<-Q/jWx`"-#G6 P3wDH/aƲK U_k.l#3#ԸK˘kȣO6 SN@8 :: 0HVR+LJǺa͞FK >(:LDBE;<q=rl "z1jQ$N4O9#H%F;.=Ep,4(ڃ1ljXaTۗJ[Ҽӱ:>~s?iN b 󆼭+KT,LWZ,Ac: YwQ7lVV]mn麍ɿÒKI!PyZO2̩2T 9qdD3ҽC# ⋋!8[pɡ0>p ;/^HhRϑ1P-1 Hrܤ}Dm5u㫢ΥXQ2#NhN O5Q]4M$,K8Fڢ5NH+ԣ9Vt1aVj⻃mg3ȣVb-*I2MZ-⃕+1* Hа|ra2Qc>IƢKlj4xۦ =[12PqG;X 8*;2WF5YT0}üۨUmg =DuaҀM!+[&b=$lu@C\Rl3S(WPhHd;H܊@5KdMVH> Dv4?VP"uӉ2LrNX4AC<ξ8rp< c}?5BܘH]M>""~@\ek<ƴa褟5(v\ >ciGկN ꊕ(=eAj )|J&VpLu03Һ%za݂Ktl2}DfK 4$3pQ^d5[kkR8YBKV$ޡӞў }o\yhmU2s;+YءP. ך5c^˞T# ̲$ >2܁ϽkT@)CEzTr!g*8u| w #E2;{R'Tl͎"<Xfo׼᤻0 4nR{IpEۓ|w ,5 PO*1D~" QCVC_gpgXI."M썬Bu;W_>Ś(CUTT0D AҎeBc%4t4C$V/-k3=0࣡09 e$%DVILPbڹpAГGgg5lVD)ND mA D2^eӮ O4l9 wLav .V*[vR1o\$A>ku}A L2ՙ7նGDY!ܽ&?U|bbLnʢC:"'_<*AlAu#aT^^cb3K:p#yD&OeJ'QS,JSȧ-`P[ Lͨ(^O P놲\{Bm= P\rAg0Ŋ17uͪ*lm:P5m |^g]a>7gTc].f|h4qslU']gds'#i =?`ϸC C`@F$?(\.>cа,# X eҰ&dDw}aGCe0$4ZLRe4 [C@켊‭+<*n8K/k;ABxJ ­zB ' (j0@,&tD44@N]kR8jv(j.EbNJz.*YR=- RT-R+v72݁kG4eLk~ǪRv"Jji'O2J+1۷,KbB2{ tB)d0a*N״|K6?!D*O< "ΐ2=齴Z4eU$j!NzYyhju[T'H N-dqöh42Hd$%)D@HmXޥh9Tk"Ӽ+bTE*ybf҃ؐN5v?ZᖷI\LƲQ`BI ioguLY{DpTu1G uh-!ZTy Jz<3?OeH0Pq0z P tĄ67fj&B: ^b YH/(?IK@a7DSN[l'x y +Kȧ(r]$Q&LB[Ls1qͷ# *f͜!yɻQ14KSHȣz_MhL)rȲT012Ŧu,B|dǒ_W)szL9nGAq)U_]pᗫd'RV I\"1}&slKWMM<}vM9kL4% {a-)&g~ZR1Ęy-,=c${RI3JHL"#mQY h3(bT ˱;/-1%2Mr! Ry > N3mtȤ|B9Bϒ I4%] kG4Tk{^@+=!d"?|`+ k4t#VYD<@'/b_ lJKRVĒ4W/񭀢7-ٗqpJ.%B\!(0Z{0I[G T').ĜbƢYTZ;CVw02"((! bq?Ua?r,r>$WӯlTJnn.gW5g δA$4~U`JdK=uJzy337Jg*`S qˁ{ґC)0nH9beGiÆN*|11jU>TUB cga?3i4:`Lњ` {W)8tn5\b,F_j+If)!4g((\Re94 ]j0U:YwpS^(S5? -- QLn(qGcX!ULHE#lglF7Iby᭯h]eVdH`?hzY.e]nLWZ4-4Gܺ˪BvoޕKd^cF nJE2]ߙzиY]vS/sHg IGCܰ~?gqN u?=#X:O,-p5>we>gSe .gxA=ʑtIe+hY7Ηmʫ!+Zu޶ͦn?7@eQbg{9Sv?<܁SRgJHV&c_g@vcӋϷpJCsng?<\=I;jAnUAYTIFO2lX(EBxnnZlZƨO8+K ~}'#. FK?z"hA@̘TNnz@aZ$Sj̺,,(h`feNTHgi`Dm;V"hqBڂ +O$Lo E6J pЊpID\ht@7=j˖旭݁i/]ˊ'wDϔ0^| ESzń@f*jGLZl6Űa*OWLeE yR$g5i,YE \#@΂JNIM\A0oH$(}Q(ubkf^îJhfSb`$ 6- Tkt,.V"MNk@k `Zx..DB'֗0$)|d!U/Bp("$:v nVrhC `?HziH b]"+&ț&w-pR7&Hıl<( cDFDD&7Np6|'hPE $ #-> fQ*S nˢ: a+ LExڕ*D8ƿ@ o*J-8dF@j*̌@ !9钧X+PD ,v@CخLhc:*VRԣlo^dMOhjjƭsg" 9g9ikTGHb,1BjK]7>!I"k"ҪۢOFuޫ3,.##q g`eIE@\WrkH%:?U&] Vq=bM)φ)Hjˣ2VfxmMX1&񵊍-(YQbɩy"ô#bK$``UlqAvHL7Nuw֡Pn&xneB#ai>d &e2l5$ "FTõ! rzϫ>m!̅=+"<-@1)L %+9mHM+'€JTQUcS#\1%"MBwM'!*^,\C m7)Rh`WF{h&)gVn=yƙ5$ IoIXN )g~[ T-XE"#CS6ʣ+f&5kl@U+PN ?˼ Ѿ*0y&Yib#H7o@XVgNOp 1M[L "QHʄn<` ΂_"JO[|O>HDB)Z(fJ-pqdJtgr)j.%20fnWHi&FTC Ҋ6#ĐĕlRjJ*|gИ#jt".Uwr5$slCLB$ '3Ev+Υ&P"9⧓,3hAm^A/V>E0[YA&.LU~~h=X8(+EǥC_?VM/ L|mbxYui++K~TvP:#Df#;YMf.dzoK:nkB.EѲe6`屩s:mQe[Td*6^ss *yfW*w4A6)0U/DynnmT?Bb0Y'LDJWl{ liy"Vl/8j! 'c$"/(#WQ.rf6샍"D;r^iVMF1$J0Lw|z.+( ,n95^#)Lhyrf* ɘR_z0 /@Pc(sgO~aF5G,&Pٖ"BP]:A.iV&DOR*2JYk=(E4Qѱagy{ϚLvh%b$A>R7ZS+".c9l y"5b&'DžDYw!|T1mWE /2cyl#*7WO; v2FYjFxYQ1O!=ʖAe܄ǖqܜ" eY2]VtJr0Ey< ב`h Z}ad#_]ɂx7] ؅@"9^:dBIKrDMz5KEa9c%B첓( Ոx 92qWiV3;"WOwD=lznI2]N6)[g>o}%R鮉0+gbe[6*yt6hEςE2.$go&Xw 7bUrB& U#f˚IƨZ8j*I֦#Zk>(Ām̦+cq'hj-/J!.'$p7?`EFJt:1փJF#G6Ǯ2J=H" 1 I=Xi"ttSA:Pdf- ΐJ$[.Pi H=9-r=3R?m Y(x>c ssB""9s%twIKj0Wz0k9[ ȚG\Kʕop laef4Hk.؈):'=:XjKV MWCzrkc*]m`L@G@$S6EY6l=%R^gV6)7t"=WjK~c浌ՕW2@I1UC\Qv} v ~ZQs6'S  Nke~!=u@U*و9rkcW>gy.)8SBV9K(lbY *$lt"Pxt,rpLa*lReA7ΛStKRG:߁ Q<+~oiD8W[`mlXH&E|V(Y_S.A^~W͐'ie6}Z49DX Ѳ7sk j.uLi.(ȕz>Q1lm$T 줱CdLjʶV{FN(}M1bԐ!yz (FP dRp4ٻq/7dWLj3'")1a1ץouk#,lDa= ˪Mf F衊&K}Jt0H֡Ue(υb%RE[ E[EӿA;B.SnH̗kE# -{FnƩS(26E 6@1r:g 8QhS'U\Q] =h)#Ҵ*YmoFK􉰃z;KHZʸQ(줺d@h|Ih$S(}BTxM4#X*#$k\i2Z1-()|˟AɻddapY|=̈j0xȪU k9JP0ۑBIQd G˴3RXګ آ ZGXBfF3G Yꛚ2Ѥ&EEE Ra|`|7^K2 )$"q$#H!΢؈=7Dq~ d%+:Ƌsbі !q0+k"KyS4 $)s jID:3 tߦa+ hC+hIs ؜:k -j(zZ^AԷ%Nl}*"u 'ajE 9c<2G|['M)Ҙ/^4%&Yk 0e8(B?B}L]`[F7tJfBP3}2 }( 1 r7{2p:]3!z?롖5FЄD8z~c}̘|ʽD%z<ԡ-JEKHP<WKy KD;0ԟ"\,HLEZ'}!@[ķO@5Z\5 ڢhDT%Kb@g\#ZC'4?`D"x4NAO *X|RP %CƱ7Hex4F)Iڪ[?RzRK|$4bt҈\ETC}!;бyJc$S[-o^V$ ҋu̺٩hr8) djrPCNF=В( ]\K8X?"Ȧ 9ˏc[ H*,-dPbY8sѥSJ5]mb }!ts9j_HaZ v6a :0G =h1ź6._1+ P=әcə}tv0:Tιx QcնtLU^#BU&Y:e~W>M8-1ҭaU~&: WJu%* =VQ({ޚW`h`{+d bLU#2П-C:D%QFfLE5ݰ<Š- 2`>S*/խ`+UMJ HV‡R,3.cU[8277)5z,} m+d=Tt>ĻJgY 9_n9FI6~T:47~vꈪ cں-h;[{Y\)DFaR‹m 0I Yj0U "!>@.Fx?J5+*ءZN"I EڀMZDNrrcJuGe_ nE'K< =Խ´n8, GLa4`y஼lbnuh R? zxmcz fmF6QFf#mV`dt \h8ڥyw4Z+&" K}D6q]\uºq WRX$N28=,lN榋!^=œ 8% rԟôgܣ^qeˡE鿽v:f:7Wier87Y0} ݓ\/NtO[n΄) sƞ;0\mlHCFk¦)Ef|瘉7 *W4ąL9cTȣŸ]렺9v@tVҾo8OkJ/9ÿH?bT.!o,蘦tOfq*fIG?¸YsNz8>K&k ٱ[K)v@ NztCę(`O# !@H`€ؤJ?bQh FQM~D"dA IҨ$^L]?P@qDĦS(;M m%$S!pȼ~%ɦH#PAcw?+PmϚRjL,jE5(MòON2DU$T@6g%X m/(T56Lu]J&S~Mp\ @,_=fݏB:f镆Fb *4J; k"3O=H%pM:˞ D#&KXP=#dԵU"LHʂ$ˣ9QR> 2JJ*Dӵ(o>Һͬ'HqBi-P̀jkʑӺLnhH4CDj?hϴҎ@B)5k;K0ø2ATQ UJ(72Eu5"Lsh.d<'q_%څI*IBՈAoL9ԀPG2]wp}J,ܧbJj*?(-ܘ_hv52ƎzxA)5zM"Onʹ6&h$-sUSE6Q6}br.ݮ>#X$440(3OIR#.NvX::./MzmnP) GJ*oa N=>bJRSܛrb })Q_rˣC5 VL@ttz}>.Ȝחix/wN9CK3I65y*)r~I5dHfiO\Gu ЬvQ>DЙC:?ɹ7NNYg#vXQs,")»6Ȣ7,@{!3$fY"]k'Rk&(ȰVjq &g)HR(0dB!3 {CazJQ ]5aO;3MPkc`S =Y6? 1 I.JB$iw\kP%'<8' ߊeAl?,!@AA2,x6(a~CU&{ m_9*v0 s'y$`ҕd!AEdKLp^$IkHI"Bdar^%BYh ! 93,otc([$1KBNuز2oX'$_ HXGC/&TFdj!sMN: $dg+!G#Y-Ije.z@ {a(rh#Ch[ǙE(5fEF8b7`ihyGwG\&Y1Udjs ᑙ$'3d, DJz\XSYsY; *~y%e*Vv'XeR‘) D =J4p5;L?%PgT{xT02M]թ'Y!d1zbQ)&7T\ѳ~X,~d(5 X܊G£ykj riMh R,uK/Ђ_z)kN5(IP5ɒ/Ԩ0xV[oHt AU85{g'^FiFc,',?Fif_9)(ޓds8H~r~M充{@2fdpRm 3ˢ^MN3\i@*Qrn@ʝ:::_KFD]g0mۏsaYj^w4<Ash&͸R0[/<1-aDy ~F^ 1LВLn@"j[[? -X|LvZ`ib 茠MQqIT~?ܛ6tntᤵ4uܐ;}#$ӽ3RML^3"DH0Sa^U^rWUp 2Kkw '{ { m&dmjd?ǭ;=ip ~f*^/nZҩZ O?)aw k}4[Yg[\h=IB]Ђ!rC@0o0^^:'wa.!xcE& rh#zn6mRrL":b#G̯h'vAg,ۈf/.tk b@ugp* =JgsܷyTҭa )JgBȃ"YֽjFlx~00̹z갰4χ0TGN.SGiĦthQ㞛nZDd~OT~^f$f ݋EJ-f!ŔSIN;ow'Bpk@kAl"ۈ$ % P<%рʶkTe0 GDz/ rj)m R$-L1,bO\FjmK(8 wQCh,FG# (̝J -mw 1pbJmrzQ0KpjҤg1'JmVa`@ j^K{)0NŠ-ܠM&xŢ0h"lRFh.51IV&m,] tgӵH' b^# {(߭rJg,"F6&%8P7㶙$ݯB(lzLMvRخ&zipl*t%~i(3 Wi4j\/*2L>mǥgKC4xdni#_Ks+a%J_'31 mh-eie-.3Zۍf$ fo#hNO+$r}O /&ʨnMP\|q .AQB+<*Dn1$poGLI.^9!KGJdj(;m0o$s'Hag&O -rAƋ'B."$!,Ms6SD57d`/)U05t(f¿*L _E$^ň ԗ.eAJ3o2ÍV*ֵe6(Brӣˌ  [al6v \lQf"~uR4ͬp/ܯy!ܖ нЎ!K>Hy-QQ7IT /zsC Eɂ+PDk{C0N ƚܪkrQ' IpK1`_$,ҩb@c a>fH^R,qk;RDTKp. tUSUPUEn54'-v0BܮS^%Ь$)#,kDYK@/W *\R!J͕aMe `8e s~aPn6}G T|IP22ٗ!4~T:)M@evYȷU7"-LgW?DJ5X0.b%*ee_a_BBMr5AtRirvWsܫΓ-5[m<4@ZrbjmWCIdǡj K`=4T$r -ʵjy:YXl,}O '~f1ĈB܆d壮E j%biVm6\: K/ *,ƒP#ƘЃNNMȭ]lpvN$MPr-~'‚$YyZNs}b$:Ȳ F iP>pbe ̻ztBZ,Z3[i@CB\ U 7fxTGxFK)Q'Vb䮗Foa"ω955vfY3 2g >g~|~)EgInځΗ]7ۍ+zCRt*TG.)[Ea{+F JKϣf&Uԗdbby}yG/Tq~Kg4A*XRgHP=H-.YR\MFQy(647@ J[s&98F{fxΛN~u]2Th]%=d̀Pgnr}j<,_gXJ%E6SӿjHԜe` E&bYYy!Yb/0`o Q84=֪. fo .u `%uԉ. bTl'ј讱r7I!yeI5)ry> R UUM1'L5L۸:6L./POT)| W|!ҡB7/ m2?jmB_E.DRr<Ah>N?z4/ Ȣs srnV' .ӃUh1ʍ'S{c nq "KـCdQ+"9=nC4 BAPh 'rNn!"׶)Й5ooϊNe|8 .*'*N>TKZA6N0:&+ȣ)[+o㖛'iVk; )Ȭ$J+Z*KZnDhcl&n8q(7J}.K()0> [K'6W5 Ȃ*1$RMR)"33WC)i<}m*Jwpo!'bv(J*(!F#yMu^Sҹ`֦Qger JNumq"mӐdE*Iޑkxǝc;Je8܃3z1H\D֚H%`H%jUvKa3ISSmHY JOtXIT3 26GtQ\1=dsd*AAF$f)Ap>AN-eAB-`Fa+x.G7<"qpkRf8m HTIO:i"|ANY @iLa>e9*.t3u] >.4.%8HFWpf0ecO=*R|4PTI @ ƃKri \-6CVRשO2u̙*ej2B&vJ1N~Tɾ'nV:H iA7*OEBR5j4NbRO*:q4I8U ΋^RUTH`jUtuvcL@IWuYoy9JÛ4 LW<$lť |ϛdʊ U_9&%ZPAӨXQ[kp%JȄc!,e,Y"bc>m_Ec{;EQ-s7NKXL@`a'B˅̆ '':&W6O»jGs !6%XF)bg/(RփL8+uK&'?'LN$LV'U{XS]dA V]#2,0$+@ nwb?oy#N1h$y* {56lN^BqϰP䓒L `gi Zx&k*FW,#3{0#y_];Z3U,Cj=َ9wQjZOrhzą$„;`m Ap씏zWGfnFإ虳YmF(Ԅ0(>!ɁH6B#r%TBl{.a}L=Yz*>GFӓ;&]#=CDڃJ$UG:yC+Ǖ͈?;A;O`ݳr^\B3cbnVCqKiFoi `^T9S)bb"BފR6S%2|Ẉ^EI2Li~kN>zysޮzy C6Ӯ%X~#=S~ ˞SP 9!J++3i8KK1V H;"i8AΊĒp(# y~ i.<+ hL_B#wc1% x ފaVc- HKD .s0k1D_$Tp0-G!xp%8l C䑟C@\JHѓp =}*)~z`#+?rIēpIS;*ӂ]7\;y= U 4lAѳctSGs?l|ȣL`#;@' 뇈c.̑IS-2?Fa :jGaLxL5tO 2;K/Z\HZ6+QY 1:% FRQ9cp{#r!D>Jc:5*P-=3͐Dx ZhhXϴv*Lu]ȁ׽HDd#&LK]9Q=.t-K ҜF06$H9ڼ}:63,SSzAPRz\ \^ڥb!a4: t>Lݽ+KF-:;$:XSi XO [q^~Rh7̍jZ`ҲJ5%Q$bxbB ;"ArEq`l5^2A"d-hpiS=bIJu~#ҥZ 7Z7 zIMgshYD1h6<\DvCiLĿ\So `ZONޖj?xDC`pXT ~`8.G_1K#U~`d ?,].͟и+%(/;Тj}CSs> ݄cX k֟@L I@yv}H*ʣl泋 9 ;ξƷ Y&D'`B4+VkC2/-r#\3Ksq iR\%Bm'D<@.ҰhkJqi*'2V³ƨHK2#42ݫJX ҌLkk# bꆎG8r.k8(rS@Cʽ'::ܮi z5l|t'8҃4Y4;DT蛩M+NK !m~0:u2 =M{E_ I wJ 0hek $ s:@ E-[Is8RlNQvSVNH)׌$th]ळjڨ"4rwYKwRPEOۀp^jFѐ I3+H h6#d=0"2rK*ˆ;Hv&sYE);;: Ӣ0>*ҲiuD MYK)1p!F-]y⠼Ӊb..2l)!k~9 Rn-6d4Qp!h`? P!y@w_a~G/fZ@Ahuڛ3n3,z(-ړm %;<ETz"p0+5!+A _`+L0#\J TD}xđc`{j|$,4u(deQ=BMRx91FiyZQ)pkPFWLan~K(Y8xD`+JG^؞ UA $Wڵ0H!>On)ڀD,RsYBY@t0gXik-2>1\h @42t* )G@,B5@(# OcD@8 D@%E Z/|Jb Idh/>X4(&f2}uG_ԹvbF"G8jUD#DvyBHy>}F]]/+R; B;uТ5;Nm)|2UtS¿K5/Is`,Bk;G: mZYxvE@]IMdwudGo)gԲ#uVhjYS^#Z} H'+O<)kԂ#JT:);/ℍ&ɋ\^3/$mƽʗ J"+Z(I-'e -zxӪP Xn{\` ^cbǍO+I0"@!܄E|*Z{Q;Hj+:'4IȺ)mF+(Ȏ4M"Ӯ,a'$u.j͉丈.cM))eVHk7\UK TG;6,Sl]W-;&-SnDDi!a!t~_q`MxR-d_Tb5M溡eʟiOVEKGӸ:_ ֥sEO2E5g [p)ךN("lyݼgTŗukwH' զ-t j3~ÈZ1.;S+]LZB|/ P~N^SQ]FJUB>qQ^4&l$}H\!|=flV~cq>r&FMma YwЕ%PgI_MaOĒ\Q`²Z? H'*ws'+F]`Nivujd)*VtòH1(y=RB Rv\P)4z:ԑv21K:",p!2sDQsFΒFɅ.~0pa.hA@;Ea6ftXp#%dž<S'J*p6VH&K~a&킎xB\ ٢(T`1SPŶ4h[+*!lfBRBs2^p.N]yZœ&˥SK ' ߛ+$DT͔Ar ǡ+)%"&UvŨŤB.&eBNi4¾bv )Bl:,EAMO%Jذb˒Qr4 WXu1zsl>@VSVjnP1?ݪE/qD [hk}^=h#؊@+4O|HS?YíNAb]VR0y&! ROƧ@6^&A-NkZ,`4$:}C;0/;ޛya) dͼHwY쾳unVI";L5mcNNhvy#gbyK@6UL4lH\>D׃-ovnC/Ԩ%wܒ-xYZ &/P$Z^O W2foC Nns~h-BOdR3%9/w2*$5δyD! br)Kh+vlkRq|uVB?]`ZozbRafȇǎUĐ@MtL6]C%FoJG4Ek i:bX١'` 4#U]O.oߩnFINe3)ԉb&LV"#Ԁ|J/̋^pԢoM&)]bМr|*XvL00GиzL:ix(Ž"U`Q ^tNX'VF(S5|k.w!F6&nhn(}ɢ-PftlT,v! O* x(ࣈLPÇ\m@hXP,dkpwLHvGD2EU@Nr)28͌)* P$cBc"RB_>Q.u&EpQ4"4N<0g|j4.oOp.`4qP%'00bRRe&^`BX,JkOpL@H?h@4¢xEJL{C^D*Lk&&nj&6-o#pA Q921hTľԏTj4m/;i=-|2Dxd`]R rBFE ?@xd82upC."InfMlh:(h"B4X Mأ 8k2Ȑ B }8S;v)E8­4qJ|28OǏ" Agxfoa B/Lx,18JAm@%ْ:}gXlS`_NHgޱ,Mc 'h@GQ*pE p0C2UK |;C"H$Ndӡ*gwE _stSI}fɮgF}:I-e9!2HBȲk5zS+ )=N Ռ¾x-/8mFXn[i|ޯj,9Qm.Xt=¬E,I]FЛNm8,4ㄱUO'M*!nP\)"^#X`bQ~$*XlB-ge)'j}C)W( jq [7n,vm,@VJ(#eQ R)cQDO4Xb JI# L5O 88񓜠6>+wLb5[UΕ?4"/^y9M>b"2녒ҨO Ҥ\` DZ45DPf_j=+)BV%+VCJg!G|eTx- 2('+S2m H4 V3cq,ߴ`O FR"GC1DVo HÓm+pt&0>БCЯ┉J}sR&Y+X ӖN"Ao YK YHF7X$YՋw=VKR4ns@U:]a-C7)5ϨsU8s?` |ӕut&kyZg}m4 wTHzFȼRÒoFK@W5 Ȋ.NS",,1jħCV1fcjafJ3'$zr Ͳ YDGtb Q9hJDFq:2óD#2HvSbq&)b`kUoޑ?F BiC!sh ?`_#𗱂☄0Dϑ%+d2üX-v8J4͝+7&2 )&Jb" ſ =}> 7)=?–cW %8J"k?/X1mH&ĕ'd:|nPIFd&9) {HC$sSl5O*,`hK cso=N/V+j#t}۟ E#ZxsHq^!Q62E.6E;2QԬa/8 h+lfp1zzrș!.HĶrfaa6F71!Qd>8b^c1bIjH%G ct&VCZM!*1gz$PH%bX*G~+7VG8OqS6*#'D#bgT1q~dgʮ5;~<I2iR94j9Kz-7A۫VdrMesmYn!D W\4qWĵFF;t:D9G`L"ƒI+ZSV+I'`~F&J:#;w WGd$ hʲOK-N-iVjma?dR)&YW/l$Owp9=\B ,e<# =2=L)Yމ}d+-Ǥoȧ?QCWĦ<~T\/ U 9E2B^,!6!4div1᫙q,dNRuGtB/>pnfK$*B?2`)pn}  =('^n!sr7]T6+ 1cz~Q:FѤ>C-9]CUS/ PRCR Ge dusH%Tqo@(D]((0k*;3a0+g9cp ,*)ûâߚ'Cd #s +]O1.Z'D HR0d&B}BSl@2SDF!!PJĦL.Y̍äP=GyxWBi>DHI/Y=D31Ɨsۣ&JNSgz z?q0 7CCrli&B.íf,زAZR{KA&IYR=!,U<5 3+ zI3$$Ji̍!GH}-dm?>MwLD 63+ԭ<#¤+ٽԦ<֒P ;SC!zD33 6CQ3R@&wȕ8ܺ@X1S20;4zvLd3\gLPr@ؚ[MsP%bAl'T.Q,ݛyJrĿ3wX7q P+cw1Ё誜DԵ藩M'Mq׫E;cG ~ $ۄT\ʧ*ͅ12(F)2 0u,,J\6G[g(GХڻ1罛0ˋL*ȉ#?;4N0$WPrG@SCQ9K"ÐACOz:XS( r8~ Q*͖ܿ%4Y δ%B⬞6R q9S%%٢5Q`)7.t. !2cAX˧֑ٓLLFQ^y_DYG`ÁWQ.O^\8E+QՍSưTe*#:D "J .vZ5(M+ \`c'#(N ذV|2Š|@b H!έR9>:71:P:*bm? UnPZ<_ UMۄ&~\ Y&OibxX6p%N]p PaD;\S9%#K9:<*\+.[0dG☡? ޿O0f?LL&/MPcԱmwCIEanil0īwmŶ#fvsSz%$7qsvaPۣy zVu˻0A$Zmd) ?<jY0"LH}P绕ӗ#̫vM*c@Qqq,I+j㔽%%òI?`(D$ 0F%_qx3% %?Q,Gpl bY"B.}Qgxf% KW& Dp %R F+(E^ꄂ T,pN"1Dr% M@ rIN"8iBvi, 9.r #EN|AZxnRM"2TV3LP@9NZ SJ\I*=X@G̿ _u t3k4,V].{{nt#Ap%N ƿh"$ 9H08h A`8>ppS$C̯b$ )Ԩ~ H0hz\AI2R";LB/iIǼ~p^*=)'@C\(cLrSgC|V}Ԕt=/0--[QJ|eN!S@5u묗p&.B~YњkfZkҖ5hO&GsWӼ,RcK9;fN$9hs*4(QѮۥv'B},}d e6DY11O🿒A,t?4$nl_qnOr3[@9K.~$ߔIxmN  r CQ$5Qn!ABtG|N.Ŧc>5K#HDSzS=hbJ\:WYĺۡjO!0HO3-:?4q5(;m->eqMm.^G LH7Bɔ8gcHLEb2?!0ox7;F[oM݂V\hм.^? &A]{GnF2{\X' `"UEIz/g.kI4YkIc#!ԏl02X%*4OH:r V$2ɬoFX4X܋ÜHfb^0p4&D4` 'bxX* gXg,g)~E!$́͢ܢ:s'Ip8Fn, ;(ioBJ@ b>aRc`4dxBak Āg*ː/'~ M)7 4M򝐪u6(I' P_I8BY0?i~` M 6E: Edb7 jR&N˃ ebbWd'RPQ+Bc\[.J!)$m8ƠP(%P$F\M~(Kr=&'( B"㎰ѭk*f[#T,I8aq? ARb9"qNtYi〡kZ &W*(d Jf5ʿ"ǐWpD!ҧ~ VPR:\\LE&*+j"2PCuH!ȚMeQφ? Kl&DuTPq1-p/F leżʯ$""㪝)΢ D8rdӖvqȨC H7ȋ,jxi8QfOڃҽJzr{ҤrM5 X֏-Fɯю܃áDs:DŖ:JvOPi - (~FXis@3}2B!ak䱓ʶX'w"  K</z"d=+,AZ(]‡YKlY0S#d ؃,h欶ϬLHZmNmF`*kM=VtSDlx#~T9L/8V##Ac%~ N $6ֺp.4}"8m!N$†"Fq!Biا2:4Jؐדa sRYCTi cJao k g,8^(5 J馄]t"k!+dCT7JFkbjzlPDͱPt>P6Oì O1{)mZ6h.|`O$D%0%+x%tM Y/䶈o,!B/anP fb#qzR'e:sTK""K?V6@:jXYe)(\$@nlSVfDS,a,b'ɼf68q.v mRt8olB2cvYDHPH=$ !i@l43q3&B@HB_t̠QA;Ȇ%*K\s҃OvM ԍ0x6mycVo7*dtIF%͋w %^4n#O%0̤:[ DL` %OQftjtӂ?S/F:vOG`UxFnnҴF$:'@!+)dž*Db>x:<8u '1ؾڅrch F< T]CETkJPҡeE~>o,SVXGULeH6ZsN&H(},xe\"B@$R br1{frRb8"*^aw//otWN80hUV$*CUGziFڝv8Yv &Kn~(orGų݁BxFA#;\%/~Dwc̶IM "f}*:~ψdjS4;7m9N' YR$L+ ֨Bm=CSy6׶$v:4"669VN+eo#k5) }JZZ40?u'%@T2>T5jOgX )Xzbķ (}^CE& }1Z>zyvQb?=ƭ.';Y%bij(;Y'nXXQBvgJg̷[Y4,gԀd84urq$?_ pX:c~;&Xr,KOM-n#-J5bv$ obi\w:]͗aAq-F=3K#N>l[WƜ ޯ)Dk哸ux IXC@9&K!Xhk 5xMJl&o{G'ĢA .#:'I+7KHݵ3j͉nBcq.yuoX\wX,Nn cTh5jva(*aj (DeM]F'/97 -R L۸w,m]Ea&,~V>S9j5c?f:ߍ&ݣoU;$0%P.X"f8r.8| ͯidJv:>!/p)+ vɲlLP:.7&Qb<)Cd/WjzPP/`񯬑u"(6|#<愔ʚJ gf<V>˶oX0@g<Cߐ\> AC(SH1'`X4 I4 AXdAB~Cҡ8*>@h{˰"D~S]"K]˺ut"*ʹ]?!HUr49g@ (ӳR/L*UǮXIhG=)m\)PTۇN॓D'α@zY^9Q)Zza6k|, ݓZ/SahH6}ޒ)J/P]/DXdy?"E8t"Q 5b J "ÝyLmMwbLP%0J9pS$!Q:Rς#1ay1unEp0md^ű V! @64E!m`Ӭ3)7 R ΔE% #i1tbxk/ CtSʹ{8tbHB|AJa~d=|<Xs*GGZ8eBNiYx \gB@F[X AIPoo؇8fk2. iU)@uFB#~".9-vefg 8Zc0ZzX8+ QF b'z$ /&CIE(a t ԷYB![ 麒BjqޭI& r]=^sOՆc莇ܖ"}fꃓp2hL!AP0B+6rOY"zRHgLgG̋;ȐLU7gſ+ Z0FA & Ƕ vAY~  u͋zl+AhE)JЙuxآ34SEmWt1Yd;M:n~ |7*dgXu+$Oɤ ({xISb[2%ºL)УF(uQH% Mv8mU9]/Cϙ MnZ\ ^0Uú&h!W:7}¼ Apxe;%ǀ[Z}ۢzͱIO=V4;T'q!O~Fuծ*IOϽKV*wB0UFϓ-;\1H״j&CdfcbjPS bk1Gw`*=m.0J%¼}JM#i WeŭA͍Z&N F*t`O+!p!R*')]`5swzUϦ#(Kٱ< 6 ʕ2i3{ 8#xS)P~?&l"j?@@I*]+ 8Ӫ䤊%D6  k)8_ İ!8830q"Yӗ_&C++8|Eb>C@AA $y$',#ܣPm1Hb1G{2:3ZHrC.=# s(|A‰==6`@AFb *͡ , “ _b"{s멡{Bڅ[j CF:),S JWk2)NeHjK˼ >EٙeX#S18MkC&8V)\53F`HP"֤O'HSaNE rVFUk4c#o,P8KUL)ﱫɓ!Y6_{?< V }Rl<ѩT:4Uh"(81D-jB2V`eGz' -{CSDɽ#9yM:$ߵx/bC˰Sȶ|)^FʞlX, FߑE0%mI*|%mY: r_ ӹ&GIɳ?uAag{hh-=/GTXP*ʦؗ.jY+;5%XV2-Xkd$8}Qjc+wnuRe!WqؑK$؎{e1;>t s SX>nv1RZv~ȱ\{ϭ+$D˶֍@g奬Ha@Nƀ$$XnƏʀ]8܅S=E"K1.شVsuQ2> @x# ?O`Ÿ<?b=~Hb@)$B$d=/ĥ IJh^s,S9d->Q&z@{E(g/SaIM3DS}C,2JJMJ4:pw<%7 %uJ2/7Fn͖IG`3R.vIHx D2syLM8TbP'=!\'ctžk1I J}r$9@G`)"*;/)<[~d!$\ ,f`.cErFEKmHCdAmnhpKkN$$X$Q0JR'$QE"iYpLkk&gIMp[s LRxܻ -w=$"KnxΖxl 4z,sx_A{` 5dFIƧ cW]ƥp5y\ Li.˃I m箾k&N'qfS iZb.A-52_*$<JL?ɺ@lrm猑)br>-AJ!9rNv2h`IMt֑^q$ R=\*+72_U'-Kҍ3z  IM1A[?, , @ggЉ8`-PtF?2)F,vC AHҤ>KCqNM쉢q#9E0xXǦm-((u~, (I_Nn5-fZL҇z:BQJsy9*HV,m珼f0K wqi~4|m㗩=[I <={O e7 "+E % /MšxZr:6Aq#5˩ͻZ ܒ>b!-ӂ}0Mëx\>UE~jҁ#k2pAUCd(GvO8śvA~~ dwlv8Bhvac^meZ_nȬo'gw ap%.aC]^{D7R(bD,tPcL7.ޤZ"ďgtF3T,Jxh(v..iG01gF$gΨT r>dĩZԨ'vŖ v8hF< ڍ8@fX(.f8H&^b즒zhDڴ.&2 o~%"Ba3 "`wģ^l `qjo.#(!KK $,߯uabr&tFJln xz{Q@Pm(f~e! Z FV V KwLԑh /BFIqnriuOs&F ^L.g$z,D춃}$;RX dF#|snҦ̓qıpor0Z>ō3ȕpN?4v3NvbNmX2]AC~Zu^gfL%0Z?p4Д$! s&քb픱JbHS20iNΟM_WIJ Yj'phT/'Zhc=COcG3@6"Ԍelk% Mav!Z2=(Og2B]AėK(S9hP4Ŋ@3V1i#L) .oGt\ΆG\FX,M^tf̕vQH-<ܺ1(U^B^dv s%LW9e cYC` gH,ҳ60a!{d%"X].rwnYBSWf{&빒Hm-7ş4 BφjCOauG"oSxZqD.m9Kv)Vu%aiqN g8±`~SbpGrVW YQ'ZRwj7GUw- _7'ט[N)gO/tQ: JlYCpr" ~//vN#0&7Y܌c.$헾 W(aۧVpF+̘>,Ut$OLC78Q3S'452J%<Ō= !@ "Cg(DPl"%DHC!xY p#XL 4fId|FIMfsWN (:vD(~=@}YlsI,*mN^Y | Y+3,/ p&2HMaJk*D`՚k]֣0IG$ꤕ ^g0݀fMI 48'FyzWpw|/R5m x[L Emݟ7TX׶ǡٻgګH$ɺH"ึ*f*Jh!߱*2e <> sܷ)˃ *,{ #') ϒL؊ܜ(HGgrDZq$H40/8 &%X?- 5K 4cрJǦbR<0G@8LY HS0)c<;4󟴄7*Inj#jԨ*+0, <+%9Gsn'D)tWKKەDGoOj)B>7^t|֟+K, 9EZXC|"~i^'0UϢ ʑ3=.%u׶6꡵Z>nmJYHCk/꺅K€;vHn'r("qRyCj  P 8ïȉ;c(C]7>E=tV14h©&zV<&&cwmGg2%]ӷ5>:}WD(N$;e*[ǫJվ Ֆq|f+ 5mx:'x.1N^zGxmd[@]+ԶԨǬ4B u%uz9~] ėy1, N @?6D;2HEid^SYD0-y.NFѼ%ƀWJ^48W|[.4Ԯة *d)ޏlCq@*vJ+6R)V'&_e>$eGēkpj䅇O 7*O" uTHbFbq֗D #pN<q,<&A FZ`!5e#[6wxWܽ a(~N(+K$sSgmX03Na^5mLҩ9O4'v0K|sB#6f}X6iӺ!~;FY2BRj,ŝRє{MiFJgIԼnM@s~)D8V$ |4kj#nfg؃zzpF/1B$ȔES蔑-ƳaFX+S;4r"=S@ri$T0ĢE^wV%Jlp@c\8gc-&r5jBUNْIzfЪr̀&7((UaE1q2NB2D s ֛Uؽ^ NPCɏwJ6K遴Y=|FR0@ X':OIBֵN;c!AezKH[bL8ߪw^Dޓ1sG׀*i)TGQ]_ppGъm,嘆ƏѝIMꆊ|AwdCxTh3% K`^h{=j<"ӌ ɡj"=GhNfP zΫЮm+摄J&6kjFS. "02u0( aNcA&Kq^n$IS,b/ Sg $# JĘ BA$'II&O4DE >"˛{qN36+X?G # <0*P3<(+f)pK<4y%ʚi"\aySQa &s s?T1 J4 |ȞW&`82c'b'tJa{k&'i;˻To@Pfó+$R's|"!@{ZH DZBA+bū"nj΀8ŋǛ^хJ?aJ맱b0<.,X*@\ia3|׹D);8vbdvvJa@l"iA|y.:{;BwT0)r+w p@A$t63+:г 2ƍ)S0r H6F#LEʈ!I'sNTe⏃Fp~ ͯ03Z 5@-AcHm-sև7-R;*  +bȆF} j\GDx?lE\K1u"T-Zec+Z&iaQOi6t+񸠟2+* q9t4 92k-!rJpÙ7"Xڠ?K&"莝aыp͢2[?DԵrbj#T,v/*TX|ºdeD+ LSғ(S <*D7973sZ"Z43G.ߗz9 la[Jץ.)N|!4} ̚|t31)#2=jGS+˳X %W\#4zwYbB8bRZQWrC{!AjƠ,uM 2cYG{ZHEKR 1S _RR{[K}[ȸyF>[^Q^#FlDdLYK؆ՠю|fՋOS)rQe.N6 AP}UE7ۨ2 ? xNB3Z sF=#[E2Gj*TۥRTPUy5iUYT½ʻ\K _eR܈e;YA4 *#?0K>2( 1EZ-J#a#d!Ur;+̥&AXΫ'+:*+܉z/݌=b=ݕ^>dQa&Rb/:|8}b\Ѧ[H ի NI>1 6Aj[V@0GMM4!GpR^6yW;/{1^⬽%%x5-Ƴ &L'*!)["O#SCTݴ69-5hU̖Ah2,6C,;S8a'VȆh; kjR'#LS5,Հopƹ/|7\àóė Lt-װ|NQ=ҽTcŬrb-G}ͣP®1+̾[^Ӷ+Wn#:eJJ&ild4zj:[eL Q_9s_"%c[EhP2R64`pdE>OFj~վ'c֗OTخš 8ripL{o"gQ*'f;MVOTB ^fhL@E\"v\wp`b ɾ qmWţ+C^a+&w]@ c%֓ůdi@;y 8% vb%أN5Ja:5'T#™y6 jBgI=+3Af*6m| .Q j.٪Wvs88;jk@;WQ1Yu$+7 b.(WmX-^vRXkn޵೏v\dN̾[4}ey<ǢYV΢sժtғPkq=’?|CR!}&:,yXFhMuGYTp,vl3tljۻͯIG. ^ӧL?DaX* af+ @QXNDYfHⰨTz~0$;% )fi;}v&eJ<2+>Ӑ%D3 Eh]vII*&|]@zDO` 5k08%)EdPzMCɨ12D^++21@ µ:L#;V3pg-䕊p ;z7T)5cq1]^Z$~9Ne٘DNM+ᯰ/G$p=(+41c"3h%n2,:M VӀN 򀐋Ȅ(<$(;BCWmrYD2NDb.(j ǬR#0*Sf-z8֮ 2 Dv@  :i$l3˲H$<=':K"A^+ dAOs2RRNy-+Lܞ B-s*WDhrHPl6ΰ.Q2/*g"5djM/x,S_S2;d8T]8B+[/!TAj,ԣuN`3TGN] l+K/5 } -oR!d;Wb~Gz Ht5e  S/+u*' i"1|<ԎMژ(cG:֒/۴1YeJ%+LsP*CM(s[1GFi%ж˱aGuYG)o5W1^+iiSPk֒gq\nbieruً&,-\9 9x0M '>I sAV8TgG? FؕH!9x3k{onLѴ#%`ExZq;/]]1B$%&\:iw) 8dP~ 6RMVP5 >IH @ֶ+cwvcqwĴOF/0xԌ#nȼ7Wޞxt-,4,OLrYAH',:= God}:vx 2KqdJ'n>G$|-1H7 FuAj @\yDEpa2\SM YKȫE"s=@#D+(RDy2 [qB- QQ&G.#KđhAT9^4B*bWLEm>(QFgSxZB͡lZiX05][PPt})TOp?6"J %Q!ʡ8e "Wjc'gHb1Df&Y0D A8^cuzEWVgy`*&uWR9 YeZZ.l|QZ'綷]v^jC,60$)Z+T7PfTC5{u}+tS欨38lc0Hi=bz8}Ƭ>W Xk!1%sa^+zذj2V+zb)U*jfST|^bL GF0x*rV0Nz.o.花ULN R>`ˌn LhN~J-,b0~GJvM61Eʛ,E>̲㰵 LXx O)ZFd4rQhU.B?B$@oOY' *&m*LM& Qp)B2Bc PØމk`i/l0NN H a@hR $Ȟ;+گvMZoڔ,Pd؞*vrPRoN*poj* ޤ-!~Äh ^!mD,`d]0e$LFQYlJ\pD8!dނml&.z.0QFG*0dO*ܠ Ա3 rDXr1q 2 CKT;QC lpn}# 1ޤ)JUo[RFg¬'?0̖].xIvzpLY&Z"dp4)p(1GDOd"kӀJ\O4r|J?Bk<s6LPM$lkdjM48^u<0bbp j  r9)zHI4q8JTpO%; {+"lه C^8^QrH/uDgO `ro)n4Mnvf_)bT+ $buHh*Ts/gAK1fQ'CS\;/4/ 'L 1D<:qe8RT-ѡD˃.&L+qzf2#zVSZ;RA(Zq^ۑ")^i[[ԋH<ی"e]Xo>%bBr}K%jTGxgL?rc*ee;qN@ՉRu]{/K_(dDPNRDU RkuB[[RVӌZ>:RPG)FCIR0tOAkgFԘ0LE\Gd[ \ruqG<;%m`^ekZŬNJ`(Ϣx8wu;$*7'AE.`Mukdh +d`.#%PJ>#4 AqBوa)gUP.,Ա3uqz(3,{5bSJ2)blUULYP؊$@e[4KjtvKygU~u8BZ9xǏppjX>%,C.MNInx Ko^eOiH$:s9)'!L xFMhꍺ(҃B"[\pcAؑ2PIJkCR1Wj4B~fQ$7abv H%ƠHl=^EUREc'{RK&G*14T[LgKKU܀ZPНkum:,2uK D@Of2dPZ>p׆LHDV;tWd0gA t YX}.({Tɲ O~ʫ?+WFqbBw+YbTL404%FY7, qV@ ^|GA6`M;EK#iO KV<;KLv7YR@P*BRKh_to^r;(H@5yV'9"lA@lB">ā|=د(Qմ+Qo0UB9M~/1Bs_T-[%_"aS"gzARͱ2Z7[nÜzil 3$5Ԯ7u m׬]M)>JXϼGsj'73 m!M#ڬW/F5Bg K%dT1ZLIH;Ќ.dD#%,J+z?I\ٱ*C>Zf#۵Yg J)K~Xs",B!7 AGi41呈XF;@E(HtZ=u&ME ,N-XWgҊ`IijyzE[IsE/ی A8NdzbP&x|ŧ7S1ɣlMhZ\FEG0l>hv6=&-}E)X(0ϹX:Yiƶ8݆'c?OD@babA4Ej]5p9և.ӫ ( P̀-bd k*I*¼2K!ˣAH 2K譯hÞ妐>> C0 f ,jĨ^ --vu*@6sYP!΃HT1't H1+KH&Sg j6U` WZLL*B#UJNgw@lKf[REKLʬ$QW ~hiQI\vcJb/ eӂ M Ƥ:N Z5W A1Pj,!(V91RvԦQ+)J! u=D+ ?Mzp\RFo1 ;3'-'E )ԕ.IHhX-&KM@{ZoI܋[ڭ9 Y25up*$HT'"gjBh[ Ae&[XiQK'JZ1#1cֱg2I>Ҩ̋kVu z[` 6hC`->cSĵq#J ;`4ں !;EtHt2Pny2% BF'%4}#ҟXf]ioGuH&$HHvir؛@uIdNQ MMѳQATOJgh9]Anw:̆D9?n]:SsZӇQi&Isv4URhGSQ@p2$?7R[؅>L zPMU7悚bA"Dl~x#PE9wỬ.'Z8F%MsSvr4(h3ÆSxДC¤;%#Nصda`n* ;dn]%Dms |&!7AjyD?O4c1,B2uirrl桏܀14nIX"-kK.ClL۹GH4**4U^444 縟|D[2/ )@ ^cUE i}YDɯ>ʏZsE eX֕TOdD t)'mW"AaL`W|b M{Z#/,0+6ЁH>ܶ_ J)v<>NJt$$(>XX̡40#{H=.uYd sl%+-w١M2HW xvfB OQο %#6S81a35kO n x Ёybp#"4!*"s ڍ˷ᤁ 5\"@ "(zP 0lB ;u 8 9۔P-*}{U4(ۃۡߟJNj5d4RX~5y9 j14Ub+؞ wʹ#c#*+RTyD#d9s';זS ۦV<A&}4٧ 6A"BЦW2/TK9e4Y&L107<2F 9QC΋8B;`*T1DBq0Ï#iGEh;)?ECF饏,Y$k1&"I@Zjs~ᤓtMH~9k#<ㆈGk nb n 0tb1C'FgSBjkR&,A52pJB!ߤ)i [x4j9t d*B @q꭛;Kړq) !*=(ğ+iEY: j趌7)Z8 \wj)3*+ܪ[8\8@B0辺8`F6# \-7XŇ}D`4ֳ|>J N;y Ik)䟌r 1'C1ی0K9A"E1u)%+C.j0yן#YZۈ9S>58~!CA4c2Ṵ̆̑-x &Cۜ1  t%Hg¨N+;\M!( НK=qм[1"$RP!1(+m# cۭ>SPtl9śE2qu6*ȣ^3s5 @ MIE TL"+Ӥm߈c 2\Ħʙ9ťTGqŵY-`!V#͸ʫ$QBԢȉRUu g479Ju`~^䴻tZ+m@Z@" I!N O]ZŠQ[az댳D }Z=9&=C-+RyyM/84F UfdiCmͯ-ξ=?[{t?Ф)X*\e=O'8(Δ?5]S ld*yy`36 ;;%}4*C=GxAW\ʺSNm]eĨ:A63ʕ*̥QnQ&=NFղ<$XR'dG N `H+n./2luDw2\g.Z*E[}R6 ?mVؕmCϒ辸/=tSB&ϓ@=)ILv41 Ta6la$e&G[7%,+V~J\<$YA3+Im8~~DZ6M.T85Q[j-뭫9j֕fQZQV(ma&7gM8?~A"(kiLe)GK x_~c 8Cem="8),i(e19/LWܚ?FI[̹и=2a~ܙ$!̗l17x!M?g i= yҲB2ZTgfYxa^Uk 4wCqwU\&riQᣃ@ U .@6 !R,O1hSVdի}sT Ã:kjO y8tmv_ҭJvA03~o/^덈wI;rewBwC6v@IPL}Mx=`}86v6'-䎓DUi\RP0$6}@Q8lU 1L}cHlf+c0f='㒸ߴzDjP AK~ju>Y:F)6=\f̂dm{[oM}+|:IՈoH=3!47cEm8jr,JD}&7A5S X,5mNE5 㜗x <mڤ{|ou *Cq򰽮j`T''=t7ټc-<Թ>!/$|fQf@6-0@K2rC2: M-6L(;6\kۑ5-1#2Mb,7S^q=P#uEltlocS/I)ul!첬6"ulpsL LHo(mѢi\rKlnFy2*#'a1&ٽw3zr_/] PAoV[.j rJ@7Z̈FM Kf啣n,==xԬH>!/ &GPCVWm-CJ(%'Xʕ[{3ʸr2"ʓY8ĉ66)@u__!.93XPk=$z(ZLD/V @*6}Xd`dܜ5 z%rȱl,]-I8|R1ԡ|*DkrWa-VI%tx!?c|c^Pj3reqPfayț;Xc,|G=kO՗+Kg!d%i\0s!'I,-I;11"be̒!nE7v['K D6\JW*J! إOMA}HpX ^ HiYFXm1+I= \wQ,ZXc# "h=VL"(T?(3g>u")Z}di=3 8Lcf|΀B@%3t=(撑$+[<ɊT?ڐ@Hpeڑ*~ 0i89Y赠|&2C _ t侢*ZCVX4mhrozT~~ ^XٷFDY1uG5DJ>͸d]\)GDOVLUO6ah (C)2Ou)Y H`cU %&,X͈.7@KX]g8ISZ$4]-:i쉨OnPa;̒6WyNJa?N /)8\+ԀV}W?g6ټng,.̥p',u.o7e L@|=~3F^ϥ֡Kr-e2g|]AM$M<ن`=uJLK4K&݊kOIr3*-Mmp `ء}.?3#$m-,PSGKK7+?~$iP / bcA!.*$,jLO -fLd^C,BIƲP,,a ŦKLSbLМ5 3dPꤾA vPKR"kH.Ӑ^mcLK,0kN!^I-$pޕP)` p3ŲJ@ H*Bn&>LVDԿHZk8*ed -*c(:)c JłxxfJwLdv V gle`Y&P$ʬqI' kᦱ 6.4Dl$c/ T#)cPr[,j # hNwO LsSi|LPh-nm8|^LPg^MHGpփie-a/q~6t.\6N8$bR~&n Kf !ljr=^aabܘnc-f+ PB+#+!-d-r؉`!^Ə=LPX+`vii袹,]tB72ٲ. ǦF.{:'o&MGFb83c-hNK}$5E*T=BnVYIvkGs@Y$}SbOE2PpsơAs|-ΰVS"~KTzld b`|Ԉ,;9hxo"merG!8_H7 ow~E{OK֨ StSG#'F4*}U)yj9N2.%4] kªh䂲oI~Gm>Urĭ.iISP-hD+-hY5[%pƉ@.6-IH }G{*Zc5_e'ZDj"tM`θowrwUkq*O ,neiT g" - P+0,7ucVh¸l0iDb"y/;2}/rkjq'IJT 8ܒmm{全m/-Vi: }v,*%܍ID'pN vUnڿ*55/89Ry&8-bFUe[7O vLNXs&/tTFqnxo!S7CKK Km#e5Xk8v|pU %V\0זl/Z ŧIWƌu):+h0C$MώY;**@#Mb~hV=&J /J/Mm 10Ȥ":)ٿi~* jm 2'-&ڮπz|%k 6*H\N2L 2#&b?8H 8þ`9<Ųk|Pz<3t2` ©-%hS2=+8" :7Lz% B`⒱rSI j~bP-ڮ៬<20M "=)NI۟@BgؖZؠ ,$0 %u+.QO QH * JyB7URHW~1cc9,CE&@>bOjJYJ=dGE՚L=%ch#LD%tZ"@szUGhUgΊ2Qkzq[F@;5զ^zU\I} ~rWaeĩ ;FsU)#tҵ;伵iN!Ȟb8($WJDM(B.A m ce{± p1MM02:0y-?! ;11wXJg.1G /MudM2LXUWp6 " YRk&M׻6=u3dcpi 9,$H.1 u$& lxMQ%#{ ??,&|9p ,&mFGaJ6&x)BQWLH,(DDvS{',v1 D.f j$}a(<(\ !6Jmݷ}-JN61@ IجlCQòTvr":u{P;c:BvpLGDDiԔS%Ѷ#V1pGaa)2]! Vjm#WB€ C?'%Mi^]shtWC(r P133."xPE }v'(q{@G5` -y !,]2a\U$؄WR&T !*5f`gM$I?!x ~TDY (<pApJ+ %edz0bS唉~kzJDj aK2TA:#$ק`0> ˶o 땤-% V') | $bnJJY# SFTɥ)8Q+2M[nd=@B8JCr\% 9;ݾnv; xfplgx~`[q&Rec#>} +LH ;'+."$JڽQjLr@"*m( %}C%gu v`YͩrRLp*zcTWA?tsvG!g(W{ DMbD^Y7elU7MZ)Eժ̼p|+7%g9aK+Y?aMŽISY:e*|kٞ2V_,7ȇM8 C3eR9C  G1ޝRGS&Y2ܭ6:Ce`/Ý Y !mQ D<|$7B<=  2 "ɻLD<\>SO9^D,. H/]=SĻ$,BHD1F>G!ԙV*b)>Md}FpA 1Z3kRЦVSiFtG؋ȕ3}r0:*@3fC h!AS+DTxųHx}!I*" D&5{uDd)s[΢ knA>C,V© 4ӟ< 7H|»$Y($ѐzZ-l *ICأGjX>E(=&sB[{%%k 2zfU86*·1=y*eI\"*d4~ ].q\XsD.2@!A>ު{:HK5pA( 呇S*I2&QL=8$NНDoЛlšnA K#2ؕq ZԲ Y[x9%ډ\4[`Lê0}'@=Wp1TF&(01sIٱ% Ж‹/㈰l1ӡ0jP=U%S;+ 2cFQ~m3P@#(btN[RYݬK 4WC*Qٴ}YZzDjRRT:]['%$HѬ,ebՉJb@C|Ȭo\q=I! Z %"1ɶrMDALES ,JUF}"V 4*CfL,6؊ĺ[(Y鈸¼ x8 PC>Y@;扲aa3 Fc]}255L-ܝa-( a8}M]nY ۪lÖ[2OwVY.'3ނč]ubv[1AОF@UX 9+?#IHe鱽YbL*6W!]b[$FHBeaa$*זXBĬ#,Zi CY ۴[H_C aʞR~P2@-\ex\*Flh5٫S* &/%ƊHjnXO%a6x|B+/N@t0rּ94eij /ѬEdb>I>- N=D e[,߬>LQb]MG&v!|xR`‰5י= ҍBg.;/4ʹmkZ)2jb$:?dp t6\bSY V"p1斫>b"=sC0b *!'#ه:|(터Sh fZvbӢ^M33tc>Bu=~X'5PܮH& g]q][w4#Y6LiGͯMpЂ,mIYT8%sCMwN.LV B?\ۯPò4kD).ۈ31S ;0J|n2b@{"W ushiV[Ť9tGģ/Df(inZ>i^?yn+Br1M _gfٓHw /QYCt/=͘ܨ[+ʱeRő!y65e>M{ S![Vu )r6?L.q%cDƭs""9$# 8PҀ4XF|E,cyQghJjњ鳺ʺrM9)F(шQ4 v$H"CQ)}cֈ@ Ao%E_(:?E Ec'7ج.B#u2ӇԞ?"s4-I$S2y4beƠQKDbQ-InB(dBxOՈ aðTLOmYF)$ טO+1۵BERy%VS <`s*.jkQW#Dg؅Sh K_jp=.mv#{RVs{ .?A`*)CM!r O; j2ϢJH' \0jz!3$=l\8(QH"6,2$I(cA.KN+%2H /BN[,/kB(dĮ2.E¤ ϫF1E?i:dreI3Sz [k'5hƱ3H2I#PJJBZӈӽsCED,j"K DTӒR*`"e- CFdU/3C ,7ܨ%:T:A/%vxP5OK-L~*֝*HeV3 f)A *)tKl[l#y ~#l-Gn gǎr6(&<&6=!^pS`" i먩Ct`M0U >%^ǧb쓫H$ܔ֢Jܺ/!GWsl 5/: oJ X*ݽB۶`=Kw_|V_G$8rSǰ U9I1pYhI9gZhF3}]i 28YRXYqRY姅=,U<|S%8x>Sd/e A3mjl<"I$bT#e?{Mmmb`K)F bcdX70vS0X#xe3 h:zRj ]~ -;ϒcͨ)cPN*,J,RMԯس1J!Rixz&d*Thڞ${lG&A,";hJSG WSo{'92(jw?3@}P_V Pʛ-c|=޲0-,bKr1TtBHSE!mS:ᙸrbL u,Ncmɮ CnB>+E3$5~GFM@gd&gcP$\\mV)7 mUH  ce-,#AA^n'zb4@X  ?O`^0TU>quHdP$.~@R(B!Vp4?ͥpa%>1M5Jd޻+$ {%FSdo>9U+ҙlO--| T6RK[VTXSV9U#|2x&%ľ!xµS,زk " p0]-cl̊|q8u>3?|?W8"?B%jS+*q8KT2β  N#F)zZѧ)z90PPCG I:9-J:媑 3F'2)*)E-  ;>i-MzG;;m?;#RNpl~'2(SF/jZw+ ՁOAdx줚*%gU֩7^䒶tMA}nzBq[9!Gn?3q :vB)om=C!ll5b#)@ GaqL#`,;[#0Av*#j-_?HYѬ!\¬2qDm8%Q-K3)s٩4p5׮ Qyf"> ;3jt֦RTcF$NB;H~dIk.q='^]NI(ZJ rU%rI>a5Dd3p,JxbdMv<4"FRrdڗ ,6C !D2~g ijw!G`O{}zĘ+D2Z/=lg2U2OK,I37&e9#ۈ숹Iz*Za$ت1Pu[L8#$h&64;mR~~~aRu X(92Df*bqp=+JgtnaI|GMlm7ȔIi?)X$:]*?x*g#:GDHLZE-d:#&==Ty#k0Y'1+HITd 7C藱Y'S)"BDIحI;<#L67OAgٿU+\Ώnۘ5&\G.Ǭyh .O󨤓Y;-j!;c  [8H7-XTGFhX٪P9`vNDۮPrElO5c&/;:Hְi>{pNI vJ<H̻O}O~D6[+8 ){ iͮ3}$ r$(طؼq3gqQN zfj )RT|?WlSf JYBN>y-@8{0ߩjޱVO6JC2*HCcijC֖ՇpҡEdqb͘Y)}Q(~q:?^n. ij3^ 8ﺟ8z때6P>m^t?*o4{C5"e Ϣ`|ޓ9m']a|ڀةHkjۛWN76"R龜0< BOh∌~' +*>Z!LgƊ;lC,:#/t4c 0Jht UdB* jmZ\8h$O[? KbץFp2Ϙ} ' }D`'"h6'@ZbRĠC@ څ҆Fn &zCZ@+0'\J j*>ψG%2*;,nj"Pt&*HVʢ#'¬0V>'raʶyhjE- AtD͎7"Cfb*`Z"Nȱ:j)̘BK X*O,#*  [p]08 NDF$eZQX".e0o$Xld[@BdJB1LN͎oM_L䠛!'t&-Y(+>b\ JBRQp"2b) pLՅ;! +bL+'lzQD˪!x=lZ`Jz!2YS~&.SZa%iH>A η,F>e$ID„,Ft#ˬSt^nsQB)f#\y>t$9!"N4gFY#+p!8ps܏1z8Î71RLDU5%29j4ZՒ& } ^nvglbcjZ̮rjQ3:X嬨 Mf'zVhGl4eW ]&`hmJ)"t(|4>^\R`f-l14t'!5Sڲ#H"DK~u*qo0sAG.pE nl`P_-HzmLg7jJJgP%dθ04hk#dKbGE>Fr{"2 "Ht@. S319/(i"K$zC 't#N_%#+)_0|uSDn gJUk%FECìwlFG &iQ"OL0> ,R#+>%npH %xL5=4/MJFƃ:0gD'^M?ȒJ+pyj6ޓLj!B`6&lgkjRkC%Nt(3h s 2Jْj-W]&"CL1R+ ?$aG8Uӆ0,>!^fHReZL =kd(DpˍҜ&_` t.f 4ЍXm#<Ԡ ,2R5#>-*nPÌyg3yoBI rRxl<5zpXԔ1L(MLxi4(q?4;Ad bڢ⥪Jևb,3QOmY"-yqI` B&ΊgPa'l`lP L8XF`SK%#T.)[/gN50&jZw Xf*zCgώ,XpPt|i[)Q~7b_sthrSMw3 \֛,?xGt`row Oh~a, &7`s*SGFN 1Iwbn0W76x3s -׬aO+WFWj<jEb?F0턞2iak GT#W'p=u q84tBȝ.Ʌf&KֳJ2`9y\{Q("5Z\%i&!HaXiPo Tq*:vpr-V=bs%+VHI[cGHBKku$X},IywjB)4dS,3--4Sݙy"u,_6EM) oQ5W+`4=s`~hӉ=+D)(TY;ω ǒa觬u9L60&ᱮƊ"$p..wT!) 8ة;x (-J4NRE74pvb 9gC0rkQ\Pg33nUBJ1TazQzn=g$5ތ mT HbC2X1Lv}q Zm;5 c[yNy0qtJ)nυ/ūwj[S #%$xQɦW nxB5A&biȆo/ZOnPc Ș©iV?٩\h,}y]1YM%+ReYug)A5[ lhAVB%ҢEG|s+#bzfƱe&љwv-Hu:ZE&1 qm%8V#ga_6B؈8_}VfGP2$6-r++`h6㍇~Y׷v 8`^ǟjUX&>g">Kݷrb8v߄:X"~Z+=ta+Wr:GFɥ5f'vhQ+-"hE>4HwYQD [}הr  a84 CNDO9c Bg~=sTbG=Ο`Zq#G*>jUЫWnkA ITb5&Qh38`Ua1IaWվ3 z@9C?&B Ҩ\ !`Y5/D /n0XF/b1kڠPld"ɀjxq 1#~.cfQ9^\oq;דV+o|F?1Wb{ sz1l#n?N$2FbFjc#I3B,CsF7ٯ" H`+K<8TMCX++ SBFCg*w/=BzzRDT*#648 Jj-)zS$7"LU08 V ;?X+)IU6)(>+/up>2:UǨ4@V( 2 OH3Y*M?cPJlkd2'fdR*5&ֳٚ:R=g4Z0Hjrcfl9#ԪM31{^-٫Ұd4DUGۅPug ԝ[@'~H ,?1nJ5mŤnD1rY&"=C'ז"u |%@gSo㦲.8seH( J)r5q'gI6r7|5~b{ NL[QJ 0QEF=%ѻ F9j@`0-@iwq`PFLϱ"&QSO :&K/Omζsp Wʘ!dQ˰ pmSl('ś'%:j5M33e;ڙt̸ @5 [۷my^%U\.,Ik,:\כ1˗[bnLQ[ZIטjN+q֣EÚxC"@EQ eBńփyT360 љq'ϓ kmt:;fG#@dᴇ F!8+[g6xv;ަ$#Qf i 0uHfnva5=E0F~ӄ3B M뷩I'o"0Zt ',2im<~y8,䊃h /C8L B+; j)d8 k4aL C&BQ+9*@} 'iU!?7537[@\%Sv ){ꧪ Jl+Ze1I …SGCzŸ($ :Z'0~<-2rBb-4s63+ i)t# aU#B!D+ -1.(/~ 0kFJ.y dH;#D4C;:ғ1c+`Y[9 ZF#bo3?1_^I L& K+{F%C!3%GMl2;Al3K~4(HG/w,;Ţd*DӞ|⍏\GJ(<{ˀ*s?h䲪@#ļ⹺±"6  Z\\K4C@,z -4*#sHi>2ћ=ļ;8 # x=\i qGȽ9GJl/Ä$?6jk%lqty(yAq َP!Bc ELy*{Ӻ5 AMP,I32>lC4g3bC 4  2<Ǻb4+/$ CxҠ@<-:o{6 L$NHBQttʝ#3^SD:g+M=<0I-l[7\2span1'F SzsD>qŋo`ix#EF,1˸HƛWMi4C]R4|M`SܖzbCqxZY4{%ÔȈzȕ } U =sÓhi4^fc c܄) IY뀋z]k蚬n]AB3% Ǹlh!U)[PD!M!-m,N|FI[%'Ѣ/&å$P!l6H*R>2ӟ`rM}WbS="ܛ 7zDy 6iI-65fhHFxR7M;HT%ڝ]6"q⎿NLir'F/Stڶ_![G0~2㧴N>΁.w~@i?:_.D!b=X6hyV*7qPCh9st^ê]'&N(Sam% e=Bm>C)` 1nJ;c[Ŝsj5.㽊nƦ:5taMڡ 9Fbd)MG-mZEI5ʆz)HybK Rm=c4Ƙ4cyl~nV[I]|RtV͘/C Ilp%ǔ,mOz/2r@.V5Ɏ,n"DլP\Zs^мފSwh0塅^NEoE|/w?w1DmZSBԊ fѺ̪C켟3W0(2 ?\\-|0}^^ @E=G=c\#!rU*|,=ZL,|(z5J|"NAzO/J0! B3[TCr(@tAkNLph|oE="WJL*>Jq5"8k\q3H$_WY92|Jkquu, "Nt eYy-W+YSAeG$׋>ύ`NNM%= g7u'¹ M*"Οvc z08FNJjrT$2?_CE⊓4:R-6lzCAUM"ǐ#!^qAT_7)%-l^Ј/_`2?qiP)ll1!IJCIDSϘ@?!Ϩ"%}0`5G@u?xX+` TO/Eu'HH{ϠQ$b ?f56_:jpE/:ra@vI=6)M4>lq bO'>/tM`P,_\ `HRdRzF~M-Y%r*IpF%􈤾1XjfM7;FM"h/~E6IJixƲ 7t Z6]d1ݸ r#) k"ףrʢzknAH<, *k)iJíLKt2t$v~-by03B[3/UJ")+J d@8r"T J>KQ+˭#9o-` #M /W2vqLdߩm% lRkMjR \-.cr*^&O }dX]Hj Elʗ$*3b(jR &W4RQ< *fsQS5eKI#Ò 2*)o2zmh~*iL.0l2XIB7\ͦ$ uf:EA$Ҟ43N;(RǴ9b8[ ƒ"Z?X''JBnBNlFF""R݂p ;b.!ʼUy"JJe4U &* $ĺ LId n$^0$NIΡ90u dӺ\P2w@tD(WBI<NpPQ>T7K*8!0h3RIXzȽ>.bD}*"t$R>6Ee͜FN/?#萅HnRA$u;"d*iAhƋ~\<Z`~SSV%30 VJ/D˖Eñĉ[ 1I y)e8w@s}xG$Y:\TDę9Rf칕BJRbI<PH= [l9=5Q`h]B3v F`kLd%?, E =tdb  twB^2D`_$}N>ʡuiHAH˥EC!+480y+˴=]]ʓU8Vd+İy^T+eNpb 8q0=7ROd1'LаNjg[`4P;8."1Vp\ƹMńnڗH>Ci$R W0iP܈4G|T${ Ոx/}kıHF\J+7.2E`̮:Tei*Y2TlawVJ6tژ^i9"3'Eqi#h^:,6jf Xv \-`EgQ\g(F+ Y0u%tZM% ~63+̺]sɣ#ek!l8TٶU]'yB1%pJ9.RTDϧLnI;,$LCdux e^1)Y (ciU܊}aͬ'^'T;Z# cqlj3YI)6!5##~]\'U ;|h{a :Vg[|U/jfbXԞ60E`̊]@ַv`z냻ɏS7dRx%\͝ ȑCjݥ-6JD6#$kJAc+]yXn^T̑8[ޤnqz!m0V'h5PGeͱs0ʘRN#6t!߳RKՆ$4~x?%RBM6Cw$tP0$ڜ谐 ɖ9S1/O1~̎;zx+0l8SԵFxڀT=Q!;xMU4x~),}y<~yTrkF\cnΒ^+J! J^T訂 jMhB$O&ⱉi$:I+q l~ ,hdjm(ljE.ob>mbRN@NXed^gBSr .Ll ;JlLhhtȋ(:ǎE"D_`Mj)kKzcI$r"VsNWL$LĐ¾):q0u-_ %Go`.v<_’%b2k&F!LuF ɼ%/ 1 S/_ 켠Ͷ!֗XO +r :FF?"n(0% Ũ,B"VU)a` RF鮈2 ԅ2HraB,kc# +tVgяb *,6Ʀ+N o0.P G*I0jTc J(dlno%Vi|@"^.ʙ"dp2nE m0D؀. rtǞ!2 䩜G/"L[).N|K)mLcX\.ʟlTźpR1E.'1 1RA o,km͟ƪ&@_(] PN$F\rWFQoR$DgY#*L 2?4j g,'O&j<)cRp!mx@0쳊N R#H,3abVkhNÐx!tf ^("S/ Wlm+q@%Bɨ5"!$ԄLld^{*M1 mT>i@*rcO#\1fkḇWOL-Lt6Mm7Cn`e џ3cGnRmb$9JOrɁ,@LeRj[(<2fZF(2箯 *H?R} 2i:L`\FhsW5, RcGPc3NDXF 2$Cڔ3bG>f :-֞ue_@ 'L_=rVBc.5 rD2igdxN%hwpJb,wBȨ7W V"ZJ³Zh}kKVWeO68+x1A^?'n6qx.:l pO#MNE!"yo'Ge"#Lp ˧' Yi몧GNQrF:s/|'LTZmG6Z񨎰&tsu}jp崦ܒ)6Z ɧ?,aj'PTiM|y`Dbr.te#NKsў HRJ֦4+EuDPhJa\֮HnT"H(^#|a 0?}L %)70"e̛JdL]ғT%k!{UW,yAYyCAnsB>ZhRʢ"DVJIƒF`Еck");ʹL~ do=#+ZhRJbh;r:Ǎb9wL'2WE!uEEu/rz9To*.@ [CbFRQjD/eXiYsw'Vq xB/IU'eX1T%`vn^1V b)ql1ljDڞB ť]LQ%9jQxZhvEw, ]tVrcTnmJIYsl kNj@.ky և#`4DwkǨĺ/sfE`}I ZHcrD jlIs=NfەH Ci5̼2?%X)I#a[4^`:W~EuPY2s%"֨$V joۗ;y4} 4&5HT5@qH(OYۯ%{W}r=5p Z&.?S,2Qj{Hj5OR+:mu-[-ʌ=zSOX)6KЯPLe&laX Vzl#ȨZFh)DB4U0Dkjna|?o/E!Ż3K\"eS#NpCcϣ/?i%;% c~ 9Gidx+UMC c[Ke\n ݽ#БRZS}pX0?<Cb4*bQ،n$D47 Ÿ7`f&F! ~ѹd2*tJ},S/Y€]:]@>XmPT\@v;(SX'K)1ȍ:á\JC*UC>(zI)dzTP)7Q}}.gٚg0K#zvE͑Nb:-\~Nˣ2_^@0׿ k YK:/ bv 5G:J.l:<(p "45+ 1-#顎d>"ȸ{F,K%Rk{"O˚> ({iNräOcO ˆCP#(dʊDj hRJʃ&G3lz"%*z.q( !E(lKIsE較,N~5@@(DB%C/S Dok0S !&,)$QĬo"īUB¯jO |k3XSt<Y((PO/#+b5^ S-4ݳX2GLzO"LJ>G>QU)isWjOT8D¤Lĵ_^rj j5 +,P kC[saCXط*MwrNϒnjֈZ2ȟb]#{]!RV`B6C|,ZtG@$#-CS0WVKlӉQկ}p T/b7;g(7hϔ:EʾIt*w ?T81 8Ԩg*|o;_>SBfa1[i= Gnߙ0G7{Z"A"KthD q0&2`l8>8"=z$64R7Կ7̡$3C8ٴG Pi qM%ԋS <~^ K+؆iyN..00HPg>ou`?Oe ̖RY\}C_/mTi0t GTE3WDU_FR]ի`B#2 n)V QD-q.L@RVbG- 7A4H8d9RD{(؍K YŤ~1+!Gț8,RDrNԁł(,vB/QG}`gFuXG^PCDgsn${L*E !"4CS5IP$ɨ>4#}')UʯLhM!?WQ[g3I1OK'2iheVT%3Sa gյ,;<~(@Ms@AyD!j V8X"065ݭş0jYe5;M<>LrزQJQ-/ :=g6h6` q#:SRŽ괪3Q5)FGP S=zUr=UCN0dĴcY E+07_'I@ΦleX+>7x ȍJ`k6u*}SUo r#=t]){ţ%;eMQaDM9kgC5gaS6׶Wg@F ǕI4ȍf1@y%eLWyD<*I$WKtaɭw>p)Pmz>Wjı6P꘻Sl1xabʯ/^E䚅fYa eA) QXm:#x|wfoFa%JcʤWm%?>'jt9ķ.5wqߧX[3yչˀXu|WbaCgdpXՓ,'ԧdm8 к(F O]C^w~rTy?+1 hBd:Cׯ #`y4+hzj"H+*Њ9j\r?< Hر3BA{E{T*4,q<1C*•A B};&3f>8Dΐ1"1~b$z =bB ?#ɈI7)˴K `0Zlbz뱛x:A}{ <* )4+f10;X4 9 z3Y0C8 ;CC(|#r033Hث"a0y*0H$`O"cpsQ0cFz :& ;a5DT?*c>dAQ:J[O˱{| ̰+B>AAZ(3|y! alE::c'5>C,B=u|KTYS4 |;jo,*$)`9'l0`RL$B/H̐6!CC,xzBq?Sm`VDf̃>+s _R$A ;D`1}@8{ 5R?=|*V@F@ |,| ='20")ͮ(p%1 %DAt:hhS%3 |X"*˳Vi4j Z, ˸24ɢTQaċ1PʘtMiNT1MA3 n$:͸׼hs<4EJ"TU@MUDV Y:| \8Jd9zS:4jagDoNc& (X=̊U) ۬ *KN@.uߙ;EO!m "&QZiW*I"2sڪkLN#"|Z*1AtAObӴII<] TNY5%Ub5{F926Xb<9;z"-YUJ&9@EQ/ 8|7,`_!%Ӧplq1l2З4FD96@5|MQVB6ˍۃ"iI8šʚm.r/"?JS+JZd=h}E5W/iR`a?`3G rY-}$ࢌ5^tL Ґ7q;BDC>^{4ؖ@s{2X(~Dl e,FWv)<\zԀ]aB5~bJͶo[b=nB_Ϸ3Q (8i=f 0;%x܁_S8`EVR[|钡^7/і.#a:_NWhh)Ċ%:74TcO-5fiȥ#e5ĜW=#U*E }=lEA(ЙP J$`[ڜcH*K)̦TȊ=9T .C|5DJ%VIf气6W3+ؓVt瑨U]W\`R$ d|c#KP$ol;Ĉgf&F1=Z0䂖t>Z-E0nt6_y"H_C2)VOϥ%eH0 GAmo)sݒ F+NHdnd-"ilp 8-,s6IE`Z$*2OP@mп܄y{JugMz5ܹ M^n.Dѳ̊ ̭wGm.@=su/"pl:2*aTOM 1=ַUu)R-6521&s4)*Ek 餛2\!)Q ČjK3'rre{1>~2%)FX+򚬭r7-4X½q9XFpum󏬕^jȼ'nan\XBوU=l*o(d&/s97:DS)<^%yj,F Ap.O'<<Tp3r`bQa+ n+@dD[٢"@ãFGm]na6rѦk Z4w –pl'qSDmk۴! 3a,ueW.؛qߊT *D:?HF;[ gfܺ=仩Pċ[h30~aD IzWë<=3+_wY{"sr0 P0!P8~@7UA = "EIK_HddI$RI$)}QE"+ϦRV/ T ʓDN^=2H(ӸP)Y@R :/5X@ h*_;UlLF}'RVIb?:$Z+"Y4 } @ ja*SbI;EdN #,lFgz?Ez'!0~,N3+ـ򌹭HFBۀ).jģ#I .ChJ'" $$ X7 2ߦIkɔv~rFcHC譵F.Jr:J*?)․ |.hq3Jc8(MʬS9'A˱#%Jm}Gk@,\ս(=".\(Dj"ʤu E8<ƱD6eA("uÈHՔL^`j}-[J%)*"~=b!@;ںh= Q,"hr|^8n?-&]3J68AAr(LƒYNg+<"#u.2o#Lp\~4l:YȽވհg {Uȗz+V$Z;ǃ]{ ʠv 7q;4.?$ ӏicHqI5H j tF@>D%SR)L #`B ? 24sWL(~v0IP&\@"&u v/5LyO Ѷs UI$t!Z-,kHZc#I HRWl*NXmǦR)4ڃ^gYz2l[kekAK,*doO\  AUN$*wc{%E{_a.x-ٷm3BBkqљaO#йTLzbhLoQIVQ[Ƃc/N{`}%="7:?ɀǥ]rSKbcyIrsY.ͪwéW}ӅJE6 \U|?* IKm6wO_nL;lfB"<`"GT܉ډ9a %&zub*)"ևfΞ8kt &Jdcb ϤDͪ ͬoG~O֯ĵ,be:-DpNΛokjm f< ܄.0PR4phc)B*^4~ C~&G$ODVN% ! .c*yc4T< +f$n f74l &g^\bB8 o R^e2d{ 6NrŔΏΡnl1 #LE\c1{2Ѩl#8@gzA )\Nc i$E2zmG" ! VpN€9gS P cf)$ Mxjw(bxnXmxc#=3p1 6h\ е56-zm-ʵ%nbR\w8" 2BLTr*#CvPk11 1lmKhe6"8`Ď-(<7z*^N7bZA'pDR,K$?eaXx0 eEp4^r @.HhStM&Y 97XO|rpO@Bx̽@O+Au ;y)pƶ kbjv4ti RĻ.ȧ!JQ `-Qr+DY!+ϞJ@Zg))V!)ϸOZZ2*N[ *X#($':(3IH+,5b$G#Q B-(rh@ RR E"@Mt .LJ % 0 GAmU n€rOq_(EHM~@ g3RNDtz"r4L[VV?.c,H@ClDO6sl]CNKW3$6@܃C՛aOw T@%EWq5Nu.QjP8341c@4δ8hi^o_5_+2?5*`whN ^n4 4_ J:y Ȁ rXcjq}kQKn&*(Nc4ADl]Ow(.dFOBE,iIvVh=MF$#b QЛj7sX$R֫P}cE#*UJnWNlm_ohlP5D` DM5p#P0)I5yv7;ribwW liqx(Ny4QJ:rU S} upIu- +qiK; /ӌ@HB nG8D\ xg;a"T^wJ'd [l6hf1 wVu73RizS9wsʉBR?Q3;m$cPJ~rD isqy%ޡN 7c.^?2:Xv5bp(kc?}(%iI *8P3P2b##Ʒr25Nˀ7mZwQ x`B9fsG6&}@yz!0u㓲98?]U Mzסr3b"KwB/FPDL⾐$s.s+M!^@AJH6oLjy֓׻9cwK %<}.6mY;/t'qjMӈi("I [n56w#х*mLHŕl,SiW:00LA} M[I? ٴ:!̈uRhS5NAr')+d`Vk#qP:GS0ӹ@S<nwc;ebY^?R+]ڵ@Kh 6iәh +ڀ  l3zˊfϱth x>E:?okMˣH;g/w ߾cvy:sy`3mGzk BK=[ShZ=]s'݉/ @  ?P"H9B @?G#,!!"iA%O+Jt҈YTb=eT%hPB1%CϸpX>nID"KO]O}D>cI *D$|刂lkR9_axH 3@= >GTcU>}!l!IG֨U^QC#\#7iMETM#ӹ>g9a*4 d?ϔaOQh䧨+-I0)<-.0^>ZF$*|L ̑bGj.% $(0S,?HBҪ/nEJ F?J~ "8ޟ$phh%Kβ#Eo #z)aH!OA1|E@8؎H*¬nRpi77œL2@ 3][QKKDKkmd'jKo$=VR(2|*93őJ9=E]1TT"Aұԣ1\3CA%" %'57V3d H^5 -$F"Jaw FRR\1-ӍЅxXs "?֕ c|^OOkWջ>w hD{ə L['4+JYrxTh^. / u"(N0/Ӽ~/2ʷz\ ڶ2s"lsOBLy=HA|;sM&]ς/UF9"u;z%S7q3X/,lq!n~FGӹxn~27H]»Lڝ^*>j Ї$& +1|۹JNBlW>+z V\z0L4A)*DHA%A'Y GDtiYk9<rʢtOuEJz\1i/rG5%!Rh֐=irnl[HTy!})ܚS,& \.%ЙN/1(VQA GLcF='Ryv@5CRFL%>Nh$B5+<'D񎒏5ѹeI5HxCd I)9D"=eY@B}!ؔώ#N… 9b‰Rt3tQܑ M$q^X<&c4Z[<2$JtmRH%DAƚ1*-#_@#rkOB[%=|A tEQu:.L%'SF1EH2N/ʊZI'T4𦄶qU7!,bhIf#RLxǰ5S3pZcq_"{Wʡ,)D!p:䶋Mu\aĪ,Z²TtMI],&) DU$ʉbq SqJ7bg帍F}/1ݤD *,t\xiWYjk*t k>Ha$154R%b*(?gϾu' =uU;k{J$q\ٜuMc%H\ܘL?VL4SN4!bt@y4tw$呻tEKU\n>Q'Xz媙D,:d!8ȶXTHLFb}=_ʤ-do m4RWLQ$:Ĵfit]E1諞CVf,ڋVٰۺǤ'K&{ ͉k1i'IU-`0i .Qna'N[HAV1qˀ8i{IҮ @,9 ImڞWu)LF[UAyɇ=L)\[NpԺM8,n}4Q"̷]Ĺ{θ.(N"Mmz ;~e ehkA>?s|SYGmy!W, ` F}`$k1P%ބw8A,6X6"BƔ+!ZR5S 7[K@*߮LKYl8:”Lo +1-A> .A1{2?KĹ2y #?2{Q2)0$yʘs@ݽCKK017229* >یQ4 $'z s\B=5$H()"M}!{â9=z'" RF.?=jӠ^01A!asؔ)ň~[;/p-鷋lJ[S17" 1)S2^;@ jPcI)iʜq)c[6\J|S:z·?کC c22KJaiȡCHh!v+:t[WA—FZZi(p~A)Ѵؒy^ACkĢ*9U}(5))oMP|Zd/C=4;$c1At-ӓrCԞS;YZB"J7&`08{Ѿmz0Ѣ6Աs C ɫ R(C22CbakO 9CO@}܄QBcˈfFOJŒ|E]SڠU%*;E}.* ]-a7<ݽӯk;£}-m[RBa0$a᲍5v.g )teU L[c,\ܰS`;(&*d-548r*}eXer#S9A@(?P{/ \zߵ4(s j SDe2ԼQghmChԣs/Cv$YNž`m؃)ȃ̸Lf4ĶtpУbUX6 p &%ak?$Όb΀5D-5ڣ1K){R `A,з:zi)֍B=qQɎXs>[ a7bk M 5#`hI~! -3bhE<ʷxMA*nqc Ň8U6[-O,Wkj uV;ݝK݋fY#;Jj2] MG[ %qoqHc-VΒQ> @jU9jKDsA,"}}zCɓ"9dc݌EFU iKw(NoNꏝ3*Jj{uܤ Br`,2pp~fi臔EJЌNEw-O tN8AkH(F`xn aاC77+h}n6Cp^XQgJ*"<-eF?_JFk`nuG5Om`l;s~ky04;@?!$Bx5E`BBz9~D0 eFcRG2B'I4 H "!AQ(PI SO$ܲX HoLGXsgGkIjIhLQT =Ө%@RIJ]GN=m̛U;KfNAX@ *缎YeGO7_TG)t|Z/,~z ̚R"1i:<'D zBO6">b! Oirr(Md¿(V(J)vGzѩPtS R/"!JTG4=(lJE&',ʰ 2<5(RNNKܦJ Ce6'T,O)33+EzDǑ4^*160mY.d3Y9 7oފO! Vy/Yl65gMd!ס$(dL[WŜO5nT5S$ҥ5bSk#NqxfJ@,5[_,M)=aG sv+s4g%{P%\)h>gjL*!w+v;?A#ޭՒָe;elg;F*ƱFht'^385(ɷ_~ͽi4&>2B H8Ic֗+.Kb@a'WkvJϣxZI$%2#  W!yPǕR 21tv;68q8)BIdݩv=*Qs8ظIE*~H,cHֶLC8G1Oez&N-Wtl eDw8_W%J&;T/j?UH!:c 0BULUQ3u#tK5-.FII f9Yd/d屰ΤݾE f/:ı~RNC;m5UD%xmTbl,hud#5eM-M\0 $ DͲ2V2 dLR}^rC9`r^O:Jcոk:ځtf5bYT}S&d OX3 Ve:Mo%VN,&G)jڢb'3Kz 6'94{n0{xaN/4ת0}^^VU`҇LAp(Vn + 1x`کY'։WdP$'DJ AvBAQG+z:HzǖF1jJLqD^"n2dCIPdJU5HlL,zhHj;wNHFiST@&T{>Yd#HH" hZm7Ud'-5d }Ͳ YUL }NfFɀHgGթL^Lvrl:T=6odwgwf{$@V/O}"/$uYȔa`2.wqZk$L?6ΘO2V]Ɗ|iaGj|t=iHX{B"dYg+[Ohn\u!#҆LH%Nc *e|::0fɜ%=i^;837u^jVHK3sb>l۬To)?ZcF{T!>pe=Ц:~n9>F-&Mk*Ik 'y,#&u߈ )}?8| ]WHE3j&*i"kc:]/pFKB9k^pGL)!Bm\Bt㶽ņnn@0#Fp$%5N:K$6+?X:X$r4LJNU, nn>K oT"M &HBm"H*pCBܡRJpqlͬ0dz J n7mp4n,y NU)>J*M*J0LlNnd(HS ?m V&z_k@LC&#@*$ZuB@ Xb2nTcƵ&ϾOr'<+B(C&*y":@=b7fv>n$F&$ u΁)ЗMMJp>PTMQS H$Ջ,JQnp&MжOt?w(nP? #lH™‚H~d{G% X#zJG1 0ЌhCD pnmc a !|ː܅PK41J$r*c 'Z:lGJ gp^LQr-p2nk(b<65BjM6U/J%`.*NJs\+ ӡH(,gk!5H^o&qpB8\f8Tnje,#y 021mZd{|mVjN<2̉*X&2* n%HfcDbH匰p RD"㜈\nV8Rh &,hdG'E?f<3?+ QHlQ2 G&# I Se8Gr Q- !Ĉ3Yͤ, #JHwhOE(:r{ 2gi;"4B8X5<+@]/"e?b+4g?0Ij1Jfӏ b0O8q: ,lNtjMfn2$[/U"dVfs=i!H_TeFt929A50urTuJuO"EOj-Fi *`hRDrn?RJ,i FTUl**!MnSb-̦Dc1A+R@!QȦgֻp? ȶ l01˔P1U"@8 DG>KEF< ]4p&*֊nIq2:STì l UL*]':gfpv"Bn/Ɠg nb/-#C.~Ҧ%2VeGIPI^ν"iFL;(CwYK(`-fVfUiDwRBD=t#G N"f$΅sVFҾϩaсfQ NUNV)^1PW~УJ&X5:ⰜLe3+'*q7YAc3|P Y7LB嘩LP |{ܤ -m4D/XaSR+㬻lp 1F1X{j& 0X^|fg8\1\9^mT8*i~0,>=7tX.̦'coΥ)nTq) ŃT`>5tM*"wq77Jv3UdKeŽ*\+,bN6ĉ .ꚁVQXbkN$[p'"}I}L ?TFg56Xo,O) 1gjxҷ$E+\/6y8L bi6TH (SU eL| sי6;Оˬ6.dO z3nf.qk9D#o M6k UY]a SWur7*U &qk~?oK*+O2Fw.ȅu Mo+#Դm|` =jLQ9gN֘Ä*DP Xl8$SoиZ% nNx n %UR=;i:њ2ZssƁZعӟIVZ ƕ 59b+ܥ)=`kEn?ThCGs5+N "m'Q[Ttrn4t .Db8j'K%C c&ԬPS^6kX5\)wzzoYX*QIWjΡcNþNLkUiUZ켜ROEjtL~~gȘ[st8=ԡf3il*i!_xK+7"o3phֳl">Qm ftI#l#WP;Sm6J"y嫶MݐsʍE.=c\=jRic,\aY瞺vt%/ر8ϋD}yZYsʡYv?4 Bp$=CP^>xBX*8P4IR'> Cyji Asٴ>L%H>eΦz  T~6>kjSQM ,4f(%W0 aFi(ubSAƧ 42aX"Q6`tS$͟Xbb@}N&¬.CۡU6ܿa8n ARuwZ_ (z-3&ɢj>%J\o%bRè`,bo::ܿ &s/gd.3Jt"LjܧIs-I#Z&Ԧh ^&b;)z KKJɠN* HDԲ@ m)KD·5,"I-LK̸NO4DPLkc22 Gn;}!nS1Q3Fl<*NT P0'5˗b+iMvFm@$˳\d5D9e!U'h-r݈-X" 9TlmV00 A[Sso:hҒͮ!U|[n`ԭncV1 Zi9Z]vDy³rYmZKSΝ:ziWγrs&4+;Ge`R<]IOdKm*m4Va@+ro>>颱} m6:/̪6%zlC2-Mt&,=?RБoJYBJσًyY|sYH+WG{"H@5rV#$B QH"Y$ͬ9,'&̜!%{6 q-OX) 0Sr!`y >\CKIkd¤V \P%q> w`,m(wy3Z ߣ{z;slfCtJL1,shbjˈͱ²PX@ےu KjGSaȓ|&M`+3>%Am-Is,Zdi(M!.ˑc"Vc,ukɘqRE;_D8v!p8:"K $R&>v/"(.,T6rI: H-#?,H$> ҒT◲@li3bX\JDVlg`˃J)f蔱lk LI;|j! UEE)=yǀT6>״m&k#o 1aRC8}5bbE{F䙫AټȕJ(2_`dؼzٔbkiF՘ڞC;r1![$mOXI*\EAV*+sE{)K\J!*mߊK$9M#CDWO ̞aiV\s=_{ :?~VfD|oŋS&"L*FJh)qPlwHk;ru$@'-0*d'u&֌A%zl(R"`Xф` fh"ӛuR&ff)5mND1 RgVAA0,ɶFˬ*= Zޮ;d#&< A!q @#Y 4^^6%DtʱӽDf@=-r '&a=ڒ"5lJ洁To4[FJԳ8ƒvEd́dz;$X a ADZY{=0|hʮ1 VA1G.\}jLp♮c.r$<8tޞJV&[K=T Bi!2H+*?U~C탙>'Lv.l2,RJV ҝC+ӿ4P0.5ٕ&J& 1ֽa/ a5K+$ɒ7"Q12.fǎi?~.iК1i*镱j99"K>ig+'<ﶚ/"?i , :;,'툓L-3c79kB'@AG BF.4q1?Sjk{H869)le#zTAI܆9<=$ y;Ĩ,DkIc೹:IK:P+#q7 :")XB,7>ʮ[\É*0в)8?eCĺ@"=29ZZpQZꉤ1W8hWJ Ӏ R!K{sL:{|kěLN>2&Jڰ6|JzLI,+"#Dry8`+eTȷB9BcG"2H JH~@Y६,B)d_ iCIO17Rl(!Y(.|$FԮx5iH:B!B"ȫ dHHO0YMğ )wŴMѹE , )z7ITs@R,'˝ 4P 펢jQDi줚ݹsCţ|Kڻ8G붘y~!QNCDr=@NXVJ7mcR̜;$~ClR@RW1ƜcF9PR}U%AYFSz)E&9&c 5ٜ+*61Փ"LmQRɨYa yJ5f?ԃ7V @D:;M K$m5vDl☢k6Y;u(%n$\P+\X7yp4o QԹKMϬŭַX׺# o9se#3:߷aW KB:ص2gj[pL ~c9BP;!LI(V*]ȍ<-|˻©/C(": (!yel*ܻ}Ɯ'=: KCвb[(bC6T*@ K*͖mKRb*\h!j\#(8M⭝2 " t+$8;j۟zd1ec-Fmj!?hIYJ\,ʢOsjG)A/;UE^M4L{ ~-@PC]R#DGb2$x~GMa.*v62ia\;FKObE Q/D2AJbOI8ݸc\g35ieNFܤa@p4aotDPdq$O#er#O#uX xB#dWFv;JUR0'D]NSS6snK^b)F뱴( rzy&lBR9I eo8|5{mi KG֘G#IJSh4-=-Ab^Z4QA<,;ǎ#XuBd`jVR;ط&+;㼘BJ3VZ"{W&&w5M=:4m(>u&e< _<^GBBK= Z1i#rl`."(Æ 3XÚnSTrH̼`5]Cꥂ)4YY!kQ$w=cM"*?1I/EA#Tn0ǶLCZ{ n.T9HWCOk,tY*r9SaBpZhei.k0խhEn%`{TF|=N:l AFXψi0&~3?=cOgm&f+'~m`x!ѥOx .=0R+j"  yxcTFbv,b_AP@ ʍʐ]Q6+ D3_e49nO(GDGbK >+eXo,GCH ᜂԷ{%C6K+uC3)m#fm7 r*"}.~[ ˜BAx@O  aP` ?bQ8 #PG2 20'Jd9F!ϩ 7 \2W E"21-C)N-I@qVNu(0Ĩ1 E'ƪO{d UF,oeZ {^kK5uh5?0HSLfĮaA=QνJcAHêY‰0R&z5H" Cg/φX "ɜbeH=X4<L1?(DWq=o֣ޣ[f, X) s|> kƱB70.D|*H=Oz7L%  #t*N.=OC(;`)O&lRB/4Ĵ4 5J.)z>h:OV,F" %I,DtCuI`kH S{p5-IlJ-! %*$[ɨDm=VhK̒Ȑܢȕp'ԝ$KKGو$ĩN۩+1+uH5NmhX`+"qskl$☲45W"Utq3CWUiKAw]M*$uCTn<Ϫ zT/Wb+=@)*&chGHz |VV6k!$vfr5:XJE:;HhjV CUU5q="5yu4SP#@Vu5} Zfp($X[Q] LDץLDF[^dN 1M̖$PR:T#H3&9 F i 5T;ZDj&cfJ@Q$Ĝy;bH\kA:T! bJ=ڋg9u]f@]X'݈w XsXmVT!и"̐.kMSxw2@!$@_x,BBnRęܤQ+UA\$Ɩ\Oi@Ι| 0ɧE&\Hb$~>5 q21zi2a04r# Ӽ% \%ƬDwfIH=O!ȩ2>%$sXӈbi .e'ՠdNPtوP@_e:䭼@%M i)yEM/(x$ӄ(w&<c}ętN뢌"P*^)d-Hb,Rg|t"G:Wy041p4+-)TN;#SQ}3ek4@!1jYⳄ4mze!}nM QSFH*@ӤaJ05Wf)-TЭN{vOQvXJH:_F 'ճG|k 2o,6JY> KU5N{J _I&5R\$5:Rԅ4oUu9&g|N&oRܼKD*x!bJZH*( 6[B1+9&fRZ|<~l-lc|C  8"ZӆvW̘d+! Ӎz]_ B̯By\W\bx,DHqt!@'\ZKJDxJ: dcU 轧0Xw%Z8`J}Mv& kh\|:In,:N4jJN-шư&Vo&EC ΁{m,BFͅbhf_ʒ&tIP`.""t<5KBpԷN^}EB`̣ 'h Ql/@ܬD VSfylNoK (ԊA+c'0H ,"M" ɂhc#DZb$UK+!nl1)iViޖ)$bByJVkwû('rA  +  cpZgd"`-Ԉ_+Kx>gҸX){ &C"0$k#'"%vа24}Kgc (!x< R ksH!0lX)1ij"]e-2"O3H|O6*h4(pɭ%hN\q|fBhlfAl,,.g u Y }+xIuAO#s"*GB!nm4zܮ6i)Dd乆9Z'eM 0 LtBE?. ڰFn.k|(oM&Tʤ"p]3 bU̢gO4:_qRpErpF-FF2@UF"T; CH>TDu+77BC0S$D|<fpiS#ZNw@=O:rETŭN˗PLEM8M2grHm!G%ԑRɴ-=R'/S#Lw*PO'B$j+[bʯ *Is iu->t(-ڳ#\-TTTan]Tܳ"3RL(p60S8lՇhS+Ҷ!ˤ`L$Oy*L3=Rq`frVqw1]w %8dxঝqʺtTL+`&s4#D<zΈK<`6067ȜZ /3 ૰C!SΔv7V/P3ZӍz+N&nJJg27r  ӁM $&k:Fv ֋{S1U',7pi74f<dQ #CZN<7p ;8t*C.t DU.+ t(CU1S! w3G!F؇k}e,LW/ZO%@3&J7Q+s_1vL"MՆ7K5EZ (֔.xi}>lH"j#@7-#;`,f-JR(Y/xOUNrFk]L,xC|X3k[yH2\h+v@!O0g@ 6p# wjy45 `:r%::bN&FϮRޤf3jsSځGSZV1`b=ʠ-h!4nCViOE+jmvbA/s_W|Kz6oBe\Siy{LEɦ5%A ϶"[O "f藏AGP a : 1Ԝ]jhbܯv9W 38n;'}+*ʱFH$)0ե/ $8ief/ig= G%I.$}xyŊ;\vyU+۳Npyuu!yE`p} {u|/J$ gF; o$h x)z]l<'cV}XzgYqx7H}_T: p.O˅F˰mO_H )!ؽu,aX<¥4e5O[`tɔuqdw$56w` f'p&"6&ȉ\vnDxcx^|2t+BRX+zb#]GlE+ zF_OZw*Btfq<#Tz6`!Ctg|k2L+͟@y+ M1'BR;cX'U|&kx͓5my+Zc $\jZo 7k5CLa9pP1hNx?y x{;.ݑpvՍ)t3;.x-9S”i>+dwyYuTҍJ؎~DJIr`~zpp9u1nn,:ȳM߇coB&m9U7S$p%yHbgД+HW8\f8 B'Fb.{uw "k}Ԭӫ|]e8= rU^0Y<~mFLAB<\e& ^9-(eq~t!L9Sq.*Iz*nI#}8w}Xbyo,B ?HTC!8LEdf3})N?"r ! C$P 3.FfRy*TX>D*C%H4UD#2YdoȴbVⴹmAXIqj2qcX ntoQYdNr fW_Ն+6Fd2,&nM2~d굢}4, p[kE8e>2k(@ {kR]/JWM䟋$8-hcȒJ;o{D<"Bo{#&O ISxQB\q:H* *hS3 OrHD`%@ \E.ۊAmj* ̒DDC):!ˤ(F~t~hCĒj*JEJB.H#pǵ M.*)-lP,}%yZr* CZ>VN~ej,4; 4 ˸KyCH5"t;_ :Nx]֊0$]%:SjF.wsKm$3a2{ y :\ZҀV"&Hqn$p?v$G=RPQdEb~Ǵ#5!P(!IX/^I2P_QX\{-]5Z *]rJ#GD""2 $%-r#+ v,i9bSNyCLdo=8iDюĆ3LDIiXoim,A GRG-s:4kM3'x8IT}R9 $R\֑ #ő&Tv+ (>p@I̼=6b+W} Ps^'O,5d(zȁR3$0E"jɵƸ6E!ꪎmQAv cA*Gb3R,\9"ܭ! Zeb)m(Be)i@%:ވz"K<}6|Gڒ%HDzj %V}fhՅ$Ry9')u1L)\-0 j2w$:6!Jh׻ @DBp|BIe˺Egw-wLհxqC9o4Mab5]3fҪ(Ib䖔O+H$.ƞI*8"2˝!%.N1YwNU]t Y%wܩ}Q "'[S .TPy֒ 9,B.t}<4(qk[kK䶉oc(Ԅ3. 2fZ;<ռ۵;g.Qwl}UPm+7f8/LC~]C떾9Uѻ@څV}: S<%f6"u6R5]dylؠP:ݝV[B26;Q5N%GqGA/25Xu4wRWq梠9>7Y=?T)mΕ,ѼxcL( cc]A竩D2wPsxO[H $D"F|6!+hwK|#@nS~'S|a##ꯨIS6K w6h@wofi&;QuWv'q<~;T#5>( 2{CYY#K  ; 9 [rfѰ~>&[/3l [SQ1.%p5SA0 rAΰ"`p`)a,i#p(r8X'B>تѹ+#s)񹏫%4%X*yM 3 sqvڈ2JP#ˀ3^(1Ik}-%8 i&_SDjs.q/hʲC" ƙF2R<9+%39,# B YJjCy^IZ8'!|F[+l,+RT1)3q&K\4zЇvE"zs5k ߖrۨ7@, 1G޺ "i,ZǨ`z<*] |!KQ ڭJ+Z$W;)l&da~,bӑBO-0 Y 8,O?(7Y #:=xIǴѥjBgs|kz$34Y3ؼJi 0 ;>Sk2H 59Je 0J 6L7pCRm8`}89x[ȷcfAGy;IWchI;"R@[dX1q&<<68ܑ[u*ymb<T%dGI,q} 7y|+< *3h%3Iy.t3?DѵOTV0OK#^"r-?$P4$|7H6D <.ޫ\sD ±SS 4 R>b߸֨'":hӮ6APC@AET쇣-8Js8x, <*3llSKR9p aljN2T8sN+4;`Le yݣEd{>(%+%T)KRJ* yC'4@+FNQDr@[VP3 N}KBZPbML3IOFS1H̄ϳ(C#CIכebڤzfE023izxQRVDuJïLY?AE<-!*OKqٓJ3"ImRuTWJGr԰#m҃83¸ۗQDD|ԉZrwj_䝧 E *&U}6\L:˩ԋJ$QM4ɪ+Ӓ4!~c$S EDBlR'1-$=y6KrȉE[tTuBCwbr\.S۱?"׮{y> CIuE!(81-5*0ؒv$IB 0", |˳L ?:-9E:v݉Ee[^㘠 ½l(]L+; \"XbRҋ$ĽX0FYI& k<CƝЉSZ5u1]JfLl^%7cfmd ֢ad[2oӒ+ځA;Yu^[rj` J؇@h1"VB:`?n<%$@MC4U̥F,8[SM]4W:Sq<~`\6 d{\aLs5x[eĪMAk@yZ+Z8N>U0+%IdXݞՔC%/g›\Fgݣ NrU.]-yv֒@=ID\3w>yؿ籿 !I4{B`L$j{ /P|Qt~j&/NW8{9vV{)7)u7~wWp8n[NVpZL'ks!9:gzT<[`p;>zլʰ'9pd.*~߯mO5]!vkf^ҩh}ai.OB$P6F?! j݆0@\$}I:}$-@@P}& 02>} I6V?3 ,k7 %(" 6Joþ;(zjC0\̙H껶U.)MsMJ -4K/gN [ ެH=—%);L rcRh'#k\]&5!(̧9 gh7ݽE@᩻~ǶeGJb1QYb7Ә\fWC2:rwZAtj}RHL@ʛEy~*);|$m%;`I&qlU[LB8N|nm=E/e;,i]usEFag(frQq(on}# ">B 2gҫV.K<N;m-;p@~W / "iX}'7 `@Vh PdT\S"0?׳p4z`CTB0VuȘl6-YjJQ{f F<2Q@F/okG|+EQ}׳(.|7Qxt?vbeOB',N` RM] 5kR-"$DcMOI̱>DeAy*lZ1SEče kJ]yh|g!j/Sn?6N^Q1M0AW]i"@̮zB2!+$8h2϶S4SBF^LœUBM*뽧2@ XȭbɊ$ ,#ZLDgOz6r:Q:ұm$&B:X弱t˕:hYDps.1PHOV}!'sUz虅e66^) !*c\n+0c@ ZJpꋮ pIid"j⻶!ғ~jCȀʝRWQhzgC]+.,ud$šy]un6 jt6#hHmmj>AqTHe 8BM8S0* C9R!0E0_CHoJ0 bwi $k=;&`õ|Cf8Vu[urg'V!5]A i %3"@'oCKTi3פnbaޤދt_~sF-;GC`|rp,*@@6`O  aO`A@V-ŀq=H_28( ?cJW!-7EoL%,Nagod11MbXĦ%5*$J}Xf5zuc)Q%yDHj$bNeЈ8H l$bWY6GuNcQByh -D?/PifJq4* f#HwI4䥼捱1s+ \0qZ8"3>)[NiR>ȉ\iNSJ}om "Р0*DKc>D󵶢߈XU]=*`C"-kDJ3|f&,b)ŀ LŮ΂_9C`|/`2\v(ZhP.)Hhju+/,1$[Yvڇۈe;WbhPsߏ ک5EF8[Ľy?&,*kNh6 Le7SK  ͥQ8ZU'J揘*R]əJ "Ȇ10-*w:R>*pZ̤ lp1-dWgV| Ih2 2\$/#7yH*R;jɺHD6>tQ 2|@_;|dݤ&wy)z 80w/嫿7PXG=!,81K 0&XY2,+> w̳4ufIpε ؾd &I>,hf"DfmDD /*t ZE9,[RN](,7#;%J&v;\.Aӱ?̅J ?1(׏rX3#(Cw. .R`NRPR5F!f?4$-x, y|s^qDrU!GuAh]GTr;"r+J\85B>t+Yp@ N gWZo#=6K&amt`ਦDoK4aـm$0 UB^]I<,!MnHGt`5(>Iy.bONI a3WGh`zZbr%psB Imq%09@)ߢdpeđTKjL -3%HJ!"TɧPdy2dIZK3H.{ɌE9p/b@}NZfP c*zYs׺|w0E]̢F\j0o f>JNM A@,RԪ׸}#s6 Orި= N<+CIW+"a[',^VzLodN|Qie&_j>qI1%\A _,w--s,0kW_K"b,7Q ,'کbP uve|\קZ|o@"7C'f[,ʼitl #U(3G#ml4[+KQƖ(礭.I&[)(d^ƇVۣTH1YNl(6 9s6Nrzn\k@-2>!Yߚ)7c*h N!-ms*u$B3z_W8ȐU, ҏ NB#mG3!csU_כ3jI;>Àa"Vs Z$NΪKM]4={EB+6ڠ>mUa-298=HE!Y8&6Sv>PŹuPUғ|$č5u" V>*'qO4,[*n %-85 jTRk)emཏ#ȕx&= qsNK:DʈSto]zg\Ib&iYs,i,˅;\*M"<+F&j&ZHf6ϊ|"BF=oHD&#mDŘ=)(F(mhŐ'}ȷɀPɢ*F;\'ž ҝ m "AD #\ntB&eX*Xj,{LPbs,FTZL8֫v$k0͢R%+E(~nh8 uJI䥢A!4+SQRL{P N##{.ebIQX0d*PK (F*bIQDP0PH4!QUGi)l6b%+~P'r. GBjB,YZP^{L oBj$o"&bl Д-|-ڤWsb#-k楋!$F֐"1 \0G|4#ֺJM)Fp?a A"TPҦ\)J=" K"rNPs'Pͧ-Qd2El^-ʪ*d"RF!L!TFc bUo%R/1oL01@ƭd#I2EHGn,F,Ѥd~Ξp;)US@Ob Nq q%Jh/zg\"*_$I'6E "0MnzYPZN/2@HhO .h$PС  a pN!'j~@]1JLTQqGsI-J q[^%^KD+~ L1Ђ0#=#Ǧk7.kp""qH)RZEǨ>8=p5 i-$pA C#ևJ)&0/ J HJ q򯥤bҜ R$[mRTM j\S  m!m?Ro7.uT;bޒq"#ώ*IELZM/`(a-FF}}?6f]$6 _GlD+?QqqB#(dpRR"7\VVe@J {2T&fhuRid`d@dTW&+qRI2aszY,LB=h$ݪ#H0Z ǢL"MQ1cpl#-Ġ -.5*`ܒ.oDc$DC)ZKCױ&_N7Vfk<(!KQ`+k)<A7B%0*HO"Aq=‰8n8H\mo|T&jjTbB~p"WE'YwCH*+$pXFNF8D %^lcl|b[q$9@ڭ 9.#RG#EЄZ*81W_uaOMNkpeH %tT4V@k-hQR;*ƾn7T 9`@RswHrӢ唐Pb pݖH4j$3 -*S|7{2,ctIs1L-Y)26clcژ`u5)Jùgdm|c MzRDMFjCH B }mN7Tkq'JP]-X"wʸEd pdNJ,sJ3bO8bHPm7JB7"YIp;Ks#2F$JJʬŃ,l!V.xNP!$iwdI>ms<0CM8?4!DfVĚDA0bށ!R! |6~! j>y &Wues^. ;/,1-7t8_f%6+WK/B%IH~"Y\ қ9t.Wqe3m8ґy*WX(N*Қ󹃟\X+%if(b /BO,",y"h!#x܌#/T'|IE0Np"XyRozVc5m01W;,!(쮲{^wM"SEl3D/IXEIYsi&8;bv"AsE:,طM3Kw-5jNi^f, Pbc6C @S PzokkD3{W#D̒˥YraPbmph?@]'dPF' !^̰d68Z]6EN7 Q"J/䚺[ͷz'$y'TZ"4Y|oXк1$K9W#rJ UHp #Z^μw*f #\[=my[9ӆnRFNDu6D~G|Oi0ū@|*GDbkB LߚX<uRJJ}$(+9cVm1[r'jIpaK.cZݦ=[D~9U #N. /KYb;v&:wbwCTusj}<@V @v|bF,'ql$t,;5!\D$Kv>@?]()ɼ"k#*aũ2G'pB@PrC~NTjEqBHºax$7N6HD&MJSr@S+%)dGQ6WnE)*M1ʒMi[~OGg 'Tekl0ٻW*M.HG"!83gzλWTGW's+v"-gQ?sWiʲ:jy8"A*643 нb_{o珅zuLz Y=4NkCyXHj lC,!,dG28<6  ; q+l#^.BiSY A Yc/3qP&O,g9CgQ MϦЙ^'A᰹ M}uoM^#˕C36;z"q0nV땉%j;>*'Q\tnT_q9 >oerPٝWNɌJ՟VqIC?m*RjQDx Y:׮ /kE2!L2<'Pv vQ,4H4&!mC0+"#yJ:H,{~b.#1a@@CVѬ.|0z*0(*M귍r*:b:)# L~=ib} D'$rωsF佩zbF(43?j&`ԠKB:ZQBS4 `PTO` j֍\&, {0<#HETjɧ;)A ʲB3 /|pac㠔M8Ҝ2z+Z2QQ^徑DB?Rit5}i]|]eM($n?VXI/p$ VzKz H]HHFW*Qib!! TbԀS1SDK'.= bLՃkq ;26Ot jH:uΫs'RK 㩎# ֤4&4Xe)զ|%sA:sw-O"?2^x@./I|/Mx[M<讒6>`c;h]48BY)śBX*d$EF F෻!:ym;H(DIbiUS}q;hNG\8V];`/>*W؄g6y9d\nC%˸:dX/O &ZLz{H"^1Sj˛y?bvd}+7i )+ Tˮb$,q6匄5*LQAV# :$?Mz!\NIMaJ` 2`yҺhN=LBVckX%d!N:^Z+hOc`\NOMZx0ŐqyLT)Ct2gY*m?;G ?^/̉D?Yi p?@R5oș' QjJjL%ב>B9U섍HFaU,{ R1XY<> !h`3_K@ۉ z2.pHdgV'[].QoO ›U8}]~9v \R%Xfrš}Qi+0N$!!$}xgt9NGA)z~6igie$HZ紋=뜝?~Dnޝ)UKJ;z>-|:YސۯxwN/;zD=wU8~-r)1i^nxd>dzB&W/DfM "F ˦88^!;iS 412Cp<%3+ { 3Ԫ&Ď3* BޫP3z2:J,p"eS-q9S5tpAK$Ca|0A@> db- |z=&Q߻úM*A=@&K@ zfAh) c!,[  zD>**>x$I2Js8ڄ&͇mG KkF+cx=Tiۺ"y ILz-E*4$T-āH% \ (#=y]Bi# }4]Bڱ+s,EDfPiIcĊ[Dr1.4&ƈ#ݔh((Hȧ=‘CB37*鳜6:C:j|Ś, oBX',8 ˦ t 䲌 xȫ,4:5خ&JL7ɢze gEÒqӼ<L[-7ژ Y"dC91۹rv/ZP8CI}$Ԗ@4NRGMMD*ˇm$DClR)4)8'8NЂň("vҫ տ`CT \(Y0E0J cGψ>[AEqSM\?1T40 E{}4XMژd0H|Q!+~PV̎*Ȋ /1VDjkQ#BSO C E1VY5$EA} jM>\:O[T{Tn$*` z8v(39b΢) DZ],TI*!Qo0q4"geD8ifc!Ii+ r>T,Ol< iYUE .(+#aa3%c: ?}@z:: q *9{;DY7I h]{ՎIa(TZɓ)@2۰d;Ne َS܈!]-Aox´ , n2!9VU98X+?Jئ۴q<;*96TD$8EPUKluK.5:%@V]8Uu;:]3'aOC)6TMCx02) >-*făHCեRXe4{dP gunfnT[~c/}O.Wc;K6 1(}p idͲP Zʥ) zXŔ't'˝݌]U?0=AfK[AܑcH WĆ= å Q4ThĊ])zCzf=<|!RM}6/pkk_KLKk_D{I@]dPs}ѿhM:l˹8"Jk_l*+Uj=9c5h_\|JZu.6X6 *`~b^2ؕ~_n:瀂^<] j{qԶ.Lp4fg6.lR/3>t%&ʊnrw*38&M'i#(aV~nX>XWg۔_2OF~۵>i#G;z}68Z8},ݠ,5kX@(n{c~բO[$Hm-6Dr#2>s~MHf.Z{ƗjWVވ\n^9E*W l/RU/v[pF©_b,⧞=V$wqcꌊKfcʰ[گN[ㄾaAs52]y1 Yfgx/YO ^1g6},w,G ׬un@G`VU½p|tF[R([ 4_֓VtME^Ҡ27٫g x=L]^E 3נ瓕g8${;̋\/** ,l^Q^|Nݫ==L=Jˬ7C[eS< * ˴{7|U !7s;c?`@B8"$bx:'PCTJ ?% <&S?yĎI+ßsDq'&:Q+Gg-O@jZ:PV(-5A* ,Ѫ)lZ_ҹmjlb٘ n^BJ-pKj%¡+F=w%$^{P1 h ux~+3ȕ~b04[uT!Gze f5o\MzSt :_rz &@#%䊮b " , 2:4R٦Ϭ)jZEK~kh⋢L *Q#"^*K649h3@PJjRZƤBl HhFp b,V +6H҄4 [B'X}L#?$) >Pj:*H+LiK51(jctຏ IJ,/)49\+kPԋM:i-2ETܨҘֵEd9Q̆418$jWGR>Kjȧ"l2Jds ?T펟0$7Y3ژ۞C*dM}E*؋UNytvyO'3(10~"q=WwFMVQ?$MX*2k"XD)*5jMov;tQv.q --ٺ uRG I:nW2Zdcҷ3BrvGط=c8Ea(M(2b\17Pa/DbpQ_sފ;eC F*`|ړ"AkbɩcA ^(EACA+hYaFuJLx0d:F\ՠYs31AU`sP+zH,l\9d9gI@ #wȸA"Ad/%ϊ3NFtJ`}DX2H0n-/)~CdNro[yCz*mr!,ƞ+cHc4URBIS6~Co"./"WGU<h7K($O !iфI:HaY͒O, )8a BTHGTPR1$x_Qyڽ&b$: O GZNɚcR==>T$"ĠMk iTdDblL](Zk *CiRV,( 8Zn?2ޣ1&{ NZcsG'srKV(JoA; ai_P66VWԙ|*̹HS+5E>IR ؊:lL Dљk%!t\HZD,ZHv`Oevb*Ol mԇ C+1K?S QF~ԹBeFl ;:ND xVdתzƻ'P|t#/gxڹ @ڸYFZ/rZ_f _vuI7e/t5d8(乲c&tGRMX?N*b]Vui+$wn8ZHNb% r:D"[K!=~$!4&{S-O٬%Sc>˶zX}иgBb2B͟1W3C!^XǀLvHd@1P_Q R!va46n =h% Wm]qG',4n]9&emKLNIҨf$ک\mu؎p,Oyi0Qǽ{YX 0J*&O>n O=}g f۵V䷅O¿md/t񜽟/h}+ Ř8jEz)ȚyC Zj┉y,/:L ¤ hH om+\U 2K (gf:"ܢ7OKxǦ C$h+̔ABp^/DlD2nK 5r ).p΢\jY:?hېk-'XyNzN'i|B TePΰha2gvPވ 1)H4et'븚˪+V5Oipz!Tiklb&Pv%&z1VNI8(t r)-ͩb ^Dp*+FUzJ"GU`pw .^`U*^(,BE bl$  k!RPؐBBHn^}pВ #qE 1(LeK`$oΘR^XIFh@"˘(|ZY) ´KjY }1l':Y¤W dB b0dBh,څve)c8JBiJ}Ȝ6̀o_s n! K*DI/:wdžNt/]JKL hDZ¬/ND,&MɄ^& .PZ: :"Z-3hʎO*ﺩɺf(x ;oP$n&ʊZ%3k fN%*XdPܽ* 72̤m' B$KDUsG-IHԋv.T>` ԅzDW(vb*vnh(hځfL #jZ$0fиf./NM!Hc4JDG2z)ޟȦA"^O ҞPM5 n.r%,Ehp^F".w?0H?+RfZ$D+UHI yJQbL-~ ,xak[O.Sbr*Bgh1jS$SЍNrhtҲP|kzY >3tnP`DX;BW "Lk f,iC* (M'L9M XNGU+14EӠ.9:a@Nef.ƳR^00dT % "N r Z몍m)$M,!wrDJP+&XU(\A*tXJX*\Y$.V.U*K}-q=Ke  p$&8Uj-b^Vxu a'&!_r:>x (3V? ȚPMC6zbfdoF*f/ǫ0BuF[r1$6Ⱥ[DSyM:ZOǩ$$'y~KY-7prS_(f)a&' fNK6~G3H*uGfRHavxD5RfjOz3pz% pU@1rJ:DwqOf _(EDPm߳ŨU3(;(/>4_F/ctx>Cn7[{$+DÍ0q汧$ T :ܺ sY1:IvNz[Q2V)V(t饦$F`E?.2pCp_uAW2quCXU`w9Yv7cXJLZZ3mU0jWZu|G %<X'[o]Ds3El]N)5C(hֹ^m&694 ;to1F*;iit(C@z Xx =G(N'kgL+4'_5Z(Lp /6Z}$ nCzxNrl0c3srEz]W2I)S,7f7$~n^˶U~+$b{8I$'d5:eҋ0WK! ƨH%/0ku#"0 *Dи@W.on#3#[ʪJxm]B%!+M2WԽY hp(spSXx& 5}ATrUz^m佫…Ndo12RV8QiX+Y;2 xvMuJB/,Lb`9a[o<]TFij SvގH|go c&v3>ڐ/uЊiIAX$FmPC)$l7Qы=z%1~NE)JbxKf xyiotZ{Ce(-;EpFDrxH-ܩOZeTdfh*dI..gDz"+4dӃ/,5r[W6g%| _fV}m) 8jXX6,h)!ΐP!Ѱ!T^ XQ3:m[no{T"0y,4z 3| j |9#퓘ȗ$]`iGTXB,?9" UKDN7[󓬗f'|Tۅo WYV=T/T.yC27rbՇ2s`.%CR\.+ֹL&Pӎ+qhĠ EeZ<'hx \‰ g+;o3]zД9lg43}SnB݌H^|I~ä{K3`|g,ipb!W!;TBC,~r˄5"qݾJxިͺ}$9Xv3}[y*p31pqr$&ԎF0~T,v8X>(3 s! à(s FЗ| !`@Ԟ%`@ t^Y2> Y^g%P1LVg D$\ d LA=}aNddg.$9]P#w I-Q;`O`NsÂd(0(/Ef5JOPxipg9JfZC- W,ޟ659/3).ݲ*"]KpmLu=Ğ3X~91jN#i*̧1>m)ʆBcc2'[&/b$)**2+ Ӿi0 ?#>1PLo2bNy{W!R =tp| g =`LJ)*ӛ"֮z*mu󢴵2]?)ZTsȄD Gh BJ3"Dj/Ӊ,B;j +fV3!uZ"oP(L)$x  ަQёOBV6$FF@'\S欚˖F32FQ);S)+s;#5T"&62UWd`۴#J!.q_/F~v9@t m#Օ-8.4v8hºR +pÈh'>+2f߽>8Q:Fg~rfǗ<Eyo.ŏ#lSM3r[#mu=lDOnBu3b'+ <d O9(W R~&dpE@2 X9!3'վA}VcD"8(L\2NIn!36V t=Xu wERn_V[ 9 26 ,6ld̰ Riחd*y]:25ՠdHQHJP*q6,>d2TA)@9892D -t jd };w I *RBO=(? J@wZY&ꖭ C.5TP OfKuVZ5mV9YDoqcFyyQxx$؟RJ_WVym-Z|:FP]b&Hy70ȔV?I^nW~i\AHj $ToO&HKdf2$SuGr$A~EgϲPJBYTf#KihXp.%(QHYTpA4cvѼcTmVEv&rCEfpFm)b9"M} _XMSgQ#vTڧ­=~`5˸3 /u $T@#2b5Or5v՘ik(iu5~>x2QX %NRͳ.u:ˇ 횠pO.郝{t=n䲔z/-%dbCrTQg:^-, Y~/cɨdmozŘY$_/>P]*B` X}EV2EʭHݷ=F:xm>AP{bUnG[$G|50oW% 8tEޗBԎ5xuB6>u6,ow̘I$Bk?b4˧5Puu/VH!«} ZmJ/)ᬨ 7K"6㘬Cջ92 kśh:҄U @ }0zHy@!x*4i'iŶ( K J.&;K.c11#'@;3 ׉0OCK&pB$q#/ /"9pry0КB.ޙ ">&Є83YY<+)X>dK2:2:@caFR5"k?a`ɬ Jqs9|_Jcy4Y %3:W+l6.*˺2Slr?3\$H|-Bq  *Hs~>Z3zIčt&%ڣI;P}@Ţ =+tt+ƙXBt Z4"?ӓ&)X$0왂ߓ3t"Z籡.7`(Xʞ!?JdH*NC:c Y5FK\pAA! XLɩDI Jʢ#\)2C7 ҧj<К* 1|)7$ȯ ?R"F*^{G.@c'/L[Nv;JˢW=Y ?Ĵȑ.%+v,S Y ɴ*0t„E)Fit9 t} ʍmH3E-(ӇGC1&TμM><,JLߵK9֖80c3254=RR|#<'ҕQ>yd ӳY91cU$i ȁ6=kҡTK,4W=EIB R8q(Î!0؉=5PW}Y F; и1pb<7 sؘ|U\ d#$9ޫ;Odd\=,[N-谍} 5AFģT_R*`حd==BT:u&0nُaRvʼ\:0T`~.I0XV@]2%% ĤʈZ;Q|2va 6U3b {̤ ,>-ܫC8eW|([@񚰸~7. (sT>E(-m }*=(UIl&uIc Y @}YVK j>]/+yR]HJE7JWQ ^Lٚ}'m;͠)E‹38 $͵ըF+Iٴ0%˵u)Ͱ(0ٚƽU3SkXqײ1 1 J7M:kLd/n$O^4'DM ՜Q1D)R1ܭ068He2`7b{7L?|O(|a@#sMDd/Z=P{h=t5̬ +яD /"3`B<ӯc?/xaEF Q##އ득-#Y{|Koh RSC+я"]_ H#$=7m0m :3>!gV_U6Kܮ)v$֤RҬ-yg AW۸B_.닽&;2Mb6*I I<DYd;=ke,Zg+B8? p!Dw67DtoX"fzJSZRUՂR_ԤR͘ۿ^cZhPN#82k4J漵P)1[LSaN[\r<2j?0p@L;&NX׏j޴q%5]4sP*2ya;thW[F`+6Z >`0|TZi[S #`Y< wQ.߶r.cV̚v?$V;@dY)< 5s3 ՜͘Y[>v:#5OTyiQf1CY:r.B'f`{ #>ǃRYlM"Wlr |S<{j:/ƎO;^<0-Kk;umbaBJ(?P0,B_P6``- =#`)$"?rܞG$ǟp9,n.C}-a %F4'FhHcF=v|9<1'I+ #Fh*#+šZ4ʿF UX})vԱWq{dn8bqEJZK̩ϐVSDn3hߧSHH SI+0S}@Wg2(H-@겞w'ncҚJ-΋FP$'mZRĴ@ 02 ⭟ Bؔ¾Oڦ#9 Alkp4*̟R16ض-Jq+ H+࡬rŎ(+ B(kI1&H̡HN$̋2kV "줭(y0'N'iRhe>l0䴸Х*: rjשʫFw'Ѻw.: 8 1 5x"h2'j!d顳)#IP"?)ԥ,kSgJ3UJϷ.1N q$N*US2~4 I<ܬR1y b78!HZRKiOGqV'LUg!j30>oVVY $*~3u*[Pi+,F# ۸-hEE8P*j`#CE*iGi-5p TǠƸRk_I./P6s:òe}#"4&q8L\ #j!<+΁`hlܺ"kH:O6v\I'}UXi# _^7'ͷ+WA,GJ#1uB ]%vRy* k֞xN9:4DK WQcYN90.-@c `5Q+cfPt6CIeqŒ)ImxL6I YZd9@p(C z"83],48G)h%d$gB6>$dtRvy7>z.1YcD wIȤw$("{J~܋\IHd _5h]#'ވ&M &apeavvNUZ]m挗4bD +.o9B8BCfqɩh #AB]!+El_ex"6Y)X"0.͊ca%IqZye#c3:utBq4聖0*D/BPVkH𒩲 .StPxX;"KL>|y_$)E-;P2M-) eJ٪S}DNb*5Ո䎑X5jL7EV"u0*bD1<DRvnAzn$⶗>s)#؀%N0}E<^zި8¼Q2vfOGWRYV?DEjb@Zbv+AdmQ0ct7~[Tc9 +|(ǦSlWfk,tmɤb_𰈡$&Tj #Vbjicעn;&xD"dGId~Q1E~If"7q?d_ѽt,F05C W՜@Iv^CXÈ""HKpc[H.8olF`RS%b\WwnY.v(qeWXКyo4kѭTI2=g孁fNc4EXalV 3޿RK^:KUr1nX]?ANҧC҄.U?(pGFڿvsաz$CCV3VOǚu=3j i ԴFlc'E8Q6UM&$I3Rɱb~O'ZmJATڄDՔJwҐj"d-pZg8tO٣fZrbKAh7AuOF>*:+Ɉ"*Xf7i>rNNc6( qdxьNIz.nfch& +/T,GF^\8V.c iHE0kbCP3 Ň]"  C>"aI@F:ћ e^@Bck6G ̀GJ,khўbB,CDFcG16%PQTɣ㋜"HɂPeBZw҄.VrE4MGm܉z+O+$ QA! I1(B( 5jIqc7cC+." iwzr!PqB'm(/Wbh;dq)N)%(381H56SZ&aNœ~iȧ r^'T&*I W$rr3`TI.`^|r2lH*5/Inh S0g֌ 30;# :MHGNǮG:CQ) )n;\Fg,UJpf q. '1!qic.-"c C4qM Kꊛ0'M="LjKLW: G8kIO^خ :FQCCH`0n6jp*vݬb1pX$kif0/*k/SO-j'TP5l>^!qHET4T5L+:Nڶ<%±̞Ut'3/Ԏ{QW0/ckkdȱ Jm%2mz?H2a&h/oxPeC^- |ot\KHtffTcQ?Wىze`y Dn->.f*TkTq8j˜賬Nsr(uK[UļYLEBs$ªAiLe ڤFpĒc6n:L^-ќE'3' ,sK@#9L9h?QKCɵGi!5Ln,TEwP.t.LqW(ƨ;C<')5pn(D$q0j/hoT#L:{{j댉h욍 ">¨rgMlԖ%~\1ͦ#z0b?<+ -waI!&0ہX5nt/-9NVT#.0bETC8}toӄq.TӉ62n:*;6mªFYBA Xx!!\PH,.t~,1z+8>jpk ~v4uK6fg2l!>%O~l.qNhFNi@6NE4N&O,tvgNX7_Ģe0‚t7f4T£Ǎ䐆=WEUVMP8a~@'s/\O  La(`4?v-nk\Ƙ!2.@ GH켯Y-mz7I]"uxPX )H,uF ZBd V*Ber^~c="8E?J^5lg8[!d}1`^ъTn÷~H{J}9 *k]alb(JB `r3mD0 =( &zV+%B)+iOLi*Xp3 Tk‘07;!KT ƊR"5}hG=QN'`W`d7m!d02xBIYԨ΄H-ktc˨Vk@9sʮS2Pp-HjHygiHT5S3O%[ǾUux'oPp` w1֘GXjky|,n +)Fj":>eZQ4>Orv)t&{NI9WK@C"v V8jk|Cn.#YmR#@+=74Îp&Ͳ(ߙftGáY$9^D3_tWB z}GBf&M$;tvORҲSfdV]X8<u_5BmLN^+.9Q ?!'?P)E0^d$\AyT:IJ$I$|MӘI I#f#H¢3u2 I'q@:ȡӐ5vH*.N䔹 2eWf2):E찫.\7$FD_xfEX ZP,}5ٝ ]R!,[*]]N/GM*- $EV8ݿg+ck?S +]a E Rv&hs#,Z @H1#(|$IB1@bʒmDD- " BwD.Dz;$Oh#̠)/H8t%CB@F$,>1Dɩ"(`qzF's:OjD!P梨[e6;?L|IndH=+. IFtIsP-ʧ&1^ؐ'm:)t6)G"ݐʌJ<9 R;U>Y +=!7uvG S)t &6܅ICGmE@`ʘ h/X R(P&8"+)XDGzU2]?djӵ:I\J05l?Y>%z~"{Q&ovI(-(E9Ir,`WCP'.u55ڏ|Iwv:'3 '3M|YGتzj>T~M))\)#3lE 1 P+M6H2ʔb;7Moѯ}'ض( u#ZW,ww1@~by3POstc'~IjɔLL81Cք3H)8ͣ/ZU@ EtC$@Rvrd3$>֌R?n-CT8$IUmӧM9Tҩ&n8~s!tS5?N6M2#%tdƲe1(gU@rd1bDBbbQT<9#舜vmW lN9 A+驦CVUJeqyL7#66>̽'-Y,DeZZ%Yk0;2ڡzh` v.y3LJAqs yMض#cX>6fi8E48Kv-0+铱!,ϣr3C,?,$36F,ʓy`c_^B vmlT6̼Q8n(>EA\M0NzU4GyejPg6=m]5ifkC9qH|DladkddJ:Yc&Z-x Hx1Gux ylXZ&.Cդ-YnmJhq3x~Is&O=47hɨ-^D|WE^ --1:=xeXLN<[9vkee?)t 960ɝ;;iv>F-LvnQjv61볗)H~;؇ 1J7;B53 a-bӖl Y}ƕYC]|3] QAK9T442Kȁ:m:s͈ai6<)n!:UZ=urC`<#kWO^@BWtTŠ[R l36r*Hc+8o݉$C$ک; $&5nCG1.Vl]8Ri V@B"Q 5P|҇8̶+9RL@YA k"Iԧ{,Cнk w,C'd%M`J4}._E۳P"cqԁ>@8A1QZ:T-bkjه/1،wr6h6$ܝ1~9 zH 4*RPOR"X D&]PPj ,K+ӅRd`0"N{"mYM2aBgOKkPDK9=Eh;: #csߤ4GF))苫1kݍ5ZQ 5،݀ ,M  + 6XA^ =Ls(/_)ԗ͵1'^p}@Bj>qb4t`TKLJ}LD9IMx!GXU)f2EEf7Pq]ѹɀ1aژŏ94F͇KG@?jj-k;=n=ٿ ^q+da?ϕ^)[-1;Ti]*SDKT](@^{jۋC&Fh_cH1t\5Nj) ,ELfGwi]P,ʇ7M҈] *Ҫ w(,Cځ*ޫ!b4:V+)jo!bȭ_رKÈe@g>1TU.3,+-%|^k. c=hS.. ~ ˥ s"CQ4cv[>Cn e𛻷F[t [$)iKő̝Շ<1s +?dI@HiDSImWX^;&|˘LQcZIe: bRUHۅlǰw^L#-M.6x-5>ڱZ9[5kv.y]15n4rϏ{9@e= VnI6vA&kl;|s14(nzo8vr,Jtu"5Ft+l1l=qԵCjټrP\DBh(-f~1E vl H CfϨ %?Q?$(U㲠 Q#ɣX@u0΀qM(|Qds 40P!hcL <@L-I|iSԩ,"aJHRiV>GnR}Urk%oHԢ;u(.TT[xۋ`,;aQxܚa([I~B ?qKeI4wz)ka>Ҩ";i﫲X[]v(;7LhńI3f@*;mދ6#փv VE(7[OSfe"$.@2C'+h ҝ/}4TYϐFTK *8DmL!",TI3P)E|&3vG vCc /\p?#H))@yZKmk7ňMPp 9?@ p~4F!;rt+ʒ^LP8Cgh" QJ!CeF~̔+!<9pc0؃FB_R@_  5*> X<"sjBCldҼ@BMnY;RE$KӈAPѩ)qҐ S>?@t4И[uh[{bo?0a @׆3d$u96>x.U#*`JbD˔uV^lYN S^qNeq5n4acAU4OTD~frK#^cn[88# )3!/ )EB~F=CWz|'#mX+UZM{zEъ1_?F@uDS$q@p(gYכ5wJUP8 >˵ VJLM5y[} qF0CGe4,V'S}<ވ3L mLcT ~Ovd^d4Fa!M P}yc-Y_ TЋoOj&?9" o&Q3 I:ʀ < nt(u8J9$8,RpO@c ^2Jx,x2v  'ȌR[Cd~( B6ӏٙ|~WrI"o@KqbM 9ͪ8?/7t^;00f>rUu=:K*F ]FvoXQ [O&f!{'!DyCnǵOI; gM)$jNT>_#b^l*&&$#0Rz*L!ԤdeSkڢ #Lg.0nge̒ cIZb"4Eե)ޛF h..%HJδdOi0,M` jT'CbBQg%΢]RK\À= $+,"BQ#l,st> -S-vOf'Dv.K~ KD"B:VcF uGFDsjξ-$a-X2Κ:qN0ЂHܓ!"TYN:cq2y(zOIbp JrBLx/2"An~g@0؟˯88$ /߮@ 2HCd6KȼM֐@V|t x'0z $@N\,E1>-R[TO"eڐD.;@mvQdC$Ǝ1 Z R#RE#&<bQY@O(% fAg ) hmCtE8*l>i`[c~(B((.Mq)O`d6Lng 7Ǭ/+r|y -?"IYv Ʊr;:cƒ" (ʐ!,  ^- , @, z, , (=sH n- HH(]U2PRfmwjB&Kj>  B . /Users/jakepetroules/OpenSource/qt/qbs/tests/auto/blackbox/testdata-apple/apple-dmg/hello.tif HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/en_GB.lproj/0000755000175100001660000000000014776170045025224 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/en_GB.lproj/eula.txt0000644000175100001660000000022514776170045026712 0ustar runnerdockerFICTIONAL CORPORATION SOFTWARE EXAMPLE AGREEMENT You agree that you will not use this app to make nuclear weapons. You agree that Qbs is the best. qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/apple-dmg.qbs0000644000175100001660000000362714776170045025512 0ustar runnerdockerProject { AppleApplicationDiskImage { Depends { name: "myapp" } Depends { name: "ib" } dmg.volumeName: "My Great App" dmg.iconSize: 128 dmg.windowWidth: 640 dmg.windowHeight: 280 files: [ "white.iconset", ] } CppApplication { name: "myapp" targetName: "My Great App" files: ["main.c"] install: true } AppleDiskImage { name: "hellodmg" targetName: "hellodmg-1.0" + (qbs.architecture ? "-" + qbs.architecture : "") dmg.volumeName: "Hello DMG" files: [ "hello.icns", "hello.tif" ] Group { files: ["en_US.lproj/eula.txt"] fileTags: ["dmg.input", "dmg.license.input"] dmg.iconX: 320 dmg.iconY: 240 dmg.licenseLocale: "en_US" } Group { files: ["*.lproj/**"] excludeFiles: ["en_US.lproj/eula.txt"] } } AppleDiskImage { name: "green" dmg.backgroundColor: "green" } AppleDiskImage { name: "german" dmg.defaultLicenseLocale: "de_DE" Group { files: ["*.lproj/**"] } } AppleDiskImage { name: "custom-buttons" Group { files: ["ru_RU.lproj/eula.txt"] dmg.licenseLocale: "sv_SE" // override auto-detected ru_RU with sv_SE dmg.licenseLanguageName: "Swedish, not Russian" dmg.licenseAgreeButtonText: "Of course" dmg.licenseDisagreeButtonText: "Never!" dmg.licensePrintButtonText: "Make Paper" dmg.licenseSaveButtonText: "Make Bits" dmg.licenseInstructionText: "Do please agree to the license!" } Group { files: ["*.lproj/**"] excludeFiles: ["ru_RU.lproj/eula.txt"] } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/0000755000175100001660000000000014776170045025710 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16@2x.png0000644000175100001660000000123114776170045030562 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16.png0000644000175100001660000000121114776170045030206 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/ru_RU.lproj/0000755000175100001660000000000014776170045025306 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/ru_RU.lproj/eula.txt0000644000175100001660000000022514776170045026774 0ustar runnerdockerFICTIONAL CORPORATION SOFTWARE EXAMPLE AGREEMENT You agree that you will not use this app to make nuclear weapons. You agree that Qbs is the best. qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/fr_FR.lproj/0000755000175100001660000000000014776170045025250 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/fr_FR.lproj/eula.txt0000644000175100001660000000027014776170045026736 0ustar runnerdockerSOCIÉTÉ FICTIONNEL EXEMPLE D'ACCORD DU LOGICIEL Vous vous engagez à ne pas utiliser cette application pour fabriquer des armes nucléaires. Vous acceptez que Qbs est le meilleur. qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/ja_JP.lproj/0000755000175100001660000000000014776170045025235 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/ja_JP.lproj/eula.txt0000644000175100001660000000035114776170045026723 0ustar runnerdocker架空CORPORATION ソフトウェア例契約 あなたは核兵器を作るために、このアプリを使用しないことに同意します。 あなたは、QBSがベストであることに同意するものとします。 qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/ko_KR.lproj/0000755000175100001660000000000014776170045025257 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/ko_KR.lproj/eula.rtf0000644000175100001660000000201614776170045026721 0ustar runnerdocker{\rtf1\ansi\ansicpg1252\cocoartf1265 {\fonttbl\f0\fnil\fcharset129 AppleSDGothicNeo-Regular;\f1\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww10800\viewh8400\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural \f0\b\fs24 \cf0 \'c7\'e3\'b1\'b8 \f1 CORPORATION\ \f0 \'bc\'d2\'c7\'c1\'c6\'ae\'bf\'fe\'be\'ee \f1 \f0 \'bf\'b9 \f1 \f0 \'b0\'e8\'be\'e0 \f1\b0 \ \ \f0 \'b4\'e7\'bd\'c5\'c0\'ba \f1 \f0 \'b4\'e7\'bd\'c5\'c0\'cc \f1 \f0 \'c7\'d9\'b9\'ab\'b1\'e2\'b8\'a6 \f1 \f0 \'b8\'b8\'b5\'e9\'b1\'e2 \f1 \f0 \'c0\'a7\'c7\'d8\'c0\'cc \f1 \f0 \'c0\'c0\'bf\'eb \f1 \f0 \'c7\'c1\'b7\'ce\'b1\'d7\'b7\'a5\'c0\'bb \f1 \f0 \'bb\'e7\'bf\'eb\'c7\'cf\'c1\'f6 \f1 \f0 \'be\'ca\'c0\'bb \f1 \f0 \'b0\'cd\'bf\'a1 \f1 \f0 \'b5\'bf\'c0\'c7\'c7\'d5\'b4\'cf\'b4\'d9 \f1 .\ \ \f0 \'b4\'e7\'bd\'c5\'c0\'ba \f1 QBS \f0 \'b0\'a1 \f1 \f0 \'c3\'d6\'b0\'ed\'b6\'f3\'b0\'ed \f1 \f0 \'b5\'bf\'c0\'c7\'c7\'d5\'b4\'cf\'b4\'d9 \f1 .}qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/main.c0000644000175100001660000000003114776170045024207 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/de_DE.lproj/0000755000175100001660000000000014776170045025212 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/de_DE.lproj/eula.txt0000644000175100001660000000024614776170045026703 0ustar runnerdockerFIKTIVE UNTERNEHMEN SOFTWARE BEISPIEL VEREINBARUNG Sie stimmen zu, dass Sie nicht mit dieser App auf Atomwaffen zu machen. Sie bestätigen, dass Qbs das Beste ist. qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/en_US.lproj/0000755000175100001660000000000014776170045025263 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/en_US.lproj/eula.txt0000644000175100001660000000022514776170045026751 0ustar runnerdockerFICTIONAL CORPORATION SOFTWARE EXAMPLE AGREEMENT You agree that you will not use this app to make nuclear weapons. You agree that Qbs is the best. qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/zh_CN.lproj/0000755000175100001660000000000014776170045025253 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-dmg/zh_CN.lproj/eula.odt0000644000175100001660000000517014776170045026714 0ustar runnerdockerPK^C^2 ''mimetypeapplication/vnd.oasis.opendocument.textPK^C \yN content.xmlXo60t, ђS]``C:Wmb)HT.Zt-!am lJnFW(r l|{|>GQ^^kÈ0:L0E%t6־>nO> -|L4r2X[a0"C##QN2K<\xU%v#gNh7j QS<}ʄ~9bXs8qlĶ0!H%aTE(a,acUIl]8TrX[h9SA4rm]jaM`W8U-j.ݐ $P~ ]gTe@֠)]l\A[qH8+pJřhgRiYR!Gnvw L 8R|KG'Ŧ9{>.F^4e^[XXNZ{wZ;d6ZKvwPM-1'8S&.85MN_>EzH"QC8 a0/ _"@Ϣ. ] ҃PMUR` ,"Ʌhzh*A690-Ehm+BW˰{Ww=%mvlS:{j1lƵcNԪ(Ԑ8 TE,F+5-J+]+]QP]Cܭ&dnH,Ʋ>\UgH|UUYۭ4襞R~fa§uO}"~\<\J'ׯO࿤r~v\R٪&߽MLh l#XboPK^CID styles.xmlVn0+ eZI $zjNM?&)%Hr]RS~$z Yp9TQ+%zDÀ˦%~OB2s`m-Z]aqc>KZ@yCkasrТV}$Xr e tZ뺆7ln$֠hL0{6y'Hݺ".iSoGÎ1`r-w뺆<]֜q}ZcrK+7Tb/#(Kl;Xެ9>vD::WOdH<߽o%b$\)_ݫ/PK^C0.eaMETA-INF/manifest.xmlj0  %I"M7MOoܒiroO_PK^C^2 ''mimetypePK^C \yN Mcontent.xmlPK^CID <styles.xmlPK^Cmeta.xmlPK^C0.eaMETA-INF/manifest.xmlPK B qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoplist/0000755000175100001660000000000014776170045023266 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoplist/infoplist.qbs0000644000175100001660000000011514776170045026001 0ustar runnerdockerCppApplication { cpp.minimumMacosVersion: "10.7" files: ["main.c"] } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoplist/main.c0000644000175100001660000000236414776170045024363 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/0000755000175100001660000000000014776170045026520 5ustar runnerdocker././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbsqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinki0000644000175100001660000000333514776170045033363 0ustar runnerdockerProject { minimumQbsVersion: "1.8" StaticLibrary { name: "multi_arch_lib" files: ["lib.c"] Depends { name: "cpp" } Depends { name: "bundle" } property bool hasX86Mac: true // cannot use xcode.version in qbs.architectures property bool hasArmMac: false bundle.isBundle: false // This will generate 2 multiplex configs and an aggregate. qbs.architectures: { if (qbs.targetPlatform === "macos") { if (hasX86Mac) return ["x86_64", "x86"]; else if (hasArmMac) return ["arm64", "x86_64"]; } else if (qbs.targetPlatform === "ios") { return ["arm64", "armv7a"]; } console.info("Cannot build fat binaries for this target platform (" + qbs.targetPlatform + ")"); return original; } qbs.buildVariant: "debug" cpp.minimumMacosVersion: "10.8" } CppApplication { name: "just_app" files: ["app.c"] // This should link only against the aggregate static library, and not against // the {debug, arm64} variant, or worse - against both the single arch variant // and the lipo-ed one. Depends { name: "multi_arch_lib" } Depends { name: "bundle" } bundle.isBundle: false qbs.architecture: { if (qbs.targetPlatform === "macos") return "x86_64"; else if (qbs.targetPlatform === "ios") return "arm64"; return original; } qbs.buildVariant: "debug" cpp.minimumMacosVersion: "10.8" multiplexByQbsProperties: [] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/app.c0000644000175100001660000000015514776170045027445 0ustar runnerdockerextern int foo(); int main(int argc, char *argv[]) { (void) argc; (void) argv; return foo(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/lib.c0000644000175100001660000000024414776170045027432 0ustar runnerdocker#include int foo() { #ifdef __i386__ printf("Hello from i386\n"); #endif #ifdef __x86_64__ printf("Hello from x86_64\n"); #endif return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-multiconfig/0000755000175100001660000000000014776170045024676 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs0000644000175100001660000001336114776170045031030 0ustar runnerdockerimport qbs.Utilities import "../multiarch-helpers.js" as Helpers Project { minimumQbsVersion: "1.8" condition: xcodeVersion property string xcodeVersion CppApplication { Depends { name: "singlelib" } Depends { name: "bundle" } property bool isShallow: { console.info("isShallow: " + bundle.isShallow); return bundle.isShallow; } name: "singleapp" targetName: "singleapp" files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" cpp.minimumIosVersion: "8.0" // Turn off multiplexing aggregate: false multiplexByQbsProperties: [] install: true installDebugInformation: false installDir: "" } CppApplication { Depends { name: "singlelib" } Depends { name: "bundle" } name: "singleapp_agg" targetName: "singleapp_agg" files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" cpp.minimumIosVersion: "8.0" // Force aggregation when not needed aggregate: true qbs.architectures: [Helpers.getNewArch(qbs)] qbs.buildVariants: ["release"] install: true installDebugInformation: false installDir: "" } DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } name: "singlelib" targetName: "singlelib" files: ["lib.c"] cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] // Turn off multiplexing aggregate: false multiplexByQbsProperties: [] install: true installDebugInformation: false installDir: "" } CppApplication { Depends { name: "multilib" } Depends { name: "bundle" } name: "multiapp" targetName: "multiapp" files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" cpp.minimumIosVersion: "8.0" install: true installDebugInformation: false installDir: "" } CppApplication { Depends { name: "multilib" } Depends { name: "bundle" } name: "fatmultiapp" targetName: "fatmultiapp" files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" cpp.minimumIosVersion: "8.0" qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) qbs.architecture: Helpers.getNewArch(qbs) multiplexByQbsProperties: Helpers.enableOldArch(qbs, project.xcodeVersion) ? ["architectures", "buildVariants"] : ["buildVariants"] qbs.buildVariants: "debug" install: true installDebugInformation: false installDir: "" } CppApplication { Depends { name: "multilib" } Depends { name: "bundle" } name: "fatmultiappmultivariant" targetName: "fatmultiappmultivariant" files: ["app.c"] cpp.rpaths: [cpp.rpathOrigin + "/../../../"] cpp.minimumMacosVersion: "10.6" cpp.minimumIosVersion: "8.0" qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) qbs.buildVariants: ["debug", "profiling"] install: true installDebugInformation: false installDir: "" } DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } name: "multilib" targetName: "multilib" files: ["lib.c"] cpp.minimumIosVersion: "8.0" cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) qbs.buildVariants: ["release", "debug", "profiling"] install: true installDebugInformation: false installDir: "" } DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } name: "multilib-no-release" targetName: "multilib-no-release" files: ["lib.c"] cpp.minimumIosVersion: "8.0" cpp.sonamePrefix: qbs.targetOS.includes("darwin") ? "@rpath" : undefined cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) qbs.buildVariants: ["debug", "profiling"] install: true installDebugInformation: false installDir: "" } DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } Depends { name: "multilibB" } name: "multilibA" files: ["lib.c"] cpp.minimumIosVersion: "8.0" cpp.sonamePrefix: "@rpath" cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) qbs.buildVariants: ["debug", "profiling"] install: true installDebugInformation: false installDir: "" } DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } name: "multilibB" files: ["lib.c"] cpp.minimumIosVersion: "8.0" cpp.sonamePrefix: "@rpath" cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)] qbs.architectures: Helpers.getArchitectures(qbs, project.xcodeVersion) qbs.buildVariants: ["debug", "profiling"] install: true installDebugInformation: false installDir: "" } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-multiconfig/app.c0000644000175100001660000000005714776170045025624 0ustar runnerdockerextern int foo(); int main() { return foo(); } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/apple-multiconfig/lib.c0000644000175100001660000000027414776170045025613 0ustar runnerdocker#include int foo() { #ifdef __i386__ printf("Hello from " VARIANT " i386\n"); #endif #ifdef __x86_64__ printf("Hello from " VARIANT " x86_64\n"); #endif return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/bundle-structure/0000755000175100001660000000000014776170045024566 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/bundle-structure/dummy_p.h0000644000175100001660000000233214776170045026411 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/bundle-structure/resource.txt0000644000175100001660000000000014776170045027144 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs0000644000175100001660000001061214776170045030604 0ustar runnerdockerProject { property stringList bundleFileTags: ["bundle.content"] property stringList buildableProducts: ["A", "B", "C", "D", "E", "F", "G"] Product { Depends { name: "bundle" } condition: { console.info("bundle.isShallow: " + bundle.isShallow); console.info("qbs.targetOS: " + qbs.targetOS); return false; } } Application { Depends { name: "cpp" } Depends { name: "B" } Depends { name: "C" } Depends { name: "D" } condition: buildableProducts.includes("A") name: "A" bundle.isBundle: true bundle.publicHeaders: ["dummy.h"] bundle.privateHeaders: ["dummy_p.h"] bundle.resources: ["resource.txt"] files: ["dummy.c"] install: true installDir: "" } Application { Depends { name: "cpp" } Depends { name: "B" } Depends { name: "C" } Depends { name: "D" } condition: buildableProducts.includes("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"] install: true installDir: "" } Application { Depends { name: "cpp" } Depends { name: "B" } Depends { name: "C" } Depends { name: "D" } condition: buildableProducts.includes("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"] install: true installDir: "" } 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"] install: true installDir: "" } 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"] install: true installDir: "" } 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"] install: true installDir: "" } ApplicationExtension { Depends { name: "cpp" } condition: buildableProducts.includes("E") name: "E" bundle.isBundle: true bundle.publicHeaders: ["dummy.h"] bundle.privateHeaders: ["dummy_p.h"] bundle.resources: ["resource.txt"] files: ["dummy.c"] install: true installDir: "" } XPCService { Depends { name: "cpp" } condition: buildableProducts.includes("F") name: "F" bundle.isBundle: true bundle.publicHeaders: ["dummy.h"] bundle.privateHeaders: ["dummy_p.h"] bundle.resources: ["resource.txt"] files: ["dummy.c"] install: true installDir: "" } Product { Depends { name: "bundle" } condition: buildableProducts.includes("G") type: ["inapppurchase"] name: "G" bundle.isBundle: true bundle.resources: ["resource.txt"] // XCode 12.5 does not support com.apple.product-type.in-app-purchase-content type anymore, // so use older specs from Qbs bundle._useXcodeBuildSpecs: false Group { fileTagsFilter: product.type.concat(project.bundleFileTags) qbs.install: true qbs.installSourceBase: product.buildDirectory } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/bundle-structure/dummy.c0000644000175100001660000000236414776170045026072 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/bundle-structure/dummy.h0000644000175100001660000000233214776170045026072 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/0000755000175100001660000000000014776170045025175 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/en.lproj/0000755000175100001660000000000014776170045026724 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/en.lproj/EnglishResource0000644000175100001660000000000014776170045031736 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/WidgetPrivate.h0000644000175100001660000000233214776170045030124 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs0000644000175100001660000000123614776170045031624 0ustar runnerdockerProject { property bool includeHeaders: true Library { Depends { name: "cpp" } Depends { name: "bundle" } property bool isShallow: { console.info("isShallow: " + bundle.isShallow); return bundle.isShallow; } name: "Widget" bundle.isBundle: true bundle.publicHeaders: project.includeHeaders ? ["Widget.h"] : undefined bundle.privateHeaders: project.includeHeaders ? ["WidgetPrivate.h"] : base bundle.resources: ["BaseResource", "en.lproj/EnglishResource"] files: ["Widget.cpp"].concat(bundle.publicHeaders || []).concat(bundle.privateHeaders || []) } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.cpp0000644000175100001660000000236314776170045027130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int foo() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/BaseResource0000644000175100001660000000000014776170045027470 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.h0000644000175100001660000000234614776170045026576 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ int foo(); qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/multiarch-helpers.js0000644000175100001660000000614514776170045025253 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ var Utilities = require("qbs.Utilities"); // Typically, multiple architectures are used for migration from "old" arch to a "new" one // For example: x86 -> x86_64 on macOS, armv7 -> arm64 on iOS function enableOldArch(qbs, xcodeVersion) { return qbs.targetOS.includes("macos") && xcodeVersion && (Utilities.versionCompare(xcodeVersion, "10") < 0 || Utilities.versionCompare(xcodeVersion, "12.2") >= 0) || qbs.targetOS.includes("ios") } function getNewArch(qbs, xcodeVersion) { if (qbs.targetOS.includes("macos")) return xcodeVersion && Utilities.versionCompare(xcodeVersion, "12.2") >= 0 ? "arm64" : "x86_64"; else if (qbs.targetOS.includes("ios-simulator")) return "x86_64" else if (qbs.targetOS.includes("ios")) return "arm64" else if (qbs.targetOS.includes("tvos")) return "arm64" else if (qbs.targetOS.includes("watchos")) return "armv7k" throw "unsupported targetOS: " + qbs.targetOS; } function getOldArch(qbs, xcodeVersion) { if (qbs.targetOS.includes("macos")) return xcodeVersion && Utilities.versionCompare(xcodeVersion, "12.2") >= 0 ? "x86_64" : "x86"; else if (qbs.targetOS.includes("ios-simulator")) return "x86" else if (qbs.targetOS.includes("ios")) return "armv7a" throw "unsupported targetOS: " + qbs.targetOS; } function getArchitectures(qbs, xcodeVersion) { return enableOldArch(qbs, xcodeVersion) ? [getOldArch(qbs, xcodeVersion), getNewArch(qbs, xcodeVersion)] : [getNewArch(qbs, xcodeVersion)]; } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoPlistVariables/0000755000175100001660000000000014776170045025057 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoPlistVariables/Info.plist0000644000175100001660000000156614776170045027037 0ustar runnerdocker Curly ${EXECUTABLE_NAME} Braces $(EXECUTABLE_NAME) At @EXECUTABLE_NAME@ CurlyMult ${EXECUTABLE_NAME}_${PRODUCT_NAME} BracesMult $(EXECUTABLE_NAME)_$(PRODUCT_NAME) AtMult @EXECUTABLE_NAME@_@PRODUCT_NAME@ CurlyNested ${${EXE}_NAME} BracesNested ${${EXE}_NAME} WithDefault ${NON_EXISTING:default=DEFAULT} qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoPlistVariables/infoPlistVariables.qbs0000644000175100001660000000063414776170045031371 0ustar runnerdockerCppApplication { Depends { name: "bundle" } cpp.minimumMacosVersion: "10.7" files: ["main.c", "Info.plist"] Properties { condition: qbs.targetOS.includes("darwin") bundle.isBundle: true bundle.identifierPrefix: "com.test" bundle.extraEnv: { var result = original; result["EXE"] = "EXECUTABLE"; return result; } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-apple/infoPlistVariables/main.c0000644000175100001660000000003114776170045026141 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/0000755000175100001660000000000014776170045021650 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wixDependencies/0000755000175100001660000000000014776170045024766 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wixDependencies/wixDependencies.qbs0000644000175100001660000000423414776170045030616 0ustar runnerdockerimport qbs.TextFile Project { WindowsInstallerPackage { Depends { name: "app" } Depends { name: "lib" } name: "QbsSetup" targetName: "qbs" files: ["QbsSetup.wxs"] wix.extensions: ["WixBalExtension", "WixUIExtension"] destinationDirectory: project.buildDirectory } Application { Depends { name: "cpp" } name: "app" files: ["main.c"] Group { fileTagsFilter: product.type qbs.install: true } destinationDirectory: project.buildDirectory } DynamicLibrary { Depends { name: "cpp" } name: "lib" files: ["main.c"] Group { fileTagsFilter: product.type qbs.install: true } Rule { // This rule tries to provoke the installer into building too early (and the test // verifies that it does not) by causing the build of the installables to take // a lot longer. multiplex: true outputFileTags: ["c"] outputArtifacts: { var artifacts = []; for (var i = 0; i < 96; ++i) artifacts.push({ filePath: "c" + i + ".c", fileTags: ["c"] }); return artifacts; } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { for (var j = 0; j < 1000; ++j) { // Artificial delay. for (var i = 0; i < outputs["c"].length; ++i) { var tf; try { tf = new TextFile(outputs["c"][i].filePath, TextFile.WriteOnly); tf.writeLine("int main" + i + "() { return 0; }"); } finally { if (tf) tf.close(); } } } }; return [cmd]; } } destinationDirectory: project.buildDirectory } } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wixDependencies/QbsSetup.wxs0000644000175100001660000000276414776170045027310 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wixDependencies/main.c0000644000175100001660000000003114776170045026050 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/codesign/0000755000175100001660000000000014776170045023443 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs0000644000175100001660000000256014776170045025750 0ustar runnerdockerProject { name: "p" property bool enableSigning: true property string hashAlgorithm property string subjectName property string signingTimestamp CppApplication { name: "A" files: "app.cpp" condition: qbs.toolchain.includes("msvc") codesign.enableCodeSigning: project.enableSigning codesign.hashAlgorithm: project.hashAlgorithm codesign.subjectName: project.subjectName codesign.signingTimestamp: project.signingTimestamp codesign.timestampAlgorithm: "sha256" install: true installDir: "" property bool dummy: { if (codesign.codesignPath) console.info("signtool path: %%" + codesign.codesignPath + "%%"); } } DynamicLibrary { Depends { name: "cpp" } name: "B" files: "app.cpp" condition: qbs.toolchain.includes("msvc") codesign.enableCodeSigning: project.enableSigning codesign.hashAlgorithm: project.hashAlgorithm codesign.subjectName: project.subjectName codesign.signingTimestamp: project.signingTimestamp codesign.timestampAlgorithm: "sha256" install: true installDir: "" property bool dummy: { if (codesign.codesignPath) console.info("signtool path: %%" + codesign.codesignPath + "%%"); } } } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/codesign/app.cpp0000644000175100001660000000003114776170045024721 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetup/0000755000175100001660000000000014776170045023674 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetup/innosetup.qbs0000644000175100001660000000130514776170045026426 0ustar runnerdockerimport qbs.FileInfo Project { InnoSetup { property bool _test: { var present = qbs.targetOS.includes("windows") && innosetup.present; console.info("has innosetup: " + present); } name: "QbsSetup" targetName: "qbs.setup.test" version: "1.5" files: [ "test.iss" ] innosetup.verboseOutput: true innosetup.includePaths: ["inc"] innosetup.defines: ["MyProgram=" + name, "MyProgramVersion=" + version] innosetup.compilerFlags: ["/V9"] } InnoSetup { name: "Example1" files: [FileInfo.joinPaths(innosetup.toolchainInstallPath, "Examples", name + ".iss")] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetup/inc/0000755000175100001660000000000014776170045024445 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetup/inc/qbsinc.iss0000644000175100001660000000000014776170045026432 0ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetup/test.iss0000644000175100001660000000016414776170045025374 0ustar runnerdocker#include "qbsinc.iss" [Setup] AppName={#MyProgram} AppVersion={#MyProgramVersion} DefaultDirName={pf}\{#MyProgram} qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetupDependencies/0000755000175100001660000000000014776170045026203 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetupDependencies/test.iss0000644000175100001660000000032214776170045027677 0ustar runnerdocker[Setup] AppName={#MyProgram} AppVersion={#MyProgramVersion} DefaultDirName={pf}\{#MyProgram} [Files] Source: "{#buildDirectory}\app.exe"; DestDir: "{app}" Source: "{#buildDirectory}\lib.dll"; DestDir: "{app}" qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetupDependencies/innosetupDependencies.qbs0000644000175100001660000000464414776170045033255 0ustar runnerdockerimport qbs.TextFile Project { InnoSetup { property bool _test: { var present = qbs.targetOS.includes("windows") && innosetup.present; console.info("has innosetup: " + present); } Depends { name: "app" } Depends { name: "lib" } name: "QbsSetup" targetName: "qbs.setup.test" version: "1.5" files: [ "test.iss" ] innosetup.verboseOutput: true innosetup.defines: [ "MyProgram=" + name, "MyProgramVersion=" + version, "buildDirectory=" + project.buildDirectory ] innosetup.compilerFlags: ["/V9"] destinationDirectory: project.buildDirectory } Application { Depends { name: "cpp" } name: "app" files: ["main.c"] Group { fileTagsFilter: product.type qbs.install: true } destinationDirectory: project.buildDirectory } DynamicLibrary { Depends { name: "cpp" } name: "lib" files: ["main.c"] Group { fileTagsFilter: product.type qbs.install: true } Rule { // This rule tries to provoke the installer into building too early (and the test // verifies that it does not) by causing the build of the installables to take // a lot longer. multiplex: true outputFileTags: ["c"] outputArtifacts: { var artifacts = []; for (var i = 0; i < 96; ++i) artifacts.push({ filePath: "c" + i + ".c", fileTags: ["c"] }); return artifacts; } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { for (var i = 0; i < outputs["c"].length; ++i) { var tf; try { tf = new TextFile(outputs["c"][i].filePath, TextFile.WriteOnly); tf.writeLine("int main" + i + "() { return 0; }"); } finally { if (tf) tf.close(); } } }; return [cmd]; } } destinationDirectory: project.buildDirectory } } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/innosetupDependencies/main.c0000644000175100001660000000003114776170045027265 0ustar runnerdockerint main() { return 0; } qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/0000755000175100001660000000000014776170045022457 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/QbsBootstrapper.wxs0000644000175100001660000000065114776170045026356 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/ExampleScript.bat0000644000175100001660000000002214776170045025721 0ustar runnerdockerecho Hello world! qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/Qt.wxs0000644000175100001660000000020414776170045023602 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/de.wxl0000644000175100001660000000011614776170045023601 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/QbsSetup.wxs0000644000175100001660000000254414776170045024775 0ustar runnerdocker qbs-src-2.6.1/tests/auto/blackbox/testdata-windows/wix/WiXInstallers.qbs0000644000175100001660000000236114776170045025740 0ustar runnerdockerimport qbs.FileInfo import qbs.Host Project { WindowsInstallerPackage { name: "QbsSetup" targetName: "qbs" files: ["QbsSetup.wxs", "ExampleScript.bat"] wix.defines: ["scriptName=ExampleScript.bat"] wix.extensions: ["WixBalExtension", "WixUIExtension"] qbs.targetPlatform: "windows" Export { Depends { name: "wix" } wix.defines: base.concat(["msiName=" + FileInfo.joinPaths(exportingProduct.buildDirectory, exportingProduct.targetName + wix.windowsInstallerSuffix)]) } } WindowsSetupPackage { Depends { name: "QbsSetup" } condition: Host.os().includes("windows") // currently does not work in Wine with WiX 3.9 name: "QbsBootstrapper" targetName: "qbs-setup-" + qbs.architecture files: ["QbsBootstrapper.wxs"] qbs.architecture: original || "x86" qbs.targetPlatform: "windows" } WindowsInstallerPackage { name: "RegressionBuster9000" files: ["QbsSetup.wxs", "Qt.wxs", "de.wxl"] wix.defines: ["scriptName=ExampleScript.bat"] wix.cultures: [] qbs.architecture: original || "x86" qbs.targetPlatform: "windows" } } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxbase.h0000644000175100001660000000706414776170045022041 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BLACKBOXBASE_H #define TST_BLACKBOXBASE_H #include "../shared.h" #include #include #include class QbsRunParameters { public: QbsRunParameters() { init(); } QbsRunParameters(QString cmd, QStringList args = QStringList()) : command(std::move(cmd)), arguments(std::move(args)) { init(); } QbsRunParameters(QStringList args) : arguments(std::move(args)) { init(); } void init() { expectFailure = false; expectCrash = false; profile = profileName(); settingsDir = settings()->baseDirectory(); environment = defaultEnvironment(); } static QProcessEnvironment defaultEnvironment() { auto result = QProcessEnvironment::systemEnvironment(); result.insert(QStringLiteral("QBS_AUTOTEST_CODE_SIGNING_REQUIRED"), QStringLiteral("0")); return result; } QString command; QStringList arguments; QString buildDirectory; QProcessEnvironment environment; QString profile; QString settingsDir; QString workingDir; bool expectFailure = false; bool expectCrash = false; }; class TestBlackboxBase : public QObject { Q_OBJECT public: TestBlackboxBase(const QString &testDataSrcDir, const QString &testName); public slots: virtual void initTestCase(); static QString findExecutable(const QStringList &fileNames); protected: virtual void validateTestProfile(); void setNeedsQt() { m_needsQt = true; } int runQbs(const QbsRunParameters ¶ms = QbsRunParameters()); void rmDirR(const QString &dir); static QByteArray unifiedLineEndings(const QByteArray &ba); static void sanitizeOutput(QByteArray *ba); static void ccp(const QString &sourceDirPath, const QString &targetDirPath); QMap findJdkTools(int *status); static qbs::Version qmakeVersion(const QString &qmakeFilePath); static qbs::Version conanVersion(const QString &conanFilePath); const QString testDataDir; const QString testSourceDir; const QString qbsExecutableFilePath; const QString defaultInstallRoot; QByteArray m_qbsStderr; QByteArray m_qbsStdout; int m_needsQt = false; }; bool waitForProcessSuccess(QProcess &p, int msecs = 30000); #endif // TST_BLACKBOXBASE_H qbs-src-2.6.1/tests/auto/blackbox/tst_clangdb.cpp0000644000175100001660000001766114776170045021352 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Christian Gagneraud. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_clangdb.h" #include "../shared.h" #include #include #include #include #include #include #include #include #include using qbs::InstallOptions; using qbs::Internal::HostOsInfo; int TestClangDb::runProcess(const QString &exec, const QStringList &args, QByteArray &stdErr, QByteArray &stdOut) { QProcess process; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(processEnvironment); process.setProcessEnvironment(env); process.start(exec, args); const int waitTime = 10 * 60000; if (!process.waitForStarted() || !process.waitForFinished(waitTime)) { stdErr = process.readAllStandardError(); return -1; } stdErr = process.readAllStandardError(); stdOut = process.readAllStandardOutput(); sanitizeOutput(&stdErr); sanitizeOutput(&stdOut); if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { if (!stdErr.isEmpty()) qDebug("%s", stdErr.constData()); if (!stdOut.isEmpty()) qDebug("%s", stdOut.constData()); } return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1; } qbs::Version TestClangDb::clangVersion() { QByteArray stdErr; QByteArray stdOut; if (runProcess("clang-check", QStringList("--version"), stdErr, stdOut) != 0) return qbs::Version(); stdOut.remove(0, stdOut.indexOf("LLVM version ") + 13); stdOut.truncate(stdOut.indexOf('\n')); return qbs::Version::fromString(QString::fromLocal8Bit(stdOut)); } TestClangDb::TestClangDb() : TestBlackboxBase(SRCDIR "/testdata-clangdb", "blackbox-clangdb"), projectDir(QDir::cleanPath(testDataDir + "/project1")), projectFileName("project.qbs"), buildDir(QDir::cleanPath(projectDir + "/" + relativeBuildDir())), sourceFilePath(QDir::cleanPath(projectDir + "/i like spaces.cpp")), dbFilePath(QDir::cleanPath(buildDir + "/compile_commands.json")) { } void TestClangDb::initTestCase() { TestBlackboxBase::initTestCase(); QDir::setCurrent(projectDir); } void TestClangDb::ensureBuildTreeCreated() { QCOMPARE(runQbs(), 0); QVERIFY(QFile::exists(buildDir)); isMsvc = m_qbsStdout.contains("is msvc"); isMingw = m_qbsStdout.contains("is mingw"); if (isMsvc || isMingw) { sanitizeOutput(&m_qbsStdout); const auto lines = m_qbsStdout.split('\n'); for (const auto &line : lines) { static const QByteArray includeEnv = "INCLUDE="; static const QByteArray libEnv = "LIB="; static const QByteArray pathEnv = "PATH="; if (line.startsWith(includeEnv)) processEnvironment.insert("INCLUDE", line.mid(includeEnv.size())); if (line.startsWith(libEnv)) processEnvironment.insert("LIB", line.mid(libEnv.size())); if (line.startsWith(pathEnv)) processEnvironment.insert("PATH", line.mid(pathEnv.size())); } } } void TestClangDb::checkCanGenerateDb() { QbsRunParameters params; params.command = "generate"; params.arguments << "--generator" << "clangdb"; QCOMPARE(runQbs(params), 0); QVERIFY(QFile::exists(dbFilePath)); } void TestClangDb::checkDbIsValidJson() { QFile file(dbFilePath); QVERIFY(file.open(QFile::ReadOnly)); const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); QVERIFY(!doc.isNull()); QVERIFY(doc.isArray()); } void TestClangDb::checkDbIsConsistentWithProject() { QFile file(dbFilePath); QVERIFY(file.open(QFile::ReadOnly)); const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); // We expect only one command for now const QJsonArray array = doc.array(); QVERIFY(array.size() == 1); // Validate the "command object" const QJsonObject entry = array.at(0).toObject(); QVERIFY(entry.contains("directory")); QVERIFY(entry.value("directory").isString()); QVERIFY(entry.contains("arguments")); QVERIFY(entry.value("arguments").isArray()); QVERIFY(entry.value("arguments").toArray().size() >= 2); QVERIFY(entry.contains("file")); QVERIFY(entry.value("file").isString()); QVERIFY(entry.value("file").toString() == sourceFilePath); // Validate the compile command itself, this requires a previous build since the command // line contains 'deep' path that are created during Qbs build run QByteArray stdErr; QByteArray stdOut; QStringList arguments; const QJsonArray jsonArguments = entry.value("arguments").toArray(); QString executable = jsonArguments.at(0).toString(); for (int i=1; i/i like spaces.cpp:11:5: warning: Assigned value is garbage or undefined // int unused = garbage; // ^~~~~~~~~~ ~~~~~~~ // <...>/i like spaces.cpp:11:9: warning: Value stored to 'unused' during its initialization is never read // int unused = garbage; // ^~~~~~ ~~~~~~~ // 2 warnings generated. void TestClangDb::checkClangDetectsSourceCodeProblems() { QByteArray stdErr; QByteArray stdOut; QStringList arguments; const QString executable = findExecutable(QStringList("clang-check")); if (executable.isEmpty()) QSKIP("No working clang-check executable found"); // Older clang versions do not support the "arguments" array in the compilation database. // Should we really want to support them, we would have to fall back to "command" instead. if (clangVersion() < qbs::Version(3, 7)) QSKIP("This test requires clang-check to be based on at least LLVM 3.7.0."); // clang-check.exe does not understand MSVC command-line syntax if (isMsvc) arguments << "-extra-arg-before=--driver-mode=cl"; else if (isMingw) arguments << "-extra-arg-before=--driver-mode=g++"; arguments << "-analyze" << "-p" << relativeBuildDir() << sourceFilePath; QVERIFY(runProcess(executable, arguments, stdErr, stdOut) == 0); const QString output = QString::fromLocal8Bit(stdErr); QVERIFY(output.contains(QRegularExpression(QStringLiteral("warning.*undefined"), QRegularExpression::CaseInsensitiveOption))); QVERIFY(output.contains(QRegularExpression(QStringLiteral("warning.*never read"), QRegularExpression::CaseInsensitiveOption))); } QTEST_MAIN(TestClangDb) qbs-src-2.6.1/tests/auto/blackbox/tst_blackbox.cpp0000644000175100001660000146645414776170045021556 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackbox.h" #include "../shared.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir) using qbs::Internal::HostOsInfo; class MacosTarHealer { public: MacosTarHealer() { if (HostOsInfo::hostOs() == HostOsInfo::HostOsMacos) { // work around absurd tar behavior on macOS qputenv("COPY_EXTENDED_ATTRIBUTES_DISABLE", "true"); qputenv("COPYFILE_DISABLE", "true"); } } ~MacosTarHealer() { if (HostOsInfo::hostOs() == HostOsInfo::HostOsMacos) { qunsetenv("COPY_EXTENDED_ATTRIBUTES_DISABLE"); qunsetenv("COPYFILE_DISABLE"); } } }; QMap TestBlackbox::findCli(int *status) { QTemporaryDir temp; QDir::setCurrent(testDataDir + "/find"); QbsRunParameters params = QStringList() << "-f" << "find-cli.qbs"; params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) *status = res; QFile file(temp.path() + "/" + relativeProductBuildDir("find-cli") + "/cli.json"); if (!file.open(QIODevice::ReadOnly)) return {}; const auto tools = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); return {{"path", QDir::fromNativeSeparators(tools["path"].toString())}}; } QMap TestBlackbox::findNodejs(int *status) { QTemporaryDir temp; QDir::setCurrent(testDataDir + "/find"); QbsRunParameters params = QStringList() << "-f" << "find-nodejs.qbs"; params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) *status = res; QFile file(temp.path() + "/" + relativeProductBuildDir("find-nodejs") + "/nodejs.json"); if (!file.open(QIODevice::ReadOnly)) return {}; const auto tools = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); return {{"node", QDir::fromNativeSeparators(tools["node"].toString())}}; } QMap TestBlackbox::findTypeScript(int *status) { QTemporaryDir temp; QDir::setCurrent(testDataDir + "/find"); QbsRunParameters params = QStringList() << "-f" << "find-typescript.qbs"; params.buildDirectory = temp.path(); const int res = runQbs(params); if (status) *status = res; QFile file(temp.path() + "/" + relativeProductBuildDir("find-typescript") + "/typescript.json"); if (!file.open(QIODevice::ReadOnly)) return {}; const auto tools = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); return {{"tsc", QDir::fromNativeSeparators(tools["tsc"].toString())}}; } QString TestBlackbox::findArchiver(const QString &fileName, int *status) { if (fileName == "jar") return findJdkTools(status).value(fileName); QString binary = findExecutable(QStringList(fileName)); if (binary.isEmpty()) { const SettingsPtr s = settings(); qbs::Profile p(profileName(), s.get()); binary = findExecutable(p.value("archiver.command").toStringList()); } return binary; } bool TestBlackbox::prepareAndRunConan() { QString executable = findExecutable({"conan"}); if (executable.isEmpty()) { qInfo() << "conan is not installed or not available in PATH."; return false; } const auto conanVersion = this->conanVersion(executable); if (!conanVersion.isValid()) { qInfo() << "Can't get conan version."; return false; } if (compare(conanVersion, qbs::Version(2, 6)) < 0) { qInfo() << "This test apples only to conan 2.6 and newer."; return false; } const auto profilePath = QDir::homePath() + "/.conan2/profiles/qbs-test-libs"; if (!QFileInfo(profilePath).exists()) { qInfo() << "conan profile is not installed, run './scripts/setup-conan-profiles.sh'"; return false; } QProcess conan; QDir::setCurrent(testDataDir + "/conan-provider/testlibdep"); rmDirR("build"); QStringList arguments{"install", ".", "--profile:all=qbs-test-libs", "--output-folder=build"}; conan.start(executable, arguments); return waitForProcessSuccess(conan, 60000); } bool TestBlackbox::lexYaccExist() { return !findExecutable(QStringList("lex")).isEmpty() && !findExecutable(QStringList("yacc")).isEmpty(); } qbs::Version TestBlackbox::bisonVersion() { const auto yaccBinary = findExecutable(QStringList("yacc")); QProcess process; process.start(yaccBinary, QStringList() << "--version"); if (!process.waitForStarted()) return qbs::Version(); if (!process.waitForFinished()) return qbs::Version(); const auto processStdOut = process.readAllStandardOutput(); if (processStdOut.isEmpty()) return qbs::Version(); const auto line = processStdOut.split('\n')[0]; const auto words = line.split(' '); if (words.empty()) return qbs::Version(); return qbs::Version::fromString(words.last()); } void TestBlackbox::sevenZip() { QDir::setCurrent(testDataDir + "/archiver"); QString binary = findArchiver("7z"); if (binary.isEmpty()) QSKIP("7zip not found"); QCOMPARE(runQbs(QbsRunParameters(QStringList() << "modules.archiver.type:7zip")), 0); const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.7z"; QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile)); QProcess listContents; 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(); QVERIFY2(output.contains("2 files"), output.constData()); QVERIFY2(output.contains("test.txt"), output.constData()); QVERIFY2(output.contains("archivable.qbs"), output.constData()); } void TestBlackbox::sourceArtifactInInputsFromDependencies() { QDir::setCurrent(testDataDir + "/source-artifact-in-inputs-from-dependencies"); QCOMPARE(runQbs(), 0); QFile outFile(relativeProductBuildDir("p") + "/output.txt"); QVERIFY2(outFile.exists(), qPrintable(outFile.fileName())); QVERIFY2(outFile.open(QIODevice::ReadOnly), qPrintable(outFile.errorString())); const QByteArrayList output = outFile.readAll().trimmed().split('\n'); QCOMPARE(output.size(), 2); bool header1Found = false; bool header2Found = false; for (const QByteArray &line : output) { const QByteArray &path = line.trimmed(); if (path == "include1/header.h") header1Found = true; else if (path == "include2/header.h") header2Found = true; } QVERIFY(header1Found); QVERIFY(header2Found); } void TestBlackbox::staticLibWithoutSources() { QDir::setCurrent(testDataDir + "/static-lib-without-sources"); QCOMPARE(runQbs(), 0); } void TestBlackbox::suspiciousCalls() { const QString projectDir = testDataDir + "/suspicious-calls"; QDir::setCurrent(projectDir); rmDirR(relativeBuildDir()); QFETCH(QString, projectFile); QbsRunParameters params(QStringList() << "-f" << projectFile); QCOMPARE(runQbs(params), 0); QFETCH(QByteArray, expectedWarning); QVERIFY2(m_qbsStderr.contains(expectedWarning), m_qbsStderr.constData()); } void TestBlackbox::suspiciousCalls_data() { QTest::addColumn("projectFile"); QTest::addColumn("expectedWarning"); QTest::newRow("File.copy() in Probe") << "copy-probe.qbs" << QByteArray(); QTest::newRow("File.copy() during evaluation") << "copy-eval.qbs" << QByteArray("File.copy()"); QTest::newRow("File.copy() in prepare script") << "copy-prepare.qbs" << QByteArray("File.copy()"); QTest::newRow("File.copy() in command") << "copy-command.qbs" << QByteArray(); QTest::newRow("File.directoryEntries() in Probe") << "direntries-probe.qbs" << QByteArray(); QTest::newRow("File.directoryEntries() during evaluation") << "direntries-eval.qbs" << QByteArray("File.directoryEntries()"); QTest::newRow("File.directoryEntries() in prepare script") << "direntries-prepare.qbs" << QByteArray(); QTest::newRow("File.directoryEntries() in command") << "direntries-command.qbs" << QByteArray(); } void TestBlackbox::systemIncludePaths() { const QString projectDir = testDataDir + "/system-include-paths"; QDir::setCurrent(projectDir); QCOMPARE(runQbs(), 0); } void TestBlackbox::distributionIncludePaths() { const QString projectDir = testDataDir + "/distribution-include-paths"; QDir::setCurrent(projectDir); QCOMPARE(runQbs(), 0); } void TestBlackbox::tar() { if (HostOsInfo::hostOs() == HostOsInfo::HostOsWindows) QSKIP("Beware of the msys tar"); MacosTarHealer tarHealer; QDir::setCurrent(testDataDir + "/archiver"); rmDirR(relativeBuildDir()); QString binary = findArchiver("tar"); if (binary.isEmpty()) QSKIP("tar not found"); QCOMPARE(runQbs(QbsRunParameters(QStringList() << "modules.archiver.type:tar")), 0); const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.tar.gz"; QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile)); QProcess listContents; listContents.start(binary, QStringList() << "tf" << outputFile); QVERIFY2(listContents.waitForStarted(), qPrintable(listContents.errorString())); QVERIFY2(listContents.waitForFinished(), qPrintable(listContents.errorString())); QVERIFY2(listContents.exitCode() == 0, listContents.readAllStandardError().constData()); QFile listFile("list.txt"); QVERIFY2(listFile.open(QIODevice::ReadOnly), qPrintable(listFile.errorString())); QCOMPARE(listContents.readAllStandardOutput(), listFile.readAll()); } void TestBlackbox::textTemplate() { QVERIFY(QDir::setCurrent(testDataDir + "/texttemplate")); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(), 0); QString outputFilePath = relativeProductBuildDir("one") + "/output.txt"; QString expectedOutputFilePath = QFINDTESTDATA("expected/output.txt"); TEXT_FILE_COMPARE(outputFilePath, expectedOutputFilePath); outputFilePath = relativeProductBuildDir("one") + "/lalala.txt"; expectedOutputFilePath = QFINDTESTDATA("expected/lalala.txt"); TEXT_FILE_COMPARE(outputFilePath, expectedOutputFilePath); } static QStringList sortedFileList(const QByteArray &ba) { auto list = QString::fromUtf8(ba).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts); std::sort(list.begin(), list.end()); return list; } void TestBlackbox::zip() { QFETCH(QString, binaryName); int status = 0; const QString binary = findArchiver(binaryName, &status); QCOMPARE(status, 0); if (binary.isEmpty()) QSKIP("zip tool not found"); QDir::setCurrent(testDataDir + "/archiver"); rmDirR(relativeBuildDir()); QbsRunParameters params(QStringList() << "modules.archiver.type:zip" << "modules.archiver.command:" + binary); QCOMPARE(runQbs(params), 0); const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.zip"; QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile)); QProcess listContents; if (binaryName == "zip") { // zipinfo is part of Info-Zip listContents.start("zipinfo", QStringList() << "-1" << outputFile); } else { listContents.start(binary, QStringList() << "tf" << outputFile); } QVERIFY2(listContents.waitForStarted(), qPrintable(listContents.errorString())); QVERIFY2(listContents.waitForFinished(), qPrintable(listContents.errorString())); QVERIFY2(listContents.exitCode() == 0, listContents.readAllStandardError().constData()); QFile listFile("list.txt"); QVERIFY2(listFile.open(QIODevice::ReadOnly), qPrintable(listFile.errorString())); QCOMPARE(sortedFileList(listContents.readAllStandardOutput()), sortedFileList(listFile.readAll())); // Make sure the module is still loaded when the java/jar fallback is not available params.command = "resolve"; params.arguments << "modules.java.jdkPath:/blubb"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); } void TestBlackbox::zip_data() { QTest::addColumn("binaryName"); QTest::newRow("zip") << "zip"; QTest::newRow("jar") << "jar"; } void TestBlackbox::zipInvalid() { QDir::setCurrent(testDataDir + "/archiver"); rmDirR(relativeBuildDir()); QbsRunParameters params(QStringList() << "modules.archiver.type:zip" << "modules.archiver.command:/bin/something"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("unrecognized archive tool: 'something'"), m_qbsStderr.constData()); } TestBlackbox::TestBlackbox() : TestBlackboxBase (SRCDIR "/testdata", "blackbox") { } void TestBlackbox::allowedValues() { QFETCH(QString, property); QFETCH(QString, value); QFETCH(QString, invalidValue); QDir::setCurrent(testDataDir + "/allowed-values"); rmDirR(relativeBuildDir()); QbsRunParameters params; if (!property.isEmpty() && !value.isEmpty()) { params.arguments << QStringLiteral("%1:%2").arg(property, value); } params.expectFailure = !invalidValue.isEmpty(); QCOMPARE(runQbs(params) == 0, !params.expectFailure); if (params.expectFailure) { const auto errorString = QStringLiteral("Value '%1' is not allowed for property").arg(invalidValue); QVERIFY2(m_qbsStderr.contains(errorString.toUtf8()), m_qbsStderr.constData()); } } void TestBlackbox::allowedValues_data() { QTest::addColumn("property"); QTest::addColumn("value"); QTest::addColumn("invalidValue"); QTest::newRow("default") << QString() << QString() << QString(); QTest::newRow("allowed (product, CLI)") << "products.p.prop" << "foo" << QString(); QTest::newRow("not allowed (product, CLI)") << "products.p.prop" << "bar" << "bar"; QTest::newRow("allowed (product, JS)") << "products.p.prop2" << "foo" << QString(); QTest::newRow("not allowed (product, JS)") << "products.p.prop2" << "bar" << "bar"; QTest::newRow("allowed single (module, CLI)") << "modules.a.prop" << "foo" << QString(); QTest::newRow("not allowed single (module, CLI)") << "modules.a.prop" << "baz" << "baz"; QTest::newRow("allowed mult (module, CLI)") << "modules.a.prop" << "foo,bar" << QString(); QTest::newRow("not allowed mult (module, CLI)") << "modules.a.prop" << "foo,baz" << "baz"; QTest::newRow("allowed single (module, JS)") << "modules.a.prop2" << "foo" << QString(); QTest::newRow("not allowed single (module, JS)") << "modules.a.prop2" << "baz" << "baz"; QTest::newRow("allowed mult (module, JS)") << "modules.a.prop2" << "foo,bar" << QString(); QTest::newRow("not allowed mult (module, JS)") << "modules.a.prop2" << "foo,baz" << "baz"; // undefined should always be allowed QTest::newRow("undefined (product)") << "products.p.prop" << "undefined" << QString(); QTest::newRow("undefined (module)") << "modules.a.prop" << "undefined" << QString(); } void TestBlackbox::addFileTagToGeneratedArtifact() { QDir::setCurrent(testDataDir + "/add-filetag-to-generated-artifact"); QCOMPARE(runQbs(QStringList("project.enableTagging:true")), 0); QVERIFY2(m_qbsStdout.contains("compressing my_app"), m_qbsStdout.constData()); const QString compressedAppFilePath = relativeProductBuildDir("my_compressed_app") + '/' + appendExecSuffix("compressed-my_app", m_qbsStdout); QVERIFY2(regularFileExists(compressedAppFilePath), qPrintable(compressedAppFilePath)); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("project.enableTagging:false"))), 0); QCOMPARE(runQbs(), 0); QVERIFY(!regularFileExists(compressedAppFilePath)); } void TestBlackbox::alwaysRun() { QFETCH(QString, projectFile); QDir::setCurrent(testDataDir + "/always-run"); rmDirR(relativeBuildDir()); QbsRunParameters params("build", QStringList() << "-f" << projectFile); if (projectFile.contains("transformer")) { params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("removed"), m_qbsStderr.constData()); return; } QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("yo")); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("yo")); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "alwaysRun: false", "alwaysRun: true"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("yo")); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("yo")); } void TestBlackbox::alwaysRun_data() { QTest::addColumn("projectFile"); QTest::newRow("Transformer") << "transformer.qbs"; QTest::newRow("Rule") << "rule.qbs"; } void TestBlackbox::artifactsMapChangeTracking() { QDir::setCurrent(testDataDir + "/artifacts-map-change-tracking"); QCOMPARE(runQbs(QStringList{"-p", "TheApp"}), 0); QVERIFY2(m_qbsStdout.contains("running rule for test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("creating test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"-p", "meta,p"}), 0); QVERIFY2(m_qbsStdout.contains("printing artifacts"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("test.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("TheBinary"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("dummy1"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("dummy2"), m_qbsStdout.constData()); // Change name of target binary. Command must be re-run, because the file name of an // artifact changed. WAIT_FOR_NEW_TIMESTAMP(); const QString projectFile("artifacts-map-change-tracking.qbs"); REPLACE_IN_FILE(projectFile, "TheBinary", "TheNewBinary"); QCOMPARE(runQbs(QStringList{"-p", "TheApp"}), 0); QVERIFY2(!m_qbsStdout.contains("running rule for test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"-p", "meta,p"}), 0); QVERIFY2(m_qbsStdout.contains("printing artifacts"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("test.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("TheNewBinary"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("TheBinary"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy2"), m_qbsStdout.constData()); // Add file tag to generated artifact. Command must be re-run, because it enumerates the keys // of the artifacts map. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "fileTags: 'cpp'", "fileTags: ['cpp', 'blubb']"); QCOMPARE(runQbs(QStringList{"-p", "TheApp"}), 0); QVERIFY2(m_qbsStdout.contains("running rule for test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"-p", "meta,p"}), 0); QVERIFY2(m_qbsStdout.contains("printing artifacts"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("test.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("TheNewBinary"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy2"), m_qbsStdout.constData()); // Add redundant file tag to generated artifact. Command must not be re-run, because // the artifacts map has not changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "fileTags: ['cpp', 'blubb']", "fileTags: ['cpp', 'blubb', 'blubb']"); QCOMPARE(runQbs(QStringList{"-p", "TheApp"}), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running rule for test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"-p", "meta,p"}), 0); QVERIFY2(!m_qbsStdout.contains("printing artifacts"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy2"), m_qbsStdout.constData()); // Rebuild the app. Command must not be re-run, because the artifacts map has not changed. WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QCOMPARE(runQbs(QStringList{"-p", "TheApp"}), 0); QVERIFY2(!m_qbsStdout.contains("running rule for test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"-p", "meta,p"}), 0); QVERIFY2(!m_qbsStdout.contains("printing artifacts"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy2"), m_qbsStdout.constData()); // Add source file to app. Command must be re-run, because the artifacts map has changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "/* 'test.txt' */", "'test.txt'"); QCOMPARE(runQbs(QStringList{"-p", "TheApp"}), 0); QEXPECT_FAIL("", "change tracking could become even more fine-grained", Continue); QVERIFY2(!m_qbsStdout.contains("running rule for test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating test.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"-p", "meta,p"}), 0); QVERIFY2(m_qbsStdout.contains("printing artifacts"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("test.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("test.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("TheNewBinary"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("dummy2"), m_qbsStdout.constData()); } void TestBlackbox::artifactsMapInvalidation() { const QString projectDir = testDataDir + "/artifacts-map-invalidation"; QDir::setCurrent(projectDir); QCOMPARE(runQbs(), 0); TEXT_FILE_COMPARE(relativeProductBuildDir("p") + "/myfile.out", "file.in"); } void TestBlackbox::artifactsMapRaceCondition() { QDir::setCurrent(testDataDir + "/artifacts-map-race-condition"); QCOMPARE(runQbs(), 0); } void TestBlackbox::artifactScanning() { const QString projectDir = testDataDir + "/artifact-scanning"; QDir::setCurrent(projectDir); QbsRunParameters params(QStringList("-vv")); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("p1.cpp"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("p2.cpp"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("p3.cpp"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("shared.h"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("external.h"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("subdir/external2.h"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("external-indirect.h"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("p1.cpp"); params.command = "resolve"; params.arguments << "modules.cpp.treatSystemHeadersAsDependencies:true"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStderr.count("scanning \"p1.cpp\""), 1); QCOMPARE(m_qbsStderr.count("scanning \"p2.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"p3.cpp\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"shared.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external2.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"external-indirect.h\""), 0); QCOMPARE(m_qbsStderr.count("scanning \"iostream\""), 1); } void TestBlackbox::buildDirectories() { const QString projectDir = QDir::cleanPath(testDataDir + QLatin1String("/build-directories")); const QString projectBuildDir = projectDir + '/' + relativeBuildDir(); QDir::setCurrent(projectDir); QCOMPARE(runQbs(), 0); const QStringList outputLines = QString::fromLocal8Bit(m_qbsStdout.trimmed()).split('\n', Qt::SkipEmptyParts); QVERIFY2(outputLines.contains(projectDir + '/' + relativeProductBuildDir("p1")), m_qbsStdout.constData()); QVERIFY2(outputLines.contains(projectDir + '/' + relativeProductBuildDir("p2")), m_qbsStdout.constData()); QVERIFY2(outputLines.contains(projectBuildDir), m_qbsStdout.constData()); QVERIFY2(outputLines.contains(projectDir), m_qbsStdout.constData()); } void TestBlackbox::buildDirPlaceholders_data() { QTest::addColumn("buildDir"); QTest::addColumn("setProjectFile"); QTest::addColumn("successExpected"); QTest::newRow("normal dir, with project file") << "somedir" << true << true; QTest::newRow("normal dir, without project file") << "somedir" << false << true; QTest::newRow("@project, with project file") << "somedir/@project" << true << true; QTest::newRow("@project, without project file") << "somedir/@project" << false << false; QTest::newRow("@path, with project file") << "somedir/@path" << true << true; QTest::newRow("@path, without project file") << "somedir/@path" << false << false; } void TestBlackbox::buildDirPlaceholders() { QFETCH(QString, buildDir); QFETCH(bool, setProjectFile); QFETCH(bool, successExpected); const QString projectDir = testDataDir + "/build-dir-placeholders"; rmDirR(projectDir); QVERIFY(QDir().mkpath(projectDir)); QDir::setCurrent(projectDir); QFile projectFile("build-dir-placeholders.qbs"); QVERIFY(projectFile.open(QIODevice::WriteOnly)); projectFile.write("Product {\n}\n"); projectFile.flush(); rmDirR(relativeBuildDir()); QbsRunParameters params; params.buildDirectory = buildDir; if (setProjectFile) { params.arguments << "-f" << "build-dir-placeholders.qbs"; } params.expectFailure = !successExpected; QCOMPARE(runQbs(params) == 0, successExpected); } void TestBlackbox::buildEnvChange() { QDir::setCurrent(testDataDir + "/buildenv-change"); QbsRunParameters params; params.expectFailure = true; params.arguments << "-k"; QVERIFY(runQbs(params) != 0); const bool isMsvc = m_qbsStdout.contains("msvc"); QVERIFY2(m_qbsStdout.contains("compiling file.c"), m_qbsStdout.constData()); QString includePath = QDir::currentPath() + "/subdir"; params.environment.insert("CPLUS_INCLUDE_PATH", includePath); params.environment.insert("CL", "/I" + includePath); QVERIFY(runQbs(params) != 0); params.command = "resolve"; params.expectFailure = false; params.arguments.clear(); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QCOMPARE(m_qbsStdout.contains("compiling file.c"), isMsvc); includePath = QDir::currentPath() + "/subdir2"; params.environment.insert("CPLUS_INCLUDE_PATH", includePath); params.environment.insert("CL", "/I" + includePath); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QCOMPARE(m_qbsStdout.contains("compiling file.c"), isMsvc); params.environment = QProcessEnvironment::systemEnvironment(); QCOMPARE(runQbs(params), 0); params.command = "build"; params.expectFailure = true; QVERIFY(runQbs(params) != 0); } void TestBlackbox::buildGraphVersions() { QDir::setCurrent(testDataDir + "/build-graph-versions"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QFile bgFile(relativeBuildGraphFilePath()); QVERIFY2(bgFile.open(QIODevice::ReadWrite), qPrintable(bgFile.errorString())); bgFile.write("blubb"); bgFile.close(); // The first attempt at simple rebuilding as well as subsequent ones must fail. QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Cannot use stored build graph"), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("Use the 'resolve' command"), m_qbsStderr.constData()); QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Cannot use stored build graph"), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("Use the 'resolve' command"), m_qbsStderr.constData()); // On re-resolving, the error turns into a warning and a new build graph is created. QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); QVERIFY2(m_qbsStderr.contains("Cannot use stored build graph"), m_qbsStderr.constData()); QVERIFY2(!m_qbsStderr.contains("Use the 'resolve' command"), m_qbsStderr.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStderr.contains("Cannot use stored build graph"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::buildVariantDefaults_data() { QTest::addColumn("buildVariant"); QTest::newRow("default") << QString(); QTest::newRow("debug") << QStringLiteral("debug"); QTest::newRow("release") << QStringLiteral("release"); QTest::newRow("profiling") << QStringLiteral("profiling"); } void TestBlackbox::buildVariantDefaults() { QFETCH(QString, buildVariant); QDir::setCurrent(testDataDir + "/build-variant-defaults"); QbsRunParameters params{QStringLiteral("resolve")}; if (!buildVariant.isEmpty()) params.arguments << ("modules.qbs.buildVariant:" + buildVariant); QCOMPARE(runQbs(params), 0); } void TestBlackbox::capnproto() { QFETCH(QString, projectFile); QFETCH(QStringList, arguments); QDir::setCurrent(testDataDir + "/capnproto"); rmDirR(relativeBuildDir()); if (QTest::currentDataTag() == QLatin1String("cpp-conan") || QTest::currentDataTag() == QLatin1String("rpc-conan")) { if (!prepareAndRunConan()) QSKIP("conan is not prepared, check messages above"); } QbsRunParameters params{QStringLiteral("resolve"), {QStringLiteral("-f"), projectFile}}; params.arguments << arguments; QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); if (m_qbsStdout.contains("capnproto is not present")) QSKIP("capnproto is not present"); params.command = QStringLiteral("build"); QCOMPARE(runQbs(params), 0); } void TestBlackbox::capnproto_data() { QTest::addColumn("projectFile"); QTest::addColumn("arguments"); QStringList pkgConfigArgs({"project.qbsModuleProviders:qbspkgconfig"}); QTest::newRow("cpp-pkgconfig") << QStringLiteral("capnproto_cpp.qbs") << pkgConfigArgs; QTest::newRow("rpc-pkgconfig") << QStringLiteral("greeter_cpp.qbs") << pkgConfigArgs; QTest::newRow("relative import") << QStringLiteral("capnproto_relative_import.qbs") << pkgConfigArgs; QTest::newRow("absolute import") << QStringLiteral("capnproto_absolute_import.qbs") << pkgConfigArgs; QStringList conanArgs( {"project.qbsModuleProviders:conan", "moduleProviders.conan.installDirectory:build"}); QTest::newRow("cpp-conan") << QStringLiteral("capnproto_cpp.qbs") << conanArgs; QTest::newRow("rpc-conan") << QStringLiteral("greeter_cpp.qbs") << conanArgs; } void TestBlackbox::changedFiles_data() { QTest::addColumn("useChangedFilesForInitialBuild"); QTest::newRow("initial build with changed files") << true; QTest::newRow("initial build without changed files") << false; } void TestBlackbox::changedFiles() { QFETCH(bool, useChangedFilesForInitialBuild); QDir::setCurrent(testDataDir + "/changed-files"); rmDirR(relativeBuildDir()); const QString changedFile = QDir::cleanPath(QDir::currentPath() + "/file1.cpp"); QbsRunParameters params1; if (useChangedFilesForInitialBuild) params1 = QbsRunParameters(QStringList("--changed-files") << changedFile); // Initial run: Build all files, even though only one of them was marked as changed // (if --changed-files was used). QCOMPARE(runQbs(params1), 0); QCOMPARE(m_qbsStdout.count("compiling"), 3); QCOMPARE(m_qbsStdout.count("creating"), 3); WAIT_FOR_NEW_TIMESTAMP(); touch(QDir::currentPath() + "/main.cpp"); // Now only the file marked as changed must be compiled, even though it hasn't really // changed and another one has. QbsRunParameters params2(QStringList("--changed-files") << changedFile); QCOMPARE(runQbs(params2), 0); QCOMPARE(m_qbsStdout.count("compiling"), 1); QCOMPARE(m_qbsStdout.count("creating"), 1); QVERIFY2(m_qbsStdout.contains("file1.cpp"), m_qbsStdout.constData()); } void TestBlackbox::changedInputsFromDependencies() { QDir::setCurrent(testDataDir + "/changed-inputs-from-dependencies"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("final prepare script"), m_qbsStdout.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("final prepare script"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("input.txt"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("final prepare script"), m_qbsStdout.constData()); } void TestBlackbox::changedRuleInputs() { QDir::setCurrent(testDataDir + "/changed-rule-inputs"); // Initial build. QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating p1-dummy"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating p2-dummy"), m_qbsStdout.constData()); // Re-build: p1 is always regenerated, and p2 has a dependency on it. QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating p1-dummy"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating p2-dummy"), m_qbsStdout.constData()); // Remove the dependency. p2 gets re-generated one last time, because its set of // inputs changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("changed-rule-inputs.qbs", "inputsFromDependencies: \"p1\"", "inputsFromDependencies: \"p3\""); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating p1-dummy"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating p2-dummy"), m_qbsStdout.constData()); // Now the artifacts are no longer connected, and p2 must not get rebuilt anymore. QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating p1-dummy"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("generating p2-dummy"), m_qbsStdout.constData()); } void TestBlackbox::changeInDisabledProduct() { QDir::setCurrent(testDataDir + "/change-in-disabled-product"); QCOMPARE(runQbs(), 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("change-in-disabled-product.qbs", "// 'test2.txt'", "'test2.txt'"); QCOMPARE(runQbs(), 0); } void TestBlackbox::changeInImportedFile() { QDir::setCurrent(testDataDir + "/change-in-imported-file"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("old output"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("prepare.js", "old output", "new output"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("new output"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("prepare.js"); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("output"), m_qbsStdout.constData()); } void TestBlackbox::changeTrackingAndMultiplexing() { QDir::setCurrent(testDataDir + "/change-tracking-and-multiplexing"); QCOMPARE(runQbs(QStringList("modules.cpp.staticLibraryPrefix:prefix1")), 0); QCOMPARE(m_qbsStdout.count("compiling lib.cpp"), 2); QCOMPARE(m_qbsStdout.count("creating prefix1l"), 2); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.cpp.staticLibraryPrefix:prefix2"))), 0); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("compiling lib.cpp"), 0); QCOMPARE(m_qbsStdout.count("creating prefix2l"), 2); } static QJsonObject findByName(const QJsonArray &objects, const QString &name) { for (const QJsonValue &v : objects) { if (!v.isObject()) continue; QJsonObject obj = v.toObject(); const QString objName = obj.value(QStringLiteral("name")).toString(); if (objName == name) return obj; } return {}; } static void readDepsOutput(const QString &depsFilePath, QJsonDocument &jsonDocument) { jsonDocument = QJsonDocument(); QFile depsFile(depsFilePath); QVERIFY2(depsFile.open(QFile::ReadOnly), qPrintable(depsFile.errorString())); QJsonParseError jsonerror; jsonDocument = QJsonDocument::fromJson(depsFile.readAll(), &jsonerror); if (jsonerror.error != QJsonParseError::NoError) { qDebug() << jsonerror.errorString(); QFAIL("JSON parsing failed."); } } void TestBlackbox::dependenciesProperty() { QDir::setCurrent(testDataDir + QLatin1String("/dependenciesProperty")); QCOMPARE(runQbs(), 0); const QString depsFile(relativeProductBuildDir("product1") + "/product1.deps"); QJsonDocument jsondoc; readDepsOutput(depsFile, jsondoc); QVERIFY(jsondoc.isArray()); QJsonArray dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 2); QJsonObject product2 = findByName(dependencies, QStringLiteral("product2")); QJsonArray product2_type = product2.value(QStringLiteral("type")).toArray(); QCOMPARE(product2_type.size(), 1); QCOMPARE(product2_type.first().toString(), QLatin1String("application")); QCOMPARE(product2.value(QLatin1String("narf")).toString(), QLatin1String("zort")); QJsonArray product2_cppArtifacts = product2.value("artifacts").toObject().value("cpp").toArray(); QCOMPARE(product2_cppArtifacts.size(), 1); QJsonArray product2_deps = product2.value(QStringLiteral("dependencies")).toArray(); QVERIFY(!product2_deps.empty()); QJsonObject product2_qbs = findByName(product2_deps, QStringLiteral("qbs")); QVERIFY(!product2_qbs.empty()); QJsonObject product2_cpp = findByName(product2_deps, QStringLiteral("cpp")); QJsonArray product2_cpp_defines = product2_cpp.value(QLatin1String("defines")).toArray(); QCOMPARE(product2_cpp_defines.size(), 1); QCOMPARE(product2_cpp_defines.first().toString(), QLatin1String("SMURF")); QJsonArray cpp_dependencies = product2_cpp.value("dependencies").toArray(); QVERIFY(!cpp_dependencies.isEmpty()); int qbsCount = 0; for (const auto dep : cpp_dependencies) { if (dep.toObject().value("name").toString() == "qbs") ++qbsCount; } QCOMPARE(qbsCount, 1); // Add new dependency, check that command is re-run. const QString projectFile("dependenciesProperty.qbs"); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "// Depends { name: 'newDependency' }", "Depends { name: 'newDependency' }"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); // Add new Depends item that does not actually introduce a new dependency, check // that command is not re-run. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "// Depends { name: 'product2' }", "Depends { name: 'product2' }"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); // Change property of dependency, check that command is re-run. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList{"products.product2.narf:zortofsky"})), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling product2.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); product2 = findByName(dependencies, QStringLiteral("product2")); QCOMPARE(product2.value(QLatin1String("narf")).toString(), QLatin1String("zortofsky")); // Change module property of dependency, check that command is re-run. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList{"products.product2.narf:zortofsky", "products.product2.cpp.defines:DIGEDAG"})), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling product2.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating product1.deps"), m_qbsStdout.constData()); readDepsOutput(depsFile, jsondoc); dependencies = jsondoc.array(); QCOMPARE(dependencies.size(), 3); product2 = findByName(dependencies, QStringLiteral("product2")); product2_deps = product2.value(QStringLiteral("dependencies")).toArray(); product2_cpp = findByName(product2_deps, QStringLiteral("cpp")); product2_cpp_defines = product2_cpp.value(QStringLiteral("defines")).toArray(); QCOMPARE(product2_cpp_defines.size(), 1); QCOMPARE(product2_cpp_defines.first().toString(), QLatin1String("DIGEDAG")); } void TestBlackbox::dependencyScanningLoop() { QDir::setCurrent(testDataDir + "/dependency-scanning-loop"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::deprecatedProperty() { QFETCH(QString, version); QFETCH(QString, mode); QFETCH(bool, expiringWarning); QFETCH(bool, expiringError); QDir::setCurrent(testDataDir + "/deprecated-property"); QbsRunParameters params(QStringList("-q")); params.expectFailure = true; params.environment.insert("REMOVAL_VERSION", version); if (!mode.isEmpty()) params.arguments << "--deprecation-warnings" << mode; QVERIFY(runQbs(params) != 0); m_qbsStderr = QDir::fromNativeSeparators(QString::fromLocal8Bit(m_qbsStderr)).toLocal8Bit(); const bool hasExpiringWarning = m_qbsStderr.contains(QByteArray( "deprecated-property.qbs:4:29 The property 'expiringProp' is " "deprecated and will be removed in Qbs ") + version.toLocal8Bit()); QVERIFY2(expiringWarning == hasExpiringWarning, m_qbsStderr.constData()); const bool hasRemovedOutput = m_qbsStderr.contains( "deprecated-property.qbs:5:28 The property 'veryOldProp' can no " "longer be used. It was removed in Qbs 1.3.0."); QVERIFY2(hasRemovedOutput == !expiringError, m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("Property 'forgottenProp' was scheduled for removal in version " "1.8.0, but is still present."), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("themodule/m.qbs:22:5 Removal version for 'forgottenProp' " "specified here."), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.count("Use newProp instead.") == 1 + int(expiringWarning && !expiringError), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.count("is deprecated") == int(expiringWarning), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.count("was removed") == int(!expiringError), m_qbsStderr.constData()); } void TestBlackbox::deprecatedProperty_data() { QTest::addColumn("version"); QTest::addColumn("mode"); QTest::addColumn("expiringWarning"); QTest::addColumn("expiringError"); const auto current = QVersionNumber::fromString(QBS_VERSION); const QString next = QVersionNumber(current.majorVersion(), current.minorVersion() + 1) .toString(); const QString nextNext = QVersionNumber(current.majorVersion(), current.minorVersion() + 2) .toString(); const QString nextMajor = QVersionNumber(current.majorVersion() + 1).toString(); QTest::newRow("default/next") << next << QString() << true << false; QTest::newRow("default/nextnext") << nextNext << QString() << false << false; QTest::newRow("default/nextmajor") << nextMajor << QString() << true << false; QTest::newRow("error/next") << next << QString("error") << true << true; QTest::newRow("error/nextnext") << nextNext << QString("error") << true << true; QTest::newRow("error/nextmajor") << nextMajor << QString("error") << true << true; QTest::newRow("on/next") << next << QString("on") << true << false; QTest::newRow("on/nextnext") << nextNext << QString("on") << true << false; QTest::newRow("on/nextmajor") << nextMajor << QString("on") << true << false; QTest::newRow("before-removal/next") << next << QString("before-removal") << true << false; QTest::newRow("before-removal/nextnext") << nextNext << QString("before-removal") << false << false; QTest::newRow("before-removal/nextmajor") << nextMajor << QString("before-removal") << true << false; QTest::newRow("off/next") << next << QString("off") << false << false; QTest::newRow("off/nextnext") << nextNext << QString("off") << false << false; QTest::newRow("off/nextmajor") << nextMajor << QString("off") << false << false; } void TestBlackbox::disappearedProfile() { QDir::setCurrent(testDataDir + "/disappeared-profile"); QbsRunParameters resolveParams; // First, we need to fail, because we don't tell qbs where the module is. resolveParams.expectFailure = true; QVERIFY(runQbs(resolveParams) != 0); // Now we set up a profile with all the necessary information, and qbs succeeds. qbs::Settings settings(QDir::currentPath() + "/settings-dir"); qbs::Profile profile("p", &settings); profile.setValue("m.p1", "p1 from profile"); profile.setValue("m.p2", "p2 from profile"); profile.setValue("preferences.qbsSearchPaths", QStringList({QDir::currentPath() + "/modules-dir"})); settings.sync(); resolveParams.command = "resolve"; resolveParams.expectFailure = false; resolveParams.settingsDir = settings.baseDirectory(); resolveParams.profile = profile.name(); QCOMPARE(runQbs(resolveParams), 0); // Now we change a property in the profile, but because we don't use the "resolve" command, // the old profile contents stored in the build graph are used. profile.setValue("m.p2", "p2 new from profile"); settings.sync(); QbsRunParameters buildParams; buildParams.profile.clear(); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(m_qbsStdout.contains("creating dummy1.txt with p1 from profile"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("creating dummy2.txt with p2 from profile"), m_qbsStdout.constData()); // Now we do use the "resolve" command, so the new property value is taken into account. QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(!m_qbsStdout.contains("creating dummy1.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("creating dummy2.txt with p2 new from profile"), m_qbsStdout.constData()); // Now we change the profile again without a "resolve" command. However, this time we // force re-resolving indirectly by changing a project file. The updated property value // must still not be taken into account. profile.setValue("m.p1", "p1 new from profile"); settings.sync(); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("modules-dir/modules/m/m.qbs", "property string p1", "property string p1: 'p1 from module'"); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating dummy1.txt"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating dummy2.txt"), m_qbsStdout.constData()); // Now we run the "resolve" command without giving the necessary settings path to find // the profile. resolveParams.expectFailure = true; resolveParams.settingsDir.clear(); resolveParams.profile.clear(); QVERIFY(runQbs(resolveParams) != 0); QVERIFY2(m_qbsStderr.contains("profile"), m_qbsStderr.constData()); } void TestBlackbox::discardUnusedData() { QDir::setCurrent(testDataDir + "/discard-unused-data"); rmDirR(relativeBuildDir()); QFETCH(QString, discardString); QFETCH(bool, symbolPresent); QbsRunParameters params; if (!discardString.isEmpty()) params.arguments << ("modules.cpp.discardUnusedData:" + discardString); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("is Darwin"), m_qbsStdout.constData()); const bool isDarwin = m_qbsStdout.contains("is Darwin: true"); const QString output = QString::fromLocal8Bit(m_qbsStdout); const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*---(.*)---.*"), QRegularExpression::DotMatchesEverythingOption); const QRegularExpressionMatch match = pattern.match(output); QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(match.lastCapturedIndex(), 1); const QString nmPath = match.captured(1); if (!QFile::exists(nmPath)) QSKIP("Cannot check for symbol presence: No nm found."); QProcess nm; nm.start( nmPath, QStringList(QDir::currentPath() + '/' + relativeExecutableFilePath("app", m_qbsStdout))); QVERIFY(nm.waitForStarted()); QVERIFY(nm.waitForFinished()); const QByteArray nmOutput = nm.readAllStandardOutput(); QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData()); if (!symbolPresent && !isDarwin) QSKIP("Unused symbol detection only supported on Darwin"); QVERIFY2(nmOutput.contains("unusedFunc") == symbolPresent, nmOutput.constData()); } void TestBlackbox::discardUnusedData_data() { QTest::addColumn("discardString"); QTest::addColumn("symbolPresent"); QTest::newRow("discard") << QString("true") << false; QTest::newRow("don't discard") << QString("false") << true; QTest::newRow("default") << QString() << true; } void TestBlackbox::dotDotPcFile() { QDir::setCurrent(testDataDir + "/dot-dot-pc-file"); QCOMPARE(runQbs(), 0); } void TestBlackbox::driverLinkerFlags() { QDir::setCurrent(testDataDir + QLatin1String("/driver-linker-flags")); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); if (!m_qbsStdout.contains("toolchain is GCC-like")) QSKIP("Test applies on GCC-like toolchains only"); QFETCH(QString, linkerMode); QFETCH(bool, expectDriverOption); const QString linkerModeArg = "modules.cpp.linkerMode:" + linkerMode; QCOMPARE(runQbs(QStringList({"-n", "--command-echo-mode", "command-line", linkerModeArg})), 0); const QByteArray driverArg = "-nostartfiles"; const QByteArrayList output = m_qbsStdout.split('\n'); QByteArray compileLine; QByteArray linkLine; for (const QByteArray &line : output) { if (line.contains(" -c ")) compileLine = line; else if (line.contains("main.cpp.o")) linkLine = line; } QVERIFY(!compileLine.isEmpty()); QVERIFY(!linkLine.isEmpty()); QVERIFY2(!compileLine.contains(driverArg), compileLine.constData()); QVERIFY2(linkLine.contains(driverArg) == expectDriverOption, linkLine.constData()); } void TestBlackbox::driverLinkerFlags_data() { QTest::addColumn("linkerMode"); QTest::addColumn("expectDriverOption"); QTest::newRow("link using compiler driver") << "automatic" << true; QTest::newRow("link using linker") << "manual" << false; } void TestBlackbox::dynamicLibraryInModule() { QDir::setCurrent(testDataDir + "/dynamic-library-in-module"); const QString installRootSpec = QString("qbs.installRoot:") + QDir::currentPath(); QbsRunParameters libParams(QStringList({"-f", "thelibs.qbs", installRootSpec})); libParams.buildDirectory = "libbuild"; QCOMPARE(runQbs(libParams), 0); QbsRunParameters appParams("build", QStringList({"-f", "theapp.qbs", installRootSpec})); appParams.buildDirectory = "appbuild"; QCOMPARE(runQbs(appParams), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); appParams.command = "run"; QCOMPARE(runQbs(appParams), 0); QVERIFY2(m_qbsStdout.contains("Hello from thelib"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("Hello from theotherlib"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("thirdlib"), m_qbsStdout.constData()); QVERIFY(!QFileInfo::exists(appParams.buildDirectory + '/' + qbs::InstallOptions::defaultInstallRoot())); } void TestBlackbox::symlinkRemoval() { if (HostOsInfo::isWindowsHost()) QSKIP("No symlink support on Windows."); QDir::setCurrent(testDataDir + "/symlink-removal"); QVERIFY(QDir::current().mkdir("dir1")); QVERIFY(QDir::current().mkdir("dir2")); QVERIFY(QFile::link("dir2", "dir1/broken-link")); QVERIFY(QFile::link(QFileInfo("dir2").absoluteFilePath(), "dir1/valid-link-to-dir")); QVERIFY(QFile::link(QFileInfo("symlink-removal.qbs").absoluteFilePath(), "dir1/valid-link-to-file")); QCOMPARE(runQbs(), 0); QVERIFY(!QFile::exists("dir1")); QVERIFY(QFile::exists("dir2")); QVERIFY(QFile::exists("symlink-removal.qbs")); } void TestBlackbox::usingsAsSoleInputsNonMultiplexed() { QDir::setCurrent(testDataDir + QLatin1String("/usings-as-sole-inputs-non-multiplexed")); QCOMPARE(runQbs(), 0); const QString p3BuildDir = relativeProductBuildDir("p3"); QVERIFY(regularFileExists(p3BuildDir + "/custom1.out.plus")); QVERIFY(regularFileExists(p3BuildDir + "/custom2.out.plus")); } void TestBlackbox::variantSuffix() { QDir::setCurrent(testDataDir + "/variant-suffix"); QFETCH(bool, multiplex); QFETCH(bool, expectFailure); QFETCH(QString, variantSuffix); QFETCH(QString, buildVariant); QFETCH(QVariantMap, fileNames); QbsRunParameters params; params.command = "resolve"; params.arguments << "--force-probe-execution"; if (multiplex) params.arguments << "products.l.multiplex:true"; else params.arguments << ("modules.qbs.buildVariant:" + buildVariant); if (!variantSuffix.isEmpty()) params.arguments << ("modules.cpp.variantSuffix:" + variantSuffix); QCOMPARE(runQbs(params), 0); const QString fileNameMapKey = m_qbsStdout.contains("is Windows: true") ? "windows" : m_qbsStdout.contains("is Apple: true") ? "apple" : "unix"; if (variantSuffix.isEmpty() && multiplex && fileNameMapKey == "unix") expectFailure = true; params.command = "build"; params.expectFailure = expectFailure; params.arguments = QStringList("--clean-install-root"); QCOMPARE(runQbs(params) == 0, !expectFailure); if (expectFailure) return; const QStringList fileNameList = fileNames.value(fileNameMapKey).toStringList(); for (const QString &fileName : fileNameList) { QFile libFile("default/install-root/lib/" + fileName); QVERIFY2(libFile.exists(), qPrintable(libFile.fileName())); } } void TestBlackbox::variantSuffix_data() { QTest::addColumn("multiplex"); QTest::addColumn("expectFailure"); QTest::addColumn("variantSuffix"); QTest::addColumn("buildVariant"); QTest::addColumn("fileNames"); QTest::newRow("default suffix, debug") << false << false << QString() << QString("debug") << QVariantMap({std::make_pair(QString("windows"), QStringList("libl.ext")), std::make_pair(QString("apple"), QStringList("libl.ext")), std::make_pair(QString("unix"), QStringList("libl.ext"))}); QTest::newRow("default suffix, release") << false << false << QString() << QString("release") << QVariantMap({std::make_pair(QString("windows"), QStringList("libl.ext")), std::make_pair(QString("apple"), QStringList("libl.ext")), std::make_pair(QString("unix"), QStringList("libl.ext"))}); QTest::newRow("custom suffix, debug") << false << false << QString("blubb") << QString("debug") << QVariantMap({std::make_pair(QString("windows"), QStringList("liblblubb.ext")), std::make_pair(QString("apple"), QStringList("liblblubb.ext")), std::make_pair(QString("unix"), QStringList("liblblubb.ext"))}); QTest::newRow("custom suffix, release") << false << false << QString("blubb") << QString("release") << QVariantMap({std::make_pair(QString("windows"), QStringList("liblblubb.ext")), std::make_pair(QString("apple"), QStringList("liblblubb.ext")), std::make_pair(QString("unix"), QStringList("liblblubb.ext"))}); QTest::newRow("default suffix, multiplex") << true << false << QString() << QString() << QVariantMap({std::make_pair(QString("windows"), QStringList({"libl.ext", "libld.ext"})), std::make_pair(QString("apple"), QStringList({"libl.ext", "libl_debug.ext"})), std::make_pair(QString("unix"), QStringList())}); QTest::newRow("custom suffix, multiplex") << true << true << QString("blubb") << QString() << QVariantMap({std::make_pair(QString("windows"), QStringList()), std::make_pair(QString("apple"), QStringList()), std::make_pair(QString("unix"), QStringList())}); } void TestBlackbox::vcsGit() { const QString gitFilePath = findExecutable(QStringList("git")); if (gitFilePath.isEmpty()) QSKIP("git not found"); // Set up repo. QTemporaryDir repoDir; QVERIFY(repoDir.isValid()); ccp(testDataDir + "/vcs", repoDir.path()); QDir::setCurrent(repoDir.path()); QProcess git; git.start(gitFilePath, QStringList("init")); QVERIFY(waitForProcessSuccess(git)); git.start(gitFilePath, QStringList({"config", "user.name", "My Name"})); QVERIFY(waitForProcessSuccess(git)); git.start(gitFilePath, QStringList({"config", "user.email", "me@example.com"})); QVERIFY(waitForProcessSuccess(git)); const auto getRepoStateFromApp = [this] { const int startIndex = m_qbsStdout.indexOf("__"); if (startIndex == -1) return QByteArray(); const int endIndex = m_qbsStdout.indexOf("__", startIndex + 2); if (endIndex == -1) return QByteArray(); return m_qbsStdout.mid(startIndex + 2, endIndex - startIndex - 2); }; QCOMPARE(runQbs({"resolve", {"-f", repoDir.path()}}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); // Run without git metadata. QbsRunParameters params("run", QStringList{"-f", repoDir.path()}); params.workingDir = repoDir.path() + "/.."; params.buildDirectory = repoDir.path(); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); QByteArray newRepoState = getRepoStateFromApp(); QCOMPARE(newRepoState, QByteArray("none")); QByteArray oldRepoState = newRepoState; // Initial commit git.start(gitFilePath, QStringList({"add", "main.cpp"})); QVERIFY(waitForProcessSuccess(git)); git.start(gitFilePath, QStringList({"commit", "-m", "initial commit"})); QVERIFY(waitForProcessSuccess(git)); // Run with git metadata. WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); newRepoState = getRepoStateFromApp(); QVERIFY(oldRepoState != newRepoState); oldRepoState = newRepoState; // Run with no changes. QCOMPARE(runQbs(params), 0); QVERIFY2(!m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); newRepoState = getRepoStateFromApp(); QCOMPARE(oldRepoState, newRepoState); // Run with changed source file. WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QCOMPARE(runQbs(params), 0); QVERIFY2(!m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); newRepoState = getRepoStateFromApp(); QCOMPARE(oldRepoState, newRepoState); // Add new file to repo. WAIT_FOR_NEW_TIMESTAMP(); touch("blubb.txt"); git.start(gitFilePath, QStringList({"add", "blubb.txt"})); QVERIFY(waitForProcessSuccess(git)); git.start(gitFilePath, QStringList({"commit", "-m", "blubb!"})); QVERIFY(waitForProcessSuccess(git)); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); newRepoState = getRepoStateFromApp(); QVERIFY(oldRepoState != newRepoState); // https://bugreports.qt.io/projects/QBS/issues/QBS-1814 oldRepoState = newRepoState; WAIT_FOR_NEW_TIMESTAMP(); touch("loremipsum.txt"); git.start(gitFilePath, QStringList({"add", "loremipsum.txt"})); QVERIFY(waitForProcessSuccess(git)); git.start(gitFilePath, QStringList({"commit", "-m", "loremipsum!"})); QVERIFY(waitForProcessSuccess(git)); // Remove .git/logs/HEAD QFile::remove(repoDir.path() + "/.git/logs/HEAD"); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); newRepoState = getRepoStateFromApp(); QVERIFY(oldRepoState != newRepoState); } void TestBlackbox::vcsSubversion() { const QString svnadminFilePath = findExecutable(QStringList("svnadmin")); if (svnadminFilePath.isEmpty()) QSKIP("svnadmin not found"); const QString svnFilePath = findExecutable(QStringList("svn")); if (svnFilePath.isEmpty()) QSKIP("svn not found"); if (HostOsInfo::isWindowsHost() && qEnvironmentVariableIsSet("GITHUB_ACTIONS")) QSKIP("Skip this test when running on GitHub"); // Set up repo. QTemporaryDir repoDir; QVERIFY(repoDir.isValid()); QProcess proc; proc.setWorkingDirectory(repoDir.path()); proc.start(svnadminFilePath, QStringList({"create", "vcstest"})); QVERIFY(waitForProcessSuccess(proc)); const QString projectUrl = "file://" + repoDir.path() + "/vcstest/trunk"; proc.start(svnFilePath, QStringList({"import", testDataDir + "/vcs", projectUrl, "-m", "initial import"})); QVERIFY(waitForProcessSuccess(proc)); QTemporaryDir checkoutDir; QVERIFY(checkoutDir.isValid()); proc.setWorkingDirectory(checkoutDir.path()); proc.start(svnFilePath, QStringList({"co", projectUrl, "."})); QVERIFY(waitForProcessSuccess(proc)); // Initial runs QDir::setCurrent(checkoutDir.path()); QbsRunParameters failParams; failParams.command = "run"; failParams.expectFailure = true; const int retval = runQbs(failParams); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); if (m_qbsStderr.contains("svn too old")) QSKIP("svn too old"); QCOMPARE(retval, 0); QVERIFY2(m_qbsStdout.contains("__1__"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(!m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("__1__"), m_qbsStdout.constData()); // Run with changed source file. WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(!m_qbsStdout.contains("generating my-repo-state.h"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("__1__"), m_qbsStdout.constData()); // Add new file to repo. WAIT_FOR_NEW_TIMESTAMP(); touch("blubb.txt"); proc.start(svnFilePath, QStringList({"add", "blubb.txt"})); QVERIFY(waitForProcessSuccess(proc)); proc.start(svnFilePath, QStringList({"commit", "-m", "blubb!"})); QVERIFY(waitForProcessSuccess(proc)); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("__2__"), m_qbsStdout.constData()); } void TestBlackbox::versionCheck() { QDir::setCurrent(testDataDir + "/versioncheck"); QFETCH(QString, requestedMinVersion); QFETCH(QString, requestedMaxVersion); QFETCH(QString, actualVersion); QFETCH(QString, errorMessage); QbsRunParameters params; params.expectFailure = !errorMessage.isEmpty(); params.arguments << "-n" << ("products.versioncheck.requestedMinVersion:'" + requestedMinVersion + "'") << ("products.versioncheck.requestedMaxVersion:'" + requestedMaxVersion + "'") << ("modules.lower.version:'" + actualVersion + "'"); QCOMPARE(runQbs(params) == 0, errorMessage.isEmpty()); if (params.expectFailure) QVERIFY2(QString(m_qbsStderr).contains(errorMessage), m_qbsStderr.constData()); } void TestBlackbox::versionCheck_data() { QTest::addColumn("requestedMinVersion"); QTest::addColumn("requestedMaxVersion"); QTest::addColumn("actualVersion"); QTest::addColumn("errorMessage"); QTest::newRow("ok1") << "1.0" << "1.1" << "1.0" << QString(); QTest::newRow("ok2") << "1.0" << "2.0.1" << "2.0" << QString(); QTest::newRow("ok3") << "1.0" << "2.5" << "1.5" << QString(); QTest::newRow("ok3") << "1.0" << "2.0" << "1.99" << QString(); QTest::newRow("bad1") << "2.0" << "2.1" << "1.5" << "needs to be at least"; QTest::newRow("bad2") << "2.0" << "3.0" << "1.5" << "needs to be at least"; QTest::newRow("bad3") << "2.0" << "3.0" << "3.5" << "needs to be lower than"; QTest::newRow("bad4") << "2.0" << "3.0" << "3.0" << "needs to be lower than"; // "bad" because the "higer" module has stronger requirements. QTest::newRow("bad5") << "0.1" << "0.9" << "0.5" << "Impossible version constraint"; } void TestBlackbox::versionScript() { QDir::setCurrent(testDataDir + "/versionscript"); QCOMPARE(runQbs(QbsRunParameters("resolve", {"qbs.installRoot:" + QDir::currentPath()})), 0); const bool isLinuxGcc = m_qbsStdout.contains("is gcc for Linux: true"); const bool isNotLinuxGcc = m_qbsStdout.contains("is gcc for Linux: false"); if (isNotLinuxGcc) QSKIP("version script test only applies to Linux"); QVERIFY(isLinuxGcc); QCOMPARE(runQbs(QbsRunParameters(QStringList("-q"))), 0); const QString output = QString::fromLocal8Bit(m_qbsStderr); const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*---(.*)---.*"), QRegularExpression::DotMatchesEverythingOption); const QRegularExpressionMatch match = pattern.match(output); QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); const QString nmPath = match.captured(1); if (!QFile::exists(nmPath)) QSKIP("Cannot check for symbol presence: No nm found."); QProcess nm; nm.start(nmPath, QStringList(QDir::currentPath() + "/libversionscript.so")); QVERIFY(nm.waitForStarted()); QVERIFY(nm.waitForFinished()); const QByteArray allSymbols = nm.readAllStandardOutput(); QCOMPARE(nm.exitCode(), 0); QVERIFY2(allSymbols.contains("dummyLocal"), allSymbols.constData()); QVERIFY2(allSymbols.contains("dummyGlobal"), allSymbols.constData()); nm.start(nmPath, QStringList() << "-g" << QDir::currentPath() + "/libversionscript.so"); QVERIFY(nm.waitForStarted()); QVERIFY(nm.waitForFinished()); const QByteArray globalSymbols = nm.readAllStandardOutput(); QCOMPARE(nm.exitCode(), 0); QVERIFY2(!globalSymbols.contains("dummyLocal"), allSymbols.constData()); QVERIFY2(globalSymbols.contains("dummyGlobal"), allSymbols.constData()); } void TestBlackbox::wholeArchive() { QDir::setCurrent(testDataDir + "/whole-archive"); QFETCH(QString, wholeArchiveString); QFETCH(bool, ruleInvalidationExpected); QFETCH(bool, dllLinkingExpected); const QbsRunParameters resolveParams("resolve", QStringList("products.dynamiclib.linkWholeArchive:" + wholeArchiveString)); QCOMPARE(runQbs(QbsRunParameters(resolveParams)), 0); const bool linkerSupportsWholeArchive = m_qbsStdout.contains("can link whole archives"); const bool linkerDoesNotSupportWholeArchive = m_qbsStdout.contains("cannot link whole archives"); QVERIFY(linkerSupportsWholeArchive != linkerDoesNotSupportWholeArchive); if (m_qbsStdout.contains("is emscripten: true")) QSKIP("Irrelevant for emscripten"); QVERIFY(m_qbsStdout.contains("is emscripten: false")); QCOMPARE(runQbs(QbsRunParameters(QStringList({ "-vvp", "dynamiclib" }))), 0); const bool wholeArchive = !wholeArchiveString.isEmpty(); const bool outdatedVisualStudio = wholeArchive && linkerDoesNotSupportWholeArchive; const QByteArray invalidationOutput = "Value for property 'staticlib 1:cpp.linkWholeArchive' has changed."; if (!outdatedVisualStudio) QCOMPARE(m_qbsStderr.contains(invalidationOutput), ruleInvalidationExpected); QCOMPARE(m_qbsStdout.contains("linking"), dllLinkingExpected && !outdatedVisualStudio); QbsRunParameters buildParams(QStringList("-p")); buildParams.expectFailure = !wholeArchive || outdatedVisualStudio; buildParams.arguments << "app1"; QCOMPARE(runQbs(QbsRunParameters(buildParams)) == 0, wholeArchive && !outdatedVisualStudio); buildParams.arguments.last() = "app2"; QCOMPARE(runQbs(QbsRunParameters(buildParams)) == 0, wholeArchive && !outdatedVisualStudio); buildParams.arguments.last() = "app4"; QCOMPARE(runQbs(QbsRunParameters(buildParams)) == 0, wholeArchive && !outdatedVisualStudio); buildParams.arguments.last() = "app3"; buildParams.expectFailure = true; QVERIFY(runQbs(QbsRunParameters(buildParams)) != 0); } void TestBlackbox::wholeArchive_data() { QTest::addColumn("wholeArchiveString"); QTest::addColumn("ruleInvalidationExpected"); QTest::addColumn("dllLinkingExpected"); QTest::newRow("link normally") << QString() << false << true; QTest::newRow("link whole archive") << "true" << true << true; QTest::newRow("link whole archive again") << "notfalse" << false << false; } static bool symlinkExists(const QString &linkFilePath) { return QFileInfo(linkFilePath).isSymLink(); } void TestBlackbox::clean() { QDir::setCurrent(testDataDir + "/clean"); // Can't clean without a build graph. QbsRunParameters failParams("clean"); failParams.expectFailure = true; QVERIFY(runQbs(failParams) != 0); // Default behavior: Remove all. QCOMPARE(runQbs(), 0); const QString objectSuffix = parsedObjectSuffix(m_qbsStdout); const QString appObjectFilePath = relativeProductBuildDir("app") + '/' + inputDirHash(".") + "/main.cpp" + objectSuffix; const QString appExeFilePath = relativeExecutableFilePath("app", m_qbsStdout); const QString depObjectFilePath = relativeProductBuildDir("dep") + '/' + inputDirHash(".") + "/dep.cpp" + objectSuffix; const QString depLibBase = relativeProductBuildDir("dep") + '/' + QBS_HOST_DYNAMICLIB_PREFIX + "dep"; const bool isEmscripten = m_qbsStdout.contains("is emscripten: true"); const bool isNotEmscripten = m_qbsStdout.contains("is emscripten: false"); QCOMPARE(isEmscripten, !isNotEmscripten); QString depLibFilePath; QStringList symlinks; if (qbs::Internal::HostOsInfo::isMacosHost()) { depLibFilePath = depLibBase + ".1.1.0" + QBS_HOST_DYNAMICLIB_SUFFIX; symlinks << depLibBase + ".1.1" + QBS_HOST_DYNAMICLIB_SUFFIX << depLibBase + ".1" + QBS_HOST_DYNAMICLIB_SUFFIX << depLibBase + QBS_HOST_DYNAMICLIB_SUFFIX; } else if (qbs::Internal::HostOsInfo::isAnyUnixHost()) { depLibFilePath = depLibBase + QBS_HOST_DYNAMICLIB_SUFFIX + ".1.1.0"; if (!isEmscripten) { symlinks << depLibBase + QBS_HOST_DYNAMICLIB_SUFFIX + ".1.1" << depLibBase + QBS_HOST_DYNAMICLIB_SUFFIX + ".1" << depLibBase + QBS_HOST_DYNAMICLIB_SUFFIX; } } else { depLibFilePath = depLibBase + QBS_HOST_DYNAMICLIB_SUFFIX; } QVERIFY2(regularFileExists(appObjectFilePath), qPrintable(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("clean"))), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(!symlinkExists(symLink), qPrintable(symLink)); // Remove all, with a forced re-resolve in between. // This checks that rescuable artifacts are also removed. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList() << "modules.cpp.optimization:none")), 0); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList() << "modules.cpp.optimization:fast")), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QCOMPARE(runQbs(QbsRunParameters("clean")), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(!symlinkExists(symLink), qPrintable(symLink)); // Dry run. QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("clean"), QStringList("-n"))), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(regularFileExists(depObjectFilePath)); QVERIFY(regularFileExists(depLibFilePath)); for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); // Product-wise, dependency only. QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(regularFileExists(depObjectFilePath)); QVERIFY(regularFileExists(depLibFilePath)); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("clean"), QStringList("-p") << "dep")), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(!QFile(depObjectFilePath).exists()); QVERIFY(!QFile(depLibFilePath).exists()); for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(!symlinkExists(symLink), qPrintable(symLink)); // Product-wise, dependent product only. QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(appObjectFilePath)); QVERIFY(regularFileExists(appExeFilePath)); QVERIFY(regularFileExists(depObjectFilePath)); QVERIFY(regularFileExists(depLibFilePath)); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("clean"), QStringList("-p") << "app")), 0); QVERIFY(!QFile(appObjectFilePath).exists()); QVERIFY(!QFile(appExeFilePath).exists()); QVERIFY(regularFileExists(depObjectFilePath)); QVERIFY(regularFileExists(depLibFilePath)); for (const QString &symLink : std::as_const(symlinks)) QVERIFY2(symlinkExists(symLink), qPrintable(symLink)); } void TestBlackbox::conditionalExport() { QDir::setCurrent(testDataDir + "/conditional-export"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("missing define"), m_qbsStderr.constData()); params.expectFailure = false; params.arguments << "project.enableExport:true"; params.command = "resolve"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); } void TestBlackbox::conditionalFileTagger() { QDir::setCurrent(testDataDir + "/conditional-filetagger"); QbsRunParameters params(QStringList("products.theApp.enableTagger:false")); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling")); params.arguments = QStringList("products.theApp.enableTagger:true"); params.command = "resolve"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling")); } void TestBlackbox::configure() { QDir::setCurrent(testDataDir + "/configure"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("Configured at"), m_qbsStdout.constData()); } void TestBlackbox::conflictingArtifacts() { QDir::setCurrent(testDataDir + "/conflicting-artifacts"); QbsRunParameters params(QStringList() << "-n"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Conflicting artifacts"), m_qbsStderr.constData()); } void TestBlackbox::cxxLanguageVersion() { QDir::setCurrent(testDataDir + "/cxx-language-version"); rmDirR(relativeBuildDir()); QFETCH(QString, version); QFETCH(QVariantMap, requiredFlags); QFETCH(QVariantMap, forbiddenFlags); QbsRunParameters resolveParams; resolveParams.command = "resolve"; resolveParams.arguments << "--force-probe-execution"; resolveParams.arguments << "modules.cpp.useLanguageVersionFallback:true"; if (!version.isEmpty()) resolveParams.arguments << ("modules.cpp.cxxLanguageVersion:" + version); QCOMPARE(runQbs(resolveParams), 0); QString mapKey; if (version == "c++17" && m_qbsStdout.contains("is even newer MSVC: true")) mapKey = "msvc-brandnew"; else if (m_qbsStdout.contains("is newer MSVC: true")) mapKey = "msvc-new"; else if (m_qbsStdout.contains("is older MSVC: true")) mapKey = "msvc_old"; else if (m_qbsStdout.contains("is GCC: true")) mapKey = "gcc"; QVERIFY2(!mapKey.isEmpty(), m_qbsStdout.constData()); QbsRunParameters buildParams; buildParams.expectFailure = mapKey == "gcc" && (version == "c++17" || version == "c++21"); buildParams.arguments = QStringList({"--command-echo-mode", "command-line"}); const int retVal = runQbs(buildParams); if (!buildParams.expectFailure) QCOMPARE(retVal, 0); const QString requiredFlag = requiredFlags.value(mapKey).toString(); if (!requiredFlag.isEmpty()) QVERIFY2(m_qbsStdout.contains(requiredFlag.toLocal8Bit()), m_qbsStdout.constData()); const QString forbiddenFlag = forbiddenFlags.value(mapKey).toString(); if (!forbiddenFlag.isEmpty()) QVERIFY2(!m_qbsStdout.contains(forbiddenFlag.toLocal8Bit()), m_qbsStdout.constData()); } void TestBlackbox::cxxLanguageVersion_data() { QTest::addColumn("version"); QTest::addColumn("requiredFlags"); QTest::addColumn("forbiddenFlags"); QTest::newRow("C++98") << QString("c++98") << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++98"))}) << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:")), std::make_pair(QString("msvc-new"), QString("/std:"))}); QTest::newRow("C++11") << QString("c++11") << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++0x"))}) << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:")), std::make_pair(QString("msvc-new"), QString("/std:"))}); QTest::newRow("C++14") << QString("c++14") << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++1y")), std::make_pair(QString("msvc-new"), QString("/std:c++14")) }) << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:"))}); QTest::newRow("C++17") << QString("c++17") << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++1z")), std::make_pair(QString("msvc-new"), QString("/std:c++latest")), std::make_pair(QString("msvc-brandnew"), QString("/std:c++17")) }) << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:"))}); QTest::newRow("C++21") << QString("c++21") << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++21")), std::make_pair(QString("msvc-new"), QString("/std:c++latest")) }) << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:"))}); QTest::newRow("default") << QString() << QVariantMap() << QVariantMap({std::make_pair(QString("gcc"), QString("-std=")), std::make_pair(QString("msvc-old"), QString("/std:")), std::make_pair(QString("msvc-new"), QString("/std:"))}); } void TestBlackbox::conanfileProbe_data() { QTest::addColumn("forceFailure"); QTest::newRow("success") << false; QTest::newRow("failure") << true; } void TestBlackbox::conanfileProbe() { QFETCH(bool, forceFailure); QString executable = findExecutable({"conan"}); if (executable.isEmpty()) QSKIP("conan is not installed or not available in PATH."); const auto conanVersion = this->conanVersion(executable); if (!conanVersion.isValid()) QSKIP("Can't get conan version."); if (compare(conanVersion, qbs::Version(2, 0)) >= 0) QSKIP("This test does not apply to conan 2.0 and newer."); // We first build a dummy package testlib and use that as dependency // in the testapp package. QDir::setCurrent(testDataDir + "/conanfile-probe/testlib"); QStringList arguments{"create -o opt=True -s os=AIX . testlib/1.2.3@qbs/testing"}; QProcess conan; conan.start(executable, arguments); QVERIFY(waitForProcessSuccess(conan)); QDir::setCurrent(testDataDir + "/conanfile-probe/testapp"); QCOMPARE(runQbs(QbsRunParameters("resolve", {"--force-probe-execution", QStringLiteral("projects.conanfile-probe-project.forceFailure:") + (forceFailure ? "true" : "false")})), forceFailure ? 1 : 0); QFile file(relativeBuildDir() + "/results.json"); QVERIFY(file.open(QIODevice::ReadOnly)); QVariantMap actualResults = QJsonDocument::fromJson(file.readAll()).toVariant().toMap(); const auto generatedFilesPath = actualResults.take("generatedFilesPath").toString(); // We want to make sure that generatedFilesPath is under the project directory, // but we don't care about the actual name. QVERIFY(directoryExists(relativeBuildDir() + "/genconan/" + QFileInfo(generatedFilesPath).baseName())); const QVariantMap expectedResults = { { "json", "TESTLIB_ENV_VAL" }, { "dependencies", QVariantList{"testlib1", "testlib2"} }, }; QCOMPARE(actualResults, expectedResults); } void TestBlackbox::conflictingPropertyValues_data() { QTest::addColumn("overrideInProduct"); QTest::newRow("don't override in product") << false; QTest::newRow("override in product") << true; } void TestBlackbox::conflictingPropertyValues() { QFETCH(bool, overrideInProduct); QDir::setCurrent(testDataDir + "/conflicting-property-values"); if (overrideInProduct) REPLACE_IN_FILE("conflicting-property-values.qbs", "// low.prop: name", "low.prop: name"); else REPLACE_IN_FILE("conflicting-property-values.qbs", "low.prop: name", "// low.prop: name"); WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(QString("resolve")), 0); if (overrideInProduct) { // Binding in product itself overrides everything else, module-level conflicts // are irrelevant. QVERIFY2(m_qbsStdout.contains("final prop value: toplevel"), m_qbsStdout.constData()); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); } else { // Only the conflicts in the highest-level modules are reported, lower-level conflicts // are irrelevant. // prop2 does not cause a conflict, because the values are the same. QVERIFY2(m_qbsStdout.contains("final prop value: highest"), m_qbsStdout.constData()); QVERIFY2(m_qbsStderr.contains("Conflicting scalar values for property 'prop'"), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.count("values.qbs") == 2, m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("values.qbs:20:23"), m_qbsStderr.constData()); QVERIFY2(m_qbsStderr.contains("values.qbs:30:23"), m_qbsStderr.constData()); } } void TestBlackbox::cpuFeatures() { QDir::setCurrent(testDataDir + "/cpu-features"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); const bool isX86 = m_qbsStdout.contains("is x86: true"); const bool isX64 = m_qbsStdout.contains("is x64: true"); if (!isX86 && !isX64) { QVERIFY2(m_qbsStdout.contains("is x86: false") && m_qbsStdout.contains("is x64: false"), m_qbsStdout.constData()); QSKIP("Not an x86 host"); } const bool isGcc = m_qbsStdout.contains("is gcc: true"); const bool isMsvc = m_qbsStdout.contains("is msvc: true"); if (!isGcc && !isMsvc) { QVERIFY2(m_qbsStdout.contains("is gcc: false") && m_qbsStdout.contains("is msvc: false"), m_qbsStdout.constData()); QSKIP("Neither GCC nor MSVC"); } QbsRunParameters params(QStringList{"--command-echo-mode", "command-line"}); params.expectFailure = true; runQbs(params); if (isGcc) { QVERIFY2(m_qbsStdout.contains("-msse2") && m_qbsStdout.contains("-mavx") && m_qbsStdout.contains("-mno-avx512f"), m_qbsStdout.constData()); } else { QVERIFY2(m_qbsStdout.contains("/arch:AVX"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("/arch:AVX2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("/arch:SSE2") == isX86, m_qbsStdout.constData()); } } void TestBlackbox::cxxModules_data() { QTest::addColumn("projectDir"); QTest::newRow("single-module") << "single-mod"; QTest::newRow("dot-in-name") << "dot-in-name"; QTest::newRow("export-import") << "export-import"; QTest::newRow("dependent-modules") << "dep-mods"; QTest::newRow("declaration-implementation") << "decl-impl"; QTest::newRow("library-module") << "lib-mod"; QTest::newRow("partitions") << "partitions"; QTest::newRow("partitions-recursive") << "part-rec"; QTest::newRow("partitions-dependency-on-module") << "part-depmod"; QTest::newRow("partitions-library") << "part-lib"; } void TestBlackbox::cxxModules() { QFETCH(QString, projectDir); QDir::setCurrent(testDataDir + "/cxx-modules/" + projectDir); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(QbsRunParameters{"resolve"}), 0); if (m_qbsStdout.contains("Unsupported toolchainType")) QSKIP("Modules are not supported for this toolchain"); QCOMPARE(runQbs(QbsRunParameters{"build"}), 0); } void TestBlackbox::cxxModulesChangesTracking() { const auto checkContains = [this](const QStringList &files) { for (const auto &file : files) { if (!m_qbsStdout.contains(QByteArrayLiteral("compiling ") + file.toUtf8())) return false; } return true; }; const auto checkNotContains = [this](const QStringList &files) { for (const auto &file : files) { if (m_qbsStdout.contains(QByteArrayLiteral("compiling ") + file.toUtf8())) return false; } return true; }; QDir::setCurrent(testDataDir + "/cxx-modules/dep-mods"); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(QbsRunParameters{"resolve"}), 0); if (m_qbsStdout.contains("Unsupported toolchainType")) QSKIP("Modules are not supported for this toolchain"); QbsRunParameters buildParams{"build"}; QCOMPARE(runQbs(buildParams), 0); QVERIFY2(checkContains({"a.cppm", "b.cppm", "c.cppm", "main.cpp"}), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(checkContains({"main.cpp"}), m_qbsStdout.constData()); QVERIFY2(checkNotContains({"a.cppm", "b.cppm", "c.cppm"}), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("c.cppm"); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(checkContains({"c.cppm", "main.cpp"}), m_qbsStdout.constData()); QVERIFY2(checkNotContains({"a.cppm", "b.cppm"}), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("b.cppm"); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(checkContains({"b.cppm", "c.cppm", "main.cpp"}), m_qbsStdout.constData()); QVERIFY2(checkNotContains({"a.cppm"}), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("a.cppm"); QCOMPARE(runQbs(buildParams), 0); QVERIFY2(checkContains({"a.cppm", "b.cppm", "c.cppm", "main.cpp"}), m_qbsStdout.constData()); } void TestBlackbox::dateProperty() { QDir::setCurrent(testDataDir + "/date-property"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("The stored date was 1999-12-31"), m_qbsStdout.constData()); } void TestBlackbox::renameDependency() { QDir::setCurrent(testDataDir + "/renameDependency"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/renameDependency/work"); QCOMPARE(runQbs(), 0); WAIT_FOR_NEW_TIMESTAMP(); QFile::remove("lib.h"); QFile::remove("lib.cpp"); ccp("../after", "."); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); } void TestBlackbox::separateDebugInfo() { QDir::setCurrent(testDataDir + "/separate-debug-info"); QCOMPARE(runQbs(QbsRunParameters(QStringList("qbs.debugInformation:true"))), 0); const bool isWindows = m_qbsStdout.contains("is windows: yes"); const bool isNotWindows = m_qbsStdout.contains("is windows: no"); QVERIFY(isWindows != isNotWindows); const bool isMacos = m_qbsStdout.contains("is macos: yes"); const bool isNotMacos = m_qbsStdout.contains("is macos: no"); QVERIFY(isMacos != isNotMacos); const bool isDarwin = m_qbsStdout.contains("is darwin: yes"); const bool isNotDarwin = m_qbsStdout.contains("is darwin: no"); QVERIFY(isDarwin != isNotDarwin); const bool isGcc = m_qbsStdout.contains("is gcc: yes"); const bool isNotGcc = m_qbsStdout.contains("is gcc: no"); QVERIFY(isGcc != isNotGcc); const bool isMsvc = m_qbsStdout.contains("is msvc: yes"); const bool isNotMsvc = m_qbsStdout.contains("is msvc: no"); QVERIFY(isMsvc != isNotMsvc); const bool isEmscripten = m_qbsStdout.contains("is emscripten: yes"); const bool isNotEmscripten = m_qbsStdout.contains("is emscripten: no"); QVERIFY(isEmscripten != isNotEmscripten); if (isDarwin) { 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("app3") + "/app3.app.dSYM")); if (isMacos) { QVERIFY(regularFileExists(relativeProductBuildDir("app3") + "/app3.app/Contents/MacOS/app3.dwarf")); } else { QVERIFY(regularFileExists(relativeProductBuildDir("app3") + "/app3.app/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("foo3") + "/foo3.framework.dSYM")); if (isMacos) { QVERIFY(regularFileExists(relativeProductBuildDir("foo3") + "/foo3.framework/Versions/A/foo3.dwarf")); } else { QVERIFY(regularFileExists(relativeProductBuildDir("foo3") + "/foo3.framework/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")); if (isMacos) { QVERIFY(regularFileExists(relativeProductBuildDir("bar3") + "/bar3.bundle/Contents/MacOS/bar3.dwarf")); } else { QVERIFY(regularFileExists(relativeProductBuildDir("bar3") + "/bar3.bundle/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 (isGcc && isNotEmscripten) { const QString exeSuffix = isWindows ? ".exe" : ""; const QString dllPrefix = isWindows ? "" : "lib"; const QString dllSuffix = isWindows ? ".dll" : ".so"; QVERIFY(QFile::exists(relativeProductBuildDir("app1") + "/app1" + exeSuffix + ".debug")); QVERIFY(!QFile::exists(relativeProductBuildDir("app2") + "/app2" + exeSuffix + ".debug")); QVERIFY(QFile::exists(relativeProductBuildDir("foo1") + '/' + dllPrefix + "foo1" + dllSuffix + ".debug")); QVERIFY(!QFile::exists(relativeProductBuildDir("foo2") + '/' + "foo2" + dllSuffix + ".debug")); QVERIFY(QFile::exists(relativeProductBuildDir("bar1") + '/' + dllPrefix + "bar1" + dllSuffix + ".debug")); QVERIFY(!QFile::exists(relativeProductBuildDir("bar2") + '/' + dllPrefix + "bar2" + dllSuffix + ".debug")); } else if (isEmscripten) { QVERIFY(QFile::exists(relativeProductBuildDir("app1") + "/app1.wasm.debug.wasm")); QVERIFY(!QFile::exists(relativeProductBuildDir("app2") + "/app2.wasm.debug.wasm")); } else if (isMsvc) { QVERIFY(QFile::exists(relativeProductBuildDir("app1") + "/app1.pdb")); QVERIFY(QFile::exists(relativeProductBuildDir("foo1") + "/foo1.pdb")); QVERIFY(QFile::exists(relativeProductBuildDir("bar1") + "/bar1.pdb")); // MSVC's linker even creates a pdb file if /Z7 is passed to the compiler. } else { QSKIP("Unsupported toolchain. Skipping."); } } void TestBlackbox::trackAddFile() { QList output; QDir::setCurrent(testDataDir + "/trackAddFile"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/trackAddFile/work"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QString objectSuffix = parsedObjectSuffix(m_qbsStdout); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!"); QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!"); QString unchangedObjectFile = relativeBuildDir() + "/someapp/narf.cpp" + objectSuffix; QDateTime unchangedObjectFileTime1 = QFileInfo(unchangedObjectFile).lastModified(); WAIT_FOR_NEW_TIMESTAMP(); ccp("../after", "."); touch("trackAddFile.qbs"); touch("main.cpp"); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!"); QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!"); QCOMPARE(output.takeFirst().trimmed().constData(), "ZORT!"); // the object file of the untouched source should not have changed QDateTime unchangedObjectFileTime2 = QFileInfo(unchangedObjectFile).lastModified(); QCOMPARE(unchangedObjectFileTime1, unchangedObjectFileTime2); } void TestBlackbox::trackExternalProductChanges() { QDir::setCurrent(testDataDir + "/trackExternalProductChanges"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); const bool isGcc = m_qbsStdout.contains("is gcc: true"); const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); QbsRunParameters params; params.environment.insert("QBS_TEST_PULL_IN_FILE_VIA_ENV", "1"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); params.command = "resolve"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling main.cpp")); QVERIFY(m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY2(!m_qbsStdout.contains("compiling jsFileChange.cpp"), m_qbsStdout.constData()); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("fileList.js", "return []", "return ['jsFileChange.cpp']"); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY(m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); rmDirR(relativeBuildDir()); REPLACE_IN_FILE("fileList.js", "['jsFileChange.cpp']", "[]"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp")); QFile cppFile("fileExists.cpp"); QVERIFY(cppFile.open(QIODevice::WriteOnly)); cppFile.write("void fileExists() { }\n"); cppFile.close(); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp")); QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp")); QVERIFY(m_qbsStdout.contains("compiling fileExists.cpp")); if (isNotGcc) QSKIP("The remainder of this test requires a GCC-like toolchain"); QVERIFY(isGcc); rmDirR(relativeBuildDir()); params.environment = QbsRunParameters::defaultEnvironment(); params.environment.insert("INCLUDE_PATH_TEST", "1"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("hiddenheaderqbs.h"), m_qbsStderr.constData()); params.command = "resolve"; params.environment.insert("CPLUS_INCLUDE_PATH", QDir::toNativeSeparators(QDir::currentPath() + "/hidden")); params.expectFailure = false; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); } void TestBlackbox::trackGroupConditionChange() { QbsRunParameters params; params.expectFailure = true; QDir::setCurrent(testDataDir + "/group-condition-change"); QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains("jibbetnich")); params.command = "resolve"; params.arguments = QStringList("project.kaputt:false"); params.expectFailure = false; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); } void TestBlackbox::trackRemoveFile() { QDir::setCurrent(testDataDir + "/trackAddFile"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); ccp("after", "work"); QDir::setCurrent(testDataDir + "/trackAddFile/work"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); const QString objectSuffix = parsedObjectSuffix(m_qbsStdout); QList output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!"); QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!"); QCOMPARE(output.takeFirst().trimmed().constData(), "ZORT!"); QString unchangedObjectFile = relativeBuildDir() + "/someapp/narf.cpp" + objectSuffix; QDateTime unchangedObjectFileTime1 = QFileInfo(unchangedObjectFile).lastModified(); WAIT_FOR_NEW_TIMESTAMP(); QFile::remove("trackAddFile.qbs"); QFile::remove("main.cpp"); QFile::copy("../before/trackAddFile.qbs", "trackAddFile.qbs"); QFile::copy("../before/main.cpp", "main.cpp"); QVERIFY(QFile::remove("zort.h")); QVERIFY(QFile::remove("zort.cpp")); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("resolve"))), 0); touch("main.cpp"); touch("trackAddFile.qbs"); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "Hello World!"); QCOMPARE(output.takeFirst().trimmed().constData(), "NARF!"); // the object file of the untouched source should not have changed QDateTime unchangedObjectFileTime2 = QFileInfo(unchangedObjectFile).lastModified(); QCOMPARE(unchangedObjectFileTime1, unchangedObjectFileTime2); // the object file for the removed cpp file should have vanished too QVERIFY(!regularFileExists(relativeBuildDir() + "/someapp/zort.cpp" + objectSuffix)); } void TestBlackbox::trackAddFileTag() { QList output; QDir::setCurrent(testDataDir + "/trackFileTags"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/trackFileTags/work"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "there's no foo here"); WAIT_FOR_NEW_TIMESTAMP(); ccp("../after", "."); touch("main.cpp"); touch("trackFileTags.qbs"); waitForFileUnlock(); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "there's 15 foo here"); } void TestBlackbox::trackRemoveFileTag() { QDir::setCurrent(testDataDir + "/trackFileTags"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("after", "work"); QDir::setCurrent(testDataDir + "/trackFileTags/work"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QString objectSuffix = parsedObjectSuffix(m_qbsStdout); const QbsRunParameters runParams("run", QStringList{"-qp", "someapp"}); QCOMPARE(runQbs(runParams), 0); // check if the artifacts are here that will become stale in the 2nd step QVERIFY(regularFileExists( relativeProductBuildDir("someapp") + '/' + inputDirHash(".") + "/main_foo.cpp" + objectSuffix)); QVERIFY(regularFileExists(relativeProductBuildDir("someapp") + "/main_foo.cpp")); QVERIFY(regularFileExists(relativeProductBuildDir("someapp") + "/main.foo")); QList output = m_qbsStdout.split('\n'); QCOMPARE(output.takeFirst().trimmed().constData(), "there's 15 foo here"); WAIT_FOR_NEW_TIMESTAMP(); ccp("../before", "."); touch("main.cpp"); touch("trackFileTags.qbs"); QCOMPARE(runQbs(runParams), 0); output = m_qbsStdout.split('\n'); QVERIFY(!output.isEmpty()); QCOMPARE(output.takeFirst().trimmed().constData(), "there's no foo here"); // check if stale artifacts have been removed QCOMPARE( regularFileExists( relativeProductBuildDir("someapp") + '/' + inputDirHash(".") + "/main_foo.cpp" + objectSuffix), false); QCOMPARE(regularFileExists(relativeProductBuildDir("someapp") + "/main_foo.cpp"), false); QCOMPARE(regularFileExists(relativeProductBuildDir("someapp") + "/main.foo"), false); } void TestBlackbox::trackAddProduct() { QDir::setCurrent(testDataDir + "/trackProducts"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDataDir + "/trackProducts/work"); QbsRunParameters params(QStringList() << "-f" << "trackProducts.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling foo.cpp")); QVERIFY(m_qbsStdout.contains("compiling bar.cpp")); QVERIFY(m_qbsStdout.contains("linking product1")); QVERIFY(m_qbsStdout.contains("linking product2")); WAIT_FOR_NEW_TIMESTAMP(); ccp("../after", "."); touch("trackProducts.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling zoo.cpp")); QVERIFY(m_qbsStdout.contains("linking product3")); QVERIFY(!m_qbsStdout.contains("compiling foo.cpp")); QVERIFY(!m_qbsStdout.contains("compiling bar.cpp")); QVERIFY(!m_qbsStdout.contains("linking product1")); QVERIFY(!m_qbsStdout.contains("linking product2")); } void TestBlackbox::trackRemoveProduct() { QDir::setCurrent(testDataDir + "/trackProducts"); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); ccp("after", "work"); QDir::setCurrent(testDataDir + "/trackProducts/work"); QbsRunParameters params(QStringList() << "-f" << "trackProducts.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling foo.cpp")); QVERIFY(m_qbsStdout.contains("compiling bar.cpp")); QVERIFY(m_qbsStdout.contains("compiling zoo.cpp")); QVERIFY(m_qbsStdout.contains("linking product1")); QVERIFY(m_qbsStdout.contains("linking product2")); QVERIFY(m_qbsStdout.contains("linking product3")); WAIT_FOR_NEW_TIMESTAMP(); QFile::remove("zoo.cpp"); QFile::remove("product3.qbs"); copyFileAndUpdateTimestamp("../before/trackProducts.qbs", "trackProducts.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling foo.cpp")); QVERIFY(!m_qbsStdout.contains("compiling bar.cpp")); QVERIFY(!m_qbsStdout.contains("compiling zoo.cpp")); QVERIFY(!m_qbsStdout.contains("linking product1")); QVERIFY(!m_qbsStdout.contains("linking product2")); QVERIFY(!m_qbsStdout.contains("linking product3")); } void TestBlackbox::wildcardRenaming() { QDir::setCurrent(testDataDir + "/wildcard_renaming"); QCOMPARE(runQbs(QbsRunParameters("install")), 0); QVERIFY(QFileInfo(defaultInstallRoot + "/pioniere.txt").exists()); WAIT_FOR_NEW_TIMESTAMP(); QFile::rename(QDir::currentPath() + "/pioniere.txt", QDir::currentPath() + "/fdj.txt"); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("install"), QStringList("--clean-install-root"))), 0); QVERIFY(!QFileInfo(defaultInstallRoot + "/pioniere.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/fdj.txt").exists()); } void TestBlackbox::recursiveRenaming() { QDir::setCurrent(testDataDir + "/recursive_renaming"); QCOMPARE(runQbs(QbsRunParameters("install")), 0); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/wasser.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/subdir/blubb.txt").exists()); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(QFile::rename(QDir::currentPath() + "/dir/wasser.txt", QDir::currentPath() + "/dir/wein.txt")); QCOMPARE(runQbs(QbsRunParameters(QStringLiteral("install"), QStringList("--clean-install-root"))), 0); QVERIFY(!QFileInfo(defaultInstallRoot + "/dir/wasser.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/wein.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/subdir/blubb.txt").exists()); } void TestBlackbox::recursiveWildcards() { QDir::setCurrent(testDataDir + "/recursive_wildcards"); QCOMPARE(runQbs(QbsRunParameters("install")), 0); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/file1.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/file2.txt").exists()); QFile outputFile(defaultInstallRoot + "/output.txt"); QVERIFY2(outputFile.open(QIODevice::ReadOnly), qPrintable(outputFile.errorString())); QCOMPARE(outputFile.readAll(), QByteArray("file1.txtfile2.txt")); outputFile.close(); WAIT_FOR_NEW_TIMESTAMP(); QFile newFile("dir/subdir/file3.txt"); QVERIFY2(newFile.open(QIODevice::WriteOnly), qPrintable(newFile.errorString())); newFile.close(); QCOMPARE(runQbs(QbsRunParameters("install")), 0); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/file3.txt").exists()); QVERIFY2(outputFile.open(QIODevice::ReadOnly), qPrintable(outputFile.errorString())); QCOMPARE(outputFile.readAll(), QByteArray("file1.txtfile2.txtfile3.txt")); outputFile.close(); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY2(newFile.remove(), qPrintable(newFile.errorString())); QVERIFY2(!newFile.exists(), qPrintable(newFile.fileName())); QCOMPARE(runQbs(QbsRunParameters("install", QStringList{ "--clean-install-root"})), 0); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/file1.txt").exists()); QVERIFY(QFileInfo(defaultInstallRoot + "/dir/file2.txt").exists()); QVERIFY(!QFileInfo(defaultInstallRoot + "/dir/file3.txt").exists()); QVERIFY2(outputFile.open(QIODevice::ReadOnly), qPrintable(outputFile.errorString())); QCOMPARE(outputFile.readAll(), QByteArray("file1.txtfile2.txt")); } void TestBlackbox::referenceErrorInExport() { QDir::setCurrent(testDataDir + "/referenceErrorInExport"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("referenceErrorInExport.qbs:5:27 'includePaths' is not defined"), m_qbsStderr.constData()); } void TestBlackbox::removeDuplicateLibraries_data() { QTest::addColumn("removeDuplicates"); QTest::newRow("remove duplicates") << true; QTest::newRow("don't remove duplicates") << false; } void TestBlackbox::removeDuplicateLibraries() { QDir::setCurrent(testDataDir + "/remove-duplicate-libs"); QFETCH(bool, removeDuplicates); const QbsRunParameters resolveParams("resolve", {"-f", "remove-duplicate-libs.qbs", "project.removeDuplicates:" + QString(removeDuplicates? "true" : "false")}); QCOMPARE(runQbs(resolveParams), 0); const bool isBfd = m_qbsStdout.contains("is bfd linker: true"); const bool isNotBfd = m_qbsStdout.contains("is bfd linker: false"); QVERIFY2(isBfd != isNotBfd, m_qbsStdout.constData()); QbsRunParameters buildParams("build"); buildParams.expectFailure = removeDuplicates && isBfd; QCOMPARE(runQbs(buildParams) == 0, !buildParams.expectFailure); } void TestBlackbox::reproducibleBuild() { QFETCH(bool, reproducible); QDir::setCurrent(testDataDir + "/reproducible-build"); QbsRunParameters params("resolve"); params.arguments << QString("modules.cpp.enableReproducibleBuilds:") + (reproducible ? "true" : "false"); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); const bool isGcc = m_qbsStdout.contains("is gcc: true"); const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); const QString objectSuffix = parsedObjectSuffix(m_qbsStdout); if (isNotGcc) QSKIP("reproducible builds only supported for gcc"); QVERIFY(isGcc); QCOMPARE(runQbs(), 0); QFile object( relativeProductBuildDir("the product") + '/' + inputDirHash(".") + '/' + "file1.cpp" + objectSuffix); QVERIFY2(object.open(QIODevice::ReadOnly), qPrintable(object.fileName())); const QByteArray oldContents = object.readAll(); object.close(); QCOMPARE(runQbs(QbsRunParameters("clean")), 0); QVERIFY(!object.exists()); params.command = "build"; QCOMPARE(runQbs(params), 0); if (reproducible) { QVERIFY(object.open(QIODevice::ReadOnly)); const QByteArray newContents = object.readAll(); QVERIFY(oldContents == newContents); object.close(); } QCOMPARE(runQbs(QbsRunParameters("clean")), 0); } void TestBlackbox::reproducibleBuild_data() { QTest::addColumn("reproducible"); QTest::newRow("non-reproducible build") << false; QTest::newRow("reproducible build") << true; } void TestBlackbox::responseFiles() { QDir::setCurrent(testDataDir + "/response-files"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "install"; params.arguments << "--install-root" << "installed"; QCOMPARE(runQbs(params), 0); QFile file("installed/response-file-content.txt"); QVERIFY(file.open(QIODevice::ReadOnly)); const QList expected = QList() << "foo" << qbs::Internal::shellQuote(QStringLiteral("with space")).toUtf8() << "bar" << ""; QList lines = file.readAll().split('\n'); for (auto &line : lines) line = line.trimmed(); QCOMPARE(lines, expected); } void TestBlackbox::retaggedOutputArtifact() { QDir::setCurrent(testDataDir + "/retagged-output-artifact"); QbsRunParameters resolveParams("resolve"); resolveParams.arguments = QStringList("products.p.useTag1:true"); QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(), 0); const QString a2 = relativeProductBuildDir("p") + "/a2.txt"; const QString a3 = relativeProductBuildDir("p") + "/a3.txt"; QVERIFY2(QFile::exists(a2), qPrintable(a2)); QVERIFY2(!QFile::exists(a3), qPrintable(a3)); resolveParams.arguments = QStringList("products.p.useTag1:false"); QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!QFile::exists(a2), qPrintable(a2)); QVERIFY2(QFile::exists(a3), qPrintable(a3)); resolveParams.arguments = QStringList("products.p.useTag1:true"); QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(), 0); QVERIFY2(QFile::exists(a2), qPrintable(a2)); QVERIFY2(!QFile::exists(a3), qPrintable(a3)); } void TestBlackbox::rpathlinkDeduplication() { QDir::setCurrent(testDataDir + "/rpathlink-deduplication"); QbsRunParameters resolveParams{"resolve"}; QCOMPARE(runQbs(resolveParams), 0); const bool useRPathLink = m_qbsStdout.contains("useRPathLink: true"); const bool dontUseRPathLink = m_qbsStdout.contains("useRPathLink: false"); QVERIFY2(useRPathLink || dontUseRPathLink, m_qbsStdout); if (dontUseRPathLink) QSKIP("Only applies to toolchains that support rPathLink"); const QString output = QString::fromLocal8Bit(m_qbsStdout); const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*===(.*)===.*"), QRegularExpression::DotMatchesEverythingOption); const QRegularExpressionMatch match = pattern.match(output); QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); const QString linkFlag = match.captured(1); QbsRunParameters buildParams; buildParams.arguments = QStringList({"--command-echo-mode", "command-line"}); QCOMPARE(runQbs(buildParams), 0); // private DynamicLibraryA is a dependency for 2 other libs but should only appear once const auto libDir = QFileInfo(relativeProductBuildDir("DynamicLibraryA")).absoluteFilePath(); QCOMPARE(m_qbsStdout.count((linkFlag + libDir).toUtf8()), 1); } void TestBlackbox::ruleConditions_data() { QTest::addColumn("enableGroup"); QTest::addColumn("enableRule"); QTest::addColumn("enableTagger"); QTest::addColumn("fileShouldExist"); QTest::newRow("all off") << false << false << false << false; QTest::newRow("group off, rule off, tagger on") << false << false << true << false; QTest::newRow("group off, rule on, tagger off") << false << true << false << false; QTest::newRow("group off, rule on, tagger on") << false << true << true << false; QTest::newRow("group on, rule off, tagger off") << true << false << false << false; QTest::newRow("group on, rule off, tagger on") << true << false << true << false; QTest::newRow("group on, rule on, tagger off") << true << true << false << false; QTest::newRow("all on") << true << true << true << true; } void TestBlackbox::ruleConditions() { QFETCH(bool, enableGroup); QFETCH(bool, enableRule); QFETCH(bool, enableTagger); QFETCH(bool, fileShouldExist); QDir::setCurrent(testDataDir + "/ruleConditions"); rmDirR(relativeBuildDir()); static const auto b2s = [](bool b) { return QString(b ? "true" : "false"); }; const QStringList args{ "modules.narfzort.enableGroup:" + b2s(enableGroup), "modules.narfzort.enableRule:" + b2s(enableRule), "modules.narfzort.enableTagger:" + b2s(enableTagger)}; QCOMPARE(runQbs(args), 0); QVERIFY(QFileInfo(relativeExecutableFilePath("ruleConditions", m_qbsStdout)).exists()); QCOMPARE( QFileInfo(relativeProductBuildDir("ruleConditions") + "/ruleConditions.foo.narf.zort") .exists(), fileShouldExist); } void TestBlackbox::ruleConnectionWithExcludedInputs() { QDir::setCurrent(testDataDir + "/rule-connection-with-excluded-inputs"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("inputs.x: 2") && m_qbsStdout.contains("inputs.y: 0"), m_qbsStdout.constData()); } void TestBlackbox::ruleCycle() { QDir::setCurrent(testDataDir + "/ruleCycle"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains("Cycle detected in rule dependencies")); } void TestBlackbox::ruleWithNoInputs() { QDir::setCurrent(testDataDir + "/rule-with-no-inputs"); QVERIFY2(runQbs() == 0, m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("running the rule"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("creating output"), m_qbsStdout.constData()); QVERIFY2(runQbs() == 0, m_qbsStderr.constData()); QVERIFY2(!m_qbsStdout.contains("running the rule"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating output"), m_qbsStdout.constData()); QbsRunParameters params("resolve", QStringList() << "products.theProduct.version:1"); QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData()); params.command = "build"; QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData()); QVERIFY2(!m_qbsStdout.contains("running the rule"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating output"), m_qbsStdout.constData()); params.command = "resolve"; params.arguments = QStringList() << "products.theProduct.version:2"; QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData()); params.command = "build"; QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData()); QVERIFY2(!m_qbsStdout.contains("running the rule"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("creating output"), m_qbsStdout.constData()); params.command = "resolve"; params.arguments = QStringList() << "products.theProduct.version:2" << "products.theProduct.dummy:true"; QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData()); params.command = "build"; QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("running the rule"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating output"), m_qbsStdout.constData()); } void TestBlackbox::ruleWithNonRequiredInputs() { QDir::setCurrent(testDataDir + "/rule-with-non-required-inputs"); QbsRunParameters params("build", {"products.p.enableTagger:false"}); QCOMPARE(runQbs(params), 0); QFile outFile(relativeProductBuildDir("p") + "/output.txt"); QVERIFY2(outFile.open(QIODevice::ReadOnly), qPrintable(outFile.errorString())); QByteArray output = outFile.readAll(); QCOMPARE(output, QByteArray("()")); outFile.close(); params.command = "resolve"; params.arguments = QStringList({"products.p.enableTagger:true"}); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(outFile.open(QIODevice::ReadOnly), qPrintable(outFile.errorString())); output = outFile.readAll(); QCOMPARE(output, QByteArray("(a.inp,b.inp,c.inp,)")); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("generating"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("a.inp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating"), m_qbsStdout.constData()); } void TestBlackbox::runMultiplexed() { QDir::setCurrent(testDataDir + "/run-multiplexed"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params("run"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); params.arguments = QStringList{"-p", "app"}; QVERIFY(runQbs(params) != 0); params.expectFailure = false; params.arguments.last() = "app {\"buildVariant\":\"debug\"}"; QCOMPARE(runQbs(params), 0); params.arguments.last() = "app {\"buildVariant\":\"release\"}"; QCOMPARE(runQbs(params), 0); } void TestBlackbox::sanitizer_data() { QTest::addColumn("sanitizer"); QTest::newRow("none") << QString(); QTest::newRow("address") << QStringLiteral("address"); QTest::newRow("undefined") << QStringLiteral("undefined"); QTest::newRow("thread") << QStringLiteral("thread"); } void TestBlackbox::sanitizer() { QFETCH(QString, sanitizer); QDir::setCurrent(testDataDir + "/sanitizer"); rmDirR(relativeBuildDir()); QbsRunParameters params("build", {"--command-echo-mode", "command-line"}); if (!sanitizer.isEmpty()) { params.arguments.append( {QStringLiteral("products.sanitizer.sanitizer:\"") + sanitizer + "\""}); } QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains(QByteArrayLiteral("Compiler does not support sanitizer"))) QSKIP("Compiler does not support the specified sanitizer"); if (!sanitizer.isEmpty()) { QVERIFY2(m_qbsStdout.contains(QByteArrayLiteral("fsanitize=") + sanitizer.toLatin1()), qPrintable(m_qbsStdout)); } else { QVERIFY2(!m_qbsStdout.contains(QByteArrayLiteral("fsanitize=")), qPrintable(m_qbsStdout)); } } void TestBlackbox::scannerItem_data() { QTest::addColumn("inProduct"); QTest::addColumn("inModule"); QTest::addColumn("enableGroup"); QTest::addColumn("successExpected"); QTest::newRow("all off") << false << false << false << false; QTest::newRow("product scanner") << true << false << false << true; QTest::newRow("module scanner, group off") << false << true << false << false; QTest::newRow("module scanner, group on") << false << true << true << true; } void TestBlackbox::scannerItem() { QFETCH(bool, inProduct); QFETCH(bool, inModule); QFETCH(bool, enableGroup); QFETCH(bool, successExpected); static const auto b2s = [](bool b) { return QString(b ? "true" : "false"); }; QDir::setCurrent(testDataDir + "/scanner-item"); rmDirR(relativeBuildDir()); const QbsRunParameters params( {"-f", "scanner-item.qbs", "products.scanner-item.productScanner:" + b2s(inProduct), "products.scanner-item.moduleScanner:" + b2s(inModule), "products.scanner-item.enableGroup:" + b2s(enableGroup)}); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("handling file1.in"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("handling file2.in"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("subdir1/file.inc"); QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStdout.contains("handling file1.in"), successExpected); QVERIFY2(!m_qbsStdout.contains("handling file2.in"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("subdir2/file.inc"); QCOMPARE(runQbs(params), 0); QVERIFY2(!m_qbsStdout.contains("handling file1.in"), m_qbsStdout.constData()); QCOMPARE(m_qbsStdout.contains("handling file2.in"), successExpected); } void TestBlackbox::scanResultInOtherProduct() { QDir::setCurrent(testDataDir + "/scan-result-in-other-product"); QCOMPARE(runQbs(QStringList("-vv")), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStderr.contains("The file dependency might get lost during change tracking"), m_qbsStderr.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("other/other.qbs", "blubb", "blubb2"); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("lib/lib.h"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); } void TestBlackbox::scanResultInNonDependency() { QDir::setCurrent(testDataDir + "/scan-result-in-non-dependency"); QCOMPARE(runQbs(QStringList("-vv")), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); QVERIFY2(m_qbsStderr.contains("The file dependency might get lost during change tracking"), m_qbsStderr.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("other/other.qbs", "blubb", "blubb2"); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("lib/lib.h"); QCOMPARE(runQbs(), 0); QEXPECT_FAIL("", "QBS-1532", Continue); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("generating text file"), m_qbsStdout.constData()); } void TestBlackbox::setupBuildEnvironment() { QDir::setCurrent(testDataDir + "/setup-build-environment"); QCOMPARE(runQbs(), 0); QFile f(relativeProductBuildDir("first_product") + QLatin1String("/m.output")); QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(f.errorString())); QCOMPARE(f.readAll().trimmed(), QByteArray("1")); f.close(); f.setFileName(relativeProductBuildDir("second_product") + QLatin1String("/m.output")); QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(f.errorString())); QCOMPARE(f.readAll().trimmed(), QByteArray()); } void TestBlackbox::setupRunEnvironment() { QDir::setCurrent(testDataDir + "/setup-run-environment"); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QString appFilePath = QDir::currentPath() + "/dryrun/" + relativeExecutableFilePath("app", m_qbsStdout); QbsRunParameters failParams("run", QStringList({"--setup-run-env-config", "ignore-lib-dependencies"})); failParams.expectFailure = true; failParams.expectCrash = m_qbsStdout.contains("is windows"); QVERIFY(runQbs(QbsRunParameters(failParams)) != 0); QVERIFY2(failParams.expectCrash || m_qbsStderr.contains("lib"), m_qbsStderr.constData()); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QbsRunParameters dryRunParams("run", QStringList("--dry-run")); dryRunParams.buildDirectory = "dryrun"; QCOMPARE(runQbs(dryRunParams), 0); QVERIFY2(m_qbsStdout.contains("Would start target") && m_qbsStdout.contains(QDir::toNativeSeparators(appFilePath).toLocal8Bit()), m_qbsStdout.constData()); } void TestBlackbox::staticLibDeps() { QFETCH(bool, withExport); QFETCH(bool, importPrivateLibraries); QFETCH(bool, successExpected); QDir::setCurrent(testDataDir + "/static-lib-deps"); rmDirR(relativeBuildDir()); QStringList args{ QStringLiteral("project.useExport:%1").arg(withExport ? "true" : "false"), QStringLiteral("modules.cpp.importPrivateLibraries:%1") .arg(importPrivateLibraries ? "true" : "false")}; QbsRunParameters params(args); params.expectFailure = !successExpected; QCOMPARE(runQbs(params) == 0, successExpected); } void TestBlackbox::staticLibDeps_data() { QTest::addColumn("withExport"); QTest::addColumn("importPrivateLibraries"); QTest::addColumn("successExpected"); QTest::newRow("no Export, with import") << false << true << true; QTest::newRow("no Export, no import") << false << false << false; QTest::newRow("with Export, with import") << true << true << true; QTest::newRow("with Export, no import") << true << false << true; } void TestBlackbox::smartRelinking() { QDir::setCurrent(testDataDir + "/smart-relinking"); rmDirR(relativeBuildDir()); QFETCH(bool, strictChecking); QbsRunParameters params(QStringList() << (QString("modules.cpp.exportedSymbolsCheckMode:%1") .arg(strictChecking ? "strict" : "ignore-undefined"))); QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("project disabled")) QSKIP("Test does not apply on this target"); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Irrelevant change. WAIT_FOR_NEW_TIMESTAMP(); touch("lib.cpp"); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Add new private symbol. WAIT_FOR_NEW_TIMESTAMP(); params.command = "resolve"; params.arguments << "products.lib.defines:PRIV2"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Remove private symbol. WAIT_FOR_NEW_TIMESTAMP(); params.arguments.removeLast(); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Add new public symbol. WAIT_FOR_NEW_TIMESTAMP(); params.arguments << "products.lib.defines:PUB2"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Remove public symbol. WAIT_FOR_NEW_TIMESTAMP(); params.arguments.removeLast(); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Add new undefined symbol. WAIT_FOR_NEW_TIMESTAMP(); params.arguments << "products.lib.defines:PRINTF"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(strictChecking == m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); // Remove undefined symbol. WAIT_FOR_NEW_TIMESTAMP(); params.arguments.removeLast(); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData()); QVERIFY2(strictChecking == m_qbsStdout.contains("linking app"), m_qbsStdout.constData()); } void TestBlackbox::smartRelinking_data() { QTest::addColumn("strictChecking"); QTest::newRow("strict checking") << true; QTest::newRow("ignore undefined") << false; } static QString soName(const QString &readElfPath, const QString &libFilePath) { QProcess readElf; auto env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("LC_ALL"), QStringLiteral("C")); // force readelf to use US encoding readElf.setProcessEnvironment(env); readElf.start(readElfPath, QStringList() << "-a" << libFilePath); if (!readElf.waitForStarted() || !readElf.waitForFinished() || readElf.exitCode() != 0) { qDebug() << readElf.errorString() << readElf.readAllStandardError(); return {}; } const QByteArray output = readElf.readAllStandardOutput(); const QByteArray magicString = "Library soname: ["; const int magicStringIndex = output.indexOf(magicString); if (magicStringIndex == -1) return {}; const int endIndex = output.indexOf(']', magicStringIndex); if (endIndex == -1) return {}; const int nameIndex = magicStringIndex + magicString.size(); const QByteArray theName = output.mid(nameIndex, endIndex - nameIndex); return QString::fromLatin1(theName); } void TestBlackbox::soVersion() { const QString readElfPath = findExecutable(QStringList("readelf")); if (readElfPath.isEmpty() || readElfPath.endsWith("exe")) QSKIP("soversion test not applicable on this system"); QDir::setCurrent(testDataDir + "/soversion"); QFETCH(QString, soVersion); QFETCH(bool, useVersion); QFETCH(QString, expectedSoName); QbsRunParameters params; params.arguments << ("products.mylib.useVersion:" + QString((useVersion ? "true" : "false"))); if (!soVersion.isNull()) params.arguments << ("modules.cpp.soVersion:" + soVersion); const QString libFilePath = relativeProductBuildDir("mylib") + "/libmylib.so" + (useVersion ? ".1.2.3" : QString()); rmDirR(relativeBuildDir()); const bool success = runQbs(params) == 0; QVERIFY(success); QVERIFY2(regularFileExists(libFilePath), qPrintable(libFilePath)); if (m_qbsStdout.contains("is emscripten: true")) QEXPECT_FAIL(nullptr, "Emscripten does not produce dynamic libraries of elf format", Abort); QCOMPARE(soName(readElfPath, libFilePath), expectedSoName); } void TestBlackbox::soVersion_data() { QTest::addColumn("soVersion"); QTest::addColumn("useVersion"); QTest::addColumn("expectedSoName"); QTest::newRow("default") << QString() << true << QString("libmylib.so.1"); QTest::newRow("explicit soVersion") << QString("1.2") << true << QString("libmylib.so.1.2"); QTest::newRow("empty soVersion") << QString("") << true << QString("libmylib.so.1.2.3"); QTest::newRow("no version, explicit soVersion") << QString("5") << false << QString("libmylib.so.5"); QTest::newRow("no version, default soVersion") << QString() << false << QString("libmylib.so"); QTest::newRow("no version, empty soVersion") << QString("") << false << QString("libmylib.so"); } void TestBlackbox::sourceArtifactChanges() { QDir::setCurrent(testDataDir + "/source-artifact-changes"); bool useCustomFileTags = false; bool overrideFileTags = true; bool filesAreTargets = false; bool useCxx11 = false; static const auto b2s = [](bool b) { return QString(b ? "true" : "false"); }; const auto resolveParams = [&useCustomFileTags, &overrideFileTags, &filesAreTargets, &useCxx11] { return QbsRunParameters("resolve", QStringList{ "modules.module_with_files.overrideTags:" + b2s(overrideFileTags), "modules.module_with_files.filesAreTargets:" + b2s(filesAreTargets), "modules.module_with_files.fileTags:" + QString(useCustomFileTags ? "custom" : "cpp"), "modules.cpp.cxxLanguageVersion:" + QString(useCxx11 ? "c++11" : "c++98") }); }; #define VERIFY_COMPILATION(expected) \ do { \ QVERIFY2(m_qbsStdout.contains("compiling main.cpp") == expected, m_qbsStdout.constData()); \ QVERIFY2(QFile::exists(appFilePath) == expected, qPrintable(appFilePath)); \ if (expected) \ QVERIFY2(m_qbsStdout.contains("cpp artifacts: 1"), m_qbsStdout.constData()); \ else \ QVERIFY2(m_qbsStdout.contains("cpp artifacts: 0"), m_qbsStdout.constData()); \ } while (false) // Initial build. QCOMPARE(runQbs(resolveParams()), 0); QVERIFY2(m_qbsStdout.contains("is gcc: "), m_qbsStdout.constData()); const bool isGcc = m_qbsStdout.contains("is gcc: true"); const QString appFilePath = QDir::currentPath() + '/' + relativeExecutableFilePath("app", m_qbsStdout); QCOMPARE(runQbs(), 0); VERIFY_COMPILATION(true); // Overwrite the file tags. Now the source file is no longer tagged "cpp" and nothing // should get built. WAIT_FOR_NEW_TIMESTAMP(); touch("modules/module_with_files/main.cpp"); useCustomFileTags = true; QCOMPARE(runQbs(resolveParams()), 0); QCOMPARE(runQbs(), 0); VERIFY_COMPILATION(false); // Now the custom file tag exists in addition to "cpp", and the app should get built again. overrideFileTags = false; QCOMPARE(runQbs(resolveParams()), 0); QCOMPARE(runQbs(), 0); VERIFY_COMPILATION(true); // Mark the cpp file as a module target. Now it will no longer be considered an input // by the compiler rule, and nothing should get built. WAIT_FOR_NEW_TIMESTAMP(); touch("modules/module_with_files/main.cpp"); filesAreTargets = true; QCOMPARE(runQbs(resolveParams()), 0); QCOMPARE(runQbs(), 0); VERIFY_COMPILATION(false); // Now just revert the last change. filesAreTargets = false; QCOMPARE(runQbs(resolveParams()), 0); QCOMPARE(runQbs(), 0); VERIFY_COMPILATION(true); // Change a relevant cpp property. A rebuild is expected. useCxx11 = true; QCOMPARE(runQbs(resolveParams()), 0); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line"})), 0); if (isGcc) { QVERIFY2(m_qbsStdout.contains("-std=c++11") || m_qbsStdout.contains("-std=c++0x"), m_qbsStdout.constData()); } #undef VERIFY_COMPILATION } void TestBlackbox::overrideProjectProperties() { QDir::setCurrent(testDataDir + "/overrideProjectProperties"); QCOMPARE(runQbs(QbsRunParameters(QStringList() << QStringLiteral("-f") << QStringLiteral("overrideProjectProperties.qbs") << QStringLiteral("project.nameSuffix:ForYou") << QStringLiteral("project.someBool:false") << QStringLiteral("project.someInt:156") << QStringLiteral("project.someStringList:one") << QStringLiteral("products.MyAppForYou.mainFile:main.cpp"))), 0); QVERIFY(regularFileExists(relativeExecutableFilePath("MyAppForYou", m_qbsStdout))); QVERIFY(QFile::remove(relativeBuildGraphFilePath())); QbsRunParameters params; params.arguments << QStringLiteral("-f") << QStringLiteral("project_using_helper_lib.qbs"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); rmDirR(relativeBuildDir()); params.arguments = QStringList() << QStringLiteral("-f") << QStringLiteral("project_using_helper_lib.qbs") << QStringLiteral("project.linkSuccessfully:true"); params.expectFailure = false; QCOMPARE(runQbs(params), 0); } void TestBlackbox::partiallyBuiltDependency() { QDir::setCurrent(testDataDir + "/partially-built-dependency"); QCOMPARE(runQbs(QbsRunParameters({"-p", "p"})), 0); QCOMPARE(m_qbsStdout.count("generating main.cpp"), 1); QCOMPARE(m_qbsStdout.count("copying main.cpp"), 1); QCOMPARE(m_qbsStdout.count("compiling main.cpp"), 1); QVERIFY2(!m_qbsStdout.contains("linking"), m_qbsStdout.constData()); } void TestBlackbox::pathProbe_data() { QTest::addColumn("projectFile"); QTest::addColumn("successExpected"); QTest::newRow("non-existent") << QString("non-existent.qbs") << false; QTest::newRow("non-existent-selector.qbs") << QString("non-existent-selector.qbs") << false; QTest::newRow("single-file") << QString("single-file.qbs") << true; QTest::newRow("single-file-selector") << QString("single-file-selector.qbs") << true; QTest::newRow("single-file-selector-array") << QString("single-file-selector-array.qbs") << true; QTest::newRow("single-file-mult-variants") << QString("single-file-mult-variants.qbs") << true; QTest::newRow("mult-files") << QString("mult-files.qbs") << true; QTest::newRow("mult-files-mult-variants") << QString("mult-files-mult-variants.qbs") << true; QTest::newRow("single-file-suffixes") << QString("single-file-suffixes.qbs") << true; QTest::newRow("mult-files-suffixes") << QString("mult-files-suffixes.qbs") << true; QTest::newRow("mult-files-common-suffixes") << QString("mult-files-common-suffixes.qbs") << true; QTest::newRow("mult-files-mult-suffixes") << QString("mult-files-mult-suffixes.qbs") << true; QTest::newRow("name-filter") << QString("name-filter.qbs") << true; QTest::newRow("candidate-filter") << QString("candidate-filter.qbs") << true; QTest::newRow("environment-paths") << QString("environment-paths.qbs") << true; } void TestBlackbox::pathProbe() { QDir::setCurrent(testDataDir + "/path-probe"); QFETCH(QString, projectFile); QFETCH(bool, successExpected); rmDirR(relativeBuildDir()); QbsRunParameters buildParams("build", QStringList{"-f", projectFile}); buildParams.expectFailure = !successExpected; buildParams.environment.insert("SEARCH_PATH", "usr/bin"); QCOMPARE(runQbs(buildParams) == 0, successExpected); if (!successExpected) QVERIFY2(m_qbsStderr.contains("Probe failed to find files"), m_qbsStderr); } void TestBlackbox::pathListInProbe() { QDir::setCurrent(testDataDir + "/path-list-in-probe"); QCOMPARE(runQbs(), 0); } void TestBlackbox::pchChangeTracking() { QDir::setCurrent(testDataDir + "/pch-change-tracking"); bool success = runQbs() == 0; if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY(success); QVERIFY(m_qbsStdout.contains("precompiling pch.h (cpp)")); WAIT_FOR_NEW_TIMESTAMP(); touch("header1.h"); success = runQbs() == 0; if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY(success); QVERIFY(m_qbsStdout.contains("precompiling pch.h (cpp)")); QVERIFY(m_qbsStdout.contains("compiling header2.cpp")); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); WAIT_FOR_NEW_TIMESTAMP(); touch("header2.h"); success = runQbs() == 0; if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY(success); QVERIFY2(!m_qbsStdout.contains("precompiling pch.h (cpp)"), m_qbsStdout.constData()); } void TestBlackbox::perGroupDefineInExportItem() { QDir::setCurrent(testDataDir + "/per-group-define-in-export-item"); QCOMPARE(runQbs(), 0); } void TestBlackbox::pkgConfigProbe() { const QString exe = findExecutable(QStringList() << "pkg-config"); if (exe.isEmpty()) QSKIP("This test requires the pkg-config tool"); QDir::setCurrent(testDataDir + "/pkg-config-probe"); QFETCH(QString, packageBaseName); QFETCH(QStringList, found); QFETCH(QStringList, libs); QFETCH(QStringList, cflags); QFETCH(QStringList, version); rmDirR(relativeBuildDir()); QbsRunParameters params(QStringList() << ("project.packageBaseName:" + packageBaseName)); QCOMPARE(runQbs(params), 0); const QString stdOut = m_qbsStdout; QVERIFY2(stdOut.contains("theProduct1 found: " + found.at(0)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct2 found: " + found.at(1)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct1 libs: " + libs.at(0)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct2 libs: " + libs.at(1)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct1 cflags: " + cflags.at(0)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct2 cflags: " + cflags.at(1)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct1 version: " + version.at(0)), m_qbsStdout.constData()); QVERIFY2(stdOut.contains("theProduct2 version: " + version.at(1)), m_qbsStdout.constData()); } void TestBlackbox::pkgConfigProbe_data() { QTest::addColumn("packageBaseName"); QTest::addColumn("found"); QTest::addColumn("libs"); QTest::addColumn("cflags"); QTest::addColumn("version"); QTest::newRow("existing package") << "dummy" << (QStringList() << "true" << "true") << (QStringList() << "[\"-Ldummydir1\",\"-ldummy1\"]" << "[\"-Ldummydir2\",\"-ldummy2\"]") << (QStringList() << "[]" << "[]") << (QStringList() << "0.0.1" << "0.0.2"); // Note: The array values should be "undefined", but we lose that information when // converting to QVariants in the ProjectResolver. QTest::newRow("non-existing package") << "blubb" << (QStringList() << "false" << "false") << (QStringList() << "[]" << "[]") << (QStringList() << "[]" << "[]") << (QStringList() << "undefined" << "undefined"); } void TestBlackbox::pkgConfigProbeSysroot() { const QString exe = findExecutable(QStringList() << "pkg-config"); if (exe.isEmpty()) QSKIP("This test requires the pkg-config tool"); QDir::setCurrent(testDataDir + "/pkg-config-probe-sysroot"); QCOMPARE(runQbs(QStringList("-v")), 0); QCOMPARE(m_qbsStderr.count("PkgConfigProbe: found packages"), 2); const QString outputTemplate = "theProduct%1 libs: [\"-L%2/usr/dummy\",\"-ldummy1\"]"; QVERIFY2(m_qbsStdout.contains(outputTemplate .arg("1", QDir::currentPath() + "/sysroot1").toLocal8Bit()), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains(outputTemplate .arg("2", QDir::currentPath() + "/sysroot2").toLocal8Bit()), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains(outputTemplate .arg("3", QDir::currentPath() + "/sysroot1").toLocal8Bit()), m_qbsStdout.constData()); } void TestBlackbox::pluginDependency() { QDir::setCurrent(testDataDir + "/plugin-dependency"); // Build the plugins and the helper2 lib. QCOMPARE(runQbs(QStringList{"--products", "plugin1,plugin2,plugin3,plugin4,helper2"}), 0); QVERIFY(m_qbsStdout.contains("plugin1")); QVERIFY(m_qbsStdout.contains("plugin2")); QVERIFY(m_qbsStdout.contains("plugin3")); QVERIFY(m_qbsStdout.contains("plugin4")); QVERIFY(m_qbsStdout.contains("helper2")); QVERIFY(!m_qbsStderr.contains("SOFT ASSERT")); // Build the app. Plugins 1 and 2 must not be linked. Plugin 3 must be linked. QCOMPARE(runQbs(QStringList{"--command-echo-mode", "command-line"}), 0); QByteArray output = m_qbsStdout + '\n' + m_qbsStderr; QVERIFY(!output.contains("plugin1")); QVERIFY(!output.contains("plugin2")); QVERIFY(!output.contains("helper2")); // Test change tracking for parameter in Parameters item. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("plugin-dependency.qbs", "false // marker 1", "true"); QCOMPARE(runQbs(QStringList{"-p", "plugin2"}), 0); QVERIFY2(!m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QCOMPARE(runQbs(QStringList{"--command-echo-mode", "command-line"}), 0); output = m_qbsStdout + '\n' + m_qbsStderr; QVERIFY2(!output.contains("plugin1"), output.constData()); QVERIFY2(!output.contains("helper2"), output.constData()); QVERIFY2(output.contains("plugin2"), output.constData()); // Test change tracking for parameter in Depends item. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("plugin-dependency.qbs", "false /* marker 2 */", "true"); QCOMPARE(runQbs(QStringList{"-p", "helper1", "--command-echo-mode", "command-line"}), 0); output = m_qbsStdout + '\n' + m_qbsStderr; QVERIFY2(output.contains("helper2"), output.constData()); // Check that the build dependency still works. QCOMPARE(runQbs(QStringLiteral("clean")), 0); QCOMPARE(runQbs(QStringList{"--products", "myapp", "--command-echo-mode", "command-line"}), 0); QVERIFY(m_qbsStdout.contains("plugin1")); QVERIFY(m_qbsStdout.contains("plugin2")); QVERIFY(m_qbsStdout.contains("plugin3")); QVERIFY(m_qbsStdout.contains("plugin4")); } void TestBlackbox::precompiledAndPrefixHeaders() { QDir::setCurrent(testDataDir + "/precompiled-and-prefix-headers"); const bool success = runQbs() == 0; if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY(success); } void TestBlackbox::precompiledHeaderAndRedefine() { QDir::setCurrent(testDataDir + "/precompiled-headers-and-redefine"); const bool success = runQbs() == 0; if (!success && m_qbsStderr.contains("mingw32_gt_pch_use_address")) QSKIP("https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91440"); QVERIFY(success); } void TestBlackbox::preventFloatingPointValues() { QDir::setCurrent(testDataDir + "/prevent-floating-point-values"); QCOMPARE(runQbs(QStringList("products.p.version:1.50")), 0); QVERIFY2(m_qbsStdout.contains("version: 1.50"), m_qbsStdout.constData()); } void TestBlackbox::probeChangeTracking() { QDir::setCurrent(testDataDir + "/probe-change-tracking"); // Product probe disabled, other probes enabled. QbsRunParameters params; params.command = "resolve"; params.arguments = QStringList("products.theProduct.runProbe:false"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("running tlpProbe")); QVERIFY(m_qbsStdout.contains("running subProbe")); QVERIFY(!m_qbsStdout.contains("running productProbe")); // Product probe newly enabled. params.arguments = QStringList("products.theProduct.runProbe:true"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("running tlpProbe")); QVERIFY(!m_qbsStdout.contains("running subProbe")); QVERIFY(m_qbsStdout.contains("running productProbe: 12")); // Re-resolving with unchanged probe. WAIT_FOR_NEW_TIMESTAMP(); touch("probe-change-tracking.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(!m_qbsStdout.contains("running tlpProbe")); QVERIFY(!m_qbsStdout.contains("running subProbe")); QVERIFY(!m_qbsStdout.contains("running productProbe")); // Re-resolving with changed configure scripts. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("probe-change-tracking.qbs", "console.info", " console.info"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(m_qbsStdout.contains("running tlpProbe")); QVERIFY(m_qbsStdout.contains("running subProbe")); QVERIFY(m_qbsStdout.contains("running productProbe: 12")); // Re-resolving with added property. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("probe-change-tracking.qbs", "condition: product.runProbe", "condition: product.runProbe\nproperty string something: 'x'"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(!m_qbsStdout.contains("running tlpProbe")); QVERIFY(!m_qbsStdout.contains("running subProbe")); QVERIFY(m_qbsStdout.contains("running productProbe: 12")); // Re-resolving with changed property. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("probe-change-tracking.qbs", "'x'", "'y'"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(!m_qbsStdout.contains("running tlpProbe")); QVERIFY(!m_qbsStdout.contains("running subProbe")); QVERIFY(m_qbsStdout.contains("running productProbe: 12")); // Re-resolving with removed property. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("probe-change-tracking.qbs", "property string something: 'y'", ""); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(!m_qbsStdout.contains("running tlpProbe")); QVERIFY(!m_qbsStdout.contains("running subProbe")); QVERIFY(m_qbsStdout.contains("running productProbe: 12")); // Re-resolving with unchanged probe again. WAIT_FOR_NEW_TIMESTAMP(); touch("probe-change-tracking.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(!m_qbsStdout.contains("running tlpProbe")); QVERIFY(!m_qbsStdout.contains("running subProbe")); QVERIFY(!m_qbsStdout.contains("running productProbe")); // Enforcing re-running via command-line option. params.arguments.prepend("--force-probe-execution"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("Resolving")); QVERIFY(m_qbsStdout.contains("running tlpProbe")); QVERIFY(m_qbsStdout.contains("running subProbe")); QVERIFY(m_qbsStdout.contains("running productProbe: 12")); } void TestBlackbox::probeProperties() { QDir::setCurrent(testDataDir + "/probeProperties"); const QByteArray dir = QDir::cleanPath(testDataDir).toLocal8Bit() + "/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()); QVERIFY2(m_qbsStdout.contains("probe3.fileName=tool"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("probe3.path=" + dir + "/bin"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("probe3.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData()); } void TestBlackbox::probesAndShadowProducts() { QDir::setCurrent(testDataDir + "/probes-and-shadow-products"); QCOMPARE(runQbs(QStringList("--log-time")), 0); QVERIFY2(m_qbsStdout.contains("2 probes encountered, 1 configure scripts executed"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("probes-and-shadow-products.qbs"); QCOMPARE(runQbs(QStringList("--log-time")), 0); QVERIFY2(m_qbsStdout.contains("2 probes encountered, 0 configure scripts executed"), m_qbsStdout.constData()); } void TestBlackbox::probeInExportedModule() { QDir::setCurrent(testDataDir + "/probe-in-exported-module"); QCOMPARE(runQbs(QbsRunParameters(QStringList() << QStringLiteral("-f") << QStringLiteral("probe-in-exported-module.qbs"))), 0); QVERIFY2(m_qbsStdout.contains("found: true"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("prop: yes"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("listProp: myother,my"), m_qbsStdout.constData()); } void TestBlackbox::probesAndArrayProperties() { QDir::setCurrent(testDataDir + "/probes-and-array-properties"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("prop: [\"probe\"]"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("probes-and-array-properties.qbs", "//", ""); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("prop: [\"product\",\"probe\"]"), m_qbsStdout.constData()); } void TestBlackbox::productProperties() { QDir::setCurrent(testDataDir + "/productproperties"); QCOMPARE(runQbs(QbsRunParameters(QStringList() << QStringLiteral("-f") << QStringLiteral("productproperties.qbs"))), 0); QVERIFY(regularFileExists(relativeExecutableFilePath("blubb_user", m_qbsStdout))); } void TestBlackbox::propertyAssignmentInFailedModule() { QDir::setCurrent(testDataDir + "/property-assignment-in-failed-module"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.m.doFail:false"))), 0); QbsRunParameters failParams; failParams.expectFailure = true; QVERIFY(runQbs(failParams) != 0); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.m.doFail:true"))), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); failParams.expectFailure = false; QCOMPARE(runQbs(failParams), 0); } void TestBlackbox::propertyChanges() { QDir::setCurrent(testDataDir + "/propertyChanges"); const QString projectFile("propertyChanges.qbs"); QbsRunParameters params(QStringList({"-f", "propertyChanges.qbs", "qbs.enableDebugCode:true"})); // Initial build. QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(m_qbsStdout.contains("generated.txt")); QVERIFY(m_qbsStdout.contains("making output from input")); QVERIFY(m_qbsStdout.contains("default value")); QVERIFY(m_qbsStdout.contains("making output from other output")); QFile generatedFile(relativeProductBuildDir("generated text file") + "/generated.txt"); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 1suffix 1")); generatedFile.close(); // Incremental build with no changes. QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp.cpp")); QVERIFY(!m_qbsStdout.contains("linking")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build with no changes, but updated project file timestamp. WAIT_FOR_NEW_TIMESTAMP(); touch(projectFile); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("linking")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed for first product WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "blubb1", "blubb01"); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("linking library")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed via project for second product. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "blubb2", "blubb02"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed via command line for second product. params.command = "resolve"; params.arguments << "project.projectDefines:blubb002"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); params.arguments.removeLast(); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, input property changed via environment for third product. params.environment.insert("QBS_BLACKBOX_DEFINE", "newvalue"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); params.environment.remove("QBS_BLACKBOX_DEFINE"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); params.environment.insert("QBS_BLACKBOX_DEFINE", "newvalue"); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); params.environment.remove("QBS_BLACKBOX_DEFINE"); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, module property changed via command line. params.arguments << "qbs.enableDebugCode:false"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.release")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); params.arguments.removeLast(); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, non-essential dependency removed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "Depends { name: 'library' }", "// Depends { name: 'library' }"); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("linking library")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); // Incremental build, prepare script of a transformer changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "contents 1", "contents 2"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 1contents 2suffix 1")); generatedFile.close(); // Incremental build, product property used in JavaScript command changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "prefix 1", "prefix 2"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 2contents 2suffix 1")); generatedFile.close(); // Incremental build, project property used in JavaScript command changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "suffix 1", "suffix 2"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); QVERIFY(!m_qbsStdout.contains("making output from input")); QVERIFY(!m_qbsStdout.contains("making output from other output")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("prefix 2contents 2suffix 2")); generatedFile.close(); // Incremental build, module property used in JavaScript command changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFile, "default value", "new value"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(m_qbsStdout.contains("making output from input")); QVERIFY(m_qbsStdout.contains("making output from other output")); QVERIFY(m_qbsStdout.contains("new value")); // Incremental build, prepare script of a rule in a module changed. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("modules/TestModule/module.qbs", "// console.info('Change in source code')", "console.info('Change in source code')"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); QVERIFY(m_qbsStdout.contains("making output from input")); QVERIFY(m_qbsStdout.contains("making output from other output")); } void TestBlackbox::propertyEvaluationContext() { const QString testDir = testDataDir + "/property-evaluation-context"; QDir::setCurrent(testDir); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("base.productInBase evaluated in: myapp"), 1); QCOMPARE(m_qbsStdout.count("base.productInTop evaluated in: myapp"), 1); QCOMPARE(m_qbsStdout.count("top.productInExport evaluated in: mylib"), 1); QCOMPARE(m_qbsStdout.count("top.productInTop evaluated in: myapp"), 1); } void TestBlackbox::qtBug51237() { const SettingsPtr s = settings(); qbs::Internal::TemporaryProfile profile("qbs_autotests_qtBug51237", s.get()); profile.p.setValue("mymodule.theProperty", QStringList()); s->sync(); QDir::setCurrent(testDataDir + "/QTBUG-51237"); QbsRunParameters params; params.profile = profile.p.name(); QCOMPARE(runQbs(params), 0); } void TestBlackbox::dynamicMultiplexRule() { const QString testDir = testDataDir + "/dynamicMultiplexRule"; QDir::setCurrent(testDir); QCOMPARE(runQbs(), 0); const QString outputFilePath = relativeProductBuildDir("dynamicMultiplexRule") + "/stuff-from-3-inputs"; QVERIFY(regularFileExists(outputFilePath)); WAIT_FOR_NEW_TIMESTAMP(); touch("two.txt"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(outputFilePath)); } void TestBlackbox::dynamicProject() { const QString testDir = testDataDir + "/dynamic-project"; QDir::setCurrent(testDir); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("compiling main.cpp"), 2); } void TestBlackbox::dynamicRuleOutputs() { const QString testDir = testDataDir + "/dynamicRuleOutputs"; QDir::setCurrent(testDir); if (QFile::exists("work")) rmDirR("work"); QDir().mkdir("work"); ccp("before", "work"); QDir::setCurrent(testDir + "/work"); QCOMPARE(runQbs(), 0); const QString appFile = relativeExecutableFilePath("genlexer", m_qbsStdout); const QString headerFile1 = relativeProductBuildDir("genlexer") + "/GeneratedFiles/numberscanner.h"; const QString sourceFile1 = relativeProductBuildDir("genlexer") + "/GeneratedFiles/numberscanner.c"; const QString sourceFile2 = relativeProductBuildDir("genlexer") + "/GeneratedFiles/lex.yy.c"; // Check build #1: source and header file name are specified in numbers.l QVERIFY(regularFileExists(appFile)); QVERIFY(regularFileExists(headerFile1)); QVERIFY(regularFileExists(sourceFile1)); QVERIFY(!QFile::exists(sourceFile2)); QDateTime appFileTimeStamp1 = QFileInfo(appFile).lastModified(); WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("../after/numbers.l", "numbers.l"); QCOMPARE(runQbs(), 0); // Check build #2: no file names are specified in numbers.l // flex will default to lex.yy.c without header file. QDateTime appFileTimeStamp2 = QFileInfo(appFile).lastModified(); QVERIFY(appFileTimeStamp1 < appFileTimeStamp2); QVERIFY(!QFile::exists(headerFile1)); QVERIFY(!QFile::exists(sourceFile1)); QVERIFY(regularFileExists(sourceFile2)); WAIT_FOR_NEW_TIMESTAMP(); copyFileAndUpdateTimestamp("../before/numbers.l", "numbers.l"); QCOMPARE(runQbs(), 0); // Check build #3: source and header file name are specified in numbers.l QDateTime appFileTimeStamp3 = QFileInfo(appFile).lastModified(); QVERIFY(appFileTimeStamp2 < appFileTimeStamp3); QVERIFY(regularFileExists(appFile)); QVERIFY(regularFileExists(headerFile1)); QVERIFY(regularFileExists(sourceFile1)); QVERIFY(!QFile::exists(sourceFile2)); } void TestBlackbox::emptyProfile() { QDir::setCurrent(testDataDir + "/empty-profile"); const SettingsPtr s = settings(); const qbs::Profile buildProfile(profileName(), s.get()); bool isMsvc = false; auto toolchainType = buildProfile.value(QStringLiteral("qbs.toolchainType")).toString(); QbsRunParameters params; params.profile = "none"; if (toolchainType.isEmpty()) { const auto toolchain = buildProfile.value(QStringLiteral("qbs.toolchain")).toStringList(); if (!toolchain.isEmpty()) toolchainType = toolchain.first(); } if (!toolchainType.isEmpty()) { params.arguments = QStringList{QStringLiteral("qbs.toolchainType:") + toolchainType}; isMsvc = toolchainType == "msvc" || toolchainType == "clang-cl"; } if (!isMsvc) { const auto tcPath = QDir::toNativeSeparators( buildProfile.value(QStringLiteral("cpp.toolchainInstallPath")).toString()); auto paths = params.environment.value(QStringLiteral("PATH")) .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); if (!tcPath.isEmpty() && !paths.contains(tcPath)) { paths.prepend(tcPath); params.environment.insert( QStringLiteral("PATH"), paths.join(HostOsInfo::pathListSeparator())); } } QCOMPARE(runQbs(params), 0); } using ASet = QSet; namespace { QString JS() { static const auto suffix = QStringLiteral(".js"); return suffix; } QString WASM() { static const auto suffix = QStringLiteral(".wasm"); return suffix; } QString WASMJS() { static const auto suffix = QStringLiteral(".wasm.js"); return suffix; } QString HTML() { static const auto suffix = QStringLiteral(".html"); return suffix; } } // namespace void TestBlackbox::emscriptenArtifacts() { QDir::setCurrent(testDataDir + "/emscripten-artifacts"); QFETCH(QString, executableSuffix); QFETCH(QString, wasmOption); QFETCH(int, buildresult); QFETCH(ASet, suffixes); const QStringList params = { QStringLiteral("modules.cpp.executableSuffix:%1").arg(executableSuffix), QStringLiteral("modules.cpp.driverLinkerFlags:%1").arg(wasmOption)}; ASet possibleSuffixes = {JS(), WASM(), WASMJS(), HTML()}; QbsRunParameters qbsParams("resolve", params); int result = runQbs(qbsParams); QCOMPARE(result, 0); if (m_qbsStdout.contains("is emscripten: false")) QSKIP("Skipping emscripten test"); QVERIFY(m_qbsStdout.contains("is emscripten: true")); result = runQbs(QbsRunParameters("build", params)); QCOMPARE(result, buildresult); if (result == 0) { const auto app = QStringLiteral("app"); const auto appWithoutSuffix = relativeProductBuildDir(app) + QLatin1Char('/') + app; ASet usedSuffixes; for (const auto &suffix : suffixes) { usedSuffixes.insert(suffix); QVERIFY(regularFileExists(appWithoutSuffix + suffix)); } possibleSuffixes.subtract(usedSuffixes); for (const auto &unusedSuffix : possibleSuffixes) { QVERIFY(!regularFileExists(appWithoutSuffix + unusedSuffix)); } } QCOMPARE(runQbs(QbsRunParameters("clean")), 0); } void TestBlackbox::emscriptenArtifacts_data() { QTest::addColumn("executableSuffix"); QTest::addColumn("wasmOption"); QTest::addColumn("buildresult"); QTest::addColumn("suffixes"); QTest::newRow(".js WASM=0") << ".js" << "-sWASM=0" << 0 << ASet{JS()}; QTest::newRow(".js WASM=1") << ".js" << "-sWASM=1" << 0 << ASet{JS(), WASM()}; QTest::newRow(".js WASM=2") << ".js" << "-sWASM=2" << 0 << ASet{JS(), WASM(), WASMJS()}; QTest::newRow(".js WASM=779") << ".js" << "-sWASM=779" << 0 << ASet{JS(), WASM()}; QTest::newRow(".wasm WASM=0") << ".wasm" << "-sWASM=0" << 1 << ASet{}; QTest::newRow(".wasm WASM=1") << ".wasm" << "-sWASM=1" << 0 << ASet{WASM()}; QTest::newRow(".wasm WASM=2") << ".wasm" << "-sWASM=2" << 0 << ASet{WASM(), WASMJS()}; QTest::newRow(".wasm WASM=848") << ".wasm" << "-sWASM=848" << 0 << ASet{WASM()}; QTest::newRow(".html WASM=0") << ".html" << "-sWASM=0" << 0 << ASet{JS(), HTML()}; QTest::newRow(".html WASM=1") << ".html" << "-sWASM=1" << 0 << ASet{JS(), HTML(), WASM()}; QTest::newRow(".html WASM=2") << ".html" << "-sWASM=2" << 0 << ASet{JS(), HTML(), WASM(), WASMJS()}; QTest::newRow(".html WASM=233") << ".html" << "-sWASM=233" << 0 << ASet{JS(), HTML(), WASM()}; } void TestBlackbox::erroneousFiles_data() { QTest::addColumn("errorMessage"); QTest::newRow("nonexistentWorkingDir") << "The working directory '.does.not.exist' for process '.*ls.*' is invalid."; QTest::newRow("outputArtifacts-missing-filePath") << "Error in Rule\\.outputArtifacts\\[0\\]\n\r?" "Property filePath must be a non-empty string\\."; QTest::newRow("outputArtifacts-missing-fileTags") << "Error in Rule\\.outputArtifacts\\[0\\]\n\r?" "Property fileTags for artifact 'outputArtifacts-missing-fileTags\\.txt' " "must be a non-empty string list\\."; QTest::newRow("texttemplate-unknown-placeholder") << "Placeholder 'what' is not defined in textemplate.dict for 'boom.txt.in'"; QTest::newRow("tag-mismatch") << "tag-mismatch.qbs:8:18.*Artifact '.*dummy1' has undeclared file tags " "\\[\"y\",\"z\"\\]."; } void TestBlackbox::erroneousFiles() { QFETCH(QString, errorMessage); QDir::setCurrent(testDataDir + "/erroneous/" + QTest::currentDataTag()); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QString err = QString::fromLocal8Bit(m_qbsStderr); if (!err.contains(QRegularExpression(errorMessage))) { qDebug().noquote() << "Output: " << err; qDebug().noquote() << "Expected: " << errorMessage; QFAIL("Unexpected error message."); } } void TestBlackbox::errorInfo() { QDir::setCurrent(testDataDir + "/error-info"); QCOMPARE(runQbs(), 0); QbsRunParameters resolveParams; QbsRunParameters buildParams; buildParams.expectFailure = true; resolveParams.command = "resolve"; resolveParams.arguments = QStringList() << "project.fail1:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("error-info.qbs:24"), m_qbsStderr); resolveParams.arguments = QStringList() << "project.fail2:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("error-info.qbs:36"), m_qbsStderr); resolveParams.arguments = QStringList() << "project.fail3:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("error-info.qbs:51"), m_qbsStderr); resolveParams.arguments = QStringList() << "project.fail4:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("error-info.qbs:66"), m_qbsStderr); resolveParams.arguments = QStringList() << "project.fail5:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("helper.js:4"), m_qbsStderr); resolveParams.arguments = QStringList() << "project.fail6:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("helper.js:8"), m_qbsStderr); resolveParams.arguments = QStringList() << "project.fail7:true"; QCOMPARE(runQbs(resolveParams), 0); buildParams.arguments = resolveParams.arguments; QVERIFY(runQbs(buildParams) != 0); QVERIFY2(m_qbsStderr.contains("JavaScriptCommand.sourceCode"), m_qbsStderr); QVERIFY2(m_qbsStderr.contains("error-info.qbs:57"), m_qbsStderr); } void TestBlackbox::escapedLinkerFlags() { QDir::setCurrent(testDataDir + "/escaped-linker-flags"); QbsRunParameters params("resolve", QStringList("products.app.escapeLinkerFlags:false")); QCOMPARE(runQbs(params), 0); const bool isGcc = m_qbsStdout.contains("is gcc: true"); const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); if (isNotGcc) QSKIP("escaped linker flags test only applies on plain unix with gcc and GNU ld"); QVERIFY(isGcc); params.command = "build"; QCOMPARE(runQbs(params), 0); params.command = "resolve"; params.arguments = QStringList() << "products.app.escapeLinkerFlags:true"; QCOMPARE(runQbs(params), 0); params.command = "build"; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Encountered escaped linker flag"), m_qbsStderr.constData()); } void TestBlackbox::exportedDependencyInDisabledProduct() { QDir::setCurrent(testDataDir + "/exported-dependency-in-disabled-product"); QFETCH(QString, depCondition); QFETCH(bool, compileExpected); rmDirR(relativeBuildDir()); const QString propertyArg = "products.dep.conditionString:" + depCondition; QCOMPARE(runQbs(QStringList(propertyArg)), 0); QCOMPARE(m_qbsStdout.contains("compiling"), compileExpected); } void TestBlackbox::exportedDependencyInDisabledProduct_data() { QTest::addColumn("depCondition"); QTest::addColumn("compileExpected"); QTest::newRow("dependency enabled") << "true" << true; QTest::newRow("dependency directly disabled") << "false" << false; QTest::newRow("dependency disabled via non-present module") << "nosuchmodule.present" << false; QTest::newRow("dependency disabled via failed module") << "broken.present" << false; } void TestBlackbox::exportedPropertyInDisabledProduct() { QDir::setCurrent(testDataDir + "/exported-property-in-disabled-product"); QFETCH(QString, depCondition); QFETCH(bool, successExpected); const QString propertyArg = "products.dep.conditionString:" + depCondition; QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList(propertyArg))), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QbsRunParameters buildParams; buildParams.expectFailure = !successExpected; QCOMPARE(runQbs(buildParams) == 0, successExpected); } void TestBlackbox::exportedPropertyInDisabledProduct_data() { QTest::addColumn("depCondition"); QTest::addColumn("successExpected"); QTest::newRow("dependency enabled") << "true" << false; QTest::newRow("dependency directly disabled") << "false" << true; QTest::newRow("dependency disabled via non-present module") << "nosuchmodule.present" << true; QTest::newRow("dependency disabled via failed module") << "broken.present" << true; } void TestBlackbox::systemRunPaths() { const QString lddFilePath = findExecutable(QStringList() << "ldd"); if (lddFilePath.isEmpty()) QSKIP("ldd not found"); QDir::setCurrent(testDataDir + "/system-run-paths"); QFETCH(bool, setRunPaths); rmDirR(relativeBuildDir()); QbsRunParameters params("resolve"); params.arguments << QString("project.setRunPaths:") + (setRunPaths ? "true" : "false"); QCOMPARE(runQbs(params), 0); const bool isUnix = m_qbsStdout.contains("is unix: true"); const bool isNotUnix = m_qbsStdout.contains("is unix: false"); if (isNotUnix) QSKIP("only applies on Unix"); QVERIFY(isUnix); const QString exe = relativeExecutableFilePath("app", m_qbsStdout); params.command = "build"; QCOMPARE(runQbs(params), 0); QProcess ldd; ldd.start(lddFilePath, QStringList() << exe); QVERIFY2(ldd.waitForStarted(), qPrintable(ldd.errorString())); QVERIFY2(ldd.waitForFinished(), qPrintable(ldd.errorString())); QVERIFY2(ldd.exitCode() == 0, ldd.readAllStandardError().constData()); const QByteArray output = ldd.readAllStandardOutput(); const QList outputLines = output.split('\n'); QByteArray libLine; for (const auto &line : outputLines) { if (line.contains("theLib")) { libLine = line; break; } } QVERIFY2(!libLine.isEmpty(), output.constData()); QVERIFY2(setRunPaths == libLine.contains("not found"), libLine.constData()); } void TestBlackbox::systemRunPaths_data() { QTest::addColumn("setRunPaths"); QTest::newRow("do not set system run paths") << false; QTest::newRow("do set system run paths") << true; } void TestBlackbox::exportRule() { QDir::setCurrent(testDataDir + "/export-rule"); QbsRunParameters params(QStringList{"modules.blubber.enableTagger:false"}); params.expectFailure = true; QVERIFY(runQbs(params) != 0); params.command = "resolve"; params.arguments = QStringList{"modules.blubber.enableTagger:true"}; params.expectFailure = false; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("creating C++ source file"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("compiling myapp.cpp"), m_qbsStdout.constData()); } void TestBlackbox::exportToOutsideSearchPath() { QDir::setCurrent(testDataDir + "/export-to-outside-searchpath"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Dependency 'aModule' not found for product 'theProduct'."), m_qbsStderr.constData()); } void TestBlackbox::exportsCMake() { QFETCH(QStringList, arguments); QDir::setCurrent(testDataDir + "/exports-cmake"); rmDirR(relativeBuildDir()); QbsRunParameters findCMakeParams("resolve", {"-f", "find-cmake.qbs"}); QCOMPARE(runQbs(findCMakeParams), 0); const QString output = QString::fromLocal8Bit(m_qbsStdout); const QRegularExpression pattern( QRegularExpression::anchoredPattern(".*---(.*)---.*"), QRegularExpression::DotMatchesEverythingOption); const QRegularExpressionMatch match = pattern.match(output); QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); const QString jsonString = match.captured(1); const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8()); const QJsonObject jsonData = jsonDoc.object(); rmDirR(relativeBuildDir()); const QStringList exporterArgs{"-f", "exports-cmake.qbs"}; QbsRunParameters exporterRunParams("build", exporterArgs); exporterRunParams.arguments << arguments; QCOMPARE(runQbs(exporterRunParams), 0); if (!jsonData.value(u"cmakeFound").toBool()) { QSKIP("cmake is not installed"); return; } if (jsonData.value(u"crossCompiling").toBool()) { QSKIP("test is not applicable with cross-compile toolchains"); return; } const auto cmakeFilePath = jsonData.value(u"cmakeFilePath").toString(); QVERIFY(!cmakeFilePath.isEmpty()); const auto generator = jsonData.value(u"generator").toString(); if (generator.isEmpty()) { QSKIP("cannot detect cmake generator"); return; } QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); const auto buildEnv = jsonData.value(u"buildEnv").toObject(); for (auto it = buildEnv.begin(), end = buildEnv.end(); it != end; ++it) { if (it.key() == "PATH") { auto paths = it.value().toString().split(HostOsInfo::pathListSeparator()); paths.append(env.value(it.key()).split(HostOsInfo::pathListSeparator())); env.insert(it.key(), paths.join(HostOsInfo::pathListSeparator())); } else { env.insert(it.key(), it.value().toString()); } } const auto installPrefix = jsonData.value(u"installPrefix").toString(); const auto cmakePrefixPath = QFileInfo(relativeBuildDir()).absoluteFilePath() + "/install-root/" + installPrefix + "/lib/cmake"; const auto sourceDirectory = testDataDir + "/exports-cmake/cmake"; QProcess configure; configure.setProcessEnvironment(env); configure.setWorkingDirectory(sourceDirectory); configure.start( cmakeFilePath, {".", "-DCMAKE_PREFIX_PATH=" + cmakePrefixPath, "-G" + generator}); QVERIFY(waitForProcessSuccess(configure, 120000)); QProcess build; build.setProcessEnvironment(env); build.setWorkingDirectory(sourceDirectory); build.start(cmakeFilePath, QStringList{"--build", "."}); QVERIFY(waitForProcessSuccess(build)); } void TestBlackbox::exportsCMake_data() { QTest::addColumn("arguments"); QTest::newRow("dynamic lib") << QStringList("project.isStatic: false"); QTest::newRow("static lib") << QStringList("project.isStatic: true"); QTest::newRow("framework") << QStringList("project.isBundle: true"); } void TestBlackbox::exportsPkgconfig() { QDir::setCurrent(testDataDir + "/exports-pkgconfig"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("creating TheFirstLib.pc"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("creating TheSecondLib.pc"), m_qbsStdout.constData()); QFile sourcePcFile(HostOsInfo::isWindowsHost() ? "TheFirstLib_windows.pc" : "TheFirstLib.pc"); QString generatedPcFilePath = relativeProductBuildDir("TheFirstLib") + "/TheFirstLib.pc"; QFile generatedPcFile(generatedPcFilePath); QVERIFY2(sourcePcFile.open(QIODevice::ReadOnly), qPrintable(sourcePcFile.errorString())); QVERIFY2(generatedPcFile.open(QIODevice::ReadOnly), qPrintable(generatedPcFile.errorString())); QCOMPARE(generatedPcFile.readAll().replace("\r", ""), sourcePcFile.readAll().replace("\r", "")); sourcePcFile.close(); generatedPcFile.close(); TEXT_FILE_COMPARE(relativeProductBuildDir("TheSecondLib") + "/TheSecondLib.pc", "TheSecondLib.pc"); WAIT_FOR_NEW_TIMESTAMP(); touch("firstlib.cpp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("linking"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating TheFirstLib.pc"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating TheSecondLib.pc"), m_qbsStdout.constData()); } void TestBlackbox::exportsQbs() { QDir::setCurrent(testDataDir + "/exports-qbs"); QCOMPARE(runQbs({"resolve", {"-f", "exports-qbs.qbs"}}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); // First we build exportable products and use them (as products) inside // the original project. QCOMPARE(runQbs(QStringList{"-f", "exports-qbs.qbs", "--command-echo-mode", "command-line"}), 0); QVERIFY2(m_qbsStdout.contains("somelocaldir"), m_qbsStdout.constData()); // Now we build an external product against the modules that were just installed. // We try debug and release mode; one module exists for each of them. QbsRunParameters paramsExternalBuild(QStringList{"-f", "consumer.qbs", "--command-echo-mode", "command-line", "modules.qbs.buildVariant:debug",}); paramsExternalBuild.buildDirectory = QDir::currentPath() + "/external-consumer-debug"; QCOMPARE(runQbs(paramsExternalBuild), 0); QVERIFY2(!m_qbsStdout.contains("somelocaldir"), m_qbsStdout.constData()); paramsExternalBuild.arguments = QStringList{"-f", "consumer.qbs", "modules.qbs.buildVariant:release"}; paramsExternalBuild.buildDirectory = QDir::currentPath() + "/external-consumer-release"; QCOMPARE(runQbs(paramsExternalBuild), 0); // Trying to build with an unsupported build variant must fail. paramsExternalBuild.arguments = QStringList{"-f", "consumer.qbs", "modules.qbs.buildVariant:profiling"}; paramsExternalBuild.buildDirectory = QDir::currentPath() + "/external-consumer-profile"; paramsExternalBuild.expectFailure = true; QVERIFY(runQbs(paramsExternalBuild) != 0); QVERIFY2(m_qbsStderr.contains("Dependency 'MyLib' not found for product 'consumer'"), m_qbsStderr.constData()); // Removing the condition from the generated module leaves us with two conflicting // candidates. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList{ "-f", "exports-qbs.qbs", "modules.Exporter.qbs.additionalContent:''"})), 0); QCOMPARE(runQbs(), 0); QVERIFY(runQbs(paramsExternalBuild) != 0); QVERIFY2(m_qbsStderr.contains("There is more than one equally prioritized candidate " "for module 'MyLib'."), m_qbsStderr.constData()); // Change tracking for accesses to product.exports (negative). QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList{"-f", "exports-qbs.qbs"})), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("exports-qbs.qbs"); QCOMPARE(runQbs(QStringList({"-p", "MyTool"})), 0); QVERIFY2(!m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); // Rebuilding the target binary should not cause recreating the module file. WAIT_FOR_NEW_TIMESTAMP(); touch("mylib.cpp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.count("linking") >= 2, m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating MyLib"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); // Changing a setting that influences the name of a target artifact should cause // recreating the module file. const QbsRunParameters resolveParams("resolve", QStringList{"-f", "exports-qbs.qbs", "modules.cpp.dynamicLibrarySuffix:.blubb"}); QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.count("linking") >= 2, m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.count("creating MyLib") == 2, m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); // Change tracking for accesses to product.exports (positive). WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("tool.qbs", "exportingProduct.toolTags", "[]"); QCOMPARE(runQbs(QStringList({"-p", "MyTool"})), 0); QVERIFY2(m_qbsStdout.contains("creating MyTool.qbs"), m_qbsStdout.constData()); } void TestBlackbox::externalLibs() { QDir::setCurrent(testDataDir + "/external-libs"); QCOMPARE(runQbs(), 0); } void TestBlackbox::fileDependencies() { QDir::setCurrent(testDataDir + "/fileDependencies"); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling narf.cpp")); QVERIFY(m_qbsStdout.contains("compiling zort.cpp")); const QString productFileName = relativeExecutableFilePath("myapp", m_qbsStdout); QVERIFY2(regularFileExists(productFileName), qPrintable(productFileName)); // Incremental build without changes. QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("compiling")); QVERIFY(!m_qbsStdout.contains("linking")); // Incremental build with changed file dependency. WAIT_FOR_NEW_TIMESTAMP(); touch("awesomelib/awesome.h"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling narf.cpp")); QVERIFY(!m_qbsStdout.contains("compiling zort.cpp")); // Incremental build with changed 2nd level file dependency. WAIT_FOR_NEW_TIMESTAMP(); touch("awesomelib/magnificent.h"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("compiling narf.cpp")); QVERIFY(!m_qbsStdout.contains("compiling zort.cpp")); // Change the product in between to force the list of dependencies to get rescued. REPLACE_IN_FILE("fileDependencies.qbs", "//", ""); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY(!m_qbsStdout.contains("compiling narf.cpp")); QVERIFY(!m_qbsStdout.contains("compiling zort.cpp")); WAIT_FOR_NEW_TIMESTAMP(); touch("awesomelib/magnificent.h"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("[myapp] compiling narf.cpp"), m_qbsStdout.constData()); QVERIFY(!m_qbsStdout.contains("compiling zort.cpp")); } void TestBlackbox::fileTagsFilterMerging() { QDir::setCurrent(testDataDir + "/filetagsfilter-merging"); QCOMPARE(runQbs(QStringList{"-f", "filetagsfilter-merging.qbs"}), 0); const QString installedApp = defaultInstallRoot + "/myapp/binDir/" + QFileInfo(relativeExecutableFilePath("myapp", m_qbsStdout)).fileName(); QVERIFY2(QFile::exists(installedApp), qPrintable(installedApp)); const QString otherOutput = relativeProductBuildDir("myapp") + "/myapp.txt"; QVERIFY2(QFile::exists(otherOutput), qPrintable(otherOutput)); } void TestBlackbox::flatbuf() { QFETCH(QString, projectFile); QDir::setCurrent(testDataDir + "/flatbuf"); rmDirR(relativeBuildDir()); if (!prepareAndRunConan()) QSKIP("conan is not prepared, check messages above"); QbsRunParameters resolveParams( "resolve", QStringList{"-f", projectFile, "moduleProviders.conan.installDirectory:build"}); QCOMPARE(runQbs(resolveParams), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const bool withFlatbuffers = m_qbsStdout.contains("has flatbuffers: true"); const bool withoutFlatbuffers = m_qbsStdout.contains("has flatbuffers: false"); QVERIFY2(withFlatbuffers || withoutFlatbuffers, m_qbsStdout.constData()); if (withoutFlatbuffers) QSKIP("flatbuf module not present"); QbsRunParameters runParams("run"); QCOMPARE(runQbs(runParams), 0); } void TestBlackbox::flatbuf_data() { QTest::addColumn("projectFile"); // QTest::newRow("c") << QString("flat_c.qbs"); QTest::newRow("cpp") << QString("flat_cpp.qbs"); QTest::newRow("relative import") << QString("flat_relative_import.qbs"); QTest::newRow("absolute import") << QString("flat_absolute_import.qbs"); QTest::newRow("filename suffix") << QString("flat_filename_suffix.qbs"); QTest::newRow("filename extension") << QString("flat_filename_extension.qbs"); QTest::newRow("keep prefix") << QString("flat_keep_prefix.qbs"); } void TestBlackbox::freedesktop() { if (!HostOsInfo::isAnyUnixHost()) QSKIP("only applies on Unix"); if (HostOsInfo::isMacosHost()) QSKIP("Does not apply on macOS"); QDir::setCurrent(testDataDir + "/freedesktop"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("is emscripten: true")) QSKIP("Irrelevant for emscripten"); QVERIFY(m_qbsStdout.contains("is emscripten: false")); // Check desktop file QString desktopFilePath = defaultInstallRoot + "/usr/local/share/applications/myapp.desktop"; QVERIFY(QFile::exists(desktopFilePath)); QFile desktopFile(desktopFilePath); QVERIFY2(desktopFile.open(QIODevice::ReadOnly), qPrintable(desktopFile.errorString())); QByteArrayList lines = desktopFile.readAll().split('\n'); // Automatically filled line: QVERIFY(lines.contains("Exec=main")); // Name specified in `freedesktop.name` property QVERIFY(lines.contains("Name=My App")); // Overridden line: QVERIFY(lines.contains("Icon=myapp.png")); // Untouched line: QVERIFY(lines.contains("Terminal=false")); // Untouched localized line: QVERIFY(lines.contains("GenericName[fr]=Éditeur d'images")); // Untouched localized line: QVERIFY(lines.contains("Comment[fr]=Créer des images et éditer des photographies")); // Check AppStream file QVERIFY(QFile::exists(defaultInstallRoot + "/usr/local/share/metainfo/myapp.appdata.xml")); // Check hicolor icon files QVERIFY( QFile::exists(defaultInstallRoot + "/usr/local/share/icons/hicolor/48x48/apps/myapp.png")); QVERIFY(QFile::exists( defaultInstallRoot + "/usr/local/share/icons/hicolor/48x48@2/apps/myapp.png")); QVERIFY( QFile::exists(defaultInstallRoot + "/usr/local/share/icons/hicolor/64x64/apps/myapp.png")); QVERIFY(QFile::exists( defaultInstallRoot + "/usr/local/share/icons/hicolor/64x64@2/apps/myapp.png")); QVERIFY(QFile::exists( defaultInstallRoot + "/usr/local/share/icons/hicolor/64x64/mimetypes/application-format.png")); QVERIFY(QFile::exists( defaultInstallRoot + "/usr/local/share/icons/hicolor/scalable/apps/myapp.png")); } void TestBlackbox::installedTransformerOutput() { QDir::setCurrent(testDataDir + "/installed-transformer-output"); QCOMPARE(runQbs(), 0); const QString installedFilePath = defaultInstallRoot + "/textfiles/HelloWorld.txt"; QVERIFY2(QFile::exists(installedFilePath), qPrintable(installedFilePath)); } void TestBlackbox::installLocations_data() { QTest::addColumn("binDir"); QTest::addColumn("dllDir"); QTest::addColumn("libDir"); QTest::addColumn("pluginDir"); QTest::addColumn("dsymDir"); QTest::newRow("explicit values") << QString("bindir") << QString("dlldir") << QString("libdir") << QString("pluginDir") << QString("dsymDir"); QTest::newRow("default values") << QString() << QString() << QString() << QString() << QString(); } void TestBlackbox::installLocations() { QDir::setCurrent(testDataDir + "/install-locations"); QFETCH(QString, binDir); QFETCH(QString, dllDir); QFETCH(QString, libDir); QFETCH(QString, pluginDir); QFETCH(QString, dsymDir); QbsRunParameters params("resolve"); if (!binDir.isEmpty()) params.arguments.push_back("products.theapp.installDir:" + binDir); if (!dllDir.isEmpty()) params.arguments.push_back("products.thelib.installDir:" + dllDir); if (!libDir.isEmpty()) params.arguments.push_back("products.thelib.importLibInstallDir:" + libDir); if (!pluginDir.isEmpty()) params.arguments.push_back("products.theplugin.installDir:" + pluginDir); if (!dsymDir.isEmpty()) { params.arguments.push_back("products.theapp.debugInformationInstallDir:" + dsymDir); params.arguments.push_back("products.thelib.debugInformationInstallDir:" + dsymDir); params.arguments.push_back("products.theplugin.debugInformationInstallDir:" + dsymDir); } QCOMPARE(runQbs(params), 0); const bool isWindows = m_qbsStdout.contains("is windows"); const bool isDarwin = m_qbsStdout.contains("is darwin"); const bool isMac = m_qbsStdout.contains("is mac"); const bool isUnix = m_qbsStdout.contains("is unix"); const bool isMingw = m_qbsStdout.contains("is mingw"); const bool isEmscripten = m_qbsStdout.contains("is emscripten"); QVERIFY(isWindows || isDarwin || isUnix); QCOMPARE(runQbs(QbsRunParameters(QStringList("--clean-install-root"))), 0); struct BinaryInfo { QString fileName; QString installDir; QString subDir; QString absolutePath(const QString &prefix) const { return QDir::cleanPath(prefix + '/' + installDir + '/' + subDir + '/' + fileName); } }; const BinaryInfo dll = { isWindows ? "thelib.dll" : isDarwin ? "thelib" : "libthelib.so", dllDir.isEmpty() ? (isDarwin ? "/Library/Frameworks" : (isWindows ? "/bin" : "/lib")) : dllDir, isDarwin ? "thelib.framework" : "" }; const BinaryInfo dllDsym = { isWindows ? (!isMingw ? "thelib.pdb" : "thelib.dll.debug") : isDarwin ? "thelib.framework.dSYM" : "libthelib.so.debug", dsymDir.isEmpty() ? dll.installDir : dsymDir, {} }; const BinaryInfo plugin = { isWindows ? "theplugin.dll" : isDarwin ? "theplugin" : "libtheplugin.so", pluginDir.isEmpty() ? dll.installDir : pluginDir, isDarwin ? (isMac ? "theplugin.bundle/Contents/MacOS" : "theplugin.bundle") : "" }; const BinaryInfo pluginDsym = { isWindows ? (!isMingw ? "theplugin.pdb" : "theplugin.dll.debug") : isDarwin ? "theplugin.bundle.dSYM" : "libtheplugin.so.debug", dsymDir.isEmpty() ? plugin.installDir : dsymDir, {} }; const BinaryInfo app = { isWindows ? "theapp.exe" : isEmscripten ? "theapp.js" : "theapp", binDir.isEmpty() ? isDarwin ? "/Applications" : "/bin" : binDir, isDarwin ? isMac ? "theapp.app/Contents/MacOS" : "theapp.app" : ""}; const BinaryInfo appDsym = { isWindows ? (!isMingw ? "theapp.pdb" : "theapp.exe.debug") : isDarwin ? "theapp.app.dSYM" : isEmscripten ? "theapp.wasm.debug.wasm" : "theapp.debug", dsymDir.isEmpty() ? app.installDir : dsymDir, {}}; const QString installRoot = QDir::currentPath() + "/default/install-root"; const QString installPrefix = (isWindows || isEmscripten) ? QString() : "/usr/local"; const QString fullInstallPrefix = installRoot + '/' + installPrefix + '/'; const QString appFilePath = app.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(appFilePath), qPrintable(appFilePath)); const QString dllFilePath = dll.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(dllFilePath), qPrintable(dllFilePath)); if (isWindows && !isEmscripten) { const BinaryInfo lib = { "thelib.lib", libDir.isEmpty() ? "/lib" : libDir, "" }; const QString libFilePath = lib.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(libFilePath), qPrintable(libFilePath)); } const QString pluginFilePath = plugin.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(pluginFilePath), qPrintable(pluginFilePath)); const QString appDsymFilePath = appDsym.absolutePath(fullInstallPrefix); QVERIFY2(QFileInfo(appDsymFilePath).exists(), qPrintable(appDsymFilePath)); if (!isEmscripten) { // no separate debug info for emscripten libs const QString dllDsymFilePath = dllDsym.absolutePath(fullInstallPrefix); QVERIFY2(QFileInfo(dllDsymFilePath).exists(), qPrintable(dllDsymFilePath)); const QString pluginDsymFilePath = pluginDsym.absolutePath(fullInstallPrefix); QVERIFY2(QFile::exists(pluginDsymFilePath), qPrintable(pluginDsymFilePath)); } } void TestBlackbox::inputsFromDependencies() { QDir::setCurrent(testDataDir + "/inputs-from-dependencies"); QCOMPARE(runQbs(), 0); const QList output = m_qbsStdout.trimmed().split('\n'); QVERIFY2(output.contains((QDir::currentPath() + "/file1.txt").toUtf8()), m_qbsStdout.constData()); QVERIFY2(output.contains((QDir::currentPath() + "/file2.txt").toUtf8()), m_qbsStdout.constData()); QVERIFY2(output.contains((QDir::currentPath() + "/file3.txt").toUtf8()), m_qbsStdout.constData()); QVERIFY2(!output.contains((QDir::currentPath() + "/file4.txt").toUtf8()), m_qbsStdout.constData()); } void TestBlackbox::installPackage() { if (HostOsInfo::hostOs() == HostOsInfo::HostOsWindows) QSKIP("Beware of the msys tar"); QString binary = findArchiver("tar"); if (binary.isEmpty()) QSKIP("tar not found"); MacosTarHealer tarHealer; QDir::setCurrent(testDataDir + "/installpackage"); QCOMPARE(runQbs(), 0); const QString tarFilePath = relativeProductBuildDir("tar-package") + "/tar-package.tar.gz"; QVERIFY2(regularFileExists(tarFilePath), qPrintable(tarFilePath)); QProcess tarList; tarList.start(binary, QStringList() << "tf" << tarFilePath); QVERIFY2(tarList.waitForStarted(), qPrintable(tarList.errorString())); QVERIFY2(tarList.waitForFinished(), qPrintable(tarList.errorString())); const QList outputLines = tarList.readAllStandardOutput().split('\n'); QList cleanOutputLines; for (const QByteArray &line : outputLines) { const QByteArray trimmedLine = line.trimmed(); if (!trimmedLine.isEmpty()) cleanOutputLines.push_back(trimmedLine); } QCOMPARE(cleanOutputLines.size(), 3); for (const QByteArray &line : std::as_const(cleanOutputLines)) { QVERIFY2(line.contains("public_tool") || line.contains("mylib") || line.contains("lib.h"), line.constData()); } } void TestBlackbox::installRootFromProjectFile() { QDir::setCurrent(testDataDir + "/install-root-from-project-file"); const QString installRoot = QDir::currentPath() + '/' + relativeBuildDir() + "/my-install-root/"; QCOMPARE(runQbs(QbsRunParameters(QStringList("products.p.installRoot:" + installRoot))), 0); const QString installedFile = installRoot + "/install-prefix/install-dir/file.txt"; QVERIFY2(QFile::exists(installedFile), qPrintable(installedFile)); } void TestBlackbox::installable() { QDir::setCurrent(testDataDir + "/installable"); QCOMPARE(runQbs(), 0); QFile installList(relativeProductBuildDir("install-list") + "/installed-files.txt"); QVERIFY2(installList.open(QIODevice::ReadOnly), qPrintable(installList.errorString())); QCOMPARE(installList.readAll().count('\n'), 2); } void TestBlackbox::installableAsAuxiliaryInput() { QDir::setCurrent(testDataDir + "/installable-as-auxiliary-input"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QbsRunParameters("run")), 0); QVERIFY2(m_qbsStdout.contains("f-impl"), m_qbsStdout.constData()); } void TestBlackbox::installTree() { QDir::setCurrent(testDataDir + "/install-tree"); QbsRunParameters params; params.command = "install"; QCOMPARE(runQbs(params), 0); const QString installRoot = relativeBuildDir() + "/install-root/"; QVERIFY(QFile::exists(installRoot + "content/foo.txt")); QVERIFY(QFile::exists(installRoot + "content/subdir1/bar.txt")); QVERIFY(QFile::exists(installRoot + "content/subdir2/baz.txt")); } void TestBlackbox::invalidArtifactPath_data() { QTest::addColumn("baseDir"); QTest::addColumn("isValid"); QTest::newRow("inside, normal case") << "subdir" << true; QTest::newRow("inside, build dir 1") << "project.buildDirectory" << true; QTest::newRow("inside, build dir 2") << "subdir/.." << true; QTest::newRow("outside, absolute") << "/tmp" << false; QTest::newRow("outside, relative 1") << "../../" << false; QTest::newRow("outside, relative 2") << "subdir/../../.." << false; } void TestBlackbox::invalidArtifactPath() { QFETCH(QString, baseDir); QFETCH(bool, isValid); rmDirR(relativeBuildDir()); QDir::setCurrent(testDataDir + "/invalid-artifact-path"); QbsRunParameters params(QStringList("project.artifactDir:" + baseDir)); params.expectFailure = !isValid; QCOMPARE(runQbs(params) == 0, isValid); if (!isValid) QVERIFY2(m_qbsStderr.contains("outside of build directory"), m_qbsStderr.constData()); } void TestBlackbox::invalidCommandProperty_data() { QTest::addColumn("errorType"); QTest::newRow("assigning QObject") << QString("qobject"); QTest::newRow("assigning input artifact") << QString("input"); QTest::newRow("assigning other artifact") << QString("artifact"); } void TestBlackbox::invalidCommandProperty() { QDir::setCurrent(testDataDir + "/invalid-command-property"); QFETCH(QString, errorType); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.p.errorType:" + errorType))), 0); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("unsuitable"), m_qbsStderr.constData()); } void TestBlackbox::invalidLibraryNames() { QDir::setCurrent(testDataDir + "/invalid-library-names"); QFETCH(QString, index); QFETCH(bool, success); QFETCH(QStringList, diagnostics); QbsRunParameters params(QStringList("project.valueIndex:" + index)); params.expectFailure = !success; QCOMPARE(runQbs(params) == 0, success); for (const QString &diag : std::as_const(diagnostics)) QVERIFY2(m_qbsStderr.contains(diag.toLocal8Bit()), m_qbsStderr.constData()); } void TestBlackbox::invalidLibraryNames_data() { QTest::addColumn("index"); QTest::addColumn("success"); QTest::addColumn("diagnostics"); QTest::newRow("null") << "0" << false << QStringList("is null"); QTest::newRow("undefined") << "1" << false << QStringList("is undefined"); QTest::newRow("number") << "2" << false << QStringList("does not have string type"); QTest::newRow("array") << "3" << false << QStringList("does not have string type"); QTest::newRow("empty string") << "4" << true << (QStringList() << "WARNING: Removing empty string from value of property " "'cpp.dynamicLibraries' in product 'invalid-library-names'." << "WARNING: Removing empty string from value of property " "'cpp.staticLibraries' in product 'invalid-library-names'."); } void TestBlackbox::invalidExtensionInstantiation() { rmDirR(relativeBuildDir()); QDir::setCurrent(testDataDir + "/invalid-extension-instantiation"); QbsRunParameters params; params.expectFailure = true; params.arguments << (QString("products.theProduct.extension:") + QTest::currentDataTag()); QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("invalid-extension-instantiation.qbs:17") && m_qbsStderr.contains('\'' + QByteArray(QTest::currentDataTag()) + "' cannot be instantiated"), m_qbsStderr.constData()); } void TestBlackbox::invalidExtensionInstantiation_data() { QTest::addColumn("dummy"); QTest::newRow("Environment"); QTest::newRow("File"); QTest::newRow("FileInfo"); QTest::newRow("Utilities"); } void TestBlackbox::invalidInstallDir() { QDir::setCurrent(testDataDir + "/invalid-install-dir"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("outside of install root"), m_qbsStderr.constData()); } void TestBlackbox::cli() { int status; findCli(&status); QCOMPARE(status, 0); const SettingsPtr s = settings(); qbs::Profile p("qbs_autotests-cli", s.get()); if (!p.exists()) QSKIP("No suitable Common Language Infrastructure test profile"); QDir::setCurrent(testDataDir + "/cli"); QbsRunParameters params(QStringList() << "-f" << "dotnettest.qbs"); params.profile = p.name(); status = runQbs(params); if (p.value("cli.toolchainInstallPath").toString().isEmpty() && status != 0 && m_qbsStderr.contains("toolchainInstallPath")) QSKIP("cli.toolchainInstallPath not set and automatic detection failed"); QCOMPARE(status, 0); rmDirR(relativeBuildDir()); QbsRunParameters params2(QStringList() << "-f" << "fshello.qbs"); params2.profile = p.name(); QCOMPARE(runQbs(params2), 0); rmDirR(relativeBuildDir()); } void TestBlackbox::combinedSources() { QDir::setCurrent(testDataDir + "/combined-sources"); QbsRunParameters params(QStringList("modules.cpp.combineCxxSources:false")); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling main.cpp")); QVERIFY(m_qbsStdout.contains("compiling combinable.cpp")); QVERIFY(m_qbsStdout.contains("compiling uncombinable.cpp")); QVERIFY(!m_qbsStdout.contains("compiling amalgamated_theapp.cpp")); params.arguments = QStringList("modules.cpp.combineCxxSources:true"); params.command = "resolve"; QCOMPARE(runQbs(params), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("combinable.cpp"); touch("main.cpp"); touch("uncombinable.cpp"); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling main.cpp")); QVERIFY(!m_qbsStdout.contains("compiling combinable.cpp")); QVERIFY(m_qbsStdout.contains("compiling uncombinable.cpp")); QVERIFY(m_qbsStdout.contains("compiling amalgamated_theapp.cpp")); } void TestBlackbox::commandFile() { QDir::setCurrent(testDataDir + "/command-file"); QbsRunParameters params(QStringList() << "-p" << "theLib"); QCOMPARE(runQbs(params), 0); params.arguments = QStringList() << "-p" << "theApp"; QCOMPARE(runQbs(params), 0); } void TestBlackbox::compilerDefinesByLanguage() { QDir::setCurrent(testDataDir + "/compilerDefinesByLanguage"); QbsRunParameters params(QStringList { "-f", "compilerDefinesByLanguage.qbs" }); QCOMPARE(runQbs(params), 0); } void TestBlackbox::jsExtensionsFile() { QDir::setCurrent(testDataDir + "/jsextensions-file"); QFile fileToMove("tomove.txt"); QVERIFY2(fileToMove.open(QIODevice::WriteOnly), qPrintable(fileToMove.errorString())); fileToMove.close(); fileToMove.setPermissions(fileToMove.permissions() & ~(QFile::ReadUser | QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther)); QbsRunParameters params(QStringList() << "-f" << "file.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY(!QFileInfo("original.txt").exists()); QFile copy("copy.txt"); QVERIFY(copy.exists()); QVERIFY(copy.open(QIODevice::ReadOnly)); const QList lines = copy.readAll().trimmed().split('\n'); QCOMPARE(lines.size(), 2); QCOMPARE(lines.at(0).trimmed().constData(), "false"); QCOMPARE(lines.at(1).trimmed().constData(), "true"); } void TestBlackbox::jsExtensionsFileInfo() { QDir::setCurrent(testDataDir + "/jsextensions-fileinfo"); QbsRunParameters params(QStringList() << "-f" << "fileinfo.qbs"); QCOMPARE(runQbs(params), 0); QFile output("output.txt"); QVERIFY(output.exists()); QVERIFY(output.open(QIODevice::ReadOnly)); const QList lines = output.readAll().trimmed().split('\n'); QCOMPARE(lines.size(), 28); int i = 0; QCOMPARE(lines.at(i++).trimmed().constData(), "blubb"); QCOMPARE(lines.at(i++).trimmed().constData(), qUtf8Printable( QFileInfo(QDir::currentPath()).canonicalFilePath())); QCOMPARE(lines.at(i++).trimmed().constData(), "/usr/bin"); QCOMPARE(lines.at(i++).trimmed().constData(), "blubb.tar"); QCOMPARE(lines.at(i++).trimmed().constData(), "blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp/blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "c:/tmp/blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "true"); QCOMPARE(lines.at(i++).trimmed().constData(), HostOsInfo::isWindowsHost() ? "true" : "false"); QCOMPARE(lines.at(i++).trimmed().constData(), "false"); QCOMPARE(lines.at(i++).trimmed().constData(), "true"); QCOMPARE(lines.at(i++).trimmed().constData(), "false"); QCOMPARE(lines.at(i++).trimmed().constData(), "false"); QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp/blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp/blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp"); QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp"); QCOMPARE(lines.at(i++).trimmed().constData(), "/"); QCOMPARE(lines.at(i++).trimmed().constData(), HostOsInfo::isWindowsHost() ? "d:/" : "d:"); QCOMPARE(lines.at(i++).trimmed().constData(), "d:"); QCOMPARE(lines.at(i++).trimmed().constData(), "d:/"); QCOMPARE(lines.at(i++).trimmed().constData(), "blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "tmp/blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "../blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "\\tmp\\blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), "c:\\tmp\\blubb.tar.gz"); QCOMPARE(lines.at(i++).trimmed().constData(), qUtf8Printable(HostOsInfo::pathListSeparator())); QCOMPARE(lines.at(i++).trimmed().constData(), qUtf8Printable(HostOsInfo::pathSeparator())); } void TestBlackbox::jsExtensionsHost() { QDir::setCurrent(testDataDir + "//jsextensions-host"); QbsRunParameters params(QStringList { "-f", "host.qbs" }); QCOMPARE(runQbs(params), 0); QFile output("output.txt"); QVERIFY(output.exists()); QVERIFY(output.open(QIODevice::ReadOnly)); const QList lines = output.readAll().trimmed().split('\n'); QCOMPARE(lines.size(), 10); int i = 0; QCOMPARE(lines.at(i++).trimmed().constData(), "architecture: " + HostOsInfo::hostOSArchitecture()); QStringList list; for (const auto &s : HostOsInfo::canonicalOSIdentifiers(HostOsInfo::hostOSIdentifier())) list.push_back(s); QCOMPARE(lines.at(i++).trimmed().constData(), "os: " + list.join(',')); QCOMPARE(lines.at(i++).trimmed().constData(), "platform: " + HostOsInfo::hostOSIdentifier()); QCOMPARE(lines.at(i++).trimmed().constData(), "osVersion: " + HostOsInfo::hostOsVersion().toString()); QCOMPARE(lines.at(i++).trimmed().constData(), "osBuildVersion: " + (HostOsInfo::hostOsBuildVersion().isNull() ? "undefined" : HostOsInfo::hostOsBuildVersion())); QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionParts: " + HostOsInfo::hostOsVersion().toString(',')); QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionMajor: " + QString::number( HostOsInfo::hostOsVersion().majorVersion())); QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionMinor: " + QString::number( HostOsInfo::hostOsVersion().minorVersion())); QCOMPARE(lines.at(i++).trimmed().constData(), "osVersionPatch: " + QString::number( HostOsInfo::hostOsVersion().patchLevel())); QString nullDevice = HostOsInfo::isWindowsHost() ? QStringLiteral("NUL") : QStringLiteral("/dev/null"); QCOMPARE(lines.at(i++).trimmed().constData(), "nullDevice: " + nullDevice); } void TestBlackbox::jsExtensionsProcess() { QDir::setCurrent(testDataDir + "/jsextensions-process"); QCOMPARE(runQbs({"resolve", {"-f", "process.qbs"}}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params(QStringList() << "-f" << "process.qbs"); QCOMPARE(runQbs(params), 0); QFile output("output.txt"); QVERIFY(output.exists()); QVERIFY(output.open(QIODevice::ReadOnly)); const QList lines = output.readAll().trimmed().split('\n'); QCOMPARE(lines.size(), 9); QCOMPARE(lines.at(0).trimmed().constData(), "0"); QVERIFY(lines.at(1).startsWith("qbs ")); QCOMPARE(lines.at(2).trimmed().constData(), "true"); QCOMPARE(lines.at(3).trimmed().constData(), "true"); QCOMPARE(lines.at(4).trimmed().constData(), "0"); QVERIFY(lines.at(5).startsWith("qbs ")); QCOMPARE(lines.at(6).trimmed().constData(), "false"); QCOMPARE(lines.at(7).trimmed().constData(), "should be"); QCOMPARE(lines.at(8).trimmed().constData(), "123"); } void TestBlackbox::jsExtensionsPropertyList() { if (!HostOsInfo::isMacosHost()) QSKIP("temporarily only applies on macOS"); QDir::setCurrent(testDataDir + "/jsextensions-propertylist"); QbsRunParameters params(QStringList() << "-nf" << "propertylist.qbs"); QCOMPARE(runQbs(params), 0); QFile file1("test.json"); QVERIFY(file1.exists()); QVERIFY(file1.open(QIODevice::ReadOnly)); QFile file2("test.xml"); QVERIFY(file2.exists()); QVERIFY(file2.open(QIODevice::ReadOnly)); QFile file3("test2.json"); QVERIFY(file3.exists()); QVERIFY(file3.open(QIODevice::ReadOnly)); QByteArray file1Contents = file1.readAll(); QCOMPARE(file3.readAll(), file1Contents); //QCOMPARE(file1Contents, file2.readAll()); // keys don't have guaranteed order QJsonParseError err1, err2; QCOMPARE(QJsonDocument::fromJson(file1Contents, &err1), QJsonDocument::fromJson(file2.readAll(), &err2)); QVERIFY(err1.error == QJsonParseError::NoError && err2.error == QJsonParseError::NoError); QFile file4("test.openstep.plist"); QVERIFY(file4.exists()); QFile file5("test3.json"); QVERIFY(file5.exists()); QVERIFY(file5.open(QIODevice::ReadOnly)); QVERIFY(file1Contents != file5.readAll()); } void TestBlackbox::jsExtensionsTemporaryDir() { QDir::setCurrent(testDataDir + "/jsextensions-temporarydir"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); } void TestBlackbox::jsExtensionsTextFile() { QDir::setCurrent(testDataDir + "/jsextensions-textfile"); QbsRunParameters params(QStringList() << "-f" << "textfile.qbs"); QCOMPARE(runQbs(params), 0); QFile file1("file1.txt"); QVERIFY(file1.exists()); QVERIFY(file1.open(QIODevice::ReadOnly)); QCOMPARE(file1.size(), qint64(0)); QFile file2("file2.txt"); QVERIFY(file2.exists()); QVERIFY(file2.open(QIODevice::ReadOnly)); const QList lines = file2.readAll().trimmed().split('\n'); QCOMPARE(lines.size(), 6); QCOMPARE(lines.at(0).trimmed().constData(), "false"); QCOMPARE(lines.at(1).trimmed().constData(), "First line."); QCOMPARE(lines.at(2).trimmed().constData(), "Second line."); QCOMPARE(lines.at(3).trimmed().constData(), "Third line."); QCOMPARE(lines.at(4).trimmed().constData(), qPrintable(QDir::currentPath() + "/file1.txt")); QCOMPARE(lines.at(5).trimmed().constData(), "true"); } void TestBlackbox::jsExtensionsBinaryFile() { QDir::setCurrent(testDataDir + "/jsextensions-binaryfile"); QbsRunParameters params(QStringList() << "-f" << "binaryfile.qbs"); QCOMPARE(runQbs(params), 0); QFile source("source.dat"); QVERIFY(source.exists()); QVERIFY(source.open(QIODevice::ReadOnly)); QCOMPARE(source.size(), qint64(0)); QFile destination("destination.dat"); QVERIFY(destination.exists()); QVERIFY(destination.open(QIODevice::ReadOnly)); const QByteArray data = destination.readAll(); QCOMPARE(data.size(), 8); QCOMPARE(data.at(0), char(0x00)); QCOMPARE(data.at(1), char(0x01)); QCOMPARE(data.at(2), char(0x02)); QCOMPARE(data.at(3), char(0x03)); QCOMPARE(data.at(4), char(0x04)); QCOMPARE(data.at(5), char(0x05)); QCOMPARE(data.at(6), char(0x06)); QCOMPARE(data.at(7), char(0xFF)); QFile destination2("destination2.dat"); QVERIFY(destination2.exists()); QVERIFY(destination2.open(QIODevice::ReadOnly)); QCOMPARE(destination2.readAll(), data); } void TestBlackbox::lastModuleCandidateBroken() { QDir::setCurrent(testDataDir + "/last-module-candidate-broken"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Dependency 'Foo' not found for product " "'last-module-candidate-broken'"), m_qbsStderr); } void TestBlackbox::ld() { QDir::setCurrent(testDataDir + "/ld"); QCOMPARE(runQbs(), 0); } void TestBlackbox::symbolLinkMode() { if (!HostOsInfo::isAnyUnixHost()) QSKIP("only applies on Unix"); QDir::setCurrent(testDataDir + "/symbolLinkMode"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; const QStringList commonArgs{"-p", "driver", "--setup-run-env-config", "ignore-lib-dependencies", "qbs.installPrefix:''"}; rmDirR(relativeBuildDir()); params.arguments = QStringList() << commonArgs << "project.shouldInstallLibrary:true"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("somefunction existed and it returned 42"), m_qbsStdout.constData()); rmDirR(relativeBuildDir()); params.arguments = QStringList() << commonArgs << "project.shouldInstallLibrary:false"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("somefunction did not exist"), m_qbsStdout.constData()); rmDirR(relativeBuildDir()); params.arguments = QStringList() << commonArgs << "project.lazy:false"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("Lib was loaded!\nmeow\n"), m_qbsStdout.constData()); if (HostOsInfo::isMacosHost()) { rmDirR(relativeBuildDir()); params.arguments = QStringList() << commonArgs << "project.lazy:true"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("meow\n") && m_qbsStdout.contains("Lib was loaded!\n"), m_qbsStdout.constData()); } } void TestBlackbox::linkerMode() { if (!HostOsInfo::isAnyUnixHost()) QSKIP("only applies on Unix"); QDir::setCurrent(testDataDir + "/linkerMode"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("qbs.installPrefix:''"))), 0); if (m_qbsStdout.contains("is emscripten: true")) QSKIP("not applicable for emscripten"); QVERIFY(m_qbsStdout.contains("is emscripten: false")); QCOMPARE(runQbs(), 0); auto testCondition = [&](const QString &lang, const std::function &condition) { if ((lang == "Objective-C" || lang == "Objective-C++") && HostOsInfo::hostOs() != HostOsInfo::HostOsMacos) return; const QString binary = defaultInstallRoot + "/LinkedProduct-" + lang; QProcess deptool; if (HostOsInfo::hostOs() == HostOsInfo::HostOsMacos) deptool.start("otool", QStringList() << "-L" << binary); else deptool.start("readelf", QStringList() << "-a" << binary); QVERIFY(deptool.waitForStarted()); QVERIFY(deptool.waitForFinished()); QByteArray deptoolOutput = deptool.readAllStandardOutput(); if (HostOsInfo::hostOs() != HostOsInfo::HostOsMacos) { QList lines = deptoolOutput.split('\n'); int sz = lines.size(); for (int i = 0; i < sz; ++i) { if (!lines.at(i).contains("NEEDED")) { lines.removeAt(i--); sz--; } } deptoolOutput = lines.join('\n'); } QCOMPARE(deptool.exitCode(), 0); QVERIFY2(condition(deptoolOutput), deptoolOutput.constData()); }; const QStringList nocpplangs = QStringList() << "Assembly" << "C" << "Objective-C"; for (const QString &lang : nocpplangs) testCondition(lang, [](const QByteArray &lddOutput) { return !lddOutput.contains("c++"); }); const QStringList cpplangs = QStringList() << "C++" << "Objective-C++"; for (const QString &lang : cpplangs) testCondition(lang, [](const QByteArray &lddOutput) { return lddOutput.contains("c++"); }); const QStringList objclangs = QStringList() << "Objective-C" << "Objective-C++"; for (const QString &lang : objclangs) testCondition(lang, [](const QByteArray &lddOutput) { return lddOutput.contains("objc"); }); } void TestBlackbox::linkerVariant_data() { QTest::addColumn("theType"); QTest::newRow("default") << QString(); QTest::newRow("bfd") << QString("bfd"); QTest::newRow("gold") << QString("gold"); QTest::newRow("mold") << QString("mold"); } void TestBlackbox::linkerVariant() { QDir::setCurrent(testDataDir + "/linker-variant"); QFETCH(QString, theType); QStringList resolveArgs("--force-probe-execution"); if (!theType.isEmpty()) resolveArgs << ("products.p.linkerVariant:" + theType); QCOMPARE(runQbs(QbsRunParameters("resolve", resolveArgs)), 0); const bool isGcc = m_qbsStdout.contains("is GCC: true"); const bool isNotGcc = m_qbsStdout.contains("is GCC: false"); QVERIFY2(isGcc != isNotGcc, m_qbsStdout.constData()); QbsRunParameters buildParams("build", QStringList{"--command-echo-mode", "command-line"}); buildParams.expectFailure = true; runQbs(buildParams); if (isGcc && !theType.isEmpty()) QCOMPARE(m_qbsStdout.count("-fuse-ld=" + theType.toLocal8Bit()), 1); else QVERIFY2(!m_qbsStdout.contains("-fuse-ld"), m_qbsStdout.constData()); } void TestBlackbox::lexyacc() { if (!lexYaccExist()) QSKIP("lex or yacc not present"); QDir::setCurrent(testDataDir + "/lexyacc/one-grammar"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const QString parserBinary = relativeExecutableFilePath("one-grammar", m_qbsStdout); QCOMPARE(runQbs(), 0); QProcess p; const QByteArray magicString = "add to PATH: "; const int magicStringIndex = m_qbsStdout.indexOf(magicString); if (magicStringIndex != -1) { const int newLineIndex = m_qbsStdout.indexOf('\n', magicStringIndex); QVERIFY(newLineIndex != -1); const int dirIndex = magicStringIndex + magicString.length(); const QString dir = QString::fromLocal8Bit(m_qbsStdout.mid(dirIndex, newLineIndex - dirIndex)); QProcessEnvironment env; env.insert("PATH", dir); p.setProcessEnvironment(env); } p.start(parserBinary, QStringList()); QVERIFY2(p.waitForStarted(), qPrintable(p.errorString())); p.write("a && b || c && !d"); p.closeWriteChannel(); QVERIFY2(p.waitForFinished(), qPrintable(p.errorString())); QVERIFY2(p.exitCode() == 0, p.readAllStandardError().constData()); const QByteArray parserOutput = p.readAllStandardOutput(); QVERIFY2(parserOutput.contains("OR AND a b AND c NOT d"), parserOutput.constData()); QDir::setCurrent(testDataDir + "/lexyacc/two-grammars"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); params.expectFailure = false; params.command = "resolve"; params.arguments << (QStringList() << "modules.lex_yacc.uniqueSymbolPrefix:true"); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStderr.contains("whatever"), m_qbsStderr.constData()); params.arguments << "modules.lex_yacc.enableCompilerWarnings:true"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); const QByteArray outputToCheck = m_qbsStdout + m_qbsStderr; QVERIFY2(outputToCheck.contains("whatever"), outputToCheck.constData()); } void TestBlackbox::lexyaccOutputs() { if (!lexYaccExist()) QSKIP("lex or yacc not present"); QFETCH(QString, lexOutputFilePath); QFETCH(QString, yaccOutputFilePath); QbsRunParameters params; if (!lexOutputFilePath.isEmpty()) params.arguments << "modules.lex_yacc.lexOutputFilePath:" + lexOutputFilePath; if (!yaccOutputFilePath.isEmpty()) params.arguments << "modules.lex_yacc.yaccOutputFilePath:" + yaccOutputFilePath; #define VERIFY_COMPILATION(file) \ if (!file.isEmpty()) { \ QByteArray expected = "compiling " + file.toUtf8(); \ if (!m_qbsStdout.contains(expected)) { \ qDebug() << "Expected output:" << expected; \ qDebug() << "Actual output:" << m_qbsStdout; \ QFAIL("Expected stdout content missing."); \ } \ } const auto version = bisonVersion(); if (version >= qbs::Version(2, 6)) { // prefix only supported starting from bison 2.6 QVERIFY(QDir::setCurrent(testDataDir + "/lexyacc/lex_prefix")); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); VERIFY_COMPILATION(yaccOutputFilePath); } QVERIFY(QDir::setCurrent(testDataDir + "/lexyacc/lex_outfile")); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); VERIFY_COMPILATION(yaccOutputFilePath); if (version >= qbs::Version(2, 4)) { // output syntax was changed in bison 2.4 QVERIFY(QDir::setCurrent(testDataDir + "/lexyacc/yacc_output")); rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); VERIFY_COMPILATION(lexOutputFilePath); } #undef VERIFY_COMPILATION } void TestBlackbox::lexyaccOutputs_data() { QTest::addColumn("lexOutputFilePath"); QTest::addColumn("yaccOutputFilePath"); QTest::newRow("none") << QString() << QString(); QTest::newRow("lexOutputFilePath") << QString{"lex_luthor.cpp"} << QString(); QTest::newRow("yaccOutputFilePath") << QString() << QString{"shaven_yak.cpp"}; } void TestBlackbox::linkerLibraryDuplicates() { QDir::setCurrent(testDataDir + "/linker-library-duplicates"); rmDirR(relativeBuildDir()); QFETCH(QString, removeDuplicateLibraries); QStringList runParams; if (!removeDuplicateLibraries.isEmpty()) runParams.append(removeDuplicateLibraries); QCOMPARE(runQbs(QbsRunParameters("resolve", runParams)), 0); const bool isGcc = m_qbsStdout.contains("is gcc: true"); const bool isNotGcc = m_qbsStdout.contains("is gcc: false"); if (isNotGcc) QSKIP("linkerLibraryDuplicates test only applies to GCC toolchain"); QVERIFY(isGcc); QCOMPARE(runQbs(QStringList { "--command-echo-mode", "command-line" }), 0); const QByteArrayList output = m_qbsStdout.split('\n'); QByteArray linkLine; for (const QByteArray &line : output) { if (line.contains("main.cpp.o")) linkLine = line; } QVERIFY(!linkLine.isEmpty()); /* Now check the the libraries appear just once. In order to avoid dealing * with the different file extensions used in different platforms, we check * only for the library base name. But we must also take into account that * the build directories of each library will contain the library base name, * so we now exclude them. */ QByteArrayList elementsWithoutPath; for (const QByteArray &element: linkLine.split(' ')) { if (element.indexOf('/') < 0) elementsWithoutPath.append(element); } QByteArray pathLessLinkLine = elementsWithoutPath.join(' '); typedef QMap ObjectCount; QFETCH(ObjectCount, expectedObjectCount); for (auto i = expectedObjectCount.begin(); i != expectedObjectCount.end(); i++) { QCOMPARE(pathLessLinkLine.count(i.key()), i.value()); } } void TestBlackbox::linkerLibraryDuplicates_data() { typedef QMap ObjectCount; QTest::addColumn("removeDuplicateLibraries"); QTest::addColumn("expectedObjectCount"); QTest::newRow("default") << QString() << ObjectCount { { "lib1", 1 }, { "lib2", 1 }, { "lib3", 1 }, }; QTest::newRow("enabled") << "modules.cpp.removeDuplicateLibraries:true" << ObjectCount { { "lib1", 1 }, { "lib2", 1 }, { "lib3", 1 }, }; QTest::newRow("disabled") << "modules.cpp.removeDuplicateLibraries:false" << ObjectCount { { "lib1", 3 }, { "lib2", 2 }, { "lib3", 1 }, }; } void TestBlackbox::linkerScripts() { const QString sourceDir = QDir::cleanPath(testDataDir + "/linkerscripts"); QbsRunParameters runParams("resolve", {"qbs.installRoot:" + QDir::currentPath()}); runParams.buildDirectory = sourceDir + "/build"; runParams.workingDir = sourceDir; QCOMPARE(runQbs(runParams), 0); const bool isGcc = m_qbsStdout.contains("is Linux gcc: true"); const bool isNotGcc = m_qbsStdout.contains("is Linux gcc: false"); if (isNotGcc) QSKIP("linker script test only applies to Linux"); QVERIFY(isGcc); runParams.command = "build"; QCOMPARE(runQbs(runParams), 0); const QString output = QString::fromLocal8Bit(m_qbsStderr); const QRegularExpression pattern(QRegularExpression::anchoredPattern(".*---(.*)---.*"), QRegularExpression::DotMatchesEverythingOption); const QRegularExpressionMatch match = pattern.match(output); QVERIFY2(match.hasMatch(), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); const QString nmPath = match.captured(1); if (!QFile::exists(nmPath)) QSKIP("Cannot check for symbol presence: No nm found."); const auto verifySymbols = [nmPath](const QByteArrayList& symbols) -> bool { QProcess nm; nm.start(nmPath, QStringList(QDir::currentPath() + "/liblinkerscripts.so")); if (!nm.waitForStarted()) { qDebug() << "Wait for process started failed."; return false; } if (!nm.waitForFinished()) { qDebug() << "Wait for process finished failed."; return false; } if (nm.exitCode() != 0) { qDebug() << "nm returned exit code " << nm.exitCode(); return false; } const QByteArray nmOutput = nm.readAllStandardOutput(); for (const QByteArray& symbol : symbols) { if (!nmOutput.contains(symbol)) { qDebug() << "Expected symbol" << symbol << "not found in" << nmOutput.constData(); return false; } } return true; }; QVERIFY(verifySymbols({"TEST_SYMBOL1", "TEST_SYMBOL2", "TEST_SYMBOL_FROM_INCLUDE", "TEST_SYMBOL_FROM_DIRECTORY", "TEST_SYMBOL_FROM_RECURSIVE"})); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(sourceDir + "/linkerscript_to_include", "TEST_SYMBOL_FROM_INCLUDE = 1;", "TEST_SYMBOL_FROM_INCLUDE_MODIFIED = 1;\n"); QCOMPARE(runQbs(runParams), 0); QVERIFY2(m_qbsStdout.contains("linking liblinkerscripts.so"), "No linking after modifying included file"); QVERIFY(verifySymbols({"TEST_SYMBOL1", "TEST_SYMBOL2", "TEST_SYMBOL_FROM_INCLUDE_MODIFIED", "TEST_SYMBOL_FROM_DIRECTORY", "TEST_SYMBOL_FROM_RECURSIVE"})); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(sourceDir + "/scripts/linkerscript_in_directory", "TEST_SYMBOL_FROM_DIRECTORY = 1;\n", "TEST_SYMBOL_FROM_DIRECTORY_MODIFIED = 1;\n"); QCOMPARE(runQbs(runParams), 0); QVERIFY2(m_qbsStdout.contains("linking liblinkerscripts.so"), "No linking after modifying file in directory"); QVERIFY(verifySymbols({"TEST_SYMBOL1", "TEST_SYMBOL2", "TEST_SYMBOL_FROM_INCLUDE_MODIFIED", "TEST_SYMBOL_FROM_DIRECTORY_MODIFIED", "TEST_SYMBOL_FROM_RECURSIVE"})); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(sourceDir + "/linkerscript_recursive", "TEST_SYMBOL_FROM_RECURSIVE = 1;\n", "TEST_SYMBOL_FROM_RECURSIVE_MODIFIED = 1;\n"); QCOMPARE(runQbs(runParams), 0); QVERIFY2(m_qbsStdout.contains("linking liblinkerscripts.so"), "No linking after modifying recursive file"); QVERIFY(verifySymbols({"TEST_SYMBOL1", "TEST_SYMBOL2", "TEST_SYMBOL_FROM_INCLUDE_MODIFIED", "TEST_SYMBOL_FROM_DIRECTORY_MODIFIED", "TEST_SYMBOL_FROM_RECURSIVE_MODIFIED"})); } void TestBlackbox::linkerModuleDefinition() { QDir::setCurrent(testDataDir + "/linker-module-definition"); QCOMPARE(runQbs({"build"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs({"run"}), 0); const auto verifyOutput = [this](const QByteArrayList &symbols) { for (const QByteArray &symbol : symbols) { if (!m_qbsStdout.contains(symbol)) { qDebug() << "Expected symbol" << symbol << "not found in" << m_qbsStdout; return false; } } return true; }; QVERIFY(verifyOutput({"foo", "bar"})); } void TestBlackbox::listProducts() { QDir::setCurrent(testDataDir + "/list-products"); QCOMPARE(runQbs(QbsRunParameters("list-products")), 0); m_qbsStdout.replace("\r\n", "\n"); QVERIFY2(m_qbsStdout.contains( "a\n" "b {\"architecture\":\"mips\",\"buildVariant\":\"debug\"}\n" "b {\"architecture\":\"mips\",\"buildVariant\":\"release\"}\n" "b {\"architecture\":\"vax\",\"buildVariant\":\"debug\"}\n" "b {\"architecture\":\"vax\",\"buildVariant\":\"release\"}\n" "c\n"), m_qbsStdout.constData()); } void TestBlackbox::listPropertiesWithOuter() { QDir::setCurrent(testDataDir + "/list-properties-with-outer"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("listProp: [\"product\",\"higher\",\"group\"]"), m_qbsStdout.constData()); } void TestBlackbox::listPropertyOrder() { QDir::setCurrent(testDataDir + "/list-property-order"); const QbsRunParameters params(QStringList() << "-q"); QCOMPARE(runQbs(params), 0); const QByteArray firstOutput = m_qbsStderr; QVERIFY(firstOutput.contains("listProp = [\"product\",\"higher3\",\"higher2\",\"higher1\",\"lower\"]")); for (int i = 0; i < 25; ++i) { rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); if (m_qbsStderr != firstOutput) break; } QCOMPARE(m_qbsStderr.constData(), firstOutput.constData()); } void TestBlackbox::require() { QDir::setCurrent(testDataDir + "/require"); QCOMPARE(runQbs(), 0); } void TestBlackbox::rescueTransformerData() { QDir::setCurrent(testDataDir + "/rescue-transformer-data"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp") && m_qbsStdout.contains("m.p: undefined"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch("main.cpp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp") && !m_qbsStdout.contains("m.p: "), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.m.p:true"))), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp") && m_qbsStdout.contains("m.p: true"), m_qbsStdout.constData()); } void TestBlackbox::multipleChanges() { QDir::setCurrent(testDataDir + "/multiple-changes"); QCOMPARE(runQbs(), 0); QFile newFile("test.blubb"); QVERIFY(newFile.open(QIODevice::WriteOnly)); newFile.close(); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList() << "project.prop:true")), 0); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("prop: true")); } void TestBlackbox::multipleConfigurations() { QDir::setCurrent(testDataDir + "/multiple-configurations"); QbsRunParameters params(QStringList{"config:x", "config:y", "config:z"}); params.profile.clear(); struct DefaultProfileSwitcher { DefaultProfileSwitcher() { const SettingsPtr s = settings(); oldDefaultProfile = s->defaultProfile(); s->setValue("defaultProfile", profileName()); s->sync(); } ~DefaultProfileSwitcher() { const SettingsPtr s = settings(); s->setValue("defaultProfile", oldDefaultProfile); s->sync(); } QVariant oldDefaultProfile; }; DefaultProfileSwitcher dps; QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStdout.count("compiling lib.cpp"), 3); QCOMPARE(m_qbsStdout.count("compiling file.cpp"), 3); QCOMPARE(m_qbsStdout.count("compiling main.cpp"), 3); } void TestBlackbox::multiplexedTool() { QDir::setCurrent(testDataDir + "/multiplexed-tool"); QCOMPARE(runQbs(QStringLiteral("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("creating tool.out"), 4); } void TestBlackbox::nestedGroups() { QDir::setCurrent(testDataDir + "/nested-groups"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(relativeExecutableFilePath("nested-groups", m_qbsStdout))); } void TestBlackbox::nestedProperties() { QDir::setCurrent(testDataDir + "/nested-properties"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("value in higherlevel"), m_qbsStdout.constData()); } void TestBlackbox::newOutputArtifact() { QDir::setCurrent(testDataDir + "/new-output-artifact"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(relativeBuildDir() + "/install-root/output_98.out")); const QString the100thArtifact = relativeBuildDir() + "/install-root/output_99.out"; QVERIFY(!regularFileExists(the100thArtifact)); QbsRunParameters params("resolve", QStringList() << "products.theProduct.artifactCount:100"); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(the100thArtifact)); } void TestBlackbox::noExportedSymbols_data() { QTest::addColumn("link"); QTest::addColumn("dryRun"); QTest::newRow("link") << true << false; QTest::newRow("link (dry run)") << true << true; QTest::newRow("do not link") << false << false; } void TestBlackbox::noExportedSymbols() { QDir::setCurrent(testDataDir + "/no-exported-symbols"); QFETCH(bool, link); QFETCH(bool, dryRun); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList{"--force-probe-execution", QString("products.the_app.link:") + (link ? "true" : "false")})), 0); const bool isMsvc = m_qbsStdout.contains("compiler is MSVC"); const bool isNotMsvc = m_qbsStdout.contains("compiler is not MSVC"); QVERIFY2(isMsvc || isNotMsvc, m_qbsStdout.constData()); if (isNotMsvc) QSKIP("Test applies with MSVC only"); QbsRunParameters buildParams; if (dryRun) buildParams.arguments << "--dry-run"; buildParams.expectFailure = link && !dryRun; QCOMPARE(runQbs(buildParams) == 0, !buildParams.expectFailure); QVERIFY2(m_qbsStderr.contains("This typically happens when a DLL does not export " "any symbols.") == buildParams.expectFailure, m_qbsStderr.constData()); } void TestBlackbox::noProfile() { QDir::setCurrent(testDataDir + "/no-profile"); QbsRunParameters params; params.profile = "none"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("profile: none"), m_qbsStdout.constData()); } void TestBlackbox::noSuchProfile() { QDir::setCurrent(testDataDir + "/no-such-profile"); QbsRunParameters params(QStringList("products.theProduct.p:1")); params.profile = "jibbetnich"; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Profile 'jibbetnich' does not exist"), m_qbsStderr.constData()); } void TestBlackbox::nonBrokenFilesInBrokenProduct() { QDir::setCurrent(testDataDir + "/non-broken-files-in-broken-product"); QbsRunParameters params(QStringList() << "-k"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStdout.contains("fine.cpp")); QVERIFY(runQbs(params) != 0); QVERIFY(!m_qbsStdout.contains("fine.cpp")); // The non-broken file must not be recompiled. } void TestBlackbox::nonDefaultProduct() { QDir::setCurrent(testDataDir + "/non-default-product"); QCOMPARE(runQbs(), 0); const QString defaultAppExe = relativeExecutableFilePath("default app", m_qbsStdout); const QString nonDefaultAppExe = relativeExecutableFilePath("non-default app", m_qbsStdout); QVERIFY2(QFile::exists(defaultAppExe), qPrintable(defaultAppExe)); QVERIFY2(!QFile::exists(nonDefaultAppExe), qPrintable(nonDefaultAppExe)); QCOMPARE(runQbs(QbsRunParameters(QStringList() << "--all-products")), 0); QVERIFY2(QFile::exists(nonDefaultAppExe), qPrintable(nonDefaultAppExe)); } void TestBlackbox::notAlwaysUpdated() { QDir::setCurrent(testDataDir + "/not-always-updated"); QCOMPARE(runQbs(), 0); QCOMPARE(runQbs(), 0); } static void switchProfileContents(qbs::Profile &p, qbs::Settings *s, bool on) { const QString scalarKey = "leaf.scalarProp"; const QString listKey = "leaf.listProp"; if (on) { p.setValue(scalarKey, "profile"); p.setValue(listKey, QStringList() << "profile"); } else { p.remove(scalarKey); p.remove(listKey); } s->sync(); } static void switchFileContents(QFile &f, bool on) { f.seek(0); QByteArray contents = f.readAll(); f.resize(0); if (on) contents.replace("// leaf.", "leaf."); else contents.replace("leaf.", "// leaf."); f.write(contents); f.flush(); } void TestBlackbox::propertyPrecedence() { QDir::setCurrent(testDataDir + "/property-precedence"); const SettingsPtr s = settings(); qbs::Internal::TemporaryProfile profile("qbs_autotests_propPrecedence", s.get()); profile.p.setValue("qbs.architecture", "x86"); // Profiles must not be empty... s->sync(); const QStringList args = QStringList() << "-f" << "property-precedence.qbs"; QbsRunParameters params(args); params.profile = profile.p.name(); QbsRunParameters resolveParams = params; resolveParams.command = "resolve"; // Case 1: [cmdline=0,prod=0,export=0,nonleaf=0,profile=0] QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QVERIFY2(m_qbsStdout.contains("scalar prop: leaf\n") && m_qbsStdout.contains("list prop: [\"leaf\"]\n"), m_qbsStdout.constData()); params.arguments.clear(); // Case 2: [cmdline=0,prod=0,export=0,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: profile\n") && m_qbsStdout.contains("list prop: [\"profile\"]\n"), m_qbsStdout.constData()); // Case 3: [cmdline=0,prod=0,export=0,nonleaf=1,profile=0] QFile nonleafFile("modules/nonleaf/nonleaf.qbs"); QVERIFY2(nonleafFile.open(QIODevice::ReadWrite), qPrintable(nonleafFile.errorString())); switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n") && m_qbsStdout.contains("list prop: [\"nonleaf\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 4: [cmdline=0,prod=0,export=0,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n") && m_qbsStdout.contains("list prop: [\"nonleaf\",\"profile\"]\n"), m_qbsStdout.constData()); // Case 5: [cmdline=0,prod=0,export=1,nonleaf=0,profile=0] QFile depFile("dep.qbs"); QVERIFY2(depFile.open(QIODevice::ReadWrite), qPrintable(depFile.errorString())); switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 6: [cmdline=0,prod=0,export=1,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"profile\"]\n"), m_qbsStdout.constData()); // Case 7: [cmdline=0,prod=0,export=1,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 8: [cmdline=0,prod=0,export=1,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: export\n") && m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"profile\"]\n"), m_qbsStdout.constData()); // Case 9: [cmdline=0,prod=1,export=0,nonleaf=0,profile=0] QFile productFile("property-precedence.qbs"); QVERIFY2(productFile.open(QIODevice::ReadWrite), qPrintable(productFile.errorString())); switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, false); switchFileContents(productFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 10: [cmdline=0,prod=1,export=0,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"profile\"]\n"), m_qbsStdout.constData()); // Case 11: [cmdline=0,prod=1,export=0,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 12: [cmdline=0,prod=1,export=0,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"profile\"]\n"), m_qbsStdout.constData()); // Case 13: [cmdline=0,prod=1,export=1,nonleaf=0,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 14: [cmdline=0,prod=1,export=1,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"profile\"]\n"), m_qbsStdout.constData()); // Case 15: [cmdline=0,prod=1,export=1,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"leaf\"]\n"), m_qbsStdout.constData()); // Case 16: [cmdline=0,prod=1,export=1,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: product\n") && m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"profile\"]\n"), m_qbsStdout.constData()); // Command line properties wipe everything, including lists. // Case 17: [cmdline=1,prod=0,export=0,nonleaf=0,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, false); switchFileContents(productFile, false); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 18: [cmdline=1,prod=0,export=0,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 19: [cmdline=1,prod=0,export=0,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 20: [cmdline=1,prod=0,export=0,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 21: [cmdline=1,prod=0,export=1,nonleaf=0,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 22: [cmdline=1,prod=0,export=1,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 23: [cmdline=1,prod=0,export=1,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 24: [cmdline=1,prod=0,export=1,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 25: [cmdline=1,prod=1,export=0,nonleaf=0,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, false); switchFileContents(productFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 26: [cmdline=1,prod=1,export=0,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 27: [cmdline=1,prod=1,export=0,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 28: [cmdline=1,prod=1,export=0,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 29: [cmdline=1,prod=1,export=1,nonleaf=0,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, false); switchFileContents(depFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 30: [cmdline=1,prod=1,export=1,nonleaf=0,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 31: [cmdline=1,prod=1,export=1,nonleaf=1,profile=0] switchProfileContents(profile.p, s.get(), false); switchFileContents(nonleafFile, true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); // Case 32: [cmdline=1,prod=1,export=1,nonleaf=1,profile=1] switchProfileContents(profile.p, s.get(), true); resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline"; QCOMPARE(runQbs(resolveParams), 0); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n") && m_qbsStdout.contains("list prop: [\"cmdline\"]\n"), m_qbsStdout.constData()); } void TestBlackbox::productDependenciesByType() { QDir::setCurrent(testDataDir + "/product-dependencies-by-type"); QCOMPARE(runQbs(), 0); QFile appListFile(relativeProductBuildDir("app list") + "/app-list.txt"); QVERIFY2(appListFile.open(QIODevice::ReadOnly), qPrintable(appListFile.fileName())); const QList appList = appListFile.readAll().trimmed().split('\n'); QCOMPARE(appList.size(), 6); QStringList apps = QStringList() << QDir::currentPath() + '/' + relativeExecutableFilePath("app1", m_qbsStdout) << QDir::currentPath() + '/' + relativeExecutableFilePath("app2", m_qbsStdout) << QDir::currentPath() + '/' + relativeExecutableFilePath("app3", m_qbsStdout) << QDir::currentPath() + '/' + relativeExecutableFilePath("app4", m_qbsStdout) << QDir::currentPath() + '/' + relativeProductBuildDir("other-product") + "/output.txt" << QDir::currentPath() + '/' + relativeProductBuildDir("yet-another-product") + "/output.txt"; for (const QByteArray &line : appList) { const QString cleanLine = QString::fromLocal8Bit(line.trimmed()); QVERIFY2(apps.removeOne(cleanLine), qPrintable(cleanLine)); } QVERIFY(apps.empty()); } void TestBlackbox::productInExportedModule() { QDir::setCurrent(testDataDir + "/product-in-exported-module"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("product: importing"), m_qbsStdout.constData()); } void TestBlackbox::properQuoting() { QDir::setCurrent(testDataDir + "/proper quoting"); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params(QStringLiteral("run"), QStringList() << "-q" << "-p" << "Hello World"); params.expectFailure = true; // Because the exit code is non-zero. QCOMPARE(runQbs(params), 156); const char * const expectedOutput = "whitespaceless\ncontains space\ncontains\ttab\n" "backslash\\\nHello World! The magic number is 156."; QCOMPARE(unifiedLineEndings(m_qbsStdout).constData(), expectedOutput); } void TestBlackbox::propertiesInExportItems() { QDir::setCurrent(testDataDir + "/properties-in-export-items"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(relativeExecutableFilePath("p1", m_qbsStdout))); QVERIFY(regularFileExists(relativeExecutableFilePath("p2", m_qbsStdout))); QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); } void TestBlackbox::protobuf_data() { QTest::addColumn("projectFile"); QTest::addColumn("properties"); QTest::addColumn("hasModules"); QTest::addColumn("successExpected"); QTest::newRow("cpp-pkgconfig") << QString("addressbook_cpp.qbs") << QStringList({"project.qbsModuleProviders:qbspkgconfig"}) << true << true; QTest::newRow("cpp-conan") << QString("addressbook_cpp.qbs") << QStringList( {"project.qbsModuleProviders:conan", "qbs.buildVariant:release", "moduleProviders.conan.installDirectory:build"}) << true << true; QTest::newRow("objc") << QString("addressbook_objc.qbs") << QStringList() << false << true; QTest::newRow("nanopb") << QString("addressbook_nanopb.qbs") << QStringList() << false << true; QTest::newRow("import") << QString("import.qbs") << QStringList() << true << true; QTest::newRow("missing import dir") << QString("needs-import-dir.qbs") << QStringList() << true << false; QTest::newRow("provided import dir") << QString("needs-import-dir.qbs") << QStringList("products.app.theImportDir:subdir") << true << true; QTest::newRow("create proto library") << QString("create-proto-library.qbs") << QStringList() << true << true; } void TestBlackbox::protobuf() { QDir::setCurrent(testDataDir + "/protobuf"); QFETCH(QString, projectFile); QFETCH(QStringList, properties); QFETCH(bool, hasModules); QFETCH(bool, successExpected); rmDirR(relativeBuildDir()); if (QTest::currentDataTag() == QLatin1String("cpp-conan")) { if (!prepareAndRunConan()) QSKIP("conan is not prepared, check messages above"); } QbsRunParameters resolveParams("resolve", QStringList{"-f", projectFile} << properties); QCOMPARE(runQbs(resolveParams), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const bool withProtobuf = m_qbsStdout.contains("has protobuf: true"); const bool withoutProtobuf = m_qbsStdout.contains("has protobuf: false"); QVERIFY2(withProtobuf || withoutProtobuf, m_qbsStdout.constData()); if (withoutProtobuf) QSKIP("protobuf module not present"); const bool hasMods = m_qbsStdout.contains("has modules: true"); const bool dontHaveMods = m_qbsStdout.contains("has modules: false"); QVERIFY2(hasMods == !dontHaveMods, m_qbsStdout.constData()); QCOMPARE(hasMods, hasModules); QbsRunParameters runParams("run"); runParams.expectFailure = !successExpected; QCOMPARE(runQbs(runParams) == 0, successExpected); } void TestBlackbox::protobufLibraryInstall() { QDir::setCurrent(testDataDir + "/protobuf-library-install"); rmDirR(relativeBuildDir()); QbsRunParameters resolveParams("resolve", QStringList{"qbs.installPrefix:/usr/local"}); QCOMPARE(runQbs(resolveParams), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); const bool withProtobuf = m_qbsStdout.contains("has protobuf: true"); const bool withoutProtobuf = m_qbsStdout.contains("has protobuf: false"); QVERIFY2(withProtobuf || withoutProtobuf, m_qbsStdout.constData()); if (withoutProtobuf) QSKIP("protobuf module not present"); QbsRunParameters buildParams("build"); buildParams.expectFailure = false; QCOMPARE(runQbs(buildParams), 0); const QString installRootInclude = relativeBuildDir() + "/install-root/usr/local/include"; QVERIFY(QFileInfo::exists(installRootInclude + "/hello.pb.h") && QFileInfo::exists(installRootInclude + "/hello/world.pb.h")); } void TestBlackbox::pseudoMultiplexing() { // This is "pseudo-multiplexing" on all platforms that initialize qbs.architectures // to an array with one element. See QBS-1243. QDir::setCurrent(testDataDir + "/pseudo-multiplexing"); QCOMPARE(runQbs(), 0); } void TestBlackbox::qbsConfig() { QbsRunParameters params("config"); #ifdef QBS_ENABLE_UNIT_TESTS QTemporaryDir tempSystemSettingsDir; params.environment.insert("QBS_AUTOTEST_SYSTEM_SETTINGS_DIR", tempSystemSettingsDir.path()); QTemporaryDir tempUserSettingsDir; QVERIFY(tempSystemSettingsDir.isValid()); QVERIFY(tempUserSettingsDir.isValid()); const QStringList settingsDirArgs = QStringList{"--settings-dir", tempUserSettingsDir.path()}; // Set values. params.arguments = settingsDirArgs + QStringList{"--system", "key.subkey.scalar", "s"}; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs + QStringList{"--system", "key.subkey.list", "['sl']"}; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs + QStringList{"--user", "key.subkey.scalar", "u"}; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs + QStringList{"key.subkey.list", "[\"u1\",\"u2\"]"}; QCOMPARE(runQbs(params), 0); // Check outputs. const auto valueExtractor = [this] { const QByteArray trimmed = m_qbsStdout.trimmed(); return trimmed.mid(trimmed.lastIndexOf(':') + 2); }; params.arguments = settingsDirArgs + QStringList{"--list", "key.subkey.scalar"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("\"u\"")); params.arguments = settingsDirArgs + QStringList{"--list", "--user", "key.subkey.scalar"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("\"u\"")); params.arguments = settingsDirArgs + QStringList{"--list", "--system", "key.subkey.scalar"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("\"s\"")); params.arguments = settingsDirArgs + QStringList{"--list", "key.subkey.list"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("[\"u1\", \"u2\", \"sl\"]")); params.arguments = settingsDirArgs + QStringList{"--list", "--user", "key.subkey.list"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("[\"u1\", \"u2\"]")); params.arguments = settingsDirArgs + QStringList{"--list", "--system", "key.subkey.list"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("[\"sl\"]")); // Remove some values and re-check. params.arguments = settingsDirArgs + QStringList{"--unset", "key.subkey.scalar"}; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs + QStringList{"--system", "--unset", "key.subkey.list"}; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs + QStringList{"--list", "key.subkey.scalar"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("\"s\"")); params.arguments = settingsDirArgs + QStringList{"--list", "key.subkey.list"}; QCOMPARE(runQbs(params), 0); QCOMPARE(valueExtractor(), QByteArray("[\"u1\", \"u2\"]")); // Check preferences.ignoreSystemSearchPaths params.arguments = settingsDirArgs + QStringList{"--system", "preferences.qbsSearchPaths", "['/usr/lib/qbs']"}; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs + QStringList{"preferences.qbsSearchPaths", "['/home/user/qbs']"}; QCOMPARE(runQbs(params), 0); qbs::Settings settings(tempUserSettingsDir.path(), tempSystemSettingsDir.path()); const qbs::Preferences prefs(&settings, "SomeProfile"); QVERIFY2(prefs.searchPaths().contains("/usr/lib/qbs") && prefs.searchPaths().contains("/home/user/qbs"), qPrintable(prefs.searchPaths().join(','))); settings.setValue("profiles.SomeProfile.preferences.ignoreSystemSearchPaths", true); QVERIFY2(!prefs.searchPaths().contains("/usr/lib/qbs") && prefs.searchPaths().contains("/home/user/qbs"), qPrintable(prefs.searchPaths().join(','))); #else qDebug() << "ability to redirect the system settings dir not compiled in, skipping" "most qbs-config tests"; #endif // QBS_ENABLE_UNIT_TESTS bool canWriteToSystemSettings; QString testSettingsFilePath; { QSettings testSettings( qbs::Settings::defaultSystemSettingsBaseDir() + "/dummyOrg" + "/dummyApp.conf", QSettings::IniFormat); testSettings.setValue("dummyKey", "dummyValue"); testSettings.sync(); canWriteToSystemSettings = testSettings.status() == QSettings::NoError; testSettingsFilePath = testSettings.fileName(); } if (canWriteToSystemSettings) QVERIFY(QFile::remove(testSettingsFilePath)); // Check that trying to write to actual system settings causes access failure. params.expectFailure = !canWriteToSystemSettings; params.environment.clear(); params.arguments = QStringList{"--system", "key.subkey.scalar", "s"}; QCOMPARE(runQbs(params) == 0, canWriteToSystemSettings); if (!canWriteToSystemSettings) { QVERIFY2(m_qbsStderr.contains("You do not have permission to write to that location."), m_qbsStderr.constData()); } else { // cleanup system settings params.arguments = QStringList{"--system", "--unset", "key.subkey.scalar"}; QCOMPARE(runQbs(params) == 0, canWriteToSystemSettings); } } void TestBlackbox::qbsConfigAddProfile() { QbsRunParameters params("config"); QTemporaryDir settingsDir1; QTemporaryDir settingsDir2; QVERIFY(settingsDir1.isValid()); QVERIFY(settingsDir2.isValid()); const QStringList settingsDir1Args = QStringList{"--settings-dir", settingsDir1.path()}; const QStringList settingsDir2Args = QStringList{"--settings-dir", settingsDir2.path()}; QFETCH(QStringList, args); QFETCH(QString, errorMsg); // Step 1: Run --add-profile. params.arguments = settingsDir1Args; params.arguments << "--add-profile"; params.arguments << args; params.expectFailure = !errorMsg.isEmpty(); QCOMPARE(runQbs(params) == 0, !params.expectFailure); if (params.expectFailure) { QVERIFY(QString::fromLocal8Bit(m_qbsStderr).contains(errorMsg)); return; } params.expectFailure = false; params.arguments = settingsDir1Args; params.arguments << "--list"; QCOMPARE(runQbs(params), 0); const QByteArray output1 = m_qbsStdout; // Step 2: Set properties manually. for (int i = 1; i < args.size(); i += 2) { params.arguments = settingsDir2Args; params.arguments << ("profiles." + args.first() + '.' + args.at(i)) << args.at(i + 1); QCOMPARE(runQbs(params), 0); } params.arguments = settingsDir2Args; params.arguments << "--list"; QCOMPARE(runQbs(params), 0); const QByteArray output2 = m_qbsStdout; // Step3: Compare results. QCOMPARE(output1, output2); } void TestBlackbox::qbsConfigAddProfile_data() { QTest::addColumn("args"); QTest::addColumn("errorMsg"); QTest::newRow("no arguments") << QStringList() << QString("Profile name missing"); QTest::newRow("empty name") << QStringList{"", "p", "v"} << QString("Profile name must not be empty"); QTest::newRow("no properties") << QStringList("p") << QString("Profile properties must be provided"); QTest::newRow("one property") << QStringList{"p", "p", "v"} << QString(); QTest::newRow("two properties") << QStringList{"p", "p1", "v1", "p2", "v2"} << QString(); QTest::newRow("missing value") << QStringList{"p", "p"} << QString("Profile properties must be key/value pairs"); QTest::newRow("missing values") << QStringList{"p", "p1", "v1", "p2"} << QString("Profile properties must be key/value pairs"); } void TestBlackbox::qbsConfigImport() { QFETCH(QString, format); QDir::setCurrent(testDataDir + "/qbs-config-import-export"); QbsRunParameters params("config"); QTemporaryDir settingsDir; QVERIFY(settingsDir.isValid()); const QStringList settingsDirArgs = QStringList{"--settings-dir", settingsDir.path()}; params.arguments = settingsDirArgs; params.arguments << "--import" << "config." + format; QCOMPARE(runQbs(params), 0); params.arguments = settingsDirArgs; params.arguments << "--list"; QCOMPARE(runQbs(params), 0); const QByteArray output = m_qbsStdout; const auto lines = output.split('\n'); QCOMPARE(lines.count(), 5); QCOMPARE(lines[0], "group.key1: \"value1\""); QCOMPARE(lines[1], "group.key2: \"value2\""); QCOMPARE(lines[2], "key: \"value\""); QCOMPARE(lines[3], "listKey: [\"valueOne\", \"valueTwo\"]"); QCOMPARE(lines[4], ""); } void TestBlackbox::qbsConfigImport_data() { QTest::addColumn("format"); QTest::newRow("text") << QStringLiteral("txt"); QTest::newRow("json") << QStringLiteral("json"); } void TestBlackbox::qbsConfigExport() { QFETCH(QString, format); QDir::setCurrent(testDataDir + "/qbs-config-import-export"); QbsRunParameters params("config"); QTemporaryDir settingsDir; const QString fileName = "config." + format; const QString filePath = settingsDir.path() + "/" + fileName; QVERIFY(settingsDir.isValid()); const QStringList commonArgs = QStringList{"--settings-dir", settingsDir.path(), "--user"}; std::pair values[] = { {"key", "value"}, {"listKey", "[\"valueOne\",\"valueTwo\"]"}, {"group.key1", "value1"}, {"group.key2", "value2"} }; for (const auto &value: values) { params.arguments = commonArgs; params.arguments << value.first << value.second; QCOMPARE(runQbs(params), 0); } params.arguments = commonArgs; params.arguments << "--export" << filePath; QCOMPARE(runQbs(params), 0); QVERIFY(QFileInfo(filePath).canonicalPath() != QFileInfo(fileName).canonicalPath()); QFile exported(filePath); QFile expected(fileName); QVERIFY(exported.open(QIODevice::ReadOnly | QIODevice::Text)); QVERIFY(expected.open(QIODevice::ReadOnly | QIODevice::Text)); QCOMPARE(exported.readAll(), expected.readAll()); } void TestBlackbox::qbsConfigExport_data() { QTest::addColumn("format"); QTest::newRow("text") << QStringLiteral("txt"); QTest::newRow("json") << QStringLiteral("json"); } static QJsonObject getNextSessionPacket(QProcess &session, QByteArray &data) { int totalSize = -1; QElapsedTimer timer; timer.start(); QByteArray msg; while (totalSize == -1 || msg.size() < totalSize) { if (data.isEmpty()) session.waitForReadyRead(1000); if (timer.elapsed() >= testTimeoutInMsecs()) return QJsonObject(); data += session.readAllStandardOutput(); if (totalSize == -1) { static const QByteArray magicString = "qbsmsg:"; const int magicStringOffset = data.indexOf(magicString); if (magicStringOffset == -1) continue; const int sizeOffset = magicStringOffset + magicString.length(); const int newlineOffset = data.indexOf('\n', sizeOffset); if (newlineOffset == -1) continue; const QByteArray sizeString = data.mid(sizeOffset, newlineOffset - sizeOffset); bool isNumber; const int size = sizeString.toInt(&isNumber); if (!isNumber || size <= 0) return QJsonObject(); data = data.mid(newlineOffset + 1); totalSize = size; } const int bytesToTake = std::min(totalSize - msg.size(), data.size()); msg += data.left(bytesToTake); data = data.mid(bytesToTake); } return QJsonDocument::fromJson(QByteArray::fromBase64(msg)).object(); } static void sendSessionPacket(QProcess &sessionProc, const QJsonObject &message) { const QByteArray data = QJsonDocument(message).toJson().toBase64(); sessionProc.write("qbsmsg:"); sessionProc.write(QByteArray::number(data.length())); sessionProc.write("\n"); sessionProc.write(data); } void TestBlackbox::qbsLanguageServer_data() { QTest::addColumn("request"); QTest::addColumn("location"); QTest::addColumn("insertLocation"); QTest::addColumn("insertString"); QTest::addColumn("expectedReply"); QTest::addRow("follow to module") << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:4:9") << QString() << QString() << (testDataDir + "/lsp/modules/m/m.qbs:1:1"); QTest::addRow("follow to submodules") << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:5:35") << QString() << QString() << ((testDataDir + "/lsp/modules/Prefix/m1/m1.qbs:1:1\n") + (testDataDir + "/lsp/modules/Prefix/m2/m2.qbs:1:1\n") + (testDataDir + "/lsp/modules/Prefix/m3/m3.qbs:1:1")); QTest::addRow("follow to product") << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:9:19") << QString() << QString() << (testDataDir + "/lsp/lsp.qbs:2:5"); QTest::addRow("follow to module, non-invalidating insert") << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:4:9") << "5:9" << QString("property bool dummy\n") << (testDataDir + "/lsp/modules/m/m.qbs:1:1"); QTest::addRow("follow to module, invalidating insert") << "--goto-def" << (testDataDir + "/lsp/lsp.qbs:4:9") << QString() << QString("property bool dummy\n") << QString(); QTest::addRow("completion: LHS, module prefix") << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("P") << QString("Prefix.m1\nPrefix.m2\nPrefix.m3"); QTest::addRow("completion: LHS, module name") << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("Prefix.m") << QString("m1\nm2\nm3"); QTest::addRow("completion: LHS, module property right after dot") << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("Prefix.m1.") << QString("p1 bool\np2 string\nx bool"); QTest::addRow("completion: LHS, module property with identifier prefix") << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("Prefix.m1.p") << QString("p1 bool\np2 string"); QTest::addRow("completion: simple RHS, module property") << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("property bool dummy: Prefix.m1.p") << QString("p1 bool\np2 string"); QTest::addRow("completion: complex RHS, module property") << "--completion" << (testDataDir + "/lsp/lsp.qbs:7:1") << QString() << QString("property bool dummy: { return Prefix.m1.p") << QString("p1 bool\np2 string"); } void TestBlackbox::qbsLanguageServer() { QFETCH(QString, request); QFETCH(QString, location); QFETCH(QString, insertLocation); QFETCH(QString, insertString); QFETCH(QString, expectedReply); QDir::setCurrent(testDataDir + "/lsp"); QProcess sessionProc; sessionProc.start(qbsExecutableFilePath, QStringList("session")); QVERIFY(sessionProc.waitForStarted()); QByteArray incomingData; // Wait for and verify hello packet. QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData); const QString socketPath = receivedMessage.value("lsp-socket").toString(); QVERIFY(!socketPath.isEmpty()); // Resolve project. QJsonObject resolveMessage; resolveMessage.insert("type", "resolve-project"); resolveMessage.insert("top-level-profile", profileName()); resolveMessage.insert("project-file-path", QDir::currentPath() + "/lsp.qbs"); resolveMessage.insert("build-root", QDir::currentPath()); resolveMessage.insert("settings-directory", settings()->baseDirectory()); sendSessionPacket(sessionProc, resolveMessage); bool receivedReply = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-resolved") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); } } QVERIFY(receivedReply); // Employ client app to send request. QProcess lspClient; const QFileInfo qbsFileInfo(qbsExecutableFilePath); const QString clientFilePath = HostOsInfo::appendExecutableSuffix( qbsFileInfo.absolutePath() + "/qbs_lspclient"); QStringList args{"--socket", socketPath, request, location}; if (!insertString.isEmpty()) args << "--insert-code" << insertString; if (!insertLocation.isEmpty()) args << "--insert-location" << insertLocation; lspClient.start(clientFilePath, args); QVERIFY2(lspClient.waitForStarted(), qPrintable(lspClient.errorString())); QVERIFY2(lspClient.waitForFinished(), qPrintable(lspClient.errorString())); QString errMsg; if (lspClient.exitStatus() != QProcess::NormalExit) errMsg = lspClient.errorString(); if (errMsg.isEmpty()) errMsg = QString::fromLocal8Bit(lspClient.readAllStandardError()); QVERIFY2(lspClient.exitCode() == 0, qPrintable(errMsg)); QVERIFY2(errMsg.isEmpty(), qPrintable(errMsg)); QString output = QString::fromUtf8(lspClient.readAllStandardOutput().trimmed()); output.replace("\r\n", "\n"); QCOMPARE(output, expectedReply); QJsonObject quitRequest; quitRequest.insert("type", "quit"); sendSessionPacket(sessionProc, quitRequest); QVERIFY(sessionProc.waitForFinished(3000)); } void TestBlackbox::qbsSession() { QDir::setCurrent(testDataDir + "/qbs-session"); QProcess sessionProc; sessionProc.start(qbsExecutableFilePath, QStringList("session")); // Uncomment for debugging. /* connect(&sessionProc, &QProcess::readyReadStandardError, [&sessionProc] { qDebug() << "stderr:" << sessionProc.readAllStandardError(); }); */ QVERIFY(sessionProc.waitForStarted()); const auto sendPacket = [&sessionProc](const QJsonObject &message) { sendSessionPacket(sessionProc, message); }; static const auto envToJson = [](const QProcessEnvironment &env) { QJsonObject envObj; const QStringList keys = env.keys(); for (const QString &key : keys) envObj.insert(key, env.value(key)); return envObj; }; static const auto envFromJson = [](const QJsonValue &v) { const QJsonObject obj = v.toObject(); QProcessEnvironment env; for (auto it = obj.begin(); it != obj.end(); ++it) env.insert(it.key(), it.value().toString()); return env; }; QByteArray incomingData; // Wait for and verify hello packet. QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type"), "hello"); QCOMPARE(receivedMessage.value("api-level").toInt(), 8); QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 2); // Resolve & verify structure QJsonObject resolveMessage; resolveMessage.insert("type", "resolve-project"); resolveMessage.insert("top-level-profile", profileName()); resolveMessage.insert("configuration-name", "my-config"); resolveMessage.insert("project-file-path", QDir::currentPath() + "/qbs-session.qbs"); resolveMessage.insert("build-root", QDir::currentPath()); resolveMessage.insert("settings-directory", settings()->baseDirectory()); QJsonObject overriddenValues; overriddenValues.insert("products.theLib.cpp.cxxLanguageVersion", "c++17"); resolveMessage.insert("overridden-properties", overriddenValues); resolveMessage.insert("environment", envToJson(QbsRunParameters::defaultEnvironment())); resolveMessage.insert("data-mode", "only-if-changed"); resolveMessage.insert("max-job-count", 2); resolveMessage.insert("log-time", true); resolveMessage.insert( "module-properties", QJsonArray::fromStringList( {"cpp.cxxLanguageVersion", "cpp.executableSuffix", "cpp.objectSuffix"})); sendPacket(resolveMessage); bool receivedLogData = false; bool receivedStartedSignal = false; bool receivedProgressData = false; bool receivedReply = false; QString objectSuffix; QString executableSuffix; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-resolved") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QCOMPARE(projectData.value("name").toString(), "qbs-session"); const QJsonArray products = projectData.value("products").toArray(); QCOMPARE(products.size(), 2); for (const QJsonValue &v : products) { const QJsonObject product = v.toObject(); const QString productName = product.value("name").toString(); QVERIFY(!productName.isEmpty()); QVERIFY2(product.value("is-enabled").toBool(), qPrintable(productName)); const QJsonObject moduleProps = product.value("module-properties").toObject(); objectSuffix = moduleProps.value("cpp.objectSuffix").toString(); executableSuffix = moduleProps.value("cpp.executableSuffix").toString(); bool theLib = false; bool theApp = false; if (productName == "theLib") theLib = true; else if (productName == "theApp") theApp = true; QVERIFY2(theLib || theApp, qPrintable(productName)); const QJsonArray groups = product.value("groups").toArray(); if (theLib) QVERIFY(groups.size() >= 3); else QVERIFY(!groups.isEmpty()); for (const QJsonValue &v : groups) { const QJsonObject group = v.toObject(); const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); const auto findArtifact = [&sourceArtifacts](const QString &fileName) { for (const QJsonValue &v : sourceArtifacts) { const QJsonObject artifact = v.toObject(); if (QFileInfo(artifact.value("file-path").toString()).fileName() == fileName) { return artifact; } } return QJsonObject(); }; const QString groupName = group.value("name").toString(); const auto getCxxLanguageVersion = [&group, &product] { QJsonObject moduleProperties = group.value("module-properties").toObject(); if (moduleProperties.isEmpty()) moduleProperties = product.value("module-properties").toObject(); return moduleProperties.toVariantMap().value("cpp.cxxLanguageVersion") .toStringList(); }; if (groupName == "sources") { const QJsonObject artifact = findArtifact("lib.cpp"); QVERIFY2(!artifact.isEmpty(), "lib.cpp"); QCOMPARE(getCxxLanguageVersion(), {"c++17"}); } else if (groupName == "headers") { const QJsonObject artifact = findArtifact("lib.h"); QVERIFY2(!artifact.isEmpty(), "lib.h"); } else if (groupName == "theApp") { const QJsonObject artifact = findArtifact("main.cpp"); QVERIFY2(!artifact.isEmpty(), "main.cpp"); QCOMPARE(getCxxLanguageVersion(), {"c++14"}); } } } break; } else if (msgType == "log-data") { if (receivedMessage.value("message").toString().contains("activity")) receivedLogData = true; } else if (msgType == "task-started") { receivedStartedSignal = true; } else if (msgType == "task-progress") { receivedProgressData = true; } else if (msgType != "new-max-progress") { QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType))); } } QVERIFY(receivedReply); QVERIFY(receivedLogData); QVERIFY(receivedStartedSignal); QVERIFY(receivedProgressData); // First build: No install, log time, default command description. QJsonObject buildRequest; buildRequest.insert("type", "build-project"); buildRequest.insert("log-time", true); buildRequest.insert("install", false); buildRequest.insert("data-mode", "only-if-changed"); sendPacket(buildRequest); receivedReply = false; receivedLogData = false; receivedStartedSignal = false; receivedProgressData = false; bool receivedCommandDescription = false; bool receivedProcessResult = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-built") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QCOMPARE(projectData.value("name").toString(), "qbs-session"); } else if (msgType == "log-data") { if (receivedMessage.value("message").toString().contains("activity")) receivedLogData = true; } else if (msgType == "task-started") { receivedStartedSignal = true; } else if (msgType == "task-progress") { receivedProgressData = true; } else if (msgType == "command-description") { if (receivedMessage.value("message").toString().contains("compiling main.cpp")) receivedCommandDescription = true; } else if (msgType == "process-result") { QCOMPARE(receivedMessage.value("exit-code").toInt(), 0); receivedProcessResult = true; } else if (msgType != "new-max-progress") { QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType))); } } QVERIFY(receivedReply); QVERIFY(receivedLogData); QVERIFY(receivedStartedSignal); QVERIFY(receivedProgressData); QVERIFY(receivedCommandDescription); QVERIFY(receivedProcessResult); const QString &exeFilePath = QDir::currentPath() + '/' + relativeProductBuildDir("theApp", "my-config") + '/' + "theApp" + executableSuffix; QVERIFY2(regularFileExists(exeFilePath), qPrintable(exeFilePath)); const QString defaultInstallRoot = QDir::currentPath() + '/' + relativeBuildDir("my-config") + "/install-root"; QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot)); // Clean. QJsonObject cleanRequest; cleanRequest.insert("type", "clean-project"); cleanRequest.insert("settings-dir", settings()->baseDirectory()); cleanRequest.insert("log-time", true); sendPacket(cleanRequest); receivedReply = false; receivedLogData = false; receivedStartedSignal = false; receivedProgressData = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-cleaned") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); } else if (msgType == "log-data") { if (receivedMessage.value("message").toString().contains("activity")) receivedLogData = true; } else if (msgType == "task-started") { receivedStartedSignal = true; } else if (msgType == "task-progress") { receivedProgressData = true; } else if (msgType != "new-max-progress") { QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType))); } } QVERIFY(receivedReply); QVERIFY(receivedLogData); QVERIFY(receivedStartedSignal); QVERIFY(receivedProgressData); QVERIFY2(!regularFileExists(exeFilePath), qPrintable(exeFilePath)); // Second build: Do not log the time, show command lines. buildRequest.insert("log-time", false); buildRequest.insert("command-echo-mode", "command-line"); sendPacket(buildRequest); receivedReply = false; receivedLogData = false; receivedStartedSignal = false; receivedProgressData = false; receivedCommandDescription = false; receivedProcessResult = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-built") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QVERIFY(projectData.isEmpty()); } else if (msgType == "log-data") { if (receivedMessage.value("message").toString().contains("activity")) receivedLogData = true; } else if (msgType == "task-started") { receivedStartedSignal = true; } else if (msgType == "task-progress") { receivedProgressData = true; } else if (msgType == "command-description") { if (QDir::fromNativeSeparators(receivedMessage.value("message").toString()) .contains("/main.cpp")) { receivedCommandDescription = true; } } else if (msgType == "process-result") { QCOMPARE(receivedMessage.value("exit-code").toInt(), 0); receivedProcessResult = true; } else if (msgType != "new-max-progress") { QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType))); } } QVERIFY(receivedReply); QVERIFY(!receivedLogData); QVERIFY(receivedStartedSignal); QVERIFY(receivedProgressData); QVERIFY(receivedCommandDescription); QVERIFY(receivedProcessResult); QVERIFY2(regularFileExists(exeFilePath), qPrintable(exeFilePath)); QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot)); // Install. QJsonObject installRequest; installRequest.insert("type", "install-project"); installRequest.insert("log-time", true); const QString customInstallRoot = QDir::currentPath() + "/my-install-root"; QVERIFY2(!QFile::exists(customInstallRoot), qPrintable(customInstallRoot)); installRequest.insert("install-root", customInstallRoot); sendPacket(installRequest); receivedReply = false; receivedLogData = false; receivedStartedSignal = false; receivedProgressData = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "install-done") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); } else if (msgType == "log-data") { if (receivedMessage.value("message").toString().contains("activity")) receivedLogData = true; } else if (msgType == "task-started") { receivedStartedSignal = true; } else if (msgType == "task-progress") { receivedProgressData = true; } else if (msgType != "new-max-progress") { QVERIFY2(false, qPrintable(QString("Unexpected message type '%1'").arg(msgType))); } } QVERIFY(receivedReply); QVERIFY(receivedLogData); QVERIFY(receivedStartedSignal); QVERIFY(receivedProgressData); QVERIFY2(!directoryExists(defaultInstallRoot), qPrintable(defaultInstallRoot)); QVERIFY2(directoryExists(customInstallRoot), qPrintable(customInstallRoot)); // Retrieve modified environment. QJsonObject getRunEnvRequest; getRunEnvRequest.insert("type", "get-run-environment"); getRunEnvRequest.insert("product", "theApp"); const QProcessEnvironment inEnv = QProcessEnvironment::systemEnvironment(); QVERIFY(!inEnv.contains("MY_MODULE")); getRunEnvRequest.insert("base-environment", envToJson(inEnv)); sendPacket(getRunEnvRequest); receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("run-environment")); QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QProcessEnvironment outEnv = envFromJson(receivedMessage.value("full-environment")); QVERIFY(outEnv.keys().size() > inEnv.keys().size()); QCOMPARE(outEnv.value("MY_MODULE"), QString("1")); // Add two files to library and re-build. QJsonObject addFilesRequest; addFilesRequest.insert("type", "add-files"); addFilesRequest.insert("product", "theLib"); addFilesRequest.insert("group", "sources"); addFilesRequest.insert("files", QJsonArray::fromStringList({QDir::currentPath() + "/file1.cpp", QDir::currentPath() + "/file2.cpp"})); sendPacket(addFilesRequest); receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("files-added")); error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) { for (const auto item: error[QStringLiteral("items")].toArray()) { const auto description = QStringLiteral("Project file updates are not enabled"); if (item.toObject()[QStringLiteral("description")].toString().contains(description)) QSKIP("File updates are disabled"); } qDebug() << error; } QVERIFY(error.isEmpty()); receivedReply = false; sendPacket(resolveMessage); while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-resolved") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QJsonArray products = projectData.value("products").toArray(); bool file1 = false; bool file2 = false; for (const QJsonValue v : products) { const QJsonObject product = v.toObject(); const QString productName = product.value("full-display-name").toString(); const QJsonArray groups = product.value("groups").toArray(); for (const QJsonValue &v : groups) { const QJsonObject group = v.toObject(); const QString groupName = group.value("name").toString(); const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); for (const QJsonValue &v : sourceArtifacts) { const QString filePath = v.toObject().value("file-path").toString(); if (filePath.endsWith("file1.cpp")) { QCOMPARE(productName, QString("theLib")); QCOMPARE(groupName, QString("sources")); file1 = true; } else if (filePath.endsWith("file2.cpp")) { QCOMPARE(productName, QString("theLib")); QCOMPARE(groupName, QString("sources")); file2 = true; } } } } QVERIFY(file1); QVERIFY(file2); } } QVERIFY(receivedReply); receivedReply = false; receivedProcessResult = false; bool compiledFile1 = false; bool compiledFile2 = false; bool compiledMain = false; bool compiledLib = false; buildRequest.remove("command-echo-mode"); sendPacket(buildRequest); while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-built") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); } else if (msgType == "command-description") { const QString msg = receivedMessage.value("message").toString(); if (msg.contains("compiling file1.cpp")) compiledFile1 = true; else if (msg.contains("compiling file2.cpp")) compiledFile2 = true; else if (msg.contains("compiling main.cpp")) compiledMain = true; else if (msg.contains("compiling lib.cpp")) compiledLib = true; } else if (msgType == "process-result") { QCOMPARE(receivedMessage.value("exit-code").toInt(), 0); receivedProcessResult = true; } } QVERIFY(receivedReply); QVERIFY(!receivedProcessResult); QVERIFY(compiledFile1); QVERIFY(compiledFile2); QVERIFY(!compiledLib); QVERIFY(!compiledMain); // Remove one of the newly added files again and re-build. WAIT_FOR_NEW_TIMESTAMP(); touch("file1.cpp"); touch("file2.cpp"); touch("main.cpp"); QJsonObject removeFilesRequest; removeFilesRequest.insert("type", "remove-files"); removeFilesRequest.insert("product", "theLib"); removeFilesRequest.insert("group", "sources"); removeFilesRequest.insert("files", QJsonArray::fromStringList({QDir::currentPath() + "/file1.cpp"})); sendPacket(removeFilesRequest); receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("files-removed")); error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); receivedReply = false; sendPacket(resolveMessage); while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-resolved") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QJsonArray products = projectData.value("products").toArray(); bool file1 = false; bool file2 = false; for (const QJsonValue v : products) { const QJsonObject product = v.toObject(); const QString productName = product.value("full-display-name").toString(); const QJsonArray groups = product.value("groups").toArray(); for (const QJsonValue &v : groups) { const QJsonObject group = v.toObject(); const QString groupName = group.value("name").toString(); const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); for (const QJsonValue &v : sourceArtifacts) { const QString filePath = v.toObject().value("file-path").toString(); if (filePath.endsWith("file1.cpp")) { file1 = true; } else if (filePath.endsWith("file2.cpp")) { QCOMPARE(productName, QString("theLib")); QCOMPARE(groupName, QString("sources")); file2 = true; } } } } QVERIFY(!file1); QVERIFY(file2); } } QVERIFY(receivedReply); receivedReply = false; receivedProcessResult = false; compiledFile1 = false; compiledFile2 = false; compiledMain = false; compiledLib = false; sendPacket(buildRequest); while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-built") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); } else if (msgType == "command-description") { const QString msg = receivedMessage.value("message").toString(); if (msg.contains("compiling file1.cpp")) compiledFile1 = true; else if (msg.contains("compiling file2.cpp")) compiledFile2 = true; else if (msg.contains("compiling main.cpp")) compiledMain = true; else if (msg.contains("compiling lib.cpp")) compiledLib = true; } else if (msgType == "process-result") { QCOMPARE(receivedMessage.value("exit-code").toInt(), 0); receivedProcessResult = true; } } QVERIFY(receivedReply); QVERIFY(receivedProcessResult); QVERIFY(!compiledFile1); QVERIFY(compiledFile2); QVERIFY(!compiledLib); QVERIFY(compiledMain); // Rename a file and re-build. WAIT_FOR_NEW_TIMESTAMP(); QVERIFY(QFile::rename("lib.cpp", "theLib.cpp")); QJsonObject renameFilesRequest; renameFilesRequest.insert("type", "rename-files"); renameFilesRequest.insert("product", "theLib"); renameFilesRequest.insert("group", "sources"); QJsonObject sourceAndTarget( {qMakePair(QString("source-path"), QJsonValue(QDir::currentPath() + "/lib.cpp")), qMakePair(QString("target-path"), QJsonValue(QDir::currentPath() + "/theLib.cpp"))}); renameFilesRequest.insert("files", QJsonArray{sourceAndTarget}); sendPacket(renameFilesRequest); receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("files-renamed")); error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); receivedReply = false; sendPacket(resolveMessage); while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-resolved") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QJsonArray products = projectData.value("products").toArray(); bool hasOldFile = false; bool hasNewFile = false; for (const QJsonValue v : products) { const QJsonObject product = v.toObject(); const QString productName = product.value("full-display-name").toString(); const QJsonArray groups = product.value("groups").toArray(); for (const QJsonValue &v : groups) { const QJsonObject group = v.toObject(); const QString groupName = group.value("name").toString(); const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray(); for (const QJsonValue &v : sourceArtifacts) { const QString filePath = v.toObject().value("file-path").toString(); if (filePath.endsWith("lib.cpp")) { hasOldFile = true; } else if (filePath.endsWith("theLib.cpp")) { QCOMPARE(productName, QString("theLib")); QCOMPARE(groupName, QString("sources")); hasNewFile = true; } } } } QVERIFY(!hasOldFile); QVERIFY(hasNewFile); } } QVERIFY(receivedReply); receivedReply = false; compiledLib = false; sendPacket(buildRequest); while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QVERIFY(!receivedMessage.isEmpty()); const QString msgType = receivedMessage.value("type").toString(); if (msgType == "project-built") { receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); } else if ( msgType == "command-description" && receivedMessage.value("message").toString().contains("compiling theLib.cpp")) { compiledLib = true; } } QVERIFY(receivedReply); QVERIFY(compiledLib); // Get generated files. QJsonObject genFilesRequestPerFile; genFilesRequestPerFile.insert("source-file", QDir::currentPath() + "/main.cpp"); genFilesRequestPerFile.insert("tags", QJsonArray{QJsonValue("obj")}); QJsonObject genFilesRequestPerProduct; genFilesRequestPerProduct.insert("full-display-name", "theApp"); genFilesRequestPerProduct.insert("requests", QJsonArray({genFilesRequestPerFile})); QJsonObject genFilesRequest; genFilesRequest.insert("type", "get-generated-files-for-sources"); genFilesRequest.insert("products", QJsonArray({genFilesRequestPerProduct})); sendPacket(genFilesRequest); receivedReply = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("generated-files-for-sources")); const QJsonArray products = receivedMessage.value("products").toArray(); QCOMPARE(products.size(), 1); const QJsonArray results = products.first().toObject().value("results").toArray(); QCOMPARE(results.size(), 1); const QJsonObject result = results.first().toObject(); QCOMPARE(result.value("source-file"), QDir::currentPath() + "/main.cpp"); const QJsonArray generatedFiles = result.value("generated-files").toArray(); QCOMPARE(generatedFiles.count(), 1); QCOMPARE( QFileInfo(generatedFiles.first().toString()).fileName(), "main.cpp" + objectSuffix); receivedReply = true; } QVERIFY(receivedReply); // Release project. const QJsonObject releaseRequest{qMakePair(QString("type"), QJsonValue("release-project"))}; sendPacket(releaseRequest); receivedReply = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("project-released")); const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); receivedReply = true; } QVERIFY(receivedReply); // Get build graph info. QJsonObject loadProjectMessage; loadProjectMessage.insert("type", "resolve-project"); loadProjectMessage.insert("configuration-name", "my-config"); loadProjectMessage.insert("build-root", QDir::currentPath()); loadProjectMessage.insert("settings-dir", settings()->baseDirectory()); loadProjectMessage.insert("restore-behavior", "restore-only"); loadProjectMessage.insert("data-mode", "only-if-changed"); sendPacket(loadProjectMessage); receivedReply = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); if (receivedMessage.value("type") != "project-resolved") continue; receivedReply = true; const QJsonObject error = receivedMessage.value("error").toObject(); if (!error.isEmpty()) qDebug() << error; QVERIFY(error.isEmpty()); const QString bgFilePath = QDir::currentPath() + '/' + relativeBuildGraphFilePath("my-config"); const QJsonObject projectData = receivedMessage.value("project-data").toObject(); QCOMPARE(projectData.value("build-graph-file-path").toString(), bgFilePath); QCOMPARE(projectData.value("overridden-properties"), overriddenValues); } QVERIFY(receivedReply); // Send unknown request. const QJsonObject unknownRequest({qMakePair(QString("type"), QJsonValue("blubb"))}); sendPacket(unknownRequest); receivedReply = false; while (!receivedReply) { receivedMessage = getNextSessionPacket(sessionProc, incomingData); QCOMPARE(receivedMessage.value("type").toString(), QString("protocol-error")); receivedReply = true; } QVERIFY(receivedReply); QJsonObject quitRequest; quitRequest.insert("type", "quit"); sendPacket(quitRequest); QVERIFY(sessionProc.waitForFinished(3000)); } void TestBlackbox::radAfterIncompleteBuild_data() { QTest::addColumn("projectFileName"); QTest::newRow("Project with Rule") << "project_with_rule.qbs"; QTest::newRow("Project with Transformer") << "project_with_transformer.qbs"; } void TestBlackbox::radAfterIncompleteBuild() { QDir::setCurrent(testDataDir + "/rad-after-incomplete-build"); rmDirR(relativeBuildDir()); const QString projectFileName = "project_with_rule.qbs"; // Step 1: Have a directory where a file used to be. QbsRunParameters params(QStringList() << "-f" << projectFileName); QCOMPARE(runQbs(params), 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFileName, "oldfile", "oldfile/newfile"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFileName, "oldfile/newfile", "newfile"); params.expectFailure = false; QCOMPARE(runQbs(params), 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFileName, "newfile", "oldfile/newfile"); QCOMPARE(runQbs(params), 0); // Step 2: Have a file where a directory used to be. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFileName, "oldfile/newfile", "oldfile"); params.expectFailure = true; QVERIFY(runQbs(params) != 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFileName, "oldfile", "newfile"); params.expectFailure = false; QCOMPARE(runQbs(params), 0); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE(projectFileName, "newfile", "oldfile"); QCOMPARE(runQbs(params), 0); } void TestBlackbox::subProfileChangeTracking() { QDir::setCurrent(testDataDir + "/subprofile-change-tracking"); const SettingsPtr s = settings(); qbs::Internal::TemporaryProfile subProfile("qbs-autotests-subprofile", s.get()); subProfile.p.setValue("baseProfile", profileName()); subProfile.p.setValue("cpp.includePaths", QStringList("/tmp/include1")); s->sync(); QCOMPARE(runQbs(), 0); subProfile.p.setValue("cpp.includePaths", QStringList("/tmp/include2")); s->sync(); QbsRunParameters params; params.command = "resolve"; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("main1.cpp")); QVERIFY(m_qbsStdout.contains("main2.cpp")); } void TestBlackbox::successiveChanges() { QDir::setCurrent(testDataDir + "/successive-changes"); QCOMPARE(runQbs(), 0); QbsRunParameters params("resolve", QStringList() << "products.theProduct.type:output,blubb"); QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); params.arguments << "project.version:2"; QCOMPARE(runQbs(params), 0); QCOMPARE(runQbs(), 0); QFile output(relativeProductBuildDir("theProduct") + "/output.out"); QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString())); const QByteArray version = output.readAll(); QCOMPARE(version.constData(), "2"); } void TestBlackbox::installedApp() { QDir::setCurrent(testDataDir + "/installed_artifact"); QCOMPARE(runQbs(), 0); const QByteArray output = m_qbsStdout; QVERIFY(regularFileExists( defaultInstallRoot + appendExecSuffix(QStringLiteral("/usr/bin/installedApp"), output))); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("qbs.installRoot:" + testDataDir + "/installed-app"))), 0); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists( testDataDir + appendExecSuffix("/installed-app/usr/bin/installedApp", output))); QFile addedFile(defaultInstallRoot + QLatin1String("/blubb.txt")); QVERIFY(addedFile.open(QIODevice::WriteOnly)); addedFile.close(); QVERIFY(addedFile.exists()); QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); QCOMPARE(runQbs(QbsRunParameters(QStringList() << "--clean-install-root")), 0); QVERIFY(regularFileExists( defaultInstallRoot + appendExecSuffix(QStringLiteral("/usr/bin/installedApp"), output))); QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/src/main.cpp"))); QVERIFY(!addedFile.exists()); // Check whether changing install parameters on the product causes re-installation. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("installed_artifact.qbs", "qbs.installPrefix: \"/usr\"", "qbs.installPrefix: '/usr/local'"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists( defaultInstallRoot + appendExecSuffix(QStringLiteral("/usr/local/bin/installedApp"), output))); QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/local/src/main.cpp"))); // Check whether changing install parameters on the artifact causes re-installation. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("installed_artifact.qbs", "qbs.installDir: \"bin\"", "qbs.installDir: 'custom'"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists( defaultInstallRoot + appendExecSuffix(QStringLiteral("/usr/local/custom/installedApp"), output))); // Check whether changing install parameters on a source file causes re-installation. WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("installed_artifact.qbs", "qbs.installDir: \"src\"", "qbs.installDir: 'source'"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/local/source/main.cpp"))); // Check whether changing install parameters on the command line causes re-installation. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("qbs.installRoot:" + relativeBuildDir() + "/blubb"))), 0); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(relativeBuildDir() + "/blubb/usr/local/source/main.cpp")); // Check --no-install rmDirR(relativeBuildDir()); QCOMPARE(runQbs(QbsRunParameters(QStringList() << "--no-install")), 0); QCOMPARE(QDir(defaultInstallRoot).entryList(QDir::NoDotAndDotDot).size(), 0); // Check --no-build (with and without an existing build graph) QbsRunParameters params("install", QStringList() << "--no-build"); QCOMPARE(runQbs(params), 0); rmDirR(relativeBuildDir()); params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Build graph not found"), m_qbsStderr.constData()); } void TestBlackbox::installDuplicates() { QDir::setCurrent(testDataDir + "/install-duplicates"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains("Cannot install files")); } void TestBlackbox::installDuplicatesNoError() { QDir::setCurrent(testDataDir + "/install-duplicates-no-error"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); } void TestBlackbox::installedSourceFiles() { QDir::setCurrent(testDataDir + "/installed-source-files"); QCOMPARE(runQbs(), 0); QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/readme.txt"))); QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/main.cpp"))); } void TestBlackbox::toolLookup() { QbsRunParameters params(QStringLiteral("setup-toolchains"), QStringList("--help")); params.profile.clear(); QCOMPARE(runQbs(params), 0); } void TestBlackbox::topLevelSearchPath() { QDir::setCurrent(testDataDir + "/toplevel-searchpath"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("MyProduct"), m_qbsStderr.constData()); params.arguments << ("project.qbsSearchPaths:" + QDir::currentPath() + "/qbs-resources"); QCOMPARE(runQbs(params), 0); } void TestBlackbox::checkProjectFilePath() { QDir::setCurrent(testDataDir + "/project_filepath_check"); QbsRunParameters params(QStringList("-f") << "project1.qbs"); QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("main.cpp"), m_qbsStdout.constData()); QCOMPARE(runQbs(params), 0); params.arguments = QStringList("-f") << "project2.qbs"; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY(m_qbsStderr.contains("project file")); params.arguments = QStringList("-f") << "project2.qbs"; params.command = "resolve"; params.expectFailure = false; QCOMPARE(runQbs(params), 0); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("main2.cpp"), m_qbsStdout.constData()); } void TestBlackbox::checkTimestamps() { QDir::setCurrent(testDataDir + "/check-timestamps"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling file.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY(QFile::remove(relativeBuildGraphFilePath())); WAIT_FOR_NEW_TIMESTAMP(); touch("file.h"); QCOMPARE(runQbs(QStringList("--check-timestamps")), 0); QVERIFY2(m_qbsStdout.contains("compiling file.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::chooseModuleInstanceByPriorityAndVersion() { QFETCH(QString, idol); QFETCH(QStringList, expectedSubStrings); QFETCH(bool, expectSuccess); QDir::setCurrent(testDataDir + "/choose-module-instance"); rmDirR(relativeBuildDir()); QbsRunParameters params(QStringList("modules.qbs.targetPlatform:" + idol)); params.expectFailure = !expectSuccess; if (expectSuccess) { QCOMPARE(runQbs(params), 0); } else { QVERIFY(runQbs(params) != 0); return; } const QString installRoot = relativeBuildDir() + "/install-root/"; QVERIFY(QFile::exists(installRoot + "/gerbil.txt")); QFile file(installRoot + "/gerbil.txt"); QVERIFY(file.open(QIODevice::ReadOnly)); const QString content = QString::fromUtf8(file.readAll()); for (const auto &str : expectedSubStrings) { if (content.contains(str)) continue; qDebug() << "content:" << content; qDebug() << "substring:" << str; QFAIL("missing substring"); } } void TestBlackbox::chooseModuleInstanceByPriorityAndVersion_data() { QTest::addColumn("idol"); QTest::addColumn("expectedSubStrings"); QTest::addColumn("expectSuccess"); QTest::newRow("ringo") << "Beatles" << QStringList() << false; QTest::newRow("ritchie1") << "Deep Purple" << QStringList{"slipped", "litchi", "ritchie"} << true; QTest::newRow("ritchie2") << "Rainbow" << QStringList{"slipped", "litchi", "ritchie"} << true; QTest::newRow("lord") << "Whitesnake" << QStringList{"chewed", "cord", "lord"} << true; } class TemporaryDefaultProfileRemover { public: TemporaryDefaultProfileRemover(qbs::Settings *settings) : m_settings(settings), m_defaultProfile(settings->defaultProfile()) { m_settings->remove(QStringLiteral("defaultProfile")); } ~TemporaryDefaultProfileRemover() { if (!m_defaultProfile.isEmpty()) m_settings->setValue(QStringLiteral("defaultProfile"), m_defaultProfile); } private: qbs::Settings *m_settings; const QString m_defaultProfile; }; void TestBlackbox::assembly() { QDir::setCurrent(testDataDir + "/assembly"); QVERIFY(runQbs(QbsRunParameters("resolve")) == 0); if (m_qbsStdout.contains("is emscripten: true")) QSKIP("Irrelevant for emscripten"); QVERIFY(m_qbsStdout.contains("is emscripten: false")); QVERIFY(runQbs() == 0); const QVariantMap properties = ([&]() { QFile propertiesFile(relativeProductBuildDir("assembly") + "/properties.json"); if (propertiesFile.open(QIODevice::ReadOnly)) return QJsonDocument::fromJson(propertiesFile.readAll()).toVariant().toMap(); return QVariantMap{}; })(); QVERIFY(!properties.empty()); const auto toolchain = properties.value("qbs.toolchain").toStringList(); QVERIFY(!toolchain.empty()); const bool haveGcc = toolchain.contains("gcc"); const bool haveMSVC = toolchain.contains("msvc"); 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); } void TestBlackbox::autotestWithDependencies() { QDir::setCurrent(testDataDir + "/autotest-with-dependencies"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QStringList({"-p", "autotest-runner"})), 0); QVERIFY2(m_qbsStdout.contains("i am the test app") && m_qbsStdout.contains("i am the helper"), m_qbsStdout.constData()); } void TestBlackbox::autotestTimeout() { QFETCH(QStringList, resolveParams); QFETCH(bool, expectFailure); QFETCH(QString, errorDetails); QDir::setCurrent(testDataDir + "/autotest-timeout"); QbsRunParameters resolveParameters("resolve", resolveParams); QCOMPARE(runQbs(resolveParameters), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters buildParameters(QStringList({"-p", "autotest-runner"})); buildParameters.expectFailure = expectFailure; if (expectFailure) { QVERIFY(runQbs(buildParameters) != 0); QVERIFY( m_qbsStderr.contains("cancelled") && m_qbsStderr.contains("timeout") && m_qbsStderr.contains(errorDetails.toLocal8Bit())); } else QVERIFY(runQbs(buildParameters) == 0); } void TestBlackbox::autotestTimeout_data() { QTest::addColumn("resolveParams"); QTest::addColumn("expectFailure"); QTest::addColumn("errorDetails"); QTest::newRow("no timeout") << QStringList() << false << QString(); QTest::newRow("timeout on test") << QStringList({"products.testApp.autotest.timeout:2"}) << true << QString("testApp"); QTest::newRow("timeout on runner") << QStringList({"products.autotest-runner.timeout:2"}) << true << QString("testApp"); } void TestBlackbox::autotests_data() { QTest::addColumn("evilPropertySpec"); QTest::addColumn("expectedErrorMessage"); QTest::newRow("missing arguments") << QString("products.test1.autotest.arguments:[]") << QByteArray("This test needs exactly one argument"); QTest::newRow("missing working dir") << QString("products.test2.autotest.workingDir:''") << QByteArray("Test resource not found"); QTest::newRow("missing flaky specifier") << QString("products.test3.autotest.allowFailure:false") << QByteArray("I am an awful test"); QTest::newRow("everything's fine") << QString() << QByteArray(); } void TestBlackbox::autotests() { QDir::setCurrent(testDataDir + "/autotests"); QFETCH(QString, evilPropertySpec); QFETCH(QByteArray, expectedErrorMessage); QbsRunParameters resolveParams("resolve"); if (!evilPropertySpec.isEmpty()) resolveParams.arguments << evilPropertySpec; QCOMPARE(runQbs(resolveParams), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters testParams(QStringList{"-p", "autotest-runner"}); if (!evilPropertySpec.isEmpty()) testParams.expectFailure = true; QCOMPARE(runQbs(testParams) == 0, !testParams.expectFailure); if (testParams.expectFailure) { QVERIFY2(m_qbsStderr.contains(expectedErrorMessage), m_qbsStderr.constData()); return; } QVERIFY2(m_qbsStdout.contains("running test test1") && m_qbsStdout.contains("running test test2") && m_qbsStdout.contains("running test test3"), m_qbsStdout.constData()); QCOMPARE(m_qbsStdout.count("PASS"), 2); QCOMPARE(m_qbsStderr.count("FAIL"), 1); } void TestBlackbox::auxiliaryInputsFromDependencies() { QDir::setCurrent(testDataDir + "/aux-inputs-from-deps"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating dummy.out"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.dep.sleep:false"))), 0); WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("generating dummy.out"), m_qbsStdout.constData()); } void TestBlackbox::explicitlyDependsOn() { QFETCH(QString, useExplicitlyDependsOn); QFETCH(QString, useExplicitlyDependsOnFromDependencies); QFETCH(QString, useModule); QFETCH(bool, expectFailure); QDir::setCurrent(testDataDir + "/explicitly-depends-on"); QbsRunParameters params("", QStringList("products.prod1.useExplicitlyDependsOn:" + useExplicitlyDependsOn) << "products.prod1.useExplicitlyDependsOnFromDependencies:" + useExplicitlyDependsOnFromDependencies << "projects.proj1.useModule:" + useModule); params.expectFailure = expectFailure; rmDirR(relativeBuildDir()); if (params.expectFailure) { // Build should fail because a rule cycle is created within the product when // explicitlyDependsOn is used. QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Cycle detected in rule dependencies"), m_qbsStderr.constData()); } else { // When explicitlyDependsOnFromDependencies is used, build should succeed due to the // "final" tag being pulled in from dependencies. QCOMPARE(runQbs(params), 0); if (useModule == QLatin1String("false")) { QVERIFY2(m_qbsStdout.contains("creating 'product-fish.txt' tagged with 'final'"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("Using explicitlyDependsOnArtifact: product-fish.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("step1 -> step2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("step2 -> step3"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("step3 -> final"), m_qbsStdout.constData()); } else { QVERIFY2(!m_qbsStdout.contains("creating 'product-fish.txt' tagged with 'final'"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("Using explicitlyDependsOnArtifact: module-fish.txt"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("step1 -> step2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("step2 -> step3"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("step3 -> final"), m_qbsStdout.constData()); } } } void TestBlackbox::explicitlyDependsOn_data() { QTest::addColumn("useExplicitlyDependsOn"); QTest::addColumn("useExplicitlyDependsOnFromDependencies"); QTest::addColumn("useModule"); QTest::addColumn("expectFailure"); QTest::newRow("useExplicitlyDependsOn -> causes cycle") << "true" << "false" << "false" << true; QTest::newRow("explicitlyDependsOnFromDependencies + product") << "false" << "true" << "false" << false; QTest::newRow("explicitlyDependsOnFromDependencies + module + filesAreTargets") << "false" << "true" << "true" << false; } static bool haveMakeNsis() { QStringList regKeys; regKeys << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS") << QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS"); QStringList paths = QProcessEnvironment::systemEnvironment().value("PATH") .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); for (const QString &key : std::as_const(regKeys)) { QSettings settings(key, QSettings::NativeFormat); QString str = settings.value(QStringLiteral(".")).toString(); if (!str.isEmpty()) paths.prepend(str); } bool haveMakeNsis = false; for (const QString &path : std::as_const(paths)) { if (regularFileExists(QDir::fromNativeSeparators(path) + HostOsInfo::appendExecutableSuffix(QStringLiteral("/makensis")))) { haveMakeNsis = true; break; } } return haveMakeNsis; } void TestBlackbox::nsis() { if (!haveMakeNsis()) { QSKIP("makensis is not installed"); return; } QDir::setCurrent(testDataDir + "/nsis"); QVERIFY(runQbs() == 0); const bool targetIsWindows = m_qbsStdout.contains("is Windows: true"); const bool targetIsNotWindows = m_qbsStdout.contains("is Windows: false"); QCOMPARE(targetIsWindows, !targetIsNotWindows); QCOMPARE(m_qbsStdout.contains("compiling hello.nsi"), targetIsWindows); QCOMPARE( m_qbsStdout.contains("SetCompressor ignored due to previous call with the /FINAL switch"), targetIsWindows); QVERIFY(!QFile::exists(defaultInstallRoot + "/you-should-not-see-a-file-with-this-name.exe")); } void TestBlackbox::nsisDependencies() { if (!haveMakeNsis()) { QSKIP("makensis is not installed"); return; } QDir::setCurrent(testDataDir + "/nsisDependencies"); QCOMPARE(runQbs(), 0); const bool targetIsWindows = m_qbsStdout.contains("is Windows: true"); const bool targetIsNotWindows = m_qbsStdout.contains("is Windows: false"); QCOMPARE(targetIsWindows, !targetIsNotWindows); QCOMPARE(m_qbsStdout.contains("compiling hello.nsi"), targetIsWindows); } void TestBlackbox::outOfDateMarking() { QDir::setCurrent(testDataDir + "/out-of-date-marking"); for (int i = 0; i < 25; ++i) { QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("generating myheader.h"), qPrintable(QString::number(i))); QVERIFY2(m_qbsStdout.contains("compiling main.c"), qPrintable(QString::number(i))); } } 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("modules.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("file"); QTest::addColumn("enable"); QTest::addColumn("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::isMacosHost()) { 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() << "modules.cpp.enableRtti:true"; rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); if (HostOsInfo::isMacosHost()) { params.arguments = QStringList() << "modules.cpp.enableRtti:true" << "project.treatAsObjcpp:true"; rmDirR(relativeBuildDir()); QCOMPARE(runQbs(params), 0); } params.expectFailure = true; params.arguments = QStringList() << "modules.cpp.enableRtti:false"; rmDirR(relativeBuildDir()); QVERIFY(runQbs(params) != 0); if (HostOsInfo::isMacosHost()) { params.arguments = QStringList() << "modules.cpp.enableRtti:false" << "project.treatAsObjcpp:true"; rmDirR(relativeBuildDir()); QVERIFY(runQbs(params) != 0); } } void TestBlackbox::envMerging() { QDir::setCurrent(testDataDir + "/env-merging"); QbsRunParameters params("resolve"); QString pathVal = params.environment.value("PATH"); pathVal.prepend(HostOsInfo::pathListSeparator()).prepend("/opt/blackbox/bin"); const QString keyName = HostOsInfo::isWindowsHost() ? "pATh" : "PATH"; params.environment.insert(keyName, pathVal); QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); params.command = "build"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(QByteArray("PATH=/opt/tool/bin") + HostOsInfo::pathListSeparator().toLatin1()) && m_qbsStdout.contains(HostOsInfo::pathListSeparator().toLatin1() + QByteArray("/opt/blackbox/bin")), m_qbsStdout.constData()); } void TestBlackbox::envNormalization() { QDir::setCurrent(testDataDir + "/env-normalization"); QbsRunParameters params; params.environment.insert("myvar", "x"); QCOMPARE(runQbs(params), 0); if (HostOsInfo::isWindowsHost()) QVERIFY2(m_qbsStdout.contains("\"MYVAR\":\"x\""), m_qbsStdout.constData()); else QVERIFY2(m_qbsStdout.contains("\"myvar\":\"x\""), m_qbsStdout.constData()); } void TestBlackbox::generatedArtifactAsInputToDynamicRule() { QDir::setCurrent(testDataDir + "/generated-artifact-as-input-to-dynamic-rule"); QCOMPARE(runQbs(), 0); const QString oldFile = relativeProductBuildDir("p") + "/old.txt"; QVERIFY2(regularFileExists(oldFile), qPrintable(oldFile)); WAIT_FOR_NEW_TIMESTAMP(); QFile inputFile("input.txt"); QVERIFY2(inputFile.open(QIODevice::WriteOnly), qPrintable(inputFile.errorString())); inputFile.resize(0); inputFile.write("new.txt"); inputFile.close(); QCOMPARE(runQbs(), 0); QVERIFY2(!regularFileExists(oldFile), qPrintable(oldFile)); const QString newFile = relativeProductBuildDir("p") + "/new.txt"; QVERIFY2(regularFileExists(newFile), qPrintable(oldFile)); QVERIFY2(m_qbsStdout.contains("generating"), m_qbsStdout.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("generating"), m_qbsStdout.constData()); } void TestBlackbox::generateLinkerMapFile() { QDir::setCurrent(testDataDir + "/generate-linker-map-file"); QCOMPARE(runQbs(), 0); const bool isUsed = m_qbsStdout.contains("use test: true"); const bool isNotUsed = m_qbsStdout.contains("use test: false"); QVERIFY(isUsed != isNotUsed); if (isUsed) { QVERIFY(QFile::exists(relativeProductBuildDir("app-map") + "/app-map.map")); QVERIFY(!QFile::exists(relativeProductBuildDir("app-nomap") + "/app-nomap.map")); QVERIFY(!QFile::exists(relativeProductBuildDir("app-nomap-default") + "/app-nomap-default.map")); } else { QSKIP("Unsupported toolchain. Skipping."); } } void TestBlackbox::generator() { QFETCH(QString, inputFile); QFETCH(QStringList, toBeCompiled); QDir::setCurrent(testDataDir + "/generator"); if (!inputFile.isEmpty()) { WAIT_FOR_NEW_TIMESTAMP(); QFile input(inputFile); QFile output("input.txt"); QVERIFY2(!output.exists() || output.remove(), qPrintable(output.errorString())); QVERIFY2(input.copy(output.fileName()), qPrintable(input.errorString())); touch(output.fileName()); } QCOMPARE(runQbs(), 0); QCOMPARE(toBeCompiled.contains("main.cpp"), m_qbsStdout.contains("compiling main.cpp")); QCOMPARE(toBeCompiled.contains("file1.cpp"), m_qbsStdout.contains("compiling file1.cpp")); QCOMPARE(toBeCompiled.contains("file2.cpp"), m_qbsStdout.contains("compiling file2.cpp")); } void TestBlackbox::generator_data() { QTest::addColumn("inputFile"); QTest::addColumn("toBeCompiled"); QTest::newRow("both") << "input.both.txt" << QStringList{"main.cpp", "file1.cpp", "file2.cpp"}; QTest::newRow("file1") << "input.file1.txt" << QStringList{"file1.cpp"}; QTest::newRow("file2") << "input.file2.txt" << QStringList{"file2.cpp"}; QTest::newRow("none") << "input.none.txt" << QStringList(); QTest::newRow("both again") << "input.both.txt" << QStringList{"file1.cpp", "file2.cpp"}; QTest::newRow("no update") << QString() << QStringList(); } void TestBlackbox::nodejs() { const SettingsPtr s = settings(); qbs::Profile p(profileName(), s.get()); int status; findNodejs(&status); QCOMPARE(status, 0); QDir::setCurrent(testDataDir + QLatin1String("/nodejs")); status = runQbs(); if (p.value("nodejs.toolchainInstallPath").toString().isEmpty() && status != 0 && m_qbsStderr.contains("toolchainInstallPath")) { QSKIP("nodejs.toolchainInstallPath not set and automatic detection failed"); } if (p.value("nodejs.packageManagerPrefixPath").toString().isEmpty() && status != 0 && m_qbsStderr.contains("nodejs.packageManagerPrefixPath")) { QSKIP("nodejs.packageManagerFilePath not set and automatic detection failed"); } if (p.value("nodejs.interpreterFilePath").toString().isEmpty() && status != 0 && m_qbsStderr.contains("interpreterPath")) { QSKIP("nodejs.interpreterFilePath not set and automatic detection failed"); } if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(status, 0); QbsRunParameters params; params.command = QLatin1String("run"); QCOMPARE(runQbs(params), 0); QVERIFY((bool)m_qbsStdout.contains("hello world")); QVERIFY(regularFileExists(relativeProductBuildDir("hello") + "/hello.js")); } void TestBlackbox::typescript() { if (qEnvironmentVariableIsSet("GITHUB_ACTIONS")) QSKIP("Skip this test when running on GitHub"); if (qEnvironmentVariableIsSet("EMSDK")) QSKIP("Skip this test when running with wasm"); const SettingsPtr s = settings(); qbs::Profile p(profileName(), s.get()); int status; findTypeScript(&status); QCOMPARE(status, 0); QDir::setCurrent(testDataDir + QLatin1String("/typescript")); QbsRunParameters params; params.expectFailure = true; status = runQbs(params); if (p.value("typescript.toolchainInstallPath").toString().isEmpty() && status != 0) { if (m_qbsStderr.contains("Path\" must be specified")) QSKIP("typescript probe failed"); 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"); } if (status != 0) qDebug() << m_qbsStderr; QCOMPARE(status, 0); params.expectFailure = false; params.command = QStringLiteral("run"); params.arguments = QStringList() << "-p" << "animals"; QCOMPARE(runQbs(params), 0); QVERIFY(regularFileExists(relativeProductBuildDir("animals") + "/animals.js")); QVERIFY(regularFileExists(relativeProductBuildDir("animals") + "/extra.js")); QVERIFY(regularFileExists(relativeProductBuildDir("animals") + "/main.js")); } void TestBlackbox::undefinedTargetPlatform() { QDir::setCurrent(testDataDir + "/undefined-target-platform"); QCOMPARE(runQbs(), 0); } void TestBlackbox::importInPropertiesCondition() { QDir::setCurrent(testDataDir + "/import-in-properties-condition"); QCOMPARE(runQbs(), 0); } void TestBlackbox::importSearchPath() { QDir::setCurrent(testDataDir + "/import-searchpath"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling somefile.cpp"), m_qbsStdout.constData()); } void TestBlackbox::importingProduct() { QDir::setCurrent(testDataDir + "/importing-product"); QCOMPARE(runQbs(), 0); } void TestBlackbox::importsConflict() { QDir::setCurrent(testDataDir + "/imports-conflict"); QCOMPARE(runQbs(), 0); } void TestBlackbox::includeLookup() { QDir::setCurrent(testDataDir + "/includeLookup"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("definition.."), m_qbsStdout.constData()); } void TestBlackbox::inputTagsChangeTracking_data() { QTest::addColumn("generateInput"); QTest::newRow("source artifact") << QString("no"); QTest::newRow("generated artifact (static)") << QString("static"); QTest::newRow("generated artifact (dynamic)") << QString("dynamic"); } void TestBlackbox::inputTagsChangeTracking() { QDir::setCurrent(testDataDir + "/input-tags-change-tracking"); const QString xOut = QDir::currentPath() + '/' + relativeProductBuildDir("p") + "/x.out"; const QString yOut = QDir::currentPath() + '/' + relativeProductBuildDir("p") + "/y.out"; QFETCH(QString, generateInput); const QbsRunParameters resolveParams("resolve", QStringList("products.p.generateInput:" + generateInput)); QCOMPARE(runQbs(resolveParams), 0); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("generating input.txt") == (generateInput == "static")); QVERIFY2(!QFile::exists(xOut), qPrintable(xOut)); QVERIFY2(!QFile::exists(yOut), qPrintable(yOut)); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("input-tags-change-tracking.qbs", "Tags: [\"txt\", \"empty\"]", "Tags: \"txt\""); QCOMPARE(runQbs(), 0); QVERIFY2(QFile::exists(xOut), qPrintable(xOut)); QVERIFY2(!QFile::exists(yOut), qPrintable(yOut)); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("input-tags-change-tracking.qbs", "Tags: \"txt\"", "Tags: [\"txt\", \"y\"]"); QCOMPARE(runQbs(), 0); QVERIFY2(!QFile::exists(xOut), qPrintable(xOut)); QVERIFY2(QFile::exists(yOut), qPrintable(yOut)); WAIT_FOR_NEW_TIMESTAMP(); REPLACE_IN_FILE("input-tags-change-tracking.qbs", "Tags: [\"txt\", \"y\"]", "Tags: [\"txt\", \"empty\"]"); QCOMPARE(runQbs(), 0); QVERIFY2(!QFile::exists(xOut), qPrintable(xOut)); QVERIFY2(!QFile::exists(yOut), qPrintable(yOut)); } void TestBlackbox::outputArtifactAutoTagging() { QDir::setCurrent(testDataDir + QLatin1String("/output-artifact-auto-tagging")); QCOMPARE(runQbs(), 0); QVERIFY( regularFileExists(relativeExecutableFilePath("output-artifact-auto-tagging", m_qbsStdout))); } void TestBlackbox::outputRedirection() { QDir::setCurrent(testDataDir + "/output-redirection"); QCOMPARE(runQbs(), 0); TEXT_FILE_COMPARE("output.txt", relativeProductBuildDir("the-product") + "/output.txt"); TEXT_FILE_COMPARE("output.bin", relativeProductBuildDir("the-product") + "/output.bin"); } void TestBlackbox::wildCardsAndRules() { QDir::setCurrent(testDataDir + "/wildcards-and-rules"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("creating output artifact")); QFile output(relativeProductBuildDir("wildcards-and-rules") + "/test.mytype"); QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString())); QCOMPARE(output.readAll().count('\n'), 1); output.close(); // Add input. WAIT_FOR_NEW_TIMESTAMP(); touch("input2.inp"); QbsRunParameters params; params.expectFailure = true; QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("creating output artifact")); QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString())); QCOMPARE(output.readAll().count('\n'), 2); output.close(); // Add "explicitlyDependsOn". WAIT_FOR_NEW_TIMESTAMP(); touch("dep.dep"); QCOMPARE(runQbs(), 0); QVERIFY(m_qbsStdout.contains("creating output artifact")); // Add nothing. QCOMPARE(runQbs(), 0); QVERIFY(!m_qbsStdout.contains("creating output artifact")); } void TestBlackbox::wildCardsAndChangeTracking_data() { QTest::addColumn("dirToModify"); QTest::addColumn("expectReResolve"); QTest::newRow("root path") << QString(".") << false; QTest::newRow("dir with recursive match") << QString("recursive1") << false; QTest::newRow("non-recursive base dir") << QString("nonrecursive") << true; QTest::newRow("empty base dir with file patterns") << QString("nonrecursive/empty") << true; } void TestBlackbox::wildCardsAndChangeTracking() { QFETCH(QString, dirToModify); QFETCH(bool, expectReResolve); const QString srcDir = testDataDir + "/wildcards-and-change-tracking"; QDir::setCurrent(srcDir); rmDirR("default"); QDir::current().mkdir("nonrecursive/empty"); QCOMPARE(runQbs({"resolve"}), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); touch(dirToModify + "/blubb.txt"); QCOMPARE(runQbs({"resolve"}), 0); QCOMPARE(m_qbsStdout.contains("Resolving"), expectReResolve); } void TestBlackbox::loadableModule() { QDir::setCurrent(testDataDir + QLatin1String("/loadablemodule")); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("foo = 42"), m_qbsStdout.constData()); } void TestBlackbox::localDeployment() { QDir::setCurrent(testDataDir + "/localDeployment"); QFile main("main.cpp"); QVERIFY(main.open(QIODevice::ReadOnly)); QByteArray content = main.readAll(); content.replace('\r', ""); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; params.command = "run"; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains(content), m_qbsStdout.constData()); } void TestBlackbox::makefileGenerator() { QDir::setCurrent(testDataDir + "/makefile-generator"); const QbsRunParameters params("generate", QStringList{"-g", "makefile"}); QCOMPARE(runQbs(params), 0); if (HostOsInfo::isWindowsHost()) return; if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QProcess make; make.setWorkingDirectory(QDir::currentPath() + '/' + relativeBuildDir()); const QString customInstallRoot = QDir::currentPath() + "/my-install-root"; make.start("make", QStringList{"INSTALL_ROOT=" + customInstallRoot, "install"}); QVERIFY(waitForProcessSuccess(make)); QVERIFY(QFile::exists(relativeExecutableFilePath("the app", m_qbsStdout))); QVERIFY(!QFile::exists(relativeBuildGraphFilePath())); QProcess app; app.start(customInstallRoot + "/usr/local/bin/the app", QStringList()); QVERIFY(waitForProcessSuccess(app)); const QByteArray appStdout = app.readAllStandardOutput(); QVERIFY2(appStdout.contains("Hello, World!"), appStdout.constData()); make.start("make", QStringList("clean")); QVERIFY(waitForProcessSuccess(make)); QVERIFY(!QFile::exists(relativeExecutableFilePath("the app", m_qbsStdout))); } void TestBlackbox::maximumCLanguageVersion() { QDir::setCurrent(testDataDir + "/maximum-c-language-version"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:true"))), 0); const bool isMsvc = m_qbsStdout.contains("is msvc: true"); if (isMsvc && m_qbsStdout.contains("is old msvc: true")) QSKIP("MSVC supports setting the C language version only from version 16.8, and Clang from version 13."); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); QVERIFY2(m_qbsStdout.contains("c11") || m_qbsStdout.contains("c1x"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:false"))), 0); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); if (isMsvc) QVERIFY2(!m_qbsStdout.contains("c11"), m_qbsStdout.constData()); else QVERIFY2(m_qbsStdout.contains("c99"), m_qbsStdout.constData()); } void TestBlackbox::maximumCxxLanguageVersion() { QDir::setCurrent(testDataDir + "/maximum-cxx-language-version"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:true"))), 0); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); QVERIFY2(m_qbsStdout.contains("c++23") || m_qbsStdout.contains("c++2b") || m_qbsStdout.contains("c++latest"), m_qbsStdout.constData()); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.enableNewestModule:false"))), 0); QCOMPARE(runQbs(QStringList({"--command-echo-mode", "command-line", "-n"})), 0); QVERIFY2(m_qbsStdout.contains("c++14") || m_qbsStdout.contains("c++1y"), m_qbsStdout.constData()); } void TestBlackbox::minimumSystemVersion() { rmDirR(relativeBuildDir()); QDir::setCurrent(testDataDir + "/minimumSystemVersion"); QFETCH(QString, file); QFETCH(QString, output); QbsRunParameters params({ "-f", file + ".qbs" }); params.command = "resolve"; QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); params.command = "run"; QCOMPARE(runQbs(params), 0); if (m_qbsStdout.contains("Unsupported compiler")) QSKIP("Unsupported compiler"); if (!m_qbsStdout.contains(output.toUtf8())) { qDebug() << "expected output:" << qPrintable(output); qDebug() << "actual output:" << m_qbsStdout.constData(); } QVERIFY(m_qbsStdout.contains(output.toUtf8())); } static qbs::Version fromMinimumDeploymentTargetValue(int v, bool isMacOS) { if (isMacOS && v < 100000) return qbs::Version(v / 100, v / 10 % 10, v % 10); return qbs::Version(v / 10000, v / 100 % 100, v % 100); } static int toMinimumDeploymentTargetValue(const qbs::Version &v, bool isMacOS) { if (isMacOS && v < qbs::Version(10, 10)) return (v.majorVersion() * 100) + (v.minorVersion() * 10) + v.patchLevel(); return (v.majorVersion() * 10000) + (v.minorVersion() * 100) + v.patchLevel(); } static qbs::Version defaultClangMinimumDeploymentTarget() { QProcess process; process.start("/usr/bin/xcrun", {"-sdk", "macosx", "clang++", "-target", "x86_64-apple-macosx-macho", "-dM", "-E", "-x", "objective-c++", "/dev/null"}); if (waitForProcessSuccess(process)) { const auto lines = process.readAllStandardOutput().split('\n'); for (const auto &line : lines) { static const QByteArray prefix = "#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ "; if (line.startsWith(prefix)) { bool ok = false; int v = line.mid(prefix.size()).trimmed().toInt(&ok); if (ok) return fromMinimumDeploymentTargetValue(v, true); break; } } } return qbs::Version(); } void TestBlackbox::minimumSystemVersion_data() { QTest::addColumn("file"); QTest::addColumn("output"); // Don't check for the full "version X.Y.Z\n" on macOS as some older versions of otool don't // show the patch version. Instead, simply check for "version X.Y" with no trailing \n. const QString unspecified = []() -> QString { if (HostOsInfo::isMacosHost()) { const auto v = defaultClangMinimumDeploymentTarget(); auto result = "__MAC_OS_X_VERSION_MIN_REQUIRED=" + QString::number(toMinimumDeploymentTargetValue(v, true)); if (v >= qbs::Version(10, 14)) result += "\nminos "; else result += "\nversion "; result += QString::number(v.majorVersion()) + "." + QString::number(v.minorVersion()); return result; } if (HostOsInfo::isWindowsHost()) return "WINVER is not defined\n"; return ""; }(); const QString specific = []() -> QString { if (HostOsInfo::isMacosHost()) return "__MAC_OS_X_VERSION_MIN_REQUIRED=1070\nversion 10.7\n"; if (HostOsInfo::isWindowsHost()) return "WINVER=1538\n6.02 operating system version\n6.02 subsystem version\n"; return ""; }(); QTest::newRow("unspecified") << "unspecified" << unspecified; QTest::newRow("unspecified-forced") << "unspecified-forced" << unspecified; if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacosHost()) QTest::newRow("specific") << "specific" << specific; if (HostOsInfo::isWindowsHost()) QTest::newRow("fakewindows") << "fakewindows" << "WINVER=1283\n5.03 operating system " "version\n5.03 subsystem version\n"; if (HostOsInfo::isMacosHost()) QTest::newRow("macappstore") << "macappstore" << "__MAC_OS_X_VERSION_MIN_REQUIRED=1071\n" "version 10.7"; } void TestBlackbox::missingBuildGraph() { QTemporaryDir tmpDir; QVERIFY(tmpDir.isValid()); QDir::setCurrent(tmpDir.path()); QFETCH(QString, configName); const QStringList commands({"clean", "dump-nodes-tree", "status", "update-timestamps"}); const QString actualConfigName = configName.isEmpty() ? QString("default") : configName; QbsRunParameters params; params.expectFailure = true; params.arguments << QLatin1String("config:") + actualConfigName; for (const QString &command : std::as_const(commands)) { params.command = command; QVERIFY2(runQbs(params) != 0, qPrintable(command)); const QString expectedErrorMessage = QString("Build graph not found for " "configuration '%1'").arg(actualConfigName); if (!m_qbsStderr.contains(expectedErrorMessage.toLocal8Bit())) { qDebug() << command; qDebug() << expectedErrorMessage; qDebug() << m_qbsStderr; QFAIL("unexpected error message"); } } } void TestBlackbox::missingBuildGraph_data() { QTest::addColumn("configName"); QTest::newRow("implicit config name") << QString(); QTest::newRow("explicit config name") << QString("customConfig"); } void TestBlackbox::missingDependency() { QDir::setCurrent(testDataDir + "/missing-dependency"); QbsRunParameters params; params.expectFailure = true; params.arguments << "-p" << "theApp"; QVERIFY(runQbs(params) != 0); QVERIFY2(!m_qbsStderr.contains("ASSERT"), m_qbsStderr.constData()); QCOMPARE(runQbs(QbsRunParameters(QStringList() << "-p" << "theDep")), 0); params.expectFailure = false; params.arguments << "-vv"; QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStderr.contains("false positive")); } void TestBlackbox::missingProjectFile() { QDir::setCurrent(testDataDir + "/missing-project-file/empty-dir"); QbsRunParameters params; params.expectFailure = true; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("No project file given and none found in current directory"), m_qbsStderr.constData()); QDir::setCurrent(testDataDir + "/missing-project-file"); params.arguments << "-f" << "empty-dir"; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("No project file found in directory"), m_qbsStderr.constData()); params.arguments = QStringList() << "-f" << "ambiguous-dir"; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("More than one project file found in directory"), m_qbsStderr.constData()); params.expectFailure = false; params.arguments = QStringList() << "-f" << "project-dir"; QCOMPARE(runQbs(params), 0); WAIT_FOR_NEW_TIMESTAMP(); touch("project-dir/file.cpp"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling file.cpp"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::missingOverridePrefix() { QDir::setCurrent(testDataDir + "/missing-override-prefix"); QbsRunParameters params; params.expectFailure = true; params.arguments << "blubb.whatever:false"; QVERIFY(runQbs(params) != 0); QVERIFY2(m_qbsStderr.contains("Property override key 'blubb.whatever' not understood"), m_qbsStderr.constData()); } void TestBlackbox::moduleConditions() { QDir::setCurrent(testDataDir + "/module-conditions"); QCOMPARE(runQbs(), 0); QCOMPARE(m_qbsStdout.count("loaded m1"), 1); QCOMPARE(m_qbsStdout.count("loaded m2"), 2); QCOMPARE(m_qbsStdout.count("loaded m3"), 1); QCOMPARE(m_qbsStdout.count("loaded m4"), 1); } void TestBlackbox::movedFileDependency() { QDir::setCurrent(testDataDir + "/moved-file-dependency"); const QString subdir2 = QDir::currentPath() + "/subdir2"; QVERIFY(QDir::current().mkdir(subdir2)); const QString oldHeaderFilePath = QDir::currentPath() + "/subdir1/theheader.h"; const QString newHeaderFilePath = subdir2 + "/theheader.h"; QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QFile f(oldHeaderFilePath); QVERIFY2(f.rename(newHeaderFilePath), qPrintable(f.errorString())); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); f.setFileName(newHeaderFilePath); QVERIFY2(f.rename(oldHeaderFilePath), qPrintable(f.errorString())); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::msvcAsmLinkerFlags() { QDir::setCurrent(testDataDir + "/msvc-asm-flags"); QCOMPARE(runQbs(), 0); } void TestBlackbox::badInterpreter() { if (!HostOsInfo::isAnyUnixHost()) QSKIP("only applies on Unix"); QDir::setCurrent(testDataDir + QLatin1String("/badInterpreter")); QCOMPARE(runQbs(), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params("run"); params.expectFailure = true; const QRegularExpression reNoSuchFileOrDir("bad interpreter:.* No such file or directory"); const QRegularExpression rePermissionDenied("bad interpreter:.* Permission denied"); params.arguments = QStringList() << "-p" << "script-interp-missing"; QCOMPARE(runQbs(params), 1); QString strerr = QString::fromLocal8Bit(m_qbsStderr); QVERIFY2(strerr.contains(reNoSuchFileOrDir), m_qbsStderr); params.arguments = QStringList() << "-p" << "script-interp-noexec"; QCOMPARE(runQbs(params), 1); strerr = QString::fromLocal8Bit(m_qbsStderr); QVERIFY2(strerr.contains(reNoSuchFileOrDir) || strerr.contains(rePermissionDenied) || strerr.contains("script-noexec: bad interpreter: execve: Exec format error"), qPrintable(strerr)); params.arguments = QStringList() << "-p" << "script-noexec"; QCOMPARE(runQbs(params), 1); QCOMPARE(runQbs(QbsRunParameters("run", QStringList() << "-p" << "script-ok")), 0); } void TestBlackbox::bomSources() { QDir::setCurrent(testDataDir + "/bom-sources"); const bool success = runQbs() == 0; if (!success) QSKIP("Assuming compiler cannot deal with byte order mark"); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); touch("theheader.h"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); } void TestBlackbox::buildDataOfDisabledProduct() { QDir::setCurrent(testDataDir + QLatin1String("/build-data-of-disabled-product")); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("compiling test.cpp"), m_qbsStdout.constData()); // Touch a source file, disable the product, rebuild the project, verify nothing happens. WAIT_FOR_NEW_TIMESTAMP(); touch("test.cpp"); QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.condition:false"))), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("linking"), m_qbsStdout.constData()); // Enable the product again, rebuild the project, verify that only the changed source file // is rebuilt. QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.app.condition:true"))), 0); QCOMPARE(runQbs(), 0); QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("compiling test.cpp"), m_qbsStdout.constData()); } void TestBlackbox::qbsVersion() { const auto v = qbs::LanguageInfo::qbsVersion(); QDir::setCurrent(testDataDir + QLatin1String("/qbsVersion")); QbsRunParameters params; params.arguments = QStringList() << "project.qbsVersion:" + v.toString() << "project.qbsVersionMajor:" + QString::number(v.majorVersion()) << "project.qbsVersionMinor:" + QString::number(v.minorVersion()) << "project.qbsVersionPatch:" + QString::number(v.patchLevel()); QCOMPARE(runQbs(params), 0); params.arguments.push_back("project.qbsVersionPatch:" + QString::number(v.patchLevel() + 1)); params.expectFailure = true; QVERIFY(runQbs(params) != 0); } void TestBlackbox::transitiveInvalidDependencies() { QDir::setCurrent(testDataDir + "/transitive-invalid-dependencies"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); QVERIFY2(m_qbsStdout.contains("b.present = false"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("c.present = true"), m_qbsStdout); QVERIFY2(m_qbsStdout.contains("d.present = false"), m_qbsStdout); } void TestBlackbox::transitiveOptionalDependencies() { QDir::setCurrent(testDataDir + "/transitive-optional-dependencies"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); } void TestBlackbox::groupsInModules() { QDir::setCurrent(testDataDir + "/groups-in-modules"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling rock.coal to rock.diamond")); QVERIFY(m_qbsStdout.contains("compiling chunk.coal to chunk.diamond")); QVERIFY(m_qbsStdout.contains("compiling helper2.c")); QVERIFY(!m_qbsStdout.contains("compiling helper3.c")); QVERIFY(m_qbsStdout.contains("compiling helper4.c")); QVERIFY(m_qbsStdout.contains("compiling helper5.c")); QVERIFY(!m_qbsStdout.contains("compiling helper6.c")); QVERIFY(m_qbsStdout.contains("compiling helper7.c")); QVERIFY(m_qbsStdout.contains("compiling helper8.c")); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling rock.coal to rock.diamond")); QVERIFY(!m_qbsStdout.contains("compiling chunk.coal to chunk.diamond")); WAIT_FOR_NEW_TIMESTAMP(); touch("modules/helper/diamondc.c"); waitForFileUnlock(); QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling diamondc.c")); QVERIFY(m_qbsStdout.contains("compiling rock.coal to rock.diamond")); QVERIFY(m_qbsStdout.contains("compiling chunk.coal to chunk.diamond")); QVERIFY(regularFileExists(relativeProductBuildDir("groups-in-modules") + "/rock.diamond")); QFile output(relativeProductBuildDir("groups-in-modules") + "/rock.diamond"); QVERIFY(output.open(QIODevice::ReadOnly)); QCOMPARE(output.readAll().trimmed(), QByteArray("diamond")); } void TestBlackbox::grpc_data() { QTest::addColumn("projectFile"); QTest::addColumn("arguments"); QTest::addColumn("hasModules"); QStringList pkgConfigArgs({"project.qbsModuleProviders:qbspkgconfig"}); // on macOS, openSSL is hidden from pkg-config by default if (qbs::Internal::HostOsInfo::isMacosHost()) { pkgConfigArgs << "moduleProviders.qbspkgconfig.extraPaths:/usr/local/opt/openssl@1.1/lib/pkgconfig"; } QTest::newRow("cpp-pkgconfig") << QString("grpc_cpp.qbs") << pkgConfigArgs << true; QStringList conanArgs( {"project.qbsModuleProviders:conan", "moduleProviders.conan.installDirectory:build"}); QTest::newRow("cpp-conan") << QString("grpc_cpp.qbs") << conanArgs << true; } void TestBlackbox::grpc() { QDir::setCurrent(testDataDir + "/grpc"); QFETCH(QString, projectFile); QFETCH(QStringList, arguments); QFETCH(bool, hasModules); rmDirR(relativeBuildDir()); if (QTest::currentDataTag() == QLatin1String("cpp-conan")) { if (!prepareAndRunConan()) QSKIP("conan is not prepared, check messages above"); } QbsRunParameters resolveParams("resolve", QStringList{"-f", projectFile}); resolveParams.arguments << arguments; QCOMPARE(runQbs(resolveParams), 0); const bool withGrpc = m_qbsStdout.contains("has grpc: true"); const bool withoutGrpc = m_qbsStdout.contains("has grpc: false"); QVERIFY2(withGrpc || withoutGrpc, m_qbsStdout.constData()); if (withoutGrpc) QSKIP("grpc module not present"); const bool hasMods = m_qbsStdout.contains("has modules: true"); const bool dontHaveMods = m_qbsStdout.contains("has modules: false"); QVERIFY2(hasMods == !dontHaveMods, m_qbsStdout.constData()); QCOMPARE(hasMods, hasModules); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QbsRunParameters runParams; QCOMPARE(runQbs(runParams), 0); } void TestBlackbox::hostOsProperties() { QDir::setCurrent(testDataDir + "/host-os-properties"); QCOMPARE(runQbs(QStringLiteral("resolve")), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Cannot run binaries in cross-compiled build"); QCOMPARE(runQbs(QStringLiteral("run")), 0); QVERIFY2(m_qbsStdout.contains( ("HOST_ARCHITECTURE = " + HostOsInfo::hostOSArchitecture().toUtf8()).data()), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains( ("HOST_PLATFORM = " + HostOsInfo::hostOSIdentifier().toUtf8()).data()), m_qbsStdout.constData()); } void TestBlackbox::ico() { QDir::setCurrent(testDataDir + "/ico"); QbsRunParameters params; params.expectFailure = true; params.arguments << "--command-echo-mode" << "command-line"; const int status = runQbs(params); if (status != 0) { if (m_qbsStderr.contains("Could not find icotool in any of the following locations:")) QSKIP("icotool is not installed"); if (!m_qbsStderr.isEmpty()) qDebug("%s", m_qbsStderr.constData()); if (!m_qbsStdout.isEmpty()) qDebug("%s", m_qbsStdout.constData()); } QCOMPARE(status, 0); QVERIFY(QFileInfo::exists(relativeProductBuildDir("icon") + "/icon.ico")); { QFile f(relativeProductBuildDir("icon") + "/icon.ico"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll().toStdString(); QCOMPARE(b.at(2), '\x1'); // icon QCOMPARE(b.at(4), '\x2'); // 2 images QVERIFY(b.find("\x89PNG") == std::string::npos); } QVERIFY(QFileInfo::exists(relativeProductBuildDir("icon-alpha") + "/icon-alpha.ico")); { QFile f(relativeProductBuildDir("icon-alpha") + "/icon-alpha.ico"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll().toStdString(); QCOMPARE(b.at(2), '\x1'); // icon QCOMPARE(b.at(4), '\x2'); // 2 images QVERIFY(b.find("\x89PNG") == std::string::npos); QVERIFY2(m_qbsStdout.contains("--alpha-threshold="), m_qbsStdout.constData()); } QVERIFY(QFileInfo::exists(relativeProductBuildDir("icon-big") + "/icon-big.ico")); { QFile f(relativeProductBuildDir("icon-big") + "/icon-big.ico"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll().toStdString(); QCOMPARE(b.at(2), '\x1'); // icon QCOMPARE(b.at(4), '\x5'); // 5 images QVERIFY(b.find("\x89PNG") != std::string::npos); } QVERIFY(QFileInfo::exists(relativeProductBuildDir("cursor") + "/cursor.cur")); { QFile f(relativeProductBuildDir("cursor") + "/cursor.cur"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll(); QVERIFY(b.size() > 0); QCOMPARE(b.at(2), '\x2'); // cursor QCOMPARE(b.at(4), '\x2'); // 2 images QCOMPARE(b.at(10), '\0'); QCOMPARE(b.at(12), '\0'); QCOMPARE(b.at(26), '\0'); QCOMPARE(b.at(28), '\0'); } QVERIFY(QFileInfo::exists(relativeProductBuildDir("cursor-hotspot") + "/cursor-hotspot.cur")); { QFile f(relativeProductBuildDir("cursor-hotspot") + "/cursor-hotspot.cur"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll(); QVERIFY(b.size() > 0); QCOMPARE(b.at(2), '\x2'); // cursor QCOMPARE(b.at(4), '\x2'); // 2 images const bool hasCursorHotspotBug = m_qbsStderr.contains( "does not support setting the hotspot for cursor files with multiple images"); if (hasCursorHotspotBug) { QCOMPARE(b.at(10), '\0'); QCOMPARE(b.at(12), '\0'); QCOMPARE(b.at(26), '\0'); QCOMPARE(b.at(28), '\0'); qWarning() << "this version of icoutil does not support setting the hotspot " "for cursor files with multiple images"; } else { QCOMPARE(b.at(10), '\x8'); QCOMPARE(b.at(12), '\x9'); QCOMPARE(b.at(26), '\x10'); QCOMPARE(b.at(28), '\x11'); } } QVERIFY(QFileInfo::exists(relativeProductBuildDir("cursor-hotspot-single") + "/cursor-hotspot-single.cur")); { QFile f(relativeProductBuildDir("cursor-hotspot-single") + "/cursor-hotspot-single.cur"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll(); QVERIFY(b.size() > 0); QCOMPARE(b.at(2), '\x2'); // cursor QCOMPARE(b.at(4), '\x1'); // 1 image // No version check needed because the hotspot can always be set if there's only one image QCOMPARE(b.at(10), '\x8'); QCOMPARE(b.at(12), '\x9'); } QVERIFY(QFileInfo::exists(relativeProductBuildDir("iconset") + "/dmg.ico")); { QFile f(relativeProductBuildDir("iconset") + "/dmg.ico"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll(); QVERIFY(b.size() > 0); QCOMPARE(b.at(2), '\x1'); // icon QCOMPARE(b.at(4), '\x5'); // 5 images } QVERIFY(QFileInfo::exists(relativeProductBuildDir("iconset") + "/dmg.cur")); { QFile f(relativeProductBuildDir("iconset") + "/dmg.cur"); QVERIFY(f.open(QIODevice::ReadOnly)); const auto b = f.readAll(); QVERIFY(b.size() > 0); QCOMPARE(b.at(2), '\x2'); // cursor QCOMPARE(b.at(4), '\x5'); // 5 images QCOMPARE(b.at(10), '\0'); QCOMPARE(b.at(12), '\0'); QCOMPARE(b.at(26), '\0'); QCOMPARE(b.at(28), '\0'); } } void TestBlackbox::importAssignment() { QDir::setCurrent(testDataDir + "/import-assignment"); QCOMPARE(runQbs(QStringList("project.qbsSearchPaths:" + QDir::currentPath())), 0); QVERIFY2(m_qbsStdout.contains("key 1 = value1") && m_qbsStdout.contains("key 2 = value2"), m_qbsStdout.constData()); } void TestBlackbox::importChangeTracking() { QDir::setCurrent(testDataDir + "/import-change-tracking"); QCOMPARE(runQbs(QStringList({"-f", "import-change-tracking.qbs"})), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in imported file that is not used in any rule or command. WAIT_FOR_NEW_TIMESTAMP(); touch("irrelevant.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in directly imported file only used by one prepare script. WAIT_FOR_NEW_TIMESTAMP(); touch("custom1prepare1.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in recursively imported file only used by one prepare script. WAIT_FOR_NEW_TIMESTAMP(); touch("custom1prepare2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in imported file used only by one command. WAIT_FOR_NEW_TIMESTAMP(); touch("custom1command.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in file only used by one prepare script, using directory import. WAIT_FOR_NEW_TIMESTAMP(); touch("custom2prepare/custom2prepare2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in file used only by one command, imported via search path. WAIT_FOR_NEW_TIMESTAMP(); touch("imports/custom2command/custom2command1.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in directly imported file only used by one Probe WAIT_FOR_NEW_TIMESTAMP(); touch("probe1.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change in indirectly imported file only used by one Probe WAIT_FOR_NEW_TIMESTAMP(); touch("probe2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); // Change everything at once. WAIT_FOR_NEW_TIMESTAMP(); touch("irrelevant.js"); touch("custom1prepare1.js"); touch("custom1prepare2.js"); touch("custom1command.js"); touch("custom2prepare/custom2prepare1.js"); touch("imports/custom2command/custom2command2.js"); touch("probe2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); } void TestBlackbox::probesInNestedModules() { QDir::setCurrent(testDataDir + "/probes-in-nested-modules"); QbsRunParameters params; QCOMPARE(runQbs(params), 0); QCOMPARE(m_qbsStdout.count("running probe a"), 1); QCOMPARE(m_qbsStdout.count("running probe b"), 1); QCOMPARE(m_qbsStdout.count("running probe c"), 1); QCOMPARE(m_qbsStdout.count("running second probe a"), 1); QVERIFY(m_qbsStdout.contains("product a, outer.somethingElse = goodbye")); QVERIFY(m_qbsStdout.contains("product b, inner.something = hahaha")); QVERIFY(m_qbsStdout.contains("product c, inner.something = hello")); QVERIFY(m_qbsStdout.contains("product a, inner.something = hahaha")); QVERIFY(m_qbsStdout.contains("product a, outer.something = hahaha")); } QTEST_MAIN(TestBlackbox) qbs-src-2.6.1/tests/auto/blackbox/blackbox-baremetal.qbs0000644000175100001660000000101514776170045022572 0ustar runnerdockerimport qbs.Utilities QbsAutotest { testName: "blackbox-baremetal" Depends { name: "qbs_app" } Depends { name: "qbs-setup-toolchains" } Group { name: "testdata" prefix: "testdata-baremetal/" files: ["**/*"] fileTags: [] } files: [ "../shared.h", "tst_blackboxbase.cpp", "tst_blackboxbase.h", "tst_blackboxbaremetal.cpp", "tst_blackboxbaremetal.h", ] cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)]) } qbs-src-2.6.1/tests/auto/blackbox/testdata-clangdb/0000755000175100001660000000000014776170045021550 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-clangdb/project1/0000755000175100001660000000000014776170045023277 5ustar runnerdockerqbs-src-2.6.1/tests/auto/blackbox/testdata-clangdb/project1/project.qbs0000644000175100001660000000212714776170045025456 0ustar runnerdocker// $ g++ 'i like spaces.cpp' '-DSPACES="!have \\fun\x5c!\n"' '-DSPICES=%T% # && $$ 1>&2 '\''\n'\''\n' '-DSLICES=(42>24)' && ./a.out // SPACES=!have \fun\! // SPICES=%T% # && $$ 1>&2 '\n' // SLICES=1 Project { Application { Probe { id: dummy property bool isMingw: qbs.toolchain.includes("mingw") property bool isMsvc: qbs.toolchain.includes("msvc") property var buildEnv: cpp.buildEnv configure: { if (!buildEnv) return; if (isMsvc) { console.info("is msvc"); console.info("INCLUDE=" + buildEnv["INCLUDE"]); console.info("LIB=" + buildEnv["LIB"]); } else if (isMingw) { console.info("is mingw"); console.info("PATH=" + buildEnv["PATH"]); } } } targetName: "i like spaces" Depends { name: "cpp" } cpp.defines: base.concat([ "SPACES=\"!have \\\\fun\\x5c!\\n\"", "SPICES=%T% # && $$ 1>&2 '\\n'\\n", "SLICES=(42>24)" ]); files: ["i like spaces.cpp"] } } qbs-src-2.6.1/tests/auto/blackbox/testdata-clangdb/project1/i like spaces.cpp0000644000175100001660000000274714776170045026411 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include using namespace std; #define _STR(x) #x #define STR(x) _STR(x) int main(int argc, char **argv) { int garbage; int unused = garbage; cout << "SPACES=" << SPACES << "SPICES=" STR(SPICES) << "SLICES=" << SLICES << endl; return 0; } qbs-src-2.6.1/tests/auto/blackbox/tst_blackboxjoblimits.cpp0000644000175100001660000001764314776170045023462 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_blackboxbase.h" #include "../shared.h" #include class TestBlackboxJobLimits : public TestBlackboxBase { Q_OBJECT public: TestBlackboxJobLimits(); private slots: void initTestCase(); void jobLimits_data(); void jobLimits(); }; TestBlackboxJobLimits::TestBlackboxJobLimits() : TestBlackboxBase (SRCDIR "/testdata-joblimits", "blackbox-joblimits") { } void TestBlackboxJobLimits::initTestCase() { TestBlackboxBase::initTestCase(); QDir::setCurrent(testDataDir + "/job-limits-init"); QCOMPARE(runQbs({"resolve"}), 0); if (m_qbsStdout.contains("targetPlatform differs from hostPlatform")) QSKIP("Skip test in cross-compiled build"); } void TestBlackboxJobLimits::jobLimits_data() { QTest::addColumn("projectJobCount"); QTest::addColumn("productJobCount"); QTest::addColumn("moduleJobCount"); QTest::addColumn("prefsJobCount"); QTest::addColumn("cliJobCount"); QTest::addColumn("projectPrecedence"); QTest::addColumn("expectSuccess"); for (int projectJobCount = -1; projectJobCount <= 1; ++projectJobCount) { for (int productJobCount = -1; productJobCount <= 1; ++productJobCount) { for (int moduleJobCount = -1; moduleJobCount <= 1; ++moduleJobCount) { for (int prefsJobCount = -1; prefsJobCount <= 1; ++prefsJobCount) { for (int cliJobCount = -1; cliJobCount <= 1; ++cliJobCount) { QString description = QString("project:%1/" "product:%2/module:%3/prefs:%4/cli:%5/project precedence") .arg(projectJobCount).arg(productJobCount).arg(moduleJobCount) .arg(prefsJobCount).arg(cliJobCount).toLocal8Bit(); bool expectSuccess; switch (productJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: switch (projectJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: switch (moduleJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: switch (cliJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: expectSuccess = prefsJobCount == 1; break; } break; } break; } break; } QTest::newRow(qPrintable(description)) << projectJobCount << productJobCount << moduleJobCount << prefsJobCount << cliJobCount << true << expectSuccess; description = QString("project:%1/" "product:%2/module:%3/prefs:%4/cli:%5/default precedence") .arg(projectJobCount).arg(productJobCount).arg(moduleJobCount) .arg(prefsJobCount).arg(cliJobCount).toLocal8Bit(); switch (cliJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: switch (prefsJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: switch (productJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: switch (projectJobCount) { case 1: expectSuccess = true; break; case 0: expectSuccess = false; break; case -1: expectSuccess = moduleJobCount == 1; break; } break; } break; } break; } QTest::newRow(qPrintable(description)) << projectJobCount << productJobCount << moduleJobCount << prefsJobCount << cliJobCount << false << expectSuccess; } } } } } } void TestBlackboxJobLimits::jobLimits() { QDir::setCurrent(testDataDir + "/job-limits"); QFETCH(int, projectJobCount); QFETCH(int, productJobCount); QFETCH(int, moduleJobCount); QFETCH(int, prefsJobCount); QFETCH(int, cliJobCount); QFETCH(bool, projectPrecedence); QFETCH(bool, expectSuccess); SettingsPtr theSettings = settings(); qbs::Internal::TemporaryProfile profile("jobLimitsProfile", theSettings.get()); profile.p.setValue("preferences.jobLimit.singleton", prefsJobCount); profile.p.setValue("baseProfile", profileName()); theSettings->sync(); QbsRunParameters resolveParams("resolve"); resolveParams.profile = profile.p.name(); resolveParams.arguments << ("project.projectJobCount:" + QString::number(projectJobCount)) << ("project.productJobCount:" + QString::number(productJobCount)) << ("project.moduleJobCount:" + QString::number(moduleJobCount)); QCOMPARE(runQbs(resolveParams), 0); QbsRunParameters buildParams; buildParams.expectFailure = !expectSuccess; if (cliJobCount != -1) buildParams.arguments << "--job-limits" << ("singleton:" + QString::number(cliJobCount)); if (projectPrecedence) buildParams.arguments << "--enforce-project-job-limits"; buildParams.profile = profile.p.name(); const int exitCode = runQbs(buildParams); if (expectSuccess) QCOMPARE(exitCode, 0); else if (exitCode == 0) QSKIP("no failure with no limit in place, result inconclusive"); else QVERIFY2(m_qbsStderr.contains("exclusive"), m_qbsStderr.constData()); if (exitCode == 0) QCOMPARE(m_qbsStdout.count("running tool"), 5); } QTEST_MAIN(TestBlackboxJobLimits) #include qbs-src-2.6.1/tests/auto/auto.qbs0000644000175100001660000000134214776170045016241 0ustar runnerdockerProject { name: "Autotests" references: [ "api/api.qbs", "blackbox/blackbox-android.qbs", "blackbox/blackbox-apple.qbs", "blackbox/blackbox-baremetal.qbs", "blackbox/blackbox-clangdb.qbs", "blackbox/blackbox-examples.qbs", "blackbox/blackbox-java.qbs", "blackbox/blackbox-joblimits.qbs", "blackbox/blackbox-providers.qbs", "blackbox/blackbox-qt.qbs", "blackbox/blackbox-tutorial.qbs", "blackbox/blackbox-windows.qbs", "blackbox/blackbox.qbs", "buildgraph/buildgraph.qbs", "cmdlineparser/cmdlineparser.qbs", "language/language.qbs", "pkgconfig/pkgconfig.qbs", "tools/tools.qbs", ] } qbs-src-2.6.1/tests/auto/buildgraph/0000755000175100001660000000000014776170045016703 5ustar runnerdockerqbs-src-2.6.1/tests/auto/buildgraph/tst_buildgraph.cpp0000644000175100001660000001215614776170045022427 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_buildgraph.h" #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using namespace qbs::Internal; const TopLevelProjectPtr project = TopLevelProject::create(); TestBuildGraph::TestBuildGraph(ILogSink *logSink) : m_logSink(logSink) { project->buildData = std::make_unique(); } void TestBuildGraph::initTestCase() { } void TestBuildGraph::cleanupTestCase() { } bool TestBuildGraph::cycleDetected(const ResolvedProductConstPtr &product) { try { CycleDetector(Logger(m_logSink)).visitProduct(product); return false; } catch (const ErrorInfo &) { return true; } } ResolvedProductConstPtr TestBuildGraph::productWithDirectCycle() { const ResolvedProductPtr product = ResolvedProduct::create(); product->project = project; product->buildData = std::make_unique(); const auto root = new Artifact; root->product = product; const auto child = new Artifact; child->product = product; product->buildData->addRootNode(root); product->buildData->addNode(root); product->buildData->addNode(child); qbs::Internal::connect(root, child); qbs::Internal::connect(child, root); return product; } ResolvedProductConstPtr TestBuildGraph::productWithLessDirectCycle() { const ResolvedProductPtr product = ResolvedProduct::create(); product->project = project; product->buildData = std::make_unique(); const auto root = new Artifact; const auto child = new Artifact; const auto grandchild = new Artifact; root->product = product; child->product = product; grandchild->product = product; product->buildData->addRootNode(root); product->buildData->addNode(root); product->buildData->addNode(child); product->buildData->addNode(grandchild); qbs::Internal::connect(root, child); qbs::Internal::connect(child, grandchild); qbs::Internal::connect(grandchild, root); return product; } // root appears as a child, but in a different tree ResolvedProductConstPtr TestBuildGraph::productWithNoCycle() { const ResolvedProductPtr product = ResolvedProduct::create(); product->project = project; product->buildData = std::make_unique(); const auto root = new Artifact; const auto root2 = new Artifact; root->product = product; root2->product = product; product->buildData->addRootNode(root); product->buildData->addRootNode(root2); product->buildData->addNode(root); product->buildData->addNode(root2); qbs::Internal::connect(root2, root); return product; } void TestBuildGraph::testCycle() { QVERIFY(cycleDetected(productWithDirectCycle())); QVERIFY(cycleDetected(productWithLessDirectCycle())); QVERIFY(!cycleDetected(productWithNoCycle())); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); TestBuildGraph tbg(ConsoleLogger::instance().logSink()); return QTest::qExec(&tbg, argc, argv); } qbs-src-2.6.1/tests/auto/buildgraph/buildgraph.qbs0000644000175100001660000000031614776170045021533 0ustar runnerdockerQbsUnittest { Depends { name: "qbsconsolelogger" } testName: "buildgraph" condition: qbsbuildconfig.enableUnitTests files: [ "tst_buildgraph.cpp", "tst_buildgraph.h" ] } qbs-src-2.6.1/tests/auto/buildgraph/tst_buildgraph.h0000644000175100001660000000514514776170045022074 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TST_BUILDGRAPH_H #define TST_BUILDGRAPH_H #include #include #include #include #include class TestBuildGraph : public QObject { Q_OBJECT public: TestBuildGraph(qbs::ILogSink *logSink); private slots: void initTestCase(); void cleanupTestCase(); void testCycle(); private: qbs::Internal::ResolvedProductConstPtr productWithDirectCycle(); qbs::Internal::ResolvedProductConstPtr productWithLessDirectCycle(); qbs::Internal::ResolvedProductConstPtr productWithNoCycle(); bool cycleDetected(const qbs::Internal::ResolvedProductConstPtr &product); qbs::ILogSink * const m_logSink; }; #endif // TST_BUILDGRAPH_H qbs-src-2.6.1/tests/auto/buildgraph/CMakeLists.txt0000644000175100001660000000020414776170045021437 0ustar runnerdockeradd_qbs_test(buildgraph SOURCES tst_buildgraph.cpp tst_buildgraph.h DEPENDS qbsquickjsheaders ) qbs-src-2.6.1/tests/auto/shared.h0000644000175100001660000003277714776170045016221 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TEST_SHARED_H #define QBS_TEST_SHARED_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define REPLACE_IN_FILE(filePath, oldContent, newContent) \ do { \ QFile f((filePath)); \ QVERIFY2(f.open(QIODevice::ReadWrite), qPrintable(f.errorString())); \ QByteArray content = f.readAll(); \ const QByteArray savedContent = content; \ content.replace((oldContent), (newContent)); \ QVERIFY(content != savedContent); \ f.resize(0); \ f.write(content); \ } while (false) inline int testTimeoutInMsecs() { bool ok; int timeoutInSecs = qEnvironmentVariableIntValue("QBS_AUTOTEST_TIMEOUT", &ok); if (!ok) timeoutInSecs = 600; return timeoutInSecs * 1000; } // On Windows, it appears that a lock is sometimes held on files for a short while even after // they are closed. The likelihood for that seems to increase with the slowness of the machine. inline void waitForFileUnlock() { bool ok; int timeoutInSecs = qEnvironmentVariableIntValue("QBS_AUTOTEST_IO_GRACE_PERIOD", &ok); if (!ok) timeoutInSecs = qbs::Internal::HostOsInfo::isWindowsHost() ? 1 : 0; if (timeoutInSecs > 0) QTest::qWait(timeoutInSecs * 1000); } using SettingsPtr = std::unique_ptr; inline SettingsPtr settings() { const QString settingsDir = QLatin1String(qgetenv("QBS_AUTOTEST_SETTINGS_DIR")); return std::make_unique(settingsDir); } inline QString profileName() { const QString suiteProfile = QLatin1String( qgetenv("QBS_AUTOTEST_PROFILE_" QBS_TEST_SUITE_NAME)); if (!suiteProfile.isEmpty()) return suiteProfile; const QString profile = QLatin1String(qgetenv("QBS_AUTOTEST_PROFILE")); return !profile.isEmpty() ? profile : QLatin1String("none"); } inline QString relativeBuildDir(const QString &configurationName = QString()) { return !configurationName.isEmpty() ? configurationName : QLatin1String("default"); } inline QString relativeBuildGraphFilePath(const QString &configName = QString()) { return relativeBuildDir(configName) + QLatin1Char('/') + relativeBuildDir(configName) + QLatin1String(".bg"); } inline bool regularFileExists(const QString &filePath) { const QFileInfo fi(filePath); return fi.exists() && fi.isFile(); } inline bool directoryExists(const QString &dirPath) { const QFileInfo fi(dirPath); return fi.exists() && fi.isDir(); } struct ReadFileContentResult { QByteArray content; QString errorString; }; inline ReadFileContentResult readFileContent(const QString &filePath) { ReadFileContentResult result; QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { result.errorString = file.errorString(); return result; } result.content = file.readAll(); return result; } inline QByteArray diffText(const QByteArray &actual, const QByteArray &expected) { QByteArray result; QList actualLines = actual.split('\n'); QList expectedLines = expected.split('\n'); int n = 1; while (!actualLines.isEmpty() && !expectedLines.isEmpty()) { QByteArray actualLine = actualLines.takeFirst(); QByteArray expectedLine = expectedLines.takeFirst(); if (actualLine != expectedLine) { result += QStringLiteral("%1: actual: %2\n%1:expected: %3\n") .arg(n, 2) .arg(QString::fromUtf8(actualLine)) .arg(QString::fromUtf8(expectedLine)) .toUtf8(); } n++; } auto addLines = [&result, &n] (const QList &lines) { for (const QByteArray &line : std::as_const(lines)) { result += QStringLiteral("%1: %2\n") .arg(n) .arg(QString::fromUtf8(line)) .toUtf8(); n++; } }; if (!actualLines.isEmpty()) { result += "Extra unexpected lines:\n"; addLines(actualLines); } if (!expectedLines.isEmpty()) { result += "Missing expected lines:\n"; addLines(expectedLines); } return result; } #define READ_TEXT_FILE(filePath, contentVariable) \ QByteArray contentVariable; \ { \ auto c = readFileContent(filePath); \ QVERIFY2(c.errorString.isEmpty(), \ qUtf8Printable(QStringLiteral("Cannot open file %1. %2") \ .arg(filePath, c.errorString))); \ contentVariable = std::move(c.content); \ } #define TEXT_FILE_COMPARE(actualFilePath, expectedFilePath) \ { \ READ_TEXT_FILE(actualFilePath, ba1); \ READ_TEXT_FILE(expectedFilePath, ba2); \ if (ba1 != ba2) { \ QByteArray msg = "File contents differ:\n" + diffText(ba1, ba2); \ QFAIL(msg.constData()); \ } \ } template inline QString prefixedIfNonEmpty(const T &prefix, const QString &str) { if (str.isEmpty()) return QString(); return prefix + str; } inline QString uniqueProductName(const QString &productName, const QString &multiplexConfigurationId) { return productName + prefixedIfNonEmpty(QLatin1Char('.'), multiplexConfigurationId); } inline QString relativeProductBuildDir(const QString &productName, const QString &configurationName = QString(), const QString &multiplexConfigurationId = QString()) { const QString fullName = uniqueProductName(productName, multiplexConfigurationId); QString dirName = qbs::Internal::HostOsInfo::rfc1034Identifier(fullName); const QByteArray hash = QCryptographicHash::hash(fullName.toUtf8(), QCryptographicHash::Sha1); dirName.append('.').append(hash.toHex().left(8)); return relativeBuildDir(configurationName) + '/' + dirName; } inline QString appendExecSuffix(const QString &productName, const QByteArray &output) { const QByteArray marker = "executable suffix: "; const int markerOffset = output.indexOf(marker); if (markerOffset == -1) return ".error"; const int suffixOffset = markerOffset + marker.size(); const int newlineOffset = output.indexOf('\n', suffixOffset); if (newlineOffset == -1) return ".error"; return productName + QString::fromLocal8Bit( output.mid(suffixOffset, newlineOffset - suffixOffset).trimmed()); } inline QString relativeExecutableFilePath( const QString &productName, const QByteArray &output, const QString &configName = QString()) { const auto relativeDir = relativeProductBuildDir(productName, configName) + QLatin1Char('/'); return relativeDir + appendExecSuffix(productName, output); } inline void waitForNewTimestamp(const QString &testDir) { // Waits for the time that corresponds to the host file system's time stamp granularity. if (qbs::Internal::HostOsInfo::isWindowsHost()) { QTest::qWait(1); // NTFS has 100 ns precision. Let's ignore exFAT. } else { const QString nameTemplate = testDir + "/XXXXXX"; QTemporaryFile f1(nameTemplate); if (!f1.open()) qFatal("Failed to open temp file"); const QDateTime initialTime = QFileInfo(f1).lastModified(); int totalMsPassed = 0; while (totalMsPassed <= 2000) { static const int increment = 50; QTest::qWait(increment); totalMsPassed += increment; QTemporaryFile f2(nameTemplate); if (!f2.open()) qFatal("Failed to open temp file"); if (QFileInfo(f2).lastModified() > initialTime) return; } qWarning("Got no new timestamp after two seconds, going ahead anyway. Subsequent " "test failure might not be genuine."); } } inline void touch(const QString &fn) { QFile f(fn); int s = f.size(); if (!f.open(QFile::ReadWrite)) qFatal("cannot open file %s", qPrintable(fn)); f.resize(s+1); f.resize(s); } inline void copyFileAndUpdateTimestamp(const QString &source, const QString &target) { QFile::remove(target); if (!QFile::copy(source, target)) qFatal("Failed to copy '%s' to '%s'", qPrintable(source), qPrintable(target)); touch(target); } inline QString parsedObjectSuffix(const QByteArray &output) { const QByteArray marker = "object suffix: "; const int markerOffset = output.indexOf(marker); if (markerOffset == -1) return ".fail"; const int suffixOffset = markerOffset + marker.size(); const int newlineOffset = output.indexOf('\n', suffixOffset); if (newlineOffset == -1) return ".fail"; return QString::fromLocal8Bit(output.mid(suffixOffset, newlineOffset - suffixOffset).trimmed()); } inline QString inputDirHash(const QString &dir) { return QCryptographicHash::hash(dir.toLatin1(), QCryptographicHash::Sha1).toHex().left(16); } inline QString testDataSourceDir(const QString &dir) { QDir result; QString testSourceRootDirFromEnv = QDir::fromNativeSeparators(qEnvironmentVariable("QBS_TEST_SOURCE_ROOT")); if (testSourceRootDirFromEnv.isEmpty()) { result.setPath(dir); } else { QDir testSourceRootDir(dir); while (testSourceRootDir.dirName() != "tests") testSourceRootDir = QFileInfo(testSourceRootDir, "").dir(); QString relativeDataPath = testSourceRootDir.relativeFilePath(dir); QString absoluteDataPath = QDir(testSourceRootDirFromEnv).absoluteFilePath(relativeDataPath); result.setPath(absoluteDataPath); } if (!result.exists()) qFatal("Expected data folder '%s' to be present, but it does not exist. You may set " "QBS_TEST_SOURCE_ROOT to the 'tests' folder in your qbs repository to configure " "a custom location.", qPrintable(result.absolutePath())); return result.absolutePath(); } inline QString testWorkDir(const QString &testName) { QString dir = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv("QBS_TEST_WORK_ROOT"))); if (dir.isEmpty()) { dir = QCoreApplication::applicationDirPath() + QStringLiteral("/../tests/auto/"); } else { if (!dir.endsWith(QLatin1Char('/'))) dir += QLatin1Char('/'); } return QDir::cleanPath(dir + testName + "/testWorkDir"); } inline bool copyDllExportHeader(const QString &srcDataDir, const QString &targetDataDir) { QFile sourceFile(srcDataDir + "/../../dllexport.h"); if (!sourceFile.exists()) return true; const QString targetPath = targetDataDir + "/dllexport.h"; QFile::remove(targetPath); return sourceFile.copy(targetPath); } #endif // Include guard. qbs-src-2.6.1/tests/auto/pkgconfig/0000755000175100001660000000000014776170045016531 5ustar runnerdockerqbs-src-2.6.1/tests/auto/pkgconfig/tst_pkgconfig.cpp0000644000175100001660000002606614776170045022110 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tst_pkgconfig.h" #include "../shared.h" #include #include #include #include #include #include #include using HostOsInfo = qbs::Internal::HostOsInfo; using PcPackage = qbs::PcPackage; using PkgConfig = qbs::PkgConfig; using Options = qbs::PkgConfig::Options; TestPkgConfig::TestPkgConfig() : m_sourceDataDir(testDataSourceDir(SRCDIR "/testdata")) , m_workingDataDir(testWorkDir(QStringLiteral("pkgconfig"))) { } void TestPkgConfig::initTestCase() { QString errorMessage; qbs::Internal::removeDirectoryWithContents(m_workingDataDir, &errorMessage); QVERIFY2(qbs::Internal::copyFileRecursion(m_sourceDataDir, m_workingDataDir, false, true, &errorMessage), qPrintable(errorMessage)); } void TestPkgConfig::fileName() { QCOMPARE(qbs::Internal::fileName(""), ""); QCOMPARE(qbs::Internal::fileName("file.txt"), "file.txt"); QCOMPARE(qbs::Internal::fileName("/home/user/file.txt"), "file.txt"); QCOMPARE(qbs::Internal::fileName("/"), ""); #if defined(Q_OS_WIN) QCOMPARE(qbs::Internal::fileName("c:file.txt"), "file.txt"); QCOMPARE(qbs::Internal::fileName("c:"), ""); #endif } void TestPkgConfig::completeBaseName() { QCOMPARE(qbs::Internal::completeBaseName(""), ""); QCOMPARE(qbs::Internal::completeBaseName("file.txt"), "file"); QCOMPARE(qbs::Internal::completeBaseName("archive.tar.gz"), "archive.tar"); QCOMPARE(qbs::Internal::completeBaseName("/home/user/file.txt"), "file"); #if defined(Q_OS_WIN) QCOMPARE(qbs::Internal::completeBaseName("c:file.txt"), "file"); QCOMPARE(qbs::Internal::completeBaseName("c:archive.tar.gz"), "archive.tar"); QCOMPARE(qbs::Internal::completeBaseName("c:"), ""); #endif } void TestPkgConfig::parentPath() { QCOMPARE(qbs::Internal::parentPath(""), ""); QCOMPARE(qbs::Internal::parentPath("file.txt"), "."); QCOMPARE(qbs::Internal::parentPath("/home/user/file.txt"), "/home/user"); QCOMPARE(qbs::Internal::parentPath("/home/user/"), "/home/user"); QCOMPARE(qbs::Internal::parentPath("/home"), "/"); QCOMPARE(qbs::Internal::parentPath("/"), "/"); #if defined(Q_OS_WIN) QCOMPARE(qbs::Internal::parentPath("c:/folder/file.txt"), "c:/folder"); QCOMPARE(qbs::Internal::parentPath("c:/folder/"), "c:/folder"); QCOMPARE(qbs::Internal::parentPath("c:/folder"), "c:/"); QCOMPARE(qbs::Internal::parentPath("c:/"), "c:/"); QCOMPARE(qbs::Internal::parentPath("c:"), "c:"); #endif } void TestPkgConfig::pkgConfig() { QFETCH(QString, pcFileName); QFETCH(QString, jsonFileName); QFETCH(QVariantMap, optionsMap); if (jsonFileName.isEmpty()) jsonFileName = pcFileName; Options options = qbs::Internal::PkgConfigJs::convertOptions( QProcessEnvironment::systemEnvironment(), optionsMap); options.libDirs.push_back(m_workingDataDir.toStdString()); PkgConfig pkgConfig(std::move(options)); QFile jsonFile(m_workingDataDir + "/" + jsonFileName + ".json"); QVERIFY(jsonFile.open(QIODevice::ReadOnly)); QJsonParseError error{}; const auto json = QJsonDocument::fromJson(jsonFile.readAll(), &error).toVariant().toMap(); QCOMPARE(error.error, QJsonParseError::NoError); const auto &packageOr = pkgConfig.getPackage(pcFileName.toStdString()); QVERIFY(packageOr.isValid()); const auto &package = packageOr.asPackage(); QCOMPARE(QString::fromStdString(package.baseFileName), pcFileName); QCOMPARE(QString::fromStdString(package.name), json.value("Name").toString()); QCOMPARE(QString::fromStdString(package.description), json.value("Description").toString()); QCOMPARE(QString::fromStdString(package.version), json.value("Version").toString()); auto variables = json["Vars"].toMap(); variables["pcfiledir"] = QFileInfo(m_workingDataDir).absoluteFilePath(); QCOMPARE(size_t(variables.size()), package.variables.size()); for (const auto &[key, value]: package.variables) { QCOMPARE(QString::fromStdString(value), variables.value(QString::fromStdString(key)).toString()); } const auto jsonLibs = json.value("Libs").toJsonArray().toVariantList(); QCOMPARE(package.libs.size(), size_t(jsonLibs.size())); for (size_t i = 0; i < package.libs.size(); ++i) { const auto &item = package.libs[i]; const auto jsonItem = jsonLibs.at(i).toMap(); QCOMPARE(item.type, *PcPackage::Flag::typeFromString(jsonItem.value("Type").toString().toStdString())); QCOMPARE(QString::fromStdString(item.value), jsonItem.value("Value").toString()); } const auto jsonLibsPrivate = json.value("LibsPrivate").toJsonArray().toVariantList(); QCOMPARE(package.libsPrivate.size(), size_t(jsonLibsPrivate.size())); for (size_t i = 0; i < package.libsPrivate.size(); ++i) { const auto &item = package.libsPrivate[i]; const auto jsonItem = jsonLibsPrivate.at(i).toMap(); QCOMPARE(item.type, *PcPackage::Flag::typeFromString(jsonItem.value("Type").toString().toStdString())); QCOMPARE(QString::fromStdString(item.value), jsonItem.value("Value").toString()); } const auto jsonCFlags = json.value("Cflags").toJsonArray().toVariantList(); QCOMPARE(package.cflags.size(), size_t(jsonCFlags.size())); for (size_t i = 0; i < package.cflags.size(); ++i) { const auto &item = package.cflags[i]; const auto jsonItem = jsonCFlags.at(i).toMap(); QCOMPARE(item.type, *PcPackage::Flag::typeFromString(jsonItem.value("Type").toString().toStdString())); QCOMPARE(QString::fromStdString(item.value), jsonItem.value("Value").toString()); } for (const auto &item: package.requiresPublic) qInfo() << "requires" << item.name.c_str() << item.version.c_str(); const auto jsonRequires = json.value("Requires").toJsonArray().toVariantList(); QCOMPARE(package.requiresPublic.size(), size_t(jsonRequires.size())); for (size_t i = 0; i < package.requiresPublic.size(); ++i) { const auto &item = package.requiresPublic[i]; const auto jsonItem = jsonRequires.at(i).toMap(); QCOMPARE(item.comparison, *PcPackage::RequiredVersion::comparisonFromString( jsonItem.value("Comparison").toString().toStdString())); QCOMPARE(QString::fromStdString(item.name), jsonItem.value("Name").toString()); QCOMPARE(QString::fromStdString(item.version), jsonItem.value("Version").toString()); } const auto jsonRequiresPrivate = json.value("RequiresPrivate").toJsonArray().toVariantList(); QCOMPARE(package.requiresPrivate.size(), size_t(jsonRequiresPrivate.size())); for (size_t i = 0; i < package.requiresPrivate.size(); ++i) { const auto &item = package.requiresPrivate[i]; const auto jsonItem = jsonRequiresPrivate.at(i).toMap(); QCOMPARE(item.comparison, *PcPackage::RequiredVersion::comparisonFromString( jsonItem.value("Comparison").toString().toStdString())); QCOMPARE(QString::fromStdString(item.name), jsonItem.value("Name").toString()); QCOMPARE(QString::fromStdString(item.version), jsonItem.value("Version").toString()); } } void TestPkgConfig::pkgConfig_data() { QTest::addColumn("pcFileName"); QTest::addColumn("jsonFileName"); QTest::addColumn("optionsMap"); QTest::newRow("empty-variable") << QStringLiteral("empty-variable") << QString() << QVariantMap(); QTest::newRow("non-l-required") << QStringLiteral("non-l-required") << QString() << QVariantMap(); QTest::newRow("simple") << QStringLiteral("simple") << QString() << QVariantMap(); QTest::newRow("requires-test") << QStringLiteral("requires-test") << QString() << QVariantMap(); QTest::newRow("special-flags") << QStringLiteral("special-flags") << QString() << QVariantMap(); QTest::newRow("system") << QStringLiteral("system") << QString() << QVariantMap(); QTest::newRow("sysroot") << QStringLiteral("sysroot") << QString() << QVariantMap({{"sysroot", "/newroot"}}); QTest::newRow("tilde") << QStringLiteral("tilde") << QString() << QVariantMap(); QTest::newRow("variables") << QStringLiteral("variables") << QString() << QVariantMap(); QTest::newRow("whitespace") << QStringLiteral("whitespace") << QString() << QVariantMap(); QTest::newRow("base.name") << QStringLiteral("base.name") << QString() << QVariantMap(); } void TestPkgConfig::benchSystem() { if (HostOsInfo::hostOs() == HostOsInfo::HostOsWindows) QSKIP("Not available on Windows"); QBENCHMARK { PkgConfig pkgConfig; QVERIFY(!pkgConfig.packages().empty()); } } void TestPkgConfig::prefix() { const auto prefixDir = m_workingDataDir; const auto libDir = m_workingDataDir + "/lib"; const auto includeDir = m_workingDataDir + "/include"; const auto pkgconfigDir = libDir + "/pkgconfig"; Options options = qbs::Internal::PkgConfigJs::convertOptions( QProcessEnvironment::systemEnvironment(), {}); options.definePrefix = true; options.libDirs.push_back(pkgconfigDir.toStdString()); PkgConfig pkgConfig(std::move(options)); const auto &packageOr = pkgConfig.getPackage("prefix"); QVERIFY(packageOr.isValid()); const auto &package = packageOr.asPackage(); QCOMPARE(package.variables.at("prefix"), prefixDir.toStdString()); QCOMPARE(package.variables.at("exec_prefix"), prefixDir.toStdString()); QCOMPARE(package.variables.at("libdir"), libDir.toStdString()); QCOMPARE(package.variables.at("includedir"), includeDir.toStdString()); QCOMPARE(package.variables.at("usrdir"), "/usrdir"); } QTEST_MAIN(TestPkgConfig) qbs-src-2.6.1/tests/auto/pkgconfig/tst_pkgconfig.h0000644000175100001660000000334014776170045021543 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TST_API_H #define QBS_TST_API_H #include #include class TestPkgConfig : public QObject { Q_OBJECT public: TestPkgConfig(); private slots: void initTestCase(); void fileName(); void completeBaseName(); void parentPath(); void pkgConfig(); void pkgConfig_data(); void benchSystem(); void prefix(); private: const QString m_sourceDataDir; const QString m_workingDataDir; }; #endif // Include guard. qbs-src-2.6.1/tests/auto/pkgconfig/pkgconfig.qbs0000644000175100001660000000065614776170045021216 0ustar runnerdockerimport qbs import qbs.Utilities QbsUnittest { Depends { name: "qbspkgconfig" } condition: qbsbuildconfig.enableUnitTests testName: "pkgconfig" files: ["../shared.h", "tst_pkgconfig.h", "tst_pkgconfig.cpp"] cpp.defines: base.concat([ "SRCDIR=" + Utilities.cStringQuote(path), ]) Group { name: "testdata" prefix: "testdata/" files: ["**/*"] fileTags: [] } } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/0000755000175100001660000000000014776170045020342 5ustar runnerdockerqbs-src-2.6.1/tests/auto/pkgconfig/testdata/tilde.pc0000644000175100001660000000011614776170045021765 0ustar runnerdockerName: tilde Description: tilde test module Version: 1.0 Libs: -L~ Cflags: -I~ qbs-src-2.6.1/tests/auto/pkgconfig/testdata/system.pc0000644000175100001660000000031314776170045022207 0ustar runnerdockerprefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: System library Description: Test package Version: 1.0.0 Libs: -L${libdir} -lsystem Cflags: -I${includedir} qbs-src-2.6.1/tests/auto/pkgconfig/testdata/empty-variable.pc0000644000175100001660000000045414776170045023612 0ustar runnerdockerrootprefix= prefix=/usr exec_prefix=${rootprefix}/${prefix} libdir=${exec_prefix}/lib includedir=${rootprefix}/${prefix}/include Name: Empty Variable test Description: Checks that empty variables are handled correcty Version: 1.0.0 Requires: Libs: -lsimple Libs.private: -lm Cflags: -I${includedir} qbs-src-2.6.1/tests/auto/pkgconfig/testdata/lib/0000755000175100001660000000000014776170045021110 5ustar runnerdockerqbs-src-2.6.1/tests/auto/pkgconfig/testdata/lib/pkgconfig/0000755000175100001660000000000014776170045023057 5ustar runnerdockerqbs-src-2.6.1/tests/auto/pkgconfig/testdata/lib/pkgconfig/prefix.pc0000644000175100001660000000036614776170045024705 0ustar runnerdockerprefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=/usr/include usrdir=/usrdir Name: Prefix test Description: This tests prefix auto detection Version: 1.0.0 Requires: Libs: -lprefix Libs.private: -lm Cflags: -I${includedir} qbs-src-2.6.1/tests/auto/pkgconfig/testdata/special-flags.json0000644000175100001660000000214114776170045023745 0ustar runnerdocker{ "Name": "Special flags test", "Description": "Dummy pkgconfig test package for testing pkgconfig", "Version": "1.0.0", "Vars": { "prefix": "/usr", "exec_prefix": "/usr", "libdir": "/usr/lib", "includedir": "/usr/include" }, "Libs": [ {"Type": "LibraryPath", "Value": "/foo"}, {"Type": "Framework", "Value": "Foo"}, {"Type": "LibraryName", "Value": "simple"}, {"Type": "LibraryPath", "Value": "/bar"}, {"Type": "Framework", "Value": "Bar"}, {"Type": "LinkerFlag", "Value": "-Wl,-framework"}, {"Type": "LinkerFlag", "Value": "-Wl,Baz"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/foo"}, {"Type": "CompilerFlag", "Value": "-g"}, {"Type": "SystemIncludePath", "Value": "/system1"}, {"Type": "DirAfterIncludePath", "Value": "/after1"}, {"Type": "CompilerFlag", "Value": "-ffoo"}, {"Type": "IncludePath", "Value": "/bar"}, {"Type": "DirAfterIncludePath", "Value": "/after2"}, {"Type": "SystemIncludePath", "Value": "/system2"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/tilde.json0000644000175100001660000000033614776170045022340 0ustar runnerdocker{ "Name": "tilde", "Description": "tilde test module", "Version": "1.0", "Libs": [ {"Type": "LibraryPath", "Value": "~"} ], "Cflags": [ {"Type": "IncludePath", "Value": "~"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/variables.pc0000644000175100001660000000040014776170045022630 0ustar runnerdockerprefix=/local exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir="${prefix}/include" cppflags=-I${includedir}/foo \ -DFOO=\"/bar\" Name: Complex variables Description: Test complex variable output Version: 1.0 Cflags: -I${includedir} ${cppflags} qbs-src-2.6.1/tests/auto/pkgconfig/testdata/sysroot.pc0000644000175100001660000000050114776170045022404 0ustar runnerdockerprefix=/opt exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include sysroot=${pc_sysrootdir} Name: Test for sysroot Description: Test package for testing sysroot Version: 1.0.0 Requires: Libs: -L${libdir} -lsystem Cflags: -I${includedir} -idirafter ${includedir}/after -isystem ${includedir}/system qbs-src-2.6.1/tests/auto/pkgconfig/testdata/variables.json0000644000175100001660000000102514776170045023203 0ustar runnerdocker{ "Name": "Complex variables", "Description": "Test complex variable output", "Version": "1.0", "Vars": { "prefix": "/local", "exec_prefix": "/local", "libdir": "/local/lib", "includedir": "\"/local/include\"", "cppflags": "-I\"/local/include\"/foo -DFOO=\\\"/bar\\\"" }, "Cflags": [ {"Type": "IncludePath", "Value": "/local/include"}, {"Type": "IncludePath", "Value": "/local/include/foo"}, {"Type": "Define", "Value": "FOO=\"/bar\""} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/whitespace.json0000644000175100001660000000155214776170045023374 0ustar runnerdocker{ "Name": "Whitespace test", "Description": "Dummy pkgconfig test package for testing pkgconfig", "Version": "1.0.0", "Vars": { "prefix": "/usr", "exec_prefix": "/usr", "libdir": "\"/usr/white space/lib\"", "includedir": "\"/usr/white space/include\"" }, "Libs": [ {"Type": "LibraryPath", "Value": "/usr/white space/lib"}, {"Type": "LibraryName", "Value": "foo bar"}, {"Type": "LibraryName", "Value": "bar baz"}, {"Type": "LinkerFlag", "Value": "-r:foo"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/usr/white space/include"}, {"Type": "IncludePath", "Value": "$(top_builddir)"}, {"Type": "IncludePath", "Value": "include dir"}, {"Type": "IncludePath", "Value": "other include dir"}, {"Type": "Define", "Value": "lala=misc"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/requires-test.json0000644000175100001660000000113614776170045024052 0ustar runnerdocker{ "Name": "Requires test package", "Description": "Dummy pkgconfig test package for testing Requires/Requires.private", "Version": "1.0.0", "Libs": [ {"Type": "LibraryPath", "Value": "/requires-test/lib"}, {"Type": "LibraryName", "Value": "requires-test"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/requires-test/include"} ], "Requires": [ {"Comparison": "GreaterThanEqual", "Name": "public-dep", "Version": "1"} ], "RequiresPrivate": [ {"Comparison": "GreaterThanEqual", "Name": "private-dep", "Version": "1"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/private-dep.pc0000644000175100001660000000030214776170045023101 0ustar runnerdockerName: Requires test package Description: Dummy pkgconfig test package for testing Requires/Requires.private Version: 1.0.0 Libs: -L/private-dep/lib -lprivate-dep Cflags: -I/private-dep/include qbs-src-2.6.1/tests/auto/pkgconfig/testdata/sysroot.json0000644000175100001660000000123714776170045022762 0ustar runnerdocker{ "Name": "Test for sysroot", "Description": "Test package for testing sysroot", "Version": "1.0.0", "Vars": { "prefix": "/opt", "exec_prefix": "/opt", "libdir": "/opt/lib", "includedir": "/opt/include", "sysroot": "/newroot" }, "Libs": [ {"Type": "LibraryPath", "Value": "/newroot/opt/lib"}, {"Type": "LibraryName", "Value": "system"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/newroot/opt/include"}, {"Type": "DirAfterIncludePath", "Value": "/newroot/opt/include/after"}, {"Type": "SystemIncludePath", "Value": "/newroot/opt/include/system"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/non-l-required.json0000644000175100001660000000060214776170045024074 0ustar runnerdocker{ "Name": "Non-l flags required test package", "Description": "Test package for checking order of non-L Libs & Cflags", "Version": "1.0.0", "Libs": [ {"Type": "StaticLibraryName", "Value": "/non-l-required.a"}, {"Type": "LinkerFlag", "Value": "-pthread"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/non-l-required/include"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/simple.json0000644000175100001660000000076214776170045022533 0ustar runnerdocker{ "Name": "Simple test", "Description": "Dummy pkgconfig test package for testing pkgconfig", "Version": "1.0.0", "Vars": { "prefix": "/usr", "exec_prefix": "/usr", "libdir": "/usr/lib", "includedir": "/usr/include" }, "Libs": [ {"Type": "LibraryName", "Value": "simple"} ], "LibsPrivate": [ {"Type": "LibraryName", "Value": "m"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/usr/include"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/base.name.pc0000644000175100001660000000036014776170045022516 0ustar runnerdockerprefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Base Name test Description: Checks correct baseName detection Version: 1.0.0 Requires: Libs: -lsimple Libs.private: -lm Cflags: -I${includedir} qbs-src-2.6.1/tests/auto/pkgconfig/testdata/non-l-required.pc0000644000175100001660000000027614776170045023534 0ustar runnerdockerName: Non-l flags required test package Description: Test package for checking order of non-L Libs & Cflags Version: 1.0.0 Libs: /non-l-required.a -pthread Cflags: -I/non-l-required/include qbs-src-2.6.1/tests/auto/pkgconfig/testdata/whitespace.pc0000644000175100001660000000056114776170045023024 0ustar runnerdockerprefix=/usr exec_prefix=${prefix} libdir="${exec_prefix}/white space/lib" includedir="${prefix}/white space/include" Name: Whitespace test Description: Dummy pkgconfig test package for testing pkgconfig Version: 1.0.0 Requires: Libs: -L${libdir} -lfoo\ bar "-lbar baz" -r:foo Cflags: -I${includedir} -I$(top_builddir) -Iinclude\ dir "-Iother include dir" -Dlala=misc qbs-src-2.6.1/tests/auto/pkgconfig/testdata/empty-variable.json0000644000175100001660000000102614776170045024155 0ustar runnerdocker{ "Name": "Empty Variable test", "Description": "Checks that empty variables are handled correcty", "Version": "1.0.0", "Vars": { "rootprefix": "", "prefix": "/usr", "exec_prefix": "//usr", "libdir": "//usr/lib", "includedir": "//usr/include" }, "Libs": [ {"Type": "LibraryName", "Value": "simple"} ], "LibsPrivate": [ {"Type": "LibraryName", "Value": "m"} ], "Cflags": [ {"Type": "IncludePath", "Value": "//usr/include"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/base.name.json0000644000175100001660000000074414776170045023073 0ustar runnerdocker{ "Name": "Base Name test", "Description": "Checks correct baseName detection", "Version": "1.0.0", "Vars": { "prefix": "/usr", "exec_prefix": "/usr", "libdir": "/usr/lib", "includedir": "/usr/include" }, "Libs": [ {"Type": "LibraryName", "Value": "simple"} ], "LibsPrivate": [ {"Type": "LibraryName", "Value": "m"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/usr/include"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/public-dep.pc0000644000175100001660000000032014776170045022705 0ustar runnerdockerName: Requires test package Description: Dummy pkgconfig test package for testing Requires/Requires.private Version: 1.0.0 Requires.private: Libs: -L/public-dep/lib -lpublic-dep Cflags: -I/public-dep/include qbs-src-2.6.1/tests/auto/pkgconfig/testdata/simple.pc0000644000175100001660000000037614776170045022165 0ustar runnerdockerprefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Simple test Description: Dummy pkgconfig test package for testing pkgconfig Version: 1.0.0 Requires: Libs: -lsimple Libs.private: -lm Cflags: -I${includedir} qbs-src-2.6.1/tests/auto/pkgconfig/testdata/system.json0000644000175100001660000000060514776170045022562 0ustar runnerdocker{ "Name": "System library", "Description": "Test package", "Version": "1.0.0", "Vars": { "prefix": "/usr", "exec_prefix": "/usr", "libdir": "/usr/lib", "includedir": "/usr/include" }, "Libs": [ {"Type": "LibraryName", "Value": "system"} ], "Cflags": [ {"Type": "IncludePath", "Value": "/usr/include"} ] } qbs-src-2.6.1/tests/auto/pkgconfig/testdata/requires-test.pc0000644000175100001660000000040514776170045023501 0ustar runnerdockerName: Requires test package Description: Dummy pkgconfig test package for testing Requires/Requires.private Version: 1.0.0 Requires: public-dep >= 1 Requires.private: private-dep >= 1 Libs: -L/requires-test/lib -lrequires-test Cflags: -I/requires-test/include qbs-src-2.6.1/tests/auto/pkgconfig/testdata/special-flags.pc0000644000175100001660000000060714776170045023403 0ustar runnerdockerprefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Special flags test Description: Dummy pkgconfig test package for testing pkgconfig Version: 1.0.0 Requires: Libs: -L/foo -framework Foo -lsimple -L/bar -framework Bar -Wl,-framework -Wl,Baz Cflags: -I/foo -g -isystem /system1 -idirafter /after1 -ffoo -I/bar -idirafter /after2 -isystem /system2 qbs-src-2.6.1/tests/auto/pkgconfig/CMakeLists.txt0000644000175100001660000000022614776170045021271 0ustar runnerdockeradd_qbs_test(pkgconfig SOURCES tst_pkgconfig.cpp tst_pkgconfig.h DEPENDS qbspkgconfig qbsquickjsheaders ) qbs-src-2.6.1/tests/clang-format-test/0000755000175100001660000000000014776170045017141 5ustar runnerdockerqbs-src-2.6.1/tests/clang-format-test/clang-format-test.qbs0000644000175100001660000000026514776170045023202 0ustar runnerdockerQtApplication { Depends { name: "Qt.core" } files: "clang-format.cpp" cpp.cxxLanguageVersion: "c++20" cpp.minimumMacosVersion: "11.0" cpp.warningLevel: "none" } qbs-src-2.6.1/tests/clang-format-test/CMakeLists.txt0000644000175100001660000000014514776170045021701 0ustar runnerdockeradd_qbs_app(clang-format-test DEPENDS Qt${QT_VERSION_MAJOR}::Core SOURCES clang-format.cpp ) qbs-src-2.6.1/tests/clang-format-test/clang-format.cpp0000644000175100001660000004574714776170045022240 0ustar runnerdocker// Copyright (C) 2017 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // // KEEP THIS FILE COMPILABLE TO ENSURE THAT WE TEST AGAINST VALID CODE. // // NOTE: Nice, includes are sorted #include #include #include #include #include #include #include #include static int aGlobalInt = 3; // ------------------------------------------------------------------------------------------------- // Preprocessor // ------------------------------------------------------------------------------------------------- // NOTE: Ops, preprocessor branches are not indented ("#define" vs "# define") #if defined(TEXTEDITOR_LIBRARY) #define TEXTEDITOR_EXPORT Q_DECL_EXPORT #else #define TEXTEDITOR_EXPORT Q_DECL_IMPORT #endif // ------------------------------------------------------------------------------------------------- // Macros // ------------------------------------------------------------------------------------------------- #define QTCREATOR_UTILS_EXPORT // qtcassert.h: namespace Utils { void writeAssertLocation(const char *msg) { std::printf("%s", msg); } } // namespace Utils #define QTC_ASSERT_STRINGIFY_HELPER(x) #x #define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x) #define QTC_ASSERT_STRING(cond) \ ::Utils::writeAssertLocation("\"" cond "\" in file " __FILE__ \ ", line " QTC_ASSERT_STRINGIFY(__LINE__)) // NOTE: Ops, macro definitions: are more verbose #define QTC_ASSERT(cond, action) \ if (cond) { \ } else { \ QTC_ASSERT_STRING(#cond); \ action; \ } \ do { \ } while (0) #define QTC_CHECK(cond) \ if (cond) { \ } else { \ QTC_ASSERT_STRING(#cond); \ } \ do { \ } while (0) #define QTC_GUARD(cond) ((cond) ? true : (QTC_ASSERT_STRING(#cond), false)) void lala(int foo) { Q_UNUSED(foo) Q_UNUSED(foo); QTC_ASSERT(true, return); // NOTE: Ops, extra space with QTC_ASSERT macro and return keyword QTC_ASSERT(true, return;); while (true) QTC_ASSERT(true, break); // ...but this is fine } // ------------------------------------------------------------------------------------------------- // Namespaces // ------------------------------------------------------------------------------------------------- namespace N { namespace C { struct Foo {}; struct Bar {}; namespace { class ClassInUnnamedNamespace {}; } // namespace // NOTE: Nice, namespace end comments are added/updated automatically } // namespace C struct Baz {}; } // namespace N namespace N2 {} // ------------------------------------------------------------------------------------------------- // Forward declarations // ------------------------------------------------------------------------------------------------- // NOTE: Ops, no one-liner anymore: forward declarations within namespace namespace N { struct Baz; } class SourceLocation; class SourceRange; class ClangString; QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE QT_FORWARD_DECLARE_CLASS(QTextDocument) QT_FORWARD_DECLARE_CLASS(QTextBlock); // ------------------------------------------------------------------------------------------------- // Using declarations, using directives, using alias, typedefs // ------------------------------------------------------------------------------------------------- // NOTE: OK, using directives are not sorted using namespace std; using namespace N2; using namespace N; // NOTE: Nice, using declarations are sorted using N::C::Bar; using N::C::Foo; // NOTE: OK, typedefs are not sorted typedef N::C::Foo TypedefedFoor; typedef N::C::Bar TypedefedBar; // NOTE: OK, using aliases are not sorted using AliasedFoor = N::C::Foo; using AliasedBar = N::C::Bar; // ------------------------------------------------------------------------------------------------- // Comments // ------------------------------------------------------------------------------------------------- // NOTE: OK, reflowing/wrapping of comments is turned off for now. // This is a fancy comment that might be reflowed or not or not or not or not or not or not or not or not or not. // NOTE: Nice, comments after declarations are aligned int foo; // fancy comment describing foo int superDuperFoo; // fancy comment describing superDuperFoo int lalaFoo; // fancy comment describing lalaFoo // ------------------------------------------------------------------------------------------------- // Function declarations // ------------------------------------------------------------------------------------------------- void f(); void f2() {} void f3(int parameter1, int parameter2, int parameter3); // NOTE: Ops, awkward placement of parameter list, there is no equivalent of // PenaltyBreakBeforeFirstCallParameter for parameter list void f3( int parameter1, int parameter2, int parameter3, int parameter4, int parameter5, int parameter6); void f3( int parameter1, int parameter2, int parameter3, int parameter4, int parameter5, int parameter6, int parrameter7, int p = aGlobalInt); bool operator==(N::Baz, N::Baz); template void fancyTemplateFunction(); template void variadicTemplateFunction(Type *...arg); // ------------------------------------------------------------------------------------------------- // Inside functions // ------------------------------------------------------------------------------------------------- int myfunction(int parameter1, int parameter2) { // Function calls myfunction(parameter1, parameter2); // Casts int value = 3; int z = (int) value; int a = static_cast(value + z); // Pointer/references alignment int *p = nullptr; int &r = *p; // Operators int result = parameter1 + parameter1 + parameter1 + parameter1 + parameter1 + parameter1 + parameter1 + parameter1; // Long expressions int someVeryLooooooooooooooooooooooooooooooooooooooooooooooooooongInt = -1; bool condition1 = false; bool condition2 = false; // NOTE: Ops, alignment of readable, boolean and complex expressions will be reverted if (condition1 || condition2 || someVeryLooooooooooooooooooooooooooooooooooooooooooooooooooongInt) { return value; } // Initializer lists vector x{1, 2, 3, 4}; vector y{{}, {}, {}, {}}; new int[3]{1, 2, 3}; // Streams // NOTE: OK, there is a heuristic (endl, '\n') to wrap statements with stream operators. cout << "Hello" << parameter1 << endl << parameter2 << endl << result << endl << condition1 << someVeryLooooooooooooooooooooooooooooooooooooooooooooooooooongInt; cout << "Hello" << parameter1 << '\n' << parameter2 << '\n' << a << '\n' << condition1 << someVeryLooooooooooooooooooooooooooooooooooooooooooooooooooongInt; // ...but here not: cout << "Hello" << parameter1 << '\t' << parameter2 << '\t' << z << '\t' << condition1 << someVeryLooooooooooooooooooooooooooooooooooooooooooooooooooongInt << r; return 1; } // ------------------------------------------------------------------------------------------------- // Ternary Operator // ------------------------------------------------------------------------------------------------- bool ternary() { bool someWhatLongerName; bool someWhatLongerName2; bool isThatReallyReallyReallyReallyReallyReallyReallyReallyTrue = false; bool isThatReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyTrue = false; bool yesno = true ? true : false; bool sino = isThatReallyReallyReallyReallyReallyReallyReallyReallyTrue ? someWhatLongerName : someWhatLongerName2; bool danet = isThatReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyTrue ? someWhatLongerName : someWhatLongerName2; return yesno && sino && danet; } // ------------------------------------------------------------------------------------------------- // Penalty Test // ------------------------------------------------------------------------------------------------- int functionToCall(int parameter1) { return 1; } int functionToCall(int paramter1, int parameter2) { return 1; } int functionToCall(int paramter1, int parameter2, int parameter3) { return 1; } int functionToCall(int paramter1, int parameter2, int parameter3, int parameter4, int parameter5) { return 1; } int functionToCall( int paramter1, int parameter2, int parameter3, int parameter4, int parameter5, int paramete6) { return 1; } int functionToCall( int paramter1, int parameter2, int parameter3, int parameter4, int parameter5, int paramete6, int parameter6) { return 1; } bool functionToCallSt(const QString ¶mter1, const QStringList &list) { return 1; } void emitAddOutput(const QString &text, int priority) {} void emitAddOutput(const QString &text, int priority, int category) {} void penaltyTests(bool isThatTrue) { int valueX = 3; int valueY = 1; int valueZ = 1; int valueXTimesY = valueX * valueY; int unbelievableBigValue = 1000000; int unlimitedValueunbelievableBigValue = 1000000; QString arguments; QString argumentsVeryLong; const QFile::OpenMode openMode = isThatTrue ? QIODevice::ReadOnly : (QIODevice::ReadOnly | QIODevice::Text); const auto someValue10 = functionToCall(valueX, valueY, valueXTimesY); const auto someValue11 = functionToCall( valueX, valueY, valueXTimesY, unbelievableBigValue, unbelievableBigValue); const auto someValue12 = functionToCall( valueX, valueY, valueXTimesY, unbelievableBigValue, unbelievableBigValue * unbelievableBigValue, unbelievableBigValue); const auto someValue13 = functionToCall( valueX, valueY, valueXTimesY, unbelievableBigValue, functionToCall(functionToCall(valueX), functionToCall(valueY)), unbelievableBigValue); const auto someValue14WithAnOutstandingLongName = functionToCall( valueX, valueY, valueXTimesY, unbelievableBigValue, functionToCall(functionToCall(valueX), functionToCall(valueY)), unbelievableBigValue); const bool someValue20 = functionToCall(valueX, valueY, valueXTimesY) || functionToCall(3); const bool someValue21 = functionToCall(valueX, valueY, valueXTimesY) || functionToCall(valueX, valueY); emitAddOutput( QCoreApplication::tr("Starting: \"%1\" %2") .arg("/some/very/very/very/very/long/path/to/an/executable", arguments), functionToCall(3), functionToCall(3) | valueX); emitAddOutput( QCoreApplication::tr("Starting: \"%1\" %2") .arg("/some/very/very/very/very/long/path/to/an/executable", argumentsVeryLong), functionToCall(3), functionToCall(3) | unlimitedValueunbelievableBigValue | unlimitedValueunbelievableBigValue); const QString path; const bool someLongerNameNNNNNNNNNN = functionToCallSt( path, QStringList(QLatin1String("-print-env"))); } // ------------------------------------------------------------------------------------------------- // Classes and member functions // ------------------------------------------------------------------------------------------------- class Base1 {}; class Base2 {}; class MyClass : public QObject, public Base1, public Base2 { Q_OBJECT public: friend class FriendX; // for X::foo() friend class OtherFriendY; // for Y::bar() MyClass() {} MyClass(int d1) : data1(d1) {} MyClass(int d1, int d2) : data1(d1) , data2(d2) , data3(d2) {} MyClass( int initialData1, int initialData2, int initialData3, int initialData4, int initialData5, int initialData6) : data1(initialData1) , data2(initialData2) , data3(initialData3) , data4(initialData4) , data5(initialData5) , data6(initialData6) { // NOTE: Ops, manual alignment of QObject::connect() arguments is reverted // (we tend to write emitter/receiver on separate lines) connect(this, &MyClass::inlineZeroStatements, this, &MyClass::nonInlineSingleStatement); } void inlineZeroStatements() {} void inlineSingleStatement() { aGlobalInt = 2; } void inlineMultipleStatements() { aGlobalInt = 2; aGlobalInt = 3; } void nonInlineZeroStatements(); void nonInlineSingleStatement(); void nonInlineMultipleStatements(); virtual void shortVirtual(int parameter1, int parameter2, int parameter3) = 0; // NOTE: Ops, awkward placement of "= 0;" virtual void longerVirtual( int parameter1, int parameter2, int parameter3, int parameter4, int parameter5) = 0; int someGetter() const; private: int data1 = 0; int data2 = 0; int data3 = 0; int data4 = 0; int data5 = 0; int data6 = 0; }; void MyClass::nonInlineZeroStatements() {} void MyClass::nonInlineSingleStatement() { aGlobalInt = 2; } void MyClass::nonInlineMultipleStatements() { aGlobalInt = 2; aGlobalInt = 2; } template class TemplateClass {}; // ------------------------------------------------------------------------------------------------- // Enums // ------------------------------------------------------------------------------------------------- // NOTE: OK, enums: one-liner are possible enum MyEnum { SourceFiles = 0x1, GeneratedFiles = 0x2, AllFiles = SourceFiles | GeneratedFiles }; // NOTE: OK, enums: a comment breaks one-liners enum MyEnumX { OSourceFiles = 0x1 // fancy }; // NOTE: OK, enums: longer ones are wrapped enum MyOtherEnum { XSourceFiles = 0x1, XGeneratedFiles = 0x2, XAllFiles = XSourceFiles | XGeneratedFiles }; enum { Match_None, Match_TooManyArgs, Match_TooFewArgs, Match_Ok } matchType = Match_None; // NOTE: Ops, awkward placement of "= value;" at enum definition+use // ------------------------------------------------------------------------------------------------- // Lambdas // ------------------------------------------------------------------------------------------------- void takeLambda(std::function) {} void takeLambdaWithSomeLongerNameHa(std::function) {} bool UtilsFiltered(QVector, std::function) { return true; } void lambda() { auto shortLambda = []() { return 1; }; auto longLambda = []() { aGlobalInt = 3; return; }; takeLambda([]() { return true; }); takeLambda([]() { aGlobalInt = 3; return aGlobalInt; }); // NOTE: Ops, lambda: capture and parameter list should be on separate line int thisCouldBeSomeLongerFunctionCallExpressionOrSoSoSo; takeLambdaWithSomeLongerNameHa( [&]() { return thisCouldBeSomeLongerFunctionCallExpressionOrSoSoSo; }); QVector myClasses; UtilsFiltered(myClasses, [](const N::Baz &) { return 1; }); // NOTE: Ops, lambda: lambda not started on new line in if-condition if (UtilsFiltered(myClasses, [](const N::Baz &) { return 1; })) { ++aGlobalInt; } } // ------------------------------------------------------------------------------------------------- // Control flow // ------------------------------------------------------------------------------------------------- int fn(int, int, int) { return 1; } void controlFlow(int x) { int y = -1; // if if (true) fn(1, 2, 3); int value = 3; if (value) { value += value + 1; --value; } if (x == y) fn(1, 2, 3); else if (x > y) fn(1, 2, 3); else fn(1, 2, 3); if (x == y) { fn(1, 2, 3); return; } else if (x > y) { fn(1, 2, 3); } else { fn(1, 2, 3); } // switch switch (x) { case 0: ++aGlobalInt; return; case 1: fn(1, 2, 3); ++aGlobalInt; break; case 2: fn(1, 2, 3); break; default: break; } // do-while do { value += value + 1; ++value; } while (true); // for QVector myVector; for (int i = 0; i < myVector.size(); ++i) ++aGlobalInt; for (QVector::const_iterator i = myVector.begin(); i != myVector.end(); ++i) ++aGlobalInt; QVector myVectorWithLongName; for (QVector::const_iterator i = myVectorWithLongName.begin(), ei = myVectorWithLongName.end(); i != ei; ++i) { } forever { ++aGlobalInt; --aGlobalInt; } } // ------------------------------------------------------------------------------------------------- // Function declarations and calls - extreme cases // ------------------------------------------------------------------------------------------------- void extremeFunction(const char[]) {} void extremeFunction( int uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuunbelievableLongParameter) { extremeFunction( uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuunbelievableLongParameter); int uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuunbelievableLongValue = 3; ++uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuunbelievableLongValue; extremeFunction( "some super duper super duper super duper super duper super duper super duper long"); // BreakStringLiterals splits the string. extremeFunction("some super duper super duper super duper super duper super duper super duper " "super duper long"); } void extremeFunction2( int parameter1, int parameter2, int parameter3WithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVerVeryVeryLong) { extremeFunction2( parameter1, parameter2, parameter3WithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVerVeryVeryLong); } void extremeFunction3( int parameter1, int parameter2, int parameter3WithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVerVeryVeryLongNameX) { extremeFunction3( parameter1, parameter2, parameter3WithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVerVeryVeryLongNameX); } // ------------------------------------------------------------------------------------------------- // Misc // ------------------------------------------------------------------------------------------------- static Q_LOGGING_CATEGORY(log, "qtc.cpptools.builtineditordocumentprocessor", QtWarningMsg) int hello; // NOTE: Ops, awkward placement of next token after Q_LOGGING_CATEGORY (semicolon helps) // ------------------------------------------------------------------------------------------------- int main() {} #include "clang-format.moc" qbs-src-2.6.1/tests/fuzzy-test/0000755000175100001660000000000014776170045015756 5ustar runnerdockerqbs-src-2.6.1/tests/fuzzy-test/fuzzytester.h0000644000175100001660000000543214776170045020551 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FUZZYTESTER_H #define QBS_FUZZYTESTER_H #include #include #include class TestError { public: TestError(QString errorMessage) : errorMessage(std::move(errorMessage)) {} ~TestError() throw() = default; QString errorMessage; private: const char *what() const throw() { return qPrintable(errorMessage); } }; class FuzzyTester { public: FuzzyTester(); ~FuzzyTester(); void runTest(const QString &profile, const QString &startCommit, int maxDurationInMinutes, int jobCount, bool log); private: void checkoutCommit(const QString &commit); QStringList findAllCommits(const QString &startCommit); QString findWorkingStartCommit(const QString &startCommit); void runGit(const QStringList &arguments, QString *output = 0); bool runQbs(const QString &buildDir, const QString &command, QString *errorOutput = 0); void removeDir(const QString &dir); bool doCleanBuild(QString *errorMessage = 0); void throwIncrementalBuildError(const QString &message, const QStringList &commitSequence); void loadSettings(); void storeSettings() const; static QString logFilePath(const QString &commit, const QString &activity); static QString defaultBuildDir(); QString m_profile; int m_jobCount = 0; bool m_log = false; QString m_headCommit; QString m_currentCommit; QString m_currentActivity; std::queue m_commitsWithLogFiles; QStringList m_unbuildableCommits; QStringList m_buildableCommits; }; #endif // Include guard. qbs-src-2.6.1/tests/fuzzy-test/commandlineparser.cpp0000644000175100001660000001142214776170045022165 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include static QString profileOption() { return "--profile"; } static QString startCommitOption() { return "--start-commit"; } static QString maxDurationoption() { return "--max-duration"; } static QString jobCountOption() { return "--jobs"; } static QString logOption() { return "--log"; } CommandLineParser::CommandLineParser() = default; void CommandLineParser::parse(const QStringList &commandLine) { m_profile.clear(); m_startCommit.clear(); m_maxDuration = 0; m_jobCount = 0; m_log = false; m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = m_commandLine.takeFirst(); while (!m_commandLine.empty()) { const QString arg = m_commandLine.takeFirst(); if (arg == profileOption()) assignOptionArgument(arg, m_profile); else if (arg == startCommitOption()) assignOptionArgument(arg, m_startCommit); else if (arg == jobCountOption()) assignOptionArgument(arg, m_jobCount); else if (arg == maxDurationoption()) parseDuration(); else if (arg == logOption()) m_log = true; else throw ParseException(QStringLiteral("Unknown parameter '%1'").arg(arg)); } if (m_profile.isEmpty()) throw ParseException("No profile given."); if (m_startCommit.isEmpty()) throw ParseException("No start commit given."); } QString CommandLineParser::usageString() const { return QStringLiteral("%1 %2 %3 [%4 ] " "[%5 ] [%6]") .arg(QFileInfo(m_command).fileName(), profileOption(), startCommitOption(), maxDurationoption(), jobCountOption(), logOption()); } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throw ParseException(QStringLiteral("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) { throw ParseException(QStringLiteral("Argument for option '%1' must not be empty.") .arg(option)); } } void CommandLineParser::assignOptionArgument(const QString &option, int &argument) { QString numberString; assignOptionArgument(option, numberString); bool ok; argument = numberString.toInt(&ok); if (!ok || argument <= 0) { throw ParseException(QStringLiteral("Invalid argument '%1' for option '%2'.") .arg(numberString, option)); } } void CommandLineParser::parseDuration() { QString durationString; QString choppedDurationString; assignOptionArgument(maxDurationoption(), durationString); choppedDurationString = durationString; const char suffix = durationString.at(durationString.size() - 1).toLatin1(); const bool hasSuffix = !std::isdigit(suffix); if (hasSuffix) choppedDurationString.chop(1); bool ok; m_maxDuration = choppedDurationString.toInt(&ok); if (!ok || m_maxDuration <= 0) { throw ParseException(QStringLiteral("Invalid duration argument '%1'.") .arg(durationString)); } if (hasSuffix) { switch (suffix) { case 'm': break; case 'd': m_maxDuration *= 24; // Fall-through. case 'h': m_maxDuration *= 60; break; default: throw ParseException(QStringLiteral("Invalid duration suffix '%1'.") .arg(suffix)); } } } qbs-src-2.6.1/tests/fuzzy-test/commandlineparser.h0000644000175100001660000000464614776170045021644 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FUZZYTEST_COMMANDLINEPARSER_H #define QBS_FUZZYTEST_COMMANDLINEPARSER_H #include #include class ParseException : public std::exception { public: ParseException(QString error) : errorMessage(std::move(error)) { } ~ParseException() throw() override = default; QString errorMessage; private: const char *what() const throw() override { return qPrintable(errorMessage); } }; class CommandLineParser { public: CommandLineParser(); void parse(const QStringList &commandLine); QString profile() const { return m_profile; } QString startCommit() const { return m_startCommit; } int maxDurationInMinutes() const { return m_maxDuration; } int jobCount() const { return m_jobCount; } bool log() const { return m_log; } QString usageString() const; private: void assignOptionArgument(const QString &option, QString &argument); void assignOptionArgument(const QString &option, int &argument); void parseDuration(); QStringList m_commandLine; QString m_command; QString m_profile; QString m_startCommit; int m_maxDuration = 0; int m_jobCount = 0; bool m_log = false; }; #endif // Include guard. qbs-src-2.6.1/tests/fuzzy-test/fuzzytester.cpp0000644000175100001660000002753314776170045021112 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "fuzzytester.h" #include #include #include #include #include #include #include #include #include static QString resolveIncrementalActivity() { return "resolve-incremental"; } static QString buildIncrementalActivity() { return "build-incremental"; } static QString buildFromScratchActivity() { return "build-from-scratch"; } FuzzyTester::FuzzyTester() { loadSettings(); } FuzzyTester::~FuzzyTester() { storeSettings(); } void FuzzyTester::runTest(const QString &profile, const QString &startCommit, int maxDurationInMinutes, int jobCount, bool log) { m_profile = profile; m_jobCount = jobCount; m_log = log; runGit(QStringList() << "rev-parse" << "HEAD", &m_headCommit); qDebug("HEAD is %s", qPrintable(m_headCommit)); qDebug("Trying to find a buildable commit to start with..."); const QString workingStartCommit = findWorkingStartCommit(startCommit); qDebug("Found buildable start commit %s.", qPrintable(workingStartCommit)); QStringList allCommits = findAllCommits(workingStartCommit); qDebug("The test set comprises all %d commits between the start commit and HEAD.", int(allCommits.size())); // Shuffle the initial sequence. Otherwise all invocations of the tool with the same start // commit would try the same sequence of commits. std::srand(std::time(nullptr)); std::shuffle(allCommits.begin(), allCommits.end(), std::mt19937(std::random_device()())); quint64 run = 0; QStringList buildSequence(workingStartCommit); QElapsedTimer timer; const qint64 maxDurationInMillis = maxDurationInMinutes * 60 * 1000; if (maxDurationInMillis != 0) timer.start(); bool timerHasExpired = false; while (std::next_permutation(allCommits.begin(), allCommits.end()) && !timerHasExpired) { qDebug("Testing permutation %llu...", ++run); const auto &allCommitsImmutable = allCommits; for (const QString ¤tCommit : allCommitsImmutable) { if (timer.isValid() && timer.hasExpired(maxDurationInMillis)) { timerHasExpired = true; break; } m_currentCommit = currentCommit; buildSequence << currentCommit; checkoutCommit(currentCommit); qDebug("Testing incremental build #%d (%s)", int(buildSequence.size()) - 1, qPrintable(currentCommit)); // Doing "resolve" and "build" separately introduces additional possibilities // for errors, as information from change tracking has to be serialized correctly. QString qbsError; m_currentActivity = resolveIncrementalActivity(); bool success = runQbs(defaultBuildDir(), QStringLiteral("resolve"), &qbsError); if (success) { m_currentActivity = buildIncrementalActivity(); success = runQbs(defaultBuildDir(), QStringLiteral("build"), &qbsError); } m_currentActivity = buildFromScratchActivity(); if (success) { if (!doCleanBuild(&qbsError)) { QString message = "An incremental build succeeded " "with a commit for which a clean build failed."; if (!m_log) { message += QStringLiteral("\nThe qbs error message " "for the clean build was: '%1'").arg(qbsError); } throwIncrementalBuildError(message, buildSequence); } } else { qDebug("Incremental build failed. Checking whether clean build works..."); if (doCleanBuild()) { QString message = "An incremental build failed " "with a commit for which a clean build succeeded."; if (!m_log) { message += QStringLiteral("\nThe qbs error message for " "the incremental build was: '%1'").arg(qbsError); } throwIncrementalBuildError(message, buildSequence); } else { qDebug("Clean build also fails. Continuing."); } } } } if (timerHasExpired) qDebug("Maximum duration reached."); else qDebug("All possible permutations were tried."); } void FuzzyTester::checkoutCommit(const QString &commit) { runGit(QStringList() << "checkout" << commit); runGit(QStringList() << "submodule" << "update" << "--init"); } QStringList FuzzyTester::findAllCommits(const QString &startCommit) { QString allCommitsString; runGit(QStringList() << "log" << (startCommit + "~1.." + m_headCommit) << "--format=format:%h", &allCommitsString); return allCommitsString.simplified().split(QLatin1Char(' '), Qt::SkipEmptyParts); } QString FuzzyTester::findWorkingStartCommit(const QString &startCommit) { const QStringList allCommits = findAllCommits(startCommit); QString qbsError; m_currentActivity = buildFromScratchActivity(); for (auto it = allCommits.crbegin(), end = allCommits.crend(); it != end; ++it) { m_currentCommit = *it; if (m_unbuildableCommits.contains(m_currentCommit)) { qDebug("Skipping known bad commit %s.", qPrintable(m_currentCommit)); continue; } checkoutCommit(m_currentCommit); removeDir(defaultBuildDir()); if (runQbs(defaultBuildDir(), QStringLiteral("build"), &qbsError)) { m_buildableCommits << m_currentCommit; return m_currentCommit; } qDebug("Commit %s is not buildable.", qPrintable(m_currentCommit)); m_unbuildableCommits << m_currentCommit; } throw TestError(QStringLiteral("Cannot run test: Failed to find a single commit that " "builds successfully with qbs. The last qbs error was: '%1'").arg(qbsError)); } void FuzzyTester::runGit(const QStringList &arguments, QString *output) { QProcess git; git.start("git", arguments); if (!git.waitForStarted()) throw TestError("Failed to start git. It is expected to be in the PATH."); if (!git.waitForFinished(300000) || git.exitStatus() != QProcess::NormalExit) // 5 minutes ought to be enough for everyone throw TestError(QStringLiteral("git failed: %1").arg(git.errorString())); if (git.exitCode() != 0) { throw TestError(QStringLiteral("git failed: %1") .arg(QString::fromLocal8Bit(git.readAllStandardError()))); } if (output) *output = QString::fromLocal8Bit(git.readAllStandardOutput()).trimmed(); } bool FuzzyTester::runQbs(const QString &buildDir, const QString &command, QString *errorOutput) { if (errorOutput) errorOutput->clear(); QProcess qbs; QStringList commandLine = QStringList(command) << "-d" << buildDir; if (m_log) { commandLine << "-vv"; const size_t maxLoggedCommits = 2; Q_ASSERT(m_commitsWithLogFiles.size() <= maxLoggedCommits + 1); if (m_commitsWithLogFiles.size() == maxLoggedCommits + 1) { static const QStringList allActivities = QStringList() << resolveIncrementalActivity() << buildIncrementalActivity() << buildFromScratchActivity(); const QString oldCommit = m_commitsWithLogFiles.front(); m_commitsWithLogFiles.pop(); for (const QString &a : allActivities) QFile::remove(logFilePath(oldCommit, a)); } qbs.setStandardErrorFile(logFilePath(m_currentCommit, m_currentActivity)); if (m_commitsWithLogFiles.empty() || m_commitsWithLogFiles.back() != m_currentCommit) m_commitsWithLogFiles.push(m_currentCommit); } else { commandLine << "-qq"; } if (m_jobCount != 0) commandLine << "--jobs" << QString::number(m_jobCount); commandLine << ("profile:" + m_profile); qbs.start("qbs", commandLine); if (!qbs.waitForStarted()) { throw TestError(QStringLiteral("Failed to start qbs. It is expected to be " "in the PATH. QProcess error string: '%1'").arg(qbs.errorString())); } if (!qbs.waitForFinished(-1) || qbs.exitCode() != 0) { if (errorOutput) *errorOutput = QString::fromLocal8Bit(qbs.readAllStandardError()); return false; } return true; } void FuzzyTester::removeDir(const QString &dirPath) { QDir dir(dirPath); if (!dir.removeRecursively()) { throw TestError(QStringLiteral("Failed to remove temporary dir '%1'.") .arg(dir.absolutePath())); } } bool FuzzyTester::doCleanBuild(QString *errorMessage) { if (m_unbuildableCommits.contains(m_currentCommit)) { qDebug("Commit is known not to be buildable, not running qbs."); return false; } if (m_buildableCommits.contains(m_currentCommit)) { qDebug("Commit is known to be buildable, not running qbs."); return true; } const QString cleanBuildDir = "fuzzytest-verification-build"; removeDir(cleanBuildDir); if (runQbs(cleanBuildDir, QStringLiteral("build"), errorMessage)) { m_buildableCommits << m_currentCommit; return true; } m_unbuildableCommits << m_currentCommit; return false; } void FuzzyTester::throwIncrementalBuildError(const QString &message, const QStringList &commitSequence) { const QString commitSequenceString = commitSequence.join(QLatin1Char(',')); throw TestError(QStringLiteral("Found qbs bug with incremental build!\n" "%1\n" "The sequence of commits was: %2.").arg(message, commitSequenceString)); } QString FuzzyTester::logFilePath(const QString &commit, const QString &activity) { return "log." + commit + '.' + activity; } QString FuzzyTester::defaultBuildDir() { return "fuzzytest-build"; } static QString organization() { return "QtProject"; } static QString app() { return "qbs-fuzzy-tester"; } static QString unbuildableCommitsKey() { return "unbuildable-commits"; } static QString buildableCommitsKey() { return "buildable-commits"; } void FuzzyTester::loadSettings() { QSettings s(organization(), app()); m_unbuildableCommits = s.value(unbuildableCommitsKey()).toStringList(); m_buildableCommits = s.value(buildableCommitsKey()).toStringList(); } void FuzzyTester::storeSettings() const { QSettings s(organization(), app()); s.setValue(unbuildableCommitsKey(), m_unbuildableCommits); s.setValue(buildableCommitsKey(), m_buildableCommits); } qbs-src-2.6.1/tests/fuzzy-test/main.cpp0000644000175100001660000000624414776170045017414 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include "fuzzytester.h" #include #include #include static bool parseCommandLine(const QStringList &commandLine, QString &profile, QString &startCommi, int &maxDuration, int &jobCount, bool &log); static bool runTest(const QString &profile, const QString &startCommit, int maxDuration, int jobCount, bool log); int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QString profile; QString startCommit; int maxDuration; int jobCount; bool log; if (!parseCommandLine(app.arguments(), profile, startCommit, maxDuration, jobCount, log)) return EXIT_FAILURE; if (!runTest(profile, startCommit, maxDuration, jobCount, log)) return EXIT_FAILURE; std::cout << "Test finished successfully." << std::endl; return EXIT_SUCCESS; } bool parseCommandLine(const QStringList &commandLine, QString &profile, QString &startCommit, int &maxDuration, int &jobCount, bool &log) { CommandLineParser cmdParser; try { cmdParser.parse(commandLine); } catch (const ParseException &e) { std::cerr << "Invalid command line: " << qPrintable(e.errorMessage) << std::endl; std::cerr << "Usage:" << std::endl << qPrintable(cmdParser.usageString()) << std::endl; return false; } profile = cmdParser.profile(); startCommit = cmdParser.startCommit(); maxDuration = cmdParser.maxDurationInMinutes(); jobCount = cmdParser.jobCount(); log = cmdParser.log(); return true; } bool runTest(const QString &profile, const QString &startCommit, int maxDuration, int jobCount, bool log) { try { FuzzyTester().runTest(profile, startCommit, maxDuration, jobCount, log); } catch (const TestError &e) { std::cerr << qPrintable(e.errorMessage) << std::endl; return false; } return true; } qbs-src-2.6.1/tests/fuzzy-test/fuzzy-test.qbs0000644000175100001660000000076214776170045020636 0ustar runnerdockerQtApplication { name: "qbs_fuzzy-test" type: "application" consoleApplication: true Depends { name: "qbsbuildconfig" } cpp.cxxLanguageVersion: "c++20" cpp.minimumMacosVersion: "11.0" files: [ "commandlineparser.cpp", "commandlineparser.h", "fuzzytester.cpp", "fuzzytester.h", "main.cpp", ] Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: qbsbuildconfig.appInstallDir } } qbs-src-2.6.1/tests/fuzzy-test/CMakeLists.txt0000644000175100001660000000033014776170045020512 0ustar runnerdockerset(SOURCES commandlineparser.cpp commandlineparser.h fuzzytester.cpp fuzzytester.h main.cpp ) add_qbs_app(qbs_fuzzy-test DEPENDS Qt${QT_VERSION_MAJOR}::Core SOURCES ${SOURCES} ) qbs-src-2.6.1/tests/benchmarker/0000755000175100001660000000000014776170045016073 5ustar runnerdockerqbs-src-2.6.1/tests/benchmarker/runsupport.cpp0000644000175100001660000000521014776170045021036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "runsupport.h" #include "exception.h" #include #include #include #include namespace qbsBenchmarker { void runProcess(const QStringList &commandLine, const QString &workingDir, QByteArray *output, int *exitCode) { QStringList args = commandLine; const QString command = args.takeFirst(); QProcess p; if (!workingDir.isEmpty()) p.setWorkingDirectory(workingDir); p.start(command, args); if (!p.waitForStarted()) throw Exception(QStringLiteral("Process '%1' failed to start.").arg(command)); p.waitForFinished(-1); if (p.exitStatus() != QProcess::NormalExit) { throw Exception(QStringLiteral("Error running '%1': %2") .arg(command, p.errorString())); } if (exitCode) *exitCode = p.exitCode(); if (p.exitCode() != 0) { QString errorString = QStringLiteral("Command '%1' finished with exit code %2.") .arg(command).arg(p.exitCode()); const QByteArray stdErr = p.readAllStandardError(); if (!stdErr.isEmpty()) { errorString += QStringLiteral("\nStandard error output was: '%1'") .arg(QString::fromLocal8Bit(stdErr)); } throw Exception(errorString); } if (output) *output = p.readAllStandardOutput().trimmed(); } } // namespace qbsBenchmarker qbs-src-2.6.1/tests/benchmarker/valgrindrunner.h0000644000175100001660000000612014776170045021303 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BENCHMARKER_BENCHMARKRUNNER_H #define QBS_BENCHMARKER_BENCHMARKRUNNER_H #include "activities.h" #include #include namespace qbsBenchmarker { class ValgrindResult { public: ValgrindResult(Activity a, qint64 ic, qint64 mem) : activity(a), instructionCount(ic), peakMemoryUsage(mem) {} Activity activity; qint64 instructionCount; qint64 peakMemoryUsage; }; class ValgrindRunner { public: ValgrindRunner(Activities activities, QString testProject, const QString &qbsBuildDir, const QString &baseOutputDir); void run(); QList results() const { return m_results; } private: void traceResolving(); void traceRuleExecution(); void traceNullBuild(); void traceActivity(Activity activity, const QString &buildDirCallgrind, const QString &buildDirMassif); QStringList qbsCommandLine(const QString &command, const QString &buildDir, bool dryRun) const; QStringList wrapForValgrind(const QStringList &commandLine, const QString &tool, const QString &outFile) const; QStringList valgrindCommandLine(const QString &qbsCommand, const QString &buildDir, bool dryRun, const QString &tool, const QString &outFile) const; void addToResults(const ValgrindResult &results); qint64 runCallgrind(const QString &qbsCommand, const QString &buildDir, bool dryRun, const QString &outFile); qint64 runMassif(const QString &qbsCommand, const QString &buildDir, bool dryRun, const QString &outFile); const Activities m_activities; const QString m_testProject; const QString m_qbsBinary; const QString m_baseOutputDir; QList m_results; std::mutex m_resultsMutex; }; } // namespace qbsBenchmarker #endif // Include guard. qbs-src-2.6.1/tests/benchmarker/valgrindrunner.cpp0000644000175100001660000002440214776170045021641 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "valgrindrunner.h" #include "exception.h" #include "runsupport.h" #include #include #include #include #include #include #include #include #include namespace qbsBenchmarker { ValgrindRunner::ValgrindRunner(Activities activities, QString testProject, const QString &qbsBuildDir, const QString &baseOutputDir) : m_activities(activities) , m_testProject(std::move(testProject)) , m_qbsBinary(qbsBuildDir + "/benchmarker/install-root/bin/qbs") , m_baseOutputDir(baseOutputDir) { if (!QDir::root().mkpath(m_baseOutputDir)) throw Exception(QStringLiteral("Failed to create directory '%1'.").arg(baseOutputDir)); } void ValgrindRunner::run() { std::deque> futures; if (m_activities & ActivityResolving) futures.push_back(QtConcurrent::run([this]{ traceResolving(); })); if (m_activities & ActivityRuleExecution) futures.push_back(QtConcurrent::run([this]{ traceRuleExecution(); })); if (m_activities & ActivityNullBuild) futures.push_back(QtConcurrent::run([this]{ traceNullBuild(); })); while (!futures.empty()) { futures.front().waitForFinished(); futures.pop_front(); } } void ValgrindRunner::traceResolving() { const QString buildDirCallgrind = m_baseOutputDir + "/build-dir.resolving.callgrind"; const QString buildDirMassif = m_baseOutputDir + "/build-dir.resolving.massif"; traceActivity(ActivityResolving, buildDirCallgrind, buildDirMassif); } void ValgrindRunner::traceRuleExecution() { const QString buildDirCallgrind = m_baseOutputDir + "/build-dir.rule-execution.callgrind"; const QString buildDirMassif = m_baseOutputDir + "/build-dir.rule-execution.massif"; runProcess(qbsCommandLine("resolve", buildDirCallgrind, false)); runProcess(qbsCommandLine("resolve", buildDirMassif, false)); traceActivity(ActivityRuleExecution, buildDirCallgrind, buildDirMassif); } void ValgrindRunner::traceNullBuild() { const QString buildDirCallgrind = m_baseOutputDir + "/build-dir.null-build.callgrind"; const QString buildDirMassif = m_baseOutputDir + "/build-dir.null-build.massif"; runProcess(qbsCommandLine("build", buildDirCallgrind, false)); runProcess(qbsCommandLine("build", buildDirMassif, false)); traceActivity(ActivityNullBuild, buildDirCallgrind, buildDirMassif); } void ValgrindRunner::traceActivity(Activity activity, const QString &buildDirCallgrind, const QString &buildDirMassif) { QString activityString; QString qbsCommand; bool dryRun = false; switch (activity) { case ActivityResolving: activityString = "resolving"; qbsCommand = "resolve"; break; case ActivityRuleExecution: activityString = "rule-execution"; qbsCommand = "build"; dryRun = true; break; case ActivityNullBuild: activityString = "null-build"; qbsCommand = "build"; break; } const QString outFileCallgrind = m_baseOutputDir + "/outfile." + activityString + ".callgrind"; const QString outFileMassif = m_baseOutputDir + "/outfile." + activityString + ".massif"; QFuture callGrindFuture = QtConcurrent::run( [this, qbsCommand, buildDirCallgrind, dryRun, outFileCallgrind] { return runCallgrind(qbsCommand, buildDirCallgrind, dryRun, outFileCallgrind); }); QFuture massifFuture = QtConcurrent::run( [this, qbsCommand, buildDirMassif, dryRun, outFileMassif] { return runMassif(qbsCommand, buildDirMassif, dryRun, outFileMassif); }); callGrindFuture.waitForFinished(); massifFuture.waitForFinished(); addToResults(ValgrindResult(activity, callGrindFuture.result(), massifFuture.result())); } QStringList ValgrindRunner::qbsCommandLine(const QString &command, const QString &buildDir, bool dryRun) const { QStringList commandLine = QStringList() << m_qbsBinary << command << "-qq" << "-d" << buildDir << "-f" << m_testProject; if (dryRun) commandLine << "--dry-run"; return commandLine; } QStringList ValgrindRunner::wrapForValgrind(const QStringList &commandLine, const QString &tool, const QString &outFile) const { return QStringList() << "valgrind" << "--smc-check=all" << "--trace-children=yes" << ("--tool=" + tool) << ("--" + tool + "-out-file=" + outFile) << commandLine; } QStringList ValgrindRunner::valgrindCommandLine(const QString &qbsCommand, const QString &buildDir, bool dryRun, const QString &tool, const QString &outFile) const { return wrapForValgrind(qbsCommandLine(qbsCommand, buildDir, dryRun), tool, outFile); } void ValgrindRunner::addToResults(const ValgrindResult &result) { std::lock_guard locker(m_resultsMutex); m_results.push_back(result); } qint64 ValgrindRunner::runCallgrind(const QString &qbsCommand, const QString &buildDir, bool dryRun, const QString &outFile) { runProcess(valgrindCommandLine(qbsCommand, buildDir, dryRun, "callgrind", outFile)); QFile f(outFile); if (!f.open(QIODevice::ReadOnly)) { throw Exception(QStringLiteral("Failed to open file '%1': %2") .arg(outFile, f.errorString())); } while (!f.atEnd()) { const QByteArray line = f.readLine().trimmed(); static const QByteArray magicString = "summary: "; if (!line.startsWith(magicString)) continue; const QByteArray icString = line.mid(magicString.size()); bool ok; const qint64 iCount = icString.toLongLong(&ok); if (!ok) { throw Exception(QStringLiteral("Unexpected line in callgrind output file " "'%1': '%2'.") .arg(outFile, QString::fromLocal8Bit(line))); } return iCount; } throw Exception(QStringLiteral("Failed to find summary line in callgrind " "output file '%1'.").arg(outFile)); } qint64 ValgrindRunner::runMassif(const QString &qbsCommand, const QString &buildDir, bool dryRun, const QString &outFile) { runProcess(valgrindCommandLine(qbsCommand, buildDir, dryRun, "massif", outFile)); QByteArray ms_printOutput; runProcess(QStringList() << "ms_print" << outFile, QString(), &ms_printOutput); QBuffer buffer(&ms_printOutput); buffer.open(QIODevice::ReadOnly); QByteArray peakSnapshot; const QString exceptionStringPattern = QStringLiteral("Failed to extract peak memory " "usage from file '%1': %2").arg(outFile); while (!buffer.atEnd()) { const QByteArray line = buffer.readLine(); static const QByteArray magicString = " (peak)"; const int magicStringOffset = line.indexOf(magicString); if (magicStringOffset == -1) continue; int delimiterOffset = line.lastIndexOf(',', magicStringOffset); if (delimiterOffset == -1) delimiterOffset = line.lastIndexOf('[', magicStringOffset); if (delimiterOffset == -1) { const QString details = QStringLiteral("Failed to extract peak snapshot from " "line '%1'.").arg(QString::fromLocal8Bit(line)); throw Exception(exceptionStringPattern.arg(details)); } peakSnapshot = line.mid(delimiterOffset + 1, magicStringOffset - delimiterOffset).trimmed(); break; } if (peakSnapshot.isEmpty()) throw Exception(exceptionStringPattern.arg("No peak marker found")); while (!buffer.atEnd()) { const QByteArray line = buffer.readLine().simplified(); if (!line.startsWith(QByteArray(peakSnapshot + ' '))) continue; const QList entries = line.split(' '); if (entries.size() != 6) { const QString details = QStringLiteral("Expected 6 entries in line '%1', but " "there are %2.").arg(QString::fromLocal8Bit(line)).arg(entries.size()); throw Exception(exceptionStringPattern.arg(details)); } QByteArray peakMemoryString = entries.at(2); peakMemoryString.replace(',', QByteArray()); bool ok; qint64 peakMemoryUsage = peakMemoryString.toLongLong(&ok); if (!ok) { const QString details = QStringLiteral("Failed to parse peak memory value '%1' " "as a number.").arg(QString::fromLocal8Bit(peakMemoryString)); throw Exception(exceptionStringPattern.arg(details)); } return peakMemoryUsage; } const QString details = QStringLiteral("Failed to find snapshot '%1'.") .arg(QString::fromLocal8Bit(peakSnapshot)); throw Exception(exceptionStringPattern.arg(details)); } } // namespace qbsBenchmarker qbs-src-2.6.1/tests/benchmarker/commandlineparser.cpp0000644000175100001660000001431714776170045022310 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include "exception.h" #include #include #include #include namespace qbsBenchmarker { static QString resolveActivity() { return "resolving"; } static QString ruleExecutionActivity() { return "rule-execution"; } static QString nullBuildActivity() { return "null-build"; } static QString allActivities() { return "all"; } CommandLineParser::CommandLineParser() = default; void CommandLineParser::parse() { QCommandLineParser parser; parser.setApplicationDescription("This tool aims to detect qbs performance regressions " "using valgrind."); parser.addHelpOption(); QCommandLineOption oldCommitOption(QStringList{"old-commit", "o"}, "The old qbs commit.", "old commit"); parser.addOption(oldCommitOption); QCommandLineOption newCommitOption(QStringList{"new-commit", "n"}, "The new qbs commit.", "new commit"); parser.addOption(newCommitOption); QCommandLineOption testProjectOption(QStringList{"test-project", "p"}, "The example project to use for the benchmark.", "project file path"); parser.addOption(testProjectOption); QCommandLineOption qbsRepoOption(QStringList{"qbs-repo", "r"}, "The qbs repository.", "repo path"); parser.addOption(qbsRepoOption); QCommandLineOption activitiesOption(QStringList{"activities", "a"}, QStringLiteral("The activities to benchmark. Possible values (CSV): %1,%2,%3,%4") .arg(resolveActivity(), ruleExecutionActivity(), nullBuildActivity(), allActivities()), "activities", allActivities()); parser.addOption(activitiesOption); QCommandLineOption thresholdOption(QStringList{"regression-threshold", "t"}, "A relative increase higher than this is considered a performance regression. " "All temporary data from running the benchmarks will be kept if that happens.", "value in per cent"); parser.addOption(thresholdOption); parser.process(*QCoreApplication::instance()); const QList mandatoryOptions = QList() << oldCommitOption << newCommitOption << testProjectOption << qbsRepoOption; for (const QCommandLineOption &o : mandatoryOptions) { if (!parser.isSet(o)) throwException(o.names().constFirst(), parser.helpText()); if (parser.value(o).isEmpty()) throwException(o.names().constFirst(), QString(), parser.helpText()); } m_oldCommit = parser.value(oldCommitOption); m_newCommit = parser.value(newCommitOption); if (m_oldCommit == m_newCommit) { throw Exception(QStringLiteral("Error parsing command line: " "'new commit' and 'old commit' must be different commits.\n%1").arg(parser.helpText())); } m_testProjectFilePath = parser.value(testProjectOption); m_qbsRepoDirPath = parser.value(qbsRepoOption); const QStringList activitiesList = parser.value(activitiesOption).split(','); m_activities = Activities(); for (const QString &activityString : activitiesList) { if (activityString == allActivities()) { m_activities = ActivityResolving | ActivityRuleExecution | ActivityNullBuild; break; } else if (activityString == resolveActivity()) { m_activities = ActivityResolving; } else if (activityString == ruleExecutionActivity()) { m_activities |= ActivityRuleExecution; } else if (activityString == nullBuildActivity()) { m_activities |= ActivityNullBuild; } else { throwException(activitiesOption.names().constFirst(), activityString, parser.helpText()); } } m_regressionThreshold = 5; if (parser.isSet(thresholdOption)) { bool ok = true; const QString rawThresholdValue = parser.value(thresholdOption); m_regressionThreshold = rawThresholdValue.toInt(&ok); if (!ok) throwException(thresholdOption.names().constFirst(), rawThresholdValue, parser.helpText()); } } void CommandLineParser::throwException(const QString &optionName, const QString &illegalValue, const QString &helpText) { const QString errorText(QStringLiteral("Error parsing command line: Illegal value '%1' " "for option '--%2'.\n%3").arg(illegalValue, optionName, helpText)); throw Exception(errorText); } void CommandLineParser::throwException(const QString &missingOption, const QString &helpText) { const QString errorText(QStringLiteral("Error parsing command line: Missing mandatory " "option '--%1'.\n%3").arg(missingOption, helpText)); throw Exception(errorText); } } // namespace qbsBenchmarker qbs-src-2.6.1/tests/benchmarker/commandlineparser.h0000644000175100001660000000447614776170045021762 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BENCHMARKER_COMMANDLINEPARSER_H #define QBS_BENCHMARKER_COMMANDLINEPARSER_H #include "activities.h" #include namespace qbsBenchmarker { class CommandLineParser { public: CommandLineParser(); void parse(); Activities activies() const { return m_activities; } QString oldCommit() const { return m_oldCommit; } QString newCommit() const { return m_newCommit; } QString testProjectFilePath() const { return m_testProjectFilePath; } QString qbsRepoDirPath() const { return m_qbsRepoDirPath; } int regressionThreshold() const { return m_regressionThreshold; } private: [[noreturn]] void throwException(const QString &optionName, const QString &illegalValue, const QString &helpText); [[noreturn]] void throwException(const QString &missingOption, const QString &helpText); Activities m_activities; QString m_oldCommit; QString m_newCommit; QString m_testProjectFilePath; QString m_qbsRepoDirPath; int m_regressionThreshold = 0; }; } // namespace qbsBenchmarker #endif // Include guard. qbs-src-2.6.1/tests/benchmarker/benchmarker.qbs0000644000175100001660000000141114776170045021060 0ustar runnerdockerQtApplication { name: "qbs_benchmarker" type: "application" consoleApplication: true cpp.cxxLanguageVersion: "c++20" cpp.minimumMacosVersion: "11.0" condition: Qt.concurrent.present Depends { name: "qbsbuildconfig" } Depends { name: "Qt.concurrent" required: false } files: [ "activities.h", "benchmarker-main.cpp", "benchmarker.cpp", "benchmarker.h", "commandlineparser.cpp", "commandlineparser.h", "exception.h", "runsupport.cpp", "runsupport.h", "valgrindrunner.cpp", "valgrindrunner.h", ] Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: qbsbuildconfig.appInstallDir } } qbs-src-2.6.1/tests/benchmarker/runsupport.h0000644000175100001660000000325214776170045020507 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BENCHMARKER_RUNSUPPORT_H #define QBS_BENCHMARKER_RUNSUPPORT_H #include #include #include QT_BEGIN_NAMESPACE class QByteArray; QT_END_NAMESPACE namespace qbsBenchmarker { void runProcess(const QStringList &commandLine, const QString& workingDir = QString(), QByteArray *output = nullptr, int *exitCode = nullptr); } // namespace qbsBenchmarker #endif // Include guard. qbs-src-2.6.1/tests/benchmarker/benchmarker.cpp0000644000175100001660000001272014776170045021062 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "benchmarker.h" #include "exception.h" #include "runsupport.h" #include "valgrindrunner.h" #include #include #include #include namespace qbsBenchmarker { Benchmarker::Benchmarker(Activities activities, QString oldCommit, QString newCommit, QString testProject, QString qbsRepo) : m_activities(activities) , m_oldCommit(std::move(oldCommit)) , m_newCommit(std::move(newCommit)) , m_testProject(std::move(testProject)) , m_qbsRepo(std::move(qbsRepo)) { } Benchmarker::~Benchmarker() { if (!m_commitToRestore.isEmpty()) { try { runProcess(QStringList() << "git" << "checkout" << m_commitToRestore, m_qbsRepo); } catch (const Exception &e) { qDebug("Failed to restore original commit %s: %s", qPrintable(m_commitToRestore), qPrintable(e.description())); } } } void Benchmarker::benchmark() { rememberCurrentRepoState(); runProcess(QStringList() << "git" << "checkout" << m_oldCommit, m_qbsRepo); const QString oldQbsBuildDir = m_baseOutputDir.path() + "/qbs-build." + m_oldCommit; std::cout << "Building from old repo state..." << std::endl; buildQbs(oldQbsBuildDir); runProcess(QStringList() << "git" << "checkout" << m_newCommit, m_qbsRepo); const QString newQbsBuildDir = m_baseOutputDir.path() + "/qbs-build." + m_newCommit; std::cout << "Building from new repo state..." << std::endl; buildQbs(newQbsBuildDir); std::cout << "Now running valgrind. This can take a while." << std::endl; ValgrindRunner oldDataRetriever(m_activities, m_testProject, oldQbsBuildDir, m_baseOutputDir.path() + "/benchmark-data." + m_oldCommit); ValgrindRunner newDataRetriever(m_activities, m_testProject, newQbsBuildDir, m_baseOutputDir.path() + "/benchmark-data." + m_newCommit); QFuture oldFuture = QtConcurrent::run([&oldDataRetriever]{ oldDataRetriever.run(); }); QFuture newFuture = QtConcurrent::run([&newDataRetriever]{ newDataRetriever.run(); }); oldFuture.waitForFinished(); const auto oldValgrindResults = oldDataRetriever.results(); for (const ValgrindResult &valgrindResult : oldValgrindResults) { BenchmarkResult &benchmarkResult = m_results[valgrindResult.activity]; benchmarkResult.oldInstructionCount = valgrindResult.instructionCount; benchmarkResult.oldPeakMemoryUsage = valgrindResult.peakMemoryUsage; } newFuture.waitForFinished(); const auto newValgrindResults = newDataRetriever.results(); for (const ValgrindResult &valgrindResult : newValgrindResults) { BenchmarkResult &benchmarkResult = m_results[valgrindResult.activity]; benchmarkResult.newInstructionCount = valgrindResult.instructionCount; benchmarkResult.newPeakMemoryUsage = valgrindResult.peakMemoryUsage; } std::cout << "Done!" << std::endl; } void Benchmarker::rememberCurrentRepoState() { QByteArray commit; int exitCode = 0; try { runProcess(QStringList() << "git" << "symbolic-ref" << "--short" << "HEAD", m_qbsRepo, &commit, &exitCode); } catch (const Exception &) { if (exitCode == 0) { // runProcess did not throw because of the exit code. throw; } // Fallback, in case git cannot retrieve a nice symbolic name. runProcess(QStringList() << "git" << "describe" << "HEAD", m_qbsRepo, &commit); } m_commitToRestore = QString::fromLatin1(commit); } void Benchmarker::buildQbs(const QString &buildDir) const { if (!QDir::root().mkpath(buildDir)) throw Exception(QStringLiteral("Failed to create directory '%1'.").arg(buildDir)); runProcess(QStringList() << QCoreApplication::applicationDirPath() + "/qbs" << "resolve" << "config:benchmarker" << "qbs.buildVariant:profiling" << "qbs.installPrefix:''" << "-f" << m_qbsRepo + "/qbs.qbs", buildDir); runProcess(QStringList() << QCoreApplication::applicationDirPath() + "/qbs" << "build" << "config:benchmarker", buildDir); } } // namespace qbsBenchmarker qbs-src-2.6.1/tests/benchmarker/exception.h0000644000175100001660000000350314776170045020243 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BENCHMARKER_EXCEPTION_H #define QBS_BENCHMARKER_EXCEPTION_H #include #include namespace qbsBenchmarker { class Exception : public QException { public: explicit Exception(QString description) : m_description(std::move(description)) {} ~Exception() throw() override = default; QString description() const { return m_description; } private: void raise() const override { throw *this; } Exception *clone() const override { return new Exception(*this); } QString m_description; }; } // namespace qbsBenchmarker #endif // Include guard. qbs-src-2.6.1/tests/benchmarker/CMakeLists.txt0000644000175100001660000000057014776170045020635 0ustar runnerdockerset(SOURCES activities.h benchmarker-main.cpp benchmarker.cpp benchmarker.h commandlineparser.cpp commandlineparser.h exception.h runsupport.cpp runsupport.h valgrindrunner.cpp valgrindrunner.h ) add_qbs_app(qbs_benchmarker DEPENDS Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Concurrent SOURCES ${SOURCES} ) qbs-src-2.6.1/tests/benchmarker/benchmarker-main.cpp0000644000175100001660000001172414776170045022007 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "benchmarker.h" #include "commandlineparser.h" #include "exception.h" #include #include #include using namespace qbsBenchmarker; static bool hasRegression = false; static int relativeChange(qint64 oldVal, qint64 newVal) { return newVal == 0 ? 0 : (newVal - oldVal) * 100 / oldVal; } static QByteArray relativeChangeString(int change) { QByteArray changeString = QByteArray::number(change); changeString += " %"; if (change > 0) changeString.prepend('+'); return changeString; } static void printResults(Activity activity, const BenchmarkResults &results, int regressionThreshold) { std::cout << "========== Performance data for "; switch (activity) { case ActivityResolving: std::cout << "Resolving"; break; case ActivityRuleExecution: std::cout << "Rule Execution"; break; case ActivityNullBuild: std::cout << "Null Build"; break; } std::cout << " ==========" << std::endl; const BenchmarkResult result = results.value(activity); const char * const indent = " "; std::cout << indent << "Old instruction count: " << result.oldInstructionCount << std::endl; std::cout << indent << "New instruction count: " << result.newInstructionCount << std::endl; int change = relativeChange(result.oldInstructionCount, result.newInstructionCount); if (change > regressionThreshold) hasRegression = true; std::cout << indent << "Relative change: " << relativeChangeString(change).constData() << std::endl; std::cout << indent << "Old peak memory usage: " << result.oldPeakMemoryUsage << " Bytes" << std::endl; std::cout << indent << "New peak memory usage: " << result.newPeakMemoryUsage << " Bytes" << std::endl; change = relativeChange(result.oldPeakMemoryUsage, result.newPeakMemoryUsage); if (change > regressionThreshold) hasRegression = true; std::cout << indent << "Relative change: " << relativeChangeString(change).constData() << std::endl; } static void printResults(Activities activities, const BenchmarkResults &results, int regressionThreshold) { if (activities & ActivityResolving) printResults(ActivityResolving, results, regressionThreshold); if (activities & ActivityRuleExecution) printResults(ActivityRuleExecution, results, regressionThreshold); if (activities & ActivityNullBuild) printResults(ActivityNullBuild, results, regressionThreshold); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(); } catch (const Exception &e) { std::cerr << qPrintable(e.description()) << std::endl; return EXIT_FAILURE; } Benchmarker benchmarker(clParser.activies(), clParser.oldCommit(), clParser.newCommit(), clParser.testProjectFilePath(), clParser.qbsRepoDirPath()); try { benchmarker.benchmark(); printResults(clParser.activies(), benchmarker.results(), clParser.regressionThreshold()); if (hasRegression) { benchmarker.keepRawData(); std::cout << "Performance regression detected. Raw benchmarking data available " "under " << qPrintable(benchmarker.rawDataBaseDir()) << '.' << std::endl; } } catch (const Exception &e) { benchmarker.keepRawData(); std::cerr << qPrintable(e.description()) << std::endl; std::cerr << "Build data available under " << qPrintable(benchmarker.rawDataBaseDir()) << '.' << std::endl; return EXIT_FAILURE; } } qbs-src-2.6.1/tests/benchmarker/activities.h0000644000175100001660000000307614776170045020416 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BENCHMARKER_ACTIVITY_H #define QBS_BENCHMARKER_ACTIVITY_H #include namespace qbsBenchmarker { enum Activity { ActivityResolving = 1, ActivityRuleExecution = 2, ActivityNullBuild = 4 }; Q_DECLARE_FLAGS(Activities, Activity) Q_DECLARE_OPERATORS_FOR_FLAGS(Activities) } // namespace qbsBenchmarker #endif // Include guard. qbs-src-2.6.1/tests/benchmarker/benchmarker.h0000644000175100001660000000474014776170045020532 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BENCHMARKER_BENCHMARKER_H #define QBS_BENCHMARKER_BENCHMARKER_H #include "activities.h" #include #include #include #include namespace qbsBenchmarker { class BenchmarkResult { public: qint64 oldInstructionCount; qint64 newInstructionCount; qint64 oldPeakMemoryUsage; qint64 newPeakMemoryUsage; }; using BenchmarkResults = QHash; class Benchmarker { public: Benchmarker(Activities activities, QString oldCommit, QString newCommit, QString testProject, QString qbsRepo); ~Benchmarker(); void benchmark(); void keepRawData() { m_baseOutputDir.setAutoRemove(false ); } BenchmarkResults results() const { return m_results; } QString rawDataBaseDir() const { return m_baseOutputDir.path(); } private: void rememberCurrentRepoState(); void buildQbs(const QString &buildDir) const; const Activities m_activities; const QString m_oldCommit; const QString m_newCommit; const QString m_testProject; const QString m_qbsRepo; QString m_commitToRestore; QTemporaryDir m_baseOutputDir; BenchmarkResults m_results; }; } // namespace qbsBenchmarker #endif // Include guard. qbs-src-2.6.1/tests/tests.qbs0000644000175100001660000000300514776170045015461 0ustar runnerdockerimport qbs.FileInfo Project { references: [ "auto/auto.qbs", "benchmarker/benchmarker.qbs", "clang-format-test/clang-format-test.qbs", "fuzzy-test/fuzzy-test.qbs", "lspclient/lspclient.qbs", ] AutotestRunner { Depends { name: "Qt.core" } Depends { name: "qbs resources" } Depends { name: "qbs_cpp_scanner" } Depends { name: "qbs_qt_scanner" } arguments: project.autotestArguments wrapper: project.autotestWrapper environment: { var env = base; env.push("QBS_INSTALL_DIR=" + FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix)); if (qbs.hostOS.contains("windows") && qbs.targetOS.contains("windows")) { var path = ""; for (var i = 0; i < env.length; ++i) { if (env[i].startsWith("PATH=")) { path = env[i].substring(5); break; } } path = Qt.core.binPath + ";" + path; var arrayElem = "PATH=" + path; if (i < env.length) env[i] = arrayElem; else env.push(arrayElem); } if (qbs.hostOS.contains("darwin") && qbs.targetOS.contains("darwin")) { env.push("DYLD_FRAMEWORK_PATH=" + Qt.core.libPath); env.push("DYLD_LIBRARY_PATH=" + Qt.core.libPath); } return env; } } } qbs-src-2.6.1/tests/CMakeLists.txt0000644000175100001660000000022214776170045016346 0ustar runnerdockeradd_subdirectory(auto) add_subdirectory(benchmarker) add_subdirectory(clang-format-test) add_subdirectory(fuzzy-test) add_subdirectory(lspclient) qbs-src-2.6.1/tests/lspclient/0000755000175100001660000000000014776170045015607 5ustar runnerdockerqbs-src-2.6.1/tests/lspclient/lspclient.cpp0000644000175100001660000003557714776170045020331 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include enum class Command { GotoDefinition, Completion, }; class LspClient : public QObject { public: LspClient(Command command, const QString &socketPath, const QString &codeToInsert, int insertLine, int insertColumn, const QString &filePath, int line, int column); void start(); private: void finishWithError(const QString &msg); void exit(int code); void initiateProtocol(); void handleIncomingData(); void sendMessage(const lsp::JsonObject &msg); void sendMessage(const lsp::JsonRpcMessage &msg); void handleCurrentMessage(); void handleInitializeReply(); void openDocument(); void insertCode(); void sendRequest(); void handleResponse(); void sendGotoDefinitionRequest(); void handleGotoDefinitionResponse(); void sendCompletionRequest(); void handleCompletionResponse(); lsp::DocumentUri uri() const; lsp::DocumentUri::PathMapper mapper() const; const Command m_command; const QString m_socketPath; const QString m_codeToInsert; const int m_insertLine; const int m_insertColumn; const QString m_filePath; int m_line; int m_column; QLocalSocket m_socket; QBuffer m_incomingData; lsp::BaseMessage m_currentMessage; QJsonObject m_messageObject; enum class State { Inactive, Connecting, Initializing, RunningCommand } m_state = State::Inactive; }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); const QCommandLineOption socketOption({"socket", "s"}, "The server socket to connect to.", "socket"); const QCommandLineOption gotoDefinitionOption( {"goto-def", "g"}, "Go to definition from the specified location."); const QCommandLineOption completionOption( {"completion", "c"}, "Request completion at the specified location."); const QCommandLineOption insertCodeOption("insert-code", "A piece of code to insert before doing the actual " "operation.", "code"); const QCommandLineOption insertLocationOption("insert-location", "The location at which to insert the code.", ":"); QCommandLineParser parser; parser.addOptions( {socketOption, insertCodeOption, insertLocationOption, gotoDefinitionOption, completionOption}); parser.addHelpOption(); parser.addPositionalArgument("location", "The location at which to operate.", "::"); parser.process(app); const auto complainAndExit = [&](const char *text) { std::cerr << text << std::endl; parser.showHelp(EXIT_FAILURE); }; if (!parser.isSet(socketOption)) complainAndExit("Socket must be specified."); // Initialized to suppress warning. TODO: In C++23, mark lambdas as noreturn instead. Command command = Command::GotoDefinition; if (parser.isSet(gotoDefinitionOption)) command = Command::GotoDefinition; else if (parser.isSet(completionOption)) command = Command::Completion; else complainAndExit("Don't know what to do."); if (parser.positionalArguments().size() != 1) complainAndExit("Need location."); const auto complainAboutLocationString = [&] { complainAndExit("Invalid location."); }; const QString loc = parser.positionalArguments().first(); int sep1 = loc.indexOf(':'); if (sep1 <= 0) complainAboutLocationString(); if (qbs::Internal::HostOsInfo::isWindowsHost()) { sep1 = loc.indexOf(':', sep1 + 1); if (sep1 < 0) complainAboutLocationString(); } const int sep2 = loc.indexOf(':', sep1 + 1); if (sep2 == -1 || sep2 == loc.size() - 1) complainAboutLocationString(); const auto extractNumber = [&](const QString &s) { bool ok; const int n = s.toInt(&ok); if (!ok || n <= 0) complainAboutLocationString(); return n; }; const int line = extractNumber(loc.mid(sep1 + 1, sep2 - sep1 - 1)); const int column = extractNumber(loc.mid(sep2 + 1)); const QString insertLoc = parser.value(insertLocationOption); int insertLine = -1; int insertColumn = -1; if (insertLoc.isEmpty()) { insertLine = line; insertColumn = column; } else { const int sep = insertLoc.indexOf(':'); if (sep <= 0) complainAboutLocationString(); insertLine = extractNumber(insertLoc.left(sep)); insertColumn = extractNumber(insertLoc.mid(sep + 1)); } LspClient client(command, parser.value(socketOption), parser.value(insertCodeOption), insertLine, insertColumn, QDir::fromNativeSeparators(loc.left(sep1)), line, column); QMetaObject::invokeMethod(&client, &LspClient::start, Qt::QueuedConnection); return app.exec(); } LspClient::LspClient(Command command, const QString &socketPath, const QString &codeToInsert, int insertLine, int insertColumn, const QString &filePath, int line, int column) : m_command(command), m_socketPath(socketPath), m_codeToInsert(codeToInsert), m_insertLine(insertLine), m_insertColumn(insertColumn), m_filePath(filePath), m_line(line), m_column(column) { connect(&m_socket, &QLocalSocket::disconnected, this, [this] { finishWithError("Server disconnected unexpectedly."); }); connect(&m_socket, &QLocalSocket::errorOccurred, this, [this] { finishWithError(QString::fromLatin1("Socket error: %1").arg(m_socket.errorString())); }); connect(&m_socket, &QLocalSocket::connected, this, &LspClient::initiateProtocol); connect(&m_socket, &QLocalSocket::readyRead, this, &LspClient::handleIncomingData); } void LspClient::start() { m_state = State::Connecting; m_incomingData.open(QIODevice::ReadWrite | QIODevice::Append); m_socket.connectToServer(m_socketPath); } void LspClient::finishWithError(const QString &msg) { std::cerr << qPrintable(msg) << std::endl; m_socket.disconnectFromServer(); exit(EXIT_FAILURE); } void LspClient::exit(int code) { m_socket.disconnect(this); qApp->exit(code); } void LspClient::initiateProtocol() { if (m_state != State::Connecting) { finishWithError(QString::fromLatin1("State should be %1, was %2.") .arg(int(State::Connecting), int(m_state))); return; } m_state = State::Initializing; lsp::DynamicRegistrationCapabilities definitionCaps; definitionCaps.setDynamicRegistration(false); lsp::TextDocumentClientCapabilities docCaps; docCaps.setDefinition(definitionCaps); lsp::ClientCapabilities clientCaps; clientCaps.setTextDocument(docCaps); lsp::InitializeParams initParams; initParams.setCapabilities(clientCaps); sendMessage(lsp::InitializeRequest(initParams)); } void LspClient::handleIncomingData() { const int pos = m_incomingData.pos(); m_incomingData.write(m_socket.readAll()); m_incomingData.seek(pos); QString parseError; lsp::BaseMessage::parse(&m_incomingData, parseError, m_currentMessage); if (!parseError.isEmpty()) { return finishWithError(QString::fromLatin1("Error parsing server message: %1.") .arg(parseError)); } if (m_currentMessage.isComplete()) { m_incomingData.buffer().remove(0, m_incomingData.pos()); m_incomingData.seek(0); handleCurrentMessage(); m_currentMessage = {}; m_messageObject = {}; if (m_socket.state() == QLocalSocket::ConnectedState) handleIncomingData(); } } void LspClient::sendMessage(const lsp::JsonObject &msg) { sendMessage(lsp::JsonRpcMessage(msg)); } void LspClient::sendMessage(const lsp::JsonRpcMessage &msg) { lsp::BaseMessage baseMsg = msg.toBaseMessage(); m_socket.write(baseMsg.header()); m_socket.write(baseMsg.content); } void LspClient::handleCurrentMessage() { m_messageObject = lsp::JsonRpcMessage(m_currentMessage).toJsonObject(); switch (m_state) { case State::Inactive: case State::Connecting: finishWithError("Received message in non-connected state."); break; case State::Initializing: handleInitializeReply(); openDocument(); insertCode(); sendRequest(); break; case State::RunningCommand: handleResponse(); break; } } void LspClient::handleInitializeReply() { lsp::ServerCapabilities serverCaps = lsp::InitializeRequest::Response( m_messageObject).result().value_or(lsp::InitializeResult()).capabilities(); const auto defProvider = serverCaps.definitionProvider(); if (!defProvider) return finishWithError("Expected definition provider."); const bool * const defProviderValue = std::get_if(&(*defProvider)); if (!defProviderValue || !*defProviderValue) return finishWithError("Expected definition provider."); sendMessage(lsp::InitializeNotification(lsp::InitializedParams())); } void LspClient::openDocument() { QFile file(m_filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return finishWithError(QString::fromLatin1("Could not open '%1': %2") .arg(m_filePath, file.errorString())); } lsp::TextDocumentItem item; item.setUri(uri()); item.setVersion(0); item.setText(QString::fromUtf8(file.readAll())); item.setLanguageId("application/x-qt.qbs+qml"); sendMessage(lsp::DidOpenTextDocumentNotification(lsp::DidOpenTextDocumentParams(item))); } void LspClient::insertCode() { if (m_codeToInsert.isEmpty()) return; lsp::VersionedTextDocumentIdentifier docId; docId.setUri(uri()); docId.setVersion(1); lsp::DidChangeTextDocumentParams params(docId); lsp::DidChangeTextDocumentParams::TextDocumentContentChangeEvent change; const lsp::Position insertPos(m_insertLine - 1, m_insertColumn- 1); change.setRange({insertPos, insertPos}); change.setText(m_codeToInsert); params.setContentChanges({change}); sendMessage(lsp::DidChangeTextDocumentNotification(params)); if (m_insertLine > m_line || (m_insertLine == m_line && m_insertColumn > m_column)) return; const int newlineCount = m_codeToInsert.count('\n'); m_line += newlineCount; m_column += m_codeToInsert.size() - (newlineCount == 0 ? 0 : m_codeToInsert.lastIndexOf('\n')); } void LspClient::sendRequest() { m_state = State::RunningCommand; switch (m_command) { case Command::GotoDefinition: return sendGotoDefinitionRequest(); case Command::Completion: return sendCompletionRequest(); } } void LspClient::handleResponse() { const QString error = m_messageObject.value(lsp::errorKey).toObject() .value("message").toString(); if (!error.isEmpty()) return finishWithError(error); switch (m_command) { case Command::GotoDefinition: return handleGotoDefinitionResponse(); case Command::Completion: return handleCompletionResponse(); } } void LspClient::sendGotoDefinitionRequest() { const lsp::TextDocumentIdentifier doc(uri()); const lsp::Position pos(m_line - 1, m_column - 1); sendMessage(lsp::GotoDefinitionRequest({doc, pos})); } void LspClient::handleGotoDefinitionResponse() { const lsp::GotoResult result(lsp::GotoDefinitionRequest::Response(m_messageObject) .result().value_or(lsp::GotoResult())); QList links; const auto loc2Link = [this](const lsp::Location &loc) { return loc.toLink(mapper()); }; if (const auto loc = std::get_if(&result)) { links << loc2Link(*loc); } else if (const auto locs = std::get_if>(&result)) { links = lsp::Utils::transform(*locs, loc2Link); } for (const lsp::Utils::Link &link : std::as_const(links)) { std::cout << qPrintable(link.targetFilePath) << ':' << link.targetLine << ':' << (link.targetColumn + 1) << std::endl; } exit(EXIT_SUCCESS); } void LspClient::sendCompletionRequest() { const lsp::TextDocumentIdentifier doc(uri()); const lsp::Position pos(m_line - 1, m_column - 1); sendMessage(lsp::CompletionRequest({doc, pos})); } void LspClient::handleCompletionResponse() { const lsp::CompletionResult result(lsp::CompletionRequest::Response(m_messageObject) .result() .value_or(lsp::CompletionResult())); if (const auto items = std::get_if>(&result)) { for (const lsp::CompletionItem &item : *items) { std::cout << qPrintable(item.label()); if (item.detail()) std::cout << ' ' << qPrintable(*item.detail()); std::cout << std::endl; } } exit(EXIT_SUCCESS); } lsp::DocumentUri LspClient::uri() const { return lsp::DocumentUri::fromFilePath(lsp::Utils::FilePath::fromUserInput(m_filePath), mapper()); } lsp::DocumentUri::PathMapper LspClient::mapper() const { return [](const lsp::Utils::FilePath &fp) { return fp; }; } qbs-src-2.6.1/tests/lspclient/lspclient.qbs0000644000175100001660000000033114776170045020310 0ustar runnerdockerQbsApp { name: "qbs_lspclient" Depends { name: "qtclsp" } Depends { name: "Qt.network" } cpp.defines: base.filter(function(d) { return d !== "QT_NO_CAST_FROM_ASCII"; }) files: "lspclient.cpp" } qbs-src-2.6.1/tests/lspclient/CMakeLists.txt0000644000175100001660000000025014776170045020344 0ustar runnerdockeradd_qbs_app(qbs_lspclient DEPENDS Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network qbscore qtclsp SOURCES lspclient.cpp ) qbs-src-2.6.1/.clang-tidy0000644000175100001660000000423514776170045014510 0ustar runnerdocker--- Checks: > -*, bugprone-*, -bugprone-easily-swappable-parameters, -bugprone-narrowing-conversions, -bugprone-throw-keyword-missing, -bugprone-unchecked-optional-access, cppcoreguidelines-interfaces-global-init, cppcoreguidelines-pro-type-member-init, cppcoreguidelines-slicing, fuchsia-virtual-inheritance, google-build-explicit-make-pair, google-build-namespaces, google-global-names-in-headers, google-objc-*, google-readability-namespace-comments, google-runtime-operator, misc-definitions-in-headers, misc-misplaced-const, misc-new-delete-overloads, misc-non-copyable-objects, misc-redundant-expression, misc-static-assert, misc-uniqueptr-reset-release, misc-unused-*, modernize-avoid-bind, modernize-deprecated-headers, modernize-loop-convert, modernize-make-*, modernize-pass-by-value, modernize-redundant-void-arg, modernize-replace-*, modernize-return-braced-init-list, modernize-shrink-to-fit, modernize-unary-static-assert, modernize-use-auto, modernize-use-bool-literals, modernize-use-emplace, modernize-use-equals-*, modernize-use-noexcept, modernize-use-nullptr, modernize-use-override, modernize-use-transparent-functors, modernize-use-using, performance-*, -performance-no-int-to-ptr, readability-avoid-const-params-in-decls, readability-container-size-empty, readability-delete-null-pointer, readability-deleted-default, readability-identifier-naming, readability-misleading-indentation, readability-misplaced-array-index, readability-non-const-parameter, readability-redundant-*, -readability-redundant-member-init, readability-simplify-boolean-expr, readability-static-definition-in-anonymous-namespace, readability-uniqueptr-delete-release WarningsAsErrors: > bugprone-*, cppcoreguidelines-*, google-*, misc-unused-*, modernize-*, performance-*, readability-*, -readability-container-size-empty HeaderFilterRegex: '' AnalyzeTemporaryDtors: false CheckOptions: modernize-loop-convert.UseCxx20ReverseRanges: false qbs-src-2.6.1/README.md0000644000175100001660000000222314776170045013726 0ustar runnerdocker# Qbs Qbs is a build automation tool designed to conveniently manage the build process of software projects across multiple platforms. Qbs can be used for any software project, regardless of programming language, toolkit, or libraries used. ## Documentation Qbs product documentation is available at [doc.qt.io/qbs](http://doc.qt.io/qbs/index.html) The project's homepage is [wiki.qt.io/qbs](http://wiki.qt.io/qbs) ## Supported platforms Qbs binaries are available for Windows, macOS, Linux, and FreeBSD. For more information about how to install Qbs on your platform, see the [Installing](https://doc.qt.io/qbs/installing.html) page in the documentation. Qbs allows to build applications for different platforms, for the list of supported platforms and the details about each platform, see the [Target Platforms](https://doc.qt.io/qbs/platforms.html) page. ## Building Qbs For information about building Qbs from sources, see ["Appendix A: Building Qbs"](http://doc.qt.io/qbs/building-qbs.html). ## Reporting Bugs Please report any bugs in our [bug tracker](https://bugreports.qt.io/browse/QBS). ## Contributing See [Contributing to Qbs](CONTRIBUTING.md) qbs-src-2.6.1/doc/0000755000175100001660000000000014776170045013215 5ustar runnerdockerqbs-src-2.6.1/doc/qbs-hugo.qdocconf0000644000175100001660000000020314776170045016453 0ustar runnerdockerinclude(config/qbs-project.qdocconf) syntaxhighlighting = true HTML.prologue = "

" qbs-src-2.6.1/doc/howtos.qdoc0000644000175100001660000007314614776170045015423 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage tutorial-8.html \nextpage reference.html \page howtos.html \title How-tos This page provides concrete instructions for common scenarios. \list \li \l{How do I build a Qt-based project?} \li \l{How do I make my app build against my library?} \li \l{How do I build release with debug information?} \li \l{How do I separate and install debugging symbols?} \li \l{How do I use precompiled headers?} \li \l{How do I make use of rpaths?} \li \l{How do I make sure my generated sources are getting compiled?} \li \l{How do I run my autotests?} \li \l{How do I use ccache?} \li \l{How do I create a module for a third-party library?} \li \l{How do I build against libraries that provide pkg-config files?} \li \l{How do I create application bundles and frameworks on iOS, macOS, tvOS, and watchOS?} \li \l{How do I apply C/C++ preprocessor macros to only a subset of the files in my product?} \li \l{How do I disable a compiler warning?} \li \l{How do I make the state of my Git repository available to my source files?} \li \l{How do I limit the number of concurrent jobs for the linker only?} \li \l{How do I add QML files to a project?} \li \l{How do I define a reusable Group of files that can be included in other \QBS files?} \li \l{How do I access properties of a base type?} \li \l{How do I print the value of a property?} \li \l{How do I debug \QBS scripts?} \li \l{How do I sign an application for an Apple platform?} \endlist \section1 How do I build a Qt-based project? First of all, your project files need to declare \l{Depends}{dependencies} on \l{Qt} modules. To build the project, you need a matching \e profile. The following commands set up and use a Qt-specific profile: \code $ qbs setup-qt /usr/bin/qmake qt $ cd my_project $ qbs profile:qt \endcode If you plan to use this profile a lot, consider making it the default one: \code $ qbs config defaultProfile qt $ cd my_project $ qbs \endcode See \l{Managing Qt Versions} for more details. \note These instructions are only relevant for building from the command line. If you use Qt Creator, profiles are set up automatically from the information in the Kit. \section1 How do I make my app build against my library? This is achieved by introducing a \e dependency between the two products using the \l{Depends} item. Here is a simple, but complete example: \code Project { CppApplication { name : "the-app" files : [ "main.cpp" ] Depends { name: "the-lib" } } DynamicLibrary { name: "the-lib" Depends { name: "cpp" } files: [ "lib.cpp", "lib.h", ] Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } } } \endcode The product \c the-lib is a dynamic library. It expects other products to build against it, and for that purpose, it exports an include path (via an \l{Export} item), so that the source files in these products can include the library's header file. The product \c the-app is an application that expresses its intent to link against \c the-lib by declaring a dependency on it. Now \c main.cpp can include \c lib.h (because of the exported include path) and the application binary will link against the library (because the linker \l{Rule}{rule} in the \l{cpp} module considers library dependencies as inputs). \note In a non-trivial project, the two products would not be defined in the same file. Instead, you would put them into files of their own and use the \l{Project::references}{Project.references} property to pull them into the project. The product definitions would stay exactly the same. In particular, their location in the project tree is irrelevant to the relationship between them. \section2 Choosing Between Dynamic and Statically-built Qt Projects To build \c "the-lib" as either a dynamic or static library, depending on how Qt was built, you can use the following code: \code Product { name: "the-lib" type: Qt.core.staticBuild ? "staticlibrary" : "dynamiclibrary" Depends { name: "Qt.core" } // ... } \endcode \section1 How do I build release with debug information? You can simply use the \c{"profiling"} \l{qbs::buildVariant}{qbs.buildVariant}: \code qbs build qbs.buildVariant:profiling \endcode \section1 How do I separate and install debugging symbols? First, you need to set the \l{cpp::debugInformation}{cpp.debugInformation} and \l{cpp::separateDebugInformation}{cpp.separateDebugInformation} properties to \c true or use some conditional expression in your product: \code CppApplication { // ... cpp.debugInformation: qbs.buildVariant !== "release" cpp.separateDebugInformation: true } \endcode Now, you can install your \l{Application}{application}, \l{DynamicLibrary}{dynamic library} or \l{LoadableModule}{loadable module} among with its debugging symbols as follows: \code CppApplication { // ... install: true installDir: "bin" installDebugInformation: true debugInformationInstallDir: "bin" } \endcode If you are not using \l{List of Convenience Items}{convenience items}, you can install debug symbols manually using the \l{Group} item. If the \l{cpp::separateDebugInformation}{cpp.separateDebugInformation} property is set to \c true, \QBS will create debugging symbols with the corresponding file tags \c "debuginfo_app" (for an application), \c "debuginfo_dll" (for a dynamic library), or \c "debuginfo_loadablemodule" (for a macOS plugin). \code Product { type: "application" Depends { name: "cpp" } cpp.debugInformation: qbs.buildVariant !== "release" cpp.separateDebugInformation: true Group { fileTagsFilter: cpp.separateDebugInformation ? ["debuginfo_app"] : [] qbs.install: true qbs.installDir: "bin" qbs.installSourceBase: buildDirectory } } \endcode If you're building a shared library, you need to use the \c "debuginfo_dll" tag instead: \code Product { type: "dynamic_library" // ... Group { fileTagsFilter: cpp.separateDebugInformation ? ["debuginfo_dll"] : [] qbs.install: true qbs.installDir: "lib" qbs.installSourceBase: buildDirectory } } \endcode If you're building a macOS plugin, you need to use the \c "debuginfo_loadablemodule" tag instead: \code Product { type: "loadablemodule" // ... Group { fileTagsFilter: cpp.separateDebugInformation ? ["debuginfo_loadablemodule"] : [] qbs.install: true qbs.installDir: "PlugIns" qbs.installSourceBase: buildDirectory } } \endcode \section1 How do I use precompiled headers? If you use a \l Group item to add a precompiled header file to a product and mark it with the \l{filetags-cpp}{relevant file tag} (\c c_pch_src, \c cpp_pch_src, \c objc_pch_src, or \c objcpp_pch_src), it is used automatically. Only one precompiled header is allowed per product and language. For example: \code CppApplication { name: "the-app" files: ["main.cpp"] Group { files: ["precompiled-header.pch"] fileTags: ["cpp_pch_src"] } } \endcode \section1 How do I make use of rpaths? rpath designates the run-time search path used by the dynamic linker when loading libraries on UNIX platforms. This concept does not apply to Windows. Suppose you have a project with two dynamic library products \c LibraryA and \c LibraryB and one dependent application product. Also, \c LibraryB depends on \c LibraryA. The application is installed to the \c bin folder and the libraries are installed to the \c lib folder next to the \c bin folder. You want the application to be able to find the dependent libraries relative to its own location. This can be achieved by usage of the \l{cpp::rpaths}{cpp.rpaths} property. First, you need to set \l{cpp::rpaths}{cpp.rpaths} in your libraries so they can find dependent libraries in the same folder where they are located. This can be done as follows: \snippet ../examples/rpaths/rpaths.qbs 0 We are setting \l{cpp::rpaths}{cpp.rpaths} to \l{cpp::rpathOrigin}{cpp.rpathOrigin} which expands to \c "$ORIGIN" on Linux and to \c "@loader_path" on macOS. On macOS you also need to set \l{cpp::sonamePrefix}{cpp.sonamePrefix} to \c "@rpath" to tell the dynamic linker to use RPATHs when loading this library. \c LibraryB looks exactly the same: \snippet ../examples/rpaths/rpaths.qbs 1 In a real project, it might be a good idea to move common properties to some base item and inherit it in library items. The application item is a bit different. It sets \l{cpp::rpaths}{cpp.rpaths} to the \c "lib" folder which is located one level up from the \c bin folder: \snippet ../examples/rpaths/rpaths.qbs 2 \section1 How do I make sure my generated sources are getting compiled? The rules in a \QBS project do not care whether its inputs are actual source files listed on the right-hand side of a \l{Product::files}{files} property or artifacts that were generated by another rule. For instance, the C++ compiler rule considers all input files of type "cpp", no matter how they got into the product. The following example project demonstrates this. One of its source files exists in the repository, the other one is generated at build time. Both are getting compiled the same way. \note Do not try to add the generated files to a \c files property. Declaring them as rule outputs is all that is needed to make \QBS know about them. \code import qbs.TextFile CppApplication { files: ["impl.cpp", "impl.h"] cpp.includePaths: sourceDirectory Rule { multiplex: true Artifact { filePath: "main.cpp"; fileTags: "cpp" } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.sourceCode = function() { var f = new TextFile(output.filePath, TextFile.WriteOnly); f.writeLine("#include "); f.writeLine("int main()"); f.writeLine("{"); f.writeLine(" return functionFromImpl();"); f.writeLine("}"); f.close(); }; return cmd; } } } \endcode \section1 How do I run my autotests? There are two simple things you need to do in your project. Firstly, you mark your test executables as such. This is done by adding the tag \c{"autotest"} to the product type: \code CppApplication { name: "test1" type: base.concat("autotest") // ... } \endcode The second step is to instantiate an \l AutotestRunner product in your project: \code Project { // ... AutotestRunner { name: "run_my_tests" } } \endcode Building an AutotestRunner product does not produce artifacts, but triggers execution of all applications whose products are tagged as autotests: \code $ qbs -p run_my_tests test1: PASS test2: PASS test3: FAIL ... \endcode See the \l{AutotestRunner}{AutotestRunner documentation} for how to fine-tune the behavior. \section1 How do I use ccache? \l ccache is a popular C/C++ compiler cache on Unix to speed up compiling the same content multiple times. \QBS excels at tracking dependencies and avoiding needless recompilations, so for linear development of one project and configuration using ccache has little benefit. But if you switch between revisions of a project, or build the same project with different configurations, a global cache like ccache can speed up compilations significantly. ccache can be used by setting up symbolic links to compiler executables (such as \c g++, \c gcc) in the file system. In this setup, the use of ccache is transparent to \QBS. If you prefer to call ccache explicitly, you should set \l{cpp::compilerWrapper}{cpp.compilerWrapper} to \c ccache. \note Using precompiled headers might prevent ccache from actually using cached results. To work around this, you can set \c{sloppiness=pch_defines,time_macros} in your local ccache options. See the \l{ccache documentation about precompiled headers} for further details. \section1 How do I create a module for a third-party library? If you have pre-built binary files in your source tree, you can create modules for them and then introduce dependencies between your project and the modules to pull in the functionality of a third-party library. Create the following folder structure to store the module files: \code $projectroot/modules/ThirdParty \endcode Then create a file in the directory that specifies the module properties for each supported toolchain. The filename must have the \c .qbs extension. The module will be pulled in if a product declares a dependency on it. In the following example, \c lib1.dylib is a multi-architecture library containing both 32-bit and 64-bit code. \code ---ThirdParty.qbs--- Module { Depends { name: "cpp" } cpp.includePaths: ["/somewhere/include"] Properties { condition: qbs.targetOS.includes("android") cpp.dynamicLibraries: ["/somewhere/android/" + Android.ndk.abi + "/lib1.so"] } Properties { condition: qbs.targetOS.includes("macos") cpp.dynamicLibraries: ["/somewhere/macos/lib1.dylib"] } Properties { condition: qbs.targetOS.includes("windows") && qbs.architecture === "x86" cpp.dynamicLibraries: ["/somewhere/windows_x86/lib1.lib"] } Properties { condition: qbs.targetOS.includes("windows") && qbs.architecture === "x86_64" cpp.dynamicLibraries: ["/somewhere/windows_x86_64/lib1.lib"] } } \endcode Finally, declare dependencies on \c ThirdParty in your project: \code CppApplication { name: "the-app" files: ["main.cpp"] Depends { name: "ThirdParty" } } \endcode \section1 How do I create application bundles and frameworks on iOS, macOS, tvOS, and watchOS? Creating an application bundle or framework is achieved by introducing a dependency on the \l{bundle} module and setting the \l{bundle::isBundle} {bundle.isBundle} property to \c true. Here is a simple example for an application: \code Application { Depends { name: "cpp" } Depends { name: "bundle" } bundle.isBundle: true name: "the-app" files: ["main.cpp"] } \endcode and for a framework: \code DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } bundle.isBundle: true name: "the-lib" files: ["lib.cpp", "lib.h"] } \endcode \QBS also supports building static frameworks. You can create one by replacing the \l{DynamicLibrary} item with a \l{StaticLibrary} item in the example above. \note When using the \l{Application} item (or convenience items, such as \l{CppApplication}, \l{DynamicLibrary}, and \l{StaticLibrary}), your products will be built as bundles on Apple platforms by default (this behavior is subject to change in a future release). To explicitly control whether your product is built as a bundle, set the \c bundle.isBundle property. Setting the \l{Product::}{consoleApplication} property of your product will also influence whether your product is built as a bundle. Building your application against your framework is the same as linking a normal dynamic or static library; see the \l{How do I make my app build against my library?} section for an example. \section1 How do I build against libraries that provide pkg-config files? Just add a \l Depends item that matches the name of the pkg-config module, set the \l Product::qbsModuleProviders property to \c "qbspkgconfig", and \QBS will employ \l{https://www.freedesktop.org/wiki/Software/pkg-config}{pkg-config} to find the headers and libraries if no matching \QBS module can be found. For instance, to build against the OpenSSL library, you would write this: \code qbsModuleProviders: "qbspkgconfig" Depends { name: "openssl" } \endcode That's it. The pkg-config behavior can be fine-tuned via the \l qbspkgconfig provider. Internally, this functionality is implemented via \l {Module Providers} \section1 How do I apply C/C++ preprocessor macros to only a subset of the files in my product? Use a \l{Group} item to define a subset of project files. To add macros within the group, you need to use the \c outer.concat property, because you are adding macros to those specified in the outer scope. In the following example, \c MACRO_EVERYWHERE is defined for all files in the \l{Product} unless a Group overrides the macro, whereas \c MACRO_GROUP is only defined for \c groupFile.cpp. \code Product { Depends { name: "cpp" } cpp.defines: ["MACRO_EVERYWHERE"] Group { cpp.defines: outer.concat("MACRO_GROUP") files: "groupFile.cpp" } } \endcode The \c cpp.defines statements inside a \c Group only apply to the files in that \c Group, and therefore you cannot use a \c Group to include a bunch of files and globally visible macros. The macros must be specified in a \l{Properties} item at the same level as the \c Group if they need to be visible to files outside the \c Group: \code Product { Depends { name: "cpp" } Group { condition: project.supportMyFeature files: "myFile.cpp" } property stringList commonDefines: ["ONE", "TWO"] Properties { condition: project.supportMyFeature cpp.defines: commonDefines.concat("MYFEATURE_SUPPORTED") } } \endcode \section1 How do I disable a compiler warning? You can use the \l {cpp::commonCompilerFlags}{cpp.commonCompilerFlags} property to pass flags to the compiler. For example, to disable deprecation warnings: \code CppApplication { // ... readonly property bool isMsvc: qbs.toolchain.includes("msvc") cpp.commonCompilerFlags: isMsvc ? "/wd4996" : "-Wno-deprecated-declarations" } \endcode It is also possible to disable all warnings at once by setting the \l {cpp::commonCompilerFlags}{cpp.warningLevel} property to \c "none". Usually this approach is discouraged, but it can be useful in some cases, such as when compiling third party code: \code Group { cpp.warningLevel: "none" files: [ "3rdparty.h", "3rdparty.cpp" ] } \endcode \section1 How do I make the state of my Git repository available to my source files? Add a dependency to the \l{vcs} module to your product: \code CppApplication { // ... Depends { name: "vcs" } // ... } \endcode Your source files will now have access to a macro whose value is a string representing the current Git or Subversion HEAD: \code #include #include int main() { std::cout << "I was built from " << VCS_REPO_STATE << std::endl; } \endcode This value is also available via the \l{vcs::repoState}{vcs.repoState} property. \section1 How do I limit the number of concurrent jobs for the linker only? \target job-pool-howto While it is usually desirable to run as many compiler jobs as there are CPU cores, the same is not true for linker jobs. The reason is that linkers are typically I/O bound rather than CPU bound. When building large libraries, they also tend to use up enormous amounts of memory. Therefore, we'd like to make sure that only a few linkers are running at the same time without limiting other types of jobs. In \QBS, this is achieved via \e{job pools}. There are several ways to make use of them. Firstly, you can provide a limit via the command line: \code $ qbs --job-limits linker:4 \endcode The above call instructs \QBS to run at most four linker instances at the same time, while leaving the general number of concurrent jobs at the default value, which is derived from the number of CPU cores. The \c linker string on the command line refers to the job pool of the same name, which the \l{cpp-job-pools}{cpp module} assigns to all its commands that invoke a linker. Secondly, you can set a limit via the settings, either generally or for a specific profile: \code $ qbs config preferences.jobLimit.linker 4 $ qbs config profiles.myprofile.preferences.jobLimit.linker 2 \endcode And finally, you can also set the limit per project or per product, using a \l JobLimit item: \code Product { name: "my_huge_library" JobLimit { jobPool: "linker" jobCount: 1 } // ... } \endcode The above construct ensures that this specific library is never linked at the same time as any other binary in the project. Job limits set on the command line override those from the settings, which in turn override the ones defined within a project. Use the \c{--enforce-project-job-limits} option to give the job limits defined via \c JobLimit items maximum precedence. \section1 How do I add QML files to a project? The simplest way to add QML files to a project is to add them to a \l {https://doc.qt.io/qt/resources.html}{Qt resource file}: \code QtGuiApplication { // ... files: "main.cpp" Group { prefix: "qml/" files: ["main.qml", "HomePage.qml"] fileTags: ["qt.qml.qml", "qt.core.resource_data"] } } \endcode In the example above, we declare each QML file as having the \l {filetags-qtcore}{"qt.core.resource_data"} file tag. This ensures that it is added to a generated resource file. \section1 How do I define a reusable Group of files that can be included in other \QBS files? Suppose you have an application and tests for that application, and that the project is structured in the following way: \badcode ├── app │ ├── app.qbs │ ├── ... │ └── qml │ └── ui │ ├── AboutPopup.qml │ └── ... ├── my-project.qbs └── tests ├── tst_app.cpp ├── ... └── tests.qbs \endcode Both projects need access to the QML files used by the application. To demonstrate how this can be done, we'll create a file named \c qml-ui.qbs and put it in the \c app/qml/ui directory: \code Group { prefix: path + "/" fileTags: ["qt.qml.qml", "qt.core.resource_data"] files: [ "AboutPopup.qml", // ... ] } \endcode This Group is a variation of the one in the \l {How do I add QML files to a project?}{section above}. If no prefix is specified, the file names listed in the \c files property are resolved relative to the \e importing product's (e.g. \c app.qbs) directory. For that reason, we set the prefix to inform \QBS that the file names should be resolved relative to the \e imported item instead: \c qml-ui.qbs. Conveniently, this also means that we don't need to specify the path prefix for each file. The application can then import the file like so: \code import "qml/ui/qml-ui.qbs" as QmlUiFiles QtGuiApplication { // ... files: "main.cpp" QmlUiFiles {} } \endcode The tests can use a relative path to import the file: \code import "../app/qml/ui/qml-ui.qbs" as QmlUiFiles QtGuiApplication { // ... files: "tst_app.cpp" QmlUiFiles {} } \endcode \section1 How do I access properties of a base type? You can use the \l base property. For example, to append to a list of files that come from the base type, you can use \c {base.concat()}: \code // TestBase.qbs QtGuiApplication { files: [ "TestCaseBase.h", "TestCaseBase.cpp" ] } \endcode \code // tst_stuff.qbs TestBase { files: base.concat(["tst_stuff.cpp"]) } \endcode See \l {Special Property Values} for more details. \section1 How do I print the value of a property? Use the \l {Console API}{console API}. For example, suppose your project is not built the way you expect it to be, and you suspect that \c qbs.targetOS has the wrong value: \code readonly property bool unix: qbs.targetOS.includes("unix") \endcode To find out the value of \c qbs.targetOS, use \c {console.info()}: \code readonly property bool unix: { console.info("qbs.targetOS: " + qbs.targetOS) return qbs.targetOS.includes("unix") } \endcode It is also possible to throw an exception with the text saying what is wrong - this might be useful if the property contains invalid or unsupported value: \code readonly property bool unix: { if (qbs.targetOS.includes("darwin")) throw "Apple platforms are not supported"; return qbs.targetOS.includes("unix") } \endcode \section1 How do I debug \QBS scripts? To debug the value of a specific property, see the \l{How do I print the value of a property} section. Similar debugging techniques could be used within \l{Rule}{Rules} or \c .js files. It is also possible to increase \QBS' logging level using the \c --more-verbose (\c -v) option of the \c{qbs build} command: \code qbs build -v config:release \endcode \QBS uses the Qt Categorized Logging system which allows to configure logging categories in \l{https://doc.qt.io/qt-5/qloggingcategory.html#configuring-categories}{multiple ways}. For example, to enable debug logging for the \c moduleloader category, use the following command: \code QT_LOGGING_RULES="qbs.moduleloader.debug=true" qbs resolve \endcode To list all the files in the project directory and show whether they are known to qbs in the respective configuration, use the \c{qbs status} command: \code qbs status config:release \endcode \section1 How do I sign an application for an Apple platform? To sign an application for an Apple platform, you need to use the \l{codesign} module. \code Depends { name: "codesign" } \endcode Several properties should be set to do signing as shown below. Make sure that bundle and team indentifiers match the one used for signing: \code bundle.identifierPrefix: "com.johndoe" codesign.teamIdentifier: "John Doe" \endcode It is also possible to use an ID of the team identifier instead of a name: \code codesign.teamIdentifier: "1234ABCDEF" \endcode \QBS will then try to find the matching signing identity and provisioning profile based on \l{codesign::signingType}{codesign.signingType}. It is also possible to specify \l{codesign::signingIdentity}{codesign.signingIdentity} manually: \code codesign.signingIdentity: "Apple Development: johndoe@apple.com (ABCDEF1234)" \endcode It is also possible to use an ID of the signing identity instead of a name: \code codesign.signingIdentity: "ABCDEF1234567890ABCDEF1234567890ABCDEF12" \endcode If \QBS cannot find the suitable provisioning profile, you can specify it manually as well: \code codesign.provisioningProfile: "abcdef12-1234-5678-1111-abcdef123456" \endcode */ qbs-src-2.6.1/doc/fixnavi.pl0000644000175100001660000001473614776170045015231 0ustar runnerdocker#! /usr/bin/perl -w ############################################################################# ## ## Copyright (C) 2016 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# use strict; my @files = (); my %defines = (); for (@ARGV) { if (/^-D(.*)$/) { $defines{$1} = 1; } elsif (/^-/) { printf STDERR "Unknown option '".$_."'\n"; exit 1; } else { push @files, $_; } } int(@files) or die "usage: $0 [-D]... \n"; my @toc = (); my %title2page = (); my $doctitle = ""; my $curpage = ""; my $intoc = 0; my %prev_skips = (); my %next_skips = (); my %define_skips = (); my %polarity_skips = (); my $prev_skip = ""; my $next_skip = ""; my $define_skip = ""; my $polarity_skip = 0; for my $file (@files) { my $skipping = 0; # no nested ifs! open FILE, $file or die "File $file cannot be opened.\n"; while () { if (/^\h*\\if\h+defined\h*\(\h*(\H+)\h*\)/) { $skipping = !defined($defines{$1}); if (!$intoc) { $define_skip = $1; $polarity_skip = $skipping; } } elsif (/^\h*\\else/) { $skipping = 1 - $skipping; } elsif (/^\h*\\endif/) { $skipping = 0; } elsif (keys(%title2page) == 1 && /^\h*\\list/) { $intoc++; } elsif (!$intoc) { if ($skipping && /^\h*\\previouspage\h+(\H+)/) { $prev_skip = $1; } elsif ($skipping && /^\h*\\nextpage\h+(\H+)/) { $next_skip = $1; } elsif (/^\h*\\page\h+(\H+)/) { $curpage = $1; } elsif (/^\h*\\title\h+(.+)$/) { if ($curpage eq "") { die "Title '$1' appears in no \\page.\n"; } if (length($define_skip)) { $define_skips{$1} = $define_skip; $polarity_skips{$1} = $polarity_skip; $prev_skips{$1} = $prev_skip; $next_skips{$1} = $next_skip; $define_skip = $prev_skip = $next_skip = ""; } $title2page{$1} = $curpage; $doctitle = $1 if (!$doctitle); $curpage = ""; } } else { if (/^\h*\\endlist/) { $intoc--; } elsif (!$skipping && /^\h*\\(?:o|li)\h+\\l\h*{(.*)}$/) { push @toc, $1; } } } close FILE; } my %prev = (); my %next = (); my $last = $doctitle; for my $title (@toc) { $next{$last} = $title2page{$title}; $prev{$title} = $title2page{$last}; $last = $title; } for my $file (@files) { open IN, $file or die "File $file cannot be opened a second time?!\n"; open OUT, '>'.$file.".out" or die "File $file.out cannot be created.\n"; my $cutting = 0; while () { if (!$cutting) { if (/^\h*\\contentspage/) { $cutting = 1; } } else { if (/^\h*\\title\h+(.+)$/) { if (defined($define_skips{$1})) { print OUT " \\if defined(".$define_skips{$1}.")\n"; if ($polarity_skips{$1}) { print OUT " \\previouspage ".$prev_skips{$1} if ($prev_skips{$1}); print OUT " \\else\n"; } } print OUT " \\previouspage ".$prev{$1} if ($prev{$1}); if (defined($define_skips{$1})) { if (!$polarity_skips{$1}) { print OUT " \\else\n"; print OUT " \\previouspage ".$prev_skips{$1} if ($prev_skips{$1}); } print OUT " \\endif\n"; } print OUT " \\page ".$title2page{$1}; if (defined($define_skips{$1})) { print OUT " \\if defined(".$define_skips{$1}.")\n"; if ($polarity_skips{$1}) { print OUT " \\nextpage ".$next_skips{$1} if ($next_skips{$1}); print OUT " \\else\n"; } } print OUT " \\nextpage ".$next{$1} if ($next{$1}); if (defined($define_skips{$1})) { if (!$polarity_skips{$1}) { print OUT " \\else\n"; print OUT " \\nextpage ".$next_skips{$1} if ($next_skips{$1}); } print OUT " \\endif\n"; } print OUT "\n"; $cutting = 0; } else { next; } } print OUT $_; } close OUT; close IN; rename($file.".out", $file) or die "Cannot replace $file with new version.\n"; } qbs-src-2.6.1/doc/config/0000755000175100001660000000000014776170045014462 5ustar runnerdockerqbs-src-2.6.1/doc/config/style/0000755000175100001660000000000014776170045015622 5ustar runnerdockerqbs-src-2.6.1/doc/config/style/qt5-sidebar.html0000644000175100001660000000152114776170045020627 0ustar runnerdocker

Qbs Manual

qbs-src-2.6.1/doc/config/qbs-project.qdocconf0000644000175100001660000000220114776170045020424 0ustar runnerdockerinclude($QT_INSTALL_DOCS/global/qt-cpp-defines.qdocconf) include($QT_INSTALL_DOCS/global/compat.qdocconf) include($QT_INSTALL_DOCS/global/fileextensions.qdocconf) project = "Qbs" description = "Qbs Manual" #Words to ignore for auto-linking ignorewords += macOS headerdirs = sourcedirs = .. imagedirs = ../images ../templates/images exampledirs = .. include(macros.qdocconf) sources.fileextensions = "*.qdoc" qhp.projects = Qbs qhp.Qbs.file = qbs.qhp qhp.Qbs.namespace = org.qt-project.qbs.$QBS_VERSION_TAG qhp.Qbs.virtualFolder = doc qhp.Qbs.indexTitle = Qbs qhp.Qbs.filterAttributes = qbs $QBS_VERSION qhp.Qbs.customFilters.Qbs.name = Qbs $QBS_VERSION qhp.Qbs.customFilters.Qbs.filterAttributes = qbs $QBS_VERSION qhp.Qbs.indexRoot = qhp.Qbs.subprojects = manual qhp.Qbs.subprojects.manual.title = Qbs Manual qhp.Qbs.subprojects.manual.indexTitle = Qbs Manual qhp.Qbs.subprojects.manual.type = manual # Doxygen compatibility commands macro.see = "\\sa" macro.function = "\\fn" navigation.homepage = "Qbs Manual" buildversion = "Qbs $QBS_VERSION" qbs-src-2.6.1/doc/config/macros.qdocconf0000644000175100001660000000560114776170045017466 0ustar runnerdockermacro.QBS = "Qbs" macro.qbsversion = $QBS_VERSION macro.defaultvalue = "Default:" macro.nodefaultvalue = "Default: Undefined" macro.appleproperty = "This property is specific to Apple platforms." macro.androidproperty = "This property is specific to Android platforms." macro.unixproperty = "This property is specific to Unix platforms." macro.windowsproperty = "This property is specific to Windows." macro.baremetalproperty = "This property is specific to bare-metal platforms." macro.funsince.HTML = "

This function was introduced in version \1.

" macro.aacute.HTML = "á" macro.Aring.HTML = "Å" macro.aring.HTML = "å" macro.Auml.HTML = "Ä" macro.author = "\\b{Author:}" macro.BR.HTML = "
" macro.copyright.HTML = "©" macro.eacute.HTML = "é" macro.gui = "\\b" macro.HR.HTML = "
" macro.iacute.HTML = "í" macro.key = "\\b" macro.macos = "macOS" macro.menu = "\\b" macro.oslash.HTML = "ø" macro.ouml.HTML = "ö" macro.QA = "\\e{Qt Assistant}" macro.QD = "\\e{Qt Designer}" macro.QL = "\\e{Qt Linguist}" macro.QQV = "\\e{Qt QML Viewer}" macro.param = "\\e" macro.raisedaster.HTML = "*" macro.rarrow.HTML = "→" macro.reg.HTML = "®" macro.return = "Returns" macro.starslash = "\\c{*/}" macro.begincomment = "\\c{/*}" macro.endcomment = "\\c{*/}" macro.uuml.HTML = "ü" macro.mdash.HTML = "—" macro.pi.HTML = "Π" macro.beginqdoc.HTML = "/*!" macro.endqdoc.HTML = "*/" macro.borderedimage = "\\div {class=\"border\"} \\image \1\n\\enddiv" macro.beginfloatleft.HTML = "
" macro.beginfloatright.HTML = "
" macro.endfloat.HTML = "
" macro.clearfloat.HTML = "
" macro.emptyspan.HTML = "" macro.CMAKE = "CMake" # Embed YouTube content by video ID - Example: \youtube dQw4w9WgXcQ # Also requires a .jpg thumbnail for offline docs. In .qdocconf, add: # # HTML.extraimages += images/dQw4w9WgXcQ.jpg # qhp.ProjectName.extraFiles += images/dQw4w9WgXcQ.jpg # macro.youtube.HTML = "
\n\n" \ "
\n" qbs-src-2.6.1/doc/tutorial.qdoc0000644000175100001660000007732214776170045015743 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage module-providers.html \page tutorial.html \nextpage tutorial-1.html \title Tutorial The tutorial describes the process of creating a typical \QBS project and explains core concepts. \list \li \l{tutorial-1.html}{Console Application} \li \l{tutorial-2.html}{Static Library} \li \l{tutorial-3.html}{Dynamic Library} \li \l{tutorial-4.html}{Convenience Items} \li \l{tutorial-5.html}{Autotest} \li \l{tutorial-6.html}{Project Properties} \li \l{tutorial-7.html}{Buildconfig Module} \li \l{tutorial-8.html}{Configurable Library} \li \l{tutorial-9.html}{Version Header} \li \l{tutorial-10.html}{C++20 Modules} \endlist */ /*! \previouspage tutorial.html \page tutorial-1.html \nextpage tutorial-2.html \title Console Application Let's start with a mandatory Hello World example. There is a Hello World example in the \l{overview.html#well-defined-language}{overview section}, but this time we will create a real-world project. We will start with a simple \QBS project file: \snippet ../tutorial/chapter-1/myproject.qbs 0 Here, we set the \l{Project::name}{name} of the project to \c "My Project" - it is mainly used for IDEs but can also be used to reference a project when setting properties from command-line. We also set the \l{Project::minimumQbsVersion}{minimumQbsVersion} - this property can be useful if the project depends on features that are not present in earlier \QBS versions. The \l{Project::references}{references} property contains the path to a file that describes our application. This file is located in a separate \c app directory - typically, projects tend to have quite a complicated structure but \QBS does not enforce any specific layout, so we will simply put each product in a separate directory. The application file sets several properties: \snippet ../tutorial/chapter-1/app/app.qbs 0 The \l{Product::name}{name} property identifies the product. The \l{Product::targetName}{targetName} property sets the name of the resulting binary (without the \c .exe extension on Windows, which is appended automatically). By default, \l{Product::targetName}{targetName} defaults to \l{Product::name}{name}. The \l{Product::files}{files} property contains a single \c main.c file which is a trivial \e{hello world} application: \snippet ../tutorial/chapter-1/app/main.c 0 We set \l{Product::consoleApplication}{consoleApplication} to \c true to indicate that our application is going to be used from a terminal. For example, on Windows, this will spawn a new console window if you double-click the resulting binary, while on macOS it will create a standalone binary file instead of an \l{https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html}{application bundle}. By default, the \l{Application::install}{CppApplication.install} property is \c false and thus \QBS does not install the binary. If the \l{Application::install}{install} property is \c true, when building a project, \QBS will also install it into an \e{installation root} folder which by default is named \c install-root and located under the build directory. This folder will contain only resulting artifacts without the build leftovers and files will have the same layout as in the target system. The \l{Application::install}{install} property should be set to \c true for all products that are to be distributed. See the \l{installing-files.html}{Installing Files} section for more details. We can now build and run our application from the project directory: \code chapter-1 $ qbs build ... Building for configuration default compiling main.c [My Application] ... linking myapp [My Application] ... Build done for configuration default. chapter-1 $ qbs run ... Starting target. Full command line: .../default/install-root/usr/local/bin/myapp Hello, world \endcode The \QBS output to console and default installation location may vary between different platforms. In most cases, \QBS should be able to find the default compiler (for example, GCC or Clang on Linux, Visual Studio on Windows, or Xcode on macOS), but if that's not the case, see the \l{configuring.html}{configuring} section. In the following chapters, we will continue to improve our project: we will add a library and make it configurable. */ /*! \previouspage tutorial-1.html \page tutorial-2.html \nextpage tutorial-3.html \title Static Library Let's add a static library to our project so we can reuse some code. Analogous to what we did for the application, we put the file into the \c{lib} directory and add it to the \l{Project::references}{references} property in our project. The modified project may look like this: \snippet ../tutorial/chapter-2/myproject.qbs 0 Let's take a look at the the library file now: \snippet ../tutorial/chapter-2/lib/lib.qbs 0 It contains the \l{StaticLibrary} item which sets the \l{Product::type}{type} of the product to \c "staticlibrary" and sets some defaults like where to install that library. As before, we set the \l{Product::files}{files} property with a header: \snippet ../tutorial/chapter-2/lib/lib.h 0 And we set the implementation file of our library: \snippet ../tutorial/chapter-2/lib/lib.c 0 We will keep our library really simple - it only contains one function, which we will later use in our application. The source file requires a \c "CRUCIAL_DEFINE" to be passed to a preprocessor. That is why we set the \l{cpp::defines}{cpp.defines} property: \snippet ../tutorial/chapter-2/lib/lib.qbs 1 Note that unlike the \l{CppApplication} item, the \l{StaticLibrary} does not pull in the dependency on the \l{cpp} module automatically - that is why we have to pull it in manually using the \l{Depends} item. Without the \l{cpp} module, \QBS would not know how to turn a \c{.c} file into an object file and the object file into a library. See \l{Rules and Product Types} for details. Next, we need to tell \QBS where to look for public headers of our library when building products that depend on it. By default, \QBS knows nothing about the layout of our library, so we tell it to look for headers in the library's source directory using the \l{Export} item: \snippet ../tutorial/chapter-2/lib/lib.qbs 2 You can export any \l{Module} property within the \l{Export} item - it will be merged in the depending product with other properties. For example, you can export \l{cpp::defines}{cpp.defines} or specific \l{cpp::commonCompilerFlags}{compiler flags} that are required to use this product. We depend on the \l{cpp} module twice - once within the \l{StaticLibrary} item and once in the \l{Export} item. This is because by default \QBS does not export anything when depending on this product and the dependencies in this item (as well as properties set in this item) are private to this product while dependencies and properties set in the \l{Export} item are for export only. Finally, we have some Apple-specific settings. You can skip this part of the tutorial if you are using some other platform. We depend on the \l{bundle} module and set the \l{bundle::isBundle}{bundle.isBundle} to false: \snippet ../tutorial/chapter-2/lib/lib.qbs 3 By default, \QBS builds static and dynamic libraries as \l{https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WhatAreFrameworks.html}{Frameworks} on macOS. So, to keep things simple, we disable the framework build and build a plain old static library file here. */ /*! \previouspage tutorial-2.html \page tutorial-3.html \nextpage tutorial-4.html \title Dynamic Library Let's now turn our static library into a dynamic library. It is a bit trickier with dynamic libraries since several things should be tweaked. First, we need to be able to mark methods (or classes) in our library as exported. Second, we need to tell our application where to look for our library at run time using \l{https://en.wikipedia.org/wiki/Rpath}{rpaths}. Some compilers, like MSVC, require us to mark which symbols we want to export or import. The \l{https://stackoverflow.com/a/6840659}{canonical} way would be to define some helper macros. Let's start with a header that defines those helper macros: \snippet ../tutorial/chapter-3/lib/lib_global.h 0 This header defines the \c MYLIB_EXPORT macro that expands either to an "export" or to an "import" directive based on the presence of the \c MYLIB_LIBRARY macro. We can use this macro to mark a function as follows: \snippet ../tutorial/chapter-3/lib/lib.h 0 The modified library product may look like this: \snippet ../tutorial/chapter-3/lib/lib.qbs 0 The most important change is that we changed the item type from \l{StaticLibrary} to \l{DynamicLibrary}. We also added the \c MYLIB_LIBRARY to the list of \l{cpp::defines}{defines}. We do this only when building the library but we are not exporting it - that way the users of our library will have methods marked for import rather than export. Finally, we set \l{cpp::sonamePrefix}{cpp.sonamePrefix} to \c "@rpath". This is required only for Apple platforms, see \l{https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/RunpathDependentLibraries.html}{Run-Path Dependent Libraries} for details. It is also required to set \l{cpp::rpaths}{cpp.rpaths} in our application file. Since the library is installed to the \c{lib} directory and the application is installed to the \c{bin} directory, we need to tell the loader to look in the \c{lib} directory. The \l{jsextension-fileinfo.html#relativePath}{FileInfo.relativePath} method can help us: \snippet ../tutorial/chapter-3/app/app.qbs 0 On Linux, this expression would be equivalent to this: \c{cpp.rpaths: ["$ORIGIN/../lib"]}. Don't forget to \c{import qbs.FileInfo} in order to be able to use the \l{jsextension-fileinfo.html} extension. To make the example complete, here's how the full \c app/app.qbs file should look like: \snippet ../tutorial/chapter-3/app/app.qbs 1 */ /*! \previouspage tutorial-3.html \page tutorial-4.html \nextpage tutorial-5.html \title Convenience Items As you might have noticed, we are repeating ourselves when setting the same properties in our products - we set \l{Product::version}{version}, \l{Application::install}{install}, \l{cpp::rpaths}{cpp.rpaths}, and so on. For a single application and a library, that is not a big deal, but what if we have a dozen libraries? Luckily, this can be achieved using item \l{language-introduction.html#reusing-project-file-code}{inheritance} - we move the common code to the base item and in the real product we will only set what is specific to that product (for example, the list of \l{Product::files}{files}). First, we need to tell \QBS where to look for our new base items. This can be achieved using the \l{Project::qbsSearchPaths}{qbsSearchPaths} property. We set this property to \c "qbs" so that \QBS will search our items in the \c{qbs} directory located in the project directory: \snippet ../tutorial/chapter-4/myproject.qbs 0 \note This directory has a pre-defined structure: base items should be located under the \c{imports} subdirectory. See \l{Custom Modules and Items} for details. Let's create a base item for all our applications and move common code there: \snippet ../tutorial/chapter-4/qbs/imports/MyApplication.qbs 0 As you see, we managed to extract most of the code here, and our application file now only contains what's relevant to it: \snippet ../tutorial/chapter-4/app/app.qbs 0 Now let's do the same for our library: \snippet ../tutorial/chapter-4/qbs/imports/MyLibrary.qbs 0 Here, we introduce a helper property, \c libraryMacro, with a default value calculated based on the capitalized product name. Since the name of out library product is \c "mylib", this property will expand to \c "MYLIB_LIBRARY". We can also override the default value for the macro in products that inherit our item like this: \code MyLibrary { libraryMacro: "SOME_OTHER_LIBRARY_MACRO" } \endcode Let's take a look at the refactored library file: \snippet ../tutorial/chapter-4/lib/lib.qbs 0 We managed to extract the reusable parts to common base items leaving the actual products clean and simple. Unfortunately, item inheritance comes with a price - when both parent and child items set the same property (\l{cpp::defines}{cpp.defines} in our case), the value in the child item wins. To work around this, the special \l{special-property-values.html#base}{base} value exists - it gives access to the base item's value of the current property and makes it possible to extend its value rather than override it. Here, we concatenate the list of defines from the base item \c{["MYLIB_LIBRARY"]} with a new list, specific to this product (namely, \c{['CRUCIAL_DEFINE']}). */ /*! \previouspage tutorial-4.html \page tutorial-5.html \nextpage tutorial-6.html \title Autotest Now that we can re-use our base items, let's add a simple autotest. We inherit the new item from the \c MyApplication item and add an \c "autotest" type: \snippet ../tutorial/chapter-5/qbs/imports/MyAutoTest.qbs 0 This additional type is required for the helper \l{AutotestRunner} item. This item runs all products with the \c "autotest" type when it is being built. It also implicitly depends on all such products, so they will be built before running as well. Let's add this item to our top-level \l{Project} item: \code Project { name: "My Project" minimumQbsVersion: "2.0" // ... AutotestRunner { timeout: 60 } } \endcode Here we set the \l{AutotestRunner::timeout}{timeout} property to 60 seconds so that our runner kills tests that run way too long. Now we need to add our first test. Let's create a new product with the following content: \snippet ../tutorial/chapter-5/test/test.qbs 0 Here we depend on our library (which we are going to test), set the product \l{Product::name}{name}, and specify the source file, which looks like this: \snippet ../tutorial/chapter-5/test/test.c 0 The test compares the value from the library with the value from the command line. Don't forget to add the new test product to the references property in the Project: \snippet ../tutorial/chapter-5/myproject.qbs 0 Now we can build the autotest product - this will also launch our test: \code $ qbs build -p "autotest-runner" ... running test mytest [autotest-runner] Build done for configuration default. \endcode */ /*! \previouspage tutorial-5.html \page tutorial-6.html \nextpage tutorial-7.html \title Project Properties It would be nice if our project was configurable. Let's add some properties to our root project file: \snippet ../tutorial/chapter-6/myproject.qbs 0 Now we can use those properties in our helper items and in products: \snippet ../tutorial/chapter-6/qbs/imports/MyApplication.qbs 0 Here, we access the project file using the special \l{special-property-values.html#project}{project} value. If the nearest project in the project tree does not have the desired property, \QBS looks it up in the parent project, potentially all the way up to the top-level project. We also use the \l{Application::installDebugInformation}{installDebugInformation} property here. By default, it has the same value as \l{Application::install}{install} but we want to make the debug information install optional. Let's now disable the tests if \c project.withTests is \c false: \snippet ../tutorial/chapter-6/myproject.qbs 1 Here we use the \l{Properties} item within the \l{SubProject} item. This item allows to override a subproject's properties which can be useful when adding some other \QBS project as a Git submodule. Of course, it is not very useful in our particular case since we only set the \l{Project::condition}{Project.condition} property. We could achieve the same effect by setting the \l{SubProject::condition}{condition} property of the \l{SubProject} item: \code SubProject { filePath: "test/test.qbs" condition: parent.withTests } \endcode Another way would be to disable the test product. That way, an IDE would still show the whole project tree including disabled tests: \code // qbs/imports/MyAutoTest.qbs MyApplication { condition: project.withTests type: base.concat(["autotest"]) } \endcode Let's finally make our \l{AutotestRunner} configurable too: \snippet ../tutorial/chapter-6/myproject.qbs 2 There are several ways to override project properties from the command line. First, the special \c project variable can be used to set the properties of the top-level project: \code $ qbs resolve project.withTests:false \endcode You can also refer to properties using project's \l{Project::name}{name}: \code $ qbs resolve "projects.My Project.withTests:false" \endcode This can again be useful for accessing the properties of external sub-projects. Note that since the project name contains spaces, we use quotes here. */ /*! \previouspage tutorial-6.html \page tutorial-7.html \nextpage tutorial-8.html \title Buildconfig Module In the previous chapter, we added some properties to our main \l{Project} file. While this is a perfect approach for \e public properties of the project, sometimes we want to add some \e private properties for better tuning. Of course, we could put everything in the \l{Project} file, but that would make it very convoluted. Also, accessing the top-level project all the way from products makes things strongly tied. You can also use a \l{Module} that \l{Product}{products} may depend on. That way, a \l{Product} only uses properties of the module it depends on without the need to know about the top-level project. Let's create a file named \c{mybuildconfig.qbs} and put it into the \c{qbs/modules/mybuildconfig} directory, near the \c{qbs/imports} directory: \code // qbs/modules/mybuildconfig.qbs Module { } \endcode So far, this is just an empty \l{Module} so let's add some properties to it: \snippet ../tutorial/chapter-7/qbs/modules/mybuildconfig/mybuildconfig.qbs 0 We added the \c appInstallDir and \c libInstallDir properties that will allow us to configure the installation location of the our application and library, respectively. Now we can use our module in the \c{MyApplication.qbs} item: \snippet ../tutorial/chapter-7/qbs/imports/MyApplication.qbs 0 We pull in the new module using the \l{Depends} item, similar to how we pulled in the \l{cpp} module dependency earlier. We also set the \l{Application::installDir}{installDir} property to the corresponding module property, namely to \c{mybuildconfig.appInstallDir}. \QBS \l{Module}{modules} have the feature to automatically export properties of other modules. Those exported properties are merged in the resulting product. We can use this feature to set the \l{cpp::rpaths}{cpp.rpaths} in our module rather than in products: \snippet ../tutorial/chapter-7/qbs/modules/mybuildconfig/mybuildconfig.qbs 1 Here, we inject the dependency on the \l{cpp} module and calculate the \c{libRPaths} property. This is a relative path from the \c{product.installDir} (which is either \c{"bin"} or \c{"lib"}, depending on product type to \c{libInstallDir}). Finally, we set \l{cpp::rpaths}{cpp.rpaths} to this property. This way, those \c rpaths will be automatically exported to all products that depend on the \c{mybuildconfig} module. Now, we can also use our new module in the library item: \snippet ../tutorial/chapter-7/qbs/imports/MyLibrary.qbs 0 Let's change the library folder name from \c{"lib"} to \c{"lib64"} when building our project: \code $ qbs modules.mybuildconfig.libDirName:lib64 ... $ ls default/install-root/usr/local/ bin lib64 \endcode */ /*! \previouspage tutorial-7.html \page tutorial-8.html \nextpage tutorial-9.html \title Configurable Library In this chapter, we will make our library more configurable. We will add configuration options to be able to choose between static and dynamic builds. We start with some new properties in the \c mybuildconfig module: \code Module { ... property bool staticBuild: false property bool installStaticLib: true ... } \endcode We need to do some modifications to export macros in the \c lib/lib_global.h header: \snippet ../tutorial/chapter-8/lib/lib_global.h 0 Here' we added a new branch when \c MYLIB_STATIC_LIBRARY is defined. In that case, we make the \c MY_LIB_EXPORT macro empty. Now, let's modify the \c qbs/imports/MyLibrary.qbs file as follows: \snippet ../tutorial/chapter-8/qbs/imports/MyLibrary.qbs 0 First thing to notice is that we changed the type of the item from \l{DynamicLibrary} to the \l{Library} item which is a common base item for dynamic and static libraries. Second, we change the \l{Product::type}{type} of the product so it depends on the \c staticBuild property: \code type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" \endcode Third, we change our \e{export macro} to be different in the static and dynamic builds to correspond with the changes we made to the \c lib_global.h: \code readonly property string _nameUpper : name.replace(" ", "_").toUpperCase() property string libraryMacro: _nameUpper + "_LIBRARY" property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY" cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro] \endcode Note that in a static build we export the \c MYLIB_STATIC_LIBRARY macro so that the dependent products will know whether they link to a static or dynamic library: \code Export { ... cpp.defines: exportingProduct.mybuildconfig.staticBuild ? [exportingProduct.staticLibraryMacro] : [] } \endcode Now we can build our project in dynamic or static mode: \code $ qbs resolve modules.mybuildconfig.staticBuild:false && qbs build ... $ ls default/install-root/usr/local/lib/ libmylib.1.0.0.so libmylib.1.0.so libmylib.1.so libmylib.so $ rm -r default $ qbs resolve modules.mybuildconfig.staticBuild:true && qbs build ... $ $ ls default/install-root/usr/local/lib/ libmylib.a \endcode */ /*! \previouspage tutorial-8.html \page tutorial-9.html \nextpage tutorial-10.html \title Version Header To create new files, such as version headers, during the build, use \l{Rules}. Every command \QBS executes, such as compile or linker commands, is described by a corresponding Rule in a Module or a Product. In this section, we will create a simple header with a string constant based on the variable in our project. First, we add this variable to our \c mybuildconfig module: \snippet ../tutorial/chapter-9/qbs/modules/mybuildconfig/mybuildconfig.qbs 0 Next, we create a new file, \c{version.h.in}, located in the \c{version-header} directory. This file contains the template for our header: \snippet ../tutorial/chapter-9/version-header/version.h.in 0 Now we create a file called \c{version-header.qbs} in the same directory. This file contains a \l{Product} with a \l{Rule} that turns the \c{version.h.in} into a real header. Let's go through the contents of the file: \snippet ../tutorial/chapter-9/version-header/version-header.qbs 0 First, we import \l{TextFile Service}{TextFile}. We will need this class to read the template and write the resulting header. Second, we declare a new \l{Product} named \c{"version_header"} and with the \c{"hpp"} type. This is the type of the artifact we will create in the Rule. Third, we add the dependency on the \c mybuildconfig module to use the new \c mybuildconfig.productVersion variable. We also add a \l{Group} with the template file and assign the \c{version_h_in} tag to the file: \snippet ../tutorial/chapter-9/version-header/version-header.qbs 1 \QBS Rules work with file tags, instead of working with files directly, which makes it easy to reuse rules. The name of the tag is chosen arbitrarily here. We could use the name of the file as a tag, but to avoid confusion between file name and file tag, we use underscores in the tag instead of dots. Now we can create a Rule itself: \snippet ../tutorial/chapter-9/version-header/version-header.qbs 2 Here, we specify that our Rule takes files tagged as \c "version_h_in" and produces an \l{Artifact} with the name \c "version.h" and tagged \c "hpp". By default, files are created in the \l{Product::destinationDirectory}{Product.destinationDirectory} folder. We add the \c "hpp" tag for the header as this is the tag the \l{cpp}{cpp module} uses for headers. That way, \QBS can track changes and process our generated file the same way it treats all other headers. Note that earlier we set the product type to \c "hpp" as well. \QBS requires that artifact type should match the product type directly or be accessible via the chain of Rules. Otherwise, the Rule won't be executed. For details, see the \l{Rules and Product Types} section. The actual code generation happens in the \l{Rule::prepare}{Rule.prepare} script: \snippet ../tutorial/chapter-9/version-header/version-header.qbs 3 In this script, we create a \l {JavaScriptCommand} object and set some meta properties, such as the description and highlight. For details about Commands, see \l{Command and JavaScriptCommand}. In the sourceCode variable, we create a JavaScript function that opens the \l{The inputs and outputs Variables}{input file}, reads its content using the \l{TextFile Service}{TextFile} object, replaces the \c "${PRODUCT_VERSION}" placeholder with the actual value in the \c product.mybuildconfig.productVersion variable, and writes the resulting content into the \l{The inputs and outputs Variables}{output file}. Finally, we export the \l{Product::buildDirectory}{exportingProduct.buildDirectory} so that products that depend on this product can include our generated header: \snippet ../tutorial/chapter-9/version-header/version-header.qbs 4 The full content of the file should look like this: \snippet ../tutorial/chapter-9/version-header/version-header.qbs 5 Let's now add our Product into the root project so \QBS will be aware of it: \snippet ../tutorial/chapter-9/myproject.qbs 0 We also need to add the dependency on the \c "version_header" to our application: \snippet ../tutorial/chapter-9/app/app.qbs 0 Now we can include the header in the \c main.c file and print the contents of the string constant: \snippet ../tutorial/chapter-9/app/main.c 0 Let's try and run our application. You should see something like this: \code $ qbs run -p "My Application" Starting target. Full command line: .../default/install-root/usr/local/bin/myapp Hello, world Hello from library ProductVersion = 1.0.0 \endcode */ /*! \previouspage tutorial-9.html \page tutorial-10.html \nextpage howtos.html \title C++20 Modules This tutorial implies you have some knowledge about C++20 modules. If not, see \l{https://learn.microsoft.com/en-us/cpp/cpp/modules-cpp}{Overview of modules in C++} for introduction. \section1 Named Modules Using C++20 modules with \QBS is pretty straightforward. Let's suppose you have a module file that exports a single function \c printHello: \snippet ../tutorial/chapter-10-1/hello.cppm 0 \note Currently, Clang only recognizes \c .cppm files as modules, however, for GCC and MSVC \QBS also recognizes \c .ixx files as C++ modules. \QBS assigns the \c "cppm" file tag to these files. You can assign this tag manually to module files with different extensions. This function is later used in the \c main.cpp file as follows: \snippet ../tutorial/chapter-10-1/main.cpp 0 The project file simply lists files and sets the \l{cpp::forceUseCxxModules}{cpp.forceUseCxxModules} property to \c true. \code // myproject.qbs CppApplication { consoleApplication: true install: true files: ["hello.cppm", "main.cpp"] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true } \endcode Now, you can build the project by simply calling \c{qbs}, assuming that your compiler supports C++20 modules. \section1 Module Partitions \l{https://learn.microsoft.com/en-us/cpp/cpp/modules-cpp?view=msvc-170#module-partitions}{Module partitions} are treated as regular modules and should also have the same extension or assigned the \c "cppm" tag manually. See this \l{https://github.com/qbs/qbs/tree/2.5/examples/cxx-modules/mod3}{example} on how to use both interface module and partitions. \section1 Modules and Libraries Using modules in dynamic libraries requires using the same export/import macros as it was shown in the \l{tutorial-3.html}{Dynamic Library} section: \snippet ../tutorial/chapter-10-2/lib/hello.cppm 0 As shown in that section, the library \c .qbs file should also define the \c MYLIB_LIBRARY macro in order to mark symbols as exported: \code // lib/lib.qbs DynamicLibrary { name: "mylib" files: ["hello.cppm", "lib_global.h"] version: "1.0.0" install: true Depends { name: "cpp" } cpp.defines: "MYLIB_LIBRARY" cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true // ... } \endcode For more details, see the complete \l{https://github.com/qbs/qbs/tree/2.5/tutorial/chapter-10-2}{example}. */qbs-src-2.6.1/doc/fix-qmlimports.py0000755000175100001660000001322014776170045016563 0ustar runnerdocker#!/usr/bin/env python3 ############################################################################# ## ## Copyright (C) 2017 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# from __future__ import print_function import os import glob import errno import sys import argparse import shutil import urllib from subprocess import Popen, PIPE import re from collections import Counter import platform useShell = (platform.system() == 'Windows') gotSoup = True try: from bs4 import BeautifulSoup except ImportError: print('Warning: Failed to import BeautifulSoup. Some functionality is disabled.', file=sys.stderr) gotSoup = False qmlTypeString = ' QML Type' # Modifies a QML Type reference page to look like a generic # JavaScript reference - Removes the 'QML Type' strings from # the titles as well as the import statement information. # This is used in the Installer Framework docs, which contain # JS reference documentation generated using commands specific # to documenting QML code. # # Parameters: a Beautiful Soup object constructed with an opened # html file to process. # # Returns True if the element tree was modified, False otherwise def modifyQMLReference(soup): pageTitle = soup.head.title.string soup.head.title.string = pageTitle.replace(qmlTypeString, '') for t in soup.find_all('h1', class_='title'): t.string = t.string.replace(qmlTypeString, '') for table in soup.find_all('table'): td = table.find('td') if td and td.string: if 'Import Statement:' in td.string: td.parent.extract() return True return False if __name__ == '__main__': parser = argparse.ArgumentParser( description = """Removes bogus import statements from the offline docs""") parser.add_argument('outputdir', help = 'output directory of the generated html files') args = parser.parse_args() if not gotSoup: print('Error: This script requires the Beautiful Soup library.', file=sys.stderr) sys.exit(1) if not os.path.isdir(args.outputdir): print('Error: No such directory:', args.outputdir, file=sys.stderr) sys.exit(1) # compile a list of all html files in the outputdir htmlFiles = [] for f in os.listdir(args.outputdir): fullPath = os.path.join(args.outputdir, f) if os.path.isdir(fullPath): continue if os.path.splitext(f)[1] == '.html': htmlFiles.append(fullPath) sys.stdout.flush() modified = {} pre_blocks = {} fileCount = 0 progStep = max(16, len(htmlFiles)) / 16 for html in htmlFiles: fileCount += 1 if not (fileCount % progStep): print('.', end='') sys.stdout.flush() with open(html, 'r+', encoding='utf8') as file_: try: soup = BeautifulSoup(file_, 'lxml') actions = [] val = 0 if modifyQMLReference(soup): actions.append('Removed QML type info') for a in actions: modified[a] = modified.get(a, 0) + 1 if actions: file_.seek(0) file_.write(str(soup)) file_.truncate() file_.close() except (AttributeError, KeyError): print('\nFailed to parse', html, ':', sys.exc_info()[0], file=sys.stderr) except IOError as e: print('\nError:', e, file=sys.stderr) except ValueError as e: print('\nError:', e, file=sys.stderr) if 'lxml' in str(e): print('(If using pip, try \"pip install lxml\")', file=sys.stderr) quit(1) for k, v in modified.items(): print ('\n\t', k, 'in %d files' % v, end='') pb = pre_blocks.get(k, 0) if pb: print (' (', pb, '
 blocks)', sep='', end='')
    print('\n')
qbs-src-2.6.1/doc/external-resources.qdoc0000644000175100001660000000655514776170045017732 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \externalpage https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW28
    \title Adopt the @2x Naming Convention
*/

/*!
    \externalpage https://login.qt.io/
    \title Qt Account
*/

/*!
    \externalpage https://www.qt.io/ide/
    \title Qt Creator
*/

/*!
    \externalpage https://www.qt.io/download/
    \title Qt SDK
*/

/*!
    \externalpage https://doc.qt.io/qt-5/licensing.html
    \title Qt Licensing
*/

/*!
    \externalpage https://www.gnu.org/licenses/gpl-2.0.html
    \title GNU General Public License, version 2
*/

/*!
    \externalpage http://www.linfo.org/bsdlicense.html
    \title BSD
*/

/*!
    \externalpage https://chocolatey.org/packages/qbs
    \title Chocolatey
*/

/*!
    \externalpage https://www.macports.org/ports.php?by=name&substr=qbs
    \title MacPorts
*/

/*!
    \externalpage https://brew.sh/
    \title Homebrew
*/

/*!
    \externalpage  http://www.typescriptlang.org
    \title TypeScript
*/

/*!
    \externalpage http://www.typescriptlang.org/docs/handbook/compiler-options.html
    \title Compiler Options
*/

/*!
    \externalpage https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dyld.1.html
    \title DYLD documentation
*/

/*!
    \externalpage https://dmgbuild.readthedocs.io/en/latest/settings.html#background
    \title dmgbuild - Settings
*/

/*!
    \externalpage http://www.jrsoftware.org/isinfo.php
    \title Inno Setup
*/

/*!
    \externalpage http://nodejs.org
    \title Node.js
*/

/*!
    \externalpage http://wixtoolset.org
    \title Windows Installer XML Toolset
*/

/*!
    \externalpage https://clang.llvm.org/docs/JSONCompilationDatabase.html
    \title JSON Compilation Database Format Specification
*/

/*!
    \externalpage https://github.com/protocolbuffers/protobuf
    \title protoc
*/

/*!
    \externalpage https://github.com/nanopb/nanopb
    \title nanopb
*/

/*!
    \externalpage https://ccache.samba.org/
    \title ccache
*/

/*!
    \externalpage https://ccache.samba.org/manual.html#_precompiled_headers
    \title ccache documentation about precompiled headers
*/
qbs-src-2.6.1/doc/targets/0000755000175100001660000000000014776170045014666 5ustar  runnerdockerqbs-src-2.6.1/doc/targets/qbs-target-ios.qdoc0000644000175100001660000000320414776170045020376 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-ios.html
    \ingroup platforms

    \title Building for iOS
    \brief Platform notes for iOS.

    This topic describes the \QBS features specific to iOS.

    \include qbs-target-apple-common.qdocinc xcode
    \include qbs-target-apple-common.qdocinc building user interfaces
    \include qbs-target-apple-common.qdocinc creating app bundles
    \include qbs-target-apple-common.qdocinc architectures and variants
*/
qbs-src-2.6.1/doc/targets/qbs-target-apple-common.qdocinc0000644000175100001660000001010014776170045022656 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!

//! [xcode]

    \note \QBS does not yet support the Swift programming language.

    The \l{xcode} module contains properties and rules for Xcode-based
    development.

//! [xcode]

//! [building user interfaces]

    \section1 Building User Interfaces

    The \l{ib} module contains properties and rules for building
    Interface Builder documents, storyboards, asset catalogs, and icon sets.

//! [building user interfaces]

//! [creating app bundles]

    \section1 Creating App Bundles

    The \l{bundle} module contains properties and rules for
    building and working with Core Foundation bundles (application bundles and
    frameworks) on Apple platforms.

    To build an application product as a bundle, or a dynamic or static library
    product as a framework, add a dependency on the bundle module and set the
    \l{bundle::isBundle}{bundle.isBundle} property to \c true:

    \code
    Depends { name: "bundle" }
    bundle.isBundle: true
    \endcode

    \QBS also provides a number of powerful features to assist in creating the
    Info.plist file that is part of your bundle. In fact, you do not need to
    provide an Info.plist file at all. Instead, \QBS will generate one
    automatically with the necessary keys, based on the values of module
    properties set in the product.

    If you do specify an Info.plist file, \QBS may still inject additional keys
    into the final output from other sources. One notable source of Info.plist
    keys are \e partial Info.plist files which are generated as a result of
    compiling other resources like asset catalogs, XIBs/NIBs, and storyboards.

    You may also use the \c bundle.infoPlist property to apply a set of
    key-value pairs to be added to the final Info.plist. This can be used
    instead of or in addition to an actual Info.plist file on disk.

//! [creating app bundles]

//! [architectures and variants]

    \section1 Multiple Architectures and Build Variants

    \QBS uses \l{Multiplexing}{multiplexing} to create multi-architecture
    \e fat binaries and multi-variant frameworks, where a single framework can
    contain both a release and debug build of a library on Apple platforms.

    You can set the \c qbs.architectures property to a list of CPU architectures
    (such as \c x86, \c x86_64, \c armv7a, \c armv7k, and \c arm64), and the
    \c qbs.buildVariants property to a list of build variants (such as \c debug
    and \c release), and \QBS will transparently perform the necessary steps to
    produce the various artifacts and combine them into a single bundle.

    Since the individual build configurations are completely independent of one
    another, you can continue to use conditional branches in your projects such
    as the following:

    \code
    Properties {
        condition: qbs.buildVariant === "release"
        cpp.optimization: "small"
    }
    \endcode

//! [architectures and variants]

*/
qbs-src-2.6.1/doc/targets/qbs-target-integrity.qdoc0000644000175100001660000000317314776170045021627 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-integrity.html
    \ingroup platforms

    \title Building for INTEGRITY
    \brief Platform notes for INTEGRITY.

    The Green Hills INTEGRITY RTOS is not yet supported but is planned for a
    future release.

    For more information about developing applications for the Green Hills
    INTEGRITY RTOS, see the \l{https://www.ghs.com/products/rtos/integrity.html}
    {INTEGRITY Product Documentation}.
*/
qbs-src-2.6.1/doc/targets/qbs-target-linux.qdoc0000644000175100001660000000266714776170045020757 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-linux.html
    \ingroup platforms

    \title Building for Linux
    \brief Platform notes for Linux.

    To develop applications for Linux, you need a GCC or Clang toolchain
    installed on your host machine.
*/
qbs-src-2.6.1/doc/targets/qbs-target-watchos.qdoc0000644000175100001660000000322414776170045021256 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-watchos.html
    \ingroup platforms

    \title Building for watchOS
    \brief Platform notes for watchOS.

    This topic describes the \QBS features specific to watchOS.

    \include qbs-target-apple-common.qdocinc xcode
    \include qbs-target-apple-common.qdocinc building user interfaces
    \include qbs-target-apple-common.qdocinc creating app bundles
    \include qbs-target-apple-common.qdocinc architectures and variants
*/
qbs-src-2.6.1/doc/targets/qbs-target-macos.qdoc0000644000175100001660000000620014776170045020705 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-macos.html
    \ingroup platforms

    \title Building for macOS
    \brief Platform notes for macOS.

    This topic describes the \QBS features specific to macOS.

    \include qbs-target-apple-common.qdocinc xcode
    \include qbs-target-apple-common.qdocinc building user interfaces
    \include qbs-target-apple-common.qdocinc creating app bundles
    \include qbs-target-apple-common.qdocinc architectures and variants

    \section1 Building macOS Disk Images

    The \l{AppleDiskImage} and \l{AppleApplicationDiskImage} items have a
    dependency on the \l{dmg} module. The former represents a
    product that is a basic Apple disk image, while the latter extends the
    former to create a drag 'n' drop disk image installer used for installing
    single application bundles.

    For example, the following code snippet creates a macOS disk image with a
    custom background and icon layout:

    \code
    AppleApplicationDiskImage {
        targetName: "cocoa-application-" + version
        version: "1.0"

        files: [
            "CocoaApplication/dmg.iconset",
            "CocoaApplication/en_US.lproj/LICENSE",
            // comment out the following line to use a solid-color background
            // (see dmg.backgroundColor below)
            "CocoaApplication/background*"
        ]

        dmg.backgroundColor: "#41cd52"
        dmg.badgeVolumeIcon: true
        dmg.iconPositions: [
            {"x": 200, "y": 200, "path": "Cocoa Application.app"},
            {"x": 400, "y": 200, "path": "Applications"}
        ]
        dmg.windowX: 420
        dmg.windowY: 250
        dmg.windowWidth: 600
        dmg.windowHeight: 422 // this includes the macOS title bar height of 22
        dmg.iconSize: 64
    }
    \endcode

    \image qbs-dmg.png

    In addition, \QBS supports multi-language license agreement prompts that
    appear when the DMG is opened, with full Unicode and rich-text formatting
    support.
*/
qbs-src-2.6.1/doc/targets/qbs-target-platforms.qdoc0000644000175100001660000000427114776170045021620 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \previouspage installing-files.html
    \group platforms
    \nextpage shell.html

    \title Target Platforms

    \QBS has built-in support for building applications for all major platforms.
    Platform support is implemented as a set of \l{List of Modules}{modules}
    that products depend on. The following topics describe the features specific
    to a particular platform, point out things to look out for, and provide tips
    for fully benefiting from the \QBS functions.

    In addition to the platforms explicitly listed below, \QBS should generally
    work on other UNIX and Unix-like platforms but these are not regularly
    tested or officially supported.

    \QBS recognizes the existence of at least AIX, HP-UX, Solaris, FreeBSD,
    NetBSD, OpenBSD, GNU Hurd, and Haiku, but provides no explicit support
    (except some minimal support for FreeBSD).

    For instructions on how to setup the target platform, see the
    \l {qbs::targetPlatform}{qbs.targetPlatform} property.
*/
qbs-src-2.6.1/doc/targets/qbs-target-windows.qdoc0000644000175100001660000000601314776170045021277 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-windows.html
    \ingroup platforms

    \title Building for Windows
    \brief Platform notes for Windows.

    This topic describes the \QBS features specific to Windows.

    \note \QBS does not currently support building applications using .NET
    technologies and languages such as C#, F#, and Visual Basic. At this time we
    recommend that you use MSBuild and the tools shipped with the various
    implementations of the .NET platform.

    \section1 Windows Resources

    The \l{ico} module contains rules and properties for building
    Windows icon (.ico) and cursor (.cur) files from a set of raw PNGs.

    \section1 Universal Windows Platform

    Building applications for the Universal Windows Platform is currently only
    partially supported. Notably, support for building APPX packages is missing,
    but will be added in a future release.

    Relevant properties include:

    \list
        \li \l{cpp::windowsApiFamily}{cpp.windowsApiFamily}
        \li \l{cpp::windowsApiAdditionalPartitions}
            {cpp.windowsApiAdditionalPartitions}
        \li \l{cpp::requireAppContainer}{cpp.requireAppContainer}
    \endlist

    See the \l{cpp} module for more information.

    \note \QBS does not (and will not) support building Windows Runtime
    applications targeting Windows 8 or Windows 8.1. We encourage users to
    instead build desktop applications for older versions of Windows, or migrate
    to Windows 10 and the Universal Windows Platform.

    \section1 Building Windows Installers

    The following modules contain properties and rules for building Windows
    installers using a number of different technologies:

    \list
        \li \l{innosetup} - Inno Setup
        \li \l{nsis} - Nullsoft Scriptable Install System
        \li \l{wix} - Windows Installer XML Toolset
    \endlist
*/
qbs-src-2.6.1/doc/targets/qbs-target-qnx.qdoc0000644000175100001660000000522514776170045020417 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-qnx.html
    \ingroup platforms

    \title Building for QNX
    \brief Platform notes for QNX.

    To develop applications for the QNX Neutrino RTOS, you need to install the
    QNX Software Development Platform (SDP) on a Linux, macOS, or Windows
    development host. You can deploy the QNX Neutrino RTOS on a target system,
    such as embedded hardware, a virtual machine, or a PC.

    \QBS automatically determines the location of the SDP base directory if the
    SDP is installed at one of the standard locations, such as \c ~/qnx700,
    \c /opt/qnx700, or \c C:\qnx700. In addition, \QBS uses the SDP and the
    information it has about the host operating system to determine the location
    of the QNX host and target directories.

    If the QNX SDP path could not be determined automatically, you must add a
    dependency to the \l{qnx} module to your application and set the
    \l{qnx::sdkDir}{qnx.sdkDir} property:

    \code
    Application {
        name: "helloworld"
        files: "main.cpp"
        Depends { name: "cpp" }

        Depends { name: "qnx" }
        qnx.sdkDir: "/path/to/qnx700"
    }
    \endcode

    Alternatively, you can set the \c qnx.sdkDir property in a profile or on
    the command line.

    \QBS supports QNX SDP version 6.5 and above.

    For more information about developing applications for the QNX Neutrino
    RTOS, see the \l{http://www.qnx.com/developers/docs/}
    {QNX Product Documentation}.
*/
qbs-src-2.6.1/doc/targets/qbs-target-android.qdoc0000644000175100001660000000622114776170045021226 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-android.html
    \ingroup platforms

    \title Building for Android
    \brief Platform notes for Android.

    To develop applications for Android, you need development tools provided by
    the Android SDK from Google, and (optionally) a C/C++ toolchain provided by
    the Android NDK.

    \note \QBS does not yet support the Kotlin programming language.

    \section1 Creating Android Application Packages

    On Android, applications are distributed in a specially structured type of
    ZIP package called an APK. The following files should be created and bundled
    into an APK:

    \list
        \li Android assets.
        \li Android resource files.
        \li AndroidManifest.xml, which provides meta-information about your
            application.
        \li Compiled Java code, which serves as the entry point into your
            application and that automatically executes the native code in your
            application (if there is any).
        \li Shared libraries containing native code.
    \endlist

    You can use the \l{Application} item to build application
    packages for Android.

    If the \l{qbs::targetPlatform}{target platform} is \c{"android"}, then the Application item has
    a dependency on the \l{Android.sdk} module, which
    contains the properties and rules to create Android application packages
    from source files.

    You can use the \l{DynamicLibrary} item to build native
    Android libraries that are bundled into the APK. The \c qbs.architectures
    property specifies the architectures to build for, with the default value
    \c armv7a.
    If you have only one native library, you can simply list its sources
    within the main Application item, and it will get built and packaged
    automatically.

    The \l{DynamicLibrary} item, as well as the \l CppApplication item,
    has a dependency on the \l{Android.ndk} module,
    and contains the properties and rules to create native libraries.
*/
qbs-src-2.6.1/doc/targets/qbs-target-tvos.qdoc0000644000175100001660000000321014776170045020574 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-tvos.html
    \ingroup platforms

    \title Building for tvOS
    \brief Platform notes for tvOS.

    This topic describes the \QBS features specific to tvOS.

    \include qbs-target-apple-common.qdocinc xcode
    \include qbs-target-apple-common.qdocinc building user interfaces
    \include qbs-target-apple-common.qdocinc creating app bundles
    \include qbs-target-apple-common.qdocinc architectures and variants
*/
qbs-src-2.6.1/doc/targets/qbs-target-vxworks.qdoc0000644000175100001660000000314714776170045021335 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
    \page qbs-target-vxworks.html
    \ingroup platforms

    \title Building for VxWorks
    \brief Platform notes for VxWorks.

    The Wind River VxWorks RTOS is not yet supported but is planned for a
    future release.

    For more information about developing applications for the WindRiver VxWorks
    RTOS, see the \l{https://www.windriver.com/products/vxworks/}
    {VxWorks Product Documentation}.
*/
qbs-src-2.6.1/doc/qbs.qdoc0000644000175100001660000025216214776170045014662 0ustar  runnerdocker/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

// **********************************************************************
// NOTE: the sections are not ordered by their logical order to avoid
// reshuffling the file each time the index order changes (i.e., often).
// Run the fixnavi.pl script to adjust the links to the index order.
// **********************************************************************


/*!
    \page index.html
    \nextpage overview.html

    \title Qbs Manual

    \section1 Version \qbsversion

    \QBS is a tool that helps simplify the build process for
    developing projects across multiple platforms. \QBS can be used for any
    software project, regardless of programming language, toolkit, or libraries used.


    \note Please report bugs and suggestions to the
    \l{http://bugreports.qt.io/}{Qt Bug Tracker}.

    \list
       \li  \l{Introduction}
       \li  \l{Setup}
           \list
               \li  \l{Installing}
               \li  \l{Configuring Profiles and Preferences}
               \li  \l{Managing Qt Versions}
           \endlist
       \li  \l{Usage}
           \list
               \li  \l{Language Introduction}
               \li  \l{Building Applications}
               \li  \l{Running Applications}
               \li  \l{Installing Files}
               \li  \l{Target Platforms}
               \li  \l{Using the Shell}
               \li  \l{Generators}
               \li  \l{Multiplexing}
               \li  \l{Custom Modules and Items}
               \li  \l{Special Property Values}
               \li  \l{Module Providers}
           \endlist
        \li  \l{Tutorial}
           \list
                \li  \l{tutorial-1.html}{Console Application}
                \li  \l{tutorial-2.html}{Static Library}
                \li  \l{tutorial-3.html}{Dynamic Library}
                \li  \l{tutorial-4.html}{Convenience Items}
                \li  \l{tutorial-5.html}{Autotest}
                \li  \l{tutorial-6.html}{Project Properties}
                \li  \l{tutorial-7.html}{Buildconfig Module}
                \li  \l{tutorial-8.html}{Configurable Library}
                \li  \l{tutorial-9.html}{Version Header}
                \li  \l{tutorial-10.html}{C++20 Modules}
            \endlist
       \li  \l{How-tos}
       \li  \l{Reference}
           \list
                \li \l{List of All Items}
                \list
                    \li \l{List of Language Items}
                    \li \l{List of Convenience Items}
                    \li \l{List of Probes}
                \endlist
                \li \l{List of Built-in Services}
                \li \l{Command-Line Interface}
                \li \l{List of Modules}
                \li \l{List of Module Providers}
                \li \l{Command and JavaScriptCommand}
           \endlist

       \li  \l{Appendix A: Building Qbs}
       \li  \l{Appendix B: Migrating from Other Build Systems}
       \li  \l{Appendix C: The JSON API}
       \li  \l{Appendix D: Licenses and Code Attributions}
    \endlist
*/


/*!
    \previouspage index.html
    \page overview.html
    \nextpage setup.html

    \title Introduction

    \QBS is a build automation tool designed to conveniently manage the build
    process of software projects across multiple platforms.

    \section1 Features

    \QBS provides the following benefits:

    \list
        \li Declarative paradigm
        \li Well-defined language
        \li Platform and programming language independence
        \li Correct and fast incremental builds
        \li Extensible architecture
        \li Easy integration to IDEs
    \endlist

    \section2 Declarative Paradigm

    When writing a project, it is important to describe the build tasks and
    dependencies between them, rather than the build order. It is difficult to
    determine the correct build order in complex projects, especially during
    parallel builds. The build tool should bear that burden, not the developer.

    With a declarative language, \QBS enables you to express intent rather than
    specifying single build steps. This provides the appropriate level of
    abstraction for a build system. For example, \e dependencies can be created
    between \e products, such that the target \e artifacts of the dependency
    can be used as input to the build \e rules in the context of the depending
    product. In addition, you can \e export dependencies and \e properties to
    other products.

    \QBS is modular with clean interfaces between modules. A \e module is a
    collection of properties and \e {language items} that are used for
    building a product if the product depends on the module. The properties
    that can be set for a module are used to control the behavior of the
    toolchain used to build the module.

    \QBS itself knows nothing about file types or extensions, and therefore all
    source files in a product are handled equally. However, you can assign
    \e {file tags} to an artifact to act as markers or to specify a file type.
    \QBS applies a rule to the source files of the project and chooses the
    ones that match the input file tags specified by the rule. It then creates
    artifacts in the build graph that have other filenames and file tags.

    Products and projects can contain \e probes that are run prior to building,
    for instance to locate dependent headers, libraries, and other files outside
    the project directory.

    \section2 Well-Defined Language

    \QBS projects are specified in a QML dialect. QML is a concise, easy to
    learn, and intuitive language that is used successfully in the Qt project.
    Its core is declarative, but it can be extended with JavaScript snippets
    for extra flexibility.

    \QBS builds applications based on the information in a project file. Each
    project file specifies one \l{Project}{project} that can contain
    several \l{Product}{products}. You specify the type of the product,
    such as an \e application, and the dependencies the product has on other
    products.

    The product type determines the set of \l{Rule}{rules} that \QBS
    applies to produce artifacts from input files. The input files can be
    divided into \l{Group}{groups} according to their type or purpose, for
    example. A group can also be used to attach \l{Properties}{properties}
    to products.

    The following is an example of a minimal project file that specifies the
    product type, application name, source file, and a dependency on the
    \l{cpp} module:

    \code
    Application {
        name: "helloworld"
        files: "main.cpp"
        Depends { name: "cpp" }
    }
    \endcode

    For more information, see \l{Language Introduction}.

    \section2 Platform and Programming Language Independence

    \QBS can be used for any software project, regardless of programming
    language, toolkit, or libraries used. \QBS has built-in support for
    building applications for Windows, Linux, macOS, Android, iOS, tvOS,
    watchOS, QNX, and FreeBSD, as well as for cross-compilation. It can be
    easily extended to support further platforms.

    Invoking \l{build}{qbs build} from the command line automatically builds the
    project for the current host platform using the best available toolchain and
    settings, unless a default profile is set. You can configure additional
    profiles for each toolchain you want to use and select the profile to use
    at build time.

    For example, to build applications for Android devices, you would need to
    set up a profile for the Android toolchain and select it when you build the
    application. If you name the profile \e Android, you would then enter the
    following command:

    \code
    qbs build profile:Android
    \endcode

    For more information, see \l{Building Applications}.

    Platform and programming language support is implemented as a set of
    \l{List of Modules}{modules} that your product depends on. In the language
    example above, the dependency on the \l{cpp} module determines
    that the C++ sources are compiled and linked into a binary.

    Alternatively, you could use the \l{CppApplication}
    convenience item that implies a dependency on the \l{cpp} module:

    \code
    CppApplication {
        name: "helloworld"
        files: "main.cpp"
    }
    \endcode

    Additionally, if the sources use Qt, you need a dependency to the
    \l{Qt.core} module, and so on.

    In addition to building projects, \QBS can install the build artifacts to
    a location from where they can be run on the desktop or on a device. \QBS
    modules can be used to create installers for the end users of the
    applications. For example, the \l{dmg} module contains
    properties and rules for building Apple Disk Images, which are typically
    used to distribute applications and installers on macOS. The
    \l{innosetup}, \l{nsis}, and \l{wix} modules contain properties and rules
    for building installers for Windows platforms.

    \section2 Correct and Fast Incremental Builds

    \QBS is an all-in-one tool that generates a build graph from a high-level
    project description (like qmake or CMake) and additionally undertakes the
    task of executing the commands in the low-level build graph (like make).

    \QBS automatically takes advantage of multi-processor and multi-core systems
    to achieve maximum build parallelization. By default, running \c qbs without
    any arguments is roughly equivalent to running \c {make -j} where \c n is
    the number of CPU cores. Similarly, \QBS allows the number of concurrent
    jobs to be explicitly specified using its own \c -j option.

    \QBS has knowledge about the whole project, and therefore builds remain
    correct even when you build sub-projects, because \QBS ensures that all
    dependencies are built too. This virtually eliminates the need for clean
    builds.

    \QBS uses dynamic build graphs with build rules that can generate a variable
    number of files and that are executed only when needed. When figuring out
    which rules to execute, \QBS starts at the product type and then looks for
    a way to produce artifacts with matching file tags from source files, using
    a chain of rules that are connected by their respective input and output
    tags. For an example of how rules are applied when building products, see
    \l{Rules and Product Types}.

    The \QBS build rules can produce a variable number of outputs.
    If the input changes, only the required rules are applied at build time.
    If a rule is applied, all the dependent rules are applied as well, but only
    those. This feature ensures the correctness of the build graph after source
    code changes without having to re-configure the whole project.

    Changing properties that do not affect the build, because they are not used
    by rules, will not cause the project to be rebuilt. The use of properties is
    tracked. Generated artifacts that cease to exist are deleted to avoid
    picking outdated generated artifacts and indefinitely increasing the size of
    the build directory.

    Fast incremental builds are crucial for a fast edit-build-run cycle.
    Instead of retrieving the timestamps of generated files, \QBS uses the time
    stamps stored in the build graph. This is especially important on Windows,
    where file system operations are slow.

    If the project files were not changed, the build graph is loaded from disk.
    It is stored in a binary format that can be loaded much faster than the real
    project files. The project files are parsed only if they were changed.

    \section2 Extensible Architecture

    You can create your own custom \l{List of Modules}{modules} and
    \l{List of Language Items}{items} and make \QBS aware of them.

    You store the custom modules and items in a subdirectory of the project
    directory and specify the path to the subdirectory as a value of the
    \l{Project::}{qbsSearchPaths} property. For example, if the custom module is
    located at \c my-modules/modules/modulename/modulename.qbs, you would
    specify it in the project file as follows:

    \code
    Project {
        qbsSearchPaths: "my-modules"
    \endcode

    For more information, see \l{Custom Modules and Items}.

    \section2 IDE Integration

    \QBS can be used not only from the command line, but also in combination
    with an IDE, such as Qt Creator or Visual Studio Code. These IDEs directly
    support \QBS projects using the new \QBS \l{session} feature. Thus, these IDEs
    can retrieve all the information required to build a single file or project
    through a session's JSON protocol \l{Appendix C: The JSON API}{API}.

    In addition, \QBS can generate projects for Visual Studio, IAR EW, and
    Keil uVision, but it still is an experimental option. For more information,
    see \l {Generators}.

    \section3 Qt Creator

    \l{http://doc.qt.io/qtcreator/index.html}{Qt Creator} provides accurate
    information about the build progress and displays a project tree that
    reflects the logical structure of the project, instead of presenting low-level
    information, such as the file system structure. Adding or removing source
    files keeps the existing project file structure intact.

    For more information about using \QBS to build projects from Qt Creator, see
    \l{http://doc.qt.io/qtcreator/creator-project-qbs.html}{Setting Up Qbs}.

    \section3 Visual Studio Code

    \l{https://code.visualstudio.com/}{Visual Studio Code} provides the
    \l{https://marketplace.visualstudio.com/items?itemName=qbs-community.qbs-tools}
    {qbs-community} plugin that provides accurate information about the build progress
    and displays a project tree that reflects the logical structure of the project.
    Also, it can provide low-level information, such as the file system structure.

    For more information about using \QBS to build projects from Visual Studio Code,
    see \l{https://github.com/denis-shienkov/vscode-qbs/blob/master/docs/how-to.md}
    {How To}.

    \section1 Build Process

    \image qbs-build-process.png

    The build process of a product starts by examining the \l{Product::}{type}
    property of the product. It contains a list of \e {file tags} that are
    similar to MIME types.

    The following example product contains one file tag, \e application:

    \code
    Product {
        Depends { name: "cpp" }
        type: ["application"]
        files: ["main.cpp", "class.cpp", "class.h"]
    }
    \endcode

    \QBS then searches through all \e rules available in the context, meaning
    rules that are defined in the project or those that are made available
    through the dependency on a module, such as the compiler and linker rules
    pulled in from the \c cpp dependency in the example.

    When \QBS finds a rule that produces one or more artifacts with the relevant
    file tag, it looks at the depencencies of that rule and finds out that it
    produces artifacts tagged \c obj. It then finds a rule that produces \c obj
    artifacts that takes \c .cpp artifacts as input.

    \code
    Module {
        // ...
        Rule {
            inputs: ["cpp"]
            Artifact {
                filePath: input.fileName + ".o"
                fileTags: ["obj"]
            }
            prepare: {
                // g++ -c main.cpp -o main.o ...
            }
        }
        //...
    }
    \endcode

    There is no rule in the current context that produces \c .cpp files, but
    we have defined \c .cpp files as inputs for the product. When we added a
    dependency on the \l{cpp} module, that dependency also pulled in another \QBS
    primitive called the \l{FileTagger}{file tagger}. The file tagger
    looked for files matching the pattern \c *.cpp, and then applied the \c cpp
    tag to those input files:

    \code
    Module {
        // ...
        FileTagger {
            patterns: "*.cpp"
            fileTags: ["cpp"]
        }
        //...
    }
    \endcode

    Since the \c .cpp files are input files, they by definition have no other
    dependencies, and we can go back the opposite way in the tree starting with
    the compiler rule described above.

    This design works well for generated files. The \c .cpp artifacts could come
    from another rule that produced them by processing some other input, either
    instead of or in addition to the raw files listed in the product.

    The compiler rule will be invoked twice, once for each \c .cpp file,
    producing a separate object file for each one. Then the linker rule will be
    invoked. Its \c multiplex property is set to \c true, which means that
    instead of producing one output per input and invoking the rule multiple
    times, all input will be collected before invoking the rule only once to
    produce the final application object.

    The standard versus multiplex rules map well to the compiler and linker
    processes. The compiler takes one input file to produce one output file,
    whereas the linker takes multiple input files to produce one output file.

    Finally, after the linker rule has been invoked, it produces an artifact
    tagged \c application. Because the product's type property did not contain
    other file tags, the build process is now complete.
*/


/*!
    \previouspage overview.html
    \page setup.html
    \nextpage installing.html

    \title Setup

    \list
        \li  \l{Installing}
        \li  \l{Configuring Profiles and Preferences}
        \li  \l{Managing Qt Versions}
    \endlist
*/

/*!
    \previouspage reference.html
    \page building-qbs.html
    \nextpage porting-to-qbs.html

    \title Appendix A: Building Qbs

    \QBS can be \l{Installing}{installed from binary packages} or built from
    sources, as described in this appendix. In addition, this appendix describes
    how to use Docker images for developing \QBS.

    \section1 Supported Platforms

    \QBS can be installed and run on the following platforms:

    \list
        \li Windows 7, or later
        \li Linux (tested on Debian 8 and 9, Ubuntu 16.04, OpenSuSE 13.2, and
            Arch Linux)
        \li macOS 10.7, or later
    \endlist

    \section1 System Requirements

    To build \QBS from the source, you need:

    \list
        \li Qt 5.15, or later
        \li Windows: MinGW with GCC 4.9 or Microsoft Visual Studio 2015,
            or later
        \li Linux: GCC 4.9, or later, or Clang 3.9.0, or later
        \li macOS: Xcode 6.2, or later
    \endlist

    An installed toolchain has to match the one that Qt was compiled with.

    \section2 Documentation

    Building the \QBS documentation requires Python 2.7 or 3.2 or above,
    as well as some third party Python modules. These can be installed via \c pip:

    \code
        pip install beautifulsoup4 lxml
    \endcode

    Regenerating the man page requires the \c help2man tool.

    \section1 Building \QBS with СMake

    To build \QBS, enter the following commands:

    \code
        mkdir build && cd build
        cmake -DQt5_DIR=${QT_DIR}/lib/cmake/Qt5/ ..
        make
    \endcode

    Where \c ${QT_DIR} is the directory where Qt is installed. Passing the \c Qt5_DIR option
    is not necessary if \c qmake is present in \c PATH.

    Depending on your platform, you might use \c mingw32-make, \c nmake, or
    \c jom instead of \c make.

    Alternatively, you can use the
    \l{https://cmake.org/cmake/help/latest/generator/Ninja.html}{Ninja} generator:
    \code
        cmake -GNinja -DQt5_DIR=${QT_DIR}/lib/cmake/Qt5/ ..
        ninja
    \endcode

    \section2 CMake Configure Options

    \QBS recognizes the following CMake options (passed to CMake in the form of \c{-DOPTION=value})
    to customize the build:

    \table
    \header \li Option              \li Notes                       \li Default value
    \row    \li WITH_TESTS          \li Enable autotests.           \li \c ON
    \row    \li WITH_UNIT_TESTS     \li Enable additional autotests. \li \c OFF
                                           \li \c OFF
    \row    \li INSTALL_PUBLIC_HEADERS     \li Whether to install public headers. \li \c ON
    \endtable

    \section2 Using ccache with CMake

    To enable using \l{https://ccache.dev}{ccache} when building \QBS, pass the following options
    to CMake:
    \code
        cmake -DQt5_DIR=${QT_DIR}/lib/cmake/Qt5/ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ..
    \endcode

    \section1 Building \QBS with \QBS

    It is also possible to build \QBS with the previously installed \QBS version.
    To build \QBS, enter the following command in the source directory:
    \code
        qbs
    \endcode
    This will use the \c defaultProfile or pick up the Qt version and the toolchain from the \c PATH
    if the \c defaultProfile is not set. See \l {Configuring Profiles and Preferences} for details
    about profiles.

    To run automatic tests, the \c autotest-runner product should be built:
    \code
        qbs build -p autotest-runner
    \endcode
    \QBS will use an empty profile when running tests which means it will try to autodetect
    toolchains, Qt versions and other things based on the system environment.
    It is possible to specify which profile should be used during the test-run by passing the
    \c QBS_AUTOTEST_PROFILE environment variable.
    This variable should be set prior to building \QBS itself; otherwise the \c resolve command
    should be used to update the environment stored in the buildgraph:
    \code
        export QBS_AUTOTEST_PROFILE=qt
        qbs resolve
        qbs build -p autotest-runner
    \endcode

    It is also possible to set up a separate profile for a particular testsuite.
    A profile for the \c tst_blackbox_android suite can be set up as follows:
    \code
        qbs setup-android pie
        export QBS_AUTOTEST_PROFILE_BLACKBOX_ANDROID=pie
    \endcode

    It might be useful to set up the directory with the \QBS settings to isolate the test
    environment:
    \code
        export QBS_AUTOTEST_SETTINGS_DIR=~/path/to/qbs/settings
    \endcode

    \section2 \QBS Build Options

    The \c qbsbuildconfig module can be used to customize the build.
    Properties of that module can be passed using command line as follows:
    \code
        qbs build modules.qbsbuildconfig.enableAddressSanitizer:true
    \endcode

    \QBS recognizes the following properties:
    \table
    \header
        \li Property
        \li Default value
        \li Notes
    \row
        \li enableAddressSanitizer
        \li \c false
        \li Whether to use address sanitizer or not. Enabling this option will add the
            -fsanitize=address flag.
    \row
        \li enableUnitTests
        \li \c false
        \li Enable additional autotests. Enabling this option will export some symbols that would
            otherwise be private.
    \row
        \li enableRPath
        \li \c true
        \li Use this property to disable the use of rpath. This can be used when packaging \QBS
            for distributions which do not permit the use of rpath, such as Fedora.
    \row
        \li installApiHeaders
        \li \c true
        \li Holds whether to install the header files for the \QBS libraries or not. This option
            is required to build against the \QBS libraries.
    \row
        \li enableBundledQt
        \li \c false
        \li Holds whether the Qt libraries that \QBS depends on will be bundled with \QBS during
            the \c install step. This option is only implemented on macOS.
    \row
        \li libDirName
        \li \c "lib"
        \li Directory name used by \c libInstallDir and \c importLibInstallDir properties.
    \row
        \li appInstallDir
        \li \c "bin"
        \li Relative directory path under the install prefix path to put application binaries.
    \row
        \li libInstallDir
        \li \c "bin" on Windows, \c libDirName otherwise
        \li Relative directory path under the install prefix path where to put shared libraries
            (excluding plugins, see the \c relativePluginsPath property).
    \row
        \li importLibInstallDir
        \li \c libDirName
        \li Relative directory path under the install prefix path where to put import libs.
    \row
        \li libexecInstallDir
        \li \c appInstallDir on Windows, \c "libexec/qbs" otherwise
        \li Relative directory path under the install prefix path where to put auxiliary binaries
            executed by the \QBS libraries.
    \row
        \li systemSettingsDir
        \li \c undefined
        \li Directory that will be used by \QBS to store its settings. If not specified, a default
            platform-dependent directory is used.
    \row
        \li installManPage
        \li \c true on Unix, \c false otherwise
        \li Whether to install man pages.
    \row
        \li installHtml
        \li \c true
        \li Whether to install HTML help pages.
    \row
        \li installQch
        \li \c false
        \li Whether to install qch files. See
            \l{https://doc.qt.io/qt-5/qthelp-framework.html}{The Qt Help Framework} for details
            about qch files.
    \row
        \li generatePkgConfigFiles
        \li auto-detected
        \li Whether to generate files for pkg-config.
    \row
        \li generateQbsModules
        \li auto-detected
        \li Whether to generate \QBS modules for the exported \QBS libraries. Use this when
            building another product against \QBS libraries using \QBS as build system.
    \row
        \li docInstallDir
        \li \c "share/doc/qbs/html"
        \li Relative directory path under the install prefix path where to put documentation.
    \row
        \li pkgConfigInstallDir
        \li \c libDirName + \c "/pkgconfig"
        \li Relative directory path under the install prefix path where to put pkg-config files.
    \row
        \li qbsModulesBaseDir
        \li \c libDirName + \c "/qbs/modules"
        \li Relative directory path under the install prefix path where to put \QBS modules.
            Applies only when \c generateQbsModules is \c true.
    \row
        \li relativeLibexecPath
        \li \c "../" + \c libexecInstallDir
        \li Path to the auxiliary binaries relative to the application binary.
    \row
        \li relativePluginsPath
        \li \c "../" + \c libDirName
        \li Path to plugin libraries relative to the application binary.
    \row
        \li relativeSearchPath
        \li \c ".."
        \li Relative path to the directory where to look for \QBS development modules and items.
    \row
        \li libRPaths
        \li auto-detected
        \li List of rpaths.
    \row
        \li resourcesInstallDir
        \li \c ""
        \li Relative directory path under the install prefix path where to put shared resources
            like documentation, \QBS user modules and items.
    \row
        \li pluginsInstallDir
        \li \c libDirName + \c "/qbs/plugins"
        \li Relative path to the directory where to put plugins to.
    \endtable

    \section1 Using Docker

    A set of Docker images for developing \QBS (which are maintained by the \QBS team) is available
    \l{https://hub.docker.com/u/qbsbuild/}{on Docker Hub}.
    Both Windows 10 and Debian Linux container types are available.

    \note The source code for the \QBS development Docker images is located in the \c{docker/}
    directory of the \QBS source tree, if you wish to build them yourself.

    \section2 Linux Containers

    The easiest way to get started is to build \QBS using a Linux container. These types of
    containers are supported out of the box on all the supported host platforms: Windows, macOS,
    and Linux.

    The images provide everything that is necessary to build and test \QBS:

    \list
        \li Qt SDK for building \QBS with \c qmake
        \li Latest stable release of \QBS for building \QBS with \QBS
    \endlist

    We are using docker-compose for building and running the Docker images because it simplifies
    the Docker command line and ensures that the correct image tag is used. All available images
    are listed in the \c docker-compose.yml file in the project root directory.

    Run the following command to download the \QBS development image based on Ubuntu 20.04
    \e Focal:

    \code
        docker-compose pull focal
    \endcode

    You can then create a new container with the \QBS source directory mounted from your host
    machine's file system, by running:

    \code
        docker-compose run --rm focal
    \endcode

    You will now be in an interactive Linux shell where you can develop and build \QBS.

    \section2 Windows Containers

    To build \QBS for Windows using Windows containers, your host OS must be running Windows 10 Pro
    and have Hyper-V enabled. \l{https://docs.docker.com/docker-for-windows/#switch-between-windows-and-linux-containers}{Switch your Docker environment to use Windows containers}.

    We are using docker-compose for building and running the Docker images because it simplifies
    the Docker command line and ensures that the correct image tag is used. All available images
    are listed in the \c docker-compose.yml file in the project root directory.

    Run the following command to download the \QBS development image based on Windows 10:

    \code
        docker-compose pull windows
    \endcode

    You can then create a new container with the \QBS source directory mounted from your host
    machine's file system, by running:

    \code
        docker-compose run --rm windows
    \endcode

    If you want to use Windows containers on a macOS or Linux host, you will have to create a
    virtual machine running Windows 10 and register it with \c{docker-machine}. There is at least
    \l{https://github.com/StefanScherer/windows-docker-machine}{one Open Source project}
    that helps to facilitate this by using using Packer, Vagrant, and VirtualBox.

    The \c{docker run} command to spawn a Windows container on a Unix host will look slightly
    different (assuming \c windows is the name of the Docker machine associated with the Windows
    container hosting VM):

    \code
        eval $(docker-machine env windows)
        docker-compose run --rm windows
    \endcode

    \section2 Building Release Packages

    Release packages for \QBS for Windows can be built using the following command on Windows:

    \code
        docker-compose run --rm windows cmd /c scripts\make-release-archives
    \endcode

    For building release packages for Windows on macOS or Linux:

    \code
        eval $(docker-machine env windows)
        docker-compose run --rm windows cmd /c scripts\\make-release-archives
    \endcode
*/


/*!
    \previouspage setup.html
    \page installing.html
    \nextpage configuring.html

    \title Installing

    \QBS binaries are available for Windows, macOS, Linux, and FreeBSD.

    On all platforms, \QBS binaries are part of the \l{Qt Creator} and \l{Qt SDK}
    installers. You can find the \c qbs executable in the \c bin directory of
    Qt Creator, or within the application bundle's \c MacOS directory on macOS.

    \QBS can also be built locally from sources. For more information, see
    \l{Appendix A: Building Qbs}.

    \section1 Windows

    The Qt Project provides prebuilt binaries for Windows (x86 and x64) at
    \l{https://download.qt.io/official_releases/qbs/}. For commercial customers of
    The Qt Company, the binaries are available in the \l {Qt Account}.
    The binaries are packaged in a .zip folder that can be extracted to a location
    of your choice.

    \QBS is also available as a \l Chocolatey package, which can be installed in
    the usual way:

    \code
    choco install qbs
    \endcode

    The \c .nupkg file can also be downloaded directly from
    \l{https://download.qt.io/official_releases/qbs/} for
    \l{https://chocolatey.org/security#organizational-use-of-chocolatey}{offline installation}.

    \section1 macOS

    \QBS can be conveniently installed on macOS with the \l{MacPorts} or \l{Homebrew}
    package managers:

    \code
    brew install qbs
    \endcode

    or

    \code
    port install qbs
    \endcode

    \section1 Linux and FreeBSD

    \QBS is \l{https://repology.org/metapackage/qbs/versions}{available via the
    package management systems} of Linux distributions, and FreeBSD.
*/

/*!
    \previouspage installing.html
    \page configuring.html
    \nextpage qt-versions.html

    \title Configuring Profiles and Preferences

    Profiles contain properties that apply to one or more projects. They are
    stored independently of the project files and are usually not shared between
    build hosts. Typically, profiles contain module properties, such as
    installation paths of tools or libraries on the host computer. This approach
    has the following advantages, among others:

    \list
        \li Team members with different computer setups can work together
            smoothly because no host-specific settings end up in the project
            files.
        \li Different versions of a tool or library can be used to build the
            same project without affecting each other.
    \endlist

    For example, a profile for building C++ applications contains at least the
    installation path and the type of the compiler toolchain. A profile for
    building Qt applications contains the toolchain-specific properties as well
    as \l{Qt::qmakeFilePaths}{the path to the Qt installation}.

    This topic describes profiles stored in the \QBS settings. In some cases it
    might be beneficial to keep profiles explicitly in the project sources. This
    can be achieved with the \l{Profile} item.

    \section1 Setting Up Toolchain Profiles

    \QBS comes with a helper tool \l{setup-toolchains} that can
    create profiles for many toolchains. Open a terminal window and type:

    \code
    qbs setup-toolchains --detect
    \endcode

    This will automatically set up a profile for each detected toolchain on your
    computer. You can list the existing profiles by running:

    \code
    qbs config --list profiles
    \endcode

    Some toolchains, especially for bare-metal targets, may require additional
    module properties. Those can be added with the \l{config} or the
    \l{config-ui} tools. Now you should be ready to build your first project
    with \QBS. Go into examples/helloworld-minimal and type:

    \code
    qbs build profile:
    \endcode

    You have successfully built your first \QBS project. If you want to build
    projects that use Qt, additional steps might be necessary. Please refer to
    \l{Managing Qt Versions} for more information.

    \section1 Global Preferences

    In addition to profiles, \QBS provides some global preferences such as \c
    qbsSearchPaths and \c defaultProfile.

    \section1 Managing Profiles and Preferences

    You can use the \l{config} command to manage all \QBS configuration
    settings, such as profiles and global preferences from the command line,
    for example:

    \code
    qbs config profiles..qbs.architecture arm
    \endcode

    For convenience, \QBS provides a tool \l{config-ui} where you can manage the
    settings in a hierarchical view.

    \image qbs-settings-gui.png

    \QBS Settings displays the keys in the specified settings directory and
    their values. To expand all keys, select \uicontrol View >
    \uicontrol {Expand All} (\key Ctrl+E or \key Cmd+E on macOS). To collapse
    all keys, select \uicontrol {Collapse All} (\key Ctrl+C or \key Cmd+C).

    To change the value of a key, double-click it and enter the new value.

    To save your changes, select \uicontrol File > \uicontrol Save.

    To refresh the settings from the settings directory, select \uicontrol File
    > \uicontrol Reload.

*/

/*!
    \previouspage configuring.html
    \page qt-versions.html
    \nextpage usage.html

    \title Managing Qt Versions

    \section1 Introduction

    If your environment has the right \c qmake binary in its \c PATH and is also set up
    properly for a matching toolchain, then you do not necessarily need a profile
    to build projects with a Qt dependency. Otherwise, you should create one:

    \code
    qbs setup-qt /usr/bin/qmake myqt
    \endcode

    This will create the \c myqt profile which can then be used on
    the command line:

    \code
    qbs profile:myqt
    \endcode

    \note If the \c setup-toolchains command has found more than one toolchain, you will need
    to manually link your Qt profile to one of them, like this:
    \code
    qbs config profiles.myqt.baseProfile 
    \endcode


    \section1 Multiple Qt Builds

    To support multiple Qt builds, or in fact any combination of related settings, you need to
    create several profiles. The following example illustrates how to set up
    three different profiles, each for a different Qt build:

    \code
    qbs setup-qt ~/dev/qt/4.7/bin/qmake qt47
    qbs setup-qt ~/dev/qt/4.8/bin/qmake qt48
    qbs setup-qt ~/dev/qt/5.0/qtbase/bin/qmake qt5
    \endcode

    You can set the default Qt build like this:

    \code
    qbs config defaultProfile qt5
    \endcode

    To choose a Qt build that is different from the default, use:

    \code
    qbs build profile:qt48
    \endcode

    You can set other properties in a profile (not just Qt ones), in the same way
    you override them from the command line. For example:

    \code
    qbs setup-qt C:\Qt\5.0.0\qtbase\bin\qmake.exe qt5
    qbs config profiles.qt5.qbs.architecture x86_64
    qbs config profiles.qt5.baseProfile msvc2010
    \endcode

    The last example uses the inheritance feature of profiles. All settings in the profile
    set as \c baseProfile are known in the derived profile as well.
    They can of course be overridden there.
*/

/*!
    \previouspage qt-versions.html
    \page usage.html
    \nextpage language-introduction.html

    \title Usage

    \list
        \li  \l{Language Introduction}
        \li  \l{Building Applications}
        \li  \l{Running Applications}
        \li  \l{Installing Files}
        \li  \l{Target Platforms}
        \li  \l{Using the Shell}
        \li  \l{Generators}
        \li  \l{Multiplexing}
        \li  \l{Custom Modules and Items}
        \li  \l{Special Property Values}
        \li  \l{Module Providers}
    \endlist

*/

/*!
    \previouspage usage.html
    \page language-introduction.html
    \nextpage building-applications.html

    \title Language Introduction

    \QBS uses project files (*.qbs) to describe the contents of a project.
    A project contains one or more \l{Product}{products}. A product is the target of a build
    process, typically an application, library or maybe a tar ball.
    \note \QBS source files are assumed to be UTF-8 encoded.

    \section1 The Obligatory Hello World Example

    \QBS project files are written using a QML dialect.
    A very simple C++ hello world project looks like this:
    \code
        ---helloworld.qbs---
        Application {
            name: "helloworld"
            files: "main.cpp"
            Depends { name: "cpp" }
        }
    \endcode

    \a Application describes the product we want to build. In this case, an
    application. This is just a shortcut for writing
    \code
        Product {
            type: "application"
            // ...
        }
    \endcode

    The \a name is the name of the product. In this case it is also the
    name of the produced executable (on Windows, the ".exe" extension is added by default).

    In the property \a files, we specify the source files for our product.
    Unlike QML, the right-hand side can be either a string or a string list.
    A single string is converted to a stringlist containing just one element.
    So we could have also written

    \code
    files: [ "main.cpp" ]
    \endcode

    \a Depends adds the dependency to the \l{cpp} module. This is necessary to
    let \QBS know that we have a C++ project and want to compile main.cpp with a
    C++ compiler. For more information about \QBS modules, see \l{Modules}.


    \section1 Reusing Project File Code
    QML-like inheritance works also in \QBS.

    \code
    ---CrazyProduct.qbs---
    Product {
        property string craziness: "low"

        files: [
            "Crazy.h",
            "Crazy.cpp"
        ]
    }

    ---hellocrazyworld.qbs---
    import "CrazyProduct.qbs" as CrazyProduct

    CrazyProduct {
        craziness: "enormous"
        name: "hellocrazyworld"
        files: base.concat(["main.cpp"])
        // ...
    }
    \endcode

    You can put JS code into separate \c{.js} files and then import them.
    \code
    ---helpers.js---
    function planetsCorrectlyAligned()
    {
        // implementation
    }

    ---myproject.qbs---
    import "helpers.js" as Helpers

    Product {
        name: "myproject"
        Group {
            condition: Helpers.planetsCorrectlyAligned()
            file: "magic_hack.cpp"
        }
        // ...
    }
    \endcode

    See \l {Special Property Values} for more details about the \l base property.

    \section1 Modules

    A \e module is a collection of properties and language items that are used for
    building a product if the product depends on (or loads) the module.

    For example, the \a cpp module looks like this (simplified):
    \code
    Module {
        name: "cpp"
        property string warningLevel
        property string optimization
        property bool debugInformation
        property pathList includePaths
        // ...
        FileTagger {
            patterns: "*.cpp"
            fileTags: ["cpp"]
        }
        Rule {...}  // compiler
        Rule {...}  // application linker
        Rule {...}  // static lib linker
        Rule {...}  // dynamic lib linker
    }
    \endcode

    The properties that can be set for the \a cpp module are used to control the behavior of
    your C++ toolchain.
    In addition, you can use FileTaggers and Rules that are explained later.

    As soon as your product depends on a module, it can set the properties of the
    module. You specify the optimization level for your product (and all build variants) like this:

    \code ---helloworld.qbs---
        Application {
            name: "helloworld"
            files: ["main.cpp"]
            cpp.optimization: "ludicrousSpeed"
            Depends { name: "cpp" }
        }
    \endcode

    A module can depend on other modules. For example, the
    \l{Qt.core} module depends on the \l{cpp} module. The module dependencies are transitive,
    i.e. in a Product, all dependent modules are accessible:

    \code
        Application {
            name: "helloworld"
            files: ["main.cpp"]
            Depends { name: "Qt.core" }
            // the "cpp" module is available since
            // "Qt.core" depends on "cpp".
            cpp.optimization: "ludicrousSpeed"
        }
    \endcode

    \section2 Different Properties for a Single File

    Not only the product, but all the source files of the product can have their own
    set of module properties. For example, assume you have some files that are known to crash
    your compiler if you turn on optimizations. You want to turn off
    optimizations for just these files and this is how you do it:

    \code
        Application {
            name: "helloworld"
            files: "main.cpp"
            Group {
                files: ["bad_file.cpp", "other_bad_file.cpp"]
                cpp.optimization: "none"
            }
            Depends { name: "cpp" }
        }
    \endcode

    \section2 Selecting Files by Properties

    Sometimes you have a file that is only going to be compiled on a certain platform.
    This is how you do it:
    \code
        Group {
            condition: qbs.targetOS.includes("windows")
            files: [
                "harddiskdeleter_win.cpp",
                "blowupmonitor_win.cpp",
                "setkeyboardonfire_win.cpp"
            ]
        }
        Group {
            condition: qbs.targetOS.includes("linux")
            files: [
                "harddiskdeleter_linux.cpp",
                "blowupmonitor_linux.cpp",
                "setkeyboardonfire_linux.cpp"
            ]
        }
    \endcode

    In the above example, \l{qbs::targetOS}{qbs.targetOS} is a property of the
    target of the the \l{qbs} module. The \c qbs module is always implicitly
    loaded. Its main properties are:

    \list
        \li \l{qbs::}{buildVariant} that specifies the name of the build variant
            for the current build.
        \li \l{qbs::}{targetOS} that specifies the operating system you want to
            build the project for.
    \endlist

    You can set these properties on the command line or by using a profile.

    \code
    $ qbs                             # qbs.buildVariant:debug, profile: (or profile:none, if no default profile exists)
    $ qbs config:release              # qbs.buildVariant:release, profile:
    $ qbs config:debug config:release # builds two configurations of the project
    $ qbs profile:none                # all module properties have their default values
    \endcode

    To select files by build variant:
    \code
        Group {
            condition: qbs.buildVariant == "debug"
            files: "debughelper.cpp"
        }
    \endcode

    To set properties for a build variant:
    \code
        Properties {
            condition: qbs.buildVariant == "debug"
            cpp.debugInformation: true
            cpp.optimization: "none"
        }
    \endcode
    Or, to use a more QML-like style:
    \code
        cpp.debugInformation: qbs.buildVariant == "debug" ? true : false
        cpp.optimization: qbs.buildVariant == "debug" ? "none" : "fast"
    \endcode

    \section1 Property Types

    While properties in \QBS generally work the same way as in QML, the set of possible property
    types has been adapted to reflect the specific needs of a build tool. The supported types
    are as follows:

    \table
    \header
        \li Property type
        \li Example
        \li Description
    \row
        \li \c bool
        \li \c{property bool someBoolean: false}
        \li The usual boolean values.
    \row
        \li \c int
        \li \c{property int theAnswer: 42}
        \li Integral numbers.
    \row
        \li \c path
        \li \c{property path aFile: "file.txt"}
        \li File paths resolved relative to the directory the product they are associated with
            is located in.
    \row
        \li \c pathList
        \li \c{property pathList twoFiles: ["file1.txt", "./file2.txt"]}
        \li A list of \c path values.
    \row
        \li \c string
        \li \c{property string parentalAdvisory: "explicit lyrics"}
        \li JavaScript strings.
    \row
        \li \c stringList
        \li \c{property stringList realWorldExample: ["no", "not really"]}
        \li A list of JavaScript strings.
    \row
        \li \c var
        \li \c{property var aMap: ({ key1: "value1", key2: "value2" })}
        \li Generic data, as in QML.
    \row
        \li \c varList
        \li \c{property var aMapList: [{ key1: "value1", key2: "value2" }, { key1: "value3" }]}
        \li A list of generic data, typically JavaScript objects.
    \endtable


    \section1 Overriding Property Values from the Command Line

    Property values set in project files or profiles can be overridden on the command line.
    The syntax is \c{.:}. The following command lines
    demonstrate how to set different kinds of properties:
    \code
    $ qbs projects.someProject.projectProperty:false          # set a property of a project
    $ qbs products.someProduct.productProperty:false          # set a property of a product
    $ qbs modules.cpp.treatWarningsAsErrors:true              # set a module property for all products
    $ qbs products.someProduct.cpp.treatWarningsAsErrors:true # set a module property for one product
    \endcode

    Property values on the command line can also be expressed in JavaScript form, the same way
    as you would write them in a project file. Make sure to take care of proper
    quoting, so that the shell does not interpret any of the values itself. Properties of type
    \c stringList can also be provided as comma-separated values, if none of the strings contain
    special characters:
    \code
    $ qbs projects.someProject.listProp:'["a", "b", "c"]'
    $ qbs projects.someProject.listProp:a,b,c               # same as above
    $ qbs projects.someProject.listProp:'["a b", "c"]'      # no CSV equivalent
    \endcode

    \section1 File Tags and Taggers

    \QBS itself knows nothing about C++ files or file extensions. All source files
    in a product are handled equally. However, you can assign \a{file tags} to an artifact
    to act as a marker or to specify a file type.

    An artifact can have multiple file tags.
    For example, you can use the \a Group item to group files with the same file tags (or a set of
    properties).

    \code
        Product {
            Group {
                files: ["file1.cpp", "file2.cpp"]
                fileTags: ["cpp"]
            }
            Group {
                files: "mydsl_scanner.l"
                fileTags: ["flex", "foobar"]
            }
            // ...
        }
    \endcode

    When you load the \a cpp module, you also load the following item:
    \code
        FileTagger {
            patterns: "*.cpp"
            fileTags: ["cpp"]
        }
    \endcode
    This construct means that each source file that matches the pattern \c{*.cpp} (and
    has not explicitly set a file tag) gets the file tag \c{cpp}.

    The above example can be simplified to
    \code
        Product {
            Depends: "cpp"
            files: ["file1.cpp", "file2.cpp"]
            Group {
                files: "mydsl_scanner.l"
                fileTags: ["flex", "foobar"]
            }
            // ...
        }
    \endcode

    The \a FileTagger from the \a cpp module automatically assigns the \c cpp
    file tag to the source files. Groups that just contain the \a files
    property can be more simply expressed by using the \a files property of the product.

    File tags are used by \a rules to transform one type of artifact into
    another. For instance, the C++ compiler rule transforms artifacts with the file tag
    \c cpp to artifacts with the file tag \c{obj}.

    In addition, it is possible to use file taggers to tag files and specify custom file tags:
    \code
        Product {
            Depends: "cpp"
            Group {
                overrideTags: false     // The overrideTags property defaults to true.
                fileTags: ["foobar"]
                files: ["main.cpp"]     // Gets the file tag "cpp" through a FileTagger item and
                                        // "foobar" from this group's fileTags property.
            }
            // ...
        }
    \endcode

    \section1 Rules

    \QBS applies a \e rule to a pool of artifacts (in the beginning it is just the set of
    source files of the project) and chooses the ones that match the input file
    tags specified by the rule. Then it creates output artifacts in the build graph that have other
    filenames and file tags. It also creates a script that transforms the input artifacts into the
    output artifacts. Artifacts created by one rule can (and typically do) serve as inputs to
    another rule. In this way, rules are connected to one another via their input and output
    file tags.

    For examples of rules, see the share/qbs/modules directory in the \QBS
    repository.

    You can define rules in your own module to be provided along with
    your project. Or you can put a rule directly into your project file.

    For more information, see \l{Rule}.
*/


/*!
    \previouspage language-introduction.html
    \page building-applications.html
    \nextpage running-applications.html

    \title Building Applications

    This section assumes that \QBS is present in \c PATH. For the details how to install \QBS, see
    the \l{Installing} page.

    To build applications from the command line, enter the following commands:

    \code
    cd examples/collidingmice
    qbs
    \endcode

    By default, \QBS uses all the CPU cores available to achieve maximum build
    parallelization. To explicitly specify the number of concurrent jobs, use
    the \c -j option. For example, to run 4 concurrent jobs, enter the following
    command:

    \code
    qbs -j4
    \endcode

    The application is built using the default build profile that is set up
    in your \QBS configuration.

    You can use the \l{config} command to set the max number of jobs per profile.
    For example, to set four jobs as the default option for a profile named
    \e Android, enter the following command:

    \code
    qbs config profiles.Android.preferences.jobs 4
    \endcode

    To build with other profiles than the default one, specify options for the
    \l{build} command. For example, to build debug and release configurations with
    the \e Android profile, enter the following command:

    \code
    qbs build profile:Android config:debug config:release
    \endcode

    The position of the property assignment is important. In the example
    above, the profile property is set for all build configurations that come
    afterwards.

    To set a property just for one build configuration, place the assignment after
    the build configuration name.
    In the following example, the property \l{cpp::treatWarningsAsErrors}
    {cpp.treatWarningsAsErrors} is set to \c true for debug only and
    \l{cpp::optimization}{cpp.optimization} is set to \c small for release only.

    \code
    qbs build config:debug modules.cpp.treatWarningsAsErrors:true config:release modules.cpp.optimization:small
    \endcode

    Projects are built in the debug build configuration by default.
*/

/*!
    \previouspage running-applications.html
    \page installing-files.html
    \nextpage {Target Platforms}

    \title Installing Files

    To install your project, specify the necessary information in the project file:

    \code
    Application {
        Group {
            name: "Runtime resources"
            files: "*.qml"
            qbs.install: true
            qbs.installDir: "share/myproject"
        }
        Group {
            name: "The App itself"
            fileTagsFilter: "application"
            qbs.install: true
            qbs.installDir: "bin"
        }
    }
    \endcode

    In this example, we want to install a couple of QML files and an executable.

    When building, \QBS installs artifacts into the default root folder, namely
    \c{/install-root}. The \l{qbs::installPrefix}{qbs.installPrefix} and
    \l{qbs::installDir}{qbs.installDir} properties are appended to the root folder.
    \code
    qbs build qbs.installPrefix:/usr
    \endcode
    In this example, the executable will be installed into the \c{/install-root/usr/bin}
    folder and the QML files will be installed into the
    \c{/install-root/usr/share/myproject} folder.

    To skip installation during the build, use the \c --no-install option.

    To override the default location, use the \c --install-root option of the \c{qbs install}
    command:
    \code
    qbs build --no-install qbs.installPrefix:/usr
    sudo qbs install --no-build --install-root /
    \endcode
    In this example, artifacts will be installed directly into the \c /usr folder. Since the
    \c{qbs install} command implies \c build, we use the \c --no-build parameter to ensure that
    we do not accidentally rebuild the project, thereby changing the artifacts' owner to \c root.

    Sometimes, it makes sense to install the application into a temporary root folder, keeping the
    same folder structure within that root folder as in the examples above; for instance,
    when building a Linux package such as \c deb or \c rmp. To install the application into the
    \c /tmp/myProjectRoot folder, use the following command:

    \code
    $ qbs install --install-root /tmp/myProjectRoot
    \endcode

    In this example, the executable will be installed into the \c{/tmp/myProjectRoot/usr/bin} folder
    and QML files will be installed into the \c{/tmp/myProjectRoot/usr/share/myproject} folder.

    To remove all files from the install root prior to installing, use the \c --clean-install-root
    parameter:

    \code
    qbs install --clean-install-root --install-root /tmp/myProjectRoot
    \endcode

    For more information about how the installation path is constructed, see
    \l {Installation Properties}.
*/

/*!
    \previouspage building-applications.html
    \page running-applications.html
    \nextpage installing-files.html

    \title Running Applications

    Qbs has the convenience \l{run}{qbs run} command that simplifies running applications.

    For example, entering the following command runs the Qt Creator application:

    \code
    qbs run --products qtcreator
    \endcode

    By default, running an application also builds it and installs it to a
    location from where it can be run on the desktop or on a device. Also, this command
    \l{Module::setupRunEnvironment}{sets up} the environment so that the application can find
    dependent libraries.

    This is not the case when running the binary manually - you'll have to make sure that the
    app will find its dependencies and/or is relocatable. You can achieve that by
    \l{How do I make use of rpaths?}{configuring rpaths} properly or setting the appropriate
    environment variable for the respective host system.

*/

/*!
    \previouspage {Target Platforms}
    \page shell.html
    \nextpage generators.html

    \title Using the Shell

    To use the \QBS shell, enter the following command:

    \code
    qbs shell
    \endcode

    This is mainly a debugging tool. It opens a shell with the same environment
    that \QBS uses when building the project, so you can, for example, inspect
    which environment variables will be set up.

*/

/*!
    \previouspage multiplexing.html
    \page custom-modules.html
    \nextpage special-property-values.html

    \title Custom Modules and Items

    Users of \QBS are not limited to the pre-defined \l{List of Modules}{modules} and
    \l{List of Language Items}{items}, they can also create their own. Here we describe how
    to set up custom modules and items so that \QBS will find them.

    \section1 File System Layout

    Items and modules are located under a common base directory, whose name and location is
    completely arbitrary. We will refer to it as \c search-path here. This directory has two
    subdirectories \c modules and \c imports, which contain \QBS modules and items, respectively.


    \section1 Custom Modules

    To introduce a custom module \c mymodule, create a directory \c{search-path/modules/mymodule/}.
    \note Module names are case-sensitive, and this also goes for the corresponding directory name.

    Then, put a file containing an instance of the \l{Module} in there and give it the \c{.qbs}
    extension. This module will be pulled in if a
    \l{Product}{product} declares a \l{Depends}{dependency} on \c mymodule.


    \section1 Custom Items

    To introduce a custom item \c MyItem, create the file \c{search-path/imports/MyItem.qbs}.

    \note Item file names must start with a capital letter due to the fact that type names can
    only start with a capital letter. Otherwise, the file will be silently ignored.

    \section1 Making \QBS Aware of Custom Modules and Items

    To be able to use your custom modules and items, you need to make them known to \QBS. You can
    do this per project or globally.

    \section2 Project-specific Modules and Items

    Let's assume you have a project that is located in \c{project_dir} and you have created some
    modules in \c{project_dir/custom-stuff/modules/} as well as some items in
    \c{project_dir/custom-stuff/imports/} that you want to use in the project.
    To achieve this, your top-level project file should look like this:
    \code
    // ...
    Project {
        // ..
        qbsSearchPaths: "custom-stuff"
        // ..
    }
    \endcode
    \note For technical reasons, the custom modules and items will not be
    available in the file that contains the \l{Project::qbsSearchPaths}
    {Project.qbsSearchPaths} property. Any product that wants to make use of
    them needs to be in a different file that is pulled in via the
    \l{Project::references}{Project.references} property, for example.
    This is not a serious limitation, since every well-structured project will
    be split up in this manner.

    \section2 Making Custom Modules and Items Available Across Projects

    What if your modules and items are generally useful and you want to access them in several
    projects? In this case, it is best to add the location to your preferences.
    For example:
    \code
    qbs config preferences.qbsSearchPaths /usr/local/share/custom-qbs-extensions
    \endcode

*/

/*!
    \previouspage custom-modules.html
    \page special-property-values.html
    \nextpage module-providers.html

    \title Special Property Values

    Depending on the context, \QBS provides the following special values for use in property
    bindings and JavaScript code:

    \list
        \li \l base
        \li \l exportingProduct
        \li \l filePath
        \li \l importingProduct
        \li \l module
        \li \l original
        \li \l outer
        \li \l path
        \li \l product
        \li \l project
    \endlist

    \section2 \c base
    This value is useful when making use of inheritance. It stands for the value of the respective
    property in the item one level up in the inheritance chain. For instance:
    \code
    Product { // defined in MyProduct.qbs
        Depends { name: "mymodule" }
        mymodule.someProperty: ["value1"]
    }
    ------ some other file ------
    MyProduct {
        mymodule.someProperty: base.concat(["value2"]) // => ["value1", "value2"]
    }
    \endcode

    \section2 \c exportingProduct
    Within an \l Export item, you can use the \c exportingProduct variable to refer to
    the product which defines the Export item:

    \code
    Product {
        Export {
            Depends { name: "cpp" }
            cpp.includePaths: exportingProduct.sourceDirectory
        }
    }
    \endcode

    \section2 \c filePath

    This value holds the full file path to the \c .qbs file it appears in. This property is
    rarely used, but might be useful when debugging:
    \code
    Product {
        property bool dummy: {
            console.info("I'm located at " + filePath);
        }
    }
    \endcode

    \section2 \c importingProduct
    Within an \l Export item, you can use the \c importingProduct variable to refer to
    the product that pulls in the resulting module:

    \code
    Product {
        Export {
            Depends { name: "cpp" }
            cpp.includePaths: importingProduct.buildDirectory
        }
    }
    \endcode
    Usually, you should use the \l product variable instead for consistency with \l Module items.

    \section2 \c module

    This value holds the properties of the module that contains the current item:
    \code
    Module {
        property bool enableGroup
        property bool enableRule
        Group {
            condition: enableGroup // available without qualification because Module is a direct parent item
            Rule {
                condition: module.enableRule // Shortcut for product..enableRule
                // ...
            }
        }
    }
    \endcode

    \section2 \c original
    On the right-hand side of a module property binding, this refers to the value of the property
    in the module itself (possibly overridden from a profile). Use it to set a module property
    conditionally:
    \code
    Module { // This is mymodule
        property string aProperty: "z"
    }
    ----------
    Product {
        Depends { name: "mymodule" }
        Depends { name: "myothermodule" }
        // "y" if myothermodule.anotherProperty is "x", "z" otherwise:
        mymodule.aProperty: myothermodule.anotherProperty === "x" ? "y" : original
    }
    \endcode
    \note In all but the most exotic cases, a \l{Properties} item is the preferred way to
          achieve the same result:
    \code
    Product {
        Depends { name: "mymodule" }
        Depends { name: "myothermodule" }
        Properties {
            condition: myothermodule.anotherProperty === "x"
            mymodule.aProperty: "y"
        }
    \endcode

    \section2 \c outer
    This value is used in nested items, where it refers to the value of the respective property
    in the surrounding item. It is only valid in \l{Group} and \l{Properties} items:
    \code
    Product {
        Depends { name: "mymodule" }
        mymodule.someProperty: ["value1"]
        Group {
            name: "special files"
            files: ["somefile1", "somefile2"]
            mymodule.someProperty: outer.concat(["value"]) // => ["value1", "value2"]
        }
    }
    \endcode

    \section2 \c path

    This value holds the path to the folder where the \c .qbs file is located. Use it to e.g. add
    the product's directory to file paths:
    \code
    Product {
        Depends { name: "cpp" }
        cpp.includePaths: path
    }
    \endcode

    \section2 \c product

    This value holds the properties of the product that contains the current item or pulls in the
    current module:
    \code
    Module {
        Rule {
            Artifact {
                fileTags: product.type
                filePath: {
                    var result = input.fileName;
                    // module properties are available as well
                    if (product.qbs.buildVariant === "debug")
                        result = result + "_debug";
                    result = result + ".out";
                    return result;
                }
            }
        }
    }
    \endcode
    Within the \l Export item, same as \l importingProduct.

    \section2 \c project
    This value holds the properties of the project that references the current item or pulls in the
    current module:
    \code
    Project {
        property bool enableProduct: true
        Product {
            name: "theProduct"
            condition: project.enableProduct
        }
    }
    \endcode
    If the nearest project in the project tree does not have the desired property, \QBS looks it
    up in the parent project, potentially all the way up to the top-level project.
*/

/*!
    \previouspage special-property-values.html
    \page module-providers.html
    \nextpage tutorial.html

    \title Module Providers

    There are use cases for which a pre-defined module is not flexible enough.
    For instance, the overall set of modules related to a certain task might depend
    on some information present on the local platform.

    Use Module Providers to create new modules during the \c resolve stage, for example when
    locating external dependencies such as libraries.

    Consider the following example:

    \code
    CppApplication {
        files: "main.cpp"
        Depends { name: "zlib" }
        qbsModuleProviders: ["conan", "qbspkgconfig"]
    }
    \endcode
    Here, we want to use the \l{https://www.zlib.net}{zlib} compression library in our application.
    Since there is no pre-defined module called \c "zlib", \QBS will try to create it using
    Module Providers. \QBS will invoke all providers specified in the
    \l{Product::qbsModuleProviders}{qbsModuleProviders} property and those providers will create
    the requested module if possible. Providers contribute to the \l{Product::}{qbsSearchPaths}
    in the order specified by this property, so modules generated by providers specified earlier
    are prioritised. In the example above, modules created by the \l conan provider have higher
    priority than modules created by \c qbspkgconfig.

    \section1 Lookup Based on Module Name
    Originally, the \l{Qt} module provider was a the only provider in \QBS and we wanted to make
    its usage transparent to users. Thus, it was implemented by automatically kicking in when \QBS
    saw the dependency on the \c Qt module such as "Qt.core". It is also possible to specify the
    order of providers explicitly:
    \code
    CppApplication {
        files: "main.cpp"
        Depends { name: "Qt.core" }
        qbsModuleProviders: ["Qt", "qbspkgconfig"]
    }
    \endcode
    That way, users have more control over the module priorities.

    Note that setting the \c qbsModuleProviders property disables the lookup based on the
    module name entirely.

    \section1 Provider Eagerness
    Historically, providers were implemented in an \e eager way meaning that once a provider is
    called, it creates as many modules as it can. For example, when called, the \l{qbspkgconfig}
    provider created a module for each .pc file found in the system. Even though providers are
    quite fast, this violates the zero-overhead principle (you don't pay for what you don't use).
    Thus, we introduced non-eager providers which only create one module at a time when that
    module is requested by the \l{Depends} item. This behavior is controlled by the
    \l{ModuleProvider::isEager}{isEager} property. We advise against using eager providers in
    new code.

    \section1 Selecting Module Providers

    As described above, you can select which providers to run using the
    \l{Product::qbsModuleProviders}{qbsModuleProviders} property. This property can be set on the
    Product as well as the \l{Project::qbsModuleProviders}{Project} level:

    \code
    $ qbs resolve project.qbsModuleProviders:providerA    \ # sets property globally for the Project
        projects.SomeProject.qbsModuleProviders:providerB \ # overrides property for the specific Project
        products.SomeProduct.qbsModuleProviders:providerC \ # overrides property for the specific Product
    \endcode

    \section1 Parameterizing Module Providers

    You can pass information to module providers from the command line, via profiles or
    from within a product, in a similar way as you would do for modules. For instance, the
    following invocation of \QBS passes information to two module providers \c a and \c b:
    \code
    $ qbs moduleProviders.a.p1:true moduleProviders.a.p2:true moduleProviders.b.p:false
    \endcode
    \QBS will set the properties of the respective module providers accordingly.
    In the above example, module provider \c a needs to declare two boolean properties \c p1
    and \c p2, and they will be set to \c true and \c false, respectively.

    \note The following section contains some implementation details. Reading this section is not
    required for most people's everyday work.

    \section1 How \QBS Uses Module Providers

    If \QBS encounters a \l Depends item whose name does not match a known module,
    it checks whether such a module can be generated. This procedure works as follows:
    \list 1
        \li If the \l{Product::qbsModuleProviders}{qbsModuleProviders} property is not
            \c undefined, for each provider name in the list, all
            \l{Project::qbsSearchPaths}{search paths} are scanned for a file called
            \c {module-providers/.qbs} or \c {module-providers//provider.qbs}.
        \li If the \l{Product::qbsModuleProviders}{qbsModuleProviders} property is \c undefined,
            \l{Project::qbsSearchPaths}{search paths} are scanned for a file called
            \c {module-providers//provider.qbs}, where \c  is the name of the dependency
            as specified in the \c Depends item. Multi-component names such as "a.b" are turned
            into nested directories, and each of them is scanned, starting with the deepest path.
            For instance, if the dependency's name is \c {a.b}, then \QBS will look for
            \c {a/b/provider.qbs} and then \c {a/provider.qbs}.
        \li If such a file is found, it needs to contain a \l ModuleProvider item. This item
            is instantiated, which potentially leads to the creation of one or more modules,
            and \QBS retrieves the search paths to find these modules from the item.
            The details are described in the \l ModuleProvider documentation.
        \li If a matching module provider was found and provided new search paths,
            a second attempt will be made to locate the dependency using the new paths.
            The search for a matching module provider ends as soon as one was found, regardless
            of whether it created any modules or not.
    \endlist

*/

/*!
    \previouspage shell.html
    \page generators.html
    \nextpage multiplexing.html

    \title Generators

    Generators are a \QBS sub-tool and set of APIs that enable arbitrary
    processing to be performed on the build graph. Currently, they are used to
    integrate \QBS with popular IDEs, such as Microsoft Visual Studio, and to
    generate Clang compilation databases.

    \section1 Generating Microsoft Visual Studio Projects

    To generate a project for another build system, such as Microsoft Visual
    Studio, use the \l{generate}{qbs generate} command and specify a generator
    using the \l{generate-generator}{-g} option. For example:

    \code
    # For Visual Studio
    qbs generate -g visualstudio2015
    \endcode

    \QBS will then generate a series of files in the current directory, based on the generator that
    was chosen. The resulting project files can be opened in the respective IDE
    and all work can be performed there.

    The project files will expose as much information as possible to the IDE and will use \QBS to
    perform the actual build.

    \note You cannot modify build system files and expect the changes
    to be reflected in \QBS. You must edit your \QBS project files and re-run
    \l{generate}{qbs generate} in order for the changes to be reflected in your
    IDE.

    \section1 Generating IAR Embedded Workbench Projects

    To generate a project for \l{https://www.iar.com/iar-embedded-workbench/}
    {IAR Embedded Workbench}, use the \l{generate}{qbs generate} command and specify
    a generator using the \l{generate-generator}{-g} option. For example:

    \code
    # For IAREW v8xxxx
    qbs generate -g iarew8 profile:
    qbs generate -g iarew8 -d  -f  profile:
    \endcode

    \note You need to specify a specific QBS profile, which is required for a generator
    to fetch a target architecture to generate the project.

    \note IAR EW generator creates a native target project.

    Supported IAR EW generators are listed in a table below:

    \table
    \header \li Generator       \li IAR EW Version      \li Target Architecture
    \row    \li iarew8          \li All 8.x.y versions  \li ARM
    \row    \li iarew7          \li All 7.x.y versions  \li AVR, MSP430
    \row    \li iarew10         \li All 10.x.y versions \li 8051 (aka MCS51)
    \row    \li iarew3          \li All 3.x.y versions  \li STM8
    \endtable

    \section1 KEIL uVision Projects

    To generate a project for \l{https://www2.keil.com/mdk5/uvision/}
    {KEIL uVision}, use the \l{generate}{qbs generate} command and specify
    a generator using the \l{generate-generator}{-g} option. For example:

    \code
    # For KEIL UV5
    qbs generate -g keiluv5 profile:
    qbs generate -g keiluv5 -d  -f  profile:
    \endcode

    \note You need to specify a specific QBS profile, which is required for a generator
    to fetch a target architecture to generate the project.

    \note KEIL UV generator creates a native target project.

    Supported KEIL UV generators are listed in a table below:

    \table
    \header \li Generator       \li KEIL UV Version     \li Target Architecture
    \row    \li keiluv5         \li All 5.x.y versions  \li 8051 (aka MCS51), ARM
    \endtable

    \section1 Generating Clang Compilation Databases

    To generate a \l{JSON Compilation Database Format Specification}
    {Clang compilation database (clangdb)}, use the following command:

    \code
    qbs generate --generator clangdb
    \endcode

    \section1 Generating Makefiles

    To generate a Makefile, use the following command:
    \code
    qbs generate --generator makefile
    \endcode

    \section2 Targets

    The generated Makefile will contain targets for all output artifacts known to \QBS.

    In addition, the following targets are created for every product:
    \list
        \li \c {} to build the product
        \li \c {clean-} to remove all files generated by the above target
        \li \c {install-} to install the product's artifacts that have
                                        \c{qbs.install} set
    \endlist
    In the above list, the placeholder \c{} stands for the product's name with
    all characters that are not ASCII letters, digits, dots or underscores replaced
    with underscore characters.

    The special target \c all builds all products whose \l{Product::builtByDefault}{builtByDefault}
    property is enabled. This is the default target. It is complemented by \c install and \c clean.

    \note The Makefile will not be able to build artifacts created by
    \l{JavaScriptCommand}{JavaScriptCommands}, because there is no command line to run for them.

    \section2 Pre-defined Variables

    The build directory and the install root are set to whatever you specified when calling the
    generator. If you did not specify anything, \QBS' default values are used. You can override
    these values when invoking the \c make tool by explicitly setting the \c{BUILD_ROOT}
    and \c{INSTALL_ROOT} variables, respectively. For instance:
    \code
    $ qbs generate -g makefile config:make modules.qbs.installRoot:/opt/mydir
    $ make -f make/Makefile                                 # Will install to /opt/mydir
    $ make -f make/Makefile INSTALL_ROOT=/opt/myotherdir    # Will install to /opt/myotherdir
    \endcode

    \section2 Spaces in Directory Names

    Due to the difficulties involved in making this work correctly, \QBS will refuse to generate
    a Makefile if the source, build or install root directories contain spaces. It will
    try to handle spaces in file names of output artifacts, though.

    \section2 Platform-specific Differences in Format

    \QBS assumes that the Makefile will be invoked on the current host platform, so that
    platform's tools will be used for copying and removing files, and path separators will
    be converted to backslashes on Windows. When dealing with spaces in artifact names,
    on Unix-like systems compatibility with GNU make is assumed with regards to quoting.

    \section1 Limitations

    Due to the high flexibility of the \QBS project format and build engine, some projects may be too
    complex to produce an equivalent project file for another build system.

    This list of limitations aims to be as small as possible, but one of the most notable (at least
    for the Microsoft Visual Studio generator) is that certain properties must contain the same
    value across all build configurations. For example, the following is not allowed:

    \code
    Product {
        // ERROR: 'name' property cannot have different values based on the configuration
        name: qbs.configuration === "debug"
            ? "MyProduct_debug"
            : "MyProduct"
    }
    \endcode

    \note This limitation only applies when property values are varied on the configuration
    name. For example, the following is OK (as long as the value of xyz itself does not vary across
    configurations):

    \code
    Product {
        // OK
        property bool isDebug: 
        name: isDebug ? "MyProduct_debug" : "MyProduct"
    }
    \endcode

    The properties to which the limitation applies includes but is not limited to:

    \list
        \li \l{Product::name}{Product.name}
        \li \l{bundle::isBundle}{bundle.isBundle}
    \endlist

    If a simple workaround is possible in a particular case (for example,
    varying \l{Product::targetName}{Product.targetName} across configuration
    instead of \l{Product::name}{Product.name}, the generator will typically
    suggest it in the error message.
*/

/*!
    \previouspage generators.html
    \page multiplexing.html
    \nextpage custom-modules.html

    \title Multiplexing

    Multiplexing is an advanced \QBS feature that allows a product to be
    transparently built in multiple \e passes along with an optional, final
    \e aggregate pass that allows the output artifacts of the initial passes
    to be combined or otherwise operated on in some way.

    The multiplexing feature is used to implement certain platform-specific
    behavior: specifically, it allows applications and libraries on Apple
    platforms to be compiled into \e fat binaries containing multiple CPU
    architectures, the creation of Apple frameworks containing multiple
    \e variants (for example, combined debug and release builds), and the
    creation of Android application and library packages containing native
    code built for multiple Android ABIs.

    A product can be multiplexed over the \l{qbs::architectures}
    {qbs.architectures} property (which maps to \l{qbs::architecture}
    {qbs.architecture}), \l{qbs::buildVariants}{qbs.buildVariants} property
    (which maps to \l{qbs::buildVariant}{qbs.buildVariant}), and \l{qbs::profiles}
    {qbs.profiles} (which maps to \l{Project::profile}{Project.profile}).

    For example, to build a "fat" \c iOS binary containing two architectures, use the following
    command:
    \code
        qbs build modules.qbs.targetPlatform:ios modules.qbs.architectures:arm64,armv7a
    \endcode

    \note The implementation details around multiplexing are subject to change.

    Product multiplexing works by examining the
    \l{Product::multiplexByQbsProperties}{Product.multiplexByQbsProperties}
    property, which can
    be set to the list of properties your product should multiplex over. For
    example, \c multiplexByQbsProperties might contain two strings,
    \c "architectures" and \c "buildVariants". \QBS evaluates the values of
    \c qbs.architectures and \c qbs.buildVariants, which in turn might contain
    the values \c ["x86", "x86_64"] and \c ["debug", "release"]. \QBS will build
    all the possible configurations of the product: \c {(x86, debug)},
    \c {(x86, release)}, \c {(x86_64, debug)}, and \c {(x86_64, release)}.

    If the \l{Product::aggregate}{Product.aggregate} property is \c true, the
    product will also be
    built a fifth time, with the values of the multiplexed properties left
    undefined. The aggregate product will have an automatic dependency on the
    original four instances of the product, allowing it to collect their output
    artifacts and to operate on them.

    The aggregate product is used in situations where the target artifacts of
    the individually multiplexed instances must be combined into one final
    aggregate artifact that makes up the overall product.
    Bundle products on Apple platforms use the aggregate product to create the
    bundle artifacts (such as \c Info.plist and \c PkgInfo) that are independent
    of a particular architecture or build variant. In addition, they use the
    \c lipo tool to join together the built native code for different
    architectures (such as \c x86 and \c x86_64) into the final,
    multi-architecture fat binary that the app bundle contains.
*/

/*!
    \previouspage json-api.html
    \page attributions.html

    \title Appendix D: Licenses and Code Attributions

    \section1 Licenses

    The \QBS library and tools are available under commercial licenses from
    \l{Qt Licensing}{The Qt Company}. In addition, they are available under
    \l{GNU Lesser General Public License, Version 3} (LGPL version 3) and
    \l{GNU General Public License, version 2} (GPL version 2).

    Shared functionality, which might be pulled in by user build scripts, is
    available under commercial licenses,
    \l{GNU Lesser General Public License, Version 2.1} (LGPL version 2.1) with
    \l{The Qt Company LGPL Exception version 1.1}, and LGPL version 3.

    Autotests are available under commercial licenses and
    \l{GNU General Public License Version 3, Annotated with The Qt Company GPL Exception 1.0}.

    Examples are available under commercial licenses and \l{BSD}.

    \section2 GNU Lesser General Public License, Version 3

    \quotefile ../LICENSE.LGPLv3

    \section2 GNU General Public License Version 3, Annotated with The Qt Company GPL Exception 1.0

    \quotefile ../LICENSE.GPL3-EXCEPT

    \section2 GNU Lesser General Public License, Version 2.1

    \quotefile ../LICENSE.LGPLv21

    \section2 The Qt Company LGPL Exception version 1.1

    \quotefile ../LGPL_EXCEPTION.txt

    \section1 Third-Party Attibutions

    \QBS contains third-party code, which we gratefully acknowledge:
    \generatelist{groupsbymodule attributions-qbs}
*/
qbs-src-2.6.1/doc/doc.qbs0000644000175100001660000000737614776170045014506 0ustar  runnerdockerimport qbs.File
import qbs.FileInfo
import qbs.Probes

Project {
    references: ["man/man.qbs"]

    Product {
        name: "qbs documentation"
        builtByDefault: false
        type: Qt.core.config.contains("cross_compile") ?
                  ["qbsdoc.qdoc-html-fixed"] : [ "qbsdoc.qdoc-html-fixed", "qch"]

        property string fixedHtmlDir: FileInfo.joinPaths(buildDirectory, "qdoc-html-fixed")
        Depends { name: "Qt.core" }
        Depends { name: "qbsbuildconfig" }
        Depends { name: "qbsversion" }

        Probes.BinaryProbe {
            id: pythonProbe
            names: ["python3", "python"] // on Windows, there's no python3
        }
        property string pythonPath: pythonProbe.found ? pythonProbe.filePath : undefined

        files: [
            "../README.md",
            "../CONTRIBUTING.md",
            "classic.css",
            "external-resources.qdoc",
            "fixnavi.pl",
            "howtos.qdoc",
            "qbs.qdoc",
            "tutorial.qdoc",
            "qbs-online.qdocconf",
            "config/*.qdocconf",
            "config/style/qt5-sidebar.html",
            "appendix/**/*",
            "reference/**/*",
            "templates/**/*",
            "images/**",
            "targets/**",
        ]
        Group {
            name: "main qdocconf file"
            files: "qbs.qdocconf"
            fileTags: "qdocconf-main"
        }
        Group {
            name: "fix-imports script"
            files: ["fix-qmlimports.py"]
            fileTags: ["qbsdoc.fiximports"]
        }

        property string versionTag: qbsversion.version.replace(/\.|-/g, "")
        Qt.core.qdocEnvironment: [
            "QBS_VERSION=" + qbsversion.version,
            "SRCDIR=" + path,
            "QT_INSTALL_DOCS=" + Qt.core.docPath,
            "QBS_VERSION_TAG=" + versionTag
        ]

        Rule {
            inputs: ["qdoc-png"]
            explicitlyDependsOn: ["qbsdoc.fiximports"]
            multiplex: true
            outputFileTags: ["qdoc-html", "qbsdoc.dummy"] // TODO: Hack. Rule injection to the rescue?
            outputArtifacts: [{filePath: "dummy", fileTags: ["qbsdoc.dummy"]}]
            prepare: {
                if (!product.pythonPath)
                    throw "Python executable was not found";
                var scriptPath = explicitlyDependsOn["qbsdoc.fiximports"][0].filePath;
                var htmlDir = FileInfo.path(FileInfo.path(inputs["qdoc-png"][0].filePath));
                var fixCmd = new Command(product.pythonPath, [scriptPath, htmlDir]);
                fixCmd.description = "fixing bogus QML import statements";
                return [fixCmd];
            }
        }

        Rule {
            inputs: ["qdoc-html"]
            Artifact {
                filePath: FileInfo.joinPaths(product.fixedHtmlDir, input.fileName)
                fileTags: ["qbsdoc.qdoc-html-fixed"]
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.silent = true;
                cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); }
                return [cmd];
            }
        }

        Group {
            fileTagsFilter: ["qbsdoc.qdoc-html-fixed"]
            qbs.install: qbsbuildconfig.installHtml
            qbs.installDir: qbsbuildconfig.docInstallDir
            qbs.installSourceBase: product.fixedHtmlDir
        }
        Group {
            fileTagsFilter: ["qdoc-css", "qdoc-png"]
            qbs.install: qbsbuildconfig.installHtml
            qbs.installDir: qbsbuildconfig.docInstallDir
            qbs.installSourceBase: Qt.core.qdocOutputDir
        }
        Group {
            fileTagsFilter: ["qch"]
            qbs.install: qbsbuildconfig.installQch
            qbs.installDir: qbsbuildconfig.docInstallDir
        }
    }
}
qbs-src-2.6.1/doc/codeattributions.qdoc0000644000175100001660000002375314776170045017461 0ustar  runnerdocker/*!

\ingroup attributions-libs
\ingroup attributions-qbs
\page qbs-attribution-ds_store.html attribution
\target ds_store

\title ds_store
\brief MIT License

Manipulate Finder .DS_Store files from Python

Used in the qbs dmg module for building Apple disk images.

The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/ds_store.

\l{https://github.com/al45tair/ds_store}{Project Homepage}, upstream version: 1.1.2


\badcode
Copyright (c) 2014 Alastair Houghton
\endcode

\l{https://spdx.org/licenses/MIT.html}{MIT License}.

\badcode
Copyright (c) 2014 Alastair Houghton

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\endcode
*/

/*!

\ingroup attributions-libs
\ingroup attributions-qbs
\page qbs-attribution-dmgbuild.html attribution
\target dmgbuild

\title dmgbuild
\brief MIT License

macOS command line utility to build disk images

Used in the qbs dmg module for building Apple disk images.

The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/dmgbuild.

\l{https://github.com/al45tair/dmgbuild}{Project Homepage}, upstream version: 1.3.1


\badcode
Copyright (c) 2014 Alastair Houghton
\endcode

\l{https://spdx.org/licenses/MIT.html}{MIT License}.

\badcode
Copyright (c) 2014 Alastair Houghton

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\endcode
*/

/*!

\ingroup attributions-libs
\ingroup attributions-qbs
\page qbs-attribution-mac_alias.html attribution
\target mac_alias

\title mac_alias
\brief MIT License

Generate/parse Mac OS Alias records from Python

Used in the qbs dmg module for building Apple disk images.

The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/mac_alias.

\l{https://github.com/al45tair/mac_alias}{Project Homepage}, upstream version: 2.0.6


\badcode
Copyright (c) 2014 Alastair Houghton
\endcode

\l{https://spdx.org/licenses/MIT.html}{MIT License}.

\badcode
Copyright (c) 2014 Alastair Houghton

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\endcode
*/

/*!

\ingroup attributions-libs
\ingroup attributions-qbs
\page qbs-attribution-biplist.html attribution
\target biplist

\title biplist
\brief BSD 3-clause "New" or "Revised" License

biplist is a library for reading/writing binary plists.

Used in the qbs dmg module for building Apple disk images.

The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/biplist.

\l{https://bitbucket.org/wooster/biplist}{Project Homepage}, upstream version: 1.0.2


\badcode
Copyright (c) 2010, Andrew Wooster
\endcode

\l{https://spdx.org/licenses/BSD-3-Clause.html}{BSD 3-clause "New" or "Revised" License}.

\badcode
Copyright (c) 2010, Andrew Wooster
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of biplist nor the names of its contributors may be
      used to endorse or promote products derived from this software without
      specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\endcode
*/

/*!

\ingroup attributions-libs
\ingroup attributions-qbs
\page qbs-attribution-cppscanner.html attribution
\target cppscanner

\title cppscanner
\brief MIT License

The cpp scanner module is used to parse C/C++ files and to find includes
in them.

The sources can be found in src/plugins/scanner/cpp.

\badcode
Copyright (c) 2008 Roberto Raggi
\endcode

\l{https://spdx.org/licenses/MIT.html}{MIT License}.

\badcode
// Copyright (c) 2008 Roberto Raggi 
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
\endcode
*/

/*!

\ingroup attributions-libs
\ingroup attributions-qbs
\page qbs-attribution-quickjs.html attribution
\target quickjs

\title QuickJS
\brief MIT License

The JavaScript engine used to evaluate all JavaScript code in \QBS project files.

The sources can be found in src/shared/quickjs.

\badcode
Copyright (c) 2017-2021 Fabrice Bellard
Copyright (c) 2017-2021 Charlie Gordon
\endcode

\l{https://spdx.org/licenses/MIT.html}{MIT License}.

\badcode
QuickJS Javascript Engine

Copyright (c) 2017-2021 Fabrice Bellard
Copyright (c) 2017-2021 Charlie Gordon

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\endcode
*/
qbs-src-2.6.1/doc/images/0000755000175100001660000000000014776170045014462 5ustar  runnerdockerqbs-src-2.6.1/doc/images/qbs-settings-gui.png0000644000175100001660000007520414776170045020405 0ustar  runnerdockerPNG


IHDRe?zKIDATx{|eTpw=w^V=pg邲PuPhWV.MkX#(K(
)efY;d4iS(tty<_SYYYii'JJJw
'iBZfTuv\#K+/9ɼYM((׵+MN%_X,[e2(3oqm.P2,˃Z`XJypamg}KdX[)VGI+\q*ϑ_<4pI[>.)S6<vݻa&?cOgn[e*ڼ&Ѱ-;{{kc͕E((ŗ;w]Z|#G),$M>RR(
rgyH
+,Y9hX(uXR,:K*D?
1ҭMÇ
KsFzҏ7_{v%ʟ.:7;|دw~|^Yeܜ:c҆9p
NM>
{ܜ3wVm詪3EKf:qU;s	Lhʙv%l_ojk/es{ly_<B4_8!jǗǗǗEAhC&9gZ^*;vlOUU%mxd{t平Jl7Pӣ	-:+2oRosN{Qeì?UW#Ho3O.?y((riǎ9jciX^,]BmGI=V-
JSox)3VV*?yrOUV<}~GP_Nud;sřy;+N੊J}cl+?;3O[ggޔ|Iɏ9oFϯBmQPxˏo笥'}漗?hYMh/U=u̙>rĈ>KKvƢO<^_>:iVvg((ri֭P%
dϴ*Oo{m?_Uҟ:Uz|xb/x&/Ι*G>3hY/dsO<*m;tm_rVR};_j?u͖Yf*ufLOznwS;]wB4mٲ.3tZTVrPվyX8
-KgۏK39A[B*:.
Jwee'8q۵:r_P6ҲMP/v*ˆ[<$W—/=a3gҥKKҥK	a_~%%%4NѣG$WV+|	\p᪶//"C*TU_+MK,
_W%|P]vt{Mݗ	9zvb3ͬ`*Kr2Ӄ|0(]|tSraC¶M/^ZW*;_}y-̗p5Ͽ~3xЫ;KriW1zp)S:觋|_^2}ϭh>zVk	z/J[ڐv*;=,|]0xa׭<$r
K:̓5aDgli/.}I&_kA_ʵV^mI[Wk
^h4+=֗M)^yiTޱK']=ߗ^wyӔçɛpVn޽o_a;2ZI=`ǞKJN—~_+Myyy2އ5:	}fA]>	{rq}[)ѷ@a~W:&%
"_5+ĩ2(FU+w.|I&_(l~If{!6?-i+xGW|ŗ@uEhX`=տz5?Mؗ?ͮU5I]'
@ӸkZO!W|iXw@ms^u̯||G\lmjVxA_:xj_+M-lH/O=˅$W—K|	_eL$)KƤID<_.XZ|m۶+W|p~]ߗkWG3K_Л|(((8.΋i''N9ٛJ)M~ɳ=BkƧ"Iq}N:M>*/+M7J{X2dfn^&Hs˺qքz''VZYJZe=|ifj2R/;%#4t-_{j˸.Bg9g|&/Eٳdm\Cbd($&s譯9[BH_ϵ>iCO$;\g_XLɾl.:.ZyxHE)Cdlq<iW+MxL$׍$(	5m/s\1z.4Ƴt/Q 'ɡr
,=6ǭlP+]BsH8PvyxPrZr}=|EUTŌ՗Iq]ϡхV6ƗPb!$x?O+c
eGc>ܥ's{? KW"9/eVCh_[_h?w25'XOG0u4_4hX&^
5<8H=Ps1|4,Mǟ12/lmKӊ<֘CXbJ؝/pH՚m4(cpa<2S{C#\V2jFf31@߇RmEQX4$b'cj5$i]YY[cZ/}o1ɜbW=ߗoǗR·_|	%_—KRAw559u7P]*Mwh*k1K2L}
kG\^=ɜ̥6Υ1G(1=1c)f,e[ɉSyIY%\?	d|;+J53I:=龤x.%5_/ܟyD9iܝԖ2e~feg
ox|,0_.dRc$kVב)!iMjĊr%!.
Oߨ/iOnnnI4n@j))45ۍqu]:,;%v>>{ d2su;ZBmʩwSaWQdcUmSDj61n`#o|k8Q/֏_
/J(رdIūl&ɑ;S*8|+|) )}_v8_%_—K|	_/HF&o|	_ƤE,U'g
}ʗl?i{_J%K}&m+-)LӬ_
hI+-
[m`{v,fʎ(a}!45/{V{,t/PRu["_"
7R.~qX)]%IKºSxWSeVQ^iy5/{/eY.((eITV&Huv5ryj4պ#)9%A[l!mE)CHxq}8}Ilp6͍h5x_ۥF_(.1-N*<Yck,ݗ-Ry,GT3՗GsHF-m!5̇N>g68,c/RZ}Ke!Nk\( d9W,/ѿyK7&YsbaRO#-~ɳd*֗Lj̀w9~ŚY'=˾6_$c|L:߃NI}=3XǨglw`J(|	_1bRKvv^Nhs%|	///_N_)˾K}&m+-)Ӭ%e:ɉSyRri6GPU5tNj	fn-u/ywdx_)tF🱌8xBA=j=R傂]L5n,7}\Wcة2z."iq/i9M1"Ki7k^,!/4Ye1ƗPXn4s)V=E/{/iOnnn\|shzX&^
5L	/I4n@jm#^󫂌Z}yK7&Q>YcEy6s5fzweIE)<>yQmEQG
Ū_~>:Ŗ8$PK|	_/K>JZvRQʐ;3v_Kn53`Ȝz-pNqP}?/1i_—W;wq&O^1N%{縛"YF͗tK`wn׈{<;e,Y'wMES
<%wŋZY|)9Vyj(	URJꕮmSz^yȼVkos~6tؗC-r9M 7H[tY1|kQuxo__—CK6tssIN-%/3-z{γd"9]-$'An#xw[R݊VVVtⴾ@;}ݴ5մb[#vZ@tbHg2zio~iitd[DW&!x?9쥎O/Nu2͔-;dcTa>z#-.SlԲLK.oHF})kjuB8gmUTU=4WχX8v]愛]h"S[kkUi =|V~SK{|l+^>I3-jN/ŗ$Ci̻7l]2+,y8ri!@>`;ߗt_R% /-qmseiXK|	_v[|Iͪ-zR)F
=՜TOYQn0̻3̶ݕq@_p&6j)a0שFĻzXYoe
l/%|y}M3Ki5j}g%Y>\Fyj9IϼrM;}=Dw^ɼkhͥ,UV[
|74(sV[z[쯷&mx;~W}Qf=w5,|	|	_/K%|z7NhMBUfDk~`v9]a<nȷ̹]>)$I;+^p*bd&)-?qs.2"RZv
]5
-b:'νz9{K/p-ʜ&\Sl'=5ddKow]S$H^R~ҤRH3b_0u͗})ekWu^~	ki3{w]O9ۉS}Iz=3_4Zѥ~ǵ&K˞)/(CY[T(N,vsoHVw׻k/&MN`;^}p;o]=<+4Q]tE9ټr[_ZAK3Sg8zPniB|5Hٻ|H-%F7 /'m(G }z$WS?9V&Л=upy]_>c2U<;}F_XAI`2 Hu}Mm/M6 y'u2u{ZQUGllSZ+)?rAh2m|&8No:>E>qzXUŊ<j7=vU&	/;<^_lfi;N_&c5EϏ߰smn_]CZyT93cgɘs:|3>/{z{,@A"k9)mLO1JԍZL68!m9k쯶ۓ)WkK-bUQl%_F]Ailh^뗤Nce]ryFQ}I\v\Nkvumc+w&|#4
{Yb2]e+_5 e(ZThܮ#vU"K2}\R$	tKRwcݏG?.͠?_M2sj<_F]AM^sϚ,+}9nKHy㓸RqPۄ(FyKd*[ӘЛu^qWZݟ}KUB.(TsRz̧4ė!mOGR[YiIPt/U1D]F_F]ADjKҚ[[/MmMrTpqڵ6E%cѥN7o{4>ip%t?S3k#mLf;/CZ|>__ʖ3a.'(%]~N}Q.@ODR;mљԏ%RZf=Je?K{q.;Rd(ȲğL}|y3$O	4	>MѪ_Zz2Yv\ZEfe
.0$_qإ^%u^ڻH7n(u-ṭH_j!ّ3C%e!S&VjCMthvA6̕
kˑ͏}PUtBB:W~e
e:';MޑY{ls:>c-;CUhViɒ1c4_;nS_5l-d'hۃ}yjҸVKz;//mc=D8BD%eG$QS_b͢~Zw>qڭI|0
5?tyBu:):/m"aKzwqUJy	/裍2"@K|	_/KKe'׊x/;%|ٗ|e˖Ѡe8m=RDȒjmp,sG{R
؜w&.龤x6QHr:2
ZS/|6ăe?̇H=Zp5Ɨzp/\kP)kໆ.oN}>aP.CJ<>{7/Z6_d8g
0 NhӞ92dW.*yȎPγieI?Ҁ \l0RÇX/CȢ(R]/[ I_ڮ-+ߕ}?K2R=[/K73DAAAAA/QPPPPPKNص
/ŒKܗ_Xs>]^Bj
V*^Zag_LٗVQ[;kߜ卵U)/w	֬^E]Y'v}~5VgrղG'}d}FՏD/{]٫LQ/GجO
ųxՌz{&|
}(-~bV"ɕPBX[_|:o(tn|x"J?Nsk/_!dB^hj?D/{]ɫ_n#/7T2J_C
*cyj'@*_s>">۟~?lKk-ע.ȇ^kA/oIkj
XY_$Onn ׹`|T;_mm?|d%K}Q}rmjwjkƧԅ@qE|jn	[Կym}]f=2_%{<|\dExve/}dB8_'yr˙sGvԽ>CGO
cݫ3R _0_Ȭȵ
o{ٿ_A2_^Oi<
>T<їc?W>8^U)#Ȋ*:'W[V\zRQc`mңvr`'߾[B_O>A&lޡ+U}ὒ&ZZ'G^޼S[{
ōb*C}}oF]EעY_+OK#=-ol\q
Y
\4=e9ec[GtпS3>;ŷ/9jjs=_͝RquG_uQ;7\Cާ&%//ĺWy꿝[uɭ{&s=0_|=7~YmP=~cko46GgO{5^yTX,<%E-_DXP6>^{t}-nl|ڽYS7D뿬t6\9NA9,6g~VCx@aeu(F]Z:QPK֠*t_}@(_^<`1?{Cu}ޥgx#|\aoh	W~5/#}IƘ鑹߰Ttɻf
)mWJiƗ,fCЗ_ڜ5"f/F9baTmK/=kro{4ajKգ3beYM$57_n >9:^:s0}||MU_V:[B
}bܗK%}7G3*2Dg]uϞPSpK}EmgO?>UJgKR&2ΣW	7Je{U,`_[S|_}bv5'>j7֡)$i"햍'4HgZn\eDcߓD7[}ko5ET갑8quQ|oަ=vcq,TPR]`{۩|1f{
qY碘uFՓ3:YUSҳHǭ+hT]y3v\[ϻvO/~)Vh[새lˆU;v;SUFcʼCy>%;Q~x)NjET[ѧR~rzb a̋6y5=WOb;_ҫ}pb?v+邻pvb!?ZPQK3_|	|	|	_/-_nٲe~4o62 ,%P}62L	/+zwy-ν!t|5JK04A	=N:—TV-t0xyڽ%t 8 /'mz.4|["_xMe@%-SM[<7F9wЅKO!egqewe/qKN#9w`\6{Icݏ[J;^|[Dz?	r)dti!cc6/_	~/Ac|)>ϗ4'777a>M'|e_6i9~dkiyE>g68,c/RZ}gvJY?$*#
`٬(jLlb^q;6[3-+:<KKK|	_/Kwޗl?i;&g_`A,&IJK064A9E*8go<ۣN|kc#|I5n4L{Bw}
oJM7bUF🱌H//{/eY.((eITVrc:Lwa^q5*#炱,|ٛp$oDTdoּXB^s"l|,0w1Z?q
aΓQax),#$Bs{? KMUAF__<ߥGHl|x1S⊢'v|c%_—|	}해!wf쾎N+k>g9's
ZN<~|	_^%'scx6s{a::7卢ޣ&[襞UOcE+SKy0x|!,$t/wǿM&bJq7Ep)/^y+<ݮ٥-r"*%|Byv0̥YPOQ2L	yKl]RrZ3aո7P+]5Vӧ)LN?Vy*;lR/ZrڛA69o=<7Hﳚbײ׻"/Pm|//=F[J_.YgjA??Z&-1gDrRZ/[
dINFZu[	/hy(i}wi+j$%i"r_G(='S'
ץ计Ődd)[2vȸ5ǨL|FiA%LfmZ|y|f;!#bK|	_^GfӍsTzkN| }Qu	I_oMxnwVӬVo4IO/nlPxs[4͗!Mĺ3=%/7$^2T+ԡ:kuvm
齡B_)N/{4'"]~~Cg}.|w^&x/+{;jY//_—K'nК҅ɛIu+҉)p.p-rx5rwݐos|RH"w}7VtUz)LR8)[/:O\.eZE|31496kZRuNU{$s?
1~y_Z9iM(!Nzj.KM65?H\oν>2.̥Ig0)1a/=RR?==<2$;4f.7sryT3{$gh:KWkMR=S+^dQ569Y̓ɳ='P2էY|Yސz}Ow0_RMFa!wB3vX`z yW*i)j>PsJyk嶾̗fp҄ry4]ėWl,+~׆ԄywvrgCiփ=ɝQKjCקՃw֜:rKJ9NP7;i+JO?);gqlb˅//{:X_<'2x^ITiHӝ{0}@k>w7{y>G[J	r[ojA^O^QҏpAI$*s,	MK7{D5t9|Ʋ/exvd@eY<I^l@"N8e|٦$VR~Jti%$%dwM/pN5=Kv[u:}b}ֱy nzznGL^vx>UͲӰwLjal~ɳݾkrfB
1txf|,_XEE.W#rR9cd&8FmpB8sJ_m۷'S:Z-!ddK8м/I4a09pv1	c ;ڶ.WLF(i>'L	e]WzkA6YkQ`;67}R]uG%|Ee2zx;j-4x52&YVr@}%%%=k<5'q8Y8	ACQ΍SK2—U174S?72e/ŗJ>ԅ>O)\P|h#Oyi/iC
~e𥶲.:0}-^cZ2З5^ښb㈽kmKFKn>y'f9[}i}rKU~rf2לGژpW#w^2'}3-{g\NP2K\,۳bvM3Kz"u=4x~P\wtE%6ȼQe?x[*|IgHd-h|:UfdKƵHZ]`HPGK3޽KNTwn@Q<[^љG:/CZ%=3#g#K>BЧaMԆf2Fl+#9|2脬tp6tNvK#3js2u|ZvKІx%chlwܦjm#&[>N5<Ѿ=2qiW#w^2_4z2pB1}K^,IjuŨExOW}[}ajl//ttWSu^D<=Fr_GdD%_—|	|z7N0|	_vK%)/r˖-AWpze ,%P}6$Y4&9QL\x^xڎ-/'5/-xMtNbCPB]k/'#ޞW{vѴ-%~s6ڠ$ABXde,,iYc2"S9fk97kYG\sYE/Q׀}8}Il2̝4tdz)Aѧ\_l=6?7>
yr
zh1k/3^H)-֠R֔w
]ߜ||I|rssà\y|n^#l/ɢqGa@;Ѧ=seȸ5Ce%]Z?U)gIۓf`
A~5lJ`Z2e_~+EQHٻ_AԿ][W/+se4z"_—K//twژsIF&oUu4WWBfs_VO?qZ3ZNv=e:Tc6e_gbÀ;?bb#-bi<νzM?7:dL~+<-Yϻy0x|!,oەt+~
|G}j|ЗKO._Cȗ{縻ɗcGdȥO޻Pdwy	=\"HCJ&u:y0yGHa>Ͳ_l:6=]|I54wB3vX`z yW*5S
Dua|"}m'nFJV_6ج4w[[JOfP1
։S-^-L4]ɂ-%F_9 /'mz.HL5@vp5uSCoeQ\(
fO(\^#MLTe9U|Y[׌'KYYAE87ȗM߿\@oq{57쭿-u/ywgpY<'EjQl7jK6B{pux<}Iu1ؖfjjc#-&#u^pW|	@/B؋l+w|Sl|,65s+[k<[4'lo*Vffv=g˞KFͳM4!Ks"z{U,T|eapi%~ڽK)H_ϵ>Xx1
[RJ1.ueUb_'Z\əi<|tJKh	)uyxPr	=͗[lx3gQR5R,*4X,tMm~M/{/-[VUUTn3qj(YҾRI՗˩֣2]c_X̻nlՒ5'5dޞZHwtv^jp|xg,TfuC~RNs.ukNQۦa$KSr(֤J̵Lc$j2֜C	e'je6z	/K%|	|	|	_/r['~JF&oX|9q'|є_EL,MK=x{Ѯۍ4kIQ_JRR45?IAAqqnUOEefLİ:MyG`-gk!/HO^^g{'Q+SbO.[̣j	p+O-CYٴ+]5m}z22ws}LOop?Я~i-/f^[/_q76
bF{
>BU%i"w(^8mU*=_IƢJ\7{|{y+$#}->׆Lr~r?:N=)jjQ^;vc}I+(ssuLP׋O/ +-zFL/S#G,zcZ*d9؊Ι?f^8	A=V9WR<5Ʀ?
v7-Y_y)齕(\fr/=|pW:f=$ucs9wS/ ۑihQWkiR=)ZZ,IfӍ3p|xg,TRhTTe'_5US.ud>{b|)ۧ	3<M,ONV$_NHEYɤzaWA×L7V߲?H|Si3_[#RNsRlh,ReGkHNt3-lIӧlZڕPl=I6
,.KI19RQ]7J\WOC?4~MW{3/-]s3,5Ҳ"36ZMu™ܴ.evxm}E͗ݴr9%_2nm4ļ%
k^2&a/rWe븁9NFq[bOWXHߜ-p~/\(HhGWRk
H^	bϞVTL-:~U1N_sz/ie.xN7`y#g(Aŧy\v%tsZ%vtJE	5*WA|HqhK4i;i	ӥKȶ|~I{isWaSBrhj\ʅ0,ۓ:,P/eXx1@>ǥ3a.*,TrdR9kEy)s$On-Uds6/YFH$9A%87Б)s;w,˨jyKԷV|];75_peuY&Kq/4ID_Y4KP664fXc"?&G	ȟdgmW
c/eKj쳔f#*<${&j}/cZ1=/sZ&N*%kD
EφcSqС/!/eKƲsTǩG1(}QRj;?UBe/͗˖-"&$rgB8:S|YiC4JM/S#)p-`eлXj,G[9L$Np
ʙG>|hlA\tc{"PY.XS3y	]e8})d!Ǧvh2>_Çwu|cCR76jɚ
i`ly7R1*]~N.@O
bI޸љyIrR>GmwrH*pt4_*˲l*Xpz:KTaOM
SneM!S,ɗi,kr}2)^U%Mշԧ)4/Cƭ⾄EVRXfwL\jM$R7j,7/.59P,Ƌ<"Ez[,5ṽ륫M*15j{]0s-Ә/(ͧ~	5b|Wn;M$cO9F~Ex+m#؝$ۛT%AܯFdoXy᡿l~]B_z_./߱~t8~^6_w
Sɂ )zIHmS7;$;G_5z	WK_bxpϻ"zwcŪ_%_—K|	_/A:*]޽V0-
/;&^[-v/&IM/uՓkdxYikGH'[ԩ/YȦoCgw#b</$ŹUc>͢&
5=fJ,VfIp<kl+LURB$4:!2;eXxעQPn1fM.SPVj6-JWM(v}[_$fb(.\%. \f׻Bj):?ԑSvIrU5	f+L[KGF_]RnfPJxQm[΁f.M9K_v/q76
bƒ^5/HEjQl7|QVS-d,eojV8?IHuGZ|
d,gю:N=*!ZtNKZAg
dH9yJzi'_1ݜV|RzQBM!Q%ɢ{%ښJ'ݞϳ('vy.Z}piӏd3§Pfub}̟yIH{{VH}7LKbt3RոQw&UR@6j]NwVj%[dE0yFI[KVi
sҒsÃKr^(9s;w,˨I?׷V|];75_1Gu)$fA:~8׺vWr!(kS_2i{ۤ%UM_=Wz¿X|y|٥^5YJ^IOSHH^ۤQ*(_t`\0AˈŐhKװ<>GX!1$hkv%k^̗jk#:Ė_в$=v|/Iwe_zJqc4&¤,WK&R`C|٭\lYUUUM5!;櫧J%)|W)L/S#G,?c}C
Y*s揙?H9weOp
ʙڇLlFE'16q=INK#|Ш^͗M	N͗9D
]Jk-4}iiM".L[q$_v/i|Ç:>"j	lՒ5'@>nt<ӂz{S췉$NJq<:s;/Z_稍w|nAB%uN	,;Rqŗr$Kp)V25cޞ0í)J-vBӣnwHi)?#YZEjd-eΣtc/_!Cve,[29AioUVuK|RNslh,R2g-&`~YDQRhFT%9#٧PY\>EQ~BGtw~sWE$_%_—K|	_/A:*];_es]n;eZtocNc_Ҷ`rqa^źQwrtgҗq'DBh|M@R^=ɜ₩Ih=SfZL:3;3eT4GTA
ѼNN9L4;RFdZyPꚈKdI>H/{GH'[ԩ/Y⭦oCgwØϫhcp7۴W$G
嶪kZj4y:So'>5?IAAqqnUOIB}4[i21Ng>fS&*)eiFbeԄh
)ÌFG(G&eo{(+5v&/[OrTz_Vf9RQ4v
RsJywׅ	GlSGNa˱WոWk'0ynyS6&N;ϡ^>/۶ƽE~ڥ)x)U̠5Mpd)VXSNY'ت`KII9<|n6SfkQmuzʶ=vG-/nm4ļ}Ά5/HEjQl7|QVS-d,&.&^?_VRsk9^6(٘E;H^	bϞVTL-:~cE7VPq7Jzi'_OKB,Lɱ㨒deEnmMBnO~YRۓf<]E|LBi%$3b}̟yI͑B{{VHx}7M_D:YY޴?jXB5Ti?7`LnŝObN엢4yI+]o(zV,y#$/^L=S,%QKExUe9
Z]'ZjpGO#dٯs6/YKhXŢW3
@Fry8,ܱ3[S%Q[Eg>~/ZmmgYϒ`Y,YD|^IK	y@Y3xAH
LY5)1sp$IÔB	87NI{BVN&ྩpܝjR4>r302o	3\$B%Xg{&]bm#Rz,)Y$֩TVJ*\0A=g-%&D[9Jc"eGWַRp˶Dg'֚/Z%e!}\Mn]2qȸ5n)ѿFW	ӊ)S5[m*V죄ڮ7qҜoSCRΜ1@WrٲeUUUo"_6Մ[LdB$}P|\ktr9kG',?c}C
Y*s揙?H9weOp
ʙڇLlFE'16q=u^څ|1
/]s%
VE+Y\Zy~&8OK缟p_"ݯF>[#+wI9iuӋz3s~1c-e߁̝=|pWRdC-͡ZNϼZ䜾HyJ+ZpTo~6ICNFgn%9?BK-!Y	~8>KƵ"!6~ʥ,.ަX_Ԍy{bC.+$4	IV,^CrfOCH2_.R;$k(uS2_?HClj+%jR8oUVu:%Wbg|&9];O7ڹLd]]A-FGRš*AU$=4ˇDї]jթs.@
xaEz[,5ṽ*Mt(v%kcCr-}'rx<9㣵BDV<{Ir9kjMQYޖ>BoݩMb౽~2΍z:)}(sEKI9nQ|il՗9U 1/G[jY65ҙQ~+ER׆	&Xzwbm'{_혯׏qihm:vDi>H/1OH=T*Je'J}Q6T*KÛ˝w_0O5/Qhsn=w;6Yy?Ϸ?!ٙȗ,k+C	~Z@_—={<=Z:ڰ^_$_%_—K|	_/ 3+XI^+i|=ĝ:Bv1_4[G:<S?/6ѣG:l7.յ'1KFAAqqnUOIB}4[i21NgӇ>fS&*)+ciFbeԄh
)ÌFŻEѻb=ZKS\V$2ײzv.PR'uN6SF?WsJr{>2&۸ACXp%LEjQl7UմTYJKA4^?R󓄔_wxڠdcv~zs+=2(/vi1X}LfQWWKk{YG[JBZg,rkNbL+|[9*^͂_a_/vaXJ,ƥR@N6j]NwVj%I='O78gջDӑ9J^.Q,yu8їHlQ~uQccL+jyU8s1>"K(JT*T͈J}|#g&qvԓ~Ee=21eNj_—K|	_/K˞C:KRܙ5W
OQ\\mnvekHw;.y_vq'/Zr{a#	$-1xddL{4iӤEn{Ѯۍ4{珕`%?CJ³mUĴfi6RMJ,_v/ŹUc>9VgdmYiT%u:C1<&o+LURNҌT?u7Zo+S'-AzW8Imn>pmfSѮtհhQkY=Mu]R(fֻf|trG'|UZ>E䰾} yWR[S#|P*)&f/wߧjjɤݢ>h%:+rZg1^&~"B+ǥ=uF[JBZg,_VI~E8:Q%ɢ{%7K@McR'
ץ3
',I~΁)fpӯv8'i֯tޥE/)QY	_^/_/vaXJ]hRGݙ0Wn~SPu9uZ%lyOƌW
,d.&D9A%E9WҞ_\쨔ZdP'ݯ4E3R~fw).]G=`(QflEm&f
]g=*:-'d+l#qŐnS
'vSpu;`w-TJf˖/e{g=gM>)p7ujDe8U?4W?LPdqC-e^3AաK5?qyv/R1(L =%i+Cm/h:?ZJQ;=m_&kM)(j=d;~ҷeetQ<e˪߰EHm	Iܙa*axgȵHIM-LEԤ>ZE0ƗweZ8r@Gl{\R/狎z2+Hpjte6ۢI$j9C/'Ɨjc>n%=|pW:f=$ucs9Az#gMN_@IWd,$qGUNǗXrєz0@$[#_-O(RV"(;Q&qRRW֎z2ѯH Qg	~?"H|c;{<%|a_%_—K虾DAAAAA{{|}G((((((}ɗ
(((((}ɗL2QPPPPpdٱ,%KKKKD&˿ 6/ϟ@lȕ// 6a_V 6a_^@l¾<؄}Y	(\`AbCT|y		
(\pqĆ\&FE
Ҕw!W,Yb?@4ȒJSAAu>@4ȒJӚ5k/_y=h,I4_~ʕ˖-[jw`.r"dI$W6mdҥK-˻;[YYYs̙5k֛ooddd̜9^{W_yӧO6-==}ʔ)/^z_|T&OlVyS6Qar
هi|DV"7Sd+rE#kd7r|G#ɃdCr"H$WXӆo~IENDB`qbs-src-2.6.1/doc/images/qbs-build-process.png0000644000175100001660000001232714776170045020533 0ustar  runnerdockerPNG


IHDRI8H>t PLTEPpQRVX[accf f!g&k(l0q6u8w:P:p::P:p::ˏ:ˬ:::@|HǂPɇX̍`ΒeϖfPfpfPfpfˏfجfffhјnқpӝx֣ק٫ڭܲPpˏȐ߸ὧïȶPp؏嬶ȶοp؏$ɱrIDATx{8EwˮYvz$l̴dCdfHH;d6Bb/\,K::8G(MZ::t$Bvq8箙ĀgP*ͦi6s~IU[:%ynAֹsV\z^JIVwUN'mmmRI2n6$ɰWDHI"I$$$DHI"I$F뎖i|Tʷ_,IQEF]tfG2z1wOr1;SsWsyP;|&@9Oج|`Cer>nr ;.rUg2L'x/WoDr.7:~#0}'f$ɫw$7gy@͑NL?@$o˕$ˈЉQ˨v/'?,_hq|4Dr=c/l^IYμsgyف]^,xA\"yÿ@<;o_p
_;NT,/D$ITwE$$$DHI"I$$$D7>I5)Jj:$(q:IzvnN=xi
1@m6hٯ:vH0߃1f{\d)w8pSN2}$$DIJ$$$H:"IZ$$uDIRG$$$HV"I$$$DIJ$ֿDRAŭM'$:ԪIvJ~iWOAny~O$F`!Ъ]l>D$WxUiQ\0DryWC=mΉʴy]L"*uWמ6\VUI5\^kKW,䒖$+N#[%ލ{aqJ<'ժ&l"9k<.9m"vVJ}[ ɖ|.h{}%Kv۽Mn*1ɮʒĻ5)A
#fN}wNUXG}=^ L{hgےn
X|IAT=!V>(D$!>ぇ$P7֭EMd!	:+w iA]	u!i+<X/Iၯg|R~ڭt7فMIa	Ʌ2`KxH{$4,'	'&!dIXGm6:>/띌x.	& "bFqޔ?OVxa|(m	HN_4ߔMIH&*A2c/?)K@SՓt	5G|LmB<դv$I#jJVyESuɄđ$ I"DK۝,8v;H„Di'UGtqD{FI(8Z'
G.`$1R$qLE/lH$q~&nHbs``FIi$ܔ[cODC
%	I7hHbm$uFN0OR_$&1-Zר4|J%dI$$UO50
ISϻHb卭9(P&jBtL")6Ǵ΍5)#)^k4p@sc$"\7
E/uf,Ăbq $c!Y
3xukcZce\aiI$Dh"8K-ʻ$[-$oOx1)eboq֭r5"NC:'bgH\DR$$DHI"I$$$DHI"I$$$DH)ɦTaM$s9:$ݵJ%"I$$$DHI"I$$$DHI"I$$$D2w#9=tvIVFS{<@oj*dvMv^~r(zגQEVQ#'q$a(d@Huےn8Qɬo"`Hb1Fs/b֟$c$'E.$DHI"I$1T#m|T&T&M]̟̊\UیnٙW>YHMqOsZO|HWoE]&ۚwr㓜w$!&9qvI~DCҫ$Iw:DR夁^'^D@2t4u3OCqn>Ir/1OPh'3}
a&i"=c/E/h|3_1|Z-Pm4,Hdݡ9˨v8K ={g> |wdƽ}yoc%׏$־ "I$$$DHI"I$Zx$­{Hr^YFM^D?xw-OY,(dyX12

t(i,(^![C#1FKZ^q&\{	1ZCԷ2ț9(몡0FX1JZ}^5߈$$DHI"I$$$DHI"I$$$DHI"I$$$D2}$#F$+5E>í_ʷёT/Mgf9Y-e2S(Hj+ݬ7~mBAR4M-od(H꒦%bPZIꓦÅ\*+6IꔦÅ
U-@Zq!{@)1\
)ᕦ45sT$KSYKN*vAIBHS-ݰ8 TXՠkݰlN@Ltj%z: u[	`/$4.Ldh+Wk#	+
ȅÃN5B*^ip.&ZyU=8WZrr_BmgiIS:42>$1َV~/IҠ$Y@W{vhեH&cm5ѯ^iPbxa0ᕆ	2ҐUqfԅ/s+
Sȭ$I4byRƀ#^i1dtۛᕶ((IH9tHKOpH1qi\*%#}~Ț鐖\_t&ӽG>E+lU_#.|ϗWs3;7JӮo#?m~t9;|+`t/߶v|y)b߃BąԬaL!?-$9qR~S{p,[]Υl=SJ7C'|iG$.~}KKק<;LP>.m$̔fJkSM		 4N;&-U`bryg'˰$q#or~C)^Ż/z&m IB[^&v88{4ĥi빪?KҲakBiJŴ5
c
)'.6&yQrL4y}b^/W<ݪ4VU}ݮ0ԵyJ}ף>TWZ_&$ϖ51҄};?^i(H]c4#G'Jw.hZ%JK\?[9JK\jZ JC\^ihx~+
s981Ҥ˺2 n+MʿR&0<0(9W
`x;RaEaB4I"L4%e§09	,J";JS[dm++͐sOcxq.i4e+Ocxv.WH0T=yr4坽˲}4
i8+MKZ2
`ᕦɹV2JӕnVP3GᕦϹ\Ajhᕦ1͆i4RJ\*^iڝUrQ:8ptK'.$D2y;&*%YlI5iI"I$$LI
}&V.$&oI5)%DHJ9(HI"I$$4L{Xt1':΁Ӓczl$~{ԠRY^Bg4^6*Ƞ-JIkAom<䚙'9{Ǻ\.>(&Y7{R62,wlId:69^d vQw37ɕ!y9i`p9sɧ4CArRAAz<5y=jp,o=dQruspoɃ3תoKEYM7$'wV%nw?`-_t܆ԗ[fIENDB`qbs-src-2.6.1/doc/images/qbs-dmg.png0000644000175100001660000012065214776170045016530 0ustar  runnerdockerPNG


IHDRf
PLTE~֊}Ԉt~r|mwluvǀoyxɂq{pzСjs=jC~Չ}Ԉ֊׋|Ӈ،ٍ{҆ڎ|ӈzхՊ׋֋|҇فٌڏ֋؍ܱߐIYŁۍy҄Ľ°܎l܏vς}ޏǪowЃɇzЅ״{ևzyԅFWr@SuͻN^yHY|Ĺ}׈ڗ4Ka鮱z΋weq|ԂrƝP\Wnۺ~օt֖{f[̤Ӿqzku؈̷ٯh~ihi{|ݡ)EuҖó{r̸Яsqsovgc_Eִ]{}soTWlm^a_?6@vmwѷ~Ў=}LZ^[LMTJm񗜦-ѧh}yꉵqtfALSM2"J`hܖmTNŧ|yz|œ|…*Оoyn[h+E4 7Q䳴Ǹɹ~[kKB_M5ꛛ싊t},Oaϴ؝Ö{yjrWWtRNS"e5ƴgNIDATx1P{ł<%=[劷C2fsPJeȤdx%P(R-[&\?~p0Y[~vӜ]e6=PK*+&">GNV>#oC!3oܾnDS+0\BO@hT0ҭ7ƾ@XZ<&%g'9"͇b)?t|p#GU.TŵN3F25^h:x?0]/|?wl
|5jEJskd};OWuӦrY7ߤ[:_-Rp׉J"z~Qwxy||34?^YSҮ!tV~:dmvuhWz0N
t%k^Y,#jg诇OwԦ!StBj+=U>z!xDBf|ij%2e,+bPꩁLc9B8JQl-M9%ks^y`"'K%ҥKQ&Hu,cLgƩرrģ1XfpWg,N'rP0E)Yb%ȣa
\s$K^nz-읃u*EUQ.׶53bD.)=#-mEm^lV]P'u)NtLx~nf{&y3E8khERAqXL]PP4"@,PB4F@C}#%u%'q;ertsNlA0a7ȱ+,˪LP౿<~?+]A1~ƥp9
WŬT#}@{?/]<78Jf/qq#R
FE c`"ccX2)/L
el TQ`=M:+j_+YA-0zWڝz#w4i'aCimݶ%:O\A{	koP5kO35S
XsIU%،D}U_fi޼8(2[ӋҲUg栙pP5]s@\}RtĞ
IW[
Wa-E
ϳ\Q_Eu4Ex@Ĥw֞Qᴓv	=5ļR<|sӊXE\&Hj4DVе
jBZ(Pfa@mڠJt!UI˓f*=Y&EE$sO꒔Ǡ\Im
AxVd\+* -rT 
je|Un,mfn&"{x=JHAsZIGw -V+sR'm|N>P41XGSS=WaZ
A\ZZ3IB{AUXI
|{*Swdk-Z3V+>xq:-jxM9N/ӘΤش
&jn{[Isl/|
T*G͞ڔRA
*Ь0go^+MGsZA	g|5Vϫp?6^I@,[XTϦJ3?}PפBv\uҙ罒A.A4d<ӏy+m7&W*!Ve#d.P
7ң*_KW{e{D3Q,U
'Mjr~kWPQuWunߙwj;Uno6',o=H
yd~P
EX"N	)YZ\q%H,;x]$&gsɣ
\~暎\Ig[V0Z$2o+t@c3-IU{47IjEGoIaث@H1Nob6i6\'J8r-I2Hґ`
N*{[f

iqT`emT0}[,(%~Yt~/-It@EQHob(sA jR+I+JsvTHÎYǰPvz:{.*X/,\Y]*rv v2{;Qr"$hT2)PP
T3&9-d/;Rh6Kna/:*8*8=*
в
NgЫ1U+g
pOz|Uy㮥un&&)jp(Wېz9٩Ô,VaAf/_S/Ux34Net&e
nuB8'8mNՆ?&bO+X2Izҙ+iV֝v^:*9+Y",̽K2N/Uұ1):L
C%g:(AcիwJ$AU+!ҩJQ.&E'\fcPZk:tŊT
pE虞I|{8A|`H	FFQ3$QR%P2BwA?YR(X~;w
(LbǸ*E)힋Ġ;T/
oWwJ=U
="W%}iu*̅\|M73ي|TRxy|Ԯ'I9+EtZ(AҖ-;\wz)D+xE>s衂A{{E
8cX׹
^F_.oԹtk;:?t@<;Lj,-RPU:];4lʐ>A]jAqk$	ʥӹChۯNI+ۚ{#ۯ	EhϥA׹b%*@RCw4S*?$}P
nV>oey"–`x;H,"
!9K2a&8U_T@	y- 4p5W(Z9BhZiy/FZ֊~-bo4U@cQ?(ǓQl'jYhZv2irtxxF꧂W:JG^@)Oo|e0W4h1_VƶfKȊv4>(4nɉ6yG^P^KD
(Y
e6dW=u
&9Q^>j@(r
!I)PDV,O+;
R|#wuR*޸rt4=S/x(9{̥
`WOyEX(7FT[	E
pi@M(#j(6Zptr|'@=	-35VhϋhNRS`'DRe]
GQ~Q`qW2χ*?ߛqFKwS8F3-kɗB4;QQBop׎T2*ر7L2UHPťDژlMXW+ܿWаt(7/*Wh_n9H+쏩6.,BsvwgϢ h~x!P[֎֒4TTƮVeY&:ToT#!XyDHO`x8kSy
P:P^
fKDbӇ1wBnۛ`Tw@	HW$~j(~_#ځDhw

hbX):P@BBsyJI^pM;7Bhԁ*
4m-r浖Pճ+Oˡ ]
T[-lAA
_;ZזT,XܿvEg4[>kDdr@
u@UMPy]{ŀ&QJ47vY=^Pƈڲ0J4]
B
̻,
t*}U0襀?ĩIw~Y32ۘ%4YjOA0J1q5q͉fbLXxn(1Ѿf~JGJeμP++/FC,jgj0ňYi͉f
%nb	6ġL4mQd?<W;NlbN6.t`)h
L
V"}`ڥ_
蕗3/+w~VuoeRWwxR%(f^h5)@Gj>8QD/h@QjMGePIh",y{6EDKyNt1owmWyuJ{&4ݖ
Z(XTPy̻ե`T^Y̟P,TT~OW/eݨ4K:#Dz\=ܗ%RIhи?
O"'>Us;ZvMJ4Q'Ӕ.Q
1DC6,%.b9}c:Pp5	|*0%Bڀf`='Z1MR<#AzLnMA9wS
FԀj7hegk"GcGێމ	hD2PPD-h<(п/QM_b:*
=v(`rez;=o=$TPAPƥ~`bX&=SXp9{jz1e
p¸"S8z>#$H9T1ڈjrW#ET7$źע1v˹ڛMARKoÉf*-``<;OD_5LCG^ˆRs[2:rZr/eXptu:{>@pDp9^Rl#/:SP`
c/BDOgW`iW_
W`P;{@G;naᯡlJYHgu-1 ,:p4pT]$u\*Rvt]},+ИjB3'2ʋp>D0f&SAfӐ5m+/-}*]|*mVtli_)QI򁎾P/rA);Ye_ɟ;
ðRX3"85xlq/j]f5Ud@h[xhzw@k@HkiUT+*%VU5dgnW})-3"=E5VDp\hu9T#EPF`:)j22kQҤG-bih|u_bѦJIo(JSZP\cO#*+n:@7-}oգ'I
h&Z
oM}^(:
tⷠM
&_x+Н&eiUG<ɢ/d#-[#8=)Ȳ$P'•)o'P/U7CM!7G
9PӢ@U_ub$b6h	]y3V{:j>T4Ѕ,)Q'u4z83k"Di(ǤkEwjZx5Dc_
-*w49@a@i}}@:鋎bFF80ܼI8REQu4
QstsKٙeKM_"ҍ!q15PQShb#tGw8t4Ժ1|Cy/G@c".hEM-"wk`Z|:F6s mCIT¬Ձ1!uл.c6&in7[<.)jFt/K3U+!)2"bUt~8#GR^Dn9¬a4kxEŪCC!+D&Tsz7f-
ŚS2PZR.B
Ȫ@Ҏg*H׽@uERH1=7# jŋd[~oƐ(Ua̱%2_.8b?{
c>b

Yp4[)4 #.5e,4ctլejZ,CY#iC²GDt#:1Gғ@4$"h~{Rjը-\@o
$uWpA.c
gY)@{Y{"a	˨YisC2!CwtS.opc?J!\wCkž}3t(>Um7*xt>]wm<5W0tVrqdf)Ϊ;kw]FaUDD_Cb(xCPG;!,!2Pi1
>My#snx8j`\"6Utm˪zWb

/:Y>1Qhڍ!@mBCr!.#N<1$կ߀z$Jv?eAu!M׆mX*K@zUp
xTܯHVfQ]tbiQ]b_oeGj֠nЀ(CqA#MU
.I_!myd[7)(KHp
xS18!cH
Xdui
rQC
V#a~z2bI7ki}C
`q4Qຌ,B&Cͬܪխ򊾬_C)

	(sehBzVkrX}S7(
BfUxPP
DcH]\akp`e(RReD!.6(.#^"ƐƐzC"	5ILf
+fvjCEs(ܑ+
cH
=.(* Cg 'jYr3WH0
iY*xyC\!sH셷L.5u*p5]uۘ*wcaK(J@%McY0/eEȕ@1}uT	Ъ*P]*#<"WٮGKH>ϟR1{Du2\ݬA݁h\č!}Fp]]?!tXC
TOtE
$-PE^	].tʆrVG3A1m)
\"iT`(!
ah4Tb915* ը6ܷݠ{5n(73ײ	p& WcX7_n:t-.CuEf}
b蔋Td4>	Q<4SE)ȕ3Q'
v
"r
v09K
짜Ɛ.)ȵ^4+xyKOCd2l,h5medۘʍ"4Q+dC
;4	4 \uD
h(Ɛ*Tw%WDr @{6Q4U..M?UPZ*KeT`(}ς+:OP̬!k\٦1&1P)%Vr(oq3Ж_-WbG.m=PM"riU0*01f
[[w)ͬ!OcC2Pzب;Dm)mlŮv4FGYO(_Ҥt)vCNc7T].Ɛ9WV
i<:+І@=
H&AKm[R	eTj1t1!+!IjT._0baCT:j+W:2iJ@ˮzC!wMg(jB\zW
$TАV*dWJBƐmc,1DcH7k@"ӬuCe(5 rOvyXGTgtHr~@l(EGw{p1ء#8rK=Wfw(VAYmDE`y1qL]7kġ5S_ksf)pJeY:ʎCZ)SQ0hwgqӼO4qc1D
Ȩm@Մb2M(>4 eVF(7Z@z:!4%ï2!.o)NelT2!D4Qe.S/ޯ&rcHf}(F
.	h7T	P<!r*xƐh5M12B\Vp
G@1$Կr8+aEE~7<ٵW]FeC67&7E1D
TrAЋYÖe5;+4j RCsCUWb,!M@Hf8
rh覣?az\!1$Jե*UI]QeI%"8B@CJW]^u2Q4!JIBƐM
=-S

·+ 
jswezO꺌:!ѦSlt> jM>_6Tr
W
e"[j)7找5bx5\j16tCb0\+\#6bЀhjcIKb9sF4P~mhIQ`qcYZ+mܬWKkIm9tju4VE
tp0?4PޥjJ2d*P}p,~v1TG	&~CKi	#@aT`;DCQFAR-5CC|m!Tr"g.
i5ڼ5-*zѼC<PX 
]!Ɛu;r5..=}v	ƐQAxwVa싏aQ51+n	.üӬ1!Ddpr@sCuPcnyv2voƐ]6%w4D1VcHRDVcHCD\JS-c.w
ʔ̶C.tƐ/ƐVpcDCYCCehep}s1`Lh6;nQFg6&
"ck#Ocȁȷ!0dlzр$%7ștVWPШ!E=s=9etT`6v[+H͍!CA4ƉgrWcCڷ'
mU\h]bKz59ɤwƐ&CƐ|C,J5b9+x.TB
Y!W
1di+rb8*хLŇUta)Sah>Qh۹)iQDi5*6D7G!(̰9*-DGk
2rݗ
|
)@w^!y
^re])_S0]b,.Ɛ,͏hq5t~X!7n)L
JhDuv1]5 5!0_1$'3iy*u[
5*Y[l(Y[M	5J@mHƧ.Cmҍ!Yc2
CmQ0DV}MTj`1#66~_PǍ!T5 2L1$"*`A,+RB1ǧ1XW}wcӟ$~YBːa547P8.oHLf֐oC*PƐ>Dlbh(9l/*Q襂F~~	Sތ!"ș<44ڷPLgeR;}51(&rT
VvjϬhk[QMV.].
cHpP@+Ɛ{__☿
Ɛ"C4Ŭa;0!r]EBCa)t2O
6!1tZܬ1O)6.	>;\(I7BwcHQApcH@.!M
\<况l
tV9y)VihUzV
P܊!zSoŐǛ39SHe8:!ۑtCVDZU&JvTDG1(W2P62@#sK1^B(]QާgMl	P,m+*źb-b/:_CFW=ZaedZ".bsKBlKe
L*!C.(b3)Q?lQ=%"Q (&<"VhsT`2!	P

ַh
wK&v-`BA

rYNY15Ls..x<Bt-kD.yQӚ12`ebHqtӝtό(1CY!d@dsRaM-\uUl(BXRT|
;BQxm!70-E.k2r2@2{d@_6}x+5V8%?*+.bȉ{VM٤+(!\".
bO鵯MŐLų,Ld$As1D,Wʡ@n_~+؆Mˋ![C!Po3 ໽i9V{+{1xL/k.c=3 .P+JbȚ@
^aCpDDk
x\.m*J@ -̵Pz+8P
TGSdΕb[1e
R-3tms>rGysJSvtUڙ}Jt
E1d/77,Z'ZQ1(3.RYM[e*Su4lU=$]A|S 	bP0:m=gE_/GKpIzq:˘GYP/U~]Bb":!ZvtCϪ&kC䌋r---9v
h''2"@]A#@-]TP.
F1$l:-@P1{}R8(It2Q/?Qa@ɐq,^3˨)²^ch@]{YQ(9qkG]F:*b.
M{]Ao
"-ة+ȹƢUdzѥD.lv/k}
{;k3rƫ'MF.c\8(X>tdG1$?2n[4!JtE7L(8Jj^tεc(\ߋ!(SAb91bț\3zQw˟^ABʣbe2Yedwk#qy2RGQAJŐlŐ4!+Fc[!G5Ő}C[
s%mlbMŐxK1F\de~S` 
OMT[9
q>u2>Z
r3CM».I|O	TqHTpuYLGlkŐ@G1䅹ȐʚF1	V Qi23s
+(SA̹֟;G1pTN[$5G(#AT\lD҃e>Q!d@R[QY<&_3v7Q|Qu;׺1EoqE8D%a"8R`\3;MAyA\Z眪{'u;eFy`E]6rEbm!DɃ̋,*bl[{qkV
M0WVAoF!EkS1Kshp-1d_f(рq݈` Q5Đ(ht;8.bBE$%x
o~#\7H~Y?9/LŰQU!
8U

b0Z4)fۻU_
AAGy=̉;DLh,MC(("Aӎ\C`!bPd
(m2!GbHg\D|C\C݀ L!|Yym*h8y$xa@EqũuŮV)+kk#8"!Ʋa=TXe
0Y#/dQ*8ȲK=D"^$hQbz79e&jSHhͷgP=E`gl(+z
."89|E:]\OW]f2 {ԎM[4/)muRIebH!&pM`tYc"ѐ
&4.Ua5pQ7Gp$%2BKsC#1db+.§C^
s%@Ш12"Eg0\qCQ!GQe22?o7=C{]#;D"iUY01j64
@PO:~=yq!!D,TЖ8!]C!u^,@Yicc\F~sA-!C씔W"yS4&8EC~$2ǣ90DY4!$.+Wب!#ăK,0Y+c|d
p\jMZ&
@ŐDiij`TYcVdV
he@˙ .PgQ1S4-A+[!3IE@lMX`EhVJQ^{d7̀@2'o޻r'wߟWybU!X"ר-ֶ<9Cvsq8C/]V-IT,\`5D_59?X|qzXޯD?{">"rc'7G5.E!E]+m^x}ٹet
T7VA;CvT1F&bH"R@Đ.3.8ksPAC
!WQEk%Z&?:n}}ZOLJX_?==,+}C|U$E2.b76DEAdU/.tUZsH!.JAS j[mxn!ZY)EbH20!mW.3._ql/7bXĐ|C,J>~-Go׏/`/wݬ~eabX֘oppCjt"yMBVh2~GӑV0 ̐%!;lcC[V`b[MqUjCH_Ee
,kP
"k
$ZlbU.-
*O?Z_#g}ѳ*2C3Cma.!j{0$GRSe1F=U9ɽ{/>|qIʮNx3"&XdDB*bU#*,SsFNh	kFY}&+
AWOZuÃ݃`èHY61а9Cqh:#x仓xxwߥ2RWeNU*x-mW;*pQ櫀!
w8sLLQ{ׇKT1":c@GM&d&pK[7<ןvγ^Kѩb+tB)#M]b͋&b`Q
1?OϮ*#RMBYXa\A+P+L+mbo|1dsfI60a_[aGܹz,Z,9crNrjP3冏rHnʽ
%rBKJgygZvw}73U)(e<"5*;.#V2]hilmKF":+!1jc=Z{z{[(r-1uޯhFsQ=1`wX5&%zR2
FaJc*m#2ykhcCڄʹ.@.c8=^m0lIWMCX"bD"Oa⿹4U
tWDkߚ{ԕԅ]]S
A!*р֥)ucai,+#s#zb02I!r5H#r|PkT.h=FX1NMg6/{qfeY9Oo]5!5;46:>caYvA\PS!]?˖?>8A4:jD%U"p.IKi
Kxc5hX2b^߶ݥBui 4o2tcn֍!f&Mډ.#\^ԻŖO%o/E,+zeF6c`1Ԍ!d[]*-$"dY 1Hn"ʴ$"cE$#8h
c+ӒƤbCa6*lSU]hèjZY
K}fͿVo;n}r7i;>^V6Mŷ_Vu1Diy(*CptEFGy;֣q/ͯv]"oBɹ.m1*
̨Oyc~cHYC!:CC1UƐt/\Xx{xO%w7ߵGb鈄bJcHV5Q(*~:MB˺2K$'fÁޚbYSJ:uc#{#Hc^΁vC:.GY&ȑI;0\]am{?P*-"QqE(6wڲ͙PoC]Akrlp-kBW"p>-֍U$J@p#$#BZNP̖MMa퓜,\Q(ClC*τ5l:2SQ-n˦Nxݒh^L<Ɔukr|oL1C\ĘRZ51&mt1
3J`,"x-I	cHHiUc7.x
HPz@#
D@if	5Ah1]ᶬ{c7/_'}oSZݥ&@xI8@!MFs?i
R.=._hΥcr]UJ%-hV]--@[AUM"X66D0fĪf]o*Wt0kD@3׶QoQrƣDžOii99y!ku`QN*6L~V7$T7hi[C2"jq]@6Е׬bЄckzBI]E*d"V7㼌 +!CUT)|dcHQ%7`ºSR2JU5XejL Thn
4L%-Nm<[6iҘn9%[QMY׀X 7xTYQln2TL(1>_wſ1g3FTZG i
1l00t1.ZNr1x]^zZ#h0uH,f

T\Q5˭[tǏ?f́F/a)	L4 1V[׬mbtjAcôXhzp-+{"@<=]ESbc1D5]
R9sU&	Յ.#uu jהՕ
&m۶le(5\Ɛ8h@
ue@%H/CD@gʛP*z
<-FNc	ʙ7ҢbH$\ROQ?
Tx]FJK].J^n=~m/_Ǔ@bcǚcfN1nu_G5-U"0>5RicH-*%j_%S1s^QV2^0Am2U^4)v?a$jm/v?R*Vie

&!1P>aƝ7_ӧsAS
&"#b|Z6"~HҒD.R5`"Fp`{8Y|Е@GSX;\D1JP\E٫L
Da8XdI  )BjADmPl;쵲ll,T{d2?f'ɜwB;~̽["Qq{CƐ2!E07,Ǻ[_|G^n'OdYfCJ*MY#X):1hxe*/^` VV4͆.#VHAmc:5{c݇o޼OަpMj輠t1$Ucۣj<ъ":o>~zK:eh3-Ͱ,|ZN| -.¿"
iN"0+t3\J	t0B_l_hrfonՀjqD~㏟>1"amg h
6hY}@U.¨8{h6?ͷ?˽[Wt1	#*ME5IoߨF`.w@'Cfb}rcfJƪF@-PU]DѬ2F	Shlej(?{ۓ
-618C1DR"?k]<txfFF"I"PcHY1$1$Ш1dR̘3!O!t`et5LScHt6'R-6%̉hC]1~(#f42:rcm5ktjAY!zb2ߩ*Y4_.
Mu)[]lu=Dm43:h8 RkV?A1R\Ucc@ӹ.CQEzCreCVc\7=55flCqE=Tc^NzϨEEP:j\$_DGbK@fUx "c!jI$'f
\D1khT]rfnEI!耭4O^>FjMD1@J4}a^vgjEƐTQߡc (鄺b5Ɛ吒=auRbKXh1BPӲ *MNM@_Av:2'UcNA(2Z4_t}F(8"RW3j]ׯsMȡ-"d{t4<̏@ GcuƬmQ7A'vTۅBɐJC.QZZT{15x08K'51$C BICh,YC?D߻'YrB+Yw?*z?R5'YJJД]JR}NBaF,"S1kp
K8<1Cb\FBYc)"kd^pfm7ʛB5HoiuJI{V)c1e`РQVS0o,K{V#pO+r+M1
KO#YMRGf"<$bHTAȪȘ˲Q^*JAk Yc"\j+ܖʼ\.((¹JڲuUPRrbuEbIRg%KEp"[5DP`mU@PCmBH(eYSn-ИJ%Bbvr*LhW&RFBd
.Y#ˀs5.\=)J"k5Ƕ=Y
pذpGA	PF\gg}ݣ:,\[EP}zL1#2]OELLa	1pi[6\28$w.&2vҊ Λ,00ULrϥA`{1$Q7e/BOE8#\SCO*xFݔ.*%\p;WIf	~46T׺ZP(/ߦ!M}b0Xk0*2
`ɽcBr!qt0p&h7HTcX@脯11QJMMayjW1AC4J:M)yܫ5ͱ,.p -~ps"* +(I,?Hՠ-0*;g.?;^0
/r!n?!CyޔqW[Lbf&4Ġ$jJĐfԜKu躹@Qwљ)ڛf`9.c)["bbiOrknůwýq|2iNoGywz܍o]?o.X1:ۭX_&`o$r-&`RQ1!X!&&}
4ҿU6UeכQ?nu8M	sX^%|$XR-ZBJPf)bN_3qdE﨡(p(~QW6谿7>=hI;ߗb)ve[J9nM7?E~ũ_/h8ml{ Q1bĐL#:C`ڦ!Yxg)jpyy}YgWw>ro)+ĐLBNb}v
U0e%q"Y8+y͒,Yj7WBV\Dˆj}6ub&i)okŘK~IY{FA;f!7i`;ju^cIMלujwӉSEYߨtL|WhtR'>ר`6r2*ӫBWɥrP/MubŊY#GlR4,?
=uLǒDM4=]9(BCDt8.I]BSCR
=3OyEĐEڛ
Nhyx"&)HeEU"<.J
@NG=rޮFݰs"	R6*wQ#LATG2rE|~VǼ{\]f<|ٔ;h~1y($k᝕auA N?5W.ŭ
rCwFq8pCmKpǒ`Xwm[eО/~onqvC\$U>MB
q#7%Cx(JO!8)ml%jQRހ{*v/~EA"DȺD!'A1$"=ʾqs9<~10$*11(шƐݭqn'㬿?EFc8
ƐocHC\DWC/
P
a#;\x%
w+hˊ(ڊ\=\|}nf
cH3 ٣rvYd(X7TB4]Ct MP׀`҄8Ɛng0`	TN*@~r(u:*@Ax@뫶*Ɛ1dfnŽ︢c&C/tcH.cn֨uRY-(Ƅ憒5ƐM%`1d*%J+Oɦ~hjiRE}HS*p4=*(
bhU14V2u*cHiƐҍ!p1$@j4cDqa/1dۈ.]bavMO	4I׀H34AC(N>PD4sT JVArt%2C'mƐ@ƐOnc`"(s2I7lw]|C0Ѐ'5LJ3Db(4 2Ϧz֦̅7m^Ħ
з
`{VcH)5tsqT
m0f"1df%nր!DҙC%8/QiNzGl.Bq3[UU5Gm(iS\䆊)IW\0G+`^+xCG-$f9BqYYCrv2T0|⼫V0k$%
|a\v(*mL$V%?Խe	,>ӓ:IFoP܀V+CTx-p#o{,F1Dq]MhSs.Yы!sy1+s.M<_*
Mu*-놹ʷ(kQI2T݁fY	T hpteQA.#~
jE
j2,@c\蟋!9}L8t
T1'OҮŐF[If4.ʈPf;PTŐ%sCHQbwq]sU@g1fϸ:PyuTRr/(ZYВ%Q^z-(N@sHʹG9Wb)nK}K]:`ikC,&tV]E*P!*
p)8X[)\jrE⟸,ڈHz*Rl̅smT4Ы=[%S@iItQ+A5%gFNl8Vp]ɈfGkz-%mM]F.ʚw[1$H{D4Uٕ#&:sQuPЈ^dـRAz(؀J[塠@l	W~W(,(DGbIg1$Й9Cbz.E%@PGQYZ9"2Q蘋PTB=QuSSA%D+[
z)pŐxrT3U;@q}5hEGGD:М
PK[Ck)@~I@袲!DƪeWFPbPh?+Xے"s۵%ae[xůEbH&㨀OTe8UQJH<5e1d[Ő|E-ƁCF1dhEXxY̥0w$J4*SAh	
`k*bȏe5'YUQ>4Khl` QGeC=Q#!Q!)|?
9zGeCR!D9ET;Z
-!d+TȘ'ЇU^(|9m
Ye1.(ve(sVhYP4242 -!YS6Q!ݙQLY1.o
\9
(\mi( *^a.7T }|Ob(8myC\F\먜h@KѣV,f.CDsGk3g1D76_5"(Dm.:b%qs|P|*V;`kYBA
\ʍ=bHY_
WE1$d|5v/cCV
>Fx`KBEeͼ/P5ckڮqA|`
jQ*g#2 ^z+NƌMDk	h&kvuҪ-"C(tQd
\oPO+kޡ=!GŏNxdMj8jF\(q*񪇖Qqg	-TvJz`#Xb.\D-p'(ۋ(%qhc$
S<>UO1WR|eb)~k1G5f1d]2 mgl2,Z'/x7#+(-QQ("b	r"Q|d\d٬{1?*G\PT,vdA;wD1$r.5@9ϫ#3@P#jQ`zcEma
/T%`g*
Y4*(T@t*ȌF1ݥ9Y}Mo"K/q{.㌋x]";&5"a;e1ge,k3 Z]{Y5G3*PnG%-fh\Xs|e;)EP]sq܆(d@,
dDU(u' 3jUYfK4uU@!;~CV5'?
qPa!
-s
c]ae|S
K_e,DO'jE@VJ6+^:G^m
-L+T$v'*CtV
$Ewtc.dh0N4	)5m@gy=>eyNL1_nSGOԁ@]tTp$3('ԧ1D.,{v4_rhMcR&\ʼKL|ytwcȽ*H_*1uyrqYy]9iآtcHz:ߌ!2'Hzed1]Ԁ&jX2Im;{CG3f!Ou2WC5+Xv/lT;d3+Xn`V:΄WC'1v@IvzC
M,jR)
xx5w4cZ򿒤*J@-Pɧ1dz%@Ze|ZohT7X`M>!
U`Y`bVݪi!7|i&+vc
ՆZ)1HEV?ev_pUvhht6/DmO ňvOhBlG){+*@y֎D5]VGt@VW燆hm4pQfb6d.2Q-o ZMΌFtexq
/I˳R
-;@GO1m)D-^uNhmLc娀p`w@X*PC3hMM2 f
91$t>"&rXe4u>3EĘq/(JAI٨.@MbVRV{\sIj̨ _);)V2#:CQ(+p檨@sT@>Ҍ!<(Ɛ܍!bM>74ucH"J]FC]Ua17UkDZԁU:ZԀYpvt4D.-0hTF>i
P\V
$
U0GKT`6c`֘%Mf^CkܲYiދ^qP]B.M]Qͺ(bj(m6U_UvlhC­nˎ1$Mho@9Ь
*X(
sl+rٺFVAahw$
&we).Or-]1=AplD8WTh1騹$h Ed@{Q|SڲI纡m+H@ aϯ114[,P!B4!0hAXE0_@G]ǃȋ+UOFTJ!k}^+Df
ތ!<#Zv5 ~\k$++
}HShT.Mf_JcȺWPk¶rbZBXfMR:'i?#.-2<DnKeP2PD!Uwɘ@ql':Ctz
Η2̥
vC
4,ke>!
ti9Q!n|bDTQ=>;jq*Z1cƳe/j]g5jE6NdQe{}3DyږkT0"Sp9ȕT3Wtm-tM#jSQ
t*a	ɨx4Go
\.xe4P]1%P}Ģ?tQ;7Q)♉W7,cȎLhC9f?!@(rDcG碾Rw&1du
ձN8g	/Vdp`s>3adChhك1a{(5 <"0kL}AhhxK(i!j#!:Z>\uG}֨`ZA+@[t)-UGni{1KqiokTb|E+P_prC~{ϋM>bf.0H41Eͨ@ͼ4ݍ!MƐU"ɈrC.
s\+
˾`/D^AIUwh]V
+na[FTiN1d~HٟexB,iC]fׇ1jbd@W<&cI^v9K@ӀZ3XCmJhh;ZAR
cHsx
iʵa.[K"zCD!	Ԁ1Ac^!OcZD& fB%ꢑ_=!&1d&j6EKK-2V Ҍ!
|1ku7+4EGH\"ݠs]*!O;*J&!|ל'fD׍"J_h3Q9P74[7k,Hڍ!rj@FԈ\ف2;PB\
|
u2T@
jVM2#Pp1$N5tn>!y4yƐɏv5t!A)f;A;U/!rC^ JbL-
%wЀ\C/hQD

R@WERT^!?Cqe@,7c3_u:Ct,BTtFD*Q#VOcH.7Th7p%j
uUOuo+u+1dZ=,\	31PgUCChغƐsR:b\0]]ynyH7h<+hƐD{&1.Ɛk\v䲣U`V
cȋ+pVW0gD]F5jNj7cYY,ч#T@?f
pؠP%.CCT~]BfFqAeG;X5"@\Exj1opXks-\@=P!
٣1$cn]H5g.lDCQʊ}&S.r2&UWc)P_!jG8QЫ1$?{;*rnuG\Ki
#(M)VPYAZ[Q^Amh".SXJMi0Aѵ@@f@-E5PJ4!@7;Xfd
DmY6H)Cޥ*j_эM@=\c-1XdrV gCj]Fݱ]j5jD2vi=C^2?Vjߘ5Ɛ@U*uDi)蜛1=P!Q2T+Ƚ@ z`
wƐ^I)Yg1d>!M8xGmE7~Ze	bqQѶ%nbW>ѝmr˯IWsig.0m+z7@>&Kb.Cx(&Ĕ6=u;!90*?mй
Ebu
Qt,t
ո>j16Zu(Q!jKG_Yf[YQnUJca*bYAeDEƝMqOgg:ё?\!Ğ='fHP."W=8$J9MW811:SFT!q\FEJC13U$w4^}TWeD^@t
m}2Ő@nDbً!XQlCsb菶ƣ}Ɔo'{e2grDQ;QC0Ő
TZ.Ő2!PπlNFGcCke}*>WQC֦ A;QK"

]ys],*@6j(^)1C7002f7aŐIF"љh-L~Qk.!!\$J$ZP[lR,S"x1C"MD)"|1QT .b
3,/
9115까03 <͋!*RDQ!sZG[.#Kh288`Cp	?~a1伬2CV\KlieJlq-:PJ=RW5|

<0WLP\Lc1Fe'qFLe
Oܠk.ms~\)h̆FN\+*9M\9oP7 D{$bDq(\:	讠jңx\hWP>MMrgZlbH-kpd*
҄[9TT4TzYC?sA[њˈRUk$?!${1$Jlh2}8a(줡t(ؖPRŐw(g*)\6*Ѓu!PwαP>W0WL܃Ԋ!0"z֘y"5¡-.R([e

U\{'bZX+
V$\FƨY+ŐC$PД
lhC$7K":( 
"P:(HTEnKPi
6CnCJehF1dFVրsquCBwŐч65t˽ъ!Zfghn~ˀЋ!tKY7QC^v۰":s)¹^Ůmsi
8WnsծsVcy|\뻷˘Eπ!1:O8=s",bȣ	Ӄ9вŐjP!+3^)9jE{1YZ1 >U%_
]DtTP)W'5qWO/i*YeYb]e!!p%h ?[Dc1$g	_^K/ѠbHɞ\3V()#z
؂ϋ!dĮ`mhz_7vW0GU{ʲ!vB[ZŐaϋ!3922$
e
vdS1$Ő,_t,u%RG ]#ڃ?=`
'WWs1DX.G_JR*,DCPeTTDѻsEs.cc1DkcL7ŐsEhܢ^Me4CdjŐf%Z::ɲ{5&U訠T6+R
`uQ
!C.70_:70mqe%jLh$2RORRj1$O,NQM
z
P

"gX܊!@H+Q

z	e
i@:*Ε$(!PA1C!PJJL0Ő)P|ͬ;Y;Ft(B/R
Ő؋!@/,@/jK*&*_EB@2*(;bHx5]U Kd2Z+J^y_sz.|j\^ɛ{R3C1d1;[/kC1hJmuE|.c1D\],Ӯ P
z1dTԋ!*X>Co,!;KԱS-kp愲XnI
]g*DB-^
;ZQ/'Gk1#M3 l{J#"Js}.EWt
«ŋ!e@JGk_OmX"
R/rTj*H4IH^Ѹ\F(j649zsWs00a`
^)UUYyl;:GYFMPh2tπhˀpP/"BAP)k
*TPhJOnKT%"Ԯ A
u/ஃbw;5Vπw!bEz1$bHl
穖5fq^q4
qY_!M@WĦc1C\2R!\xJC1wB+PG="%hJ+'+!
-V̲,c/VI^!:2bHCo
bȽzbHCg%fVa#uCr|&4zb+X]>)Xs\@z_)
)8
!8;[c.C4bhy-0.R3 浗5IEZDbH5b
U3jh(؝d;_|EW*3>QѮ Tl
yTTIƲFʵ"e/kˀ+I4DhVԤb#S=>Cƍ4^!Q%j(`QAl

*x>)ȃ
Do
j$1_C2洣7$!2؀bHGo04!qJ@I@U2:ǭbhvbz|\ڊ!:A'ȋTQAa1
bST=؏\OW6\~;7|=[W8eɮ㱝BP-@ɮn9yF%ӵ*e|ƅ߭A@*y'9]_
Cm*jm3tb.XPT
:Zl
>WN޷+kG7W꺸-Sc黏77~8.ǻ
ۇq@?ވ9wvѷx@m;ώwn	hWtlE%K5o]6\PdcO~axk{oN}W_o[\7/7g$P\W@qd4n(j@[5dCyo@ES;V1?rE;΅^P{{??߿ŠIUTIENDB`qbs-src-2.6.1/doc/classic.css0000644000175100001660000001032014776170045015344 0ustar  runnerdockerBODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
  font-family: Arial, Geneva, Helvetica, sans-serif;
}
H1 {
  text-align: center;
  font-size: 160%;
}
H2 {
  font-size: 120%;
}
H3 {
  font-size: 100%;
}

h3.fn,span.fn
{
  background-color: #eee;
  border-width: 1px;
  border-style: solid;
  border-color: #ddd;
  font-weight: bold;
  padding: 6px 0px 6px 10px;
  margin: 42px 0px 0px 0px;
}

hr {
  border: 0;
  color: #a0a0a0;
  background-color: #ccc;
  height: 1px;
  width: 100%;
  text-align: left;
  margin: 34px 0px 34px 0px;
}

table.valuelist {
	border-width: 1px 1px 1px 1px;
	border-style: solid;
	border-color: #dddddd;
	border-collapse: collapse;
	background-color: #f0f0f0;
}

table.indextable {
	border-width: 1px 1px 1px 1px;
	border-collapse: collapse;
	background-color: #f0f0f0;
    border-color:#555;
    font-size: 110%;
}

table td.largeindex {
	border-width: 1px 1px 1px 1px;
	border-collapse: collapse;
	background-color: #f0f0f0;
    border-color:#555;
    font-size: 120%;
}

table.valuelist th {
	border-width: 1px 1px 1px 2px;
	padding: 4px;
	border-style: solid;
	border-color: #666;
    color:white;
    background-color:#666;
}

th.titleheader  {
	border-width: 1px 0px 1px 0px;
	padding: 4px;
	border-style: solid;
	border-color: #444;
    color:white;
    background-color:#555555;
    font-size: 110%;
}

th.largeheader {
	border-width: 1px 0px 1px 0px;
	padding: 4px;
	border-style: solid;
	border-color: #444;
    color:white;
    background-color:#555555;
    font-size: 120%;
}

p {

  margin-left: 4px;
  margin-top: 8px;
  margin-bottom: 8px;
}

a:link
{
  color: #0046ad;
  text-decoration: none
}

a:visited
{
  color: #672967;
  text-decoration: none
}

a.obsolete
{
  color: #661100;
  text-decoration: none
}

a.compat
{
  color: #661100;
  text-decoration: none
}

a.obsolete:visited
{
  color: #995500;
  text-decoration: none
}

a.compat:visited
{
  color: #995500;
  text-decoration: none
}

body
{
  background: #ffffff;
  color: black
}

table.generic, table.annotated
{
  border-width: 1px;
  border-color:#bbb;
  border-style:solid;  
  border-collapse:collapse;
}

table td.memItemLeft {
  width: 180px;
  padding: 2px 0px 0px 8px;
  margin: 4px;
  border-width: 1px;
  border-color: #E0E0E0;
  border-style: none;
  font-size: 100%;
  white-space: nowrap
}

table td.memItemRight {
  padding: 2px 8px 0px 8px;
  margin: 4px;
  border-width: 1px;
  border-color: #E0E0E0;
  border-style: none;
  font-size: 100%;
}

table tr.odd {
  background: #f0f0f0;
  color: black;
}

table tr.even {
  background: #e4e4e4;
  color: black;
}

table.annotated th {
  padding: 3px;
  text-align: left
}

table.annotated td {
  padding: 3px;
}

table tr pre
{
  padding-top: 0px;
  padding-bottom: 0px;
  padding-left: 0px;
  padding-right: 0px;
  border: none;
  background: none
}

tr.qt-style
{
  background: #96E066;
  color: black
}

body pre
{
  padding: 0.2em;
  border: #e7e7e7 1px solid;
  background: #f1f1f1;
  color: black
}

table tr.qt-code pre
{
  padding: 0.2em;
  border: #e7e7e7 1px solid;
  background: #f1f1f1;
  color: black
}

span.preprocessor, span.preprocessor a
{
  color: darkblue;
}

span.comment
{
  color: darkred;
  font-style: italic
}

span.string,span.char
{
  color: darkgreen;
}

.title
{
    text-align: center
}

.subtitle
{
    font-size: 0.8em
}

.small-subtitle
{
    font-size: 0.65em
}

.qmlitem {
    padding: 0;
}

.qmlname {
    white-space: nowrap;
    font-weight: bold;
    font-size: 125%;
}

.qmltype {
    font-weight: bold;
    font-size: 125%;
}

.qmlproto, .qmldoc {
   // border-top: 1px solid #84b0c7;
}

.qmlproto {
    padding: 0;
    //background-color: #e4e4e4;//#d5e1e8;
    //font-weight: bold;
    //-webkit-border-top-left-radius: 8px;
    //-webkit-border-top-right-radius: 8px;
    //-moz-border-radius-topleft: 8px;
    //-moz-border-radius-topright: 8px;
}

.qmldoc {
    border-top: 1px solid #e4e4e4;
    //padding: 2px 5px;
    //background-color: #eef3f5;
    //border-top-width: 0;
    //-webkit-border-bottom-left-radius: 8px;
    //-webkit-border-bottom-right-radius: 8px;
    //-moz-border-radius-bottomleft: 8px;
    //-moz-border-radius-bottomright: 8px;
}

.qmldoc p, .qmldoc dl, .qmldoc ul {
    //margin: 6px 0;
}

*.qmlitem p {
    //margin-top: 0px;
    //margin-bottom: 0px;
}
qbs-src-2.6.1/doc/qbs-online.qdocconf0000644000175100001660000000170714776170045017007 0ustar  runnerdockerinclude(config/qbs-project.qdocconf)

HTML.footer = \
    "   
\n" \ "

\n" \ " © 2022 The Qt Company Ltd.\n" \ " Documentation contributions included herein are the copyrights of\n" \ " their respective owners. " \ " The documentation provided herein is licensed under the terms of the" \ " GNU Free Documentation" \ " License version 1.3 as published by the Free Software Foundation. " \ " Qt and respective logos are trademarks of The Qt Company Ltd " \ " in Finland and/or other countries worldwide. All other trademarks are property\n" \ " of their respective owners.

\n" include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf) # Add an .html file with sidebar content, used in the online style HTML.stylesheets += config/style/qt5-sidebar.html qbs-src-2.6.1/doc/reference/0000755000175100001660000000000014776170045015153 5ustar runnerdockerqbs-src-2.6.1/doc/reference/cli/0000755000175100001660000000000014776170045015722 5ustar runnerdockerqbs-src-2.6.1/doc/reference/cli/tools/0000755000175100001660000000000014776170045017062 5ustar runnerdockerqbs-src-2.6.1/doc/reference/cli/tools/cli-config.qdoc0000644000175100001660000001064014776170045021745 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-config.html \ingroup cli \title config \brief Manages \QBS settings, such as preferences and profiles. \section1 Synopsis \code qbs config [--settings-dir ] [--user|--system] [--list [ ...]] [--unset ] [--export ] [--import ] qbs config [--settings-dir ] [--user|--system] qbs config [--settings-dir ] [--user|--system] \endcode \section1 Description Manages \QBS settings, such as preferences and profiles. You can list all keys and remove the specified key, as well as import settings from a file or export them to a file. The second form of this command displays the specified \c . The third form sets the specified \c with the specified \c . There are two sets of settings: The system-level settings affect all users, while the user-level settings are specific to the current user. By default, the read operations consider both sources. If the same key is present in both settings, then for list values, the system value is appended to the user value, while for other types of values the user-level one takes precedence. Write operations go to the user-level settings by default. Use the \c {--user} and \c {--system} options to change this behavior. \note It is conceivable that the default system value of the \c {preferences.qbsSearchPaths} setting could pull in unwanted \QBS modules, in particular when doing cross-builds. In such a case, you can set \c {preferences.ignoreSystemSearchPaths} to exclude the search paths coming from the system settings. You'll typically do this for a specific profile: \code $ qbs config profiles.myprofile.preferences.ignoreSystemSearchPaths true \endcode You can use the \l{config-ui} command to open the Qbs Settings tool for managing settings in a hierarchical view. For more information, see \l{Configuring Profiles and Preferences}, \l{Managing Qt Versions}, \l{Modules}, \l {List of Modules}, and \l{Custom Modules and Items}. \section1 Options \include cli-options.qdocinc settings-dir \include cli-options.qdocinc list-root \include cli-options.qdocinc unset \include cli-options.qdocinc export \include cli-options.qdocinc import \include cli-options.qdocinc config-user \include cli-options.qdocinc config-system \include cli-options.qdocinc help \section1 Parameters \include cli-parameters.qdocinc key \section1 Examples Lists the existing profiles: \code qbs config --list profiles \endcode Shows the default profile: \code qbs config defaultProfile \endcode \note If no output is shown, the default profile used is the built-in profile \c none, which sets no properties. Sets the profile called \c gcc as the base profile of the Qt profile called \c myqt: \code qbs config profiles.myqt.baseProfile gcc \endcode Adds the location of a custom module to your preferences, to make the module accessible in several projects: \code qbs config preferences.qbsSearchPaths /usr/local/share/custom-qbs-extensions \endcode */ qbs-src-2.6.1/doc/reference/cli/tools/cli-create-project.qdoc0000644000175100001660000000457514776170045023421 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-create-project.html \ingroup cli \title create-project \brief Creates a \QBS project from an existing set of source files. \section1 Synopsis \code qbs create-project [--blacklist ] [--whitelist ] [--flat] \endcode \section1 Description Automatically generates \QBS project files from an arbitrary directory structure. You can filter the files to add to the project by blacklisting or whitelisting them. The command creates nested project files, unless you use the \c --flat option. This is a useful starting point when migrating from other build tools, such as qmake or CMake. \note Run this command from the project directory. After generating the initial .qbs files, add the missing configuration variables and functions to them. \section1 Options \include cli-options.qdocinc blacklist \include cli-options.qdocinc whitelist \include cli-options.qdocinc flat \include cli-options.qdocinc help \section1 Examples Creates \c .qbs files in the project directory when run from there: \code qbs create-project \endcode */ qbs-src-2.6.1/doc/reference/cli/tools/cli-config-ui.qdoc0000644000175100001660000000414014776170045022356 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-config-ui.html \ingroup cli \title config-ui \brief Opens a GUI application for managing \QBS settings, such as preferences and profiles. \section1 Synopsis \code qbs config-ui [--settings-dir ] [--system] \endcode \section1 Description Opens the \QBS Settings application for managing \QBS settings, such as preferences and profiles, in a hierarchical view. This makes it easier to manage a large number of settings than using the \l{config} command from the command line. \image qbs-settings-gui.png For more information, see \l{Configuring Profiles and Preferences}. \section1 Options \include cli-options.qdocinc settings-dir \include cli-options.qdocinc config-ui-system \include cli-options.qdocinc help \section1 Examples Opens \QBS Settings: \code qbs config-ui \endcode */ qbs-src-2.6.1/doc/reference/cli/tools/cli-setup-toolchains.qdoc0000644000175100001660000000573014776170045024005 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-setup-toolchains.html \ingroup cli \title setup-toolchains \brief Creates \QBS profiles for toolchains, such as GCC or MSVC. \section1 Synopsis \code qbs setup-toolchains [--settings-dir ] [--system] --detect qbs setup-toolchains [--settings-dir ] [--system] [--type ] \endcode \section1 Description The first form tries to auto-detect all known toolchains, looking them up via the PATH variable. The second form creates a profile with the name \c {} for the toolchain located at \c {}. It will attempt to determine the toolchain type automatically based on the file name or the compiler executable. If that fails, you need to provide the compiler type as a value of the \c --type option. For more information, see \l{Configuring Profiles and Preferences}. \section1 Options \include cli-options.qdocinc settings-dir \include cli-options.qdocinc setup-tools-system \include cli-options.qdocinc detect-toolchains \include cli-options.qdocinc type \include cli-options.qdocinc help \section1 Examples Looks up toolchains via the PATH variable and creates profiles for them: \code qbs setup-toolchains --detect \endcode Creates a profile called \c mingw for the toolchain located in \c C:\mingw530_32\bin on Windows: \code qbs setup-toolchains C:\mingw530_32\bin\g++.exe mingw \endcode Creates a profile called \c g++-mingw-w64 for the toolchain located in \c /usr/bin/x86_64-w64-mingw32-g++ g++-mingw-w64 on Ubuntu: \code qbs setup-toolchains /usr/bin/x86_64-w64-mingw32-g++ g++-mingw-w64 \endcode */ qbs-src-2.6.1/doc/reference/cli/tools/cli-setup-android.qdoc0000644000175100001660000000447114776170045023263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-setup-android.html \ingroup cli \title setup-android \brief Creates \QBS profiles for Android SDK and NDK installations. \section1 Synopsis \code qbs setup-android [--settings-dir ] [--ndk-dir ] [--sdk-dir ] [--qt-dir ] \endcode \section1 Description Creates \QBS profiles for Android SDK and NDK installations. If a Qt path is given, these additional profiles will be suitable for building Qt binaries for the respective architecture, if the Qt installation has support for it. \section1 Options \include cli-options.qdocinc settings-dir \include cli-options.qdocinc ndk-dir \include cli-options.qdocinc sdk-dir \include cli-options.qdocinc qt-dir \include cli-options.qdocinc help \section1 Examples Creates a profile with the name \c oreo that specifies the target platforms' \l{qbs::}{architectures} and operating systems, as well as the toolchains available: \code qbs setup-android oreo \endcode */ qbs-src-2.6.1/doc/reference/cli/tools/cli-setup-qt.qdoc0000644000175100001660000000457614776170045022275 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-setup-qt.html \ingroup cli \title setup-qt \brief Creates \QBS profiles for Qt installations. \section1 Synopsis \code qbs setup-qt [--settings-dir ] [--system] --detect qbs setup-qt [--settings-dir ] [--system] \endcode \section1 Description Creates \QBS profiles for Qt installations. The first form tries to auto-detect all known Qt versions, looking them up via the PATH variable. The second form creates a profile with the name \c {} for the Qt version located at \c {}. For more information, see \l{Managing Qt Versions}. \section1 Options \include cli-options.qdocinc detect-qt-versions \include cli-options.qdocinc settings-dir \include cli-options.qdocinc setup-tools-system \include cli-options.qdocinc help \section1 Examples Looks up Qt versions in the PATH and creates profiles for them: \code qbs setup-qt --detect \endcode Creates a profile called \c myqt for the Qt version located in \c /usr/bin/qmake: \code qbs setup-qt /usr/bin/qmake myqt \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/0000755000175100001660000000000014776170045017370 5ustar runnerdockerqbs-src-2.6.1/doc/reference/cli/builtin/cli-resolve.qdoc0000644000175100001660000000461514776170045022472 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-resolve.html \ingroup cli \title resolve \brief Resolves a project without building it. \section1 Synopsis \code qbs resolve [options] [[config:configuration-name] [property:value] ...] \endcode \section1 Description Resolves a \l{Project}{project} in one or more configurations. Run this command to change the properties of an existing build. \section1 Options \include cli-options.qdocinc build-directory \include cli-options.qdocinc dry-run \include cli-options.qdocinc project-file \include cli-options.qdocinc force-probe-execution \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc log-time \include cli-options.qdocinc more-verbose \include cli-options.qdocinc settings-dir \include cli-options.qdocinc show-progress \include cli-options.qdocinc deprecation-warnings \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Examples Resolves the default configuration of the project in the current directory: \code qbs resolve \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-session.qdoc0000644000175100001660000000360614776170045022475 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-session.html \ingroup cli \title session \brief Starts a session for interacting with an IDE \section1 Synopsis \code qbs session \endcode \section1 Description Starts a session, communicating via standard input and standard output. In this mode, \QBS takes commands from standard input and sends replies to standard output, using a \l{Appendix C: The JSON API}{JSON-based API}. This is the recommended \QBS interface for IDEs. It can be used to retrieve information about a project and interact with it in various ways, such as building it, collecting the list of executables, adding new source files and so on. */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-help.qdoc0000644000175100001660000000346714776170045021747 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-help.html \ingroup cli \title help \brief Shows general or command-specific help. \section1 Synopsis \code qbs help [] \endcode \section1 Description Shows a list of available commands with descriptions. Specify a command name to list the options that the command takes with descriptions. \section1 Options This command takes no options. \section1 Examples Shows an overview of all commands: \code qbs help \endcode Lists the options that the \c build command takes: \code qbs help build \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-build.qdoc0000644000175100001660000000771214776170045022113 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-build.html \ingroup cli \title build \brief Builds a project. \section1 Synopsis \code qbs build [options] [[config:configuration-name] [property:value] ...] \endcode \section1 Description Builds projects in one or more configurations. You can specify \l{Project}{project}, \l{Product}{product}, or \l{List of Modules}{module} properties, as well as a \l{Profile} {profile} separately for each configuration. This is the default command. If the build directory does not exist, it will be created. For more information, see \l{Building Applications}. \section1 Options \target build-all-products \include cli-options.qdocinc all-products \include cli-options.qdocinc build-directory \include cli-options.qdocinc changed-files \include cli-options.qdocinc check-outputs \include cli-options.qdocinc check-timestamps \include cli-options.qdocinc clean_install_root \include cli-options.qdocinc command-echo-mode \include cli-options.qdocinc dry-run \include cli-options.qdocinc project-file \target build-force-probe-execution \include cli-options.qdocinc force-probe-execution \include cli-options.qdocinc jobs \include cli-options.qdocinc job-limits \include cli-options.qdocinc keep-going \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc log-time \include cli-options.qdocinc more-verbose \include cli-options.qdocinc no-install \target build-products \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \include cli-options.qdocinc show-progress \include cli-options.qdocinc wait-lock \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Examples Builds the application specified by the \c .qbs file in the current directory using the default profile: \code qbs \endcode Builds the application using four concurrent build jobs: \code qbs -j 4 \endcode Builds the default configuration of an application using the profile called \c Android: \code qbs build profile:Android \endcode Builds the application using different \l{cpp} module properties for debug and release configurations. For the debug configuration, warnings will cause the build to fail, whereas for the release configuration, the size of the build artifacts will be optimized. Both configurations are built with a profile named \c{"qt"}: \code qbs build profile:qt config:debug modules.cpp.treatWarningsAsErrors:true config:release modules.cpp.optimization:small \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-version.qdoc0000644000175100001660000000277714776170045022507 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-version.html \ingroup cli \title show-version \brief Prints the \QBS version. \section1 Synopsis \code qbs show-version \endcode \section1 Description Prints the version of \QBS to stdout. \section1 Options This command takes no options. */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-run.qdoc0000644000175100001660000000631714776170045021620 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-run.html \ingroup cli \title run \brief Runs an executable generated by building a project. \section1 Synopsis \code qbs run [options] [config:configuration-name] [property:value] ... [ -- ] \endcode \section1 Description Runs the specified product's executable with the specified \c . If the project has only one product, the \c --products option may be omitted. The product will be built if it is not up to date, unless the \c --no-build option is specified. For more information, see \l{build}. For more information about running applications, see \l{Running Applications}. \section1 Options \include cli-options.qdocinc all-products \include cli-options.qdocinc build-directory \include cli-options.qdocinc changed-files \include cli-options.qdocinc check-outputs \include cli-options.qdocinc check-timestamps \include cli-options.qdocinc clean_install_root \include cli-options.qdocinc command-echo-mode \include cli-options.qdocinc dry-run \include cli-options.qdocinc project-file \include cli-options.qdocinc force-probe-execution \include cli-options.qdocinc install-root \include cli-options.qdocinc jobs \include cli-options.qdocinc keep-going \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc log-time \include cli-options.qdocinc more-verbose \include cli-options.qdocinc no-build \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \include cli-options.qdocinc setup-run-env-config \include cli-options.qdocinc wait-lock \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Arguments \include cli-parameters.qdocinc arguments \section1 Examples Runs the Qt Creator application: \code qbs run --products qtcreator \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-install.qdoc0000644000175100001660000000544214776170045022460 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-install.html \ingroup cli \title install \brief Installs a project. \section1 Synopsis \code qbs install [options] [[config:configuration-name] [property:value] ...] \endcode \section1 Description Install all files marked as installable to their respective destinations. The project is built first, if necessary, unless the \c --no-build option is given. For more information, see \l{Installing Files}. \section1 Options \include cli-options.qdocinc all-products \include cli-options.qdocinc build-directory \include cli-options.qdocinc changed-files \include cli-options.qdocinc check-outputs \include cli-options.qdocinc check-timestamps \include cli-options.qdocinc clean_install_root \include cli-options.qdocinc command-echo-mode \include cli-options.qdocinc dry-run \include cli-options.qdocinc project-file \include cli-options.qdocinc force-probe-execution \include cli-options.qdocinc install-root \include cli-options.qdocinc jobs \include cli-options.qdocinc keep-going \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc log-time \include cli-options.qdocinc more-verbose \include cli-options.qdocinc no-build \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \include cli-options.qdocinc wait-lock \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Examples */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-generate.qdoc0000644000175100001660000000514114776170045022600 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-generate.html \ingroup cli \title generate \brief Invokes a project generator, for example to create project files for another build tool. \section1 Synopsis \code qbs generate [options] [[config:configuration-name] [property:value] ...] \endcode \section1 Description Invokes a project generator, for example to create project files for another build tool. For more information, see \l{Generators}. \section1 Options \target generate-generator \include cli-options.qdocinc generator \include cli-options.qdocinc build-directory \include cli-options.qdocinc project-file \include cli-options.qdocinc install-root \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc log-time \include cli-options.qdocinc more-verbose \include cli-options.qdocinc settings-dir \include cli-options.qdocinc show-progress \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Examples Generates a project for Microsoft Visual Studio: \code qbs generate -g visualstudio2015 \endcode Generates a \l{https://clang.llvm.org/docs/JSONCompilationDatabase.html} {Clang compilation database (clangdb)}: \code qbs generate --generator clangdb \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-shell.qdoc0000644000175100001660000000412714776170045022120 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-shell.html \ingroup cli \title shell \brief Opens a shell with a product's environment. \section1 Synopsis \code qbs shell [options] [config:configuration-name] [property:value] \endcode \section1 Description Opens a shell in the environment that a build with the specified parameters would use. For more information, see \l{Using the Shell}. \section1 Options \include cli-options.qdocinc build-directory \include cli-options.qdocinc project-file \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Examples Opens a shell with the same environment that \QBS uses when building the project: \code qbs shell \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-clean.qdoc0000644000175100001660000000435214776170045022073 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-clean.html \ingroup cli \title clean \brief Removes the files generated during a build. \section1 Synopsis \code qbs clean [options] [config:configuration-name] \endcode \section1 Description Removes build \l{Artifact}{artifacts} for the specified build configuration. \section1 Options \include cli-options.qdocinc build-directory \include cli-options.qdocinc dry-run \include cli-options.qdocinc keep-going \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc log-time \include cli-options.qdocinc more-verbose \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \include cli-options.qdocinc show-progress \section1 Parameters \include cli-parameters.qdocinc configuration-name \section1 Examples Removes the build artifacts in the current directory for the default build configuration: \code qbs clean \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-status.qdoc0000644000175100001660000000363314776170045022335 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-status.html \ingroup cli \title status \brief Shows the status of files in the project directory. \section1 Synopsis \code qbs status [options] [config:configuration-name] \endcode \section1 Description Lists all the files in the project directory and shows whether they are known to \QBS in the respective configuration. \section1 Options \include cli-options.qdocinc build-directory \include cli-options.qdocinc settings-dir \section1 Parameters \include cli-parameters.qdocinc configuration-name \section1 Examples To list the files in the project directory and view their status: \code qbs status \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-dump-nodes-tree.qdoc0000644000175100001660000000377314776170045024027 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-dump-nodes-tree.html \ingroup cli \title dump-nodes-tree \brief Dumps the nodes in the build graph to \c stdout. \section1 Synopsis \code qbs dump-nodes-tree [options] [config:configuration-name] \endcode \section1 Description Dumps the nodes in the build graph to \c stdout. This is an internal command that is used for debugging purposes only. \section1 Options \include cli-options.qdocinc build-directory \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \section1 Parameters \include cli-parameters.qdocinc configuration-name \section1 Examples Dumps the nodes tree into a file called \c nodes-tree.log: \code qbs dump-nodes-tree >nodes-tree.log \endcode */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-update-timestamps.qdoc0000644000175100001660000000453414776170045024461 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-update-timestamps.html \ingroup cli \title update-timestamps \brief Marks the build as up-to-date. \section1 Synopsis \code qbs update-timestamps [options] [config:configuration-name] ... \endcode \section1 Description Updates the timestamps of all build \l{Artifact}{artifacts}, causing the next builds of the \l{Project}{project} to do nothing until source files are updated again. This command is useful if you know that the current changes to source files are irrelevant to the build. \note Using this command causes a discrepancy between the actual state of source files and the information in the build graph, so be careful. \section1 Options \include cli-options.qdocinc build-directory \include cli-options.qdocinc less-verbose \include cli-options.qdocinc log-level \include cli-options.qdocinc more-verbose \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings \section1 Parameters \include cli-parameters.qdocinc configuration-name \include cli-parameters.qdocinc property \section1 Examples */ qbs-src-2.6.1/doc/reference/cli/builtin/cli-list-products.qdoc0000644000175100001660000000361014776170045023621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page cli-list-products.html \ingroup cli \title list-products \brief Lists all products in the given project. \section1 Synopsis \code qbs list-products [options] [config:configuration-name] \endcode \section1 Description Lists all products that exist in a project. \section1 Options \include cli-options.qdocinc project-file \include cli-options.qdocinc build-directory \include cli-options.qdocinc settings-dir \section1 Parameters \include cli-parameters.qdocinc configuration-name \section1 Examples To list all products for the project in the current directory: \code qbs list-products \endcode */ qbs-src-2.6.1/doc/reference/cli/cli-parameters.qdocinc0000644000175100001660000000721314776170045022177 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! //! [arguments] \section2 \c -- Command-line arguments to be passed to the program to be run. //! [arguments] //! [configuration-name] \section2 \c config:configuration-name Specifies the build configuration to use. \QBS can build a project for one or multiple configurations at once, each having a different set of parameters. The \c config parameter has a special function: with each occurrence a new configuration instance begins and all subsequent parameters until the next \c config are assigned to this instance. Parameter assignments before the first occurrence of \c config are applied to all build configurations. Inside products and modules, the current active build configuration can be retrieved via \l{qbs::configurationName}{qbs.configurationName}. In the following snippet, a profile \c clang is applied to all configurations while \c cpp.optimization is different for \c debug and \c release: \code profile:clang config:debug cpp.optimization:none config:release cpp.optimization:small \endcode The value of \c config determines the name of the build folder and affects the default value of the \l{qbs::buildVariant}{qbs.buildVariant} property. \QBS knows the \c config values \c{"debug"} and \c{"release"}, but in general any name can be chosen. When naming configurations created for special purposes, follow the rules for legal names generally used in programming languages: \list \li The first character must be a letter (a-z), an underscore (_), or a dollar sign ($). \li Subsequent characters may be letters, digits, underscores, or dollar signs. \endlist //! [configuration-name] //! [key] \section2 \c Typically, a \c consists of several levels separated by periods. The first level shows a \e root value, such as \e preferences or \e profiles. The root determines whether the second-level keys are build preferences or profile names. The lower level keys consist of a module name, followed by a property name. //! [key] //! [property] \section2 \c {property:value} Property values set in project files or profiles can be overridden on the command line. The syntax is: \code .: \endcode For more information, see \l{Overriding Property Values from the Command Line}. //! [property] */ qbs-src-2.6.1/doc/reference/cli/cli-options.qdocinc0000644000175100001660000003220014776170045021521 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! //! [all-products] \section2 \c --all-products Processes all \l{Product}{products}, even if their \c builtByDefault property is \c false. //! [all-products] //! [blacklist] \section2 \c {--blacklist } Ignores files whose names match the patterns specified by \c . The list entries can contain wildcards and are separated by commas. By default, no files are ignored. //! [blacklist] //! [build-directory] \section2 \c {--build-directory|-d } Specifies a \c where build artifacts are stored. The default value is the current directory unless \c preferences.defaultBuildDirectory is set. Relative paths will be interpreted relative to the current directory. You can use the following special values as placeholders: \list \li \c @project is expanded to the name of the project file excluding the extension \c .qbs. \li \c @path is expanded to the name of the directory containing the project file. \endlist //! [build-directory] //! [changed-files] \section2 \c {--changed-files [,...]} Assumes that the files specified by \c , and only those files, have changed. //! [changed-files] //! [check-outputs] \section2 \c --check-outputs Forces transformer output \l{Artifact}{artifact} checks. Verifies that the output artifacts declared by \l{Rule}{rules} in the \l{Project}{project} are actually created. //! [check-outputs] //! [check-timestamps] \section2 \c --check-timestamps Forces timestamp checks. Retrieves the timestamps from the file system, instead of using the file timestamps that are stored in the build graph. //! [check-timestamps] //! [clean_install_root] \section2 \c --clean-install-root Removes the installation base directory before installing. //! [clean_install_root] //! [command-echo-mode] \section2 \c {--command-echo-mode } Determines what kind of output to show when executing commands. Possible values of \c are: \list \li \c silent \li \c summary (default value) \li \c command-line \li \c command-line-with-environment \endlist //! [command-echo-mode] //! [detect-qt-versions] \section2 \c --detect Attempts to auto-detect all known Qt versions, looking them up in the PATH environment variable. //! [detect-qt-versions] //! [detect-toolchains] \section2 \c --detect Attempts to auto-detect all known toolchains, looking them up in the PATH environment variable. //! [detect-toolchains] //! [dry-run] \section2 \c --dry-run|-n Performs a dry run. No commands will be executed and no permanent changes to the build graph will be done. //! [dry-run] //! [export] \section2 \c {--export } Exports settings to the specified \c . //! [export] //! [project-file] \section2 \c {[--file|-f ]} Uses \c as the project file. If \c is a directory and it contains a single file with the extension \c .qbs, that file will be used. If this option is not given at all, the behavior is the same as for \c{-f }. //! [project-file] //! [flat] \section2 \c --flat Does not create nested project files, even if there are subdirectories and the top-level directory does not contain any files. //! [flat] //! [force-probe-execution] \section2 \c --force-probe-execution Forces re-execution of all \l{Probe} items' configure scripts, rather than using the cached data. //! [force-probe-execution] //! [generator] \section2 \c {--generator|-g } Uses the specified build system generator. Possible values of \c include: \list \li \c clangdb \li \c visualstudio2015 \li \c iarew8 \endlist The available generators are listed if you run the \c {qbs generate} command without passing a generator to it. //! [generator] //! [help] \section2 \c {--help|-h|-?} Displays help for the command. //! [help] //! [import] \section2 \c {--import } Imports settings from the specified \c . //! [import] //! [install-root] \section2 \c {--install-root } Installs into the specified \c . If the directory does not exist, it will be created. The default value is \c /install-root. Use the special value \c @sysroot to install into the \c sysroot. That is, the value of the \l{qbs::sysroot}{qbs.sysroot} property. //! [install-root] //! [jobs] \section2 \c {--jobs|-j } Uses \c concurrent build jobs, where \c must be an integer greater than zero. The default is the number of logical cores. //! [jobs] //! [job-limits] \section2 \c {--job-limits :[,:...]} Sets pool-specific job limits. See \l{job-pool-howto}{here} for more information on job pools. \section2 \c {--enforce-project-job-limits} Normally, job limits defined in project files via the \l JobLimit item get overridden by those set on the command line. If this option is passed, they get maximum priority instead. Use it if there are product-specific limits that make more sense for that part of the code base than the generic ones you'd like to apply globally. //! [job-limits] //! [keep-going] \section2 \c --keep-going|-k Keeps going when errors occur, if at all possible. //! [keep-going] //! [less-verbose] \section2 \c --less-verbose|-q Becomes more quiet by decreasing the log level by one. This option can be given more than once. Excessive occurrences have no effect. If the option \c --log-level appears anywhere on the command line in addition to this option, its value is taken as the base for the decrease. //! [less-verbose] //! [list-root] \section2 \c {--list [ ...]} Lists keys under the key \c or all keys if the root is not specified. Possible values are: \list \li \c defaultProfile is the default \l{Profile}{profile} to use if a profile is not specified \li \c preferences accepts build preferences as second-level keys \li \c profiles accepts profile names as second-level keys \endlist //! [list-root] //! [config-user] \section2 \c {--user} Causes read operations to display only the user-level settings, while the system-level settings are ignored. Write operations will target the user-level settings, which is also the default. //! [config-user] //! [config-system] \section2 \c {--system} Read and write operations will consider only the system-level settings. //! [config-system] //! [config-ui-system] \section2 \c {--system} Instructs the tool to work on the system-level settings. Otherwise, the user-level settings are presented. //! [config-ui-system] //! [deprecation-warnings] \section2 \c {--deprecation-warnings } Uses the specified deprecation warning mode, which controls what to do when deprecated items or properties are encountered in the project. By default, a warning is emitted if the item or property is scheduled for removal in the next minor version of \QBS. Warnings can also be switched on or off unconditionally, and it can be specified that project resolving should abort if deprecated constructs are present. Possible values of \c are: \list \li \c error \li \c on \li \c before-removal (default value) \li \c off \endlist //! [deprecation-warnings] //! [log-level] \section2 \c {--log-level } Uses the specified log level. Possible values of \c are: \list \li \c error \li \c warning \li \c info (default value) \li \c debug \li \c trace \endlist //! [log-level] //! [log-time] \section2 \c --log-time Logs the time that the operations involved in this command take. This option is implied in log levels \c debug and higher. This option is mutually exclusive with \c --show-progress. //! [log-time] //! [more-verbose] \section2 \c --more-verbose|-v Becomes more verbose by increasing the log level by one. This option can be given more than once. Excessive occurrences have no effect. If the option \c --log-level appears anywhere on the command line in addition to this option, its value is taken as the base for the increase. //! [more-verbose] //! [ndk-dir] \section2 \c {--ndk-dir } Specifies a \c that contains an Android NDK. //! [ndk-dir] //! [no-build] \section2 \c --no-build Does not re-build the project before installing or running it. //! [no-build] //! [no-install] \section2 \c --no-install Does not install any artifacts as part of the build process. //! [no-install] //! [products-specified] \section2 \c {--products|-p [,...]} Takes only the \l{Product}{products} specified by \c and their dependencies into account. //! [products-specified] //! [qt-dir] \section2 \c {--qt-dir } Specifies a \c that contains a Qt version. //! [qt-dir] //! [sdk-dir] \section2 \c {--sdk-dir } Specifies a \c that contains an Android SDK. //! [sdk-dir] //! [settings-dir] \section2 \c {--settings-dir } Reads all settings (such as \l{Profile}{profile} information) from the specified \c . If the directory does not exist, it will be created. The default value is system-specific. For example: \list \li Linux: \c $HOME/.config/QtProject/qbs \li Windows: \c %APPDATA%\QtProject\qbs \li macOS: \c $HOME/Library/Preferences/qbs \endlist //! [settings-dir] //! [setup-run-env-config] \target --setup-run-env-config \section2 \c --setup-run-env-config A comma-separated list of strings. They will show up in the \c config parameter of all \l{Module::}{setupRunEnvironment} scripts. //! [setup-run-env-config] //! [show-progress] \section2 \c --show-progress Shows how command execution is progressing. This option is mutually exclusive with \c --log-time. //! [show-progress] //! [no-fallback-module-provider] \section2 \c --no-fallback-module-provider If this option is set, then \QBS will not fall back to a pkg-config based \l{Module Providers}{module provider} if a dependency is not found. //! [no-fallback-module-provider] //! [setup-tools-system] \section2 \c {--system} If this option is given, the profile(s) created by this tool will end up in the system-level settings and thus be available to all users. Otherwise, they go into the user-level settings. //! [setup-tools-system] //! [type] \section2 \c {--type } Specifies the type of the toolchain. Needed if \QBS cannot determine the compiler from the name of the executable file located in the specified directory. Possible values include: \list \li \c clang \li \c gcc \li \c mingw \li \c msvc \li \c iar \li \c keil \li \c sdcc \li \c cosmic \li \c dmc \li \c watcom \endlist //! [type] //! [unset] \section2 \c {--unset } Removes the specified \c . //! [unset] //! [wait-lock] \section2 \c --wait-lock Waits indefinitely for other processes to release the build graph lock. This option is typically used by \l{Generators}{generators}, which may re-invoke multiple \QBS processes on the same project simultaneously. //! [wait-lock] //! [whitelist] \section2 \c {--whitelist } Considers only files whose names match the patterns specified by \c . The list entries can contain wildcards and are separated by commas. By default, all files are considered. //! [whitelist] */ qbs-src-2.6.1/doc/reference/cli/cli.qdoc0000644000175100001660000000325114776170045017342 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \group cli \title Command-Line Interface \brief A list of available command-line commands. The \c qbs command-line commands can be invoked as \c{qbs }. This reference summarizes the command-line commands. The authoritative source of up-to-date information is the respective help screen, which you get by calling \c{qbs help }. Some commands are described in context in the \l{Usage} section of the manual. */ qbs-src-2.6.1/doc/reference/reference.qdoc0000644000175100001660000000716414776170045017771 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage howtos.html \page reference.html \nextpage building-qbs.html \title Reference \list \li \l{List of All Items} \list \li \l{List of Language Items} \li \l{List of Convenience Items} \li \l{List of Probes} \endlist \li \l{List of Built-in Services} \li \l{Command-Line Interface} \li \l{List of Modules} \li \l{Command and JavaScriptCommand} \endlist */ /*! \group list-of-builtin-services \title List of Built-in Services \QBS provides the following built-in JavaScript extensions to simplify operations that are expected to be needed often in project files. To gain access to the operations provided by a particular Service - for example, the File service - use the following statement at the top of your \QBS project file: \code import qbs.File \endcode If you instead need to access the service from a JavaScript file, import it using the following statement at the top of your JavaScript file: \code var File = require("qbs.File"); \endcode */ /*! \qmlmodule QbsModules \title List of Modules These are the modules shipped with \QBS. For a list of \QBS modules that provide support for Qt modules, see \l{Qt Modules}. Only the Qt modules that have properties and relevant file tags are described in separate topics. */ /*! \qmlmodule QbsModuleProviders \title List of Module Providers These are the module providers shipped with \QBS. */ /*! \group list-of-items \title List of All Items \QBS provides the following \l{List of Language Items}{built-in}, \l{List of Convenience Items}{convenience}, and \l{List of Probes}{probe} items to define projects. */ /*! \qmlmodule QbsLanguageItems \title List of Language Items \QBS provides the following built-in QML items to define projects. These are the primitives upon which all other \QBS items are built. */ /*! \qmlmodule QbsConvenienceItems \title List of Convenience Items \QBS provides the following QML items for convenience. */ /*! \qmlmodule QbsProbes \title List of Probes These are the probes shipped with \QBS. Probes are used to retrieve information from the system prior to building. Typically, probes call external processes to get the required information. For details, see \l{Probe}{Probe} page. */ qbs-src-2.6.1/doc/reference/commands.qdoc0000644000175100001660000002316414776170045017632 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ // TODO: "\c" markup is used for all properties in table due to QTBUG-35505. /*! \page commands.html \title Command and JavaScriptCommand \brief Types of commands to be used in rules A \e command is what \QBS executes at build time. It is represented in the language by an object of type \c Command, which runs a process, or \c JavaScriptCommand, which executes arbitrary JavaScript code. A command is always created in the prepare script of a \c Rule. \section1 Command A \c Command represents a process that will be invoked at build time. Its constructor arguments are the binary to run and a list of command-line arguments. For instance: \code var insaneCommand = new Command("rm", ["-r", "/"]); \endcode The \l{Rule} item documentation shows a \c Command in context. \section1 JavaScriptCommand A \c JavaScriptCommand represents a chunk of JavaScript code that is run at build time. For instance: \code var cmd = new JavaScriptCommand(); cmd.apology = "Sorry."; cmd.sourceCode = function() { console.info("I'm a rather pointless command."); console.info(apology); }; \endcode Within the source code, the special identifiers \c project and \c product (giving access to project and product properties, respectively) as well as \c inputs and \c outputs are available. As the example shows, arbitrary properties can be set on the command object and then used within the source code. This technique is typically used to forward values from the prepare script to the command. The \l{Rule} item documentation shows a \c JavaScriptCommand in context. \section1 Properties \section2 Common Properties The following properties are available in both \c Command and \c JavaScriptCommand. \table \header \li Property \li Type \li Default \li Description \row \li \c description \li string \li empty \li A message that is displayed when the command is executed. \row \li \c extendedDescription \li string \li empty \li A detailed description that is displayed when the command is executed. \row \li \c highlight \li string \li empty \li A tag that can be used to influence how the \c description is displayed. In principle, the values are arbitrary. The \QBS command-line tool understands the following values and maps them to different colors if the output device is a terminal: \list \li "compiler" indicates that the command processes source code \li "linker" indicates that the command links objects \li "codegen" indicates that the command generates source code \li "filegen" indicates that the command creates arbitrary files \endlist All other values are mapped to the default color. \row \li \c jobPool \li string \li empty \li Determines which job pool the command will use. An empty string, which is the default, stands for the global job pool. See \l{JobLimit}{here} and \l{job-pool-howto}{here} for more information on job pools. \row \li \c silent \li bool \li false \li A flag that controls whether the \c description is printed. Set it to \c true for commands that users need not know about. \note If this property is \c false, then \c description must not be empty. \row \li \c timeout \li int \li -1 \li Time limit for the command execution in seconds. If the command does not finish within the timeout, it is cancelled. In case of a \c Command, the process is requested to terminate. If it does not terminate within three seconds, it is killed. A value below or equal to 0 means no timeout. \br This property was introduced in Qbs 1.15. \endtable \section2 Command Properties \table \header \li Property \li Type \li Default \li Description \row \li \c arguments \li stringList \li empty \li The list of arguments to invoke the command with. Explicitly setting this property overrides an argument list provided when instantiating the object. \row \li \c environment \li stringList \li empty \li A list of environment variables that are added to the common build environment. They are provided as a list of strings in the form "varName=value". \row \li \c maxExitCode \li int \li 0 \li The maximum exit code from the process to interpret as success. Setting this should rarely be necessary, as all well-behaved applications use values other than zero to indicate failure. \row \li \c program \li string \li undefined \li The binary to invoke. Explicitly setting this property overrides a path provided when instantiating the object. \row \li \c relevantEnvironmentVariables \li stringList \li undefined \li Names of environment variables that the invoked binary considers. If one of these variables changes in the build environment, the command will be re-run even if the input files are still up to date. \row \li \c responseFileThreshold \li int \li 32000 on Windows, -1 elsewhere \li If this value is greater than zero and less than the length of the full command line, and if \c responseFileUsagePrefix is not empty, the contents of the command line are moved to a temporary file, whose path becomes the entire contents of the argument list. The program is then supposed to read the full argument list from that file. This mechanism is mainly useful to work around Windows limitations regarding the maximum length of the command line and will only work with programs that explicitly support it. \row \li \c responseFileArgumentIndex \li int \li 0 \li Index of the first argument to include in the response file. For example this may be used in conjunction with a compiler wrapper where the first argument (the path to the compiler) must be included on the raw command line. \row \li \c responseFileUsagePrefix \li string \li empty \li The prefix that informs \c program that the rest of the argument is a path to a file containing the actual command line. \row \li \c stderrFilterFunction \li function \li undefined \li A function that takes as input the command's actual standard error output and returns a string that is presented to the user as the command's standard error output. If it is not set, the output is shown unfiltered. \row \li \c stdoutFilterFunction \li function \li undefined \li A function that takes as input the command's actual standard output and returns a string that is presented to the user as the command's standard output. If it is not set, the output is shown unfiltered. \row \li \c workingDirectory \li string \li empty \li The program's working directory. \row \li \c stdoutFilePath \li string \li undefined \li Redirects the filtered standard output content to \c stdoutFilePath. If \c stdoutFilePath is undefined, the filtered standard output is forwarded to \QBS, possibly to be printed to the console. \row \li \c stderrFilePath \li string \li undefined \li Redirects the filtered standard error output content to \c stderrFilePath. If \c stderrFilePath is undefined, the filtered standard error output is forwarded to \QBS, possibly to be printed to the console. \endtable \section2 JavaScriptCommand Properties \table \header \li Property \li Type \li Default \li Description \row \li \c sourceCode \li function \li undefined \li The JavaScript function to execute. \endtable */ qbs-src-2.6.1/doc/reference/jsextensions/0000755000175100001660000000000014776170045017707 5ustar runnerdockerqbs-src-2.6.1/doc/reference/jsextensions/jsextension-file.qdoc0000644000175100001660000000753614776170045024060 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-file.html \ingroup list-of-builtin-services \title File Service \brief Provides operations on the file system. The \c File service offers limited access to the file system for operations such as copying or removing files. \section1 Available Operations \section2 copy \code File.copy(sourceFilePath: string, targetFilePath: string): boolean \endcode Copies \c sourceFilePath to \c targetFilePath. Any directory components in \c targetFilePath that do not yet exist will be created. If \c sourceFilePath is a directory, a recursive copy will be made. If an error occurs, a JavaScript exception will be thrown. \note \c targetFilePath must be the counterpart of \c sourceFilePath at the new location, \b{not} the new parent directory. This allows the copy to have a different name and is true even if \c sourceFilePath is a directory. \note The file is not copied if the source file timestamp is older than the destination file timestamp. If you want to replace the newer file, you need to remove it first via File.remove(). \section2 exists \code File.exists(filePath: string): boolean \endcode Returns true if and only if there is a file at \c filePath. \section2 directoryEntries \code File.directoryEntries(path: string, filter: File.Filter): string[] \endcode Returns a sorted list of the directory \c{path}'s contents non-recursively, filtered by \c filter. The values of \c filter are equivalent to Qt's \c QDir::Filter. \section2 lastModified \code File.lastModified(filePath: string): number \endcode Returns the time of last modification for the file at \c filePath. The concrete semantics of the returned value are platform-specific. You should only rely on the property that a smaller value indicates an older timestamp. \section2 makePath \code File.makePath(path: string): boolean \endcode Makes the directory at \c path, creating intermediate directories if necessary. Conceptually equivalent to \c{mkdir -p} \section2 move \code File.move(oldPath: string, newPath: string, overwrite: boolean = true): boolean \endcode Renames the file \c oldPath to \c newPath. Returns \c true if successful; otherwise returns \c false. If a file with the name \c newPath already exists, and \c overwrite is \c false, \c move() returns \c false (that is, the file will not be overwritten). \section2 remove \code File.remove(filePath: string): boolean \endcode Removes the file at \c filePath. In case of a directory, it will be removed recursively. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-temporarydir.qdoc0000644000175100001660000000443714776170045025657 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-temporarydir.html \ingroup list-of-builtin-services \title TemporaryDir Service \brief Creates a unique directory for temporary use. The \c TemporaryDir service creates a unique directory for temporary use. \section1 Available Operations \section2 Constructor \code TemporaryDir() \endcode Allocates and returns a new TemporaryDir object. This method creates the temporary directory. \section2 isValid \code isValid(): boolean \endcode Returns \c true if the temporary directory was created successfully. \section2 path \code path(): string \endcode Returns the path to the temporary directory. Empty if the temporary directory could not be created. \section2 remove \code remove(): boolean \endcode Removes the temporary directory, including all its contents. Returns \c true if removing was successful. It is recommended to always call this function as soon as you are finished with the temporary directory. The directory will not be removed automatically. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-utilities.qdoc0000644000175100001660000000561614776170045025151 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-utilities.html \ingroup list-of-builtin-services \title Utilities Service \brief Provides miscellaneous operations. The \c Utilities service offers miscellaneous operations. \section1 Available Operations \section2 cStringQuote \badcode Utilities.cStringQuote(str: string): string \endcode Takes a string and escapes special characters in a way that the result is suitable for use as a C/C++ string literal. This function is typically used to specify values for \l{cpp::defines}{cpp.defines}. \section2 getHash \badcode Utilities.getHash(key: string): string \endcode Calculates a 16-byte hash of the input and returns it. Rules in modules should use this function to find unique locations for output artifacts in the build directory without duplicating the whole directory structure of the respective input file (to deal with the case of two files with the same name in different subdirectories of the same product). \section2 rfc1034Identifier \badcode Utilities.rfc1034Identifier(str: string): string \endcode Returns an RFC-1034 compliant identifier based on the given string by replacing each character that is not Latin alphanumeric or \c{.} with \c{-}. \section2 versionCompare \badcode Utilities.versionCompare(version1: string, version2: string): number \endcode Interprets the two arguments as version numbers and returns a number that is smaller than, equal to, or greater than zero if \c version1 is smaller than, equal to, or greater than \c version2, respectively. The version strings consist of up to three numbers separated by dots. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-textfile.qdoc0000644000175100001660000000707514776170045024763 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-textfile.html \ingroup list-of-builtin-services \title TextFile Service \brief Provides read and write operations on text files. The \c TextFile service allows you to read from and write into text files. \section1 Related Declarations \section2 TextFile.OpenMode \code enum TextFile.OpenMode { ReadOnly, WriteOnly, ReadWrite, Append } \endcode List of modes that a file may be opened in. The OpenMode values can be combined with the bitwise or operator. \section1 Available operations \section2 Constructor \code TextFile(filePath: string, openMode: OpenMode = TextFile.ReadOnly) \endcode Opens the file at \c filePath in the given mode and returns the object representing the file. \note The mode influences which of the operations listed below can actually be used on the file. \section2 atEof \code atEof(): boolean \endcode Returns \c{true} if no more data can be read from the file, \c{false} otherwise. \section2 close \code close(): void \endcode Closes the file. It is recommended to always call this function as soon as you are finished with the file, in order to keep the number of in-flight file descriptors as low as possible. \section2 filePath \code filePath(): string \endcode The absolute path of the file represented by this object. \section2 readAll \code readAll(): string \endcode Reads all data from the file and returns it. \section2 readLine \code readLine(): string \endcode Reads one line of text from the file and returns it. The returned string does not contain the newline characters. \section2 setCodec \code setCodec(codec: string): void \endcode Sets the text codec to \c codec. The supported codecs are the same as for \c QTextCodec, for example: "UTF-8", "UTF-16", and "ISO 8859-1". \section2 truncate \code truncate(): void \endcode Truncates the file, that is, gives it the size of zero, removing all content. \section2 write \code write(data: string): void \endcode Writes \c data into the file at the current position. \section2 writeLine \code writeLine(data: string): void \endcode Writes \c data into the file at the current position and appends the newline character(s). */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-fileinfo.qdoc0000644000175100001660000001436514776170045024732 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-fileinfo.html \ingroup list-of-builtin-services \title FileInfo Service \brief Provides operations on file paths. The \c FileInfo service offers various operations on file paths, such as turning absolute paths into relative ones, splitting a path into its components, and so on. \section1 Available Operations \section2 baseName \code FileInfo.baseName(filePath: string): string \endcode Returns the file name of \c filePath up to (but not including) the first '.' character. \section2 canonicalPath \code FileInfo.canonicalPath(filePath: string): string \endcode Returns a canonicalized \c filePath, i.e. an absolute path without symbolic links or redundant "." or ".." elements. On Windows, drive substitutions are also resolved. It is recommended to use \c{canonicalPath} in only those cases where canonical paths are really necessary. In most cases, \c{cleanPath} should be enough. \section2 cleanPath \code FileInfo.cleanPath(filePath: string): string \endcode Returns \c filePath without redundant separators and with resolved occurrences of \c{.} and \c{..} components. For instance, \c{/usr/local//../bin/} becomes \c{/usr/bin}. \section2 completeBaseName \code FileInfo.completeBaseName(filePath: string): string \endcode Returns the file name of \c filePath up to (but not including) the last '.' character. \section2 completeSuffix \code FileInfo.completeSuffix(filePath: string): string \endcode Returns the file suffix of \c filePath from (but not including) the last '.' character. \funsince 1.12 \section2 fileName \code FileInfo.fileName(filePath: string): string \endcode Returns the last component of \c filePath, that is, everything after the last '/' character. \section2 fromNativeSeparators \code FileInfo.fromNativeSeparators(filePath: string): string \endcode On Windows hosts, this function behaves the same as \l fromWindowsSeparators. On other operating systems, it returns the input unmodified. \section2 fromWindowsSeparators \code FileInfo.fromWindowsSeparators(filePath: string): string \endcode Returns \c filePath with all '\\' characters replaced by '/'. \section2 isAbsolutePath \code FileInfo.isAbsolutePath(filePath: string, hostOS?: string[]): boolean \endcode Returns true if \c filePath is an absolute path and false if it is a relative one. If \c hostOS is specified, treats \c filePath as a file path of the kind found on that platform. This parameter defaults to the host OS on which \QBS is running and should normally be omitted. \section2 joinPaths \code FileInfo.joinPaths(...paths: string[]): string \endcode Concatenates the given paths using the '/' character. \section2 path \code FileInfo.path(filePath: string, hostOS?: string[]): string \endcode Returns the part of \c filePath that is not the file name, that is, everything up to (but not including) the last '/' character. If \c filePath is just a file name, then '.' is returned. If \c filePath ends with a '/' character, then the file name is assumed to be empty for the purpose of the above definition. If \c hostOS is specified, treats \c filePath as a file path of the kind found on that platform. This parameter defaults to the host OS on which \QBS is running and should normally be omitted. \section2 relativePath \code FileInfo.relativePath(dirPath: string, filePath: string): string \endcode Returns a relative path so that joining \c dirPath and the returned path results in \c filePath. If necessary, '..' components are inserted. The function assumes \c dirPath and \c filePath to be absolute paths and \c dirPath to be a directory. \section2 suffix \code FileInfo.suffix(filePath: string): string \endcode Returns the file suffix of \c filePath from (but not including) the first '.' character. \funsince 1.12 \section2 toNativeSeparators \code FileInfo.toNativeSeparators(filePath: string): string \endcode On Windows hosts, this function behaves the same as \l toWindowsSeparators. On other operating systems, it returns the input unmodified. \section2 toWindowsSeparators \code FileInfo.toWindowsSeparators(filePath: string): string \endcode Returns \c filePath with all '/' characters replaced by '\\'. \section2 pathListSeparator \code FileInfo.pathListSeparator(): string \endcode Returns the host operating system separator for a path list that is used in environment variables or other contexts. \funsince 1.22 \section2 pathSeparator \code FileInfo.pathSeparator(): string \endcode Returns the host operating system path separator. \funsince 1.22 \section2 executableSuffix \code FileInfo.executableSuffix(): string \endcode Returns the host operating system executable suffix. \funsince 1.23 */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-propertylist.qdoc0000644000175100001660000001137314776170045025713 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-propertylist.html \ingroup list-of-builtin-services \title PropertyList Service \brief Provides read, write and convert operations on property list files. The \c PropertyList service allows you to read and write property list files in all formats supported by the Core Foundation API: XML, binary, JSON, and OpenStep (read-only). This service is only available on Darwin platforms such as iOS, macOS, tvOS, and watchOS. \section1 Available operations \section2 Constructor \code PropertyList() \endcode Allocates and returns a new PropertyList object. \section2 clear \code clear(): void \endcode Voids the property list by deleting its internal object reference. \section2 isEmpty \code isEmpty(): boolean \endcode Returns true if the property list has no internal object reference set, otherwise false. \section2 format \code format(): string \endcode Returns the data format that the property list data was deserialized from. This property is set after calling \c readFromString or \c readFromFile. Possible return values include: \c "binary1", \c "json", \c "openstep", and \c "xml1". If the property list object is empty or the input format could not be determined, returns \c undefined. \section2 readFromFile \code readFromFile(filePath: string): void \endcode Parses the file and stores the result in the property list. Throws an exception if an I/O error occurs or the input is in an invalid format. \section2 readFromObject \code readFromObject(obj: any): void \endcode Sets the given object as the property list's internal object. \c format() will return \c undefined as this method does not deserialize a storage format. \section2 readFromString \code readFromString(input: string): void \endcode Parses \c input and stores the result in the property list. This is most useful for initializing a property list object from the result of a \c JSON.stringify call. Throws an exception if the input is in an invalid format. \section2 toObject \code toObject(): any \endcode Returns an object representing the property list. \section2 toJSON \code toJSON(style: string = "compact"): string \endcode Returns a string representation of the property list in JSON format. Possible values for \c style include \c "pretty" and \c "compact". The default is compact. \section2 toString \code toString(format: string): string \endcode Returns a string representation of the property list in the specified format. Possible values for \c format include: \c "json" (compact), \c "json-compact", \c "json-pretty", and \c "xml1". Currently, the OpenStep format is not supported. Throws an exception if the object cannot be written in the given format. \section2 toXMLString \code toXMLString(): string \endcode Returns a string representation of the property list in XML format. This function is a synonym for \c toString("xml1"). \section2 writeToFile \code writeToFile(filePath: string, format: string): void \endcode Writes the property list to the file in the given format. Possible values for \c format include: \c "binary1", \c "json" (compact), \c "json-compact", \c "json-pretty", and \c "xml1". Currently, the OpenStep format is not supported for writing. Throws an exception if an I/O error occurs or the object cannot be written in the given format. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-binaryfile.qdoc0000644000175100001660000000712614776170045025260 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 Sergey Belyashov ** Copyright (C) 2017 Denis Shienkov ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-binaryfile.html \ingroup list-of-builtin-services \title BinaryFile Service \brief Provides read and write operations on binary files. The \c BinaryFile service allows you to read from and write into binary files. \section1 Related Declarations \section2 BinaryFile.OpenMode \code enum BinaryFile.OpenMode { ReadOnly, WriteOnly, ReadWrite } \endcode List of modes that a file may be opened in. The OpenMode values can be combined with the bitwise or operator. \section1 Available operations \section2 Constructor \code BinaryFile(filePath: string, openMode: OpenMode = BinaryFile.ReadOnly) \endcode Opens the file at \c filePath in the given mode and returns the object representing the file. \note The mode influences which of the operations listed below can actually be used on the file. \section2 atEof \code atEof(): boolean \endcode Returns \c{true} if no more data can be read from the file, \c{false} otherwise. \section2 close \code close(): void \endcode Closes the file. It is recommended to always call this function as soon as you are finished with the file, in order to keep the number of in-flight file descriptors as low as possible. \section2 filePath \code filePath(): string \endcode The absolute path of the file represented by this object. \section2 size \code size(): number \endcode Returns the size of the file (in bytes). \section2 resize \code resize(size: number): void \endcode Sets the file \c size (in bytes). If \c size is larger than the file currently is, the new bytes will be set to 0; if \c size is smaller, the file is truncated. \section2 pos \code pos(): number \endcode Returns the position that data is written to or read from. \section2 seek \code seek(pos: number): void \endcode Sets the current position to \c pos. \section2 read \code read(size: number): number[] \endcode Reads at most \c size bytes of data from the file and returns it as an array. \section2 write \code write(data: number[]): void \endcode Writes \c data into the file at the current position. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-xml.qdoc0000644000175100001660000001760214776170045023734 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-xml.html \ingroup list-of-builtin-services \title Xml Service \brief Provides a DOM parser and generator to JavaScript. The \c Xml service enables you to access and manipulate XML Document Object Model (DOM) documents. The entire document is a \e {document node}, each XML element is an \e {element node}, the text paragraphs in the XML elements are \e {text nodes}, and each attribute is an \e {attribute node}. XML DOM presents documents as tree structures. The contents of the nodes can be accessed in the tree. They can be modified or deleted, and new nodes can be created. The nodes in the node tree have a hierarchical relationship to each other. The top node is called the \e root. Each node, except the root, has exactly one \e parent node, while it can have any number of \e children. Nodes with the same parent are called \e siblings. \section1 XML DOM Document Node Operations A document node represents an entire document. That is, the root of the DOM tree. \section2 Constructor \badcode Xml.DomDocument() \endcode Creates an XML DOM root node that can contain one element. \section2 createCDATASection \badcode Xml.DomDocument.createCDATASection(value: string) \endcode Creates a CDATA section that is not parsed by a parser. It can be used to include XML fragments without having to escape the delimiters, for example. Tags inside the section are not treated as markup nor are entities expanded. \section2 createElement \badcode Xml.DomDocument.createElement(tagName: string) \endcode Creates an element that can contain other elements, CDATA sections, and text nodes. \section2 createTextNode \badcode Xml.DomDocument.createTextNode(value: string) \endcode Creates a text node that represents textual content in an element or attribute. \section2 documentElement \badcode Xml.DomDocument.documentElement() \endcode Returns the document element. \section2 load \badcode Xml.DomDocument.load(filePath: string): void \endcode Loads the document specified by \c filePath. \section2 save \badcode Xml.DomDocument.save(filePath: string, indentation: int): void \endcode Saves the document at the location specified by \c filePath with the indentation specified by \c int. \section2 setContent \badcode Xml.DomDocument.setContent(content: string) \endcode Returns the content of the document. \section2 toString \badcode Xml.DomDocument.toString(indentation: int) \endcode Converts the document to a string with the indentation specified by \c int. \section1 XML DOM Node Operations A node represents a single node in the document tree. There are several different types of nodes, such as element, attribute, and text nodes. All objects inherit the node properties for handling parents and children, even if they cannot have parents or children. For example, attempting to add children to text nodes results in a DOM error. \section2 Constructor \badcode Xml.DomNode() \endcode Creates an XML DOM node. \section2 appendChild \badcode Xml.DomNode.appendChild(tagName: string) \endcode Appends a new child node to the end of the list of children of a node. \section2 attribute \badcode Xml.DomNode.attribute(name: string, defaultValue: string) \endcode Returns the name and default value of the attribute. \section2 clear \badcode Xml.DomNode.clear() \endcode Clears the contents of the node. \section2 data \badcode Xml.DomNode.data() \endcode Returns the contents of the text node, CDATA section, or character data node. \section2 firstChild \badcode Xml.DomNode.firstChild(tagName: string) \endcode Returns the first child of a node. \section2 hasAttribute \badcode Xml.DomNode.hasAttribute(name: string) boolean \endcode Returns \c true if the node has the specified attribute. \section2 hasAttributes \badcode Xml.DomNode.hasAttributes() boolean \endcode Returns \c true if the node has attributes. \section2 hasChildNodes \badcode Xml.DomNode.hasChildNodes() boolean \endcode Returns \c true if the node has children. \section2 insertAfter \badcode Xml.DomNode.insertAfter(newChild: tagName, refChild: tagName) \endcode Inserts a new child node after the child node specified by \c refChild. \section2 insertBefore \badcode Xml.DomNode.insertBefore(newChild: tagName, refChild: tagName) \endcode Inserts a new child node before the child node specified by \c refChild. \section2 isCDATASection \badcode Xml.DomNode.isCDATASection() boolean \endcode Returns \c true if this is a CDATA section. \section2 isElement \badcode Xml.DomNode.isElement() boolean \endcode Returns \c true if this is an element. \section2 isText \badcode Xml.DomNode.isText() boolean \endcode Returns \c true if this is a text node. \section2 lastChild \badcode Xml.DomNode.lastChild(tagName: string) \endcode Returns the last child of a node. \section2 nextSibling \badcode Xml.DomNode.nextSibling(tagName: string) \endcode Returns the node immediately following a node. \section2 parentNode \badcode Xml.DomNode.parentNode() \endcode Returns the parent of the node. \section2 previousSibling \badcode Xml.DomNode.previousSibling(tagName: string) \endcode Returns the node before a node. \section2 removeChild \badcode Xml.DomNode.removeChild(tagName: string) \endcode Removes the child node. \section2 replaceChild \badcode Xml.DomNode.replaceChild(newChild: tagName, oldChild: tagName) \endcode Replaces a child node with another one. \section2 setAttribute \badcode Xml.DomNode.setAttribute(name: string, value: string) \endcode Sets the name and value of an attribute. \section2 setData \badcode Xml.DomNode.setData(value: string): void \endcode Sets the data of the node to a text node, CDATA section, or character data node. \section2 setTagName \badcode Xml.DomNode.setTagName(tagName: string) \endcode Sets the tag name of the node. \section2 tagName \badcode Xml.DomNode.tagName() \endcode Returns the tag name of the node. \section2 text \badcode Xml.DomNode.text() \endcode Returns the text of the node. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextensions-general.qdoc0000644000175100001660000001153314776170045024731 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Petroules Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextensions-general.html \ingroup list-of-builtin-services \title General Services \brief Provides various operations. These are operations that do not fit into any of the other categories. They are automatically available in any \QBS project file or JavaScript file. \section1 Available Operations \section2 require \code require(identifier: string): any \endcode Loads an extension and returns an object representing the extension. If \a identifier is a relative or absolute file path, this function will load a JavaScript file and return an object containing the evaluated context of that file. Otherwise, loads a \QBS extension named \a identifier and returns an object that contains the extension's context. This function is only available in JavaScript files and is designed to behave similarly to the CommonJS/RequireJS/Node.js module resolution systems. \code var MyFunctions = require("./myfunctions.js"); MyFunctions.doSomething(); var FileInfo = require("qbs.FileInfo"); var fileName = FileInfo.fileName(filePath); \endcode \section1 Extensions to JavaScript Built-in Objects \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[] \endcode Returns a copy of this array joined with the array \c{other}. Duplicates that would originate from the concatenation are removed. The order of elements is preserved. \section1 Console API \QBS provides a subset of the non-standard Console API available in most ECMAScript runtimes. The output of each of these functions will only be displayed if the logging level is at least the level which the function outputs at. Logging levels from lowest to highest are: 'error', 'warning', 'info', 'debug', and 'trace'. The default is 'info'. \warning The contents of this section are subject to change in order to align with future \l{https://www.w3.org/2011/08/browser-testing-charter.html}{standardization} \l{https://github.com/DeveloperToolsWG/console-object/blob/master/api.md}{processes}. \section2 console.debug \code console.debug(s: string): void \endcode This method is an alias for \c{console.log()}. \section2 console.error \code console.error(s: string): void \endcode Logs an \c{error} level message. Outputs to stderr when the logger output is a terminal. The string will be prefixed with \c{"ERROR: "} and colored red when the logger output is a color-capable terminal. \section2 console.info \code console.info(s: string): void \endcode Logs an \c{info} level message. Outputs to stdout when the logger output is a terminal. \section2 console.log \code console.log(s: string): void \endcode Logs a \c{debug} level message. Outputs to stderr when the logger output is a terminal. \section2 console.warn \code console.warn(s: string): void \endcode Logs a \c{warning} level message. Outputs to stderr when the logger output is a terminal. The string will be prefixed with \c{"WARNING: "} and colored yellow when the logger output is a color-capable terminal. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-host.qdoc0000644000175100001660000001100114776170045024074 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Raphaël Cotty ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-host.html \ingroup list-of-builtin-services \title Host Service \brief Provides host information. The \c Host service offers various information about the host environment, such as operating system names, platform name. \section1 Available Operations \section2 architecture \code Host.architecture(): string \endcode Returns the host operating system architecture. See \l{qbs::architecture}{qbs.architecture} for the target-specific equivalent property. architecture. \funsince 1.22 \section2 os \code Host.os(): string[] \endcode Returns the host operating system names. See the \l{qbs::targetOS}{qbs.targetOS} for the target-specific equivalent property. \funsince 1.22 \section2 platform \code Host.platform(): string \endcode Returns the host operating system platform. See the \l{qbs::targetPlatform}{qbs.targetPlatform} for the target-specific equivalent property. \funsince 1.22 \section2 osVersion \code Host.osVersion(): string \endcode Returns the host operating system version. Currently, only defined for Windows and Apple platforms. Consists of two or three numbers separated by dots. For example, \c "10.9" or \c "6.3.9600". \funsince 1.22 \section2 osBuildVersion \code Host.osBuildVersion(): string \endcode Returns the host operating system build version. Currently, only defined for Windows and Apple platforms. On Windows, this is the 4 or 5 digit Windows build number and is equivalent to \l{qbs::}{versionPatch}. On Apple platforms, this is a standard build number in the Apple versioning scheme. For example, \c "13C64". \funsince 1.22 \section2 osVersionParts \code Host.osVersionParts(): string[] \endcode Returns the host operating system version as a list. For example, Windows 8.1 (version 6.3.9600) would correspond to a value of \c[6, 3, 9600]. \funsince 1.22 \section2 osVersionMajor \code Host.osVersionMajor(): number \endcode Returns the host operating system major version. \funsince 1.22 \section2 osVersionMinor \code Host.osVersionMinor(): number \endcode Returns the host operating system minor version. \funsince 1.22 \section2 osVersionPatch \code Host.osVersionPatch(): number \endcode Returns the host operating system patch level. \funsince 1.22 \section2 nullDevice \code Host.nullDevice(): string[] \endcode Returns the platform-specific file path corresponding to the null device. \funsince 1.22 */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-environment.qdoc0000644000175100001660000000513014776170045025471 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-environment.html \ingroup list-of-builtin-services \title Environment Service \brief Provides operations on the system environment. The \c Environment service offers access to the system environment or process environment. \section1 Available Operations \section2 currentEnv \code Environment.currentEnv(): { [key: string]: string; } \endcode Returns the environment of \QBS in the current context as an object whose properties are the environment variables. \section2 getEnv \code Environment.getEnv(key: string): string \endcode Tries to find a variable with the given name in the current context's environment and returns its value. If no such variable could be found, \c undefined is returned. \section2 putEnv \code Environment.putEnv(key: string, value: string): void \endcode Sets the value of the environment variable with the given name in the build or run environment. This method is only available in the \c Module.setupBuildEnvironment and \c Module.setupRunEnvironment scripts. \section2 unsetEnv \code Environment.unsetEnv(key: string): void \endcode Unsets the environment variable with the given name from the build or run environment. This method is only available in the \c Module.setupBuildEnvironment and \c Module.setupRunEnvironment scripts. */ qbs-src-2.6.1/doc/reference/jsextensions/jsextension-process.qdoc0000644000175100001660000001377014776170045024614 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page jsextension-process.html \ingroup list-of-builtin-services \title Process Service \brief Allows you to start external processes. The \c Process service allows you to start processes, track their output, and so on. \section1 Available Operations \section2 Constructor \code Process() \endcode Allocates and returns a new Process object. \section2 close \code close(): void \endcode Frees the resources associated with the process. It is recommended to always call this function as soon as you are finished with the process. \section2 closeWriteChannel \code closeWriteChannel(): void \endcode Schedules the stdin channel of process to be closed. The channel will close once all data has been written to the process. After calling this function, any attempts to write to the process will do nothing. See \c QProcess::closeWriteChannel() for more details. \section2 exec \code exec(filePath: string, arguments: string[], throwOnError: boolean): number \endcode Executes the program at \c filePath with the given argument list and blocks until the process is finished. If an error occurs (for example, there is no executable file at \c filePath) and \c throwOnError is true, then a JavaScript exception will be thrown. Otherwise (the default), -1 will be returned in case of an error. The normal return code is the exit code of the process. \section2 exitCode \code exitCode(): number \endcode Returns the exit code of the process. This is needed for retrieving the exit code from processes started via \c start(), rather than \c exec(). \section2 getEnv \code getEnv(varName: string): string \endcode Returns the value of the variable \c varName in the process' environment. \section2 kill \code kill(): void \endcode Kills the process, causing it to exit immediately. \section2 readLine \code readLine(): string \endcode Reads and returns one line of text from the process output, without the newline character(s). \section2 atEnd \code atEnd(): boolean \endcode Returns true if there is no more data to be read from the process output, otherwise returns false. \section2 readStdErr \code readStdErr(): string \endcode Reads and returns all data from the process' standard error channel. \section2 readStdOut \code readStdOut(): string \endcode Reads and returns all data from the process' standard output channel. \section2 setCodec \code setCodec(codec) \endcode Sets the text codec to \c codec. The codec is used for reading and writing from and to the process, respectively. The supported codecs are the same as for \c QTextCodec, for example: "UTF-8", "UTF-16", and "ISO 8859-1". \section2 setEnv \code setEnv(varName: string, varValue: string): string \endcode Sets the value of variable \c varName to \c varValue in the process environment. This only has an effect if called before the process is started. \section2 setWorkingDirectory \code setWorkingDirectory(path: string): void \endcode Sets the directory the process will be started in. This only has an effect if called before the process is started. \section2 start \code start(filePath: string, arguments: string[]): boolean \endcode Starts the program at \c filePath with the given list of arguments. Returns \c{true} if the process could be started and \c{false} otherwise. \note This call returns right after starting the process and should be used only if you need to interact with the process while it is running. Most of the time, you want to use \c exec() instead. \section2 terminate \code terminate(): void \endcode Tries to terminate the process. This is not guaranteed to make the process exit immediately; if you need that, use \c kill(). \section2 waitForFinished \code waitForFinished(timeout: number): boolean \endcode Blocks until the process has finished or \c timeout milliseconds have passed (default is 30000). Returns true if the process has finished and false if the operation has timed out. Calling this function only makes sense for processes started via \c start() (as opposed to \c exec()). \section2 workingDirectory \code workingDirectory(): string \endcode Returns the directory the process will be started in. \section2 write \code write(data: string): void \endcode Writes \c data into the process' input channel. \section2 writeLine \code writeLine(data: string): void \endcode Writes \c data, followed by the newline character(s), into the process' input channel. */ qbs-src-2.6.1/doc/reference/modules/0000755000175100001660000000000014776170045016623 5ustar runnerdockerqbs-src-2.6.1/doc/reference/modules/cpp-module.qdoc0000644000175100001660000015224214776170045021546 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype cpp \inqmlmodule QbsModules \since Qbs 1.0 \brief Provides C/C++ support. The \c cpp module contains the properties and rules for toolchains of the C/C++ family. On Apple platforms, this includes support for Objective-C/C++. \section2 Setting Up the Run Environment When running an application that has dependencies on dynamic libraries, the script specified by \l{Module::setupRunEnvironment}{Module.setupRunEnvironment} automatically adds the locations of the libraries to the environment. That is, to \c PATH on Windows, \c DYLD_LIBRARY_PATH on macOS, and \c LD_LIBRARY_PATH on Linux and other Unix platforms. If the value \c{"ignore-lib-dependencies"} shows up in the \c config array, this behavior is disabled. Users can set the value via the \l run command. \target dependency-parameters-cpp \section2 Dependency Parameters \table \header \li Parameter \li Type \li Since \li Default \li Description \row \li \c{link} \li \c{bool} \li 1.9 \li undefined \li If \c{false}, the dependency will not be linked, even if it is a valid input for a linker rule. This property affects library dependencies only. \row \li \c{linkWholeArchive} \li \c{bool} \li 1.9 \li undefined \li If \c{true}, then if the dependency is a static library, all of its objects will be pulled into target binary, even if their symbols do not appear to be used. This parameter is mainly useful when creating a dynamic library from static libraries. \row \li \c{symbolLinkMode} \li \c{string} \li 1.9 \li undefined \li Attribute specifying how the library or framework will be linked. May contain the values: "weak", "lazy", "reexport", and "upward"; refer to the Apple ld64 man page for full details. \c{undefined} uses normal linking. Currently only applies when linking for Apple platforms. Note that \c "lazy" mode is deprecated and doesn't work with Xcode 15 and above. \endtable \section2 Relevant File Tags \target filetags-cpp \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"application"} \li n/a \li 1.0.1 \li The rule that creates executable files (typically via a linker) attaches this tag to its output artifact. \row \li \c{"asm"} \li \c{*.s} (for GCC-like toolchains), \c{*.asm} (for MSVC) \li 1.1.0 \li Source files with this tag serve as inputs to a rule invoking the toolchain's assembler. One object file is generated for each such file. \row \li \c{"asm_cpp"} \li \c{*.S}, \c{*.sx} \li 1.1.0 \li Like \c{"asm"}, but for source files that need preprocessing. This tag only has an effect with GCC-like toolchains. \row \li \c{"c"} \li \c{*.c} (if \c combineCSources is not enabled) \li 1.0.1 \li Source files with this tag serve as inputs to a rule invoking the toolchain's C compiler. One object file is generated for each such file. \row \li \c{"c.combine"} \li \c{*.c} (if \c combineCSources is enabled) \li 1.8 \li Source files with this tag serve as inputs to a rule combining them into a single C file, which will then be compiled. \row \li \c{"cpp"} \li \c{*.C}, \c{*.cpp}, \c{*.cxx}, \c{*.c++}, \c{*.cc} (if \c combineCxxSources is not enabled) \li 1.0.1 \li Source files with this tag serve as inputs to a rule invoking the toolchain's C++ compiler. One object file is generated for each such file. \row \li \c{"cpp.combine"} \li \c{*.C}, \c{*.cpp}, \c{*.cxx}, \c{*.c++}, \c{*.cc} (if \c combineCxxSources is enabled) \li 1.8 \li Source files with this tag serve as inputs to a rule combining them into a single C++ file, which will then be compiled. \row \li \c{"c_pch_src"}, \c{"cpp_pch_src"}, \c{"objc_pch_src"}, \c{"objcpp_pch_src"} \li - \li 1.5 \li Files with this tag will be turned into precompiled headers for C, C++, Objective-C and Objective-C++, respectively. There can be only one such file per product and language. \row \li \c{"def"} \li - \li 1.17.0 \li This tag is used for a module-definition file (.def) to be passed to the linker. Such a file provides the linker with information about exports, attributes, and other information about the program to be linked. This file tag only has an effect with the MSVC toolchain. \row \li \c{"dynamiclibrary"} \li n/a \li 1.0.1 \li The rule that creates dynamic libraries (typically via a linker) attaches this tag to its output artifact. \row \li \c{"dynamiclibrary_import"} \li n/a \li 1.0.0 \li This tag is used for import libraries of dynamic libraries. For example, the MSVC linker rule creates a \c{dynamiclibrary_import} artifact \c{foo.lib} in addition to a \c{dynamiclibrary} artifact \c{foo.dll}. \row \li \c{"hpp"} \li \c{*.h}, \c{*.H}, \c{*.hpp}, \c{*.hxx}, \c{*.h++} \li 1.0.1 \li This tag is used for header files (C, C++, Objective-C and Objective-C++). No rule in this module generates output artifacts from such files directly, but the compiler rule will have a dependency on all rules that create such files. \row \li \c{"linkerscript"} \li - \li 1.5.0 \li This tag is used for \c ld linker scripts. You can provide such a file if you need to replace the default linker script. This file tag only has an effect with GCC-like toolchains. The linker needs to be \c{ld}-compatible. \row \li \c{"obj"} \li n/a \li 1.0.1 \li The rule that creates object files (typically via a compiler) attaches this tag to its output artifacts. Such files are usually intermediate artifacts of the build process and rarely need to be referenced in project files. \row \li \c{"objc"} \li \c{*.m} (if \c combineObjcSources is not enabled) \li 1.1.0 \li Source files with this tag serve as inputs to a rule invoking the toolchain's Objective-C compiler. One object file is generated for each such file. \row \li \c{"objc.combine"} \li \c{*.m} (if \c combineObjcSources is enabled) \li 1.8 \li Source files with this tag serve as inputs to a rule combining them into a single Objective-C file, which will then be compiled. \row \li \c{"objcpp"} \li \c{*.mm} (if \c combineObjcxxSources is not enabled) \li 1.1.0 \li Source files with this tag serve as inputs to a rule invoking the toolchain's Objective-C++ compiler. One object file is generated for each such file. \row \li \c{"objcpp.combine"} \li \c{*.mm} (if \c combineObjcxxSources is enabled) \li 1.8 \li Source files with this tag serve as inputs to a rule combining them into a single Objective-C++ file, which will then be compiled. \row \li \c{"rc"} \li \c{*.rc} \li 1.1.0 \li Files with this tag serve as inputs to the Windows resource compiler. One object file is generated for each such file. The tag has no effect on target platforms other than Windows. \row \li \c{"staticlibrary"} \li n/a \li 1.0.1 \li The rule that creates static libraries (typically via a linker) attaches this tag to its output artifact. \row \li \c{"versionscript"} \li - \li 1.5.0 \li This tag is used for \c ld linker scripts. You can provide such a file if you need fine-grained control over the symbols present in a shared library. This file tag only has an effect with GCC-like toolchains. The linker needs to be \c{ld}-compatible. \endtable \section2 Relevant Job Pools \target cpp-job-pools \table \header \li Pool \li Since \li Description \row \li \c{"assembler"} \li 1.13 \li The job pool used by rules that run the toolchain's assembler. This is only relevant for direct invocations of the assembler binary, not for running it indirectly via the compiler. \row \li \c{"compiler"} \li 1.13 \li The job pool used by rules that run a compiler. All language variants use the same pool. \row \li \c{"linker"} \li 1.13 \li The job pool used by rules that run a linker. \endtable */ /*! \qmlproperty bool cpp::allowUnresolvedSymbols \since Qbs 1.2 Set to \c true if you want the linking step to succeed even if the resulting binary contains unresolved symbols. Normally, this makes little sense, but in special cases it is possible that the respective symbols will be available at load time even if they are not present during linking. \nodefaultvalue */ /*! \qmlproperty string cpp::architecture The target architecture. \defaultvalue \l{qbs::architecture}{qbs.architecture} */ /*! \qmlproperty string cpp::endianness \since Qbs 1.9 Specifies the endianness of the target platform's processor architecture (\c{"big"} or \c{"little"}). The value is automatically detected from the compiler's default values, but can also be manually set in order to select a specific endianness when targeting bi-endian architectures like MIPS and PowerPC. \defaultvalue Compiler default value. */ /*! \qmlproperty bool cpp::debugInformation Whether to generate debug information. \defaultvalue \l{qbs::debugInformation}{qbs.debugInformation} */ /*! \qmlproperty bool cpp::combineCSources \since Qbs 1.8 Enabling this property on a \l{Product}{product} instructs the \l{FileTagger}{file tagger} to attach the tag \c{"c.combine"} to C sources, rather than \c{"c"}. As a result, all C sources of the product will be combined into a single file, which is then compiled. This can speed up initial compilation significantly, but is of course detrimental in the context of incremental builds. Also, perfectly legal code may fail to compile with this option due to the merging of translation units. To enable this property in a product that has sources that cannot be merged, put the sources into a dedicated \l{Group} and set their \l{Group::} {fileTags} property to \c{"c"}, overriding the file tagger. \note Module properties set on specific source files (that is, at the Group level) will not be taken into account when building the combined file. You either need to set these properties at the product level or prevent the respective files from getting combined via the mechanism described above. \defaultvalue \c false */ /*! \qmlproperty bool cpp::combineCxxSources \since Qbs 1.8 Like \l{cpp::}{combineCSources}, but for C++. The \l{filetags-cpp} {relevant file tags} are \c{"cpp"} and \c{"cpp.combine"}. \defaultvalue \c false \sa combineCSources */ /*! \qmlproperty bool cpp::combineObjcSources \since Qbs 1.8 Like \l{cpp::}{combineCSources}, but for Objective-C. The \l{filetags-cpp} {relevant file tags} are \c{"objc"} and \c{"objc.combine"}. \defaultvalue \c false \sa combineCSources */ /*! \qmlproperty bool cpp::combineObjcxxSources \since Qbs 1.8 Like \l{cpp::}{combineCSources}, but for Objective-C++. The \l{filetags-cpp} {relevant file tags} are \c{"objcpp"} and \c{"objcpp.combine"}. \defaultvalue \c false \sa combineCSources */ /*! \qmlproperty bool cpp::createSymlinks \unixproperty Whether to create version alias symlinks when building a dynamic library. \defaultvalue \c true */ /*! \qmlproperty bool cpp::discardUnusedData \since Qbs 1.10 If this property is \c true, the linker will discard data from objects that it determines to be unused. With MSVC and on Apple platforms, the granularity is per symbol, elsewhere it is per section. \nodefaultvalue */ /*! \qmlproperty bool cpp::separateDebugInformation \since Qbs 1.4 Whether to store debug information in an external file or bundle instead of within the binary. The type of files that will be generated when this property is \c{true} is dependent on the compiler and target platform: \list \li With MSVC, this property controls the generation of \c{.pdb} (Program Debug Database) files. \li On Apple platforms with GCC or Clang, this property controls the generation of \c{.dSYM} (DWARF Symbol) bundles or, if \l{cpp::}{dsymutilFlags} contains the \c{-f} or \c{--flat} flags, \c{.dwarf} symbol files. \li On other platforms with GCC or Clang (including Windows/MinGW), this property controls the generation of \c{.debug} symbol files. \endlist \defaultvalue \c{true} for MSVC and with GCC or Clang on Apple platforms, otherwise \c{false}. \sa debugInformation, {How do I separate and install debugging symbols?} */ /*! \qmlproperty stringList cpp::defines A list of preprocessor macros that gets passed to the compiler. To set macro values, use the following syntax: \code cpp.defines: ["USE_COLORS=1", 'COLOR_STR="blanched almond"'] \endcode \nodefaultvalue */ /*! \qmlproperty stringList cpp::platformDefines A list of preprocessor macros that are used for all projects that are built for the current target platform. User project files usually do not set this property. \nodefaultvalue */ /*! \qmlproperty pathList cpp::includePaths A list of include paths. Relative paths are considered to be relative to the \c .qbs product file they are used in. \nodefaultvalue */ /*! \qmlproperty pathList cpp::systemIncludePaths A list of include paths that are passed as system include paths to the compiler. For header files in those paths, warnings will be ignored. Relative paths are considered to be relative to the \c .qbs product file they are used in. \nodefaultvalue */ /*! \qmlproperty stringList cpp::systemRunPaths \since Qbs 1.6 The paths the dynamic linker uses on process start-up to locate dynamic libraries. \defaultvalue Auto-detected for host builds on Linux via \c ldconfig, \c{["/lib", "/usr/lib"]} otherwise on Unix, \c [] on Windows. */ /*! \qmlproperty pathList cpp::libraryPaths A list of library search paths. The paths will be passed to the linker in the appropriate way. For example, the \c {-L} argument will be used when using \c {ld}-like linkers. Relative paths are considered to be relative to the \c .qbs product file they are used in. \nodefaultvalue \sa dynamicLibraries, {How do I create a module for a third-party library?} */ /*! \qmlproperty stringList cpp::dynamicLibraries A List of dynamic libraries to be linked. If the library is part of your project, consider using a \l{Depends} item instead. Each library can be specified in one of two ways: \list \li An absolute file path (for example, \c "/foo/bar.lib"), in which case it is passed directly to the linker, ignoring \l libraryPaths. \li A library basename (for example, \c "bar"), in which case the directory that contains the library must be provided via \l libraryPaths. \endlist Relative paths (\c "foo/bar.lib") are not allowed. \nodefaultvalue \sa libraryPaths, {How do I create a module for a third-party library?} */ /*! \qmlproperty stringList cpp::staticLibraries A list of static libraries to be linked. If the library is part of your project, consider using a \l{Depends} item instead. \nodefaultvalue */ /*! \qmlproperty string cpp::executablePrefix A string to prepend to the executable file \l{Product::targetName}{name}. \defaultvalue \c "" */ /*! \qmlproperty string cpp::dynamicLibraryPrefix A string to prepend to the dynamic library file \l{Product::targetName}{name}. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c "" or \c "lib" */ /*! \qmlproperty string cpp::loadableModulePrefix \appleproperty A string to prepend to the Darwin loadable module file \l{Product::targetName}{name}. \defaultvalue \c "" */ /*! \qmlproperty string cpp::staticLibraryPrefix A string to prepend to the static library file \l{Product::targetName}{name}. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c "" or \c "lib" */ /*! \qmlproperty string cpp::executableSuffix A string to append to the executable file \l{Product::targetName}{name}. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c "" or \c ".exe" */ /*! \qmlproperty string cpp::dynamicLibrarySuffix A string to append to the dynamic library file \l{Product::targetName}{name}. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c ".so", \c ".dll" or \c "dylib" */ /*! \qmlproperty string cpp::dynamicLibraryImportSuffix \windowsproperty A string to append to the dynamic library import file \l{Product::targetName}{name}. \defaultvalue \c ".lib" */ /*! \qmlproperty string cpp::loadableModuleSuffix \appleproperty A string to append to the Darwin loadable module file \l{Product::targetName}{name}. \defaultvalue \c ".bundle" */ /*! \qmlproperty string cpp::staticLibrarySuffix A string to append to the executable file \l{Product::targetName}{name}. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c ".a" or \c ".lib" */ /*! \qmlproperty string cpp::debugInfoSuffix A string to append to the debug information file name. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c ".debug", \c ".pdb" or \c ".dwarf" */ /*! \qmlproperty string cpp::debugInfoBundleSuffix \appleproperty A string to append to the debug information bundle name. \defaultvalue \c ".dSYM" */ /*! \qmlproperty string cpp::objectSuffix A string to append to the generated object files. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c ".o" or \c ".obj" */ /*! \qmlproperty string cpp::linkerMapSuffix A string to append to the generated linker memory map files. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical value is \c ".map" */ /*! \qmlproperty string cpp::compilerListingSuffix A string to append to the generated compiler listing files. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical value is \c ".lst" */ /*! \qmlproperty string cpp::assemblerListingSuffix A string to append to the generated assembler listing files. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical value is \c ".lst" */ /*! \qmlproperty pathList cpp::prefixHeaders \since Qbs 1.0.1 A list of files to automatically include at the beginning of each source file in the \l{Product}{product}. \nodefaultvalue */ /*! \qmlproperty string cpp::optimization The optimization level. \defaultvalue \l{qbs::optimization}{qbs.optimization} */ /*! \qmlproperty bool cpp::treatWarningsAsErrors Whether warnings will be handled as errors and cause the build to fail. \defaultvalue \c{false} */ /*! \qmlproperty bool cpp::useCPrecompiledHeader \since Qbs 1.5 Whether to use a precompiled header for compiling C sources if one is present. Set this property to \c false in a \l Group item to disable precompiled headers for some sources even though a precompiled header is present in the product. See \l{filetags-cpp}{Relevant File Tags} for the associated file tags. \defaultvalue \c true */ /*! \qmlproperty bool cpp::useCxxPrecompiledHeader \since Qbs 1.5 Like \l useCPrecompiledHeader, but for C++. \defaultvalue \c true */ /*! \qmlproperty bool cpp::useObjcPrecompiledHeader \since Qbs 1.5 Like \l useCPrecompiledHeader, but for Objective-C. \defaultvalue \c true */ /*! \qmlproperty bool cpp::useObjcxxPrecompiledHeader \since Qbs 1.5 Like \l useCPrecompiledHeader, but for Objective-C++. \defaultvalue \c true */ /*! \qmlproperty string cpp::warningLevel The warning level for the compiler: \c{"none"} or \c{"all"}. \defaultvalue \c{"all"} */ /*! \qmlproperty stringList cpp::driverFlags \since Qbs 1.6 A list of flags that are added to all compilation and linking commands performed by the compiler driver, independently of the language. \nodefaultvalue */ /*! \qmlproperty stringList cpp::driverLinkerFlags \since Qbs 1.11 A list of flags that are added to all linking commands performed by the compiler driver, independently of the language. \nodefaultvalue */ /*! \qmlproperty stringList cpp::commonCompilerFlags \since Qbs 1.0.1 A list of flags that are added to all compilation commands independently of the language. \nodefaultvalue */ /*! \qmlproperty string cpp::compilerVersion Compiler version string consisting of major, minor and patch numbers, separated by a dot. \nodefaultvalue */ /*! \qmlproperty int cpp::compilerVersionMajor \since Qbs 1.4 The major version of the compiler. \nodefaultvalue */ /*! \qmlproperty int cpp::compilerVersionMinor \since Qbs 1.4 The minor version of the compiler. \nodefaultvalue */ /*! \qmlproperty int cpp::compilerVersionPatch \since Qbs 1.4 The patch level component of the compiler version. \nodefaultvalue */ /*! \qmlproperty stringList cpp::assemblerFlags \since Qbs 1.5 A list of additional flags for the assembler. \nodefaultvalue */ /*! \qmlproperty stringList cpp::cppFlags A list of additional flags for the C preprocessor. \nodefaultvalue */ /*! \qmlproperty stringList cpp::cFlags A list of additional flags for the C compiler. \nodefaultvalue */ /*! \qmlproperty stringList cpp::cxxFlags A list of additional flags for the C++ compiler. \nodefaultvalue */ /*! \qmlproperty stringList cpp::cLanguageVersion \since Qbs 1.4 The version of the C standard with which the code must comply. If this property is set, the corresponding compiler and linker flags will be added, depending on the toolchain. If the value is left undefined, the compiler default will be used. If the list contains more than one value, the highest version is chosen. Possible values include: \c{"c89"}, \c{"c99"}, \c{"c11"}, \c{"c17"}, \c{"c2x"}. \nodefaultvalue */ /*! \qmlproperty stringList cpp::cxxLanguageVersion \since Qbs 1.4 The version of the C++ standard with which the code must comply. If this property is set, the corresponding compiler and linker flags will be added, depending on the toolchain. If the value is left undefined, the compiler default will be used. If the list contains more than one value, the highest version is chosen. Possible values include: \c{"c++98"}, \c{"c++11"}, \c{"c++14"}, \c{"c++17"}, \c{"c++20"}, \c{"c++23"}. \nodefaultvalue */ /*! \qmlproperty bool cpp::useLanguageVersionFallback \since Qbs 1.11 Whether to explicitly use the language standard version fallback values in compiler command line invocations. By default, \QBS will automatically substitute fallback values for the C and C++ language standard versions specified by the \l cLanguageVersion and \l cxxLanguageVersion properties, which are passed to the \c{-std=} compiler command line option with GNU-compatible toolchains, if it detects that you are using an older toolchain which does not support the standard values. The substitutions are made as follows: \table \header \li Value \li Substitute \row \li c++11 \li c++0x \row \li c11 \li c1x \row \li c++14 \li c++1y \row \li c++17 \li c++1z \endtable If this property is explicitly set to \c true, \QBS will always use the fallback values. If this property is explicitly set to \c false, \QBS will never use the fallback values. This property has no effect with the Microsoft Visual C++ compiler. \nodefaultvalue */ /*! \qmlproperty string cpp::cxxStandardLibrary \since Qbs 1.4 The C++ standard library to link to. If this property is set, the corresponding compiler and linker flags will be added, assuming the value is valid for the current toolchain. If the value is left undefined, the compiler default will be used. Possible values include: \c{"libstdc++"}, \c{"libc++"}. \nodefaultvalue */ /*! \qmlproperty stringList cpp::objcFlags A list of additional flags for the Objective-C compiler. \nodefaultvalue */ /*! \qmlproperty stringList cpp::objcxxFlags A list of additional flags for the Objective-C++ compiler. \nodefaultvalue */ /*! \qmlproperty stringList cpp::linkerFlags A list of additional flags for the linker. These flags should \e not be escaped using the \c -Wl or \c -Xlinker syntaxes, as \QBS will do this automatically based on the linker being used. \sa linkerMode \nodefaultvalue */ /*! \qmlproperty string cpp::assemblerName \since Qbs 1.5 The name of the assembler binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::toolchainInstallPath The directory path where the toolchain is installed. This property is set in the build profile. This is usually the base property from which all compiler and tool paths are automatically derived. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::assemblerPath \since Qbs 1.5 The full path of the assembler binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::compilerName The name of the main compiler binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::compilerPath The full path of the main compiler binary. This property is set in the build profile. If the toolchain provides different compilers for different languages, \l{cpp::}{compilerPathByLanguage} is used. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty var cpp::compilerPathByLanguage \since Qbs 1.3 A \c{string} to \c{string} map that maps file tags to full paths of compiler binaries. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty stringList cpp::compilerWrapper \since Qbs 1.1 A wrapper binary and its arguments for wrapping compiler calls. This is useful for compiler wrappers, such as \c ccache. \nodefaultvalue */ /*! \qmlproperty string cpp::linkerName \since Qbs 1.1.1 The name of the linker binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::linkerPath \since Qbs 1.1.1 The full path of the linker binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty stringList cpp::linkerWrapper \since Qbs 1.6.2 A wrapper binary and its arguments for wrapping linker calls. This is useful for linker wrappers as needed by Bullseye Coverage, for example. \nodefaultvalue */ /*! \qmlproperty string cpp::entryPoint \since Qbs 1.3 The name of the entry point of an executable or dynamic library. If this property is left undefined, the toolchain's default is used. \nodefaultvalue */ /*! \qmlproperty string cpp::runtimeLibrary \since Qbs 1.3.3 The type of the runtime library used. Accepted values are \c{"static"} and \c{"dynamic"}. If this property is set to \c{undefined}, the default runtime library of the toolchain is used. \note This property is only functional for MSVC and MinGW. \defaultvalue \c{"dynamic"} for MSVC and MinGW, \c{undefined} for other compilers. */ /*! \qmlproperty bool cpp::enableExceptions \since Qbs 1.5 Whether to enable exceptions in C++ code. \defaultvalue \c{true} */ /*! \qmlproperty bool cpp::enableSuspiciousLinkerFlagWarnings \since Qbs 1.8 Whether to print warnings about escaped linker flags (such as \c -Xlinker and \c -Wl). \defaultvalue \c{true} */ /*! \qmlproperty string cpp::exceptionHandlingModel \since Qbs 1.5 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 the only exception handling model. \defaultvalue \c{"default"} */ /*! \qmlproperty bool cpp::enableRtti \since Qbs 1.5 Whether to enable runtime type information in C++ code. \nodefaultvalue */ /*! \qmlproperty bool cpp::enableReproducibleBuilds \since Qbs 1.5 Whether the compiler should try to generate reproducible object files. Some compilers (notably GCC) use random numbers for generating symbol names that have to be different in every compilation unit. This is avoided by setting this property to \c{true}. \defaultvalue \c{false} */ /*! \qmlproperty bool cpp::treatSystemHeadersAsDependencies \since Qbs 1.8 Whether included header files found via \l{cpp::}{systemIncludePaths}, \l{cpp::}{distributionIncludePaths}, or \l{cpp::}{compilerIncludePaths} will be added to the dependencies of the respective object file. This means that modification of such header files (or any of the headers they include) will cause recompilation. \defaultvalue \c{false} */ /*! \qmlproperty stringList cpp::dsymutilFlags \since Qbs 1.4.1 \appleproperty Additional flags for the \c dsymutil tool. \note If this property contains the \c{-f} or \c{--flat} options, this will cause \QBS to generate "flat" (single-file) \c{.dwarf} debug symbol files instead of \c{.dSYM} bundles (directories) when \l{cpp::}{separateDebugInformation} is set to \c{true}. \nodefaultvalue */ /*! \qmlproperty string cpp::dsymutilPath \since Qbs 1.4 \appleproperty The full path of the \c dsymutil binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::lipoPath \since Qbs 1.9 \appleproperty The full path of the \c lipo binary. \defaultvalue Determined automatically. */ /*! \qmlproperty pathList cpp::frameworkPaths \appleproperty A list of framework search paths. Relative paths are considered to be relative to the \c .qbs product file they are used in. \nodefaultvalue */ /*! \qmlproperty pathList cpp::systemFrameworkPaths \appleproperty A list of framework search paths. Relative paths are considered to be relative to the \c .qbs product file they are used in. Header files in frameworks in those paths will not cause warnings. \nodefaultvalue */ /*! \qmlproperty stringList cpp::frameworks \appleproperty A list of frameworks to be linked. If the framework is part of your project, consider using a \l{Depends} item instead. \nodefaultvalue */ /*! \qmlproperty stringList cpp::weakFrameworks \appleproperty A list of frameworks to be weakly linked. If the framework is part of your project, consider using a \l{Depends} item instead. \nodefaultvalue */ /*! \qmlproperty bool cpp::automaticReferenceCounting \since Qbs 1.4 \appleproperty Whether to enable Automatic Reference Counting (ARC) for Objective-C and Objective-C++ source code. If left undefined, uses the compiler default (probably \c{false}). \nodefaultvalue */ /*! \qmlproperty bool cpp::requireAppExtensionSafeApi \since Qbs 1.4 \appleproperty Whether to enforce the use of only app-extension-safe APIs on Apple platforms. This is necessary for building Application Extensions in OS X Yosemite and iOS 8 and above. If left undefined, uses the compiler and linker defaults (probably \c{false}). \nodefaultvalue */ /*! \qmlproperty string cpp::minimumIosVersion \appleproperty A version number in the format \c{[major].[minor]} indicating the earliest version of iOS that the product should run on. Passes \c{-miphoneos-version-min=} to the compiler. If set to undefined, compiler defaults will be used. \note \QBS sets minimum version to \c "6.0" for \c armv7a because earlier iOS versions are broken in recent XCode installations. \defaultvalue \c "6.0" for \c armv7a, \c undefined otherwise */ /*! \qmlproperty string cpp::minimumOsxVersion \obsolete \appleproperty Deprecated in \QBS 1.5.2. Use \l{cpp::minimumMacosVersion} instead. \nodefaultvalue */ /*! \qmlproperty string cpp::minimumMacosVersion \since Qbs 1.5.2 \appleproperty A version number in the format \c{[major].[minor]}indicating the earliest version of macOS that the product should run on. Passes \c{-mmacosx-version-min=} to the compiler. If left undefined, compiler defaults will be used. \nodefaultvalue */ /*! \qmlproperty string cpp::minimumWatchosVersion \appleproperty A version number in the format \c{[major].[minor]} indicating the earliest version of Apple watchOS that the product should run on. If left undefined, compiler defaults will be used. \nodefaultvalue */ /*! \qmlproperty string cpp::minimumTvosVersion \since Qbs 1.5 \appleproperty A version number in the format \c{[major].[minor]} indicating the earliest version of Apple tvOS that the product should run on. If left undefined, compiler defaults will be used. \note \QBS sets the minimum version to \c "6.0", because earlier tvOS versions are not supported by recent XCode installations by default. \defaultvalue \c "6.0 */ /*! \qmlproperty string cpp::archiverName \unixproperty The name of the archiver binary. This property is set in the build profile. \defaultvalue \c{"ar"} */ /*! \qmlproperty string cpp::archiverPath \unixproperty The full path of the archiver binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::exportedSymbolsCheckMode \since Qbs 1.4.1 \unixproperty Controls how \QBS determines whether an updated dynamic library causes relinking of dependents. The default value is \c "ignore-undefined", which means that undefined symbols being added or removed do not cause any relinking. If that should happen, for example because dependent products are linked with an option such as \c "--no-undefined", this property can be set to \c "strict". \defaultvalue \c "ignore-undefined" */ /*! \qmlproperty string cpp::linkerMode \since Qbs 1.6 Controls whether to automatically use an appropriate compiler frontend instead of the system linker when linking binaries. The default is \c{"automatic"}, which chooses either the C++ compiler, C compiler, or system linker specified by the \l{cpp::}{linkerName} and \l{cpp::}{linkerPath} properties, depending on the type of object files present on the linker command line. Set this property to \c{"manual"} to explicitly specify the linker using the \l{cpp::}{linkerName} and \l{cpp::}{linkerPath} properties. \defaultvalue \c "automatic" */ /*! \qmlproperty string cpp::linkerVariant \since Qbs 1.13 Set this property to force the use of a specific linker. A non-empty value will result in the \c {-fuse-ld} option being emitted when linking with \c gcc, \c clang or \c clang-cl. Other toolchains do not support this property. The possible values for \c clang and \c gcc are \c "bfd", \c "gold", \c "lld" and \c "mold", the possible values for \c clang-cl are \c "link" and \c "lld". The following example demonstrates how to change the linker for different toolchains: \code Properties { condition: qbs.toolchain.includes("gcc") cpp.linkerVariant: "gold" } Properties { condition: qbs.toolchain.includes("clang-cl") cpp.linkerVariant: "lld" } \endcode \nodefaultvalue */ /*! \qmlproperty string cpp::nmName \since Qbs 1.2 \unixproperty The name of the \c nm binary. This property is set in the build profile. \defaultvalue \c{"nm"} */ /*! \qmlproperty string cpp::nmPath \since Qbs 1.2 \unixproperty The full path of the \c nm binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::objcopyName \since Qbs 1.4 \unixproperty The name of the \c objcopy binary. This property is set in the build profile. \defaultvalue \c{"objcopy"} */ /*! \qmlproperty string cpp::objcopyPath \since Qbs 1.4 \unixproperty The full path of the \c objcopy binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty string cpp::stripName \since Qbs 1.4 \unixproperty The name of the \c strip binary. This property is set in the build profile. \defaultvalue \c{"strip"} */ /*! \qmlproperty string cpp::stripPath \since Qbs 1.4 \unixproperty The full path of the \c strip binary. This property is set in the build profile. \defaultvalue Determined by \l{setup-toolchains}{qbs setup-toolchains}. */ /*! \qmlproperty bool cpp::positionIndependentCode \unixproperty Whether to generate position-independent code. If this property is left undefined, position-independent code is generated for libraries, but not for applications. \nodefaultvalue */ /*! \qmlproperty string cpp::rpathOrigin \since Qbs 1.11 \unixproperty A placeholder value used in an \c rpath string to refer to the directory containing the referring executable or shared library. \defaultvalue \c{"@loader_path"} on Mach-O based platforms (macOS, iOS, tvOS, watchOS); \c{"$ORIGIN"} on ELF based platforms (Linux and most other Unix-like platforms). */ /*! \qmlproperty stringList cpp::rpaths \unixproperty A list of \c rpaths that are passed to the linker. Paths that also appear in \l{cpp::}{systemRunPaths} are ignored. \nodefaultvalue \sa{How do I make use of rpaths?} */ /*! \qmlproperty string cpp::sonamePrefix \since Qbs 1.5 \unixproperty A library name or full library path. If defined, the value of this property is used as a path to be prepended to the built shared library's \c SONAME identifier. The \c SONAME (\c LC_ID_DYLIB on Apple platforms, \c DT_SONAME on other Unix-like platforms) is the identifier that the dynamic linker will later use to reference the library. On Apple platforms, the path may contain the following placeholders: \list \li \c @rpath - Expands to paths defined by \c LC_RPATH Mach-O commands in the current process executable or the referring libraries. \li \c @executable_path - Expands to the current process executable location. \li \c @loader_path - Expands to the referring executable or library location. \endlist In most cases, using \c @rpath is sufficient and recommended. However, the prefix may be also specified using different placeholders, or an absolute path. For more information, see the \l{DYLD documentation} on dynamic library install names. \nodefaultvalue \sa{How do I make use of rpaths?} */ /*! \qmlproperty string cpp::soVersion \since Qbs 1.7 \unixproperty The version number to be appended to the soname in ELF shared libraries. \defaultvalue The major part of \l{Product::version}{product.version} if a version is set, otherwise \c []. */ /*! \qmlproperty bool cpp::useRPaths \since Qbs 1.3 \unixproperty If \c{false}, prevents the linker from writing \c rpaths to the binary. \defaultvalue \c{true} */ /*! \qmlproperty bool cpp::useRPathLink \since Qbs 1.8 \unixproperty Whether to use the \c{-rpath-link} linker option for transitive shared objects. \defaultvalue \c{true} on non-Darwin Unix platforms or when targeting macOS 10.4.x and older. */ /*! \qmlproperty string cpp::rpathLinkFlag \since Qbs 1.9 The rpath link flag used by the linker. \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical values are \c "-rpath-link=" or \c "-L" */ /*! \qmlproperty string cpp::variantSuffix \since Qbs 1.10 A suffix to add to a product's target name if that product is of the \l{Product::type}{type} \c staticlibrary or \c dynamiclibrary. On Darwin platforms, applications and loadable modules are also affected. By default, this property is left empty on all platforms unless the product is multiplexed over the \l{qbs::buildVariants}{qbs.buildVariants} property. In that case, for the debug variant of the product, the default value is \c{"d"} on Windows and \c{"_debug"} on Darwin platforms, such as macOS. On all other platforms and in release mode, the default value is \c []. For example, building a dynamic library called \c MyLib that is multiplexed over the \l{qbs::buildVariants}{qbs.buildVariants} property with MSVC will produce files called \c{MyLib.dll} (for the release version of the product) and \c{MyLibd.dll} (for the debug version). \defaultvalue Platform-specific. */ /*! \qmlproperty string cpp::visibility \unixproperty The visibility level for exported symbols. Possible values include: \c{"default"}, \c{"hidden"}, \c{"hiddenInlines"}, and \c{"minimal"}, which combines \c{"hidden"} and \c{"hiddenInlines"}. \defaultvalue \c{"default"} */ /*! \qmlproperty bool cpp::generateManifestFile \since Qbs 1.5.0 \windowsproperty Whether to auto-generate a manifest file and include it in the binary. Set this property to \c false if you provide your own \c rc file. \defaultvalue \c{true} */ /*! \qmlproperty string cpp::windowsApiCharacterSet \since Qbs 1.0.1 \windowsproperty The character set used in the Win32 API. The value \c "unicode" defines the preprocessor symbols \c UNICODE and \c _UNICODE, \c "mbcs" defines \c _MBCS, and setting the value to \c undefined will use the default character set. \defaultvalue \c{"unicode"} */ /*! \qmlproperty string cpp::windowsApiFamily \since Qbs 1.10 \windowsproperty The Windows API family that the application or library is targeting. This value is used when building Universal Windows Platform applications. Possible values include: \c{"desktop"}, \c{"pc"}, \c{"phone"}, \c{"server"}, and \c{"system"}, which are mapped to the corresponding set of possible values for the \c WINAPI_FAMILY preprocessor define in the Windows SDK. \defaultvalue Undefined, which lets the Windows SDK headers determine the default. */ /*! \qmlproperty stringList cpp::windowsApiAdditionalPartitions \since Qbs 1.10 \windowsproperty A list of additional Windows API partitions to enable in addition to the ones implicitly enabled by the value of \l{cpp::}{windowsApiFamily} (\c WINAPI_FAMILY). This value is used when building Windows Store applications. For example, setting \l{cpp::}{windowsApiFamily} to \c{"pc"} and this property to \c{["phone"]} will allow you to create Windows Store applications that target all Universal Windows Platform device families (\c "Universal" apps). Possible values include: \c{"app"}, \c{"desktop"}, \c{"pc"}, \c{"phone"}, \c{"server"}, and \c{"system"}, which are mapped to the corresponding set of possible \c WINAPI_PARTITION_* preprocessor defines in the Windows SDK. \defaultvalue Undefined, which lets the Windows SDK headers determine the default partitions based on the value of \c WINAPI_FAMILY. \sa windowsApiFamily */ /*! \qmlproperty bool cpp::requireAppContainer \since Qbs 1.10 \windowsproperty Whether the generated executable or dynamic-link library \e requires an AppContainer execution environment. Set to \c true when creating Universal Windows Platform applications. \nodefaultvalue */ /*! \qmlproperty string cpp::minimumWindowsVersion \windowsproperty A version number in the format \c{[major].[minor]} indicating the earliest version of Windows that the product should run on. Defines \c WINVER, \c _WIN32_WINNT, and \c _WIN32_WINDOWS, and applies a version number to the linker flags \c /SUBSYSTEM and \c /OSVERSION for MSVC or \c --major-subsystem-version, \c --minor-subsystem-version, \c --major-os-version, and \c --minor-os-version for MinGW. If left undefined, compiler defaults will be used. \nodefaultvalue */ /*! \qmlproperty bool cpp::alwaysUseLipo \since Qbs 1.9 Whether to always use \c lipo when combining Mach-O output files on Apple platforms, even if there is only one CPU architecture. This value should not normally need to be changed. \defaultvalue \c{false} */ /*! \qmlproperty var cpp::compilerDefinesByLanguage \since Qbs 1.10 A \c{string} to \c{string} to \c{string} map of language tags to list of preprocessor macros that are used for all projects that are using the current toolchain. User project files usually do not set this property. \note This property will not be usable without also setting \l{cpp::}{enableCompilerDefinesByLanguage}. \nodefaultvalue */ /*! \qmlproperty pathList cpp::compilerIncludePaths \since Qbs 1.6 A list of \c #include search paths that are used for all projects that are using the current toolchain. User project files usually do not set this property. \defaultvalue Determined automatically by probing the compiler. */ /*! \qmlproperty pathList cpp::compilerFrameworkPaths \since Qbs 1.6 A list of framework search paths that are used for all projects that are using the current toolchain. User project files usually do not set this property. \defaultvalue Determined automatically by probing the compiler. */ /*! \qmlproperty pathList cpp::compilerLibraryPaths \since Qbs 1.6 A list of library search paths that are used for all projects that are using the current toolchain. User project files usually do not set this property. \defaultvalue Determined automatically by probing the compiler. */ /*! \qmlproperty pathList cpp::distributionFrameworkPaths \since Qbs 1.8 A list of distribution-specific framework search paths, prioritized after \l{cpp::}{systemFrameworkPaths}. Intended for use by module authors implementing support for new operating systems or distributions. User project files should not set this property. \nodefaultvalue */ /*! \qmlproperty pathList cpp::distributionIncludePaths \since Qbs 1.8 A list of distribution-specific include paths that are passed as system include paths to the compiler, prioritized after \l{cpp::}{systemIncludePaths}. Intended for use by module authors implementing support for new operating systems or distributions. User project files should not set this property. \nodefaultvalue */ /*! \qmlproperty pathList cpp::distributionLibraryPaths \since Qbs 1.8 A list of distribution-specific library search paths. Intended for use by module authors implementing support for new operating systems or distributions. User project files should not set this property. \nodefaultvalue */ /*! \qmlproperty stringList cpp::enableCompilerDefinesByLanguage \since Qbs 1.10 A list of languages (one or more of \c{"c"}, \c{"cpp"}, \c{"objc"}, \c{"objcpp"}) to extract the list of default compiler defines for in \l{cpp::}{compilerDefinesByLanguage}. Because this has performance implications, no languages are enabled by default. \nodefaultvalue */ /*! \qmlproperty bool cpp::generateLinkerMapFile \since Qbs 1.13 Whether to auto-generate a linker map file. \defaultvalue \c{false} */ /*! \qmlproperty bool cpp::generateCompilerListingFiles \since Qbs 1.15 Whether to auto-generate compiler listing files. \defaultvalue \c{false} */ /*! \qmlproperty bool cpp::generateAssemblerListingFiles \since Qbs 1.15 \baremetalproperty Whether to auto-generate an assembler listing files. \defaultvalue \c{false} */ /*! \qmlproperty bool cpp::removeDuplicateLibraries \since Qbs 1.16 Whether the list of the objects and libraries is reduced to a list of unique values before being passed to the linker. \defaultvalue \c{true} */ /*! \qmlproperty string cpp::windowsSdkVersion \since Qbs 1.19 Which Windows SDK version should be used with MSVC toolchain. By default, the latest SDK is used. \windowsproperty \nodefaultvalue */ /*! \qmlproperty string cpp::enableCxxLanguageMacro \since Qbs 1.20 Whether to set the \c{/Zc:__cplusplus} macro (\l{https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus}) This property only applies to MSVC toolchain. clang-cl also supports this option, but it has no effect. \windowsproperty \defaultvalue \c{true} for MSVC, \c{false} for clang-cl */ /*! \qmlproperty string cpp::importPrivateLibraries \since Qbs 2.4 Whether to automatically import external libraries from dependencies. If set to true in the product that depends on the static library, the external dependencies (such as \l{cpp::staticLibraries}{staticLibraries} and \l{cpp::dynamicLibraries}{dynamicLibraries}) of this library are also added to products that depend on this library. \code StaticLibrary { files: "lib.cpp" cpp.staticLibraries: ["l", "y"] } \endcode If set to false, the explicit \l{Export} item is required: \code StaticLibrary { files: "lib.cpp" Export { Depends { name: "cpp" } cpp.staticLibraries: ["l", "y"] } } \endcode We recommend using the \l{Export} item as it provides more flexibility. \note The default value is subject to change. \defaultvalue \c{true} */ /*! \qmlproperty bool cpp::forceUseCxxModules \since Qbs 2.5 Set this property to \c true to force support for C++20 Modules. On details how to use modules, see the corresponding \l{tutorial-10.html}{section} in the tutorial. By default, modules support is disabled since this feature is considered experimental. \note The default value is subject to change. \defaultvalue \c{false} */ qbs-src-2.6.1/doc/reference/modules/vcs-module.qdoc0000644000175100001660000000640414776170045021555 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype vcs \inqmlmodule QbsModules \since Qbs 1.10 \brief Provides support for version control systems. The \c vcs module provides the current state of the project's repository via the \l{vcs::}{repoState} property. By default, a \c C header is also generated, allowing for simple retrieval of the repository state directly from within your C/C++ sources. This is useful to embed information into binaries about the exact state of the repository from which they were built. For example: \code #include #include int main() { std::cout << "I was built from " << VCS_REPO_STATE << std::endl; } \endcode Above, a header file called \c{vcs-repo-state.h} is created, defining a macro called \c VCS_REPO_STATE, which expands to a character constant describing the current state of the repository. For Git, this would be the current HEAD's commit hash. */ /*! \qmlproperty string vcs::headerFileName The name of the C header file to be created. Set this to \c undefined if you do not want a header file to be generated. \defaultvalue \c{"vcs-repo-state.h"} */ /*! \qmlproperty string vcs::repoDir The root directory of the repository. \defaultvalue The top-level project directory (\l{Project::sourceDirectory} {project.sourceDirectory}). */ /*! \qmlproperty string vcs::repoState The current state of the repository. For example, in Git this is the commit hash of the current HEAD. \nodefaultvalue */ /*! \qmlproperty string vcs::toolFilePath Set this property if the tool has an unusual name in your local installation, or if it is located in a directory that is not in the build environment's \c PATH. \defaultvalue The file name of the version control tool corresponding to \l{vcs::type}{type}. */ /*! \qmlproperty string vcs::type The version control system used in the project. Currently, the supported values are \c{"git"} and \c{"svn"}. \defaultvalue auto-detected */ qbs-src-2.6.1/doc/reference/modules/ico-module.qdoc0000644000175100001660000000734014776170045021534 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype ico \inqmlmodule QbsModules \since Qbs 1.11 \brief Provides support for building ICO (.ico) and CUR (.cur) files. The \c ico module contains properties and rules for building Microsoft Windows Icon (.ico) and Microsoft Windows Cursor (.cur) files. \note This module relies on the \c icotool command-line tool from the \c icotools package, which must be installed separately and found in the \c PATH or an appropriate system binaries directory for your system (for example, \c /usr/bin or \c /usr/local/bin). \section2 Relevant File Tags \target filetags-ico \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"cur"} \li n/a \li 1.11 \li The rule that creates cursor (.cur) files attaches this tag to its output artifact. \row \li \c{"ico"} \li n/a \li 1.11 \li The rule that creates icon (.ico) files attaches this tag to its output artifact. \row \li \c{"png"} \li \c{"*.png"} \li 1.11 \li Source files with this tag indicate PNG files which are used as inputs to create icon or cursor files. \endtable */ /*! \qmlproperty int ico::cursorHotspotX The cursor hotspot x coordinate. Only relevant when building .cur files. This property must be set individually for each input PNG file. \note \c icoutils version 0.32 or greater is required to set the hotspot in cursor files with multiple images. \nodefaultvalue */ /*! \qmlproperty int ico::cursorHotspotY The cursor hotspot y coordinate. Only relevant when building .cur files. This property must be set individually for each input PNG file. \note \c icoutils version 0.32 or greater is required to set the hotspot in cursor files with multiple images. \nodefaultvalue */ /*! \qmlproperty bool ico::raw Whether to store the input file as a raw PNG, as supported in Windows Vista. Only relevant when building .ico files. This property must be set individually for each input PNG file. It is recommended to set this value only for icon sizes larger than or equal to 256x256. \defaultvalue \c{false} */ /*! \qmlproperty string ico::icotoolFilePath The full path of the \c icotool binary. This property should not normally need to be changed if \QBS was able to automatically detect it. \defaultvalue Determined automatically. */ qbs-src-2.6.1/doc/reference/modules/asan-module.qdoc0000644000175100001660000000540614776170045021705 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Sanitizers.address \inqmlmodule QbsModules \brief Provides AddressSanitizer support. Provides support for the \l{https://clang.llvm.org/docs/AddressSanitizer.html}{AddressSanitizer} tool, which uses compiler instrumentation to detect memory corruption bugs at runtime. */ /*! \qmlproperty string Sanitizers.address::detectUseAfterReturn Controls whether support for detecting problems with stack use after returning from a function should be built into the application. The possible values are: \list \li \c "always": Check for this type of problem unconditionally. \li \c "runtime": Build with this capability, but only do the respective checks if they are explicitly requested at runtime. \li \c "never": Do not build with support for this check. \endlist \note Only the clang compiler (starting at 13.0) supports the full set of values. With GCC and MSVC, "runtime" maps to "always". \defaultvalue \c "always" */ /*! \qmlproperty bool Sanitizers.address::detectUseAfterScope Controls whether to detect bugs relating the use of variables after they've gone out of scope. \note This property has no effect when building with with GCC and MSVC. \defaultvalue \c true */ /*! \qmlproperty bool Sanitizers.address::enabled Controls whether to enable AddressSanitizer. \note You do not need to check if the current toolchain supports AddressSanitizer: If \QBS detects that it doesn't, this property has no effect. \defaultvalue \c true */ qbs-src-2.6.1/doc/reference/modules/xcode-module.qdoc0000644000175100001660000001103714776170045022062 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype xcode \inqmlmodule QbsModules \since Qbs 1.5 \brief Provides Xcode support. The \c xcode module contains properties and rules for Xcode-based development. This module provides the foundation for several other modules on Apple platforms, including the \l{cpp} and \l{ib} modules. */ /*! \qmlproperty path xcode::developerPath The developer directory of the Xcode installation. Corresponds to the \c DEVELOPER_DIR environment variable. \defaultvalue The developer directory of the Xcode installation at its default location in \c /Applications. For example, \c{"/Applications/Xcode.app/Contents/Developer"}. */ /*! \qmlproperty string xcode::sdk The version of the Xcode SDK used to build products. This can be specified as a full canonical SDK name (\c{"macosx10.10"}), a platform version number (\c{"10.10"}), or a platform identifier (\c{"macosx"}), in which case the latest SDK available for that platform will be used. \defaultvalue The latest SDK available in the Xcode installation for the current platform. Determined by \l{qbs::targetOS}{qbs.targetOS}. */ /*! \qmlproperty stringList xcode::targetDevices A list of the Apple devices targeted by this product. For macOS, watchOS, and tvOS, this should always be \c "mac", \c "watch", and \c "tv", respectively. For iOS, this can be one or both of \c "iphone" and \c "ipad". \defaultvalue The list of all device types supported by the current platform. Determined by \l{qbs::targetOS}{qbs.targetOS}. */ /*! \qmlproperty string xcode::sdkName \readonly The canonical name of the SDK used to build products. For example, \c macosx10.9. \defaultvalue \l{xcode::}{sdk} */ /*! \qmlproperty string xcode::sdkVersion \readonly The version number of the SDK used to build products. For example, 10.9. \defaultvalue \l{xcode::}{sdk} */ /*! \qmlproperty string xcode::latestSdkName \readonly The canonical name of the latest SDK available in the Xcode installation. For example, \c {macosx10.10}. \defaultvalue \l{xcode::}{developerPath} */ /*! \qmlproperty string xcode::latestSdkVersion \readonly The version number of the latest SDK available in the Xcode installation. For example, 10.10. \defaultvalue \l{xcode::}{developerPath} */ /*! \qmlproperty stringList xcode::availableSdkNames \readonly The canonical names of all SDKs available in the Xcode installation for the current platform. For example, \c {[macosx10.9, macosx10.10]}. \defaultvalue \l{xcode::}{developerPath} */ /*! \qmlproperty stringList xcode::availableSdkVersions \readonly The version numbers of all SDK available in the Xcode installation for the current platform. For example, \c {[10.9, 10.10]}. \defaultvalue \l{xcode::}{developerPath} */ /*! \qmlproperty path xcode::platformPath \readonly The path of the platform directory containing \l{xcode::}{sdkPath}. \defaultvalue \l{xcode::}{developerPath} */ /*! \qmlproperty path xcode::sdkPath \readonly The path of the SDK used to build products. Equivalent to \l{qbs::sysroot}{qbs.sysroot}. \defaultvalue Determined by \l{xcode::}{developerPath} and \l{xcode::}{sdk}. */ qbs-src-2.6.1/doc/reference/modules/qt-gui-module.qdoc0000644000175100001660000000372414776170045022172 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.gui \inqmlmodule QbsModules \brief Provides Qt GUI support. The Qt.gui module provides support for the Qt GUI module, which contains base classes for graphical user interface (GUI) components. \section2 Relevant File Tags \target filetags-gui \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"ui"} \li \c{*.ui} \li 1.0 \li Source files with this tag serve as inputs to the rule running the \c uic tool. \endtable */ /*! \qmlproperty string Qt.gui::uicName The base name of the \c uic tool. Set this property if your system uses a name such as \c uic-qt4. \defaultvalue \c{"uic"} */ qbs-src-2.6.1/doc/reference/modules/innosetup-module.qdoc0000644000175100001660000001144414776170045023006 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype innosetup \inqmlmodule QbsModules \since Qbs 1.7 \brief Provides Inno Setup support. The \c innosetup module contains properties and rules for building EXE setup packages with \l{Inno Setup}. Inno Setup 5 and above are supported. \note A typical Inno Setup Script includes an \c OutputBaseFilename command to set the filename of the generated installer executable. However, \QBS overrides any \c OutputBaseFilename commands found in the script by passing the \c /F option to the ISCC compiler, and therefore, you must use the \l{Product::targetName}{Product.targetName} property to set the filename. \QBS also overrides any \c Output commands by passing the \c /O option to the ISCC compiler. \section2 Relevant File Tags \target filetags-innosetup \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"innosetup.iss"} \li \c{"*.iss"} \li 1.7 \li Source files with this tag identify Inno Setup Script files, which serve as inputs to a rule invoking the Inno Setup Script Compiler. \row \li \c{"innosetup.exe"} \li n/a \li 1.7 \li The rule that creates Inno Setup executable files attaches this tag (as well as the \l{filetags-cpp}{"application"} tag) to its output artifact. \endtable */ /*! \qmlproperty stringList innosetup::defines A list of preprocessor macros that get passed to the compiler. To set macro values, use the following syntax: \badcode innosetup.defines: ["USE_COLORS=1", 'COLOR_STR="blanched almond"'] \endcode \nodefaultvalue */ /*! \qmlproperty pathList innosetup::includePaths A list of include paths. Relative paths are considered to be relative to the \c .qbs product file they are used in. \nodefaultvalue */ /*! \qmlproperty bool innosetup::verboseOutput Whether to display verbose output from the Inno Setup compiler. \defaultvalue \c{false} */ /*! \qmlproperty stringList innosetup::compilerFlags A list of additional flags for the Inno Setup compiler. \nodefaultvalue */ /*! \qmlproperty string innosetup::version The Inno Setup version. Consists of three numbers separated by dots, for instance \c {"5.5.9"}. \nodefaultvalue */ /*! \qmlproperty int innosetup::versionMajor The Inno Setup major version. \defaultvalue \c{versionParts[0]} */ /*! \qmlproperty int innosetup::versionMinor The Inno Setup minor version. \defaultvalue \c{versionParts[1]} */ /*! \qmlproperty list innosetup::versionParts The Inno Setup version as a list. For instance, Inno Setup version 5.5.9 would correspond to a value of \c[5, 5, 9]. \defaultvalue \c [] */ /*! \qmlproperty int innosetup::versionPatch The Inno Setup patch level. \defaultvalue \c{versionParts[2]} */ /*! \qmlproperty path innosetup::toolchainInstallPath The Inno Setup installation directory. Determined by searching the registry for the latest version. This property should not normally need to be changed. \defaultvalue Determined automatically. */ /*! \qmlproperty string innosetup::compilerName The name of the compiler binary. This property should not normally need to be changed. \defaultvalue \c{"ISCC.exe"} */ /*! \qmlproperty string innosetup::compilerPath The full path of the compiler binary. This property should not normally need to be changed. \defaultvalue \c{compilerName} */ qbs-src-2.6.1/doc/reference/modules/exporter-cmake.qdoc0000644000175100001660000001113514776170045022422 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Raphael Cotty (raphael.cotty@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Exporter.cmake \inqmlmodule QbsModules \since Qbs 2.3 \brief Provides support for generating \CMAKE packages from dynamic, static and header library products. The Exporter.cmake module contains the properties and rules to create a \CMAKE config \l{https://cmake.org/cmake/help/v3.29/manual/cmake-packages.7.html#config-file-packages}{files} from the \l Export item of a \l Product. For instance, suppose you are creating a library. To allow exporting to \CMAKE, you would write something like the following: \code DynamicLibrary { name: "mylibrary" qbs.installPrefix: "/opt/mylibrary" Depends { name: "Exporter.cmake" } Exporter.cmake.packageName: "MyLibrary" property string headersInstallDir: "include" // ... Group { name: "API headers" files: ["mylib.h"] qbs.install: true qbs.installDir: headersInstallDir } Group { fileTagsFilter: ["Exporter.cmake.package"] qbs.installDir: "lib/cmake/MyLibrary" } Export { Depends { name: "cpp" } cpp.includePaths: FileInfo.joinPaths( exportingProduct.qbs.installRoot, exportingProduct.qbs.installPrefix, exportingProduct.headersInstallDir) } } \endcode To build against this library, from within your \CMAKE project, you simply use \l{https://cmake.org/cmake/help/v3.29/command/find_package.html}{find_package}: \code find_package(MyLibrary PATHS REQUIRED) add_executable(Consumer main.cpp) target_link_libraries(Consumer MyLibrary) \endcode \section2 Relevant File Tags \target filetags-exporter-qbs \table \header \li Tag \li Since \li Description \row \li \c{"Exporter.cmake.package"} \li 2.3.0 \li This tag is attached to all generated module files. \row \li \c{"Exporter.cmake.configFile"} \li 2.3.0 \li This tag is attached to the generated config file. \row \li \c{"Exporter.cmake.versionFile"} \li 2.3.0 \li This tag is attached to the generated version file. \endtable */ /*! \qmlproperty string Exporter.cmake::configFileName The name of the generated config file. \defaultvalue \c{packageName + "Config.cmake"} */ /*! \qmlproperty string Exporter.cmake::versionFileName The name of the generated version file. \defaultvalue \c{packageName + "ConfigVersion.cmake"} */ /*! \qmlproperty string Exporter.cmake::packageName The name of the \CMAKE package. \defaultvalue \l{Product::targetName}{Product.targetName} */ qbs-src-2.6.1/doc/reference/modules/capnprotocpp-module.qdoc0000644000175100001660000000706314776170045023474 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype capnproto.cpp \inqmlmodule QbsModules \since Qbs 1.17 \brief Provides support for Cap'n Proto for the C++ language. The \c capnproto.cpp module provides support for generating C++ headers and sources from proto definition files using the \c capnpc tool. A simple qbs file that uses Cap'n Proto can be written as follows: \code CppApplication { Depends { name: "capnproto.cpp" } files: ["foo.capnp", "main.cpp"] } \endcode A generated header now can be included in the C++ sources: \code #include int main(int argc, char* argv[]) { ::capnp::MallocMessageBuilder message; auto foo = message.initRoot(); foo.setAnswer(42); return 0; } \endcode \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"capnproto.input"} \li \c{*.capnp} \li 1.17.0 \li Source files with this tag are considered inputs to the \c capnpc compiler. \endtable \section2 Dependencies This module depends on the \c capnp module and on the \c capnp-rpc module if \l{capnproto.cpp::useRpc}{useRpc} property is \c true. These modules are created by the \l{Module Providers} via the \c pkg-config tool. */ /*! \qmlproperty string capnproto.cpp::compilerName The name of the capnp binary. \defaultvalue \c "capnpc" */ /*! \qmlproperty string capnproto.cpp::compilerPath The path to the protoc binary. Use this property to override the auto-detected location. \defaultvalue \c auto-detected */ /*! \qmlproperty pathList capnproto.cpp::importPaths The list of import paths that are passed to the \c capnpc tool via the \c --import-path option. \defaultvalue \c [] */ /*! \qmlproperty string capnproto.cpp::outputDir The directory where the \c capnpc compiler generated files are placed. \defaultvalue \c product.buildDirectory + "/capnp" */ /*! \qmlproperty bool capnproto.cpp::useRpc Use this property to enable support for the RPC framework. A simple qbs file that uses rpc can be written as follows: \quotefile ../examples/capnproto/calculator_cpp/calculator_cpp.qbs \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/modules/flatbuf-c-module.qdoc0000644000175100001660000000476514776170045022635 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype flatbuf.c \inqmlmodule QbsModules \since Qbs 2.4 \brief Provides support for \l{https://google.github.io/flatbuffers/}{FlatBuffers} for the C language. The \c flatbuf.c module provides support for generating C headers and sources from flatbuffers definition files using the \c flatcc tool. \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"flatbuffers.input"} \li \c{*.fbs} \li 2.4.0 \li Source files with this tag are considered inputs to the \c flatcc compiler. \endtable \section2 Dependencies This module depends on the \c flatcc module which can be created via the \l{conan}{Conan} module provider. */ /*! \qmlproperty string flatbuf.c::compilerName The name of the \c flatcc binary. \defaultvalue \c "flatcc" */ /*! \qmlproperty string flatbuf.c::compilerPath The path to the \c flatcc binary. Use this property to override the auto-detected location. \defaultvalue \c auto-detected */ /*! \qmlproperty pathList flatbuf.c::importPaths The list of import paths that are passed to the \c flatcc tool via the \c -I option. \defaultvalue \c [] */ qbs-src-2.6.1/doc/reference/modules/exporter-qbs-module.qdoc0000644000175100001660000001100014776170045023401 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Exporter.qbs \inqmlmodule QbsModules \since Qbs 1.12 \brief Provides support for generating \QBS modules from products. The Exporter.qbs module contains the properties and rules to create a \QBS module from the \l Export item of a \l Product. Such a module acts as your product's interface to other projects written in \QBS. For instance, suppose you are creating a library. To allow other products both within and outside of your project to make use of it, you would write something like the following: \code DynamicLibrary { name: "mylibrary" qbs.installPrefix: "/opt/mylibrary" Depends { name: "Exporter.qbs" } property string headersInstallDir: "include" // ... Group { name: "API headers" files: ["mylib.h"] qbs.install: true qbs.installDir: headersInstallDir } Group { fileTagsFilter: ["Exporter.qbs.module"] qbs.installDir: "qbs/modules/mylibrary" } Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] prefixMapping: [{ prefix: exportingProduct.sourceDirectory, replacement: FileInfo.joinPaths(exportingProduct.qbs.installPrefix, exportingProduct.headersInstallDir) }] } } \endcode To build against this library, from within your project or any other one, you simply declare a \l{Depends}{dependency}: \code Depends { name: "mylibrary" } \endcode \section2 Relevant File Tags \target filetags-exporter-qbs \table \header \li Tag \li Since \li Description \row \li \c{"Exporter.qbs.module"} \li 1.12.0 \li This tag is attached to the generated module file. \endtable */ /*! \qmlproperty stringList Exporter.qbs::artifactTypes Artifacts that match these tags will become \l{Group::filesAreTargets}{target artifacts} of the generated module, so they can get picked up by the rules of depending products. If you do not specify anything here, all installed artifacts of the product are considered. \note You can only limit the default set of artifacts by setting this property, but you cannot extend it, because only artifacts that are to be installed are considered. \defaultvalue \c undefined */ /*! \qmlproperty string Exporter.qbs::additionalContent The value of this property will be copied verbatim into the generated module. \defaultvalue \c undefined */ /*! \qmlproperty stringList Exporter.qbs::excludedDependencies Normally, all \l Depends items in the \l Export item are copied into the generated module. However, if there are any exported dependencies that only make sense for products in the same project, then you can enter their names into this array, and they will get filtered out. \note You should strive to structure your projects in such a way that you do not need to set this property. \defaultvalue \c undefined */ /*! \qmlproperty string Exporter.qbs::fileName The name of the generated module file. \defaultvalue \c {product.targetName + ".qbs"} */ qbs-src-2.6.1/doc/reference/modules/qbs-module.qdoc0000644000175100001660000006030614776170045021550 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype qbs \inqmlmodule QbsModules \since Qbs 1.0 \brief Comprises general properties. The \c qbs module is implicitly loaded in every product. It contains properties of the current build environment, independent of the used programming languages and toolchains. \section2 Installation Properties Typically, you use \l{Group} items to specify the target directories for installing files. To install a group of files, set the \l{qbs::install} {qbs.install} property of the Group to \c true. The value of \l{qbs::installDir}{qbs.installDir} specifies the path to the directory where the files will be installed. You can specify a base directory for all installation directories as the value of \l{qbs::installPrefix} {qbs.installPrefix}. For example, the following properties specify where a set of QML files and an application executable are installed on Windows and Linux: \badcode Application { name: "myapp" Group { name: "Runtime resources" files: "*.qml" qbs.install: true qbs.installDir: condition: qbs.targetOS.includes("unix") ? "share/myapp" : "resources" } Group { name: "The App itself" fileTagsFilter: "application" qbs.install: true qbs.installDir: "bin" } qbs.installPrefix: condition: qbs.targetOS.includes("unix") ? "usr/local" : "MyApp" } \endcode On Windows, the QML files will ultimately get installed in \c{MyApp\resources} and the application executable in \c MyApp\bin, for instance under \c{C:\Program Files}. On Linux, the QML files will be installed in \c /usr/local/share/myapp and the executable in \c /usr/local/bin. By default, \l{qbs::installRoot}{qbs.installRoot} creates the \c install-root directory in the build directory for packaging the binaries before installation. It is a temporary directory that is usually not available when the application is run, and it should therefore not be set in the project files. You can override the default value from the command line, as described in \l{Installing Files}. \section2 Multiplexing Properties The following properties are specific to \l{Multiplexing} {product multiplexing}: \list \li \l{qbs::}{architectures} \li \l{qbs::}{buildVariants} \li \l{qbs::}{profiles} \endlist */ /*! \qmlproperty string qbs::configurationName \since Qbs 1.6 \readonly The name of the current build configuration. The build configuration is set via the command line parameter \c config. For more information, see \l{build}{build}. \defaultvalue \c{"default"} */ /*! \qmlproperty string qbs::buildVariant The name of the build variant for the current build. Possible values are \c{"debug"}, \c{"release"} and \c{"profiling"}. A debug build usually contains additional debug symbols that are needed for debugging the application and has optimizations turned off. A profiling build usually contains debug symbols and has optimizations turned on. This is useful for profiling tools or when you need to retain debug symbols in a release build. A release build is a build without debug information and with optimizations enabled. \defaultvalue \c{"release"} if \l{qbs::configurationName}{qbs.configurationName} is \c{"release"}. Otherwise \c{"debug"} */ /*! \qmlproperty bool qbs::debugInformation Whether to generate debug information. \defaultvalue \c{true} if \l{qbs::buildVariant}{qbs.buildVariant} is \c{"debug"} or \c{"profiling"}. Otherwise \c{false}. */ /*! \qmlproperty bool qbs::enableDebugCode Whether to enable debug functionality in the product. Not to be confused with generation of debug symbols or the code optimization level. The property changes the following things when enabled: \list \li Passes a flag to the Windows linker to link against a debug Windows CRT (common runtime) library (for example /MTd instead of /MT) \endlist The property changes the following things when disabled: \list \li Passes the \c{NDEBUG} define to the compiler \endlist Typically, this property is enabled for debug builds and disabled for release or profiling builds. \defaultvalue \c{true} for debug builds, \c{false} otherwise. */ /*! \qmlproperty string qbs::optimization The general type of optimization that should be performed by all toolchains. Allowed values are: \list \li \c{"fast"} \li \c{"none"} \li \c{"small"} \endlist \defaultvalue \c{"none"} if \l{qbs::buildVariant}{qbs.buildVariant} is \c{"debug"}. Otherwise \c{"fast"}. */ /*! \qmlproperty string qbs::targetPlatform \since 1.11 The OS you want to build the project for. This property is typically set in a profile or for a particular product where the target OS is always known (such as an Apple Watch app written in native code). For example, a profile used for building for the iOS Simulator platform will have this property set to the \c ios-simulator value: \code profiles.xcode-iphonesimulator.qbs.targetPlatform: "ios-simulator" \endcode You should generally treat this property as \e{write-only} and avoid using it to test for the current target OS. Instead, use the \l{qbs::}{targetOS} property for conditionals. \section2 Relation between targetPlatform and targetOS This table describes the possible values and matching between the \c targetPlatform and the \l{qbs::}{targetOS} properties: \table \header \li Target Platform \li Target OS \row \li \c{"aix"} \li \c{["aix", "unix"]} \row \li \c{"android"} \li \c{["android", "linux", "unix"]} \row \li \c{"dos"} \li \c{["dos"]} \row \li \c{"freebsd"} \li \c{["freebsd", "bsd", "unix"]} \row \li \c{"haiku"} \li \c{["haiku"]} \row \li \c{"hpux"} \li \c{["hpux", "unix"]} \row \li \c{"hurd"} \li \c{["hurd", "unix"]} \row \li \c{"integrity"} \li \c{["integrity", "unix"]} \row \li \c{"ios"} \li \c{["ios", "darwin", "bsd", "unix"]} \row \li \c{"ios-simulator"} \li \c{["ios-simulator", "ios", "darwin", "bsd", "unix"]} \row \li \c{"linux"} \li \c{["linux", "unix"]} \row \li \c{"lynx"} \li \c{["lynx"]} \row \li \c{"macos"} \li \c{["macos", "darwin", "bsd", "unix"]} \row \li \c{"netbsd"} \li \c{["netbsd", "bsd", "unix"]} \row \li \c{"openbsd"} \li \c{["openbsd", "bsd", "unix"]} \row \li \c{"os2"} \li \c{["os2"]} \row \li \c{"qnx"} \li \c{["qnx", "unix"]} \row \li \c{"solaris"} \li \c{["solaris", "unix"]} \row \li \c{"tvos"} \li \c{["tvos", "darwin", "bsd", "unix"]} \row \li \c{"tvos-simulator"} \li \c{["tvos-simulator", "tvos", "darwin", "bsd", "unix"]} \row \li \c{"unix"} \li \c{["unix"]} \row \li \c{"vxworks"} \li \c{["vxworks"]} \row \li \c{"watchos"} \li \c{["watchos", "darwin", "bsd", "unix"]} \row \li \c{"watchos-simulator"} \li \c{["watchos-simulator", "watchos", "darwin", "bsd", "unix"]} \row \li \c{"windows"} \li \c{["windows"]} \row \li \c{"none"} \li \c{["none"]} \row \li \c{undefined} \li \c{[]} \endtable \note The "none" value is usually used for a bare-metal platforms. \sa {Target Platforms} \defaultvalue \l{platform}{Host.platform()} */ /*! \qmlproperty string qbs::architecture The target platform's processor architecture. \c{undefined} indicates that the target platform is architecture-independent (for example the CLR or JVM). This property is typically set in a profile. Commonly used values are: \c{"x86"}, \c{"x86_64"}, and \c{"arm"}. \section2 Supported Processor Architectures This table describes the possible values of the \l{qbs::}{architecture} property: \table \header \li Architecture \li Description \row \li \c{"78k"} \li 16- and 8-bit accumulator-based register-bank CISC architecture microcontroller family manufactured by Renesas Electronics \row \li \c{"arm"} \li 32-bit RISC architecture for computer processors developed by Acorn RISC Machine \note There are a lot of sub-variants of the ARM architecture. Some specialized \QBS modules differentiate between them, making use of values such as \c "armv7a". Please consult the respective module-specific documentation for information on what kind of value to use. \row \li \c{"arm64"} \li 64-bit RISC architecture for computer processors developed by Acorn RISC Machine \row \li \c{"avr"} \li 8-bit modified Harvard RISC architecture microcontroller family manufactured by Microchip Technology \row \li \c{"avr32"} \li 32-bit RISC architecture microcontroller family developed by Atmel \row \li \c{"c166"} \li 16-bit architecture microcontroller family developed by Infineon \row \li \c{"cr16"} \li 16-bit compact RISC architecture microcontroller family developed by National Semiconductor \row \li \c{"e2k"} \li 512-bit Russian wide VLIW microprocessor developed by Moscow Center of SPARC Technologies (MCST) and fabricated by TSMC \row \li \c{"hcs8"} \li 8-bit HC08 and S08 microcontroller family from Freescale Semiconductor \row \li \c{"hcs12"} \li 16-bit HC12 and S12 microcontroller family from Freescale Semiconductor \row \li \c{"hppa"} \li 64-bit PA-RISC processor architecture developed by Hewlett-Packard \row \li \c{"ia64"} \li 64-bit ISA architecture of the Itanium family processors developed by Intel \row \li \c{"m16c"} \li 16-bit CISC microcontrollers featuring high ROM code efficiency manufactured by Renesas Electronics \row \li \c{"m32c"} \li 32- and 16-bit CISC microcontrollers featuring high ROM code efficiency manufactured by Renesas Electronics \row \li \c{"m32r"} \li 32-bit RISC microcontrollers for general industrial and car-mounted systems, digital AV equipment, digital imaging equipment manufactured by Renesas Electronics \row \li \c{"m68k"} \li 16- and 32-bit CISC microprocessor, developed by Motorola Semiconductor Products Sector, and further improved as ColdFire architecture developed by NXP \row \li \c{"mcs251"} \li 8-, 16-, and 32-bit microcontroller family which is a next binary compatible generation for the \c "mcs51" family \row \li \c{"mcs51"} \li 8-bit Harvard architecture microcontroller family developed by Intel \row \li \c{"mips"} \li 32-bit RISC microprocessor without interlocked pipelined stages architecture developed by MIPS Computer Systems \row \li \c{"mips64"} \li 64-bit RISC microprocessor without interlocked pipelined stages architecture developed by MIPS Computer Systems \row \li \c{"msp430"} \li 16-bit mixed-signal microcontroller family manufactured by Texas Instruments \row \li \c{"ppc"} \li 32-bit RISC architecture processor family developed by Apple–IBM–Motorola alliance \row \li \c{"ppc64"} \li 64-bit RISC architecture processor family developed by Apple–IBM–Motorola alliance \row \li \c{"r32c"} \li 32-bit CISC microcontrollers with improved code efficiency and processing performance manufactured by Renesas Electronics \row \li \c{"rh850"} \li 32-bit automotive microcontroller family manufactured by Renesas Electronics \row \li \c{"riscv"} \li Open and free standard instruction set architecture based on established RISC principles \row \li \c{"rl78"} \li 16- and 8-bit accumulator-based register-bank CISC architecture with 3-stage instruction pipelining microcontroller family manufactured by Renesas Electronics \row \li \c{"rx"} \li High performance 32-bit CISC microcontroller family manufactured by Renesas Electronics \row \li \c{"s390x"} \li 64- and 32-bit System/390 processor architecture developed by IBM \row \li \c{"sh"} \li 32-bit RISC architecture processor family developed by Hitachi and currently manufactured by Renesas Electronics \row \li \c{"sparc"} \li 32-bit RISC architecture processor family developed by Sun Microsystems and Fujitsu \row \li \c{"sparc64"} \li 64-bit RISC architecture processor family developed by Sun Microsystems and Fujitsu \row \li \c{"stm8"} \li 8-bit microcontroller family manufactured by STMicroelectronics \row \li \c{"v850"} \li 32-bit RISC microcontroller family manufactured by Renesas Electronics \row \li \c{"x86"} \li 32-bit ISA architecture processor family developed by Intel \row \li \c{"x86_16"} \li 16-bit ISA architecture processor family developed by Intel \row \li \c{"x86_64"} \li 64-bit ISA architecture processor family developed by AMD \row \li \c{"xtensa"} \li 32-bit architecture with a compact 16- and 24-bit instruction set developed by Tensilica \endtable \nodefaultvalue */ /*! \qmlproperty stringList qbs::toolchain Contains the list of string values describing the toolchain and toolchain family that is used to build a project. This property is deduced from the \l{qbs::}{toolchainType} property and is typically used to test for a particular toolchain or toolchain family in conditionals: \code Properties { // flags for GCC condition: qbs.toolchain.includes("gcc") cpp.commonCompilerFlags: ... } Properties { // flags for MSVC condition: qbs.toolchain.includes("msvc") cpp.commonCompilerFlags: ... } \endcode Unlike \l{qbs::}{toolchainType}, which contains a single value, \c qbs.toolchain is a string list which also contains the toolchain family. This allows to make conditions and checks simpler. For example, instead of: \code (qbs.toolchainType === "xcode" || qbs.toolchainType === "clang" || qbs.toolchainType === "gcc") \endcode use: \code qbs.toolchain.includes("gcc") \endcode since XCode, GCC and Clang belong to the \c "gcc" family. \section2 Relation between toolchainType and toolchain This table describes the possible values and matching between the \l{qbs::}{toolchainType} and the \c toolchain properties: \table \header \li Toolchain Type \li Toolchain \row \li \c{"clang"} \li \c{["clang", "llvm", "gcc"]} \row \li \c{"clang-cl"} \li \c{["clang-cl", "msvc"]} \row \li \c{"cosmic"} \li \c{["cosmic"]} \row \li \c{"dmc"} \li \c{["dmc"]} \row \li \c{"gcc"} \li \c{["gcc"]} \row \li \c{"iar"} \li \c{["iar"]} \row \li \c{"keil"} \li \c{["keil"]} \row \li \c{"llvm"} \li \c{["llvm", "gcc"]} \row \li \c{"mingw"} \li \c{["mingw", "gcc"]} \row \li \c{"msvc"} \li \c{["msvc"]} \row \li \c{"qcc"} \li \c{["qcc"]} \row \li \c{"sdcc"} \li \c{["sdcc"]} \row \li \c{"watcom"} \li \c{["watcom"]} \row \li \c{"xcode"} \li \c{["xcode", "clang", "llvm", "gcc"]} \endtable \nodefaultvalue */ /*! \qmlproperty string qbs::toolchainType \since Qbs 1.11 The toolchain that is going to be used for this build. For example, to build a project using the \c "clang" toolchain, simply do \code qbs build qbs.toolchainType:clang \endcode You should generally treat this property as \e{write-only} and avoid using it to test for the current toolchain. Instead, use the \l{qbs::}{toolchain} property for conditionals. Typical values include: \c{"gcc"}, \c{"clang"}, \c{"clang-cl"}, \c{"mingw"}, \c{"msvc"}, and \c{"xcode"}. Also see \l{Relation between toolchainType and toolchain}. By default, \c qbs.toolchainType is automatically detected based on the \l{qbs::}{targetOS} property: \table \header \li Target OS \li Toolchain \row \li \c{"darwin"} \li \c{"xcode"} \row \li \c{"freebsd"} \li \c{"clang"} \row \li \c{"haiku"} \li \c{"gcc"} \row \li \c{"qnx"} \li \c{"qcc"} \row \li \c{"unix"} \li \c{"gcc"} \row \li \c{"vxworks"} \li \c{"gcc"} \row \li \c{"windows"} \li \c{"msvc"} \endtable \defaultvalue Determined automatically. */ /*! \qmlproperty string qbs::sysroot The \c sysroot of the target platform. This property is typically set in a profile for cross-compiling. \nodefaultvalue */ /*! \qmlproperty path qbs::shellPath \since Qbs 1.5 The platform-specific file path corresponding to the command line interpreter. On Windows, this is the path to \c{cmd.exe}, which is held in the \c{COMSPEC} environment variable (typically, \c{C:/Windows/System32/cmd.exe}), On Unix-like platforms, this is \c{/bin/sh}. \defaultvalue \c{"%COMSPEC%"} on Windows, \c{"/bin/sh"} on Unix */ /*! \qmlproperty stringList qbs::targetOS \readonly Contains the list of string values describing the OS and OS family that is used to build a project. This property is calculated based on the \l{qbs::}{targetPlatform} property and is typically used to test for a particular OS or OS family in conditionals: \code Group { // Includes all Unix-like platforms, such as: Linux, BSD, Apple platforms and others. condition: qbs.targetOS.includes("unix") files: ... } Group { // Includes all Apple platforms, such as macOS, iOS, and iOS Simulator. condition: qbs.targetOS.includes("darwin") files: ... } Group { // Includes only macOS condition: qbs.targetOS.includes("macos") files: ... } \endcode Avoid using \l{qbs::}{targetPlatform} for this purpose. For example, instead of: \code qbs.targetPlatform === "macos" || qbs.targetPlatform === "ios" || qbs.targetPlatform === "tvos" || qbs.targetPlatform === "watchos" \endcode use \code qbs.targetOS.includes("darwin") \endcode However, in some cases using \l{qbs::}{targetPlatform} would be acceptable, such as when the resulting condition would be simpler while still being correct: \code qbs.targetPlatform === "linux" \endcode versus \code qbs.targetOS.includes("linux") && !qbs.targetOS.includes("android") \endcode For the complete list of possible values, see \l{Relation between targetPlatform and targetOS}. \nodefaultvalue */ /*! \qmlproperty string qbs::version \readonly \since Qbs 1.4.1 The version number of \QBS as a string. For example, \c "1.4.1". */ /*! \qmlproperty int qbs::versionMajor \readonly \since Qbs 1.4.1 The major version number of \QBS. */ /*! \qmlproperty int qbs::versionMinor \readonly \since Qbs 1.4.1 The minor version number of \QBS. */ /*! \qmlproperty int qbs::versionPatch \readonly \since Qbs 1.4.1 The patch version number of \QBS. */ /*! \qmlproperty bool qbs::install Whether to install a certain set of files. This property is typically set in a \l{Group} item to mark a number of files as installable. \note Artifacts for which this property is enabled automatically receive the file tag \c "installable". This is useful for writing packaging-related rules. \defaultvalue \c{false} */ /*! \qmlproperty string qbs::installSourceBase \since Qbs 1.4 The base directory of the local files that are going to be installed. The source base directory is omitted from the target directory path specified in \l{qbs::}{installDir}. \defaultvalue The directory of the current file to be installed, relative to the product's source directory. */ /*! \qmlproperty string qbs::installDir The installation directory for the files of a \l{Product}{product} or a \l{Group}. The value of this property is a path that is relative to \l{qbs::} {installPrefix}. \nodefaultvalue */ /*! \qmlproperty string qbs::installPrefix \since Qbs 1.1 The global installation prefix. It is implicitly prepended to all values of \l{qbs::}{installDir}. The value of this property itself is relative to the \l{qbs::}{installRoot} in the context of installation. \defaultvalue \c "/usr/local" on Unix, \c "" otherwise */ /*! \qmlproperty string qbs::installRoot \since Qbs 1.4 The global installation root. It is implicitly prepended to all values of \l{qbs::}{installPrefix} in the context of installation. \note This property is fundamentally different from \l{qbs::}{installDir} and \l{qbs::}{installPrefix} in that it must not be visible to the code being built. In fact, the install root is often just a temporary location used to package the binaries, which should therefore not assume they will be in that location at run-time. For the same reason, this property is usually not set from within project files. \defaultvalue \c{/install-root} */ /*! \qmlproperty stringList qbs::architectures \since Qbs 1.9 The architectures the product will be built for. \nodefaultvalue */ /*! \qmlproperty stringList qbs::buildVariants \since Qbs 1.9 The build variants the product will be built for. \nodefaultvalue */ /*! \qmlproperty stringList qbs::profiles \since Qbs 1.9 The profiles for which the product should be built. For each profile listed here, one instance of the product will be built according to the properties set in the respective profile. \defaultvalue \l{Project::profile}{[project.profile]} */ qbs-src-2.6.1/doc/reference/modules/qt-plugin_support-module.qdoc0000644000175100001660000000565714776170045024507 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.plugin_support \inqmlmodule QbsModules \since Qbs 1.13.0 \brief Allows to fine-tune which Qt plugins get pulled in. The \c Qt.plugin_support module provides properties that allow users to control which Qt plugins to pull into a product. This is mostly relevant if Qt was built statically, in which case the respective plugins are static libraries that get linked into your application or library. */ /*! \qmlproperty varList Qt.plugin_support::pluginsByType Set this property if you want to override the set of plugins for a certain plugin type. For instance, to disable all image plugins except the JPEG one: \code Qt.plugin_support.pluginsByType: ({imageformats: "qjpeg"}) \endcode For plugin types that are not specifically overridden like this, the value in defaultPluginsByType is used. \nodefaultvalue */ /*! \qmlproperty var Qt.plugin_support::allPluginsByType Provides the complete set of plugins in a statically built Qt. The value is a map. The keys are the plugin types, and the values are lists of plugin names. \readonly */ /*! \qmlproperty var Qt.plugin_support::defaultPluginsByType Provides the set of plugins that your application or library will link to if you do not set pluginsByType. The value is a map. The keys are the plugin types, and the values are lists of plugin names. The value depends on the Qt modules your product pulls in. \readonly */ /*! \qmlproperty bool Qt.plugin_support::linkPlugins Controls whether plugins of a statically built Qt should be linked into the product. \defaultvalue \c true if the product is an application or shared library, \c false otherwise. */ qbs-src-2.6.1/doc/reference/modules/wix-module.qdoc0000644000175100001660000001753614776170045021601 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype wix \inqmlmodule QbsModules \since Qbs 1.2 \brief Provides Windows Installer XML Toolset support. The \c wix module contains properties and rules for building MSI and EXE setup packages with the \l{Windows Installer XML Toolset}. This module is available on all platforms. \section2 Relevant File Tags \target filetags-wix \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"msi"} \li - \li 1.2 \li The rule that creates the Microsoft Installer setup file attaches this tag to its output artifact. \row \li \c{"wixpdb"} \li - \li 1.2 \li The rule that creates the Microsoft Installer setup file or WiX setup executable attaches this tag to the associated debug symbol file. \row \li \c{"wixsetup"} \li - \li 1.2 \li The rule that creates the WiX setup executable attaches this tag to its output artifact. \row \li \c{"wxi"} \li \c{*.wxi} \li 1.2 \li This tag is attached to WiX include files. \row \li \c{"wxl"} \li \c{*.wxl} \li 1.2 \li This tag is attached to WiX localization files. \row \li \c{"wxs"} \li \c{*.wxs} \li 1.2 \li This tag is attached to WiX source files. Each source file will be compiled into one WiX object file. \endtable */ /*! \qmlproperty bool wix::debugInformation Whether to generate debug information. \sa {qbs::debugInformation}{qbs.debugInformation} \defaultvalue \l{qbs::debugInformation}{qbs.debugInformation} */ /*! \qmlproperty stringList wix::defines A list of preprocessor macros that get passed to the compiler. To set macro values, use the following syntax: \badcode wix.defines: ["USE_COLORS=1", 'COLOR_STR="blanched almond"'] \endcode \nodefaultvalue */ /*! \qmlproperty bool wix::enableQbsDefines Whether to define preprocessor macros corresponding to values from the project and product objects. When building a 64-bit package, the preprocessor variable \c{Win64} will also be defined. \defaultvalue \c{true} */ /*! \qmlproperty bool wix::visualStudioCompatibility Whether to pass most of the same preprocessor macros to the compiler as Visual Studio does. This allows easier authoring of WiX files that are compatible with both \QBS and MSBuild. \defaultvalue \c{true} */ /*! \qmlproperty pathList wix::includePaths A list of include paths. Relative paths are considered to be relative to the \c .qbs product file they are used in. \nodefaultvalue */ /*! \qmlproperty bool wix::treatWarningsAsErrors Whether warnings will be handled as errors and cause the build to fail. \defaultvalue \c{false} */ /*! \qmlproperty string wix::warningLevel The severity of warnings to emit. The higher the level, the more warnings will be shown. Possible values include: \c{"none"}, \c{"normal"}, \c{"pedantic"} \defaultvalue \c{"normal"} */ /*! \qmlproperty bool wix::verboseOutput Whether to display verbose output from the compiler and linker. \defaultvalue \c{false} */ /*! \qmlproperty stringList wix::compilerFlags A list of additional flags for the Candle compiler. \nodefaultvalue */ /*! \qmlproperty stringList wix::linkerFlags A list of additional flags for the Light linker. \nodefaultvalue */ /*! \qmlproperty stringList wix::cultures A list of localizations to include in the MSI. If left undefined, includes all localizations. \nodefaultvalue */ /*! \qmlproperty stringList wix::extensions A list of extension assemblies to link into the output. Possible values include: \list \li custom assemblies \li \c{"WixBalExtension"} \li \c{"WixComPlusExtension"} \li \c{"WixDependencyExtension"} \li \c{"WixDifxAppExtension"} \li \c{"WixDirectXExtension"} \li \c{"WixFirewallExtension"} \li \c{"WixGamingExtension"} \li \c{"WixIisExtension"} \li \c{"WixMsmqExtension"} \li \c{"WixNetFxExtension"} \li \c{"WixPSExtension"} \li \c{"WixSqlExtension"} \li \c{"WixTagExtension"} \li \c{"WixUIExtension"} \li \c{"WixUtilExtension"} \li \c{"WixVSExtension"} \endlist \defaultvalue \c{["WixBalExtension"]} if the product type is an EXE setup application, otherwise \c{undefined}. */ /*! \qmlproperty string wix::version The WiX version. Consists of four numbers separated by dots. For example, "3.7.1224.0". \nodefaultvalue */ /*! \qmlproperty int wix::versionMajor The WiX major version. \defaultvalue \c{versionParts[0]} */ /*! \qmlproperty int wix::versionMinor The WiX minor version. \defaultvalue \c{versionParts[1]} */ /*! \qmlproperty list wix::versionParts The WiX version as a list. For example, WiX version 3.7.1224.0 would correspond to a value of \c[3, 7, 1224, 0]. \defaultvalue \c [] */ /*! \qmlproperty int wix::versionPatch The WiX patch level. \defaultvalue \c{versionParts[2]} */ /*! \qmlproperty int wix::versionBuild The fourth WiX version number component. \defaultvalue \c{versionParts[3]} */ /*! \qmlproperty path wix::toolchainInstallPath The WiX installation directory. This property should not normally need to be changed. \defaultvalue Determined automatically by searching the registry for the latest version. */ /*! \qmlproperty path wix::toolchainInstallRoot The WiX binaries directory. This property should not normally need to be changed. \defaultvalue Determined automatically by searching the registry for the latest version. */ /*! \qmlproperty string wix::compilerName The name of the compiler binary. This property should not normally need to be changed. \defaultvalue \c{"candle.exe"} */ /*! \qmlproperty string wix::compilerPath The directory where the compiler binary is located. This property should not normally need to be changed. \defaultvalue \l{wix::}{compilerName} */ /*! \qmlproperty string wix::linkerName The name of the linker binary. This property should not normally need to be changed. \defaultvalue \c{"light.exe"} */ /*! \qmlproperty string wix::linkerPath The directory where the linker binary is located. This property should not normally need to be changed. \defaultvalue \l{wix::}{linkerName} */ qbs-src-2.6.1/doc/reference/modules/qt-dbus-module.qdoc0000644000175100001660000000522514776170045022341 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.dbus \inqmlmodule QbsModules \brief Provides Qt D-Bus support. The Qt.dbus module provides support for the Qt D-Bus module, which contains classes for inter-process communication over the D-Bus protocol. \section2 Relevant File Tags \target filetags-debus \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"qt.dbus.adaptor"} \li - \li 1.5 \li Source files with this tag serve as inputs to the rule running the \c qdbusxml2cpp tool, which will create an adaptor class. \row \li \c{"qt.dbus.interface"} \li - \li 1.5 \li Source files with this tag serve as inputs to the rule running the \c qdbusxml2cpp tool, which will create an interface class. \endtable */ /*! \qmlproperty string Qt.dbus::xml2cppName The base name of the \c qdbusxml2cpp tool. Set this property if your system uses a name different from the default value. \defaultvalue \c{"qdbusxml2cpp"} */ /*! \qmlproperty stringList Qt.dbus::xml2CppHeaderFlags A list of additional flags when running the \c qdbusxml2cpp tool to create header files. \defaultvalue \c [] */ /*! \qmlproperty stringList Qt.dbus::xml2CppSourceFlags A list of additional flags when running the \c qdbusxml2cpp tool to create source files. \defaultvalue \c [] */ qbs-src-2.6.1/doc/reference/modules/qt-modules.qdoc0000644000175100001660000001172414776170045021572 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page qt-modules.html \inmodule qbs-modules \title Qt Modules \brief Provides Qt support. The \c{Qt.*} modules contain properties and rules for Qt. Qt modules are generated by the \l[QML]{Qt} module provider. \section1 Creating Dependencies to Qt Modules The Qt modules are grouped using the prefix \c Qt. If your product depends on the Qt.core and Qt.network modules, you could write: \code Depends { name: "Qt.core" } Depends { name: "Qt.network" } \endcode Or, alternatively: \code Depends { name: "Qt"; submodules: [ "core", "network" ] } \endcode The Qt modules that have properties and relevant file tags are described in separate topics. \section1 List of Submodules \table \header \li Submodule Name \li Qt Module Name \li Notes \row \li axcontainer \li QAxContainer \li This module is only available on Windows. \row \li axserver \li QAxServer \li This module is only available on Windows. \row \li concurrent \li Qt Concurrent \li \row \li \l{Qt.core}{core} \li Qt Core \li For more information, see \l{Qt.core}. \row \li \l{Qt.dbus}{dbus} \li Qt D-Bus \li For more information, see \l{Qt.dbus}. \row \li \l{Qt.declarative}{declarative} \li Qt Quick 1 \li Provides the \c{Qt Quick 1} module. For more information, see \l{Qt.declarative}. \row \li designer \li Qt Designer \li \row \li enginio \li Qt Enginio \li \row \li \l{Qt.gui}{gui} \li Qt GUI \li For more information, see \l {Qt.gui}. \row \li help \li Qt Help \li You do not need this module for building \c qdoc documentation, because that functionality is part of the Qt.core module. This module is for using Qt classes such as \c QHelpEngine. \row \li multimedia \li Qt Multimedia \li \row \li multimediawidgets \li Qt Multimedia Widgets \li \row \li network \li Qt Network \li \row \li opengl \li Qt OpenGL \li \row \li phonon \li Phonon (Qt 4 only) \li \row \li printsupport \li Qt Print Support \li \row \li \l{Qt.quick}{quick} \li Qt Quick 2 \li Provides the \c{Qt Quick} module (Qt Quick 2). For more information, see \l{Qt.quick}. \row \li quickcontrols2 \li Qt Quick Controls 2 \row \li \l{Qt.qml}{qml} \li Qt QML \li For more information, see \l{Qt.qml}. \row \li qmltest \li Qt Quick Test \li \row \li script \li Qt Script \li \row \li \l{Qt.scxml}{scxml} \li Qt Scxml \li For more information, see \l {Qt.scxml}. \row \li sql \li Qt SQL \li \row \li svg \li Qt SVG \li \row \li testlib \li Qt Test \li \row \li webkit \li Qt WebKit \li \row \li webkitwidgets \li Qt WebKit Widgets \li \row \li widgets \li Qt Widgets \li \row \li xml \li Qt XML \li You do not need this module for the \c QXmlStreamReader and \c QXmlStreamWriter classes, because those classes are a part of the \c Qt.core module. This module provides the deprecated DOM and SAX classes. \row \li xmlpatterns \li Qt XML Patterns \li \li \endtable */ qbs-src-2.6.1/doc/reference/modules/qt-qml-module.qdoc0000644000175100001660000001314714776170045022177 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.qml \inqmlmodule QbsModules \brief Provides Qt QML support. The Qt.qml module provides support for the Qt QML module, which contains classes for QML and JavaScript languages. \note If the current value of \l{qbs::architecture}{qbs.architecture} is not supported by \c qmlcachegen, the QML cache file generator rule is disabled. \sa Qt.quick, Qt.declarative \section2 Relevant File Tags \target filetags-qml \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"qt.qml.js"} \li \c{*.js} \li 1.10 \li QML companion JavaScript files. Source files with this tag serve as input for the QML cache file generator. \row \li \c{"qt.qml.qml"} \li \c{*.qml} \li 1.8 \li Source files with this tag serve as inputs to the QML plugin scanner. \row \li \c{"qt.qml.types"} \li n/a \li 1.16 \li This tag is attached to the files created by the \c qmltyperegistrar tool if the \l importName property is set. \endtable */ /*! \qmlproperty string Qt.qml::importName Setting this value triggers QML type registration via the \c qmltyperegistrar tool, which results in the creation of a file with the tag \c{"qt.qml.types"}. The given string is the name under which the registered types can be imported by QML code that wants to use them. \note This functionality is only available with Qt 5.15 or later. \since Qbs 1.16 \nodefaultvalue */ /*! \qmlproperty string Qt.qml::importVersion Specifies the version of the types to be registered. Values consist of a major and an optional minor number, separated by dots. This property has no effect if \l importName is not set. \since Qbs 1.16 \defaultvalue \l {Product::version}{The product version} */ /*! \qmlproperty string Qt.qml::typesFileName Specifies the name of the file that declares the types registered for this product. For applications, the default value is \c{.qmltypes}, where \c{} is the product's \l{Product::targetName}{target name}. Otherwise, the default value is "plugins.qmltypes". \note The naming conventions are still in flux. When in doubt, consult the Qt documentation. This property has no effect if \l importName is not set. \since Qbs 1.16 */ /*! \qmlproperty string Qt.qml::typesInstallDir The directory to install the qmltypes file into. If this property is empty or undefined, the file will not be installed. This property has no effect if \l importName is not set. \since Qbs 1.16 \nodefaultvalue */ /*! \qmlproperty stringList Qt.qml::extraMetaTypesFiles Specifies extra metatypes files to pass to the \c qmltyperegistrar tool via the \c{--foreign-types} option when registering QML types. \note This property is only needed for external libraries, not products or modules pulled via \c Depends items. In particular, you don't need to (and should not) use it to collect the metatypes files of Qt modules. These are found automatically. This property has no effect if \l importName is not set. \since Qbs 1.16 \nodefaultvalue */ /*! \qmlproperty string Qt.qml::qmlImportScannerName The base name of the QML import scanner. Set this value if your system uses a name different from the default value. \defaultvalue \c{"qmlimportscanner"} */ /*! \qmlproperty string Qt.qml::qmlPath The absolute path to the directory where Qt's QML files are installed. \defaultvalue Determined by \l{setup-qt}. */ /*! \qmlproperty bool Qt.qml::generateCacheFiles Whether QML cache files are generated. \defaultvalue \c{false} */ /*! \qmlproperty bool Qt.qml::cachingEnabled \readonly This property is \c true if \l{Qt.qml::}{generateCacheFiles} is \c{true} and the platform supports QML cache generation. \defaultvalue \c{false} */ /*! \qmlproperty string Qt.qml::qmlCacheGenPath The absolute path to the \c qmlcachegen executable. \defaultvalue Determined by \l{setup-qt}. */ /*! \qmlproperty string Qt.qml::cacheFilesInstallDir The path to the directory where the cache files are installed. If this property is set, QML cache files are automatically installed. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/modules/bundle-module.qdoc0000644000175100001660000003354514776170045022241 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Jake Petroules. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype bundle \inqmlmodule QbsModules \since Qbs 1.4 \brief Provides Core Foundation bundle support. The \c bundle module contains properties and rules for building and working with Core Foundation bundles on Apple platforms (commonly known as CFBundles or simply \e bundles), directories with a standardized hierarchical structure that hold executable code and resources. Examples include applications, frameworks, and plugins. This module is available on all platforms but is currently only useful on Apple platforms. \note Core Foundation bundles are not to be confused with Mach-O loadable modules, which are also referred to as (loadable) \e bundles in Apple parlance. In \QBS, Core Foundation bundles are referred to as \e bundles, while Mach-O loadable bundles are referred to as \e {loadable modules}. \section2 Relevant File Tags \target filetags-bundle \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"bundle.content"} \li - \li 1.8 \li Attached to the output artifacts of the rule that produces the bundle. \row \li \c{"infoplist"} \li \c{Info.plist}, \c{*-Info.plist} \li 1.5 \li Source files with this tag are Info property lists files or fragments that are merged into the bundle's final \c Info.plist. \endtable */ /*! \qmlproperty bool bundle::isBundle Whether the product should actually be packaged as a bundle as opposed to a flat file. This allows a product indirectly dependent on the \c{bundle} module to retain control of whether it should actually be built as a bundle. \defaultvalue \c{true} for applications and dynamic libraries on Apple platforms, \c{false} otherwise. */ /*! \qmlproperty bool bundle::isShallow \readonly Whether the bundle directory tree is \e shallow. That is, whether it lacks a \c Contents subdirectory. This is the default on all platforms other than macOS. \defaultvalue \c{false} on macOS, otherwise \c{true}. */ /*! \qmlproperty string bundle::identifierPrefix A prefix for the product's bundle identifier. If \l{bundle::}{identifier} is left unset, the bundle identifier will be a concatenation of this value and the \l{Product::targetName}{Product.targetName} property formatted as an RFC-1034 identifier, separated by a period (.). This corresponds to the organization identifier in Xcode. \defaultvalue \c{org.example} */ /*! \qmlproperty string bundle::identifier The bundle's identifier. If left unset, the bundle identifier will be a concatenation of the \l{bundle::}{identifierPrefix} value and the \l{Product::targetName}{Product.targetName} propertyy formatted as an RFC-1034 identifier, separated by a period (.). \defaultvalue A combination of \l{bundle::}{identifierPrefix} and the product's target name formatted as an RFC-1034 identifier. */ /*! \qmlproperty string bundle::extension The extension of the bundle's wrapper directory, without the leading period (.). This property should not normally need to be set unless creating a custom bundle type. \defaultvalue \c{"app"} for \c{"APPL"} packages, \c{"framework"} for \c{"FMWK"} packages, and \c{"bundle"} for \c{"BNDL"} and custom packages. */ /*! \qmlproperty string bundle::packageType The four-letter file type code of the bundle, specified in the bundle's \c PkgInfo file and in the bundle's \c Info.plist as the value for the \c CFBundlePackageType key. This property should almost never need to be changed, even though specifying an alternative package type for custom bundles is allowed. \defaultvalue \c{"APPL"} for applications, \c{"FMWK"} for frameworks, and \c{"BNDL"} for custom bundles. */ /*! \qmlproperty bool bundle::generatePackageInfo \since Qbs 1.5 Whether to generate a \c PkgInfo file for the bundle. This property should almost never need to be changed, even though enabling it when specifying an alternative package type for custom bundles using \l{bundle::}{packageType} is allowed. \defaultvalue \c{true} for applications, otherwise \c{false}. */ /*! \qmlproperty string bundle::signature The four-letter signature specific to the bundle, also known as the creator code, specified in the bundle's \c PkgInfo file and in the bundle's \c Info.plist as the value for the \c CFBundleSignature key. This property should normally never need to be set. \defaultvalue \c{"????"} */ /*! \qmlproperty string bundle::bundleName The file name of the bundle's wrapper directory. This property should not normally need to be changed. \defaultvalue A combination of the product's \l{Product::}{targetName} and bundle's \l{bundle::}{extension}. */ /*! \qmlproperty string bundle::frameworkVersion For framework bundles, the version of the framework. Not used for other package types. \defaultvalue \c{"A"} */ /*! \qmlproperty pathList bundle::publicHeaders A list of public header files to copy to a framework bundle's \c Headers subdirectory. \nodefaultvalue */ /*! \qmlproperty pathList bundle::privateHeaders A list of private header files to copy to a framework bundle's \c PrivateHeaders subdirectory \nodefaultvalue */ /*! \qmlproperty pathList bundle::resources A list of resources to copy to a bundle's \c Resources subdirectory. Files will automatically be copied into \c lproj subdirectories corresponding to the input files' paths. \nodefaultvalue */ /*! \qmlproperty var bundle::infoPlist A dictionary of key-value pairs to add to the bundle's \c Info.plist. The contents of this property will be aggregated with the values from any \c plist files. If this property and any \c plist files contain the same key, this property will take precedence. However, it might be overridden during postprocessing (see \l{bundle::}{processInfoPlist}). If \c undefined, will not be taken into account. \nodefaultvalue */ /*! \qmlproperty bool bundle::processInfoPlist Whether to perform post-processing on the aggregated \c Info.plist contents. If this property is \c{true}, various post-processing operations will be applied to the bundle's property list dictionary after it has been aggregated from the contents of any \c plist files on disk, and the \l{bundle::}{infoPlist} property. First, values from a list of defaults will be added to the dictionary if they were not already present. Second, values from the \c AdditionalInfo key of the platform SDK's \c Info.plist file will be added to the dictionary if they were not already present, as well as some other miscellaneous keys, such as \c BuildMachineOSBuild and \c UIDeviceFamily (on iOS). Finally, variable expansions will be performed such that substrings of the form \c $(VAR) or \c ${VAR} will be replaced with their corresponding environment variables. \defaultvalue \c{true} */ /*! \qmlproperty bool bundle::embedInfoPlist Whether to create a \c{__TEXT} section in the product's executable containing the processed \c Info.plist. Only applies to command line applications. \defaultvalue \c{true} if the product is a command line tool, otherwise \c{false}. */ /*! \qmlproperty string bundle::infoPlistFormat The file format to write the product's resulting \c Info.plist in. Possible values are: \list \li \c{"binary1"} \li \c{"json"} \li \c{"same-as-input"} \li \c{"xml1"} \endlist \defaultvalue \c{"binary1"} for iOS, \c{"same-as-input"} or \c{"xml1"} for macOS depending on whether a \c plist file is used, and \c{undefined} for all other operating systems. */ /*! \qmlproperty string bundle::infoPlistPath \readonly The path that the \c Info.plist file will be written to. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::infoStringsPath \readonly \since Qbs 1.5 The path that the \c InfoPlist.strings file will be written to. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::pkgInfoPath \readonly The path that the \c PkgInfo file will be written to. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::versionPlistPath \readonly The path that the \c version.plist file will be written to. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::executablePath \readonly The path that the main executable file will be written to. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::contentsFolderPath \readonly The path of the bundle's \c Contents subdirectory. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::documentationFolderPath \readonly \since Qbs 1.5 The path of the directory where documentation will be written. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::executableFolderPath \readonly The path of the directory where the main exectuable will be written. The path is relative to the directory that contains the bundle. Not to be confused with \l{bundle::}{executablesFolderPath}. */ /*! \qmlproperty string bundle::executablesFolderPath \readonly The path of the directory where auxiliary executables will be copied. The path is relative to the directory that contains the bundle. Not to be confused with \l{bundle::}{executableFolderPath}. */ /*! \qmlproperty string bundle::frameworksFolderPath \readonly The path of the directory where internal frameworks will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::javaFolderPath \readonly \since Qbs 1.5 The path of the directory where Java content will be written. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::localizedResourcesFolderPath \readonly \since Qbs 1.5 The path of the directory where localized resource files will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::pluginsFolderPath \readonly The path of the directory where plugins will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::privateHeadersFolderPath \readonly The path of the directory where private header files will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::publicHeadersFolderPath \readonly The path of the directory where public headers files will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::scriptsFolderPath \readonly The path of the directory where script files will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::sharedFrameworksFolderPath \readonly The path of the directory where shared frameworks will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::sharedSupportFolderPath \readonly The path of the directory where shared support files will be copied. The path is relative to the directory that contains the bundle. */ /*! \qmlproperty string bundle::unlocalizedResourcesFolderPath \readonly The path of the directory where non-localized resource files will be copied. The path is relative to the directory that contains the bundle. This is the same as the base resources path. */ /*! \qmlproperty bool bundle::useBuiltinXcodeBuildSpecs Set this property to \c true to use Xcode \c .xcspec files shipped with \QBS. This property can be used as a workaround when using a new Xcode version that is not supported by \QBS yet. \default false */ /*! \qmlproperty string bundle::versionsFolderPath \readonly \since Qbs 1.5 The path of the bundle's \c Versions subdirectory. The path is relative to the directory that contains the bundle. This is only relevant for (non-shallow) framework bundles. */ qbs-src-2.6.1/doc/reference/modules/dmg-module.qdoc0000644000175100001660000003165114776170045021533 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype dmg \inqmlmodule QbsModules \since Qbs 1.9 \brief Provides support for building Apple Disk Images. The \c dmg module contains properties and rules for building Apple Disk Images, which are typically used to distribute applications and installers on macOS. This module is only available on Apple platforms. \QBS enables you to build macOS disk images with custom backgrounds and icon layouts. Most applications on macOS are installed via a \c .dmg file, which is usually customized by using a custom image background and icon layout. Unfortunately, it is challenging to construct such DMG files correctly, because the layout relies on several undocumented proprietary file formats, some of which date back to the Mac OS Classic days, and which are even nested within one another. Most of the existing tools to create DMG files do so by using AppleScript to manipulate the Finder graphically to generate the appropriate icon layout, which is both unstable and incompatible with headless build servers, because the necessary OS services to launch graphical applications may not be running at all. Many projects create the primary \c .DS_Store file manually, and commit the result to their source repository. This binary blob is difficult to inspect and edit, and might not be backwards compatible with older versions of the OS, depending on how it was generated. \QBS takes a different approach. It generates the necessary files programmatically, in an entirely reproducible manner. There are no external dependencies that need to be separately installed nor do any binary blobs need to be committed to your source repository. \section2 Appearance Properties Appearance properties are used to control the contents of the .DS_Store file and its embedded Alias and Bookmark records, that will be generated by \QBS in order to control the appearance of the disk image when mounted in Finder. \section2 License Properties License properties are used to control the content and appearance of the license prompt displayed when a user attempts to mount the resulting disk image via Finder. \section2 Relevant File Tags \target filetags-dmg The file tags determine how the tagged files are handled. \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"dmg.input"} \li n/a \li 1.9 \li Tagged files are copied into the disk image. The \l{dmg::}{sourceBase} property controls the destination directory and hierarchy of copied files within the disk image. \row \li \c{"dmg.license.input"} \li \c{*.txt}, \c{*.rtf}, \c{*.html}, \c{*.doc}, \c{*.docx}, \c{*.odt}, \c{*.xml}, \c{*.webarchive} \li 1.9 \li Tagged files are converted into rich text and used for the license prompt when mounting the DMG. \row \li \c{"icns"} \li \c{*.icns} \li 1.3 \li The tagged file is added as the Apple Disk Image volume icon, which will show up in the Finder as an overlay on the file icon. \row \li \c{"tiff"} \li \c{*.tif}, \c{*.tiff} \li 1.9 \li The tagged file is used as the background image of the directory as shown in Finder when the DMG file is mounted. \endtable */ /*! \qmlproperty string dmg::volumeName The name of the disk image that is displayed in Finder when the DMG is mounted. \defaultvalue \l{Product::targetName}{product.targetName} */ /*! \qmlproperty bool dmg::badgeVolumeIcon Whether to render the user-supplied icon (\l{filetags-dmg}{"icns"}) on top of the default volume icon instead of using it directly. This generally gives the disk image icon a better and more consistent appearance. \defaultvalue \c{false} */ /*! \qmlproperty string dmg::format The format to create the disk image in. Allowed values include but are not limited to \c{"UDZO"}, \c{"UDBZ"}, and \c{"ULFO"}. \defaultvalue \c{"UDBZ"} */ /*! \qmlproperty int dmg::compressionLevel The \c zlib, \c bzip2, or \c lzfse compression level for UDZO, UDBZ, or ULFO disk images. \defaultvalue \c 9 in release mode, otherwise \c undefined. */ /*! \qmlproperty string dmg::sourceBase The base directory of the files that are going to be embedded in the DMG (\l{filetags-dmg}{"dmg.input"}). The source base directory is omitted from the target directory path of the DMG directory. \defaultvalue The directory of the current file to be embedded, relative to the product's source directory. */ /*! \qmlproperty string dmg::backgroundColor The background color of the disk image as seen when mounted in Finder. For the full list of supported color names and formats, see the \l{dmgbuild - Settings} documentation. For more information about how to use an image for the background instead, see \l{filetags-dmg}{"tiff"}. \nodefaultvalue */ /*! \qmlproperty int dmg::iconSize The width and height of the file icons as seen when the disk image is mounted in Finder. \defaultvalue \c{128} */ /*! \qmlproperty int dmg::windowX The x position of the Finder window that displays the disk image contents when it is mounted. \defaultvalue \c{100} */ /*! \qmlproperty int dmg::windowY The y position of the Finder window that displays the disk image contents when it is mounted. \defaultvalue \c{100} */ /*! \qmlproperty int dmg::windowWidth The width of the Finder window that displays the disk image contents when it is mounted. \defaultvalue \c{640} */ /*! \qmlproperty int dmg::windowHeight The height of the Finder window that displays the disk image contents when it is mounted. \note The window height includes the height of the standard macOS title bar (22 points). \defaultvalue \c{480} */ /*! \qmlproperty list dmg::iconPositions A list of objects containing the \c{path}, \c{x}, and \c{y} properties, which correspond to disk image-relative file paths and visual coordinates of file icons in the disk image as seen when it is mounted in Finder. For example: \code dmg.iconPositions: [ {"path": "Applications", "x": 128, "y": 128}, {"path": "Foo Bar.app", "x": 256, "y": 128} ] \endcode This property is useful for specifying the positions of files where you do not have direct control over the corresponding \QBS artifact, or there is no corresponding \QBS artifact (for example, "Foo Bar.app" is a directory, which has no equivalent artifact in the build graph). For files to which you are directly applying the \l{filetags-dmg}{dmg.input} file tag, you should use the \l{dmg::}{iconX} and \l{dmg::}{iconY} properties instead. \nodefaultvalue */ /*! \qmlproperty int dmg::iconX The x position of the file icon in the Finder window that displayed the disk image contents when it is mounted. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.input}. It cannot be used at the product level to affect all files. If you do not have access to the artifact corresponding to the file whose position you want to set, use the \l{dmg::}{iconPositions} property instead. \defaultvalue \c{windowWidth / 2} */ /*! \qmlproperty int dmg::iconY The y position of the file icon in the Finder window that displayed the disk image contents when it is mounted. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.input}. It cannot be used at the product level to affect all files. If you do not have access to the artifact corresponding to the file whose position you want to set, use the \l{dmg::}{iconPositions} property instead. \defaultvalue \c{windowHeight / 2} */ /*! \qmlproperty string dmg::defaultLicenseLocale The locale of the default license to display when there is no license whose locale matches the system locale. \defaultvalue \c{"en_US"} */ /*! \qmlproperty string dmg::licenseLocale The locale of the license file. Defaults to a value guessed from the file path, specifically the base name of any \c .lproj directory found in the file's path. If the locale could not be determined from the file path and this property is not set, an error will be emitted. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue Determined automatically. */ /*! \qmlproperty string dmg::licenseLanguageName The name of the language associated with the license file, localized to that language. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue \c{"English"} */ /*! \qmlproperty string dmg::licenseAgreeButtonText The text shown on the \e Agree button associated with the license file, localized to the value of \l{dmg::}{licenseLanguageName}. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue \c{"Agree"} */ /*! \qmlproperty string dmg::licenseDisagreeButtonText The text shown on the \c Disagree button associated with the license file, localized to the value of \l{dmg::}{licenseLanguageName}. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue \c{"Disagree"} */ /*! \qmlproperty string dmg::licensePrintButtonText The text shown on the \c Print button associated with the license file, localized to the value of \l{dmg::}{licenseLanguageName}. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue \c{"Print"} */ /*! \qmlproperty string dmg::licenseSaveButtonText The text shown on the \e Save button associated with the license file, localized to the value of \l{dmg::}{licenseLanguageName}. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue \c{"Save"} */ /*! \qmlproperty string dmg::licenseInstructionText An instruction text associated with the license file that will be shown on the license dialog, localized to the value of \l{dmg::}{licenseLanguageName}. This property is only useful with artifacts tagged \l{filetags-dmg} {dmg.license.input}. It cannot be used at the product level to affect all files. \defaultvalue \c{"If you agree with the terms of this license, press \"Agree\" to install the software. If you do not agree, press \"Disagree\"."} */ /*! \qmlproperty string dmg::dmgSuffix The file extension for disk images. This should not normally need to be changed. \defaultvalue \c{".dmg"} */ /*! \qmlproperty string dmg::hdiutilPath The path to the \c hdiutil binary used to perform disk image related operations. This should not normally need to be changed. \defaultvalue \c{"/usr/bin/hdiutil"} */ /*! \qmlproperty string dmg::textutilPath The path to the \c textutil binary used to convert license agreement files to rich text format. This should not normally need to be changed. \defaultvalue \c{"/usr/bin/textutil"} */ qbs-src-2.6.1/doc/reference/modules/archiver-module.qdoc0000644000175100001660000001142214776170045022561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype archiver \inqmlmodule QbsModules \since Qbs 1.4 \brief Provides support for building archives. The \c archiver module contains the properties and rules for creating (compressed) archives. The output artifact has the file tag \c "archiver.archive". The sole input artifact is a text file containing the list of files to package, with one file path per line. The paths can be relative, in which case they will be looked for in \l{archiver::}{workingDirectory}. The file tag of this input artifact is \c "archiver.input-list". */ /*! \qmlproperty stringList archiver::flags Custom options not covered by any of the other properties. \defaultvalue \c [] */ /*! \qmlproperty string archiver::archiveBaseName The base name of the archive file. That is, the file name without any extensions. \defaultvalue \l{Product::targetName}{product.targetName} */ /*! \qmlproperty string archiver::compressionLevel How much effort to put into the compression of a \c 7-Zip or \c zip archive. Possible values for zip are: \list \li \c undefined \li \c "0" \li \c "1" \li \c "2" \li \c "3" \li \c "4" \li \c "5" \li \c "6" \li \c "7" \li \c "8" \li \c "9" \endlist 7-Zip only supports 0 and the odd numbers above. Higher numbers result in a smaller archive, but the compression process will take more time. If the value is left undefined, the default compression level is used. \nodefaultvalue */ /*! \qmlproperty string archiver::compressionType How to compress a \c tar or \c zip archive. Possible options are: \list \li \c "bz2" \li \c "deflate" \li \c "gz" \li \c "none" \li \c "store" \li \c undefined, which uses the archiver's default compression type. \li \c "xz" \li \c "Z" \endlist \defaultvalue \c{"gz"} for \c tar archives, otherwise \c undefined. */ /*! \qmlproperty string archiver::outputDirectory Where to put the archive file. \defaultvalue \l{Product::destinationDirectory} {product.destinationDirectory} */ /*! \qmlproperty string archiver::type Which kind of archiver to use. The currently supported values are: \list \li \c "7zip" \li \c "tar" \li \c "zip" \endlist \nodefaultvalue */ /*! \qmlproperty string archiver::workingDirectory The directory in which to execute the archiver tool specified by \l{archiver::}{command}. \nodefaultvalue */ /*! \qmlproperty string archiver::command The path to the executable used to create the archive. This is usually the native tool corresponding to the archive type being produced, but may fall back to another tool also capable of producing that archive type if the native tool is not installed on the host system. This behavior is especially useful on platforms such as Windows, where the native tools for producing \c tar and \c zip archives in particular are much less likely to be installed. The following table lists the supported \l{archiver::type}{archive types} and the tools capable of producing them, listed in search order from left to right: \table \header \li Type \li Supported tools \row \li 7zip \li 7z \row \li tar \li tar, 7z \row \li zip \li zip \e (Info-Zip), 7z, jar \e (from Java JDK) \endtable \defaultvalue Depends on \l{archiver::}{type}. */ qbs-src-2.6.1/doc/reference/modules/nsis-module.qdoc0000644000175100001660000001315014776170045021732 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype nsis \inqmlmodule QbsModules \since Qbs 1.2 \brief Provides Nullsoft Scriptable Install System support. The \c nsis module contains properties and rules for building EXE installers for Windows using the Nullsoft Scriptable Install System (NSIS). This module is available on all platforms. \note A typical NSIS script includes an \c OutFile command to set the filename of the generated installer executable. However, \QBS overrides any \c OutFile commands found in the script, and therefore, you must use the \l{Product::targetName}{product.targetName} property to set the filename. \section2 Relevant File Tags \target filetags-nsis \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"nsh"} \li \c{*.nsh} \li 1.2 \li This tag is attached to NSIS header files. \row \li \c{"nsi"} \li \c{*.nsi} \li 1.2 \li This tag is attached to NSIS script files. \row \li \c{"nsissetup"} \li - \li 1.2 \li The rule that creates the NSIS setup executable attaches this tag to its output artifact. \endtable */ /*! \qmlproperty stringList nsis::defines A list of preprocessor macros that get passed to the compiler. To set macro values, use the following syntax: \badcode cpp.defines: ["USE_COLORS=1", 'COLOR_STR="blanched almond"'] \endcode \nodefaultvalue */ /*! \qmlproperty bool nsis::disableConfig Whether to exclude \c nsisconf.nsh. Generally, you do not need to set this property. \defaultvalue \c{false} */ /*! \qmlproperty bool nsis::enableQbsDefines Whether to define preprocessor macros corresponding to the values from the \l{Project}{project} and \l{Product}{product} objects. When building a 64-bit package, the preprocessor variable \c{Win64} will also be defined. \defaultvalue \c{true} */ /*! \qmlproperty string nsis::warningLevel The severity of the warnings to emit. The higher the level, the more warnings will be shown. The levels \c{none}, \c{errors}, \c{warnings}, \c{info}, and \c{all} correspond to the NSIS verbosity levels 0 through 4, inclusive. \c{normal} corresponds to the default level. \defaultvalue \c{"normal"} */ /*! \qmlproperty stringList nsis::compilerFlags A list of additional flags for the NSIS compiler. \nodefaultvalue */ /*! \qmlproperty string nsis::compressor The compression algorithm used to compress files and data in the installer. Setting this property overrides any \c SetCompressor command in the NSI file being compiled. Possible values include: \c{"default"}, \c{"zlib"}, \c{"zlib-solid"}, \c{"bzip2"}, \c{"bzip2-solid"}, \c{"lzma"}, \c{"lzma-solid"}. \defaultvalue \c{"default"} */ /*! \qmlproperty string nsis::version The NSIS version. Consists of four numbers separated by dots. For example, \c "2.46.0.0". \nodefaultvalue */ /*! \qmlproperty int nsis::versionMajor The NSIS major version. \defaultvalue \c{versionParts[0]} */ /*! \qmlproperty int nsis::versionMinor The NSIS minor version. \defaultvalue \c{versionParts[1]} */ /*! \qmlproperty list nsis::versionParts The NSIS version as a list. For example, the NSIS version 2.46.0.0 would correspond to a value of \c[2, 46, 0, 0]. \defaultvalue \c [] */ /*! \qmlproperty int nsis::versionPatch The NSIS patch level. \defaultvalue \c{versionParts[2]} */ /*! \qmlproperty int nsis::versionBuild The fourth NSIS version number component. \defaultvalue \c{versionParts[3]} */ /*! \qmlproperty path nsis::toolchainInstallPath The NSIS installation directory. Determined by searching from the known registry keys and known installation paths until a match is found. This property should not normally need to be changed. \defaultvalue Determined automatically. */ /*! \qmlproperty string nsis::compilerName The name of the compiler binary. This property should not normally need to be changed. \defaultvalue \c{"makensis"} */ /*! \qmlproperty string nsis::compilerPath The directory where the compiler binary is located. This property should not normally need to be changed. \defaultvalue \l{nsis::}{compilerName} */ qbs-src-2.6.1/doc/reference/modules/qt-android_support-module.qdoc0000644000175100001660000000562114776170045024620 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.android_support \inqmlmodule QbsModules \brief Provides Qt support for the Android platform. The \c Qt.android_support module provides the glue for \QBS' Qt and Android support. It is automatically pulled in by \c Qt.core, so you do not need to add an explicit dependency to it in your product, unless you want to set one of its properties. */ /*! \qmlproperty string Qt.android_support::qmlRootDir The root directory of the product's QML files. This information is passed to the \c androiddeployqt tool, which will use it to decide which resources to include in the APK file. \defaultvalue \c product.sourceDirectory */ /*! \qmlproperty stringList Qt.android_support::deploymentDependencies Use this property to completely override the Qt deployment dependencies of your app. Corresponds to qmake's ANDROID_DEPLOYMENT_DEPENDENCIES. \defaultvalue \c undefined */ /*! \qmlproperty stringList Qt.android_support::extraPlugins Additional non-asset files to be packaged. Corresponds to qmake's ANDROID_EXTRA_PLUGINS. \defaultvalue \c undefined */ /*! \qmlproperty stringList Qt.android_support::extraLibs Additional libs to be packaged and loaded on start-up (mind the order). Corresponds to qmake's ANDROID_EXTRA_LIBS. \defaultvalue \c undefined */ /*! \qmlproperty stringList Qt.android_support::qmlImportPaths Additional directories to search for QML imports. \defaultvalue \c undefined \since 1.22 */ /*! \qmlproperty bool Qt.android_support::verboseAndroidDeployQt Enable this property if you want verbose output from the \c androiddeployqt tool. \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/modules/qt-core-module.qdoc0000644000175100001660000003375014776170045022340 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.core \inqmlmodule QbsModules \brief Provides Qt Core support. All other Qt modules have a dependency on the Qt.core module, and therefore you do not need to list it in your dependencies if you depend on at least one other \l{Qt Modules}{Qt module}. Some of the Qt.core properties only need to be defined if the respective installation of Qt was built in some unusual way, for instance by setting non-default \c configure flags. \section2 Relevant File Tags \target filetags-qtcore \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"qch"} \li n/a \li 1.1 \li This tag is attached to the output artifacts of the rule that runs the \c qhelpgenerator tool. \row \li \c{"qdoc"} \li \c{*.qdoc} \li 1.1 \li Source files with this tag trigger a re-execution of the rule running the \c qdoc tool when their timestamp changes. \row \li \c{"qdocconf"} \li \c{*.qdocconf} \li 1.1 \li Source files with this tag trigger a re-execution of the rule running the \c qdoc tool when their timestamp changes. \row \li \c{"qdocconf-main"} \li - \li 1.1 \li Source files with this tag serve as inputs to the rule running the \c qdoc tool. \row \li \c{"qdoc-output"} \li n/a \li 1.5 \li Use this tag to match all \c qdoc outputs, for instance in a \l{Group} using the \l{Group::fileTagsFilter}{group.fileTagsFilter} property. \row \li \c{"qhp"} \li \c{*.qhp} \li 1.1 \li Files with this tag serve as inputs to the rule running the \c qhelpgenerator tool. Such files are created by \c qdoc, but can also appear as source files. \row \li \c{"qm"} \li n/a \li 1.1 \li This tag is attached to the output artifacts of the rule that runs the \c lrelease tool. \row \li \c{"qrc"} \li \c{*.qrc} \li 1.0 \li Files with this tag serve as inputs to the rule running the \c rcc tool. \row \li \c{"qt_plugin_metadata"} \li - \li 1.0 \li Source files with this tag trigger a re-execution of the rule running the \c moc tool when their timestamp changes. \row \li \c{"qt.core.metatypes"} \li n/a \li 1.16 \li This tag is attached to the JSON files that are potentially created if \l{Qt.core::generateMetaTypesFile}{generateMetaTypesFile} is enabled. \row \li \c{"qt.core.resource_data"} \li - \li 1.7 \li Source files with this tag serve as inputs to the rule creating \c qrc files. \row \li \c{"ts"} \li \c{*.ts} \li 1.0 \li Files with this tag serve as inputs to the rule running the \c lrelease tool. \row \li \c{"mocable"} \li - \li 1.13 \li Use this tag to force \QBS to run \c moc on the respective files, even though they do not contain \c Q_OBJECT or a related macro. \row \li \c{"unmocable"} \li - \li 1.2 \li Use this tag for files that \QBS should not run \c moc on, even though they contain \c Q_OBJECT or a related macro. \endtable */ /*! \qmlproperty stringList Qt.core::availableBuildVariants The build variants that this Qt installation offers. \defaultvalue Set by \l{setup-qt}. */ /*! \qmlproperty path Qt.core::binPath The path in which Qt tools such as \c qmake, \c moc, and so on are located. \nodefaultvalue */ /*! \qmlproperty bool Qt.core::combineMocOutput Whether the C++ sources created by \c moc are combined into a single C++ file per product. For projects where many header files are to be handled by \c moc, this can speed up compilation considerably. However, side effects may occur as a result of merging translation units. \defaultvalue \l{cpp::combineCxxSources}{cpp.combineCxxSources} */ /*! \qmlproperty bool Qt.core::enableBigResources Whether the Qt resource compiler is run in a two-pass fashion that supports the creation of big resources. \defaultvalue \c{false} */ /*! \qmlproperty stringList Qt.core::config Corresponds to the default value of qmake's \c CONFIG variable. \defaultvalue \c [] */ /*! \qmlproperty stringList Qt.core::disabledFeatures Corresponds to cmake's \c QT_DISABLED_PUBLIC_FEATURES variable. \readonly */ /*! \qmlproperty path Qt.core::docPath The path in which the Qt documentation is located. \nodefaultvalue */ /*! \qmlproperty stringList Qt.core::enabledFeatures Corresponds to cmake's \c QT_ENABLED_PUBLIC_FEATURES variable. \readonly */ /*! \qmlproperty bool Qt.core::enableKeywords Set this property to \c false if you do not want Qt to define the symbols \c {signals}, \c {slots}, and \c {emit}. This can be necessary if your project interacts with code that also defines such symbols. \defaultvalue \c true */ /*! \qmlproperty bool Qt.core::frameworkBuild Whether Qt was built as a framework. This is only relevant for Darwin systems. \nodefaultvalue */ /*! \qmlproperty bool Qt.core::generateMetaTypesFile If this property is enabled, a JSON file tagged as \c "qt.core.metatypes" will potentially be generated from metatype information collected by \c moc. \nodefaultvalue \since Qbs 1.16 */ /*! \qmlproperty string Qt.core::generatedHeadersDir The directory where tools that generate headers (such as \c moc or \c uic) put resulting files. Normally, you don't need to change this property. The one use-case is when there are several files with the same file name in the Product. The file name produced by \c moc is based only on the source file's base file name (without the directory path) which leads to a conflict in the mentioned case. You can resolve the conflict by setting this property to a non-default value for one of the files. For example: \code QtApplication { files: ["my_cool_header.h", "main.cpp"] Group { name: "legacy" files: "legacy/my_cool_header.h" Qt.core.generatedHeadersDir: "qt.legacy.headers" } } \endcode \defaultvalue \c product.buildDirectory + "/qt.headers" */ /*! \qmlproperty bool Qt.core::metaTypesInstallDir The directory to install the metatypes file into. If this property is empty or undefined, the metatypes file will not be installed. If the \l{Qt.core::generateMetaTypesFile}{generateMetaTypesFile} property is not \c true, then this property has no effect. \nodefaultvalue \since Qbs 1.16 */ /*! \qmlproperty path Qt.core::incPath The base path of the Qt headers. \nodefaultvalue */ /*! \qmlproperty string Qt.core::libInfix The library infix can be set at Qt build time to change the name of Qt's libraries. For example, if the infix is \c "Test", on Unix systems, the Qt Core library will be in a file called \c{libQt5CoreTest.so} instead of the default \c{libQt5Core.so}. \defaultvalue \c [] */ /*! \qmlproperty path Qt.core::libPath The path in which the Qt libraries are located. \nodefaultvalue */ /*! \qmlproperty bool Qt.core::lreleaseMultiplexMode If this property is \c true, \c lrelease will merge all \c .ts files into one \c .qm file. Otherwise, one \c .qm file will be created for each \c .ts file. \defaultvalue \c{false} */ /*! \qmlproperty string Qt.core::lreleaseName The base name of the \c lrelease tool. Set this if your system uses a name such as \c "lrelease-qt4". \defaultvalue \c{"lrelease"} */ /*! \qmlproperty path Qt.core::mkspecPath The path in which the Qt \c mkspecs are located. \nodefaultvalue */ /*! \qmlproperty stringList Qt.core::mocFlags A list of additional flags to \c moc. You will rarely need to set this property. \defaultvalue \c [] */ /*! \qmlproperty string Qt.core::mocName The base name of the \c moc tool. Set this if your system uses a name such as \c "moc-qt4". \defaultvalue \c{"moc"} */ /*! \qmlproperty string Qt.core::namespace The Qt namespace that can be set at build time via the \c configure script. By default, Qt is not built in a namespace. \nodefaultvalue */ /*! \qmlproperty stringList Qt.core::pluginMetaData A list of additional plugin metadata. The elements of the list are key-value pairs separated by the \c = character. A possible use case is to set the plugin URI when building a static QML plugin: \badcode Qt.core.pluginMetaData: ["uri=thePlugin"] \endcode \defaultvalue \c [] */ /*! \qmlproperty path Qt.core::pluginPath The path in which the Qt plugins are located. \nodefaultvalue */ /*! \qmlproperty stringList Qt.core::qdocEnvironment The environment for calls to \c qdoc. Typically, you will need to set some variables here when running \c qdoc to build your project documentation. \nodefaultvalue */ /*! \qmlproperty string Qt.core::qdocName The base name of the \c qdoc tool. \defaultvalue \c{"qdoc3"} for Qt 4, \c{"qdoc"} otherwise. */ /*! \qmlproperty string Qt.core::qdocOutputDir The directory name where the \c qdoc tool writes its output. \defaultvalue \c{product.buildDirectory + "/qdoc_html"} */ /*! \qmlproperty string Qt.core::qmBaseName The base name of the \c .qm file to be built from the \c .ts files in the product. This property is ignored if \l{Qt.core::}{lreleaseMultiplexMode} is \c false. \defaultvalue \l{Product::targetName}{product.targetName} */ /*! \qmlproperty string Qt.core::qmDir The directory name where to put the \c .qm file to be built. \defaultvalue \l{Product::destinationDirectory}{product.destinationDirectory} */ /*! \qmlproperty string Qt.core::qtBuildVariant Specifies the type of Qt libraries to build against: \c "debug" or \c "release". \note On some systems, it is not possible to link code built in debug mode against libraries built in release mode and vice versa. \defaultvalue The build variant of the code linking against Qt. If Qt does not offer that build variant, the build variant offered by Qt is chosen instead. */ /*! \qmlproperty stringList Qt.core::qtConfig Corresponds to the default value of qmake's \c QT_CONFIG variable. \defaultvalue \c [] */ /*! \qmlproperty path Qt.core::resourceSourceBase For files tagged as \l{filetags-qtcore}{qt.core.resource_data}, this property determines which part of their path will end up in the generated \c .qrc file. If this property is set to \c undefined, only the file name is used. \nodefaultvalue */ /*! \qmlproperty string Qt.core::resourcePrefix For files tagged as \l{filetags-qtcore}{qt.core.resource_data}, this property determines the prefix under which they will be available in the generated \c .qrc file. \defaultvalue \c{"/"} */ /*! \qmlproperty string Qt.core::resourceFileBaseName For files tagged as \l{filetags-qtcore}{qt.core.resource_data}, this property determines the base name of the generated \c .qrc file. If this property needs to be changed, it must be set in the corresponding \l{Product}{product} rather than in a \l{Group}. \defaultvalue \l{Product::targetName}{product.targetName} */ /*! \qmlproperty bool Qt.core::staticBuild Whether Qt was built statically. \nodefaultvalue */ /*! \qmlproperty path Qt.core::translationsPath This property provides the absolute path to the directory where the Qt translation files (.qm) are installed. \nodefaultvalue \since 2.5 */ /*! \qmlproperty string Qt.core::version The Qt version. Consists of three numbers separated by dots. For example "5.9.1". \nodefaultvalue */ /*! \qmlproperty int Qt.core::versionMajor The Qt major version. \defaultvalue \c{versionParts[0]} */ /*! \qmlproperty int Qt.core::versionMinor The Qt minor version. \defaultvalue \c{versionParts[1]} */ /*! \qmlproperty list Qt.core::versionParts The Qt version as a list. For example, Qt version 5.9.1 would correspond to a value of \c[5, 9, 1]. \defaultvalue \c [] */ /*! \qmlproperty int Qt.core::versionPatch The Qt patch level. \defaultvalue \c{versionParts[2]} */ /*! \qmlproperty bool Qt.core::useRPaths Whether to add \l{Qt.core::libPath}{Qt.core.libPath} to \l{cpp::rpaths}{cpp.rpaths}. \defaultvalue \c true on Linux, \c false everywhere else. */ qbs-src-2.6.1/doc/reference/modules/qnx-module.qdoc0000644000175100001660000000512114776170045021563 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype qnx \inqmlmodule QbsModules \since Qbs 1.8 \brief Provides support for building QNX applications using the QNX SDK. The \c qnx module contains properties and rules for QNX development. It has been tested with the QNX 6.5, 6.6, and 7.0 SDKs. */ /*! \qmlproperty string qnx::sdkDir The SDK base directory. \defaultvalue Determined automatically if the QNX SDK is installed at one of the standard locations, such as \c ~/qnx700, \c /opt/qnx700, or \c C:\\qnx700. */ /*! \qmlproperty string qnx::configurationDir The QNX configuration directory. Equivalent to the \c{QNX_CONFIGURATION} environment variable. \defaultvalue \c{~/.qnx} */ /*! \qmlproperty string qnx::hostDir The QNX host directory. Equivalent to the \c{QNX_HOST} environment variable. You should not normally need to set this property as it will be set to an appropriate value based on your host operating system and the installed QNX SDK in \l{qnx::}{sdkDir}. \defaultvalue Determined automatically. */ /*! \qmlproperty string qnx::targetDir The QNX target directory. Equivalent to the \c{QNX_TARGET} environment variable. You should not normally need to set this property as it will be set to an appropriate value based on the installed QNX SDK in \l{qnx::}{sdkDir}. \defaultvalue Determined automatically. */ qbs-src-2.6.1/doc/reference/modules/android-sdk-module.qdoc0000644000175100001660000002024414776170045023157 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Android.sdk \inqmlmodule QbsModules \since Qbs 1.4 \brief Provides support for building Android packages. The Android.sdk module contains the properties and rules to create Android application packages from Java sources, resources, and so on. It is usually pulled in indirectly by declaring an \l Application product. \section2 Relevant File Tags \target filetags-android-sdk \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"android.aidl"} \li \c{*.aidl} \li 1.4.0 \li Attached to Android AIDL files. One Java source file will be generated for each such file. \row \li \c{"android.assets"} \li - \li 1.4.0 \li Attached to Android assets, which are typically located in an \c{assets/} subdirectory. These files are tagged automatically if the \l automaticSources property is enabled. \row \li \c{"android.manifest"} \li \c{AndroidManifest.xml} \li 1.4.0 \li Attached to the Android manifest. There must be one such file for every Android app. \row \li \c{"android.resources"} \li - \li 1.4.0 \li Attached to Android resources, which are typically located in a \c{res/} subdirectory. These files are tagged automatically if the \l automaticSources property is enabled. \endtable */ /*! \qmlproperty string Android.sdk::buildToolsVersion The version of the build tools such as \c aapt and \c dx. \defaultvalue Highest build tools version version available in the SDK. */ /*! \qmlproperty string Android.sdk::ndkDir The NDK base directory, if an NDK is present. \defaultvalue Determined automatically based on standard search paths. */ /*! \qmlproperty string Android.sdk::platform The versioned platform name (for example, \c "android-21"). \defaultvalue Highest build tools version version available in the SDK. */ /*! \qmlproperty string Android.sdk::sdkDir The SDK base directory. \defaultvalue Determined automatically based on standard search paths. */ /*! \qmlproperty bool Android.sdk::embedJar \since Qbs 1.10 If \c true, then if the dependency is a JAR file, its classes and the classes of its dependencies (if \c{embedJar} is also true for them) will be recursively processed by \c{dex} and included in the final APK. \defaultvalue \c{true} */ /*! \qmlproperty path Android.sdk::assetsDir The base directory for Android assets in the respective product. \note Android requires that the file name of this directory is always \c "assets". \defaultvalue \c "src/main/assets" in the product source directory */ /*! \qmlproperty bool Android.sdk::automaticSources If \c true, Java sources as well as Android resources, assets, and the manifest file will be automatically included in the respective product via wildcards. Set this property to \c false if you want to specify these files manually. \defaultvalue \c true */ /*! \qmlproperty string Android.sdk::manifestFile The file path to the Android manifest file. This property is only relevant if \l automaticSources is enabled. \note Android requires that the file name is always "AndroidManifest.xml". \defaultvalue \c "src/main/AndroidManifest.xml" in the product source directory */ /*! \qmlproperty string Android.sdk::packageName The package name of the respective product. The \c package attribute in the manifest file will be set to this value automatically. \defaultvalue \c name */ /*! \qmlproperty string Android.sdk::versionCode The Android Manifest version code of the respective product. The \c android:versionCode attribute in the manifest file will be set to this value if not undefined. In the following example we provide an architecture-specific value for \c android:versionCode: \code // ... property int _version: 1 property int _patchVersion: 0 Android.sdk.versionCode: { switch (Android.ndk.abi) { case "armeabi-v7a": return 132000000 | _version * 10 + _patchVersion; case "arm64-v8a": return 164000000 | _version * 10 + _patchVersion; case "x86": return 232000000 | _version * 10 + _patchVersion; case "x86_64": return 264000000 | _version * 10 + _patchVersion; } throw "Unknown architecture"; } \endcode \defaultvalue \c undefined */ /*! \qmlproperty string Android.sdk::versionName The Android Manifest version name of the respective product. The \c android:versionName attribute in the manifest file will be set to this value if not undefined. \defaultvalue \c undefined */ /*! \qmlproperty path Android.sdk::resourcesDir The base directory for Android resources in the respective product. \note Android requires that the file name of this directory is always \c "res". \defaultvalue \c "src/main/res" in the product source directory */ /*! \qmlproperty path Android.sdk::sourcesDir The base directory for Java sources. This property is only relevant if \l automaticSources is enabled. \defaultvalue \c "src/main/java" in the product source directory */ /*! \qmlproperty string Android.sdk::apkBaseName The base name of the APK file to to be built, that is, the file name without the ".apk" extension. \defaultvalue \l packageName */ /*! \qmlproperty stringList Android.sdk::aidlSearchPaths Search paths for import statements to pass to the \c aidl tool via the \c{-I} option. */ /*! \qmlproperty string Android.sdk::aaptName \since Qbs 1.17 Name of the aapt binary. Allowed options: "aapt" and "aapt2". \defaultvalue \c "aapt2" */ /*! \qmlproperty string Android.sdk::packageType \since Qbs 1.17 Type of the package. Allowed options: "apk" and "aab". Type "apk" generates a runnable package whereas "aab" generates a package for Google Play. \defaultvalue \c "apk" */ /*! \qmlproperty stringList Android.sdk::extraResourcePackages \since Qbs 2.5 List of additional Java package names to compile resources for. \defaultvalue \c undefined */ /*! \qmlproperty string Android.sdk::dexCompilerName \since Qbs 1.20 Name of the dex compiler binary. Allowed options: "dx" and "d8". \defaultvalue \c "d8" */ /*! \qmlproperty bool Android.sdk::d8Desugaring \since Qbs 2.5 Whether desugaring is enabled for "d8" dex compiler. \defaultvalue \c false */ /*! \qmlproperty string Android.sdk::minimumVersion \since Qbs 1.17 Minimum API Level required for the application to run. \defaultvalue \c "21" */ /*! \qmlproperty string Android.sdk::targetVersion \since Qbs 1.17 API Level that the application targets. \defaultvalue \c platformVersion */ qbs-src-2.6.1/doc/reference/modules/codesign-module.qdoc0000644000175100001660000002347614776170045022565 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype codesign \inqmlmodule QbsModules \since Qbs 1.19 \brief Provides code signing support. The \c codesign module contains properties and rules for code signing on Apple and Android platforms. \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"codesign.entitlements"} \li \c{*.entitlements} \li 1.19.0 \li \l{https://developer.apple.com/documentation/bundleresources/entitlements}{Xcode entitlements} \row \li \c{"codesign.provisioningprofile"} \li \c{*.mobileprovision, *.provisionprofile} \li 1.19.0 \li Xcode provisioning profiles \row \li \c{"codesign.signed_artifact"} \li n/a \li 1.19.0 \li This tag is attached to all signed artifacts such as applications or libraries \endtable */ /*! \qmlproperty string codesign::signingTimestamp URL of the timestamp authority RFC 3161 server to be contacted to authenticate code signing. \c undefined or \c empty indicates that a system-specific default should be used; \c{"none"} explicitly disables the use of timestamp services on Apple platforms. \since Qbs 1.19 \defaultvalue \c "none" on Apple, \c undefined otherwise */ /*! \qmlproperty stringList codesign::codesignFlags Additional flags passed to the \c{codesign} tool. \since Qbs 1.19 \nodefaultvalue */ /*! \qmlproperty string codesign::codesignName The name of the \c{codesign} binary. \since Qbs 1.19 \defaultvalue Determined automatically */ /*! \qmlproperty string codesign::codesignPath Path to the \c{codesign} tool. \since Qbs 1.19 \defaultvalue Determined automatically */ /*! \qmlproperty bool codesign::enableCodeSigning Whether to actually perform code signing. \since Qbs 1.19 \defaultvalue \c false */ /*! \qmlproperty string codesign::provisioningProfile Name or UUID of the provisioning profile to embed in the product. Typically this should be left blank to allow \QBS to use automatic provisioning. \since Qbs 1.19 \defaultvalue \c undefined \appleproperty */ /*! \qmlproperty path codesign::provisioningProfilesPath Path to directory containing provisioning profiles installed on the system. This should not normally need to be changed. \since Qbs 1.19 \defaultvalue \c{"~/Library/MobileDevice/Provisioning Profiles"} \appleproperty */ /*! \qmlproperty string codesign::signingIdentity 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" or the certificate's SHA1 fingerprint. 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 It is also possible to use the special \c "-" value to use the ad-hoc signing. 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. In general you should use \l{codesign::signingType}{signingType} instead. \since Qbs 1.19 \defaultvalue Determined by \l{codesign::signingType}{signingType} \appleproperty */ /*! \qmlproperty string codesign::signingType Type of code signing to use. This should generally be used in preference to an explicit signing identity like "Mac Developer: John Doe (XXXXXXXXXX)" since it is not user specific and can be set in a project file. Possible values include: \c{"app-store"}, \c{"apple-id"}, \c{"ad-hoc"}, which sign for the App Store or Mac App Store, Developer ID, and Ad-hoc code signing, respectively. \section1 Relation between the signingType and signingIdentity The following table shows how the signingIdentity's default value is calculated. \table \header \li \c qbs.targetOS \li \c codesign.signingType \li \c qbs.buildVariant \li \c codesign.signingIdentity \row \li {1, 4} \c "macos" \li \c "ad-hoc" \li any \li \c "-" \row \li {1, 2} \c "app-store" \li \c "debug", \c "profiling" \li \c "Mac Developer" \row \li \c "release" \li \c "3rd Party Mac Developer Application" \row \li \c "apple-id" \li any \li \c "Developer ID Application" \row \li {1, 2} \c "ios", \c "tvos", \c "watchos" \li {1, 2} \c "app-store" \li \c "debug", \c "profiling" \li \c "iPhone Developer" \row \li \c "release" \li \c "iPhone Distribution" \endtable \since Qbs 1.19 \defaultvalue Determined automatically \appleproperty */ /*! \qmlproperty string codesign::teamIdentifier Human readable name or 10-digit identifier of the Apple development team that the signing identity belongs to. This is used to disambiguate between multiple certificates of the same type in different teams. Typically this can be left blank if the development machine is only signed in to a single development team, and should be set in a profile otherwise. \since Qbs 1.19 \defaultvalue \c undefined \appleproperty */ /*! \qmlproperty bool codesign::useApksigner If \c true, the package is signed using apksignerFilePath binary. Set this property to \c false to use the jarsignerFilePath one. Set by the Android.sdk module. \since Qbs 1.19 \defaultvalue \c true \androidproperty */ /*! \qmlproperty string codesign::keystorePath The absolute path to the keystore file. \since Qbs 1.19 \defaultvalue \c "${HOME}/.android/debug.keystore" \androidproperty */ /*! \qmlproperty string codesign::keystorePassword The keystore password. \since Qbs 1.19 \defaultvalue \c "android" \androidproperty */ /*! \qmlproperty string codesign::keyPassword The key password. \since Qbs 1.19 \defaultvalue \c "android" \androidproperty */ /*! \qmlproperty string codesign::keyAlias The key alias. \since Qbs 1.19 \defaultvalue \c "androiddebugkey" \androidproperty */ /*! \qmlproperty string codesign::subjectName Specifies the name of the subject of the signing certificate. This value can be a substring of the entire subject name. \since Qbs 1.19 \defaultvalue \c undefined \windowsproperty */ /*! \qmlproperty string codesign::rootSubjectName Specifies the name of the subject of the root certificate that the signing certificate must chain to. This value may be a substring of the entire subject name of the root certificate. \since Qbs 1.19 \defaultvalue \c undefined \windowsproperty */ /*! \qmlproperty string codesign::hashAlgorithm Specifies the default hash algorithm used on the signing certificate. The possible values are \c sha1, \c sha256, \c sha384, and \c sha512. \note Only available in Windows 10 kit builds 20236 and later. \since Qbs 1.19 \defaultvalue \c undefined \windowsproperty */ /*! \qmlproperty string codesign::timestampAlgorithm Specifies the default timestamp algorithm used together with the \c signingTimestamp property. The possible values are \c sha1, \c sha256. \note If this value is not set, then the default sha1 algorithm will be used. \since Qbs 1.19.2 \defaultvalue \c undefined \windowsproperty */ /*! \qmlproperty string codesign::certificatePath Specifies the full path to the signing certificate file (*.pfx). \since Qbs 1.19 \defaultvalue \c undefined \windowsproperty */ /*! \qmlproperty string codesign::certificatePassword Specifies the password to use when opening a signing certificate file (*.pfx). \since Qbs 1.19 \defaultvalue \c undefined \windowsproperty */ /*! \qmlproperty string codesign::crossCertificatePath Specifies the full path to the additional certificate file (*.cer). \since Qbs 1.19 \defaultvalue \c undefined \windowsproperty */ qbs-src-2.6.1/doc/reference/modules/java-module.qdoc0000644000175100001660000001364614776170045021711 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype java \inqmlmodule QbsModules \since Qbs 1.4 \brief Provides Java support. The \c java module contains the properties and rules for building Java projects. \section2 Relevant File Tags \target filetags-java \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"java.class"} \li - \li 1.4 \li This tag is attached to the output artifacts of the rule that runs the \c javac tool. \row \li \c{"java.jar"} \li - \li 1.4 \li This tag is attached to the output artifacts of the rule that runs the \c jar tool. \row \li \c{"java.java"} \li \c{*.java} \li 1.4 \li Source files with this tag serve as inputs to the rule running the \c javac tool. \row \li \c{"java.manifest"} \li \c{*.mf} \li 1.8 \li The contents of files with this tag will be aggregated with the values in \l{java::}{manifest}. \endtable */ /*! \qmlproperty stringList java::additionalClassPaths The locations beside this product's class output path to consider when compiling. \nodefaultvalue */ /*! \qmlproperty stringList java::additionalCompilerFlags A list of compiler flags not covered by any of the properties in this module. \nodefaultvalue */ /*! \qmlproperty stringList java::additionalJarFlags A list of archiver flags not covered by any of the properties in this module. \nodefaultvalue */ /*! \qmlproperty stringList java::bootClassPaths A list of non-standard bootstrap class files. \nodefaultvalue */ /*! \qmlproperty string java::compilerFilePath The command to invoke when compiling Java sources. \defaultvalue \l compilerName, prefixed by \l jdkPath if it is defined. */ /*! \qmlproperty string java::compilerName The file name of the Java compiler. \defaultvalue \c{"javac"} */ /*! \qmlproperty bool java::enableWarnings Whether warnings are emitted when compiling Java sources. \defaultvalue \c true */ /*! \qmlproperty string java::interpreterFilePath The command to invoke when executing Java code. \defaultvalue \l interpreterName, prefixed by \l jdkPath if it is defined. */ /*! \qmlproperty string java::interpreterName The file name of the Java interpreter. \defaultvalue \c{"java"} */ /*! \qmlproperty string java::jarFilePath The command to run when creating or extracting \c jar files. \defaultvalue \l jarName, prefixed by \l jdkPath if it is defined. */ /*! \qmlproperty string java::jarName The file name of the \c jar tool. \defaultvalue \c{"jar"} */ /*! \qmlproperty pathList java::jdkIncludePaths \since Qbs 1.4.1 A list of include paths for native header files. Applications using JNI to interface with native code should add these paths to \l{cpp::includePaths}{cpp.includePaths}. \defaultvalue Determined automatically. */ /*! \qmlproperty string java::jdkPath The base path of the Java Development Kit (JDK). This is equivalent to the \c JAVA_HOME environment variable, and by default will be determined automatically from one of the following: \list \li \c JAVA_HOME environment variable (all platforms) \li Registry (Windows) \li \c java_home tool (macOS) \li Known JDK paths (other Unix platforms) \endlist \defaultvalue Determined automatically. */ /*! \qmlproperty string java::languageVersion The Java language version to interpret source code as. If left undefined, the compiler will use its default. \nodefaultvalue */ /*! \qmlproperty string java::runtimeVersion The version of the Java runtime to generate compatible bytecode for. If left undefined, the compiler will use its default. \nodefaultvalue */ /*! \qmlproperty var java::manifest \since Qbs 1.4.2 The properties to add to the manifest file when building a JAR. The contents of this property will be aggregated with the values from any files tagged \l{filetags-java}{"java.manifest"}. If this property and a manifest file contain the same key, this property will take precedence. If left undefined, this property will not be taken into account. \nodefaultvalue */ /*! \qmlproperty stringList java::manifestClassPath A list of entries to add to the manifest's Class-Path when building a JAR. \nodefaultvalue */ /*! \qmlproperty bool java::warningsAsErrors If this property is \c true, the compiler will abort where it would normally emit a warning. \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/modules/exporter-pkgconfig-module.qdoc0000644000175100001660000001573614776170045024607 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Exporter.pkgconfig \inqmlmodule QbsModules \since Qbs 1.12 \brief Provides support for generating pkg-config files. The \c Exporter.pkgconfig module contains the properties and rules to create a \l{https://www.freedesktop.org/wiki/Software/pkg-config}{pkg-config} metadata (\c{.pc}) file for a \l Product. By default, \QBS will attempt to derive some of the \c {.pc} file's contents from the product's \l Export item. This behavior can be suppressed by setting the \l autoDetect property to \c false. \section2 Relevant File Tags \target filetags-exporter-pkgconfig \table \header \li Tag \li Since \li Description \row \li \c{"Exporter.pkgconfig.pc"} \li 1.12.0 \li This tag is attached to the generated \c{.pc} file. \endtable */ /*! \qmlproperty bool Exporter.pkgconfig::autoDetect If this property is enabled, then \QBS will try to derive various \c {.pc} file entries from the contents of the product's \l Export item, including the dependencies declared therein. Values for these fields can still be explicitly provided via the respective properties, in which case they will be concatenated with the auto-detected ones. If an exported dependency is known to correspond to a pkg-config module (either by pulling in the \c{Exporter.pkgconfig} module or by appearing in the \l requiresEntry property), it will end up in the \c Requires field of the \c{.pc} file, otherwise its exported \l cpp properties will be collected for use in the \c Cflags and \c Libs fields. The \l excludedDependencies property can be used to ignore specific products altogether. \defaultvalue \c true */ /*! \qmlproperty stringList Exporter.pkgconfig::cflagsEntry The value of the \c Cflags field in the \c {.pc} file. If \l autoDetect is enabled, then this value will be appended to the flags derived from the product's \l Export item and the dependencies declared therein. \defaultvalue \c {[]} */ /*! \qmlproperty stringList Exporter.pkgconfig::conflictsEntry The value of the \c Conflicts field in the \c {.pc} file. \defaultvalue \c {[]} */ /*! \qmlproperty stringList Exporter.pkgconfig::excludedDependencies If \l autoDetect is enabled, the entries of this property will be matched against the product's exported dependencies. In case such a dependency's name is present in the array, \QBS will not traverse that dependency to collect entries for the \c Cflags, \c Libs, \c Requires and \c {Requires.private} fields. This list must not contain any values that are present in \l requiresEntry. \defaultvalue \c undefined */ /*! \qmlproperty string Exporter.pkgconfig::fileName The file name of the generated pkg-config metadata file. \defaultvalue \c {product.targetName + ".pc"} */ /*! \qmlproperty stringList Exporter.pkgconfig::libsEntry The value of the \c Libs field in the \c {.pc} file. If \l autoDetect is enabled, then this value will be appended to the flags derived from the product's \l Export item and the dependencies declared therein. \defaultvalue \c {[]} */ /*! \qmlproperty stringList Exporter.pkgconfig::libsPrivateEntry The value of the \c Libs.Private field in the \c {.pc} file. \defaultvalue \c {[]} */ /*! \qmlproperty string Exporter.pkgconfig::nameEntry The value of the \c Name field in the \c {.pc} file. \defaultvalue \c {product.name} */ /*! \qmlproperty stringList Exporter.pkgconfig::requiresEntry The value of the \c Requires field in the \c {.pc} file. If \l autoDetect is enabled, then those of the product's exported dependencies that pull in the \c {Exporter.pkgconfig} module will also end up in the \c Requires field, provided they are not listed in \l excludedDependencies. If an exported dependency matches an entry of this array, \QBS will not traverse that dependency to gather \l cpp properties for use in the \l cflagsEntry and \l libsEntry values, as pkg-config takes care of that itself. \defaultvalue \c {[]} */ /*! \qmlproperty stringList Exporter.pkgconfig::requiresPrivateEntry The value of the \c Requires.private field in the \c {.pc} file. If \l autoDetect is enabled, then those of the product's non-exported dependencies that pull in the \c {Exporter.pkgconfig} module will also end up in the \c Requires.private field, provided they are not listed in \l excludedDependencies. \defaultvalue \c {[]} */ /*! \qmlproperty var Exporter.pkgconfig::transformFunction A function with the signature \c {function(product, moduleName, propertyName, value)}. This can be useful to "fine-tune" property values if \l autoDetect is enabled, in case they need amending for the purpose of pkg-config. The \c product parameter represents the exporting product, the remaining parameters describe the module property. The modified value of the module property shall be returned. \defaultvalue \c undefined */ /*! \qmlproperty string Exporter.pkgconfig::urlEntry The value of the \c URL field in the \c {.pc} file. \defaultvalue \c undefined */ /*! \qmlproperty string Exporter.pkgconfig::versionEntry The value of the \c Version field in the \c {.pc} file. \defaultvalue \c {product.version} */ /*! \qmlproperty string Exporter.pkgconfig::customVariables Use this property to add arbitrary variable assignments into the \c .pc file. The property is a map that will produce one assignment per entry. The keys and values of the map represent the left-hand sides and right-hand sides of these assignments, respectively. The values are strings that will be written into the file verbatim. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/modules/android-ndk-module.qdoc0000644000175100001660000000664314776170045023161 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Android.ndk \inqmlmodule QbsModules \since Qbs 1.4 \brief Provides support for building native Android libraries. The \c Android.ndk module contains the properties and rules to create native libraries for use in Android applications. Normally, you will not use this module directly, but instead work with the \l{DynamicLibrary}, \l{StaticLibrary} and \l Application items that \QBS provides. Here is what the project file for the \c hello-jni example that comes with the NDK could look like: \code CppApplication { name: "HelloJni" Android.sdk.packageName: "com.example.hellojni" qbs.architectures: ["arm", "x86"] files: "app/src/main/jni/hello-jni.c" } \endcode \section2 Relevant File Tags \target filetags-android-ndk \table \header \li Tag \li Since \li Description \row \li \c{"android.nativelibrary"} \li 1.4.0 \li Attached to dynamic libraries that will end up in APK packages. You do not normally need to use the tag explicitly, as it is the default type of the \l{DynamicLibrary} item for Android targets. \endtable */ /*! \qmlproperty string Android.ndk::abi The ABI name as it appears under \c "lib/" in the application package. Corresponds to \c APP_ABI in \c Android.mk. \nodefaultvalue */ /*! \qmlproperty string Android.ndk::buildId Value to pass to the --build-id linker flag. Plain --build-id option is used when buildId property is empty. \since Qbs 1.21 \defaultvalue \c "sha1" */ /*! \qmlproperty string Android.ndk::appStl The library to use for C++. The possible values are: \list \li \c "c++_shared" \li \c "c++_static" \endlist \defaultvalue \c{"c++_shared"} */ /*! \qmlproperty path Android.ndk::ndkDir The NDK base directory. \nodefaultvalue */ /*! \qmlproperty string Android.ndk::platform The versioned platform name. \defaultvalue \c{"android-16"} for 32 bit arm ABIs and \c{"android-21"} for all 64 bit ABIs and x86. x86 ABI has broken wstring support in android-16 to android-19. */ qbs-src-2.6.1/doc/reference/modules/freedesktop-module.qdoc0000644000175100001660000001426614776170045023302 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Alberto Mardegan ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype freedesktop \inqmlmodule QbsModules \since Qbs 1.16 \brief Provides support for some freedesktop.org specifications. The \c freedesktop module contains properties and rules for building and working with applications compliant to freedesktop.org specifications on UNIX platforms. The areas in which this module can be of use include: \list \li Creation or post-processing of \l{https://specifications.freedesktop.org/desktop-entry-spec/latest/}{\c{.desktop} files} \li Installation of \l{https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html}{AppStream} metadata \li Defining the location for \l{https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout} {application icons} \endlist This module is available on all platforms but is currently only useful on UNIX platforms. \section2 Example usage \target example-freedesktop \code Application { ... Depends { name: "freedesktop" } Group { files: [ ... // Declare the desktop and appstream files "data/my-app.desktop", "data/my-app.metainfo.xml", ] } // Add/change some fields in the desktop file freedesktop.desktopKeys: ({ 'Exec': FileInfo.joinPaths(qbs.installPrefix, product.installDir, product.targetName) + ' --argument', 'X-Application-Version': product.version, }) // Define the source directory for application icons freedesktop.hicolorRoot: project.sourceDirectory + "/icons/" // Declare the application icons Group { prefix: project.sourceDirectory + "/icons/" files: [ "32x32/apps/my-application.png", "32x32@2/apps/my-application.png", "32x32/mimetypes/application-format.png", ... "scalable/apps/my-application.svg", ] fileTags: "freedesktop.appIcon" } } \endcode \section2 Relevant File Tags \target filetags-freedesktop \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"freedesktop.desktopfile_source"} \li \c{*.desktop} \li 1.16 \li A source file with this tag is a \c{.desktop} file or fragment that will be merged into the application's final \c{.desktop} file. \row \li \c{"freedesktop.desktopfile"} \li - \li 1.16 \li Attached to the output artifacts of the rule that produces the merged \c{.desktop} file. \row \li \c{"freedesktop.appstream"} \li \c{*.metainfo.xml}, \c{*.appdata.xml} \li 1.16 \li Source files with this tag are AppStream metadata files which will be installed under \l{qbs::}{installPrefix}\c{/share/metainfo} \row \li \c{"freedesktop.appIcon"} \li - \li 1.16 \li Source files with this tag are application icons compliant with the \l{https://specifications.freedesktop.org/icon-theme-spec/}{freedesktop.org Icon Theme Specification}. These icons will be installed under \l{qbs::}{installPrefix}\c{/share/icons/hicolor} in their respective resolution-based directories (e.g., \c{48x48/apps/}, \c{256x256/apps/}), ensuring compatibility with desktop environments following this specification. \note After Qbs version 2.5, the \c{hicolorRoot} property must be set to define the source directory for these icons. Without setting this property, icons will not be installed. \endtable */ /*! \qmlproperty string freedesktop::appName The display name of the application which will be stored in the \c{.desktop} file. \defaultvalue \l{Product::name}{product.name} */ /*! \qmlproperty var freedesktop::desktopKeys A dictionary of key-value pairs to add to the application's \c{.desktop} file. The contents of this property will be aggregated with the values from any \c{.desktop} file. If this property and any \c{.desktop} files contain the same key, this property will take precedence. \nodefaultvalue */ /*! \qmlproperty string freedesktop::hicolorRoot Defines the source directory for application icons, which are installed according to the \l{https://specifications.freedesktop.org/icon-theme-spec/}{freedesktop.org Icon Theme Specification}. It is used with the \c{freedesktop.appIcon} tag to install icons into the \c{share/icons/hicolor} directory structure (e.g., \c{48x48/apps/}, \c{256x256/apps/}). If \c{hicolorRoot} is not set, icons will not be installed. Set this property to the path containing your icon files. \nodefaultvalue \since 2.5 */ qbs-src-2.6.1/doc/reference/modules/ib-module.qdoc0000644000175100001660000001705414776170045021357 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype ib \inqmlmodule QbsModules \since Qbs 1.1 \brief Provides support for Apple Interface Builder and related tools and file types. The \c ib module contains properties and rules for building Interface Builder documents, storyboards, asset catalogs, and icon sets. This module is only available on Apple platforms. \section2 Relevant File Tags \target filetags-ib The file tags determine how the tagged directories and files are handled. \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"assetcatalog"} \li \c{*.xcassets} \li 1.3 \li Tagged directories are compiled into compiled asset catalog archives (\c .car files) on supported platforms, or a collection of loose resource files. The resulting files will be automatically tagged \l{filetags-bundle}{bundle.input}. If the current product is a bundle, the files will be included in the bundle's resources directory. \row \li \c{"iconset"} \li \c{*.iconset} \li 1.3 \li Tagged directories are compiled into Apple ICNS files. The resulting files will be automatically tagged \l{filetags-bundle} {bundle.input}. If the current product is a bundle, the files will be included in the bundle's resources directory. \row \li \c{"nib"} \li \c{*.nib}, \c{*.xib} \li 1.1 \li Tagged "NIB" and "XIB" files will be compiled. The output may be a flat file or a bundle (directory structure). The resulting files will be automatically tagged \l{filetags-bundle} {bundle.input}. If the current product is a bundle, the files will be included in the bundle's resources directory. \row \li \c{"png"} \li \c{*.png} \li 1.9 \li Tagged PNG files may be converted into multi-resolution TIFFs. Source files should adopt the \l{Adopt the @2x Naming Convention} {@2x naming convention} in order to be properly grouped. The resulting files will be given the \l{filetags-dmg}{tiff} file tag. \row \li \c{"storyboard"} \li \c{*.storyboard} \li 1.3 \li Tagged storyboard files will be compiled. The output may be a flat file or a bundle (directory structure). The resulting files will be automatically tagged \l{filetags-bundle} {bundle.input}. If the current product is a bundle, the files will be included in the bundle's resources directory. \endtable */ /*! \qmlproperty bool ib::warnings Whether to print warnings when compiling. Does not apply to icon sets. \defaultvalue \c{true} */ /*! \qmlproperty bool ib::errors Whether to print errors when compiling. Does not apply to icon sets. \defaultvalue \c{true} */ /*! \qmlproperty bool ib::notices Whether to print notifications when compiling. Does not apply to icon sets. \defaultvalue \c{true} */ /*! \qmlproperty stringList ib::flags Additional flags to pass to the underlying tool (\c ibtool, \c actool, \c iconutil). \nodefaultvalue \defaultvalue \c{true} */ /*! \qmlproperty string ib::ibtoolName \since Qbs 1.3 The name of the \c ibtool binary used to compile NIBs and storyboards. This property should not normally need to be changed. \defaultvalue \c{"ibtool"} */ /*! \qmlproperty string ib::ibtoolPath \since Qbs 1.3 The directory where the \c ibtool binary is located. This property should not normally need to be changed. \defaultvalue \c{ibtoolName} */ /*! \qmlproperty bool ib::flatten Compiles XIBs and storyboards into flattened (non-wrapper) files. Set to \c{false} to preserve editability of the resulting NIB and storyboard bundles in Interface Builder. This property should not normally need to be changed. \defaultvalue \c{true} */ /*! \qmlproperty string ib::module \since Qbs 1.3 Sets the name of the module that the NIB or storyboard is a part of. Requires Xcode 6 or newer. \nodefaultvalue */ /*! \qmlproperty bool ib::autoActivateCustomFonts \since Qbs 1.3 Instructs the \c ibtool compiler to add custom fonts to the application's \c Info.plist when compiling XIBs and storyboards, which will cause the fonts to activate upon application launch. Requires Xcode 6 or newer. \defaultvalue \c{true} */ /*! \qmlproperty string ib::actoolName \since Qbs 1.3 The name of the \c actool binary used to compile asset catalogs. This property should not normally need to be changed. \defaultvalue \c{"actool"} */ /*! \qmlproperty string ib::actoolPath \since Qbs 1.3 The directory where the \c actool binary is located. This property should not normally need to be changed. \defaultvalue \c{actoolName} */ /*! \qmlproperty string ib::appIconName \since Qbs 1.3 The name of the resource in the asset catalog that will be used as the application's icon. Used to generate the partial \c Info.plist which will be merged into the resulting app. If this property is \c{undefined}, no application icon will be specified. \nodefaultvalue */ /*! \qmlproperty string ib::launchImageName \since Qbs 1.3 The name of the resource in the asset catalog that will be used as the application's launch image. Used to generate the partial \c Info.plist which will be merged into the resulting app. If this property is \c{undefined}, no launch image will be specified. This property is specific to iOS. \nodefaultvalue */ /*! \qmlproperty bool ib::compressPngs \since Qbs 1.3 Whether to compress PNG image files when building asset catalogs. \defaultvalue \c{true} */ /*! \qmlproperty string ib::iconutilName \since Qbs 1.3 The name of the \c iconutil binary used to compile icon sets. This property should not normally need to be changed. \defaultvalue \c{"iconutil"} */ /*! \qmlproperty string ib::iconutilPath \since Qbs 1.3 The directory where the \c iconutil binary is located. This property should not normally need to be changed. \defaultvalue \c{iconutilName} */ qbs-src-2.6.1/doc/reference/modules/protobufcpp-module.qdoc0000644000175100001660000001313514776170045023324 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype protobuf.cpp \inqmlmodule QbsModules \since Qbs 1.13 \brief Provides support for protocol buffers for the C++ language. The \c protobuf.cpp module provides support for generating C++ headers and sources from proto definition files using the \l protoc tool. A simple qbs file that uses protobuf can be written as follows: \code CppApplication { Depends { name: "protobuf.cpp" } files: ["foo.proto", "main.cpp"] } \endcode A generated header now can be included in the C++ sources: \code #include int main(int argc, char* argv[]) { Foo bar; bar.set_answer(42); google::protobuf::ShutdownProtobufLibrary(); return 0; } \endcode \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"protobuf.input"} \li \c{*.proto} \li 1.13.0 \li Source files with this tag are considered inputs to the \c protoc compiler. \row \li \c{"protobuf.grpc"} \li \li 1.14.0 \li Source files with this tag are considered as gRPC files. \row \li \c{"protobuf.hpp"} \li \li 1.18.0 \li This tag is attached to the header files generated by \c protoc compiler. \endtable \section2 Dependencies The \l protobuf.cpp module requires runtime libraries to be operational. It depends on the \c "protobuflib" module which can be created by the \l qbspkgconfig or fallback module providers (the corresponding packages are \c protobuf or \c protobuf-lite). If \l useGrpc is set to true, the \l protobuf.cpp module also depends on the \c "grpc++" module. */ /*! \qmlproperty string protobuf.cpp::compilerName The name of the protoc binary. \since Qbs 1.17 \defaultvalue \c "protoc" */ /*! \qmlproperty string protobuf.cpp::compilerPath The path to the protoc binary. Use this property to override the auto-detected location. \since Qbs 1.17 \defaultvalue \c auto-detected */ /*! \qmlproperty pathList protobuf.cpp::importPaths The list of imports that are passed to the \c protoc tool via the \c --proto_path option. These imports should contain the proto files. They are used to determine the relative structure of the generated files. \note The paths are passed to \c protoc in the same order as specified in this property and \c protoc output may differ depending on that order. \defaultvalue \c [] */ /*! \qmlproperty string protobuf.cpp::outputDir \readonly The directory where the \c protoc compiler generated files are placed. The value of this property is automatically set by \QBS and cannot be changed by the user. */ /*! \qmlproperty bool protobuf.cpp::useGrpc Whether to use gRPC framework. Use this property to enable support for the modern open source high performance RPC framework by Google, gRPC (\l{https://www.grpc.io}). A simple qbs file that uses grpc can be written as follows: \code CppApplication { Depends { name: "protobuf.cpp" } protobuf.cpp.useGrpc: true files: ["main.cpp"] Group { files: "grpc.proto" fileTags: "protobuf.grpc" } } \endcode \note that \c protobuf.grpc tag should be assigned manually because gRPC uses same \c *.proto files and \QBS can't detect whether to generate gRPC or \c protobuf. The following \c grpc.proto file... \code syntax = "proto3"; package Qbs; message Request { string name = 1; } message Response { string name = 1; } service Grpc { rpc doWork(Request) returns (Response) {} } \endcode ...can be used in the C++ sources as follows: \code #include class Service final : public Qbs::Grpc::Service { grpc::Status doWork( grpc::ServerContext* context, const Qbs::Request* request, Qbs::Response* reply) override { (void)context; reply->set_name(request->name()); return grpc::Status::OK; } }; \endcode \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/modules/pkgconfig-module.qdoc0000644000175100001660000000617214776170045022733 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype pkgconfig \inqmlmodule QbsModules \since 1.13 \brief Allows to configure the pkg-config tool. The \c pkgconfig module is used to fine-tune the behavior of the \c {pkg-config} tool, which is \l{How do I build against libraries that provide pkg-config files?}{potentially employed} when looking up dependencies. */ /*! \qmlproperty string pkgconfig::executableFilePath The path to the \c {pkg-config} executable. \defaultvalue auto-detected */ /*! \qmlproperty stringList pkgconfig::libDirs Set this if you need to overwrite the default search directories. The values given here will be forwarded to the tool via the \c PKG_CONFIG_LIBDIR environment variable. \note You do not need to set this for cross-compilation in order to point \c {pkg-config} to the sysroot. \QBS does that for you. \nodefaultvalue */ /*! \qmlproperty bool pkgconfig::staticMode If this property is \c true, then calls to \c{pkg-config} will include the \c{--static} option. Set this if your product is to be linked statically. \defaultvalue \c false */ /*! \qmlproperty path pkgconfig::sysroot This property controls the value of the \l{PkgConfigProbe::sysroot}{PkgConfigProbe.sysroot} property. Set this property if you need to overwrite the default search sysroot path used by \c pkg-config. This can be useful if \c pkg-config files are located in the directory other than qbs.sysroot. This is the case on macOS platform - all XCode profiles are sysrooted to the SDK directory, but \c pkg-config is typically intalled using Brew and resides in the \c /usr/local directory. Setting this property to \c undefined or empty (\c "") value will use pkg-config's default search paths: \code qbs build modules.pkgconfig.sysroot:undefined \endcode \defaultvalue \c "" on macOS, \c qbs.sysroot on other platforms */ qbs-src-2.6.1/doc/reference/modules/nodejs-module.qdoc0000644000175100001660000000324114776170045022240 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype nodejs \inqmlmodule QbsModules \since Qbs 1.3 \brief Provides Node.js support. The \c nodejs module contains support for running \l{Node.js} applications from \QBS. */ /*! \qmlproperty path Node.js::applicationFile The input JavaScript file whose corresponding output will be executed when running the Node.js application. If this property is \c{undefined}, the product will not be runnable. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/modules/qt-declarative-module.qdoc0000644000175100001660000000370114776170045023664 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.declarative \inqmlmodule QbsModules \brief Provides Qt Quick 1 support. The Qt.declarative module provides support for Qt Quick 1. \sa Qt.quick, Qt.qml */ /*! \qmlproperty bool Qt.declarative::qmlDebugging Whether QML debugging support is compiled into your binaries. \defaultvalue \c{false} */ /*! \qmlproperty string Qt.declarative::qmlImportsPath The absolute path to the directory where Qt's QML imports are installed. \defaultvalue Determined by \l{setup-qt}. */ /*! \qmlproperty string Qt.declarative::qmlPath The absolute path to the directory where Qt's QML files are installed. This property is left undefined for Qt 4. \defaultvalue Determined by \l{setup-qt}. */ qbs-src-2.6.1/doc/reference/modules/texttemplate-module.qdoc0000644000175100001660000000622014776170045023476 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype texttemplate \inqmlmodule QbsModules \since Qbs 1.13 \brief Provides support for text template files. The \c texttemplate module provides support for text template files. \section2 Example Consider the following text file \e{greeting.txt.in}. \code ${greeting} ${name}! \endcode This can be used in a project like this: \code Product { type: ["text"] files: ["greeting.txt.in"] Depends { name: "texttemplate" } texttemplate.dict: ({ greeting: "Hello", name: "World" }) } \endcode Which will create the file \e{greeting.txt}. \code Hello World! \endcode \section2 Placeholder Syntax A placeholder \c{${foo}} is replaced by its corresponding value in \e{texttemplate.dict}. Placeholder names consist of alphanumeric characters only. The placeholder \c{${$}} is always replaced with \c{$}. If you need a literal \c{${foo}} in your template, use \c{${$}{foo}}. Placeholders that are not defined in the dictionary will produce an error. \section2 Relevant File Tags \target filetags-texttemplate \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"texttemplate.input"} \li \c{*.in} \li 1.13.0 \li Source files with this tag serve as inputs for the text template rule. \endtable */ /*! \qmlproperty var texttemplate::dict The dictionary containing values for all keys used in the template file. \defaultvalue \c{{}} */ /*! \qmlproperty string texttemplate::outputFileName The output file name that is assigned to produced artifacts. \defaultvalue Complete base name of the input file */ /*! \qmlproperty string texttemplate::outputTag The output tag that is assigned to produced artifacts. \defaultvalue \c{"text"} */ qbs-src-2.6.1/doc/reference/modules/flatbuf-cpp-module.qdoc0000644000175100001660000000777014776170045023174 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype flatbuf.cpp \inqmlmodule QbsModules \since Qbs 2.4 \brief Provides support for \l{https://google.github.io/flatbuf/}{flatbuf} for the C++ language. The \c flatbuf.cpp module provides support for generating C++ headers and sources from flatbuf definition files using the \c flatc tool. A simple qbs file that uses flatbuf can be written as follows: \code CppApplication { Depends { name: "flatbuf.cpp" } files: ["foo.fbs", "main.cpp"] } \endcode A generated header now can be included in the C++ sources: \code #include int main(int argc, char* argv[]) { flatbuf::FlatBufferBuilder builder; auto foo = QbsTest::CreateFoo(builder, 42); return 0; } \endcode \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"flatbuf.input"} \li \c{*.fbs} \li 2.4.0 \li Source files with this tag are considered inputs to the \c flatc compiler. \endtable \section2 Dependencies This module depends on the \c flatbuffers module which can be created via the \l{conan}{Conan} module provider. */ /*! \qmlproperty string flatbuf.cpp::compilerName The name of the \c flatc binary. \defaultvalue \c "flatc" */ /*! \qmlproperty string flatbuf.cpp::compilerPath The path to the \c flatc binary. Use this property to override the auto-detected location. \defaultvalue \c auto-detected */ /*! \qmlproperty string flatbuf.cpp::filenameExtension The extension appended to the generated file names. If not specified, the default extension (\c ".h") is used. This property corresponds to the \c --filename-ext option of the \c flatc tool. \nodefaultvalue */ /*! \qmlproperty string flatbuf.cpp::filenameSuffix The suffix appended to the generated file names. If not specified, the default suffix (\c "_generated") is used. This property corresponds to the \c --filename-suffix option of the \c flatc tool. \nodefaultvalue */ /*! \qmlproperty pathList flatbuf.cpp::importPaths The list of import paths that are passed to the \c flatc tool via the \c -I option. \defaultvalue \c [] */ /*! \qmlproperty string flatbuf.cpp::includePrefix Prefix path prepended to any generated include statements. This property corresponds to the \c --include-prefix option of the \c flatc tool. \nodefaultvalue */ /*! \qmlproperty bool flatbuf.cpp::keepPrefix Whether to keep original prefix of schema include statement. This property corresponds to the \c --keep-prefix option of the \c flatc tool. \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/modules/protobufobjc-module.qdoc0000644000175100001660000000726414776170045023465 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype protobuf.objc \inqmlmodule QbsModules \since Qbs 1.13 \brief Provides support for protocol buffers for the Objective-C language. The \c protobuf.objc module provides support for generating Objective-C headers and sources from proto definition files using the \l protoc tool. \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"protobuf.input"} \li \c{*.proto} \li 1.13.0 \li Source files with this tag are considered inputs to the \c protoc compiler. \row \li \c{"protobuf.hpp"} \li \li 1.18.0 \li This tag is attached to the header files generated by \c protoc compiler. \endtable */ /*! \qmlproperty string protobuf.objc::compilerName The name of the protoc binary. \since Qbs 1.17 \defaultvalue \c "protoc" */ /*! \qmlproperty string protobuf.objc::compilerPath The path to the protoc binary. Use this property to override the auto-detected location. \since Qbs 1.17 \defaultvalue \c auto-detected */ /*! \qmlproperty pathList protobuf.objc::importPaths The list of imports that are passed to the \c protoc tool via the \c --proto_path option. These imports should contain the proto files. They are used to determine the relative structure of the generated files. \note The paths are passed to \c protoc in the same order as specified in this property and \c protoc output may differ depending on that order. \defaultvalue \c [] */ /*! \qmlproperty string protobuf.objc::includePath The path where protobuf Objective-C headers are located. Set this property to override the default location. \note If frameworkPath is specified, this property has no effect. \defaultvalue \c auto-detected */ /*! \qmlproperty string protobuf.objc::libraryPath \note If frameworkPath is specified, this property has no effect. \defaultvalue \c auto-detected */ /*! \qmlproperty string protobuf.objc::frameworkPath The path where \c Protobuf.framework is located. Set this property to override the default location. \defaultvalue \c auto-detected */ /*! \qmlproperty string protobuf.objc::outputDir \readonly The directory where the \c protoc compiler generated files are placed. The value of this property is automatically set by \QBS and cannot be changed by the user. */ qbs-src-2.6.1/doc/reference/modules/qt-scxml-module.qdoc0000644000175100001660000000531414776170045022531 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.scxml \inqmlmodule QbsModules \brief Provides Qt SCXML support. The Qt.scxml module provides support for the Qt SCXML module, which enables creating state machines from SCXML files. \section2 Relevant File Tags \target filetags-scxml \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"qt.scxml.compilable"} \li - \li 1.7 \li Source files with this tag serve as inputs to the rule running the Qt SCXML compiler, which will create a C++ class representing a state machine. \endtable */ /*! \qmlproperty string Qt.scxml::className The class name of the generated state machine. By default, the compiler will use the \c name attribute of the input file's \c{} tag. \nodefaultvalue */ /*! \qmlproperty string Qt.scxml::generateStateMethods If this property is \c true, the Qt SCXML compiler will generate read and notify methods for states. \defaultvalue \c false \since 1.11 */ /*! \qmlproperty string Qt.scxml::namespace The C++ namespace in which to put the generated class. By default, the compiler will place the class in the global namespace. \nodefaultvalue */ /*! \qmlproperty string Qt.scxml::qscxmlcName The base name of the Qt SCXML compiler. Set this value if your system uses a name different from the default value. \defaultvalue \c{"qscxmlc"} */ qbs-src-2.6.1/doc/reference/modules/protobufnanopb-module.qdoc0000644000175100001660000001056414776170045024022 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype protobuf.nanopb \inqmlmodule QbsModules \since Qbs 1.18 \brief Provides support for protocol buffers for embedded systems. The \c protobuf.nanopb module provides support for generating nanopb C headers and sources from proto definition files using the \l nanopb plugin for the \l protoc tool suitable for embedded systems. A simple qbs file that uses protobuf can be written as follows: \code CppApplication { Depends { name: "protobuf.nanopb" } files: ["foo.proto", "main.cpp"] } \endcode A generated header now can be included in the C++ sources: \code #include int main(int argc, char* argv[]) { Foo bar; bar.has_answer = true; bar.answer = 42; return 0; } \endcode Nanopb .options files to define nanopb specific proto options are supported. \section2 Relevant File Tags \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"protobuf.input"} \li \c{*.proto} \li 1.13.0 \li Source files with this tag are considered inputs to the \c protoc compiler. \row \li \c{"protobuf.hpp"} \li \li 1.18.0 \li This tag is attached to the header files generated by \c protoc compiler. \endtable */ /*! \qmlproperty string protobuf.nanopb::compilerName The name of the protoc binary. \defaultvalue \c "protoc" */ /*! \qmlproperty string protobuf.nanopb::compilerPath The path to the protoc binary. Use this property to override the auto-detected location. \defaultvalue \c auto-detected */ /*! \qmlproperty pathList protobuf.nanopb::importPaths The list of imports that are passed to the \c protoc tool via the \c --proto_path option. These imports should contain the proto files. They are used to determine the relative structure of the generated files. \note The paths are passed to \c protoc in the same order as specified in this property and \c protoc output may differ depending on that order. \defaultvalue \c [] */ /*! \qmlproperty string protobuf.nanopb::includePath The path where protobuf nanopb C headers are located. Set this property to override the default location. \defaultvalue \c auto-detected */ /*! \qmlproperty string protobuf.nanopb::libraryPath The path where the protobuf nanopb runtime library is located. Set this property to override the default location. \defaultvalue \c auto-detected */ /*! \qmlproperty string protobuf.nanopb::outputDir \readonly The directory where the \c protoc compiler generated files are placed. The value of this property is automatically set by \QBS and cannot be changed by the user. */ /*! \qmlproperty string protobuf.nanopb::pluginName The name of the nanopb protoc plugin. \defaultvalue \c "protoc-gen-nanopb" */ /*! \qmlproperty string protobuf.nanopb::pluginPath The path to the nanopb protoc plugin. Use this property to override the auto-detected location. \defaultvalue \c auto-detected */ qbs-src-2.6.1/doc/reference/modules/typescript-module.qdoc0000644000175100001660000001172214776170045023167 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype typescript \inqmlmodule QbsModules \since Qbs 1.3 \brief Provides TypeScript support. The \c typescript module contains properties and rules for building \l{TypeScript} applications and may be used in combination with the \l{nodejs} module to run the applications directly from \QBS. */ /*! \qmlproperty string typescript::warningLevel The severity of warnings to emit. The higher the level, the more warnings will be shown. \c{pedantic} causes the TypeScript to emit warnings on expressions and declarations with an implied \e any type. \defaultvalue \c{"normal"} */ /*! \qmlproperty string typescript::targetVersion The ECMAScript target version for generated JavaScript code. If left undefined, the TypeScript \l{Compiler Options}{compiler default} is used. \nodefaultvalue */ /*! \qmlproperty string typescript::moduleLoader If TypeScript modules are being used, the JavaScript module loading mechanism to use in the generated JavaScript code. If left undefined, modules are not used. See \l{Compiler Options} for a list of possible values. \nodefaultvalue */ /*! \qmlproperty bool typescript::stripComments Whether to remove comments from the generated JavaScript files. \defaultvalue \l{qbs::debugInformation}{!qbs.debugInformation} */ /*! \qmlproperty bool typescript::generateDeclarations Whether to generate the corresponding \c .d.ts files during compilation. These are TypeScript's equivalent of header files. \defaultvalue \c{false} */ /*! \qmlproperty bool typescript::generateSourceMaps Whether to generate the corresponding \c .map files during compilation. \defaultvalue \l{qbs::debugInformation}{qbs.debugInformation} */ /*! \qmlproperty stringList typescript::compilerFlags A list of additional flags for the TypeScript compiler. \nodefaultvalue */ /*! \qmlproperty bool typescript::singleFile Whether to compile all TypeScript source files to a single JavaScript output file. The default is to compile each TypeScript file to a corresponding JavaScript file. This property is incompatible with \l{typescript}{moduleLoader}. \defaultvalue \c{false} */ /*! \qmlproperty string typescript::version The TypeScript version. Consists of four numbers separated by dots. For example, "1.0.0.0". \nodefaultvalue */ /*! \qmlproperty int typescript::versionMajor The TypeScript major version. \defaultvalue \c{versionParts[0]} */ /*! \qmlproperty int typescript::versionMinor The TypeScript minor version. \defaultvalue \c{versionParts[1]} */ /*! \qmlproperty list typescript::versionParts The TypeScript version as a list. For example, TypeScript version 1.0 would correspond to a value of \c[1, 0, 0, 0]. \defaultvalue \c [] */ /*! \qmlproperty int typescript::versionPatch The TypeScript patch level. \defaultvalue \c{versionParts[2]} */ /*! \qmlproperty int typescript::versionBuild The fourth TypeScript version number component. \defaultvalue \c{versionParts[3]} */ /*! \qmlproperty path typescript::toolchainInstallPath The TypeScript installation directory. This property should not normally need to be changed if \c{tsc} is available by searching the PATH environment variable. \nodefaultvalue */ /*! \qmlproperty string typescript::compilerName The name of the compiler binary. This property should not normally need to be changed. \defaultvalue \c{"tsc"} */ /*! \qmlproperty string typescript::compilerPath The directory where the compiler binary is located. This property should not normally need to be changed. \defaultvalue \c{compilerName} */ qbs-src-2.6.1/doc/reference/modules/qt-quick-module.qdoc0000644000175100001660000000545014776170045022520 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt.quick \inqmlmodule QbsModules \brief Provides Qt Quick 2 support. The Qt.quick module provides support for Qt Quick 2. \sa Qt.qml, Qt.declarative \section2 Relevant File Tags \target filetags-quick \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"qt.quick.qrc"} \li \c{*.qrc} \li 1.10 \li Qt resource files with this file tag will be picked up by the Qt Quick compiler rule, and all QML files in the resource will be compiled. This file tag will only be added automatically if the Qt Quick compiler is available. \endtable */ /*! \qmlproperty bool Qt.quick::compilerAvailable Whether the Qt installation contains the Qt Quick compiler. \defaultvalue auto-detected \since 1.10 */ /*! \qmlproperty bool Qt.quick::useCompiler Whether to make use of the Qt Quick compiler. \defaultvalue \l compilerAvailable \since 1.11 */ /*! \qmlproperty bool Qt.quick::qmlDebugging Whether QML debugging support should be compiled into your binaries. \defaultvalue \c{false} */ /*! \qmlproperty string Qt.quick::qmlImportsPath The absolute path to the directory where Qt's QML imports are installed. \defaultvalue Determined by \l{setup-qt}. */ /*! \qmlproperty string Qt.quick::qmlPath The absolute path to the directory where Qt's QML files are installed. This property is left undefined for Qt 4. \defaultvalue Determined by \l{setup-qt}. */ qbs-src-2.6.1/doc/reference/modules/autotest-module.qdoc0000644000175100001660000000503614776170045022632 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype autotest \inqmlmodule QbsModules \since Qbs 1.13 \brief Allows to fine-tune autotest execution. The \c autotest module provides properties that allow autotest applications to specify how exactly they should be run. */ /*! \qmlproperty bool autotest::allowFailure Autotests for which this property is \c true can return a non-zero exit code without causing the entire \l AutotestRunner to fail. Use this for tests that are known to be unreliable. \defaultvalue \c false */ /*! \qmlproperty stringList autotest::arguments The list of arguments to invoke the autotest with. If not specified, then the \l{AutotestRunner::arguments}{arguments} property of the \l AutotestRunner that invokes the autotest is used. \nodefaultvalue */ /*! \qmlproperty string autotest::workingDir The working directory for running the autotest. If not specified, then the \l{AutotestRunner::workingDir}{workingDir} property of the \l AutotestRunner that invokes the autotest is used. \nodefaultvalue */ /*! \qmlproperty int autotest::timeout The time limit for the execution of the autotest. If not specified, the \l{AutotestRunner::timeout}{timeout} property of the \l AutotestRunner that invokes the autotest is used. \nodefaultvalue \since Qbs 1.15 */ qbs-src-2.6.1/doc/reference/modules/cpufeatures-module.qdoc0000644000175100001660000001214414776170045023306 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype cpufeatures \inqmlmodule QbsModules \since Qbs 1.10 \brief Provides support for fine-tuning CPU features. The \c cpufeatures module offers properties for enabling or disabling specific CPU features. Use it if you want to override the compiler defaults for a given platform. The compiler rules in the \l{cpp} module evaluate this module's properties and generate matching compiler flags. All properties in this module are of type \c bool and have the following semantics: \list \li The default value \c undefined has no effect on the compiler command line. \li If the value is \c true and the compiler has a flag to enable the feature, that flag is added to the command line if it is applicable to the current architecture. For example, enabling the property \c x86_sse2 would result in the GCC option \c{-msse2}. \li If the value is \c false and the compiler has a flag to disable the feature, that flag is added to the command line if it is applicable to the current architecture. For example, disabling the property \c x86_sse2 would result in the GCC option \c{-no-msse2}. \endlist */ /*! \qmlproperty bool cpufeatures::arm_neon Whether to use NEON instructions in ARM binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::arm_vfpv4 Whether to use VFPv4 instructions in ARM binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::mips_dsp Whether to use DSP instructions in MIPS binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::mips_dspr2 Whether to use DSPr2 instructions in MIPS binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx Whether to use AVX instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx2 Whether to use AVX2 instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512bw Whether to use AVX-512-BW instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512cd Whether to use AVX-512-CD instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512dq Whether to use AVX-512-DQ instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512er Whether to use AVX-512-ER instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512f Whether to use AVX-512 instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512ifma Whether to use AVX-512-IFMA instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512pf Whether to use AVX-512-PF instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512vbmi Whether to use AVX-512-VBMI instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_avx512vl Whether to use AVX-512-VL instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_f16c Whether to use F16C instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_sse2 Whether to use SSE2 instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_sse3 Whether to use SSE3 instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_ssse3 Whether to use SSSE3 instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_sse4_1 Whether to use SSE4.1 instructions in x86 binaries. \nodefaultvalue */ /*! \qmlproperty bool cpufeatures::x86_sse4_2 Whether to use SSE4.2 instructions in x86 binaries. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/modules/lexyacc-module.qdoc0000644000175100001660000001047314776170045022413 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype lex_yacc \inqmlmodule QbsModules \since Qbs 1.6 \brief Provides support for the \c lex and \c yacc tools. The \c lex_yacc module allows you to create scanners and parsers via the POSIX tools \c lex and \c yacc, respectively. These tools are closely related and share a number of properties, which is why they are represented by a single module. \section2 Relevant File Tags \target filetags-lexyacc \table \header \li Tag \li Auto-tagged File Names \li Since \li Description \row \li \c{"lex.input"} \li \c{*.l} \li 1.6 \li Source files with this tag serve as inputs to the \c lex tool. \row \li \c{"yacc.input"} \li \c{*.y} \li 1.6 \li Source files with this tag serve as inputs to the \c yacc tool. \endtable */ /*! \qmlproperty bool lex_yacc::enableCompilerWarnings \since Qbs 1.8 Whether compiler warnings are displayed. Because \c lex and \c yacc are known to produce files that will trigger compiler warnings, such warnings are suppressed by default. Set this property to \c true if you want to see them. \defaultvalue \c{false} */ /*! \qmlproperty string lex_yacc::lexBinary The file path of the \c lex tool. \defaultvalue \c{"lex"} */ /*! \qmlproperty stringList lex_yacc::lexFlags Additional command-line options for the \c lex tool. \defaultvalue \c [] */ /*! \qmlproperty string lex_yacc::lexOutputFilePath The output file for the \c lex tool. This corresponds to \c{%option outfile} in the .l file. If \c{%option outfile} is set in the .l file then this property is ignored. \defaultvalue \c undefined \since 1.12 */ /*! \qmlproperty string lex_yacc::outputTag The file tag for the generated scanner and parser sources. Use \l{filetags-cpp}{"cpp"} if you want to use a C++ compiler on them. \defaultvalue \l{filetags-cpp}{"c"} */ /*! \qmlproperty bool lex_yacc::uniqueSymbolPrefix If this property is \c true, the prefix \c yy normally used for the generated lexer and parser functions is replaced by the base name of the file provided as input to \c lex and \c yacc, respectively. Enable this property if you want to use more than one lexer or parser in a single product. \note Enabling this property requires that the associated lexer and scanner source files have the same base name. It also assumes a variant of \c lex that supports the non-POSIX option \c{-P}, such as \c flex. \defaultvalue \c{false} */ /*! \qmlproperty string lex_yacc::yaccBinary The file path of the \c yacc tool. \defaultvalue \c{"yacc"} */ /*! \qmlproperty stringList lex_yacc::yaccFlags Additional command-line options for the \c yacc tool. \defaultvalue \c [] */ /*! \qmlproperty string lex_yacc::yaccOutputFilePath Main output file for the \c yacc tool. This corresponds to \c{%output} in the .y file. If \c{%output} is set in the .y file then this property is ignored. \defaultvalue \c undefined \since 1.12 */ qbs-src-2.6.1/doc/reference/items/0000755000175100001660000000000014776170045016274 5ustar runnerdockerqbs-src-2.6.1/doc/reference/items/language/0000755000175100001660000000000014776170045020057 5ustar runnerdockerqbs-src-2.6.1/doc/reference/items/language/propertyoptions.qdoc0000644000175100001660000000401614776170045024230 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Properties \nextpage Rule \inqmlmodule QbsLanguageItems \qmltype PropertyOptions \ingroup list-of-items \keyword QML.PropertyOptions \brief Provides inline documentation for properties within product and module items. A PropertyOptions item can appear inside a \l{Product} or \l{Module} item to provide inline documentation for properties. */ /*! \qmlproperty stringList PropertyOptions::allowedValues A list of the values permitted by the property. The default value, \c{undefined}, indicates that any value is permitted. */ /*! \qmlproperty string PropertyOptions::description A brief description of the property. \nodefaultvalue */ /*! \qmlproperty string PropertyOptions::name The name of the property to document. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/language/rule.qdoc0000644000175100001660000003160514776170045021703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage PropertyOptions \nextpage Scanner \qmltype Rule \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Rule \brief Creates transformers for input tags. In \QBS, rules create \e transformers that produce output files from input files. The term \e transformer refers to a list of \l{Command and JavaScriptCommand}{commands}. These commands are created in a rule's \l{prepare} script. They do the actual work, either directly or by executing external commands. \section1 A Simple Example The following rule takes text files and replaces Windows-style line endings with their Unix-style counterparts. We will look at it one piece at a time. \quotefromfile ../examples/rule/rule.qbs \skipto Rule \printuntil multiplex: false A \e {multiplex rule} creates one transformer that takes all input artifacts with the matching input file tag and creates one or more output artifacts. We are setting the respective property to \c false here, indicating that we want to create one transformer per input file. \note This is actually the default, so the above assignment is not required. \printuntil inputs: ["txt_input"] Here we are specifying that our rule is interested in input files that have the tag \c "txt_input". Such files could be source files, in which case you would tag them using a \l{Group}. Or they could in turn get generated by a different rule, in which case that rule would assign the file tag. The files matching the tag will be available in the \l{prepare} script under the name \c inputs (see \l{inputs and outputs}{The inputs and outputs Variables}). \printuntil } Here we are specifying that for every input file, we want to create one output file whose name is the same as the input file, but with an additional extension. Because we are giving a relative path, \QBS will prepend that path by the product's build directory. In addition, we tell \QBS that the output files should get the file tag \c "txt_output". This enables other rules to use these files as inputs. You must always assign suitable file tags to your output artifacts, or the rule will not be run. See \l{Rules and Product Types} for details. If you want to create more than one output file per input file, you simply provide multiple \l Artifact items. The set of output artifacts will be available in the prepare script under the name \c outputs (see \l{inputs and outputs}{The inputs and outputs Variables}). \printuntil /^\s{4}\}/ The prepare script shown above puts everything together by creating the command that does the actual transformation of the file contents, employing the help of the \l{TextFile Service}{TextFile} class. As you can see, the return value is an array, meaning you can provide several commands to implement the rule's functionality. For instance, if we had provided two \c Artifact items, we might have also provided two commands, each of them creating one output file. For the \c input and \c output variables used in the code, see the next section. \target inputs and outputs \section1 The \c inputs and \c outputs Variables We already mentioned that the input and output artifacts are available in the prepare script via the variables \c inputs and \c outputs, respectively. These variables are JavaScript objects whose property keys are file tags and whose property values are lists of objects representing the artifacts matching these tags. In our example, the \c inputs variable has a single property \c txt_input, whose value is a list with one element. Similarly, the \c outputs variable also has one single property \c txt_output, again with a list containing one element. The actual artifact objects have the following properties: \table \header \li Property \li Description \row \li \c baseName \li The file name without any extension. \row \li \c completeBaseName \li The file name without the last extension. \row \li \c fileName \li The name of the file (that is, \c filePath without any directory components). \row \li \c filePath \li The full file path. \row \li \c fileTags \li The list of the artifact's file tags. \endtable The artifact object contains a property for every module that is used in the product. That can be used to access the module's properties. For instance, for an artifact in a C++ product, \c{artifact.cpp.defines} is the list of defines that will be passed when compiling the respective file. But what about the variables \c input and \c output that appeared in our example? These are simply convenience variables which are available in the case that the \c inputs and \c outputs variables contain only one artifact, respectively. So in our example, instead of \c input we also could have written \c {inputs.txt_input[0]}, which is considerably more verbose. \section1 Rules and Product Types It is important to know that when figuring out which rules to execute, \QBS starts at the product type and then looks for a way to produce artifacts with matching file tags from source files, using a chain of rules that are connected by their respective input and output tags. For instance, consider this simple C++ project: \code Product { type: ["application"] Depends { name: "cpp" } files: ["main.cpp"] } \endcode Here's how this product is built: \list 1 \li \QBS looks for a rule that can produce artifacts with the file tag \c{"application"}. Such a rule is found in the \l{cpp} module (namely, the rule that invokes the linker). \li Since the rule found in the previous step takes inputs of type \c{"obj"}, \QBS now looks for a rule that produces artifacts of that type. Again, such a rule is found in the \c cpp module (the rule that runs the compiler). \li The rule found in the previous step takes inputs of type \c{"cpp"}. No rule is found that creates such artifacts, but we do have a source file with a matching type (because the \c cpp module contains a \l{FileTagger} which attached that type to \c{"main.cpp"} due to its file extension). \li Now that there is a chain of rules leading from a source file tag to the product type, the commands of these rules are executed one after the other until we end up with our executable. \endlist \section1 A Complete Example The following code snippet shows a single \l{Rule} within a \l{Product} and summarizes the previous sections. \note The product's type is set up to the \c "txt_output" file tag to tell \QBS that the product depends on output artifacts produced by the custom rule. Otherwise the rule would not be executed. \quotefile ../examples/rule/rule.qbs */ /*! \qmlproperty bool Rule::multiplex Determines whether this is a multiplex rule. \defaultvalue \c false */ /*! \qmlproperty stringList Rule::inputs A list of file tags the input artifacts must match. All output artifacts will depend on all artifacts in the product with the given input file tags. Also, these artifacts are available in the \c inputs variable of the \l{prepare} script. \nodefaultvalue */ /*! \qmlproperty stringList Rule::auxiliaryInputs A list of file tags. This rule will be dependent on (that is: applied after) every other rule in the same product that (potentially) produces artifacts that are compatible with the value of this property. Unlike \l{inputs}, this property has no effect on the content of the \c inputs variable of the \l{prepare} script. \nodefaultvalue */ /*! \qmlproperty stringList Rule::auxiliaryInputsFromDependencies Like \l auxiliaryInputs, except that instead of rules from the current product, those from product dependencies are considered. \nodefaultvalue \since 2.6 */ /*! \qmlproperty stringList Rule::excludedInputs A list of file tags. Connections to rules that produce these file tags are prevented. \nodefaultvalue \since Qbs 1.12 */ /*! \qmlproperty stringList Rule::inputsFromDependencies A list of file tags that the artifacts of product dependencies must match. For example, the product \a foo might appear as follows in the current product: \code Depends { name: "foo" } \endcode All artifacts of \a foo that match the given file tags will appear in the \c inputs variable of the \l{prepare} script. \nodefaultvalue */ /*! \qmlproperty var Rule::outputArtifacts An array of output artifacts, specified as JavaScript objects. For example: \code outputArtifacts: [{ filePath: "myfile.cpp", fileTags: ["cpp"], cpp: { cxxLanguageVersion: "c++11" } }] \endcode For a description of the possible properties, see the documentation of the \l{Artifact} item. Output artifacts can be specified either by this property or by \l{Artifact} items. Use this property if the set of outputs is not fixed but depends the input's content. If no file tags are provided, \QBS will apply all \l{FileTagger}{file taggers} known in the current context to the output file name. The user may set the property \c{explicitlyDependsOn} on artifact objects, which is similar to \l{Rule::explicitlyDependsOn}{Rule.explicitlyDependsOn}. \nodefaultvalue */ /*! \qmlproperty stringList Rule::outputFileTags If output artifacts are specified by \l{outputArtifacts}, this property must specify a list of file tags that the rule potentially produces. \nodefaultvalue */ /*! \qmlproperty bool Rule::condition If \c true, the rule is enabled, otherwise it does nothing. \defaultvalue \c true */ /*! \qmlproperty stringList Rule::explicitlyDependsOn A list of file tags. Each artifact that matches the file tags is added to the dependencies of each output node. All artifacts in the current product are considered. The main difference between this property and \l inputs is that all matching artifacts are dependencies for all output artifacts, regardless of whether \l multiplex is true or not. \nodefaultvalue */ /*! \qmlproperty stringList Rule::explicitlyDependsOnFromDependencies Like \l explicitlyDependsOn, except that instead of artifacts from the current product, those from product dependencies are considered. \nodefaultvalue \since Qbs 1.12 */ /*! \qmlproperty script Rule::prepare A script that prepares the commands to transform the inputs to outputs. The code in this script is treated as a function with the signature \c{function(project, product, inputs, outputs, input, output, explicitlyDependsOn)}. The argument \c{input} is \c{undefined} if there's more than one input artifact for this rule. Similarly, \c{output} is only defined if there is exactly one output artifact. \nodefaultvalue */ /*! \qmlproperty bool Rule::requiresInputs Specifies whether a rule's commands should be created even if no inputs are available. Enabling this property can be useful if you are not sure whether input files exist, and you want \QBS to create an output file even if they do not. Set to \c true if the rule declares any inputs, \c false otherwise. */ /*! \qmlproperty bool Rule::alwaysRun If \c true, the rule's commands are always executed, even if all output artifacts are up to date. \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/items/language/export.qdoc0000644000175100001660000001106614776170045022254 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Depends \nextpage FileTagger \qmltype Export \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Export \brief Exports dependencies and properties to other products. An Export item can appear inside a \l{Product} item. It defines a \l{Module} with the product's name that can be depended on by other products. The properties attached to the Export item will take effect in all products that depend on the product inside which the Export item is defined. As an example, consider these two products: \code Product { name: "A" Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.sourceDirectory cpp.defines: ["USING_" + exportingProduct.name.toUpperCase()] } } Product { name: "B" Depends { name: "A" } } \endcode The sources in product B will be able to use headers from product A without specifying the full path to them, because the include path has been made known to the compiler via A's Export item. Additionally, product B will be compiled with the define \c{USING_A}. The dependent \l{Product}'s modules are not exported unless explicitly specified within the \l{Export} item: \code Product { name: "B-Exporting-A" Depends { name: "A" } Export { Depends { name: "A" } } } \endcode The relationship of the exported dependencies is transitive. A product C depending on a product B-Exporting-A will also get a direct dependency on A and thus inherit include paths and preprocessor macros exported by A. \code Product { name: "C" Depends { name: "B-Exporting-A" } } \endcode Within an Export item, you can use the \c exportingProduct variable to refer to the product which defines the Export item. Use the \c{importingProduct} variable to refer to the product that pulls in the resulting module: \code Product { name: "D" Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory, importingProduct.buildDirectory] } } \endcode */ /*! \qmlproperty var Export::prefixMapping This property allows to provide a translation of exported values between non-deployed and deployed contexts. It is an array of objects with properties \c prefix and \c replacement. The array's elements get applied to all other properties set in this item such that if the property's value start with \c prefix, that prefix gets replaced with \c replacement. It is typically used for C/C++ include paths. For instance, in a library that provides header files for inclusion both directly from its source directory (when building it as part of a bigger project) and from some installed location (when building an unrelated project against it), you would write something like the following: \code Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] prefixMapping: [{ prefix: exportingProduct.sourceDirectory, replacement: FileInfo.joinPaths(qbs.installPrefix, "include") }] } \endcode \defaultvalue \c undefined \see Exporter.qbs \see Exporter.pkgconfig \since 1.12 */ qbs-src-2.6.1/doc/reference/items/language/profile.qdoc0000644000175100001660000000616314776170045022375 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Product \nextpage Project \qmltype Profile \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Profile \brief Creates a profile within the project. The profiles used by \QBS are normally set up on a user's machine and are then available to all projects. See \l{Configuring Profiles and Preferences} for information on how to set up and use profiles on the command line. In some rare cases, however, the creator of a project has complete knowledge about the system on which that project is to be built. Then it can make sense to integrate the profile into the project: \code Product { // ... Profile { name: "my-special-profile" qbs.toolchainType: "gcc" qbs.targetPlatform: "linux" qbs.architecture: "armv7a" cpp.toolchainInstallPath: "/opt/special-gcc/bin" cpp.toolchainPrefix: "arm-linux-gnueabi-" } qbs.profiles: ["my-special-profile"] // ... } \endcode The project in the above example can be built in a particular well-known environment without any additional setup. \c Profile items can appear inside \l{Product} and \l{Project} items. */ /*! \qmlproperty string Profile::baseProfile The name of a profile from which this profile inherits. If the same property is set in both this profile and the base profile, the value from this profile takes precedence. \nodefaultvalue */ /*! \qmlproperty bool Profile::condition Determines whether this profile can be used. If this property is set to \c false, the profile cannot be used. \defaultvalue \c true */ /*! \qmlproperty string Profile::name The name under which the profile can be referenced later. Setting this property is required. The value must be unique among all profiles in an entire project. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/language/properties.qdoc0000644000175100001660000001155214776170045023127 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Project \nextpage PropertyOptions \qmltype Properties \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Properties \brief Provides conditional setting of properties. \note This topic documents the Properties item in the context of \l{Product} {products}. For more information about using it in sub-projects, see \l{SubProject}. The Properties item is an auxiliary item for setting multiple property values conditionally. In the following example, two properties are set if the project is built for Windows: \code Product { Properties { condition: qbs.targetOS.includes("windows") cpp.defines: ["ON_WINDOWS"] cpp.includePaths: ["extraWindowsIncludes"] } } \endcode As the above example demonstrates, the \c Properties item is especially useful if there are several properties whose values depend on the same set of conditions. These conditions do not need to be mutually exclusive, but care should be taken not to set the same scalar property in more than one matching \c Properties item. \QBS makes no guarantees about the value of the property in such cases. If the same property is set both inside and outside of a \c Properties item, the outside binding is only considered if none of the \c Properties conditions match, that is, it acts as an "else" case. \code Product { Properties { condition: qbs.targetOS.includes("windows") cpp.defines: ["ON_WINDOWS"] cpp.includePaths: ["myWindowsIncludes"] } Properties { condition: qbs.targetOS.includes("linux") cpp.defines: ["ON_LINUX"] cpp.includePaths: ["myLinuxIncludes"] } cpp.defines: ["ON_UNKNOWN_PLATFORM"] } \endcode is roughly equivalent to \code Product { cpp.defines: { if (qbs.targetOS.includes("windows")) return ["ON_WINDOWS"]; if (qbs.targetOS.includes("linux")) return ["ON_LINUX"]; return ["ON_UNKNOWN_PLATFORM"]; } cpp.includePaths: { if (qbs.targetOS.includes("windows")) return ["myWindowsIncludes"]; if (qbs.targetOS.includes("linux")) return ["myLinuxIncludes"]; return base ? base : original; } } \endcode In Properties items, one can access the \l{Special Property Values#outer}{outer} value of a property. \code Product { Properties { condition: qbs.targetOS.includes("windows") cpp.defines: outer.concat("ON_WINDOWS") // === ["FOO", "ON_WINDOWS"] } Properties { condition: qbs.targetOS.includes("linux") cpp.defines: ["ON_LINUX"] // === ["ON_LINUX"] } cpp.defines: ["FOO"] } \endcode */ /*! \qmlproperty bool Properties::condition The condition to be used for the other bindings in this item. \default true \note The special value \c undefined can be used to indicate that this condition should be considered true if and only if none of the other Properties items matched for a given property binding. */ /*! \qmlproperty bool Properties::overrideListProperties List properties set within this item will override the values coming from modules, rather than getting merged with them, which is the default behavior. Use this in the rare case that a module you depend on inserts a value into a list property that is problematic for some product. \defaultvalue \c false */ qbs-src-2.6.1/doc/reference/items/language/depends.qdoc0000644000175100001660000001347614776170045022364 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Artifact \nextpage Export \qmltype Depends \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Depends \brief Represents dependencies between products and modules. A Depends item can appear inside a \l{Product} or \l{Module} item. For example, the following product will load the \l{cpp} module. In addition, it will try to load modules that may or may not exist, and pass this information on to the compiler. \code Product { Depends { name: "cpp" } Depends { name: "optional_module" versionAtLeast: "2.0" required: false } Properties { condition: optional_module.present cpp.defines: "HAS_OPTIONAL_MODULE" } // ... } \endcode \section1 Dependency Parameters Sometimes it is desirable to have certain dependencies handled differently than others. For example, one might want to depend on a dynamic library without linking it. This can be done by setting the \l{dependency-parameters-cpp}{cpp.link} dependency parameter to \c{true} in the dynamic library dependency: \code Product { Depends { name: "cpp" } Depends { name: "some_dynamic_lib"; cpp.link: false } // ... } \endcode Dependency parameters are a special type of property that can only be set within Depends and \l [QML] {Parameters} items. Dependency parameters are declared in the modules they belong to. In the example above, the \l{cpp} module declares the parameter \c{link}. The Depends item for \c{some_dynamic_lib} sets \c{cpp.link} to \c{false}, which tells the linker rule to ignore this particular dependency. */ /*! \qmlproperty bool Depends::condition Determines whether the dependency will actually be applied. \defaultvalue \c true */ /*! \qmlproperty string Depends::versionAtLeast The minimum value that the dependency's \c version property needs to have. If the actual version is lower than that, loading the dependency will fail. The value consists of integers separated by dots. \nodefaultvalue */ /*! \qmlproperty string Depends::versionBelow A value that the dependency's \c version property must be lower than. If the actual version is equal to or higher than that, loading the dependency will fail. The value consists of integers separated by dots. \nodefaultvalue */ /*! \qmlproperty stringList Depends::productTypes A list of product types. Any enabled product in the project that has a matching type will become a dependency of the product containing the Depends item. This property is mutually exclusive with the \l name and \l submodules properties. The \l required and \l profiles properties are ignored if this property is set. \note This property does not work recursively. Consider this example: \code Product { name: "A" type: "x" Depends { productTypes: "someTag" } } Product { name: "B" Depends { productTypes: "x" } } \endcode It is not guaranteed that \c A will show up in \c B's dependencies. \nodefaultvalue */ /*! \qmlproperty bool Depends::required Setting this property to \c false creates a \e{soft dependency}, meaning that it is not considered an error if the given module cannot be found. In such a case, an instance of the respective module will be created, but only the \l{Module::present}{Module.present} property will be available for querying, and it will be set to \c false. \defaultvalue \c true */ /*! \qmlproperty string Depends::name The name of the dependent product or module. \nodefaultvalue */ /*! \qmlproperty stringList Depends::profiles A list of profiles. If the dependency is on a product and that product is going to be built for more than one profile, you can specify here which instance of the product the dependency is on. See the \l{qbs::profiles}{qbs.profiles} property for more information. An empty list means a dependency on all instances of the product with the given name, regardless of their profile. \nodefaultvalue */ /*! \qmlproperty bool Depends::limitToSubProject If \l productTypes is set and this property is \c true, only products that are in the same sub-project as the product containing the Depends item are considered. \defaultvalue \c false */ /*! \qmlproperty stringList Depends::submodules A list of submodules of the module to depend on, if applicable. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/language/moduleprovider.qdoc0000644000175100001660000001251214776170045023770 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Module \nextpage Parameter \qmltype ModuleProvider \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.ModuleProvider \brief Creates modules on demand. The \c ModuleProvider item implements the module creation part of the procedure described in the \l {Module Providers} overview. It is always located in a file called \c provider.qbs. The actual module creation is done on the right-hand side of the \l{ModuleProvider::relativeSearchPaths}{relativeSearchPaths} property. A ModuleProvider item may contain \l{Probe} items. Here is a complete minimal example of a module provider. It just creates an empty module. If you put this item into the file \c {module-providers/mymodule/provider.qbs} in your project source directory, you will be able to successfully build a product which contains a dependency on the module \c mymodule. \code import qbs.File import qbs.FileInfo import qbs.TextFile ModuleProvider { relativeSearchPaths: { var moduleDir = FileInfo.joinPaths(outputBaseDir, "modules", name); File.makePath(moduleDir); var moduleFilePath = FileInfo.joinPaths(moduleDir, name + ".qbs"); var moduleFile = new TextFile(moduleFilePath, TextFile.WriteOnly); moduleFile.writeLine("Module {"); moduleFile.writeLine("}"); moduleFile.close(); return ""; } } \endcode */ /*! \qmlproperty bool ModuleProvider::isEager Holds whether provider is eager. Eager provider is executed only once and should create multiple modules at once when executed). A non-eager provider is executed multiple times, one time for each module \QBS tries to instantiate. \sa ModuleProvider::moduleName \default true */ /*! \qmlproperty string ModuleProvider::name The name of the module provider. This property is set by \QBS. If provider is \l{How \QBS Uses Module Providers}{requested} via the \l{Product::qbsModuleProviders}{qbsModuleProviders} property, it is the name specified in this property and matches the provider file name, without the \c .qbs extension. Otherwise, it is the name of the directory the provider was found in, relative to the particular module-providers base directory. For instance, if the dependency is \c {x.m1} and the provider was found in \c {module-providers/x/m1/provider.qbs}, then \c name is \c {x.m1}. If the provider was found in \c {module-providers/x/provider.qbs}, then \c name is \c x. */ /*! \qmlproperty string ModuleProvider::moduleName This property is set by QBS for non-eager providers and contains the name of the module that is currently being instantiated by the provider. For eager providers, the value of this property is \c undefined. \sa ModuleProvider::isEager */ /*! \qmlproperty string ModuleProvider::outputBaseDir The path under which the new modules should be created when \l relativeSearchPaths is evaluated. The path is unique for the current provider in the given configuration. This property is set by \QBS. */ /*! \qmlproperty stringList ModuleProvider::relativeSearchPaths This property gets evaluated by \QBS to retrieve new search paths with which to re-attempt the module look-up. It is here where you need to put the code that creates the new module files. Use the directory structure explained in \l {Custom Modules and Items}. That is, the file for a module called \c m will be located in a directory \c {modules/m/}, anchored at \l outputBaseDir. The return value is the list of search paths required to find the new module, relative to \l outputBaseDir. In most cases, only a single search path will be required, in which case a single-element list containing an empty string should be returned (or just the empty string, because of \QBS' auto-conversion feature). The returned list can also be empty, which means that the module provider was not able to generate any modules in this environment. */ qbs-src-2.6.1/doc/reference/items/language/artifact.qdoc0000644000175100001660000000533214776170045022527 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \nextpage Depends \ingroup list-of-language-items \qmltype Artifact \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Artifact \brief Describes a file produced by a Rule. An Artifact represents a single file produced by a \l{Rule}. For example, if a rule produces three files, it needs to contain three Artifact items. In addition to Artifact properties, you can set module properties within an Artifact item, as follows: \code Artifact { filePath: "somefile.cpp" fileTags: ["cpp"] cpp.cxxLanguageVersion: "c++11" // ... } \endcode \note The code on the right-hand side of Artifact properties has access to the set of input artifacts. That is, it can refer to the \c inputs map and, if the rule is not a multiplex rule, the \c input variable. */ /*! \qmlproperty bool Artifact::alwaysUpdated Setting this property to \c false means the file is not necessarily always written to by any command run by the rule. If all artifacts of a rule have this property set to \c false, the commands of the rule are only executed if all of them are out of date compared to the inputs. \defaultvalue \c true */ /*! \qmlproperty string Artifact::filePath The file path of the target artifact. \nodefaultvalue */ /*! \qmlproperty stringList Artifact::fileTags A list of tags to attach to the target file. These can then be matched by a \l{Rule}. \defaultvalue An empty list */ qbs-src-2.6.1/doc/reference/items/language/group.qbs0000644000175100001660000000343014776170045021722 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ Project { Product { //! [0] Group { name: "Word processing documents" files: ["*.doc", "*.rtf"] prefix: "**/" qbs.install: true qbs.installDir: "share" excludeFiles: "do_not_install_this_file.*" } //! [0] } } qbs-src-2.6.1/doc/reference/items/language/scanner.qdoc0000644000175100001660000000615314776170045022365 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Rule \nextpage SubProject \qmltype Scanner \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Scanner \brief Creates custom dependency scanners in products or modules. A Scanner item can appear inside a \l{Module} item, and allows to extract dependencies for artifacts from the artifacts' file contents. For example, this is what a scanner for "qrc" files might look like: \code import qbs.Xml Module { Scanner { inputs: 'qrc' scan: { var xml = new Xml.DomDocument(input.filePath); dependencies = []; // retrieve entries from the XML document return dependencies; } } } \endcode */ /*! \qmlproperty bool Scanner::condition If \c true, the scanner is enabled, otherwise it does nothing. \defaultvalue \c true */ /*! \qmlproperty stringList Scanner::inputs A list of \l{FileTagger}{file tags} the input artifacts must match. \nodefaultvalue */ /*! \qmlproperty bool Scanner::recursive Determines whether to scan the returned dependencies using the same scanner. \defaultvalue \c false */ /*! \qmlproperty script Scanner::searchPaths A script that returns the paths where to look for dependencies. The code in this script is treated as a function with the signature \c{function(project, product, input)}. \nodefaultvalue */ /*! \qmlproperty script Scanner::scan A script that reads the input artifact and returns a string list with dependencies. The code in this script is treated as a function with the signature \c{function(project, product, input, filePath)}, where \c input is the artifact at which the scan originated, and \c filePath is the currently scanned file. For non-recursive scans, \c filePath is always equal to \c{input.filePath}. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/language/probe.qdoc0000644000175100001660000000571114776170045022042 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Parameters \nextpage Product \qmltype Probe \inqmlmodule QbsLanguageItems \ingroup list-of-items \ingroup list-of-probes \keyword QML.Probe \brief Locates files outside the project. Probe items can appear inside \l{Product}, \l{Project} and \l{ModuleProvider} items. They are run prior to building, for instance to locate dependent headers, libraries, and other files outside the project directory whose locations are not known ahead of time. Probes can be parameterized via their properties and typically store results in properties as well. These results are then retrieved via the Probe's id, which is mandatory: \code Product { Probe { id: valueCalculator property string parameter: "whatever" property int value configure: { value = Utils.calculateValue(parameter); // Expensive operation found = true; } } property int theValue: valueCalculator.value } \endcode \note Because Probes often invoke external processes, which is relatively expensive compared to evaluating normal properties, their results are cached. To force re-evaluation of a Probe, you can supply the \l{build-force-probe-execution} {--force-probe-execution} command-line option to the \l{build} command. */ /*! \qmlproperty bool Probe::condition Determines whether the probe will actually be run. \defaultvalue \c true */ /*! \qmlproperty bool Probe::found Indicates whether the probe was run successfully. Set by \l{configure}. \nodefaultvalue */ /*! \qmlproperty script Probe::configure A script that is executed when the probe is run. */ qbs-src-2.6.1/doc/reference/items/language/project.qdoc0000644000175100001660000001055514776170045022403 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Profile \nextpage Properties \qmltype Project \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Project \brief Represents a collection of products and properties. A Project item represents a collection of of products. In a non-trivial project, these products are typically defined in their own files and referenced in the main project file: \code Project { references: [ "product1/product1.qbs", "product2/product2.qbs" ] } \endcode Any property \c prop attached to this item is available in sub-items as \c project.prop. While the root of the item hierarchy is always a Project, this kind of item can also appear further down the hierarchy. Such sub-projects are usually introduced to group products. See \l{SubProject} for details. \note If your project consists of only one product, the Project item can be omitted. */ /*! \qmlproperty path Project::buildDirectory \readonly The build directory of the top-level project. */ /*! \qmlproperty string Project::name The project name. Only relevant when displaying a project tree in an IDE, for example. \defaultvalue The basename of the file that defines the project. */ /*! \qmlproperty string Project::profile \readonly The top-level \l{Profile}{profile} for building the project. This property is set by \QBS when the project is being set up. */ /*! \qmlproperty bool Project::condition Whether the project is enabled. If \c false, no \l{Product}{products} or sub-projects will be collected. \defaultvalue \c true */ /*! \qmlproperty stringList Project::qbsSearchPaths A list of paths that are searched for imports, modules and module providers in addition to the ones listed in \c{preferences.qbsSearchPaths}. The value set here is merged with the value inherited from the parent project, if there is one. The result is inherited by all products in the project. For the details about how to add custom items, see the \l{Custom Modules and Items} page. \defaultvalue An empty list */ /*! \qmlproperty pathList Project::references A list of files from which to import products. This is equivalent to defining the respective \l{Product} items directly under this Project item. \defaultvalue An empty list */ /*! \qmlproperty path Project::sourceDirectory \readonly The directory where the file containing the top-level Project item is located. */ /*! \qmlproperty string Project::minimumQbsVersion The minimum version of \QBS that is needed to build this project. \defaultvalue \c "1.3.0" */ /*! \qmlproperty stringList Project::qbsModuleProviders The list of \l{Module Providers} to use for this project. Providers contribute to the \l{Product::}{qbsSearchPaths} in the order specified here, so modules generated by providers specified earlier are prioritized. Currently, this order also corresponds with the actual execution order of the providers, but this should not be relied upon. \sa Product::qbsModuleProviders \since Qbs 1.21 */ qbs-src-2.6.1/doc/reference/items/language/parameter.qdoc0000644000175100001660000000347414776170045022717 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Module \nextpage Parameters \qmltype Parameter \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Parameter \brief Declares a dependency parameter. The Parameter item declares a dependency parameter. It can appear only within \l{Module} and \l{Export} items. The Parameter item contains exactly one property declaration. Example: \code Module { Parameter { property string extra } } \endcode For more information about dependency parameters, see \l{Module#dependency-parameters}{Module - Dependency Parameters}. */ qbs-src-2.6.1/doc/reference/items/language/joblimit.qdoc0000644000175100001660000000732214776170045022544 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Group \nextpage Module \qmltype JobLimit \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.JobLimit \brief Restricts concurrent execution of jobs in a given pool. In addition to the global limit on concurrently running commands, a project might want to restrict concurrent execution of certain types of commands even further, for instance because they are not well-suited to share certain types of resources. In the following example, we define a rule that runs a tool of which at most one instance can be running for the same project at any given time: \code Rule { // ... prepare: { var cmd = new Command("my-exclusive-tool", [project.buildDirectory]); cmd.description = "running the exclusive tool"; cmd.jobPool = "exclusive_tool"; return cmd; } } JobLimit { jobPool: "exclusive_tool" jobCount: 1 } \endcode \c JobLimit items can appear inside \l Product, \l Project and \l Module items. In the case of collisions, that is, items matching the same job pool but setting different values, the ones defined inside products have the highest precedence, and the ones inside modules have the lowest. Items defined in sub-projects have higher precedence than those defined in parent projects. For items with the same precedence level, the most restrictive one is chosen, that is, the one with the lowest job number greater than zero. \see {How do I limit the number of concurrent jobs for the linker only?} */ /*! \qmlproperty bool JobLimit::condition Determines whether the job limit is active. If this property is set to \c false, the job limit is ignored. \defaultvalue \c true */ /*! \qmlproperty int JobLimit::jobCount The maximum number of commands in the given \l{jobPool}{job pool} that can run concurrently. A value of zero means "unlimited", negative values are not allowed. \note The global job limit always applies: For instance, if you set this property to 100 for some job pool, and "-j 8" was given on the command line, then no more than eight instances of commands from the respective job pool will run at any time. This property must always be set. \nodefaultvalue */ /*! \qmlproperty string JobLimit::jobPool The job pool to which apply the limit. This property must always be set to a non-empty value. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/language/module.qdoc0000644000175100001660000002301614776170045022216 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage JobLimit \nextpage ModuleProvider \qmltype Module \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Module \brief Represents a collection of properties and items that can be loaded into a product. A Module item is a collection of properties and language items. It contributes to building a product if the product has a \l{Depends}{dependency} on the module. Modules may contain the following items: \list \li \l{Depends} \li \l{FileTagger} \li \l{Group} \li \l{JobLimit} \li \l{Parameter} \li \l{Probe} \li \l{PropertyOptions} \li \l{Rule} \li \l{Scanner} \endlist When a product expresses a dependency on a module, \QBS will create an instance of the module item in the scope of the product. The product can then read and write properties from and to the loaded module, respectively. Modules in different products are isolated from each other, just as products cannot access each other's properties. However, products can use the \l{Export} item to pass dependencies and properties of modules to other dependent products. The following (somewhat artificial) module pre-processes text files by removing certain characters from them. The module's name is \c{txt_processor}. \qml import qbs.FileInfo import qbs.TextFile Module { property stringList unwantedCharacters: [] FileTagger { patterns: ["*.raw"] fileTags: ["raw-txt"] } Rule { inputs: ["raw-txt"] Artifact { filePath: FileInfo.relativePath(input.filePath, product.sourceDirectory) + "/" + input.fileName + ".processed" fileTags: ["processed-txt"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "Processing " + input.fileName; cmd.sourceCode = function() { var inFile = new TextFile(input.filePath, TextFile.ReadOnly); var content = inFile.readAll(); inFile.close(); var unwantedChars = input.txt_processor.unwantedCharacters; for (var c in unwantedChars) content = content.replace(unwantedChars[c], ""); var outFile = new TextFile(output.filePath, TextFile.WriteOnly); outFile.write(content); outFile.close(); }; return cmd; } } } \endqml And this is how a \l{Product} would use the module: \qml Product { type: "processed-txt" Depends { name: "txt_processor" } txt_processor.unwantedCharacters: ["\r"] files: [ "file1.raw", "file2.raw" ] } \endqml The resulting files are tagged with \c{processed-txt} and might be consumed by a rule in another module. That is possible if another rule has \c{processed-txt} in its \l{Rule::inputs}{inputs} property. For more information about how you make your own modules available to \QBS, see \l{Custom Modules and Items}. \section1 Accessing Product and Module Properties When defining a property in a module item, the right-hand side expression is a binding. Bindings may reference other properties of: \list \li the current module \li other modules that this module depends on \li the dependent product \endlist Please note that this applies to bindings in modules only. Property access in rules and other nested items is different. \section2 Accessing Properties of the Current Module Sibling properties in the same module can be accessed directly by their name: \qml Module { property stringList windowsDefaults: ["\r"] property stringList unwantedCharacters: windowsDefaults } \endqml \section2 Properties of the Dependent Modules When a module loads another module through a \l{Depends} element, it can access properties of the other module through its name. Assuming there was a module \c OtherModule with a property \c otherProperty, such an access would look like this: \qml Module { Depends { name: "OtherModule" } property string myProperty: "something-" + OtherModule.otherProperty } \endqml \section2 Accessing Properties of the Dependent Product \qml Module { property bool featureEnabled: (product.type.includes("application")) ? true : false } \endqml \section2 Special Property Values For every property defined in a module, \QBS provides the special \l{Special Property Values#original}{original} value containing the value of the property in the module itself (possibly overridden from a profile). \section1 Dependency Parameters Modules can declare dependency parameters. Those parameters can be set within \l{Depends} items. \l{Rule}{Rules} of the module can read the parameters of dependencies and act accordingly. In the following example, the module \e{foo} declares the parameter \c{ignore}. A dependency to \c{bar} then sets the parameter \c{foo.ignore} to \c{true}. A rule in \c{foo} ignores all dependencies that have \c{foo.ignore} set to true. \code Module { // Definition of module 'foo'. Parameter { property bool ignore } Rule { ... prepare: { for (i in product.dependencies) { var dep = product.dependencies[i]; if (dep.foo.ignore) continue; // Do something with the dependency. } } } ... } ---------- Product { Depends { name: "foo" } Depends { name: "bar"; foo.ignore: true } } \endcode */ /*! \qmlproperty stringList Module::additionalProductTypes A list of elements that will be added to the \l{Product::type}{type} property of a product that has a dependency on the module. \defaultvalue \c [] */ /*! \qmlproperty bool Module::condition Whether the module is enabled. If this property is \c false, the surrounding Module item will not be considered in the module look-up. \defaultvalue \c true */ /*! \qmlproperty bool Module::present \readonly This property is \c false if and only if the respective \l{Depends} item had its \l{Depends::required}{required} property set to \c false and the module was not found. \defaultvalue \c true */ /*! \qmlproperty int Module::priority The priority of this module instance. If there is more than one module instance available for a module name, the module with the highest priority is chosen. \defaultvalue 0 */ /*! \qmlproperty script Module::setupBuildEnvironment A script for setting up the environment in which a product is built. The code in this script is treated as a function with the signature \c{function(project, product)}. Use the \l{Environment Service}{Environment} functions to alter the environment. The return value of this script is ignored. \nodefaultvalue */ /*! \qmlproperty script Module::setupRunEnvironment A script for setting up the environment in which a product is run. The code in this script is treated as a function with the signature \c{function(project, product, config)}. The \c config parameter is a list of arbitrary strings that can be passed via the \l{run} command. The values supported by specific modules are listed in their respective documentation. Use the \l{Environment Service}{Environment} functions to alter the environment. The return value of this script is ignored. \nodefaultvalue */ /*! \qmlproperty script Module::validate A script that is run after the module is loaded. It can be used to check property values and throw errors in unexpected cases. The return value is ignored. \nodefaultvalue */ /*! \qmlproperty string Module::version The module's version. It consists of integer values separated by dots. You can check for specific values of this property in a \l{Depends} item. */ qbs-src-2.6.1/doc/reference/items/language/subproject.qdoc0000644000175100001660000000743014776170045023113 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Scanner \qmltype SubProject \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.SubProject \brief Adds a project from a different file. A SubProject item is used to add a sub-project that is defined in a separate file. Additionally, properties of the sub-project can be set without modifying the separate project file. The following example adds a sub-project defined in \c{subdir/project.qbs} and overrides its name. \code Project { SubProject { filePath: "subdir/project.qbs" Properties { name: "A sub-project" } } ... } \endcode A typical use case for SubProject items is to conditionally include sub-projects. The following example pulls in the \e{tests} sub-project if and only if the \c{withTests} property is \c{true}. \code Project { property bool withTests: false SubProject { filePath: "tests/tests.qbs" Properties { condition: parent.withTests } } ... } \endcode If you do not need to set any properties on the sub-project, you can also use the \l{Project::references}{Project.references} property, the same way you would for a product. \code Project { references: "subdir/project.qbs" } \endcode is equivalent with \code Project { SubProject { filePath: "subdir/project.qbs" } } \endcode It is also possible to nest \l{Project} items directly in the same file. */ /*! \qmlproperty bool SubProject::condition Whether the sub-project is added. If \c false, the sub-project is not included. Setting this property has the same effect as setting the \c{condition} property within a \l{Properties} item. If both this property and the \c{condition} property within a \l{Properties} item are defined, the sub-project is included only if both properties evaluate to \c{true}. \defaultvalue \c true */ /*! \qmlproperty path SubProject::filePath The file path of the project to add as a sub-project. If the top-level item in this file is a \l{Product}, it gets wrapped automatically in a new project. \defaultvalue empty */ /*! \qmlproperty bool SubProject::inheritProperties Determines whether the sub-project should inherit the properties of the surrounding \l{Project}. You can use this feature to share global settings between projects and sub-projects. \defaultvalue \c true */ qbs-src-2.6.1/doc/reference/items/language/filetagger.qdoc0000644000175100001660000000706514776170045023050 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Export \nextpage Group \qmltype FileTagger \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.FileTagger \brief Assigns file tags to files. This item assigns file tags to files. The FileTagger item can appear in \l{Product} items or \l{Module} items. For every source artifact that has no file tag, \QBS will search for a FileTagger with a pattern that matches the file name of the source artifact. If a matching file tagger is found, then the file tags specified in the FileTagger item are assigned to the source artifact. If there is more than one matching FileTagger, all file taggers with the same highest priority are taken into account and their file tags are accumulated. The FileTagger item can be attached to a product or a module. In the latter case, its effect is the same as if it had been attached to all products having a dependency on the respective module. For instance, the \l{cpp} module of \QBS has, among others, the following file tagger: \code FileTagger { patterns: "*.cpp" fileTags: ["cpp"] } \endcode As a result, the \c "cpp" tag is automatically attached to all files ending with \c ".cpp" in products depending on the \c cpp module. This causes them to be compiled, because a C++ compiler rule has \c "cpp" in its list of matching input tags. File taggers are disabled if file tags are set explicitly in a \l{Product} {product} or \l{Group}{group}. For example, the \c "cpp" tag is not attached to the \c .cpp files in the following product: \code Product { Depends { name: "cpp" } Group { files: "*.cpp" fileTags: "other" } } \endcode */ /*! \qmlproperty stringList FileTagger::patterns \since Qbs 1.0 A list of patterns to match against. Supports the usual wildcards '*', '?' and '[]'. Neither the list itself nor any of its elements may be empty. */ /*! \qmlproperty list FileTagger::fileTags \since Qbs 1.0 Tags to attach to a product's files. These can then be matched by a rule. \defaultvalue An empty list */ /*! \qmlproperty int FileTagger::priority \since Qbs 1.10 The priority of the FileTagger. A higher numerical value means a higher priority. \defaultvalue 0 */ qbs-src-2.6.1/doc/reference/items/language/parameters.qdoc0000644000175100001660000000436414776170045023101 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Parameter \nextpage Probe \qmltype Parameters \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Parameters \brief Defines default values for dependency parameters within Module and Export items. The Parameters item defines default values for dependency parameters within \l{Module} and \l{Export} items. Example: \code DynamicLibrary { name: "foo" ... Export { ... Parameters { cpp.link: false } } } \endcode Every dependency on \e{foo} has the parameter \l{dependency-parameters-cpp} {cpp.link} set to \c{false} by default. This can be overridden explicitly: \code Depends { name: "foo"; cpp.link: true } \endcode The Parameters item contains a number of property bindings where each property must be a properly declared dependency parameter. For more information, see \l{Parameter} and \l{Module#dependency-parameters}{Module - Dependency Parameters}. */ qbs-src-2.6.1/doc/reference/items/language/group.qdoc0000644000175100001660000002242514776170045022070 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage FileTagger \nextpage JobLimit \qmltype Group \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Group \brief Groups files and other items in a product or module. This item is attached to a \l{Product}{product} or \l{Module}{module} and used to group files and other items that have something in common. \section1 Typical Uses of Groups by Example \code Application { Group { name: "common files" files: ["myclass.h", "myclass_common_impl.cpp"] } Group { name: "Windows files" condition: qbs.targetOS.includes("windows") files: "myclass_win_impl.cpp" } Group { name: "Unix files" condition: qbs.targetOS.includes("unix") files: "unixhelper.cpp" Group { name: "Linux files" condition: qbs.targetOS.includes("linux") files: "myclass_linux_impl.cpp" } Group { name: "FreeBSD files" condition: qbs.targetOS.includes("freebsd") files: "myclass_freebsd_impl.cpp" } } Group { name: "Files to install" qbs.install: true qbs.installDir: "share" files: "runtime_resource.txt" } } \endcode \section1 Wildcards When specifying files, you can use the wildcards \c "*", \c "?" and \c "[]", which have their \l{https://en.wikipedia.org/wiki/Wildcard_character#File_and_directory_patterns}{usual meaning} as in Unix Shell. By default, matching files are only picked up directly from the parent directory, but you can tell \QBS to consider the whole directory tree. It is also possible to exclude certain files from the list. The pattern \c "**" used in a pathname expansion context will match all files and zero or more directories and subdirectories. For example: \snippet reference/items/language/group.qbs 0 \section1 Attaching Module Properties to Source Files Within a \c Group item, module properties can be attached either to all files in the product, or to only the files in that group. The following example demonstrates both: \code Product { // ... Group { condition: project.hasSpecialFeature cpp.defines: "FEATURE_SPECIFIC" product.cpp.defines: "WITH_FEATURE" files: "feature.cpp" } } \endcode Here, the macro \c "FEATURE_SPECIFIC" will only be visible inside \c feature.cpp, whereas \c "WITH_FEATURE" applies to all source files in the product. A group-level property binding starting with \c "product." is semantically equivalent to putting the same property binding without that prefix inside a top-level \l Properties item with the same condition as the group. The above example could therefore also have been written like this: \code Product { // ... Group { condition: project.hasSpecialFeature cpp.defines: "FEATURE_SPECIFIC" files: "feature.cpp" } Properties { condition: project.hasSpecialFeature cpp.defines: "WITH_FEATURE" } } \endcode Obviously, the original variant is to be preferred, as it does not duplicate the condition and keeps related code close together. It should be noted that there is a third way to write the same example, with a \l Properties item inside the group: \code Product { // ... Group { condition: project.hasSpecialFeature cpp.defines: "FEATURE_SPECIFIC" files: "feature.cpp" Properties { cpp.defines: "WITH_FEATURE" } } } \endcode This construct just adds verbosity here, but might be useful in cases where the product-level property binding is dependent on an additional condition. \section1 Attaching Module Properties to Generated Files A group can also be used to attach properties to build artifacts such as executables or libraries. In the following example, an application is installed to "/bin". \code Application { Group { fileTagsFilter: "application" qbs.install: true qbs.installDir: "bin" } } \endcode \section1 Groups in Modules Groups may also appear in \l{Module}{modules}, which causes the respective sources to be added to the products depending on the said module, unless the \l{filesAreTargets} property is set. \section1 Grouping Related Items Groups can contain other items, namely \l Depends, \l FileTagger, \l Rule and \l Scanner items. They can also contain other groups, that is, they can be nested. The \l{condition} of a groups's child item gets logically ANDed with the one of the parent group. Additionally, if the child item is a group itself, the child group inherits the module properties and \l{FileTagger}{file tags} as well as the prefix of its parent group. */ /*! \qmlproperty string Group::name The name of the group. Not used internally; mainly useful for IDEs. \defaultvalue "Group x", where x is a unique number among all the groups in the product. */ /*! \qmlproperty pathList Group::files The files in the group. Mutually exclusive with \l{fileTagsFilter}. Relative paths are resolved using the parent directory of the file that contains the Group item. However, if the \l{prefix} property is set to an absolute path, then that one becomes the base directory. The values can contain wildcards. \defaultvalue An empty list */ /*! \qmlproperty bool Group::filesAreTargets If this property is \c true and the group is in a \l{Module}, the files in the group will not become source artifacts of the product that depends on the module. Instead, they are treated like target artifacts of products. That is, they will be matched against the \l{Rule::inputsFromDependencies}{inputsFromDependencies} file tag list of \l{Rule}{rules} in products that depend on the module. \defaultvalue \c false */ /*! \qmlproperty string Group::prefix A string to prepend to all files. Slashes are allowed and have directory semantics. \defaultvalue The prefix of the parent group if one exists, otherwise empty. */ /*! \qmlproperty stringList Group::fileTagsFilter List of \l{Artifact::fileTags}{artifact.fileTags} to match. Any properties set in this group will be applied to the product's artifacts whose file tags match the ones listed here. The file tags that the group's \l{fileTags} property specifies will be added to the matching artifacts. This property is mutually exclusive with \l{files}. \defaultvalue An empty list */ /*! \qmlproperty bool Group::condition Determines whether the files in the group are actually considered part of the project. \defaultvalue \c true */ /*! \qmlproperty stringList Group::fileTags A list of file tags to attach to the group's files. These can then be matched by a \l{Rule}{rule}. \note \l{FileTagger}{File taggers} are never applied to a file that has this property set. \defaultvalue An empty list */ /*! \qmlproperty bool Group::overrideTags Determines how tags on files that are listed both at the top level of a product (or the parent group, if there is one) and a group are handled. If this property is \c true, then the \l{FileTagger}{file tags} set via the group replace the ones set via the product or parent group. If it is \c false, the \e {group tags} are added to the \e {parent tags}. This property is ignored if \l{fileTagsFilter} is set. \defaultvalue \c true */ /*! \qmlproperty pathList Group::excludeFiles A list of files that are \e subtracted from the \l{files} list. The values can contain wildcards. This property is ignored if \l{fileTagsFilter} is set. \defaultvalue An empty list */ qbs-src-2.6.1/doc/reference/items/language/product.qdoc0000644000175100001660000002066014776170045022413 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Probe \nextpage Profile \qmltype Product \inqmlmodule QbsLanguageItems \ingroup list-of-items \keyword QML.Product \brief Represents the result of a build process. A Product typically represents the result of a build process. It specifies a set of input and output files and a way to transform the former into the latter. For example, the following product sets up a very simple C++ application: \code Product { name: "helloworld" type: "application" files: "main.cpp" Depends { name: "cpp" } } \endcode The \l{type} property specifies what will be built (an executable). The \l{files} property specifies the input files (one C++ source file), and the \l{Depends} item pulls in the logic from the \l{cpp} module about how to do the necessary transformations. For some often-used types of products, \QBS pre-defines special derived items that save users some typing. These are: \list \li \l{Application} \li \l{CppApplication} \li \l{DynamicLibrary} \li \l{StaticLibrary} \endlist Therefore, the above example could also be written like this: \code CppApplication { name: "helloworld" files: "main.cpp" } \endcode Any property \c prop attached to this item is available in sub-items as \c product.prop, as well as in modules that are loaded from this product. \section1 Multiplexing Properties The following properties are relevant for product multiplexing only. Unless multiplexing is desired, they can be left at their default values: \list \li \l{aggregate} \li \l{multiplexedType} \li \l{multiplexByQbsProperties} \endlist \note We do not promise backwards compatibility for multiplexing properties as they are likely to change in future \QBS versions. \section1 Read-Only Properties The following properties are automatically set by \QBS and cannot be changed by the user: \list \li \l{buildDirectory} \li \l{sourceDirectory} \endlist */ /*! \qmlproperty bool Product::builtByDefault Determines whether the product will be built. If \c false, the product will only be built if this is explicitly requested, either by listing the product name as an argument to the \l{build-products}{--products} option or by using the \l{build-all-products}{--all-products} option of the \l{build} command. \defaultvalue \c true */ /*! \qmlproperty bool Product::condition Determines whether the product will be built. If \c false, the product will not be built. \defaultvalue \c true */ /*! \qmlproperty string Product::name The name of the product. Used to identify the product in a \l{Depends} item, for example. The value of this property must be a simple JavaScript expression that does not depend on module properties or values that are non-local to this product. \code CppApplication { name: "hello" + "world" // valid } CppApplication { name: "app_" + qbs.targetOS.join("_") // invalid } \endcode To change the name of your product's target artifact, modify \l{targetName} instead. \defaultvalue An empty string */ /*! \qmlproperty stringList Product::type The file tags matching the product's target artifacts. \defaultvalue An empty list */ /*! \qmlproperty string Product::targetName The base file name of the product's target artifacts. \defaultvalue The value of \l{name} with illegal file name characters replaced by underscores. */ /*! \qmlproperty string Product::destinationDirectory The directory where the target artifacts will be located. If a relative path is given, the base directory will be \l{Project::buildDirectory} {project.buildDirectory}. \defaultvalue \c{product.buildDirectory} */ /*! \qmlproperty stringList Product::files A list of source files. Syntactic sugar to save a \l{Group} item for simple products. Relative paths are resolved using the parent directory of the project file that sets the property. \defaultvalue An empty list */ /*! \qmlproperty stringList Product::excludeFiles A list of source files not to include. Useful with wildcards. For more information, see \l{Group}. \defaultvalue An empty list */ /*! \qmlproperty bool Product::consoleApplication On Windows, determines whether a console or GUI application is generated. If \c true, a console application is generated. If \c false, a GUI application is generated. On Apple platforms, influences the default application type. If \c true, a normal executable is generated. If \c false, an application bundle is generated. \defaultvalue Linker-dependent */ /*! \qmlproperty stringList Product::qbsSearchPaths A list of paths that are searched for imports, modules and module providers. The value set here will be merged with the value of \l{Project::qbsSearchPaths}{project.qbsSearchPaths}. For the details about how to add custom items, see the \l{Custom Modules and Items} page. \defaultvalue \l{Project::qbsSearchPaths}{project.qbsSearchPaths} */ /*! \qmlproperty string Product::version The version number of the product. Used in shared library filenames and generated Info.plist files in Apple application and framework bundles, for example. \nodefaultvalue */ /*! \qmlproperty bool Product::aggregate If \c{true}, an aggregate product will be created that has dependencies on all multiplex instances of this product. \note If you do not want to do multiplexing, you can use the default value \c{undefined}. */ /*! \qmlproperty stringList Product::multiplexedType Specifies the product type for the multiplexed product instances. \note If you do not want to do multiplexing, you can use the default value \c{undefined}. */ /*! \qmlproperty stringList Product::multiplexByQbsProperties Specifies which properties of the \l{qbs} module will be used for product multiplexing: \list \li \l{qbs::architectures}{architectures} \li \l{qbs::buildVariants}{buildVariants} \li \l{qbs::profiles}{profiles} \endlist The value must be a subset of the above values. \note If you do not want to do multiplexing, you can use the default value \c{["profiles"]}. */ /*! \qmlproperty path Product::buildDirectory \readonly The build directory for this product. This is the directory where generated files are placed. The value of this property is automatically set by \QBS and cannot be changed by the user. */ /*! \qmlproperty path Product::sourceDirectory \readonly The source directory for this product. This is the directory of the file where this product is defined. The value of this property is automatically set by \QBS and cannot be changed by the user. */ /*! \qmlproperty stringList Product::qbsModuleProviders The list of \l{Module Providers} to use for this product. Overrides \l{Project::qbsModuleProviders}{Project.qbsModuleProviders}. \sa Project::qbsModuleProviders \since Qbs 1.21 */ qbs-src-2.6.1/doc/reference/items/convenience/0000755000175100001660000000000014776170045020570 5ustar runnerdockerqbs-src-2.6.1/doc/reference/items/convenience/library.qdoc0000644000175100001660000001036714776170045023113 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage JavaJarFile \nextpage LoadableModule \qmltype Library \since Qbs 1.4 \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.NativeBinary \brief Generic library. A Library item is a base item for native libraries and can have \l{Product::}{type} set to one of the following values: \c "dynamiclibrary", \c "staticlibrary", \c "loadablemodule". The default \l{Product::}{type} value is \c "dynamiclibrary" except for iOS prior to version 8, in which case the default value is \c "staticlibrary". This item can automatically install the library target (and library symlinks on Unix) and separated debug information. For Android targets, the following applies: \list \li The \l{Product::type}{Product.type} property value contains \c "android.nativelibrary" in addition to \c "dynamiclibrary". \li There is a dependency on the \l{cpp} and \l{Android.ndk} modules. \endlist */ /*! \qmlproperty bool Library::install If \c{true}, the library will be installed to \l{Library::installDir}{installDir}. \defaultvalue \c false \since Qbs 1.13 */ /*! \qmlproperty string Library::installDir Where to install the library, if \l{Library::install}{install} is enabled. On Unix, the symbolic links are also installed to this location. The value is appended to \l{qbs::installPrefix}{qbs.installPrefix} when constructing the actual installation directory. \defaultvalue \c Library/Frameworks if the library is a \l{bundle::isBundle}{bundle}, otherwise \c bin for Windows and \c lib for Unix-like targets. \since Qbs 1.13 */ /*! \qmlproperty bool Library::installDebugInformation If \c{true}, the debug information will be installed to \l{Library::debugInformationInstallDir}{debugInformationInstallDir}. \defaultvalue \c false \since Qbs 1.16 \sa{How do I separate and install debugging symbols?} */ /*! \qmlproperty string Library::debugInformationInstallDir Where to install the debug information if \l installDebugInformation is enabled. The value is appended to \l{qbs::installPrefix}{qbs.installPrefix} when constructing the actual installation directory. \defaultvalue \l installDir. \since Qbs 1.16 \sa{How do I separate and install debugging symbols?} */ /*! \qmlproperty bool Library::installImportLib If \c{true}, the import library will be installed to \l importLibInstallDir. This property is only relevant for Windows targets. Enable it if you want to create a development package. \defaultvalue \c false \since Qbs 1.13 */ /*! \qmlproperty string Library::importLibInstallDir Where to install the import library, if \l installImportLib is enabled. The value is appended to \l{qbs::installPrefix}{qbs.installPrefix} when constructing the actual installation directory. This property is only relevant for Windows targets. \defaultvalue \c lib \since Qbs 1.13 */ qbs-src-2.6.1/doc/reference/items/convenience/innosetup.qdoc0000644000175100001660000000312714776170045023467 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage DynamicLibrary \nextpage InstallPackage \qmltype InnoSetup \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.InnoSetup \brief Inno Setup installer executable. A InnoSetup item is a \l{Product}{product} of the \l{Product::}{type} \c{"innosetup.exe"} that has a dependency on the \l{innosetup} module. */ qbs-src-2.6.1/doc/reference/items/convenience/qtlupdaterunner.qdoc0000644000175100001660000000627014776170045024702 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 The Qt Company Ltd. ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage QtGuiApplication \nextpage StaticLibrary \qmltype QtLupdateRunner \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.QtLupdateRunner \since 2.6 \brief A product that updates all Qt translation files in the project. A QtLupdateRunner has a dependency on all \l{Product}{products} that have a Qt dependency. Building the QtLupdateRunner product will run the \l{https://doc.qt.io/qt-6/linguist-lupdate.html}{lupdate} tool on eligible source files from these products in order to update the project's translation files with regard to the translatable strings in these sources. The \l{Product::}{builtByDefault} property is set to \c false by default, so updating the translation files has to be explicitly requested. The default name of the product is \c "lupdate-runner". To use this feature: \list 1 \li Instantiate a \c QtLupdateRunner in your project, typically at the top level: \code Project { // ... QtLupdateRunner { } // ... } \endcode \li Trigger the translation files update by building the product: \code qbs build -p lupdate-runner \endcode \endlist \section2 Relevant File Tags \table \header \li Tag \li Since \li Description \row \li \c{"qt.untranslatable"} \li 2.6 \li Attach this tag to source files that lupdate should not consider. \endtable */ /*! \qmlproperty bool QtLupdateRunner::limitToSubProject By default, only the source files of products that live in the same sub-project that QtLupdateRunner was instantiated in are looked at. Set this property to \c false to consider all products in the project. \defaultvalue \c true */ /*! \qmlproperty stringList QtLupdateRunner::extraArguments Additional arguments to pass to the \c lupdate tool. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/convenience/staticlibrary.qdoc0000644000175100001660000000303414776170045024314 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage QtLupdateRunner \nextpage XPCService \qmltype StaticLibrary \inherits Library \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.StaticLibrary \brief Static library. A StaticLibrary item is a \l{Library}{library} of the \l{Product::}{type} \c "staticlibrary". */ qbs-src-2.6.1/doc/reference/items/convenience/applicationextension.qdoc0000644000175100001660000000331414776170045025701 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Application \nextpage AutotestRunner \qmltype ApplicationExtension \inherits XPCService \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.ApplicationExtension \brief Application Extension for iOS, macOS, tvOS, or watchOS. An ApplicationExtension item is a \l{Product} based on the \l{XPCService} item that sets some properties required for iOS, macOS, tvOS, or watchOS Application Extensions. */ qbs-src-2.6.1/doc/reference/items/convenience/applediskimage.qdoc0000644000175100001660000000335514776170045024425 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage AppleApplicationDiskImage \nextpage Application \qmltype AppleDiskImage \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.AppleDiskImage \brief Apple disk image. An AppleDiskImage item is a is a \l{Product}{product} of the \l{Product::} {type} \c{"dmg.dmg"} that has a dependency on the \l{dmg} module. For single-application drag 'n' drop disk image installers, you will probably want to use the \l{AppleApplicationDiskImage} item instead. */ qbs-src-2.6.1/doc/reference/items/convenience/appleapplicationdiskimage.qdoc0000644000175100001660000001017214776170045026644 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \nextpage AppleDiskImage \qmltype AppleApplicationDiskImage \since Qbs 1.9 \inherits AppleDiskImage \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.AppleApplicationDiskImage \brief Apple application drag 'n' drop disk image installer. An AppleApplicationDiskImage item is a \l{Product}{product} of the \l{Product::}{type} \c{"dmg.dmg"} that has a dependency on the \l{dmg} module. In addition, it has rules and properties specific to building drag 'n' drop disk image installers with an application bundle and symbolic link to the \c /Applications directory. Any artifacts of product dependencies that are tagged \c{"installable"} will be copied into the disk image, provided their file paths are relative to the path specified by the \l{sourceBase} property (that is, are located in that directory). Any artifacts tagged \c{"installable"} that are not relative to \l{sourceBase} will be ignored. Here is what the project file could look like for a simple DMG installer: \code AppleApplicationDiskImage { Depends { name: "myapp" } name: "My App" dmg.volumeName: name dmg.iconSize: 128 dmg.windowWidth: 640 dmg.windowHeight: 280 dmg.iconPositions: [ {"path": "Applications", "x": 128, "y": 128}, {"path": "My App.app", "x": 256, "y": 128} ] files: ["background.tiff", "volume-icon.icns"] Group { files: ["*.lproj/**"] // licenses fileTags: ["dmg.license.input"] } } \endcode For plain disk images whose contents are not a single application bundle, consider the base \l{AppleDiskImage} item instead. */ /*! \qmlproperty string AppleApplicationDiskImage::sourceBase The base directory from which artifacts installed into the disk image will be copied. This directory is always considered to be relative to \l{qbs::installRoot} {qbs.installRoot}/\l{qbs::installPrefix} {qbs.installPrefix}. For example, if the application Example.app exists at \c{qbs.installRoot/qbs.installPrefix/Applications/Example.app}, and the value of this property is \c{"/Applications"}, the application will be located at \c{/Example.app} relative to the disk image root. Therefore, its full path when the disk image is mounted would be something like \c{/Volumes/Example-1.0/Example.app}. \defaultvalue \c{"/Applications"} */ /*! \qmlproperty stringList AppleApplicationDiskImage::symlinks List of symlinks to create in the disk image. This is specified as a list of strings, each string containing two file paths separated by a colon. The first path is the symlink target, and the second path is the name of the symlink relative to the root of the disk image. \defaultvalue \c{["/Applications:Applications"]} */ qbs-src-2.6.1/doc/reference/items/convenience/application.qdoc0000644000175100001660000000646614776170045023757 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage AppleDiskImage \nextpage ApplicationExtension \qmltype Application \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.Application \brief Product of the type application. An Application item is a \l{Product} representing an application. The target artifact of this type of product is usually an executable binary tagged \c "application". However, on Android, unless you set \l{Product::}{consoleApplication} to \c true, the application target will be an APK or an AAB package tagged \c "android.package" according to the \l{Android.sdk}{packageType} property. A dependency to the \l{Android.sdk} module is automatically added to the product. */ /*! \qmlproperty bool Application::install If \c{true}, the executable that is produced when building the application will be installed to \l{Application::installDir}{installDir}. \defaultvalue \c false \since Qbs 1.13 */ /*! \qmlproperty string Application::installDir Where to install the executable that is produced when building the application, if \l{Application::install}{install} is enabled. The value is appended to \l{qbs::installPrefix}{qbs.installPrefix} when constructing the actual installation directory. \defaultvalue \c Applications if the app is a \l{bundle::isBundle}{bundle}, \c bin otherwise. \since Qbs 1.13 */ /*! \qmlproperty bool Application::installDebugInformation If \c{true}, the debug information will be installed to \l{Application::debugInformationInstallDir}{debugInformationInstallDir}. \defaultvalue \c false \since Qbs 1.16 \sa{How do I separate and install debugging symbols?} */ /*! \qmlproperty string Application::debugInformationInstallDir Where to install the debug information if \l installDebugInformation is enabled. The value is appended to \l{qbs::installPrefix}{qbs.installPrefix} when constructing the actual installation directory. \defaultvalue \l installDir. \since Qbs 1.16 \sa{How do I separate and install debugging symbols?} */ qbs-src-2.6.1/doc/reference/items/convenience/cppapplication.qdoc0000644000175100001660000000324514776170045024452 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage AutotestRunner \nextpage DynamicLibrary \qmltype CppApplication \inherits Application \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.CppApplication \brief C++ application. A CppApplication is an \l{Application}{application} that has a dependency on the \l{cpp} module. It is entirely equivalent to the following: \code Application { Depends { name: "cpp" } } \endcode */ qbs-src-2.6.1/doc/reference/items/convenience/dynamiclibrary.qdoc0000644000175100001660000000351114776170045024451 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage CppApplication \nextpage InnoSetup \qmltype DynamicLibrary \inherits Library \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.DynamicLibrary \brief Dynamic library. A DynamicLibrary item is a \l{Library}{library} of the \l{Product::}{type} \c "dynamiclibrary". For Android targets, the following applies: \list \li The \l{Product::type}{Product.type} property value contains \c "android.nativelibrary" in addition to \c "dynamiclibrary". \li There is a dependency on the \l{cpp} and \l{Android.ndk} modules. \endlist */ qbs-src-2.6.1/doc/reference/items/convenience/javaclasscollection.qdoc0000644000175100001660000000333614776170045025470 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage InstallPackage \nextpage JavaJarFile \qmltype JavaClassCollection \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.JavaClassCollection \brief Collection of Java class files not bundled in a jar file. A JavaClassCollection item is a \l{Product}{product} of the \l{Product::} {type} \c{"java.class"} that has a dependency on the \l{java} module. If the files should end up in a jar file, you should use \l{JavaJarFile} instead. */ qbs-src-2.6.1/doc/reference/items/convenience/loadablemodule.qdoc0000644000175100001660000000317214776170045024414 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage Library \nextpage QtApplication \qmltype LoadableModule \inherits Library \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.LoadableModule \brief Loadable module. A LoadableModule item is a \l{Product}{product} of the \l{Product::}{type} \c{"loadablemodule"}. It exists for the convenience of project file authors. */ qbs-src-2.6.1/doc/reference/items/convenience/qtguiapplication.qdoc0000644000175100001660000000314014776170045025013 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage QtApplication \nextpage QtLupdateRunner \qmltype QtGuiApplication \inherits QtApplication \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.QtGuiApplication \brief Application with a dependency on the Qt GUI module. A QtGuiApplication is an application that extends the \l{QtApplication} item by loading the \l{Qt.gui} module. */ qbs-src-2.6.1/doc/reference/items/convenience/qtapplication.qdoc0000644000175100001660000000335614776170045024317 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage LoadableModule \nextpage QtGuiApplication \qmltype QtApplication \inherits CppApplication \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.QtApplication \brief Application with a dependency on the Qt Core module. A QtApplication is a \l{CppApplication}{C++ application} that has a \l{Depends}{dependency} on the \l{Qt.core} module. It is entirely equivalent to the following: \code CppApplication { Depends { name: "Qt.core" } } \endcode */ qbs-src-2.6.1/doc/reference/items/convenience/installpackage.qdoc0000644000175100001660000000551014776170045024423 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage InnoSetup \nextpage JavaClassCollection \qmltype InstallPackage \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.InstallPackage \brief Archive of an installed project. An InstallPackage item is a \l{Product}{product} of the \l{Product::}{type} \c{archiver.archive} that has a \l{Depends}{dependency} on the \l{archiver} module. It is used to produce an archive from a set of installable files. Consider the following example project: \code Project { CppApplication { name: "myapp" Depends { name: "mylib" } files: ["main.cpp"] Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "bin" } } DynamicLibrary { name: "mylib" files: ["mylib.cpp"] Group { name: "public headers" files: ["mylib.h"] qbs.install: true qbs.installDir: "include" } Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: "lib" } } InstallPackage { archiver.type: "tar" name: "tar-package" Depends { name: "myapp" } Depends { name: "mylib" } } } \endcode Building the product \c "tar-package" on a Unix system will result in a tar file with these contents: \code include/mylib.h lib/libmylib.so bin/myapp \endcode */ qbs-src-2.6.1/doc/reference/items/convenience/javajarfile.qdoc0000644000175100001660000000337114776170045023722 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage JavaClassCollection \nextpage Library \qmltype JavaJarFile \inherits Product \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.JavaJarFile \brief Collection of Java class files bundled in a jar file. A JavaJarFile item is a \l{Product}{product} of the \l{Product::}{type} \c{java.jar}. It is used to produce a jar archive from a set of Java sources. */ /*! \qmlproperty string JavaJarFile::entryPoint The entry point for an executable jar file. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/convenience/autotestrunner.qdoc0000644000175100001660000001340714776170045024547 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage ApplicationExtension \nextpage CppApplication \qmltype AutotestRunner \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.AutotestRunner \brief Product that runs all autotests in the project. An AutotestRunner has a dependency on all \l{Product}{products} with the \l{Product::}{type} \c "autotest". Building the AutotestRunner product will then run the respective executables. The \l{Product::}{builtByDefault} property is set to \c false by default, so running the autotests has to be explicitly requested. The default name of the product is \c "autotest-runner". To use this feature: \list 1 \li Attach the \c "autotest" type to your autotests: \code CppApplication { name: "tst_mytest" type: ["application", "autotest"] // ... } \endcode \li Instantiate exactly one AutotestRunner in your project, typically at the top level: \code Project { // ... AutotestRunner { } // ... } \endcode \li Trigger the autotest execution by building the product: \code qbs build -p autotest-runner \endcode \endlist \section2 Setting Properties for individual Tests \target autotestrunner-autotest-module To control the behavior of individual tests, some properties of the \c AutotestRunner can be overridden by depending on the \l autotest module and setting its properties: \code CppApplication { name: "tst_mytest" type: ["application", "autotest"] Depends { name: "autotest" } autotest.timeout: 60 // ... } \endcode \section2 Relevant Job Pools \target autotestrunner-job-pools \table \header \li Pool \li Since \li Description \row \li \c{"autotest-runner"} \li 1.15 \li The job pool used to run the tests. \endtable */ /*! \qmlproperty stringList AutotestRunner::arguments The list of arguments to invoke the autotest with. A test can override this by setting the \l{autotest::arguments}{arguments} property of the \l autotest module. \defaultvalue \c [] */ /*! \qmlproperty stringList AutotestRunner::auxiliaryInputs This property can contain arbitrary file tags. The AutotestRunner will get dependencies on all products whose type matches at least one of these tags, and invocation of the test executables will happen only after all of the respective artifacts have been built. Set this property if your test executables have run-time dependencies on other products. \nodefaultvalue \since Qbs 1.12 */ /*! \qmlproperty stringList AutotestRunner::environment A list of environment variables that are added to the run environment. They are provided as a list of strings in the form \c "varName=value". \defaultvalue DYLD_LIBRARY_PATH, DYLD_FRAMEWORK_PATH, and DYLD_ROOT_PATH are set on macOS, or an empty list for other platforms. */ /*! \qmlproperty bool AutotestRunner::limitToSubProject By default, only those autotests are considered that are in the same sub-project that AutotestRunner was instantiated in. If you want to run all autotests regardless of their location in the project hierarchy, set this property to \c false. \defaultvalue \c true */ /*! \qmlproperty string AutotestRunner::workingDir If this property is set, it will be the working directory for all invoked test executables. Otherwise, the working directory will the the parent directory of the respective executable. A test can override this by setting the \l{autotest::workingDir}{workingDir} property of the \l autotest module. \nodefaultvalue \since Qbs 1.12 */ /*! \qmlproperty stringList AutotestRunner::wrapper Wrapper binary and its arguments for wrapping autotest calls. This is useful for tools like Valgrind and alike. \defaultvalue empty */ /*! \qmlproperty int AutotestRunner::timeout Time limit for the execution of the individual tests. If a test does not finish within the time limit, the test is cancelled and considered failed. A value below or equal to 0 means no timeout. A test can override this by setting the \l{autotest::timeout}{timeout} property of the \l autotest module. \defaultvalue -1 \since Qbs 1.15 */ qbs-src-2.6.1/doc/reference/items/convenience/xpcservice.qdoc0000644000175100001660000000317014776170045023614 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage StaticLibrary \qmltype XPCService \inherits Application \inqmlmodule QbsConvenienceItems \ingroup list-of-items \keyword QML.XPCService \brief XPC service for macOS, iOS, tvOS, or watchOS. An XPCService item is a convenience item based on \l Application that sets some properties required for macOS, iOS, tvOS, or watchOS XPC services. */ qbs-src-2.6.1/doc/reference/items/probe/0000755000175100001660000000000014776170045017403 5ustar runnerdockerqbs-src-2.6.1/doc/reference/items/probe/binary-probe.qdoc0000644000175100001660000000607314776170045022652 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype BinaryProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.BinaryProbe \inherits PathProbe \brief Locates executable files outside the project. Finds executable files that have the specified file names. BinaryProbe searches for executable files within directories specified by the PATH environment variable. \note On Unix, also searches in the \c /usr/bin and \c /usr/local/bin directories by default. Override \l {PathProbe::platformSearchPaths}{PathProbe.platformSearchPaths} to change this behavior. \note On Windows, only files that have \e .com, \e .exe, \e .bat, \e .cmd extensions are considered \e executables. Override \l {PathProbe::nameSuffixes}{PathProbe.nameSuffixes} to change this behavior. For example, BinaryProbe can be used to search for a protobuf compiler executable as follows: \code // Assuming module is called "myproto" import qbs.File import qbs.Probes Module { // search for a protoc executable Probes.BinaryProbe { id: protocProbe names: "protoc" } property string executableFilePath: protocProbe.filePath validate: { if (!File.exists(executableFilePath)) throw "The executable '" + executableFilePath + "' does not exist."; } // use the found executable Rule { // rule input/outputs here... // run executable for the module called "myproto": prepare: { var args = // initialize arguments... var cmd = new Command(input.myproto.executableFilePath, args); cmd.highlight = "codegen"; cmd.description = "generating protobuf files for " + input.fileName; return [cmd]; } } } \endcode */ qbs-src-2.6.1/doc/reference/items/probe/library-probe.qdoc0000644000175100001660000000432614776170045023031 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype LibraryProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.IncludeProbe \inherits PathProbe \brief Locates library files outside the project. On Windows, searches for library files within directories specified by the \c PATH environment variable. On Unix, searches for library files within directories specified by the \c LIBRARY_PATH environment variable, as well as in \c "/usr/lib" and \c "/usr/local/lib". On Linux, also searches in platform-specific directories, such as \c "/usr/lib64" and \c "/usr/lib/x86_64-linux-gnu". For example, LibraryProbe can be used to search for a \c zlib library as follows: \code import qbs.Probes CppApplication { Probes.LibraryProbe { id: zlibProbe names: "z" } cpp.libraryPaths: zlibProbe.found ? [zlibProbe.path] : [] cpp.dynamicLibraries: zlibProbe.found ? [zlibProbe.names] : [] files: 'main.cpp' } \endcode */ qbs-src-2.6.1/doc/reference/items/probe/path-probe.qdoc0000644000175100001660000001572614776170045022327 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype PathProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.PathProbe \brief Locates files outside the project. Finds files that have the specified file name suffix, such as \e .exe, from the specified locations. PathProbe takes as input lists of paths to search files from and file name patterns. The paths are specified by using the environmentPaths, searchPaths, platformEnvironmentPaths and platformSearchPaths properties; the path are searched in the same order as listed. The file name patterns are specified by the \l names and nameSuffixes properties. Returns the first file that matches the file name patterns. If no such file is found, the \l {Probe::found}{probe.found} property is set to \c false. For example, a simple PathProbe that searches for the stdio.h header can be used as follows: \code Product { Depends { name: "cpp" } PathProbe { id: probe pathSuffixes: ["include"] names: ["stdio.h"] } cpp.includePaths: probe.found ? [probe.path] : [] } \endcode */ /*! \qmlproperty varList PathProbe::allResults This property contains the list of objects, each object representing a single found file: \code { found: true, candidatePaths: ["path1/to/file", "path2/to/file", ...] filePath: "path/to/file" fileName: "file" path: "path/to" } \endcode \sa {PathProbe::filePath}{filePath}, {PathProbe::fileName}{fileName}, {PathProbe::path}{path} */ /*! \qmlproperty var PathProbe::candidateFilter This property holds the function that can be used to filter out unsuitable candidates. For example, when searching for a library, it might be necessary to check its architecture: \code PathProbe { pathSuffixes: [".so", ".dll", ".dylib"] candidateFilter: { function getLibraryArchitecture(file) { ... } return function(file) { return Utilities.isSharedLibrary(file) && getLibraryArchitecture(file) == qbs.architecture; } } } \endcode */ /*! \qmlproperty stringList PathProbe::names The list of file names to search for. \nodefaultvalue */ /*! \qmlproperty stringList PathProbe::nameSuffixes The list of file suffixes to search for. These suffixes are appended to every file name passed via the \l names property. \nodefaultvalue */ /*! \qmlproperty script PathProbe::nameFilter A script that is executed for each file name before prepending file suffixes. Can be used to transform file names. */ /*! \qmlproperty pathList PathProbe::searchPaths The list of paths where to search files. \nodefaultvalue */ /*! \qmlproperty pathList PathProbe::platformSearchPaths The list of platform paths where to search files. \defaultvalue \c {['/usr', '/usr/local']} on Unix hosts, empty otherwise */ /*! \qmlproperty stringList PathProbe::pathSuffixes A list of relative paths that are appended to each path where PathProbe searches for files. That is, the file should be located within one of the subfolders passed using this property. \nodefaultvalue */ /*! \qmlproperty stringList PathProbe::environmentPaths The list of environment variables that contains paths where to search files. Paths in the environment variable should be separated using \l{pathListSeparator}{FileInfo.pathListSeparator()}. \nodefaultvalue */ /*! \qmlproperty stringList PathProbe::platformEnvironmentPaths The list of platform environment variables that contains paths where to search files. Paths in the environment variable should be separated using \l{pathListSeparator}{FileInfo.pathListSeparator()}. \nodefaultvalue */ /*! \qmlproperty stringList PathProbe::candidatePaths This property contains the result list of all paths that were checked before a file was found (including the file names). This property is set even if the Probe didn't find anything and can be used to give the user a hint what went wrong: \code Module { Probes.BinaryProbe { id: pythonProbe names: "python" } validate: { if (!pythonProbe.found) { throw ModUtils.ModuleError( "Could not find python binary at any of the following locations:\n\t" + pythonProbe.candidatePaths.join("\n\t")); } } } \endcode \nodefaultvalue */ /*! \qmlproperty string PathProbe::path This property contains the full path where the found file is located (that is, the file directory). \nodefaultvalue */ /*! \qmlproperty string PathProbe::filePath This property contains the full path to the found file, including the file name. \nodefaultvalue */ /*! \qmlproperty string PathProbe::fileName This property contains the found file's name (excluding the path). \nodefaultvalue */ /*! \qmlproperty varList PathProbe::selectors This property should be used to search for multiple files. It contains the list of selectors each of which describes a single file to search for. A selector can be either a string, a stringList, or a dictionary. The following example searches for three files and illustrates different ways to specify selectors: \code selectors: [ // 1st file with a single name "header.h", // 2nd file with possible name variants ["config.h", "foo-config.h", "bar-config.h"], // 3rd file with possible name and suffix variants {names: ["footk", "footk-version"], nameSuffixes: [".h", ".hpp"]} ] \endcode */ qbs-src-2.6.1/doc/reference/items/probe/dmc-probe.qdoc0000644000175100001660000000543614776170045022133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype DmcProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.DmcProbe \inherits PathProbe \brief Collects Digital Mars toolchain compiler information. \since Qbs 1.13 \internal Detects the version, supported architecture, the platform endianness, and other stuff for the specified compiler executable from the \l{https://www.digitalmars.com/}{Digital Mars} toolchain. */ /*! \qmlproperty string DmcProbe::compilerFilePath An input property which is a full path to the Digital Mars compiler executable. \nodefaultvalue */ /*! \qmlproperty string DmcProbe::architecture Detected architecture of the target platform's processor. The possible values are \c "x86" and \c "x86_16". \nodefaultvalue */ /*! \qmlproperty string DmcProbe::targetPlatform Detected target platform. The possible values are \c "windows" and \c "dos". \nodefaultvalue */ /*! \qmlproperty int DmcProbe::versionMajor Detected major compiler version. \nodefaultvalue */ /*! \qmlproperty int DmcProbe::versionMinor Detected minor compiler version. \nodefaultvalue */ /*! \qmlproperty int DmcProbe::versionPatch Detected patch compiler version. \nodefaultvalue */ /*! \qmlproperty stringList DmcProbe::includePaths Detected compiler include paths. \nodefaultvalue */ /*! \qmlproperty var DmcProbe::compilerDefinesByLanguage Detected set of compiler pre-defined macros depending on the \c "C" or \c "C++" language. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/probe/sdcc-probe.qdoc0000644000175100001660000000477214776170045022306 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype SdccProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.SdccProbe \inherits PathProbe \brief Collects SDCC toolchain compiler information. \since Qbs 1.14 \internal Detects the version, supported architecture and the platform endianness of the specified compiler executable file from the \l{http://sdcc.sourceforge.net/}{SDCC} toolchain. */ /*! \qmlproperty string SdccProbe::compilerFilePath An input property which is a full path to the SDCC compiler executable file. \nodefaultvalue */ /*! \qmlproperty string SdccProbe::architecture Detected architecture of the target platform's processor. The possible values are \c "mcs51", \c "stm8", and \c "hcs8". \nodefaultvalue */ /*! \qmlproperty string SdccProbe::endianness Detected endianness of the target platform's processor architecture. The possible values are \c "little". \nodefaultvalue */ /*! \qmlproperty int SdccProbe::versionMajor Detected major compiler version. \nodefaultvalue */ /*! \qmlproperty int SdccProbe::versionMinor Detected minor compiler version. \nodefaultvalue */ /*! \qmlproperty int SdccProbe::versionPatch Detected patch compiler version. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/probe/keil-probe.qdoc0000644000175100001660000000501214776170045022302 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype KeilProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.KeilProbe \inherits PathProbe \brief Collects KEIL toolchain compiler information. \since Qbs 1.13 \internal Detects the version, supported architecture and the platform endianness of the specified compiler executable file from the \l{https://www.keil.com/}{KEIL} toolchain. */ /*! \qmlproperty string KeilProbe::compilerFilePath An input property which is a full path to the KEIL compiler executable file. \nodefaultvalue */ /*! \qmlproperty string KeilProbe::architecture Detected architecture of the target platform's processor. The possible values are \c "arm", \c "mcs51", \c "mcs251" and \c "c166". \nodefaultvalue */ /*! \qmlproperty string KeilProbe::endianness Detected endianness of the target platform's processor architecture. The possible values are \c "big" or \c "little". \nodefaultvalue */ /*! \qmlproperty int KeilProbe::versionMajor Detected major compiler version. \nodefaultvalue */ /*! \qmlproperty int KeilProbe::versionMinor Detected minor compiler version. \nodefaultvalue */ /*! \qmlproperty int KeilProbe::versionPatch Detected patch compiler version. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/probe/pkgconfig-probe.qdoc0000644000175100001660000001566214776170045023341 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype PkgConfigProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.PkgConfigProbe \brief Retrieves the information about installed packages using the pkg-config binary. This probe takes the package name or the list of package names as input and returns the information that is required to compile and link using those packages. Usually, you can simply use a Depends item as described in \l{How do I build against libraries that provide pkg-config files?}. Alternatively, the probe can be used directly as follows: \code CppApplication { name: project.name Probes.PkgConfigProbe { id: pkgConfig name: "QtCore" minVersion: '4.0.0' maxVersion: '5.99.99' } files: 'main.cpp' cpp.defines : pkgConfig.defines cpp.includePaths: pkgConfig.includePaths cpp.dynamicLibraries: pkgConfig.libraries cpp.libraryPaths: pkgConfig.libraryPaths cpp.commonCompilerFlags: pkgConfig.compilerFlags cpp.linkerFlags: pkgConfig.linkerFlags } \endcode */ /*! \qmlproperty string PkgConfigProbe::sysroot This property sets the value of the \c PKG_CONFIG_SYSROOT_DIR environment variable passed to the \c pkg-config binary. This variable modifies -I and -L flags to use the directories located in target sysroot. This property is useful when cross-compiling packages that use \c pkg-config to determine CFLAGS and LDFLAGS. For example, if \c sysroot is set to \c /var/target, a \c -I/usr/include/libfoo will become \c -I/var/target/usr/include/libfoo. \defaultvalue \c qbs.sysroot */ /*! \qmlproperty string PkgConfigProbe::executable The name of or the path to the pkg-config executable. \defaultvalue "pkg-config" */ /*! \qmlproperty string PkgConfigProbe::name The name this probe. This property is used as \l{PkgConfigProbe::packageNames}{PkgConfigProbe.packageNames} value by default. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::packageNames The list of package names to pass to the pkg-config executable. For each package, pkg-config will return the information required to compile and link to this package. \defaultvalue [\l{PkgConfigProbe::name}{PkgConfigProbe.name}] */ /*! \qmlproperty string PkgConfigProbe::minVersion The minimum version of the required package. If set, pkg-config will ignore packages with version less than the value of this property. \nodefaultvalue */ /*! \qmlproperty string PkgConfigProbe::exactVersion The exact version of the required package. If set, pkg-config will ignore packages with version that is not equal to the value of this property. \nodefaultvalue */ /*! \qmlproperty string PkgConfigProbe::maxVersion The maximum version of the required package. If set, pkg-config will ignore packages with version greater than the value of this property. \nodefaultvalue */ /*! \qmlproperty bool PkgConfigProbe::forStaticBuild If \c true, pkg-config will return linker flags for a static linking instead of dynamic. \defaultvalue \c false */ /*! \qmlproperty stringList PkgConfigProbe::libDirs List of full, non-sysrooted paths where pkg-config should search for .pc files. This overrides the built-in path (which is usually /usr/lib/pkgconfig). This property sets the value of the \c PKG_CONFIG_LIBDIR environment variable passed to the \c pkg-config binary. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::cflags \internal This property contains the unparsed output from "pkg-config --cflags" call. Usually, you should use \l{PkgConfigProbe::defines}{PkgConfigProbe.defines}, \l{PkgConfigProbe::includePaths}{PkgConfigProbe.includePaths} and \l{PkgConfigProbe::compilerFlags}{PkgConfigProbe.compilerFlags} properties instead. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::libs \internal This property contains the unparsed output from "pkg-config --libs" call. Usually, you should use \l{PkgConfigProbe::libraries}{PkgConfigProbe.libraries}, \l{PkgConfigProbe::libraryPaths}{PkgConfigProbe.libraryPaths} and \l{PkgConfigProbe::linkerFlags}{PkgConfigProbe.linkerFlags} properties instead. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::defines This output property contains the list of defines that should be passed to a compiler when using requested package. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::libraries This output property contains the list of library names that should be passed to a linker when using requested package. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::libraryPaths This output property contains the list of library paths that should be passed to a linker when using requested package. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::includePaths This output property contains the list of include paths that should be passed to a compiler when using requested package. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::compilerFlags This output property contains the list of flags that should be passed to a compiler when using requested package. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::linkerFlags This output property contains the list of flags that should be passed to a linker when using requested package. \nodefaultvalue */ /*! \qmlproperty stringList PkgConfigProbe::modversion This output property contains the version of the found package. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/probe/watcom-probe.qdoc0000644000175100001660000000622414776170045022656 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype WatcomProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.WatcomProbe \inherits PathProbe \brief Collects Oopen Watcom toolchain compiler information. \since Qbs 1.22 \internal Detects the version, supported architecture, the platform endianness, and other stuff for the specified compiler executable from the \l{https://github.com/open-watcom}{Open Watcom} toolchain. */ /*! \qmlproperty string WatcomProbe::compilerFilePath An input property which is a full path to the Digital Mars compiler executable. \nodefaultvalue */ /*! \qmlproperty string WatcomProbe::architecture Detected architecture of the target platform's processor. The possible values are \c "x86" and \c "x86_16". \nodefaultvalue */ /*! \qmlproperty string WatcomProbe::endianness Detected endianness of the target platform's processor architecture. The possible values are \c "big" and \c "little". \nodefaultvalue */ /*! \qmlproperty string WatcomProbe::targetPlatform Detected target platform. The possible values are \c "windows", \c "linux", \c "os2" and \c "dos". \nodefaultvalue */ /*! \qmlproperty int WatcomProbe::versionMajor Detected major compiler version. \nodefaultvalue */ /*! \qmlproperty int WatcomProbe::versionMinor Detected minor compiler version. \nodefaultvalue */ /*! \qmlproperty int WatcomProbe::versionPatch Detected patch compiler version. \nodefaultvalue */ /*! \qmlproperty stringList WatcomProbe::includePaths Detected compiler include paths. \nodefaultvalue */ /*! \qmlproperty var WatcomProbe::compilerDefinesByLanguage Detected set of compiler pre-defined macros depending on the \c "C" or \c "C++" language. \nodefaultvalue */ /*! \qmlproperty var WatcomProbe::environment Detected compiler run environment. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/probe/include-probe.qdoc0000644000175100001660000000350614776170045023007 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype IncludeProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.IncludeProbe \inherits PathProbe \brief Locates header files outside the project. This is the convenience item that searches for files in "include" directories. For example, IncludeProbe can be used to search for a zlib header as follows: \code import qbs.Probes CppApplication { Probes.IncludeProbe { id: zlibProbe names: "zlib.h" } cpp.includePaths: zlibProbe.found ? [zlibProbe.path] : [] files: 'main.cpp' } \endcode */ qbs-src-2.6.1/doc/reference/items/probe/framework-probe.qdoc0000644000175100001660000000433014776170045023355 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype FrameworkProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.FrameworkProbe \inherits PathProbe \brief Locates \macos frameworks outside the project. Finds \macos frameworks that have the specified file names. By default, FrameworkProbe searches for frameworks in \c ~/Library/Frameworks, \c /usr/local/lib, \c /Library/Frameworks, and in \c /System/Library/Frameworks. Also, if \l {qbs::sysroot}{qbs.sysroot} is specified (for example, when compiling using XCode SDK), the probe searches in the \c sysroot/System/Library/Frameworks folder first. For example, a simple FrameworkProbe that searches for the Foundation framework can be used as follows: \code import qbs.Probes Product { Depends { name: "cpp"; } Probes.FrameworkProbe { id: foundationProbe names: ["Foundation"] } cpp.frameworkPaths: foundationProbe.found ? [foundationProbe.path] : [] } \endcode */ qbs-src-2.6.1/doc/reference/items/probe/iar-probe.qdoc0000644000175100001660000000527114776170045022140 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype IarProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.IarProbe \inherits PathProbe \brief Collects IAR toolchain compiler information. \since Qbs 1.13 \internal Detects the version, supported architecture and the platform endianness of the specified compiler executable file from the \l{https://www.iar.com/}{IAR} toolchain. */ /*! \qmlproperty string IarProbe::compilerFilePath An input property which is a full path to the IAR compiler executable file. \nodefaultvalue */ /*! \qmlproperty string IarProbe::architecture Detected architecture of the target platform's processor. The possible values are \c "arm", \c "mcs51", \c "avr", \c "avr32", \c "stm8", \c "riscv", \c "rl78", \c "rx", \c "rh850", \c "v850", \c "78k", \c "sh", \c "r32c", \c "m32c", \c "m16c", \c "msp430", \c "hcs12", \c "hcs8", \c "m68k", and \c "cr16". \nodefaultvalue */ /*! \qmlproperty string IarProbe::endianness Detected endianness of the target platform's processor architecture. The possible values are \c "big" or \c "little". \nodefaultvalue */ /*! \qmlproperty int IarProbe::versionMajor Detected major compiler version. \nodefaultvalue */ /*! \qmlproperty int IarProbe::versionMinor Detected minor compiler version. \nodefaultvalue */ /*! \qmlproperty int IarProbe::versionPatch Detected patch compiler version. \nodefaultvalue */ qbs-src-2.6.1/doc/reference/items/probe/conanfile-probe.qdoc0000644000175100001660000002212614776170045023321 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Richard Weickelt ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype ConanfileProbe \inqmlmodule QbsProbes \ingroup list-of-items \keyword QML.ConanfileProbe \brief Extracts information about dependencies from a Conan recipe file. The \c ConanfileProbe interfaces \QBS to the \l{https://conan.io/}{Conan package manager}. It runs \l{https://docs.conan.io/en/latest/reference/commands/consumer/install.html}{conan install} on a Conan recipe file such as \c conanfile.py or \c conanfile.txt and extracts all available meta information about package dependencies using the \l{https://docs.conan.io/en/latest/reference/generators/json.html}{json generator}. The output may be used to set up \l{Profile} items or module properties in products. \c ConanfileProbe can also be used to run other Conan generators and to retrieve their output. \section1 Examples In the following examples we assume that our project contains a \c conanfile.py. This file describes all dependencies of our project. The dependency packages are expected to export meta information to be consumed by our project. \section2 Using ConanfileProbe with Conan Module Provider Conan 2.6 has a built-in \l{https://docs.conan.io/2/reference/tools/qbs/qbsdeps.html#qbsdeps}{QbsDeps} generator that creates JSON files suitable for consumption by the \l{conan}{conan} module provider. Use it to access dependencies. \qml import qbs.Probes Project { Probes.ConanfileProbe { id: conanProbe conanfilePath: project.sourceDirectory + "/conanfile.py" generators: "QbsDeps" } CppApplication { type: "application" files: "main.cpp" qbsModuleProviders: "conan" moduleProviders.conan.installDirectory: conanProbe.generatedFilesPath Depends { name: "mylib" } } } \endqml \section2 Including Files Generated by Conan \note This example does not apply to Conan 2.0, or newer. Conan 1 has a built-in \l{https://docs.conan.io/en/latest/reference/generators/qbs.html}{qbs generator} that creates a project file containing dummy products. This is the easiest way to access dependencies, but also the least flexible one. It requires each Conan package to export correct meta information and works only if the dependency is a library. \qml import qbs.Probes Project { Probes.ConanfileProbe { id: conan conanfilePath: project.sourceDirectory + "/conanfile.py" generators: "qbs" } references: conan.generatedFilesPath + "/conanbuildinfo.qbs" CppApplication { type: "application" files: "main.cpp" Depends { name: "mylib" } } } \endqml \section2 Setting Module Properties in Products \note This example does not apply to Conan 2.0, or newer. When a product depends on a Conan package that does not have a dedicated \l{List of Modules}{module}, package meta information may be directly fed into the \l{cpp} module. This approach is very flexible. \qml import qbs.Probes CppApplication { Probes.ConanfileProbe { id: conan conanfilePath: product.sourceDirectory + "/conanfile.py" options: ({opt1: "True"; opt2: "TheValue"}) } cpp.includePaths: conan.dependencies["myLib"].include_paths cpp.libraryPaths: conan.dependencies["myLib"].lib_paths cpp.dynamicLibraries: conan.dependencies["mylib"].libs } \endqml \section2 Setting Up a Profile \note This example does not apply to Conan 2.0, or newer. When multiple products depend on one or more Conan packages, the dependency information may be combined in a \l{Profile}. This is especially useful when \QBS modules are available for some of the packages, but some of their properties need to be initialized. Otherwise, it would have to be done manually in global profiles. \qml import qbs.Probes Project { Probes.ConanfileProbe { id: conan conanfilePath: project.sourceDirectory + "/conanfile.py" } Profile { name: "arm-gcc" cpp.toolchainInstallPath: conan.dependencies["arm-none-eabi-gcc"].rootpath + "/bin" cpp.toolchainPrefix: "arm-linux-gnueabi-" qbs.toolchainType: "gcc" } } \endqml This allows fully automated dependency management, including compiler toolchains and is very useful when teams work in heterougeneous environments. */ /*! \qmlproperty stringList ConanfileProbe::additionalArguments Additional command line arguments that are appended to the \c{conan install} command. \defaultvalue [] */ /*! \qmlproperty path ConanfileProbe::conanfilePath Path to a \c conanfile.py or \c conanfile.txt that is used by this probe. This property cannot be set at the same time as \l{ConanfileProbe::}{packageReference}. \nodefaultvalue */ /*! \qmlproperty var ConanfileProbe::dependencies This property contains the same information as \l{ConanfileProbe::}{json}.dependencies, but instead of an array, \c dependencies is a map with package names as keys for convenient access. \note This property does not apply to Conan 2.0, or newer. \readonly \nodefaultvalue */ /*! \qmlproperty path ConanfileProbe::executable The name of or the path to the Conan executable. \defaultvalue "conan.exe" on Windows, "conan" otherwise */ /*! \qmlproperty path ConanfileProbe::generatedFilesPath The path of the folder where Conan generators store their files. Each instance of this probe creates a unique folder under \l{Project::buildDirectory}{Project.buildDirectory}. The folder name is a hash of the arguments supplied to \c{conan install}. \readonly \nodefaultvalue */ /*! \qmlproperty stringList ConanfileProbe::generators Conan generators to be executed by this probe. When using Conan 2.x, \l{https://docs.conan.io/2/reference/tools/qbs/qbsdeps.html#qbsdeps}{QbsDeps} generator is added by default. When using Conan 1.x, the \l{https://docs.conan.io/en/latest/reference/generators/json.html}{JSON generator} is always enabled. All generated files are written to the \l{ConanfileProbe::generatedFilesPath}{generatedFilesPath} folder. \sa {https://docs.conan.io/en/latest/reference/generators.html}{Available generators} \autodetected */ /*! \qmlproperty var ConanfileProbe::json The parsed output of Conan's \l{https://docs.conan.io/en/latest/reference/generators/json.html}{JSON generator} as a JavaScript object. \note This property does not apply to Conan 2.0, or newer. \readonly \nodefaultvalue */ /*! \qmlproperty var ConanfileProbe::options Options applied to \c{conan install} via the \c{-o} flag. This property is an object in the form \c{key:value}. Example: \qml options: ({someOpt: "True", someOtherOpt: "TheValue"}) \endqml \nodefaultvalue */ /*! \qmlproperty string ConanfileProbe::packageReference Reference of a Conan package in the form \c{name/version@user/channel}. Use this property if you want to probe an existing package in the local cache or on a remote. This property cannot be set at the same time as \l{ConanfileProbe::}{conanfilePath}. \nodefaultvalue */ /*! \qmlproperty var ConanfileProbe::settings Settings applied to \c{conan install} via the \c{-s} flag. This property is an object in the form \c{key:value}. Example: \qml settings: ({os: "Linux", compiler: "gcc"}) \endqml \nodefaultvalue */ /*! \qmlproperty var ConanfileProbe::verbose Set to \c{true} to print all output of `conan install`. If this property is \c{false} only error output will be printed. \defaultvalue \c{false} */ qbs-src-2.6.1/doc/reference/module-providers/0000755000175100001660000000000014776170045020453 5ustar runnerdockerqbs-src-2.6.1/doc/reference/module-providers/conan-module-provider.qdoc0000644000175100001660000000652014776170045025537 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype conan \inqmlmodule QbsModuleProviders \since 2.4 \brief Module provider for the Conan package manager. This module provider allows integration with the \l{https://conan.io}{Conan} package manager. \section1 Prerequisites In order to use this provider, you will need \c Conan version 2.5.0 or higher. Earlier versions do not have the \c QbsDeps generator. \section1 Example For details on how to setup a project to use with Conan, see the \ l{https://github.com/qbs/qbs/blob/master/examples/protobuf/addressbook_conan}{addressbook_conan} folder in examples. First, you will need a \l{https://docs.conan.io/2/reference/conanfile_txt.html}{conanfile} as shown below. \code [requires] protobuf/3.21.12 [tool_requires] protobuf/3.21.12 [generators] QbsDeps \endcode We use the text version for simplicity, but you can use the Python conanfile as well. Next, set the \l{Product::qbsModuleProviders}{qbsModuleProviders} property to \c "conan": \snippet ../examples/protobuf/addressbook_conan/addressbook_conan.qbs 0 Install Conan dependencies and run the QbsDeps generator from the \c addressbook_conan dir: \code $ conan install . -g=QbsDeps --output-folder=build --build missing \endcode This will create the \c{./build/qbs-deps} directory contaning files for provider. Now you can pass the conan install directory to the provider: \code $ qbs moduleProviders.conan.installDirectory:build \endcode You should see the following output if everything is correct: \code Build graph does not yet exist for configuration 'default'. Starting from scratch. Resolving project for configuration default Setting up Conan module 'protobuflib' Setting up Conan module 'zlib' ... Build done for configuration default. \endcode */ /*! \qmlproperty string conan::installDirectory The path to the conan install installDirectory. \QBS searches for files created by the QbsDeps generator in that directory. If not set, the provider will not be run. \defaultvalue undefined */ qbs-src-2.6.1/doc/reference/module-providers/qbspkgconfig-module-provider.qdoc0000644000175100001660000001107714776170045027121 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype qbspkgconfig \inqmlmodule QbsModuleProviders \since 1.20 \brief Module provider based on the qbspkg-config library. \QBS uses a built-in parser of the \c{*.pc} files and does not require the presence of the \c pkg-config tool in the system. However, if the \c pkg-config tool is present, \QBS will use the same libDirs as the system pkg-config uses by default; otherwise, a built-in list of paths is used. In order to enable usage of this provider in your Product, set the \l{Product::qbsModuleProviders}{qbsModuleProviders} property as shown in the example below: \snippet ../examples/pkgconfig-provider/pkgconfig-provider.qbs 0 */ /*! \qmlproperty string qbspkgconfig::executableFilePath The path to the \c {pkg-config} executable. If not set, the pkg-config from PATH is used. \defaultvalue undefined */ /*! \qmlproperty stringList qbspkgconfig::libDirs Set this if you need to overwrite the default search directories. \note You do not need to set this for cross-compilation in order to point to the sysroot. \QBS does that for you. This property is the equivalent of the \c{PKG_CONFIG_LIBDIR} variable for the \c{pkg-config} tool. \nodefaultvalue */ /*! \qmlproperty stringList qbspkgconfig::extraPaths Set this if you need to add extra search directories. This property is the equivalent of the \c{PKG_CONFIG_PATH} variable for the \c{pkg-config} tool. \nodefaultvalue */ /*! \qmlproperty bool qbspkgconfig::staticMode If this property is \c true, then \QBS will include "private" libs and dependencies of the package. This property is the equivalent of the \c{--static} option for the \c{pkg-config} tool. Set this if your product is to be linked statically. \defaultvalue \c false */ /*! \qmlproperty bool qbspkgconfig::definePrefix If this property is \c true, then \QBS will override the ${prefix} variable in the packages with a value that is guessed based on the location of the .pc file. This option corresponds to the \c --define-prefix / \c --dont-define-prefix command line options of the \c pkg-config tool. \defaultvalue \c true on Windows, \c false otherwise */ /*! \qmlproperty stringList qbspkgconfig::executableNames The names of the \c pkg-config executable to search for. Note that since newer distributions use \l{http://pkgconf.org}{pkgconf} by default, it has higher priority over \c pkg-config. \defaultvalue \c{["pkgconf", "pkg-config"]} */ /*! \qmlproperty path qbspkgconfig::sysroot Set this property if you need to overwrite the default search sysroot path used by \c pkg-config. This can be useful if \c pkg-config files are located in the directory other than qbs.sysroot. This is the case on macOS platform - all XCode profiles are sysrooted to the SDK directory, but \c pkg-config is typically intalled using Brew and resides in the \c /usr/local directory. Setting this property to \c undefined or empty (\c "") value will use pkg-config's default search paths: \code qbs resolve moduleProviders.qbspkgconfig.sysroot:undefined \endcode This property is the equivalent of the \c{PKG_CONFIG_SYSROOT_DIR} variable for the \c{pkg-config} tool. \defaultvalue \c "" on macOS, \c qbs.sysroot on other platforms */ qbs-src-2.6.1/doc/reference/module-providers/qt-module-provider.qdoc0000644000175100001660000000575014776170045025071 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \qmltype Qt \inqmlmodule QbsModuleProviders \brief Module provider that generates Qt modules. Looking up a Qt installation happens via a \l{Module Providers}{module provider}. By default, if a dependency to a Qt module is encountered, \QBS collects all Qt installations it can find. This lookup happens by searching for \c qmake executables in the \c PATH environment variable. Alternatively, you can explicitly tell \QBS which Qt installations it should consider by setting the qmakeFilePaths module provider \l{Parameterizing Module Providers}{property}. In that case, the environment will be ignored. For instance, with the following Linux command line, \QBS will build the project against a custom Qt instead of the standard one in \c{/usr/bin}: \code $ qbs moduleProviders.Qt.qmakeFilePaths:/opt/myqt/bin/qmake \endcode You can also set the module provider property in a profile. The simplest way to do this is via the \l setup-qt tool. For examples of how to use this tool, see the \l{Managing Qt Versions} section. This provider is activated automatically when encountering a dependency on the Qt module and the \l{Product::qbsModuleProviders}{qbsModuleProviders} property is \c undefined: \code CppApplication { Depends { name: "Qt.core" } files: "main.cpp" } \endcode Alternatively, you can activate this provider explicitly via the \l{Product::qbsModuleProviders}{qbsModuleProviders} property: \code CppApplication { Depends { name: "Qt.core" } files: "main.cpp" qbsModuleProviders: "Qt" } \endcode */ /*! \qmlproperty stringList Qt::qmakeFilePaths List of paths to \c qmake executables. \defaultvalue undefined */ qbs-src-2.6.1/doc/man/0000755000175100001660000000000014776170045013770 5ustar runnerdockerqbs-src-2.6.1/doc/man/see-also.h2m0000644000175100001660000000025514776170045016112 0ustar runnerdocker[SEE ALSO] For detailed help on a command, use the .B help command. For instance: .IP qbs help build .PP The full documentation for .B qbs is available at . qbs-src-2.6.1/doc/man/man.qbs0000644000175100001660000000467214776170045015263 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.ModUtils import qbs.Probes import qbs.Utilities Product { name: "qbs man page" type: ["manpage"] Depends { productTypes: ["qbsapplication"]; condition: updateManPage } Depends { name: "qbsbuildconfig" } property bool updateManPage: false property string help2ManFilePath: help2ManProbe.filePath Group { name: "man page" files: ["qbs.1"] qbs.install: qbsbuildconfig.installManPage qbs.installDir: "share/man/man1" } Group { name: "additional sections" files: ["see-also.h2m"] fileTags: ["man.section"] } Rule { condition: updateManPage multiplex: true // TODO: Remove in 1.14. explicitlyDependsOn: ["application"] property stringList explicitlyDependsOnFromDependencies: ["application"] inputs: ["man.section"] Artifact { filePath: "qbs.1" fileTags: ["manpage"] } prepare: { var help2ManExe = product.help2ManFilePath; if (!help2ManExe) throw "Cannot update man page: help2man not available"; if (Utilities.versionCompare(product.qbs.version, "1.9") < 0) throw "Cannot update man page: qbs >= 1.9 required"; var qbsApp; for (var i = 0; i < explicitlyDependsOn.application.length; ++i) { var artifact = explicitlyDependsOn.application[i]; if (artifact.product.name === "qbs_app") qbsApp = ModUtils.artifactInstalledFilePath(artifact); } var args = [qbsApp, "-o", output.filePath, "--no-info", "--name=the Qbs build tool"]; var sections = inputs ? inputs["man.section"] : []; for (var i = 0; i < sections.length; ++i) args.push("--include=" + sections[i].filePath); var help2ManCmd = new Command(help2ManExe, args); help2ManCmd.description = "creating man page"; var copyCmd = new JavaScriptCommand(); copyCmd.silent = true; copyCmd.sourceCode = function() { File.copy(output.filePath, FileInfo.joinPaths(product.sourceDirectory, output.fileName)); } return [help2ManCmd, copyCmd]; } } Probes.BinaryProbe { id: help2ManProbe names: ["help2man"] } } qbs-src-2.6.1/doc/man/CMakeLists.txt0000644000175100001660000000020014776170045016520 0ustar runnerdockerif (QBS_INSTALL_MAN_PAGE) install(FILES qbs.1 DESTINATION ${QBS_RESOURCES_INSTALL_DIR}/man/man1 COMPONENT qbs_docs) endif() qbs-src-2.6.1/doc/man/qbs.10000644000175100001660000000321314776170045014636 0ustar runnerdocker.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.7. .TH QBS "1" "December 2018" "qbs 1.12.3" "User Commands" .SH NAME qbs \- the Qbs build tool .SH SYNOPSIS .B qbs [\fI\,command\/\fR] [\fI\,command parameters\/\fR] .SH DESCRIPTION Qbs 1.12.3, a cross\-platform build tool. .SS "Built-in commands:" .TP build Build (parts of) a project. This is the default command. .TP clean Remove the files generated during a build. .TP dump\-nodes\-tree Dumps the nodes in the build graph to stdout. .TP generate Generate project files for another build tool. .TP help Show general or command\-specific help. .TP install Install (parts of) a project. .TP list\-products Lists all products in the project, including sub\-projects. .TP resolve Resolve a project without building it. .TP run Run an executable generated by building a project. .TP shell Open a shell with a product's environment. .TP show\-version Print the Qbs version number to stdout. .TP status Show the status of files in the project directory. .TP update\-timestamps Mark the build as up to date. .SS "Auxiliary commands:" .TP config This tool manages qbs settings. .TP config\-ui This tool displays qbs settings in a GUI. .TP create\-project This tool creates a qbs project from an existing source tree. .TP setup\-android This tool creates qbs profiles from Android SDK and NDK installations. .TP setup\-qt This tool creates qbs profiles from Qt versions. .TP setup\-toolchains This tool creates qbs profiles from toolchains. .SH "SEE ALSO" For detailed help on a command, use the .B help command. For instance: .IP qbs help build .PP The full documentation for .B qbs is available at . qbs-src-2.6.1/doc/CMakeLists.txt0000644000175100001660000000157214776170045015762 0ustar runnerdockerset(_DOC_SOURCES ../README.md ../CONTRIBUTING.md classic.css external-resources.qdoc fixnavi.pl howtos.qdoc qbs.qdoc qbs-online.qdocconf config/style/qt5-sidebar.html ) file(GLOB_RECURSE _DOC_APPENDIX_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/appendix/*") file(GLOB_RECURSE _DOC_REFERENCE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/reference/*") file(GLOB_RECURSE _DOC_TEMPLATES_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/templates/*") file(GLOB_RECURSE _DOC_IMAGES_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/images/*") file(GLOB_RECURSE _DOC_TARGETS_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/targets/*") add_qbs_documentation( "qbs.qdocconf" SOURCES ${_DOC_SOURCES} ${_DOC_APPENDIX_SOURCES} ${_DOC_REFERENCE_SOURCES} ${_DOC_TEMPLATES_SOURCES} ${_DOC_IMAGES_SOURCES} ${_DOC_TARGETS_SOURCES} ) add_subdirectory(man) qbs-src-2.6.1/doc/qbs.qdocconf0000644000175100001660000000015114776170045015515 0ustar runnerdockerinclude(config/qbs-project.qdocconf) include($QT_INSTALL_DOCS/global/qt-html-templates-offline.qdocconf) qbs-src-2.6.1/doc/appendix/0000755000175100001660000000000014776170045015025 5ustar runnerdockerqbs-src-2.6.1/doc/appendix/json-api.qdoc0000644000175100001660000011213014776170045017413 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage porting-to-qbs.html \nextpage attributions.html \page json-api.html \title Appendix C: The JSON API This API is the recommended way to provide \QBS support to an IDE. It is accessible via the \l{session} command. \section1 Packet Format All information is exchanged via \e packets, which have the following structure: \code packet = "qbsmsg:" [] \endcode First comes a fixed string indentifying the start of a packet, followed by the size of the actual data in bytes. After that, further meta data might follow. There is none currently, but future extensions might add some. A line feed character marks the end of the meta data section and is followed immediately by the payload, which is a single JSON object encoded in Base64 format. We call this object a \e message. \section1 Messages The message data is UTF8-encoded. Most messages are either \e requests or \e replies. Requests are messages sent to \QBS via the session's standard input channel. Replies are messages sent by \QBS via the session's standard output channel. A reply always corresponds to one specific request. Every request (with the exception of the \l{quit-message}{quit request}) expects exactly one reply. A reply implies that the requested operation has finished. At the very least, it carries information about whether the operation succeeded, and often contains additional data specific to the respective request. Every message object has a \c type property, which is a string that uniquely identifies the message type. All requests block the session for other requests, including those of the same type. For instance, if client code wishes to restart building the project with different parameters, it first has to send a \l{cancel-message}{cancel} request, wait for the current build job's reply, and only then can it request another build. The only other message beside \l{cancel-message}{cancel} that can legally be sent while a request is currently being handled is the \l{quit-message}{quit} message. A reply object may carry an \c error property, indicating that the respective operation has failed. If this property is not present, the request was successful. The format of the \c error property is described \l{ErrorInfo}{here}. In the remainder of this page, we describe the structure of all messages that can be sent to and received from \QBS, respectively. The property tables may have a column titled \e Mandatory, whose values indicate whether the respective message property is always present. If this column is missing, all properties of the respective message are mandatory, unless otherwise noted. \section1 The \c hello Message This message is sent by \QBS exactly once, right after the session was started. It is the only message from \QBS that is not a response to a request. The value of the \c type property is \c "hello", the other properties are as follows: \table \header \li Property \li Type \row \li api-level \li int \row \li api-compat-level \li int \row \li lsp-socket \li string \endtable The value of \c api-level is increased whenever the API is extended, for instance by adding new messages or properties. The value of \c api-compat-level is increased whenever incompatible changes are being done to this API. A tool written for API level \c n should refuse to work with a \QBS version with an API compatibility level greater than \c n, because it cannot guarantee proper behavior. This value will not change unless it is absolutely necessary. The value of \c api-compat-level is always less than or equal to the value of \c api-level. The value of \c lsp-socket is a path to a local domain socket (on Unix) or a named pipe (on Windows). It provides a server implementing the \l{https://microsoft.github.io/language-server-protocol}{Language Server Protocol}. \section1 Resolving a Project To instruct \QBS to load a project from disk, a request of type \c resolve-project is sent. The other properties are: \table \header \li Property \li Type \li Mandatory \row \li build-root \li \l FilePath \li yes \row \li configuration-name \li string \li no \row \li data-mode \li \l DataMode \li no \row \li deprecation-warning-mode \li string \li no \row \li dry-run \li bool \li no \row \li environment \li \l Environment \li no \row \li error-handling-mode \li string \li no \row \li force-probe-execution \li bool \li no \row \li log-time \li bool \li no \row \li log-level \li \l LogLevel \li no \row \li max-job-count \li int \li no \row \li module-properties \li list of strings \li no \row \li overridden-properties \li object \li no \row \li project-file-path \li FilePath \li if resolving from scratch \row \li restore-behavior \li string \li no \row \li settings-directory \li string \li no \row \li top-level-profile \li string \li no \row \li wait-lock-build-graph \li bool \li no \endtable The \c environment property defines the environment to be used for resolving the project, as well as for all subsequent \QBS operations on this project. The \c error-handling-mode specifies how \QBS should deal with issues in project files, such as assigning to an unknown property. The possible values are \c "strict" and \c "relaxed". In strict mode, \QBS will immediately abort and set the reply's \c error property accordingly. In relaxed mode, \QBS will continue to resolve the project if possible. A \l{warning-message}{warning message} will be emitted for every error that was encountered, and the reply's \c error property will \e not be set. The default error handling mode is \c "strict". If the \c log-time property is \c true, then \QBS will emit \l log-data messages containing information about which part of the operation took how much time. The \c module-properties property lists the names of the module properties which should be contained in the \l{ProductData}{product data} that will be sent in the reply message. For instance, if the project to be resolved is C++-based and the client code is interested in which C++ version the code uses, then \c module-properties would contain \c{"cpp.cxxLanguageVersion"}. Properties that have the value \c undefined will not be sent. The \c overridden-properties property is used to override the values of module, product or project properties. The possible ways to specify keys are described \l{Overriding Property Values from the Command Line}{here}. The \c restore-behavior property specifies if and how to make use of an existing build graph. The value \c "restore-only" indicates that a build graph should be loaded from disk and used as-is. In this mode, it is an error if the build graph file does not exist. The value \c "resolve-only" indicates that the project should be resolved from scratch and that an existing build graph should be ignored. In this mode, it is an error if the \c "project-file-path" property is not present. The default value is \c "restore-and-track-changes", which uses an existing build graph if possible and re-resolves the project if no build graph was found, if the parameters are different from the ones used when the project was last resolved, or if other relevant changes are detected, such as updated time stamps in a project file. The \c "restore-and-resolve" value is similar to \c "restore-and-track-changes", but also re-resolves the project if no changes were detected. The \c top-level-profile property specifies which \QBS profile to use for resolving the project. It corresponds to the \c profile key when using the \l resolve command. All other properties correspond to command line options of the \l resolve command, and their semantics are described there. When the project has been resolved, \QBS will reply with a \c project-resolved message. The possible properties are: \table \header \li Property \li Type \li Mandatory \row \li error \li \l ErrorInfo \li no \row \li project-data \li \l TopLevelProjectData \li no \endtable The \c error-info property is present if and only if the operation failed. The \c project-data property is present if and only if the conditions stated by the request's \c data-mode property are fulfilled. All other project-related requests need a resolved project to operate on. If there is none, they will fail. There is at most one resolved project per session. If client code wants to open several projects or one project in different configurations, it needs to start additional sessions. \section1 Building a Project To build a project, a request of type \c build-project is sent. The other properties, none of which are mandatory, are listed below: \table \header \li Property \li Type \row \li active-file-tags \li string list \row \li changed-files \li \l FilePath list \row \li check-outputs \li bool \row \li check-timestamps \li bool \row \li clean-install-root \li bool \row \li data-mode \li \l DataMode \row \li dry-run \li bool \row \li command-echo-mode \li string \row \li enforce-project-job-limits \li bool \row \li files-to-consider \li \l FilePath list \row \li install \li bool \row \li job-limits \li list of objects \row \li keep-going \li bool \row \li log-level \li \l LogLevel \row \li log-time \li bool \row \li max-job-count \li int \row \li module-properties \li list of strings \row \li products \li list of strings or \c "all" \endtable All boolean properties except \c install default to \c false. The \c active-file-tags and \c files-to-consider are used to limit the build to certain output tags and/or source files. For instance, if only C/C++ object files should get built, then \c active-file-tags would be set to \c "obj". The objects in a \c job-limits array consist of a string property \c pool and an int property \c limit. If the \c log-time property is \c true, then \QBS will emit \l log-data messages containing information about which part of the operation took how much time. If \c products is an array, the elements must correspond to the \c full-display-name property of previously retrieved \l ProductData, and only these products will get built. If \c products is the string \c "all", then all products in the project will get built. If \c products is not present, then products whose \l{Product::builtByDefault}{builtByDefault} property is \c false will be skipped. The \c module-properties property has the same meaning as in the \l{Resolving a Project}{resolve-project} request. All other properties correspond to options of the \l build command. When the build has finished, \QBS will reply with a \c project-built message. The possible properties are: \table \header \li Property \li Type \li Mandatory \row \li error \li \l ErrorInfo \li no \row \li project-data \li \l TopLevelProjectData \li no \endtable The \c error-info property is present if and only if the operation failed. The \c project-data property is present if and only if the conditions stated by the request's \c data-mode property are fulfilled. Unless the \c command-echo-mode value is \c "silent", a message of type \c command-description is emitted for every command to be executed. It consists of two string properties \c highlight and \c message, where \c message is the message to present to the user and \c highlight is a hint on how to display the message. It corresponds to the \l{Command and JavaScriptCommand}{Command} property of the same name. For finished process commands, a message of type \c process-result might be emitted. The other properties are: \table \header \li Property \li Type \row \li arguments \li list of strings \row \li error \li string \row \li executable-file-path \li \l FilePath \row \li exit-code \li int \row \li stderr \li list of strings \row \li stdout \li list of strings \row \li success \li bool \row \li working-directory \li \l FilePath \endtable The \c error string is one of \c "failed-to-start", \c "crashed", \c "timed-out", \c "write-error", \c "read-error" and \c "unknown-error". Its value is not meaningful unless \c success is \c false. The \c stdout and \c stderr properties describe the process's standard output and standard error output, respectively, split into lines. The \c success property is \c true if the process finished without errors and an exit code of zero. The other properties describe the exact command that was executed. This message is only emitted if the process failed or it has printed data to one of the output channels. \section1 Cleaning a Project To remove a project's build artifacts, a request of type \c clean-project is sent. The other properties are: \table \header \li Property \li Type \row \li dry-run \li bool \row \li keep-going \li bool \row \li log-level \li \l LogLevel \row \li log-time \li bool \row \li products \li list of strings \endtable The elements of the \c products array correspond to a \c full-display-name of a \l ProductData. If this property is present, only the respective products' artifacts are removed. If the \c log-time property is \c true, then \QBS will emit \l log-data messages containing information about which part of the operation took how much time. All other properties correspond to options of the \l clean command. None of these properties are mandatory. After all artifacts have been removed, \QBS replies with a \c project-cleaned message. If the operation was successful, this message has no properties. Otherwise, a property \c error of type \l ErrorInfo indicates what went wrong. \section1 Installing a Project Installing is normally part of the \l{Building a Project}{build} process. To do it in a separate step, the \c install property is set to \c false when building and a dedicated \c install-project message is sent. The other properties are: \table \header \li Property \li Type \row \li clean-install-root \li bool \row \li dry-run \li bool \row \li install-root \li \l FilePath \row \li keep-going \li bool \row \li log-level \li \l LogLevel \row \li log-time \li bool \row \li products \li list of strings \row \li use-sysroot \li bool \endtable The elements of the \c products array correspond to a \c full-display-name of a \l ProductData. If this property is present, only the respective products' artifacts are installed. If the \c log-time property is \c true, then \QBS will emit \l log-data messages containing information about which part of the operation took how much time. If the \c use-sysroot property is \c true and \c install-root is not present, then the install root will be \l{qbs::sysroot}{qbs.sysroot}. All other properties correspond to options of the \l install command. None of these properties are mandatory. \target cancel-message \section1 Canceling an Operation Potentially long-running operations can be aborted using the \c cancel-job request. This message does not have any properties. There is no dedicated reply message; instead, the usual reply for the request associated with the currently running operation will be sent, with the \c error property set to indicate that it was canceled. If there is no operation in progress, this request will have no effect. In particular, if it arrives after the operation that it was supposed to cancel has already finished (i.e. there is a race condition), the reply received by client code will not contain a cancellation-related error. \section1 Adding, Removing and Renaming Source Files Source files can be added to, removed from and renamed in \QBS project files with the \c add-files, \c remove-files and \c rename-files messages, respectively. These two requests have the same set of properties: \table \header \li Property \li Type \row \li files \li see below \row \li group \li string \row \li product \li string \endtable The \c files property specifies which files should be added, removed or renamed. For the \c add-files and \c remove-files messages, this is a \c FilePath list. For the \c rename-files message, this is a list of objects with two properties \c source-path and \c target-path, each of which is a \c FilePath. The \c product property corresponds to the \c full-display-name of a \l ProductData and specifies to which product to apply the operation. The \c group property corresponds to the \c name of a \l GroupData and specifies to which group in the product to apply the operation. After the operation has finished, \QBS replies with a \c files-added, \c files-removed and \c files-renamed message, respectively. Again, the properties are the same: \table \header \li Property \li Type \li Mandatory \row \li error \li \l ErrorInfo \li no \row \li failed-files \li \l FilePath list \li no \endtable If the \c error property is present, the operation has at least partially failed and \c failed-files will list the files that could not be added or removed. \section1 The \c get-run-environment Message This request retrieves the full run environment for a specific executable product, taking into account the \l{Module::setupRunEnvironment}{setupRunEnvironment} scripts of all modules pulled in by the product. The properties are as follows: \table \header \li Property \li Type \li Mandatory \row \li base-environment \li \l Environment \li no \row \li config \li list of strings \li no \row \li product \li string \li yes \endtable The \c base-environment property defines the environment into which the \QBS-specific values should be merged. The \c config property corresponds to the \l{--setup-run-env-config} option of the \l run command. The \c product property specifies the product whose environment to retrieve. The value must correspond to the \c full-display-name of some \l ProductData in the project. \QBS will reply with a \c run-environment message. In case of failure, it will contain a property \c error of type \l ErrorInfo, otherwise it will contain a property \c full-environment of type \l Environment. \section1 The \c get-generated-files-for-sources Message This request allows client code to retrieve information about which artifacts are generated from a given source file. Its sole property is a list \c products, whose elements are objects with the two properties \c full-display-name and \c requests. The first identifies the product to which the requests apply, and it must match the property of the same name in a \l ProductData in the project. The latter is a list of objects with the following properties: \table \header \li Property \li Type \li Mandatory \row \li source-file \li \l FilePath \li yes \row \li tags \li list of strings \li no \row \li recursive \li bool \li no \endtable The \c source-file property specifies a source file in the respective product. The \c tags property constrains the possible file tags of the generated files to be matched. This is relevant if a source files serves as input to more than one rule or the rule generates more than one type of output. If the \c recursive property is \c true, files indirectly generated from the source file will also be returned. The default is \c false. For instance, íf this property is enabled for a C++ source file, the final link target (e.g. a library or an application executable) will be returned in addition to the object file. \QBS will reply with a \c generated-files-for-sources message, whose structure is similar to the request. It also has a single object list property \c products, whose elements consist of a string property \c full-display-name and an object list property \c results. The properties of these objects are: \table \header \li Property \li Type \row \li source-file \li \l FilePath \row \li generated-files \li \l FilePath list \endtable The \c source-file property corresponds to an entry of the same name in the request, and the \c generated-files are the files which are generated by \QBS rules that take the source file as an input, taking the constraints specified in the request into account. Source files for which the list would be empty are not listed. Similarly, products for which the \c results list would be empty are also omitted. \note The results may be incomplete if the project has not been fully built. \section1 Closing a Project A project is closed with a \c release-project message. This request has no properties. \QBS will reply with a \c project-released message. If no project was open, the reply will contain an \c error property of type \l ErrorInfo. \target quit-message \section1 Closing the Session To close the session, a \c quit message is sent. This request has no properties. \QBS will cancel all currently running operations and then close itself. No reply will be sent. \section1 Progress Messages While a request is being handled, \QBS may emit progress information in order to enable client code to display a progress bar. \target task-started \section2 The \c task-started Message This is always the first progress-related message for a specific request. It appears at most once per request. It consists of a string property \c description, whose value can be displayed to users, and an integer property \c max-progress that indicates which progress value corresponds to 100 per cent. \target task-progress \section2 The \c task-progress Message This message updates the progress via an integer property \c progress. \target new-max-progress \section2 The \c new-max-progress Message This message is emitted if the original estimated maximum progress has to be corrected. Its integer property \c max-progress updates the value from a preceding \l task-started message. \section1 Messages for Users There are two types of messages that purely contain information to be presented to users. \target log-data \section2 The \c log-data Message This object has a string property \c message, which is the text to be shown to the user. \target warning-message \section2 The \c warning Message This message has a single property of type \l ErrorInfo. The name of the property is either \c warning or \c error, depending on how the client should display it. \section1 The \c protocol-error Message \QBS sends this message as a reply to a request with an unknown \c type. It contains an \c error property of type \l ErrorInfo. \section1 Project Data If a request can alter the build graph data, the associated reply may contain a \c project-data property whose value is of type \l TopLevelProjectData. \section2 TopLevelProjectData This data type represents the entire project. It has the same properties as \l PlainProjectData. If it is part of a \c project-resolved message, these additional properties are also present: \table \header \li Property \li Type \row \li build-directory \li \l FilePath \row \li build-graph-file-path \li \l FilePath \row \li build-system-files \li \l FilePath list \row \li overridden-properties \li object \row \li profile-data \li object \endtable The value of \c build-directory is the top-level build directory. The \c build-graph-file-path value is the path to the build graph file. The \c build-system-files value contains all \QBS project files, including modules and JavaScript helper files. The value of \c overridden-properties is the one that was passed in when the project was last \l{Resolving a Project}{resolved}. The \c profile-data property maps the names of the profiles used in the project to the respective property maps. Unless profile multiplexing is used, this object will contain exactly one property. \section2 PlainProjectData This data type describes a \l Project item. The properties are as follows: \table \header \li Property \li Type \row \li is-enabled \li bool \row \li location \li \l FilePath \row \li name \li string \row \li products \li \l ProductData list \row \li sub-projects \li \l PlainProjectData list \endtable The \c is-enabled property corresponds to the project's \l{Project::condition}{condition}. The \c location property is the exact position in a \QBS project file where the corresponding \l Project item was defined. The \c products and \c sub-projects are what the project has pulled in via its \l{Project::references}{references} property. \section2 ProductData This data type describes a \l Product item. The properties are as follows: \table \header \li Property \li Type \row \li build-directory \li \l FilePath \row \li dependencies \li list of strings \row \li full-display-name \li string \row \li generated-artifacts \li \l ArtifactData list \row \li groups \li \l GroupData list \row \li is-enabled \li bool \row \li is-multiplexed \li bool \row \li is-runnable \li bool \row \li location \li \l Location \row \li module-properties \li \l ModulePropertiesData \row \li multiplex-configuration-id \li string \row \li name \li string \row \li properties \li object \row \li target-executable \li \l FilePath \row \li target-name \li string \row \li type \li list of strings \row \li version \li string \endtable The elements of the \c dependencies array correspond to the full-display-name properties of the products that this product has pulled in via \l Depends items. The \c generated-artifacts are files that are created by the \l{Rule}{rules} in this product. The \c groups list corresponds to the \l Group items in this product. In addition, a "pseudo-group" is created for the \l{Product::files}{files} property of the product itself. Its name is the same as the product's. The \c is-enabled property corresponds to the product's \l{Product::condition}{condition}. A product may also get disabled if it contains errors and \QBS was was instructed to operate in relaxed mode when the project was \l{Resolving a Project}{resolved}. The \c is-multiplexed property is true if and only if the product is \l{Multiplexing}{multiplexed} over one ore more properties. The \c is-runnable property indicates whether one of the product's target artifacts is an executable file. In that case, the file is available via the \c target-executable property. The \c location property is the exact position in a \QBS project file where the corresponding \l Product item was defined. The \c module-properties object provides the values of the module properties that were requested when the project was \l{Resolving a Project}{resolved}. The \c name property is the value given in the \l{Product::name}{Product item}, whereas \c full-display-name is a name that uniquely identifies the product in the entire project, even in the presence of multiplexing. In the absence of multiplexing, it is the same as \c name. In either case, it is suitable for being presented to users. See the \l Product item documentation for a description of the other properties. \section2 GroupData This data type describes a \l Group item. The properties are: \table \header \li Property \li Type \row \li is-enabled \li bool \row \li location \li \l Location \row \li module-properties \li \l ModulePropertiesData \row \li name \li string \row \li prefix \li string \row \li source-artifacts \li \l ArtifactData list \row \li source-artifacts-from-wildcards \li \l ArtifactData list \endtable The \c is-enabled property corresponds to the groups's \l{Group::condition}{condition}. However, if the group's product is disabled, this property will always be \c false. The \c location property is the exact position in a \QBS project file where the corresponding \l Group item occurs. The \c module-properties object provides the values of the module properties that were requested when the project was \l{Resolving a Project}{resolved}. If no module properties are set on the Group level and the value would therefore be the same as in the group's product, then this property is omitted. The \c source-artifacts list corresponds the the files listed verbatim in the group's \l{Group::files}{files} property. The \c source-artifacts-from-wildcards list represents the the files expanded from wildcard entries in the group's \l{Group::files}{files} property. See the \l Group item documentation for a description of the other properties. \section2 ArtifactData This data type represents files that occur in the project, either as sources or as outputs of a rules. \QBS project files, on the other hand, are not artifacts. The properties are: \table \header \li Property \li Type \row \li file-path \li \l FilePath \row \li file-tags \li list of strings \row \li install-data \li object \row \li is-executable \li bool \row \li is-generated \li bool \row \li is-target \li bool \row \li module-properties \li \l ModulePropertiesData \endtable The \c install-data property is an object whose \c is-installable property indicates whether the artifact gets installed. If so, then the \l FilePath properties \c install-file-path and \c install-root provide further information. The \c is-target property is true if the artifact is a target artifact of its product, that is, \c is-generated is true and \c file-tags intersects with the \l{Product::type}{product type}. The \c module-properties object provides the values of the module properties that were requested when the project was \l{Resolving a Project}{resolved}. This property is only present for generated artifacts. For source artifacts, the value can be retrieved from their \l{GroupData}{group}. The other properties should be self-explanatory. \section2 ModulePropertiesData This data type maps fully qualified module property names to their respective values. \section1 Other Custom Data Types There are a number of custom data types that serve as building blocks in various messages. They are described below. \section2 FilePath A \e FilePath is a string that describes a file or directory. FilePaths are always absolute and use forward slashes for separators, regardless of the host operating system. \section2 Location A \e Location is an object representing a file path and possibly also a position within the respective file. It consists of the following properties: \table \header \li Property \li Type \li Mandatory \row \li file-path \li \l FilePath \li yes \row \li line \li int \li no \row \li column \li int \li no \endtable \section2 ErrorInfo An \e ErrorInfo is an object representing error information. Its sole property \c items is an array of objects with the following structure: \table \header \li Property \li Type \li Mandatory \row \li description \li string \li yes \row \li location \li \l Location \li no \endtable \section2 DataMode This is the type of the \c data-mode property in a \l{Resolving a project}{resolve} or \l{Building a project}{build} request. It is used to indicate under which circumstances the reply message should include the project data. The possible values have string type and are as follows: \list \li \c "never": Do not attach project data to the reply. \li \c "always": Do attach project data to the reply. \li \c "only-if-changed": Attach project data to the reply only if it is different from the current project data. \endlist The default value is \c "never". \section2 LogLevel This is the type of the \c log-level property that can occur in various requests. It is used to indicate whether the client would like to receive \l log-data and/or \l{warning-message}{warning} messages. The possible values have string type and are as follows: \list \li "error": Do not log anything. \li "warning": \QBS may emit \l{warning-message}{warnings}, but no \l log-data messages. \li "info": In addition to warnings, \QBS may emit informational \l log-data messages. \li "debug": \QBS may emit debug output. No messages will be generated; instead, the standard error output channel will be used. \endlist The default value is \c "info". \section2 Environment This data type describes a set of environment variables. It is an object whose keys are names of environment variables and whose values are the values of these environment variables. */ qbs-src-2.6.1/doc/appendix/qbs-porting.qdoc0000644000175100001660000003454514776170045020155 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \previouspage building-qbs.html \page porting-to-qbs.html \nextpage json-api.html \title Appendix B: Migrating from Other Build Systems You can use the \l{create-project}{qbs create-project} command to automatically generate \QBS project files from an arbitrary directory structure. This is a useful starting point when migrating from other build tools, such as qmake or CMake. To use the tool, switch to the project directory and run the \c {qbs create-project} command, which is located in the \c bin directory of the \QBS installation directory (or the Qt Creator installation directory). After generating the initial .qbs file, add the missing configuration variables and functions to it, as described in the following sections. \section1 Migrating from qmake The following sections describe the \QBS equivalents of qmake variable values. \section2 CONFIG Specify project configuration and compiler options. \section3 console Set the \l{Product::consoleApplication}{Product.consoleApplication} property to \c true for the \l{Application}, \l{CppApplication},or \l{QtApplication} item. For example: \code Application { name: "helloworld" files: "main.cpp" Depends { name: "cpp" } consoleApplication: true } \endcode \section3 ordered This qmake variable has no direct equivalent in \QBS. Instead, the build order is determined by implicit and explicit dependencies between products. To add an explicit dependency, add a \l{Depends} item to a \l{Product}{product}: \code CppApplication { name: "myapp" Depends { name: "mylib" } } \endcode The \c myapp product depends on and links to the \c mylib product, and is therefore built after it. \section3 qt In qmake, the Qt dependency is implicit, whereas in \QBS it is not. If \c {CONFIG -= qt}, add a \l{Depends} item to specify that the \l{Product}{product} depends on the \l{cpp} module: \code Product { Depends { name: "cpp" } } \endcode \section2 DEFINES Set the \l{cpp::defines}{cpp.defines} property for the \l{Product}{product}. \note To reference \c cpp.defines, you must specify a dependency on the \l{cpp} module. \code Product { Depends { name: "cpp" } cpp.defines: ["SUPPORT_MY_FEATURES"] } \endcode \section2 DESTDIR We recommend that you use the \l{Installing Files}{installation mechanism} to specify the location of the target file: \code Application { Group { name: "Runtime resources" files: "*.qml" qbs.install: true qbs.installDir: "share/myproject" } Group { name: "The App itself" fileTagsFilter: "application" qbs.install: true qbs.installDir: "bin" } } \endcode If that is not possible, you can use the \l{Product::}{destinationDirectory} property: \code DynamicLibrary { name: "mydll" destinationDirectory: "libDir" } \endcode \section2 HEADERS, SOURCES, FORMS, RESOURCES, OTHER_FILES Include header, source, form, and resource files as well as any other files as values of a \l{Product::files}{Product.files} or \l{Group::files}{Group.files} property: \code QtApplication { name: "myapp" files: ["myapp.h", "myapp.cpp", "myapp.ui", "myapp.qrc", "readme.txt"] } \endcode \QBS uses \l{FileTagger}{file taggers} to figure out what kind of file it is dealing with. \section2 ICON There is no direct equivalent in \QBS. If you add a \l{Depends} {dependency} to the \l{ib} module and add the \c .xcassets directory as a value of the \l{Product::files}{Product.files} property, \QBS takes care of setting the application icon automatically when building for Apple platforms: \code Application { name: "myapp" files [".xcassets"] Depends { name: "ib" } } \endcode Alternatively, you can set the icon name as the value of the \l{bundle::infoPlist}{bundle.infoPlist} parameter, specify a dependency to the \l{ib} module, and add the application \c .icns file as a value of the \l{Product::}{files} property: \code Application { name: "myapp" files ["myapp.icns"] Depends { name: "ib" } bundle.infoPlist: ({"CFBundleIconFile": "myapp"}) \endcode \section2 INCLUDEPATH Add the paths to the include files as values of the \l{cpp::includePaths} {cpp.includePaths} property: \code CppApplication { cpp.includePaths: ["..", "some/other/dir"] } \endcode \section2 LIBS For libraries that are part of the project, use \l{Depends} items. To pull in external libraries, use the \l{cpp::libraryPaths} {cpp.libraryPaths} property for the Unix \c -L (library path) flags and the \l{cpp::dynamicLibraries}{cpp.dynamicLibraries} and \l{cpp::staticLibraries} {cpp.staticLibraries} properties for the \c -l (library) flags. For example, \c {LIBS += -L/usr/local/lib -lm} would become: \code CppApplication { cpp.libraryPaths: ["/usr/local/lib"] cpp.dynamicLibraries: ["m"] } \endcode \section2 OUT_PWD Use the \l{Product::buildDirectory}{Product.buildDirectory} property to refer to the base output directory of the generated artifacts. \section2 PWD Corresponds to the the file-scope variable \c path. \section2 _PRO_FILE_ Corresponds to the file-scope variable \c filePath when used in a \l{Project}{project} or \l{Product}{product}. \section2 _PRO_FILE_PWD_ Corresponds to the \l{Project::sourceDirectory}{Project.sourceDirectory} or \l{Product::sourceDirectory}{Product.sourceDirectory} property. \section2 QMAKE_ASSET_CATALOGS Add a \l{Depends}{dependency} to the \l{ib} module and add the \c .xcassets directory as a value of the \l{Product::}{files} property: \code Application { name: "myapp" files [".xcassets"] Depends { name: "ib" } } \endcode \section2 QMAKE_BUNDLE_DATA For the time being, you can manually place files in the appropriate location using the \l{Installing Files}{installation mechanism}. Better solutions are under development. \section2 QMAKE_BUNDLE_EXTENSION Set the \l{bundle::extension}{bundle.extension} property. \note Unlike qmake, \QBS automatically prepends a period (.) to the property value. \section2 QMAKE_{C,CXX,OBJECTIVE}_CFLAGS{_DEBUG,_RELEASE} Use the \l{cpp::commonCompilerFlags}{cpp.commonCompilerFlags} property or the properties corresponding to each compiler flags variable: \table \header \li qmake Variable \li cpp Module Property \row \li \c QMAKE_CFLAGS_DEBUG \c QMAKE_CFLAGS_RELEASE \li \l{cpp::cFlags}{cpp.cFlags} \row \li \c QMAKE_CXXFLAGS_DEBUG \c QMAKE_CXXFLAGS_RELEASE \li \l{cpp::cxxFlags}{cpp.cxxFlags} \row \li \c QMAKE_OBJECTIVE_CFLAGS \li \l{cpp::objcFlags}{cpp.objcFlags} \l{cpp::objcxxFlags}{cpp.objcxxFlags} \endtable Use \l{Properties} items or simple conditionals as values of the \l{qbs::buildVariant}{qbs.buildVariant} property to simulate the \c _DEBUG and \c _RELEASE variants of the qmake variables. \section2 QMAKE_FRAMEWORK_BUNDLE_NAME Set the \l{bundle::bundleName}{bundle.bundleName} property (which is derived from \l{Product::targetName}{Product.targetName}) combined with \l{bundle::extension}{bundle.extension}. \section2 QMAKE_FRAMEWORK_VERSION Set the \l{bundle::frameworkVersion}{bundle.frameworkVersion} property. \section2 QMAKE_INFO_PLIST Include the \c info.plist file as a value of \l{Product::}{files} property and specify a dependency to the \l{bundle} module: \code Application { name: "myapp" files ["info.plist"] Depends { name: "bundle" } } \endcode \QBS will automatically add any necessary properties to your \c Info.plist file. Typically, it determines the appropriate values from the other properties in the project, and therefore you do not need to use the \c {Info.plist.in > Info.plist} configuration mechanism. Further, you almost never need to embed placeholders into the source \c Info.plist file. Set the \l{bundle::processInfoPlist}{bundle.processInfoPlist} property to \c false to disable this behavior: \code \\ ... bundle.processInfoPlist: false \endcode In addition to, or instead of, using an actual \c Info.plist file, you can add \c Info.plist properties using the \l{bundle::infoPlist} {bundle.infoPlist} property. For example: \code \\ ... bundle.infoPlist: ({ "NSHumanReadableCopyright": "Copyright (c) 2017 Bob Inc", "Some other key", "Some other value, & XML special characters are no problem! >;) 非凡!" }) \endcode \section2 QMAKE_LFLAGS Set the \l{cpp::linkerFlags}{cpp.linkerFlags} property for the \l{Product} {product}. \section2 QMAKE_{MACOSX,IOS,TVOS,WATCHOS}_DEPLOYMENT_TARGET For each qmake deployment target variable, use the corresponding property of the \l{cpp} module: \table \header \li qmake Variable \li cpp Module Property \row \li \c QMAKE_MACOSX_DEPLOYMENT_TARGET \li \l{cpp::minimumMacosVersion}{cpp.minimumMacosVersion} \row \li \c QMAKE_IOS_DEPLOYMENT_TARGET \li \l{cpp::minimumIosVersion}{cpp.minimumIosVersion} \row \li \c QMAKE_TVOS_DEPLOYMENT_TARGET \li \l{cpp::minimumTvosVersion}{cpp.minimumTvosVersion} \row \li \c QMAKE_WATCHOS_DEPLOYMENT_TARGET \li \l{cpp::minimumWatchosVersion}{cpp.minimumWatchosVersion} \endtable \section2 QMAKE_RPATHDIR Set the \l{cpp::rpaths}{cpp.rpaths} property for the \l{Product}{product}. \section2 QMAKE_SONAME_PREFIX Use the \l{cpp::sonamePrefix}{cpp.sonamePrefix} property for the \l{Product} {product}. \section2 QML_IMPORT_PATH Used only for Qt Creator QML syntax highlighting. Inside a \l{Product}, \l{Application}, \l{CppApplication}, or \l{QtApplication}, create a \c qmlImportPaths property: \code Product { name: "myProduct" property stringList qmlImportPaths: [sourceDirectory + "/path/to/qml/"] } \endcode \section2 QT Add a \l{Depends} item to the \l{Product}{product} that specifies the dependencies to \l{Qt} modules. For example: \code QtApplication { Depends { name: "Qt.widgets" } } \endcode You could also use the following form that is equivalent to the previous one: \code QtApplication { Depends { name: "Qt"; submodules: "widgets" } } \endcode \section2 QTPLUGIN Building static applications often requires linking to static QPA plugins, such as \c qminimal. You can use the following syntax to enable \QBS to link to the required plugins: \code QtApplication { name: "myapp" Depends { name: "Qt"; submodules: ["core", "gui", "widgets"] } Depends { name: "Qt.qminimal"; condition: Qt.core.staticBuild } } \endcode \section2 RC_FILE Add Windows resource files to the value of the \l{Product::files} {Product.files} property. \section2 TARGET Use the \l{Product::targetName}{Product.targetName} property to specify the base file name of target artifacts. \section2 TEMPLATE \section3 app Use \l{Application} or \l{CppApplication} as the \l{Product}{product}: \code CppApplication { name: "helloworld" files: "main.cpp" } \endcode This is roughly equivalent to: \code Product { name: "helloworld" type: "application" files: "main.cpp" Depends { name: "cpp" } } \endcode \section3 lib Use either \l{DynamicLibrary} or \l{StaticLibrary} as the \l{Product} {product}, depending on whether the value of \c CONFIG in the .pro file is \c shared or \c static. For example, if the value is \c shared: \code DynamicLibrary { name: "mydll" files: ["mySourceFile.cpp"] Depends { name: "cpp" } } \endcode \section3 subdirs In a \l{Project} item, specify subdirectories as values of the \l{Project::}{references} property: \code Project { references: [ "app/app.qbs", "lib/lib.qbs" ] } \endcode \section2 message(), warning(), error(), log() You can use the \l{Console API} to print info, warning, error, and log messages to the console. \code Product { name: { console.info("--> now evaluating the product name"); return "theName"; } Depends { name: "cpp" } cpp.includePath: { throw "An error occurred." } } \endcode */ qbs-src-2.6.1/.dockerignore0000644000175100001660000000002714776170045015123 0ustar runnerdocker* !docker/* !scripts/* qbs-src-2.6.1/VERSION0000644000175100001660000000000614776170045013514 0ustar runnerdocker2.6.1 qbs-src-2.6.1/docker/0000755000175100001660000000000014776170045013717 5ustar runnerdockerqbs-src-2.6.1/docker/entrypoint.sh0000755000175100001660000000720014776170045016470 0ustar runnerdocker#!/usr/bin/env bash set -e ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# # # Entrypoint script when starting the container. The script checks the current # working directory and changes the uid/gid of developer/users to match whatever # is found in the working directory. This is useful to match the user and group # of mounted volumes into the container # # If not root, re-run script as root to fix ids # if [ "$(id -u)" != "0" ]; then exec gosu root /sbin/entrypoint.sh "$@" fi # # Try to determine the uid of the working directory and adjust the current # user's uid/gid accordingly. # USER_GID=${USER_GID:-$(stat -c "%g" .)} USER_UID=${USER_UID:-$(stat -c "%u" .)} USER_NAME=${USER_NAME:-devel} USER_GROUP=${USER_GROUP:-devel} EXEC="" export HOME=/home/${USER_NAME} # # This is a problem on Linux hosts when we mount a folder from the # user file system and write artifacts into that. Thus, we downgrade # the current user and make sure that the uid and gid matches the one # of the mounted project folder. # # This work-around is not needed on Windows hosts as Windows doesn't # have such a concept. # if [ "${USER_UID}" != "0" ]; then if [ "$(id -u ${USER_NAME})" != "${USER_UID}" ]; then usermod -o -u ${USER_UID} ${USER_NAME} # After changing the user's uid, all files in user's home directory # automatically get the new uid. fi current_gid=$(id -g ${USER_NAME}) if [ "$(id -g ${USER_NAME})" != "${USER_GID}" ]; then groupmod -o -g ${USER_GID} ${USER_GROUP} # Set the new gid on all files in the home directory that still have the # old gid. find /home/${USER_NAME} -gid "${current_gid}" ! -type l -exec chgrp ${USER_GID} {} \; fi fi EXEC="exec gosu ${USER_NAME}:${USER_GROUP}" if [ -z "$1" ]; then ${EXEC} bash -l else ${EXEC} bash -l -c "$*" fi qbs-src-2.6.1/docker/leap/0000755000175100001660000000000014776170045014640 5ustar runnerdockerqbs-src-2.6.1/docker/leap/entrypoint.sh0000755000175100001660000000720414776170045017415 0ustar runnerdocker#!/usr/bin/env bash set -e ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# # # Entrypoint script when starting the container. The script checks the current # working directory and changes the uid/gid of developer/users to match whatever # is found in the working directory. This is useful to match the user and group # of mounted volumes into the container # # If not root, re-run script as root to fix ids # if [ "$(id -u)" != "0" ]; then exec sudo -i /sbin/entrypoint.sh "$@" fi # # Try to determine the uid of the working directory and adjust the current # user's uid/gid accordingly. # USER_GID=${USER_GID:-$(stat -c "%g" .)} USER_UID=${USER_UID:-$(stat -c "%u" .)} USER_NAME=${USER_NAME:-devel} USER_GROUP=${USER_GROUP:-devel} EXEC="" export HOME=/home/${USER_NAME} # # This is a problem on Linux hosts when we mount a folder from the # user file system and write artifacts into that. Thus, we downgrade # the current user and make sure that the uid and gid matches the one # of the mounted project folder. # # This work-around is not needed on Windows hosts as Windows doesn't # have such a concept. # if [ "${USER_UID}" != "0" ]; then if [ "$(id -u ${USER_NAME})" != "${USER_UID}" ]; then usermod -o -u ${USER_UID} ${USER_NAME} # After changing the user's uid, all files in user's home directory # automatically get the new uid. fi current_gid=$(id -g ${USER_NAME}) if [ "$(id -g ${USER_NAME})" != "${USER_GID}" ]; then groupmod -o -g ${USER_GID} ${USER_GROUP} # Set the new gid on all files in the home directory that still have the # old gid. find /home/${USER_NAME} -gid "${current_gid}" ! -type l -exec chgrp ${USER_GID} {} \; fi fi EXEC="exec sudo -u ${USER_NAME} -g ${USER_GROUP}" if [ -z "$1" ]; then ${EXEC} bash -l else ${EXEC} bash -l -c "$*" fi qbs-src-2.6.1/docker/leap/Dockerfile0000644000175100001660000000557614776170045016647 0ustar runnerdocker# # Install Qt and Qbs for Linux # FROM opensuse/leap:15.3 LABEL Description="OpenSUSE development environment for Qbs with Qt and various dependencies for testing Qbs modules and functionality" ARG QT_VERSION ARG QTCREATOR_VERSION # Allow colored output on command line. ENV TERM=xterm-color # # Make it possible to change UID/GID in the entrypoint script. The docker # container usually runs as root user on Linux hosts. When the Docker container # mounts a folder on the host and creates files there, those files would be # owned by root instead of the current user. Thus we create a user here who's # UID will be changed in the entrypoint script to match the UID of the current # host user. # ARG USER_UID=1000 ARG USER_NAME=devel RUN zypper in -y \ ca-certificates \ sudo \ system-user-mail \ system-group-wheel && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G wheel ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/leap/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # # Qbs build dependencies RUN zypper install -y \ bison \ capnproto \ ccache \ cmake \ command-not-found \ curl \ gcc10 \ gcc10-c++ \ glibc-devel-static \ flex \ fontconfig \ git \ gzip \ help2man \ icoutils \ libcapnp-devel \ libgthread-2_0-0 \ libfreetype6 \ Mesa-libGL-devel \ Mesa-libGL1 \ nanopb-devel \ ninja \ perl \ pkg-config \ psmisc \ python3-pip \ p7zip-full \ subversion \ tar \ unzip \ which \ zip && \ update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 && \ update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 && \ pip install --upgrade pip && \ pip install beautifulsoup4 lxml # # Install Qt and Qbs for Linux from qt.io # COPY scripts/install-qt.sh install-qt.sh RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qttools qtx11extras qtscxml qt5compat icu && \ ./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \ echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh ENV PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:${PATH} # Configure Qbs USER $USER_NAME RUN qbs-setup-toolchains /usr/bin/g++ gcc && \ qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-gcc_64 && \ qbs config profiles.qt-gcc_64.baseProfile gcc && \ qbs config defaultProfile qt-gcc_64 # Switch back to root user for the entrypoint script. USER root # Work-around for QTBUG-79020 RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh qbs-src-2.6.1/docker/noble/0000755000175100001660000000000014776170045015016 5ustar runnerdockerqbs-src-2.6.1/docker/noble/test-qt6-wasm.Dockerfile0000644000175100001660000000465214776170045021452 0ustar runnerdocker# # Testing Qbs with Web Assembly # FROM ubuntu:noble LABEL Description="Ubuntu wasm test environment for Qbs" ARG QT_VERSION ARG EMSCRIPTEN_VERSION # Allow colored output on command line. ENV TERM=xterm-color # # Make it possible to change UID/GID in the entrypoint script. The docker # container usually runs as root user on Linux hosts. When the Docker container # mounts a folder on the host and creates files there, those files would be # owned by root instead of the current user. Thus we create a user here who's # UID will be changed in the entrypoint script to match the UID of the current # host user. # ARG USER_UID=1000 ARG USER_NAME=devel RUN apt-get update -qq && \ apt-get install -qq -y \ ca-certificates \ gosu \ sudo && \ userdel ubuntu && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G sudo ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] RUN sudo apt-get update -qq && \ apt-get install -qq -y \ curl \ libglib2.0-0 \ locales \ p7zip-full \ python3 \ python3-pip \ unzip # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN curl -L https://github.com/emscripten-core/emsdk/archive/refs/heads/main.zip > /emsdk.zip && \ unzip /emsdk.zip && \ rm /emsdk.zip && \ mv /emsdk-main /emsdk && \ cd /emsdk && \ ./emsdk install ${EMSCRIPTEN_VERSION} && \ ./emsdk activate ${EMSCRIPTEN_VERSION} ENV EMSDK=/emsdk \ PATH="/emsdk:/emsdk/upstream/emscripten:/emsdk/node/18.20.3_64bit/bin:${PATH}" # # Install Qt for Wasm from qt.io # COPY scripts/install-qt.sh install-qt.sh RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qttools qtx11extras qtscxml qt5compat icu && \ echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:\${PATH}" > /etc/profile.d/qt.sh RUN ./install-qt.sh --version ${QT_VERSION} --target wasm --toolchain wasm_multithread qtbase qtdeclarative qttools qtx11extras qtscxml qt5compat icu && \ echo "export PATH=/opt/Qt/${QT_VERSION}/wasm_multithread/bin:\${PATH}" > /etc/profile.d/qt.sh # Work-around for QTBUG-79020 RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh qbs-src-2.6.1/docker/noble/test-android.Dockerfile0000644000175100001660000001266214776170045021413 0ustar runnerdocker# # Android SDK/NDK + Qt for Android for testing Qbs # FROM ubuntu:noble LABEL Description="Ubuntu test environment for Qbs and Qt for Android" # Allow colored output on command line. ENV TERM=xterm-color # # Make it possible to change UID/GID in the entrypoint script. The docker # container usually runs as root user on Linux hosts. When the Docker container # mounts a folder on the host and creates files there, those files would be # owned by root instead of the current user. Thus we create a user here who's # UID will be changed in the entrypoint script to match the UID of the current # host user. # ARG USER_UID=1000 ARG USER_NAME=devel RUN apt-get update -qq && \ apt-get install -qq -y \ ca-certificates \ gosu \ sudo && \ userdel ubuntu && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G sudo ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Qbs build dependencies RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends \ ca-certificates \ curl \ gdb \ libasan5 \ libglib2.0-0 \ locales \ openjdk-8-jdk-headless \ p7zip-full \ unzip # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 RUN echo "export JAVA_HOME=${JAVA_HOME}" > /etc/profile.d/android.sh && \ echo "export PATH=${JAVA_HOME}/bin:\${PATH}" >> /etc/profile.d/android.sh ARG ANDROID_NDK_VERSION ENV ANDROID_HOME="/home/${USER_NAME}/android" ENV ANDROID_SDK_ROOT=${ANDROID_HOME} ENV ANDROID_NDK_ROOT=${ANDROID_HOME}/"ndk"/${ANDROID_NDK_VERSION} ENV PATH="${JAVA_HOME}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:$PATH" RUN echo "export ANDROID_HOME=/home/${USER_NAME}/android" >> /etc/profile.d/android.sh && \ echo "export ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export PATH=${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:\$PATH" >> /etc/profile.d/android.sh # # We ned to run the following steps as the target user # USER ${USER_NAME} RUN mkdir ${ANDROID_HOME} # Get Android command line tools ARG COMMAND_LINE_TOOLS_VERSION="6858069" RUN curl -s https://dl.google.com/android/repository/commandlinetools-linux-${COMMAND_LINE_TOOLS_VERSION}_latest.zip > ${ANDROID_HOME}/commandlinetools.zip && \ unzip ${ANDROID_HOME}/commandlinetools.zip -d ${ANDROID_HOME} && \ rm -v ${ANDROID_HOME}/commandlinetools.zip # Accept SDK license ARG ANDROID_PLATFORM="android-30" ARG BUILD_TOOLS="29.0.2" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" --verbose --licenses && \ sdkmanager "--sdk_root=${ANDROID_HOME}" --update && \ sdkmanager "--sdk_root=${ANDROID_HOME}" "platforms;${ANDROID_PLATFORM}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "build-tools;${BUILD_TOOLS}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "platform-tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "ndk;${ANDROID_NDK_VERSION}" RUN /usr/lib/jvm/java-8-openjdk-amd64/bin/keytool -genkey -keystore /home/${USER_NAME}/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname 'CN=Android Debug,O=Android,C=US' # Install ndk samples in ${ANDROID_NDK_ROOT}/samples RUN cd ${ANDROID_NDK_ROOT} && \ curl -sLO https://github.com/android/ndk-samples/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv ndk-samples-master samples # Install android-BasicMediaDecoder in ${ANDROID_SDK_ROOT}/samples RUN mkdir ${ANDROID_SDK_ROOT}/samples && \ cd ${ANDROID_SDK_ROOT}/samples && \ curl -sLO https://github.com/googlearchive/android-BasicMediaDecoder/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv android-BasicMediaDecoder-master android-BasicMediaDecoder # Download buildtool to generate aab packages in ${ANDROID_SDK_ROOT} RUN cd ${ANDROID_SDK_ROOT} && \ curl -sLO https://github.com/google/bundletool/releases/download/1.3.0/bundletool-all-1.3.0.jar USER root # # Install Qt and Qbs for Linux from qt.io # ARG QT_VERSION COPY scripts/install-qt.sh install-qt.sh RUN if [ "${QT_VERSION}" \< "5.14" ] || [ ! "${QT_VERSION}" \< "6.0.0" ]; then \ QT_ABIS="android_armv7 android_arm64_v8a android_x86 android_x86_64"; \ else \ QT_ABIS="any"; \ fi; \ if [ ! "${QT_VERSION}" \< "6.0.0" ]; then \ ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative icu; \ if [ "${QT_VERSION}" \< "6.1.0" ]; then \ QT_COMPONENTS="qtbase qtdeclarative qttools qtquickcontrols2 qtquicktimeline svg"; \ else \ QT_COMPONENTS="qtbase qtdeclarative qttools qtquicktimeline svg"; \ fi; \ else \ QT_COMPONENTS="qtbase qtdeclarative qttools qtimageformats"; \ fi; \ for abi in ${QT_ABIS}; do \ ./install-qt.sh --version ${QT_VERSION} --target android --toolchain ${abi} ${QT_COMPONENTS}; \ done && \ echo "export QT_VERSION=${QT_VERSION}" >> /etc/profile.d/qt.sh qbs-src-2.6.1/docker/noble/Dockerfile0000644000175100001660000000757014776170045017021 0ustar runnerdocker# # Install Qt and Qbs for Linux # FROM ubuntu:noble LABEL Description="Ubuntu development environment for Qbs with Qt and various dependencies for testing Qbs modules and functionality" ARG QT_VERSION ARG QTCREATOR_VERSION # Allow colored output on command line. ENV TERM=xterm-color # # Make it possible to change UID/GID in the entrypoint script. The docker # container usually runs as root user on Linux hosts. When the Docker container # mounts a folder on the host and creates files there, those files would be # owned by root instead of the current user. Thus we create a user here who's # UID will be changed in the entrypoint script to match the UID of the current # host user. # ARG USER_UID=1000 ARG USER_NAME=devel RUN apt-get update -qq && \ apt-get install -qq -y \ ca-certificates \ gosu \ sudo && \ userdel ubuntu && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G sudo ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Qbs build dependencies RUN apt-get update -qq && \ DEBIAN_FRONTEND="noninteractive" apt-get install -qq -y --no-install-recommends \ bison \ build-essential \ ca-certificates \ capnproto \ ccache \ clang-18 \ clang-tidy-18 \ cmake \ curl \ flex \ git \ gdb \ help2man \ icoutils \ libcapnp-dev \ libclang-rt-18-dev \ libdbus-1-3 \ libfreetype6 \ libfontconfig1 \ libgl1-mesa-dev \ libnanopb-dev \ libprotobuf-dev \ libgrpc++-dev \ libxkbcommon-x11-0 \ locales \ nanopb \ ninja-build \ nsis \ pkg-config \ protobuf-compiler \ protobuf-compiler-grpc \ psmisc \ python3-pip \ python3-setuptools \ python3-venv \ p7zip-full \ subversion \ unzip \ zip && \ update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100 && \ update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100 && \ update-alternatives --install /usr/bin/clang-check clang-check /usr/bin/clang-check-18 100 && \ update-alternatives --install /usr/bin/python python /usr/bin/python3 100 ENV LLVM_INSTALL_DIR=/usr/lib/llvm-18 # Set up Python RUN python3 -m venv /venv && \ /venv/bin/pip3 install beautifulsoup4 lxml protobuf==3.19.1 pyyaml conan ENV PATH=/venv/bin:${PATH} # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 # # Install Qt and Qbs for Linux from qt.io # COPY scripts/install-qt.sh install-qt.sh RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qttools qtx11extras qtscxml qt5compat icu && \ ./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \ echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh ENV PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:${PATH} # Configure Qbs USER $USER_NAME RUN qbs-setup-toolchains /usr/bin/g++ gcc && \ qbs-setup-toolchains /usr/bin/clang clang && \ qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-gcc_64 && \ qbs config profiles.qt-gcc_64.baseProfile gcc && \ qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-clang_64 && \ qbs config profiles.qt-clang_64.baseProfile clang && \ qbs config defaultProfile qt-gcc_64 # Configure Conan RUN conan profile detect --name qbs-test # Switch back to root user for the entrypoint script. USER root # Work-around for QTBUG-79020 RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh qbs-src-2.6.1/docker/noble/test-baremetal.Dockerfile0000644000175100001660000000300114776170045021712 0ustar runnerdocker# # Baremetal toolchains for testing Qbs # FROM ubuntu:noble LABEL Description="Ubuntu baremetal test environment for Qbs" # Allow colored output on command line. ENV TERM=xterm-color # # Make it possible to change UID/GID in the entrypoint script. The docker # container usually runs as root user on Linux hosts. When the Docker container # mounts a folder on the host and creates files there, those files would be # owned by root instead of the current user. Thus we create a user here who's # UID will be changed in the entrypoint script to match the UID of the current # host user. # ARG USER_UID=1000 ARG USER_NAME=devel RUN apt-get update -qq && \ apt-get install -qq -y \ ca-certificates \ gosu \ sudo && \ userdel ubuntu && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G sudo ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Install baremetal toolchains and Qbs runtime dependencies. RUN apt-get update -qq && \ apt-get install -qq -y \ libasan5 \ libglib2.0-0 \ libgssapi-krb5-2 \ gcc-arm-none-eabi \ gcc-avr \ avr-libc \ sdcc \ binutils-xtensa-lx106 \ gcc-xtensa-lx106 \ gcc-riscv64-unknown-elf # Work-around for QTBUG-79020. RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh qbs-src-2.6.1/docker/noble/test-android-no-qt.Dockerfile0000644000175100001660000001040714776170045022442 0ustar runnerdocker# # Android SDK/NDK for testing Qbs # FROM ubuntu:noble LABEL Description="Ubuntu test environment for Qbs for Android" # Allow colored output on command line. ENV TERM=xterm-color # # Make it possible to change UID/GID in the entrypoint script. The docker # container usually runs as root user on Linux hosts. When the Docker container # mounts a folder on the host and creates files there, those files would be # owned by root instead of the current user. Thus we create a user here who's # UID will be changed in the entrypoint script to match the UID of the current # host user. # ARG USER_UID=1000 ARG USER_NAME=devel RUN apt-get update -qq && \ apt-get install -qq -y \ ca-certificates \ gosu \ sudo && \ userdel ubuntu && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G sudo ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Qbs build dependencies RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends \ ca-certificates \ curl \ gdb \ libasan5 \ libglib2.0-0 \ openjdk-8-jdk-headless \ p7zip-full \ unzip ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 RUN echo "export JAVA_HOME=${JAVA_HOME}" > /etc/profile.d/android.sh && \ echo "export PATH=${JAVA_HOME}/bin:\${PATH}" >> /etc/profile.d/android.sh ARG ANDROID_NDK_VERSION ENV ANDROID_HOME="/home/${USER_NAME}/android" ENV ANDROID_SDK_ROOT=${ANDROID_HOME} ENV ANDROID_NDK_ROOT=${ANDROID_HOME}/"ndk"/${ANDROID_NDK_VERSION} ENV PATH="${JAVA_HOME}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:$PATH" RUN echo "export ANDROID_HOME=/home/${USER_NAME}/android" >> /etc/profile.d/android.sh && \ echo "export ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export PATH=${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:\$PATH" >> /etc/profile.d/android.sh # # We ned to run the following steps as the target user # USER ${USER_NAME} RUN mkdir ${ANDROID_HOME} # Get Android command line tools ARG COMMAND_LINE_TOOLS_VERSION="6858069" RUN curl -s https://dl.google.com/android/repository/commandlinetools-linux-${COMMAND_LINE_TOOLS_VERSION}_latest.zip > ${ANDROID_HOME}/commandlinetools.zip && \ unzip ${ANDROID_HOME}/commandlinetools.zip -d ${ANDROID_HOME} && \ rm -v ${ANDROID_HOME}/commandlinetools.zip # Accept SDK license ARG ANDROID_PLATFORM="android-29" ARG BUILD_TOOLS="29.0.2" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" --verbose --licenses && \ sdkmanager "--sdk_root=${ANDROID_HOME}" --update && \ sdkmanager "--sdk_root=${ANDROID_HOME}" "platforms;${ANDROID_PLATFORM}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "build-tools;${BUILD_TOOLS}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "platform-tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "ndk;${ANDROID_NDK_VERSION}" RUN /usr/lib/jvm/java-8-openjdk-amd64/bin/keytool -genkey -keystore /home/${USER_NAME}/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname 'CN=Android Debug,O=Android,C=US' # Install ndk samples in ${ANDROID_NDK_ROOT}/samples RUN cd ${ANDROID_NDK_ROOT} && \ curl -sLO https://github.com/android/ndk-samples/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv ndk-samples-master samples # Install android-BasicMediaDecoder in ${ANDROID_SDK_ROOT}/samples RUN mkdir ${ANDROID_SDK_ROOT}/samples && \ cd ${ANDROID_SDK_ROOT}/samples && \ curl -sLO https://github.com/googlearchive/android-BasicMediaDecoder/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv android-BasicMediaDecoder-master android-BasicMediaDecoder # Download buildtool to generate aab packages in ${ANDROID_SDK_ROOT} RUN cd ${ANDROID_SDK_ROOT} && \ curl -sLO https://github.com/google/bundletool/releases/download/1.3.0/bundletool-all-1.3.0.jar USER root qbs-src-2.6.1/docker/windowsservercore/0000755000175100001660000000000014776170045017511 5ustar runnerdockerqbs-src-2.6.1/docker/windowsservercore/Dockerfile0000644000175100001660000000503114776170045021502 0ustar runnerdocker FROM mcr.microsoft.com/windows/servercore:1809 LABEL Description="Windows Server Core development environment for Qbs with Qt, Chocolatey and various dependencies for testing Qbs modules and functionality" # Disable crash dialog for release-mode runtimes RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v Disabled /t REG_DWORD /d 1 /f RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v DontShowUI /t REG_DWORD /d 1 /f # Install VS 2019 from the website since chocolatey has broken .NET 4.8 (dotnetfx package) which is a # dependency for the visualstudio2019buildtools package RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \ Invoke-WebRequest "https://aka.ms/vs/16/release/vs_community.exe" \ -OutFile "%TEMP%\vs_community.exe" -UseBasicParsing RUN "%TEMP%\vs_community.exe" --quiet --wait --norestart --noUpdateInstaller \ --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 \ --add Microsoft.VisualStudio.Component.Windows10SDK.20348 RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \ $Env:chocolateyVersion = '0.10.15' ; \ $Env:chocolateyUseWindowsCompression = 'false' ; \ "[Net.ServicePointManager]::SecurityProtocol = \"tls12, tls11, tls\"; iex ((New-Object System.Net.WebClient).DownloadString('http://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" RUN choco install -y python --version 3.9 && \ choco install -y 7zip --version 19.0 && \ choco install -y git --version 2.24.0 --params "/GitAndUnixToolsOnPath" && \ choco install -y vswhere # for building the documentation RUN pip install beautifulsoup4 lxml # clcache for speeding up MSVC builds ENV CLCACHE_DIR="C:/.ccache" RUN certutil -generateSSTFromWU roots.sst && \ certutil -addstore -f root roots.sst && \ del roots.sst && \ pip install --trusted-host=pypi.org \ git+https://github.com/frerich/clcache.git@cae73d8255d78db8ba11e23c51fd2c9a89e7475b ########### Install Qt ############# ARG QT_VERSION COPY scripts/install-qt.sh install-qt.sh RUN bash -c "./install-qt.sh -d /c/Qt --version ${QT_VERSION} --toolchain win64_msvc2019_64 qtbase qtdeclarative qttools qt5compat" ENV QTDIR64=C:\\Qt\\${QT_VERSION}\\msvc2019_64 ########### Install Qbs ############# ARG QTCREATOR_VERSION RUN bash -c "./install-qt.sh -d /c/Qt --version ${QTCREATOR_VERSION} qtcreator" RUN setx PATH "C:\\Qt\\Tools\\QtCreator\\bin;%PATH%" RUN qbs setup-toolchains --detect && \ qbs setup-qt %QTDIR64%/bin/qmake.exe qt64 && \ qbs config defaultProfile qt64 qbs-src-2.6.1/docker/docker.qbs0000644000175100001660000000042114776170045015672 0ustar runnerdocker // This is a convenience product to be able to use Qt Creator for editing the docker files. // For building and managing the images, use docker-compose as explained in // https://doc.qt.io/qbs/building-qbs.html#using-docker. Product { name: "docker" files: "**" } qbs-src-2.6.1/LGPL_EXCEPTION.txt0000644000175100001660000000225014776170045015364 0ustar runnerdockerThe Qt Company LGPL Exception version 1.1 As an additional permission to the GNU Lesser General Public License version 2.1, the object code form of a "work that uses the Library" may incorporate material from a header file that is part of the Library. You may distribute such object code under terms of your choice, provided that: (i) the header files of the Library have not been modified; and (ii) the incorporated material is limited to numerical parameters, data structure layouts, accessors, macros, inline functions and templates; and (iii) you comply with the terms of Section 6 of the GNU Lesser General Public License version 2.1. Moreover, you may apply this exception to a modified version of the Library, provided that such modification does not involve copying material from the Library into the modified Library's header files unless such material is limited to (i) numerical parameters; (ii) data structure layouts; (iii) accessors; and (iv) small macros, templates and inline functions of five lines or less in length. Furthermore, you are not required to apply this additional permission to a modified version of the Library. qbs-src-2.6.1/tutorial/0000755000175100001660000000000014776170045014313 5ustar runnerdockerqbs-src-2.6.1/tutorial/LICENSE0000644000175100001660000000465714776170045015334 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** Files in this directory are part of the Qbs tutorial. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use these files 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this these files under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/qbs-src-2.6.1/tutorial/chapter-9/0000755000175100001660000000000014776170045016107 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/app/0000755000175100001660000000000014776170045016667 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/app/app.qbs0000644000175100001660000000025614776170045020161 0ustar runnerdocker//! [0] MyApplication { Depends { name: "mylib" } Depends { name: "version_header" } name: "My Application" targetName: "myapp" files: "main.c" } //! [0] qbs-src-2.6.1/tutorial/chapter-9/app/main.c0000644000175100001660000000033414776170045017757 0ustar runnerdocker//![0] #include #include #include int main() { printf("Hello, world\n"); printf("%s\n", get_string()); printf("ProductVersion = %s\n", kProductVersion); return 0; } //![0] qbs-src-2.6.1/tutorial/chapter-9/lib/0000755000175100001660000000000014776170045016655 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/lib/lib.h0000644000175100001660000000015614776170045017576 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-9/lib/lib.qbs0000644000175100001660000000022614776170045020132 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] } qbs-src-2.6.1/tutorial/chapter-9/lib/lib.c0000644000175100001660000000022414776170045017565 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.6.1/tutorial/chapter-9/lib/lib_global.h0000644000175100001660000000107514776170045021117 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MY_LIB_DECL_EXPORT __declspec(dllexport) #define MY_LIB_DECL_IMPORT __declspec(dllimport) #else #define MY_LIB_DECL_EXPORT __attribute__((visibility("default"))) #define MY_LIB_DECL_IMPORT __attribute__((visibility("default"))) #endif // ![0] // lib/lib_global.h #if defined(MYLIB_STATIC_LIBRARY) #define MYLIB_EXPORT #else #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MY_LIB_DECL_EXPORT #else #define MYLIB_EXPORT MY_LIB_DECL_IMPORT #endif #endif // ![0] #endif // LIB_GLOBAL_H qbs-src-2.6.1/tutorial/chapter-9/qbs/0000755000175100001660000000000014776170045016674 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/qbs/imports/0000755000175100001660000000000014776170045020371 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/qbs/imports/MyLibrary.qbs0000644000175100001660000000173514776170045023020 0ustar runnerdocker// ![0] Library { Depends { name: "cpp" } Depends { name: "mybuildconfig" } type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" version: mybuildconfig.productVersion install: !mybuildconfig.staticBuild || mybuildconfig.installStaticLib installDir: mybuildconfig.libInstallDir readonly property string _nameUpper : name.replace(" ", "_").toUpperCase() property string libraryMacro: _nameUpper + "_LIBRARY" property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY" cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] cpp.defines: exportingProduct.mybuildconfig.staticBuild ? [exportingProduct.staticLibraryMacro] : [] } Depends { name: "bundle" } bundle.isBundle: false } // ![0] qbs-src-2.6.1/tutorial/chapter-9/qbs/imports/MyAutoTest.qbs0000644000175100001660000000007014776170045023153 0ustar runnerdockerMyApplication { type: ["application", "autotest"] } qbs-src-2.6.1/tutorial/chapter-9/qbs/imports/MyApplication.qbs0000644000175100001660000000044414776170045023653 0ustar runnerdockerCppApplication { Depends { name: "mybuildconfig" } version: mybuildconfig.productVersion cpp.rpaths: mybuildconfig.libRPaths consoleApplication: true installDir: mybuildconfig.appInstallDir install: true installDebugInformation: project.installDebugInformation } qbs-src-2.6.1/tutorial/chapter-9/qbs/modules/0000755000175100001660000000000014776170045020344 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/qbs/modules/mybuildconfig/0000755000175100001660000000000014776170045023177 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/qbs/modules/mybuildconfig/mybuildconfig.qbs0000644000175100001660000000157114776170045026545 0ustar runnerdockerimport qbs.FileInfo //! [0] // qbs/modules/mybuildconfig/mybuildconfig.qbs Module { Depends { name: "cpp" } property string productVersion: "1.0.0" // ... //! [0] property string appInstallDir: "bin" property string libDirName: "lib" property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName property bool staticBuild: false property bool installStaticLib: true property bool enableRPath: true property stringList libRPaths: { if (enableRPath && cpp.rpathOrigin && product.installDir) { return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.installDir), FileInfo.joinPaths('/', libDirName))) ]; } return []; } } qbs-src-2.6.1/tutorial/chapter-9/myproject.qbs0000644000175100001660000000134114776170045020631 0ustar runnerdockerProject { property string version: "1.0.0" property bool withTests: true property bool installDebugInformation: true property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" //! [0] // myproject.qbs references: [ "app/app.qbs", "lib/lib.qbs", "version-header/version-header.qbs", ] //! [0] qbsSearchPaths: "qbs" SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } } qbs-src-2.6.1/tutorial/chapter-9/version-header/0000755000175100001660000000000014776170045021022 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/version-header/version.h.in0000644000175100001660000000023614776170045023266 0ustar runnerdocker//! [0] // version-header/version.h.in #ifndef VERSION_H #define VERSION_H const char kProductVersion[] = "${PRODUCT_VERSION}"; #endif // VERSION_H //! [0] qbs-src-2.6.1/tutorial/chapter-9/version-header/version-header.qbs0000644000175100001660000000234514776170045024450 0ustar runnerdocker//! [5] // version-header/version-header.qbs //! [0] import qbs.TextFile Product { name: "version_header" type: "hpp" Depends { name: "mybuildconfig" } //! [0] //! [1] Group { files: ["version.h.in"] fileTags: ["version_h_in"] } //! [1] //! [2] Rule { inputs: ["version_h_in"] Artifact { filePath: "version.h" fileTags: "hpp" } //! [2] //! [3] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(input.filePath, TextFile.ReadOnly); var content = file.readAll(); content = content.replace( "${PRODUCT_VERSION}", product.mybuildconfig.productVersion); file = new TextFile(output.filePath, TextFile.WriteOnly); file.write(content); file.close(); } return cmd; } //! [3] } //! [4] Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.buildDirectory } //! [4] } //! [5] qbs-src-2.6.1/tutorial/chapter-9/test/0000755000175100001660000000000014776170045017066 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-9/test/test.qbs0000644000175100001660000000012414776170045020551 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.6.1/tutorial/chapter-9/test/test.c0000644000175100001660000000056214776170045020214 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.6.1/tutorial/chapter-3/0000755000175100001660000000000014776170045016101 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-3/app/0000755000175100001660000000000014776170045016661 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-3/app/app.qbs0000644000175100001660000000112114776170045020143 0ustar runnerdocker//! [1] // app/app.qbs import qbs.FileInfo CppApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" version: "1.0.0" consoleApplication: true install: true //! [0] cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } //! [0] } //! [1] qbs-src-2.6.1/tutorial/chapter-3/app/main.c0000644000175100001660000000020314776170045017744 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-3/lib/0000755000175100001660000000000014776170045016647 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-3/lib/lib.h0000644000175100001660000000021314776170045017562 0ustar runnerdocker#ifndef LIB_H #define LIB_H //! [0] // lib/lib.h #include "lib_global.h" MYLIB_EXPORT const char *get_string(); //! [0] #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-3/lib/lib.qbs0000644000175100001660000000100414776170045020117 0ustar runnerdocker//! [0] // lib/lib.qbs DynamicLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] version: "1.0.0" install: true Depends { name: "cpp" } cpp.defines: ["MYLIB_LIBRARY", "CRUCIAL_DEFINE"] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: "bundle" } bundle.isBundle: false } //! [0] qbs-src-2.6.1/tutorial/chapter-3/lib/lib.c0000644000175100001660000000026614776170045017565 0ustar runnerdocker //! [0] // lib/lib.cpp #include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } //! [0] qbs-src-2.6.1/tutorial/chapter-3/lib/lib_global.h0000644000175100001660000000076514776170045021116 0ustar runnerdocker//! [0] // lib/lib_global.h #ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H //! [0] qbs-src-2.6.1/tutorial/chapter-3/myproject.qbs0000644000175100001660000000017714776170045020631 0ustar runnerdockerProject { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs" ] } qbs-src-2.6.1/tutorial/chapter-4/0000755000175100001660000000000014776170045016102 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-4/app/0000755000175100001660000000000014776170045016662 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-4/app/app.qbs0000644000175100001660000000022714776170045020152 0ustar runnerdocker//! [0] // app/app.qbs MyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } //! [0] qbs-src-2.6.1/tutorial/chapter-4/app/main.c0000644000175100001660000000020314776170045017745 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-4/lib/0000755000175100001660000000000014776170045016650 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-4/lib/lib.h0000644000175100001660000000015614776170045017571 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-4/lib/lib.qbs0000644000175100001660000000027614776170045020132 0ustar runnerdocker//! [0] // lib/lib.qbs MyLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] cpp.defines: base.concat(["CRUCIAL_DEFINE"]) } //! [0] qbs-src-2.6.1/tutorial/chapter-4/lib/lib.c0000644000175100001660000000022414776170045017560 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.6.1/tutorial/chapter-4/lib/lib_global.h0000644000175100001660000000071714776170045021114 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.6.1/tutorial/chapter-4/qbs/0000755000175100001660000000000014776170045016667 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-4/qbs/imports/0000755000175100001660000000000014776170045020364 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-4/qbs/imports/MyLibrary.qbs0000644000175100001660000000076214776170045023012 0ustar runnerdocker//! [0] // qbs/imports/MyLibrary.qbs DynamicLibrary { version: "1.0.0" install: true Depends { name: 'cpp' } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } //! [0] qbs-src-2.6.1/tutorial/chapter-4/qbs/imports/MyApplication.qbs0000644000175100001660000000074614776170045023653 0ustar runnerdocker//! [0] // qbs/imports/MyApplication.qbs import qbs.FileInfo CppApplication { version: "1.0.0" consoleApplication: true install: true cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } } //! [0] qbs-src-2.6.1/tutorial/chapter-4/myproject.qbs0000644000175100001660000000025014776170045020622 0ustar runnerdocker//! [0] Project { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs" ] qbsSearchPaths: "qbs" } //! [0] qbs-src-2.6.1/tutorial/chapter-7/0000755000175100001660000000000014776170045016105 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/app/0000755000175100001660000000000014776170045016665 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/app/app.qbs0000644000175100001660000000016714776170045020160 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.6.1/tutorial/chapter-7/app/main.c0000644000175100001660000000020314776170045017750 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-7/lib/0000755000175100001660000000000014776170045016653 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/lib/lib.h0000644000175100001660000000015614776170045017574 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-7/lib/lib.qbs0000644000175100001660000000504214776170045020131 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MyLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] } qbs-src-2.6.1/tutorial/chapter-7/lib/lib.c0000644000175100001660000000022414776170045017563 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.6.1/tutorial/chapter-7/lib/lib_global.h0000644000175100001660000000071714776170045021117 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.6.1/tutorial/chapter-7/qbs/0000755000175100001660000000000014776170045016672 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/qbs/imports/0000755000175100001660000000000014776170045020367 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/qbs/imports/MyLibrary.qbs0000644000175100001660000000123614776170045023012 0ustar runnerdockerDynamicLibrary { version: project.version install: true installDebugInformation: project.installDebugInformation //! [0] // qbs/imports/MyLibrary.qbs // ... Depends { name: "mybuildconfig" } installDir: mybuildconfig.libInstallDir Depends { name: "cpp" } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { // ... //! [0] Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.6.1/tutorial/chapter-7/qbs/imports/MyAutoTest.qbs0000644000175100001660000000007014776170045023151 0ustar runnerdockerMyApplication { type: ["application", "autotest"] } qbs-src-2.6.1/tutorial/chapter-7/qbs/imports/MyApplication.qbs0000644000175100001660000000040314776170045023644 0ustar runnerdocker//! [0] CppApplication { Depends { name: "mybuildconfig" } installDir: mybuildconfig.appInstallDir version: "1.0.0" // ... //! [0] consoleApplication: true install: true installDebugInformation: project.installDebugInformation } qbs-src-2.6.1/tutorial/chapter-7/qbs/modules/0000755000175100001660000000000014776170045020342 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/qbs/modules/mybuildconfig/0000755000175100001660000000000014776170045023175 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/qbs/modules/mybuildconfig/mybuildconfig.qbs0000644000175100001660000000137314776170045026543 0ustar runnerdockerimport qbs.FileInfo //! [1] //! [0] // qbs/modules/mybuildconfig.qbs Module { property string appInstallDir: "bin" property string libDirName: "lib" property string libInstallDir: qbs.targetOS.contains("windows") ? appInstallDir : libDirName //! [0] Depends { name: "cpp" } property bool enableRPath: true property stringList libRPaths: { if (enableRPath && cpp.rpathOrigin && product.installDir) { return [FileInfo.joinPaths(cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.installDir), FileInfo.joinPaths('/', libInstallDir)))]; } return []; } cpp.rpaths: libRPaths } //! [1] qbs-src-2.6.1/tutorial/chapter-7/myproject.qbs0000644000175100001660000000114214776170045020626 0ustar runnerdockerProject { property bool withTests: true property bool installDebugInformation: true property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs", ] qbsSearchPaths: "qbs" SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } } qbs-src-2.6.1/tutorial/chapter-7/test/0000755000175100001660000000000014776170045017064 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-7/test/test.qbs0000644000175100001660000000012414776170045020547 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.6.1/tutorial/chapter-7/test/test.c0000644000175100001660000000056214776170045020212 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.6.1/tutorial/chapter-8/0000755000175100001660000000000014776170045016106 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/app/0000755000175100001660000000000014776170045016666 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/app/app.qbs0000644000175100001660000000016714776170045020161 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.6.1/tutorial/chapter-8/app/main.c0000644000175100001660000000020314776170045017751 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-8/lib/0000755000175100001660000000000014776170045016654 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/lib/lib.h0000644000175100001660000000015614776170045017575 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-8/lib/lib.qbs0000644000175100001660000000022614776170045020131 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] } qbs-src-2.6.1/tutorial/chapter-8/lib/lib.c0000644000175100001660000000022414776170045017564 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.6.1/tutorial/chapter-8/lib/lib_global.h0000644000175100001660000000107414776170045021115 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MY_LIB_DECL_EXPORT __declspec(dllexport) #define MY_LIB_DECL_IMPORT __declspec(dllimport) #else #define MY_LIB_DECL_EXPORT __attribute__((visibility("default"))) #define MY_LIB_DECL_IMPORT __attribute__((visibility("default"))) #endif // ![0] // lib/lib_global.h #if defined(MYLIB_STATIC_LIBRARY) #define MYLIB_EXPORT #else #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MY_LIB_DECL_EXPORT #else #define MYLIB_EXPORT MY_LIB_DECL_IMPORT #endif #endif // ![0] #endif // LIB_GLOBAL_Hqbs-src-2.6.1/tutorial/chapter-8/qbs/0000755000175100001660000000000014776170045016673 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/qbs/imports/0000755000175100001660000000000014776170045020370 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/qbs/imports/MyLibrary.qbs0000644000175100001660000000171014776170045023010 0ustar runnerdocker// ![0] Library { Depends { name: "cpp" } Depends { name: "mybuildconfig" } type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" version: "1.0.0" install: !mybuildconfig.staticBuild || mybuildconfig.installStaticLib installDir: mybuildconfig.libInstallDir readonly property string _nameUpper : name.replace(" ", "_").toUpperCase() property string libraryMacro: _nameUpper + "_LIBRARY" property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY" cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] cpp.defines: exportingProduct.mybuildconfig.staticBuild ? [exportingProduct.staticLibraryMacro] : [] } Depends { name: "bundle" } bundle.isBundle: false } // ![0] qbs-src-2.6.1/tutorial/chapter-8/qbs/imports/MyAutoTest.qbs0000644000175100001660000000007014776170045023152 0ustar runnerdockerMyApplication { type: ["application", "autotest"] } qbs-src-2.6.1/tutorial/chapter-8/qbs/imports/MyApplication.qbs0000644000175100001660000000041714776170045023652 0ustar runnerdockerCppApplication { Depends { name: "mybuildconfig" } version: "1.0.0" cpp.rpaths: mybuildconfig.libRPaths consoleApplication: true installDir: mybuildconfig.appInstallDir install: true installDebugInformation: project.installDebugInformation } qbs-src-2.6.1/tutorial/chapter-8/qbs/modules/0000755000175100001660000000000014776170045020343 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/qbs/modules/mybuildconfig/0000755000175100001660000000000014776170045023176 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/qbs/modules/mybuildconfig/mybuildconfig.qbs0000644000175100001660000000137714776170045026550 0ustar runnerdockerimport qbs.FileInfo Module { Depends { name: "cpp" } property string appInstallDir: "bin" property string libDirName: "lib" property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName property bool staticBuild: false property bool installStaticLib: true property bool enableRPath: true property stringList libRPaths: { if (enableRPath && cpp.rpathOrigin && product.installDir) { return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.installDir), FileInfo.joinPaths('/', libDirName))) ]; } return []; } } qbs-src-2.6.1/tutorial/chapter-8/myproject.qbs0000644000175100001660000000114214776170045020627 0ustar runnerdockerProject { property bool withTests: true property bool installDebugInformation: true property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs", ] qbsSearchPaths: "qbs" SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } } qbs-src-2.6.1/tutorial/chapter-8/test/0000755000175100001660000000000014776170045017065 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-8/test/test.qbs0000644000175100001660000000012414776170045020550 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.6.1/tutorial/chapter-8/test/test.c0000644000175100001660000000056214776170045020213 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.6.1/tutorial/chapter-1/0000755000175100001660000000000014776170045016077 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-1/app/0000755000175100001660000000000014776170045016657 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-1/app/app.qbs0000644000175100001660000000032114776170045020142 0ustar runnerdocker//! [0] CppApplication { name: "My Application" targetName: "myapp" files: "main.c" version: "1.0.0" consoleApplication: true install: true installDebugInformation: true } //! [0] qbs-src-2.6.1/tutorial/chapter-1/app/main.c0000644000175100001660000000013714776170045017750 0ustar runnerdocker//! [0] #include int main() { printf("Hello, world\n"); return 0; } //! [0] qbs-src-2.6.1/tutorial/chapter-1/myproject.qbs0000644000175100001660000000017114776170045020621 0ustar runnerdocker//! [0] Project { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs" ] } //! [0] qbs-src-2.6.1/tutorial/chapter-10-2/0000755000175100001660000000000014776170045016316 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-10-2/app/0000755000175100001660000000000014776170045017076 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-10-2/app/app.qbs0000644000175100001660000000106314776170045020365 0ustar runnerdockerCppApplication { condition: qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16) consoleApplication: true name: "app" files: ["main.cpp"] install: true cpp.rpaths: [cpp.rpathOrigin + "/../lib"] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true Depends { name: "mylib" } } qbs-src-2.6.1/tutorial/chapter-10-2/app/main.cpp0000644000175100001660000000007614776170045020531 0ustar runnerdockerimport hello; int main() { Hello::printHello("world"); } qbs-src-2.6.1/tutorial/chapter-10-2/lib/0000755000175100001660000000000014776170045017064 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-10-2/lib/hello.cppm0000644000175100001660000000044214776170045021050 0ustar runnerdocker//![0] // lib/hello.cppm module; #include "lib_global.h" #include #include export module hello; export namespace Hello { void MYLIB_EXPORT printHello(std::string_view name) { std::cout << "Hello, " << name << '!' << std::endl; } } // namespace Hello //![0]qbs-src-2.6.1/tutorial/chapter-10-2/lib/lib.qbs0000644000175100001660000000151514776170045020343 0ustar runnerdocker//! [0] // lib/lib.qbs DynamicLibrary { condition: { if (qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } name: "mylib" files: ["hello.cppm", "lib_global.h"] version: "1.0.0" install: true Depends { name: "cpp" } cpp.defines: "MYLIB_LIBRARY" cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true Depends { name: "bundle" } bundle.isBundle: false } qbs-src-2.6.1/tutorial/chapter-10-2/lib/lib_global.h0000644000175100001660000000076514776170045021333 0ustar runnerdocker//! [0] // lib/lib_global.h #ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H //! [0] qbs-src-2.6.1/tutorial/chapter-10-2/myproject.qbs0000644000175100001660000000017714776170045021046 0ustar runnerdockerProject { name: "My Project" minimumQbsVersion: "2.5" references: [ "app/app.qbs", "lib/lib.qbs" ] } qbs-src-2.6.1/tutorial/chapter-10-1/0000755000175100001660000000000014776170045016315 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-10-1/hello.cppm0000644000175100001660000000037114776170045020302 0ustar runnerdocker//![0] // hello.cppm module; #include #include export module hello; export namespace Hello { void printHello(std::string_view name) { std::cout << "Hello, " << name << '!' << std::endl; } } // namespace Hello //![0]qbs-src-2.6.1/tutorial/chapter-10-1/myproject.qbs0000644000175100001660000000112614776170045021040 0ustar runnerdocker// myproject.qbs CppApplication { condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true install: true files: ["hello.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true } qbs-src-2.6.1/tutorial/chapter-10-1/main.cpp0000644000175100001660000000013014776170045017737 0ustar runnerdocker//![0] // main.cpp import hello; int main() { Hello::printHello("World"); } //![0]qbs-src-2.6.1/tutorial/tutorial.qbs0000644000175100001660000000005714776170045016667 0ustar runnerdockerProduct { files: [ "*/**", ] } qbs-src-2.6.1/tutorial/chapter-6/0000755000175100001660000000000014776170045016104 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-6/app/0000755000175100001660000000000014776170045016664 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-6/app/app.qbs0000644000175100001660000000016714776170045020157 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.6.1/tutorial/chapter-6/app/main.c0000644000175100001660000000020314776170045017747 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-6/lib/0000755000175100001660000000000014776170045016652 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-6/lib/lib.h0000644000175100001660000000015614776170045017573 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-6/lib/lib.qbs0000644000175100001660000000023614776170045020130 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] cpp.defines: base.concat(['CRUCIAL_DEFINE']) } qbs-src-2.6.1/tutorial/chapter-6/lib/lib.c0000644000175100001660000000022414776170045017562 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.6.1/tutorial/chapter-6/lib/lib_global.h0000644000175100001660000000071714776170045021116 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.6.1/tutorial/chapter-6/qbs/0000755000175100001660000000000014776170045016671 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-6/qbs/imports/0000755000175100001660000000000014776170045020366 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-6/qbs/imports/MyLibrary.qbs0000644000175100001660000000101114776170045023000 0ustar runnerdockerDynamicLibrary { version: project.version install: true installDebugInformation: project.installDebugInformation Depends { name: 'cpp' } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.6.1/tutorial/chapter-6/qbs/imports/MyAutoTest.qbs0000644000175100001660000000006614776170045023155 0ustar runnerdockerMyApplication { type: base.concat(["autotest"]) } qbs-src-2.6.1/tutorial/chapter-6/qbs/imports/MyApplication.qbs0000644000175100001660000000103014776170045023640 0ustar runnerdockerimport qbs.FileInfo //! [0] CppApplication { version: project.version consoleApplication: true install: true installDebugInformation: project.installDebugInformation // ... //! [0] cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } } qbs-src-2.6.1/tutorial/chapter-6/myproject.qbs0000644000175100001660000000132714776170045020632 0ustar runnerdocker//! [0] Project { property string version: "1.0.0" property bool installDebugInformation: true property bool withTests: false property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" // ... //! [0] references: [ "app/app.qbs", "lib/lib.qbs", ] qbsSearchPaths: "qbs" //! [1] SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } //! [1] //! [2] AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } //! [2] } qbs-src-2.6.1/tutorial/chapter-6/test/0000755000175100001660000000000014776170045017063 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-6/test/test.qbs0000644000175100001660000000012414776170045020546 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.6.1/tutorial/chapter-6/test/test.c0000644000175100001660000000056214776170045020211 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.6.1/tutorial/chapter-5/0000755000175100001660000000000014776170045016103 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-5/app/0000755000175100001660000000000014776170045016663 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-5/app/app.qbs0000644000175100001660000000016714776170045020156 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.6.1/tutorial/chapter-5/app/main.c0000644000175100001660000000020314776170045017746 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-5/lib/0000755000175100001660000000000014776170045016651 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-5/lib/lib.h0000644000175100001660000000015614776170045017572 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.6.1/tutorial/chapter-5/lib/lib.qbs0000644000175100001660000000023614776170045020127 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] cpp.defines: base.concat(['CRUCIAL_DEFINE']) } qbs-src-2.6.1/tutorial/chapter-5/lib/lib.c0000644000175100001660000000022414776170045017561 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.6.1/tutorial/chapter-5/lib/lib_global.h0000644000175100001660000000071714776170045021115 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.6.1/tutorial/chapter-5/qbs/0000755000175100001660000000000014776170045016670 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-5/qbs/imports/0000755000175100001660000000000014776170045020365 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-5/qbs/imports/MyLibrary.qbs0000644000175100001660000000070414776170045023007 0ustar runnerdockerDynamicLibrary { version: "1.0.0" install: true Depends { name: 'cpp' } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.6.1/tutorial/chapter-5/qbs/imports/MyAutoTest.qbs0000644000175100001660000000014514776170045023152 0ustar runnerdocker//! [0] // qbs/imports/MyAutoTest.qbs MyApplication { type: base.concat(["autotest"]) } //! [0] qbs-src-2.6.1/tutorial/chapter-5/qbs/imports/MyApplication.qbs0000644000175100001660000000072614776170045023652 0ustar runnerdockerimport qbs.FileInfo CppApplication { version: "1.0.0" consoleApplication: true install: true installDebugInformation: true cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } } qbs-src-2.6.1/tutorial/chapter-5/myproject.qbs0000644000175100001660000000040014776170045020620 0ustar runnerdockerProject { name: "My Project" minimumQbsVersion: "2.0" // ![0] references: [ "app/app.qbs", "lib/lib.qbs", "test/test.qbs", ] // ![0] qbsSearchPaths: "qbs" AutotestRunner { timeout: 60 } } qbs-src-2.6.1/tutorial/chapter-5/test/0000755000175100001660000000000014776170045017062 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-5/test/test.qbs0000644000175100001660000000016614776170045020553 0ustar runnerdocker//! [0] // test/test.qbs MyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } //! [0] qbs-src-2.6.1/tutorial/chapter-5/test/test.c0000644000175100001660000000062114776170045020204 0ustar runnerdocker//! [0] // test/test.c #include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } //! [0]qbs-src-2.6.1/tutorial/chapter-2/0000755000175100001660000000000014776170045016100 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-2/app/0000755000175100001660000000000014776170045016660 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-2/app/app.qbs0000644000175100001660000000033714776170045020152 0ustar runnerdockerCppApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" version: "1.0.0" consoleApplication: true install: true installDebugInformation: true } qbs-src-2.6.1/tutorial/chapter-2/app/main.c0000644000175100001660000000020314776170045017743 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.6.1/tutorial/chapter-2/lib/0000755000175100001660000000000014776170045016646 5ustar runnerdockerqbs-src-2.6.1/tutorial/chapter-2/lib/lib.h0000644000175100001660000000014714776170045017567 0ustar runnerdocker//! [0] // lib/lib.h #ifndef LIB_H #define LIB_H const char *get_string(); #endif // LIB_H //! [0] qbs-src-2.6.1/tutorial/chapter-2/lib/lib.qbs0000644000175100001660000000070514776170045020125 0ustar runnerdocker//! [0] StaticLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] version: "1.0.0" install: true //! [1] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] //! [1] //! [2] Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } //! [2] //! [3] Depends { name: 'bundle' } bundle.isBundle: false //! [3] } //! [0] qbs-src-2.6.1/tutorial/chapter-2/lib/lib.c0000644000175100001660000000026514776170045017563 0ustar runnerdocker//! [0] // lib/lib.cpp #include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } //! [0] qbs-src-2.6.1/tutorial/chapter-2/myproject.qbs0000644000175100001660000000021714776170045020623 0ustar runnerdocker//! [0] Project { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs" ] } //! [0] qbs-src-2.6.1/RELEASE.md0000644000175100001660000000670514776170045014062 0ustar runnerdocker# Release Instructions This file contains instructions how to publish a Qbs release into various package systems. ## Building packages Release packages are built automatically by the [Build release packages](https://github.com/qbs/qbs/actions/workflows/release.yml) job on GitHub actions. The job builds every commit, so you'll need to find a specific run triggered by pushing a git tag instead of a commit. The only interesting artifact is qbs-release-v1.x.y - it contains Windows binary packages as well as source packages. Packages should then be uploaded to the [Qt Website](https://download.qt.io/official_releases/qbs/). ## Chocolatey For updating Qbs in [Chocolatey](https://community.chocolatey.org/packages/qbs), you'll need to be a maintainer of the Qbs project. You'll also will need an API key from your [account](https://community.chocolatey.org/account) (make sure you have one). Get the qbs.1.x.y.nupkg file from the qbs-release-v1.x.y.zip archive and run the following command: ``` choco push --api-key qbs.1.x.y.nupkg" ``` Choco will upload the file, download binary packages from the Qt Website and publish Qbs automatically. ## Homebrew First, you'll need to [install](https://docs.brew.sh/Installation) Homewbrew. Second, you'll need to fork the [homebrew-core](https://github.com/Homebrew/homebrew-core) repo to you GitHub account. Next you'll need to add your remote to the existing repo: ``` $ brew update $ cd "$(brew --repository homebrew/core)" $ git remote add github git@github.com:/homebrew-core.git # Create a new git branch for your formula so your pull request is easy to # modify if any changes come up during review. $ git checkout -b origin/master ``` You'll need a SHA-256 sum for the qbs-src-1.x.y.tar.gz source package. SHA-256 sum can be found in the sha256sums.txt file from the qbs-release-v1.x.y.zip. Check if the same upgrade has been already submitted by searching the open pull requests for [Qbs](https://github.com/Homebrew/homebrew-core/pulls?q=is%3Apr+is%3Aopen+qbs). Run the following command, replacing the version and SHA-256 sum: ``` $ brew bump-formula-pr --strict qbs \ --url https://download.qt.io/official_releases/qbs/1.x.y/qbs-src-1.x.y.tar.gz \ --sha256= ``` The above can also be done manually by editing the formula source code and creating a pull request. Some useful commands to build/test formula locally: ``` $ brew install --build-from-source qbs $ brew test qbs $ brew audit --strict qbs ``` ## Mac Ports Fork [macports-ports](https://github.com/macports/macports-ports) to your GitHub account and clone the repo. Run the following command in the repo dir (must be done only once): ``` $ sudo /opt/local/bin/portindex ``` Make sure that /opt/local/etc/macports/sources.conf contains a line like file:///Users/abbapoh/dev/macports-ports [default] pointing to your local repo. Get the qbs-src-1.x.y.tar.gz source package from the archive or from the [Qt Website](https://download.qt.io/official_releases/qbs/) and make note of the file size: ``` $ ls -l qbs-src-1.x.y.tar.gz ``` Get checksums: ``` $ openssl sha256 qbs-src-1.x.y.tar.gz $ openssl rmd160 qbs-src-1.x.y.tar.gz ``` Update the devel/qbs/Portfile file with the new url, filesize and checksums. Build the package: ``` $ /opt/local/bin/port lint qbs $ sudo /opt/local/bin/port -vst install qbs $ /opt/local/bin/qbs --version # Check that this reports the right version ``` Commit. Push. Create merge request. qbs-src-2.6.1/LICENSE.LGPLv210000644000175100001660000006350214776170045014551 0ustar runnerdocker GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! qbs-src-2.6.1/src/0000755000175100001660000000000014776170045013237 5ustar runnerdockerqbs-src-2.6.1/src/app/0000755000175100001660000000000014776170045014017 5ustar runnerdockerqbs-src-2.6.1/src/app/config/0000755000175100001660000000000014776170045015264 5ustar runnerdockerqbs-src-2.6.1/src/app/config/configcommandlineparser.h0000644000175100001660000000566114776170045022336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef COMMANDLINEPARSER_H #define COMMANDLINEPARSER_H #include "configcommand.h" #include #include class ConfigCommandLineParser { public: void parse(const QStringList &commandLine); ConfigCommand command() const { return m_command; } qbs::Settings::Scopes scope() const { return m_scope; } QString settingsDir() const { return m_settingsDir; } bool helpRequested() const { return m_helpRequested; } void printUsage() const; class Error { public: Error(QString message) : m_message(std::move(message)) { } QString message() const { return m_message; } private: QString m_message; }; private: void assignOptionArgument(const QString &option, QString &argument); void setCommand(ConfigCommand::Command command); void setScope(qbs::Settings::Scope scope); ConfigCommand m_command; qbs::Settings::Scopes m_scope = qbs::Settings::allScopes(); bool m_helpRequested = false; QString m_settingsDir; QStringList m_commandLine; }; #endif // COMMANDLINEPARSER_H qbs-src-2.6.1/src/app/config/configmain.cpp0000644000175100001660000000565414776170045020114 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "configcommandlineparser.h" #include "configcommandexecutor.h" #include #include #include #include #include #include using qbs::Internal::Tr; using qbs::Settings; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); ConfigCommandLineParser parser; try { parser.parse(app.arguments().mid(1)); if (parser.helpRequested()) { std::cout << qPrintable(Tr::tr("This tool manages qbs settings.")) << std::endl; parser.printUsage(); return EXIT_SUCCESS; } Settings settings(parser.settingsDir()); ConfigCommandExecutor(&settings, parser.scope()).execute(parser.command()); } catch (const ConfigCommandLineParser::Error &e) { std::cerr << qPrintable(e.message()) << std::endl; parser.printUsage(); return EXIT_FAILURE; } catch (const qbs::ErrorInfo &e) { std::cerr << qPrintable(e.toString()) << std::endl; return EXIT_FAILURE; } } qbs-src-2.6.1/src/app/config/config.qbs0000644000175100001660000000037614776170045017246 0ustar runnerdockerQbsApp { name: "qbs-config" files: [ "configcommand.h", "configcommandexecutor.cpp", "configcommandexecutor.h", "configcommandlineparser.cpp", "configcommandlineparser.h", "configmain.cpp" ] } qbs-src-2.6.1/src/app/config/configcommandexecutor.h0000644000175100001660000000512514776170045022023 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CONFIGCOMMANDEXECUTOR_H #define CONFIGCOMMANDEXECUTOR_H #include #include class ConfigCommand; class ConfigCommandExecutor { Q_DECLARE_TR_FUNCTIONS(ConfigCommandExecutor) public: ConfigCommandExecutor(qbs::Settings *settings, qbs::Settings::Scopes scope); void execute(const ConfigCommand &command); private: void setValue(const QString &key, const QString &rawInput); void printSettings(const ConfigCommand &command); void printOneSetting(const QString &key); void exportSettings(const QString &filename); void importSettings(const QString &filename); qbs::Settings *m_settings; const qbs::Settings::Scopes m_scope; }; #endif // CONFIGCOMMANDEXECUTOR_H qbs-src-2.6.1/src/app/config/CMakeLists.txt0000644000175100001660000000041314776170045020022 0ustar runnerdockerset(SOURCES configcommand.h configcommandexecutor.cpp configcommandexecutor.h configcommandlineparser.cpp configcommandlineparser.h configmain.cpp ) add_qbs_app(qbs-config DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.6.1/src/app/config/configcommandlineparser.cpp0000644000175100001660000001635414776170045022672 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "configcommandlineparser.h" #include #include #include using namespace qbs; using namespace Internal; void ConfigCommandLineParser::parse(const QStringList &commandLine) { m_command = ConfigCommand(); m_helpRequested = false; m_settingsDir.clear(); m_commandLine = commandLine; if (m_commandLine.empty()) throw Error(Tr::tr("No parameters supplied.")); if (m_commandLine.size() == 1 && (m_commandLine.front() == QLatin1String("--help") || m_commandLine.front() == QLatin1String("-h"))) { m_helpRequested = true; return; } while (!m_commandLine.empty() && m_commandLine.front().startsWith(QLatin1String("--"))) { const QString arg = m_commandLine.takeFirst().mid(2); if (arg == QLatin1String("list")) setCommand(ConfigCommand::CfgList); else if (arg == QLatin1String("unset")) setCommand(ConfigCommand::CfgUnset); else if (arg == QLatin1String("export")) setCommand(ConfigCommand::CfgExport); else if (arg == QLatin1String("import")) setCommand(ConfigCommand::CfgImport); else if (arg == QLatin1String("add-profile")) setCommand(ConfigCommand::CfgAddProfile); else if (arg == QLatin1String("settings-dir")) assignOptionArgument(arg, m_settingsDir); else if (arg == QLatin1String("user")) setScope(qbs::Settings::UserScope); else if (arg == QLatin1String("system")) setScope(qbs::Settings::SystemScope); else throw Error(Tr::tr("Unknown option for config command.")); } switch (command().command) { case ConfigCommand::CfgNone: if (m_commandLine.empty()) throw Error(Tr::tr("No parameters supplied.")); if (m_commandLine.size() > 2) throw Error(Tr::tr("Too many arguments.")); m_command.varNames << m_commandLine.front(); if (m_commandLine.size() == 1) { setCommand(ConfigCommand::CfgList); } else { m_command.varValue = m_commandLine.at(1); setCommand(ConfigCommand::CfgSet); } break; case ConfigCommand::CfgUnset: if (m_commandLine.empty()) throw Error(Tr::tr("Need name of variable to unset.")); m_command.varNames = m_commandLine; break; case ConfigCommand::CfgExport: if (m_commandLine.size() != 1) throw Error(Tr::tr("Need name of file to which to export.")); m_command.fileName = m_commandLine.front(); break; case ConfigCommand::CfgImport: if (m_commandLine.size() != 1) throw Error(Tr::tr("Need name of file from which to import.")); m_command.fileName = m_commandLine.front(); break; case ConfigCommand::CfgList: m_command.varNames = m_commandLine; break; case ConfigCommand::CfgAddProfile: if (m_commandLine.empty()) throw Error(Tr::tr("Profile name missing.")); m_command.varValue = m_commandLine.takeFirst(); if (m_command.varValue.isEmpty()) throw Error(Tr::tr("Profile name must not be empty.")); m_command.varNames = m_commandLine; if (m_command.varNames.isEmpty()) throw Error(Tr::tr("Profile properties must be provided.")); if (m_command.varNames.size() % 2 != 0) throw Error(Tr::tr("Profile properties must be key/value pairs.")); for (const auto &varName : std::as_const(m_command.varNames)) { if (varName.isEmpty()) throw Error(Tr::tr("Property names must not be empty.")); } break; default: break; } } void ConfigCommandLineParser::setCommand(ConfigCommand::Command command) { if (m_command.command != ConfigCommand::CfgNone) throw Error(Tr::tr("You cannot specify more than one command.")); m_command.command = command; } void ConfigCommandLineParser::setScope(Settings::Scope scope) { if (m_scope != qbs::Settings::allScopes()) throw Error(Tr::tr("The --user and --system options can only appear once.")); m_scope = scope; } void ConfigCommandLineParser::printUsage() const { std::puts("Usage:\n" " qbs config [--settings-dir \n" " qbs config [--settings-dir \n" " qbs config [--settings-dir " "\n" "Options:\n" " --list [ ...] list keys under key or all keys\n" " --user consider only user-level settings\n" " --system consider only system-level settings\n" " --unset remove key with given name\n" " --add-profile ... add profile with the given name and properties\n" " --import import settings from given file\n" " --export export settings to given file\n"); } void ConfigCommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throw Error(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throw Error(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } qbs-src-2.6.1/src/app/config/configcommandexecutor.cpp0000644000175100001660000002053214776170045022355 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "configcommandexecutor.h" #include "configcommand.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using namespace qbs; static QJsonObject settingsToJSONObject( Settings &settings, qbs::Settings::Scopes scopes, const QString &parentGroup = {}) { QJsonObject result; const auto allKeys = settings.directChildren(parentGroup, scopes); for (const auto& key : allKeys) { const auto fullKey = parentGroup.isEmpty() ? key : QStringLiteral("%1.%2").arg(parentGroup, key); const auto value = settings.value(fullKey, scopes); if (value.isValid()) { // looks like a real value result[key] = QJsonValue::fromVariant(value); } else { // looks like a group result[key] = settingsToJSONObject(settings, scopes, fullKey); } } return result; } static void settingsFromJSONObject( Settings &settings, const QJsonObject &object, const QString &parentGroup = {}) { for (auto it = object.begin(), end = object.end(); it != end; ++it) { const auto key = it.key(); const auto value = it.value(); const auto fullKey = parentGroup.isEmpty() ? key : QStringLiteral("%1.%2").arg(parentGroup, key); if (value.isObject()) { settingsFromJSONObject(settings, it.value().toObject(), fullKey); } else { settings.setValue(fullKey, value.toVariant()); } } } ConfigCommandExecutor::ConfigCommandExecutor(Settings *settings, Settings::Scopes scope) : m_settings(settings), m_scope(scope) { if (m_scope == qbs::Settings::SystemScope) m_settings->setScopeForWriting(qbs::Settings::SystemScope); } void ConfigCommandExecutor::execute(const ConfigCommand &command) { switch (command.command) { case ConfigCommand::CfgList: printSettings(command); break; case ConfigCommand::CfgSet: setValue(command.varNames.front(), command.varValue); break; case ConfigCommand::CfgUnset: for (const QString &varName : command.varNames) m_settings->remove(varName); break; case ConfigCommand::CfgAddProfile: { Profile profile(command.varValue, m_settings); profile.removeProfile(); Q_ASSERT(command.varNames.size() % 2 == 0); for (int i = 0; i < command.varNames.size(); i += 2) { const QString &key = command.varNames.at(i); const QString &rawValue = command.varNames.at(i + 1); profile.setValue(key, representationToSettingsValue(rawValue)); } break; } case ConfigCommand::CfgExport: exportSettings(command.fileName); break; case ConfigCommand::CfgImport: // Display old and new settings, in case import fails or user accidentally nukes everything std::printf("old "); // Will end up as "old settings:" printSettings(command); importSettings(command.fileName); std::printf("\nnew "); printSettings(command); break; case ConfigCommand::CfgNone: qFatal("%s: Impossible command value.", Q_FUNC_INFO); break; } } void ConfigCommandExecutor::setValue(const QString &key, const QString &rawInput) { m_settings->setValue(key, representationToSettingsValue(rawInput)); } void ConfigCommandExecutor::printSettings(const ConfigCommand &command) { if (command.varNames.empty()) { const auto keys = m_settings->allKeys(m_scope); for (const QString &key : keys) printOneSetting(key); } else { for (const QString &parentKey : command.varNames) { if (m_settings->value(parentKey, m_scope).isValid()) { // Key is a leaf. printOneSetting(parentKey); } else { // Key is a node. const auto keys = m_settings->allKeysWithPrefix(parentKey, m_scope); for (const QString &key : keys) printOneSetting(parentKey + QLatin1Char('.') + key); } } } } void ConfigCommandExecutor::printOneSetting(const QString &key) { std::printf("%s: %s\n", qPrintable(key), qPrintable(qbs::settingsValueToRepresentation(m_settings->value(key, m_scope)))); } void ConfigCommandExecutor::exportSettings(const QString &filename) { QFile file(filename); if (!file.open(QFile::Truncate | QFile::WriteOnly | QFile::Text)) { throw ErrorInfo(tr("Could not open file '%1' for writing: %2") .arg(QDir::toNativeSeparators(filename), file.errorString())); } if (QFileInfo(filename).suffix() == u"json") { QJsonDocument doc; doc.setObject(settingsToJSONObject(*m_settings, m_scope)); file.write(doc.toJson()); } else { QTextStream stream(&file); setupDefaultCodec(stream); const auto keys = m_settings->allKeys(m_scope); for (const QString &key : keys) stream << key << ": " << qbs::settingsValueToRepresentation(m_settings->value(key, m_scope)) << Qt::endl; } } void ConfigCommandExecutor::importSettings(const QString &filename) { QFile file(filename); if (!file.open(QFile::ReadOnly | QFile::Text)) { throw ErrorInfo(tr("Could not open file '%1' for reading: %2") .arg(QDir::toNativeSeparators(filename), file.errorString())); } // Remove all current settings const auto keys = m_settings->allKeys(m_scope); for (const QString &key : keys) m_settings->remove(key); if (QFileInfo(filename).suffix() == u"json") { const auto doc = QJsonDocument::fromJson(file.readAll()); const auto object = doc.object(); settingsFromJSONObject(*m_settings, doc.object()); } else { QTextStream stream(&file); setupDefaultCodec(stream); while (!stream.atEnd()) { QString line = stream.readLine(); int colon = line.indexOf(QLatin1Char(':')); if (colon >= 0 && !line.startsWith(QLatin1Char('#'))) { const QString key = line.left(colon).trimmed(); const QString value = line.mid(colon + 1).trimmed(); m_settings->setValue(key, representationToSettingsValue(value)); } } } } qbs-src-2.6.1/src/app/config/configcommand.h0000644000175100001660000000441414776170045020244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CONFIGCOMMAND_H #define CONFIGCOMMAND_H #include #include #include class ConfigCommand { public: enum Command { CfgSet, CfgUnset, CfgList, CfgExport, CfgImport, CfgAddProfile, CfgNone }; ConfigCommand() : command(CfgNone) {} Command command; QStringList varNames; QString varValue; QString fileName; }; #endif // CONFIGCOMMAND_H qbs-src-2.6.1/src/app/qbs-setup-toolchains/0000755000175100001660000000000014776170045020103 5ustar runnerdockerqbs-src-2.6.1/src/app/qbs-setup-toolchains/watcomprobe.cpp0000644000175100001660000002341414776170045023135 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "watcomprobe.h" #include "probe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; namespace { struct Details { QStringView architecture; QStringView platform; }; constexpr struct Platform { QStringView flag; Details keys; Details target; } knownPlatforms[] = { // DOS 16/32 bit. {u"-bdos", {u"__I86__", u"__DOS__"}, {u"x86_16", u"dos"}}, {u"-bdos4g", {u"__386__", u"__DOS__"}, {u"x86", u"dos"}}, // Windows 16/32 bit. {u"-bwindows", {u"__I86__", u"__WINDOWS__"}, {u"x86_16", u"windows"}}, {u"-bnt", {u"__386__", u"__NT__"}, {u"x86", u"windows"}}, // OS/2 16/32 bit. {u"-bos2", {u"__I86__", u"__OS2__"}, {u"x86_16", u"os2"}}, {u"-bos2v2", {u"__386__", u"__OS2__"}, {u"x86", u"os2"}}, // Linux 32 bit. {u"-blinux", {u"__386__", u"__LINUX__"}, {u"x86", u"linux"}}, }; } // namespace static QStringList knownWatcomCompilerNames() { return {QStringLiteral("owcc")}; } static QStringList dumpOutput(const QFileInfo &compiler, QStringView flag, const QList &keys) { const QString filePath = QDir(QDir::tempPath()).absoluteFilePath( QLatin1String("watcom-dump.c")); QFile fakeIn(filePath); if (!fakeIn.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return {}; } fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); fakeIn.write("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)\n"); for (const auto &key : keys) { fakeIn.write("#if defined(" + key.toLatin1() + ")\n"); fakeIn.write("#pragma message (VAR_NAME_VALUE(" + key.toLatin1() + "))\n"); fakeIn.write("#endif\n"); } fakeIn.close(); QProcess p; QStringList args; if (!flag.isEmpty()) args.push_back(flag.toString()); args.push_back(QDir::toNativeSeparators(filePath)); p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); fakeIn.remove(); QStringList lines = QString::fromUtf8(p.readAllStandardOutput()) .split(QRegularExpression(QLatin1String("\\r?\\n"))); return lines; } static bool supportsWatcomPlatform(const QFileInfo &compiler, const Platform &platform) { const auto macros = dumpMacros([&compiler, &platform]() { const QList keys = {platform.keys.architecture, platform.keys.platform}; return dumpOutput(compiler, platform.flag, keys); }); auto matches = [¯os](QStringView key) { const auto k = key.toString(); if (!macros.contains(k)) return false; return macros.value(k) == QLatin1String("1"); }; return matches(platform.keys.architecture) && matches(platform.keys.platform); } static std::vector createWatcomProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QStringView profileName = {}) { const QFileInfo compiler = info.compilerPath; std::vector profiles; for (const auto &knownPlatform : knownPlatforms) { // Don't create a profile in case the compiler does // not support the proposed architecture. if (!supportsWatcomPlatform(compiler, knownPlatform)) continue; QString fullProfilename; if (profileName.isEmpty()) { // Create a full profile name in case we is in auto-detecting mode. if (!info.compilerVersion.isValid()) { fullProfilename = QStringLiteral("watcom-unknown-%1-%2") .arg(knownPlatform.target.platform) .arg(knownPlatform.target.architecture); } else { const QString version= info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); fullProfilename = QStringLiteral("watcom-%1-%2-%3") .arg(version) .arg(knownPlatform.target.platform) .arg(knownPlatform.target.architecture); } } else { // Append the detected actual architecture name to the proposed profile name. fullProfilename = QStringLiteral("%1-%2-%3") .arg(profileName) .arg(knownPlatform.target.platform) .arg(knownPlatform.target.architecture); } Profile profile(fullProfilename, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("watcom")); profile.setValue(QStringLiteral("qbs.architecture"), knownPlatform.target.architecture.toString()); profile.setValue(QStringLiteral("qbs.targetPlatform"), knownPlatform.target.platform.toString()); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); profiles.push_back(std::move(profile)); } return profiles; } static Version dumpWatcomVersion(const QFileInfo &compiler) { const QList keys = {u"__WATCOMC__", u"__WATCOM_CPLUSPLUS__"}; const auto macros = dumpMacros([&compiler, &keys]() { return dumpOutput(compiler, u"", keys); }); for (const auto ¯o : macros) { const int verCode = macro.toInt(); return Version{(verCode - 1100) / 100, (verCode / 10) % 10, ((verCode % 10) > 0) ? (verCode % 10) : 0}; } qbsWarning() << Tr::tr("No __WATCOMC__ or __WATCOM_CPLUSPLUS__ tokens was found" " in the compiler dump"); return Version{}; } static std::vector installedWatcomsFromPath() { std::vector infos; const auto compilerNames = knownWatcomCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo watcomPath(findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!watcomPath.exists()) continue; const Version version = dumpWatcomVersion(watcomPath); infos.push_back({watcomPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } bool isWatcomCompiler(const QString &compilerName) { return Internal::any_of(knownWatcomCompilerNames(), [compilerName](const QString &knownName) { return compilerName.contains(knownName); }); } void createWatcomProfile(const QFileInfo &compiler, Settings *settings, QStringView profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createWatcomProfileHelper(info, settings, profileName); } void watcomProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect WATCOM toolchains..."); const std::vector allInfos = installedWatcomsFromPath(); if (allInfos.empty()) { qbsInfo() << Tr::tr("No WATCOM toolchains found."); return; } for (const ToolchainInstallInfo &info : allInfos) { const auto newProfiles = createWatcomProfileHelper(info, settings); profiles.reserve(profiles.size() + int(newProfiles.size())); std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles)); } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/emscriptenprobe.cpp0000644000175100001660000000767314776170045024025 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Danya Patrushev ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "emscriptenprobe.h" #include "../shared/logging/consolelogger.h" #include "probe.h" #include #include #include #include #include #include #include #include using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; namespace { qbs::Profile writeProfile( const QString &profileName, const QFileInfo &compiler, qbs::Settings *settings) { qbs::Profile profile(profileName, settings); profile.setValue(QStringLiteral("qbs.architecture"), QStringLiteral("wasm")); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("emscripten")); profile.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("wasm-emscripten")); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); return profile; } } //namespace bool isEmscriptenCompiler(const QString &compilerName) { return compilerName.startsWith(QLatin1String("emcc")) || compilerName.startsWith(QLatin1String("em++")); } qbs::Profile createEmscriptenProfile( const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName) { qbs::Profile profile = writeProfile(profileName, compiler, settings); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); return profile; } void emscriptenProbe(qbs::Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect emscripten toolchain..."); const QString emcc = HostOsInfo::isWindowsHost() ? QStringLiteral("emcc.bat") : QStringLiteral("emcc"); const QString compilerPath = findExecutable(emcc); if (compilerPath.isEmpty()) { qbsInfo() << Tr::tr("No emscripten toolchain found."); return; } const qbs::Profile profile = createEmscriptenProfile( QFileInfo(compilerPath), settings, QLatin1String("wasm")); profiles.push_back(profile); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/cosmicprobe.cpp0000644000175100001660000001526314776170045023123 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "cosmicprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownCosmicCompilerNames() { return {QStringLiteral("cxcorm"), QStringLiteral("cxstm8"), QStringLiteral("cx6808"), QStringLiteral("cx6812"), QStringLiteral("cx332")}; } static QString guessCosmicArchitecture(const QFileInfo &compiler) { const auto baseName = compiler.baseName(); if (baseName == QLatin1String("cxcorm")) return QStringLiteral("arm"); if (baseName == QLatin1String("cxstm8")) return QStringLiteral("stm8"); if (baseName == QLatin1String("cx6808")) return QStringLiteral("hcs8"); if (baseName == QLatin1String("cx6812")) return QStringLiteral("hcs12"); if (baseName == QLatin1String("cx332")) return QStringLiteral("m68k"); return {}; } static Profile createCosmicProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QString profileName = QString()) { const QFileInfo compiler = info.compilerPath; const QString architecture = guessCosmicArchitecture(compiler); // In case the profile is auto-detected. if (profileName.isEmpty()) { if (!info.compilerVersion.isValid()) { profileName = QStringLiteral("cosmic-unknown-%1").arg(architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); profileName = QStringLiteral("cosmic-%1-%2").arg( version, architecture); } } Profile profile(profileName, settings); profile.setValue(QLatin1String("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QLatin1String("qbs.toolchainType"), QLatin1String("cosmic")); if (!architecture.isEmpty()) profile.setValue(QLatin1String("qbs.architecture"), architecture); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); return profile; } static Version dumpCosmicCompilerVersion(const QFileInfo &compiler) { QProcess p; QStringList args; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } const QByteArray output = p.readAllStandardError(); const QRegularExpression re(QLatin1String("^COSMIC.+V(\\d+)\\.?(\\d+)\\.?(\\*|\\d+)?")); const QRegularExpressionMatch match = re.match(QString::fromLatin1(output)); if (!match.hasMatch()) return Version{}; const auto major = match.captured(1).toInt(); const auto minor = match.captured(2).toInt(); const auto patch = match.captured(3).toInt(); return Version{major, minor, patch}; } static std::vector installedCosmicsFromPath() { std::vector infos; const auto compilerNames = knownCosmicCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo cosmicPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!cosmicPath.exists()) continue; const Version version = dumpCosmicCompilerVersion(cosmicPath); infos.push_back({cosmicPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } bool isCosmicCompiler(const QString &compilerName) { return Internal::any_of(knownCosmicCompilerNames(), [compilerName](const QString &knownName) { return compilerName.contains(knownName); }); } void createCosmicProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createCosmicProfileHelper(info, settings, std::move(profileName)); } void cosmicProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect COSMIC toolchains..."); const std::vector allInfos = installedCosmicsFromPath(); qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) { return createCosmicProfileHelper(info, settings); }); if (allInfos.empty()) qbsInfo() << Tr::tr("No COSMIC toolchains found."); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/xcodeprobe.h0000644000175100001660000000415014776170045022406 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_XCODEPROBE_H #define QBS_SETUPTOOLCHAINS_XCODEPROBE_H #include namespace qbs { class Profile; class Settings; } void xcodeProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/sdccprobe.h0000644000175100001660000000520114776170045022216 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_SDCCPROBE_H #define QBS_SETUPTOOLCHAINS_SDCCPROBE_H #include #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } struct SdccInstallInfo { QString compilerPath; QString version; }; inline bool operator==(const SdccInstallInfo &lhs, const SdccInstallInfo &rhs) { return std::tie(lhs.compilerPath, lhs.version) == std::tie(rhs.compilerPath, rhs.version); } bool isSdccCompiler(const QString &compilerName); void createSdccProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); void sdccProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/keilprobe.h0000644000175100001660000000453514776170045022237 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_KEILPROBE_H #define QBS_SETUPTOOLCHAINS_KEILPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isKeilCompiler(const QString &compilerName); void createKeilProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); void keilProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/clangclprobe.cpp0000644000175100001660000001224114776170045023242 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "clangclprobe.h" #include "msvcprobe.h" #include "probe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using qbs::Settings; using qbs::Profile; using qbs::Internal::ClangClInfo; using qbs::Internal::HostOsInfo; using qbs::Internal::Tr; namespace { Profile createProfileHelper( Settings *settings, const QString &profileName, const QString &toolchainInstallPath, const QString &vcvarsallPath, const QString &architecture) { Profile profile(profileName, settings); profile.removeProfile(); profile.setValue(QStringLiteral("qbs.architecture"), architecture); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("clang-cl")); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), toolchainInstallPath); profile.setValue(QStringLiteral("cpp.vcvarsallPath"), vcvarsallPath); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), QDir::toNativeSeparators(toolchainInstallPath)); return profile; } QString findClangCl() { const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); auto compilerFromPath = findExecutable(compilerName); if (!compilerFromPath.isEmpty()) return compilerFromPath; return {}; } } // namespace void createClangClProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { const auto clangCl = ClangClInfo::fromCompilerFilePath( compiler.filePath(), ConsoleLogger::instance()); if (clangCl.isEmpty()) return; const auto hostArch = HostOsInfo::hostOSArchitecture(); createProfileHelper( settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, hostArch); } /*! \brief Creates a clang-cl profile based on auto-detected vsversion. \internal */ void clangClProbe(Settings *settings, std::vector &profiles) { const auto compilerName = QStringLiteral("clang-cl"); qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); const auto clangCls = ClangClInfo::installedCompilers( {findClangCl()}, ConsoleLogger::instance()); if (clangCls.empty()) { qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName); return; } const QString architectures[] = { QStringLiteral("x86_64"), QStringLiteral("x86") }; for (size_t index = 0; index < clangCls.size(); ++index) { const auto &clangCl = clangCls[index]; const QString suffix = index == 0 ? QString() : QStringLiteral("-%1").arg(index); qbs::Internal::transform( architectures, profiles, [settings, clangCl, suffix](const auto &arch) { const auto profileName = QStringLiteral("clang-cl%1-%2").arg(suffix, arch); return createProfileHelper( settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, arch); }); } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/xcodeprobe.cpp0000644000175100001660000002243414776170045022746 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "xcodeprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; static const QString defaultDeveloperPath = QStringLiteral("/Applications/Xcode.app/Contents/Developer"); static const std::regex defaultDeveloperPathRegex( "^/Applications/Xcode([a-zA-Z0-9 ._-]+)\\.app/Contents/Developer$"); static QString targetOS(const QString &applePlatformName) { if (applePlatformName == QStringLiteral("macosx")) return QStringLiteral("macos"); if (applePlatformName == QStringLiteral("iphoneos")) return QStringLiteral("ios"); if (applePlatformName == QStringLiteral("iphonesimulator")) return QStringLiteral("ios-simulator"); if (applePlatformName == QStringLiteral("appletvos")) return QStringLiteral("tvos"); if (applePlatformName == QStringLiteral("appletvsimulator")) return QStringLiteral("tvos-simulator"); if (applePlatformName == QStringLiteral("watchos")) return QStringLiteral("watchos"); if (applePlatformName == QStringLiteral("watchsimulator")) return QStringLiteral("watchos-simulator"); return {}; } static QStringList archList(const QString &applePlatformName) { QStringList archs; if (applePlatformName == QStringLiteral("macosx") || applePlatformName == QStringLiteral("iphonesimulator") || applePlatformName == QStringLiteral("appletvsimulator") || applePlatformName == QStringLiteral("watchsimulator")) { if (applePlatformName != QStringLiteral("appletvsimulator")) archs << QStringLiteral("x86"); if (applePlatformName != QStringLiteral("watchsimulator")) archs << QStringLiteral("x86_64"); if (applePlatformName == QStringLiteral("macosx")) archs << QStringLiteral("arm64"); } else if (applePlatformName == QStringLiteral("iphoneos") || applePlatformName == QStringLiteral("appletvos")) { if (applePlatformName != QStringLiteral("appletvos")) archs << QStringLiteral("armv7a"); archs << QStringLiteral("arm64"); } else if (applePlatformName == QStringLiteral("watchos")) { archs << QStringLiteral("armv7k"); } return archs; } namespace { class XcodeProbe { public: XcodeProbe(qbs::Settings *settings, std::vector &profiles) : settings(settings), profiles(profiles) { } bool addDeveloperPath(const QString &path); void detectDeveloperPaths(); void setupDefaultToolchains(const QString &devPath, const QString &xCodeName); void detectAll(); private: qbs::Settings *settings; std::vector &profiles; QStringList developerPaths; }; bool XcodeProbe::addDeveloperPath(const QString &path) { if (path.isEmpty()) return false; QFileInfo pInfo(path); if (!pInfo.exists() || !pInfo.isDir()) return false; if (developerPaths.contains(path)) return false; developerPaths.push_back(path); qbsInfo() << Tr::tr("Added developer path %1").arg(path); return true; } void XcodeProbe::detectDeveloperPaths() { QProcess selectedXcode; QString program = QStringLiteral("/usr/bin/xcode-select"); QStringList arguments(QStringLiteral("--print-path")); selectedXcode.start(program, arguments, QProcess::ReadOnly); if (!selectedXcode.waitForFinished(-1) || selectedXcode.exitCode()) { qbsInfo() << Tr::tr("Could not detect selected Xcode with /usr/bin/xcode-select"); } else { QString path = QString::fromLocal8Bit(selectedXcode.readAllStandardOutput().trimmed()); addDeveloperPath(path); } addDeveloperPath(defaultDeveloperPath); QProcess launchServices; program = QStringLiteral("/usr/bin/mdfind"); arguments = QStringList(QStringLiteral("kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'")); launchServices.start(program, arguments, QProcess::ReadOnly); if (!launchServices.waitForFinished(-1) || launchServices.exitCode()) { qbsInfo() << Tr::tr("Could not detect additional Xcode installations with /usr/bin/mdfind"); } else { const auto paths = QString::fromLocal8Bit(launchServices.readAllStandardOutput()) .split(QLatin1Char('\n'), Qt::SkipEmptyParts); for (const QString &path : paths) addDeveloperPath(path + QStringLiteral("/Contents/Developer")); } } void XcodeProbe::setupDefaultToolchains(const QString &devPath, const QString &xcodeName) { qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(xcodeName, devPath); Profile installationProfile(xcodeName, settings); installationProfile.removeProfile(); installationProfile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("xcode")); if (devPath != defaultDeveloperPath) installationProfile.setValue(QStringLiteral("xcode.developerPath"), devPath); profiles.push_back(installationProfile); QStringList platforms; platforms << QStringLiteral("macosx") << QStringLiteral("iphoneos") << QStringLiteral("iphonesimulator") << QStringLiteral("appletvos") << QStringLiteral("appletvsimulator") << QStringLiteral("watchos") << QStringLiteral("watchsimulator"); for (const QString &platform : std::as_const(platforms)) { Profile platformProfile(xcodeName + QLatin1Char('-') + platform, settings); platformProfile.removeProfile(); platformProfile.setBaseProfile(installationProfile.name()); platformProfile.setValue(QStringLiteral("qbs.targetPlatform"), targetOS(platform)); profiles.push_back(platformProfile); const auto architectures = archList(platform); for (const QString &arch : architectures) { Profile archProfile(xcodeName + QLatin1Char('-') + platform + QLatin1Char('-') + arch, settings); archProfile.removeProfile(); archProfile.setBaseProfile(platformProfile.name()); archProfile.setValue(QStringLiteral("qbs.architecture"), qbs::canonicalArchitecture(arch)); profiles.push_back(archProfile); } } } void XcodeProbe::detectAll() { int i = 1; detectDeveloperPaths(); for (const QString &developerPath : std::as_const(developerPaths)) { QString profileName = QStringLiteral("xcode"); if (developerPath != defaultDeveloperPath) { const auto devPath = developerPath.toStdString(); std::smatch match; if (std::regex_match(devPath, match, defaultDeveloperPathRegex)) profileName += QString::fromStdString(match[1]).toLower(). replace(QLatin1Char(' '), QLatin1Char('-')). replace(QLatin1Char('.'), QLatin1Char('_')); else profileName += QString::number(i++); } setupDefaultToolchains(developerPath, profileName); } } } // end anonymous namespace void xcodeProbe(qbs::Settings *settings, std::vector &profiles) { XcodeProbe probe(settings, profiles); probe.detectAll(); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/gccprobe.cpp0000644000175100001660000005547714776170045022415 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "gccprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; constexpr char kUninstallRegistryKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \ "Windows\\CurrentVersion\\Uninstall\\"; static QString qsystem(const QString &exe, const QStringList &args = QStringList()) { QProcess p; p.setProcessChannelMode(QProcess::MergedChannels); p.start(exe, args); if (!p.waitForStarted()) { throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2") .arg(exe, p.errorString())); } if (!p.waitForFinished(-1) || p.exitCode() != 0) throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2") .arg(exe, p.errorString())); return QString::fromLocal8Bit(p.readAll()); } static QStringList validMinGWMachines() { // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs return {QStringLiteral("mingw32"), QStringLiteral("mingw64"), QStringLiteral("i686-w64-mingw32"), QStringLiteral("x86_64-w64-mingw32"), QStringLiteral("i686-w64-mingw32.shared"), QStringLiteral("x86_64-w64-mingw32.shared"), QStringLiteral("i686-w64-mingw32.static"), QStringLiteral("x86_64-w64-mingw32.static"), QStringLiteral("i586-mingw32msvc"), QStringLiteral("amd64-mingw32msvc")}; } static QString gccMachineName(const QFileInfo &compiler) { return qsystem(compiler.absoluteFilePath(), {QStringLiteral("-dumpmachine")}) .trimmed(); } static QStringList standardCompilerFileNames() { return {HostOsInfo::appendExecutableSuffix(QStringLiteral("gcc")), HostOsInfo::appendExecutableSuffix(QStringLiteral("g++")), HostOsInfo::appendExecutableSuffix(QStringLiteral("clang")), HostOsInfo::appendExecutableSuffix(QStringLiteral("clang++"))}; } class ToolchainDetails { public: explicit ToolchainDetails(const QFileInfo &compiler) { auto baseName = HostOsInfo::stripExecutableSuffix(compiler.fileName()); // Extract the version sub-string if it exists. We assume that a version // sub-string located after the compiler prefix && suffix. E.g. this code // parses a version from the compiler names, like this: // - avr-gcc-4.9.2.exe // - arm-none-eabi-gcc-8.2.1 // - rl78-elf-gcc-4.9.2.201902-GNURL78 const QRegularExpression re(QLatin1String("-(\\d+|\\d+\\.\\d+|" \ "\\d+\\.\\d+\\.\\d+|" \ "\\d+\\.\\d+\\.\\d+\\.\\d+)" \ "[-[0-9a-zA-Z]*]?$")); const QRegularExpressionMatch match = re.match(baseName); if (match.hasMatch()) { version = match.captured(1); baseName = baseName.left(match.capturedStart()); } const auto dashIndex = baseName.lastIndexOf(QLatin1Char('-')); suffix = baseName.mid(dashIndex + 1); prefix = baseName.left(dashIndex + 1); } QString prefix; QString suffix; QString version; }; static void setCommonProperties(Profile &profile, const QFileInfo &compiler, const QString &toolchainType, const ToolchainDetails &details) { if (toolchainType == QStringLiteral("mingw")) profile.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows")); if (!details.prefix.isEmpty()) profile.setValue(QStringLiteral("cpp.toolchainPrefix"), details.prefix); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), toolchainType); if (!standardCompilerFileNames().contains( HostOsInfo::appendExecutableSuffix(details.suffix))) { qWarning("%s", qPrintable( QStringLiteral("'%1' is not a standard compiler file name; " "you must set the cpp.cCompilerName and " "cpp.cxxCompilerName properties of this profile " "manually").arg(compiler.fileName()))); } } class ToolPathSetup { public: explicit ToolPathSetup(Profile *profile, QString path, ToolchainDetails details) : m_profile(profile), m_compilerDirPath(std::move(path)), m_details(std::move(details)) { } void apply(const QString &toolName, const QString &propertyName) const { // Check for full tool name at first (includes suffix and version). QString filePath = toolFilePath(toolName, UseFullToolName); if (filePath.isEmpty()) { // Check for base tool name at second (without of suffix and version). filePath = toolFilePath(toolName, UseBaseToolName); if (filePath.isEmpty()) { // Check for short tool name at third (only a tool name). filePath = toolFilePath(toolName, UseOnlyShortToolName); } } if (filePath.isEmpty()) { qWarning("%s", qPrintable( QStringLiteral("'%1' not found in '%2'. " "Qbs will try to find it in PATH at build time.") .arg(toolName, m_compilerDirPath))); } else { m_profile->setValue(propertyName, filePath); } } private: enum ToolNameParts : quint8 { UseOnlyShortToolName = 0x0, UseToolPrefix = 0x01, UseToolSuffix = 0x02, UseToolVersion = 0x04, UseFullToolName = UseToolPrefix | UseToolSuffix | UseToolVersion, UseBaseToolName = UseToolPrefix, }; QString toolFilePath(const QString &toolName, int parts) const { QString fileName; if ((parts & UseToolPrefix) && !m_details.prefix.isEmpty()) fileName += m_details.prefix; if ((parts & UseToolSuffix) && !m_details.suffix.isEmpty()) fileName += m_details.suffix + QLatin1Char('-'); fileName += toolName; if ((parts & UseToolVersion) && !m_details.version.isEmpty()) fileName += QLatin1Char('-') + m_details.version; fileName = HostOsInfo::appendExecutableSuffix(fileName); QString filePath = QDir(m_compilerDirPath).absoluteFilePath(fileName); if (QFile::exists(filePath)) return filePath; return {}; } Profile * const m_profile; QString m_compilerDirPath; ToolchainDetails m_details; }; static bool doesProfileTargetOS(const Profile &profile, const QString &os) { const auto target = profile.value(QStringLiteral("qbs.targetPlatform")); if (target.isValid()) return Internal::contains(HostOsInfo::canonicalOSIdentifiers(target.toString()), os); return Internal::contains(HostOsInfo::hostOSIdentifiers(), os); } static QString buildProfileName(const QFileInfo &cfi) { // We need to replace a dot-separated compiler version string // with a underscore-separated string, because the profile // name does not allow a dots. auto result = cfi.completeBaseName(); result.replace(QLatin1Char('.'), QLatin1Char('_')); return result; } static QStringList buildCompilerNameFilters(const QString &compilerName) { QStringList filters = { // "clang", "gcc" compilerName, // "clang-8", "gcc-5" compilerName + QLatin1String("-[1-9]*"), // "avr-gcc" QLatin1String("*-") + compilerName, // "avr-gcc-5.4.0" QLatin1String("*-") + compilerName + QLatin1String("-[1-9]*"), // "arm-none-eabi-gcc" QLatin1String("*-*-*-") + compilerName, // "arm-none-eabi-gcc-9.1.0" QLatin1String("*-*-*-") + compilerName + QLatin1String("-[1-9]*"), // "x86_64-pc-linux-gnu-gcc" QLatin1String("*-*-*-*-") + compilerName, // "x86_64-pc-linux-gnu-gcc-7.4.1" QLatin1String("*-*-*-*-") + compilerName + QLatin1String("-[1-9]*") }; Internal::transform(filters, [](const auto &filter) { return HostOsInfo::appendExecutableSuffix(filter); }); return filters; } static QStringList gnuRegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\ARM"; #else static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\ARM"; #endif QStringList searchPaths; QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto groupKeys = registry.childGroups(); for (const QString &groupKey : groupKeys) { registry.beginGroup(groupKey); const QString rootPath = registry.value(QStringLiteral("InstallFolder")).toString(); if (!rootPath.isEmpty()) { const QFileInfo toolchainPath(rootPath + QLatin1String("/bin")); if (toolchainPath.exists()) { const auto filePath = toolchainPath.absoluteFilePath(); if (!searchPaths.contains(filePath)) searchPaths.push_back(filePath); } } registry.endGroup(); } return searchPaths; } static QStringList atmelRegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; // Registry token for the "Atmel" toolchains, e.g. provided by installed // "Atmel Studio" IDE. static const char kRegistryToken[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Atmel\\"; QStringList searchPaths; QSettings registry(QLatin1String(kRegistryToken), QSettings::NativeFormat); // This code enumerate the installed toolchains provided // by the Atmel Studio v6.x. const auto toolchainGroups = registry.childGroups(); for (const QString &toolchainKey : toolchainGroups) { if (!toolchainKey.endsWith(QLatin1String("GCC"))) continue; registry.beginGroup(toolchainKey); const auto entries = registry.childGroups(); for (const auto &entryKey : entries) { registry.beginGroup(entryKey); const QString installDir = registry.value( QStringLiteral("Native/InstallDir")).toString(); const QString version = registry.value( QStringLiteral("Native/Version")).toString(); registry.endGroup(); QString toolchainPath = installDir + QLatin1String("/Atmel Toolchain/") + toolchainKey + QLatin1String("/Native/") + version; if (toolchainKey.startsWith(QLatin1String("ARM"))) toolchainPath += QLatin1String("/arm-gnu-toolchain"); else if (toolchainKey.startsWith(QLatin1String("AVR32"))) toolchainPath += QLatin1String("/avr32-gnu-toolchain"); else if (toolchainKey.startsWith(QLatin1String("AVR8)"))) toolchainPath += QLatin1String("/avr8-gnu-toolchain"); else break; toolchainPath += QLatin1String("/bin"); if (QFileInfo::exists(toolchainPath)) { searchPaths.push_back(toolchainPath); break; } } registry.endGroup(); } // This code enumerate the installed toolchains provided // by the Atmel Studio v7. registry.beginGroup(QStringLiteral("AtmelStudio")); const auto productVersions = registry.childGroups(); for (const auto &productVersionKey : productVersions) { registry.beginGroup(productVersionKey); const QString installDir = registry.value( QStringLiteral("InstallDir")).toString(); registry.endGroup(); const QStringList knownToolchainSubdirs = { QStringLiteral("/toolchain/arm/arm-gnu-toolchain/bin/"), QStringLiteral("/toolchain/avr8/avr8-gnu-toolchain/bin/"), QStringLiteral("/toolchain/avr32/avr32-gnu-toolchain/bin/"), }; for (const auto &subdir : knownToolchainSubdirs) { const QString toolchainPath = installDir + subdir; if (!QFileInfo::exists(toolchainPath)) continue; searchPaths.push_back(toolchainPath); } } registry.endGroup(); return searchPaths; } static QStringList renesasRl78RegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; QStringList searchPaths; QSettings registry(QLatin1String(kUninstallRegistryKey), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { // Registry token for the "Renesas RL78" toolchain. if (!productKey.startsWith( QLatin1String("GCC for Renesas RL78"))) { continue; } registry.beginGroup(productKey); const QString installLocation = registry.value( QLatin1String("InstallLocation")).toString(); registry.endGroup(); if (installLocation.isEmpty()) continue; const QFileInfo toolchainPath(QDir(installLocation).absolutePath() + QLatin1String("/rl78-elf/rl78-elf/bin")); if (!toolchainPath.exists()) continue; searchPaths.push_back(toolchainPath.absoluteFilePath()); } return searchPaths; } static QStringList mplabX32RegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; QStringList searchPaths; QSettings registry(QLatin1String(kUninstallRegistryKey), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { // Registry token for the "MPLAB X32" toolchain. if (!productKey.startsWith( QLatin1String("MPLAB XC32 Compiler"))) { continue; } registry.beginGroup(productKey); const QString installLocation = registry.value( QLatin1String("InstallLocation")).toString(); registry.endGroup(); if (installLocation.isEmpty()) continue; const QFileInfo toolchainPath(QDir(installLocation).absolutePath() + QLatin1String("/bin")); if (!toolchainPath.exists()) continue; searchPaths.push_back(toolchainPath.absoluteFilePath()); } return searchPaths; } Profile createGccProfile(const QFileInfo &compiler, Settings *settings, const QString &toolchainType, const QString &profileName) { const QString machineName = gccMachineName(compiler); if (toolchainType == QLatin1String("mingw")) { if (!validMinGWMachines().contains(machineName)) { throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.") .arg(machineName)); } } Profile profile(!profileName.isEmpty() ? profileName : machineName, settings); profile.removeProfile(); const ToolchainDetails details(compiler); setCommonProperties(profile, compiler, toolchainType, details); if (HostOsInfo::isWindowsHost() && toolchainType == QLatin1String("clang")) { const QStringList profileNames = settings->profiles(); bool foundMingw = false; for (const QString &profileName : profileNames) { const Profile otherProfile(profileName, settings); if (otherProfile.value(QLatin1String("qbs.toolchainType")).toString() == QLatin1String("mingw") || otherProfile.value(QLatin1String("qbs.toolchain")) .toStringList().contains(QLatin1String("mingw"))) { const QFileInfo tcDir(otherProfile.value(QLatin1String("cpp.toolchainInstallPath")) .toString()); if (!tcDir.fileName().isEmpty() && tcDir.exists()) { profile.setValue(QLatin1String("qbs.sysroot"), tcDir.path()); foundMingw = true; break; } } } if (!foundMingw) { qbsWarning() << Tr::tr("Using clang on Windows requires a mingw installation. " "Please set qbs.sysroot accordingly for profile '%1'.") .arg(profile.name()); } } if (toolchainType != QLatin1String("clang")) { // Check whether auxiliary tools reside within the toolchain's install path. // This might not be the case when using icecc or another compiler wrapper. const QString compilerDirPath = compiler.absolutePath(); const ToolPathSetup toolPathSetup(&profile, compilerDirPath, details); toolPathSetup.apply(QStringLiteral("ar"), QStringLiteral("cpp.archiverPath")); toolPathSetup.apply(QStringLiteral("as"), QStringLiteral("cpp.assemblerPath")); toolPathSetup.apply(QStringLiteral("nm"), QStringLiteral("cpp.nmPath")); if (doesProfileTargetOS(profile, QStringLiteral("darwin"))) toolPathSetup.apply(QStringLiteral("dsymutil"), QStringLiteral("cpp.dsymutilPath")); else toolPathSetup.apply(QStringLiteral("objcopy"), QStringLiteral("cpp.objcopyPath")); toolPathSetup.apply(QStringLiteral("strip"), QStringLiteral("cpp.stripPath")); } qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); return profile; } void gccProbe(Settings *settings, std::vector &profiles, const QString &compilerName) { qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); QStringList searchPaths; searchPaths << systemSearchPaths() << gnuRegistrySearchPaths() << atmelRegistrySearchPaths() << renesasRl78RegistrySearchPaths() << mplabX32RegistrySearchPaths(); std::vector candidates; const auto filters = buildCompilerNameFilters(compilerName); for (const auto &searchPath : std::as_const(searchPaths)) { const QDir dir(searchPath); const QStringList fileNames = dir.entryList( filters, QDir::Files | QDir::Executable); for (const QString &fileName : fileNames) { // Ignore unexpected compiler names. if (fileName.startsWith(QLatin1String("c89-gcc")) || fileName.startsWith(QLatin1String("c99-gcc"))) { continue; } const QFileInfo candidate(dir.filePath(fileName)); // Filter duplicates. const auto existingEnd = candidates.end(); const auto existingIt = std::find_if( candidates.begin(), existingEnd, [candidate](const QFileInfo &existing) { return isSameExecutable(candidate.absoluteFilePath(), existing.absoluteFilePath()); }); if (existingIt == existingEnd) { // No duplicates are found, just add a new candidate. candidates.push_back(candidate); } else { // Replace the existing entry if a candidate name more than // an existing name. const auto candidateName = candidate.completeBaseName(); const auto existingName = existingIt->completeBaseName(); if (candidateName > existingName) *existingIt = candidate; } } } if (candidates.empty()) { qbsInfo() << Tr::tr("No %1 toolchains found.").arg(compilerName); return; } // Sort candidates so that mingw comes first. Information from mingw profiles is potentially // used for setting up clang profiles. if (HostOsInfo::isWindowsHost()) { std::sort(candidates.begin(), candidates.end(), [](const QFileInfo &fi1, const QFileInfo &fi2) { return fi1.absoluteFilePath().contains(QLatin1String("mingw")) && !fi2.absoluteFilePath().contains(QLatin1String("mingw")); }); } for (const auto &candidate : std::as_const(candidates)) { const QString toolchainType = toolchainTypeFromCompilerName( candidate.baseName()); const QString profileName = buildProfileName(candidate); try { auto profile = createGccProfile(candidate, settings, toolchainType, profileName); profiles.push_back(std::move(profile)); } catch (const qbs::ErrorInfo &info) { qbsWarning() << Tr::tr("Skipping %1: %2").arg(profileName, info.toString()); } } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/qbs-setup-toolchains.exe.manifest0000644000175100001660000000073614776170045026505 0ustar runnerdocker qbs-src-2.6.1/src/app/qbs-setup-toolchains/emscriptenprobe.h0000644000175100001660000000466714776170045023472 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Danya Patrushev ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_EMSCRIPTENPROBE_H #define QBS_SETUPTOOLCHAINS_EMSCRIPTENPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; class QString; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } // namespace qbs bool isEmscriptenCompiler(const QString &compilerName); qbs::Profile createEmscriptenProfile( const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName = QString()); void emscriptenProbe(qbs::Settings *settings, std::vector &profiles); #endif // QBS_SETUPTOOLCHAINS_EMSCRIPTENPROBE_H qbs-src-2.6.1/src/app/qbs-setup-toolchains/sdccprobe.cpp0000644000175100001660000002521214776170045022555 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "sdccprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownSdccCompilerNames() { return {QStringLiteral("sdcc")}; } static QStringList dumpOutput(const QFileInfo &compiler, const QString &targetFlag = QString()) { QTemporaryFile fakeIn(QStringLiteral("XXXXXX.c")); if (!fakeIn.open()) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return {}; } fakeIn.close(); const QStringList args = {QStringLiteral("-dM"), QStringLiteral("-E"), targetFlag, fakeIn.fileName()}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1").arg(QString::fromUtf8(out)); return {}; } static QRegularExpression re(QStringLiteral("\\r?\\n")); return QString::fromUtf8(p.readAllStandardOutput()).split(re); } static bool supportsSdccArchitecture(const QFileInfo &compiler, QStringView flag) { const auto target = QStringLiteral("-m%1").arg(flag); const auto macros = dumpMacros([&compiler, &target]() { return dumpOutput(compiler, target); }); const auto token = QStringLiteral("__SDCC_%1").arg(flag); return macros.contains(token); } static std::vector createSdccProfileHelper(const ToolchainInstallInfo &info, Settings *settings, const QString &profileName = QString()) { const QFileInfo compiler = info.compilerPath; std::vector profiles; static constexpr struct KnownArch { QStringView architecture; QStringView flag; } knownArchs[] = {{u"mcs51", u"mcs51"}, {u"stm8", u"stm8"}, {u"hcs8", u"hc08"}}; for (const auto &knownArch : knownArchs) { // Don't create a profile in case the compiler does // not support the proposed architecture. if (!supportsSdccArchitecture(compiler, knownArch.flag)) continue; QString fullProfileName; if (profileName.isEmpty()) { // Create a full profile name in case we is // in auto-detecting mode. if (!info.compilerVersion.isValid()) { fullProfileName = QStringLiteral("sdcc-unknown-%1").arg(knownArch.architecture); } else { const QString version = info.compilerVersion.toString( QLatin1Char('_'), QLatin1Char('_')); fullProfileName = QStringLiteral("sdcc-%1-%2").arg( version, knownArch.architecture); } } else { // Append the detected actual architecture name // to the proposed profile name. fullProfileName = QStringLiteral("%1-%2").arg(profileName, knownArch.architecture); } Profile profile(fullProfileName, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("sdcc")); profile.setValue(QStringLiteral("qbs.architecture"), knownArch.architecture.toString()); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); profiles.push_back(std::move(profile)); } return profiles; } static Version dumpSdccVersion(const QFileInfo &compiler) { const auto macros = dumpMacros([&compiler]() { return dumpOutput(compiler); }); if (!macros.contains(QLatin1String("__SDCC"))) { qbsWarning() << Tr::tr("No __SDCC token was found in the compiler dump"); return Version{}; } auto value = macros.value(QLatin1String("__SDCC")); value.replace(QLatin1Char('_'), QLatin1Char('.')); return Version::fromString(value); } static std::vector installedSdccsFromPath() { std::vector infos; const auto compilerNames = knownSdccCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo sdccPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!sdccPath.exists()) continue; const Version version = dumpSdccVersion(sdccPath); infos.push_back({sdccPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } static std::vector installedSdccsFromRegistry() { std::vector infos; if (HostOsInfo::isWindowsHost()) { // Tries to detect the candidate from the 32-bit // or 64-bit system registry format. auto probeSdccToolchainInfo = [](QSettings::Format format) { SdccInstallInfo info; QSettings registry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\SDCC"), format); const QString rootPath = registry.value(QStringLiteral("Default")) .toString(); if (rootPath.isEmpty()) return info; // Build full compiler path. const QFileInfo sdccPath(rootPath + QLatin1String("\\bin\\sdcc.exe")); if (!sdccPath.exists()) return info; info.compilerPath = sdccPath.filePath(); // Build compiler version. const QString version = QStringLiteral("%1.%2.%3").arg( registry.value(QStringLiteral("VersionMajor")).toString(), registry.value(QStringLiteral("VersionMinor")).toString(), registry.value(QStringLiteral("VersionRevision")).toString()); info.version = version; return info; }; static constexpr QSettings::Format allowedFormats[] = { QSettings::NativeFormat, #ifdef Q_OS_WIN QSettings::Registry32Format, QSettings::Registry64Format, #endif }; for (const QSettings::Format format : allowedFormats) { const SdccInstallInfo candidate = probeSdccToolchainInfo(format); if (candidate.compilerPath.isEmpty()) continue; const auto infosEnd = infos.cend(); const auto infosIt = std::find_if(infos.cbegin(), infosEnd, [candidate](const ToolchainInstallInfo &info) { return candidate == SdccInstallInfo{ info.compilerPath.filePath(), info.compilerVersion.toString()}; }); if (infosIt == infosEnd) { infos.push_back({QFileInfo(candidate.compilerPath), Version::fromString(candidate.version)}); } } } std::sort(infos.begin(), infos.end()); return infos; } bool isSdccCompiler(const QString &compilerName) { return Internal::any_of(knownSdccCompilerNames(), [compilerName]( const QString &knownName) { return compilerName.contains(knownName); }); } void createSdccProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createSdccProfileHelper(info, settings, profileName); } void sdccProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect SDCC toolchains..."); // Make sure that a returned infos are sorted before using the std::set_union! const std::vector regInfos = installedSdccsFromRegistry(); const std::vector pathInfos = installedSdccsFromPath(); std::vector allInfos; allInfos.reserve(regInfos.size() + pathInfos.size()); std::set_union(regInfos.cbegin(), regInfos.cend(), pathInfos.cbegin(), pathInfos.cend(), std::back_inserter(allInfos)); if (allInfos.empty()) qbsInfo() << Tr::tr("No SDCC toolchains found."); for (const ToolchainInstallInfo &info : allInfos) { const auto newProfiles = createSdccProfileHelper(info, settings); profiles.reserve(profiles.size() + int(newProfiles.size())); std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles)); } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/commandlineparser.cpp0000644000175100001660000001342114776170045024313 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString detectOption() { return QStringLiteral("--detect"); } static QString typeOption() { return QStringLiteral("--type"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_autoDetectionMode = false; m_compilerPath.clear(); m_toolchainType.clear(); m_profileName.clear(); m_settingsDir.clear(); if (m_commandLine.empty()) throwError(Tr::tr("No command-line arguments provided.")); while (!m_commandLine.empty()) { const QString arg = m_commandLine.front(); if (!arg.startsWith(QLatin1Char('-'))) break; m_commandLine.removeFirst(); if (arg == helpOptionShort() || arg == helpOptionLong()) m_helpRequested = true; else if (arg == detectOption()) m_autoDetectionMode = true; else if (arg == systemOption()) m_settingsScope = qbs::Settings::SystemScope; else if (arg == typeOption()) assignOptionArgument(typeOption(), m_toolchainType); else if (arg == settingsDirOption()) assignOptionArgument(settingsDirOption(), m_settingsDir); } if (m_helpRequested || m_autoDetectionMode) { if (!m_commandLine.empty()) complainAboutExtraArguments(); return; } switch (m_commandLine.size()) { case 0: case 1: throwError(Tr::tr("Not enough command-line arguments provided.")); case 2: m_compilerPath = m_commandLine.at(0); m_profileName = m_commandLine.at(1); m_profileName.replace(QLatin1Char('.'), QLatin1Char('-')); break; default: complainAboutExtraArguments(); } } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool creates qbs profiles from toolchains.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%4] %3\n") .arg(m_command, settingsDirOption(), detectOption(), systemOption()); s += Tr::tr(" %1 [%3 ] [%4] [%2 ] " " \n") .arg(m_command, typeOption(), settingsDirOption(), systemOption()); s += Tr::tr(" %1 %2|%3\n").arg(m_command, helpOptionShort(), helpOptionLong()); s += Tr::tr("The first form tries to auto-detect all known toolchains, looking them up " "via the PATH environment variable.\n"); s += Tr::tr("The second form creates one profile for one toolchain. It will attempt " "to find out the toolchain type automatically.\nIn case the compiler has " "an unusual file name, you may need to provide the '--type' option."); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs0000644000175100001660000000223414776170045024677 0ustar runnerdockerQbsApp { name: "qbs-setup-toolchains" cpp.dynamicLibraries: qbs.targetOS.contains("windows") ? base.concat("shell32") : base files: [ "clangclprobe.cpp", "clangclprobe.h", "commandlineparser.cpp", "commandlineparser.h", "cosmicprobe.cpp", "cosmicprobe.h", "dmcprobe.cpp", "dmcprobe.h", "emscriptenprobe.cpp", "emscriptenprobe.h", "gccprobe.cpp", "gccprobe.h", "iarewprobe.cpp", "iarewprobe.h", "keilprobe.cpp", "keilprobe.h", "main.cpp", "msvcprobe.cpp", "msvcprobe.h", "probe.cpp", "probe.h", "sdccprobe.cpp", "sdccprobe.h", "watcomprobe.cpp", "watcomprobe.h", "xcodeprobe.cpp", "xcodeprobe.h", ] Group { name: "MinGW specific files" condition: qbs.toolchain.contains("mingw") files: "qbs-setup-toolchains.rc" Group { name: "qbs-setup-toolchains manifest" files: "qbs-setup-toolchains.exe.manifest" fileTags: [] // the manifest is referenced by the rc file } } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/clangclprobe.h0000644000175100001660000000450414776170045022712 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H #define QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H #include #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } void createClangClProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); void clangClProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/commandlineparser.h0000644000175100001660000000607514776170045023767 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #define QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } bool autoDetectionMode() const { return m_autoDetectionMode; } QString compilerPath() const { return m_compilerPath; } QString toolchainType() const { return m_toolchainType; } QString profileName() const { return m_profileName; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; bool m_autoDetectionMode = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_compilerPath; QString m_toolchainType; QString m_profileName; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/dmcprobe.cpp0000644000175100001660000002462714776170045022415 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "dmcprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; namespace { struct Target { QString platform; QString architecture; QString extender; }; } static QStringList knownDmcCompilerNames() { return {QStringLiteral("dmc")}; } static QStringList dumpOutput(const QFileInfo &compiler, const QStringList &flags, const QStringList &keys) { const QString filePath = QDir(QDir::tempPath()).absoluteFilePath( QLatin1String("dmc-dump.c")); QFile fakeIn(filePath); if (!fakeIn.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return {}; } fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); fakeIn.write("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)\n"); for (const auto &key : keys) { const auto content = key.toLatin1(); fakeIn.write("#if defined(" + content + ")\n"); fakeIn.write("#pragma message (VAR_NAME_VALUE(" + content + "))\n"); fakeIn.write("#endif\n"); } fakeIn.close(); QStringList args = {QStringLiteral("-e")}; args.reserve(args.size() + int(flags.size())); std::copy(flags.cbegin(), flags.cend(), std::back_inserter(args)); args.push_back(QDir::toNativeSeparators(filePath)); QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); fakeIn.remove(); static QRegularExpression re(QLatin1String("\\r?\\n")); return QString::fromUtf8(p.readAllStandardOutput()).split(re); } static std::optional dumpDmcTarget(const QFileInfo &compiler, const QStringList &flags) { const QStringList keys = { QStringLiteral("DOS16RM"), QStringLiteral("DOS386"), QStringLiteral("MSDOS"), QStringLiteral("__NT__"), QStringLiteral("_WINDOWS"), }; const auto macros = dumpMacros([&compiler, &flags, &keys]() { return dumpOutput(compiler, flags, keys); }); if (macros.contains(QLatin1String("__NT__"))) { return Target{QLatin1String("windows"), QLatin1String("x86"), QLatin1String("")}; } else if (macros.contains(QLatin1String("_WINDOWS"))) { return Target{QLatin1String("windows"), QLatin1String("x86_16"), QLatin1String("")}; } else if (macros.contains(QLatin1String("DOS386"))) { if (flags.contains(QLatin1String("-mx"))) return Target{QLatin1String("dos"), QLatin1String("x86"), QLatin1String("dosx")}; else if (flags.contains(QLatin1String("-mp"))) return Target{QLatin1String("dos"), QLatin1String("x86"), QLatin1String("dosp")}; } else if (macros.contains(QLatin1String("DOS16RM"))) { if (flags.contains(QLatin1String("-mz"))) return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("dosz")}; else if (flags.contains(QLatin1String("-mr"))) return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("dosr")}; } else if (macros.contains(QLatin1String("MSDOS"))) { return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("")}; } return {}; } static std::vector createDmcProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QStringView profileName = {}) { const QFileInfo compiler = info.compilerPath; std::vector profiles; const QVector probes = { { QStringLiteral("-mn"), QStringLiteral("-WA") }, // Windows NT 32 bit. { QStringLiteral("-ml"), QStringLiteral("-WA") }, // Windows 3.x 16 bit. { QStringLiteral("-mx") }, // DOS with DOSX extender 32 bit. { QStringLiteral("-mp") }, // DOS with Phar Lap extender 32 bit. { QStringLiteral("-mr") }, // DOS with Rational DOS Extender 16 bit. { QStringLiteral("-mz") }, // DOS with ZPM DOS Extender 16 bit. { QStringLiteral("-mc") }, // DOS 16 bit. }; for (const auto &flags : probes) { const auto target = dumpDmcTarget(compiler, flags); if (!target) continue; QString fullProfilename; QString platform = target->extender.isEmpty() ? target->platform : target->extender; if (profileName.isEmpty()) { // Create a full profile name in case we is in auto-detecting mode. if (!info.compilerVersion.isValid()) { fullProfilename = QStringLiteral("dmc-unknown-%1-%2") .arg(platform, target->architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); fullProfilename = QStringLiteral("dmc-%1-%2-%3") .arg(version, platform, target->architecture); } } else { // Append the detected actual architecture name to the proposed profile name. fullProfilename = QStringLiteral("%1-%2-%3") .arg(profileName, platform, target->architecture); } Profile profile(fullProfilename, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("dmc")); profile.setValue(QStringLiteral("qbs.architecture"), target->architecture); profile.setValue(QStringLiteral("qbs.targetPlatform"), target->platform); if (!target->extender.isEmpty()) profile.setValue(QStringLiteral("cpp.extenderName"), target->extender); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); profiles.push_back(std::move(profile)); } return profiles; } static Version dumpDmcVersion(const QFileInfo &compiler) { const QStringList keys = {QStringLiteral("__DMC__")}; const auto macros = dumpMacros([&compiler, keys]() { return dumpOutput(compiler, {}, keys); }); for (const auto ¯o : macros) { if (!macro.startsWith(QLatin1String("0x"))) continue; const int verCode = macro.mid(2).toInt(); return Version{(verCode / 100), (verCode % 100), 0}; } qbsWarning() << Tr::tr("No __DMC__ token was found in the compiler dump"); return Version{}; } static std::vector installedDmcsFromPath() { std::vector infos; const auto compilerNames = knownDmcCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo dmcPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!dmcPath.exists()) continue; const Version version = dumpDmcVersion(dmcPath); infos.push_back({dmcPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } bool isDmcCompiler(const QString &compilerName) { return Internal::any_of(knownDmcCompilerNames(), [compilerName](const QString &knownName) { return compilerName.contains(knownName); }); } void createDmcProfile(const QFileInfo &compiler, Settings *settings, QStringView profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createDmcProfileHelper(info, settings, profileName); } void dmcProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect DMC toolchains..."); const std::vector allInfos = installedDmcsFromPath(); if (allInfos.empty()) { qbsInfo() << Tr::tr("No DMC toolchains found."); return; } for (const ToolchainInstallInfo &info : allInfos) { const auto newProfiles = createDmcProfileHelper(info, settings); profiles.reserve(profiles.size() + int(newProfiles.size())); std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles)); } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/msvcprobe.cpp0000644000175100001660000002117714776170045022617 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "msvcprobe.h" #include "probe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using namespace qbs::Internal; using Internal::Tr; QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(WinSDK, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(MSVC, Q_MOVABLE_TYPE); QT_END_NAMESPACE // Not necessary but helps setup-qt automatically associate base profiles static void setQtHelperProperties(Profile &p, const MSVC *msvc) { QString targetArch = msvc->architecture.split(QLatin1Char('_')).last(); if (targetArch.isEmpty()) targetArch = QStringLiteral("x86"); if (targetArch == QStringLiteral("arm")) targetArch = QStringLiteral("armv7"); p.setValue(QStringLiteral("qbs.architecture"), canonicalArchitecture(targetArch)); } static void addMSVCPlatform(Settings *settings, std::vector &profiles, QString name, MSVC *msvc) { qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(name); Profile p(std::move(name), settings); p.removeProfile(); p.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows")); p.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("msvc")); p.setValue(QStringLiteral("cpp.toolchainInstallPath"), msvc->binPath); setQtHelperProperties(p, msvc); profiles.push_back(p); } static QString wow6432Key() { #ifdef Q_OS_WIN64 return QStringLiteral("\\Wow6432Node"); #else return {}; #endif } void msvcProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Detecting MSVC toolchains..."); // 1) Installed SDKs preferred over standalone Visual studio std::vector winSDKs; WinSDK defaultWinSDK; const QSettings sdkRegistry(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + QLatin1String("\\Microsoft\\Microsoft SDKs\\Windows"), QSettings::NativeFormat); const QString defaultSdkPath = sdkRegistry.value(QStringLiteral("CurrentInstallFolder")).toString(); if (!defaultSdkPath.isEmpty()) { const auto sdkKeys = sdkRegistry.childGroups(); for (const QString &sdkKey : sdkKeys) { WinSDK sdk; sdk.version = sdkKey; sdk.vcInstallPath = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString(); sdk.isDefault = (sdk.vcInstallPath == defaultSdkPath); if (sdk.vcInstallPath.isEmpty()) continue; if (sdk.vcInstallPath.endsWith(QLatin1Char('\\'))) sdk.vcInstallPath.chop(1); if (sdk.isDefault) defaultWinSDK = sdk; const auto ais = MSVC::findSupportedArchitectures(sdk); qbs::Internal::transform(ais, winSDKs, [&sdk](const auto &ai) { WinSDK specificSDK = sdk; specificSDK.architecture = ai.arch; specificSDK.binPath = ai.binPath; return specificSDK; }); } } for (const WinSDK &sdk : std::as_const(winSDKs)) { qbsInfo() << Tr::tr(" Windows SDK %1 detected:\n" " installed in %2").arg(sdk.version, sdk.vcInstallPath); if (sdk.isDefault) qbsInfo() << Tr::tr(" This is the default SDK on this machine."); } // 2) Installed MSVCs std::vector msvcs = MSVC::installedCompilers(ConsoleLogger::instance()); for (const MSVC &msvc : std::as_const(msvcs)) { qbsInfo() << Tr::tr(" MSVC %1 (%2) detected in\n" " %3").arg(msvc.version, msvc.architecture, QDir::toNativeSeparators(msvc.binPath)); } if (winSDKs.empty() && msvcs.empty()) { qbsInfo() << Tr::tr("Could not detect an installation of " "the Windows SDK or Visual Studio."); return; } qbsInfo() << Tr::tr("Detecting build environment..."); std::vector msvcPtrs; msvcPtrs.reserve(winSDKs.size() + msvcs.size()); std::transform(winSDKs.begin(), winSDKs.end(), std::back_inserter(msvcPtrs), [] (WinSDK &sdk) -> MSVC * { return &sdk; }); std::transform(msvcs.begin(), msvcs.end(), std::back_inserter(msvcPtrs), [] (MSVC &msvc) -> MSVC * { return &msvc; }); for (WinSDK &sdk : winSDKs) { const QString name = QLatin1String("WinSDK") + sdk.version + QLatin1Char('-') + sdk.architecture; try { addMSVCPlatform(settings, profiles, name, &sdk); } catch (const ErrorInfo &error) { qbsWarning() << Tr::tr("Failed to set up %1: %2").arg(name, error.toString()); } } // we want the same MSVC version share the same suffix in profiles, thus use // a set to know the number of versions processed so far std::map> msvcCounters; for (MSVC &msvc : msvcs) { // each VS needs its own counter auto &msvcVersions = msvcCounters[msvc.version]; // vcInstallPath is "Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.16.27023/bin" // Since msvcs are sorted by version, when the new vcInstallPath is inserted, we start // a new group of compilers of the same version incrementing the set size msvcVersions.insert(msvc.vcInstallPath); // index is the number of specific vcInstallPaths (e.g. compiler versions) seen so far const size_t index = msvcVersions.size() - 1; const QString suffix = index == 0 ? QString() : QStringLiteral("-%1").arg(index); const QString name = QLatin1String("MSVC") + msvc.version + suffix + QLatin1Char('-') + msvc.architecture; try { addMSVCPlatform(settings, profiles, name, &msvc); } catch (const ErrorInfo &error) { qbsWarning() << Tr::tr("Failed to set up %1: %2").arg(name, error.toString()); } } } void createMsvcProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { const auto compilerFilePath = compiler.absoluteFilePath(); MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath)); msvc.init(); std::vector dummy; addMSVCPlatform(settings, dummy, profileName, &msvc); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profileName, QDir::toNativeSeparators(compilerFilePath)); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/iarewprobe.h0000644000175100001660000000453314776170045022420 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_IAREWPROBE_H #define QBS_SETUPTOOLCHAINS_IAREWPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isIarCompiler(const QString &compilerName); void createIarProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); void iarProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/dmcprobe.h0000644000175100001660000000453314776170045022054 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_DMCPROBE_H #define QBS_SETUPTOOLCHAINS_DMCPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isDmcCompiler(const QString &compilerName); void createDmcProfile(const QFileInfo &compiler, qbs::Settings *settings, QStringView profileName); void dmcProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/main.cpp0000644000175100001660000000571714776170045021545 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include "probe.h" #include #include #include #include #include #include using qbs::Settings; static void printUsage(const QString &usageString) { std::cout << qPrintable(usageString) << std::endl; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(app.arguments()); if (clParser.helpRequested()) { printUsage(clParser.usageString()); return EXIT_SUCCESS; } Settings settings(clParser.settingsDir()); settings.setScopeForWriting(clParser.settingsScope()); if (clParser.autoDetectionMode()) { probe(&settings); return EXIT_SUCCESS; } createProfile(clParser.profileName(), clParser.toolchainType(), clParser.compilerPath(), &settings); } catch (const qbs::ErrorInfo &e) { std::cerr << qPrintable(e.toString()) << std::endl; return EXIT_FAILURE; } } qbs-src-2.6.1/src/app/qbs-setup-toolchains/gccprobe.h0000644000175100001660000000466714776170045022055 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_GCCPROBE_H #define QBS_SETUPTOOLCHAINS_GCCPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } qbs::Profile createGccProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &toolchainType, const QString &profileName = QString()); void gccProbe(qbs::Settings *settings, std::vector &profiles, const QString &compilerName); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/msvcprobe.h0000644000175100001660000000445614776170045022265 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_MSVCPROBE_H #define QBS_SETUPTOOLCHAINS_MSVCPROBE_H #include #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } void createMsvcProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); void msvcProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/CMakeLists.txt0000644000175100001660000000113714776170045022645 0ustar runnerdockerset(SOURCES clangclprobe.cpp clangclprobe.h commandlineparser.cpp commandlineparser.h cosmicprobe.cpp cosmicprobe.h dmcprobe.cpp dmcprobe.h emscriptenprobe.cpp emscriptenprobe.h gccprobe.cpp gccprobe.h iarewprobe.cpp iarewprobe.h keilprobe.cpp keilprobe.h main.cpp msvcprobe.cpp msvcprobe.h probe.cpp probe.h sdccprobe.cpp sdccprobe.h watcomprobe.cpp watcomprobe.h xcodeprobe.cpp xcodeprobe.h ) add_qbs_app(qbs-setup-toolchains DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.6.1/src/app/qbs-setup-toolchains/qbs-setup-toolchains.rc0000644000175100001660000000023014776170045024510 0ustar runnerdocker#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-toolchains.exe.manifest" qbs-src-2.6.1/src/app/qbs-setup-toolchains/cosmicprobe.h0000644000175100001660000000455114776170045022566 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_COSMICPROBE_H #define QBS_SETUPTOOLCHAINS_COSMICPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isCosmicCompiler(const QString &compilerName); void createCosmicProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); void cosmicProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/probe.cpp0000644000175100001660000002763014776170045021726 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "clangclprobe.h" #include "cosmicprobe.h" #include "dmcprobe.h" #include "emscriptenprobe.h" #include "gccprobe.h" #include "iarewprobe.h" #include "keilprobe.h" #include "msvcprobe.h" #include "sdccprobe.h" #include "watcomprobe.h" #include "xcodeprobe.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN // We need defines for Windows 8. #undef _WIN32_WINNT #define _WIN32_WINNT _WIN32_WINNT_WIN8 #include #include #else #include #endif // Q_OS_WIN using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; static QTextStream qStdout(stdout); static QTextStream qStderr(stderr); QStringList systemSearchPaths() { return QString::fromLocal8Bit(qgetenv("PATH")).split(HostOsInfo::pathListSeparator()); } QString findExecutable(const QString &fileName) { QStringList suffixList{QString()}; if (HostOsInfo::isWindowsHost()) { if (!fileName.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive) && !fileName.endsWith(QLatin1String(".bat"), Qt::CaseInsensitive)) suffixList = QStringList{QStringLiteral(".exe"), QStringLiteral(".bat")}; } const auto ppaths = systemSearchPaths(); for (const QString &ppath : ppaths) { for (const auto &suffix : suffixList) { const QString fullPath = ppath + QLatin1Char('/') + fileName + suffix; if (QFileInfo::exists(fullPath)) return QDir::cleanPath(fullPath); } } return {}; } QString toolchainTypeFromCompilerName(const QString &compilerName) { if (compilerName == QLatin1String("cl.exe")) return QStringLiteral("msvc"); if (compilerName == QLatin1String("clang-cl.exe")) return QStringLiteral("clang-cl"); const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"), QStringLiteral("mingw"), QStringLiteral("gcc") }; for (const auto &type : types) { if (compilerName.contains(type)) return type; } if (compilerName == QLatin1String("g++")) return QStringLiteral("gcc"); if (isEmscriptenCompiler(compilerName)) return QStringLiteral("emscripten"); if (isIarCompiler(compilerName)) return QStringLiteral("iar"); if (isKeilCompiler(compilerName)) return QStringLiteral("keil"); if (isSdccCompiler(compilerName)) return QStringLiteral("sdcc"); if (isCosmicCompiler(compilerName)) return QStringLiteral("cosmic"); if (isDmcCompiler(compilerName)) return QStringLiteral("dmc"); if (isWatcomCompiler(compilerName)) return QStringLiteral("watcom"); return {}; } void probe(Settings *settings) { std::vector profiles; if (HostOsInfo::isWindowsHost()) { msvcProbe(settings, profiles); clangClProbe(settings, profiles); } else if (HostOsInfo::isMacosHost()) { xcodeProbe(settings, profiles); } gccProbe(settings, profiles, QStringLiteral("gcc")); gccProbe(settings, profiles, QStringLiteral("clang")); iarProbe(settings, profiles); keilProbe(settings, profiles); sdccProbe(settings, profiles); cosmicProbe(settings, profiles); dmcProbe(settings, profiles); watcomProbe(settings, profiles); emscriptenProbe(settings, profiles); if (profiles.empty()) { qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl; } else if (profiles.size() == 1 && settings->defaultProfile().isEmpty()) { const QString profileName = profiles.front().name(); qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << Qt::endl; settings->setValue(QStringLiteral("defaultProfile"), profileName); } } void createProfile(const QString &profileName, const QString &toolchainType, const QString &compilerFilePath, Settings *settings) { QFileInfo compiler(compilerFilePath); if (compilerFilePath == compiler.fileName() && !compiler.exists()) compiler = QFileInfo(findExecutable(compilerFilePath)); if (!compiler.exists()) { throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found") .arg(compilerFilePath)); } const QString realToolchainType = !toolchainType.isEmpty() ? toolchainType : toolchainTypeFromCompilerName(compiler.fileName()); const QStringList toolchain = canonicalToolchain(realToolchainType); if (toolchain.contains(QLatin1String("clang-cl"))) createClangClProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("msvc"))) createMsvcProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("emscripten"))) createEmscriptenProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("gcc"))) createGccProfile(compiler, settings, realToolchainType, profileName); else if (toolchain.contains(QLatin1String("iar"))) createIarProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("keil"))) createKeilProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("sdcc"))) createSdccProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("cosmic"))) createCosmicProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("dmc"))) createDmcProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("watcom"))) createWatcomProfile(compiler, settings, profileName); else throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type.")); } int extractVersion(const QByteArray ¯oDump, const QByteArray &keyToken) { const int startIndex = macroDump.indexOf(keyToken); if (startIndex == -1) return -1; const int endIndex = macroDump.indexOf('\n', startIndex); if (endIndex == -1) return -1; const auto keyLength = keyToken.length(); const int version = macroDump.mid(startIndex + keyLength, endIndex - startIndex - keyLength) .toInt(); return version; } static QString resolveSymlinks(const QString &filePath) { QFileInfo fi(filePath); int links = 16; while (links-- && fi.isSymLink()) fi.setFile(fi.dir(), fi.symLinkTarget()); if (links <= 0) return {}; return fi.filePath(); } // Copied from qfilesystemengine_win.cpp. #ifdef Q_OS_WIN // File ID for Windows up to version 7. static inline QByteArray fileIdWin7(HANDLE handle) { BY_HANDLE_FILE_INFORMATION info; if (GetFileInformationByHandle(handle, &info)) { char buffer[sizeof "01234567:0123456701234567\0"]; std::snprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx", info.dwVolumeSerialNumber, info.nFileIndexHigh, info.nFileIndexLow); return QByteArray(buffer); } return {}; } // File ID for Windows starting from version 8. static QByteArray fileIdWin8(HANDLE handle) { QByteArray result; FILE_ID_INFO infoEx = {}; if (::GetFileInformationByHandleEx( handle, static_cast(18), // FileIdInfo in Windows 8 &infoEx, sizeof(FILE_ID_INFO))) { result = QByteArray::number(infoEx.VolumeSerialNumber, 16); result += ':'; // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one. result += QByteArray(reinterpret_cast(&infoEx.FileId), int(sizeof(infoEx.FileId))).toHex(); } return result; } static QByteArray fileIdWin(HANDLE fHandle) { return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ? fileIdWin8(HANDLE(fHandle)) : fileIdWin7(HANDLE(fHandle)); } static QByteArray fileId(const QString &filePath) { QByteArray result; const HANDLE handle = ::CreateFile( reinterpret_cast(filePath.utf16()), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (handle != INVALID_HANDLE_VALUE) { result = fileIdWin(handle); ::CloseHandle(handle); } return result; } static qint64 fileSize(const QString &filePath) { return QFileInfo(filePath).size(); } #else static QByteArray fileId(const QString &filePath) { QByteArray result; if (Q_UNLIKELY(filePath.isEmpty())) return {}; QT_STATBUF statResult = {}; if (QT_STAT(filePath.toLocal8Bit().constData(), &statResult)) return {}; result = QByteArray::number(quint64(statResult.st_dev), 16); result += ':'; result += QByteArray::number(quint64(statResult.st_ino)); return result; } #endif // Q_OS_WIN bool isSameExecutable(const QString &filePath1, const QString &filePath2) { if (filePath1 == filePath2) return true; if (resolveSymlinks(filePath1) == resolveSymlinks(filePath2)) return true; if (fileId(filePath1) == fileId(filePath2)) return true; #ifdef Q_OS_WIN if (fileSize(filePath1) == fileSize(filePath2)) return true; #endif return false; } MacrosMap dumpMacros(const std::function &func) { MacrosMap macros; const QStringList lines = func(); for (const QString &line : lines) { const QString prefix = QLatin1String("#define "); if (!line.startsWith(prefix)) return macros; const auto index = line.indexOf(QLatin1String(" "), prefix.length()); if (index != -1) { const auto key = line.mid(prefix.length(), index - prefix.length()); const auto value = line.mid(index + 1); macros.insert(key, value); } } return macros; } qbs-src-2.6.1/src/app/qbs-setup-toolchains/watcomprobe.h0000644000175100001660000000455014776170045022602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_WATCOMPROBE_H #define QBS_SETUPTOOLCHAINS_WATCOMPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } // namespace qbs bool isWatcomCompiler(const QString &compilerName); void createWatcomProfile( const QFileInfo &compiler, qbs::Settings *settings, QStringView profileName); void watcomProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.6.1/src/app/qbs-setup-toolchains/iarewprobe.cpp0000644000175100001660000003347514776170045022762 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "iarewprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownIarCompilerNames() { return {QStringLiteral("icc8051"), QStringLiteral("iccarm"), QStringLiteral("iccavr"), QStringLiteral("iccstm8"), QStringLiteral("icc430"), QStringLiteral("iccrl78"), QStringLiteral("iccrx"), QStringLiteral("iccrh850"), QStringLiteral("iccv850"), QStringLiteral("icc78k"), QStringLiteral("iccavr32"), QStringLiteral("iccsh"), QStringLiteral("iccriscv"), QStringLiteral("icccf"), QStringLiteral("iccm32c"), QStringLiteral("iccr32c"), QStringLiteral("iccm16c"), QStringLiteral("icccr16c"), QStringLiteral("icchcs12"), QStringLiteral("iccs08")}; } static QString guessIarArchitecture(const QFileInfo &compiler) { const auto baseName = compiler.baseName(); if (baseName == QLatin1String("icc8051")) return QStringLiteral("mcs51"); if (baseName == QLatin1String("iccarm")) return QStringLiteral("arm"); if (baseName == QLatin1String("iccavr")) return QStringLiteral("avr"); if (baseName == QLatin1String("iccstm8")) return QStringLiteral("stm8"); if (baseName == QLatin1String("icc430")) return QStringLiteral("msp430"); if (baseName == QLatin1String("iccrl78")) return QStringLiteral("rl78"); if (baseName == QLatin1String("iccrx")) return QStringLiteral("rx"); if (baseName == QLatin1String("iccrh850")) return QStringLiteral("rh850"); if (baseName == QLatin1String("iccv850")) return QStringLiteral("v850"); if (baseName == QLatin1String("icc78k")) return QStringLiteral("78k"); if (baseName == QLatin1String("iccavr32")) return QStringLiteral("avr32"); if (baseName == QLatin1String("iccsh")) return QStringLiteral("sh"); if (baseName == QLatin1String("iccriscv")) return QStringLiteral("riscv"); if (baseName == QLatin1String("icccf")) return QStringLiteral("m68k"); if (baseName == QLatin1String("iccm32c")) return QStringLiteral("m32c"); if (baseName == QLatin1String("iccr32c")) return QStringLiteral("r32c"); if (baseName == QLatin1String("iccm16c")) return QStringLiteral("m16c"); if (baseName == QLatin1String("icccr16c")) return QStringLiteral("cr16"); if (baseName == QLatin1String("icchcs12")) return QStringLiteral("hcs12"); if (baseName == QLatin1String("iccs08")) return QStringLiteral("hcs8"); return {}; } static Profile createIarProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QString profileName = QString()) { const QFileInfo compiler = info.compilerPath; const QString architecture = guessIarArchitecture(compiler); // In case the profile is auto-detected. if (profileName.isEmpty()) { if (!info.compilerVersion.isValid()) { profileName = QStringLiteral("iar-unknown-%1").arg(architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); profileName = QStringLiteral("iar-%1-%2").arg( version, architecture); } } Profile profile(profileName, settings); profile.setValue(QLatin1String("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QLatin1String("qbs.toolchainType"), QLatin1String("iar")); if (!architecture.isEmpty()) profile.setValue(QLatin1String("qbs.architecture"), architecture); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); return profile; } static Version dumpIarCompilerVersion(const QFileInfo &compiler) { const QString outFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + QLatin1String("/macros.dump"); const QStringList args = {QStringLiteral("."), QStringLiteral("--predef_macros"), outFilePath}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } QByteArray dump; QFile out(outFilePath); if (out.open(QIODevice::ReadOnly)) dump = out.readAll(); out.remove(); const int verCode = extractVersion(dump, "__VER__ "); if (verCode < 0) { qbsWarning() << Tr::tr("No '__VER__' token was found in a compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } const QString arch = guessIarArchitecture(compiler); if (arch == QLatin1String("arm")) return Version{verCode / 1000000, (verCode / 1000) % 1000, verCode % 1000}; if (arch == QLatin1String("avr") || arch == QLatin1String("mcs51") || arch == QLatin1String("stm8") || arch == QLatin1String("msp430") || arch == QLatin1String("rl78") || arch == QLatin1String("rx") || arch == QLatin1String("rh850") || arch == QLatin1String("v850") || arch == QLatin1String("78k") || arch == QLatin1String("avr32") || arch == QLatin1String("sh") || arch == QLatin1String("riscv") || arch == QLatin1String("m68k") || arch == QLatin1String("m32c") || arch == QLatin1String("r32c") || arch == QLatin1String("m16c") || arch == QLatin1String("rc16") || arch == QLatin1String("hcs12") || arch == QLatin1String("hcs8")) { return Version{verCode / 100, verCode % 100}; } return Version{}; } static std::vector installedIarsFromPath() { std::vector infos; const auto compilerNames = knownIarCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo iarPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!iarPath.exists()) continue; const Version version = dumpIarCompilerVersion(iarPath); infos.push_back({iarPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } static std::vector installedIarsFromRegistry() { std::vector infos; if (HostOsInfo::isWindowsHost()) { #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\IAR Systems\\Embedded Workbench"; #else static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\IAR Systems\\Embedded Workbench"; #endif // Dictionary for know toolchains. static const struct Entry { QString registryKey; QString subExePath; } knowToolchains[] = { {QStringLiteral("EWARM"), QStringLiteral("/arm/bin/iccarm.exe")}, {QStringLiteral("EWAVR"), QStringLiteral("/avr/bin/iccavr.exe")}, {QStringLiteral("EW8051"), QStringLiteral("/8051/bin/icc8051.exe")}, {QStringLiteral("EWSTM8"), QStringLiteral("/stm8/bin/iccstm8.exe")}, {QStringLiteral("EW430"), QStringLiteral("/430/bin/icc430.exe")}, {QStringLiteral("EWRL78"), QStringLiteral("/rl78/bin/iccrl78.exe")}, {QStringLiteral("EWRX"), QStringLiteral("/rx/bin/iccrx.exe")}, {QStringLiteral("EWRH850"), QStringLiteral("/rh850/bin/iccrh850.exe")}, {QStringLiteral("EWV850"), QStringLiteral("/v850/bin/iccv850.exe")}, {QStringLiteral("EW78K"), QStringLiteral("/78k/bin/icc78k.exe")}, {QStringLiteral("EWAVR32"), QStringLiteral("/avr32/bin/iccavr32.exe")}, {QStringLiteral("EWSH"), QStringLiteral("/sh/bin/iccsh.exe")}, {QStringLiteral("EWRISCV"), QStringLiteral("/riscv/bin/iccriscv.exe")}, {QStringLiteral("EWCF"), QStringLiteral("/cf/bin/icccf.exe")}, {QStringLiteral("EWM32C"), QStringLiteral("/m32c/bin/iccm32c.exe")}, {QStringLiteral("EWR32C"), QStringLiteral("/r32c/bin/iccr32c.exe")}, {QStringLiteral("EWM16C"), QStringLiteral("/m16c/bin/iccm16c.exe")}, {QStringLiteral("EWCR16C"), QStringLiteral("/cr16c/bin/icccr16c.exe")}, {QStringLiteral("EWHCS12"), QStringLiteral("/hcs12/bin/icchcs12.exe")}, {QStringLiteral("EWS08"), QStringLiteral("/s08/bin/iccs08.exe")}, }; QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto oneLevelGroups = registry.childGroups(); for (const QString &oneLevelKey : oneLevelGroups) { registry.beginGroup(oneLevelKey); const auto twoLevelGroups = registry.childGroups(); for (const Entry &entry : knowToolchains) { if (twoLevelGroups.contains(entry.registryKey)) { registry.beginGroup(entry.registryKey); const auto threeLevelGroups = registry.childGroups(); for (const QString &threeLevelKey : threeLevelGroups) { registry.beginGroup(threeLevelKey); const QString rootPath = registry.value( QStringLiteral("InstallPath")).toString(); if (!rootPath.isEmpty()) { // Build full compiler path. const QFileInfo iarPath(rootPath + entry.subExePath); if (iarPath.exists()) { // Note: threeLevelKey is a guessed toolchain version. infos.push_back({iarPath, Version::fromString(threeLevelKey, true)}); } } registry.endGroup(); } registry.endGroup(); } } registry.endGroup(); } } std::sort(infos.begin(), infos.end()); return infos; } bool isIarCompiler(const QString &compilerName) { return Internal::any_of(knownIarCompilerNames(), [compilerName]( const QString &knownName) { return compilerName.contains(knownName); }); } void createIarProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createIarProfileHelper(info, settings, std::move(profileName)); } void iarProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect IAR toolchains..."); // Make sure that a returned infos are sorted before using the std::set_union! const std::vector regInfos = installedIarsFromRegistry(); const std::vector pathInfos = installedIarsFromPath(); std::vector allInfos; allInfos.reserve(regInfos.size() + pathInfos.size()); std::set_union(regInfos.cbegin(), regInfos.cend(), pathInfos.cbegin(), pathInfos.cend(), std::back_inserter(allInfos)); qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) { return createIarProfileHelper(info, settings); }); if (allInfos.empty()) qbsInfo() << Tr::tr("No IAR toolchains found."); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/keilprobe.cpp0000644000175100001660000004077514776170045022600 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probe.h" #include "keilprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownKeilCompilerNames() { return {QStringLiteral("c51"), QStringLiteral("c251"), QStringLiteral("c166"), QStringLiteral("armcc"), QStringLiteral("armclang")}; } static QString guessKeilArchitecture(const QFileInfo &compiler) { const auto baseName = compiler.baseName(); if (baseName == QLatin1String("c51")) return QStringLiteral("mcs51"); if (baseName == QLatin1String("c251")) return QStringLiteral("mcs251"); if (baseName == QLatin1String("c166")) return QStringLiteral("c166"); if (baseName == QLatin1String("armcc")) return QStringLiteral("arm"); if (baseName == QLatin1String("armclang")) return QStringLiteral("arm"); return {}; } static bool isArmClangCompiler(const QFileInfo &compiler) { return compiler.baseName() == QLatin1String("armclang"); } static Profile createKeilProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QString profileName = QString()) { const QFileInfo compiler = info.compilerPath; const QString architecture = guessKeilArchitecture(compiler); // In case the profile is auto-detected. if (profileName.isEmpty()) { if (!info.compilerVersion.isValid()) { profileName = QStringLiteral("keil-unknown-%1").arg(architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); if (architecture == QLatin1String("arm") && isArmClangCompiler(compiler)) { profileName = QStringLiteral("keil-llvm-%1-%2").arg( version, architecture); } else { profileName = QStringLiteral("keil-%1-%2").arg( version, architecture); } } } Profile profile(profileName, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("cpp.compilerName"), compiler.fileName()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("keil")); if (!architecture.isEmpty()) profile.setValue(QStringLiteral("qbs.architecture"), architecture); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); return profile; } static Version dumpMcsCompilerVersion(const QFileInfo &compiler) { QTemporaryFile fakeIn; if (!fakeIn.open()) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return Version{}; } fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); // Prepare for C51 compiler. fakeIn.write("#if defined(__C51__) || defined(__CX51__)\n"); fakeIn.write("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"\n"); fakeIn.write("# if defined (__C51__)\n"); fakeIn.write("# pragma message (VAR_NAME_VALUE(__C51__))\n"); fakeIn.write("# endif\n"); fakeIn.write("# if defined(__CX51__)\n"); fakeIn.write("# pragma message (VAR_NAME_VALUE(__CX51__))\n"); fakeIn.write("# endif\n"); fakeIn.write("#endif\n"); // Prepare for C251 compiler. fakeIn.write("#if defined(__C251__)\n"); fakeIn.write("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"\n"); fakeIn.write("# if defined(__C251__)\n"); fakeIn.write("# warning (VAR_NAME_VALUE(__C251__))\n"); fakeIn.write("# endif\n"); fakeIn.write("#endif\n"); fakeIn.close(); const QStringList args = {fakeIn.fileName()}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const QStringList knownKeys = {QStringLiteral("__C51__"), QStringLiteral("__CX51__"), QStringLiteral("__C251__")}; auto extractVersion = [&knownKeys](const QByteArray &output) { QTextStream stream(output); QString line; while (stream.readLineInto(&line)) { if (!line.startsWith(QLatin1String("***"))) continue; enum { KEY_INDEX = 1, VALUE_INDEX = 2, ALL_PARTS = 4 }; const QStringList parts = line.split(QLatin1String("\"|\"")); if (parts.count() != ALL_PARTS) continue; if (!knownKeys.contains(parts.at(KEY_INDEX))) continue; return parts.at(VALUE_INDEX).toInt(); } return -1; }; const QByteArray dump = p.readAllStandardOutput(); const int verCode = extractVersion(dump); if (verCode < 0) { qbsWarning() << Tr::tr("No %1 tokens was found" " in the compiler dump:\n%2") .arg(knownKeys.join(QLatin1Char(',')), QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 100, verCode % 100}; } static Version dumpC166CompilerVersion(const QFileInfo &compiler) { QTemporaryFile fakeIn; if (!fakeIn.open()) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return Version{}; } fakeIn.write("#if defined(__C166__)\n"); fakeIn.write("# warning __C166__\n"); fakeIn.write("# pragma __C166__\n"); fakeIn.write("#endif\n"); fakeIn.close(); const QStringList args = {fakeIn.fileName()}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); // Extract the compiler version pattern in the form, like: // // *** WARNING C320 IN LINE 41 OF c51.c: __C166__ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored // // where the '__C166__' is a key, and the '757' is a value (aka version). auto extractVersion = [](const QString &output) { const QStringList lines = output.split(QStringLiteral("\r\n")); for (auto it = lines.cbegin(); it != lines.cend();) { if (it->startsWith(QLatin1String("***")) && it->endsWith(QLatin1String("__C166__"))) { ++it; if (it == lines.cend() || !it->startsWith(QLatin1String("***"))) break; const int startIndex = it->indexOf(QLatin1Char('\'')); if (startIndex == -1) break; const int stopIndex = it->indexOf(QLatin1Char('\''), startIndex + 1); if (stopIndex == -1) break; const QString v = it->mid(startIndex + 1, stopIndex - startIndex - 1); return v.toInt(); } ++it; } return -1; }; const QByteArray dump = p.readAllStandardOutput(); const int verCode = extractVersion(QString::fromUtf8(dump)); if (verCode < 0) { qbsWarning() << Tr::tr("No __C166__ token was found" " in the compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 100, verCode % 100}; } static Version dumpArmCCCompilerVersion(const QFileInfo &compiler) { const QStringList args = {QStringLiteral("-E"), QStringLiteral("--list-macros"), QStringLiteral("nul")}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } const QByteArray dump = p.readAll(); const int verCode = extractVersion(dump, "__ARMCC_VERSION "); if (verCode < 0) { qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found " "in the compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000}; } static Version dumpArmClangCompilerVersion(const QFileInfo &compiler) { const QStringList args = {QStringLiteral("-dM"), QStringLiteral("-E"), QStringLiteral("-xc"), QStringLiteral("--target=arm-arm-none-eabi"), QStringLiteral("-mcpu=cortex-m0"), QStringLiteral("nul")}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } const QByteArray dump = p.readAll(); const int verCode = extractVersion(dump, "__ARMCC_VERSION "); if (verCode < 0) { qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found " "in the compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000}; } static Version dumpKeilCompilerVersion(const QFileInfo &compiler) { const QString arch = guessKeilArchitecture(compiler); if (arch == QLatin1String("mcs51") || arch == QLatin1String("mcs251")) return dumpMcsCompilerVersion(compiler); if (arch == QLatin1String("c166")) return dumpC166CompilerVersion(compiler); if (arch == QLatin1String("arm")) { if (isArmClangCompiler(compiler)) return dumpArmClangCompilerVersion(compiler); return dumpArmCCCompilerVersion(compiler); } return Version{}; } static std::vector installedKeilsFromPath() { std::vector infos; const auto compilerNames = knownKeilCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo keilPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!keilPath.exists()) continue; const Version version = dumpKeilCompilerVersion(keilPath); infos.push_back({keilPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } static std::vector installedKeilsFromRegistry() { std::vector infos; if (HostOsInfo::isWindowsHost()) { #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Keil\\Products"; #else static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Keil\\Products"; #endif QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { registry.beginGroup(productKey); const QString productPath = registry.value(QStringLiteral("Path")) .toString(); QString productVersion = registry.value(QStringLiteral("Version")) .toString(); if (productVersion.startsWith(QLatin1Char('V'))) productVersion.remove(0, 1); if (productKey == QLatin1String("MDK")) { const QFileInfo ccPath(productPath + QStringLiteral("/ARMCC/bin/armcc.exe")); if (ccPath.exists()) infos.push_back({ccPath, Version::fromString(productVersion)}); const QFileInfo clangPath(productPath + QStringLiteral("/ARMCLANG/bin/armclang.exe")); if (clangPath.exists()) infos.push_back({clangPath, Version::fromString(productVersion)}); } if (productKey == QLatin1String("C51")) { const QFileInfo cPath(productPath + QStringLiteral("/BIN/c51.exe")); if (cPath.exists()) infos.push_back({cPath, Version::fromString(productVersion)}); } if (productKey == QLatin1String("C251")) { const QFileInfo cPath(productPath + QStringLiteral("/BIN/c251.exe")); if (cPath.exists()) infos.push_back({cPath, Version::fromString(productVersion)}); } if (productKey == QLatin1String("C166")) { const QFileInfo cPath(productPath + QStringLiteral("/BIN/c166.exe")); if (cPath.exists()) infos.push_back({cPath, Version::fromString(productVersion)}); } registry.endGroup(); } } std::sort(infos.begin(), infos.end()); return infos; } bool isKeilCompiler(const QString &compilerName) { return Internal::any_of(knownKeilCompilerNames(), [compilerName]( const QString &knownName) { return compilerName.contains(knownName); }); } void createKeilProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createKeilProfileHelper(info, settings, std::move(profileName)); } void keilProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect KEIL toolchains..."); // Make sure that a returned infos are sorted before using the std::set_union! const std::vector regInfos = installedKeilsFromRegistry(); const std::vector pathInfos = installedKeilsFromPath(); std::vector allInfos; allInfos.reserve(regInfos.size() + pathInfos.size()); std::set_union(regInfos.cbegin(), regInfos.cend(), pathInfos.cbegin(), pathInfos.cend(), std::back_inserter(allInfos)); qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) { return createKeilProfileHelper(info, settings); }); if (allInfos.empty()) qbsInfo() << Tr::tr("No KEIL toolchains found."); } qbs-src-2.6.1/src/app/qbs-setup-toolchains/probe.h0000644000175100001660000000617714776170045021376 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_PROBE_H #define QBS_SETUPTOOLCHAINS_PROBE_H #include #include #include #include #include // for std::function #include // for std::tie namespace qbs { class Settings; } QStringList systemSearchPaths(); QString findExecutable(const QString &fileName); QString toolchainTypeFromCompilerName(const QString &compilerName); void createProfile(const QString &profileName, const QString &toolchainType, const QString &compilerFilePath, qbs::Settings *settings); void probe(qbs::Settings *settings); struct ToolchainInstallInfo { QFileInfo compilerPath; qbs::Version compilerVersion; }; inline bool operator<(const ToolchainInstallInfo &lhs, const ToolchainInstallInfo &rhs) { const auto lp = lhs.compilerPath.absoluteFilePath(); const auto rp = rhs.compilerPath.absoluteFilePath(); return std::tie(lp, lhs.compilerVersion) < std::tie(rp, rhs.compilerVersion); } int extractVersion(const QByteArray ¯oDump, const QByteArray &keyToken); bool isSameExecutable(const QString &exe1, const QString &exe2); using MacrosMap = QMap; MacrosMap dumpMacros(const std::function &func); #endif // Header guard qbs-src-2.6.1/src/app/qbs-create-project/0000755000175100001660000000000014776170045017511 5ustar runnerdockerqbs-src-2.6.1/src/app/qbs-create-project/createproject.h0000644000175100001660000000651614776170045022524 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_CREATEPROJECT_H #define QBS_CREATEPROJECT_H #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QDir; class QTextStream; QT_END_NAMESPACE enum class ProjectStructure { Flat, Composite }; class ProjectCreator { public: void run(const QString &topLevelDir, ProjectStructure projectStructure, const QStringList &whiteList, const QStringList &blacklist); private: enum ProductFlag { IsApp = 1, NeedsCpp = 2, NeedsQt = 4 }; Q_DECLARE_FLAGS(ProductFlags, ProductFlag) struct Project; void setupProject(Project *project); void serializeProject(const Project &project); void addGroups(QTextStream &stream, const QDir &baseDir, const Project &subProject); bool isSourceFile(const QString &fileName); ProductFlags getFlags(const Project &project); void getFlagsFromFileNames(const Project &project, ProductFlags &flags); void getFlagsFromFileContents(const Project &project, ProductFlags &flags); using ProjectPtr = std::unique_ptr; struct Project { QString dirPath; QString dirName; QStringList fileNames; std::vector subProjects; }; Project m_topLevelProject; ProjectStructure m_projectStructure = ProjectStructure::Flat; QList m_whiteList; QList m_blackList; }; #endif // QBS_CREATEPROJECT_H qbs-src-2.6.1/src/app/qbs-create-project/qbs-create-project.qbs0000644000175100001660000000023014776170045023705 0ustar runnerdockerQbsApp { name: "qbs-create-project" files: [ "createproject.cpp", "createproject.h", "create-project-main.cpp", ] } qbs-src-2.6.1/src/app/qbs-create-project/createproject.cpp0000644000175100001660000002332414776170045023053 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "createproject.h" #include #include #include #include #include #include #include #include #include #include #include using qbs::ErrorInfo; using qbs::Internal::Tr; static const char *indent = " "; void ProjectCreator::run(const QString &topLevelDir, ProjectStructure projectStructure, const QStringList &whiteList, const QStringList &blackList) { m_projectStructure = projectStructure; qbs::Internal::transform(whiteList, m_whiteList, [](const QString &s) { return QRegularExpression(QRegularExpression::wildcardToRegularExpression(s)); }); qbs::Internal::transform(blackList, m_blackList, [](const QString &s) { return QRegularExpression(QRegularExpression::wildcardToRegularExpression(s)); }); m_topLevelProject.dirPath = topLevelDir; setupProject(&m_topLevelProject); serializeProject(m_topLevelProject); } void ProjectCreator::setupProject(Project *project) { QDirIterator dit(project->dirPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); while (dit.hasNext()) { dit.next(); if (dit.fileInfo().isFile()) { if (dit.fileName().endsWith(QLatin1String(".qbs"))) throw ErrorInfo(Tr::tr("Project already contains qbs files, aborting.")); if (isSourceFile(dit.fileName())) project->fileNames << dit.fileName(); } else if (dit.fileInfo().isDir()) { ProjectPtr subProject(new Project); subProject->dirName = dit.fileName(); subProject->dirPath = dit.filePath(); setupProject(subProject.get()); if (!subProject->fileNames.empty() || !subProject->subProjects.empty()) project->subProjects.push_back(std::move(subProject)); } } project->fileNames.sort(); std::sort(project->subProjects.begin(), project->subProjects.end(), [](const ProjectPtr &p1, const ProjectPtr &p2) { return p1->dirName < p2->dirName; }); } void ProjectCreator::serializeProject(const ProjectCreator::Project &project) { const QString fileName = QFileInfo(project.dirPath).baseName() + QLatin1String(".qbs"); QFile projectFile(project.dirPath + QLatin1Char('/') + fileName); if (!projectFile.open(QIODevice::WriteOnly)) { throw ErrorInfo(Tr::tr("Failed to open '%1' for writing: %2") .arg(projectFile.fileName(), projectFile.errorString())); } QTextStream fileContents(&projectFile); qbs::setupDefaultCodec(fileContents); if (!project.fileNames.empty() || m_projectStructure == ProjectStructure::Flat) { fileContents << "Product {\n"; const ProductFlags productFlags = getFlags(project); if (productFlags.testFlag(IsApp)) { fileContents << indent << "type: [\"application\"]\n"; } else { fileContents << indent << "type: [\"unknown\"] // E.g. \"application\", " "\"dynamiclibrary\", \"staticlibrary\"\n"; } if (productFlags.testFlag(NeedsQt)) { fileContents << indent << "Depends {\n"; fileContents << indent << indent << "name: \"Qt\"\n"; fileContents << indent << indent << "submodules: [\"core\"] " "// Add more here if needed\n"; fileContents << indent << "}\n"; } else if (productFlags.testFlag(NeedsCpp)) { fileContents << indent << "Depends { name: \"cpp\" }\n"; } fileContents << indent << "files: [\n"; for (const QString &fileName : std::as_const(project.fileNames)) fileContents << indent << indent << qbs::toJSLiteral(fileName) << ",\n"; fileContents << indent << "]\n"; for (const ProjectPtr &p : project.subProjects) addGroups(fileContents, QDir(project.dirPath), *p); } else { fileContents << "Project {\n"; fileContents << indent << "references: [\n"; for (const ProjectPtr &p : project.subProjects) { serializeProject(*p); fileContents << indent << indent << qbs::toJSLiteral(QFileInfo(p->dirPath).fileName()) << ",\n"; } fileContents << indent << "]\n"; } fileContents << "}\n"; } void ProjectCreator::addGroups(QTextStream &stream, const QDir &baseDir, const ProjectCreator::Project &subProject) { stream << indent << "Group {\n"; stream << indent << indent << "name: " << qbs::toJSLiteral(QFileInfo(subProject.dirPath).fileName()) << "\n"; stream << indent << indent << "prefix: " << qbs::toJSLiteral(baseDir.relativeFilePath(subProject.dirPath) + QLatin1Char('/')) << '\n'; stream << indent << indent << "files: [\n"; for (const QString &fileName : std::as_const(subProject.fileNames)) stream << indent << indent << indent << qbs::toJSLiteral(fileName) << ",\n"; stream << indent << indent << "]\n"; stream << indent << "}\n"; for (const ProjectPtr &p : subProject.subProjects) addGroups(stream, baseDir, *p); } bool ProjectCreator::isSourceFile(const QString &fileName) { const auto isMatch = [fileName](const QRegularExpression &rex) { return rex.match(fileName).hasMatch(); }; return !qbs::Internal::any_of(m_blackList, isMatch) && (m_whiteList.empty() || qbs::Internal::any_of(m_whiteList, isMatch)); } ProjectCreator::ProductFlags ProjectCreator::getFlags(const ProjectCreator::Project &project) { ProductFlags flags; getFlagsFromFileNames(project, flags); if (flags.testFlag(IsApp) && flags.testFlag(NeedsQt)) return flags; if (!flags.testFlag(NeedsCpp)) return flags; getFlagsFromFileContents(project, flags); return flags; } void ProjectCreator::getFlagsFromFileNames(const ProjectCreator::Project &project, ProductFlags &flags) { for (const QString &fileName : std::as_const(project.fileNames)) { if (flags.testFlag(IsApp) && flags.testFlag(NeedsQt)) return; const QFileInfo fi(project.dirPath + QLatin1Char('/') + fileName); const QString &suffix = fi.suffix(); if (suffix == QLatin1String("qrc")) { flags |= NeedsQt; continue; } if (suffix == QLatin1String("cpp") || suffix == QLatin1String("c") || suffix == QLatin1String("m") || suffix == QLatin1String("mm")) { flags |= NeedsCpp; } if (flags.testFlag(NeedsCpp) && fi.completeBaseName() == QLatin1String("main")) flags |= IsApp; } for (const ProjectPtr &p : project.subProjects) { getFlagsFromFileNames(*p, flags); if (flags.testFlag(IsApp) && flags.testFlag(NeedsQt)) return; } } void ProjectCreator::getFlagsFromFileContents(const ProjectCreator::Project &project, ProductFlags &flags) { for (const QString &fileName : std::as_const(project.fileNames)) { QFile f (project.dirPath + QLatin1Char('/') + fileName); if (!f.open(QIODevice::ReadOnly)) { qDebug() << "Ignoring failure to read" << f.fileName(); continue; } while (!f.atEnd()) { const QByteArray &line = f.readLine(); if (line.contains("#include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { using qbs::ErrorInfo; using qbs::Internal::Tr; QCoreApplication app(argc, argv); const QCommandLineOption flatOpt(QStringLiteral("flat"), Tr::tr("Do not create nested project files, even if there are subdirectories and " "the top-level directory does not contain any files.")); const QCommandLineOption whiteListOpt(QStringLiteral("whitelist"), Tr::tr("Only consider files whose names match these patterns. The list entries " "can contain wildcards and are separated by commas. By default, all files " "are considered."), QStringLiteral("whitelist")); const QCommandLineOption blackListOpt(QStringLiteral("blacklist"), Tr::tr("Ignore files whose names match these patterns. The list entries " "can contain wildcards and are separated by commas. By default, no files " "are ignored."), QStringLiteral("blacklist")); QCommandLineParser parser; parser.setApplicationDescription(Tr::tr("This tool creates a qbs project from an existing " "source tree.\nNote: The resulting project file(s) " "will likely require manual editing.")); parser.addOption(flatOpt); parser.addOption(whiteListOpt); parser.addOption(blackListOpt); parser.addHelpOption(); parser.process(app); const ProjectStructure projectStructure = parser.isSet(flatOpt) ? ProjectStructure::Flat : ProjectStructure::Composite; const QStringList whiteList = parser.value(whiteListOpt).split(QLatin1Char(','), Qt::SkipEmptyParts); const QStringList blackList = parser.value(blackListOpt).split(QLatin1Char(','), Qt::SkipEmptyParts); try { ProjectCreator().run(QDir::currentPath(), projectStructure, whiteList, blackList); } catch (const ErrorInfo &e) { std::cerr << qPrintable(Tr::tr("Error creating project: %1").arg(e.toString())) << std::endl; return 1; } } qbs-src-2.6.1/src/app/qbs/0000755000175100001660000000000014776170045014604 5ustar runnerdockerqbs-src-2.6.1/src/app/qbs/stdinreader.cpp0000644000175100001660000002475114776170045017625 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "stdinreader.h" #include #include #include #include #include #include #include #ifdef Q_OS_WIN32 #include #else #include #endif namespace qbs { namespace Internal { class UnixStdinReader : public StdinReader { public: UnixStdinReader(QObject *parent) : StdinReader(parent), m_notifier(0, QSocketNotifier::Read) {} private: void start() override { if (!m_stdIn.open(stdin, QIODevice::ReadOnly)) { emit errorOccurred(tr("Cannot read from standard input.")); return; } #ifdef Q_OS_UNIX const auto emitError = [this] { emit errorOccurred(tr("Failed to make standard input non-blocking: %1") .arg(QLatin1String(std::strerror(errno)))); }; const int flags = fcntl(0, F_GETFL, 0); if (flags == -1) { emitError(); return; } if (fcntl(0, F_SETFL, flags | O_NONBLOCK)) { emitError(); return; } #endif connect(&m_notifier, &QSocketNotifier::activated, this, [this] { emit dataAvailable(m_stdIn.readAll()); }); // Neither the aboutToClose() nor the readChannelFinished() signals // are triggering, so we need a timer to check whether the controlling // process disappeared. const auto stdinClosedChecker = new QTimer(this); connect(stdinClosedChecker, &QTimer::timeout, this, [this, stdinClosedChecker] { if (m_stdIn.atEnd()) { stdinClosedChecker->stop(); emit errorOccurred(tr("Input channel closed unexpectedly.")); } }); stdinClosedChecker->start(1000); } QFile m_stdIn; QSocketNotifier m_notifier; }; class WindowsStdinReader : public StdinReader { public: WindowsStdinReader(QObject *parent) : StdinReader(parent) {} private: #ifdef Q_OS_WIN32 class FileReaderThread : public QThread { public: FileReaderThread(WindowsStdinReader &parent, HANDLE stdInHandle, HANDLE exitEventHandle) : QThread(&parent), m_stdIn{stdInHandle}, m_exitEvent{exitEventHandle} { } ~FileReaderThread() { wait(); CloseHandle(m_exitEvent); } void run() override { WindowsStdinReader *r = static_cast(parent()); char buf[1024]; while (true) { DWORD bytesRead = 0; if (!ReadFile(m_stdIn, buf, sizeof buf, &bytesRead, nullptr)) { emit r->errorOccurred(tr("Failed to read from input channel.")); break; } if (!bytesRead) break; emit r->dataAvailable(QByteArray(buf, bytesRead)); } } private: HANDLE m_stdIn; HANDLE m_exitEvent; }; class ConsoleReaderThread : public QThread { public: ConsoleReaderThread(WindowsStdinReader &parent, HANDLE stdInHandle, HANDLE exitEventHandle) : QThread(&parent), m_stdIn{stdInHandle}, m_exitEvent{exitEventHandle} { } virtual ~ConsoleReaderThread() override { SetEvent(m_exitEvent); wait(); CloseHandle(m_exitEvent); } void run() override { WindowsStdinReader *r = static_cast(parent()); DWORD origConsoleMode; GetConsoleMode(m_stdIn, &origConsoleMode); DWORD consoleMode = ENABLE_PROCESSED_INPUT; SetConsoleMode(m_stdIn, consoleMode); HANDLE handles[2] = {m_exitEvent, m_stdIn}; char buf[1024]; while (true) { auto result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) break; INPUT_RECORD consoleInput; DWORD inputsRead = 0; if (!PeekConsoleInputA(m_stdIn, &consoleInput, 1, &inputsRead)) { emit r->errorOccurred(tr("Failed to read from input channel.")); break; } if (inputsRead) { if (consoleInput.EventType != KEY_EVENT || !consoleInput.Event.KeyEvent.bKeyDown || !consoleInput.Event.KeyEvent.uChar.AsciiChar) { if (!ReadConsoleInputA(m_stdIn, &consoleInput, 1, &inputsRead)) { emit r->errorOccurred(tr("Failed to read console input.")); break; } } else { DWORD bytesRead = 0; if (!ReadConsoleA(m_stdIn, buf, sizeof buf, &bytesRead, nullptr)) { emit r->errorOccurred(tr("Failed to read console.")); break; } emit r->dataAvailable(QByteArray(buf, bytesRead)); } } } SetConsoleMode(m_stdIn, origConsoleMode); } private: HANDLE m_stdIn; HANDLE m_exitEvent; }; class PipeReaderThread : public QThread { public: PipeReaderThread(WindowsStdinReader &parent, HANDLE stdInHandle, HANDLE exitEventHandle) : QThread(&parent), m_stdIn{stdInHandle}, m_exitEvent{exitEventHandle} { } virtual ~PipeReaderThread() override { SetEvent(m_exitEvent); wait(); CloseHandle(m_exitEvent); } void run() override { WindowsStdinReader *r = static_cast(parent()); OVERLAPPED overlapped = {}; overlapped.hEvent = CreateEventA(NULL, TRUE, TRUE, NULL); if (!overlapped.hEvent) { emit r->errorOccurred(StdinReader::tr("Failed to create handle for overlapped event.")); return; } char buf[1024]; DWORD bytesRead; HANDLE handles[2] = {m_exitEvent, overlapped.hEvent}; while (true) { bytesRead = 0; auto readResult = ReadFile(m_stdIn, buf, sizeof buf, NULL, &overlapped); if (!readResult) { if (GetLastError() != ERROR_IO_PENDING) { emit r->errorOccurred(StdinReader::tr("ReadFile Failed.")); break; } auto result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) break; } if (!GetOverlappedResult(m_stdIn, &overlapped, &bytesRead, FALSE)) { if (GetLastError() != ERROR_HANDLE_EOF) emit r->errorOccurred(StdinReader::tr("Error GetOverlappedResult.")); break; } emit r->dataAvailable(QByteArray(buf, bytesRead)); } CancelIo(m_stdIn); CloseHandle(overlapped.hEvent); } private: HANDLE m_stdIn; HANDLE m_exitEvent; }; #endif void start() override { #ifdef Q_OS_WIN32 HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE); if (!stdInHandle) { emit errorOccurred(StdinReader::tr("Failed to create handle for standard input.")); return; } HANDLE exitEventHandle = CreateEventA(NULL, TRUE, FALSE, NULL); if (!exitEventHandle) { emit errorOccurred(StdinReader::tr("Failed to create handle for exit event.")); return; } auto result = GetFileType(stdInHandle); switch (result) { case FILE_TYPE_CHAR: (new ConsoleReaderThread(*this, stdInHandle, exitEventHandle))->start(); return; case FILE_TYPE_PIPE: (new PipeReaderThread(*this, stdInHandle, exitEventHandle))->start(); return; case FILE_TYPE_DISK: (new FileReaderThread(*this, stdInHandle, exitEventHandle))->start(); return; default: emit errorOccurred(StdinReader::tr("Unable to handle unknown input type")); return; } #endif } }; StdinReader *StdinReader::create(QObject *parent) { if (HostOsInfo::isWindowsHost()) return new WindowsStdinReader(parent); return new UnixStdinReader(parent); } StdinReader::StdinReader(QObject *parent) : QObject(parent) { } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/app/qbs/sessionpacketreader.h0000644000175100001660000000471014776170045021015 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SESSIONPACKETREADER_H #define QBS_SESSIONPACKETREADER_H #include #include #include namespace qbs { namespace Internal { class SessionPacketReader : public QObject { Q_OBJECT public: explicit SessionPacketReader(QObject *parent = nullptr); ~SessionPacketReader() override; void start(); signals: void packetReceived(const QJsonObject &packet); void errorOccurred(const QString &msg); private: class Private; const std::unique_ptr d; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/app/qbs/ctrlchandler.cpp0000644000175100001660000000473414776170045017765 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "application.h" static void cancel() { qbs::Application * const app = qbs::Application::instance(); if (app) app->userInterrupt(); } #if defined(Q_OS_WIN) && defined(Q_CC_MSVC) #include static BOOL WINAPI consoleCtrlHandlerRoutine(__in DWORD dwCtrlType) { Q_UNUSED(dwCtrlType); cancel(); return TRUE; } void installCtrlCHandler() { SetConsoleCtrlHandler(&consoleCtrlHandlerRoutine, TRUE); } #else #include static void sigIntHandler(int sig) { Q_UNUSED(sig); cancel(); } void installCtrlCHandler() { signal(SIGINT, sigIntHandler); } #endif qbs-src-2.6.1/src/app/qbs/commandlinefrontend.cpp0000644000175100001660000006652414776170045021353 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlinefrontend.h" #include "application.h" #include "consoleprogressobserver.h" #include "session.h" #include "status.h" #include "parser/commandlineoption.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { using namespace Internal; CommandLineFrontend::CommandLineFrontend(const CommandLineParser &parser, Settings *settings, QObject *parent) : QObject(parent) , m_parser(parser) , m_settings(settings) , m_observer(nullptr) , m_cancelStatus(CancelStatusNone) , m_cancelTimer(new QTimer(this)) { } CommandLineFrontend::~CommandLineFrontend() { m_cancelTimer->stop(); delete m_observer; } // Called from interrupt handler. Don't do anything non-trivial here. void CommandLineFrontend::cancel() { m_cancelStatus = CancelStatusRequested; } void CommandLineFrontend::checkCancelStatus() { switch (m_cancelStatus) { case CancelStatusNone: break; case CancelStatusRequested: m_cancelStatus = CancelStatusCanceling; m_cancelTimer->stop(); if (m_resolveJobs.empty() && m_buildJobs.empty()) std::exit(EXIT_FAILURE); for (AbstractJob * const job : std::as_const(m_resolveJobs)) job->cancel(); for (AbstractJob * const job : std::as_const(m_buildJobs)) job->cancel(); break; case CancelStatusCanceling: QBS_ASSERT(false, return); break; } } void CommandLineFrontend::start() { try { switch (m_parser.command()) { case RunCommandType: case ShellCommandType: if (m_parser.products().size() > 1) { throw ErrorInfo(Tr::tr("Invalid use of command '%1': Cannot use more than one " "product.\nUsage: %2") .arg(m_parser.commandName(), m_parser.commandDescription())); } Q_FALLTHROUGH(); case StatusCommandType: case InstallCommandType: case DumpNodesTreeCommandType: case ListProductsCommandType: if (m_parser.buildConfigurations().size() > 1) { QString error = Tr::tr("Invalid use of command '%1': There can be only one " "build configuration.\n").arg(m_parser.commandName()); error += Tr::tr("Usage: %1").arg(m_parser.commandDescription()); throw ErrorInfo(error); } break; case SessionCommandType: { startSession(); return; } default: break; } if (m_parser.showVersion()) { std::puts(QBS_VERSION); qApp->exit(EXIT_SUCCESS); return; } if (m_parser.showProgress()) m_observer = new ConsoleProgressObserver; SetupProjectParameters params; params.setEnvironment(QProcessEnvironment::systemEnvironment()); params.setProjectFilePath(m_parser.projectFilePath()); params.setDryRun(m_parser.dryRun()); params.setForceProbeExecution(m_parser.forceProbesExecution()); params.setWaitLockBuildGraph(m_parser.waitLockBuildGraph()); params.setLogElapsedTime(m_parser.logTime()); params.setSettingsDirectory(m_settings->baseDirectory()); params.setOverrideBuildGraphData(m_parser.command() == ResolveCommandType); params.setPropertyCheckingMode(ErrorHandlingMode::Strict); params.setDeprecationWarningMode(m_parser.deprecationWarningMode()); if (!m_parser.buildBeforeInstalling() || !m_parser.commandCanResolve()) params.setRestoreBehavior(SetupProjectParameters::RestoreOnly); const auto buildConfigs = m_parser.buildConfigurations(); for (const QVariantMap &buildConfig : buildConfigs) { QVariantMap userConfig = buildConfig; const QString configurationKey = QStringLiteral("qbs.configurationName"); const QString profileKey = QStringLiteral("qbs.profile"); const QString installRootKey = QStringLiteral("qbs.installRoot"); QString installRoot = userConfig.value(installRootKey).toString(); if (!installRoot.isEmpty() && QFileInfo(installRoot).isRelative()) { installRoot.prepend(QLatin1Char('/')).prepend(QDir::currentPath()); userConfig.insert(installRootKey, installRoot); } const QString configurationName = userConfig.take(configurationKey).toString(); const QString profileName = userConfig.take(profileKey).toString(); const Preferences prefs(m_settings); params.setSearchPaths(prefs.searchPaths(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_SEARCH_PATH)))); params.setPluginPaths(prefs.pluginPaths(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_PLUGINS_PATH)))); params.setLibexecPath(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH))); params.setTopLevelProfile(profileName); params.setConfigurationName(configurationName); params.setBuildRoot(buildDirectory(profileName)); params.setOverriddenValues(userConfig); params.setMaxJobCount(m_parser.jobCount(profileName)); SetupProjectJob * const job = Project().setupProject(params, ConsoleLogger::instance().logSink(), this); connectJob(job); m_resolveJobs.push_back(job); } /* * Progress reporting on the terminal gets a bit tricky when resolving several projects * concurrently, since we cannot show multiple progress bars at the same time. Instead, * we just set the total effort to the number of projects and increase the progress * every time one of them finishes, ignoring the progress reports from the jobs themselves. * (Yes, that does mean it will take disproportionately long for the first progress * notification to arrive.) */ if (m_parser.showProgress() && resolvingMultipleProjects()) m_observer->initialize(tr("Setting up projects"), m_resolveJobs.size()); // Check every two seconds whether we received a cancel request. This value has been // experimentally found to be acceptable. // Note that this polling approach is not problematic here, since we are doing work anyway, // so there's no danger of waking up the processor for no reason. connect(m_cancelTimer, &QTimer::timeout, this, &CommandLineFrontend::checkCancelStatus); m_cancelTimer->start(2000); } catch (const ErrorInfo &error) { qbsError() << error.toString(); if (m_buildJobs.empty() && m_resolveJobs.empty()) { qApp->exit(EXIT_FAILURE); } else { cancel(); checkCancelStatus(); } } } void CommandLineFrontend::handleCommandDescriptionReport(const QString &highlight, const QString &message) { qbsInfo() << MessageTag(highlight) << message; } void CommandLineFrontend::handleJobFinished(bool success, AbstractJob *job) { try { job->deleteLater(); if (!success) { qbsError() << job->error().toString(); m_resolveJobs.removeOne(job); m_buildJobs.removeOne(job); if (m_resolveJobs.empty() && m_buildJobs.empty()) { qApp->exit(EXIT_FAILURE); return; } cancel(); } else if (const auto setupJob = qobject_cast(job)) { m_resolveJobs.removeOne(job); m_projects.push_back(setupJob->project()); if (m_observer && resolvingMultipleProjects()) m_observer->incrementProgressValue(); if (m_resolveJobs.empty()) handleProjectsResolved(); } else if (qobject_cast(job)) { if (m_parser.command() == RunCommandType) qApp->exit(runTarget()); else qApp->quit(); } else { // Build or clean. m_buildJobs.removeOne(job); if (m_buildJobs.empty()) { switch (m_parser.command()) { case RunCommandType: case InstallCommandType: install(); break; case GenerateCommandType: generate(); // fall through case BuildCommandType: case CleanCommandType: qApp->exit(m_cancelStatus == CancelStatusNone ? EXIT_SUCCESS : EXIT_FAILURE); break; default: Q_ASSERT_X(false, Q_FUNC_INFO, "Missing case in switch statement"); } } } } catch (const ErrorInfo &error) { qbsError() << error.toString(); qApp->exit(EXIT_FAILURE); } } void CommandLineFrontend::handleNewTaskStarted(const QString &description, int totalEffort) { // If the user does not want a progress bar, we just print the current activity. if (!m_parser.showProgress()) { if (!m_parser.logTime()) qbsInfo() << description; return; } if (isBuilding()) { m_totalBuildEffort += totalEffort; if (++m_buildEffortsRetrieved == m_buildEffortsNeeded) { m_observer->initialize(tr("Building"), m_totalBuildEffort); if (m_currentBuildEffort > 0) m_observer->setProgressValue(m_currentBuildEffort); } } else if (!resolvingMultipleProjects()) { m_observer->initialize(description, totalEffort); } } void CommandLineFrontend::handleTotalEffortChanged(int totalEffort) { // Can only happen when resolving. if (m_parser.showProgress() && !isBuilding() && !resolvingMultipleProjects()) m_observer->setMaximum(totalEffort); } void CommandLineFrontend::handleTaskProgress(int value, AbstractJob *job) { if (isBuilding()) { int ¤tJobEffort = m_buildEfforts[job]; m_currentBuildEffort += value - currentJobEffort; currentJobEffort = value; if (m_buildEffortsRetrieved == m_buildEffortsNeeded) m_observer->setProgressValue(m_currentBuildEffort); } else if (!resolvingMultipleProjects()) { m_observer->setProgressValue(value); } } void CommandLineFrontend::handleProcessResultReport(const qbs::ProcessResult &result) { bool hasOutput = !result.stdOut().empty() || !result.stdErr().empty(); if (!hasOutput && result.success()) return; LogWriter w = result.success() ? qbsInfo() : qbsError(); w << shellQuote(QDir::toNativeSeparators(result.executableFilePath()), result.arguments()) << (hasOutput ? QStringLiteral("\n") : QString()) << (result.stdOut().empty() ? QString() : result.stdOut().join(QLatin1Char('\n'))); if (!result.stdErr().empty()) w << result.stdErr().join(QLatin1Char('\n')) << MessageTag(QStringLiteral("stdErr")); } bool CommandLineFrontend::resolvingMultipleProjects() const { return isResolving() && m_resolveJobs.size() + m_projects.size() > 1; } bool CommandLineFrontend::isResolving() const { return !m_resolveJobs.empty(); } bool CommandLineFrontend::isBuilding() const { return !m_buildJobs.empty(); } CommandLineFrontend::ProductMap CommandLineFrontend::productsToUse() const { ProductMap products; QStringList productNames; const bool useAll = m_parser.products().empty(); for (const Project &project : std::as_const(m_projects)) { QList &productList = products[project]; const ProjectData projectData = project.projectData(); for (const ProductData &product : projectData.allProducts()) { productNames << product.fullDisplayName(); if (useAll || m_parser.products().contains(product.fullDisplayName())) { productList.push_back(product); } } } const auto parsedProductNames = m_parser.products(); for (const QString &productName : parsedProductNames) { if (!productNames.contains(productName)) { QString msg; if (productNames.size() <= 10) { productNames.sort(); const QString available = productNames.join(QLatin1String("', '")); msg = Tr::tr("No such product '%1'. " "Available products: '%2'").arg(productName, available); } else { msg = Tr::tr("No such product '%1'. Use 'list-products' to see " "all available products.").arg(productName); } throw ErrorInfo(msg); } } return products; } void CommandLineFrontend::handleProjectsResolved() { if (m_cancelStatus != CancelStatusNone) throw ErrorInfo(Tr::tr("Execution canceled.")); switch (m_parser.command()) { case ResolveCommandType: qApp->quit(); break; case CleanCommandType: makeClean(); break; case ShellCommandType: qApp->exit(runShell()); break; case StatusCommandType: qApp->exit(printStatus(m_projects.front().projectData())); break; case GenerateCommandType: checkGeneratorName(); Q_FALLTHROUGH(); case BuildCommandType: build(); break; case InstallCommandType: case RunCommandType: if (m_parser.buildBeforeInstalling()) build(); else install(); break; case UpdateTimestampsCommandType: updateTimestamps(); qApp->quit(); break; case DumpNodesTreeCommandType: dumpNodesTree(); qApp->quit(); break; case ListProductsCommandType: listProducts(); qApp->quit(); break; case HelpCommandType: case VersionCommandType: case SessionCommandType: Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible."); } } void CommandLineFrontend::makeClean() { if (m_parser.products().empty()) { for (const Project &project : std::as_const(m_projects)) { m_buildJobs << project.cleanAllProducts(m_parser.cleanOptions(project.profile()), this); } } else { const ProductMap &products = productsToUse(); for (ProductMap::ConstIterator it = products.begin(); it != products.end(); ++it) { m_buildJobs.push_back(it.key().cleanSomeProducts( it.value(), m_parser.cleanOptions(it.key().profile()), this)); } } connectBuildJobs(); } int CommandLineFrontend::runShell() { ProductData productToRun; switch (m_parser.products().size()) { case 0: // No specific product, use project-global environment. break; case 1: productToRun = productsToUse().values().front().front(); break; default: throw ErrorInfo(Tr::tr("The command '%1' cannot take more than one product.")); } RunEnvironment runEnvironment = m_projects.front().getRunEnvironment(productToRun, m_parser.installOptions(m_projects.front().profile()), QProcessEnvironment::systemEnvironment(), QStringList(), m_settings); return runEnvironment.doRunShell(); } BuildOptions CommandLineFrontend::buildOptions(const Project &project) const { BuildOptions options = m_parser.buildOptions(m_projects.front().profile()); if (options.maxJobCount() <= 0) { const QString profileName = project.profile(); QBS_CHECK(!profileName.isEmpty()); options.setMaxJobCount(Preferences(m_settings, profileName).jobs()); } return options; } QString CommandLineFrontend::buildDirectory(const QString &profileName) const { QString buildDir = m_parser.projectBuildDirectory(); if (buildDir.isEmpty()) { buildDir = Preferences(m_settings, profileName).defaultBuildDirectory(); if (buildDir.isEmpty()) { qbsDebug() << "No project build directory given; using current directory."; buildDir = QDir::currentPath(); } else { qbsDebug() << "No project build directory given; using directory from preferences."; } } QString projectName(QFileInfo(m_parser.projectFilePath()).baseName()); QString originalBuildDir = buildDir; buildDir.replace(BuildDirectoryOption::magicProjectString(), projectName); const QString buildDirPlaceHolderMsgTemplate = Tr::tr( "You must provide the path to the project file when using build directory " "placeholder '%1'."); if (buildDir != originalBuildDir && projectName.isEmpty()) { throw ErrorInfo( buildDirPlaceHolderMsgTemplate.arg(BuildDirectoryOption::magicProjectString())); } QString projectDir(QFileInfo(m_parser.projectFilePath()).path()); originalBuildDir = buildDir; buildDir.replace(BuildDirectoryOption::magicProjectDirString(), projectDir); if (buildDir != originalBuildDir && projectDir.isEmpty()) { throw ErrorInfo( buildDirPlaceHolderMsgTemplate.arg(BuildDirectoryOption::magicProjectDirString())); } if (!QFileInfo(buildDir).isAbsolute()) buildDir = QDir::currentPath() + QLatin1Char('/') + buildDir; buildDir = QDir::cleanPath(buildDir); return buildDir; } void CommandLineFrontend::build() { if (m_parser.products().empty()) { const Project::ProductSelection productSelection = m_parser.withNonDefaultProducts() ? Project::ProductSelectionWithNonDefault : Project::ProductSelectionDefaultOnly; for (const Project &project : std::as_const(m_projects)) m_buildJobs << project.buildAllProducts(buildOptions(project), productSelection, this); } else { const ProductMap &products = productsToUse(); for (ProductMap::ConstIterator it = products.begin(); it != products.end(); ++it) m_buildJobs.push_back(it.key().buildSomeProducts(it.value(), buildOptions(it.key()), this)); } connectBuildJobs(); /* * Progress reporting for the build jobs works as follows: We know that for every job, * the newTaskStarted() signal is emitted exactly once (unless there's an error). So we add up * the respective total efforts as they come in. Once all jobs have reported their total * efforts, we can start the overall progress report. */ m_buildEffortsNeeded = m_buildJobs.size(); m_buildEffortsRetrieved = 0; m_totalBuildEffort = 0; m_currentBuildEffort = 0; } void CommandLineFrontend::checkGeneratorName() { const QString generatorName = m_parser.generateOptions().generatorName(); m_generator = ProjectGeneratorManager::findGenerator(generatorName); if (m_generator) return; const auto generatorNames = ProjectGeneratorManager::loadedGeneratorNames(); if (!generatorNames.empty()) { const QString generatorNamesString = generatorNames.join(QLatin1String("\n\t")); if (!generatorName.isEmpty()) { throw ErrorInfo(Tr::tr("No generator named '%1'. Available generators:\n\t%2") .arg(generatorName, generatorNamesString)); } throw ErrorInfo(Tr::tr("No generator specified. Available generators:\n\t%1") .arg(generatorNamesString)); } throw ErrorInfo(Tr::tr("No generator specified or no generators are available.")); } void CommandLineFrontend::generate() { QBS_CHECK(!!m_generator); const ErrorInfo error = m_generator->generate(m_projects, m_parser.buildConfigurations(), m_parser.installOptions(QString()), m_parser.settingsDir(), ConsoleLogger::instance(m_settings)); if (error.hasError()) throw error; } int CommandLineFrontend::runTarget() { const ProductData productToRun = getTheOneRunnableProduct(); const QString executableFilePath = productToRun.targetExecutable(); if (executableFilePath.isEmpty()) { throw ErrorInfo(Tr::tr("Cannot run: Product '%1' is not an application.") .arg(productToRun.fullDisplayName())); } RunEnvironment runEnvironment = m_projects.front().getRunEnvironment(productToRun, m_parser.installOptions(m_projects.front().profile()), QProcessEnvironment::systemEnvironment(), m_parser.runEnvConfig(), m_settings); return runEnvironment.doRunTarget(executableFilePath, m_parser.runArgs(), m_parser.dryRun()); } void CommandLineFrontend::updateTimestamps() { const ProductMap &products = productsToUse(); for (ProductMap::ConstIterator it = products.constBegin(); it != products.constEnd(); ++it) { Project p = it.key(); p.updateTimestamps(it.value()); } } void CommandLineFrontend::dumpNodesTree() { QFile stdOut; stdOut.open(stdout, QIODevice::WriteOnly); const ErrorInfo error = m_projects.front().dumpNodesTree(stdOut, productsToUse() .value(m_projects.front())); if (error.hasError()) throw error; } void CommandLineFrontend::listProducts() { const QList products = productsToUse().constBegin().value(); QStringList output; for (const ProductData &p : products) { QString productInfo = p.fullDisplayName(); if (!p.isEnabled()) productInfo.append(QLatin1Char(' ')).append(Tr::tr("[disabled]")); else if (!p.properties().value(QStringLiteral("builtByDefault")).toBool()) productInfo.append(QLatin1Char(' ')).append(Tr::tr("[not built by default]")); output += productInfo; } output.sort(); qbsInfo() << output.join(QLatin1Char('\n')); } void CommandLineFrontend::connectBuildJobs() { for (AbstractJob * const job : std::as_const(m_buildJobs)) connectBuildJob(job); } void CommandLineFrontend::connectBuildJob(AbstractJob *job) { connectJob(job); const auto bjob = qobject_cast(job); if (!bjob) return; connect(bjob, &BuildJob::reportCommandDescription, this, &CommandLineFrontend::handleCommandDescriptionReport); connect(bjob, &BuildJob::reportProcessResult, this, &CommandLineFrontend::handleProcessResultReport); } void CommandLineFrontend::connectJob(AbstractJob *job) { connect(job, &AbstractJob::finished, this, &CommandLineFrontend::handleJobFinished); connect(job, &AbstractJob::taskStarted, this, &CommandLineFrontend::handleNewTaskStarted); connect(job, &AbstractJob::totalEffortChanged, this, &CommandLineFrontend::handleTotalEffortChanged); if (m_parser.showProgress()) { connect(job, &AbstractJob::taskProgress, this, &CommandLineFrontend::handleTaskProgress); } } ProductData CommandLineFrontend::getTheOneRunnableProduct() { QBS_CHECK(m_projects.size() == 1); // Has been checked earlier. if (m_parser.products().size() == 1) { for (const ProductData &p : m_projects.front().projectData().allProducts()) { if (p.fullDisplayName() == m_parser.products().constFirst()) return p; } QBS_CHECK(false); } QBS_CHECK(m_parser.products().isEmpty()); QList runnableProducts; for (const ProductData &p : m_projects.front().projectData().allProducts()) { if (p.isRunnable()) runnableProducts.push_back(p); } if (runnableProducts.size() == 1) return runnableProducts.front(); if (runnableProducts.empty()) { throw ErrorInfo(Tr::tr("Cannot execute command '%1': Project has no runnable product.") .arg(m_parser.commandName())); } ErrorInfo error(Tr::tr("Ambiguous use of command '%1': No product given, but project " "has more than one runnable product.").arg(m_parser.commandName())); error.append(Tr::tr("Use the '--products' option with one of the following products:")); for (const ProductData &p : std::as_const(runnableProducts)) error.append(QLatin1String("\t") + p.fullDisplayName()); throw error; } void CommandLineFrontend::install() { Q_ASSERT(m_projects.size() == 1); const Project project = m_projects.front(); InstallJob *installJob; if (m_parser.products().empty()) { const Project::ProductSelection productSelection = m_parser.withNonDefaultProducts() ? Project::ProductSelectionWithNonDefault : Project::ProductSelectionDefaultOnly; installJob = project.installAllProducts(m_parser.installOptions(project.profile()), productSelection); } else { const Project project = m_projects.front(); const ProductMap products = productsToUse(); installJob = project.installSomeProducts(products.value(project), m_parser.installOptions(project.profile())); } connectJob(installJob); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/status.cpp0000644000175100001660000001552114776170045016637 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "status.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include namespace qbs { static QList createIgnoreList(const QString &projectRootPath) { QList ignoreRegularExpressionList { QRegularExpression(QRegularExpression::anchoredPattern(projectRootPath + QLatin1String("/build.*"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.qbs"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.pro"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*Makefile"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.so*"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.o"))) }; QString ignoreFilePath = projectRootPath + QLatin1String("/.qbsignore"); QFile ignoreFile(ignoreFilePath); if (ignoreFile.open(QFile::ReadOnly)) { const QList ignoreTokenList = ignoreFile.readAll().split('\n'); for (const QByteArray &btoken : ignoreTokenList) { const QString token = QString::fromLatin1(btoken); if (token.startsWith(QLatin1String("/"))) ignoreRegularExpressionList.push_back( QRegularExpression(QRegularExpression::anchoredPattern( projectRootPath + token + QLatin1String(".*")))); else if (!token.isEmpty()) ignoreRegularExpressionList.push_back( QRegularExpression(QRegularExpression::anchoredPattern(token))); } } return ignoreRegularExpressionList; } static QStringList allFilesInDirectoryRecursive( const QDir &rootDirecory, const QList &ignoreRegularExpressionList) { QStringList fileList; const auto fileInfos = rootDirecory.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::Name); for (const QFileInfo &fileInfo : fileInfos) { QString absoluteFilePath = fileInfo.absoluteFilePath(); bool inIgnoreList = false; for (const QRegularExpression &ignoreRegularExpression : ignoreRegularExpressionList) { if (ignoreRegularExpression.match(absoluteFilePath).hasMatch()) { inIgnoreList = true; break; } } if (!inIgnoreList) { if (fileInfo.isFile()) fileList.push_back(absoluteFilePath); else if (fileInfo.isDir()) fileList << allFilesInDirectoryRecursive(QDir(absoluteFilePath), ignoreRegularExpressionList); } } return fileList; } static QStringList allFilesInProject(const QString &projectRootPath) { QList ignoreRegularExpressionList = createIgnoreList(projectRootPath); return allFilesInDirectoryRecursive(QDir(projectRootPath), ignoreRegularExpressionList); } QStringList allFiles(const ProductData &product) { QStringList files; for (const GroupData &group : product.groups()) files += group.allFilePaths(); return files; } int printStatus(const ProjectData &project) { const QString projectFilePath = project.location().filePath(); QString projectDirectory = QFileInfo(projectFilePath).dir().path(); int projectDirectoryPathLength = projectDirectory.length(); QStringList untrackedFilesInProject = allFilesInProject(projectDirectory); QStringList missingFiles; for (const ProductData &product : project.allProducts()) { qbsInfo() << "\nProduct: " << product.name() << " (" << product.location().filePath() << ":" << product.location().line() << ")"; for (const GroupData &group : product.groups()) { qbsInfo() << " Group: " << group.name() << " (" << group.location().filePath() << ":" << group.location().line() << ")"; const QStringList sourceFiles = Internal::sorted(group.allFilePaths()); for (const QString &sourceFile : sourceFiles) { if (!QFileInfo::exists(sourceFile)) missingFiles.push_back(sourceFile); qbsInfo() << " " << sourceFile.mid(projectDirectoryPathLength + 1); untrackedFilesInProject.removeOne(sourceFile); } } } qbsInfo() << "\nMissing files:"; for (const QString &untrackedFile : std::as_const(missingFiles)) qbsInfo() << " " << untrackedFile.mid(projectDirectoryPathLength + 1); qbsInfo() << "\nUntracked files:"; for (const QString &missingFile : std::as_const(untrackedFilesInProject)) qbsInfo() << " " << missingFile.mid(projectDirectoryPathLength + 1); return 0; } } // namespace qbs qbs-src-2.6.1/src/app/qbs/status.h0000644000175100001660000000377514776170045016314 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef STATUS_H #define STATUS_H namespace qbs { class ProjectData; int printStatus(const ProjectData &project); } // namespace qbs #endif // STATUS_H qbs-src-2.6.1/src/app/qbs/session.cpp0000644000175100001660000010064614776170045017002 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "session.h" #include "lspserver.h" #include "sessionpacket.h" #include "sessionpacketreader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN32 #include #include #include #include #include #endif namespace qbs { namespace Internal { using FilePair = std::pair; class SessionLogSink : public QObject, public ILogSink { Q_OBJECT signals: void newMessage(const QJsonObject &msg); private: static const QString &warningString() { static const QString warning(QLatin1String("warning")); return warning; } void doPrintMessage(LoggerLevel, const QString &message, const QString &) override { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("log-data")); msg.insert(StringConstants::messageKey(), message); emit newMessage(msg); } void doPrintWarning(const ErrorInfo &warning) override { QJsonObject msg; msg.insert(StringConstants::type(), warningString()); msg.insert(warningString(), warning.toJson()); emit newMessage(msg); } void doPrintError(const ErrorInfo &error) override { QJsonObject msg; msg.insert(StringConstants::type(), warningString()); static const QString errorString(QLatin1String("error")); msg.insert(errorString, error.toJson()); msg.insert(warningString(), error.toJson()); // Backward compatibility emit newMessage(msg); } }; class Session : public QObject { Q_OBJECT public: Session(); private: enum class ProjectDataMode { Never, Always, OnlyIfChanged }; ProjectDataMode dataModeFromRequest(const QJsonObject &request); QStringList modulePropertiesFromRequest(const QJsonObject &request); void insertProjectDataIfNecessary( QJsonObject &reply, ProjectDataMode dataMode, const ProjectData &oldProjectData, bool includeTopLevelData ); void setLogLevelFromRequest(const QJsonObject &request); bool checkNormalRequestPrerequisites(const char *replyType); void sendPacket(const QJsonObject &message); void setupProject(const QJsonObject &request); void buildProject(const QJsonObject &request); void cleanProject(const QJsonObject &request); void installProject(const QJsonObject &request); void addFiles(const QJsonObject &request); void removeFiles(const QJsonObject &request); void renameFiles(const QJsonObject &request); void getRunEnvironment(const QJsonObject &request); void getGeneratedFilesForSources(const QJsonObject &request); void releaseProject(); void cancelCurrentJob(); void quitSession(); void sendErrorReply(const char *replyType, const QString &message); void sendErrorReply(const char *replyType, const ErrorInfo &error); void insertErrorInfoIfNecessary(QJsonObject &reply, const ErrorInfo &error); void connectProgressSignals(AbstractJob *job); QList getProductsByName(const QStringList &productNames) const; ProductData getProductByName(const QString &productName) const; struct ProductSelection { ProductSelection(Project::ProductSelection s) : selection(s) {} ProductSelection(QList p) : products(std::move(p)) {} Project::ProductSelection selection = Project::ProductSelectionDefaultOnly; QList products; }; ProductSelection getProductSelection(const QJsonObject &request); template struct FileUpdateData { QJsonObject createErrorReply(const char *type, const QString &mainMessage) const; ProductData product; GroupData group; QList filePaths; ErrorInfo error; }; template FileUpdateData prepareFileUpdate(const QJsonObject &request); SessionPacketReader m_packetReader; LspServer m_lspServer; SessionLogSink m_logSink; Project m_project; ProjectData m_projectData; std::unique_ptr m_settings; QJsonObject m_resolveRequest; QStringList m_moduleProperties; AbstractJob *m_currentJob = nullptr; }; void startSession() { const auto session = new Session; QObject::connect(qApp, &QCoreApplication::aboutToQuit, session, [session] { delete session; }); } Session::Session() { #ifdef Q_OS_WIN32 // Make sure the line feed character appears as itself. if (_setmode(_fileno(stdout), _O_BINARY) == -1) { constexpr size_t errmsglen = FILENAME_MAX; char errmsg[errmsglen]; strerror_s(errmsg, errmsglen, errno); std::cerr << "Failed to set stdout to binary mode: " << errmsg << std::endl; qApp->exit(EXIT_FAILURE); } #endif sendPacket(SessionPacket::helloMessage(m_lspServer.socketPath())); connect(&m_logSink, &SessionLogSink::newMessage, this, &Session::sendPacket); connect(&m_packetReader, &SessionPacketReader::errorOccurred, this, [](const QString &msg) { std::cerr << qPrintable(tr("Error: %1").arg(msg)); qApp->exit(EXIT_FAILURE); }); connect(&m_packetReader, &SessionPacketReader::packetReceived, this, [this](const QJsonObject &packet) { // qDebug() << "got packet:" << packet; // Uncomment for debugging. const QString type = packet.value(StringConstants::type()).toString(); if (type == QLatin1String("resolve-project")) setupProject(packet); else if (type == QLatin1String("build-project")) buildProject(packet); else if (type == QLatin1String("clean-project")) cleanProject(packet); else if (type == QLatin1String("install-project")) installProject(packet); else if (type == QLatin1String("add-files")) addFiles(packet); else if (type == QLatin1String("remove-files")) removeFiles(packet); else if (type == QLatin1String("rename-files")) renameFiles(packet); else if (type == QLatin1String("get-run-environment")) getRunEnvironment(packet); else if (type == QLatin1String("get-generated-files-for-sources")) getGeneratedFilesForSources(packet); else if (type == QLatin1String("release-project")) releaseProject(); else if (type == QLatin1String("quit")) quitSession(); else if (type == QLatin1String("cancel-job")) cancelCurrentJob(); else sendErrorReply("protocol-error", tr("Unknown request type '%1'.").arg(type)); }); m_packetReader.start(); } Session::ProjectDataMode Session::dataModeFromRequest(const QJsonObject &request) { const QString modeString = request.value(QLatin1String("data-mode")).toString(); if (modeString == QLatin1String("only-if-changed")) return ProjectDataMode::OnlyIfChanged; if (modeString == QLatin1String("always")) return ProjectDataMode::Always; return ProjectDataMode::Never; } void Session::sendPacket(const QJsonObject &message) { std::cout << SessionPacket::createPacket(message).constData() << std::flush; } void Session::setupProject(const QJsonObject &request) { if (m_currentJob) { if (qobject_cast(m_currentJob) && m_currentJob->state() == AbstractJob::StateCanceling) { m_resolveRequest = request; return; } sendErrorReply("project-resolved", tr("Cannot start resolving while another job is still running.")); return; } m_moduleProperties = modulePropertiesFromRequest(request); auto params = SetupProjectParameters::fromJson(request); const ProjectDataMode dataMode = dataModeFromRequest(request); m_settings = std::make_unique(params.settingsDirectory()); const Preferences prefs(m_settings.get()); const QString appDir = QDir::cleanPath(QCoreApplication::applicationDirPath()); params.setSearchPaths(prefs.searchPaths(appDir + QLatin1String( "/" QBS_RELATIVE_SEARCH_PATH))); params.setPluginPaths(prefs.pluginPaths(appDir + QLatin1String( "/" QBS_RELATIVE_PLUGINS_PATH))); params.setLibexecPath(appDir + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH)); params.setOverrideBuildGraphData(true); setLogLevelFromRequest(request); SetupProjectJob * const setupJob = m_project.setupProject(params, &m_logSink, this); m_currentJob = setupJob; connectProgressSignals(setupJob); connect(setupJob, &AbstractJob::finished, this, [this, setupJob, dataMode](bool success) { if (!m_resolveRequest.isEmpty()) { // Canceled job was superseded. const QJsonObject newRequest = std::move(m_resolveRequest); m_resolveRequest = QJsonObject(); m_currentJob->deleteLater(); m_currentJob = nullptr; setupProject(newRequest); return; } const ProjectData oldProjectData = m_projectData; m_project = setupJob->project(); m_projectData = m_project.projectData(); m_lspServer.updateProjectData(m_projectData, m_project.codeLinks()); QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("project-resolved")); if (success) insertProjectDataIfNecessary(reply, dataMode, oldProjectData, true); else insertErrorInfoIfNecessary(reply, setupJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::buildProject(const QJsonObject &request) { if (!checkNormalRequestPrerequisites("project-built")) return; const ProductSelection productSelection = getProductSelection(request); setLogLevelFromRequest(request); auto options = BuildOptions::fromJson(request); options.setSettingsDirectory(m_settings->baseDirectory()); BuildJob * const buildJob = productSelection.products.empty() ? m_project.buildAllProducts(options, productSelection.selection, this) : m_project.buildSomeProducts(productSelection.products, options, this); m_currentJob = buildJob; m_moduleProperties = modulePropertiesFromRequest(request); const ProjectDataMode dataMode = dataModeFromRequest(request); connectProgressSignals(buildJob); connect(buildJob, &BuildJob::reportCommandDescription, this, [this](const QString &highlight, const QString &message) { QJsonObject descData; descData.insert(StringConstants::type(), QLatin1String("command-description")); descData.insert(QLatin1String("highlight"), highlight); descData.insert(StringConstants::messageKey(), message); sendPacket(descData); }); connect(buildJob, &BuildJob::reportProcessResult, this, [this](const ProcessResult &result) { if (result.success() && result.stdOut().isEmpty() && result.stdErr().isEmpty()) return; QJsonObject resultData = result.toJson(); resultData.insert(StringConstants::type(), QLatin1String("process-result")); sendPacket(resultData); }); connect(buildJob, &BuildJob::finished, this, [this, dataMode](bool success) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("project-built")); const ProjectData oldProjectData = m_projectData; m_projectData = m_project.projectData(); if (success) insertProjectDataIfNecessary(reply, dataMode, oldProjectData, false); else insertErrorInfoIfNecessary(reply, m_currentJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::cleanProject(const QJsonObject &request) { if (!checkNormalRequestPrerequisites("project-cleaned")) return; setLogLevelFromRequest(request); const ProductSelection productSelection = getProductSelection(request); const auto options = CleanOptions::fromJson(request); m_currentJob = productSelection.products.empty() ? m_project.cleanAllProducts(options, this) : m_project.cleanSomeProducts(productSelection.products, options, this); connectProgressSignals(m_currentJob); connect(m_currentJob, &AbstractJob::finished, this, [this](bool success) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("project-cleaned")); if (!success) insertErrorInfoIfNecessary(reply, m_currentJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::installProject(const QJsonObject &request) { if (!checkNormalRequestPrerequisites("install-done")) return; setLogLevelFromRequest(request); const ProductSelection productSelection = getProductSelection(request); const auto options = InstallOptions::fromJson(request); m_currentJob = productSelection.products.empty() ? m_project.installAllProducts(options, productSelection.selection, this) : m_project.installSomeProducts(productSelection.products, options, this); connectProgressSignals(m_currentJob); connect(m_currentJob, &AbstractJob::finished, this, [this](bool success) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("install-done")); if (!success) insertErrorInfoIfNecessary(reply, m_currentJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::addFiles(const QJsonObject &request) { const FileUpdateData data = prepareFileUpdate(request); if (data.error.hasError()) { sendPacket(data.createErrorReply("files-added", tr("Failed to add files to project: %1") .arg(data.error.toString()))); return; } ErrorInfo error; QStringList failedFiles; for (const QString &filePath : data.filePaths) { const ErrorInfo e = m_project.addFiles(data.product, data.group, {filePath}); if (e.hasError()) { for (const ErrorItem &ei : e.items()) error.append(ei); failedFiles.push_back(filePath); } } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("files-added")); insertErrorInfoIfNecessary(reply, error); if (failedFiles.size() != data.filePaths.size()) { // Note that Project::addFiles() directly changes the existing project data object, so // there's no need to retrieve it from m_project. insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false); } if (!failedFiles.isEmpty()) reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); sendPacket(reply); } void Session::removeFiles(const QJsonObject &request) { const FileUpdateData data = prepareFileUpdate(request); if (data.error.hasError()) { sendPacket(data.createErrorReply("files-removed", tr("Failed to remove files from project: %1") .arg(data.error.toString()))); return; } ErrorInfo error; QStringList failedFiles; for (const QString &filePath : data.filePaths) { const ErrorInfo e = m_project.removeFiles(data.product, data.group, {filePath}); if (e.hasError()) { for (const ErrorItem &ei : e.items()) error.append(ei); failedFiles.push_back(filePath); } } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("files-removed")); insertErrorInfoIfNecessary(reply, error); if (failedFiles.size() != data.filePaths.size()) insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false); if (!failedFiles.isEmpty()) reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); sendPacket(reply); } void Session::renameFiles(const QJsonObject &request) { const FileUpdateData data = prepareFileUpdate(request); if (data.error.hasError()) { sendPacket(data.createErrorReply( "files-renamed", tr("Failed to rename files in project: %1").arg(data.error.toString()))); return; } ErrorInfo error; QStringList failedFiles; for (const FilePair &sourceAndTarget : data.filePaths) { const ErrorInfo removeError = m_project.removeFiles( data.product, data.group, {sourceAndTarget.first}); if (removeError.hasError()) { for (const ErrorItem &ei : removeError.items()) error.append(ei); failedFiles.push_back(sourceAndTarget.first); } else { const ErrorInfo addError = m_project.addFiles( data.product, data.group, {sourceAndTarget.second}); if (addError.hasError()) { for (const ErrorItem &ei : addError.items()) error.append(ei); failedFiles.push_back(sourceAndTarget.first); } } } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("files-renamed")); insertErrorInfoIfNecessary(reply, error); if (failedFiles.size() != data.filePaths.size()) insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false); if (!failedFiles.isEmpty()) reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); sendPacket(reply); } void Session::connectProgressSignals(AbstractJob *job) { static QString maxProgressString(QLatin1String("max-progress")); connect(job, &AbstractJob::taskStarted, this, [this](const QString &description, int maxProgress) { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("task-started")); msg.insert(StringConstants::descriptionProperty(), description); msg.insert(maxProgressString, maxProgress); sendPacket(msg); }); connect(job, &AbstractJob::totalEffortChanged, this, [this](int maxProgress) { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("new-max-progress")); msg.insert(maxProgressString, maxProgress); sendPacket(msg); }); connect(job, &AbstractJob::taskProgress, this, [this](int progress) { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("task-progress")); msg.insert(QLatin1String("progress"), progress); sendPacket(msg); }); } static QList getProductsByNameForProject(const ProjectData &project, QStringList &productNames) { QList products; if (productNames.empty()) return products; for (const ProductData &p : project.products()) { for (auto it = productNames.begin(); it != productNames.end(); ++it) { if (*it == p.fullDisplayName()) { products << p; productNames.erase(it); if (productNames.empty()) return products; break; } } } for (const ProjectData &p : project.subProjects()) { products << getProductsByNameForProject(p, productNames); if (productNames.empty()) break; } return products; } QList Session::getProductsByName(const QStringList &productNames) const { QStringList remainingNames = productNames; return getProductsByNameForProject(m_projectData, remainingNames); } ProductData Session::getProductByName(const QString &productName) const { const QList products = getProductsByName({productName}); return products.empty() ? ProductData() : products.first(); } void Session::getRunEnvironment(const QJsonObject &request) { const char * const replyType = "run-environment"; if (!checkNormalRequestPrerequisites(replyType)) return; const QString productName = request.value(QLatin1String("product")).toString(); const ProductData product = getProductByName(productName); if (!product.isValid()) { sendErrorReply(replyType, tr("No such product '%1'.").arg(productName)); return; } const auto inEnv = fromJson( request.value(QLatin1String("base-environment"))); const QStringList config = fromJson(request.value(QLatin1String("config"))); const RunEnvironment runEnv = m_project.getRunEnvironment(product, InstallOptions(), inEnv, config, m_settings.get()); ErrorInfo error; const QProcessEnvironment outEnv = runEnv.runEnvironment(&error); if (error.hasError()) { sendErrorReply(replyType, error); return; } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); QJsonObject outEnvObj; const QStringList keys = outEnv.keys(); for (const QString &key : keys) outEnvObj.insert(key, outEnv.value(key)); reply.insert(QLatin1String("full-environment"), outEnvObj); sendPacket(reply); } void Session::getGeneratedFilesForSources(const QJsonObject &request) { const char * const replyType = "generated-files-for-sources"; if (!checkNormalRequestPrerequisites(replyType)) return; QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); const QJsonArray specs = request.value(StringConstants::productsKey()).toArray(); QJsonArray resultProducts; for (const auto &p : specs) { const QJsonObject productObject = p.toObject(); const ProductData product = getProductByName( productObject.value(StringConstants::fullDisplayNameKey()).toString()); if (!product.isValid()) continue; QJsonObject resultProduct; resultProduct.insert(StringConstants::fullDisplayNameKey(), product.fullDisplayName()); QJsonArray results; const QJsonArray requests = productObject.value(QLatin1String("requests")).toArray(); for (const auto &r : requests) { const QJsonObject request = r.toObject(); const QString filePath = request.value(QLatin1String("source-file")).toString(); const QStringList tags = fromJson(request.value(QLatin1String("tags"))); const bool recursive = request.value(QLatin1String("recursive")).toBool(); const QStringList generatedFiles = m_project.generatedFiles(product, filePath, recursive, tags); if (!generatedFiles.isEmpty()) { QJsonObject result; result.insert(QLatin1String("source-file"), filePath); result.insert(QLatin1String("generated-files"), QJsonArray::fromStringList(generatedFiles)); results << result; } } if (!results.isEmpty()) { resultProduct.insert(QLatin1String("results"), results); resultProducts << resultProduct; } } reply.insert(StringConstants::productsKey(), resultProducts); sendPacket(reply); } void Session::releaseProject() { const char * const replyType = "project-released"; if (!m_project.isValid()) { sendErrorReply(replyType, tr("No open project.")); return; } if (m_currentJob) { m_currentJob->disconnect(this); m_currentJob->cancel(); m_currentJob = nullptr; } m_project = Project(); m_projectData = ProjectData(); m_resolveRequest = QJsonObject(); QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); sendPacket(reply); } void Session::cancelCurrentJob() { if (m_currentJob) { if (!m_resolveRequest.isEmpty()) m_resolveRequest = QJsonObject(); m_currentJob->cancel(); } } Session::ProductSelection Session::getProductSelection(const QJsonObject &request) { const QJsonValue productSelection = request.value(StringConstants::productsKey()); if (productSelection.isArray()) return {getProductsByName(fromJson(productSelection))}; return { productSelection.toString() == QLatin1String("all") ? Project::ProductSelectionWithNonDefault : Project::ProductSelectionDefaultOnly}; } template Session::FileUpdateData Session::prepareFileUpdate(const QJsonObject &request) { FileUpdateData data; const QString productName = request.value(QLatin1String("product")).toString(); data.product = getProductByName(productName); if (data.product.isValid()) { const QString groupName = request.value(QLatin1String("group")).toString(); for (const GroupData &g : data.product.groups()) { if (g.name() == groupName) { data.group = g; break; } } if (!data.group.isValid()) data.error = tr("Group '%1' not found in product '%2'.").arg(groupName, productName); } else { data.error = tr("Product '%1' not found in project.").arg(productName); } const QJsonArray filesArray = request.value(QLatin1String("files")).toArray(); for (const auto &v : filesArray) if constexpr (std::is_same_v) { data.filePaths << v.toString(); } else if constexpr (std::is_same_v) { const QJsonObject file = v.toObject(); data.filePaths << std::make_pair( file.value(QLatin1String("source-path")).toString(), file.value(QLatin1String("target-path")).toString()); } if (m_currentJob) data.error = tr("Cannot update the list of source files while a job is running."); if (!m_project.isValid()) data.error = tr("No valid project. You need to resolve first."); return data; } void Session::insertProjectDataIfNecessary(QJsonObject &reply, ProjectDataMode dataMode, const ProjectData &oldProjectData, bool includeTopLevelData) { const bool sendProjectData = dataMode == ProjectDataMode::Always || (dataMode == ProjectDataMode::OnlyIfChanged && m_projectData != oldProjectData); if (!sendProjectData) return; QJsonObject projectData = m_projectData.toJson(m_moduleProperties); if (includeTopLevelData) { QJsonArray buildSystemFiles; for (const QString &f : m_project.buildSystemFiles()) buildSystemFiles.push_back(f); projectData.insert(StringConstants::buildDirectoryKey(), m_projectData.buildDirectory()); projectData.insert(QLatin1String("build-system-files"), buildSystemFiles); const Project::BuildGraphInfo bgInfo = m_project.getBuildGraphInfo(); projectData.insert(QLatin1String("build-graph-file-path"), bgInfo.bgFilePath); projectData.insert(QLatin1String("profile-data"), QJsonObject::fromVariantMap(bgInfo.profileData)); projectData.insert(QLatin1String("overridden-properties"), QJsonObject::fromVariantMap(bgInfo.overriddenProperties)); } reply.insert(QLatin1String("project-data"), projectData); } void Session::setLogLevelFromRequest(const QJsonObject &request) { const QString logLevelString = request.value(QLatin1String("log-level")).toString(); if (logLevelString.isEmpty()) return; for (const LoggerLevel l : {LoggerError, LoggerWarning, LoggerInfo, LoggerDebug, LoggerTrace}) { if (logLevelString == logLevelName(l)) { m_logSink.setLogLevel(l); return; } } } bool Session::checkNormalRequestPrerequisites(const char *replyType) { if (m_currentJob) { sendErrorReply(replyType, tr("Another job is still running.")); return false; } if (!m_project.isValid()) { sendErrorReply(replyType, tr("No valid project. You need to resolve first.")); return false; } return true; } QStringList Session::modulePropertiesFromRequest(const QJsonObject &request) { return fromJson(request.value(StringConstants::modulePropertiesKey())); } void Session::sendErrorReply(const char *replyType, const ErrorInfo &error) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); insertErrorInfoIfNecessary(reply, error); sendPacket(reply); } void Session::sendErrorReply(const char *replyType, const QString &message) { sendErrorReply(replyType, ErrorInfo(message)); } void Session::insertErrorInfoIfNecessary(QJsonObject &reply, const ErrorInfo &error) { if (error.hasError()) reply.insert(QLatin1String("error"), error.toJson()); } void Session::quitSession() { m_logSink.disconnect(this); m_packetReader.disconnect(this); if (m_currentJob) { m_currentJob->disconnect(this); connect(m_currentJob, &AbstractJob::finished, qApp, QCoreApplication::quit); m_currentJob->cancel(); } else { qApp->quit(); } } template QJsonObject Session::FileUpdateData::createErrorReply( const char *type, const QString &mainMessage) const { QBS_ASSERT(error.hasError(), return QJsonObject()); ErrorInfo error(mainMessage); for (const ErrorItem &ei : error.items()) error.append(ei); QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(type)); reply.insert(QLatin1String("error"), error.toJson()); QStringList failedFiles; if constexpr (std::is_same_v) { failedFiles = filePaths; } else if constexpr (std::is_same_v) { failedFiles = transformed(filePaths, [](const FilePair &fp) { return fp.first; }); } reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); return reply; } } // namespace Internal } // namespace qbs #include qbs-src-2.6.1/src/app/qbs/qbstool.cpp0000644000175100001660000000772314776170045017004 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qbstool.h" #include #include #include #include #include #include static QString toolPrefix() { return QStringLiteral("qbs-"); } static QString qbsBinDir() { return QCoreApplication::applicationDirPath(); } static QString qbsToolFilePath(const QString &toolName) { return qbsBinDir() + QLatin1Char('/') + toolPrefix() + qbs::Internal::HostOsInfo::appendExecutableSuffix(toolName); } void QbsTool::runTool(const QString &toolName, const QStringList &arguments) { m_failedToStart = false; m_exitCode = -1; const QString filePath = qbsToolFilePath(toolName); const QFileInfo fi(filePath); if (!fi.exists() || !fi.isFile() || !fi.isExecutable()) { m_failedToStart = true; return; } QProcess toolProc; toolProc.start(filePath, arguments); if (!toolProc.waitForStarted()) m_failedToStart = true; toolProc.waitForFinished(-1); m_exitCode = toolProc.exitCode(); m_stdout = QString::fromLocal8Bit(toolProc.readAllStandardOutput()); m_stderr = QString::fromLocal8Bit(toolProc.readAllStandardError()); } bool QbsTool::tryToRunTool(const QString &toolName, const QStringList &arguments, int *exitCode) { QbsTool tool; tool.runTool(toolName, arguments); if (exitCode) *exitCode = tool.exitCode(); if (tool.failedToStart()) return false; std::cout << qPrintable(tool.stdOut()); std::cerr << qPrintable(tool.stdErr()); return true; } QStringList QbsTool::allToolNames() { const QString suffix = QLatin1String(QBS_HOST_EXE_SUFFIX); const QStringList toolFileNames = QDir(qbsBinDir()).entryList(QStringList(toolPrefix() + QStringLiteral("*%1").arg(suffix)), QDir::Files, QDir::Name); QStringList toolNames; const int prefixLength = toolPrefix().size(); for (const QString &toolFileName : toolFileNames) { toolNames << toolFileName.mid(prefixLength, toolFileName.size() - prefixLength - suffix.size()); } return toolNames; } qbs-src-2.6.1/src/app/qbs/application.h0000644000175100001660000000450414776170045017263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef APPLICATION_H #define APPLICATION_H #include namespace qbs { class CommandLineFrontend; class Application : public QCoreApplication { Q_OBJECT public: Application(int &argc, char **argv); static Application *instance(); void setCommandLineFrontend(CommandLineFrontend *clFrontend); void userInterrupt(); private: CommandLineFrontend *m_clFrontend; bool m_canceled; }; } // namespace qbs #endif // APPLICATION_H qbs-src-2.6.1/src/app/qbs/sessionpacket.cpp0000644000175100001660000001041114776170045020160 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "sessionpacket.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { const QByteArray packetStart = "qbsmsg:"; SessionPacket::Status SessionPacket::parseInput(QByteArray &input) { //qDebug() << m_expectedPayloadLength << m_payload << input; if (m_expectedPayloadLength == -1) { const int packetStartOffset = input.indexOf(packetStart); if (packetStartOffset == -1) return Status::Incomplete; const int numberOffset = packetStartOffset + packetStart.length(); const int newLineOffset = input.indexOf('\n', numberOffset); if (newLineOffset == -1) return Status::Incomplete; const QByteArray sizeString = input.mid(numberOffset, newLineOffset - numberOffset); bool isNumber; const int payloadLen = sizeString.toInt(&isNumber); if (!isNumber || payloadLen < 0) return Status::Invalid; m_expectedPayloadLength = payloadLen; input.remove(0, newLineOffset + 1); } const int bytesToAdd = m_expectedPayloadLength - m_payload.length(); QBS_ASSERT(bytesToAdd >= 0, return Status::Invalid); m_payload += input.left(bytesToAdd); input.remove(0, bytesToAdd); return isComplete() ? Status::Complete : Status::Incomplete; } QJsonObject SessionPacket::retrievePacket() { QBS_ASSERT(isComplete(), return QJsonObject()); auto packet = QJsonDocument::fromJson(QByteArray::fromBase64(m_payload)).object(); m_payload.clear(); m_expectedPayloadLength = -1; return packet; } QByteArray SessionPacket::createPacket(const QJsonObject &packet) { const QByteArray jsonData = QJsonDocument(packet).toJson(QJsonDocument::Compact).toBase64(); return QByteArray(packetStart).append(QByteArray::number(jsonData.length())).append('\n') .append(jsonData); } QJsonObject SessionPacket::helloMessage(const QString &lspSocket) { return QJsonObject{ {StringConstants::type(), QLatin1String("hello")}, {QLatin1String("api-level"), 8}, {QLatin1String("api-compat-level"), 2}, {QLatin1String("lsp-socket"), lspSocket}}; } bool SessionPacket::isComplete() const { return m_payload.length() == m_expectedPayloadLength; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/app/qbs/session.h0000644000175100001660000000401614776170045016441 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SESSION_H #define QBS_SESSION_H namespace qbs { namespace Internal { void startSession(); } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/app/qbs/application.cpp0000644000175100001660000000535014776170045017616 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "application.h" #include "commandlinefrontend.h" #include "ctrlchandler.h" namespace qbs { Application::Application(int &argc, char **argv) : QCoreApplication(argc, argv), m_clFrontend(nullptr), m_canceled(false) { setApplicationName(QStringLiteral("qbs")); setOrganizationName(QStringLiteral("QtProject")); setOrganizationDomain(QStringLiteral("qt-project.org")); } Application *Application::instance() { return qobject_cast(QCoreApplication::instance()); } void Application::setCommandLineFrontend(CommandLineFrontend *clFrontend) { installCtrlCHandler(); m_clFrontend = clFrontend; } /** * Interrupt the application. This is directly called from a signal handler. */ void Application::userInterrupt() { if (m_canceled) return; Q_ASSERT(m_clFrontend); m_canceled = true; m_clFrontend->cancel(); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/stdinreader.h0000644000175100001660000000451114776170045017262 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_STDINREADER_H #define QBS_STDINREADER_H #include namespace qbs { namespace Internal { class StdinReader : public QObject { Q_OBJECT public: static StdinReader *create(QObject *parent); virtual void start() = 0; signals: void errorOccurred(const QString &error); void dataAvailable(const QByteArray &data); protected: explicit StdinReader(QObject *parent); }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/app/qbs/lspserver.cpp0000644000175100001660000005556114776170045017351 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lspserver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WINDOWS #include #else #include #endif namespace qbs::Internal { static int getPid() { #ifdef Q_OS_WINDOWS return _getpid(); #else return getpid(); #endif } using LspErrorResponse = lsp::ResponseError; using LspErrorCode = LspErrorResponse::ErrorCodes; class Document { public: bool isPositionUpToDate(const CodePosition &pos) const; bool isPositionUpToDate(const lsp::Position &pos) const; QString savedContent; QString currentContent; }; static CodePosition posFromLspPos(const lsp::Position &pos) { return {pos.line() + 1, pos.character() + 1}; } static lsp::Position lspPosFromCodeLocation(const CodeLocation &loc) { return {loc.line() - 1, loc.column() - 1}; } static QString uriToString(const lsp::DocumentUri &uri) { return uri.toFilePath([](const lsp::Utils::FilePath &fp) { return fp; }); } static int posToOffset(const CodePosition &pos, const QString &doc); static int posToOffset(const lsp::Position &pos, const QString &doc) { return posToOffset(posFromLspPos(pos), doc); } class AstNodeLocator : public QbsQmlJS::AST::Visitor { public: AstNodeLocator(int position, QbsQmlJS::AST::UiProgram &ast) : m_position(position) { ast.accept(this); } QList path() const { return m_path; } private: bool preVisit(QbsQmlJS::AST::Node *node) override { if (int(node->firstSourceLocation().offset) > m_position) return false; if (int(node->lastSourceLocation().offset) < m_position) return false; m_path << node; return true; } const int m_position; QList m_path; }; class LspServer::Private { public: void setupConnection(); void handleIncomingData(); void discardSocket(); template void sendResponse(const T &msg); void sendErrorResponse(LspErrorCode code, const QString &message); void sendErrorNotification(const QString &message); void sendNoSuchDocumentError(const QString &filePath); void sendMessage(const lsp::JsonObject &msg); void sendMessage(const lsp::JsonRpcMessage &msg); void handleCurrentMessage(); void handleInitializeRequest(); void handleInitializedNotification(); void handleGotoDefinitionRequest(); void handleCompletionRequest(); void handleShutdownRequest(); void handleDidOpenNotification(); void handleDidChangeNotification(); void handleDidSaveNotification(); void handleDidCloseNotification(); QLocalServer server; QBuffer incomingData; lsp::BaseMessage currentMessage; QJsonObject messageObject; QLocalSocket *socket = nullptr; ProjectData projectData; CodeLinks codeLinks; std::unordered_map documents; enum class State { None, InitRequest, InitNotification, Shutdown }; State state = State::None; }; LspServer::LspServer() : d(new Private) { if (!d->server.listen(QString::fromLatin1("qbs-lsp-%1").arg(getPid()))) { // This is not fatal, qbs main operation can continue. qWarning() << "failed to open lsp socket:" << d->server.errorString(); return; } QObject::connect(&d->server, &QLocalServer::newConnection, [this] { d->socket = d->server.nextPendingConnection(); d->setupConnection(); d->server.close(); }); } LspServer::~LspServer() { delete d; } void LspServer::updateProjectData(const ProjectData &projectData, const CodeLinks &codeLinks) { d->projectData = projectData; d->codeLinks = codeLinks; } QString LspServer::socketPath() const { return d->server.fullServerName(); } void LspServer::Private::setupConnection() { QBS_ASSERT(socket, return); QObject::connect(socket, &QLocalSocket::errorOccurred, [this] { discardSocket(); }); QObject::connect(socket, &QLocalSocket::disconnected, [this] { discardSocket(); }); QObject::connect(socket, &QLocalSocket::readyRead, [this] { handleIncomingData(); }); incomingData.open(QIODevice::ReadWrite | QIODevice::Append); handleIncomingData(); } void LspServer::Private::handleIncomingData() { const int pos = incomingData.pos(); incomingData.write(socket->readAll()); incomingData.seek(pos); QString parseError; lsp::BaseMessage::parse(&incomingData, parseError, currentMessage); if (!parseError.isEmpty()) return sendErrorResponse(LspErrorResponse::ParseError, parseError); if (currentMessage.isComplete()) { incomingData.buffer().remove(0, incomingData.pos()); incomingData.seek(0); handleCurrentMessage(); currentMessage = {}; messageObject = {}; if (socket) handleIncomingData(); } } void LspServer::Private::discardSocket() { socket->disconnect(); socket->deleteLater(); socket = nullptr; } template void LspServer::Private::sendResponse(const T &msg) { lsp::Response response(lsp::MessageId(messageObject.value(lsp::idKey))); response.setResult(msg); sendMessage(response); } void LspServer::Private::sendErrorResponse(LspErrorCode code, const QString &message) { lsp::Response response(lsp::MessageId( messageObject.value(lsp::idKey))); lsp::ResponseError error; error.setCode(code); error.setMessage(message); response.setError(error); sendMessage(response); } void LspServer::Private::sendErrorNotification(const QString &message) { lsp::ShowMessageParams params; params.setType(lsp::Error); params.setMessage(message); sendMessage(lsp::ShowMessageNotification(params)); } void LspServer::Private::sendNoSuchDocumentError(const QString &filePath) { sendErrorNotification(Tr::tr("No such document: '%1'").arg(filePath)); } void LspServer::Private::sendMessage(const lsp::JsonObject &msg) { sendMessage(lsp::JsonRpcMessage(msg)); } void LspServer::Private::sendMessage(const lsp::JsonRpcMessage &msg) { lsp::BaseMessage baseMsg = msg.toBaseMessage(); socket->write(baseMsg.header()); socket->write(baseMsg.content); } void LspServer::Private::handleCurrentMessage() { messageObject = lsp::JsonRpcMessage(currentMessage).toJsonObject(); const QString method = messageObject.value(lsp::methodKey).toString(); if (method == QLatin1String("exit")) return discardSocket(); if (state == State::Shutdown) { return sendErrorResponse(LspErrorResponse::InvalidRequest, Tr::tr("Method '%1' not allowed after shutdown.")); } if (method == "shutdown") return handleShutdownRequest(); if (method == QLatin1String("initialize")) return handleInitializeRequest(); if (state == State::None) { return sendErrorResponse(LspErrorResponse::ServerNotInitialized, Tr::tr("First message must be initialize request.")); } if (method == "initialized") return handleInitializedNotification(); if (method == "textDocument/didOpen") return handleDidOpenNotification(); if (method == "textDocument/didChange") return handleDidChangeNotification(); if (method == "textDocument/didSave") return handleDidSaveNotification(); if (method == "textDocument/didClose") return handleDidCloseNotification(); if (method == "textDocument/definition") return handleGotoDefinitionRequest(); if (method == "textDocument/completion") return handleCompletionRequest(); sendErrorResponse(LspErrorResponse::MethodNotFound, Tr::tr("This server can do very little.")); } void LspServer::Private::handleInitializeRequest() { if (state != State::None) { return sendErrorResponse(LspErrorResponse::InvalidRequest, Tr::tr("Received initialize request in initialized state.")); } state = State::InitRequest; lsp::ServerInfo serverInfo; serverInfo.insert(lsp::nameKey, "qbs"); serverInfo.insert(lsp::versionKey, QBS_VERSION); lsp::InitializeResult result; result.insert(lsp::serverInfoKey, serverInfo); lsp::ServerCapabilities capabilities; // TODO: hover capabilities.setDefinitionProvider(true); capabilities.setTextDocumentSync({int(lsp::TextDocumentSyncKind::Incremental)}); lsp::ServerCapabilities::CompletionOptions completionOptions; completionOptions.setTriggerCharacters({"."}); capabilities.setCompletionProvider(completionOptions); result.setCapabilities(capabilities); sendResponse(result); } void LspServer::Private::handleInitializedNotification() { if (state != State::InitRequest) { return sendErrorResponse(LspErrorResponse::InvalidRequest, Tr::tr("Unexpected initialized notification.")); } state = State::InitNotification; } void LspServer::Private::handleGotoDefinitionRequest() { const lsp::TextDocumentPositionParams params(messageObject.value(lsp::paramsKey)); const QString sourceFile = params.textDocument().uri().toLocalFile(); const Document *sourceDoc = nullptr; if (const auto it = documents.find(sourceFile); it != documents.end()) sourceDoc = &it->second; const auto fileEntry = codeLinks.constFind(sourceFile); if (fileEntry == codeLinks.constEnd()) return sendResponse(nullptr); const CodePosition sourcePos = posFromLspPos(params.position()); if (sourceDoc && !sourceDoc->isPositionUpToDate(sourcePos)) return sendResponse(nullptr); for (auto it = fileEntry->cbegin(); it != fileEntry->cend(); ++it) { if (!it.key().contains(sourcePos)) continue; if (sourceDoc && !sourceDoc->isPositionUpToDate(it.key().end())) return sendResponse(nullptr); QList targets = it.value(); QBS_ASSERT(!targets.isEmpty(), return sendResponse(nullptr)); for (auto it = targets.begin(); it != targets.end();) { const Document *targetDoc = nullptr; if (it->filePath() == sourceFile) targetDoc = sourceDoc; else if (const auto docIt = documents.find(it->filePath()); docIt != documents.end()) targetDoc = &docIt->second; if (targetDoc && !targetDoc->isPositionUpToDate(CodePosition(it->line(), it->column()))) it = targets.erase(it); else ++it; } struct JsonArray : public QJsonArray { void reserve(std::size_t) {}}; const auto locations = transformed(targets, [](const CodeLocation &loc) { const lsp::Position startPos = lspPosFromCodeLocation(loc); const lsp::Position endPos(startPos.line(), startPos.character() + 1); lsp::Location targetLocation; targetLocation.setUri(lsp::DocumentUri::fromProtocol( QUrl::fromLocalFile(loc.filePath()).toString())); targetLocation.setRange({startPos, endPos}); return QJsonObject(targetLocation); }); if (locations.size() == 1) return sendResponse(locations.first().toObject()); return sendResponse(locations); } sendResponse(nullptr); } // We operate under the assumption that the client has basic QML support. // Therefore, we only provide completion for qbs modules and their properties. // Only a simple prefix match is implemented, with no regard to the contents after the cursor. void LspServer::Private::handleCompletionRequest() { if (!projectData.isValid()) return sendResponse(nullptr); const lsp::CompletionParams params(messageObject.value(lsp::paramsKey)); const QString sourceFile = params.textDocument().uri().toLocalFile(); const Document *sourceDoc = nullptr; if (const auto it = documents.find(sourceFile); it != documents.end()) sourceDoc = &it->second; if (!sourceDoc) return sendResponse(nullptr); // If there are products corresponding to this file, check only these when looking for modules. // Otherwise, check all products. const QList allProducts = projectData.allProducts(); if (allProducts.isEmpty()) return sendResponse(nullptr); QList relevantProducts; for (const ProductData &p : allProducts) { if (p.location().filePath() == sourceFile) relevantProducts << p; } if (relevantProducts.isEmpty()) relevantProducts = allProducts; QString identifierPrefix; QStringList modulePrefixes; const int offset = posToOffset(params.position(), sourceDoc->currentContent) - 1; if (offset < 0 || offset >= sourceDoc->currentContent.length()) return sendResponse(nullptr); const auto collectFromRawString = [&] { int currentPos = offset; const auto constructIdentifier = [&] { QString id; while (currentPos >= 0) { const QChar c = sourceDoc->currentContent.at(currentPos); if (!c.isLetterOrNumber() && c != '_') break; id.prepend(c); --currentPos; } return id; }; identifierPrefix = constructIdentifier(); while (true) { if (currentPos <= 0 || sourceDoc->currentContent.at(currentPos) != '.') return; --currentPos; const QString modulePrefix = constructIdentifier(); if (modulePrefix.isEmpty()) return; modulePrefixes.prepend(modulePrefix); } }; // Parse the current file. Note that completion usually happens on invalid code, which // often confuses the parser so much that it yields unusable results. Therefore, we always // gather our input parameters from the raw string. We only use the parse result to skip // completion in contexts where it is undesirable. QbsQmlJS::Engine engine; QbsQmlJS::Lexer lexer(&engine); lexer.setCode(sourceDoc->currentContent, 1); QbsQmlJS::Parser parser(&engine); parser.parse(); if (parser.ast()) { AstNodeLocator locator(offset, *parser.ast()); const QList &astPath = locator.path(); if (!astPath.isEmpty()) { switch (astPath.last()->kind) { case QbsQmlJS::AST::Node::Kind_FieldMemberExpression: case QbsQmlJS::AST::Node::Kind_UiObjectDefinition: case QbsQmlJS::AST::Node::Kind_UiQualifiedId: case QbsQmlJS::AST::Node::Kind_UiScriptBinding: break; default: return sendResponse(nullptr); } } } collectFromRawString(); if (modulePrefixes.isEmpty() && identifierPrefix.isEmpty()) return sendResponse(nullptr); // We do not want to start completion from nothing. QJsonArray results; QMap namesAndTypes; for (const ProductData &product : std::as_const(relevantProducts)) { const PropertyMap &moduleProps = product.moduleProperties(); const QStringList allModules = moduleProps.allModules(); const QString moduleNameOrPrefix = modulePrefixes.join('.'); // Case 1: Prefixes match a module name. Identifier can only expand to the name // of a module property. // Example: "Qt.core.a^" -> "Qt.core.availableBuildVariants" if (!modulePrefixes.isEmpty() && allModules.contains(moduleNameOrPrefix)) { for (const PropertyMap::PropertyInfo &info : moduleProps.allPropertiesForModule(moduleNameOrPrefix)) { if (info.isBuiltin) continue; if (!identifierPrefix.isEmpty() && !info.name.startsWith(identifierPrefix)) continue; namesAndTypes.insert(info.name, info.type); } continue; } // Case 2: Isolated identifier. Can only expand to a module name. // Example: "Q^" -> "Qt.core", "Qt.widgets", ... // Case 3: Prefixes match a module prefix. Identifier can only expand to a module name. // Example: "Qt.c^" -> "Qt.core", "Qt.concurrent", ... QString fullPrefix = identifierPrefix; int nameOffset = 0; if (!modulePrefixes.isEmpty()) { fullPrefix.prepend(moduleNameOrPrefix + '.'); nameOffset = moduleNameOrPrefix.length() + 1; } for (const QString &module : allModules) { if (module.startsWith(fullPrefix)) namesAndTypes.insert(module.mid(nameOffset), {}); } } for (auto it = namesAndTypes.cbegin(); it != namesAndTypes.cend(); ++it) { lsp::CompletionItem item; item.setLabel(it.key()); if (!it.value().isEmpty()) item.setDetail(it.value()); results.append(QJsonObject(item)); }; sendResponse(results); } void LspServer::Private::handleShutdownRequest() { state = State::Shutdown; sendResponse(nullptr); } void LspServer::Private::handleDidOpenNotification() { const lsp::TextDocumentItem docItem = lsp::DidOpenTextDocumentNotification(messageObject) .params().value_or(lsp::DidOpenTextDocumentParams()) .textDocument(); if (!docItem.isValid()) return sendErrorNotification(Tr::tr("Invalid didOpen parameters.")); const QString filePath = uriToString(docItem.uri()); Document &doc = documents[filePath]; doc.savedContent = doc.currentContent = docItem.text(); } void LspServer::Private::handleDidChangeNotification() { const auto params = lsp::DidChangeTextDocumentNotification(messageObject) .params().value_or(lsp::DidChangeTextDocumentParams()); if (!params.isValid()) return sendErrorNotification(Tr::tr("Invalid didChange parameters.")); const QString filePath = uriToString(params.textDocument().uri()); const auto docIt = documents.find(filePath); if (docIt == documents.end()) return sendNoSuchDocumentError(filePath); Document &doc = docIt->second; const auto changes = params.contentChanges(); for (const auto &change : changes) { const auto range = change.range(); if (!range) { doc.currentContent = change.text(); continue; } const int startPos = posToOffset(range->start(), doc.currentContent); const int endPos = posToOffset(range->end(), doc.currentContent); if (startPos == -1 || endPos == -1 || startPos > endPos) return sendErrorResponse(LspErrorResponse::InvalidParams, Tr::tr("Invalid range.")); doc.currentContent.replace(startPos, endPos - startPos, change.text()); } } void LspServer::Private::handleDidSaveNotification() { const QString filePath = uriToString(lsp::DidSaveTextDocumentNotification(messageObject) .params().value_or(lsp::DidSaveTextDocumentParams()) .textDocument().uri()); const auto docIt = documents.find(filePath); if (docIt == documents.end()) return sendNoSuchDocumentError(filePath); docIt->second.savedContent = docIt->second.currentContent; // TODO: Mark the project data as out of date until the next update(),if the document // is in buildSystemFiles(). } void LspServer::Private::handleDidCloseNotification() { const QString filePath = uriToString(lsp::DidCloseTextDocumentNotification(messageObject) .params().value_or(lsp::DidCloseTextDocumentParams()) .textDocument().uri()); const auto docIt = documents.find(filePath); if (docIt == documents.end()) return sendNoSuchDocumentError(filePath); documents.erase(docIt); } static int posToOffset(const CodePosition &pos, const QString &doc) { int offset = 0; for (int newlines = 0, next = 0; newlines < pos.line() - 1; ++newlines) { offset = doc.indexOf('\n', next); if (offset == -1) return -1; next = offset + 1; } return offset + pos.column(); } bool Document::isPositionUpToDate(const CodePosition &pos) const { const int origOffset = posToOffset(pos, savedContent); if (origOffset > int(currentContent.size())) return false; return QStringView(currentContent).left(origOffset) == QStringView(savedContent).left(origOffset); } bool Document::isPositionUpToDate(const lsp::Position &pos) const { return isPositionUpToDate(posFromLspPos(pos)); } } // namespace qbs::Internal qbs-src-2.6.1/src/app/qbs/qbs.qbs0000644000175100001660000000370214776170045016102 0ustar runnerdockerimport qbs.Utilities QbsApp { name: "qbs_app" targetName: "qbs" Depends { name: "qbs resources" } Depends { name: "qtclsp" } Depends { name: "Qt.network" } Depends { condition: Qt.core.staticBuild || qbsbuildconfig.staticBuild productTypes: ["qbsplugin"] } cpp.defines: base.concat([ "QBS_VERSION=" + Utilities.cStringQuote(qbsversion.version), "QBS_RELATIVE_LIBEXEC_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeLibexecPath), "QBS_RELATIVE_SEARCH_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeSearchPath), "QBS_RELATIVE_PLUGINS_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativePluginsPath), ]) files: [ "application.cpp", "application.h", "commandlinefrontend.cpp", "commandlinefrontend.h", "consoleprogressobserver.cpp", "consoleprogressobserver.h", "ctrlchandler.cpp", "ctrlchandler.h", "main.cpp", "qbstool.cpp", "qbstool.h", "session.cpp", "session.h", "sessionpacket.cpp", "sessionpacket.h", "sessionpacketreader.cpp", "sessionpacketreader.h", "status.cpp", "status.h", "stdinreader.cpp", "stdinreader.h", ] Group { name: "parser" prefix: name + '/' files: [ "commandlineoption.cpp", "commandlineoption.h", "commandlineoptionpool.cpp", "commandlineoptionpool.h", "commandlineparser.cpp", "commandlineparser.h", "commandpool.cpp", "commandpool.h", "commandtype.h", "parsercommand.cpp", "parsercommand.h", ] } Group { name: "lsp" cpp.defines: outer.filter(function(d) { return d !== "QT_NO_CAST_FROM_ASCII"; }) files: [ "lspserver.cpp", "lspserver.h", ] } } qbs-src-2.6.1/src/app/qbs/ctrlchandler.h0000644000175100001660000000370614776170045017430 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CTRLCHANDLER_H #define CTRLCHANDLER_H void installCtrlCHandler(); #endif // CTRLCHANDLER_H qbs-src-2.6.1/src/app/qbs/sessionpacketreader.cpp0000644000175100001660000000702314776170045021350 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "sessionpacketreader.h" #include "sessionpacket.h" #include "stdinreader.h" #include namespace qbs { namespace Internal { class SessionPacketReader::Private { public: QByteArray incomingData; SessionPacket currentPacket; }; SessionPacketReader::SessionPacketReader(QObject *parent) : QObject(parent) , d(std::make_unique()) { } SessionPacketReader::~SessionPacketReader() = default; void SessionPacketReader::start() { StdinReader * const stdinReader = StdinReader::create(this); connect(stdinReader, &StdinReader::errorOccurred, this, &SessionPacketReader::errorOccurred); connect(stdinReader, &StdinReader::dataAvailable, this, [this](const QByteArray &data) { /* Because this SessionPacketReader can be destroyed in the emit packetReceived, * use a `QPointer self(this)` to check whether this instance still exists. * When self evaluates to false, this instance should no longer be referenced, * so the parent QObject and d should no longer be used in any way. */ QPointer self(this); d->incomingData += data; while (self && !d->incomingData.isEmpty()) { switch (d->currentPacket.parseInput(d->incomingData)) { case SessionPacket::Status::Invalid: emit errorOccurred(tr("Received invalid input.")); return; case SessionPacket::Status::Complete: emit packetReceived(d->currentPacket.retrievePacket()); break; case SessionPacket::Status::Incomplete: return; } } }); stdinReader->start(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/app/qbs/qbstool.h0000644000175100001660000000502514776170045016442 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_QBSTOOL_H #define QBS_QBSTOOL_H #include class QbsTool { public: void runTool(const QString &toolName, const QStringList &arguments); bool failedToStart() const { return m_failedToStart; } int exitCode() const { return m_exitCode; } QString stdOut() const { return m_stdout; } QString stdErr() const { return m_stderr; } static QStringList allToolNames(); static bool tryToRunTool(const QString &toolName, const QStringList &arguments, int *exitCode = 0); private: bool m_failedToStart = false; int m_exitCode = 0; QString m_stdout; QString m_stderr; }; #endif // QBS_QBSTOOL_H qbs-src-2.6.1/src/app/qbs/lspserver.h0000644000175100001660000000436614776170045017013 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include #include namespace qbs { class ProjectData; namespace Internal { class LspServer { public: LspServer(); ~LspServer(); void updateProjectData(const ProjectData &projectData, const CodeLinks &codeLinks); QString socketPath() const; private: class Private; Private * const d; }; } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/app/qbs/main.cpp0000644000175100001660000000660614776170045016244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "application.h" #include "commandlinefrontend.h" #include "qbstool.h" #include "parser/commandlineparser.h" #include "../shared/logging/consolelogger.h" #include #include #include using namespace qbs; static bool tryToRunTool(const QStringList &arguments, int &exitCode) { if (arguments.empty()) return false; QStringList toolArgs = arguments; const QString toolName = toolArgs.takeFirst(); if (toolName.startsWith(QLatin1Char('-'))) return false; return QbsTool::tryToRunTool(toolName, toolArgs, &exitCode); } int main(int argc, char *argv[]) { ConsoleLogger::instance(); try { Application app(argc, argv); QStringList arguments = app.arguments(); arguments.removeFirst(); int toolExitCode = 0; if (tryToRunTool(arguments, toolExitCode)) return toolExitCode; CommandLineParser parser; if (!parser.parseCommandLine(arguments)) return EXIT_FAILURE; if (parser.command() == HelpCommandType) { parser.printHelp(); return 0; } Settings settings(parser.settingsDir()); ConsoleLogger::instance().setSettings(&settings); CommandLineFrontend clFrontend(parser, &settings); app.setCommandLineFrontend(&clFrontend); QTimer::singleShot(0, &clFrontend, &CommandLineFrontend::start); return app.exec(); } catch (const ErrorInfo &error) { qbsError() << error.toString(); return EXIT_FAILURE; } } qbs-src-2.6.1/src/app/qbs/consoleprogressobserver.h0000644000175100001660000000477514776170045021771 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CONSOLEPROGRESSOBSERVER_H #define CONSOLEPROGRESSOBSERVER_H #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { class ConsoleProgressObserver { public: void initialize(const QString &task, int max); void setMaximum(int maximum); void setProgressValue(int value); void incrementProgressValue() { setProgressValue(m_value + 1); } private: void eraseCurrentPercentageString(); void updateProgressBarIfNecessary(); void writePercentageString(); int m_maximum; int m_value; int m_percentage; int m_hashesPrinted; }; } // namespace qbs #endif // CONSOLEPROGRESSOBSERVER_H qbs-src-2.6.1/src/app/qbs/CMakeLists.txt0000644000175100001660000000241514776170045017346 0ustar runnerdockerset(SOURCES application.cpp application.h commandlinefrontend.cpp commandlinefrontend.h consoleprogressobserver.cpp consoleprogressobserver.h ctrlchandler.cpp ctrlchandler.h lspserver.cpp lspserver.h main.cpp qbstool.cpp qbstool.h session.cpp session.h sessionpacket.cpp sessionpacket.h sessionpacketreader.cpp sessionpacketreader.h status.cpp status.h stdinreader.cpp stdinreader.h ) set(PARSER_SOURCES commandlineoption.cpp commandlineoption.h commandlineoptionpool.cpp commandlineoptionpool.h commandlineparser.cpp commandlineparser.h commandpool.cpp commandpool.h commandtype.h parsercommand.cpp parsercommand.h ) list_transform_prepend(PARSER_SOURCES parser/) add_qbs_app(qbs DEFINES "QBS_VERSION=\"${QBS_VERSION}\"" "QBS_RELATIVE_LIBEXEC_PATH=\"${QBS_RELATIVE_LIBEXEC_PATH}\"" "QBS_RELATIVE_SEARCH_PATH=\"${QBS_RELATIVE_SEARCH_PATH}\"" "QBS_RELATIVE_PLUGINS_PATH=\"${QBS_RELATIVE_PLUGINS_PATH}\"" DEPENDS qbscore qbsconsolelogger qtclsp Qt${QT_VERSION_MAJOR}::Network SOURCES ${SOURCES} ${PARSER_SOURCES} ) add_dependencies(qbs qbs_cpp_scanner qbs_qt_scanner) qbs-src-2.6.1/src/app/qbs/parser/0000755000175100001660000000000014776170045016100 5ustar runnerdockerqbs-src-2.6.1/src/app/qbs/parser/commandlineoptionpool.cpp0000644000175100001660000002435714776170045023230 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineoptionpool.h" namespace qbs { CommandLineOptionPool::~CommandLineOptionPool() { qDeleteAll(m_options); } CommandLineOption *CommandLineOptionPool::getOption(CommandLineOption::Type type) const { CommandLineOption *& option = m_options[type]; if (!option) { switch (type) { case CommandLineOption::FileOptionType: option = new FileOption; break; case CommandLineOption::BuildDirectoryOptionType: option = new BuildDirectoryOption; break; case CommandLineOption::LogLevelOptionType: option = new LogLevelOption; break; case CommandLineOption::VerboseOptionType: option = new VerboseOption; break; case CommandLineOption::QuietOptionType: option = new QuietOption; break; case CommandLineOption::JobsOptionType: option = new JobsOption; break; case CommandLineOption::KeepGoingOptionType: option = new KeepGoingOption; break; case CommandLineOption::DryRunOptionType: option = new DryRunOption; break; case CommandLineOption::ForceProbesOptionType: option = new ForceProbesOption; break; case CommandLineOption::ShowProgressOptionType: option = new ShowProgressOption; break; case CommandLineOption::ChangedFilesOptionType: option = new ChangedFilesOption; break; case CommandLineOption::ProductsOptionType: option = new ProductsOption; break; case CommandLineOption::NoInstallOptionType: option = new NoInstallOption; break; case CommandLineOption::InstallRootOptionType: option = new InstallRootOption; break; case CommandLineOption::RemoveFirstOptionType: option = new RemoveFirstOption; break; case CommandLineOption::NoBuildOptionType: option = new NoBuildOption; break; case CommandLineOption::ForceTimestampCheckOptionType: option = new ForceTimeStampCheckOption; break; case CommandLineOption::ForceOutputCheckOptionType: option = new ForceOutputCheckOption; break; case CommandLineOption::BuildNonDefaultOptionType: option = new BuildNonDefaultOption; break; case CommandLineOption::LogTimeOptionType: option = new LogTimeOption; break; case CommandLineOption::CommandEchoModeOptionType: option = new CommandEchoModeOption; break; case CommandLineOption::SettingsDirOptionType: option = new SettingsDirOption; break; case CommandLineOption::JobLimitsOptionType: option = new JobLimitsOption; break; case CommandLineOption::RespectProjectJobLimitsOptionType: option = new RespectProjectJobLimitsOption; break; case CommandLineOption::GeneratorOptionType: option = new GeneratorOption; break; case CommandLineOption::WaitLockOptionType: option = new WaitLockOption; break; case CommandLineOption::RunEnvConfigOptionType: option = new RunEnvConfigOption; break; case CommandLineOption::DeprecationWarningsOptionType: option = new DeprecationWarningsOption; break; default: qFatal("Unknown option type %d", type); } } return option; } FileOption *CommandLineOptionPool::fileOption() const { return static_cast(getOption(CommandLineOption::FileOptionType)); } BuildDirectoryOption *CommandLineOptionPool::buildDirectoryOption() const { return static_cast(getOption(CommandLineOption::BuildDirectoryOptionType)); } LogLevelOption *CommandLineOptionPool::logLevelOption() const { return static_cast(getOption(CommandLineOption::LogLevelOptionType)); } VerboseOption *CommandLineOptionPool::verboseOption() const { return static_cast(getOption(CommandLineOption::VerboseOptionType)); } QuietOption *CommandLineOptionPool::quietOption() const { return static_cast(getOption(CommandLineOption::QuietOptionType)); } ShowProgressOption *CommandLineOptionPool::showProgressOption() const { return static_cast(getOption(CommandLineOption::ShowProgressOptionType)); } DryRunOption *CommandLineOptionPool::dryRunOption() const { return static_cast(getOption(CommandLineOption::DryRunOptionType)); } ForceProbesOption *CommandLineOptionPool::forceProbesOption() const { return static_cast(getOption(CommandLineOption::ForceProbesOptionType)); } ChangedFilesOption *CommandLineOptionPool::changedFilesOption() const { return static_cast(getOption(CommandLineOption::ChangedFilesOptionType)); } KeepGoingOption *CommandLineOptionPool::keepGoingOption() const { return static_cast(getOption(CommandLineOption::KeepGoingOptionType)); } JobsOption *CommandLineOptionPool::jobsOption() const { return static_cast(getOption(CommandLineOption::JobsOptionType)); } ProductsOption *CommandLineOptionPool::productsOption() const { return static_cast(getOption(CommandLineOption::ProductsOptionType)); } NoInstallOption *CommandLineOptionPool::noInstallOption() const { return static_cast(getOption(CommandLineOption::NoInstallOptionType)); } InstallRootOption *CommandLineOptionPool::installRootOption() const { return static_cast(getOption(CommandLineOption::InstallRootOptionType)); } RemoveFirstOption *CommandLineOptionPool::removeFirstoption() const { return static_cast(getOption(CommandLineOption::RemoveFirstOptionType)); } NoBuildOption *CommandLineOptionPool::noBuildOption() const { return static_cast(getOption(CommandLineOption::NoBuildOptionType)); } ForceTimeStampCheckOption *CommandLineOptionPool::forceTimestampCheckOption() const { return static_cast( getOption(CommandLineOption::ForceTimestampCheckOptionType)); } ForceOutputCheckOption *CommandLineOptionPool::forceOutputCheckOption() const { return static_cast( getOption(CommandLineOption::ForceOutputCheckOptionType)); } BuildNonDefaultOption *CommandLineOptionPool::buildNonDefaultOption() const { return static_cast( getOption(CommandLineOption::BuildNonDefaultOptionType)); } LogTimeOption *CommandLineOptionPool::logTimeOption() const { return static_cast(getOption(CommandLineOption::LogTimeOptionType)); } CommandEchoModeOption *CommandLineOptionPool::commandEchoModeOption() const { return static_cast( getOption(CommandLineOption::CommandEchoModeOptionType)); } SettingsDirOption *CommandLineOptionPool::settingsDirOption() const { return static_cast(getOption(CommandLineOption::SettingsDirOptionType)); } JobLimitsOption *CommandLineOptionPool::jobLimitsOption() const { return static_cast(getOption(CommandLineOption::JobLimitsOptionType)); } RespectProjectJobLimitsOption *CommandLineOptionPool::respectProjectJobLimitsOption() const { return static_cast( getOption(CommandLineOption::RespectProjectJobLimitsOptionType)); } GeneratorOption *CommandLineOptionPool::generatorOption() const { return static_cast(getOption(CommandLineOption::GeneratorOptionType)); } WaitLockOption *CommandLineOptionPool::waitLockOption() const { return static_cast(getOption(CommandLineOption::WaitLockOptionType)); } RunEnvConfigOption *CommandLineOptionPool::runEnvConfigOption() const { return static_cast(getOption(CommandLineOption::RunEnvConfigOptionType)); } DeprecationWarningsOption *CommandLineOptionPool::deprecationWarningsOption() const { return static_cast (getOption(CommandLineOption::DeprecationWarningsOptionType)); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/parser/commandpool.h0000644000175100001660000000453214776170045020565 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_COMMANDPOOL_H #define QBS_COMMANDPOOL_H #include "commandtype.h" #include namespace qbs { class Command; class CommandLineOptionPool; class CommandPool { Q_DISABLE_COPY(CommandPool) public: CommandPool(CommandLineOptionPool &optionPool); ~CommandPool(); Command *getCommand(CommandType type) const; private: CommandLineOptionPool &m_optionPool; mutable QHash m_commands; }; } // namespace qbs #endif // QBS_COMMANDPOOL_H qbs-src-2.6.1/src/app/qbs/parser/parsercommand.h0000644000175100001660000002266214776170045021114 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PARSER_COMMAND_H #define QBS_PARSER_COMMAND_H #include "commandlineoption.h" #include "commandtype.h" #include namespace qbs { class CommandLineOptionPool; class Command { public: virtual ~Command(); virtual CommandType type() const = 0; virtual QString shortDescription() const = 0; virtual QString longDescription() const = 0; virtual QString representation() const = 0; void parse(QStringList &input); QStringList additionalArguments() const { return m_additionalArguments; } bool canResolve() const; protected: Command(CommandLineOptionPool &optionPool) : m_optionPool(optionPool) {} const CommandLineOptionPool &optionPool() const { return m_optionPool; } QString supportedOptionsDescription() const; [[noreturn]] void throwError(const QString &reason); virtual void parseNext(QStringList &input); private: QList actualSupportedOptions() const; void parseOption(QStringList &input); void parsePropertyAssignment(const QString &argument); virtual QList supportedOptions() const = 0; QStringList m_additionalArguments; std::set m_usedOptions; const CommandLineOptionPool &m_optionPool; }; class ResolveCommand : public Command { public: ResolveCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return ResolveCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class GenerateCommand : public Command { public: GenerateCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return GenerateCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class BuildCommand : public Command { public: BuildCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return BuildCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class CleanCommand : public Command { public: CleanCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return CleanCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class InstallCommand : public Command { public: InstallCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return InstallCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class RunCommand : public Command { public: RunCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} QStringList targetParameters() const { return m_targetParameters; } private: CommandType type() const override { return RunCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; void parseNext(QStringList &input) override; QStringList m_targetParameters; }; class ShellCommand : public Command { public: ShellCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return ShellCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; // TODO: It seems wrong that a configuration has to be given here. Ideally, this command would just track *all* files regardless of conditions. Is that possible? class StatusCommand : public Command { public: StatusCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return StatusCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class UpdateTimestampsCommand : public Command { public: UpdateTimestampsCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return UpdateTimestampsCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class DumpNodesTreeCommand : public Command { public: DumpNodesTreeCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override{ return DumpNodesTreeCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class ListProductsCommand : public Command { public: ListProductsCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return ListProductsCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class HelpCommand : public Command { public: HelpCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} QString commandToDescribe() const { return m_command; } private: CommandType type() const override { return HelpCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; void parseNext(QStringList &input) override; QString m_command; }; class VersionCommand : public Command { public: VersionCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return VersionCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; void parseNext(QStringList &input) override; }; class SessionCommand : public Command { public: SessionCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return SessionCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override { return {}; } void parseNext(QStringList &input) override; }; } // namespace qbs #endif // QBS_PARSER_COMMAND_H qbs-src-2.6.1/src/app/qbs/parser/commandlineoptionpool.h0000644000175100001660000000717514776170045022674 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_COMMANDLINEOPTIONPOOL_H #define QBS_COMMANDLINEOPTIONPOOL_H #include "commandlineoption.h" #include namespace qbs { class CommandLineOptionPool { public: ~CommandLineOptionPool(); CommandLineOption *getOption(CommandLineOption::Type type) const; FileOption *fileOption() const; BuildDirectoryOption *buildDirectoryOption() const; LogLevelOption *logLevelOption() const; VerboseOption *verboseOption() const; QuietOption *quietOption() const; ShowProgressOption *showProgressOption() const; DryRunOption *dryRunOption() const; ForceProbesOption *forceProbesOption() const; ChangedFilesOption *changedFilesOption() const; KeepGoingOption *keepGoingOption() const; JobsOption *jobsOption() const; ProductsOption *productsOption() const; NoInstallOption *noInstallOption() const; InstallRootOption *installRootOption() const; RemoveFirstOption *removeFirstoption() const; NoBuildOption *noBuildOption() const; ForceTimeStampCheckOption *forceTimestampCheckOption() const; ForceOutputCheckOption *forceOutputCheckOption() const; BuildNonDefaultOption *buildNonDefaultOption() const; LogTimeOption *logTimeOption() const; CommandEchoModeOption *commandEchoModeOption() const; SettingsDirOption *settingsDirOption() const; JobLimitsOption *jobLimitsOption() const; RespectProjectJobLimitsOption *respectProjectJobLimitsOption() const; GeneratorOption *generatorOption() const; WaitLockOption *waitLockOption() const; RunEnvConfigOption *runEnvConfigOption() const; DeprecationWarningsOption *deprecationWarningsOption() const; private: mutable QHash m_options; }; } // namespace qbs #endif // QBS_COMMANDLINEOPTIONPOOL_H qbs-src-2.6.1/src/app/qbs/parser/commandlineparser.cpp0000644000175100001660000005520414776170045022315 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include "commandlineoption.h" #include "commandlineoptionpool.h" #include "commandpool.h" #include "parsercommand.h" #include "../qbstool.h" #include "../../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_UNIX #include #endif namespace qbs { using Internal::Tr; class CommandLineParser::CommandLineParserPrivate { public: CommandLineParserPrivate(); void doParse(); Command *commandFromString(const QString &commandString) const; QList allCommands() const; QString generalHelp() const; void setupProjectFile(); void setupBuildDirectory(); void setupProgress(); void setupLogLevel(); void setupBuildOptions(); void setupBuildConfigurations(); bool checkForExistingBuildConfiguration(const QList &buildConfigs, const QString &configurationName); bool withNonDefaultProducts() const; bool dryRun() const; QString settingsDir() const { return optionPool.settingsDirOption()->settingsDir(); } CommandEchoMode echoMode() const; QString propertyName(const QString &aCommandLineName) const; QStringList commandLine; Command *command; QString projectFilePath; QString projectBuildDirectory; BuildOptions buildOptions; QList buildConfigurations; CommandLineOptionPool optionPool; CommandPool commandPool; bool showProgress; bool logTime; }; CommandLineParser::CommandLineParser() = default; CommandLineParser::~CommandLineParser() = default; void CommandLineParser::printHelp() const { QTextStream stream(stdout); Q_ASSERT(d->command == d->commandPool.getCommand(HelpCommandType)); const auto helpCommand = static_cast(d->command); if (helpCommand->commandToDescribe().isEmpty()) { stream << "Qbs " QBS_VERSION ", a cross-platform build tool.\n"; stream << d->generalHelp(); } else { const Command * const commandToDescribe = d->commandFromString(helpCommand->commandToDescribe()); if (commandToDescribe) { stream << commandToDescribe->longDescription(); } else if (!QbsTool::tryToRunTool(helpCommand->commandToDescribe(), QStringList(QStringLiteral("--help")))) { throw ErrorInfo(Tr::tr("No such command '%1'.\n%2") .arg(helpCommand->commandToDescribe(), d->generalHelp())); } } } CommandType CommandLineParser::command() const { return d->command->type(); } QString CommandLineParser::projectFilePath() const { return d->projectFilePath; } QString CommandLineParser::projectBuildDirectory() const { return d->projectBuildDirectory; } BuildOptions CommandLineParser::buildOptions(const QString &profile) const { d->buildOptions.setMaxJobCount(jobCount(profile)); if (d->buildOptions.echoMode() < 0) { Settings settings(settingsDir()); d->buildOptions.setEchoMode(Preferences(&settings, profile).defaultEchoMode()); } return d->buildOptions; } CleanOptions CommandLineParser::cleanOptions(const QString &profile) const { CleanOptions options; options.setDryRun(buildOptions(profile).dryRun()); options.setKeepGoing(buildOptions(profile).keepGoing()); options.setLogElapsedTime(logTime()); return options; } GenerateOptions CommandLineParser::generateOptions() const { GenerateOptions options; options.setGeneratorName(d->optionPool.generatorOption()->generatorName()); return options; } InstallOptions CommandLineParser::installOptions(const QString &profile) const { InstallOptions options; options.setRemoveExistingInstallation(d->optionPool.removeFirstoption()->enabled()); options.setInstallRoot(d->optionPool.installRootOption()->installRoot()); options.setInstallIntoSysroot(d->optionPool.installRootOption()->useSysroot()); if (!options.installRoot().isEmpty()) { QFileInfo fi(options.installRoot()); if (!fi.isAbsolute()) options.setInstallRoot(fi.absoluteFilePath()); } options.setDryRun(buildOptions(profile).dryRun()); options.setKeepGoing(buildOptions(profile).keepGoing()); options.setLogElapsedTime(logTime()); return options; } int CommandLineParser::jobCount(const QString &profile) const { if (const int explicitJobCount = d->optionPool.jobsOption()->jobCount(); explicitJobCount > 0) return explicitJobCount; Settings settings(settingsDir()); return Preferences(&settings, profile).jobs(); } bool CommandLineParser::forceTimestampCheck() const { return d->optionPool.forceTimestampCheckOption()->enabled(); } bool CommandLineParser::forceOutputCheck() const { return d->optionPool.forceOutputCheckOption()->enabled(); } bool CommandLineParser::dryRun() const { return d->dryRun(); } bool CommandLineParser::forceProbesExecution() const { return d->optionPool.forceProbesOption()->enabled(); } bool CommandLineParser::waitLockBuildGraph() const { return d->optionPool.waitLockOption()->enabled(); } bool CommandLineParser::logTime() const { return d->logTime; } bool CommandLineParser::withNonDefaultProducts() const { return d->withNonDefaultProducts(); } bool CommandLineParser::buildBeforeInstalling() const { return !d->optionPool.noBuildOption()->enabled(); } QStringList CommandLineParser::runArgs() const { Q_ASSERT(d->command->type() == RunCommandType); return static_cast(d->command)->targetParameters(); } QStringList CommandLineParser::products() const { return d->optionPool.productsOption()->arguments(); } QStringList CommandLineParser::runEnvConfig() const { return d->optionPool.runEnvConfigOption()->arguments(); } bool CommandLineParser::showProgress() const { return d->showProgress; } bool CommandLineParser::showVersion() const { return d->command->type() == VersionCommandType; } QString CommandLineParser::settingsDir() const { return d->settingsDir(); } DeprecationWarningMode CommandLineParser::deprecationWarningMode() const { return d->optionPool.deprecationWarningsOption()->mode(); } QString CommandLineParser::commandName() const { return d->command->representation(); } bool CommandLineParser::commandCanResolve() const { return d->command->canResolve(); } QString CommandLineParser::commandDescription() const { return d->command->longDescription(); } static QString getBuildConfigurationName(const QVariantMap &buildConfig) { return buildConfig.value(QStringLiteral("qbs.configurationName")).toString(); } QList CommandLineParser::buildConfigurations() const { return d->buildConfigurations; } bool CommandLineParser::parseCommandLine(const QStringList &args) { d = std::make_unique(); d->commandLine = args; try { d->doParse(); return true; } catch (const ErrorInfo &error) { qbsError() << error.toString(); return false; } } CommandLineParser::CommandLineParserPrivate::CommandLineParserPrivate() : command(nullptr), commandPool(optionPool), showProgress(false), logTime(false) { } void CommandLineParser::CommandLineParserPrivate::doParse() { if (commandLine.empty()) { // No command given, use default. command = commandPool.getCommand(BuildCommandType); } else { command = commandFromString(commandLine.front()); if (command) { const QString commandName = commandLine.takeFirst(); // if the command line contains a `` with // either `-h` or `--help` switch, we transform // it to corresponding `help ` instead const QStringList helpSwitches = {QStringLiteral("-h"), QStringLiteral("--help")}; if (auto it = std::find_first_of( commandLine.begin(), commandLine.end(), helpSwitches.begin(), helpSwitches.end()); it != commandLine.end()) { command = commandPool.getCommand(HelpCommandType); commandLine = QList{commandName}; // keep only command's name } } else { // No command given. if (commandLine.front() == QLatin1String("-h") || commandLine.front() == QLatin1String("--help")) { command = commandPool.getCommand(HelpCommandType); commandLine.takeFirst(); } else if (commandLine.front() == QLatin1String("-V") || commandLine.front() == QLatin1String("--version")) { command = commandPool.getCommand(VersionCommandType); commandLine.takeFirst(); } else { command = commandPool.getCommand(BuildCommandType); } } } command->parse(commandLine); if (command->type() == HelpCommandType || command->type() == VersionCommandType) return; setupBuildDirectory(); setupBuildConfigurations(); setupProjectFile(); setupProgress(); setupLogLevel(); setupBuildOptions(); } Command *CommandLineParser::CommandLineParserPrivate::commandFromString(const QString &commandString) const { const auto commands = allCommands(); for (Command * const command : commands) { if (command->representation() == commandString) return command; } return nullptr; } QList CommandLineParser::CommandLineParserPrivate::allCommands() const { return {commandPool.getCommand(GenerateCommandType), commandPool.getCommand(ResolveCommandType), commandPool.getCommand(BuildCommandType), commandPool.getCommand(CleanCommandType), commandPool.getCommand(RunCommandType), commandPool.getCommand(ShellCommandType), commandPool.getCommand(StatusCommandType), commandPool.getCommand(UpdateTimestampsCommandType), commandPool.getCommand(InstallCommandType), commandPool.getCommand(DumpNodesTreeCommandType), commandPool.getCommand(ListProductsCommandType), commandPool.getCommand(VersionCommandType), commandPool.getCommand(SessionCommandType), commandPool.getCommand(HelpCommandType)}; } static QString extractToolDescription(const QString &tool, const QString &output) { if (tool == QLatin1String("create-project")) { // This command uses QCommandLineParser, where the description is not in the first line. const int eol1Pos = output.indexOf(QLatin1Char('\n')); const int eol2Pos = output.indexOf(QLatin1Char('\n'), eol1Pos + 1); return output.mid(eol1Pos + 1, eol2Pos - eol1Pos - 1); } return output.left(output.indexOf(QLatin1Char('\n'))); } QString CommandLineParser::CommandLineParserPrivate::generalHelp() const { QString help = Tr::tr("Usage: qbs [command] [command parameters]\n"); help += Tr::tr("Built-in commands:\n"); const int rhsIndentation = 30; // Sorting the commands by name is nicer for the user. QMap commandMap; const auto commands = allCommands(); for (const Command * command : commands) commandMap.insert(command->representation(), command); for (const Command * command : std::as_const(commandMap)) { help.append(QLatin1String(" ")).append(command->representation()); const QString whitespace = QString(rhsIndentation - 2 - command->representation().size(), QLatin1Char(' ')); help.append(whitespace).append(command->shortDescription()).append(QLatin1Char('\n')); } QStringList toolNames = QbsTool::allToolNames(); toolNames.sort(); if (!toolNames.empty()) { help.append(QLatin1Char('\n')).append(Tr::tr("Auxiliary commands:\n")); for (const QString &toolName : std::as_const(toolNames)) { help.append(QLatin1String(" ")).append(toolName); const QString whitespace = QString(rhsIndentation - 2 - toolName.size(), QLatin1Char(' ')); QbsTool tool; tool.runTool(toolName, QStringList(QStringLiteral("--help"))); if (tool.exitCode() != 0) continue; const QString shortDescription = extractToolDescription(toolName, tool.stdOut()); help.append(whitespace).append(shortDescription).append(QLatin1Char('\n')); } } return help; } void CommandLineParser::CommandLineParserPrivate::setupProjectFile() { projectFilePath = optionPool.fileOption()->projectFilePath(); } void CommandLineParser::CommandLineParserPrivate::setupBuildDirectory() { projectBuildDirectory = optionPool.buildDirectoryOption()->projectBuildDirectory(); } void CommandLineParser::CommandLineParserPrivate::setupBuildOptions() { buildOptions.setDryRun(dryRun()); QStringList changedFiles = optionPool.changedFilesOption()->arguments(); QDir currentDir; for (QString &file : changedFiles) file = QDir::fromNativeSeparators(currentDir.absoluteFilePath(file)); buildOptions.setChangedFiles(changedFiles); buildOptions.setKeepGoing(optionPool.keepGoingOption()->enabled()); buildOptions.setForceTimestampCheck(optionPool.forceTimestampCheckOption()->enabled()); buildOptions.setForceOutputCheck(optionPool.forceOutputCheckOption()->enabled()); const JobsOption * jobsOption = optionPool.jobsOption(); buildOptions.setMaxJobCount(jobsOption->jobCount()); buildOptions.setLogElapsedTime(logTime); buildOptions.setEchoMode(echoMode()); buildOptions.setInstall(!optionPool.noInstallOption()->enabled()); buildOptions.setRemoveExistingInstallation(optionPool.removeFirstoption()->enabled()); buildOptions.setJobLimits(optionPool.jobLimitsOption()->jobLimits()); buildOptions.setProjectJobLimitsTakePrecedence( optionPool.respectProjectJobLimitsOption()->enabled()); buildOptions.setSettingsDirectory(settingsDir()); } void CommandLineParser::CommandLineParserPrivate::setupBuildConfigurations() { // first: configuration name, second: properties. // Empty configuration name used for global properties. using PropertyListItem = std::pair; QList propertiesPerConfiguration; const QString configurationNameKey = QStringLiteral("qbs.configurationName"); QString currentConfigurationName; QVariantMap currentProperties; const auto args = command->additionalArguments(); for (const QString &arg : args) { const int sepPos = arg.indexOf(QLatin1Char(':')); QBS_CHECK(sepPos > 0); const QString key = arg.left(sepPos); const QString rawValue = arg.mid(sepPos + 1); if (key == QLatin1String("config") || key == configurationNameKey) { propertiesPerConfiguration.push_back(std::make_pair(currentConfigurationName, currentProperties)); currentConfigurationName = rawValue; currentProperties.clear(); continue; } currentProperties.insert(propertyName(key), representationToSettingsValue(rawValue)); } propertiesPerConfiguration.push_back(std::make_pair(currentConfigurationName, currentProperties)); if (propertiesPerConfiguration.size() == 1) // No configuration name specified on command line. propertiesPerConfiguration.push_back(PropertyListItem(QStringLiteral("default"), QVariantMap())); const QVariantMap globalProperties = propertiesPerConfiguration.takeFirst().second; QList buildConfigs; for (const PropertyListItem &item : std::as_const(propertiesPerConfiguration)) { QVariantMap properties = item.second; for (QVariantMap::ConstIterator globalPropIt = globalProperties.constBegin(); globalPropIt != globalProperties.constEnd(); ++globalPropIt) { if (!properties.contains(globalPropIt.key())) properties.insert(globalPropIt.key(), globalPropIt.value()); } const QString configurationName = item.first; if (checkForExistingBuildConfiguration(buildConfigs, configurationName)) { qbsWarning() << Tr::tr("Ignoring redundant request to build for configuration '%1'.") .arg(configurationName); continue; } properties.insert(configurationNameKey, configurationName); buildConfigs.push_back(properties); } buildConfigurations = buildConfigs; } void CommandLineParser::CommandLineParserPrivate::setupProgress() { const ShowProgressOption * const option = optionPool.showProgressOption(); showProgress = option->enabled(); #ifdef Q_OS_UNIX if (showProgress && !isatty(STDOUT_FILENO)) { showProgress = false; qbsWarning() << Tr::tr("Ignoring option '%1', because standard output is " "not connected to a terminal.").arg(option->longRepresentation()); } #endif } void CommandLineParser::CommandLineParserPrivate::setupLogLevel() { const LogLevelOption * const logLevelOption = optionPool.logLevelOption(); const VerboseOption * const verboseOption = optionPool.verboseOption(); const QuietOption * const quietOption = optionPool.quietOption(); int logLevel = logLevelOption->logLevel(); logLevel += verboseOption->count(); logLevel -= quietOption->count(); if (showProgress && logLevel != LoggerMinLevel) { const bool logLevelWasSetByUser = logLevelOption->logLevel() != defaultLogLevel() || verboseOption->count() > 0 || quietOption->count() > 0; if (logLevelWasSetByUser) { qbsInfo() << Tr::tr("Setting log level to '%1', because option '%2'" " has been given.").arg(logLevelName(LoggerMinLevel), optionPool.showProgressOption()->longRepresentation()); } logLevel = LoggerMinLevel; } if (logLevel < LoggerMinLevel) { qbsWarning() << Tr::tr("Cannot decrease log level as much as specified; using '%1'.") .arg(logLevelName(LoggerMinLevel)); logLevel = LoggerMinLevel; } else if (logLevel > LoggerMaxLevel) { qbsWarning() << Tr::tr("Cannot increase log level as much as specified; using '%1'.") .arg(logLevelName(LoggerMaxLevel)); logLevel = LoggerMaxLevel; } logTime = optionPool.logTimeOption()->enabled(); if (showProgress && logTime) { qbsWarning() << Tr::tr("Options '%1' and '%2' are incompatible. Ignoring '%2'.") .arg(optionPool.showProgressOption()->longRepresentation(), optionPool.logTimeOption()->longRepresentation()); logTime = false; } ConsoleLogger::instance().logSink()->setLogLevel(static_cast(logLevel)); } QString CommandLineParser::CommandLineParserPrivate::propertyName(const QString &aCommandLineName) const { // Make fully-qualified, ie "platform" -> "qbs.platform" if (aCommandLineName.contains(QLatin1Char('.'))) return aCommandLineName; return QLatin1String("qbs.") + aCommandLineName; } bool CommandLineParser::CommandLineParserPrivate::checkForExistingBuildConfiguration( const QList &buildConfigs, const QString &configurationName) { return Internal::any_of(buildConfigs, [&configurationName](const auto &buildConfig) { return configurationName == getBuildConfigurationName(buildConfig); }); } bool CommandLineParser::CommandLineParserPrivate::withNonDefaultProducts() const { if (command->type() == GenerateCommandType) return true; return optionPool.buildNonDefaultOption()->enabled(); } bool CommandLineParser::CommandLineParserPrivate::dryRun() const { if (command->type() == GenerateCommandType || command->type() == ListProductsCommandType) return true; return optionPool.dryRunOption()->enabled(); } CommandEchoMode CommandLineParser::CommandLineParserPrivate::echoMode() const { if (command->type() == GenerateCommandType) return CommandEchoModeSilent; if (optionPool.commandEchoModeOption()->commandEchoMode() < CommandEchoModeInvalid) return optionPool.commandEchoModeOption()->commandEchoMode(); return defaultCommandEchoMode(); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/parser/commandlineoption.cpp0000644000175100001660000005710514776170045022333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineoption.h" #include #include #include #include #include namespace qbs { using namespace Internal; CommandLineOption::~CommandLineOption() = default; void CommandLineOption::parse(CommandType command, const QString &representation, QStringList &input) { m_command = command; doParse(representation, input); } CommandLineOption::CommandLineOption() : m_command(static_cast(-1)) { } QString CommandLineOption::getArgument(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': Missing argument.\nUsage: %2") .arg(representation, description(command()))); } return input.takeFirst(); } QString FileOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tUse as the project file.\n" "\tIf is a directory and it contains a single file ending in '.qbs',\n" "\tthat file will be used.\n" "\tIf this option is not given at all, behavior is the same as for '-f .'.\n") .arg(longRepresentation(), shortRepresentation()); } QString FileOption::shortRepresentation() const { return QStringLiteral("-f"); } QString FileOption::longRepresentation() const { return QStringLiteral("--file"); } void FileOption::doParse(const QString &representation, QStringList &input) { m_projectFilePath = getArgument(representation, input); } QString BuildDirectoryOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tBuild in the given directory. The default value is the current directory\n" "\tunless preferences.defaultBuildDirectory is set.\n" "\tRelative paths will be interpreted relative to the current directory.\n" "\tIf the directory does not exist, it will be created. Use the following\n" "\tspecial values as placeholders:\n" "\t%3: name of the project file excluding the extension\n" "\t%4: directory containing the project file\n") .arg(longRepresentation(), shortRepresentation(), magicProjectString(), magicProjectDirString()); } QString BuildDirectoryOption::shortRepresentation() const { return QStringLiteral("-d"); } QString BuildDirectoryOption::longRepresentation() const { return QStringLiteral("--build-directory"); } QString BuildDirectoryOption::magicProjectString() { return QStringLiteral("@project"); } QString BuildDirectoryOption::magicProjectDirString() { return QStringLiteral("@path"); } void BuildDirectoryOption::doParse(const QString &representation, QStringList &input) { m_projectBuildDirectory = getArgument(representation, input); } QString GeneratorOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tUse the given build system generator.\n") .arg(longRepresentation(), shortRepresentation()); } QString GeneratorOption::shortRepresentation() const { return QStringLiteral("-g"); } QString GeneratorOption::longRepresentation() const { return QStringLiteral("--generator"); } void GeneratorOption::doParse(const QString &representation, QStringList &input) { m_generatorName = getArgument(representation, input); if (m_generatorName.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': No generator given.\nUsage: %2") .arg(representation, description(command()))); } } static QString loglevelLongRepresentation() { return QStringLiteral("--log-level"); } QString VerboseOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tBe more verbose. Increases the log level by one.\n" "\tThis option can be given more than once.\n" "\tExcessive occurrences have no effect.\n" "\tIf option '%3' appears anywhere on the command line in addition\n" "\tto this option, its value is taken as the base which to increase.\n") .arg(longRepresentation(), shortRepresentation(), loglevelLongRepresentation()); } QString VerboseOption::shortRepresentation() const { return QStringLiteral("-v"); } QString VerboseOption::longRepresentation() const { return QStringLiteral("--more-verbose"); } QString QuietOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tBe more quiet. Decreases the log level by one.\n" "\tThis option can be given more than once.\n" "\tExcessive occurrences have no effect.\n" "\tIf option '%3' appears anywhere on the command line in addition\n" "\tto this option, its value is taken as the base which to decrease.\n") .arg(longRepresentation(), shortRepresentation(), loglevelLongRepresentation()); } QString QuietOption::shortRepresentation() const { return QStringLiteral("-q"); } QString QuietOption::longRepresentation() const { return QStringLiteral("--less-verbose"); } QString JobsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tUse concurrent build jobs. must be an integer greater than zero.\n" "\tThe default is the number of cores.\n") .arg(longRepresentation(), shortRepresentation()); } QString JobsOption::shortRepresentation() const { return QStringLiteral("-j"); } QString JobsOption::longRepresentation() const { return QStringLiteral("--jobs"); } void JobsOption::doParse(const QString &representation, QStringList &input) { const QString jobCountString = getArgument(representation, input); bool stringOk; m_jobCount = jobCountString.toInt(&stringOk); if (!stringOk || m_jobCount <= 0) throw ErrorInfo(Tr::tr("Invalid use of option '%1': Illegal job count '%2'.\nUsage: %3") .arg(representation, jobCountString, description(command()))); } QString KeepGoingOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tKeep going when errors occur (if at all possible).\n") .arg(longRepresentation(), shortRepresentation()); } QString KeepGoingOption::shortRepresentation() const { return QStringLiteral("-k"); } QString KeepGoingOption::longRepresentation() const { return QStringLiteral("--keep-going"); } QString DryRunOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tDry run. No commands will be executed and no permanent changes to the\n" "\tbuild graph will be done.\n") .arg(longRepresentation(), shortRepresentation()); } QString DryRunOption::shortRepresentation() const { return QStringLiteral("-n"); } QString DryRunOption::longRepresentation() const { return QStringLiteral("--dry-run"); } QString ForceProbesOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n" "\tForce re-execution of all Probe items' configure scripts, rather than using the\n" "\tcached data.\n") .arg(longRepresentation()); } QString ForceProbesOption::longRepresentation() const { return QStringLiteral("--force-probe-execution"); } QString NoInstallOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n" "\tDo not install any artifacts as part of the build process.\n") .arg(longRepresentation()); } QString NoInstallOption::longRepresentation() const { return QStringLiteral("--no-install"); } static QString logTimeRepresentation() { return QStringLiteral("--log-time"); } QString ShowProgressOption::description(CommandType command) const { Q_UNUSED(command); QString desc = Tr::tr("%1\n" "\tShow a progress bar. Implies '%2=%3'.\n").arg(longRepresentation(), loglevelLongRepresentation(), logLevelName(LoggerMinLevel)); return desc += Tr::tr("\tThis option is mutually exclusive with '%1'.\n") .arg(logTimeRepresentation()); } static QString showProgressRepresentation() { return QStringLiteral("--show-progress"); } QString ShowProgressOption::longRepresentation() const { return showProgressRepresentation(); } void StringListOption::doParse(const QString &representation, QStringList &input) { m_arguments = getArgument(representation, input).split(QLatin1Char(',')); if (m_arguments.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': Argument list must not be empty.\n" "Usage: %2").arg(representation, description(command()))); } for (const QString &element : std::as_const(m_arguments)) { if (element.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': Argument list must not contain " "empty elements.\nUsage: %2") .arg(representation, description(command()))); } } } QString ChangedFilesOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 [,...]\n" "\tAssume these and only these files have changed.\n").arg(longRepresentation()); } QString ChangedFilesOption::longRepresentation() const { return QStringLiteral("--changed-files"); } QString ProductsOption::description(CommandType command) const { const QString prefix = Tr::tr("%1|%2").arg(longRepresentation(), shortRepresentation()); switch (command) { case InstallCommandType: case RunCommandType: case ShellCommandType: return Tr::tr("%1 \n\tUse the specified product.\n").arg(prefix); default: return Tr::tr("%1 [,...]\n" "\tTake only the specified products into account.\n").arg(prefix); } } QString ProductsOption::shortRepresentation() const { return QStringLiteral("-p"); } QString ProductsOption::longRepresentation() const { return QStringLiteral("--products"); } static QStringList allLogLevelStrings() { QStringList result; for (int i = static_cast(LoggerMinLevel); i <= static_cast(LoggerMaxLevel); ++i) result << logLevelName(static_cast(i)); return result; } LogLevelOption::LogLevelOption() : m_logLevel(defaultLogLevel()) { } QString LogLevelOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tUse the specified log level.\n" "\tPossible values are '%2'.\n" "\tThe default is '%3'.\n").arg(longRepresentation(), allLogLevelStrings().join(QLatin1String("', '")), logLevelName(defaultLogLevel())); } QString LogLevelOption::longRepresentation() const { return loglevelLongRepresentation(); } void LogLevelOption::doParse(const QString &representation, QStringList &input) { const QString levelString = getArgument(representation, input); const QList levels = QList() << LoggerError << LoggerWarning << LoggerInfo << LoggerDebug << LoggerTrace; for (const LoggerLevel &l : levels) { if (logLevelName(l) == levelString) { m_logLevel = l; return; } } throw ErrorInfo(Tr::tr("Invalid use of option '%1': Unknown log level '%2'.\nUsage: %3") .arg(representation, levelString, description(command()))); } QString ForceTimeStampCheckOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tForce timestamp checks.\n" "\tInstead of using the file timestamps that are stored in the build graph,\n" "\tretrieve the timestamps from the file system.\n").arg(longRepresentation()); } QString ForceTimeStampCheckOption::longRepresentation() const { return QStringLiteral("--check-timestamps"); } QString ForceOutputCheckOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tForce transformer output artifact checks.\n" "\tVerify that the output artifacts declared by rules in the\n" "\tproject are actually created.\n").arg(longRepresentation()); } QString ForceOutputCheckOption::longRepresentation() const { return QStringLiteral("--check-outputs"); } QString BuildNonDefaultOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tBuild all products, even if their builtByDefault property is false.\n") .arg(longRepresentation()); } QString BuildNonDefaultOption::longRepresentation() const { return QStringLiteral("--all-products"); } InstallRootOption::InstallRootOption() : m_useSysroot(false) { } static QString magicSysrootString() { return QStringLiteral("@sysroot"); } QString InstallRootOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tInstall into the given directory.\n" "\tThe default value is '/%2'.\n" "\tIf the directory does not exist, it will be created. Use the special\n" "\tvalue '%3' to install into the sysroot (i.e. the value of the\n" "\tproperty qbs.sysroot).\n") .arg(longRepresentation(), InstallOptions::defaultInstallRoot(), magicSysrootString()); } QString InstallRootOption::longRepresentation() const { return QStringLiteral("--install-root"); } void InstallRootOption::doParse(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: Argument expected.\n" "Usage: %2").arg(representation, description(command()))); } const QString installRoot = input.takeFirst(); if (installRoot == magicSysrootString()) m_useSysroot = true; else m_installRoot = installRoot; } QString RemoveFirstOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tRemove the installation base directory before installing.\n") .arg(longRepresentation()); } QString RemoveFirstOption::longRepresentation() const { return QStringLiteral("--clean-install-root"); } QString NoBuildOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tDo not build before installing.\n") .arg(longRepresentation()); } QString NoBuildOption::longRepresentation() const { return QStringLiteral("--no-build"); } QString LogTimeOption::description(CommandType command) const { Q_UNUSED(command); QString desc = Tr::tr("%1\n\tLog the time that the operations involved in this command take.\n") .arg(longRepresentation()); desc += Tr::tr("\tThis option is implied in log levels '%1' and higher.\n") .arg(logLevelName(LoggerDebug)); return desc += Tr::tr("\tThis option is mutually exclusive with '%1'.\n") .arg(showProgressRepresentation()); } QString LogTimeOption::shortRepresentation() const { return QStringLiteral("-t"); } QString LogTimeOption::longRepresentation() const { return logTimeRepresentation(); } SettingsDirOption::SettingsDirOption() = default; QString SettingsDirOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tRead all settings (such as profile information) from the given directory.\n" "\tThe default value is system-specific (see the QSettings documentation).\n" "\tIf the directory does not exist, it will be created.\n") .arg(longRepresentation()); } QString SettingsDirOption::longRepresentation() const { return QStringLiteral("--settings-dir"); } void SettingsDirOption::doParse(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: Argument expected.\n" "Usage: %2").arg(representation, description(command()))); } m_settingsDir = input.takeFirst(); } QString JobLimitsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 :[,:...]\n" "\tSet pool-specific job limits.\n").arg(longRepresentation()); } QString JobLimitsOption::longRepresentation() const { return QStringLiteral("--job-limits"); } void JobLimitsOption::doParse(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: Argument expected.\n" "Usage: %2").arg(representation, description(command()))); } const QString jobLimitsSpec = input.takeFirst(); const QStringList jobLimitStrings = jobLimitsSpec.split(QLatin1Char(',')); for (const QString &jobLimitString : jobLimitStrings) { const int sepIndex = jobLimitString.indexOf(QLatin1Char(':')); if (sepIndex <= 0 || sepIndex == jobLimitString.size() - 1) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: " "Invalid job limits specification '%2'.\n" "Usage: %3").arg(representation, jobLimitsSpec, description(command()))); } const QString pool = jobLimitString.left(sepIndex); const QString limitString = jobLimitString.mid(sepIndex + 1); bool isValidNumber; const int limit = limitString.toInt(&isValidNumber); if (!isValidNumber) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: '%2' is not a number.\n" "Usage: %3").arg(representation, limitString, description(command()))); } m_jobLimits.setJobLimit(pool, limit); } } QString RespectProjectJobLimitsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tGive maximum priority to job limits defined inside the project.\n") .arg(longRepresentation()); } QString RespectProjectJobLimitsOption::longRepresentation() const { return QStringLiteral("--enforce-project-job-limits"); } CommandEchoModeOption::CommandEchoModeOption() = default; QString CommandEchoModeOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tKind of output to show when executing commands.\n" "\tPossible values are '%2'.\n" "\tThe default is '%3'.\n") .arg(longRepresentation(), allCommandEchoModeStrings().join(QLatin1String("', '")), commandEchoModeName(defaultCommandEchoMode())); } QString CommandEchoModeOption::longRepresentation() const { return QStringLiteral("--command-echo-mode"); } CommandEchoMode CommandEchoModeOption::commandEchoMode() const { return m_echoMode; } void CommandEchoModeOption::doParse(const QString &representation, QStringList &input) { const QString mode = getArgument(representation, input); if (mode.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': No command echo mode given.\nUsage: %2") .arg(representation, description(command()))); } if (!allCommandEchoModeStrings().contains(mode)) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': " "Invalid command echo mode '%2' given.\nUsage: %3") .arg(representation, mode, description(command()))); } m_echoMode = commandEchoModeFromName(mode); } QString DeprecationWarningsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tWhat to do when encountering deprecated items or properties.\n" "\tPossible values are '%2'.\n" "\tThe default is '%3'.\n") .arg(longRepresentation(), allDeprecationWarningModeStrings().join(QLatin1String("', '")), deprecationWarningModeName(defaultDeprecationWarningMode())); } QString DeprecationWarningsOption::longRepresentation() const { return QStringLiteral("--deprecation-warnings"); } void DeprecationWarningsOption::doParse(const QString &representation, QStringList &input) { const QString mode = getArgument(representation, input); if (mode.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': No deprecation warning mode given.\n" "Usage: %2") .arg(representation, description(command()))); } if (!allDeprecationWarningModeStrings().contains(mode)) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': " "Invalid deprecation warning mode '%2' given.\nUsage: %3") .arg(representation, mode, description(command()))); } m_mode = deprecationWarningModeFromName(mode); } QString WaitLockOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tWait indefinitely for other processes to release the build graph lock.\n") .arg(longRepresentation()); } QString WaitLockOption::longRepresentation() const { return QStringLiteral("--wait-lock"); } QString RunEnvConfigOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tComma-separated list of strings to pass to all modules' " "setupRunEnvironment scripts.\n").arg(longRepresentation()); } QString RunEnvConfigOption::longRepresentation() const { return QStringLiteral("--setup-run-env-config"); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/parser/commandlineparser.h0000644000175100001660000000713014776170045021755 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_COMMANDLINEPARSER_H #define QBS_COMMANDLINEPARSER_H #include "commandtype.h" #include #include #include #include namespace qbs { class BuildOptions; class CleanOptions; class GenerateOptions; class InstallOptions; class Settings; class CommandLineParser { Q_DISABLE_COPY(CommandLineParser) public: CommandLineParser(); ~CommandLineParser(); bool parseCommandLine(const QStringList &args); void printHelp() const; CommandType command() const; QString commandName() const; bool commandCanResolve() const; QString commandDescription() const; QString projectFilePath() const; QString projectBuildDirectory() const; BuildOptions buildOptions(const QString &profile) const; CleanOptions cleanOptions(const QString &profile) const; GenerateOptions generateOptions() const; InstallOptions installOptions(const QString &profile) const; int jobCount(const QString &profile) const; bool forceTimestampCheck() const; bool forceOutputCheck() const; bool dryRun() const; bool forceProbesExecution() const; bool waitLockBuildGraph() const; bool logTime() const; bool withNonDefaultProducts() const; bool buildBeforeInstalling() const; QStringList runArgs() const; QStringList products() const; QStringList runEnvConfig() const; QList buildConfigurations() const; bool showProgress() const; bool showVersion() const; QString settingsDir() const; DeprecationWarningMode deprecationWarningMode() const; private: class CommandLineParserPrivate; std::unique_ptr d; }; } // namespace qbs #endif // QBS_COMMANDLINEPARSER_H qbs-src-2.6.1/src/app/qbs/parser/commandlineoption.h0000644000175100001660000003145314776170045021776 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_COMMANDLINEOPTION_H #define QBS_COMMANDLINEOPTION_H #include "commandtype.h" #include #include #include #include namespace qbs { class CommandLineOption { public: enum Type { FileOptionType, BuildDirectoryOptionType, LogLevelOptionType, VerboseOptionType, QuietOptionType, JobsOptionType, KeepGoingOptionType, DryRunOptionType, ForceProbesOptionType, ShowProgressOptionType, ChangedFilesOptionType, ProductsOptionType, NoInstallOptionType, InstallRootOptionType, RemoveFirstOptionType, NoBuildOptionType, ForceTimestampCheckOptionType, ForceOutputCheckOptionType, BuildNonDefaultOptionType, LogTimeOptionType, CommandEchoModeOptionType, SettingsDirOptionType, JobLimitsOptionType, RespectProjectJobLimitsOptionType, GeneratorOptionType, WaitLockOptionType, RunEnvConfigOptionType, DeprecationWarningsOptionType, }; virtual ~CommandLineOption(); virtual QString description(CommandType command) const = 0; virtual QString shortRepresentation() const = 0; virtual QString longRepresentation() const = 0; virtual bool canAppearMoreThanOnce() const { return false; } void parse(CommandType command, const QString &representation, QStringList &input); protected: CommandLineOption(); QString getArgument(const QString &representation, QStringList &input); CommandType command() const { return m_command; } private: virtual void doParse(const QString &representation, QStringList &input) = 0; CommandType m_command; }; class FileOption : public CommandLineOption { public: QString projectFilePath() const { return m_projectFilePath; } private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; private: QString m_projectFilePath; }; class BuildDirectoryOption : public CommandLineOption { public: QString projectBuildDirectory() const { return m_projectBuildDirectory; } static QString magicProjectString(); static QString magicProjectDirString(); private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; private: QString m_projectBuildDirectory; }; class GeneratorOption : public CommandLineOption { public: QString generatorName() const { return m_generatorName; } private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; private: QString m_generatorName; }; class CountingOption : public CommandLineOption { public: int count() const { return m_count; } protected: CountingOption() : m_count(0) {} private: bool canAppearMoreThanOnce() const override{ return true; } void doParse(const QString &, QStringList &) override { ++m_count; } int m_count; }; class VerboseOption : public CountingOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class QuietOption : public CountingOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class JobsOption : public CommandLineOption { public: JobsOption() : m_jobCount(0) {} int jobCount() const { return m_jobCount; } private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; int m_jobCount; }; class OnOffOption : public CommandLineOption { public: bool enabled() const { return m_enabled; } protected: OnOffOption() : m_enabled(false) {} private: void doParse(const QString &, QStringList &) override { m_enabled = true; } bool m_enabled; }; class KeepGoingOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class DryRunOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class ForceProbesOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class NoInstallOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ShowProgressOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ForceTimeStampCheckOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ForceOutputCheckOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class BuildNonDefaultOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class StringListOption : public CommandLineOption { public: QStringList arguments() const { return m_arguments; } private: void doParse(const QString &representation, QStringList &input) override; QStringList m_arguments; }; class ChangedFilesOption : public StringListOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ProductsOption : public StringListOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class RunEnvConfigOption : public StringListOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class LogLevelOption : public CommandLineOption { public: LogLevelOption(); int logLevel() const { return m_logLevel; } private: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; int m_logLevel; }; class InstallRootOption : public CommandLineOption { public: InstallRootOption(); QString installRoot() const { return m_installRoot; } bool useSysroot() const { return m_useSysroot; } QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; private: void doParse(const QString &representation, QStringList &input) override; QString m_installRoot; bool m_useSysroot; }; class RemoveFirstOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class NoBuildOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class LogTimeOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class CommandEchoModeOption : public CommandLineOption { public: CommandEchoModeOption(); QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; CommandEchoMode commandEchoMode() const; private: void doParse(const QString &representation, QStringList &input) override; CommandEchoMode m_echoMode = CommandEchoModeInvalid; }; class DeprecationWarningsOption : public CommandLineOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; DeprecationWarningMode mode() const { return m_mode; } private: void doParse(const QString &representation, QStringList &input) override; DeprecationWarningMode m_mode = defaultDeprecationWarningMode(); }; class SettingsDirOption : public CommandLineOption { public: SettingsDirOption(); QString settingsDir() const { return m_settingsDir; } QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; private: void doParse(const QString &representation, QStringList &input) override; QString m_settingsDir; }; class JobLimitsOption : public CommandLineOption { public: JobLimits jobLimits() const { return m_jobLimits; } QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; private: void doParse(const QString &representation, QStringList &input) override; JobLimits m_jobLimits; }; class RespectProjectJobLimitsOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class WaitLockOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; } // namespace qbs #endif // QBS_COMMANDLINEOPTION_H qbs-src-2.6.1/src/app/qbs/parser/commandtype.h0000644000175100001660000000442014776170045020571 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef COMMANDTYPE_H #define COMMANDTYPE_H namespace qbs { enum CommandType { ResolveCommandType, BuildCommandType, CleanCommandType, RunCommandType, ShellCommandType, StatusCommandType, UpdateTimestampsCommandType, DumpNodesTreeCommandType, InstallCommandType, HelpCommandType, GenerateCommandType, ListProductsCommandType, VersionCommandType, SessionCommandType, }; } // namespace qbs #endif // COMMANDTYPE_H qbs-src-2.6.1/src/app/qbs/parser/commandpool.cpp0000644000175100001660000000740714776170045021124 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandpool.h" #include "parsercommand.h" namespace qbs { CommandPool::CommandPool(CommandLineOptionPool &optionPool) : m_optionPool(optionPool) { } CommandPool::~CommandPool() { qDeleteAll(m_commands); } qbs::Command *CommandPool::getCommand(CommandType type) const { Command *& command = m_commands[type]; if (!command) { switch (type) { case ResolveCommandType: command = new ResolveCommand(m_optionPool); break; case GenerateCommandType: command = new GenerateCommand(m_optionPool); break; case BuildCommandType: command = new BuildCommand(m_optionPool); break; case CleanCommandType: command = new CleanCommand(m_optionPool); break; case RunCommandType: command = new RunCommand(m_optionPool); break; case ShellCommandType: command = new ShellCommand(m_optionPool); break; case StatusCommandType: command = new StatusCommand(m_optionPool); break; case UpdateTimestampsCommandType: command = new UpdateTimestampsCommand(m_optionPool); break; case InstallCommandType: command = new InstallCommand(m_optionPool); break; case DumpNodesTreeCommandType: command = new DumpNodesTreeCommand(m_optionPool); break; case ListProductsCommandType: command = new ListProductsCommand(m_optionPool); break; case HelpCommandType: command = new HelpCommand(m_optionPool); break; case VersionCommandType: command = new VersionCommand(m_optionPool); break; case SessionCommandType: command = new SessionCommand(m_optionPool); break; } } return command; } } // namespace qbs qbs-src-2.6.1/src/app/qbs/parser/parsercommand.cpp0000644000175100001660000005073514776170045021451 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "parsercommand.h" #include "commandlineoption.h" #include "commandlineoptionpool.h" #include #include #include #include #include #include #include namespace qbs { using namespace Internal; Command::~Command() = default; void Command::parse(QStringList &input) { while (!input.empty()) parseNext(input); } bool Command::canResolve() const { return supportedOptions().contains(CommandLineOption::FileOptionType); } void Command::parsePropertyAssignment(const QString &argument) { const auto throwError = [argument](const QString &msgTemplate) { ErrorInfo error(msgTemplate.arg(argument)); error.append(QLatin1String("Expected an assignment of the form :, " "profile: or config:.")); throw error; }; if (argument.startsWith(QLatin1Char('-'))) throwError(Tr::tr("Unexpected option '%1'.")); const int sepPos = argument.indexOf(QLatin1Char(':')); if (sepPos == -1) throwError(Tr::tr("Unexpected command line parameter '%1'.")); if (sepPos == 0) throwError(Tr::tr("Empty key not allowed in assignment '%1'.")); if (!canResolve() && argument.contains(QLatin1Char(':')) && !argument.startsWith(QLatin1String("config:"))) { throw ErrorInfo(Tr::tr("The '%1' command does not support property assignments.") .arg(representation())); } m_additionalArguments << argument; } QList Command::actualSupportedOptions() const { QList options = supportedOptions(); if (type() != HelpCommandType) options.push_back(CommandLineOption::SettingsDirOptionType); // Valid for almost all commands. return options; } void Command::parseOption(QStringList &input) { const QString optionString = input.front(); QBS_CHECK(optionString.startsWith(QLatin1Char('-'))); input.removeFirst(); if (optionString.size() == 1) throwError(Tr::tr("Empty options are not allowed.")); // Split up grouped short options. if (optionString.at(1) != QLatin1Char('-') && optionString.size() > 2) { QString parameter; for (int i = optionString.size(); --i > 0;) { const QChar c = optionString.at(i); if (c.isDigit()) { parameter.prepend(c); } else { if (!parameter.isEmpty()) { input.prepend(parameter); parameter.clear(); } input.prepend(QLatin1Char('-') + c); } } if (!parameter.isEmpty()) throwError(Tr::tr("Unknown numeric option '%1'.").arg(parameter)); return; } bool matchFound = false; const auto optionTypes = actualSupportedOptions(); for (const CommandLineOption::Type optionType : optionTypes) { CommandLineOption * const option = optionPool().getOption(optionType); if (option->shortRepresentation() != optionString && option->longRepresentation() != optionString) { continue; } if (contains(m_usedOptions, option) && !option->canAppearMoreThanOnce()) throwError(Tr::tr("Option '%1' cannot appear more than once.").arg(optionString)); option->parse(type(), optionString, input); m_usedOptions.insert(option); matchFound = true; break; } if (!matchFound) throwError(Tr::tr("Unknown option '%1'.").arg(optionString)); } void Command::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); if (input.front().startsWith(QLatin1Char('-'))) parseOption(input); else parsePropertyAssignment(input.takeFirst()); } QString Command::supportedOptionsDescription() const { // Sorting the options by name is nicer for the user. QMap optionMap; const auto opTypes = actualSupportedOptions(); for (const CommandLineOption::Type opType : opTypes) { const CommandLineOption * const option = optionPool().getOption(opType); optionMap.insert(option->longRepresentation(), option); } QString s = Tr::tr("The possible options are:\n"); for (const CommandLineOption *option : std::as_const(optionMap)) s += option->description(type()); return s; } void Command::throwError(const QString &reason) { ErrorInfo error(Tr::tr("Invalid use of command '%1': %2").arg(representation(), reason)); error.append(Tr::tr("Type 'qbs help %1' to see how to use this command.") .arg(representation())); throw error; } QString ResolveCommand::shortDescription() const { return Tr::tr("Resolve a project without building it."); } QString ResolveCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...] ...\n") .arg(representation()); description += Tr::tr("Resolves a project in one or more configuration(s).\n"); return description += supportedOptionsDescription(); } QString ResolveCommand::representation() const { return QStringLiteral("resolve"); } static QList resolveOptions() { return { CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType, CommandLineOption::LogLevelOptionType, CommandLineOption::VerboseOptionType, CommandLineOption::QuietOptionType, CommandLineOption::ShowProgressOptionType, CommandLineOption::DryRunOptionType, CommandLineOption::ForceProbesOptionType, CommandLineOption::LogTimeOptionType, CommandLineOption::DeprecationWarningsOptionType, CommandLineOption::JobsOptionType}; } QList ResolveCommand::supportedOptions() const { return resolveOptions(); } QString GenerateCommand::shortDescription() const { return Tr::tr("Generate project files for another build tool."); } QString GenerateCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...] ...\n") .arg(representation()); description += Tr::tr("Generates files to build the project using another build tool.\n"); return description += supportedOptionsDescription(); } QString GenerateCommand::representation() const { return QStringLiteral("generate"); } QList GenerateCommand::supportedOptions() const { return {CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType, CommandLineOption::LogLevelOptionType, CommandLineOption::VerboseOptionType, CommandLineOption::QuietOptionType, CommandLineOption::ShowProgressOptionType, CommandLineOption::InstallRootOptionType, CommandLineOption::LogTimeOptionType, CommandLineOption::GeneratorOptionType}; } QString BuildCommand::shortDescription() const { return Tr::tr("Build (parts of) a project. This is the default command."); } QString BuildCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...] ...\n") .arg(representation()); description += Tr::tr("Builds a project in one or more configuration(s).\n"); return description += supportedOptionsDescription(); } static QString buildCommandRepresentation() { return QStringLiteral("build"); } QString BuildCommand::representation() const { return buildCommandRepresentation(); } static QList buildOptions() { QList options = resolveOptions(); return options << CommandLineOption::KeepGoingOptionType << CommandLineOption::ProductsOptionType << CommandLineOption::ChangedFilesOptionType << CommandLineOption::ForceTimestampCheckOptionType << CommandLineOption::ForceOutputCheckOptionType << CommandLineOption::BuildNonDefaultOptionType << CommandLineOption::CommandEchoModeOptionType << CommandLineOption::NoInstallOptionType << CommandLineOption::RemoveFirstOptionType << CommandLineOption::JobLimitsOptionType << CommandLineOption::RespectProjectJobLimitsOptionType << CommandLineOption::WaitLockOptionType; } QList BuildCommand::supportedOptions() const { return buildOptions(); } QString CleanCommand::shortDescription() const { return Tr::tr("Remove the files generated during a build."); } QString CleanCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] ...\n") .arg(representation()); description += Tr::tr("Removes build artifacts for the given configuration(s).\n"); return description += supportedOptionsDescription(); } QString CleanCommand::representation() const { return QStringLiteral("clean"); } QList CleanCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType, CommandLineOption::DryRunOptionType, CommandLineOption::KeepGoingOptionType, CommandLineOption::LogTimeOptionType, CommandLineOption::ProductsOptionType, CommandLineOption::QuietOptionType, CommandLineOption::SettingsDirOptionType, CommandLineOption::ShowProgressOptionType, CommandLineOption::VerboseOptionType}; } QString InstallCommand::shortDescription() const { return Tr::tr("Install (parts of) a project."); } QString InstallCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...]\n") .arg(representation()); description += Tr::tr("Install all files marked as installable " "to their respective destinations.\n" "The project is built first, if necessary, unless the '%1' option " "is given.\n").arg(optionPool().noBuildOption()->longRepresentation()); return description += supportedOptionsDescription(); } QString InstallCommand::representation() const { return QStringLiteral("install"); } QList installOptions() { QList options = buildOptions() << CommandLineOption::InstallRootOptionType << CommandLineOption::NoBuildOptionType; options.removeOne(CommandLineOption::NoInstallOptionType); return options; } QList InstallCommand::supportedOptions() const { return installOptions(); } QString RunCommand::shortDescription() const { return QStringLiteral("Run an executable generated by building a project."); } QString RunCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] [:] ... " "[ -- ]\n").arg(representation()); description += Tr::tr("Run the specified product's executable with the specified arguments.\n"); description += Tr::tr("If the project has only one product, the '%1' option may be omitted.\n") .arg(optionPool().productsOption()->longRepresentation()); description += Tr::tr("The product will be built if it is not up to date; " "see the '%2' command.\n").arg(buildCommandRepresentation()); return description += supportedOptionsDescription(); } QString RunCommand::representation() const { return QStringLiteral("run"); } QList RunCommand::supportedOptions() const { return QList() << installOptions() << CommandLineOption::RunEnvConfigOptionType; } void RunCommand::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); if (input.front() != QLatin1String("--")) { Command::parseNext(input); return; } input.removeFirst(); m_targetParameters = input; input.clear(); } QString ShellCommand::shortDescription() const { return Tr::tr("Open a shell with a product's environment."); } QString ShellCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] [:] ...\n") .arg(representation()); description += Tr::tr("Opens a shell in the same environment that a build with the given " "parameters would use.\n"); return description += supportedOptionsDescription(); } QString ShellCommand::representation() const { return QStringLiteral("shell"); } QList ShellCommand::supportedOptions() const { return {CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType, CommandLineOption::ProductsOptionType}; } QString StatusCommand::shortDescription() const { return Tr::tr("Show the status of files in the project directory."); } QString StatusCommand::longDescription() const { QString description = Tr::tr("qbs %1 [options] [config:]\n") .arg(representation()); description += Tr::tr("Lists all the files in the project directory and shows whether " "they are known to qbs in the respective configuration.\n"); return description += supportedOptionsDescription(); } QString StatusCommand::representation() const { return QStringLiteral("status"); } QList StatusCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType}; } QString UpdateTimestampsCommand::shortDescription() const { return Tr::tr("Mark the build as up to date."); } QString UpdateTimestampsCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] ...\n") .arg(representation()); description += Tr::tr("Update the timestamps of all build artifacts, causing the next " "builds of the project to do nothing if no updates to source files happen in between.\n" "This functionality is useful if you know that the current changes to source files " "are irrelevant to the build.\n" "NOTE: Doing this causes a discrepancy between the \"real world\" and the information " "in the build graph, so use with care.\n"); return description += supportedOptionsDescription(); } QString UpdateTimestampsCommand::representation() const { return QStringLiteral("update-timestamps"); } QList UpdateTimestampsCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType, CommandLineOption::LogLevelOptionType, CommandLineOption::VerboseOptionType, CommandLineOption::QuietOptionType, CommandLineOption::ProductsOptionType}; } QString DumpNodesTreeCommand::shortDescription() const { return Tr::tr("Dumps the nodes in the build graph to stdout."); } QString DumpNodesTreeCommand::longDescription() const { QString description = Tr::tr("qbs %1 [options] [config:] ...\n") .arg(representation()); description += Tr::tr("Internal command; for debugging purposes only.\n"); return description += supportedOptionsDescription(); } QString DumpNodesTreeCommand::representation() const { return QStringLiteral("dump-nodes-tree"); } QList DumpNodesTreeCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType, CommandLineOption::ProductsOptionType}; } QString ListProductsCommand::shortDescription() const { return Tr::tr("Lists all products in the project, including sub-projects."); } QString ListProductsCommand::longDescription() const { QString description = Tr::tr("qbs %1 [options] [[config:] " "[:] ...] ...\n").arg(representation()); return description += supportedOptionsDescription(); } QString ListProductsCommand::representation() const { return QStringLiteral("list-products"); } QList ListProductsCommand::supportedOptions() const { return {CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType}; } QString HelpCommand::shortDescription() const { return Tr::tr("Show general or command-specific help."); } QString HelpCommand::longDescription() const { QString description = Tr::tr("qbs %1 []\n").arg(representation()); return description += Tr::tr("Shows either the general help or a description of " "the given command.\n"); } QString HelpCommand::representation() const { return QStringLiteral("help"); } QList HelpCommand::supportedOptions() const { return {}; } void HelpCommand::parseNext(QStringList &input) { if (input.empty()) return; if (input.size() > 1) throwError(Tr::tr("Cannot describe more than one command.")); m_command = input.takeFirst(); QBS_CHECK(input.empty()); } QString VersionCommand::shortDescription() const { return Tr::tr("Print the Qbs version number to stdout."); } QString VersionCommand::longDescription() const { QString description = Tr::tr("qbs %1\n").arg(representation()); return description += Tr::tr("%1\n").arg(shortDescription()); } QString VersionCommand::representation() const { return QStringLiteral("show-version"); } QList VersionCommand::supportedOptions() const { return {}; } void VersionCommand::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); throwError(Tr::tr("This command takes no arguments.")); } QString SessionCommand::shortDescription() const { return Tr::tr("Starts a session for an IDE."); } QString SessionCommand::longDescription() const { QString description = Tr::tr("qbs %1\n").arg(representation()); return description += Tr::tr("Communicates on stdin and stdout via a JSON-based API.\n" "Intended for use with other tools, such as IDEs.\n"); } QString SessionCommand::representation() const { return QLatin1String("session"); } void SessionCommand::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); throwError(Tr::tr("This command takes no arguments.")); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/commandlinefrontend.h0000644000175100001660000001070414776170045021005 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef COMMANDLINEFRONTEND_H #define COMMANDLINEFRONTEND_H #include "parser/commandlineparser.h" #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE namespace qbs { class AbstractJob; class ConsoleProgressObserver; class ErrorInfo; class ProcessResult; class ProjectGenerator; class Settings; class CommandLineFrontend : public QObject { Q_OBJECT public: explicit CommandLineFrontend(const CommandLineParser &parser, Settings *settings, QObject *parent = nullptr); ~CommandLineFrontend() override; void cancel(); void start(); private: void handleCommandDescriptionReport(const QString &highlight, const QString &message); void handleJobFinished(bool success, qbs::AbstractJob *job); void handleNewTaskStarted(const QString &description, int totalEffort); void handleTotalEffortChanged(int totalEffort); void handleTaskProgress(int value, qbs::AbstractJob *job); void handleProcessResultReport(const qbs::ProcessResult &result); void checkCancelStatus(); using ProductMap = QHash>; ProductMap productsToUse() const; bool resolvingMultipleProjects() const; bool isResolving() const; bool isBuilding() const; void handleProjectsResolved(); void makeClean(); int runShell(); void build(); void checkGeneratorName(); void generate(); int runTarget(); void updateTimestamps(); void dumpNodesTree(); void listProducts(); void connectBuildJobs(); void connectBuildJob(AbstractJob *job); void connectJob(AbstractJob *job); ProductData getTheOneRunnableProduct(); void install(); BuildOptions buildOptions(const Project &project) const; QString buildDirectory(const QString &profileName) const; const CommandLineParser &m_parser; Settings * const m_settings; QList m_resolveJobs; QList m_buildJobs; QList m_projects; ConsoleProgressObserver *m_observer = nullptr; enum CancelStatus { CancelStatusNone, CancelStatusRequested, CancelStatusCanceling }; CancelStatus m_cancelStatus = CancelStatus::CancelStatusNone; QTimer * const m_cancelTimer; int m_buildEffortsNeeded = 0; int m_buildEffortsRetrieved = 0; int m_totalBuildEffort = 0; int m_currentBuildEffort = 0; QHash m_buildEfforts; std::shared_ptr m_generator; }; } // namespace qbs #endif // COMMANDLINEFRONTEND_H qbs-src-2.6.1/src/app/qbs/consoleprogressobserver.cpp0000644000175100001660000001007414776170045022311 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "consoleprogressobserver.h" #include #include #include namespace qbs { void ConsoleProgressObserver::initialize(const QString &task, int max) { m_maximum = max; m_value = 0; m_percentage = 0; m_hashesPrinted = 0; std::cout << task.toLocal8Bit().constData() << ": 0%" << std::flush; setMaximum(max); } void ConsoleProgressObserver::setMaximum(int maximum) { m_maximum = maximum; if (maximum == 0) { m_percentage = 100; updateProgressBarIfNecessary(); writePercentageString(); std::cout << std::endl; } } void ConsoleProgressObserver::setProgressValue(int value) { if (value > m_maximum || value <= m_value) return; // TODO: Should be an assertion, but the executor currently breaks it. m_value = value; const int newPercentage = (100 * m_value) / m_maximum; if (newPercentage == m_percentage) return; eraseCurrentPercentageString(); m_percentage = newPercentage; updateProgressBarIfNecessary(); writePercentageString(); if (m_value == m_maximum) std::cout << std::endl; else std::cout << std::flush; } void ConsoleProgressObserver::eraseCurrentPercentageString() { const int charsToErase = m_percentage == 0 ? 2 : m_percentage < 10 ? 3 : 4; const QByteArray backspaceCommand(charsToErase, '\b'); // Move cursor before the old percentage string. std::cout << backspaceCommand.constData(); // Erase old percentage string. std::cout << QByteArray(charsToErase, ' ').constData(); // Move cursor before the erased string. std::cout << backspaceCommand.constData(); } void ConsoleProgressObserver::updateProgressBarIfNecessary() { static const int TotalHashCount = 50; // Should fit on most terminals without a line break. const int hashesNeeded = (m_percentage * TotalHashCount) / 100; if (m_hashesPrinted < hashesNeeded) { std::cout << QByteArray(hashesNeeded - m_hashesPrinted, '#').constData(); m_hashesPrinted = hashesNeeded; } } void ConsoleProgressObserver::writePercentageString() { std::cout << QStringLiteral(" %1%").arg(m_percentage).toLocal8Bit().constData(); } } // namespace qbs qbs-src-2.6.1/src/app/qbs/sessionpacket.h0000644000175100001660000000472314776170045017636 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SESSIONPACKET_H #define QBS_SESSIONPACKET_H #include #include namespace qbs { namespace Internal { class SessionPacket { public: enum class Status { Incomplete, Complete, Invalid }; Status parseInput(QByteArray &input); QJsonObject retrievePacket(); static QByteArray createPacket(const QJsonObject &packet); static QJsonObject helloMessage(const QString &lspSocket); private: bool isComplete() const; QByteArray m_payload; int m_expectedPayloadLength = -1; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/app/config-ui/0000755000175100001660000000000014776170045015677 5ustar runnerdockerqbs-src-2.6.1/src/app/config-ui/Info.plist0000644000175100001660000000070614776170045017652 0ustar runnerdocker CFBundleIdentifier org.qt-project.qbs-config-ui CFBundleInfoDictionaryVersion 6.0 CFBundleName Qbs Settings LSUIElement 1 qbs-src-2.6.1/src/app/config-ui/mainwindow.ui0000644000175100001660000000151414776170045020413 0ustar runnerdocker MainWindow 0 0 800 600 Qbs Settings 0 0 800 27 qbs-src-2.6.1/src/app/config-ui/mainwindow.cpp0000644000175100001660000002163014776170045020561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #else #include #endif #include #include #include #include #include namespace { class TrimValidator : public QValidator { public: explicit TrimValidator(QObject *parent = nullptr) : QValidator(parent) {} // QValidator interface State validate(QString &input, int &pos) const override { Q_UNUSED(pos); if (input.startsWith(QLatin1Char(' ')) || input.endsWith(QLatin1Char(' '))) return State::Intermediate; return State::Acceptable; } void fixup(QString &input) const override { input = input.trimmed(); } }; class SettingsItemDelegate: public QStyledItemDelegate { public: explicit SettingsItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override { const auto editor = QStyledItemDelegate::createEditor(parent, option, index); const auto lineEdit = qobject_cast(editor); if (lineEdit) lineEdit->setValidator(new TrimValidator(lineEdit)); return editor; } }; } // namespace MainWindow::MainWindow(const QString &settingsDir, qbs::Settings::Scope scope, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); m_model = new qbs::SettingsModel(settingsDir, scope, this); ui->treeView->setModel(m_model); ui->treeView->setItemDelegate(new SettingsItemDelegate(ui->treeView)); ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->treeView, &QTreeView::expanded, this, &MainWindow::adjustColumns); connect(ui->treeView, &QWidget::customContextMenuRequested, this, &MainWindow::provideContextMenu); adjustColumns(); QMenu * const fileMenu = menuBar()->addMenu(tr("&File")); QMenu * const viewMenu = menuBar()->addMenu(tr("&View")); const auto reloadAction = new QAction(tr("&Reload"), this); reloadAction->setShortcut(QKeySequence::Refresh); connect(reloadAction, &QAction::triggered, this, &MainWindow::reloadSettings); const auto saveAction = new QAction(tr("&Save"), this); saveAction->setShortcut(QKeySequence::Save); connect(saveAction, &QAction::triggered, this, &MainWindow::saveSettings); const auto expandAllAction = new QAction(tr("&Expand All"), this); expandAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_E)); connect(expandAllAction, &QAction::triggered, this, &MainWindow::expandAll); const auto collapseAllAction = new QAction(tr("C&ollapse All"), this); collapseAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_O)); connect(collapseAllAction, &QAction::triggered, this, &MainWindow::collapseAll); const auto exitAction = new QAction(tr("E&xit"), this); exitAction->setShortcut(QKeySequence::Quit); exitAction->setMenuRole(QAction::QuitRole); connect(exitAction, &QAction::triggered, this, &MainWindow::exit); fileMenu->addAction(reloadAction); fileMenu->addAction(saveAction); fileMenu->addSeparator(); fileMenu->addAction(exitAction); viewMenu->addAction(expandAllAction); viewMenu->addAction(collapseAllAction); ui->treeView->installEventFilter(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::adjustColumns() { for (int column = 0; column < m_model->columnCount(); ++column) ui->treeView->resizeColumnToContents(column); } void MainWindow::expandAll() { ui->treeView->expandAll(); adjustColumns(); } void MainWindow::collapseAll() { ui->treeView->collapseAll(); adjustColumns(); } void MainWindow::reloadSettings() { if (m_model->hasUnsavedChanges()) { const QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Unsaved Changes"), tr("You have unsaved changes. Do you want to discard them?")); if (answer != QMessageBox::Yes) return; } m_model->reload(); } void MainWindow::saveSettings() { m_model->save(); } void MainWindow::exit() { if (m_model->hasUnsavedChanges()) { const QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Unsaved Changes"), tr("You have unsaved changes. Do you want to save them now?")); if (answer == QMessageBox::Yes) m_model->save(); } qApp->quit(); } void MainWindow::provideContextMenu(const QPoint &pos) { const QModelIndex index = ui->treeView->indexAt(pos); if (index.isValid() && index.column() != m_model->keyColumn()) return; const QString settingsKey = m_model->data(index).toString(); QMenu contextMenu; QAction addKeyAction(this); QAction removeKeyAction(this); if (index.isValid()) { addKeyAction.setText(tr("Add new key below '%1'").arg(settingsKey)); removeKeyAction.setText(tr("Remove key '%1' and all its sub-keys").arg(settingsKey)); contextMenu.addAction(&addKeyAction); contextMenu.addAction(&removeKeyAction); } else { addKeyAction.setText(tr("Add new top-level key")); contextMenu.addAction(&addKeyAction); } const QAction *action = contextMenu.exec(ui->treeView->mapToGlobal(pos)); if (action == &addKeyAction) m_model->addNewKey(index); else if (action == &removeKeyAction) m_model->removeKey(index); } extern "C" void qt_macos_forceTransformProcessToForegroundApplicationAndActivate(); bool MainWindow::eventFilter(QObject *watched, QEvent *event) { if (ui->treeView->hasFocus() && event->type() == QEvent::KeyPress) { const auto keyEvent = static_cast(event); if (keyEvent->matches(QKeySequence::Delete)) { const QModelIndexList indexes = ui->treeView->selectionModel()->selectedRows(); if (indexes.size() == 1) { const QModelIndex index = indexes.front(); if (index.isValid()) { m_model->removeKey(index); return true; } } } } if (event->type() == QEvent::WindowActivate) { // Effectively delay the foreground process transformation from QApplication construction to // when the UI is shown - this prevents the application icon from popping up in the Dock // when running `qbs help`, and QCoreApplication::arguments() requires the application // object to be constructed, so it is not easily worked around #if defined(Q_OS_MACOS) qt_macos_forceTransformProcessToForegroundApplicationAndActivate(); #endif } return QMainWindow::eventFilter(watched, event); } qbs-src-2.6.1/src/app/config-ui/commandlineparser.cpp0000644000175100001660000001047414776170045022114 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_settingsDir.clear(); if (m_commandLine.empty()) return; const QString &arg = m_commandLine.front(); if (arg == helpOptionShort() || arg == helpOptionLong()) { m_commandLine.removeFirst(); m_helpRequested = true; } else if (arg == systemOption()) { m_commandLine.removeFirst(); m_settingsScope = qbs::Settings::SystemScope; } else if (arg == settingsDirOption()) { m_commandLine.removeFirst(); assignOptionArgument(settingsDirOption(), m_settingsDir); } if (!m_commandLine.empty()) complainAboutExtraArguments(); } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool displays qbs settings in a GUI.\n" "If you have more than a few settings, this might be preferable to " "plain \"qbs config\", as it presents a hierarchical view.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%5] [%3|%4]\n") .arg(m_command, settingsDirOption(), helpOptionShort(), helpOptionLong(), systemOption()); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.6.1/src/app/config-ui/commandlineparser.h0000644000175100001660000000527514776170045021564 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_CONFIGUI_COMMANDLINEPARSER_H #define QBS_CONFIGUI_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Include guard qbs-src-2.6.1/src/app/config-ui/mainwindow.h0000644000175100001660000000520514776170045020226 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include namespace qbs { class SettingsModel; } QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } class QPoint; QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(const QString &settingsDir, qbs::Settings::Scope scope, QWidget *parent = nullptr); ~MainWindow() override; bool eventFilter(QObject *watched, QEvent *event) override; private: void adjustColumns(); void expandAll(); void collapseAll(); void reloadSettings(); void saveSettings(); void exit(); void provideContextMenu(const QPoint &pos); Ui::MainWindow *ui; qbs::SettingsModel *m_model; }; #endif // MAINWINDOW_H qbs-src-2.6.1/src/app/config-ui/fgapp.mm0000644000175100001660000000426114776170045017332 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import #include extern "C" void qt_macos_forceTransformProcessToForegroundApplicationAndActivate() { [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; } qbs-src-2.6.1/src/app/config-ui/main.cpp0000644000175100001660000000507014776170045017331 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mainwindow.h" #include "commandlineparser.h" #include #include #include #include #include int main(int argc, char *argv[]) { QApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(app.arguments()); if (clParser.helpRequested()) { std::cout << qPrintable(clParser.usageString()); return EXIT_SUCCESS; } } catch (const qbs::ErrorInfo &error) { std::cerr << qPrintable(error.toString()); return EXIT_FAILURE; } MainWindow mw(clParser.settingsDir(), clParser.settingsScope()); mw.show(); return app.exec(); } qbs-src-2.6.1/src/app/config-ui/CMakeLists.txt0000644000175100001660000000070414776170045020440 0ustar runnerdockerset(SOURCES commandlineparser.cpp commandlineparser.h main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) # TODO: support Info.plist if(APPLE) set(MACOS_SOURCES fgapp.mm) set(MACOS_FRAMEWORKS "-framework ApplicationServices" "-framework Cocoa") endif() add_qbs_app(qbs-config-ui DEPENDS qbscore qbsconsolelogger Qt${QT_VERSION_MAJOR}::Widgets ${MACOS_FRAMEWORKS} SOURCES ${SOURCES} ${MACOS_SOURCES} ) qbs-src-2.6.1/src/app/config-ui/config-ui.qbs0000644000175100001660000000126514776170045020272 0ustar runnerdockerQbsApp { Depends { name: "Qt.widgets" } name: "qbs-config-ui" consoleApplication: false files: [ "commandlineparser.cpp", "commandlineparser.h", "main.cpp", "mainwindow.cpp", "mainwindow.h", "mainwindow.ui", ] Group { condition: qbs.targetOS.contains("macos") files: [ "fgapp.mm", "Info.plist" ] } Properties { condition: qbs.targetOS.contains("macos") cpp.frameworks: ["ApplicationServices", "Cocoa"] bundle.isBundle: false } Properties { condition: qbs.targetOS.contains("darwin") bundle.isBundle: false } } qbs-src-2.6.1/src/app/qbs-setup-qt/0000755000175100001660000000000014776170045016364 5ustar runnerdockerqbs-src-2.6.1/src/app/qbs-setup-qt/setupqt.h0000644000175100001660000000557314776170045020254 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPQT_H #define QBS_SETUPQT_H #include #include #include #include #include namespace qbs { class Settings; class QtEnvironment { public: QString qmakeFilePath; QStringList qbsToolchain; QString architecture; QString targetPlatform; Version qtVersion; Version vcVersion; }; class SetupQt { Q_DECLARE_TR_FUNCTIONS(SetupQt) public: static bool isQMakePathValid(const QString &qmakePath); static std::vector fetchEnvironments(); static QtEnvironment fetchEnvironment(const QString &qmakePath); static bool checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion, const std::vector &qtEnvironments); static void saveToQbsSettings(const QString &qtVersionName, const QtEnvironment &qtEnvironment, Settings *settings); }; } // namespace qbs #endif // QBS_SETUPQT_H qbs-src-2.6.1/src/app/qbs-setup-qt/setupqt.cpp0000644000175100001660000003542114776170045020602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "setupqt.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { using Internal::none_of; using Internal::contains; using Internal::HostOsInfo; using Internal::Tr; using Internal::rangeTo; static QStringList qmakeExecutableNames() { const QString baseName = HostOsInfo::appendExecutableSuffix(QStringLiteral("qmake")); QStringList lst(baseName); if (HostOsInfo::isLinuxHost()) { // Some distributions ship binaries called qmake-qt5 or qmake-qt4. lst << baseName + QLatin1String("-qt5") << baseName + QLatin1String("-qt4"); } return lst; } static QStringList collectQmakePaths() { const QStringList qmakeExeNames = qmakeExecutableNames(); QStringList qmakePaths; QByteArray environmentPath = qgetenv("PATH"); const QList environmentPaths = environmentPath.split(HostOsInfo::pathListSeparator().toLatin1()); for (const QByteArray &path : environmentPaths) { for (const QString &qmakeExecutableName : qmakeExeNames) { QFileInfo pathFileInfo(QDir(QLatin1String(path)), qmakeExecutableName); if (pathFileInfo.exists()) { QString qmakePath = pathFileInfo.absoluteFilePath(); if (!qmakePaths.contains(qmakePath)) qmakePaths.push_back(qmakePath); } } } return qmakePaths; } bool SetupQt::isQMakePathValid(const QString &qmakePath) { QFileInfo qmakeFileInfo(qmakePath); return qmakeFileInfo.exists() && qmakeFileInfo.isFile() && qmakeFileInfo.isExecutable(); } std::vector SetupQt::fetchEnvironments() { std::vector qtEnvironments; const auto qmakePaths = collectQmakePaths(); for (const QString &qmakePath : qmakePaths) { const QtEnvironment env = fetchEnvironment(qmakePath); if (none_of(qtEnvironments, [&env](const QtEnvironment &otherEnv) { return env.qmakeFilePath == otherEnv.qmakeFilePath; })) { qtEnvironments.push_back(env); } } return qtEnvironments; } // These functions work only for Qt from installer. static QStringList qbsToolchainFromDirName(const QString &dir) { if (dir.startsWith(QLatin1String("msvc"))) return {QStringLiteral("msvc")}; if (dir.startsWith(QLatin1String("mingw"))) return {QStringLiteral("mingw"), QStringLiteral("gcc")}; if (dir.startsWith(QLatin1String("clang"))) return {QStringLiteral("clang"), QStringLiteral("llvm"), QStringLiteral("gcc")}; if (dir.startsWith(QLatin1String("gcc"))) return {QStringLiteral("gcc")}; return {}; } static Version vcVersionFromDirName(const QString &dir) { static const std::regex regexp("^msvc(\\d\\d\\d\\d).*$"); std::smatch match; const std::string dirString = dir.toStdString(); if (!std::regex_match(dirString, match, regexp)) return Version{}; // see https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd QMap mapping{ std::make_pair("2005", "8"), std::make_pair("2008", "9"), std::make_pair("2010", "10"), std::make_pair("2012", "11"), std::make_pair("2013", "12"), std::make_pair("2015", "14"), std::make_pair("2017", "14.10"), std::make_pair("2019", "14.20"), std::make_pair("2022", "14.30")}; return Version::fromString(QString::fromStdString(mapping.value(match[1].str()))); } static Version vcVersionFromToolchainInstallPath(const QString &toolchainPath) { // e.g. 14.40.33807\bin\Hostx64\x64 QDir dir(toolchainPath); dir.cdUp(); dir.cdUp(); dir.cdUp(); return Version::fromString(dir.dirName()); } static QString archFromDirName(const QString &dir) { static const std::regex regexp("^[^_]+_(.*).*$"); std::smatch match; const std::string dirString = dir.toStdString(); if (!std::regex_match(dirString, match, regexp)) return {}; QString arch = QString::fromStdString(match[1]); if (arch == QLatin1String("32")) return QStringLiteral("x86"); if (arch == QLatin1String("64")) return QStringLiteral("x86_64"); if (arch.contains(QLatin1String("arm64"))) return QStringLiteral("arm64"); return arch; } static QString platformFromDirName(const QString &dir) { if (dir.startsWith(QLatin1String("android"))) return QStringLiteral("android"); if (dir == QLatin1String("Boot2Qt")) return QStringLiteral("linux"); return HostOsInfo::hostOSIdentifier(); } QtEnvironment SetupQt::fetchEnvironment(const QString &qmakePath) { QtEnvironment env; env.qmakeFilePath = qmakePath; QDir qtDir = QFileInfo(qmakePath).dir(); if (qtDir.dirName() == QLatin1String("bin")) { qtDir.cdUp(); env.qbsToolchain = qbsToolchainFromDirName(qtDir.dirName()); env.vcVersion = vcVersionFromDirName(qtDir.dirName()); env.architecture = archFromDirName(qtDir.dirName()); if (env.vcVersion.isValid() && env.architecture.isEmpty()) env.architecture = QStringLiteral("x86"); env.targetPlatform = platformFromDirName(qtDir.dirName()); qtDir.cdUp(); env.qtVersion = Version::fromString(qtDir.dirName()); } return env; } static bool isToolchainProfile(const Profile &profile) { const auto actual = rangeTo>( profile.allKeys(Profile::KeySelectionRecursive)); Internal::Set expected{ QStringLiteral("qbs.toolchainType") }; if (HostOsInfo::isMacosHost()) expected.insert(QStringLiteral("qbs.targetPlatform")); // match only Xcode profiles return Internal::Set(actual).unite(expected) == actual; } static bool isQtProfile(const Profile &profile) { if (!profile.value(QStringLiteral("moduleProviders.Qt.qmakeFilePaths")).toStringList() .empty()) { return true; } // For Profiles created with setup-qt < 5.13. const QStringList searchPaths = profile.value(QStringLiteral("preferences.qbsSearchPaths")).toStringList(); return Internal::any_of(searchPaths, [] (const QString &path) { return QFileInfo(path + QStringLiteral("/modules/Qt")).isDir(); }); } template bool areProfilePropertiesIncompatible(const T &set1, const T &set2) { // Two objects are only considered incompatible if they are both non empty and compare inequal // This logic is used for comparing target OS, toolchain lists, and architectures return set1.size() > 0 && set2.size() > 0 && set1 != set2; } enum Match { MatchFull, MatchPartial, MatchNone }; static Match compatibility(const QtEnvironment &env, const Profile &toolchainProfile) { Match match = MatchFull; const auto toolchainType = toolchainProfile.value(QStringLiteral("qbs.toolchainType")).toString(); const auto toolchain = !toolchainType.isEmpty() ? canonicalToolchain(toolchainType) : toolchainProfile.value(QStringLiteral("qbs.toolchain")).toStringList(); const auto toolchainNames = rangeTo>(toolchain); const auto qtToolchainNames = rangeTo>(env.qbsToolchain); if (areProfilePropertiesIncompatible(toolchainNames, qtToolchainNames)) { auto intersection = toolchainNames; intersection.intersect(qtToolchainNames); if (!intersection.empty()) match = MatchPartial; else return MatchNone; } const auto targetPlatform = toolchainProfile.value( QStringLiteral("qbs.targetPlatform")).toString(); if (!targetPlatform.isEmpty() && targetPlatform != env.targetPlatform) return MatchNone; const QString toolchainArchitecture = toolchainProfile.value(QStringLiteral("qbs.architecture")) .toString(); if (areProfilePropertiesIncompatible(canonicalArchitecture(env.architecture), canonicalArchitecture(toolchainArchitecture))) return MatchNone; if (toolchainType == QStringLiteral("msvc") && env.vcVersion.isValid()) { // We want to know for sure that MSVC compiler versions match, // because it's especially important for this toolchain const Version compilerVersion = vcVersionFromToolchainInstallPath( toolchainProfile.value(QStringLiteral("cpp.toolchainInstallPath")).toString()); static const Version vs2017Version{14, 10}; if (env.vcVersion >= vs2017Version) { if (env.vcVersion.majorVersion() != compilerVersion.majorVersion() || compilerVersion < vs2017Version) { return MatchNone; } } else if ( env.vcVersion.majorVersion() != compilerVersion.majorVersion() || env.vcVersion.minorVersion() != compilerVersion.minorVersion()) { return MatchNone; } } return match; } QString profileNameWithoutHostArch(const QString &profileName) { QString result; int i = profileName.indexOf(QLatin1Char('-')); if (i == -1) return result; ++i; int j = profileName.indexOf(QLatin1Char('_'), i); if (j == -1) return result; result = profileName.mid(0, i) + profileName.mid(j + 1); return result; } // "Compressing" MSVC profiles means that if MSVC2017-x64 and MSVC2017-x86_x64 fully match, // then we drop the crosscompiling toolchain MSVC2017-x86_x64. static void compressMsvcProfiles(QStringList &profiles) { Internal::removeIf(profiles, [&profiles] (const QString &profileName) { int idx = profileName.indexOf(QLatin1Char('_')); if (idx == -1) return false; return contains(profiles, profileNameWithoutHostArch(profileName)); }); } void SetupQt::saveToQbsSettings(const QString &qtVersionName, const QtEnvironment &qtEnvironment, Settings *settings) { const QString cleanQtVersionName = Profile::cleanName(qtVersionName); QString msg = QCoreApplication::translate("SetupQt", "Creating profile '%1'.") .arg(cleanQtVersionName); std::printf("%s\n", qPrintable(msg)); Profile profile(cleanQtVersionName, settings); profile.removeProfile(); profile.setValue(QStringLiteral("moduleProviders.Qt.qmakeFilePaths"), QStringList(qtEnvironment.qmakeFilePath)); if (!profile.baseProfile().isEmpty()) return; if (isToolchainProfile(profile)) return; QStringList fullMatches; QStringList partialMatches; const auto profileNames = settings->profiles(); for (const QString &profileName : profileNames) { const Profile otherProfile(profileName, settings); if (profileName == profile.name() || !isToolchainProfile(otherProfile) || isQtProfile(otherProfile)) continue; switch (compatibility(qtEnvironment, otherProfile)) { case MatchFull: fullMatches << profileName; break; case MatchPartial: partialMatches << profileName; break; default: break; } } if (fullMatches.size() > 1) compressMsvcProfiles(fullMatches); QString bestMatch; if (fullMatches.size() == 1) bestMatch = fullMatches.front(); else if (fullMatches.empty() && partialMatches.size() == 1) bestMatch = partialMatches.front(); if (bestMatch.isEmpty()) { QString message = Tr::tr("You may want to set up toolchain information " "for the generated Qt profile. "); if (!fullMatches.empty() || !partialMatches.empty()) { message += Tr::tr("Consider setting one of these profiles as this profile's base " "profile: %1.").arg((fullMatches + partialMatches) .join(QLatin1String(", "))); } qbsInfo() << message; } else { profile.setBaseProfile(bestMatch); qbsInfo() << Tr::tr("Setting profile '%1' as the base profile for this profile.") .arg(bestMatch); } } bool SetupQt::checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion, const std::vector &qtEnvironments) { bool foundOneVersion = false; for (const QtEnvironment &qtEnvironment : qtEnvironments) { if (qtEnvironment.qtVersion == qtVersion) { if (foundOneVersion) return true; foundOneVersion = true; } } return false; } } // namespace qbs qbs-src-2.6.1/src/app/qbs-setup-qt/commandlineparser.cpp0000644000175100001660000001241614776170045022577 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString detectOption() { return QStringLiteral("--detect"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_autoDetectionMode = false; m_qmakePath.clear(); m_profileName.clear(); m_settingsDir.clear(); if (m_commandLine.empty()) throwError(Tr::tr("No command-line arguments provided.")); while (!m_commandLine.empty()) { const QString arg = m_commandLine.front(); if (!arg.startsWith(QLatin1Char('-'))) break; m_commandLine.removeFirst(); if (arg == helpOptionShort() || arg == helpOptionLong()) m_helpRequested = true; else if (arg == detectOption()) m_autoDetectionMode = true; else if (arg == systemOption()) m_settingsScope = qbs::Settings::SystemScope; else if (arg == settingsDirOption()) assignOptionArgument(settingsDirOption(), m_settingsDir); } if (m_helpRequested || m_autoDetectionMode) { if (!m_commandLine.empty()) complainAboutExtraArguments(); return; } switch (m_commandLine.size()) { case 0: case 1: throwError(Tr::tr("Not enough command-line arguments provided.")); case 2: m_qmakePath = m_commandLine.at(0); m_profileName = m_commandLine.at(1); break; default: complainAboutExtraArguments(); } } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool creates qbs profiles from Qt versions.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%4] %3\n") .arg(m_command, settingsDirOption(), detectOption(), systemOption()); s += Tr::tr(" %1 [%2 ] [%4] \n") .arg(m_command, settingsDirOption(), systemOption()); s += Tr::tr(" %1 %2|%3\n").arg(m_command, helpOptionShort(), helpOptionLong()); s += Tr::tr("The first form tries to auto-detect all known Qt versions, looking them up " "via the PATH environment variable.\n"); s += Tr::tr("The second form creates one profile for one Qt version."); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.6.1/src/app/qbs-setup-qt/commandlineparser.h0000644000175100001660000000573114776170045022246 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #define QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } bool autoDetectionMode() const { return m_autoDetectionMode; } QString qmakePath() const { return m_qmakePath; } QString profileName() const { return m_profileName; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; bool m_autoDetectionMode = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_qmakePath; QString m_profileName; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Include guard qbs-src-2.6.1/src/app/qbs-setup-qt/qbs-setup-qt.rc0000644000175100001660000000022014776170045021251 0ustar runnerdocker#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-qt.exe.manifest" qbs-src-2.6.1/src/app/qbs-setup-qt/main.cpp0000644000175100001660000001074314776170045020021 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "setupqt.h" #include "commandlineparser.h" #include #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; int main(int argc, char *argv[]) { QCoreApplication application(argc, argv); try { CommandLineParser clParser; clParser.parse(application.arguments()); if (clParser.helpRequested()) { std::cout << qPrintable(clParser.usageString()) << std::endl; return EXIT_SUCCESS; } Settings settings(clParser.settingsDir()); settings.setScopeForWriting(clParser.settingsScope()); if (clParser.autoDetectionMode()) { // search all Qt's in path and dump their settings const std::vector qtEnvironments = SetupQt::fetchEnvironments(); if (qtEnvironments.empty()) { std::cout << qPrintable(Tr::tr("No Qt installations detected. " "No profiles created.")) << std::endl; } for (const QtEnvironment &qtEnvironment : qtEnvironments) { QString profileName = QLatin1String("qt-") + qtEnvironment.qtVersion.toString(); if (SetupQt::checkIfMoreThanOneQtWithTheSameVersion(qtEnvironment.qtVersion, qtEnvironments)) { QStringList prefixPathParts = QFileInfo(qtEnvironment.qmakeFilePath).path() .split(QLatin1Char('/'), Qt::SkipEmptyParts); if (!prefixPathParts.empty()) profileName += QLatin1String("-") + prefixPathParts.last(); } SetupQt::saveToQbsSettings(profileName, qtEnvironment, &settings); } return EXIT_SUCCESS; } if (!SetupQt::isQMakePathValid(clParser.qmakePath())) { std::cerr << qPrintable(Tr::tr("'%1' does not seem to be a qmake executable.") .arg(clParser.qmakePath())) << std::endl; return EXIT_FAILURE; } const QtEnvironment qtEnvironment = SetupQt::fetchEnvironment(clParser.qmakePath()); QString profileName = clParser.profileName(); profileName.replace(QLatin1Char('.'), QLatin1Char('-')); SetupQt::saveToQbsSettings(profileName, qtEnvironment, &settings); return EXIT_SUCCESS; } catch (const ErrorInfo &e) { std::cerr << qPrintable(e.toString()) << std::endl; return EXIT_FAILURE; } } qbs-src-2.6.1/src/app/qbs-setup-qt/qbs-setup-qt.exe.manifest0000644000175100001660000000072614776170045023246 0ustar runnerdocker qbs-src-2.6.1/src/app/qbs-setup-qt/CMakeLists.txt0000644000175100001660000000031314776170045021121 0ustar runnerdockerset(SOURCES commandlineparser.cpp commandlineparser.h main.cpp setupqt.cpp setupqt.h ) add_qbs_app(qbs-setup-qt DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.6.1/src/app/qbs-setup-qt/qbs-setup-qt.qbs0000644000175100001660000000077314776170045021447 0ustar runnerdockerQbsApp { name: "qbs-setup-qt" files: [ "commandlineparser.cpp", "commandlineparser.h", "main.cpp", "setupqt.cpp", "setupqt.h" ] Group { name: "MinGW specific files" condition: qbs.toolchain.contains("mingw") files: "qbs-setup-qt.rc" Group { name: "qbs-setup-qt manifest" files: "qbs-setup-qt.exe.manifest" fileTags: [] // the manifest is referenced by the rc file } } } qbs-src-2.6.1/src/app/shared/0000755000175100001660000000000014776170045015265 5ustar runnerdockerqbs-src-2.6.1/src/app/shared/shared.qbs0000644000175100001660000000010314776170045017234 0ustar runnerdockerProject { references: [ "logging/logging.qbs", ] } qbs-src-2.6.1/src/app/shared/logging/0000755000175100001660000000000014776170045016713 5ustar runnerdockerqbs-src-2.6.1/src/app/shared/logging/coloredoutput.cpp0000644000175100001660000000741014776170045022331 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "coloredoutput.h" #include #ifdef Q_OS_WIN32 # include #endif #include #ifdef Q_OS_UNIX #include #endif void printfColored(TextColor color, const char *str, va_list vl) { fprintfColored(color, stdout, str, vl); } void printfColored(TextColor color, const char *str, ...) { va_list vl; va_start(vl, str); printfColored(color, str, vl); va_end(vl); } void fprintfColored(TextColor color, std::FILE *file, const char *str, va_list vl) { #if defined(Q_OS_UNIX) if (color != TextColorDefault && isatty(fileno(file))) { unsigned char bright = (color & TextColorBright) >> 3; std::fprintf(file, "\033[%d;%dm", bright, 30 + (color & ~TextColorBright)); std::vfprintf(file, str, vl); std::fprintf(stdout, "\033[0m"); std::fprintf(stderr, "\033[0m"); } else #elif defined(Q_OS_WIN32) HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbiInfo; if (color != TextColorDefault && hStdout != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { WORD bgrColor = ((color & 1) << 2) | (color & 2) | ((color & 4) >> 2); // BGR instead of RGB. if (color & TextColorBright) bgrColor += FOREGROUND_INTENSITY; SetConsoleTextAttribute(hStdout, (csbiInfo.wAttributes & 0xf0) | bgrColor); std::vfprintf(file, str, vl); SetConsoleTextAttribute(hStdout, csbiInfo.wAttributes); } else #endif { std::vfprintf(file, str, vl); } } void fprintfColored(TextColor color, std::FILE *file, const char *str, ...) { va_list vl; va_start(vl, str); fprintfColored(color, file, str, vl); va_end(vl); } bool terminalSupportsColor() { #if defined(Q_OS_UNIX) const QByteArray &term = qgetenv("TERM"); return !term.isEmpty() && term != "dumb"; #else return true; #endif } qbs-src-2.6.1/src/app/shared/logging/logging.qbs0000644000175100001660000000050214776170045021045 0ustar runnerdockerQbsStaticLibrary { Depends { name: "qbscore" } name: "qbsconsolelogger" files: [ "coloredoutput.cpp", "coloredoutput.h", "consolelogger.cpp", "consolelogger.h" ] Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.sourceDirectory } } qbs-src-2.6.1/src/app/shared/logging/coloredoutput.h0000644000175100001660000000616314776170045022002 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_COLOREDOUTPUT_H #define QBS_COLOREDOUTPUT_H #include #include // http://en.wikipedia.org/wiki/ANSI_escape_code#Colors enum TextColor { TextColorDefault = -1, TextColorBlack = 0, TextColorDarkRed = 1, TextColorDarkGreen = 2, TextColorDarkBlue = 4, TextColorDarkCyan = TextColorDarkGreen | TextColorDarkBlue, TextColorDarkMagenta = TextColorDarkRed | TextColorDarkBlue, TextColorDarkYellow = TextColorDarkRed | TextColorDarkGreen, TextColorGray = 7, TextColorBright = 8, TextColorRed = TextColorDarkRed | TextColorBright, TextColorGreen = TextColorDarkGreen | TextColorBright, TextColorBlue = TextColorDarkBlue | TextColorBright, TextColorCyan = TextColorDarkCyan | TextColorBright, TextColorMagenta = TextColorDarkMagenta | TextColorBright, TextColorYellow = TextColorDarkYellow | TextColorBright, TextColorWhite = TextColorGray | TextColorBright }; void printfColored(TextColor color, const char *str, va_list vl); void printfColored(TextColor color, const char *str, ...); void fprintfColored(TextColor color, std::FILE *file, const char *str, va_list vl); void fprintfColored(TextColor color, std::FILE *file, const char *str, ...); bool terminalSupportsColor(); #endif // QBS_COLOREDOUTPUT_H qbs-src-2.6.1/src/app/shared/logging/consolelogger.h0000644000175100001660000000637314776170045021737 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LOGSINK_H #define QBS_LOGSINK_H #include "coloredoutput.h" #include namespace qbs { class Settings; } class ConsoleLogSink : public qbs::ILogSink { public: ConsoleLogSink(); void setColoredOutputEnabled(bool enabled) { m_coloredOutputEnabled = enabled; } void setEnabled(bool enabled) { m_enabled = enabled; } private: void doPrintMessage(qbs::LoggerLevel level, const QString &message, const QString &tag) override; void fprintfWrapper(TextColor color, FILE *file, const char *str, ...); private: bool m_coloredOutputEnabled; bool m_enabled; }; class ConsoleLogger : public qbs::Internal::Logger { public: static ConsoleLogger &instance(qbs::Settings *settings = 0); ConsoleLogSink *logSink() { return &m_logSink; } void setSettings(qbs::Settings *settings); private: ConsoleLogger(qbs::Settings *settings); ConsoleLogSink m_logSink; }; inline qbs::Internal::LogWriter qbsError() { return ConsoleLogger::instance().qbsLog(qbs::LoggerError); } inline qbs::Internal::LogWriter qbsWarning() { return ConsoleLogger::instance().qbsWarning(); } inline qbs::Internal::LogWriter qbsInfo() { return ConsoleLogger::instance().qbsInfo(); } inline qbs::Internal::LogWriter qbsDebug() { return ConsoleLogger::instance().qbsDebug(); } inline qbs::Internal::LogWriter qbsTrace() { return ConsoleLogger::instance().qbsTrace(); } #endif // QBS_LOGSINK_H qbs-src-2.6.1/src/app/shared/logging/CMakeLists.txt0000644000175100001660000000030314776170045021447 0ustar runnerdockerset(SOURCES coloredoutput.cpp coloredoutput.h consolelogger.cpp consolelogger.h ) add_qbs_library(qbsconsolelogger STATIC DEPENDS qbscore SOURCES ${SOURCES} ) qbs-src-2.6.1/src/app/shared/logging/consolelogger.cpp0000644000175100001660000000773214776170045022272 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "consolelogger.h" #include #include #include static QHash setupColorTable() { QHash colorTable; colorTable[QStringLiteral("compiler")] = TextColorDefault; colorTable[QStringLiteral("linker")] = TextColorDarkGreen; colorTable[QStringLiteral("codegen")] = TextColorDarkYellow; colorTable[QStringLiteral("filegen")] = TextColorDarkYellow; return colorTable; } ConsoleLogSink::ConsoleLogSink() : m_coloredOutputEnabled(true), m_enabled(true) { } void ConsoleLogSink::doPrintMessage(qbs::LoggerLevel level, const QString &message, const QString &tag) { if (!m_enabled) return; std::FILE * const file = level == qbs::LoggerInfo && tag != QStringLiteral("stdErr") ? stdout : stderr; const QString levelTag = logLevelTag(level); TextColor color = TextColorDefault; switch (level) { case qbs::LoggerError: color = TextColorRed; break; case qbs::LoggerWarning: color = TextColorYellow; break; default: break; } fprintfWrapper(color, file, levelTag.toLocal8Bit().constData()); static QHash colorTable = setupColorTable(); fprintfWrapper(colorTable.value(tag, TextColorDefault), file, "%s\n", message.toLocal8Bit().constData()); std::fflush(file); } void ConsoleLogSink::fprintfWrapper(TextColor color, std::FILE *file, const char *str, ...) { va_list vl; va_start(vl, str); if (m_coloredOutputEnabled && terminalSupportsColor()) fprintfColored(color, file, str, vl); else std::vfprintf(file, str, vl); va_end(vl); } ConsoleLogger &ConsoleLogger::instance(qbs::Settings *settings) { static ConsoleLogger logger(settings); return logger; } void ConsoleLogger::setSettings(qbs::Settings *settings) { if (settings) m_logSink.setColoredOutputEnabled(qbs::Preferences(settings).useColoredOutput()); } ConsoleLogger::ConsoleLogger(qbs::Settings *settings) : Logger(&m_logSink) { setSettings(settings); } qbs-src-2.6.1/src/app/shared/CMakeLists.txt0000644000175100001660000000003214776170045020020 0ustar runnerdockeradd_subdirectory(logging) qbs-src-2.6.1/src/app/apps.qbs0000644000175100001660000000054214776170045015472 0ustar runnerdockerProject { references: [ "config/config.qbs", "config-ui/config-ui.qbs", "qbs/qbs.qbs", "qbs-create-project/qbs-create-project.qbs", "qbs-setup-android/qbs-setup-android.qbs", "qbs-setup-qt/qbs-setup-qt.qbs", "qbs-setup-toolchains/qbs-setup-toolchains.qbs", "shared/shared.qbs", ] } qbs-src-2.6.1/src/app/qbs-setup-android/0000755000175100001660000000000014776170045017360 5ustar runnerdockerqbs-src-2.6.1/src/app/qbs-setup-android/qbs-setup-android.qbs0000644000175100001660000000103414776170045023426 0ustar runnerdockerQbsApp { name: "qbs-setup-android" files: [ "android-setup.cpp", "android-setup.h", "commandlineparser.cpp", "commandlineparser.h", "main.cpp", ] Group { name: "MinGW specific files" condition: qbs.toolchain.contains("mingw") files: "qbs-setup-android.rc" Group { name: "qbs-setup-android manifest" files: "qbs-setup-android.exe.manifest" fileTags: [] // the manifest is referenced by the rc file } } } qbs-src-2.6.1/src/app/qbs-setup-android/android-setup.cpp0000644000175100001660000002313214776170045022643 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "android-setup.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using qbs::Internal::Tr; static QString qls(const char *s) { return QLatin1String(s); } static QStringList expectedArchs() { return {QStringLiteral("arm64"), QStringLiteral("armv7a"), QStringLiteral("x86"), QStringLiteral("x86_64")}; } void setupSdk(qbs::Settings *settings, const QString &profileName, const QString &sdkDirPath) { if (!QDir(sdkDirPath).exists()) { throw ErrorInfo(Tr::tr("SDK directory '%1' does not exist.") .arg(QDir::toNativeSeparators(sdkDirPath))); } Profile profile(profileName, settings); profile.removeProfile(); if (!sdkDirPath.isEmpty()) profile.setValue(qls("Android.sdk.sdkDir"), QDir::cleanPath(sdkDirPath)); profile.setValue(qls("qbs.targetPlatform"), qls("android")); } static QString mapArch(const QString &androidName) { if (androidName == qls("arm64-v8a")) return qls("arm64"); if (androidName == qls("armeabi")) return qls("armv5te"); if (androidName == qls("armeabi-v7a")) return qls("armv7a"); return androidName; } struct QtAndroidInfo { bool isValid() const { return !archs.isEmpty(); } QString qmakePath; QStringList archs; QString platform; }; static QtAndroidInfo getInfoForQtDir(const QString &qtDir) { QtAndroidInfo info; info.qmakePath = qbs::Internal::HostOsInfo::appendExecutableSuffix(qtDir + qls("/bin/qmake")); if (!QFile::exists(info.qmakePath)) return info; QFile qdevicepri(qtDir + qls("/mkspecs/qdevice.pri")); if (!qdevicepri.open(QIODevice::ReadOnly)) return info; while (!qdevicepri.atEnd()) { // For Qt < 5.14 use DEFAULT_ANDROID_TARGET_ARCH (which is the abi) to compute // the architecture // DEFAULT_ANDROID_ABIS doesn't exit // For Qt >= 5.14: // DEFAULT_ANDROID_TARGET_ARCH doesn't exist, use DEFAULT_ANDROID_ABIS to compute // the architectures const QByteArray line = qdevicepri.readLine().simplified(); const bool isArchLine = line.startsWith("DEFAULT_ANDROID_TARGET_ARCH"); const bool isAbisLine = line.startsWith("DEFAULT_ANDROID_ABIS"); const bool isPlatformLine = line.startsWith("DEFAULT_ANDROID_PLATFORM"); if (!isArchLine && !isPlatformLine && !isAbisLine) continue; const QList elems = line.split('='); if (elems.size() != 2) continue; const QString rhs = QString::fromLatin1(elems.at(1).trimmed()); if (isArchLine) { info.archs << mapArch(rhs); } else if (isAbisLine) { const auto abis = rhs.split(QLatin1Char(' ')); for (const QString &abi: abis) info.archs << mapArch(abi); } else { info.platform = rhs; } } return info; } using QtInfoPerArch = QHash; static QtInfoPerArch getQtAndroidInfo(const QString &qtSdkDir) { QtInfoPerArch archs; if (qtSdkDir.isEmpty()) return archs; QStringList qtDirs(qtSdkDir); const QStringList nameFilters{QStringLiteral("android_*"), QStringLiteral("android")}; QDirIterator dit(qtSdkDir, nameFilters, QDir::Dirs); while (dit.hasNext()) qtDirs << dit.next(); for (const auto &qtDir : std::as_const(qtDirs)) { const QtAndroidInfo info = getInfoForQtDir(qtDir); if (info.isValid()) { for (const QString &arch: info.archs) archs.insert(arch, info); } } return archs; } static QString maximumPlatform(const QString &platform1, const QString &platform2) { if (platform1.isEmpty()) return platform2; if (platform2.isEmpty()) return platform1; static const QString prefix = qls("android-"); const QString numberString1 = platform1.mid(prefix.size()); const QString numberString2 = platform2.mid(prefix.size()); bool ok; const int value1 = numberString1.toInt(&ok); if (!ok) { qWarning("Ignoring malformed Android platform string '%s'.", qPrintable(platform1)); return platform2; } const int value2 = numberString2.toInt(&ok); if (!ok) { qWarning("Ignoring malformed Android platform string '%s'.", qPrintable(platform2)); return platform1; } return prefix + QString::number(std::max(value1, value2)); } static QString getToolchainType(const QString &ndkDirPath) { QFile sourceProperties(ndkDirPath + qls("/source.properties")); if (!sourceProperties.open(QIODevice::ReadOnly)) return QStringLiteral("gcc"); // <= r10 while (!sourceProperties.atEnd()) { const QByteArray curLine = sourceProperties.readLine().simplified(); static const QByteArray prefix = "Pkg.Revision = "; if (!curLine.startsWith(prefix)) continue; qbs::Version ndkVersion = qbs::Version::fromString( QString::fromLatin1(curLine.mid(prefix.size()))); if (!ndkVersion.isValid()) { qWarning("Unexpected format of NDK revision string in '%s'", qPrintable(sourceProperties.fileName())); return QStringLiteral("clang"); } return qls(ndkVersion.majorVersion() >= 18 ? "clang" : "gcc"); } qWarning("No revision entry found in '%s'", qPrintable(sourceProperties.fileName())); return QStringLiteral("clang"); } static void setupNdk(qbs::Settings *settings, const QString &profileName, const QString &ndkDirPath, const QString &qtSdkDirPath) { if (!QDir(ndkDirPath).exists()) { throw ErrorInfo(Tr::tr("NDK directory '%1' does not exist.") .arg(QDir::toNativeSeparators(ndkDirPath))); } Profile mainProfile(profileName, settings); if (!ndkDirPath.isEmpty()) { mainProfile.setValue(qls("Android.ndk.ndkDir"), QDir::cleanPath(ndkDirPath)); mainProfile.setValue(qls("Android.sdk.ndkDir"), QDir::cleanPath(ndkDirPath)); } mainProfile.setValue(qls("qbs.toolchainType"), getToolchainType(ndkDirPath)); const QStringList archs = expectedArchs(); const QtInfoPerArch infoPerArch = getQtAndroidInfo(qtSdkDirPath); const QStringList archsForProfile = infoPerArch.empty() ? archs : QStringList(infoPerArch.keys()); if (archsForProfile.size() == 1) mainProfile.setValue(qls("qbs.architecture"), archsForProfile.front()); else mainProfile.setValue(qls("qbs.architectures"), archsForProfile); QStringList qmakeFilePaths; QString platform; for (const QString &arch : archs) { const QtAndroidInfo qtAndroidInfo = infoPerArch.value(arch); if (!qtAndroidInfo.isValid()) continue; qmakeFilePaths << qtAndroidInfo.qmakePath; platform = maximumPlatform(platform, qtAndroidInfo.platform); } if (!qmakeFilePaths.empty()) { qmakeFilePaths.removeDuplicates(); mainProfile.setValue(qls("moduleProviders.Qt.qmakeFilePaths"), qmakeFilePaths); } if (!platform.isEmpty()) mainProfile.setValue(qls("Android.ndk.platform"), platform); } void setupAndroid(Settings *settings, const QString &profileName, const QString &sdkDirPath, const QString &ndkDirPath, const QString &qtSdkDirPath) { setupSdk(settings, profileName, sdkDirPath); setupNdk(settings, profileName, ndkDirPath, qtSdkDirPath); } qbs-src-2.6.1/src/app/qbs-setup-android/qbs-setup-android.exe.manifest0000644000175100001660000000073314776170045025234 0ustar runnerdocker qbs-src-2.6.1/src/app/qbs-setup-android/commandlineparser.cpp0000644000175100001660000001336714776170045023601 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include CommandLineParser::CommandLineParser() = default; using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString sdkDirOption() { return QStringLiteral("--sdk-dir"); } static QString ndkDirOption() { return QStringLiteral("--ndk-dir"); } static QString qtSdkDirOption() { return QStringLiteral("--qt-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_sdkDir.clear(); m_ndkDir.clear(); m_profileName.clear(); m_settingsDir.clear(); if (m_commandLine.empty()) throwError(Tr::tr("No command-line arguments provided.")); while (!m_commandLine.empty()) { const QString arg = m_commandLine.front(); if (!arg.startsWith(QLatin1Char('-'))) break; m_commandLine.removeFirst(); if (arg == helpOptionShort() || arg == helpOptionLong()) m_helpRequested = true; else if (arg == settingsDirOption()) assignOptionArgument(settingsDirOption(), m_settingsDir); else if (arg == systemOption()) m_settingsScope = qbs::Settings::SystemScope; else if (arg == sdkDirOption()) assignOptionArgument(sdkDirOption(), m_sdkDir); else if (arg == ndkDirOption()) assignOptionArgument(ndkDirOption(), m_ndkDir); else if (arg == qtSdkDirOption()) assignOptionArgument(arg, m_qtSdkDir); else throwError(Tr::tr("Unknown option '%1'.").arg(arg)); } if (m_helpRequested) { if (!m_commandLine.empty()) complainAboutExtraArguments(); return; } switch (m_commandLine.size()) { case 0: throwError(Tr::tr("No profile name supplied.")); case 1: m_profileName = m_commandLine.takeFirst(); m_profileName.replace(QLatin1Char('.'), QLatin1Char('-')); break; default: complainAboutExtraArguments(); } } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool creates qbs profiles from Android SDK and NDK installations.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%6] [%3 ] [%4 ] [%5 ] " "\n") .arg(m_command, settingsDirOption(), ndkDirOption(), sdkDirOption(), qtSdkDirOption(), systemOption()); s += Tr::tr(" %1 %2|%3\n").arg(m_command, helpOptionShort(), helpOptionLong()); s += Tr::tr("If an NDK path is given, the profile will be suitable for use with Android " "projects that contain native C/C++ code.\n"); s += Tr::tr("If a Qt path is also given, the profile will be suitable for developing " "Qt applications for Android.\n"); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.6.1/src/app/qbs-setup-android/commandlineparser.h0000644000175100001660000000602014776170045023232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUP_ANDROID_COMMANDLINEPARSER_H #define QBS_SETUP_ANDROID_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: CommandLineParser(); void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } QString sdkDir() const { return m_sdkDir; } QString ndkDir() const { return m_ndkDir; } QString qtSdkDir() const { return m_qtSdkDir; } QString profileName() const { return m_profileName; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_sdkDir; QString m_ndkDir; QString m_qtSdkDir; QString m_profileName; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Include guard. qbs-src-2.6.1/src/app/qbs-setup-android/android-setup.h0000644000175100001660000000435014776170045022311 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUP_ANDROID_SDKSETUP_H #define QBS_SETUP_ANDROID_SDKSETUP_H #include namespace qbs { class Settings; } QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE void setupAndroid(qbs::Settings *settings, const QString &profileName, const QString &sdkDirPath, const QString &ndkDirPath, const QString &qtSdkDirPath); #endif // Include guard. qbs-src-2.6.1/src/app/qbs-setup-android/main.cpp0000644000175100001660000000545214776170045021016 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandlineparser.h" #include "android-setup.h" #include #include #include #include #include #include int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(app.arguments()); if (clParser.helpRequested()) { std::cout << qPrintable(clParser.usageString()) << std::endl; return EXIT_SUCCESS; } qbs::Settings settings(clParser.settingsDir()); settings.setScopeForWriting(clParser.settingsScope()); setupAndroid(&settings, clParser.profileName(), clParser.sdkDir(), clParser.ndkDir(), clParser.qtSdkDir()); } catch (const qbs::ErrorInfo &e) { std::cerr << qPrintable(qbs::Internal::Tr::tr("Error: %1").arg(e.toString())) << std::endl; return EXIT_FAILURE; } } qbs-src-2.6.1/src/app/qbs-setup-android/CMakeLists.txt0000644000175100001660000000033414776170045022120 0ustar runnerdockerset(SOURCES android-setup.cpp android-setup.h commandlineparser.cpp commandlineparser.h main.cpp ) add_qbs_app(qbs-setup-android DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.6.1/src/app/qbs-setup-android/qbs-setup-android.rc0000644000175100001660000000022514776170045023246 0ustar runnerdocker#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-android.exe.manifest" qbs-src-2.6.1/src/app/CMakeLists.txt0000644000175100001660000000036314776170045016561 0ustar runnerdockeradd_subdirectory(config) add_subdirectory(config-ui) add_subdirectory(qbs) add_subdirectory(qbs-create-project) add_subdirectory(qbs-setup-android) add_subdirectory(qbs-setup-qt) add_subdirectory(qbs-setup-toolchains) add_subdirectory(shared) qbs-src-2.6.1/src/lib/0000755000175100001660000000000014776170045014005 5ustar runnerdockerqbs-src-2.6.1/src/lib/msbuild/0000755000175100001660000000000014776170045015444 5ustar runnerdockerqbs-src-2.6.1/src/lib/msbuild/msbuild/0000755000175100001660000000000014776170045017103 5ustar runnerdockerqbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildimportgroup.cpp0000644000175100001660000000444714776170045023567 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildimportgroup.h" #include "imsbuildnodevisitor.h" #include "msbuildimport.h" namespace qbs { class MSBuildImportGroupPrivate { public: QString label; }; MSBuildImportGroup::MSBuildImportGroup(MSBuildProject *parent) : IMSBuildGroup(parent) , d(new MSBuildImportGroupPrivate) { } MSBuildImportGroup::~MSBuildImportGroup() = default; QString MSBuildImportGroup::label() const { return d->label; } void MSBuildImportGroup::setLabel(const QString &label) { d->label = label; } void MSBuildImportGroup::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); for (const auto &child : children()) { if (const auto import = qobject_cast(child)) import->accept(visitor); } visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildpropertybase.cpp0000644000175100001660000000445514776170045023716 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildpropertybase.h" namespace qbs { class MSBuildPropertyBasePrivate { public: QString condition; QString name; QVariant value; }; MSBuildPropertyBase::MSBuildPropertyBase(QObject *parent) : QObject(parent) , d(new MSBuildPropertyBasePrivate) { } MSBuildPropertyBase::~MSBuildPropertyBase() = default; QString MSBuildPropertyBase::condition() const { return d->condition; } void MSBuildPropertyBase::setCondition(const QString &condition) { d->condition = condition; } QString MSBuildPropertyBase::name() const { return d->name; } void MSBuildPropertyBase::setName(const QString &name) { d->name = name; } QVariant MSBuildPropertyBase::value() const { return d->value; } void MSBuildPropertyBase::setValue(const QVariant &value) { d->value = value; } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildpropertybase.h0000644000175100001660000000424414776170045023357 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDPROPERTYBASE_H #define MSBUILDPROPERTYBASE_H #include #include #include namespace qbs { class MSBuildPropertyBasePrivate; class MSBuildPropertyBase : public QObject { Q_OBJECT protected: explicit MSBuildPropertyBase(QObject *parent = nullptr); public: ~MSBuildPropertyBase() override; QString condition() const; void setCondition(const QString &condition); QString name() const; void setName(const QString &name); QVariant value() const; void setValue(const QVariant &value); private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDPROPERTYBASE_H qbs-src-2.6.1/src/lib/msbuild/msbuild/imsbuildgroup.cpp0000644000175100001660000000404414776170045022476 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "imsbuildgroup.h" #include "msbuildproject.h" namespace qbs { class IMSBuildGroupPrivate { public: QString condition; }; IMSBuildGroup::IMSBuildGroup(MSBuildProject *parent) : QObject(parent) , d(new IMSBuildGroupPrivate) { } IMSBuildGroup::~IMSBuildGroup() = default; QString IMSBuildGroup::condition() const { return d->condition; } void IMSBuildGroup::setCondition(const QString &condition) { d->condition = condition; } IMSBuildItemGroup::IMSBuildItemGroup(MSBuildProject *parent) : IMSBuildGroup(parent) { } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditemgroup.h0000644000175100001660000000443214776170045022652 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDITEMGROUP_H #define MSBUILDITEMGROUP_H #include "imsbuildgroup.h" #include "imsbuildnode.h" #include namespace qbs { class MSBuildProject; class MSBuildItemGroupPrivate; /*! * \brief The MSBuildItemGroup class represents an MSBuild ItemGroup element. * * https://msdn.microsoft.com/en-us/library/646dk05y.aspx */ class MSBuildItemGroup : public IMSBuildItemGroup, public IMSBuildNode { Q_OBJECT Q_DISABLE_COPY(MSBuildItemGroup) public: explicit MSBuildItemGroup(MSBuildProject *parent = nullptr); ~MSBuildItemGroup() override; QString label() const; void setLabel(const QString &label); void accept(IMSBuildNodeVisitor *visitor) const override; private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDITEMGROUP_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditemmetadata.cpp0000644000175100001660000000406514776170045023633 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuilditemmetadata.h" #include "imsbuildnodevisitor.h" #include "msbuilditem.h" namespace qbs { MSBuildItemMetadata::MSBuildItemMetadata(MSBuildItem *parent) : MSBuildPropertyBase(parent) { } MSBuildItemMetadata::MSBuildItemMetadata(const QString &name, const QVariant &value, MSBuildItem *parent) : MSBuildItemMetadata(parent) { setName(name); setValue(value); } void MSBuildItemMetadata::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/imsbuildgroup.h0000644000175100001660000000415314776170045022144 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef IMSBUILDGROUP_H #define IMSBUILDGROUP_H #include #include namespace qbs { class MSBuildProject; class IMSBuildGroupPrivate; class IMSBuildGroup : public QObject { Q_OBJECT public: explicit IMSBuildGroup(MSBuildProject *parent = nullptr); ~IMSBuildGroup() override; QString condition() const; void setCondition(const QString &condition); private: std::unique_ptr d; }; class IMSBuildItemGroup : public IMSBuildGroup { Q_OBJECT public: explicit IMSBuildItemGroup(MSBuildProject *parent = nullptr); }; } // namespace qbs #endif // IMSBUILDGROUP_H qbs-src-2.6.1/src/lib/msbuild/msbuild/imsbuildnode.cpp0000644000175100001660000000312014776170045022261 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "imsbuildnode.h" namespace qbs { IMSBuildNode::~IMSBuildNode() = default; } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/imsbuildnodevisitor.h0000644000175100001660000000617714776170045023365 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef IMSBUILDNODEVISITOR_H #define IMSBUILDNODEVISITOR_H namespace qbs { class MSBuildImport; class MSBuildImportGroup; class MSBuildItem; class MSBuildItemDefinitionGroup; class MSBuildItemGroup; class MSBuildItemMetadata; class MSBuildProject; class MSBuildProperty; class MSBuildPropertyGroup; class IMSBuildNodeVisitor { public: virtual ~IMSBuildNodeVisitor() = default; virtual void visitStart(const MSBuildImport *import) = 0; virtual void visitEnd(const MSBuildImport *import) = 0; virtual void visitStart(const MSBuildImportGroup *importGroup) = 0; virtual void visitEnd(const MSBuildImportGroup *importGroup) = 0; virtual void visitStart(const MSBuildItem *item) = 0; virtual void visitEnd(const MSBuildItem *item) = 0; virtual void visitStart(const MSBuildItemDefinitionGroup *itemDefinitionGroup) = 0; virtual void visitEnd(const MSBuildItemDefinitionGroup *itemDefinitionGroup) = 0; virtual void visitStart(const MSBuildItemGroup *itemGroup) = 0; virtual void visitEnd(const MSBuildItemGroup *itemGroup) = 0; virtual void visitStart(const MSBuildItemMetadata *itemMetadata) = 0; virtual void visitEnd(const MSBuildItemMetadata *itemMetadata) = 0; virtual void visitStart(const MSBuildProject *project) = 0; virtual void visitEnd(const MSBuildProject *project) = 0; virtual void visitStart(const MSBuildProperty *property) = 0; virtual void visitEnd(const MSBuildProperty *property) = 0; virtual void visitStart(const MSBuildPropertyGroup *propertyGroup) = 0; virtual void visitEnd(const MSBuildPropertyGroup *propertyGroup) = 0; }; } // namespace qbs #endif // IMSBUILDNODEVISITOR_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildproperty.cpp0000644000175100001660000000405414776170045023056 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildproperty.h" #include "imsbuildnodevisitor.h" #include "msbuildpropertygroup.h" namespace qbs { MSBuildProperty::MSBuildProperty(MSBuildPropertyGroup *parent) : MSBuildPropertyBase(parent) { } MSBuildProperty::MSBuildProperty(const QString &name, const QVariant &value, MSBuildPropertyGroup *parent) : MSBuildProperty(parent) { setName(name); setValue(value); } void MSBuildProperty::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/imsbuildnode.h0000644000175100001660000000335714776170045021742 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef IMSBUILDNODE_H #define IMSBUILDNODE_H namespace qbs { class IMSBuildNodeVisitor; class IMSBuildNode { public: virtual ~IMSBuildNode(); virtual void accept(IMSBuildNodeVisitor *visitor) const = 0; }; } // namespace qbs #endif // IMSBUILDNODE_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildimport.h0000644000175100001660000000461614776170045022155 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDIMPORT_H #define MSBUILDIMPORT_H #include #include "imsbuildnode.h" #include namespace qbs { class MSBuildImportGroup; class MSBuildImportPrivate; class MSBuildProject; /*! * \brief The MSBuildImport class represents an MSBuild Import element. * * https://msdn.microsoft.com/en-us/library/92x05xfs.aspx */ class MSBuildImport : public QObject, public IMSBuildNode { Q_OBJECT Q_DISABLE_COPY(MSBuildImport) public: explicit MSBuildImport(MSBuildProject *parent); explicit MSBuildImport(MSBuildImportGroup *parent); ~MSBuildImport() override; QString project() const; void setProject(const QString &project); QString condition() const; void setCondition(const QString &condition); void accept(IMSBuildNodeVisitor *visitor) const override; private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDIMPORT_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditemmetadata.h0000644000175100001660000000435214776170045023277 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDITEMMETADATA_H #define MSBUILDITEMMETADATA_H #include "imsbuildnode.h" #include "msbuildpropertybase.h" namespace qbs { class MSBuildItem; /*! * \brief The MSBuildItemMetadata class represents an MSBuild ItemMetadata element. * * https://msdn.microsoft.com/en-us/library/ms164284.aspx */ class MSBuildItemMetadata : public MSBuildPropertyBase, public IMSBuildNode { Q_OBJECT Q_DISABLE_COPY(MSBuildItemMetadata) public: explicit MSBuildItemMetadata(MSBuildItem *parent = nullptr); MSBuildItemMetadata(const QString &name, const QVariant &value = QVariant(), MSBuildItem *parent = nullptr); void accept(IMSBuildNodeVisitor *visitor) const override; }; } // namespace qbs #endif // MSBUILDITEMMETADATA_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildproject.cpp0000644000175100001660000000611614776170045022641 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildproject.h" #include "imsbuildnodevisitor.h" #include "msbuildimport.h" #include "msbuildimportgroup.h" #include "msbuilditemdefinitiongroup.h" #include "msbuilditemgroup.h" #include "msbuildpropertygroup.h" namespace qbs { class MSBuildProjectPrivate { public: QString defaultTargets; QString toolsVersion; }; MSBuildProject::MSBuildProject(QObject *parent) : QObject(parent) , d(new MSBuildProjectPrivate) { } MSBuildProject::~MSBuildProject() = default; QString MSBuildProject::defaultTargets() const { return d->defaultTargets; } void MSBuildProject::setDefaultTargets(const QString &defaultTargets) { d->defaultTargets = defaultTargets; } QString MSBuildProject::toolsVersion() const { return d->toolsVersion; } void MSBuildProject::setToolsVersion(const QString &toolsVersion) { d->toolsVersion = toolsVersion; } void MSBuildProject::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); for (const auto &child : children()) { if (const auto node = qobject_cast(child)) node->accept(visitor); else if (const auto node = qobject_cast(child)) node->accept(visitor); else if (const auto node = qobject_cast(child)) node->accept(visitor); else if (const auto node = qobject_cast(child)) node->accept(visitor); else if (const auto node = qobject_cast(child)) node->accept(visitor); } visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditemdefinitiongroup.cpp0000644000175100001660000000411614776170045025255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuilditemdefinitiongroup.h" #include "imsbuildnodevisitor.h" #include "msbuilditem.h" namespace qbs { MSBuildItemDefinitionGroup::MSBuildItemDefinitionGroup(MSBuildProject *parent) : IMSBuildItemGroup(parent) { } MSBuildItemDefinitionGroup::~MSBuildItemDefinitionGroup() = default; void MSBuildItemDefinitionGroup::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); for (const auto &child : children()) { if (const auto item = qobject_cast(child)) item->accept(visitor); } visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildproperty.h0000644000175100001660000000427114776170045022524 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDPROPERTY_H #define MSBUILDPROPERTY_H #include "imsbuildnode.h" #include "msbuildpropertybase.h" namespace qbs { class MSBuildPropertyGroup; /*! * \brief The MSBuildProperty class represents an MSBuild Property element. * * https://msdn.microsoft.com/en-us/library/ms164288.aspx */ class MSBuildProperty : public MSBuildPropertyBase, public IMSBuildNode { Q_OBJECT public: explicit MSBuildProperty(MSBuildPropertyGroup *parent = nullptr); MSBuildProperty(const QString &name, const QVariant &value = QVariant(), MSBuildPropertyGroup *parent = nullptr); void accept(IMSBuildNodeVisitor *visitor) const override; }; } // namespace qbs #endif // MSBUILDPROPERTY_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildimport.cpp0000644000175100001660000000465414776170045022512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildimport.h" #include "imsbuildnodevisitor.h" #include "msbuildimportgroup.h" #include "msbuildproject.h" namespace qbs { class MSBuildImportPrivate { public: QString project; QString condition; }; MSBuildImport::MSBuildImport(MSBuildProject *parent) : QObject(parent) , d(new MSBuildImportPrivate) { } MSBuildImport::MSBuildImport(MSBuildImportGroup *parent) : QObject(parent) , d(new MSBuildImportPrivate) { } MSBuildImport::~MSBuildImport() = default; QString MSBuildImport::project() const { return d->project; } void MSBuildImport::setProject(const QString &project) { d->project = project; } QString MSBuildImport::condition() const { return d->condition; } void MSBuildImport::setCondition(const QString &condition) { d->condition = condition; } void MSBuildImport::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildproject.h0000644000175100001660000000452314776170045022306 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDPROJECT_H #define MSBUILDPROJECT_H #include #include "imsbuildnode.h" #include namespace qbs { class MSBuildProjectPrivate; /*! * \brief The MSBuildProject class represents an MSBuild Project element. * * https://msdn.microsoft.com/en-us/library/bcxfsh87.aspx */ class MSBuildProject : public QObject, public IMSBuildNode { Q_OBJECT Q_DISABLE_COPY(MSBuildProject) public: explicit MSBuildProject(QObject *parent = nullptr); ~MSBuildProject() override; QString defaultTargets() const; void setDefaultTargets(const QString &defaultTargets); QString toolsVersion() const; void setToolsVersion(const QString &toolsVersion); void accept(IMSBuildNodeVisitor *visitor) const override; private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDPROJECT_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildpropertygroup.cpp0000644000175100001660000000474714776170045024144 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildpropertygroup.h" #include "imsbuildnodevisitor.h" #include "msbuildproperty.h" namespace qbs { class MSBuildPropertyGroupPrivate { public: QString condition; QString label; }; MSBuildPropertyGroup::MSBuildPropertyGroup(MSBuildProject *parent) : IMSBuildGroup(parent) , d(new MSBuildPropertyGroupPrivate) { } MSBuildPropertyGroup::~MSBuildPropertyGroup() = default; QString MSBuildPropertyGroup::label() const { return d->label; } void MSBuildPropertyGroup::setLabel(const QString &label) { d->label = label; } void MSBuildPropertyGroup::appendProperty(const QString &name, const QVariant &value) { new MSBuildProperty(name, value, this); } void MSBuildPropertyGroup::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); for (const auto &child : children()) { if (const MSBuildProperty *property = qobject_cast(child)) property->accept(visitor); } visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditem.cpp0000644000175100001660000000524214776170045022130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuilditem.h" #include "imsbuildnodevisitor.h" #include "msbuilditemdefinitiongroup.h" #include "msbuilditemgroup.h" #include "msbuilditemmetadata.h" namespace qbs { class MSBuildItemPrivate { public: QString name = QStringLiteral("Item"); QString include; }; MSBuildItem::MSBuildItem(const QString &name, IMSBuildItemGroup *parent) : QObject(parent) , d(new MSBuildItemPrivate) { setName(name); } MSBuildItem::~MSBuildItem() = default; QString MSBuildItem::name() const { return d->name; } void MSBuildItem::setName(const QString &name) { d->name = name; } QString MSBuildItem::include() const { return d->include; } void MSBuildItem::setInclude(const QString &include) { d->include = include; } void MSBuildItem::appendProperty(const QString &name, const QVariant &value) { new MSBuildItemMetadata(name, value, this); } void MSBuildItem::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); for (const auto &child : children()) { if (const auto itemMetadata = qobject_cast(child)) itemMetadata->accept(visitor); } visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildimportgroup.h0000644000175100001660000000443114776170045023225 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDIMPORTGROUP_H #define MSBUILDIMPORTGROUP_H #include "imsbuildgroup.h" #include "imsbuildnode.h" namespace qbs { class MSBuildProject; class MSBuildImportGroupPrivate; /*! * \brief The MSBuildImportGroup class represents an MSBuild ImportGroup element. * * https://msdn.microsoft.com/en-us/library/ff606262.aspx */ class MSBuildImportGroup : public IMSBuildGroup, public IMSBuildNode { Q_OBJECT Q_DISABLE_COPY(MSBuildImportGroup) public: explicit MSBuildImportGroup(MSBuildProject *parent = nullptr); ~MSBuildImportGroup() override; QString label() const; void setLabel(const QString &label); void accept(IMSBuildNodeVisitor *visitor) const override; private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDIMPORTGROUP_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditem.h0000644000175100001660000000463514776170045021602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDITEM_H #define MSBUILDITEM_H #include #include "imsbuildnode.h" #include namespace qbs { class IMSBuildItemGroup; class MSBuildItemDefinitionGroup; class MSBuildItemGroup; class MSBuildItemPrivate; /*! * \brief The MSBuildItem class represents an MSBuild Item element. * * https://msdn.microsoft.com/en-us/library/ms164283.aspx */ class MSBuildItem : public QObject, public IMSBuildNode { Q_OBJECT public: explicit MSBuildItem(const QString &name, IMSBuildItemGroup *parent = nullptr); ~MSBuildItem() override; QString name() const; void setName(const QString &name); QString include() const; void setInclude(const QString &include); void appendProperty(const QString &name, const QVariant &value); void accept(IMSBuildNodeVisitor *visitor) const override; private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDITEM_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditemdefinitiongroup.h0000644000175100001660000000427514776170045024730 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDITEMDEFINITIONGROUP_H #define MSBUILDITEMDEFINITIONGROUP_H #include "imsbuildgroup.h" #include "imsbuildnode.h" namespace qbs { class MSBuildProject; class MSBuildItemDefinitionGroupPrivate; /*! * \brief The MSBuildItemDefinitionGroup class represents an MSBuild ItemDefinitionGroup element. * * https://msdn.microsoft.com/en-us/library/bb629392.aspx */ class MSBuildItemDefinitionGroup : public IMSBuildItemGroup, public IMSBuildNode { Q_OBJECT public: explicit MSBuildItemDefinitionGroup(MSBuildProject *parent = nullptr); ~MSBuildItemDefinitionGroup() override; void accept(IMSBuildNodeVisitor *visitor) const override; }; } // namespace qbs #endif // MSBUILDITEMDEFINITIONGROUP_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuilditemgroup.cpp0000644000175100001660000000444414776170045023210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuilditemgroup.h" #include "imsbuildnodevisitor.h" #include "msbuilditem.h" #include namespace qbs { class MSBuildItemGroupPrivate { public: QString label; }; MSBuildItemGroup::MSBuildItemGroup(MSBuildProject *parent) : IMSBuildItemGroup(parent) , d(new MSBuildItemGroupPrivate) { } MSBuildItemGroup::~MSBuildItemGroup() = default; QString MSBuildItemGroup::label() const { return d->label; } void MSBuildItemGroup::setLabel(const QString &label) { d->label = label; } void MSBuildItemGroup::accept(IMSBuildNodeVisitor *visitor) const { visitor->visitStart(this); for (const auto &child : children()) { if (const MSBuildItem *item = qobject_cast(child)) item->accept(visitor); } visitor->visitEnd(this); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/0000755000175100001660000000000014776170045020224 5ustar runnerdockerqbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildlink.h0000644000175100001660000000341114776170045022711 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDLINK_H #define MSBUILDLINK_H #include "../msbuilditem.h" namespace qbs { class IMSBuildItemGroup; class MSBuildLink : public MSBuildItem { Q_OBJECT public: explicit MSBuildLink(IMSBuildItemGroup *parent = nullptr); }; } // namespace qbs #endif // MSBUILDLINK_H qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildfileitem.cpp0000644000175100001660000000461014776170045024107 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildfileitem.h" #include #include "../msbuilditemmetadata.h" namespace qbs { class MSBuildFileItemPrivate { public: std::unique_ptr filter; }; MSBuildFileItem::MSBuildFileItem(const QString &name, IMSBuildItemGroup *parent) : MSBuildItem(name, parent) , d(new MSBuildFileItemPrivate) { d->filter = std::make_unique(QStringLiteral("Filter"), QVariant()); } MSBuildFileItem::~MSBuildFileItem() = default; QString MSBuildFileItem::filePath() const { return include(); } void MSBuildFileItem::setFilePath(const QString &filePath) { setInclude(filePath); } QString MSBuildFileItem::filterName() const { return d->filter->value().toString(); } void MSBuildFileItem::setFilterName(const QString &filterName) { d->filter->setValue(filterName); d->filter->setParent(!filterName.isEmpty() ? this : nullptr); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildfilter.cpp0000644000175100001660000000734114776170045023602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildfilter.h" #include "../msbuilditemmetadata.h" #include #include namespace qbs { static const QString MSBuildFilterItemName = QStringLiteral("Filter"); class MSBuildFilterPrivate { public: QUuid identifier; QList extensions; bool parseFiles = true; bool sourceControlFiles = true; MSBuildItemMetadata *identifierMetadata = nullptr; MSBuildItemMetadata *extensionsMetadata = nullptr; }; MSBuildFilter::MSBuildFilter(IMSBuildItemGroup *parent) : MSBuildItem(MSBuildFilterItemName, parent) , d(new MSBuildFilterPrivate) { d->identifierMetadata = new MSBuildItemMetadata(QStringLiteral("UniqueIdentifier"), QVariant(), this); d->extensionsMetadata = new MSBuildItemMetadata(QStringLiteral("Extensions"), QVariant(), this); setIdentifier(QUuid::createUuid()); } MSBuildFilter::MSBuildFilter(const QString &name, const QList &extensions, IMSBuildItemGroup *parent) : MSBuildFilter(parent) { setInclude(name); setExtensions(extensions); } MSBuildFilter::~MSBuildFilter() = default; QUuid MSBuildFilter::identifier() const { return d->identifier; } void MSBuildFilter::setIdentifier(const QUuid &identifier) { d->identifier = identifier; d->identifierMetadata->setValue(identifier.toString()); } QList MSBuildFilter::extensions() const { return d->extensions; } void MSBuildFilter::setExtensions(const QList &extensions) { d->extensions = extensions; d->extensionsMetadata->setValue(QStringList(extensions).join( Internal::HostOsInfo::pathListSeparator( Internal::HostOsInfo::HostOsWindows))); } bool MSBuildFilter::parseFiles() const { return d->parseFiles; } void MSBuildFilter::setParseFiles(bool parseFiles) { d->parseFiles = parseFiles; } bool MSBuildFilter::sourceControlFiles() const { return d->sourceControlFiles; } void MSBuildFilter::setSourceControlFiles(bool sourceControlFiles) { d->sourceControlFiles = sourceControlFiles; } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildnone.h0000644000175100001660000000342414776170045022717 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDNONE_H #define MSBUILDNONE_H #include "msbuildfileitem.h" namespace qbs { class MSBuildNone : public MSBuildFileItem { Q_OBJECT Q_DISABLE_COPY(MSBuildNone) public: explicit MSBuildNone(IMSBuildItemGroup *parent = nullptr); }; } // namespace qbs #endif // MSBUILDNONE_H qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildlink.cpp0000644000175100001660000000336014776170045023247 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildlink.h" #include "../imsbuildgroup.h" namespace qbs { static const QString MSBuildLinkItemName = QStringLiteral("Link"); MSBuildLink::MSBuildLink(IMSBuildItemGroup *parent) : MSBuildItem(MSBuildLinkItemName, parent) { } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildclcompile.cpp0000644000175100001660000000336314776170045024264 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildclcompile.h" namespace qbs { static const QString MSBuildClCompileItemName = QStringLiteral("ClCompile"); MSBuildClCompile::MSBuildClCompile(IMSBuildItemGroup *parent) : MSBuildFileItem(MSBuildClCompileItemName, parent) { } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildclinclude.h0000644000175100001660000000346214776170045023724 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDCLINCLUDE_H #define MSBUILDCLINCLUDE_H #include "msbuildfileitem.h" namespace qbs { class MSBuildClInclude : public MSBuildFileItem { Q_OBJECT Q_DISABLE_COPY(MSBuildClInclude) public: explicit MSBuildClInclude(IMSBuildItemGroup *parent = nullptr); }; } // namespace qbs #endif // MSBUILDCLINCLUDE_H qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildfileitem.h0000644000175100001660000000406214776170045023555 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDFILEITEM_H #define MSBUILDFILEITEM_H #include "../msbuilditem.h" namespace qbs { class MSBuildFileItemPrivate; class MSBuildFileItem : public MSBuildItem { public: ~MSBuildFileItem() override; QString filePath() const; void setFilePath(const QString &filePath); QString filterName() const; void setFilterName(const QString &filterName); protected: explicit MSBuildFileItem(const QString &name, IMSBuildItemGroup *parent = nullptr); private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDFILEITEM_H qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildclinclude.cpp0000644000175100001660000000336314776170045024257 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildclinclude.h" namespace qbs { static const QString MSBuildClIncludeItemName = QStringLiteral("ClInclude"); MSBuildClInclude::MSBuildClInclude(IMSBuildItemGroup *parent) : MSBuildFileItem(MSBuildClIncludeItemName, parent) { } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildclcompile.h0000644000175100001660000000346214776170045023731 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDCLCOMPILE_H #define MSBUILDCLCOMPILE_H #include "msbuildfileitem.h" namespace qbs { class MSBuildClCompile : public MSBuildFileItem { Q_OBJECT Q_DISABLE_COPY(MSBuildClCompile) public: explicit MSBuildClCompile(IMSBuildItemGroup *parent = nullptr); }; } // namespace qbs #endif // MSBUILDCLCOMPILE_H qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildnone.cpp0000644000175100001660000000322414776170045023250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildnone.h" namespace qbs { MSBuildNone::MSBuildNone(IMSBuildItemGroup *parent) : MSBuildFileItem(QStringLiteral("None"), parent) { } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild/items/msbuildfilter.h0000644000175100001660000000453614776170045023252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDFILTER_H #define MSBUILDFILTER_H #include "../msbuilditem.h" namespace qbs { class IMSBuildItemGroup; class MSBuildFilterPrivate; class MSBuildFilter : public MSBuildItem { Q_OBJECT public: explicit MSBuildFilter(IMSBuildItemGroup *parent = nullptr); MSBuildFilter(const QString &name, const QList &extensions, IMSBuildItemGroup *parent = nullptr); ~MSBuildFilter() override; QUuid identifier() const; void setIdentifier(const QUuid &identifier); QList extensions() const; void setExtensions(const QList &extensions); bool parseFiles() const; void setParseFiles(bool parseFiles); bool sourceControlFiles() const; void setSourceControlFiles(bool sourceControlFiles); private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDFILTER_H qbs-src-2.6.1/src/lib/msbuild/msbuild/msbuildpropertygroup.h0000644000175100001660000000456514776170045023607 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDPROPERTYGROUP_H #define MSBUILDPROPERTYGROUP_H #include "imsbuildgroup.h" #include "imsbuildnode.h" namespace qbs { class MSBuildProject; class MSBuildPropertyGroupPrivate; /*! * \brief The MSBuildPropertyGroup class represents an MSBuild PropertyGroup element. * * https://msdn.microsoft.com/en-us/library/t4w159bs.aspx */ class MSBuildPropertyGroup : public IMSBuildGroup, public IMSBuildNode { Q_OBJECT Q_DISABLE_COPY(MSBuildPropertyGroup) public: explicit MSBuildPropertyGroup(MSBuildProject *parent = nullptr); ~MSBuildPropertyGroup() override; QString label() const; void setLabel(const QString &label); void appendProperty(const QString &name, const QVariant &value); void accept(IMSBuildNodeVisitor *visitor) const override; private: std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDPROPERTYGROUP_H qbs-src-2.6.1/src/lib/msbuild/io/0000755000175100001660000000000014776170045016053 5ustar runnerdockerqbs-src-2.6.1/src/lib/msbuild/io/visualstudiosolutionwriter.h0000644000175100001660000000443214776170045024014 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef VISUALSTUDIOSOLUTIONWRITER_H #define VISUALSTUDIOSOLUTIONWRITER_H #include #include #include #include namespace qbs { namespace Internal { class VisualStudioVersionInfo; } class VisualStudioSolution; class VisualStudioSolutionWriterPrivate; class VisualStudioSolutionWriter { Q_DISABLE_COPY(VisualStudioSolutionWriter) public: explicit VisualStudioSolutionWriter(std::ostream *device); ~VisualStudioSolutionWriter(); std::string projectBaseDirectory() const; void setProjectBaseDirectory(const std::string &dir); bool write(const VisualStudioSolution *solution); private: void addDefaultGlobalSections(); std::unique_ptr d; }; } // namespace qbs #endif // VISUALSTUDIOSOLUTIONWRITER_H qbs-src-2.6.1/src/lib/msbuild/io/visualstudiosolutionwriter.cpp0000644000175100001660000001214314776170045024345 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "visualstudiosolutionwriter.h" #include "../solution/visualstudiosolutionfileproject.h" #include "../solution/visualstudiosolutionfolderproject.h" #include "../solution/visualstudiosolutionglobalsection.h" #include "../solution/visualstudiosolution.h" #include #include #include #include #include #include #include #include #include namespace qbs { using namespace Internal; class VisualStudioSolutionWriterPrivate { public: std::ostream *device = nullptr; std::string baseDir; }; VisualStudioSolutionWriter::VisualStudioSolutionWriter(std::ostream *device) : d(new VisualStudioSolutionWriterPrivate) { d->device = device; } VisualStudioSolutionWriter::~VisualStudioSolutionWriter() = default; std::string VisualStudioSolutionWriter::projectBaseDirectory() const { return d->baseDir; } void VisualStudioSolutionWriter::setProjectBaseDirectory(const std::string &dir) { d->baseDir = dir; } bool VisualStudioSolutionWriter::write(const VisualStudioSolution *solution) { auto &out = *d->device; out << "Microsoft Visual Studio Solution File, Format Version " << solution->versionInfo().solutionVersion().toStdString() << "\n# Visual Studio " << solution->versionInfo().version().majorVersion() << "\n"; const auto fileProjects = solution->fileProjects(); for (const auto &project : fileProjects) { auto projectFilePath = project->filePath().toStdString(); // Try to make the project file path relative to the // solution file path if we're writing to a file device if (!d->baseDir.empty()) { const QDir solutionDir(QString::fromStdString(d->baseDir)); projectFilePath = Internal::PathUtils::toNativeSeparators( solutionDir.relativeFilePath(QString::fromStdString(projectFilePath)), Internal::HostOsInfo::HostOsWindows).toStdString(); } out << "Project(\"" << project->projectTypeGuid().toString().toStdString() << "\") = \"" << QFileInfo(QString::fromStdString(projectFilePath)).baseName().toStdString() << "\", \"" << projectFilePath << "\", \"" << project->guid().toString().toStdString() << "\"\n"; out << "EndProject\n"; } const auto folderProjects = solution->folderProjects(); for (const auto &project : folderProjects) { out << "Project(\"" << project->projectTypeGuid().toString().toStdString() << "\") = \"" << project->name().toStdString() << "\", \"" << project->name().toStdString() << "\", \"" << project->guid().toString().toStdString() << "\"\n"; out << "EndProject\n"; } out << "Global\n"; const auto globalSections = solution->globalSections(); for (const auto &globalSection : globalSections) { out << "\tGlobalSection(" << globalSection->name().toStdString() << ") = " << (globalSection->isPost() ? "postSolution" : "preSolution") << "\n"; for (const auto &property : globalSection->properties()) out << "\t\t" << property.first.toStdString() << " = " << property.second.toStdString() << "\n"; out << "\tEndGlobalSection\n"; } out << "EndGlobal\n"; return out.good(); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/io/msbuildprojectwriter.h0000644000175100001660000000400614776170045022507 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef MSBUILDPROJECTWRITER_H #define MSBUILDPROJECTWRITER_H #include #include #include namespace qbs { class MSBuildProject; class MSBuildProjectWriterPrivate; class MSBuildProjectWriter { Q_DISABLE_COPY(MSBuildProjectWriter) public: explicit MSBuildProjectWriter(std::ostream *device); ~MSBuildProjectWriter(); bool write(const MSBuildProject *project); private: const std::unique_ptr d; }; } // namespace qbs #endif // MSBUILDPROJECTWRITER_H qbs-src-2.6.1/src/lib/msbuild/io/msbuildprojectwriter.cpp0000644000175100001660000002051014776170045023040 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "msbuildprojectwriter.h" #include "../msbuild/imsbuildnodevisitor.h" #include "../msbuild/msbuildimport.h" #include "../msbuild/msbuildimportgroup.h" #include "../msbuild/msbuilditem.h" #include "../msbuild/msbuilditemdefinitiongroup.h" #include "../msbuild/msbuilditemgroup.h" #include "../msbuild/msbuilditemmetadata.h" #include "../msbuild/msbuildproject.h" #include "../msbuild/msbuildproperty.h" #include "../msbuild/msbuildpropertygroup.h" #include #include namespace qbs { static const QString kMSBuildSchemaURI = QStringLiteral("http://schemas.microsoft.com/developer/msbuild/2003"); class MSBuildProjectWriterPrivate : public IMSBuildNodeVisitor { public: std::ostream *device = nullptr; QByteArray buffer; std::unique_ptr writer; void visitStart(const MSBuildImport *import) override; void visitEnd(const MSBuildImport *import) override; void visitStart(const MSBuildImportGroup *importGroup) override; void visitEnd(const MSBuildImportGroup *importGroup) override; void visitStart(const MSBuildItem *item) override; void visitEnd(const MSBuildItem *item) override; void visitStart(const MSBuildItemDefinitionGroup *itemDefinitionGroup) override; void visitEnd(const MSBuildItemDefinitionGroup *itemDefinitionGroup) override; void visitStart(const MSBuildItemGroup *itemGroup) override; void visitEnd(const MSBuildItemGroup *itemGroup) override; void visitStart(const MSBuildItemMetadata *itemMetadata) override; void visitEnd(const MSBuildItemMetadata *itemMetadata) override; void visitStart(const MSBuildProject *project) override; void visitEnd(const MSBuildProject *project) override; void visitStart(const MSBuildProperty *property) override; void visitEnd(const MSBuildProperty *property) override; void visitStart(const MSBuildPropertyGroup *propertyGroup) override; void visitEnd(const MSBuildPropertyGroup *propertyGroup) override; }; MSBuildProjectWriter::MSBuildProjectWriter(std::ostream *device) : d(std::make_unique()) { d->device = device; d->writer = std::make_unique(&d->buffer); d->writer->setAutoFormatting(true); } MSBuildProjectWriter::~MSBuildProjectWriter() = default; bool MSBuildProjectWriter::write(const MSBuildProject *project) { d->buffer.clear(); d->writer->writeStartDocument(); project->accept(d.get()); d->writer->writeEndDocument(); if (d->writer->hasError()) return false; d->device->write(&*std::begin(d->buffer), d->buffer.size()); return d->device->good(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildImport *import) { writer->writeStartElement(QStringLiteral("Import")); writer->writeAttribute(QStringLiteral("Project"), import->project()); if (!import->condition().isEmpty()) writer->writeAttribute(QStringLiteral("Condition"), import->condition()); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildImport *) { writer->writeEndElement(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildImportGroup *importGroup) { writer->writeStartElement(QStringLiteral("ImportGroup")); if (!importGroup->condition().isEmpty()) writer->writeAttribute(QStringLiteral("Condition"), importGroup->condition()); if (!importGroup->label().isEmpty()) writer->writeAttribute(QStringLiteral("Label"), importGroup->label()); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildImportGroup *) { writer->writeEndElement(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildItem *item) { writer->writeStartElement(item->name()); if (!item->include().isEmpty()) writer->writeAttribute(QStringLiteral("Include"), item->include()); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildItem *) { writer->writeEndElement(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildItemDefinitionGroup *itemDefinitionGroup) { writer->writeStartElement(QStringLiteral("ItemDefinitionGroup")); if (!itemDefinitionGroup->condition().isEmpty()) writer->writeAttribute(QStringLiteral("Condition"), itemDefinitionGroup->condition()); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildItemDefinitionGroup *) { writer->writeEndElement(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildItemGroup *itemGroup) { writer->writeStartElement(QStringLiteral("ItemGroup")); if (!itemGroup->condition().isEmpty()) writer->writeAttribute(QStringLiteral("Condition"), itemGroup->condition()); if (!itemGroup->label().isEmpty()) writer->writeAttribute(QStringLiteral("Label"), itemGroup->label()); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildItemGroup *) { writer->writeEndElement(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildItemMetadata *itemMetadata) { QString stringValue; if (itemMetadata->value().userType() == QMetaType::Bool) { stringValue = itemMetadata->value().toBool() ? QStringLiteral("True") : QStringLiteral("False"); } else { stringValue = itemMetadata->value().toString(); } writer->writeTextElement(itemMetadata->name(), stringValue); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildItemMetadata *) { } void MSBuildProjectWriterPrivate::visitStart(const MSBuildProject *project) { writer->writeStartElement(QStringLiteral("Project")); if (!project->defaultTargets().isEmpty()) writer->writeAttribute(QStringLiteral("DefaultTargets"), project->defaultTargets()); if (!project->toolsVersion().isEmpty()) writer->writeAttribute(QStringLiteral("ToolsVersion"), project->toolsVersion()); writer->writeAttribute(QStringLiteral("xmlns"), kMSBuildSchemaURI); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildProject *) { writer->writeEndElement(); } void MSBuildProjectWriterPrivate::visitStart(const MSBuildProperty *property) { QString stringValue; if (property->value().userType() == QMetaType::Bool) stringValue = property->value().toBool() ? QStringLiteral("True") : QStringLiteral("False"); else stringValue = property->value().toString(); writer->writeTextElement(property->name(), stringValue); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildProperty *) { } void MSBuildProjectWriterPrivate::visitStart(const MSBuildPropertyGroup *propertyGroup) { writer->writeStartElement(QStringLiteral("PropertyGroup")); if (!propertyGroup->condition().isEmpty()) writer->writeAttribute(QStringLiteral("Condition"), propertyGroup->condition()); if (!propertyGroup->label().isEmpty()) writer->writeAttribute(QStringLiteral("Label"), propertyGroup->label()); } void MSBuildProjectWriterPrivate::visitEnd(const MSBuildPropertyGroup *) { writer->writeEndElement(); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/solution/0000755000175100001660000000000014776170045017320 5ustar runnerdockerqbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolutionglobalsection.h0000644000175100001660000000453314776170045026574 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef VISUALSTUDIOSOLUTIONGLOBALSECTION_H #define VISUALSTUDIOSOLUTIONGLOBALSECTION_H #include #include namespace qbs { class VisualStudioSolutionGlobalSectionPrivate; class VisualStudioSolutionGlobalSection : public QObject { Q_OBJECT Q_DISABLE_COPY(VisualStudioSolutionGlobalSection) public: explicit VisualStudioSolutionGlobalSection(const QString &name, QObject *parent = nullptr); ~VisualStudioSolutionGlobalSection() override; QString name() const; void setName(const QString &name); bool isPost() const; void setPost(bool post); std::vector > properties() const; void appendProperty(const QString &key, const QString &value); private: std::unique_ptr d; }; } // namespace qbs #endif // VISUALSTUDIOSOLUTIONGLOBALSECTION_H qbs-src-2.6.1/src/lib/msbuild/solution/ivisualstudiosolutionproject.cpp0000644000175100001660000000434414776170045026121 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "ivisualstudiosolutionproject.h" namespace qbs { class IVisualStudioSolutionProjectPrivate { public: QUuid guid = QUuid::createUuid(); QString name; QString filePath; }; IVisualStudioSolutionProject::IVisualStudioSolutionProject(QObject *parent) : QObject(parent) , d(new IVisualStudioSolutionProjectPrivate) { } IVisualStudioSolutionProject::~IVisualStudioSolutionProject() = default; QUuid IVisualStudioSolutionProject::guid() const { return d->guid; } void IVisualStudioSolutionProject::setGuid(const QUuid &guid) { d->guid = guid; } QString IVisualStudioSolutionProject::name() const { return d->name; } void IVisualStudioSolutionProject::setName(const QString &name) { d->name = name; } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/solution/ivisualstudiosolutionproject.h0000644000175100001660000000434314776170045025565 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef IVISUALSTUDIOSOLUTIONPROJECT_H #define IVISUALSTUDIOSOLUTIONPROJECT_H #include #include #include #include namespace qbs { class IVisualStudioSolutionProjectPrivate; class IVisualStudioSolutionProject : public QObject { Q_OBJECT protected: explicit IVisualStudioSolutionProject(QObject *parent = nullptr); public: ~IVisualStudioSolutionProject() override; virtual QUuid projectTypeGuid() const = 0; QUuid guid() const; void setGuid(const QUuid &guid); virtual QString name() const; void setName(const QString &name); private: std::unique_ptr d; }; } // namespace qbs #endif // IVISUALSTUDIOSOLUTIONPROJECT_H qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolution.h0000644000175100001660000000616414776170045024030 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef VISUALSTUDIOSOLUTION_H #define VISUALSTUDIOSOLUTION_H #include #include namespace qbs { namespace Internal { class VisualStudioVersionInfo; } class MSBuildProject; class IVisualStudioSolutionProject; class VisualStudioSolutionFileProject; class VisualStudioSolutionFolderProject; class VisualStudioSolutionGlobalSection; class VisualStudioSolutionPrivate; class VisualStudioSolution : public QObject { Q_OBJECT Q_DISABLE_COPY(VisualStudioSolution) public: explicit VisualStudioSolution(const Internal::VisualStudioVersionInfo &versionInfo, QObject *parent = nullptr); ~VisualStudioSolution() override; Internal::VisualStudioVersionInfo versionInfo() const; QList projects() const; QList fileProjects() const; QList folderProjects() const; void appendProject(IVisualStudioSolutionProject *project); void removeProject(const IVisualStudioSolutionProject *project); void clearProjects(); QList dependencies( VisualStudioSolutionFileProject *project) const; void addDependency(VisualStudioSolutionFileProject *project, VisualStudioSolutionFileProject *dependency); QList globalSections() const; void appendGlobalSection(VisualStudioSolutionGlobalSection *globalSection); private: void addDefaultGlobalSections(); std::unique_ptr d; }; } // namespace qbs #endif // VISUALSTUDIOSOLUTION_H qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolutionfolderproject.h0000644000175100001660000000366114776170045026612 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef VISUALSTUDIOSOLUTIONFOLDERPROJECT_H #define VISUALSTUDIOSOLUTIONFOLDERPROJECT_H #include #include "ivisualstudiosolutionproject.h" namespace qbs { class VisualStudioSolutionFolderProject : public IVisualStudioSolutionProject { Q_OBJECT public: explicit VisualStudioSolutionFolderProject(QObject *parent); QUuid projectTypeGuid() const override; }; } // namespace qbs #endif // VISUALSTUDIOSOLUTIONFOLDERPROJECT_H qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolutionfileproject.cpp0000644000175100001660000000515214776170045026606 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "visualstudiosolutionfileproject.h" #include namespace qbs { class VisualStudioSolutionFileProjectPrivate { public: QString filePath; }; VisualStudioSolutionFileProject::VisualStudioSolutionFileProject(const QString &filePath, QObject *parent) : IVisualStudioSolutionProject(parent) , d(new VisualStudioSolutionFileProjectPrivate) { setFilePath(filePath); } VisualStudioSolutionFileProject::~VisualStudioSolutionFileProject() = default; QString VisualStudioSolutionFileProject::name() const { auto projectName = IVisualStudioSolutionProject::name(); if (projectName.isEmpty()) return QFileInfo(filePath()).baseName(); return projectName; } QUuid VisualStudioSolutionFileProject::projectTypeGuid() const { return QUuid::fromString(QStringLiteral("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")); // C++ } QString VisualStudioSolutionFileProject::filePath() const { return d->filePath; } void VisualStudioSolutionFileProject::setFilePath(const QString &filePath) { d->filePath = filePath; } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolutionfolderproject.cpp0000644000175100001660000000357614776170045027152 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "visualstudiosolutionfolderproject.h" #include namespace qbs { VisualStudioSolutionFolderProject::VisualStudioSolutionFolderProject(QObject *parent) : IVisualStudioSolutionProject(parent) { } QUuid VisualStudioSolutionFolderProject::projectTypeGuid() const { return QUuid::fromString(QStringLiteral("{2150E333-8FDC-42A3-9474-1A3956D46DE8}")); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolutionfileproject.h0000644000175100001660000000437014776170045026254 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef VISUALSTUDIOSOLUTIONFILEPROJECT_H #define VISUALSTUDIOSOLUTIONFILEPROJECT_H #include #include "ivisualstudiosolutionproject.h" #include namespace qbs { class VisualStudioSolutionFileProjectPrivate; class VisualStudioSolutionFileProject : public IVisualStudioSolutionProject { Q_OBJECT public: explicit VisualStudioSolutionFileProject(const QString &filePath, QObject *parent = nullptr); ~VisualStudioSolutionFileProject() override; QString name() const override; QString filePath() const; void setFilePath(const QString &filePath); QUuid projectTypeGuid() const override; private: std::unique_ptr d; }; } // namespace qbs #endif // VISUALSTUDIOSOLUTIONFILEPROJECT_H qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolution.cpp0000644000175100001660000001015514776170045024356 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "visualstudiosolution.h" #include "visualstudiosolutionfileproject.h" #include "visualstudiosolutionfolderproject.h" #include #include namespace qbs { class VisualStudioSolutionPrivate { public: VisualStudioSolutionPrivate(const Internal::VisualStudioVersionInfo &versionInfo) : versionInfo(versionInfo) { } const Internal::VisualStudioVersionInfo versionInfo; QList projects; QMap> dependencies; QList globalSections; }; VisualStudioSolution::VisualStudioSolution(const Internal::VisualStudioVersionInfo &versionInfo, QObject *parent) : QObject(parent) , d(new VisualStudioSolutionPrivate(versionInfo)) { } VisualStudioSolution::~VisualStudioSolution() = default; Internal::VisualStudioVersionInfo VisualStudioSolution::versionInfo() const { return d->versionInfo; } QList VisualStudioSolution::projects() const { return d->projects; } QList VisualStudioSolution::fileProjects() const { QList list; for (const auto &project : std::as_const(d->projects)) if (auto fileProject = qobject_cast(project)) list.push_back(fileProject); return list; } QList VisualStudioSolution::folderProjects() const { QList list; for (const auto &project : std::as_const(d->projects)) if (auto folderProject = qobject_cast(project)) list.push_back(folderProject); return list; } void VisualStudioSolution::appendProject(IVisualStudioSolutionProject *project) { d->projects.push_back(project); } QList VisualStudioSolution::dependencies( VisualStudioSolutionFileProject *project) const { return d->dependencies.value(project); } void VisualStudioSolution::addDependency(VisualStudioSolutionFileProject *project, VisualStudioSolutionFileProject *dependency) { d->dependencies[project].push_back(dependency); } QList VisualStudioSolution::globalSections() const { return d->globalSections; } void VisualStudioSolution::appendGlobalSection(VisualStudioSolutionGlobalSection *globalSection) { d->globalSections.push_back(globalSection); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/solution/visualstudiosolutionglobalsection.cpp0000644000175100001660000000531414776170045027125 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "visualstudiosolutionglobalsection.h" #include #include namespace qbs { class VisualStudioSolutionGlobalSectionPrivate { public: QString name; std::vector> properties; bool post = false; }; VisualStudioSolutionGlobalSection::VisualStudioSolutionGlobalSection(const QString &name, QObject *parent) : QObject(parent) , d(new VisualStudioSolutionGlobalSectionPrivate) { setName(name); } VisualStudioSolutionGlobalSection::~VisualStudioSolutionGlobalSection() = default; QString VisualStudioSolutionGlobalSection::name() const { return d->name; } void VisualStudioSolutionGlobalSection::setName(const QString &name) { d->name = name; } bool VisualStudioSolutionGlobalSection::isPost() const { return d->post; } void VisualStudioSolutionGlobalSection::setPost(bool post) { d->post = post; } std::vector > VisualStudioSolutionGlobalSection::properties() const { return d->properties; } void VisualStudioSolutionGlobalSection::appendProperty(const QString &key, const QString &value) { d->properties.emplace_back(key, value); } } // namespace qbs qbs-src-2.6.1/src/lib/msbuild/msbuild.qbs0000644000175100001660000000511414776170045017613 0ustar runnerdockerQbsStaticLibrary { Depends { name: "cpp" } Depends { name: "qbscore" } name: "qbsmsbuild" cpp.visibility: "default" cpp.includePaths: base.concat([ ".", "../corelib", // for some header-only functions in tools ]) Group { name: "Solution Object Model" prefix: "solution/" files: [ "ivisualstudiosolutionproject.cpp", "ivisualstudiosolutionproject.h", "visualstudiosolutionfileproject.cpp", "visualstudiosolutionfileproject.h", "visualstudiosolutionfolderproject.cpp", "visualstudiosolutionfolderproject.h", "visualstudiosolution.cpp", "visualstudiosolution.h", "visualstudiosolutionglobalsection.cpp", "visualstudiosolutionglobalsection.h", ] } Group { name: "MSBuild Object Model" prefix: "msbuild/" files: [ "imsbuildgroup.cpp", "imsbuildgroup.h", "imsbuildnode.cpp", "imsbuildnode.h", "imsbuildnodevisitor.h", "msbuildimport.cpp", "msbuildimport.h", "msbuildimportgroup.cpp", "msbuildimportgroup.h", "msbuilditem.cpp", "msbuilditem.h", "msbuilditemdefinitiongroup.cpp", "msbuilditemdefinitiongroup.h", "msbuilditemgroup.cpp", "msbuilditemgroup.h", "msbuilditemmetadata.cpp", "msbuilditemmetadata.h", "msbuildproject.cpp", "msbuildproject.h", "msbuildproperty.cpp", "msbuildproperty.h", "msbuildpropertybase.cpp", "msbuildpropertybase.h", "msbuildpropertygroup.cpp", "msbuildpropertygroup.h", ] } Group { name: "MSBuild Object Model Items" prefix: "msbuild/items/" files: [ "msbuildclcompile.cpp", "msbuildclcompile.h", "msbuildclinclude.cpp", "msbuildclinclude.h", "msbuildfileitem.cpp", "msbuildfileitem.h", "msbuildfilter.cpp", "msbuildfilter.h", "msbuildlink.cpp", "msbuildlink.h", "msbuildnone.cpp", "msbuildnone.h", ] } Group { name: "Visual Studio Object Model I/O" prefix: "io/" files: [ "msbuildprojectwriter.cpp", "msbuildprojectwriter.h", "visualstudiosolutionwriter.cpp", "visualstudiosolutionwriter.h", ] } } qbs-src-2.6.1/src/lib/msbuild/CMakeLists.txt0000644000175100001660000000344414776170045020211 0ustar runnerdockerset(SOLUTION_SOURCES ivisualstudiosolutionproject.cpp ivisualstudiosolutionproject.h visualstudiosolutionfileproject.cpp visualstudiosolutionfileproject.h visualstudiosolutionfolderproject.cpp visualstudiosolutionfolderproject.h visualstudiosolution.cpp visualstudiosolution.h visualstudiosolutionglobalsection.cpp visualstudiosolutionglobalsection.h ) list_transform_prepend(SOLUTION_SOURCES solution/) set(MSBUILD_SOURCES imsbuildgroup.cpp imsbuildgroup.h imsbuildnode.cpp imsbuildnode.h imsbuildnodevisitor.h msbuildimport.cpp msbuildimport.h msbuildimportgroup.cpp msbuildimportgroup.h msbuilditem.cpp msbuilditem.h msbuilditemdefinitiongroup.cpp msbuilditemdefinitiongroup.h msbuilditemgroup.cpp msbuilditemgroup.h msbuilditemmetadata.cpp msbuilditemmetadata.h msbuildproject.cpp msbuildproject.h msbuildproperty.cpp msbuildproperty.h msbuildpropertybase.cpp msbuildpropertybase.h msbuildpropertygroup.cpp msbuildpropertygroup.h ) list_transform_prepend(MSBUILD_SOURCES msbuild/) set(MSBUILD_ITEMS_SOURCES msbuildclcompile.cpp msbuildclcompile.h msbuildclinclude.cpp msbuildclinclude.h msbuildfileitem.cpp msbuildfileitem.h msbuildfilter.cpp msbuildfilter.h msbuildlink.cpp msbuildlink.h msbuildnone.cpp msbuildnone.h ) list_transform_prepend(MSBUILD_ITEMS_SOURCES msbuild/items/) set(IO_SOURCES msbuildprojectwriter.cpp msbuildprojectwriter.h visualstudiosolutionwriter.cpp visualstudiosolutionwriter.h ) list_transform_prepend(IO_SOURCES io/) add_qbs_library(qbsmsbuild STATIC DEPENDS qbscore SOURCES ${SOLUTION_SOURCES} ${MSBUILD_SOURCES} ${MSBUILD_ITEMS_SOURCES} ${IO_SOURCES} ) qbs-src-2.6.1/src/lib/corelib/0000755000175100001660000000000014776170045015424 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/corelib.qbs0000644000175100001660000004077514776170045017567 0ustar runnerdockerimport qbs.Utilities QbsLibrary { Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["core-private", "network", "xml"] } Depends { name: "Qt.core5compat"; condition: Utilities.versionCompare(Qt.core.version, "6.0.0") >= 0 } Depends { name: "quickjs" } Depends { name: "qbspkgconfig" } name: "qbscore" cpp.includePaths: base.concat([ ".", "../.." // for the plugin headers ]) cpp.defines: { var defines = base.concat([ "QBS_RELATIVE_LIBEXEC_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeLibexecPath), "QBS_VERSION=" + Utilities.cStringQuote(version), ]); if (project.withTests) defines.push("QBS_WITH_TESTS"); if (qbsbuildconfig.enableUnitTests) defines.push("QBS_ENABLE_UNIT_TESTS"); if (qbsbuildconfig.systemSettingsDir) defines.push('QBS_SYSTEM_SETTINGS_DIR="' + qbsbuildconfig.systemSettingsDir + '"'); defines.push("CPLUSPLUS_NO_PARSER"); return defines; } Properties { condition: qbs.targetOS.contains("windows") cpp.dynamicLibraries: ["psapi", "shell32"] } Properties { condition: qbs.toolchain.contains("mingw") cpp.cxxFlags: "-Wa,-mbig-obj" } Properties { cpp.dynamicLibraries: base } Properties { condition: qbs.targetOS.contains("darwin") cpp.frameworks: ["Foundation", "Security"] } Group { name: product.name files: ["qbs.h"] qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix } Group { name: "project file updating" prefix: "api/" files: [ "changeset.cpp", "changeset.h", "projectfileupdater.cpp", "projectfileupdater.h", "qmljsrewriter.cpp", "qmljsrewriter.h", ] } Group { name: "api" prefix: name + '/' files: [ "internaljobs.cpp", "internaljobs.h", "jobs.cpp", "languageinfo.cpp", "project.cpp", "project_p.h", "projectdata.cpp", "projectdata_p.h", "propertymap_p.h", "rulecommand.cpp", "rulecommand_p.h", "runenvironment.cpp", "transformerdata.cpp", "transformerdata_p.h", ] } Group { name: "public api headers" qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix + "/api" prefix: "api/" files: [ "jobs.h", "languageinfo.h", "project.h", "projectdata.h", "rulecommand.h", "runenvironment.h", "transformerdata.h", ] } Group { name: "buildgraph" prefix: name + '/' files: [ "abstractcommandexecutor.cpp", "abstractcommandexecutor.h", "artifact.cpp", "artifact.h", "artifactcleaner.cpp", "artifactcleaner.h", "artifactsscriptvalue.cpp", "artifactsscriptvalue.h", "artifactvisitor.cpp", "artifactvisitor.h", "buildgraph.cpp", "buildgraph.h", "buildgraphnode.cpp", "buildgraphnode.h", "buildgraphloader.cpp", "buildgraphloader.h", "buildgraphvisitor.h", "cppmodulesscanner.cpp", "cppmodulesscanner.h", "cycledetector.cpp", "cycledetector.h", "dependencyparametersscriptvalue.cpp", "dependencyparametersscriptvalue.h", "depscanner.cpp", "depscanner.h", "emptydirectoriesremover.cpp", "emptydirectoriesremover.h", "environmentscriptrunner.cpp", "environmentscriptrunner.h", "executor.cpp", "executor.h", "executorjob.cpp", "executorjob.h", "filedependency.cpp", "filedependency.h", "inputartifactscanner.cpp", "inputartifactscanner.h", "jscommandexecutor.cpp", "jscommandexecutor.h", "nodeset.cpp", "nodeset.h", "nodetreedumper.cpp", "nodetreedumper.h", "processcommandexecutor.cpp", "processcommandexecutor.h", "productbuilddata.cpp", "productbuilddata.h", "productinstaller.cpp", "productinstaller.h", "projectbuilddata.cpp", "projectbuilddata.h", "qtmocscanner.cpp", "qtmocscanner.h", "rawscanneddependency.cpp", "rawscanneddependency.h", "rawscanresults.cpp", "rawscanresults.h", "requestedartifacts.cpp", "requestedartifacts.h", "requesteddependencies.cpp", "requesteddependencies.h", "rescuableartifactdata.h", "rulecommands.cpp", "rulecommands.h", "rulegraph.cpp", "rulegraph.h", "rulenode.cpp", "rulenode.h", "rulesapplicator.cpp", "rulesapplicator.h", "rulesevaluationcontext.cpp", "rulesevaluationcontext.h", "timestampsupdater.cpp", "timestampsupdater.h", "transformer.cpp", "transformer.h", "transformerchangetracking.cpp", "transformerchangetracking.h", ] } Group { name: "public buildgraph headers" qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix + "/buildgraph" files: "buildgraph/forward_decls.h" } Group { name: "generators" prefix: "generators/" files: [ "generatableprojectiterator.cpp", "generatableprojectiterator.h", "generator.cpp", "generatordata.cpp", "generatorutils.cpp", "generatorutils.h", "generatorversioninfo.cpp", "generatorversioninfo.h", "igeneratableprojectvisitor.h", "ixmlnodevisitor.h", "xmlproject.cpp", "xmlproject.h", "xmlprojectwriter.cpp", "xmlprojectwriter.h", "xmlproperty.cpp", "xmlproperty.h", "xmlpropertygroup.cpp", "xmlpropertygroup.h", "xmlworkspace.cpp", "xmlworkspace.h", "xmlworkspacewriter.cpp", "xmlworkspacewriter.h", ] } Group { name: "public generator headers" prefix: "generators/" qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix + "/generators" files: [ "generator.h", "generatordata.h", ] } Group { name: "jsextensions" prefix: name + '/' files: [ "environmentextension.cpp", "file.cpp", "fileinfoextension.cpp", "host.cpp", "jsextension.h", "jsextensions.cpp", "jsextensions.h", "moduleproperties.cpp", "moduleproperties.h", "pkgconfigjs.cpp", "pkgconfigjs.h", "process.cpp", "temporarydir.cpp", "textfile.cpp", "binaryfile.cpp", "utilitiesextension.cpp", "domxml.cpp", ] } Group { name: "jsextensions (Non-Darwin-specific)" prefix: "jsextensions/" condition: !qbs.targetOS.contains("darwin") files: [ "propertylist.cpp", ] } Group { name: "jsextensions (Darwin-specific)" prefix: "jsextensions/" condition: qbs.targetOS.contains("darwin") files: [ "propertylist_darwin.mm", "propertylistutils.h", "propertylistutils.mm", ] } Group { name: "language" prefix: name + '/' files: [ "artifactproperties.cpp", "artifactproperties.h", "asttools.cpp", "asttools.h", "builtindeclarations.cpp", "builtindeclarations.h", "deprecationinfo.h", "evaluator.cpp", "evaluator.h", "filecontext.cpp", "filecontext.h", "filecontextbase.cpp", "filecontextbase.h", "filetags.cpp", "filetags.h", "identifiersearch.cpp", "identifiersearch.h", "item.cpp", "item.h", "itemdeclaration.cpp", "itemdeclaration.h", "itemobserver.h", "itempool.cpp", "itempool.h", "itemtype.h", "jsimports.h", "language.cpp", "language.h", "moduleproviderinfo.h", "preparescriptobserver.cpp", "preparescriptobserver.h", "property.cpp", "property.h", "propertydeclaration.cpp", "propertydeclaration.h", "propertymapinternal.cpp", "propertymapinternal.h", "qualifiedid.cpp", "qualifiedid.h", "resolvedfilecontext.cpp", "resolvedfilecontext.h", "scriptengine.cpp", "scriptengine.h", "scriptimporter.cpp", "scriptimporter.h", "scriptpropertyobserver.cpp", "scriptpropertyobserver.h", "value.cpp", "value.h", ] } Group { name: "public language headers" qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix + "/language" files: "language/forward_decls.h" } Group { name: "loader" prefix: name + '/' files: [ "astimportshandler.cpp", "astimportshandler.h", "astpropertiesitemhandler.cpp", "astpropertiesitemhandler.h", "dependenciesresolver.cpp", "dependenciesresolver.h", "groupshandler.cpp", "groupshandler.h", "itemreader.cpp", "itemreader.h", "itemreaderastvisitor.cpp", "itemreaderastvisitor.h", "itemreadervisitorstate.cpp", "itemreadervisitorstate.h", "loaderutils.cpp", "loaderutils.h", "localprofiles.cpp", "localprofiles.h", "moduleinstantiator.cpp", "moduleinstantiator.h", "moduleloader.cpp", "moduleloader.h", "modulepropertymerger.cpp", "modulepropertymerger.h", "moduleproviderloader.cpp", "moduleproviderloader.h", "probesresolver.cpp", "probesresolver.h", "productitemmultiplexer.cpp", "productitemmultiplexer.h", "productresolver.cpp", "productresolver.h", "productscollector.cpp", "productscollector.h", "productsresolver.cpp", "productsresolver.h", "projectresolver.cpp", "projectresolver.h", ] } Group { name: "logging" prefix: name + '/' files: [ "categories.cpp", "categories.h", "ilogsink.cpp", "logger.cpp", "logger.h", "translator.h" ] } Group { name: "public logging headers" qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix + "/logging" files: "logging/ilogsink.h" } Group { name: "parser" prefix: name + '/' files: [ "qmlerror.cpp", "qmlerror.h", "qmljs.g", "qmljsast.cpp", "qmljsast_p.h", "qmljsastfwd_p.h", "qmljsastvisitor.cpp", "qmljsastvisitor_p.h", "qmljsengine_p.cpp", "qmljsengine_p.h", "qmljsglobal_p.h", "qmljsgrammar.cpp", "qmljsgrammar_p.h", "qmljskeywords_p.h", "qmljslexer.cpp", "qmljslexer_p.h", "qmljsmemorypool_p.h", "qmljsparser.cpp", "qmljsparser_p.h" ] } Group { name: "tools" prefix: name + '/' files: [ "architectures.cpp", "buildgraphlocker.cpp", "buildgraphlocker.h", "buildoptions.cpp", "clangclinfo.cpp", "clangclinfo.h", "cleanoptions.cpp", "codelocation.cpp", "commandechomode.cpp", "deprecationwarningmode.cpp", "dynamictypecheck.h", "error.cpp", "executablefinder.cpp", "executablefinder.h", "fileinfo.cpp", "fileinfo.h", "filesaver.cpp", "filesaver.h", "filetime.cpp", "filetime.h", "generateoptions.cpp", "hostosinfo.h", "id.cpp", "id.h", "iosutils.h", "joblimits.cpp", "jsliterals.cpp", "jsliterals.h", "jsonhelper.h", "installoptions.cpp", "launcherinterface.cpp", "launcherinterface.h", "launcherpackets.cpp", "launcherpackets.h", "launchersocket.cpp", "launchersocket.h", "msvcinfo.cpp", "msvcinfo.h", "pathutils.h", "pimpl.h", "persistence.cpp", "persistence.h", "porting.h", "preferences.cpp", "processresult.cpp", "processresult_p.h", "processutils.cpp", "processutils.h", "profile.cpp", "profiling.cpp", "profiling.h", "progressobserver.cpp", "progressobserver.h", "projectgeneratormanager.cpp", "propagate_const.h", "qbsassert.cpp", "qbsassert.h", "qbspluginmanager.cpp", "qbspluginmanager.h", "qbsprocess.cpp", "qbsprocess.h", "qttools.cpp", "qttools.h", "scannerpluginmanager.cpp", "scannerpluginmanager.h", "scripttools.cpp", "scripttools.h", "set.h", "settings.cpp", "settingscreator.cpp", "settingscreator.h", "settingsmodel.cpp", "settingsrepresentation.cpp", "setupprojectparameters.cpp", "shellutils.cpp", "shellutils.h", "stlutils.h", "stringconstants.h", "stringutils.h", "toolchains.cpp", "version.cpp", "visualstudioversioninfo.cpp", "visualstudioversioninfo.h", "vsenvironmentdetector.cpp", "vsenvironmentdetector.h", "weakpointer.h", ] } Group { name: "public tools headers" prefix: "tools/" files: [ "architectures.h", "buildoptions.h", "cleanoptions.h", "codelocation.h", "commandechomode.h", "deprecationwarningmode.h", "error.h", "generateoptions.h", "installoptions.h", "joblimits.h", "mutexdata.h", "preferences.h", "processresult.h", "profile.h", "projectgeneratormanager.h", "qbs_export.h", "settings.h", "settingsmodel.h", "settingsrepresentation.h", "setupprojectparameters.h", "toolchains.h", "version.h", ] qbs.install: qbsbuildconfig.installApiHeaders qbs.installDir: headerInstallPrefix + "/tools" } Group { condition: qbs.targetOS.contains("macos") name: "tools (macOS)" prefix: "tools/" files: [ "applecodesignutils.cpp", "applecodesignutils.h" ] } Group { name: "Cpp Scanner" prefix: "cppscanner/" files: [ "CPlusPlusForwardDeclarations.h", "Lexer.cpp", "Lexer.h", "Token.cpp", "Token.h", "cppscanner.cpp", "cppscanner.h", ] } } qbs-src-2.6.1/src/lib/corelib/loader/0000755000175100001660000000000014776170045016672 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/loader/productscollector.cpp0000644000175100001660000010612614776170045023156 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "productscollector.h" #include "dependenciesresolver.h" #include "itemreader.h" #include "loaderutils.h" #include "localprofiles.h" #include "productitemmultiplexer.h" #include "probesresolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { class ProductsCollector::Private { public: Private(LoaderState &loaderState) : loaderState(loaderState) {} void handleProject(Item *projectItem, ProjectContext *parentProject, const Set &referencedFilePaths); QList multiplexProductItem(ProductContext &dummyContext, Item *productItem); void prepareProduct(ProjectContext &projectContext, Item *productItem, ProductContext *mainProduct = nullptr); void handleSubProject(ProjectContext &projectContext, Item *projectItem, const Set &referencedFilePaths); enum class PropertyFilter { All, BuiltIns }; void copyProperties(const Item *sourceProject, Item *targetProject, PropertyFilter filter); QList loadReferencedFile( const QString &relativePath, const CodeLocation &referencingLocation, const Set &referencedFilePaths, ProductContext &dummyContext); bool mergeExportItems(ProductContext &productContext); bool checkExportItemCondition(Item *exportItem, const ProductContext &product); void initProductProperties(const ProductContext &product); void checkProjectNamesInOverrides(); void collectProductsByNameAndItem(); void checkProductNamesInOverrides(); void mergeProperty(Item *dst, const QString &name, const ValuePtr &value); LoaderState &loaderState; Settings settings{loaderState.parameters().settingsDirectory()}; Set disabledProjects; Version qbsVersion; Item *tempScopeItem = nullptr; private: // TODO: Put this in loaderutils class TempBaseModuleAttacher { public: TempBaseModuleAttacher(Private *d, ProductContext &product); ~TempBaseModuleAttacher() { drop(); } void drop(); Item *tempBaseModuleItem() const { return m_tempBaseModule; } private: Item * const m_productItem; ValuePtr m_origQbsValue; Item *m_tempBaseModule = nullptr; }; }; ProductsCollector::ProductsCollector(LoaderState &loaderState) : d(makePimpl(loaderState)) {} ProductsCollector::~ProductsCollector() = default; void ProductsCollector::run(Item *rootProject) { d->handleProject(rootProject, nullptr, {rootProject->file()->filePath()}); d->checkProjectNamesInOverrides(); d->collectProductsByNameAndItem(); d->checkProductNamesInOverrides(); d->loaderState.topLevelProject().checkForLocalProfileAsTopLevelProfile( d->loaderState.parameters().topLevelProfile()); } void ProductsCollector::Private::handleProject(Item *projectItem, ProjectContext *parentProject, const Set &referencedFilePaths) { const SetupProjectParameters ¶meters = loaderState.parameters(); Evaluator &evaluator = loaderState.evaluator(); Logger &logger = loaderState.logger(); ItemReader &itemReader = loaderState.itemReader(); TopLevelProjectContext &topLevelProject = loaderState.topLevelProject(); auto p = std::make_unique(); auto &projectContext = *p; projectContext.item = projectItem; projectContext.parent = parentProject; projectContext.topLevelProject = &topLevelProject; ItemValuePtr itemValue = ItemValue::create(projectItem); projectContext.scope = Item::create(&loaderState.itemPool(), ItemType::Scope); projectContext.scope->setFile(projectItem->file()); projectContext.scope->setProperty(StringConstants::projectVar(), itemValue); ProductContext dummyProduct; dummyProduct.project = &projectContext; dummyProduct.moduleProperties = parameters.finalBuildConfigurationTree(); dummyProduct.profileModuleProperties = dummyProduct.moduleProperties; dummyProduct.profileName = parameters.topLevelProfile(); loadBaseModule(dummyProduct, projectItem, loaderState); projectItem->overrideProperties(parameters.overriddenValuesTree(), StringConstants::projectPrefix(), parameters, logger); projectContext.name = evaluator.stringValue(projectItem, StringConstants::nameProperty()); if (projectContext.name.isEmpty()) { projectContext.name = FileInfo::baseName(projectItem->location().filePath()); projectItem->setProperty(StringConstants::nameProperty(), VariantValue::create(projectContext.name)); } if (parentProject) parentProject->children.push_back(p.get()); topLevelProject.addProject(p.release()); projectItem->overrideProperties(parameters.overriddenValuesTree(), StringConstants::projectsOverridePrefix() + projectContext.name, parameters, logger); if (!topLevelProject.checkItemCondition(projectItem, evaluator)) { disabledProjects.insert(projectContext.name); return; } SearchPathsManager searchPathsManager(itemReader, itemReader.readExtraSearchPaths(projectItem) << projectItem->file()->dirPath()); projectContext.searchPathsStack = itemReader.extraSearchPathsStack(); const QString minVersionStr = evaluator.stringValue(projectItem, StringConstants::minimumQbsVersionProperty(), QStringLiteral("1.3.0")); const Version minVersion = Version::fromString(minVersionStr); if (!minVersion.isValid()) { throw ErrorInfo(Tr::tr("The value '%1' of Project.minimumQbsVersion " "is not a valid version string.") .arg(minVersionStr), projectItem->location()); } if (!qbsVersion.isValid()) qbsVersion = Version::fromString(QLatin1String(QBS_VERSION)); if (qbsVersion < minVersion) { throw ErrorInfo(Tr::tr("The project requires at least qbs version %1, but " "this is qbs version %2.").arg(minVersion.toString(), qbsVersion.toString())); } for (Item * const child : projectItem->children()) child->setScope(projectContext.scope); ProbesResolver(loaderState).resolveProbes(dummyProduct, projectItem); collectProfilesFromItems(projectItem, projectContext.scope, loaderState); QList multiplexedProducts; for (Item * const child : projectItem->children()) { if (child->type() == ItemType::Product) multiplexedProducts << multiplexProductItem(dummyProduct, child); } for (Item * const additionalProductItem : std::as_const(multiplexedProducts)) Item::addChild(projectItem, additionalProductItem); const QList originalChildren = projectItem->children(); for (Item * const child : originalChildren) { switch (child->type()) { case ItemType::Product: prepareProduct(projectContext, child); break; case ItemType::SubProject: handleSubProject(projectContext, child, referencedFilePaths); break; case ItemType::Project: copyProperties(projectItem, child, PropertyFilter::All); handleProject(child, &projectContext, referencedFilePaths); break; default: break; } } const QStringList refs = evaluator.stringListValue( projectItem, StringConstants::referencesProperty()); const CodeLocation referencingLocation = projectItem->property(StringConstants::referencesProperty())->location(); QList additionalProjectChildren; for (const QString &filePath : refs) { try { additionalProjectChildren << loadReferencedFile( filePath, referencingLocation, referencedFilePaths, dummyProduct); } catch (const ErrorInfo &error) { if (parameters.productErrorMode() == ErrorHandlingMode::Strict) throw; logger.printError(error); } } for (Item * const subItem : std::as_const(additionalProjectChildren)) { Item::addChild(projectContext.item, subItem); switch (subItem->type()) { case ItemType::Product: prepareProduct(projectContext, subItem); break; case ItemType::Project: copyProperties(projectItem, subItem, PropertyFilter::All); handleProject(subItem, &projectContext, Set(referencedFilePaths) << subItem->file()->filePath()); break; default: break; } } } QList ProductsCollector::Private::multiplexProductItem(ProductContext &dummyContext, Item *productItem) { // Overriding the product item properties must be done here already, because multiplexing // properties might depend on product properties. const QString &nameKey = StringConstants::nameProperty(); QString productName = loaderState.evaluator().stringValue(productItem, nameKey); if (productName.isEmpty()) { productName = FileInfo::completeBaseName(productItem->file()->filePath()); productItem->setProperty(nameKey, VariantValue::create(productName)); } productItem->overrideProperties(loaderState.parameters().overriddenValuesTree(), StringConstants::productsOverridePrefix() + productName, loaderState.parameters(), loaderState.logger()); dummyContext.item = productItem; TempBaseModuleAttacher tbma(this, dummyContext); return multiplex(productName, productItem, tbma.tempBaseModuleItem(), [&] { tbma.drop(); }, loaderState); } void ProductsCollector::Private::prepareProduct(ProjectContext &projectContext, Item *productItem, ProductContext *mainProduct) { const SetupProjectParameters ¶meters = loaderState.parameters(); Evaluator &evaluator = loaderState.evaluator(); TopLevelProjectContext &topLevelProject = loaderState.topLevelProject(); AccumulatingTimer timer(parameters.logElapsedTime() ? &topLevelProject.timingData().preparingProducts : nullptr); topLevelProject.checkCancelation(); qCDebug(lcModuleLoader) << "prepareProduct" << productItem->file()->filePath(); if (mainProduct) mainProduct->shadowProduct = std::make_unique(); else projectContext.products.emplace_back(); ProductContext &productContext = mainProduct ? *mainProduct->shadowProduct : projectContext.products.back(); productContext.item = productItem; productContext.project = &projectContext; // Retrieve name, profile and multiplex id. productContext.name = evaluator.stringValue(productItem, StringConstants::nameProperty()); QBS_CHECK(!productContext.name.isEmpty()); const ItemValueConstPtr qbsItemValue = productItem->itemProperty(StringConstants::qbsModule(), loaderState.itemPool()); if (qbsItemValue && qbsItemValue->item()->hasProperty(StringConstants::profileProperty())) { TempBaseModuleAttacher tbma(this, productContext); productContext.profileName = evaluator.stringValue( tbma.tempBaseModuleItem(), StringConstants::profileProperty(), QString()); } else { productContext.profileName = parameters.topLevelProfile(); } productContext.multiplexConfigurationId = evaluator.stringValue( productItem, StringConstants::multiplexConfigurationIdProperty()); QBS_CHECK(!productContext.profileName.isEmpty()); // Set up full module property map based on the profile. std::optional flatConfig = topLevelProject.profileConfig(productContext.profileName); if (!flatConfig) { const Profile profile(productContext.profileName, &settings, loaderState.topLevelProject().localProfiles()); if (!profile.exists()) { ErrorInfo error(Tr::tr("Profile '%1' does not exist.").arg(profile.name()), productItem->location()); productContext.handleError(error); return; } flatConfig = SetupProjectParameters::expandedBuildConfiguration( profile, parameters.configurationName()); topLevelProject.addProfileConfig(productContext.profileName, *flatConfig); } productContext.profileModuleProperties = SetupProjectParameters::finalBuildConfigurationTree( *flatConfig, {}); productContext.moduleProperties = SetupProjectParameters::finalBuildConfigurationTree( *flatConfig, parameters.overriddenValues()); initProductProperties(productContext); // Set up product scope. This is mainly for using the "product" and "project" // variables in some contexts. ItemValuePtr itemValue = ItemValue::create(productItem); productContext.scope = Item::create(&loaderState.itemPool(), ItemType::Scope); productContext.scope->setProperty(StringConstants::productVar(), itemValue); productContext.scope->setFile(productItem->file()); productContext.scope->setScope(productContext.project->scope); // If there are any child items with an id, set up a scope for them. This is mostly // relevant for Probe items. While we might get away with using the file's id scope // in the absence of multiplexing, having a proper per-product scope seems cleaner. QBS_CHECK(productItem->scope()); QBS_CHECK(productItem->scope() == productContext.project->scope); for (Item * const child : productItem->children()) { if (child->id().isEmpty()) continue; if (productItem->scope() == productContext.project->scope) { productItem->setScope(Item::create(&loaderState.itemPool(), ItemType::Scope)); productItem->scope()->setScope(productContext.project->scope); } const ItemValuePtr childValue = ItemValue::create(child); productItem->scope()->setProperty(child->id(), childValue); productContext.scope->setProperty(child->id(), childValue); } const bool hasExportItems = mergeExportItems(productContext); setScopeForDescendants(productItem, productContext.scope, false); if (!hasExportItems) return; // This "shadow product" exists only to pull in a dependency on the actual product // and nothing else, thus providing us with the pure environment that we need to // evaluate the product's exported properties in isolation in the project resolver. Item * const importer = Item::create(&loaderState.itemPool(), ItemType::Product); importer->setProperty( QStringLiteral("name"), VariantValue::create( QString(StringConstants::shadowProductPrefix() + productContext.name))); importer->setFile(productItem->file()); importer->setLocation(productItem->location()); importer->setScope(projectContext.scope); importer->setupForBuiltinType(parameters.deprecationWarningMode(), loaderState.logger()); Item * const dependsItem = Item::create(&loaderState.itemPool(), ItemType::Depends); dependsItem->setProperty(QStringLiteral("name"), VariantValue::create(productContext.name)); dependsItem->setProperty(QStringLiteral("required"), VariantValue::create(false)); dependsItem->setFile(importer->file()); dependsItem->setLocation(importer->location()); dependsItem->setupForBuiltinType(parameters.deprecationWarningMode(), loaderState.logger()); dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), VariantValue::create(productContext.multiplexConfigurationId)); Item::addChild(importer, dependsItem); prepareProduct(projectContext, importer, &productContext); } void ProductsCollector::Private::handleSubProject( ProjectContext &projectContext, Item *projectItem, const Set &referencedFilePaths) { const SetupProjectParameters ¶meters = loaderState.parameters(); Evaluator &evaluator = loaderState.evaluator(); Logger &logger = loaderState.logger(); ItemReader &itemReader = loaderState.itemReader(); TopLevelProjectContext &topLevelProject = loaderState.topLevelProject(); qCDebug(lcModuleLoader) << "handleSubProject" << projectItem->file()->filePath(); Item * const propertiesItem = projectItem->child(ItemType::PropertiesInSubProject); if (!topLevelProject.checkItemCondition(projectItem, evaluator)) return; if (propertiesItem) { propertiesItem->setScope(projectItem); if (!topLevelProject.checkItemCondition(propertiesItem, evaluator)) return; } Item *loadedItem = nullptr; QString subProjectFilePath; try { const QString projectFileDirPath = FileInfo::path(projectItem->file()->filePath()); const QString relativeFilePath = evaluator.stringValue(projectItem, StringConstants::filePathProperty()); subProjectFilePath = FileInfo::resolvePath(projectFileDirPath, relativeFilePath); if (referencedFilePaths.contains(subProjectFilePath)) throw ErrorInfo(Tr::tr("Cycle detected while loading subproject file '%1'.") .arg(relativeFilePath), projectItem->location()); loadedItem = itemReader.setupItemFromFile(subProjectFilePath, projectItem->location()); } catch (const ErrorInfo &error) { if (parameters.productErrorMode() == ErrorHandlingMode::Strict) throw; logger.printError(error); return; } loadedItem = itemReader.wrapInProjectIfNecessary(loadedItem); const bool inheritProperties = evaluator.boolValue( projectItem, StringConstants::inheritPropertiesProperty()); copyProperties( projectItem->parent(), loadedItem, inheritProperties ? PropertyFilter::All : PropertyFilter::BuiltIns); if (propertiesItem) { const Item::PropertyMap &overriddenProperties = propertiesItem->properties(); for (auto it = overriddenProperties.begin(); it != overriddenProperties.end(); ++it) loadedItem->setProperty(it.key(), it.value()); } Item::addChild(projectItem, loadedItem); projectItem->setScope(projectContext.scope); handleProject(loadedItem, &projectContext, Set(referencedFilePaths) << subProjectFilePath); } void ProductsCollector::Private::copyProperties( const Item *sourceProject, Item *targetProject, PropertyFilter filter) { if (!sourceProject) return; const QList builtinProjectProperties = BuiltinDeclarations::instance().declarationsForType(ItemType::Project).properties(); Set builtinProjectPropertyNames; for (const PropertyDeclaration &p : builtinProjectProperties) builtinProjectPropertyNames << p.name(); for (auto it = sourceProject->propertyDeclarations().begin(); it != sourceProject->propertyDeclarations().end(); ++it) { // We must not inherit built-in properties such as "name", // but there are exceptions. if (it.key() == StringConstants::qbsSearchPathsProperty() || it.key() == StringConstants::profileProperty() || it.key() == StringConstants::buildDirectoryProperty() || it.key() == StringConstants::sourceDirectoryProperty() || it.key() == StringConstants::minimumQbsVersionProperty()) { const JSSourceValueConstPtr &v = targetProject->sourceProperty(it.key()); QBS_ASSERT(v, continue); if (v->sourceCode() == StringConstants::undefinedValue()) sourceProject->copyProperty(it.key(), targetProject); continue; } if (filter == PropertyFilter::BuiltIns) continue; if (builtinProjectPropertyNames.contains(it.key())) continue; if (targetProject->hasOwnProperty(it.key())) continue; // Ignore stuff the target project already has. targetProject->setPropertyDeclaration(it.key(), it.value()); sourceProject->copyProperty(it.key(), targetProject); } } QList ProductsCollector::Private::loadReferencedFile( const QString &relativePath, const CodeLocation &referencingLocation, const Set &referencedFilePaths, ProductContext &dummyContext) { QString absReferencePath = FileInfo::resolvePath(FileInfo::path(referencingLocation.filePath()), relativePath); if (FileInfo(absReferencePath).isDir()) { QString qbsFilePath; QDirIterator dit(absReferencePath, StringConstants::qbsFileWildcards()); while (dit.hasNext()) { if (!qbsFilePath.isEmpty()) { throw ErrorInfo(Tr::tr("Referenced directory '%1' contains more than one " "qbs file.").arg(absReferencePath), referencingLocation); } qbsFilePath = dit.next(); } if (qbsFilePath.isEmpty()) { throw ErrorInfo(Tr::tr("Referenced directory '%1' does not contain a qbs file.") .arg(absReferencePath), referencingLocation); } absReferencePath = qbsFilePath; } if (referencedFilePaths.contains(absReferencePath)) throw ErrorInfo(Tr::tr("Cycle detected while referencing file '%1'.").arg(relativePath), referencingLocation); Item * const subItem = loaderState.itemReader().setupItemFromFile( absReferencePath, referencingLocation); if (subItem->type() != ItemType::Project && subItem->type() != ItemType::Product) { ErrorInfo error(Tr::tr("Item type should be 'Product' or 'Project', but is '%1'.") .arg(subItem->typeName())); error.append(Tr::tr("Item is defined here."), subItem->location()); error.append(Tr::tr("File is referenced here."), referencingLocation); throw error; } subItem->setScope(dummyContext.project->scope); subItem->setParent(dummyContext.project->item); QList loadedItems; loadedItems << subItem; if (subItem->type() == ItemType::Product) { collectProfilesFromItems(subItem, dummyContext.project->scope, loaderState); loadedItems << multiplexProductItem(dummyContext, subItem); } return loadedItems; } void ProductsCollector::Private::mergeProperty(Item *dst, const QString &name, const ValuePtr &value) { if (value->type() == Value::ItemValueType) { const ItemValueConstPtr itemValue = std::static_pointer_cast(value); const Item * const valueItem = itemValue->item(); Item * const subItem = dst->itemProperty(name, itemValue, loaderState.itemPool())->item(); for (auto it = valueItem->properties().begin(); it != valueItem->properties().end(); ++it) mergeProperty(subItem, it.key(), it.value()); return; } // If the property already exists, set up the base value. if (value->type() == Value::JSSourceValueType) { const auto jsValue = static_cast(value.get()); if (jsValue->isBuiltinDefaultValue()) return; const ValuePtr baseValue = dst->property(name); if (baseValue) { QBS_CHECK(baseValue->type() == Value::JSSourceValueType); const JSSourceValuePtr jsBaseValue = std::static_pointer_cast( baseValue->clone(loaderState.itemPool())); jsValue->setBaseValue(jsBaseValue); std::vector alternatives = jsValue->alternatives(); jsValue->clearAlternatives(); for (JSSourceValue::Alternative &a : alternatives) { a.value->setBaseValue(jsBaseValue); jsValue->addAlternative(a); } } } dst->setProperty(name, value); } bool ProductsCollector::Private::mergeExportItems(ProductContext &productContext) { const SetupProjectParameters ¶meters = loaderState.parameters(); Evaluator &evaluator = loaderState.evaluator(); Logger &logger = loaderState.logger(); TopLevelProjectContext &topLevelProject = loaderState.topLevelProject(); std::vector exportItems; QList children = productContext.item->children(); const auto isExport = [](Item *item) { return item->type() == ItemType::Export; }; std::copy_if(children.cbegin(), children.cend(), std::back_inserter(exportItems), isExport); qbs::Internal::removeIf(children, isExport); // Note that we do not return if there are no Export items: The "merged" item becomes the // "product module", which always needs to exist, regardless of whether the product sources // actually contain an Export item or not. if (!exportItems.empty()) productContext.item->setChildren(children); Item *merged = Item::create(&loaderState.itemPool(), ItemType::Export); const QString &nameKey = StringConstants::nameProperty(); const ValuePtr nameValue = VariantValue::create(productContext.name); merged->setProperty(nameKey, nameValue); Set filesWithExportItem; QVariantMap defaultParameters; for (Item * const exportItem : exportItems) { topLevelProject.checkCancelation(); if (Q_UNLIKELY(filesWithExportItem.contains(exportItem->file()))) throw ErrorInfo(Tr::tr("Multiple Export items in one product are prohibited."), exportItem->location()); exportItem->setProperty(nameKey, nameValue); if (!checkExportItemCondition(exportItem, productContext)) continue; filesWithExportItem += exportItem->file(); for (Item * const child : exportItem->children()) { if (child->type() == ItemType::Parameters) { adjustParametersScopes(child, child); defaultParameters = mergeDependencyParameters(defaultParameters, getJsVariant(evaluator.engine()->context(), evaluator.scriptValue(child)).toMap()); } else { Item::addChild(merged, child); } } const Item::PropertyDeclarationMap &decls = exportItem->propertyDeclarations(); for (auto it = decls.constBegin(); it != decls.constEnd(); ++it) { const PropertyDeclaration &newDecl = it.value(); const PropertyDeclaration &existingDecl = merged->propertyDeclaration(it.key()); if (existingDecl.isValid() && existingDecl.type() != newDecl.type()) { ErrorInfo error(Tr::tr("Export item in inherited item redeclares property " "'%1' with different type.").arg(it.key()), exportItem->location()); handlePropertyError(error, parameters, logger); } merged->setPropertyDeclaration(newDecl.name(), newDecl); } for (QMap::const_iterator it = exportItem->properties().constBegin(); it != exportItem->properties().constEnd(); ++it) { mergeProperty(merged, it.key(), it.value()); } } merged->setFile(exportItems.empty() ? productContext.item->file() : exportItems.back()->file()); merged->setLocation(exportItems.empty() ? productContext.item->location() : exportItems.back()->location()); Item::addChild(productContext.item, merged); merged->setupForBuiltinType(parameters.deprecationWarningMode(), logger); productContext.mergedExportItem = merged; productContext.defaultParameters = defaultParameters; return !exportItems.empty(); } // TODO: This seems dubious. Can we merge the conditions instead? bool ProductsCollector::Private::checkExportItemCondition(Item *exportItem, const ProductContext &product) { class ScopeHandler { public: ScopeHandler(Item *exportItem, const ProductContext &productContext, Item **cachedScopeItem, ItemPool &itemPool) : m_exportItem(exportItem), m_itemPool(itemPool) { if (!*cachedScopeItem) *cachedScopeItem = Item::create(&m_itemPool, ItemType::Scope); Item * const scope = *cachedScopeItem; QBS_CHECK(productContext.item->file()); scope->setFile(productContext.item->file()); scope->setScope(productContext.item); productContext.project->scope->copyProperty(StringConstants::projectVar(), scope); productContext.scope->copyProperty(StringConstants::productVar(), scope); QBS_CHECK(!exportItem->scope()); exportItem->setScope(scope); } ~ScopeHandler() { m_exportItem->setScope(nullptr); } private: Item * const m_exportItem; ItemPool &m_itemPool; } scopeHandler(exportItem, product, &tempScopeItem, loaderState.itemPool()); return loaderState.topLevelProject().checkItemCondition(exportItem, loaderState.evaluator()); } void ProductsCollector::Private::initProductProperties(const ProductContext &product) { QString buildDir = ResolvedProduct::deriveBuildDirectoryName(product.name, product.multiplexConfigurationId); buildDir = FileInfo::resolvePath(product.project->topLevelProject->buildDirectory(), buildDir); product.item->setProperty(StringConstants::buildDirectoryProperty(), VariantValue::create(buildDir)); const QString sourceDir = QFileInfo(product.item->file()->filePath()).absolutePath(); product.item->setProperty(StringConstants::sourceDirectoryProperty(), VariantValue::create(sourceDir)); } void ProductsCollector::Private::checkProjectNamesInOverrides() { for (const QString &projectNameInOverride : loaderState.topLevelProject().projectNamesUsedInOverrides()) { if (disabledProjects.contains(projectNameInOverride)) continue; if (!any_of(loaderState.topLevelProject().projects(), [&projectNameInOverride](const ProjectContext *p) { return p->name == projectNameInOverride; })) { handlePropertyError(Tr::tr("Unknown project '%1' in property override.") .arg(projectNameInOverride), loaderState.parameters(), loaderState.logger()); } } } void ProductsCollector::Private::collectProductsByNameAndItem() { TopLevelProjectContext &topLevelProject = loaderState.topLevelProject(); for (ProjectContext * const project : topLevelProject.projects()) { for (ProductContext &product : project->products) topLevelProject.addProduct(product); } } void ProductsCollector::Private::checkProductNamesInOverrides() { TopLevelProjectContext &topLevelProject = loaderState.topLevelProject(); for (const QString &productNameInOverride : topLevelProject.productNamesUsedInOverrides()) { if (!topLevelProject.productWithNameAndConstraint( productNameInOverride, [&productNameInOverride](const ProductContext &product) { // In an override string such as "a.b.c:d, we cannot tell whether we have a product // "a" and a module "b.c" or a product "a.b" and a module "c", so we need to take // care not to emit false positives here. return product.name == productNameInOverride || product.name.startsWith(productNameInOverride + StringConstants::dot()); })) { handlePropertyError(Tr::tr("Unknown product '%1' in property override.") .arg(productNameInOverride), loaderState.parameters(), loaderState.logger()); } } } ProductsCollector::Private::TempBaseModuleAttacher::TempBaseModuleAttacher( ProductsCollector::Private *d, ProductContext &product) : m_productItem(product.item) { const ValuePtr qbsValue = m_productItem->property(StringConstants::qbsModule()); // Cloning is necessary because the original value will get "instantiated" now. if (qbsValue) m_origQbsValue = qbsValue->clone(d->loaderState.itemPool()); m_tempBaseModule = loadBaseModule(product, m_productItem, d->loaderState); } void ProductsCollector::Private::TempBaseModuleAttacher::drop() { if (!m_tempBaseModule) return; // "Unload" the qbs module again. if (m_origQbsValue) m_productItem->setProperty(StringConstants::qbsModule(), m_origQbsValue); else m_productItem->removeProperty(StringConstants::qbsModule()); m_productItem->removeModules(); m_tempBaseModule = nullptr; } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/modulepropertymerger.h0000644000175100001660000001034114776170045023336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs::Internal { class Item; class LoaderState; class ProductContext; // This module comprises functions for collecting values attached to module properties // in different contexts. // For example, in the Qt.core module you will find a property binding such as this: // cpp.defines: "QT_CORE_LIB" // while in the Qt.widgets module, it will look like this: // cpp.defines: "QT_WIDGETS_LIB" // A product with a dependency on both these modules will end up with a value of // ["QT_WIDGETS_LIB", "QT_CORE_LIB"], plus potentially other defines set elsewhere. // Each of these values is assigned a priority that roughly corresponds to the "level" at which // the module containing the property binding resides in the dependency hierarchy. // For list properties, the priorities determine the order of the respecive values in the // final array, for scalar values they determine which one survives. Different scalar values // with the same priority trigger a warning message. // Since the right-hand side of a binding can refer to properties of the surrounding context, // each such value gets its own scope. // This function is called when a module is loaded via a Depends item. // loadingItem is the product or module containing the Depends item. // loadingName is the name of that module. It is used as a tie-breaker for list property values // with equal priority. // localInstance is the module instance placeholder in the ItemValue of a property binding, // i.e. the "cpp" in "cpp.defines". // globalInstance is the actual module into which the properties from localInstance get merged. void mergeFromLocalInstance(ProductContext &product, Item *loadingItem, const QString &loadingName, const Item *localInstance, Item *globalInstance, LoaderState &loaderState); // This function is called after all dependencies have been resolved. It uses its global // knowledge of module priorities to potentially adjust the order of list values or // favor different scalar values. It can also remove previously merged-in values again; // this can happen if a module fails to load after it already merged some values, or // if it fails validation in the end. void doFinalMerge(ProductContext &product, LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/loaderutils.cpp0000644000175100001660000010767214776170045021742 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "loaderutils.h" #include "itemreader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { QString fullProductDisplayName(const QString &name, const QString &multiplexId) { static const auto multiplexIdToString =[](const QString &id) { return QString::fromUtf8(QByteArray::fromBase64(id.toUtf8())); }; QString result = name; if (!multiplexId.isEmpty()) result.append(QLatin1Char(' ')).append(multiplexIdToString(multiplexId)); return result; } void adjustParametersScopes(Item *item, Item *scope) { if (item->type() == ItemType::ModuleParameters) { item->setScope(scope); return; } for (const auto &value : item->properties()) { if (value->type() == Value::ItemValueType) adjustParametersScopes(std::static_pointer_cast(value)->item(), scope); } } QString ProductContext::uniqueName() const { return ResolvedProduct::uniqueName(name, multiplexConfigurationId); } QString ProductContext::displayName() const { return fullProductDisplayName(name, multiplexConfigurationId); } void ProductContext::handleError(const ErrorInfo &error) { const bool alreadyHadError = delayedError.hasError(); if (!alreadyHadError) { delayedError.append(Tr::tr("Error while handling product '%1':") .arg(name), item->location()); } if (error.isInternalError()) { if (alreadyHadError) { qCDebug(lcModuleLoader()) << "ignoring subsequent internal error" << error.toString() << "in product" << name; return; } } const auto errorItems = error.items(); for (const ErrorItem &ei : errorItems) delayedError.append(ei.description(), ei.codeLocation()); project->topLevelProject->addDisabledItem(item); } TopLevelProjectContext::~TopLevelProjectContext() { qDeleteAll(m_projects); } bool TopLevelProjectContext::checkItemCondition(Item *item, Evaluator &evaluator) { if (evaluator.boolValue(item, StringConstants::conditionProperty())) return true; addDisabledItem(item); return false; } void TopLevelProjectContext::checkCancelation() { if (m_progressObserver && m_progressObserver->canceled()) m_canceled = true; if (m_canceled) throw CancelException(); } QString TopLevelProjectContext::sourceCodeForEvaluation(const JSSourceValueConstPtr &value) { const auto sourceCodeGuard = m_sourceCode.lock(); QString &code = sourceCodeGuard.get()[value->sourceCode()]; if (!code.isNull()) return code; code = value->sourceCodeForEvaluation(); return code; } ScriptFunctionPtr TopLevelProjectContext::scriptFunctionValue(Item *item, const QString &name) { const JSSourceValuePtr value = item->sourceProperty(name); QBS_CHECK(value); const auto scriptFunctionMapGuard = m_scriptFunctionMap.lock(); ScriptFunctionPtr &script = scriptFunctionMapGuard.get()[value->location()]; if (!script.get()) { script = ScriptFunction::create(); const PropertyDeclaration decl = item->propertyDeclaration(name); script->sourceCode = sourceCodeAsFunction(value, decl); script->location = value->location(); script->fileContext = resolvedFileContext(value->file()); } return script; } QString TopLevelProjectContext::sourceCodeAsFunction(const JSSourceValueConstPtr &value, const PropertyDeclaration &decl) { const auto scriptFunctionMapGuard = m_scriptFunctions.lock(); QString &scriptFunction = scriptFunctionMapGuard.get()[std::make_pair(value->sourceCode(), decl.functionArgumentNames())]; if (!scriptFunction.isNull()) return scriptFunction; const QString args = decl.functionArgumentNames().join(QLatin1Char(',')); if (value->hasFunctionForm()) { // Insert the argument list. scriptFunction = value->sourceCodeForEvaluation(); scriptFunction.insert(10, args); // Remove the function application "()" that has been // added in ItemReaderASTVisitor::visitStatement. scriptFunction.chop(2); } else { scriptFunction = QLatin1String("(function(") + args + QLatin1String("){return ") + value->sourceCode().toString() + QLatin1String(";})"); } return scriptFunction; } const ResolvedFileContextPtr &TopLevelProjectContext::resolvedFileContext( const FileContextConstPtr &ctx) { ResolvedFileContextPtr &result = m_fileContextMap[ctx]; if (!result) result = ResolvedFileContext::create(*ctx); return result; } void TopLevelProjectContext::removeProductToHandle(const ProductContext &product) { std::unique_lock lock(m_productsToHandle.mutex); m_productsToHandle.data.remove(&product); } bool TopLevelProjectContext::isProductQueuedForHandling(const ProductContext &product) const { std::shared_lock lock(m_productsToHandle.mutex); return m_productsToHandle.data.contains(&product); } void TopLevelProjectContext::addDisabledItem(Item *item) { m_disabledItems.lock().get() << item; } bool TopLevelProjectContext::isDisabledItem(const Item *item) const { return m_disabledItems.lock_shared().get().contains(item); } void TopLevelProjectContext::setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; } ProgressObserver *TopLevelProjectContext::progressObserver() const { return m_progressObserver; } void TopLevelProjectContext::addQueuedError(const ErrorInfo &error) { m_queuedErrors.lock().get() << error; } void TopLevelProjectContext::addProfileConfig(const QString &profileName, const QVariantMap &profileConfig) { m_profileConfigs.insert(profileName, profileConfig); } std::optional TopLevelProjectContext::profileConfig(const QString &profileName) const { const auto it = m_profileConfigs.constFind(profileName); if (it == m_profileConfigs.constEnd()) return {}; return it.value().toMap(); } void TopLevelProjectContext::addProjectLevelProbe(const ProbeConstPtr &probe) { m_probesInfo.projectLevelProbes << probe; } const std::vector TopLevelProjectContext::projectLevelProbes() const { return m_probesInfo.projectLevelProbes; } void TopLevelProjectContext::addProduct(ProductContext &product) { m_productsByName.insert({product.name, &product}); } void TopLevelProjectContext::addProductByType(ProductContext &product, const FileTags &tags) { const auto productsByTypeGuard = m_productsByType.lock(); for (const FileTag &tag : tags) productsByTypeGuard.get().insert({tag, &product}); } ProductContext *TopLevelProjectContext::productWithNameAndConstraint( const QString &name, const std::function &constraint) { const auto candidates = m_productsByName.equal_range(name); for (auto it = candidates.first; it != candidates.second; ++it) { ProductContext * const candidate = it->second; if (constraint(*candidate)) return candidate; } return nullptr; } std::vector TopLevelProjectContext::productsWithNameAndConstraint( const QString &name, const std::function &constraint) { std::vector result; const auto candidates = m_productsByName.equal_range(name); for (auto it = candidates.first; it != candidates.second; ++it) { ProductContext * const candidate = it->second; if (constraint(*candidate)) result << candidate; } return result; } std::vector TopLevelProjectContext::productsWithTypeAndConstraint( const FileTags &tags, const std::function &constraint) { const auto productsByTypeGuard = m_productsByType.lock_shared(); std::vector matchingProducts; for (const FileTag &typeTag : tags) { const auto range = productsByTypeGuard.get().equal_range(typeTag); for (auto it = range.first; it != range.second; ++it) { if (constraint(*it->second)) matchingProducts.push_back(it->second); } } return matchingProducts; } std::vector> TopLevelProjectContext::finishedProductsWithBulkDependency(const FileTag &tag) const { return m_reverseBulkDependencies.value(tag); } void TopLevelProjectContext::registerBulkDependencies(ProductContext &product) { for (const auto &tagAndLoc : product.bulkDependencies) { for (const FileTag &tag : tagAndLoc.first) m_reverseBulkDependencies[tag].emplace_back(&product, tagAndLoc.second); } } void TopLevelProjectContext::addProjectNameUsedInOverrides(const QString &name) { m_projectNamesUsedInOverrides << name; } const Set &TopLevelProjectContext::projectNamesUsedInOverrides() const { return m_projectNamesUsedInOverrides; } void TopLevelProjectContext::addProductNameUsedInOverrides(const QString &name) { m_productNamesUsedInOverrides << name; } const Set &TopLevelProjectContext::productNamesUsedInOverrides() const { return m_productNamesUsedInOverrides; } void TopLevelProjectContext::addMultiplexConfiguration(const QString &id, const QVariantMap &config) { m_multiplexConfigsById.insert(std::make_pair(id, config)); } QVariantMap TopLevelProjectContext::multiplexConfiguration(const QString &id) const { if (id.isEmpty()) return {}; const auto it = m_multiplexConfigsById.find(id); QBS_CHECK(it != m_multiplexConfigsById.end() && !it->second.isEmpty()); return it->second; } std::lock_guard TopLevelProjectContext::moduleProvidersCacheLock() { return std::lock_guard(m_moduleProvidersCacheMutex); } void TopLevelProjectContext::setModuleProvidersCache(const ModuleProvidersCache &cache) { m_moduleProvidersCache = cache; } ModuleProviderInfo *TopLevelProjectContext::moduleProvider(const ModuleProvidersCacheKey &key) { if (const auto it = m_moduleProvidersCache.find(key); it != m_moduleProvidersCache.end()) return &it->second; return nullptr; } ModuleProviderInfo &TopLevelProjectContext::addModuleProvider(const ModuleProvidersCacheKey &key, const ModuleProviderInfo &provider) { return m_moduleProvidersCache[key] = provider; } void TopLevelProjectContext::addParameterDeclarations(const Item *moduleProto, const Item::PropertyDeclarationMap &decls) { m_parameterDeclarations.lock().get().insert({moduleProto, decls}); } Item::PropertyDeclarationMap TopLevelProjectContext::parameterDeclarations(Item *moduleProto) const { const auto parameterDeclarationsGuard = m_parameterDeclarations.lock_shared(); const auto &declarations = parameterDeclarationsGuard.get(); if (const auto it = declarations.find(moduleProto); it != declarations.end()) { return it->second; } return {}; } void TopLevelProjectContext::setParameters(const Item *moduleProto, const QVariantMap ¶meters) { m_parameters.lock().get().insert({moduleProto, parameters}); } QVariantMap TopLevelProjectContext::parameters(Item *moduleProto) const { const auto parametersGuard = m_parameters.lock_shared(); const auto ¶meters = parametersGuard.get(); if (const auto it = parameters.find(moduleProto); it != parameters.end()) { return it->second; } return {}; } void TopLevelProjectContext::addCodeLink(const QString &sourceFile, const CodeRange &sourceRange, const CodeLocation &target) { const auto codeLinksGuard = m_codeLinks.lock(); QList &links = codeLinksGuard.get()[sourceFile][sourceRange]; if (!links.contains(target)) links << target; } QString TopLevelProjectContext::findModuleDirectory( const QualifiedId &module, const QString &searchPath, const std::function &findOnDisk) { const auto modulePathCacheGuard = m_modulePathCache.lock(); auto &path = modulePathCacheGuard.get()[{searchPath, module}]; if (!path) path = findOnDisk(); return *path; } QStringList TopLevelProjectContext::getModuleFilesForDirectory( const QString &dir, const std::function &findOnDisk) { const auto moduleFilesGuard = m_moduleFilesPerDirectory.lock(); auto &list = moduleFilesGuard.get()[dir]; if (!list) list = findOnDisk(); return *list; } void TopLevelProjectContext::removeModuleFileFromDirectoryCache(const QString &filePath) { const auto moduleFilesGuard = m_moduleFilesPerDirectory.lock(); auto &moduleFiles = moduleFilesGuard.get(); const auto it = moduleFiles.find(FileInfo::path(filePath)); QBS_CHECK(it != moduleFiles.end()); auto &files = it->second; QBS_CHECK(files); files->removeOne(filePath); } void TopLevelProjectContext::addUnknownProfilePropertyError(const Item *moduleProto, const ErrorInfo &error) { m_unknownProfilePropertyErrors.lock().get()[moduleProto].push_back(error); } const std::vector &TopLevelProjectContext::unknownProfilePropertyErrors( const Item *moduleProto) const { const auto errorsGuard = m_unknownProfilePropertyErrors.lock_shared(); const auto &errors = errorsGuard.get(); if (const auto it = errors.find(moduleProto); it != errors.end()) { return it->second; } static const std::vector empty; return empty; } Item *TopLevelProjectContext::getModulePrototype(const QString &filePath, const QString &profile, const std::function &produce) { const auto modulePrototypesGuard = m_modulePrototypes.lock(); auto &prototypeList = modulePrototypesGuard.get()[filePath]; for (const auto &prototype : prototypeList) { if (prototype.second == profile) return prototype.first; } Item * const module = produce(); if (module) prototypeList.emplace_back(module, profile); return module; } void TopLevelProjectContext::addLocalProfile(const QString &name, const QVariantMap &values, const CodeLocation &location) { if (m_localProfiles.contains(name)) throw ErrorInfo(Tr::tr("Local profile '%1' redefined.").arg(name), location); m_localProfiles.insert(name, values); } void TopLevelProjectContext::checkForLocalProfileAsTopLevelProfile(const QString &topLevelProfile) { for (auto it = m_localProfiles.cbegin(); it != m_localProfiles.cend(); ++it) { if (it.key() != topLevelProfile) continue; // This covers the edge case that a locally defined profile was specified as the // top-level profile, in which case we must invalidate the qbs module prototype that was // created in early setup before local profiles were handled. const auto prototypesGuard = m_modulePrototypes.lock(); auto &modulePrototypes = prototypesGuard.get(); QBS_CHECK(modulePrototypes.size() == 1); modulePrototypes.clear(); break; } } std::lock_guard TopLevelProjectContext::probesCacheLock() { return std::lock_guard(m_probesMutex); } void TopLevelProjectContext::setOldProjectProbes(const std::vector &oldProbes) { for (const ProbeConstPtr& probe : oldProbes) m_probesInfo.oldProjectProbes[probe->globalId()] << probe; } ProbeConstPtr TopLevelProjectContext::findOldProjectProbe(const QString &id, const ProbeFilter &filter) const { for (const ProbeConstPtr &oldProbe : m_probesInfo.oldProjectProbes.value(id)) { if (filter(oldProbe)) return oldProbe; } return {}; } void TopLevelProjectContext::setOldProductProbes( const QHash> &oldProbes) { m_probesInfo.oldProductProbes = oldProbes; } ProbeConstPtr TopLevelProjectContext::findOldProductProbe(const QString &productName, const ProbeFilter &filter) const { for (const ProbeConstPtr &oldProbe : m_probesInfo.oldProductProbes.value(productName)) { if (filter(oldProbe)) return oldProbe; } return {}; } void TopLevelProjectContext::addNewlyResolvedProbe(const ProbeConstPtr &probe) { m_probesInfo.currentProbes[probe->location()] << probe; } ProbeConstPtr TopLevelProjectContext::findCurrentProbe(const CodeLocation &location, const ProbeFilter &filter) const { for (const ProbeConstPtr &probe : m_probesInfo.currentProbes.value(location)) { if (filter(probe)) return probe; } return {}; } void TopLevelProjectContext::collectDataFromEngine(const ScriptEngine &engine) { const auto project = dynamic_cast(m_projects.front()->project.get()); QBS_CHECK(project); project->canonicalFilePathResults.insert(engine.canonicalFilePathResults()); project->fileExistsResults.insert(engine.fileExistsResults()); project->directoryEntriesResults.insert(engine.directoryEntriesResults()); project->fileLastModifiedResults.insert(engine.fileLastModifiedResults()); project->environment.insert(engine.environment()); project->buildSystemFiles.unite(engine.imports()); } ItemPool &TopLevelProjectContext::createItemPool() { m_itemPools.push_back(std::make_unique()); return *m_itemPools.back(); } class LoaderState::Private { public: Private(LoaderState &q, const SetupProjectParameters ¶meters, TopLevelProjectContext &topLevelProject, ItemPool &itemPool, ScriptEngine &engine, Logger &&logger) : parameters(parameters), topLevelProject(topLevelProject), itemPool(itemPool), logger(std::move(logger)), itemReader(q), evaluator(&engine) { this->logger.clearWarnings(); this->logger.storeWarnings(); } const SetupProjectParameters ¶meters; TopLevelProjectContext &topLevelProject; ItemPool &itemPool; Logger logger; ItemReader itemReader; Evaluator evaluator; }; LoaderState::LoaderState(const SetupProjectParameters ¶meters, TopLevelProjectContext &topLevelProject, ItemPool &itemPool, ScriptEngine &engine, Logger logger) : d(makePimpl(*this, parameters, topLevelProject, itemPool, engine, std::move(logger))) { d->itemReader.init(); } LoaderState::~LoaderState() = default; const SetupProjectParameters &LoaderState::parameters() const { return d->parameters; } ItemPool &LoaderState::itemPool() { return d->itemPool; } Evaluator &LoaderState::evaluator() { return d->evaluator; } Logger &LoaderState::logger() { return d->logger; } ItemReader &LoaderState::itemReader() { return d->itemReader; } TopLevelProjectContext &LoaderState::topLevelProject() { return d->topLevelProject; } static QString verbatimValue(LoaderState &state, const ValueConstPtr &value) { QString result; if (value && value->type() == Value::JSSourceValueType) { const JSSourceValueConstPtr sourceValue = std::static_pointer_cast( value); result = state.topLevelProject().sourceCodeForEvaluation(sourceValue); } return result; } static void resolveRuleArtifactBinding( LoaderState &state, const RuleArtifactPtr &ruleArtifact, Item *item, const QStringList &namePrefix, QualifiedIdSet *seenBindings) { for (auto it = item->properties().constBegin(); it != item->properties().constEnd(); ++it) { const QStringList name = QStringList(namePrefix) << it.key(); if (it.value()->type() == Value::ItemValueType) { resolveRuleArtifactBinding(state, ruleArtifact, std::static_pointer_cast(it.value())->item(), name, seenBindings); } else if (it.value()->type() == Value::JSSourceValueType) { const auto insertResult = seenBindings->insert(name); if (!insertResult.second) continue; JSSourceValuePtr sourceValue = std::static_pointer_cast(it.value()); RuleArtifact::Binding rab; rab.name = name; rab.code = state.topLevelProject().sourceCodeForEvaluation(sourceValue); rab.location = sourceValue->location(); ruleArtifact->bindings.push_back(rab); } else { QBS_ASSERT(!"unexpected value type", continue); } } } static void resolveRuleArtifact(LoaderState &state, const RulePtr &rule, Item *item) { RuleArtifactPtr artifact = RuleArtifact::create(); rule->artifacts.push_back(artifact); artifact->location = item->location(); if (const auto sourceProperty = item->sourceProperty(StringConstants::filePathProperty())) artifact->filePathLocation = sourceProperty->location(); artifact->filePath = verbatimValue(state, item->property(StringConstants::filePathProperty())); artifact->fileTags = state.evaluator().fileTagsValue(item, StringConstants::fileTagsProperty()); artifact->alwaysUpdated = state.evaluator().boolValue( item, StringConstants::alwaysUpdatedProperty()); QualifiedIdSet seenBindings; for (Item *obj = item; obj; obj = obj->prototype()) { for (QMap::const_iterator it = obj->properties().constBegin(); it != obj->properties().constEnd(); ++it) { if (it.value()->type() != Value::ItemValueType) continue; resolveRuleArtifactBinding( state, artifact, std::static_pointer_cast(it.value())->item(), QStringList(it.key()), &seenBindings); } } } void resolveRule(LoaderState &state, Item *item, ProjectContext *projectContext, ProductContext *productContext, ModuleContext *moduleContext) { Evaluator &evaluator = state.evaluator(); if (!evaluator.boolValue(item, StringConstants::conditionProperty())) return; RulePtr rule = Rule::create(); // read artifacts bool hasArtifactChildren = false; for (Item * const child : item->children()) { if (Q_UNLIKELY(child->type() != ItemType::Artifact)) { throw ErrorInfo(Tr::tr("'Rule' can only have children of type 'Artifact'."), child->location()); } hasArtifactChildren = true; resolveRuleArtifact(state, rule, child); } rule->name = evaluator.stringValue(item, StringConstants::nameProperty()); rule->prepareScript.initialize(state.topLevelProject().scriptFunctionValue( item, StringConstants::prepareProperty())); rule->outputArtifactsScript.initialize(state.topLevelProject().scriptFunctionValue( item, StringConstants::outputArtifactsProperty())); rule->outputFileTags = evaluator.fileTagsValue(item, StringConstants::outputFileTagsProperty()); if (rule->outputArtifactsScript.isValid()) { if (hasArtifactChildren) throw ErrorInfo(Tr::tr("The Rule.outputArtifacts script is not allowed in rules " "that contain Artifact items."), item->location()); } if (!hasArtifactChildren && rule->outputFileTags.empty()) { throw ErrorInfo(Tr::tr("A rule needs to have Artifact items or a non-empty " "outputFileTags property."), item->location()); } rule->multiplex = evaluator.boolValue(item, StringConstants::multiplexProperty()); rule->alwaysRun = evaluator.boolValue(item, StringConstants::alwaysRunProperty()); rule->inputs = evaluator.fileTagsValue(item, StringConstants::inputsProperty()); rule->inputsFromDependencies = evaluator.fileTagsValue(item, StringConstants::inputsFromDependenciesProperty()); bool requiresInputsSet = false; rule->requiresInputs = evaluator.boolValue(item, StringConstants::requiresInputsProperty(), &requiresInputsSet); if (!requiresInputsSet) rule->requiresInputs = rule->declaresInputs(); rule->auxiliaryInputs = evaluator.fileTagsValue(item, StringConstants::auxiliaryInputsProperty()); rule->auxiliaryInputsFromDependencies = evaluator.fileTagsValue( item, StringConstants::auxiliaryInputsFromDependenciesProperty()); rule->excludedInputs = evaluator.fileTagsValue(item, StringConstants::excludedInputsProperty()); if (rule->excludedInputs.empty()) { rule->excludedInputs = evaluator.fileTagsValue( item, StringConstants::excludedAuxiliaryInputsProperty()); } rule->explicitlyDependsOn = evaluator.fileTagsValue(item, StringConstants::explicitlyDependsOnProperty()); rule->explicitlyDependsOnFromDependencies = evaluator.fileTagsValue( item, StringConstants::explicitlyDependsOnFromDependenciesProperty()); rule->module = moduleContext ? moduleContext->module : projectContext->dummyModule; if (!rule->multiplex && !rule->declaresInputs()) { throw ErrorInfo(Tr::tr("Rule has no inputs, but is not a multiplex rule."), item->location()); } if (!rule->multiplex && !rule->requiresInputs) { throw ErrorInfo(Tr::tr("Rule.requiresInputs is false for non-multiplex rule."), item->location()); } if (!rule->declaresInputs() && rule->requiresInputs) { throw ErrorInfo(Tr::tr("Rule.requiresInputs is true, but the rule " "does not declare any input tags."), item->location()); } if (productContext) { rule->product = productContext->product.get(); productContext->product->rules.push_back(rule); } else { projectContext->rules.push_back(rule); } } void resolveFileTagger(LoaderState &state, Item *item, ProjectContext *projectContext, ProductContext *productContext) { Evaluator &evaluator = state.evaluator(); if (!evaluator.boolValue(item, StringConstants::conditionProperty())) return; std::vector &fileTaggers = productContext ? productContext->product->fileTaggers : projectContext->fileTaggers; const QStringList patterns = evaluator.stringListValue(item, StringConstants::patternsProperty()); if (patterns.empty()) throw ErrorInfo(Tr::tr("FileTagger.patterns must be a non-empty list."), item->location()); const FileTags fileTags = evaluator.fileTagsValue(item, StringConstants::fileTagsProperty()); if (fileTags.empty()) throw ErrorInfo(Tr::tr("FileTagger.fileTags must not be empty."), item->location()); for (const QString &pattern : patterns) { if (pattern.isEmpty()) throw ErrorInfo(Tr::tr("A FileTagger pattern must not be empty."), item->location()); } const int priority = evaluator.intValue(item, StringConstants::priorityProperty()); fileTaggers.push_back(FileTagger::create(patterns, fileTags, priority)); } void resolveJobLimit(LoaderState &state, Item *item, ProjectContext *projectContext, ProductContext *productContext, ModuleContext *moduleContext) { Evaluator &evaluator = state.evaluator(); if (!evaluator.boolValue(item, StringConstants::conditionProperty())) return; const QString jobPool = evaluator.stringValue(item, StringConstants::jobPoolProperty()); if (jobPool.isEmpty()) throw ErrorInfo(Tr::tr("A JobLimit item needs to have a non-empty '%1' property.") .arg(StringConstants::jobPoolProperty()), item->location()); bool jobCountWasSet; const int jobCount = evaluator.intValue(item, StringConstants::jobCountProperty(), -1, &jobCountWasSet); if (!jobCountWasSet) { throw ErrorInfo(Tr::tr("A JobLimit item needs to have a '%1' property.") .arg(StringConstants::jobCountProperty()), item->location()); } if (jobCount < 0) { throw ErrorInfo(Tr::tr("A JobLimit item must have a non-negative '%1' property.") .arg(StringConstants::jobCountProperty()), item->location()); } JobLimits &jobLimits = moduleContext ? moduleContext->jobLimits : productContext ? productContext->product->jobLimits : projectContext->jobLimits; JobLimit jobLimit(jobPool, jobCount); const int oldLimit = jobLimits.getLimit(jobPool); if (oldLimit == -1 || oldLimit > jobCount) jobLimits.setJobLimit(jobLimit); } const FileTag unknownFileTag() { static const FileTag tag("unknown-file-tag"); return tag; } bool ProductContext::dependenciesResolvingPending() const { return (!dependenciesContext || !dependenciesContext->dependenciesResolved) && !product && !delayedError.hasError(); } std::pair ProductContext::pendingDependency() const { return dependenciesContext ? dependenciesContext->pendingDependency() : std::make_pair(ProductDependency::None, nullptr); } TimingData &TimingData::operator+=(const TimingData &other) { dependenciesResolving += other.dependenciesResolving; moduleProviders += other.moduleProviders; moduleInstantiation += other.moduleInstantiation; propertyMerging += other.propertyMerging; groupsSetup += other.groupsSetup; groupsResolving += other.groupsResolving; preparingProducts += other.preparingProducts; resolvingProducts += other.resolvingProducts; probes += other.probes; propertyEvaluation += other.propertyEvaluation; propertyChecking += other.propertyChecking; return *this; } DependenciesContext::~DependenciesContext() = default; ItemReaderCache::AstCacheEntry &ItemReaderCache::retrieveOrSetupCacheEntry( const QString &filePath, const std::function &setup) { const auto astCacheGuard = m_astCache.lock(); AstCacheEntry &entry = astCacheGuard.get()[filePath]; if (!entry.ast) { setup(entry); m_filesRead << filePath; } return entry; } const QStringList &ItemReaderCache::retrieveOrSetDirectoryEntries( const QString &dir, const std::function &findOnDisk) { const auto directoryEntriesGuard = m_directoryEntries.lock(); auto &entries = directoryEntriesGuard.get()[dir]; if (!entries) entries = findOnDisk(); return *entries; } bool ItemReaderCache::AstCacheEntry::addProcessingThread() { return m_processingThreads.lock().get().insert(std::this_thread::get_id()).second; } void ItemReaderCache::AstCacheEntry::removeProcessingThread() { m_processingThreads.lock().get().remove(std::this_thread::get_id()); } class DependencyParametersMerger { public: DependencyParametersMerger(std::vector &&candidates) : m_candidates(std::move(candidates)) { } QVariantMap merge(); private: void merge(QVariantMap ¤t, const QVariantMap &next, int nextPrio); const std::vector m_candidates; struct Conflict { Conflict(QStringList path, QVariant val1, QVariant val2, int prio) : path(std::move(path)), val1(std::move(val1)), val2(std::move(val2)), priority(prio) {} QStringList path; QVariant val1; QVariant val2; int priority; }; std::vector m_conflicts; QVariantMap m_currentValue; int m_currentPrio = INT_MIN; QStringList m_path; }; QVariantMap mergeDependencyParameters(std::vector &&candidates) { return DependencyParametersMerger(std::move(candidates)).merge(); } QVariantMap mergeDependencyParameters(const QVariantMap &m1, const QVariantMap &m2) { return mergeDependencyParameters({std::make_pair(m1, 0), std::make_pair(m2, 0)}); } QVariantMap DependencyParametersMerger::merge() { for (const auto &next : m_candidates) { merge(m_currentValue, next.first, next.second); m_currentPrio = next.second; } if (!m_conflicts.empty()) { ErrorInfo error(Tr::tr("Conflicting parameter values encountered:")); for (const Conflict &conflict : m_conflicts) { // TODO: Location would be nice ... error.append(Tr::tr(" Parameter '%1' cannot be both '%2' and '%3'.") .arg(conflict.path.join(QLatin1Char('.')), conflict.val1.toString(), conflict.val2.toString())); } throw error; } return m_currentValue; } void DependencyParametersMerger::merge(QVariantMap ¤t, const QVariantMap &next, int nextPrio) { for (auto it = next.begin(); it != next.end(); ++it) { m_path << it.key(); const QVariant &newValue = it.value(); QVariant ¤tValue = current[it.key()]; if (newValue.userType() == QMetaType::QVariantMap) { QVariantMap mdst = currentValue.toMap(); merge(mdst, it.value().toMap(), nextPrio); currentValue = mdst; } else { if (m_currentPrio == nextPrio) { if (currentValue.isValid() && !qVariantsEqual(currentValue, newValue)) m_conflicts.emplace_back(m_path, currentValue, newValue, m_currentPrio); } else { removeIf(m_conflicts, [this](const Conflict &conflict) { return m_path == conflict.path; }); } currentValue = newValue; } m_path.removeLast(); } } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/itemreaderastvisitor.cpp0000644000175100001660000004066214776170045023657 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "itemreaderastvisitor.h" #include "astimportshandler.h" #include "astpropertiesitemhandler.h" #include "itemreadervisitorstate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace QbsQmlJS; namespace qbs { namespace Internal { ItemReaderASTVisitor::ItemReaderASTVisitor(ItemReaderVisitorState &visitorState, FileContextPtr file, ItemPool *itemPool, Logger &logger) : m_visitorState(visitorState) , m_file(std::move(file)) , m_itemPool(itemPool) , m_logger(logger) { } ItemReaderASTVisitor::~ItemReaderASTVisitor() = default; bool ItemReaderASTVisitor::visit(AST::UiProgram *uiProgram) { ASTImportsHandler importsHandler(m_visitorState, m_logger, m_file); importsHandler.handleImports(uiProgram->imports); m_typeNameToFile = importsHandler.typeNameFileMap(); return true; } static ItemValuePtr findItemProperty(const Item *container, const Item *item) { ItemValuePtr itemValue; const auto &srcprops = container->properties(); auto it = std::find_if(srcprops.begin(), srcprops.end(), [item] (const ValuePtr &v) { return v->type() == Value::ItemValueType && std::static_pointer_cast(v)->item() == item; }); if (it != srcprops.end()) itemValue = std::static_pointer_cast(it.value()); return itemValue; } bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) { const QString typeName = ast->qualifiedTypeNameId->name.toString(); const CodeLocation itemLocation = toCodeLocation(ast->qualifiedTypeNameId->identifierToken); const Item *baseItem = nullptr; Item *mostDerivingItem = nullptr; Item *item = Item::create(m_itemPool, ItemType::Unknown); item->setFile(m_file); item->setLocation(itemLocation); const AST::SourceLocation &endLoc = ast->lastSourceLocation(); item->setEndPosition(CodePosition(endLoc.startLine, endLoc.startColumn)); // Inheritance resolving, part 1: Find out our actual type name (needed for setting // up children and alternatives). const QStringList fullTypeName = toStringList(ast->qualifiedTypeNameId); const QString baseTypeFileName = m_typeNameToFile.value(fullTypeName); ItemType itemType; if (!baseTypeFileName.isEmpty()) { const bool isMostDerivingItem = (m_visitorState.mostDerivingItem() == nullptr); if (isMostDerivingItem) m_visitorState.setMostDerivingItem(item); mostDerivingItem = m_visitorState.mostDerivingItem(); baseItem = m_visitorState.readFile(baseTypeFileName, m_file->searchPaths(), m_itemPool); if (isMostDerivingItem) m_visitorState.setMostDerivingItem(nullptr); QBS_CHECK(baseItem->type() <= ItemType::LastActualItem); itemType = baseItem->type(); } else { if (fullTypeName.size() > 1) { throw ErrorInfo(Tr::tr("Invalid item '%1'. Did you mean to set a module property?") .arg(fullTypeName.join(QLatin1Char('.'))), itemLocation); } itemType = BuiltinDeclarations::instance().typeForName(typeName, itemLocation); checkDeprecationStatus(itemType, typeName, itemLocation); if (itemType == ItemType::Properties && m_item && m_item->type() == ItemType::SubProject) itemType = ItemType::PropertiesInSubProject; } item->m_type = itemType; if (m_item) { Item::addChild(m_item, item); // Add this item to the children of the parent item. } else { m_item = item; // This is the root item. if (itemType == ItemType::Module) { QBS_CHECK(!m_moduleItemLocker); m_moduleItemLocker = std::make_unique(*m_item); } } if (ast->initializer) { Item *mdi = m_visitorState.mostDerivingItem(); m_visitorState.setMostDerivingItem(nullptr); qSwap(m_item, item); const ItemType oldInstanceItemType = m_instanceItemType; if (itemType == ItemType::Parameters || itemType == ItemType::Depends) m_instanceItemType = ItemType::ModuleParameters; ast->initializer->accept(this); m_instanceItemType = oldInstanceItemType; qSwap(m_item, item); m_visitorState.setMostDerivingItem(mdi); } ASTPropertiesItemHandler(item, *m_itemPool, m_logger).handlePropertiesItems(); // Inheritance resolving, part 2 (depends on alternatives having been set up). if (baseItem) { inheritItem(item, baseItem); if (baseItem->file()->idScope()) { // Make ids from the derived file visible in the base file. // ### Do we want to turn off this feature? It's QMLish but kind of strange. item->file()->ensureIdScope(m_itemPool); baseItem->file()->idScope()->setPrototype(item->file()->idScope()); // Replace the base item with the most deriving item. ItemValuePtr baseItemIdValue = findItemProperty(baseItem->file()->idScope(), baseItem); if (baseItemIdValue) baseItemIdValue->setItem(mostDerivingItem); } } else { // Only the item at the top of the inheritance chain is a built-in item. // We cannot do this in "part 1", because then the visitor would complain about duplicate // bindings. item->setupForBuiltinType(m_visitorState.deprecationWarningMode(), m_logger); } return false; } void ItemReaderASTVisitor::checkDuplicateBinding(Item *item, const QStringList &bindingName, const AST::SourceLocation &sourceLocation) { if (Q_UNLIKELY(item->hasOwnProperty(bindingName.last()))) { QString msg = Tr::tr("Duplicate binding for '%1'"); throw ErrorInfo(msg.arg(bindingName.join(QLatin1Char('.'))), toCodeLocation(sourceLocation)); } } bool ItemReaderASTVisitor::visit(AST::UiPublicMember *ast) { PropertyDeclaration p; if (Q_UNLIKELY(ast->name.isEmpty())) throw ErrorInfo(Tr::tr("public member without name")); if (Q_UNLIKELY(ast->memberType.isEmpty())) throw ErrorInfo(Tr::tr("public member without type")); if (Q_UNLIKELY(ast->type == AST::UiPublicMember::Signal)) throw ErrorInfo(Tr::tr("public member with signal type not supported")); p.setName(ast->name.toString()); p.setType(PropertyDeclaration::propertyTypeFromString(ast->memberType.toString())); if (p.type() == PropertyDeclaration::UnknownType) { throw ErrorInfo(Tr::tr("Unknown type '%1' in property declaration.") .arg(ast->memberType.toString()), toCodeLocation(ast->typeToken)); } if (Q_UNLIKELY(!ast->typeModifier.isEmpty())) { throw ErrorInfo(Tr::tr("public member with type modifier '%1' not supported").arg( ast->typeModifier.toString())); } if (ast->isReadonlyMember) p.setFlags(PropertyDeclaration::ReadOnlyFlag); m_item->m_propertyDeclarations.insert(p.name(), p); const JSSourceValuePtr value = JSSourceValue::create(); value->setFile(m_file); if (ast->statement) { handleBindingRhs(ast->statement, value); const QStringList bindingName(p.name()); checkDuplicateBinding(m_item, bindingName, ast->colonToken); } m_item->setProperty(p.name(), value); return false; } bool ItemReaderASTVisitor::visit(AST::UiScriptBinding *ast) { QBS_CHECK(ast->qualifiedId); QBS_CHECK(!ast->qualifiedId->name.isEmpty()); const QStringList bindingName = toStringList(ast->qualifiedId); if (bindingName.length() == 1 && bindingName.front() == QStringLiteral("id")) { const auto * const expStmt = AST::cast(ast->statement); if (Q_UNLIKELY(!expStmt)) throw ErrorInfo(Tr::tr("id: must be followed by identifier")); const auto * const idExp = AST::cast(expStmt->expression); if (Q_UNLIKELY(!idExp || idExp->name.isEmpty())) throw ErrorInfo(Tr::tr("id: must be followed by identifier")); if (m_item->type() == ItemType::Module) throw ErrorInfo(Tr::tr("Module items cannot have an id property.")); m_item->m_id = idExp->name.toString(); m_file->ensureIdScope(m_itemPool); ItemValueConstPtr existingId = m_file->idScope()->itemProperty(m_item->id(), *m_itemPool); if (existingId) { ErrorInfo e(Tr::tr("The id '%1' is not unique.").arg(m_item->id())); e.append(Tr::tr("First occurrence is here."), existingId->item()->location()); e.append(Tr::tr("Next occurrence is here."), m_item->location()); throw e; } m_file->idScope()->setProperty(m_item->id(), ItemValue::create(m_item)); return false; } const JSSourceValuePtr value = JSSourceValue::create(); handleBindingRhs(ast->statement, value); Item * const targetItem = targetItemForBinding(bindingName, value); checkDuplicateBinding(targetItem, bindingName, ast->qualifiedId->identifierToken); targetItem->setProperty(bindingName.last(), value); return false; } bool ItemReaderASTVisitor::handleBindingRhs(AST::Statement *statement, const JSSourceValuePtr &value) { QBS_CHECK(statement); QBS_CHECK(value); if (AST::cast(statement)) value->setHasFunctionForm(); value->setFile(m_file); value->setSourceCode(textViewOf(m_file->content(), statement)); value->setLocation(statement->firstSourceLocation().startLine, statement->firstSourceLocation().startColumn); bool usesBase, usesOuter, usesOriginal; IdentifierSearch idsearch; idsearch.add(StringConstants::baseVar(), &usesBase); idsearch.add(StringConstants::outerVar(), &usesOuter); idsearch.add(StringConstants::originalVar(), &usesOriginal); idsearch.start(statement); if (usesBase) value->setSourceUsesBase(); if (usesOuter) value->setSourceUsesOuter(); if (usesOriginal) value->setSourceUsesOriginal(); return false; } CodeLocation ItemReaderASTVisitor::toCodeLocation(const AST::SourceLocation &location) const { return CodeLocation(m_file->filePath(), location.startLine, location.startColumn); } Item *ItemReaderASTVisitor::targetItemForBinding(const QStringList &bindingName, const JSSourceValueConstPtr &value) { Item *targetItem = m_item; const int c = bindingName.size() - 1; for (int i = 0; i < c; ++i) { ValuePtr v = targetItem->ownProperty(bindingName.at(i)); if (!v) { const ItemType itemType = i < c - 1 ? ItemType::ModulePrefix : m_instanceItemType; Item *newItem = Item::create(m_itemPool, itemType); newItem->setLocation(value->location()); v = ItemValue::create(newItem); targetItem->setProperty(bindingName.at(i), v); } if (Q_UNLIKELY(v->type() != Value::ItemValueType)) { QString msg = Tr::tr("Binding to non-item property."); throw ErrorInfo(msg, value->location()); } targetItem = std::static_pointer_cast(v)->item(); } return targetItem; } void ItemReaderASTVisitor::inheritItem(Item *dst, const Item *src) { int insertPos = 0; for (Item *child : std::as_const(src->m_children)) { dst->m_children.insert(insertPos++, child); child->m_parent = dst; } for (const PropertyDeclaration &pd : src->propertyDeclarations()) { if (pd.flags().testFlag(PropertyDeclaration::ReadOnlyFlag) && dst->hasOwnProperty(pd.name())) { throw ErrorInfo(Tr::tr("Cannot set read-only property '%1'.").arg(pd.name()), dst->property(pd.name())->location()); } dst->setPropertyDeclaration(pd.name(), pd); } std::unique_ptr locker; if (src->type() == ItemType::Module) locker = std::make_unique(*src); for (auto it = src->properties().constBegin(); it != src->properties().constEnd(); ++it) { ValuePtr &v = dst->m_properties[it.key()]; if (!v) { v = it.value(); continue; } if (v->type() == Value::ItemValueType && it.value()->type() != Value::ItemValueType) throw ErrorInfo(Tr::tr("Binding to non-item property."), v->location()); if (v->type() != it.value()->type()) continue; switch (v->type()) { case Value::JSSourceValueType: { JSSourceValuePtr sv = std::static_pointer_cast(v); QBS_CHECK(!sv->baseValue()); const JSSourceValuePtr baseValue = std::static_pointer_cast(it.value()); sv->setBaseValue(baseValue); for (const JSSourceValue::Alternative &alt : sv->m_alternatives) alt.value->setBaseValue(baseValue); break; } case Value::ItemValueType: inheritItem(std::static_pointer_cast(v)->item(), std::static_pointer_cast(it.value())->item()); break; default: QBS_CHECK(!"unexpected value type"); } } } void ItemReaderASTVisitor::checkDeprecationStatus(ItemType itemType, const QString &itemName, const CodeLocation &itemLocation) { const ItemDeclaration itemDecl = BuiltinDeclarations::instance().declarationsForType(itemType); const ErrorInfo error = itemDecl.checkForDeprecation(m_visitorState.deprecationWarningMode(), itemName, itemLocation, m_logger); if (error.hasError()) throw error; } void ItemReaderASTVisitor::doCheckItemTypes(const Item *item) { const ItemDeclaration decl = BuiltinDeclarations::instance().declarationsForType(item->type()); for (const Item * const child : item->children()) { if (!decl.isChildTypeAllowed(child->type())) { throw ErrorInfo(Tr::tr("Items of type '%1' cannot contain items of type '%2'.") .arg(item->typeName(), child->typeName()), child->location()); } doCheckItemTypes(child); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/moduleloader.h0000644000175100001660000000440614776170045021523 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once namespace qbs { class CodeLocation; class VersionRange; namespace Internal { class Item; class LoaderState; class ProductContext; class QualifiedId; Item *searchAndLoadModuleFile( LoaderState &loaderState, ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const VersionRange &requiredVersion); } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/moduleloader.cpp0000644000175100001660000004246614776170045022066 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "moduleloader.h" #include "itemreader.h" #include "loaderutils.h" #include "moduleproviderloader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { class ModuleLoader { public: ModuleLoader( LoaderState &loaderState, ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const VersionRange &requiredVersion) : m_loaderState(loaderState) , m_product(product) , m_dependsItemLocation(dependsItemLocation) , m_moduleName(moduleName) , m_requiredVersion(requiredVersion) {} Item *load(); private: std::pair loadModuleFile(const QString &moduleName, const QString &filePath); Item *getModulePrototype(const QString &moduleName, const QString &filePath); Item *createAndInitModuleItem(const QString &moduleName, const QString &filePath); bool evaluateModuleCondition(Item *module, const QString &fullModuleName); void checkForUnknownProfileProperties(const Item *module); QString findModuleDirectory(const QString &searchPath); QStringList findModuleDirectories(); QStringList getModuleFilePaths(const QString &dir); LoaderState &m_loaderState; ProductContext &m_product; const CodeLocation &m_dependsItemLocation; const QualifiedId &m_moduleName; const VersionRange &m_requiredVersion; }; struct PrioritizedItem { PrioritizedItem(Item *item, int priority, int searchPathIndex) : item(item), priority(priority), searchPathIndex(searchPathIndex) { } Item * const item; int priority = 0; const int searchPathIndex; bool fulfillsVersionRequirement = true; }; static Item *chooseModuleCandidate(const std::vector &candidates, const QString &moduleName) { auto maxIt = std::max_element( candidates.begin(), candidates.end(), [](const PrioritizedItem &a, const PrioritizedItem &b) { if (a.fulfillsVersionRequirement != b.fulfillsVersionRequirement) return b.fulfillsVersionRequirement; if (a.priority < b.priority) return true; if (a.priority > b.priority) return false; return a.searchPathIndex > b.searchPathIndex; }); size_t nmax = std::count_if( candidates.begin(), candidates.end(), [maxIt](const PrioritizedItem &i) { return i.priority == maxIt->priority && i.searchPathIndex == maxIt->searchPathIndex && i.fulfillsVersionRequirement == maxIt->fulfillsVersionRequirement; }); if (nmax > 1) { ErrorInfo e(Tr::tr("There is more than one equally prioritized candidate for module '%1'.") .arg(moduleName)); for (size_t i = 0; i < candidates.size(); ++i) { const auto candidate = candidates.at(i); if (candidate.priority == maxIt->priority) { //: The %1 denotes the number of the candidate. e.append(Tr::tr("candidate %1").arg(i + 1), candidates.at(i).item->location()); } } throw e; } return maxIt->item; } Item *searchAndLoadModuleFile( LoaderState &loaderState, ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const VersionRange &requiredVersion) { return ModuleLoader(loaderState, product, dependsItemLocation, moduleName, requiredVersion) .load(); } Item *ModuleLoader::load() { SearchPathsManager searchPathsManager(m_loaderState.itemReader()); QStringList existingPaths = findModuleDirectories(); if (existingPaths.isEmpty()) { // no suitable names found, try to use providers AccumulatingTimer providersTimer(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.moduleProviders : nullptr); auto result = ModuleProviderLoader(m_loaderState) .executeModuleProviders(m_product, m_dependsItemLocation, m_moduleName); if (result.searchPaths) { qCDebug(lcModuleLoader) << "Re-checking for module" << m_moduleName.toString() << "with newly added search paths from module provider"; m_loaderState.itemReader().pushExtraSearchPaths(*result.searchPaths); existingPaths = findModuleDirectories(); } } const QString fullName = m_moduleName.toString(); bool triedToLoadModule = false; std::vector candidates; candidates.reserve(size_t(existingPaths.size())); for (int i = 0; i < existingPaths.size(); ++i) { const QStringList &moduleFileNames = getModuleFilePaths(existingPaths.at(i)); for (const QString &filePath : moduleFileNames) { const auto [module, triedToLoad] = loadModuleFile(fullName, filePath); if (module) candidates.emplace_back(module, 0, i); if (!triedToLoad) m_loaderState.topLevelProject().removeModuleFileFromDirectoryCache(filePath); triedToLoadModule = triedToLoadModule || triedToLoad; } } if (candidates.empty()) return nullptr; Item *moduleItem = nullptr; if (candidates.size() == 1) { moduleItem = candidates.at(0).item; } else { const bool needsVersionCheck = m_requiredVersion.minimum.isValid() || m_requiredVersion.maximum.isValid(); for (auto &candidate : candidates) { ModuleItemLocker lock(*candidate.item); candidate.priority = m_loaderState.evaluator() .intValue(candidate.item, StringConstants::priorityProperty(), candidate.priority); if (needsVersionCheck) { const auto version = Version::fromString(m_loaderState.evaluator().stringValue( candidate.item, StringConstants::versionProperty())); candidate.fulfillsVersionRequirement = (!m_requiredVersion.minimum.isValid() || version >= m_requiredVersion.minimum) && (!m_requiredVersion.maximum.isValid() || version < m_requiredVersion.maximum); } } moduleItem = chooseModuleCandidate(candidates, fullName); } checkForUnknownProfileProperties(moduleItem); return moduleItem; } std::pair ModuleLoader::loadModuleFile(const QString &moduleName, const QString &filePath) { qCDebug(lcModuleLoader) << "loadModuleFile" << moduleName << "from" << filePath; Item * const module = getModulePrototype(moduleName, filePath); if (!module) return {nullptr, false}; const auto it = m_product.modulePrototypeEnabledInfo.find(module); if (it != m_product.modulePrototypeEnabledInfo.end()) { qCDebug(lcModuleLoader) << "prototype cache hit (level 2)"; return {it->second ? module : nullptr, true}; } if (!evaluateModuleCondition(module, moduleName)) { qCDebug(lcModuleLoader) << "condition of module" << moduleName << "is false"; m_product.modulePrototypeEnabledInfo.insert({module, false}); return {nullptr, true}; } m_product.modulePrototypeEnabledInfo.insert({module, true}); return {module, true}; } Item * ModuleLoader::getModulePrototype(const QString &moduleName, const QString &filePath) { bool fromCache = true; Item * const module = m_loaderState.topLevelProject().getModulePrototype( filePath, m_product.profileName, [&] { fromCache = false; return createAndInitModuleItem(moduleName, filePath); }); if (fromCache) qCDebug(lcModuleLoader) << "prototype cache hit (level 1)"; return module; } Item *ModuleLoader::createAndInitModuleItem(const QString &moduleName, const QString &filePath) { Item * const module = m_loaderState.itemReader().setupItemFromFile(filePath, {}); if (module->type() != ItemType::Module) { qCDebug(lcModuleLoader).nospace() << "Alleged module " << moduleName << " has type '" << module->typeName() << "', so it's not a module after all."; return nullptr; } // Not technically needed, but we want to keep the invariant in item.cpp. ModuleItemLocker locker(*module); module->setProperty(StringConstants::nameProperty(), VariantValue::create(moduleName)); if (moduleName == StringConstants::qbsModule()) { module->setProperty(QStringLiteral("hostPlatform"), VariantValue::create(HostOsInfo::hostOSIdentifier())); module->setProperty(QStringLiteral("hostArchitecture"), VariantValue::create(HostOsInfo::hostOSArchitecture())); module->setProperty(QStringLiteral("libexecPath"), VariantValue::create(m_loaderState.parameters().libexecPath())); const Version qbsVersion = LanguageInfo::qbsVersion(); module->setProperty(QStringLiteral("versionMajor"), VariantValue::create(qbsVersion.majorVersion())); module->setProperty(QStringLiteral("versionMinor"), VariantValue::create(qbsVersion.minorVersion())); module->setProperty(QStringLiteral("versionPatch"), VariantValue::create(qbsVersion.patchLevel())); } else { Item::PropertyDeclarationMap decls; const auto &moduleChildren = module->children(); for (Item *param : moduleChildren) { if (param->type() == ItemType::Parameter) { const auto ¶mDecls = param->propertyDeclarations(); for (auto it = paramDecls.begin(); it != paramDecls.end(); ++it) decls.insert(it.key(), it.value()); } else if (param->type() == ItemType::Parameters) { adjustParametersScopes(param, param); Evaluator &evaluator = m_loaderState.evaluator(); QVariantMap parameters = getJsVariant(evaluator.engine()->context(), evaluator.scriptValue(param)).toMap(); m_loaderState.topLevelProject().setParameters(module, parameters); } } m_loaderState.topLevelProject().addParameterDeclarations(module, decls); } // Module properties that are defined in the profile are used as default values. // This is the reason we need to have different items per profile. const QVariantMap profileModuleProperties = m_product.profileModuleProperties.value(moduleName).toMap(); for (auto it = profileModuleProperties.cbegin(); it != profileModuleProperties.cend(); ++it) { if (Q_UNLIKELY(!module->hasProperty(it.key()))) { m_loaderState.topLevelProject().addUnknownProfilePropertyError( module, {Tr::tr("Unknown property: %1.%2").arg(moduleName, it.key())}); continue; } const PropertyDeclaration decl = module->propertyDeclaration(it.key()); VariantValuePtr v = VariantValue::create( PropertyDeclaration::convertToPropertyType(it.value(), decl.type(), QStringList(moduleName), it.key())); v->markAsSetByProfile(); module->setProperty(it.key(), v); } return module; } bool ModuleLoader::evaluateModuleCondition(Item *module, const QString &fullModuleName) { ModuleItemLocker locker(*module); // Temporarily make the product's qbs module instance available, so the condition // can use qbs.targetOS etc. class TempQbsModuleProvider { public: TempQbsModuleProvider(const ProductContext &product, Item *module, const QString &moduleName) : m_module(module), m_needsQbsItem(moduleName != StringConstants::qbsModule()) { if (m_needsQbsItem) { m_prevQbsItemValue = module->property(StringConstants::qbsModule()); module->setProperty(StringConstants::qbsModule(), product.item->property(StringConstants::qbsModule())); } } ~TempQbsModuleProvider() { if (!m_needsQbsItem) return; if (m_prevQbsItemValue) m_module->setProperty(StringConstants::qbsModule(), m_prevQbsItemValue); else m_module->removeProperty(StringConstants::qbsModule()); } private: Item * const m_module; ValuePtr m_prevQbsItemValue; const bool m_needsQbsItem; }; const TempQbsModuleProvider tempQbs(m_product, module, fullModuleName); return m_loaderState.evaluator().boolValue(module, StringConstants::conditionProperty()); } void ModuleLoader::checkForUnknownProfileProperties(const Item *module) { const std::vector &errors = m_loaderState.topLevelProject().unknownProfilePropertyErrors(module); if (errors.empty()) return; ErrorInfo error(Tr::tr("Loading module '%1' for product '%2' failed due to invalid values " "in profile '%3':") .arg(m_moduleName.toString(), m_product.displayName(), m_product.profileName)); for (const ErrorInfo &e : errors) error.append(e.toString()); handlePropertyError(error, m_loaderState.parameters(), m_loaderState.logger()); } QString ModuleLoader::findModuleDirectory(const QString &searchPath) { // isFileCaseCorrect is a very expensive call on macOS, so we cache the value for the // modules and search paths we've already processed return m_loaderState.topLevelProject().findModuleDirectory(m_moduleName, searchPath, [&] { QString dirPath = searchPath + QStringLiteral("/modules"); for (const QString &moduleNamePart : m_moduleName) { dirPath = FileInfo::resolvePath(dirPath, moduleNamePart); if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) return QString(); } return dirPath; }); } QStringList ModuleLoader::findModuleDirectories() { const QStringList &searchPaths = m_loaderState.itemReader().allSearchPaths(); QStringList result; result.reserve(searchPaths.size()); for (const auto &path: searchPaths) { const QString dirPath = findModuleDirectory(path); if (!dirPath.isEmpty()) result.append(dirPath); } return result; } QStringList ModuleLoader::getModuleFilePaths(const QString &dir) { return m_loaderState.topLevelProject().getModuleFilesForDirectory(dir, [&] { QStringList moduleFiles; QDirIterator dirIter(dir, StringConstants::qbsFileWildcards()); while (dirIter.hasNext()) moduleFiles += dirIter.next(); return moduleFiles; }); } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/itemreader.h0000644000175100001660000001026214776170045021165 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMREADER_H #define QBS_ITEMREADER_H #include #include #include #include #include namespace qbs { class SetupProjectParameters; namespace Internal { class Evaluator; class Item; class ItemPool; class ItemReaderVisitorState; class LoaderState; /* * Reads a qbs file and creates a tree of Item objects. * * In this stage the following steps are performed: * - The QML/JS parser creates the AST. * - The AST is converted to a tree of Item objects. * * This class is also responsible for the QMLish inheritance semantics. */ class ItemReader { public: ItemReader(LoaderState &loaderState); ~ItemReader(); void init(); void pushExtraSearchPaths(const QStringList &extraSearchPaths); void popExtraSearchPaths(); const std::vector &extraSearchPathsStack() const; void setExtraSearchPathsStack(const std::vector &s); void clearExtraSearchPathsStack(); const QStringList &allSearchPaths() const; // Parses a file, creates an item for it, generates PropertyDeclarations from // PropertyOptions items and removes said items from the item tree. Item *setupItemFromFile(const QString &filePath, const CodeLocation &referencingLocation); Item *wrapInProjectIfNecessary(Item *item); QStringList readExtraSearchPaths(Item *item, bool *wasSet = nullptr); qint64 elapsedTime() const { return m_elapsedTime; } private: void setSearchPaths(const QStringList &searchPaths); Item *readFile(const QString &filePath); Item *readFile(const QString &filePath, const CodeLocation &referencingLocation); void handlePropertyOptions(Item *optionsItem); void handleAllPropertyOptionsItems(Item *item); LoaderState &m_loaderState; QStringList m_searchPaths; std::vector m_extraSearchPaths; mutable QStringList m_allSearchPaths; std::unique_ptr m_visitorState; QString m_projectFilePath; qint64 m_elapsedTime = -1; }; class SearchPathsManager { public: SearchPathsManager(ItemReader &itemReader, const QStringList &extraSearchPaths = {}); ~SearchPathsManager(); private: ItemReader &m_itemReader; size_t m_oldSize{0}; }; } // namespace Internal } // namespace qbs #endif // QBS_ITEMREADER_H qbs-src-2.6.1/src/lib/corelib/loader/productsresolver.cpp0000644000175100001660000006354314776170045023036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "productsresolver.h" #include "itemreader.h" #include "loaderutils.h" #include "productresolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { namespace { struct ThreadInfo { ThreadInfo(std::future &&future, LoaderState &loaderState) : future(std::move(future)), loaderState(loaderState) {} std::future future; LoaderState &loaderState; bool done = false; }; struct ProductWithLoaderState { ProductWithLoaderState(ProductContext &product, LoaderState *loaderState) : product(&product), loaderState(loaderState) {} ProductContext * const product; LoaderState *loaderState; }; class ThreadsLocker { public: ThreadsLocker(std::launch mode, std::mutex &mutex) { if (mode == std::launch::async) lock = std::make_unique>(mutex); } std::unique_ptr> lock; }; } // namespace class ProductsResolver { public: ProductsResolver(LoaderState &loaderState) : m_loaderState(loaderState) {} void resolve(); private: void initialize(); void initializeProductQueue(); void initializeLoaderStatePool(); void runScheduler(); void scheduleNext(); bool tryToReserveLoaderState(ProductWithLoaderState &product, Deferral deferral); std::optional> unblockProductWaitingForLoaderState(LoaderState &loaderState); void startJob(const ProductWithLoaderState &product, Deferral deferral); void checkForCancelation(); void handleFinishedThreads(); void queueProductForScheduling(const ProductWithLoaderState &product, Deferral deferral); void waitForSingleDependency(const ProductWithLoaderState &product, ProductContext &dependency); void waitForBulkDependency(const ProductWithLoaderState &product); void unblockProductsWaitingForDependency(ProductContext &finishedProduct); void postProcess(); void checkForMissedBulkDependencies(const ProductContext &product); static int dependsItemCount(const Item *item); static int dependsItemCount(ProductContext &product); LoaderState &m_loaderState; std::queue> m_productsToSchedule; std::vector m_finishedProducts; std::unordered_map> m_waitingForSingleDependency; std::vector m_waitingForBulkDependency; std::unordered_map>> m_waitingForLoaderState; std::unordered_map m_runningThreads; std::mutex m_threadsMutex; std::condition_variable m_threadsNotifier; std::vector> m_enginePool; std::vector> m_loaderStatePool; std::vector m_availableLoaderStates; std::mutex m_cancelingMutex; std::launch m_asyncMode = std::launch::async; int m_maxJobCount = m_loaderState.parameters().maxJobCount(); bool m_canceling = false; }; void resolveProducts(LoaderState &loaderState) { ProductsResolver(loaderState).resolve(); } void ProductsResolver::resolve() { initialize(); try { runScheduler(); } catch (const ErrorInfo &e) { for (auto &thread : m_runningThreads) thread.second.future.wait(); throw e; } postProcess(); } void ProductsResolver::initialize() { initializeProductQueue(); initializeLoaderStatePool(); } void ProductsResolver::initializeProductQueue() { TopLevelProjectContext &topLevelProject = m_loaderState.topLevelProject(); std::vector sortedProducts; for (ProjectContext * const projectContext : topLevelProject.projects()) { for (ProductContext &product : projectContext->products) { topLevelProject.addProductToHandle(product); const auto it = std::lower_bound(sortedProducts.begin(), sortedProducts.end(), product, [&product](ProductContext *p1, const ProductContext &) { return dependsItemCount(*p1) < dependsItemCount(product); }); sortedProducts.insert(it, &product); } } for (ProductContext * const product : sortedProducts) { queueProductForScheduling(ProductWithLoaderState(*product, nullptr), Deferral::Allowed); if (product->shadowProduct) { topLevelProject.addProductToHandle(*product->shadowProduct); queueProductForScheduling(ProductWithLoaderState(*product->shadowProduct, nullptr), Deferral::Allowed); } } } void ProductsResolver::initializeLoaderStatePool() { TopLevelProjectContext &topLevelProject = m_loaderState.topLevelProject(); // Adapt max job count: It makes no sense to have it be higher than the number of products // or what can actually be run concurrently. In both cases, we would simply waste resources. const int maxConcurrency = std::thread::hardware_concurrency(); if (maxConcurrency > 0 && maxConcurrency < m_maxJobCount) m_maxJobCount = maxConcurrency; if (m_maxJobCount > topLevelProject.productsToHandleCount()) m_maxJobCount = topLevelProject.productsToHandleCount(); // The number of engines and loader states we need to allocate here is one less than the // total number of concurrent jobs, as we already have one loader state that we can re-use. if (m_maxJobCount > 1) m_enginePool.reserve(m_maxJobCount - 1); m_loaderStatePool.reserve(m_enginePool.size()); m_availableLoaderStates.reserve(m_enginePool.size() + 1); m_availableLoaderStates.push_back(&m_loaderState); m_loaderState.evaluator().engine()->setSetupProjectParameters(m_loaderState.parameters()); for (std::size_t i = 0; i < m_enginePool.capacity(); ++i) { ScriptEngine &engine = *m_enginePool.emplace_back( ScriptEngine::create(m_loaderState.logger(), EvalContext::PropertyEvaluation)); ItemPool &itemPool = topLevelProject.createItemPool(); engine.setEnvironment(m_loaderState.parameters().adjustedEnvironment()); auto loaderState = std::make_unique( m_loaderState.parameters(), topLevelProject, itemPool, engine, m_loaderState.logger()); loaderState->evaluator().engine()->setSetupProjectParameters(m_loaderState.parameters()); m_loaderStatePool.push_back(std::move(loaderState)); m_availableLoaderStates.push_back(m_loaderStatePool.back().get()); if (topLevelProject.progressObserver()) topLevelProject.progressObserver()->addScriptEngine(m_enginePool.back().get()); } qCDebug(lcLoaderScheduling) << "using" << m_availableLoaderStates.size() << "loader states"; if (int(m_availableLoaderStates.size()) == 1) m_asyncMode = std::launch::deferred; } void ProductsResolver::runScheduler() { AccumulatingTimer timer(m_loaderState.parameters().logElapsedTime() ? &m_loaderState.topLevelProject().timingData().resolvingProducts : nullptr); ThreadsLocker threadsLock(m_asyncMode, m_threadsMutex); while (true) { scheduleNext(); if (m_runningThreads.empty()) break; if (m_asyncMode == std::launch::async) { qCDebug(lcLoaderScheduling()) << "scheduling paused, waiting for threads to finish"; m_threadsNotifier.wait(*threadsLock.lock); } checkForCancelation(); handleFinishedThreads(); } QBS_CHECK(m_productsToSchedule.empty()); QBS_CHECK(m_loaderState.topLevelProject().productsToHandleCount() == 0); QBS_CHECK(m_runningThreads.empty()); QBS_CHECK(m_waitingForSingleDependency.empty()); QBS_CHECK(m_waitingForBulkDependency.empty()); } void ProductsResolver::scheduleNext() { TopLevelProjectContext &topLevelProject = m_loaderState.topLevelProject(); AccumulatingTimer timer(m_loaderState.parameters().logElapsedTime() ? &topLevelProject.timingData().schedulingProducts : nullptr); while (m_maxJobCount > int(m_runningThreads.size()) && !m_productsToSchedule.empty()) { auto [product, toHandleCountOnInsert] = m_productsToSchedule.front(); m_productsToSchedule.pop(); qCDebug(lcLoaderScheduling) << "potentially scheduling product" << product.product->displayName() << "unhandled product count on queue insertion" << toHandleCountOnInsert << "current unhandled product count" << topLevelProject.productsToHandleCount(); // If the number of unfinished products has shrunk since the last time we tried handling // this product, there has been forward progress and we can allow a deferral. const Deferral deferral = toHandleCountOnInsert == -1 || toHandleCountOnInsert > topLevelProject.productsToHandleCount() ? Deferral::Allowed : Deferral::NotAllowed; if (!tryToReserveLoaderState(product, deferral)) continue; startJob(product, deferral); } // There are jobs running, so forward progress is still possible. if (!m_runningThreads.empty()) return; QBS_CHECK(m_productsToSchedule.empty()); // If we end up here, nothing was scheduled in the loop above, which means that either ... // a) ... we are done or // b) ... we finally need to schedule our bulk dependencies or // c) ... we need to schedule products waiting for an unhandled dependency. // In the latter case, the project has at least one dependency cycle, and the // DependencyResolver will emit an error. // a) if (m_waitingForBulkDependency.empty() && m_waitingForSingleDependency.empty()) return; // b) for (const ProductWithLoaderState &product : m_waitingForBulkDependency) queueProductForScheduling(product, Deferral::NotAllowed); if (!m_productsToSchedule.empty()) { m_waitingForBulkDependency.clear(); scheduleNext(); return; } // c) for (const auto &e : m_waitingForSingleDependency) { for (const ProductWithLoaderState &p : e.second) queueProductForScheduling(p, Deferral::NotAllowed); } QBS_CHECK(!m_productsToSchedule.empty()); scheduleNext(); } bool ProductsResolver::tryToReserveLoaderState(ProductWithLoaderState &product, Deferral deferral) { QBS_CHECK(!m_availableLoaderStates.empty()); if (!product.loaderState) { product.loaderState = m_availableLoaderStates.back(); m_availableLoaderStates.pop_back(); return true; } if (const auto it = std::find(m_availableLoaderStates.begin(), m_availableLoaderStates.end(), product.loaderState); it != m_availableLoaderStates.end()) { m_availableLoaderStates.erase(it); return true; } qCDebug(lcLoaderScheduling) << "loader state" << product.loaderState << " for product" << product.product->displayName() << "not available, adding product to wait queue"; m_waitingForLoaderState[product.loaderState].push({product.product, deferral}); return false; } std::optional> ProductsResolver::unblockProductWaitingForLoaderState(LoaderState &loaderState) { auto &waitingForLoaderState = m_waitingForLoaderState[&loaderState]; if (waitingForLoaderState.empty()) return {}; const auto product = waitingForLoaderState.front(); waitingForLoaderState.pop(); qCDebug(lcLoaderScheduling) << "loader state" << &loaderState << "now available for product" << product.first->displayName(); return product; } void ProductsResolver::startJob(const ProductWithLoaderState &product, Deferral deferral) { QBS_CHECK(product.loaderState); qCDebug(lcLoaderScheduling) << "scheduling product" << product.product->displayName() << "with loader state" << product.loaderState << "and deferral mode" << int(deferral); try { const auto it = m_runningThreads.emplace(product.product, ThreadInfo(std::async(m_asyncMode, [this, product, deferral] { product.loaderState->itemReader().setExtraSearchPathsStack( product.product->project->searchPathsStack); resolveProduct(*product.product, deferral, *product.loaderState); // The search paths stack can change during dependency resolution // (due to module providers); check that we've rolled back all the changes QBS_CHECK(product.loaderState->itemReader().extraSearchPathsStack() == product.product->project->searchPathsStack); std::lock_guard cancelingLock(m_cancelingMutex); if (m_canceling) return; ThreadsLocker threadsLock(m_asyncMode, m_threadsMutex); if (const auto it = m_runningThreads.find(product.product); it != m_runningThreads.end()) { it->second.done = true; qCDebug(lcLoaderScheduling) << "thread for product" << product.product->displayName() << "finished, waking up scheduler"; m_threadsNotifier.notify_one(); } }), *product.loaderState)); // With just one worker thread, the notify/wait overhead would be excessive, so // we run the task synchronously. if (m_asyncMode == std::launch::deferred) { qCDebug(lcLoaderScheduling) << "blocking on product thread immediately"; it.first->second.future.wait(); } } catch (const std::system_error &e) { if (e.code() != std::errc::resource_unavailable_try_again) throw e; qCWarning(lcLoaderScheduling) << "failed to create thread"; if (m_maxJobCount >= 2) { m_maxJobCount /= 2; qCWarning(lcLoaderScheduling) << "throttling down to" << m_maxJobCount << "jobs"; } queueProductForScheduling(product, deferral); m_availableLoaderStates.push_back(product.loaderState); } } void ProductsResolver::checkForCancelation() { if (m_loaderState.topLevelProject().isCanceled()) { m_cancelingMutex.lock(); m_canceling = true; m_cancelingMutex.unlock(); for (auto &thread : m_runningThreads) thread.second.future.wait(); throw CancelException(); } } void ProductsResolver::handleFinishedThreads() { TopLevelProjectContext &topLevelProject = m_loaderState.topLevelProject(); AccumulatingTimer timer(m_loaderState.parameters().logElapsedTime() ? &topLevelProject.timingData().schedulingProducts : nullptr); std::vector> productsToScheduleDirectly; for (auto it = m_runningThreads.begin(); it != m_runningThreads.end();) { ThreadInfo &ti = it->second; if (!ti.done) { ++it; continue; } ti.future.wait(); ProductContext &product = *it->first; LoaderState &loaderState = ti.loaderState; it = m_runningThreads.erase(it); qCDebug(lcLoaderScheduling) << "handling finished thread for product" << product.displayName() << "current unhandled product count is" << topLevelProject.productsToHandleCount(); // If there are products waiting for the loader state used in the finished thread, // we can start a job for one of them right away (but not in the loop, // because startJob() modifies the thread list we are currently iterating over). if (const auto productInfo = unblockProductWaitingForLoaderState(loaderState)) { productsToScheduleDirectly.emplace_back( ProductWithLoaderState(*productInfo->first, &loaderState), productInfo->second); } else { qCDebug(lcLoaderScheduling) << "making loader state" << &loaderState << "available again"; m_availableLoaderStates.push_back(&loaderState); } // If we encountered a dependency to an in-progress product or to a bulk dependency, // we defer handling this product. if (product.dependenciesResolvingPending()) { qCDebug(lcLoaderScheduling) << "dependencies resolving not finished for product" << product.displayName(); const auto pending = product.pendingDependency(); switch (pending.first) { case ProductDependency::Single: waitForSingleDependency(ProductWithLoaderState(product, &loaderState), *pending.second); break; case ProductDependency::Bulk: waitForBulkDependency(ProductWithLoaderState(product, &loaderState)); break; case ProductDependency::None: // This can happen if the dependency has finished in between the check in // DependencyResolver and the one here. QBS_CHECK(pending.second); queueProductForScheduling(ProductWithLoaderState(product, &loaderState), Deferral::Allowed); break; } topLevelProject.incProductDeferrals(); } else { qCDebug(lcLoaderScheduling) << "product" << product.displayName() << "finished"; topLevelProject.removeProductToHandle(product); if (!product.name.startsWith(StringConstants::shadowProductPrefix())) m_finishedProducts.push_back(&product); topLevelProject.timingData() += product.timingData; checkForMissedBulkDependencies(product); topLevelProject.registerBulkDependencies(product); unblockProductsWaitingForDependency(product); } } for (const auto &productInfo : productsToScheduleDirectly) startJob(productInfo.first, productInfo.second); } void ProductsResolver::queueProductForScheduling(const ProductWithLoaderState &product, Deferral deferral) { qCDebug(lcLoaderScheduling) << "queueing product" << product.product->displayName() << "with deferral mode" << int(deferral); m_productsToSchedule.emplace(product, deferral == Deferral::Allowed ? -1 : m_loaderState.topLevelProject().productsToHandleCount()); } void ProductsResolver::waitForSingleDependency(const ProductWithLoaderState &product, ProductContext &dependency) { qCDebug(lcLoaderScheduling) << "product" << product.product->displayName() << "now waiting for single dependency" << dependency.displayName(); m_waitingForSingleDependency[&dependency].push_back(product); } void ProductsResolver::waitForBulkDependency(const ProductWithLoaderState &product) { qCDebug(lcLoaderScheduling) << "product" << product.product->displayName() << "now waiting for bulk dependency"; m_waitingForBulkDependency.push_back(product); } void ProductsResolver::unblockProductsWaitingForDependency(ProductContext &finishedProduct) { const auto it = m_waitingForSingleDependency.find(&finishedProduct); if (it == m_waitingForSingleDependency.end()) return; qCDebug(lcLoaderScheduling) << "unblocking all products waiting for now-finished product" << finishedProduct.displayName(); for (const ProductWithLoaderState &p : it->second) { qCDebug(lcLoaderScheduling) << " unblocking product" << p.product->displayName(); queueProductForScheduling(p, Deferral::Allowed); } m_waitingForSingleDependency.erase(it); } void ProductsResolver::postProcess() { for (ProductContext * const product : m_finishedProducts) { if (product->product) product->product->project->products.push_back(product->product); // This has to be done in post-processing, because we need both product and shadow product // to be ready, and contrary to what one might assume, there is no proper ordering // between them regarding dependency resolving. setupExports(*product, m_loaderState); } for (const auto &engine : m_enginePool) m_loaderState.topLevelProject().collectDataFromEngine(*engine); QBS_CHECK(!m_loaderState.topLevelProject().projects().empty()); const auto project = std::dynamic_pointer_cast( m_loaderState.topLevelProject().projects().front()->project); QBS_CHECK(project); for (LoaderState * const loaderState : m_availableLoaderStates) { project->warningsEncountered << loaderState->logger().warnings(); project->errorsEncountered << loaderState->logger().errors(); if (loaderState == &m_loaderState) { project->warningsEncountered << loaderState->evaluator().engine()->logger().warnings(); project->errorsEncountered << loaderState->evaluator().engine()->logger().errors(); } } } void ProductsResolver::checkForMissedBulkDependencies(const ProductContext &product) { if (!product.product || !product.product->enabled || !product.bulkDependencies.empty()) return; for (const FileTag &tag : product.product->fileTags) { for (const auto &[p, location] : m_loaderState.topLevelProject().finishedProductsWithBulkDependency(tag)) { if (!p->product->enabled) continue; if (p->name == product.name) continue; ErrorInfo e; e.append(Tr::tr("Cyclic dependencies detected:")); e.append(Tr::tr("First product is '%1'.") .arg(product.displayName()), product.item->location()); e.append(Tr::tr("Second product is '%1'.") .arg(p->displayName()), p->item->location()); e.append(Tr::tr("Dependency from %1 to %2 was established via Depends.productTypes.") .arg(p->displayName(), product.displayName()), location); if (m_loaderState.parameters().productErrorMode() == ErrorHandlingMode::Strict) throw e; m_loaderState.logger().printError(e); m_loaderState.logger().printError(ErrorInfo( Tr::tr("Product '%1' had errors and was disabled.").arg(product.displayName()), product.item->location())); m_loaderState.logger().printError(ErrorInfo( Tr::tr("Product '%1' had errors and was disabled.").arg(p->displayName()), p->item->location())); product.product->enabled = false; p->product->enabled = false; } } } int ProductsResolver::dependsItemCount(const Item *item) { int count = 0; for (const Item * const child : item->children()) { if (child->type() == ItemType::Depends) ++count; } return count; } int ProductsResolver::dependsItemCount(ProductContext &product) { if (product.dependsItemCount == -1) product.dependsItemCount = dependsItemCount(product.item); return product.dependsItemCount; } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/productitemmultiplexer.cpp0000644000175100001660000002513514776170045024236 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "productitemmultiplexer.h" #include "loaderutils.h" #include "moduleinstantiator.h" #include #include #include #include #include #include #include #include #include #include // This module deals with product multiplexing over the various defined axes. // For instance, a product with qbs.architectures: ["x86", "arm"] will get multiplexed into // two products with qbs.architecture: "x86" and qbs.architecture: "arm", respectively. namespace qbs::Internal { namespace { using MultiplexRow = std::vector; using MultiplexTable = std::vector; class MultiplexInfo { public: std::vector properties; MultiplexTable table; bool aggregate = false; VariantValuePtr multiplexedType; QString toIdString(size_t row, LoaderState &loaderState) const; }; } // namespace class ProductItemMultiplexer { public: ProductItemMultiplexer(const QString &productName, Item *productItem, Item *tempQbsModuleItem, const std::function &dropTempQbsModule, LoaderState &loaderState) : m_loaderState(loaderState), m_productName(productName), m_productItem(productItem), m_tempQbsModuleItem(tempQbsModuleItem), m_dropTempQbsModule(dropTempQbsModule) {} QList multiplex(); private: MultiplexInfo extractMultiplexInfo(); MultiplexTable combine(const MultiplexTable &table, const MultiplexRow &values); LoaderState &m_loaderState; const QString &m_productName; Item * const m_productItem; Item * const m_tempQbsModuleItem; const std::function &m_dropTempQbsModule; }; QList ProductItemMultiplexer::multiplex() { const auto multiplexInfo = extractMultiplexInfo(); m_dropTempQbsModule(); if (multiplexInfo.table.size() > 1) m_productItem->setProperty(StringConstants::multiplexedProperty(), VariantValue::trueValue()); VariantValuePtr productNameValue = VariantValue::create(m_productName); Item *aggregator = multiplexInfo.aggregate ? m_productItem->clone(m_loaderState.itemPool()) : nullptr; QList additionalProductItems; std::vector multiplexConfigurationIdValues; for (size_t row = 0; row < multiplexInfo.table.size(); ++row) { Item *item = m_productItem; const auto &mprow = multiplexInfo.table.at(row); QBS_CHECK(mprow.size() == multiplexInfo.properties.size()); if (row > 0) { item = m_productItem->clone(m_loaderState.itemPool()); additionalProductItems.push_back(item); } const QString multiplexConfigurationId = multiplexInfo.toIdString(row, m_loaderState); const VariantValuePtr multiplexConfigurationIdValue = VariantValue::create(multiplexConfigurationId); if (multiplexInfo.table.size() > 1 || aggregator) { multiplexConfigurationIdValues.push_back(multiplexConfigurationIdValue); item->setProperty(StringConstants::multiplexConfigurationIdProperty(), multiplexConfigurationIdValue); } if (multiplexInfo.multiplexedType) item->setProperty(StringConstants::typeProperty(), multiplexInfo.multiplexedType); for (size_t column = 0; column < mprow.size(); ++column) { Item * const qbsItem = retrieveQbsItem(item, m_loaderState); const QString &propertyName = multiplexInfo.properties.at(column); const VariantValuePtr &mpvalue = mprow.at(column); qbsItem->setProperty(propertyName, mpvalue); } } if (aggregator) { additionalProductItems << aggregator; // Add dependencies to all multiplexed instances. for (const auto &v : multiplexConfigurationIdValues) { Item *dependsItem = Item::create(&m_loaderState.itemPool(), ItemType::Depends); dependsItem->setProperty(StringConstants::nameProperty(), productNameValue); dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), v); dependsItem->setProperty(StringConstants::profilesProperty(), VariantValue::create(QStringList())); dependsItem->setFile(aggregator->file()); dependsItem->setupForBuiltinType(m_loaderState.parameters().deprecationWarningMode(), m_loaderState.logger()); Item::addChild(aggregator, dependsItem); } } return additionalProductItems; } MultiplexInfo ProductItemMultiplexer::extractMultiplexInfo() { static const QString mpmKey = QStringLiteral("multiplexMap"); Evaluator &evaluator = m_loaderState.evaluator(); JSContext * const ctx = evaluator.engine()->context(); const ScopedJsValue multiplexMap(ctx, evaluator.value(m_tempQbsModuleItem, mpmKey)); const QStringList multiplexByQbsProperties = evaluator.stringListValue( m_productItem, StringConstants::multiplexByQbsPropertiesProperty()); MultiplexInfo multiplexInfo; multiplexInfo.aggregate = evaluator.boolValue( m_productItem, StringConstants::aggregateProperty()); const QString multiplexedType = evaluator.stringValue( m_productItem, StringConstants::multiplexedTypeProperty()); if (!multiplexedType.isEmpty()) multiplexInfo.multiplexedType = VariantValue::create(multiplexedType); Set uniqueMultiplexByQbsProperties; for (const QString &key : multiplexByQbsProperties) { const QString mappedKey = getJsStringProperty(ctx, multiplexMap, key); if (mappedKey.isEmpty()) throw ErrorInfo(Tr::tr("There is no entry for '%1' in 'qbs.multiplexMap'.").arg(key)); if (!uniqueMultiplexByQbsProperties.insert(mappedKey).second) continue; const ScopedJsValue arr(ctx, evaluator.value(m_tempQbsModuleItem, key)); if (JS_IsUndefined(arr)) continue; if (!JS_IsArray(ctx, arr)) throw ErrorInfo(Tr::tr("Property '%1' must be an array.").arg(key)); const quint32 arrlen = getJsIntProperty(ctx, arr, StringConstants::lengthProperty()); if (arrlen == 0) continue; MultiplexRow mprow; mprow.reserve(arrlen); QVariantList entriesForKey; for (quint32 i = 0; i < arrlen; ++i) { const ScopedJsValue sv(ctx, JS_GetPropertyUint32(ctx, arr, i)); const QVariant value = getJsVariant(ctx, sv); if (entriesForKey.contains(value)) continue; entriesForKey << value; mprow.push_back(VariantValue::create(value)); } multiplexInfo.table = combine(multiplexInfo.table, mprow); multiplexInfo.properties.push_back(mappedKey); } return multiplexInfo; } MultiplexTable ProductItemMultiplexer::combine(const MultiplexTable &table, const MultiplexRow &values) { MultiplexTable result; if (table.empty()) { result.resize(values.size()); for (size_t i = 0; i < values.size(); ++i) { MultiplexRow row; row.resize(1); row[0] = values.at(i); result[i] = row; } } else { for (const auto &row : table) { for (const auto &value : values) { MultiplexRow newRow = row; newRow.push_back(value); result.push_back(newRow); } } } return result; } QString MultiplexInfo::toIdString(size_t row, LoaderState &loaderState) const { const auto &mprow = table.at(row); QVariantMap multiplexConfiguration; for (size_t column = 0; column < mprow.size(); ++column) { const QString &propertyName = properties.at(column); const VariantValuePtr &mpvalue = mprow.at(column); multiplexConfiguration.insert(propertyName, mpvalue->value()); } QString id = QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration) .toJson(QJsonDocument::Compact) .toBase64()); // Cache for later use in multiplexIdToVariantMap() loaderState.topLevelProject().addMultiplexConfiguration(id, multiplexConfiguration); return id; } QList multiplex(const QString &productName, Item *productItem, Item *tempQbsModuleItem, const std::function &dropTempQbsModule, LoaderState &loaderState) { return ProductItemMultiplexer(productName, productItem, tempQbsModuleItem, dropTempQbsModule, loaderState).multiplex(); } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/dependenciesresolver.cpp0000644000175100001660000014271614776170045023621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "dependenciesresolver.h" #include "itemreader.h" #include "loaderutils.h" #include "moduleinstantiator.h" #include "moduleloader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { namespace { enum class HandleDependency { Use, Ignore, Defer }; class LoadModuleResult { public: Item *moduleItem = nullptr; ProductContext *product = nullptr; HandleDependency handleDependency = HandleDependency::Use; }; // Corresponds completely to a Depends item. // May result in more than one module, due to "multiplexing" properties such as subModules etc. // May also result in no module at all, e.g. if productTypes does not match anything. class EvaluatedDependsItem { public: Item *item = nullptr; QualifiedId name; QStringList subModules; FileTags productTypes; QStringList multiplexIds; std::optional profiles; VersionRange versionRange; QVariantMap parameters; bool limitToSubProject = false; bool requiredLocally = true; bool requiredGlobally = true; }; // As opposed to EvaluatedDependsItem, one of these corresponds exactly to one module // to be loaded. Such an attempt might still fail, though, which may or may not result // in an error, depending on the value of Depends.required and other circumstances. class FullyResolvedDependsItem { public: FullyResolvedDependsItem(ProductContext *product, const EvaluatedDependsItem &dependency); FullyResolvedDependsItem(const EvaluatedDependsItem &dependency, QualifiedId name, QString profile, QString multiplexId); FullyResolvedDependsItem() = default; static FullyResolvedDependsItem makeBaseDependency(); QString id() const; CodeLocation location() const; QString displayName() const; // If product is non-null, we already know which product the dependency targets. // This happens either if Depends.productTypes was set, or if we tried to load the // dependency before and already identified the product, but could not complete the // procedure because said product had itself not been handled yet. ProductContext *product = nullptr; Item *item = nullptr; QualifiedId name; QString profile; QString multiplexId; VersionRange versionRange; QVariantMap parameters; bool limitToSubProject = false; bool requiredLocally = true; bool requiredGlobally = true; bool checkProduct = true; }; class DependenciesResolvingState { public: Item *loadingItem = nullptr; FullyResolvedDependsItem loadingItemOrigin; std::queue pendingDependsItems; std::optional currentDependsItem; std::queue pendingResolvedDependencies; bool requiredByLoadingItem = true; }; class DependenciesContextImpl : public DependenciesContext { public: DependenciesContextImpl(ProductContext &product, LoaderState &loaderState); std::list stateStack; private: std::pair pendingDependency() const override; void setSearchPathsForProduct(LoaderState &loaderState); ProductContext &m_product; }; class DependenciesResolver { public: DependenciesResolver(LoaderState &loaderState, ProductContext &product, Deferral deferral) : m_loaderState(loaderState), m_product(product), m_deferral(deferral) {} void resolve(); LoadModuleResult loadModule(Item *loadingItem, const FullyResolvedDependsItem &dependency); private: void evaluateNextDependsItem(); HandleDependency handleResolvedDependencies(); std::pair findExistingModule(const FullyResolvedDependsItem &dependency, Item *item); void updateModule(Item::Module &module, const FullyResolvedDependsItem &dependency); int dependsChainLength(); ProductContext *findMatchingProduct(const FullyResolvedDependsItem &dependency); Item *findMatchingModule(const FullyResolvedDependsItem &dependency); std::pair checkProductDependency( const FullyResolvedDependsItem &depSpec, const ProductContext &dep); void checkModule(const FullyResolvedDependsItem &dependency, Item *moduleItem, ProductContext *productDep); void checkForModuleNamePrefixCollision(const FullyResolvedDependsItem &dependency); Item::Module createModule(const FullyResolvedDependsItem &dependency, Item *item, ProductContext *productDep); void adjustDependsItemForMultiplexing(Item *dependsItem); std::optional evaluateDependsItem(Item *item); std::queue multiplexDependency( const EvaluatedDependsItem &dependency); QVariantMap extractParameters(Item *dependsItem) const; void forwardParameterDeclarations(const Item *dependsItem, const Item::Modules &modules); void forwardParameterDeclarations(const QualifiedId &moduleName, Item *item, const Item::Modules &modules); std::list &stateStack(); LoaderState &m_loaderState; ProductContext &m_product; Deferral m_deferral; }; static bool haveSameSubProject(const ProductContext &p1, const ProductContext &p2); static QVariantMap safeToVariant(JSContext *ctx, const JSValue &v); static void collectDependsItems(Item *parent, std::queue &dependsItems); } // namespace void resolveDependencies(ProductContext &product, Deferral deferral, LoaderState &loaderState) { DependenciesResolver(loaderState, product, deferral).resolve(); } Item *loadBaseModule(ProductContext &product, Item *item, LoaderState &loaderState) { const auto baseDependency = FullyResolvedDependsItem::makeBaseDependency(); Item * const moduleItem = DependenciesResolver(loaderState, product, Deferral::NotAllowed) .loadModule(item, baseDependency).moduleItem; if (Q_UNLIKELY(!moduleItem)) throw ErrorInfo(Tr::tr("Cannot load base qbs module.")); return moduleItem; } namespace { void DependenciesResolver::resolve() { AccumulatingTimer timer(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.dependenciesResolving : nullptr); if (!m_product.dependenciesContext) { m_product.dependenciesContext = std::make_unique( m_product, m_loaderState); } else { QBS_CHECK(!m_product.dependenciesContext->dependenciesResolved); } SearchPathsManager searchPathsMgr(m_loaderState.itemReader(), m_product.searchPaths); while (!stateStack().empty()) { auto &state = stateStack().front(); // If we have pending FullyResolvedDependsItems, then these are handled first. if (handleResolvedDependencies() == HandleDependency::Defer) return; // The above procedure might have pushed another state to the stack due to recursive // dependencies (i.e. Depends items in the newly loaded module), in which case we // continue with that one. if (&state != &stateStack().front()) continue; // If we have a pending EvaluatedDependsItem, we multiplex it and then handle // the resulting FullyResolvedDependsItems, if there were any. if (state.currentDependsItem) { QBS_CHECK(state.pendingResolvedDependencies.empty()); // We postpone handling Depends.productTypes for as long as possible, because // the full type of a product becomes available only after its modules have been loaded. if (!state.currentDependsItem->productTypes.empty() && m_deferral == Deferral::Allowed) return; state.pendingResolvedDependencies = multiplexDependency(*state.currentDependsItem); state.currentDependsItem.reset(); m_deferral = Deferral::Allowed; // We made progress. continue; } // Here we have no resolved/evaluated Depends items of any kind, so we evaluate the next // pending Depends item. evaluateNextDependsItem(); if (state.currentDependsItem) continue; // No resolved or unresolved Depends items are left, so we're done with the current state. QBS_CHECK(!state.currentDependsItem); QBS_CHECK(state.pendingResolvedDependencies.empty()); QBS_CHECK(state.pendingDependsItems.empty()); // This ensures our invariant: A sorted module list in the product // (dependers after dependencies). if (stateStack().size() > 1) { QBS_CHECK(state.loadingItem->type() == ItemType::ModuleInstance); Item::Modules &modules = m_product.item->modules(); const auto loadingItemModule = std::find_if(modules.begin(), modules.end(), [&](const Item::Module &m) { return m.item == state.loadingItem; }); QBS_CHECK(loadingItemModule != modules.end()); const Item::Module tempModule = *loadingItemModule; modules.erase(loadingItemModule); modules.push_back(tempModule); } stateStack().pop_front(); } m_product.dependenciesContext->dependenciesResolved = true; } void DependenciesResolver::evaluateNextDependsItem() { auto &state = stateStack().front(); while (!state.pendingDependsItems.empty()) { QBS_CHECK(!state.currentDependsItem); QBS_CHECK(state.pendingResolvedDependencies.empty()); Item * const dependsItem = state.pendingDependsItems.front(); state.pendingDependsItems.pop(); adjustDependsItemForMultiplexing(dependsItem); if (auto evaluated = evaluateDependsItem(dependsItem)) { evaluated->requiredGlobally = evaluated->requiredLocally && state.loadingItemOrigin.requiredGlobally; state.currentDependsItem = evaluated; return; } } } HandleDependency DependenciesResolver::handleResolvedDependencies() { DependenciesResolvingState &state = stateStack().front(); while (!state.pendingResolvedDependencies.empty()) { QBS_CHECK(!state.currentDependsItem); const FullyResolvedDependsItem dependency = state.pendingResolvedDependencies.front(); try { const LoadModuleResult res = loadModule(state.loadingItem, dependency); switch (res.handleDependency) { case HandleDependency::Defer: QBS_CHECK(m_deferral == Deferral::Allowed); // Optimization: We already looked up the product, so let's not do that again // next time. if (res.product) state.pendingResolvedDependencies.front().product = res.product; return HandleDependency::Defer; case HandleDependency::Ignore: // This happens if the dependency was not required or the module was already // loaded via another path. state.pendingResolvedDependencies.pop(); continue; case HandleDependency::Use: if (dependency.name.toString() == StringConstants::qbsModule()) { // Shortcut: No need to look for recursive dependencies in the base module. state.pendingResolvedDependencies.pop(); continue; } m_deferral = Deferral::Allowed; // We made progress. break; } QBS_CHECK(res.moduleItem); // Now continue with the dependencies of the just-loaded module. std::queue moduleDependsItems; collectDependsItems(res.moduleItem, moduleDependsItems); state.pendingResolvedDependencies.pop(); stateStack().push_front( {res.moduleItem, dependency, moduleDependsItems, {}, {}, dependency.requiredGlobally || state.requiredByLoadingItem}); stateStack().front().pendingResolvedDependencies.push( FullyResolvedDependsItem::makeBaseDependency()); break; } catch (const ErrorInfo &e) { if (dependency.name.toString() == StringConstants::qbsModule()) throw e; // See QBS-1338 for why we do not abort handling the product. state.pendingResolvedDependencies.pop(); Item::Modules &modules = m_product.item->modules(); // Unwind. bool unwound = false; while (stateStack().size() > 1) { const auto loadingItemModule = std::find_if( modules.begin(), modules.end(), [&](const Item::Module &m) { return m.item == stateStack().front().loadingItem; }); for (auto it = loadingItemModule; it != modules.end(); ++it) { createNonPresentModule(m_loaderState.itemPool(), it->name.toString(), QLatin1String("error in Depends chain"), it->item); } modules.erase(loadingItemModule, modules.end()); stateStack().pop_front(); unwound = true; } m_product.handleError(e); if (unwound) return HandleDependency::Ignore; continue; } } return HandleDependency::Ignore; } // Produces an item of type ModuleInstance corresponding to the specified dependency. // The instance's prototype item is either of type Export (if the dependency is a product) // or of type Module (for an actual module). // The loadingItem parameter is either the depending product or another module. The newly // created module is added to the module list of the product item and additionally to the // loading item's one, if it is not the product. Its name is also injected into the respective // scopes. LoadModuleResult DependenciesResolver::loadModule( Item *loadingItem, const FullyResolvedDependsItem &dependency) { qCDebug(lcModuleLoader) << "loadModule name:" << dependency.name.toString() << "id:" << dependency.id(); QBS_CHECK(loadingItem); ProductContext *productDep = nullptr; Item *moduleItem = nullptr; const auto addLoadContext = [&](Item::Module &module) { module.loadContexts.emplace_back(dependency.item, std::make_pair(dependency.parameters, INT_MAX - dependsChainLength())); }; // The module might already have been loaded for this product (directly or indirectly). const auto &[existingModule, moduleWithSameName] = findExistingModule(dependency, m_product.item); if (existingModule) { // Merge version range and required property. These will be checked again // after probes resolving. if (existingModule->name.toString() != StringConstants::qbsModule()) updateModule(*existingModule, dependency); QBS_CHECK(existingModule->item); moduleItem = existingModule->item; const auto matcher = [loadingItem](const Item::Module::LoadContext &context) { return context.loadingItem() == loadingItem; }; const auto it = std::find_if(existingModule->loadContexts.begin(), existingModule->loadContexts.end(), matcher); if (it == existingModule->loadContexts.end()) addLoadContext(*existingModule); else it->parameters.first = mergeDependencyParameters(it->parameters.first, dependency.parameters); } else if (dependency.product) { productDep = dependency.product; // We have already done the look-up. } else if (productDep = findMatchingProduct(dependency); !productDep) { moduleItem = findMatchingModule(dependency); } if (productDep) { const auto checkResult = checkProductDependency(dependency, *productDep); // We found a product dependency, but that product has not been handled yet, // so stop dependency resolving for the current product and resume it later, when the // dependency is ready. if (checkResult.second == HandleDependency::Defer) return {nullptr, productDep, HandleDependency::Defer}; if (checkResult.first) { QBS_CHECK(productDep->mergedExportItem); moduleItem = productDep->mergedExportItem->clone(m_loaderState.itemPool()); moduleItem->setParent(nullptr); // Needed for isolated Export item evaluation. moduleItem->setPrototype(productDep->mergedExportItem); } else { // The product dependency is faulty, but Depends.reqired was false. productDep = nullptr; } } if (moduleItem) checkModule(dependency, moduleItem, productDep); // Can only happen with multiplexing. if (moduleWithSameName && moduleWithSameName != moduleItem) QBS_CHECK(productDep); // The loading name is only used to ensure consistent sorting in case of equal // value priorities; see ModulePropertyMerger. QString loadingName; if (loadingItem == m_product.item) { loadingName = m_product.name; } else if (m_product.dependenciesContext && !stateStack().empty()) { const auto &loadingItemOrigin = stateStack().front().loadingItemOrigin; loadingName = loadingItemOrigin.name.toString() + loadingItemOrigin.multiplexId + loadingItemOrigin.profile; } instantiateModule({m_product, loadingItem, loadingName, moduleItem, moduleWithSameName, productDep ? productDep->item : nullptr, dependency.name, dependency.id(), bool(existingModule)}, m_loaderState); // At this point, a null module item is only possible for a non-required dependency. // Note that we still needed to to the instantiation above, as that injects the module // name into the surrounding item for the ".present" check. if (!moduleItem) { QBS_CHECK(!dependency.requiredGlobally); return {nullptr, nullptr, HandleDependency::Ignore}; } const auto addLocalModule = [&] { if (loadingItem->type() == ItemType::ModuleInstance && !findExistingModule(dependency, loadingItem).first) { loadingItem->addModule(createModule(dependency, moduleItem, productDep)); } }; // The module has already been loaded, so we don't need to add it to the product's list of // modules, nor do we need to handle its dependencies. The only thing we might need to // do is to add it to the "local" list of modules of the loading item, if it isn't in there yet. if (existingModule) { addLocalModule(); return {nullptr, nullptr, HandleDependency::Ignore}; } qCDebug(lcModuleLoader) << "module loaded:" << dependency.name.toString(); if (m_product.item) { Item::Module module = createModule(dependency, moduleItem, productDep); module.required = dependency.requiredGlobally; addLoadContext(module); module.maxDependsChainLength = dependsChainLength(); m_product.item->addModule(module); addLocalModule(); } return {moduleItem, nullptr, HandleDependency::Use}; } std::pair DependenciesResolver::findExistingModule( const FullyResolvedDependsItem &dependency, Item *item) { if (!item) // Happens if and only if called via loadBaseModule(). return {}; Item *moduleWithSameName = nullptr; for (Item::Module &m : item->modules()) { if (m.name != dependency.name) continue; if (!m.product) { QBS_CHECK(!dependency.product); return {&m, m.item}; } if ((dependency.profile.isEmpty() || (m.product->profileName == dependency.profile)) && m.product->multiplexConfigurationId == dependency.multiplexId) { return {&m, m.item}; } // This can happen if there are dependencies to several variants of a multiplexed // product. moduleWithSameName = m.item; } return {nullptr, moduleWithSameName}; } void DependenciesResolver::updateModule( Item::Module &module, const FullyResolvedDependsItem &dependency) { forwardParameterDeclarations(dependency.item, m_product.item->modules()); module.versionRange.narrowDown(dependency.versionRange); module.required |= dependency.requiredGlobally; if (dependsChainLength() > module.maxDependsChainLength) module.maxDependsChainLength = dependsChainLength(); } int DependenciesResolver::dependsChainLength() { return m_product.dependenciesContext ? stateStack().size() : 1; } ProductContext *DependenciesResolver::findMatchingProduct( const FullyResolvedDependsItem &dependency) { const auto constraint = [this, &dependency](ProductContext &product) { if (product.multiplexConfigurationId != dependency.multiplexId) return false; if (!dependency.profile.isEmpty() && dependency.profile != product.profileName) return false; if (dependency.limitToSubProject && !haveSameSubProject(m_product, product)) return false; return true; }; return m_product.project->topLevelProject->productWithNameAndConstraint( dependency.name.toString(), constraint); } Item *DependenciesResolver::findMatchingModule( const FullyResolvedDependsItem &dependency) { // If we can tell that this is supposed to be a product dependency, we can skip // the module look-up. if (!dependency.profile.isEmpty() || !dependency.multiplexId.isEmpty()) { if (dependency.requiredGlobally) { if (!dependency.profile.isEmpty()) { throw ErrorInfo(Tr::tr("Product '%1' depends on '%2', which does not exist " "for the requested profile '%3'.") .arg(m_product.displayName(), dependency.displayName(), dependency.profile), m_product.item->location()); } throw ErrorInfo(Tr::tr("Product '%1' depends on '%2', which does not exist.") .arg(m_product.displayName(), dependency.displayName()), m_product.item->location()); } return nullptr; } if (Item *moduleItem = searchAndLoadModuleFile( m_loaderState, m_product, dependency.location(), dependency.name, dependency.versionRange)) { QBS_CHECK(moduleItem->type() == ItemType::Module); Item * const proto = moduleItem; ModuleItemLocker locker(*moduleItem); moduleItem = moduleItem->clone(m_loaderState.itemPool()); moduleItem->setPrototype(proto); // For parameter declarations. return moduleItem; } if (!dependency.requiredGlobally) { return createNonPresentModule(m_loaderState.itemPool(), dependency.name.toString(), QStringLiteral("not found"), nullptr); } throw ErrorInfo(Tr::tr("Dependency '%1' not found for product '%2'.") .arg(dependency.name.toString(), m_product.displayName()), dependency.location()); } std::pair DependenciesResolver::checkProductDependency( const FullyResolvedDependsItem &depSpec, const ProductContext &dep) { // Optimization: If we already checked the product earlier and then deferred, we don't // need to check it again. if (!depSpec.checkProduct) return {true, HandleDependency::Use}; if (&dep == &m_product) { throw ErrorInfo(Tr::tr("Dependency '%1' refers to itself.").arg(depSpec.name.toString()), depSpec.location()); } if (m_product.project->topLevelProject->isProductQueuedForHandling(dep)) { if (m_deferral == Deferral::Allowed) return {false, HandleDependency::Defer}; ErrorInfo e; e.append(Tr::tr("Cyclic dependencies detected:")); e.append(Tr::tr("First product is '%1'.") .arg(m_product.displayName()), m_product.item->location()); e.append(Tr::tr("Second product is '%1'.") .arg(dep.displayName()), dep.item->location()); e.append(Tr::tr("Requested here."), depSpec.location()); throw e; } // This covers both the case of user-disabled products and products with errors. // The latter are force-disabled in ProductContext::handleError(). if (m_product.project->topLevelProject->isDisabledItem(dep.item)) { if (depSpec.requiredGlobally) { ErrorInfo e; e.append(Tr::tr("Product '%1' depends on '%2',") .arg(m_product.displayName(), dep.displayName()), m_product.item->location()); e.append(Tr::tr("but product '%1' is disabled.").arg(dep.displayName()), dep.item->location()); throw e; } return {false, HandleDependency::Ignore}; } return {true, HandleDependency::Use}; } void DependenciesResolver::checkModule( const FullyResolvedDependsItem &dependency, Item *moduleItem, ProductContext *productDep) { // When loading a pseudo or temporary qbs module in early setup via loadBaseModule(), // there is no proper state yet. if (!m_product.dependenciesContext) return; for (auto it = stateStack().begin(); it != stateStack().end(); ++it) { Item *itemToCheck = moduleItem; if (it->loadingItem != itemToCheck) { if (!productDep) continue; itemToCheck = productDep->item; } if (it->loadingItem != itemToCheck) continue; ErrorInfo e; e.append(Tr::tr("Cyclic dependencies detected:")); while (true) { e.append(it->loadingItemOrigin.name.toString(), it->loadingItemOrigin.location()); if (it->loadingItem->type() == ItemType::ModuleInstance) { createNonPresentModule(m_loaderState.itemPool(), it->loadingItemOrigin.name.toString(), QLatin1String("cyclic dependency"), it->loadingItem); } if (it == stateStack().begin()) break; --it; } e.append(dependency.name.toString(), dependency.location()); throw e; } checkForModuleNamePrefixCollision(dependency); } void DependenciesResolver::adjustDependsItemForMultiplexing(Item *dependsItem) { if (m_product.name.startsWith(StringConstants::shadowProductPrefix())) return; Evaluator &evaluator = m_loaderState.evaluator(); const QString name = evaluator.stringValue(dependsItem, StringConstants::nameProperty()); const bool productIsMultiplexed = !m_product.multiplexConfigurationId.isEmpty(); if (name == m_product.name) { QBS_CHECK(!productIsMultiplexed); // This product must be an aggregator. return; } bool hasNonMultiplexedDependency = false; const std::vector multiplexedDependencies = m_product.project ->topLevelProject->productsWithNameAndConstraint(name, [&hasNonMultiplexedDependency] (const ProductContext &product) { if (product.multiplexConfigurationId.isEmpty()) { hasNonMultiplexedDependency = true; return false; } return true; }); const bool hasMultiplexedDependencies = !multiplexedDependencies.empty(); // These are the allowed cases: // (1) Normal dependency with no multiplexing whatsoever. // (2) Both product and dependency are multiplexed. // (2a) The profiles property is not set, we want to depend on the best // matching variant. // (2b) The profiles property is set, we want to depend on all variants // with a matching profile. // (3) The product is not multiplexed, but the dependency is. // (3a) The profiles property is not set, the dependency has an aggregator. // We want to depend on the aggregator. // (3b) The profiles property is not set, the dependency does not have an // aggregator. We want to depend on all the multiplexed variants. // (3c) The profiles property is set, we want to depend on all variants // with a matching profile regardless of whether an aggregator exists or not. // (4) The product is multiplexed, but the dependency is not. We don't have to adapt // any Depends items. // (1) and (4) if (!hasMultiplexedDependencies) return; bool profilesPropertyIsSet; const QStringList profiles = evaluator.stringListValue( dependsItem, StringConstants::profilesProperty(), &profilesPropertyIsSet); // (3a) if (!productIsMultiplexed && hasNonMultiplexedDependency && !profilesPropertyIsSet) return; static const auto multiplexConfigurationIntersects = [](const QVariantMap &lhs, const QVariantMap &rhs) { QBS_CHECK(!lhs.isEmpty() && !rhs.isEmpty()); for (auto lhsProperty = lhs.constBegin(); lhsProperty != lhs.constEnd(); lhsProperty++) { const auto rhsProperty = rhs.find(lhsProperty.key()); const bool isCommonProperty = rhsProperty != rhs.constEnd(); if (isCommonProperty && !qVariantsEqual(lhsProperty.value(), rhsProperty.value())) return false; } return true; }; QStringList multiplexIds; const auto productMultiplexConfig = m_loaderState.topLevelProject().multiplexConfiguration( m_product.multiplexConfigurationId); for (const ProductContext *dependency : multiplexedDependencies) { if (productIsMultiplexed && !profilesPropertyIsSet) { // 2a if (dependency->multiplexConfigurationId == m_product.multiplexConfigurationId) { const ValuePtr &multiplexId = m_product.item->property( StringConstants::multiplexConfigurationIdProperty()); dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), multiplexId); return; } // Otherwise collect partial matches and decide later const auto dependencyMultiplexConfig = m_loaderState.topLevelProject() .multiplexConfiguration(dependency->multiplexConfigurationId); if (multiplexConfigurationIntersects(dependencyMultiplexConfig, productMultiplexConfig)) multiplexIds << dependency->multiplexConfigurationId; } else { // (2b), (3b) or (3c) const bool profileMatch = !profilesPropertyIsSet || profiles.empty() || profiles.contains(dependency->profileName); if (profileMatch) multiplexIds << dependency->multiplexConfigurationId; } } if (multiplexIds.empty()) { const QString productName = m_product.displayName(); throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' not fulfilled. " "There are no eligible multiplex candidates.").arg(productName, name), dependsItem->location()); } // In case of (2a), at most 1 match is allowed if (productIsMultiplexed && !profilesPropertyIsSet && multiplexIds.size() > 1) { QStringList candidateNames; for (const auto &id : std::as_const(multiplexIds)) candidateNames << fullProductDisplayName(name, id); throw ErrorInfo( Tr::tr("Dependency from product '%1' to product '%2' is ambiguous. " "Eligible multiplex candidates: %3.").arg( m_product.displayName(), name, candidateNames.join(QLatin1String(", "))), dependsItem->location()); } dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), VariantValue::create(multiplexIds)); } std::optional DependenciesResolver::evaluateDependsItem(Item *item) { Evaluator &evaluator = m_loaderState.evaluator(); for (Item *current = item; current->type() == ItemType::Depends || current->type() == ItemType::Group; current = current->parent()) { if (!m_loaderState.topLevelProject().checkItemCondition( current, m_loaderState.evaluator())) { qCDebug(lcModuleLoader) << "Depends item disabled, ignoring."; return {}; } } const QString name = evaluator.stringValue(item, StringConstants::nameProperty()); if (name == StringConstants::qbsModule()) // Redundant return {}; bool submodulesPropertySet; const QStringList submodules = evaluator.stringListValue( item, StringConstants::submodulesProperty(), &submodulesPropertySet); if (submodules.empty() && submodulesPropertySet) { qCDebug(lcModuleLoader) << "Ignoring Depends item with empty submodules list."; return {}; } if (Q_UNLIKELY(submodules.size() > 1 && !item->id().isEmpty())) { QString msg = Tr::tr("A Depends item with more than one module cannot have an id."); throw ErrorInfo(msg, item->location()); } bool productTypesWasSet; const QStringList productTypes = evaluator.stringListValue( item, StringConstants::productTypesProperty(), &productTypesWasSet); if (!name.isEmpty() && !productTypes.isEmpty()) { throw ErrorInfo(Tr::tr("The name and productTypes are mutually exclusive " "in a Depends item."), item->location()); } if (productTypes.isEmpty() && productTypesWasSet) { qCDebug(lcModuleLoader) << "Ignoring Depends item with empty productTypes list."; return {}; } if (name.isEmpty() && !productTypesWasSet) { throw ErrorInfo(Tr::tr("Either name or productTypes must be set in a Depends item"), item->location()); } bool profilesPropertyWasSet = false; std::optional profiles; bool required = true; if (productTypes.isEmpty()) { const QStringList profileList = evaluator.stringListValue( item, StringConstants::profilesProperty(), &profilesPropertyWasSet); if (profilesPropertyWasSet) profiles.emplace(profileList); required = evaluator.boolValue(item, StringConstants::requiredProperty()); } const Version minVersion = Version::fromString( evaluator.stringValue(item, StringConstants::versionAtLeastProperty())); const Version maxVersion = Version::fromString( evaluator.stringValue(item, StringConstants::versionBelowProperty())); const bool limitToSubProject = evaluator.boolValue( item, StringConstants::limitToSubProjectProperty()); const QStringList multiplexIds = evaluator.stringListValue( item, StringConstants::multiplexConfigurationIdsProperty()); adjustParametersScopes(item, item); forwardParameterDeclarations(item, m_product.item->modules()); const QVariantMap parameters = extractParameters(item); const FileTags productTypeTags = FileTags::fromStringList(productTypes); if (!productTypeTags.empty()) m_product.bulkDependencies.emplace_back(productTypeTags, item->location()); return EvaluatedDependsItem{ item, QualifiedId::fromString(name), submodules, productTypeTags, multiplexIds, profiles, {minVersion, maxVersion}, parameters, limitToSubProject, required}; } // Potentially multiplexes a dependency along Depends.productTypes, Depends.subModules and // Depends.profiles, as well as internally set up multiplexing axes. // Each entry in the resulting queue corresponds to exactly one product or module to pull in. std::queue DependenciesResolver::multiplexDependency(const EvaluatedDependsItem &dependency) { std::queue dependencies; if (!dependency.productTypes.empty()) { const auto constraint = [&](const ProductContext &product) { return &product != &m_product && product.name != m_product.name && (!dependency.limitToSubProject || haveSameSubProject(m_product, product)); }; const std::vector matchingProducts = m_product.project->topLevelProject ->productsWithTypeAndConstraint(dependency.productTypes, constraint); if (matchingProducts.empty()) { qCDebug(lcModuleLoader) << "Depends.productTypes does not match anything." << dependency.item->location(); return {}; } for (ProductContext * const match : matchingProducts) dependencies.emplace(match, dependency); return dependencies; } const QStringList profiles = dependency.profiles && !dependency.profiles->isEmpty() ? *dependency.profiles : QStringList(QString()); const QStringList multiplexIds = !dependency.multiplexIds.isEmpty() ? dependency.multiplexIds : QStringList(QString()); const QStringList subModules = !dependency.subModules.isEmpty() ? dependency.subModules : QStringList(QString()); for (const QString &profile : profiles) { for (const QString &multiplexId : multiplexIds) { for (const QString &subModule : subModules) { QualifiedId name = dependency.name; if (!subModule.isEmpty()) name << subModule.split(QLatin1Char('.')); dependencies.emplace(dependency, name, profile, multiplexId); } } } return dependencies; } QVariantMap DependenciesResolver::extractParameters(Item *dependsItem) const { try { QVariantMap result; const auto &properties = dependsItem->properties(); Evaluator &evaluator = m_loaderState.evaluator(); for (auto it = properties.begin(); it != properties.end(); ++it) { if (it.value()->type() != Value::ItemValueType) continue; const JSValue sv = evaluator.scriptValue( std::static_pointer_cast(it.value())->item()); result.insert(it.key(), safeToVariant(evaluator.engine()->context(), sv)); } return result; } catch (const ErrorInfo &exception) { auto ei = exception; ei.prepend(Tr::tr("Error in dependency parameter."), dependsItem->location()); throw ei; } } void DependenciesResolver::forwardParameterDeclarations(const Item *dependsItem, const Item::Modules &modules) { for (auto it = dependsItem->properties().begin(); it != dependsItem->properties().end(); ++it) { if (it.value()->type() != Value::ItemValueType) continue; forwardParameterDeclarations(it.key(), std::static_pointer_cast(it.value())->item(), modules); } } void DependenciesResolver::forwardParameterDeclarations( const QualifiedId &moduleName, Item *item, const Item::Modules &modules) { auto it = std::find_if(modules.begin(), modules.end(), [&moduleName] (const Item::Module &m) { return m.name == moduleName; }); if (it != modules.end()) { item->setPropertyDeclarations(m_loaderState.topLevelProject().parameterDeclarations( it->item->rootPrototype())); } else { for (auto it = item->properties().begin(); it != item->properties().end(); ++it) { if (it.value()->type() != Value::ItemValueType) continue; forwardParameterDeclarations(QualifiedId(moduleName) << it.key(), std::static_pointer_cast(it.value())->item(), modules); } } } std::list &DependenciesResolver::stateStack() { QBS_CHECK(m_product.dependenciesContext); return static_cast(m_product.dependenciesContext.get())->stateStack; } void DependenciesResolver::checkForModuleNamePrefixCollision( const FullyResolvedDependsItem &dependency) { if (!m_product.item) return; for (const Item::Module &m : m_product.item->modules()) { if (m.name.length() == dependency.name.length()) continue; QualifiedId shortName; QualifiedId longName; if (m.name.length() < dependency.name.length()) { shortName = m.name; longName = dependency.name; } else { shortName = dependency.name; longName = m.name; } const auto isPrefix = [&] { for (int i = 0; i < shortName.length(); ++i) { if (shortName.at(i) != longName.at(i)) return false; } return true; }; if (!isPrefix()) continue; throw ErrorInfo(Tr::tr("The name of module '%1' is a prefix of the name of module '%2', " "which is not allowed") .arg(shortName.toString(), longName.toString()), dependency.location()); } } Item::Module DependenciesResolver::createModule( const FullyResolvedDependsItem &dependency, Item *item, ProductContext *productDep) { Item::Module m; m.item = item; m.product = productDep; m.name = dependency.name; m.required = dependency.requiredLocally; m.versionRange = dependency.versionRange; return m; } FullyResolvedDependsItem::FullyResolvedDependsItem( ProductContext *product, const EvaluatedDependsItem &dependency) : product(product) , item(dependency.item) , name(product->name) , versionRange(dependency.versionRange) , parameters(dependency.parameters) , checkProduct(false) {} FullyResolvedDependsItem FullyResolvedDependsItem::makeBaseDependency() { FullyResolvedDependsItem item; item.name = StringConstants::qbsModule(); return item; } FullyResolvedDependsItem::FullyResolvedDependsItem( const EvaluatedDependsItem &dependency, QualifiedId name, QString profile, QString multiplexId) : item(dependency.item) , name(std::move(name)) , profile(std::move(profile)) , multiplexId(std::move(multiplexId)) , versionRange(dependency.versionRange) , parameters(dependency.parameters) , limitToSubProject(dependency.limitToSubProject) , requiredLocally(dependency.requiredLocally) , requiredGlobally(dependency.requiredGlobally) {} QString FullyResolvedDependsItem::id() const { if (!item) { QBS_CHECK(name.toString() == StringConstants::qbsModule()); return {}; } return item->id(); } CodeLocation FullyResolvedDependsItem::location() const { if (!item) { QBS_CHECK(name.toString() == StringConstants::qbsModule()); return {}; } return item->location(); } QString FullyResolvedDependsItem::displayName() const { return fullProductDisplayName(name.toString(), multiplexId); } bool haveSameSubProject(const ProductContext &p1, const ProductContext &p2) { for (const Item *otherParent = p2.item->parent(); otherParent; otherParent = otherParent->parent()) { if (otherParent == p1.item->parent()) return true; } return false; } QVariantMap safeToVariant(JSContext *ctx, const JSValue &v) { QVariantMap result; handleJsProperties(ctx, v, [&](const JSAtom &prop, const JSPropertyDescriptor &desc) { const JSValue u = desc.value; if (JS_IsError(ctx, u)) throw ErrorInfo(getJsString(ctx, u)); const QString name = getJsString(ctx, prop); result[name] = (JS_IsObject(u) && !JS_IsArray(ctx, u) && !JS_IsRegExp(ctx, u)) ? safeToVariant(ctx, u) : getJsVariant(ctx, u); }); return result; } void collectDependsItems(Item *parent, std::queue &dependsItems) { for (Item * const child : parent->children()) { if (child->type() == ItemType::Depends) dependsItems.push(child); else if (child->type() == ItemType::Group) collectDependsItems(child, dependsItems); } } DependenciesContextImpl::DependenciesContextImpl(ProductContext &product, LoaderState &loaderState) : m_product(product) { setSearchPathsForProduct(loaderState); // Initialize the state with the direct Depends items of the product item. DependenciesResolvingState newState{product.item,}; collectDependsItems(product.item, newState.pendingDependsItems); stateStack.push_front(std::move(newState)); stateStack.front().pendingResolvedDependencies.push( FullyResolvedDependsItem::makeBaseDependency()); } std::pair DependenciesContextImpl::pendingDependency() const { QBS_CHECK(!stateStack.empty()); if (const auto ¤tDependsItem = stateStack.front().currentDependsItem; currentDependsItem && !currentDependsItem->productTypes.empty()) { qCDebug(lcLoaderScheduling) << "product" << m_product.displayName() << "to be delayed because of bulk dependency"; return {ProductDependency::Bulk, nullptr}; } if (!stateStack.front().pendingResolvedDependencies.empty()) { if (ProductContext * const dep = stateStack.front().pendingResolvedDependencies .front().product) { if (m_product.project->topLevelProject->isProductQueuedForHandling(*dep)) { qCDebug(lcLoaderScheduling) << "product" << m_product.displayName() << "to be delayed because of dependency " "to unfinished product" << dep->displayName(); return {ProductDependency::Single, dep}; } else { qCDebug(lcLoaderScheduling) << "product" << m_product.displayName() << "to be re-scheduled, as dependency " << dep->displayName() << "appears to have finished in the meantime"; return {ProductDependency::None, dep}; } } } return {ProductDependency::None, nullptr}; } void DependenciesContextImpl::setSearchPathsForProduct(LoaderState &loaderState) { QBS_CHECK(m_product.searchPaths.isEmpty()); m_product.searchPaths = loaderState.itemReader().readExtraSearchPaths(m_product.item); Settings settings(loaderState.parameters().settingsDirectory()); const QStringList prefsSearchPaths = Preferences(&settings, m_product.profileModuleProperties) .searchPaths(); const QStringList ¤tSearchPaths = loaderState.itemReader().allSearchPaths(); for (const QString &p : prefsSearchPaths) { if (!currentSearchPaths.contains(p) && FileInfo(p).exists()) m_product.searchPaths << p; } } } // namespace } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/astpropertiesitemhandler.h0000644000175100001660000000466514776170045024177 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ASTPROPERTIESITEMHANDLER_H #define QBS_ASTPROPERTIESITEMHANDLER_H namespace qbs { namespace Internal { class Item; class ItemPool; class Logger; class ASTPropertiesItemHandler { public: ASTPropertiesItemHandler(Item *parentItem, ItemPool &itemPool, Logger &logger); void handlePropertiesItems(); private: void prepareGroup(); void setupAlternatives(); void handlePropertiesBlock(const Item *propertiesItem); Item * const m_parentItem; ItemPool &m_itemPool; Logger &m_logger; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/loader/dependenciesresolver.h0000644000175100001660000000507214776170045023257 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once namespace qbs::Internal { class Item; class LoaderState; class ProductContext; enum class Deferral; // Collects the products' dependencies and builds the list of modules from them. // Actual loading of module files is offloaded to ModuleLoader. void resolveDependencies(ProductContext &product, Deferral deferral, LoaderState &loaderState); // Note: This function is never called for regular loading of the base module into a product, // but only for the special cases of loading the dummy base module into a project // and temporarily providing a base module for product multiplexing. Item *loadBaseModule(ProductContext &product, Item *item, LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/astimportshandler.cpp0000644000175100001660000003072414776170045023147 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "astimportshandler.h" #include "itemreadervisitorstate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { ASTImportsHandler::ASTImportsHandler(ItemReaderVisitorState &visitorState, Logger &logger, const FileContextPtr &file) : m_visitorState(visitorState) , m_logger(logger) , m_file(file) , m_directory(FileInfo::path(m_file->filePath())) { } void ASTImportsHandler::handleImports(const QbsQmlJS::AST::UiImportList *uiImportList) { const auto searchPaths = m_file->searchPaths(); for (const QString &searchPath : searchPaths) collectPrototypes(searchPath + QStringLiteral("/imports"), QString()); // files in the same directory are available as prototypes collectPrototypes(m_directory, QString()); bool baseImported = false; for (const auto *it = uiImportList; it; it = it->next) handleImport(it->import, &baseImported); if (!baseImported) { QStringRef qbsref(&StringConstants::qbsModule()); QbsQmlJS::AST::UiQualifiedId qbsURI(qbsref); qbsURI.finish(); QbsQmlJS::AST::UiImport imp(&qbsURI); handleImport(&imp, &baseImported); } for (auto it = m_jsImports.constBegin(); it != m_jsImports.constEnd(); ++it) m_file->addJsImport(it.value()); } void ASTImportsHandler::handleImport(const QbsQmlJS::AST::UiImport *import, bool *baseImported) { QStringList importUri; bool isBase = false; if (import->importUri) { importUri = toStringList(import->importUri); isBase = (importUri.size() == 1 && importUri.front() == StringConstants::qbsModule()) || (importUri.size() == 2 && importUri.front() == StringConstants::qbsModule() && importUri.last() == StringConstants::baseVar()); if (isBase) { *baseImported = true; checkImportVersion(import->versionToken); } else if (import->versionToken.length) { m_logger.printWarning(ErrorInfo(Tr::tr("Superfluous version specification."), toCodeLocation(m_file->filePath(), import->versionToken))); } } QString as; if (isBase) { if (Q_UNLIKELY(!import->importId.isNull())) { throw ErrorInfo(Tr::tr("Import of qbs.base must have no 'as '"), toCodeLocation(m_file->filePath(), import->importIdToken)); } } else { if (importUri.size() == 2 && importUri.front() == StringConstants::qbsModule()) { const QString extensionName = importUri.last(); if (JsExtensions::hasExtension(extensionName)) { if (Q_UNLIKELY(!import->importId.isNull())) { throw ErrorInfo(Tr::tr("Import of built-in extension '%1' " "must not have 'as' specifier.").arg(extensionName), toCodeLocation(m_file->filePath(), import->asToken)); } if (Q_UNLIKELY(m_file->jsExtensions().contains(extensionName))) { m_logger.printWarning(ErrorInfo(Tr::tr("Built-in extension '%1' already " "imported.").arg(extensionName), toCodeLocation(m_file->filePath(), import->importToken))); } else { m_file->addJsExtension(extensionName); } return; } } if (import->importId.isNull()) { if (!import->fileName.isNull()) { throw ErrorInfo(Tr::tr("File imports require 'as '"), toCodeLocation(m_file->filePath(), import->importToken)); } if (importUri.empty()) { throw ErrorInfo(Tr::tr("Invalid import URI."), toCodeLocation(m_file->filePath(), import->importToken)); } as = importUri.last(); } else { as = import->importId.toString(); } if (Q_UNLIKELY(JsExtensions::hasExtension(as))) throw ErrorInfo(Tr::tr("Cannot reuse the name of built-in extension '%1'.").arg(as), toCodeLocation(m_file->filePath(), import->importIdToken)); if (Q_UNLIKELY(!m_importAsNames.insert(as).second)) { throw ErrorInfo(Tr::tr("Cannot import into the same name more than once."), toCodeLocation(m_file->filePath(), import->importIdToken)); } } if (!import->fileName.isNull()) { QString filePath = FileInfo::resolvePath(m_directory, import->fileName.toString()); QFileInfo fi(filePath); if (Q_UNLIKELY(!fi.exists())) throw ErrorInfo(Tr::tr("Cannot find imported file %0.") .arg(QDir::toNativeSeparators(filePath)), CodeLocation(m_file->filePath(), import->fileNameToken.startLine, import->fileNameToken.startColumn)); filePath = fi.canonicalFilePath(); if (fi.isDir()) { collectPrototypesAndJsCollections(filePath, as, toCodeLocation(m_file->filePath(), import->fileNameToken)); } else { if (filePath.endsWith(QStringLiteral(".js"), Qt::CaseInsensitive)) { JsImport &jsImport = m_jsImports[as]; jsImport.scopeName = as; jsImport.filePaths.push_back(filePath); jsImport.location = toCodeLocation(m_file->filePath(), import->firstSourceLocation()); } else if (filePath.endsWith(QStringLiteral(".qbs"), Qt::CaseInsensitive)) { m_typeNameToFile.insert(QStringList(as), filePath); } else { throw ErrorInfo(Tr::tr("Can only import .qbs and .js files"), CodeLocation(m_file->filePath(), import->fileNameToken.startLine, import->fileNameToken.startColumn)); } } } else if (!importUri.empty()) { const QString importPath = isBase ? QStringLiteral("qbs/base") : importUri.join(QDir::separator()); bool found = m_typeNameToFile.contains(importUri); if (!found) { const auto searchPaths = m_file->searchPaths(); for (const QString &searchPath : searchPaths) { const QFileInfo fi(FileInfo::resolvePath( FileInfo::resolvePath(searchPath, StringConstants::importsDir()), importPath)); if (fi.isDir()) { // ### versioning, qbsdir file, etc. const QString &resultPath = fi.absoluteFilePath(); collectPrototypesAndJsCollections(resultPath, as, toCodeLocation(m_file->filePath(), import->fileNameToken)); found = true; break; } } } if (Q_UNLIKELY(!found)) { throw ErrorInfo(Tr::tr("import %1 not found") .arg(importUri.join(QLatin1Char('.'))), toCodeLocation(m_file->filePath(), import->fileNameToken)); } } } Version ASTImportsHandler::readImportVersion(const QString &str, const CodeLocation &location) { const Version v = Version::fromString(str); if (Q_UNLIKELY(!v.isValid())) throw ErrorInfo(Tr::tr("Cannot parse version number in import statement."), location); if (Q_UNLIKELY(v.patchLevel() != 0)) { throw ErrorInfo(Tr::tr("Version number in import statement cannot have more than " "two components."), location); } return v; } bool ASTImportsHandler::addPrototype(const QString &fileName, const QString &filePath, const QString &as, bool needsCheck) { if (needsCheck && fileName.size() <= 4) return false; const QString componentName = fileName.left(fileName.size() - 4); // ### validate componentName if (needsCheck && !componentName.at(0).isUpper()) return false; QStringList prototypeName; if (!as.isEmpty()) prototypeName.push_back(as); prototypeName.push_back(componentName); if (!m_typeNameToFile.contains(prototypeName)) m_typeNameToFile.insert(prototypeName, filePath); return true; } void ASTImportsHandler::checkImportVersion(const QbsQmlJS::AST::SourceLocation &versionToken) const { if (!versionToken.length) return; const QString importVersionString = m_file->content().mid(versionToken.offset, versionToken.length); const Version importVersion = readImportVersion(importVersionString, toCodeLocation(m_file->filePath(), versionToken)); if (Q_UNLIKELY(importVersion != BuiltinDeclarations::instance().languageVersion())) throw ErrorInfo(Tr::tr("Incompatible qbs language version %1. This is version %2.").arg( importVersionString, BuiltinDeclarations::instance().languageVersion().toString()), toCodeLocation(m_file->filePath(), versionToken)); } void ASTImportsHandler::collectPrototypes(const QString &path, const QString &as) { QStringList fileNames; // Yes, file *names*. m_visitorState.findDirectoryEntries(path, &fileNames); for (const QString &fileName : std::as_const(fileNames)) addPrototype(fileName, path + QLatin1Char('/') + fileName, as, false); } void ASTImportsHandler::collectPrototypesAndJsCollections(const QString &path, const QString &as, const CodeLocation &location) { collectPrototypes(path, as); QDirIterator dirIter(path, StringConstants::jsFileWildcards()); while (dirIter.hasNext()) { dirIter.next(); JsImport &jsImport = m_jsImports[as]; if (jsImport.scopeName.isNull()) { jsImport.scopeName = as; jsImport.location = location; } jsImport.filePaths.push_back(dirIter.filePath()); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/moduleproviderloader.h0000644000175100001660000001040614776170045023273 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MODULEPROVIDERLOADER_H #define MODULEPROVIDERLOADER_H #include "loaderutils.h" #include #include #include #include #include #include namespace qbs::Internal { class Item; class LoaderState; class ProductContext; class ModuleProviderLoader { public: explicit ModuleProviderLoader(LoaderState &loaderState); struct ModuleProviderResult { bool providerFound = false; std::optional searchPaths; }; ModuleProviderResult executeModuleProviders( ProductContext &productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName); private: enum class ModuleProviderLookup { Scoped, Named }; struct Provider { QualifiedId name; ModuleProviderLookup lookup; }; ModuleProviderResult executeModuleProvidersHelper( ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const std::vector &providers); std::pair findOrCreateProviderInfo(ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const QualifiedId &name, ModuleProviderLookup lookupType, const QVariantMap &qbsModule); void setupModuleProviderConfig(ProductContext &product); std::optional> getModuleProviders(Item *item); QString findModuleProviderFile(const QualifiedId &name, ModuleProviderLookup lookupType); QVariantMap evaluateQbsModule(ProductContext &product) const; Item *createProviderScope(const ProductContext &product, const QVariantMap &qbsModule); using EvaluationResult = std::pair; EvaluationResult evaluateModuleProvider( ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const QualifiedId &name, const QString &providerFile, const QVariantMap &moduleConfig, const QVariantMap &qbsModule); void checkAllowedValues(Item *providerItem); LoaderState &m_loaderState; }; } // namespace qbs::Internal #endif // MODULEPROVIDERLOADER_H qbs-src-2.6.1/src/lib/corelib/loader/probesresolver.cpp0000644000175100001660000003203614776170045022456 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2022 Raphaël Cotty ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "probesresolver.h" #include "itemreader.h" #include "loaderutils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static QString probeGlobalId(Item *probe) { QString id; for (Item *obj = probe; obj; obj = obj->prototype()) { if (!obj->id().isEmpty()) { id = obj->id(); break; } } if (id.isEmpty()) return {}; QBS_CHECK(probe->file()); return id + QLatin1Char('_') + probe->file()->filePath(); } ProbesResolver::ProbesResolver(LoaderState &loaderState) : m_loaderState(loaderState) {} void ProbesResolver::resolveProbes(ProductContext &productContext, Item *item) { AccumulatingTimer probesTimer(m_loaderState.parameters().logElapsedTime() ? &productContext.timingData.probes : nullptr); EvalContextSwitcher evalContextSwitcher(m_loaderState.evaluator().engine(), EvalContext::ProbeExecution); for (Item * const child : item->children()) { if (child->type() == ItemType::Probe) resolveProbe(productContext, item, child); } } void ProbesResolver::resolveProbe(ProductContext &productContext, Item *parent, Item *probe) { qCDebug(lcModuleLoader) << "Resolving Probe at " << probe->location().toString(); const QString &probeId = probeGlobalId(probe); if (Q_UNLIKELY(probeId.isEmpty())) throw ErrorInfo(Tr::tr("Probe.id must be set."), probe->location()); const bool isProjectLevelProbe = parent->type() == ItemType::Project || productContext.name.startsWith(StringConstants::shadowProductPrefix()); const JSSourceValueConstPtr configureScript = probe->sourceProperty(StringConstants::configureProperty()); QBS_CHECK(configureScript); if (Q_UNLIKELY(configureScript->sourceCode() == StringConstants::undefinedValue())) throw ErrorInfo(Tr::tr("Probe.configure must be set."), probe->location()); using ProbeProperty = std::pair; std::vector probeBindings; Evaluator &evaluator = m_loaderState.evaluator(); ScriptEngine * const engine = evaluator.engine(); JSContext * const ctx = engine->context(); QVariantMap initialProperties; for (Item *obj = probe; obj; obj = obj->prototype()) { const Item::PropertyMap &props = obj->properties(); for (auto it = props.cbegin(); it != props.cend(); ++it) { const QString &name = it.key(); if (name == StringConstants::configureProperty()) continue; const JSValue value = evaluator.value(probe, name); probeBindings.emplace_back(name, ScopedJsValue(ctx, value)); if (name != StringConstants::conditionProperty()) initialProperties.insert(name, getJsVariant(ctx, value)); } } const bool condition = evaluator.boolValue(probe, StringConstants::conditionProperty()); const QString &sourceCode = configureScript->sourceCode().toString(); ProbeConstPtr resolvedProbe; std::lock_guard lock(m_loaderState.topLevelProject().probesCacheLock()); m_loaderState.topLevelProject().incrementProbesCount(); if (isProjectLevelProbe) { resolvedProbe = findOldProjectProbe(probeId, condition, initialProperties, sourceCode); } else { resolvedProbe = findOldProductProbe(productContext.uniqueName(), condition, initialProperties, sourceCode); } if (!resolvedProbe) { resolvedProbe = findCurrentProbe(probe->location(), condition, initialProperties); if (resolvedProbe) { qCDebug(lcModuleLoader) << "probe results cached from current run"; m_loaderState.topLevelProject().incrementReusedCurrentProbesCount(); } } else { qCDebug(lcModuleLoader) << "probe results cached from earlier run"; m_loaderState.topLevelProject().incrementReusedOldProbesCount(); } ScopedJsValue configureScope(ctx, JS_UNDEFINED); std::vector importedFilesUsedInConfigure; if (!condition) { qCDebug(lcModuleLoader) << "Probe disabled; skipping"; } else if (!resolvedProbe) { m_loaderState.topLevelProject().incrementRunProbesCount(); qCDebug(lcModuleLoader) << "configure script needs to run"; const Evaluator::FileContextScopes fileCtxScopes = evaluator.fileContextScopes(configureScript->file()); configureScope.setValue(engine->newObject()); for (const ProbeProperty &b : probeBindings) setJsProperty(ctx, configureScope, b.first, JS_DupValue(ctx, b.second)); engine->clearRequestedProperties(); const JSValue scopes[] = { fileCtxScopes.fileScope, fileCtxScopes.importScope, configureScope}; ScopedJsValue sv( ctx, engine->evaluate( JsValueOwner::Caller, configureScript->sourceCodeForEvaluation(), {}, 1, scopes)); if (JsException ex = engine->checkAndClearException(configureScript->location())) throw ex.toErrorInfo(); importedFilesUsedInConfigure = engine->importedFilesUsedInScript(); } else { importedFilesUsedInConfigure = resolvedProbe->importedFilesUsed(); } QMap storedValues; for (const ProbeProperty &b : probeBindings) { if (b.first == StringConstants::conditionProperty() || b.first == StringConstants::configureProperty()) continue; VariantValuePtr storedValue; QVariant newValue; if (resolvedProbe) { storedValue = resolvedProbe->values().value(b.first); } else { if (condition) { JSValue v = getJsProperty(ctx, configureScope, b.first); const JSValue saved = v; ScopedJsValue valueMgr(ctx, saved); const PropertyDeclaration decl = probe->propertyDeclaration(b.first); evaluator.convertToPropertyType(decl, probe->location(), v); // If the value was converted from scalar to array as per our convenience // functionality, then the original value is now the only element of a // newly allocated array and thus gets deleted via that array. // The array itself is owned by the script engine, so we must stay out of // memory management here. if (v != saved) valueMgr.setValue(JS_UNDEFINED); if (JsException ex = engine->checkAndClearException({})) throw ex.toErrorInfo(); newValue = getJsVariant(ctx, v); // Special case, string and path lists are represented as js arrays but we don't // want to make them const as we do for object lists. Converting to QStringList // allows to distinguish between these two cases in ScriptEngine::asJsValue if (newValue.userType() == QMetaType::QVariantList && (decl.type() == PropertyDeclaration::StringList || decl.type() == PropertyDeclaration::PathList)) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) newValue.convert(QMetaType(QMetaType::QStringList)); #else newValue.convert(QMetaType::QStringList); #endif } } else { newValue = initialProperties.value(b.first); } storedValue = VariantValue::createStored(newValue); } if (storedValue) { // It would be simplier and faster to do this unconditionally, but setting invalid // VariantValue for "undefined" (e.g. unchanged) properties leads to undesired // convertion of lists properties from "undefined" to []. // See convertToPropertyType in evaluator.cpp and QTBUG-51237 if (!qVariantsEqual(storedValue->value(), getJsVariant(ctx, b.second))) { probe->setProperty(b.first, storedValue); } if (!resolvedProbe) storedValues[b.first] = storedValue; } } if (!resolvedProbe) { resolvedProbe = Probe::create( probeId, probe->location(), condition, sourceCode, initialProperties, storedValues, importedFilesUsedInConfigure); m_loaderState.topLevelProject().addNewlyResolvedProbe(resolvedProbe); } if (isProjectLevelProbe) m_loaderState.topLevelProject().addProjectLevelProbe(resolvedProbe); else productContext.probes << resolvedProbe; } ProbeConstPtr ProbesResolver::findOldProjectProbe( const QString &globalId, bool condition, const QVariantMap &initialProperties, const QString &sourceCode) const { if (m_loaderState.parameters().forceProbeExecution()) return {}; return m_loaderState.topLevelProject().findOldProjectProbe(globalId, [&](const ProbeConstPtr &oldProbe) { return probeMatches(oldProbe, condition, initialProperties, sourceCode, CompareScript::Yes); }); } ProbeConstPtr ProbesResolver::findOldProductProbe( const QString &productName, bool condition, const QVariantMap &initialProperties, const QString &sourceCode) const { if (m_loaderState.parameters().forceProbeExecution()) return {}; return m_loaderState.topLevelProject().findOldProductProbe(productName, [&](const ProbeConstPtr &oldProbe) { return probeMatches(oldProbe, condition, initialProperties, sourceCode, CompareScript::Yes); }); } ProbeConstPtr ProbesResolver::findCurrentProbe( const CodeLocation &location, bool condition, const QVariantMap &initialProperties) const { return m_loaderState.topLevelProject().findCurrentProbe(location, [&](const ProbeConstPtr &probe) { return probeMatches(probe, condition, initialProperties, QString(), CompareScript::No); }); } bool ProbesResolver::probeMatches(const ProbeConstPtr &probe, bool condition, const QVariantMap &initialProperties, const QString &configureScript, CompareScript compareScript) const { return probe->condition() == condition && qVariantMapsEqual(probe->initialProperties(), initialProperties) && (compareScript == CompareScript::No || (probe->configureScript() == configureScript && !probe->needsReconfigure(m_loaderState.topLevelProject().lastResolveTime()))); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/localprofiles.h0000644000175100001660000000405514776170045021705 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once namespace qbs::Internal { class Item; class LoaderState; void collectProfilesFromItems(Item *productOrProject, Item *projectScope, LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/groupshandler.h0000644000175100001660000000514014776170045021720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once namespace qbs::Internal { class LoaderState; class ProductContext; // Sets up Group items for the actual resolving stage. Responsibilities: // - Moving Group items located in modules over to the product. // - Identifying groups declaring target artifacts and marking them accordingly. // - Setting up group-level module instances to ensure proper resolving of per-group module // properties. // - As a side effect of the above point, collecting all properties set on the Group level // to help the ProjectResolver decide which properties need to be re-evaluated at all, // which is an important optimization (see commit 9cd8653eef). void setupGroups(ProductContext &product, LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/moduleinstantiator.cpp0000644000175100001660000004333214776170045023330 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "moduleinstantiator.h" #include "loaderutils.h" #include "modulepropertymerger.h" #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { static std::pair getOrSetModuleInstanceItem( Item *container, Item *moduleItem, const QualifiedId &moduleName, const QString &id, bool replace, LoaderState &loaderState, ProductContext *product); class ModuleInstantiator { public: ModuleInstantiator(const InstantiationContext &context, LoaderState &loaderState) : context(context), loaderState(loaderState) {} void instantiate(); private: void overrideProperties(); void setupScope(); void exchangePlaceholderItem(Item *loadingItem, Item *moduleItemForItemValues); const InstantiationContext &context; LoaderState &loaderState; }; void ModuleInstantiator::instantiate() { AccumulatingTimer timer(loaderState.parameters().logElapsedTime() ? &context.product.timingData.moduleInstantiation : nullptr); // This part needs to be done only once per module and product, and only if the module // was successfully loaded. if (context.module && !context.alreadyLoaded) { context.module->setType(ItemType::ModuleInstance); overrideProperties(); setupScope(); } // This strange-looking code deals with the fact that our syntax cannot properly handle // dependencies on several multiplexed variants of the same product. // See getOrSetModuleInstanceItem() below for details. Item * const moduleItemForItemValues = context.moduleWithSameName ? context.moduleWithSameName : context.module; // Now attach the module instance as an item value to the loading item, potentially // evicting a previously attached placeholder item and merging its values into the instance. // Note that we potentially do this twice, once for the actual loading item and once // for the product item, if the two are different. The reason is this: // For convenience, in the product item we allow attaching to properties from indirectly // loaded modules. For instance: // Product { // Depends { name: "Qt.core" } // cpp.cxxLanguageVersion: "c++20" // Works even though there is no Depends item for cpp // } // It's debatable whether that's a good feature, but it has been working (accidentally?) // for a long time, and removing it now would break a lot of existing projects. // Note that we omit this extra step if the Depends item has an id, as those should not // spread outside the loading item. exchangePlaceholderItem(context.loadingItem, moduleItemForItemValues); if (!context.alreadyLoaded && context.product.item && context.product.item != context.loadingItem && context.id.isEmpty()) { exchangePlaceholderItem(context.product.item, moduleItemForItemValues); } } void ModuleInstantiator::exchangePlaceholderItem(Item *loadingItem, Item *moduleItemForItemValues) { // If we have a module item, set an item value pointing to it as a property on the loading item. // Evict a possibly existing placeholder item, and return it to us, so we can merge its values // into the instance. const auto &[oldItem, newItem] = getOrSetModuleInstanceItem( loadingItem, moduleItemForItemValues, context.moduleName, context.id, true, loaderState, &context.product); // The new item always exists, even if we don't have a module item. In that case, the // function created a placeholder item for us, which we then have to turn into a // non-present module. QBS_CHECK(newItem); if (!moduleItemForItemValues) { createNonPresentModule(loaderState.itemPool(), context.moduleName.toString(), QLatin1String("not found"), newItem); return; } if (!moduleItemForItemValues->isPresentModule()) return; // This will yield false negatives for the case where there is an invalid property attached // for a module that is actually found by pkg-config via the fallback provider. // However, this is extremely rare compared to the case where the presence of the fallback // module simply indicates "not present". if (moduleItemForItemValues->isFallbackModule()) return; // If the old and the new items are the same, it means the existing item value already // pointed to a module instance (rather than a placeholder). // This can happen in two cases: // a) Multiple identical Depends items on the same level (easily possible with inheritance). // b) Dependencies to multiplexed variants of the same product // (see getOrSetModuleInstanceItem() below for details). if (oldItem == newItem) { QBS_CHECK(oldItem->type() == ItemType::ModuleInstance); QBS_CHECK(context.alreadyLoaded || context.exportingProduct); return; } // In all other cases, our request to set the module instance item must have been honored. QBS_CHECK(newItem == moduleItemForItemValues); // If there was no placeholder item, we don't have to merge any values and are done. if (!oldItem) return; // If an item was replaced, then it must have been a placeholder. QBS_CHECK(oldItem->type() == ItemType::ModuleInstancePlaceholder); // Prevent setting read-only properties. for (auto it = oldItem->properties().cbegin(); it != oldItem->properties().cend(); ++it) { const PropertyDeclaration &pd = moduleItemForItemValues->propertyDeclaration(it.key()); if (pd.flags().testFlag(PropertyDeclaration::ReadOnlyFlag)) { throw ErrorInfo(Tr::tr("Cannot set read-only property '%1'.").arg(pd.name()), it.value()->location()); } } // Now merge the locally attached values into the actual module instance. mergeFromLocalInstance(context.product, loadingItem, context.loadingName, oldItem, moduleItemForItemValues, loaderState); // TODO: We'd like to delete the placeholder item here, because it's not // being referenced anymore and there's a lot of them. However, this // is not supported by ItemPool. Investigate the use of std::pmr. } Item *retrieveModuleInstanceItem(Item *containerItem, const QualifiedId &name, LoaderState &loaderState) { return getOrSetModuleInstanceItem(containerItem, nullptr, name, {}, false, loaderState, nullptr) .second; } Item *retrieveQbsItem(Item *containerItem, LoaderState &loaderState) { return retrieveModuleInstanceItem(containerItem, StringConstants::qbsModule(), loaderState); } void ModuleInstantiator::overrideProperties() { // Users can override module properties on the command line with the // modules..: syntax. // For simplicity and backwards compatibility, qbs properties can also be given without // the "modules." prefix, i.e. just qbs.:. // In addition, users can override module properties just for certain products // using the products...: syntax. // Such product-specific overrides have higher precedence. const QString fullName = context.moduleName.toString(); const QString generalOverrideKey = QStringLiteral("modules.") + fullName; const QString perProductOverrideKey = StringConstants::productsOverridePrefix() + context.product.name + QLatin1Char('.') + fullName; const SetupProjectParameters ¶meters = loaderState.parameters(); Logger &logger = loaderState.logger(); context.module->overrideProperties(parameters.overriddenValuesTree(), generalOverrideKey, parameters, logger); if (fullName == StringConstants::qbsModule()) { context.module->overrideProperties(parameters.overriddenValuesTree(), fullName, parameters, logger); } context.module->overrideProperties(parameters.overriddenValuesTree(), perProductOverrideKey, parameters, logger); } void ModuleInstantiator::setupScope() { Item * const scope = Item::create(&loaderState.itemPool(), ItemType::Scope); QBS_CHECK(context.module->file()); scope->setFile(context.module->file()); QBS_CHECK(context.product.project->scope); context.product.project->scope->copyProperty(StringConstants::projectVar(), scope); if (context.product.scope) context.product.scope->copyProperty(StringConstants::productVar(), scope); else QBS_CHECK(context.moduleName.toString() == StringConstants::qbsModule()); // Dummy product. const ItemValuePtr moduleItemValue = ItemValue::create(context.module); scope->setProperty(StringConstants::moduleVar(), moduleItemValue); if (!context.module->id().isEmpty()) scope->setProperty(context.module->id(), moduleItemValue); setScopeForDescendants(context.module, scope, true); context.module->setScope(scope); if (context.exportingProduct) { QBS_CHECK(context.exportingProduct->type() == ItemType::Product); const auto exportingProductItemValue = ItemValue::create(context.exportingProduct); scope->setProperty(QStringLiteral("exportingProduct"), exportingProductItemValue); const auto importingProductItemValue = ItemValue::create(context.product.item); scope->setProperty(QStringLiteral("importingProduct"), importingProductItemValue); // FIXME: This looks wrong. Introduce exportingProject variable? scope->setProperty(StringConstants::projectVar(), ItemValue::create(context.exportingProduct->parent())); PropertyDeclaration pd(StringConstants::qbsSourceDirPropertyInternal(), PropertyDeclaration::String, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); context.module->setPropertyDeclaration(pd.name(), pd); context.module->setProperty(pd.name(), context.exportingProduct->property( StringConstants::sourceDirectoryProperty())); } } void instantiateModule(const InstantiationContext &context, LoaderState &loaderState) { ModuleInstantiator(context, loaderState).instantiate(); } // This important function deals with retrieving and setting (pseudo-)module instances from/on // items. // Use case 1: Suppose we resolve the dependency cpp in module Qt.core, which also contains // property bindings for cpp such as "cpp.defines: [...]". // The "cpp" part of this binding is represented by an ItemValue whose // item is of type ModuleInstancePlaceholder, originally set up by ItemReaderASTVisitor. // This function will be called with the actual cpp module item and will // replace the placeholder item in the item value. It will also return // the placeholder item for subsequent merging of its properties with the // ones of the actual module (in ModulePropertyMerger::mergeFromLocalInstance()). // If there were no cpp property bindings defined in Qt.core, then we'd still // have to replace the placeholder item, because references to "cpp" on the // right-hand-side of other properties must refer to the module item. // This is the common use of this function as employed by resolveProdsucDependencies(). // Note that if a product has dependencies on more than one variant of a multiplexed // product, these dependencies are competing for the item value property name, // i.e. this case is not properly supported by the syntax. You must therefore not // export properties from multiplexed products that will be different between the // variants. In this function, the condition manifests itself by a module instance // being encountered instead of a module instance placeholder, in which case // nothing is done at all. // Use case 2: We inject a fake qbs module into a project item, so qbs properties set in profiles // can be accessed in the project level. Doing this is discouraged, and the // functionality is kept mostly for backwards compatibility. The moduleItem // parameter is null in this case, and the item will be created by the function itself. // Use case 3: A temporary qbs module is attached to a product during low-level setup, namely // in product multiplexing and setting qbs.profile. // Use case 4: Module propagation to the the Group level. // In all cases, the first returned item is the existing one, and the second returned item // is the new one. Depending on the use case, they might be null and might also be the same item. std::pair getOrSetModuleInstanceItem( Item *container, Item *moduleItem, const QualifiedId &moduleName, const QString &id, bool replace, LoaderState &loaderState, ProductContext *product) { Item *instance = container; const QualifiedId itemValueName = !id.isEmpty() ? QualifiedId::fromString(id) : moduleName; for (int i = 0; i < itemValueName.size(); ++i) { const QString &moduleNameSegment = itemValueName.at(i); const ValuePtr v = instance->ownProperty(itemValueName.at(i)); if (v && v->type() == Value::ItemValueType) { ItemValue * const itemValue = std::static_pointer_cast(v).get(); instance = itemValue->item(); if (i == itemValueName.size() - 1) { if (replace && instance != moduleItem && instance->type() == ItemType::ModuleInstancePlaceholder) { if (!moduleItem) { moduleItem = Item::create(&loaderState.itemPool(), ItemType::ModuleInstancePlaceholder); } itemValue->setItem(moduleItem); } return {instance, itemValue->item()}; } } else { Item *newItem = i < itemValueName.size() - 1 ? Item::create(&loaderState.itemPool(), ItemType::ModulePrefix) : moduleItem ? moduleItem : Item::create(&loaderState.itemPool(), ItemType::ModuleInstancePlaceholder); instance->setProperty(moduleNameSegment, ItemValue::create(newItem)); instance = newItem; } } // If the Depends item has an id, make sure it now points to the module. Otherwise nested // child items will still get the Depends item when referring to it. if (!id.isEmpty() && (container->type() == ItemType::Product || container->type() == ItemType::ModuleInstance)) { Item * const scope = container->type() == ItemType::Product ? product->scope : container->scope(); QBS_CHECK(scope); const ValuePtr idValue = scope->property(id); QBS_CHECK(idValue); QBS_CHECK(idValue->type() == Value::ItemValueType); const auto idIv = static_cast(idValue.get()); if (idIv->item()->type() != ItemType::ModuleInstance) { QBS_CHECK(idIv->item()->type() == ItemType::Depends); scope->setProperty(id, ItemValue::create(moduleItem)); } } return {nullptr, instance}; } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/probesresolver.h0000644000175100001660000000647414776170045022132 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2022 Raphaël Cotty ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PROBESRESOLVER_H #define PROBESRESOLVER_H #include #include #include namespace qbs::Internal { class Item; class LoaderState; class ProductContext; class ProbesResolver { public: explicit ProbesResolver(LoaderState &loaderState); void resolveProbes(ProductContext &productContext, Item *item); private: ProbeConstPtr findOldProjectProbe(const QString &globalId, bool condition, const QVariantMap &initialProperties, const QString &sourceCode) const; ProbeConstPtr findOldProductProbe(const QString &productName, bool condition, const QVariantMap &initialProperties, const QString &sourceCode) const; ProbeConstPtr findCurrentProbe(const CodeLocation &location, bool condition, const QVariantMap &initialProperties) const; enum class CompareScript { No, Yes }; bool probeMatches(const ProbeConstPtr &probe, bool condition, const QVariantMap &initialProperties, const QString &configureScript, CompareScript compareScript) const; void resolveProbe(ProductContext &productContext, Item *parent, Item *probe); LoaderState &m_loaderState; }; } // namespace qbs::Internal #endif // PROBESRESOLVER_H qbs-src-2.6.1/src/lib/corelib/loader/modulepropertymerger.cpp0000644000175100001660000002753514776170045023706 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "modulepropertymerger.h" #include "loaderutils.h" #include #include #include #include #include #include #include #include #include namespace qbs::Internal { class ModulePropertyMerger { public: ModulePropertyMerger(ProductContext &product, LoaderState &loaderState) : m_product(product), m_loaderState(loaderState) {} void mergeFromLocalInstance(Item *loadingItem, const QString &loadingName, const Item *localInstance, Item *globalInstance); void doFinalMerge(); private: int compareValuePriorities(const ValueConstPtr &v1, const ValueConstPtr &v2); void mergePropertyFromLocalInstance(Item *loadingItem, const QString &loadingName, Item *globalInstance, const QString &name, const ValuePtr &value); bool doFinalMerge(Item *moduleItem); bool doFinalMerge(const PropertyDeclaration &propertyDecl, ValuePtr &propertyValue); void finalizeCandidates(const ValuePtr &value); ProductContext & m_product; LoaderState &m_loaderState; }; void mergeFromLocalInstance(ProductContext &product, Item *loadingItem, const QString &loadingName, const Item *localInstance, Item *globalInstance, LoaderState &loaderState) { ModulePropertyMerger(product, loaderState).mergeFromLocalInstance( loadingItem, loadingName, localInstance, globalInstance); } void doFinalMerge(ProductContext &product, LoaderState &loaderState) { ModulePropertyMerger(product, loaderState).doFinalMerge(); } void ModulePropertyMerger::mergeFromLocalInstance(Item *loadingItem, const QString &loadingName, const Item *localInstance, Item *globalInstance) { AccumulatingTimer t(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.propertyMerging : nullptr); for (auto it = localInstance->properties().constBegin(); it != localInstance->properties().constEnd(); ++it) { mergePropertyFromLocalInstance(loadingItem, loadingName, globalInstance, it.key(), it.value()); } } void ModulePropertyMerger::doFinalMerge() { AccumulatingTimer t(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.propertyMerging : nullptr); std::unordered_set itemsToInvalidate; for (const Item::Module &module : m_product.item->modules()) { if (doFinalMerge(module.item)) itemsToInvalidate.insert(module.item); } // For each module item, if it requires invalidation, we also add modules that depend on // that module item, all the way up to the Product item. std::unordered_set visitedItems; const auto collectDependentItems = [&itemsToInvalidate, &visitedItems](const Item *item, const auto &collect) -> bool { const bool alreadyInSet = itemsToInvalidate.count(item); if (!visitedItems.insert(item).second) // item handled already return alreadyInSet; bool addItem = false; for (const Item::Module &m : item->modules()) { if (collect(m.item, collect)) addItem = true; } if (addItem && !alreadyInSet) itemsToInvalidate.insert(item); return addItem || alreadyInSet; }; collectDependentItems(m_product.item, collectDependentItems); for (const Item * const item : itemsToInvalidate) m_loaderState.evaluator().clearCache(item); } int ModulePropertyMerger::compareValuePriorities(const ValueConstPtr &v1, const ValueConstPtr &v2) { QBS_CHECK(v1); QBS_CHECK(v2); QBS_CHECK(v1 != v2); QBS_CHECK(v1->scope() != v2->scope()); QBS_CHECK(v1->type() == Value::JSSourceValueType || v2->type() == Value::JSSourceValueType); const int prio1 = v1->priority(m_product.item); const int prio2 = v2->priority(m_product.item); if (prio1 != prio2) return prio1 - prio2; const int prioDiff = v1->scopeName().compare(v2->scopeName()); // Sic! See 8ff1dd0044 QBS_CHECK(prioDiff != 0); return prioDiff; } void ModulePropertyMerger::mergePropertyFromLocalInstance( Item *loadingItem, const QString &loadingName, Item *globalInstance, const QString &name, const ValuePtr &value) { if (loadingItem->type() == ItemType::Project) { throw ErrorInfo(Tr::tr("Module properties cannot be set in Project items."), value->location()); } const PropertyDeclaration decl = globalInstance->propertyDeclaration(name); if (!decl.isValid()) { if (value->type() == Value::ItemValueType || value->createdByPropertiesBlock()) return; throw ErrorInfo(Tr::tr("Property '%1' is not declared.") .arg(name), value->location()); } if (const ErrorInfo error = decl.checkForDeprecation( m_loaderState.parameters().deprecationWarningMode(), value->location(), m_loaderState.logger()); error.hasError()) { handlePropertyError(error, m_loaderState.parameters(), m_loaderState.logger()); return; } if (value->setInternally()) { // E.g. qbs.architecture after multiplexing. globalInstance->setProperty(decl.name(), value); return; } QBS_CHECK(value->type() != Value::ItemValueType); const ValuePtr globalVal = globalInstance->ownProperty(decl.name()); value->setScope(loadingItem, loadingName); QBS_CHECK(globalVal); // Values set internally cannot be overridden by JS values. // The same goes for values set on the command line. // Note that in both cases, there is no merging for list properties: The override is absolute. if (globalVal->setInternally() || globalVal->setByCommandLine()) return; QBS_CHECK(value->type() == Value::JSSourceValueType); QBS_CHECK(!globalVal->expired(m_product.item)); QBS_CHECK(!value->expired(m_product.item)); if (compareValuePriorities(globalVal, value) < 0) { value->setCandidates(globalVal->candidates()); globalVal->setCandidates({}); value->addCandidate(globalVal); globalInstance->setProperty(decl.name(), value); } else { globalVal->addCandidate(value); } } bool ModulePropertyMerger::doFinalMerge(Item *moduleItem) { if (!moduleItem->isPresentModule()) return false; bool mustInvalidateCache = false; for (auto it = moduleItem->properties().begin(); it != moduleItem->properties().end(); ++it) { if (doFinalMerge(moduleItem->propertyDeclaration(it.key()), it.value())) mustInvalidateCache = true; } return mustInvalidateCache; } bool ModulePropertyMerger::doFinalMerge(const PropertyDeclaration &propertyDecl, ValuePtr &propertyValue) { if (propertyValue->type() == Value::VariantValueType) return false; if (!propertyDecl.isValid()) return false; // Caught later by dedicated checker. propertyValue->resetPriority(); if (propertyValue->candidates().empty()) return false; std::pair> candidatesWithHighestPrio; candidatesWithHighestPrio.first = propertyValue->priority(m_product.item); candidatesWithHighestPrio.second.push_back(propertyValue); for (const ValuePtr &v : propertyValue->candidates()) { const int prio = v->priority(m_product.item); if (prio < candidatesWithHighestPrio.first) continue; if (prio > candidatesWithHighestPrio.first) { candidatesWithHighestPrio.first = prio; candidatesWithHighestPrio.second = {v}; continue; } candidatesWithHighestPrio.second.push_back(v); } ValuePtr chosenValue = candidatesWithHighestPrio.second.front(); if (propertyDecl.isScalar() && int(candidatesWithHighestPrio.second.size()) > 1) { ErrorInfo error( Tr::tr("Conflicting scalar values for property '%1'.").arg(propertyDecl.name())); error.append({}, chosenValue->location()); QBS_CHECK(chosenValue->type() == Value::JSSourceValueType); QStringView sourcCode = static_cast(chosenValue.get())->sourceCode(); for (int i = 1; i < int(candidatesWithHighestPrio.second.size()); ++i) { const ValuePtr &v = candidatesWithHighestPrio.second.at(i); QBS_CHECK(v->type() == Value::JSSourceValueType); // Note that this is a bit silly: The source code could still evaluate to // different values in the end. if (static_cast(v.get())->sourceCode() != sourcCode) error.append({}, v->location()); } if (error.items().size() > 2) m_loaderState.logger().printWarning(error); } if (propertyValue == chosenValue) { const std::vector oldCandidates = propertyValue->candidates(); finalizeCandidates(propertyValue); return oldCandidates != propertyValue->candidates(); } std::vector candidates = propertyValue->candidates(); candidates.erase(std::find(candidates.begin(), candidates.end(), chosenValue)); chosenValue->setCandidates(candidates); chosenValue->addCandidate(propertyValue); propertyValue->setCandidates({}); propertyValue = chosenValue; finalizeCandidates(propertyValue); return true; } void ModulePropertyMerger::finalizeCandidates(const ValuePtr &value) { value->removeExpiredCandidates(m_product.item); value->sortCandidates([this](const ValuePtr &v1, const ValuePtr &v2) { // https://stackoverflow.com/questions/38966516/should-sorting-algorithm-pass-same-element-in-the-comparison-function if (v1 == v2) return false; return compareValuePriorities(v1, v2) > 0; }); } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/moduleproviderloader.cpp0000644000175100001660000004346114776170045023635 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "moduleproviderloader.h" #include "itemreader.h" #include "probesresolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static QString getConfigHash(const QVariantMap& config) { QJsonDocument doc; doc.setObject(QJsonObject::fromVariantMap(config)); return QString::fromLatin1( QCryptographicHash::hash(doc.toJson(), QCryptographicHash::Sha1).toHex().left(16)); } ModuleProviderLoader::ModuleProviderLoader(LoaderState &loaderState) : m_loaderState(loaderState) {} ModuleProviderLoader::ModuleProviderResult ModuleProviderLoader::executeModuleProviders( ProductContext &productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName) { ModuleProviderLoader::ModuleProviderResult result; try { std::vector providersToRun; qCDebug(lcModuleLoader) << "Module" << moduleName.toString() << "not found, checking for module providers"; const auto providerNames = getModuleProviders(productContext.item); if (providerNames) { providersToRun = transformed>(*providerNames, [](const auto &name) { return Provider{name, ModuleProviderLookup::Named}; }); } else { for (QualifiedId providerName = moduleName; !providerName.empty(); providerName.pop_back()) { providersToRun.push_back({providerName, ModuleProviderLookup::Scoped}); } } result = executeModuleProvidersHelper( productContext, dependsItemLocation, moduleName, providersToRun); } catch (const ErrorInfo &error) { auto ei = error; ei.prepend( Tr::tr("Error executing provider for module '%1':").arg(moduleName.toString()), dependsItemLocation); productContext.handleError(ei); } return result; } ModuleProviderLoader::ModuleProviderResult ModuleProviderLoader::executeModuleProvidersHelper( ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const std::vector &providers) { if (providers.empty()) return {}; QStringList allSearchPaths; ModuleProviderResult result; setupModuleProviderConfig(product); const auto qbsModule = evaluateQbsModule(product); for (const auto &[name, lookupType] : providers) { const auto &[info, fromCache] = findOrCreateProviderInfo( product, dependsItemLocation, moduleName, name, lookupType, qbsModule); if (info.providerFile.isEmpty()) { if (lookupType == ModuleProviderLookup::Named) throw ErrorInfo(Tr::tr("Unknown provider '%1'").arg(name.toString())); continue; } if (fromCache) qCDebug(lcModuleLoader) << "Re-using provider" << name.toString() << "from cache"; result.providerFound = true; if (info.searchPaths.empty()) { qCDebug(lcModuleLoader) << "Module provider did run, but did not set up any modules."; continue; } qCDebug(lcModuleLoader) << "Module provider added" << info.searchPaths.size() << "new search path(s)"; allSearchPaths << info.searchPaths; } if (allSearchPaths.isEmpty()) return result; result.searchPaths = std::move(allSearchPaths); return result; } std::pair ModuleProviderLoader::findOrCreateProviderInfo( ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const QualifiedId &name, ModuleProviderLookup lookupType, const QVariantMap &qbsModule) { QBS_CHECK(product.providerConfig); const QVariantMap config = product.providerConfig->value(name.toString()).toMap(); std::lock_guard lock(m_loaderState.topLevelProject().moduleProvidersCacheLock()); ModuleProvidersCacheKey cacheKey{name.toString(), {}, config, qbsModule, int(lookupType)}; // TODO: get rid of non-eager providers and eliminate following if-logic // first, try to find eager provider (stored with an empty module name) if (ModuleProviderInfo *provider = m_loaderState.topLevelProject().moduleProvider(cacheKey)) return {*provider, true}; // second, try to find non-eager provider for a specific module name std::get<1>(cacheKey) = moduleName.toString(); // override moduleName if (ModuleProviderInfo *provider = m_loaderState.topLevelProject().moduleProvider(cacheKey)) return {*provider, true}; bool isEager = false; ModuleProviderInfo info; info.name = name; info.config = config; info.providerFile = findModuleProviderFile(name, lookupType); if (!info.providerFile.isEmpty()) { qCDebug(lcModuleLoader) << "Running provider" << name << "at" << info.providerFile; std::tie(info.searchPaths, isEager) = evaluateModuleProvider( product, dependsItemLocation, moduleName, name, info.providerFile, config, qbsModule); info.transientOutput = m_loaderState.parameters().dryRun(); } std::get<1>(cacheKey) = isEager ? QString() : moduleName.toString(); return {m_loaderState.topLevelProject().addModuleProvider(cacheKey, info), false}; } void ModuleProviderLoader::setupModuleProviderConfig(ProductContext &product) { if (product.providerConfig) return; QVariantMap providerConfig; const ItemValueConstPtr configItemValue = product.item->itemProperty(StringConstants::moduleProviders(), m_loaderState.itemPool()); if (configItemValue) { const std::function collectMap = [this, &providerConfig, &collectMap](const Item *item, const QualifiedId &name) { const Item::PropertyMap &props = item->properties(); for (auto it = props.begin(); it != props.end(); ++it) { QVariant value; switch (it.value()->type()) { case Value::ItemValueType: { const auto childItem = static_cast(it.value().get())->item(); childItem->setScope(item->scope()); collectMap(childItem, QualifiedId(name) << it.key()); continue; } case Value::JSSourceValueType: { it.value()->setScope(item->scope(), {}); const ScopedJsValue sv(m_loaderState.evaluator().engine()->context(), m_loaderState.evaluator().value(item, it.key())); value = getJsVariant(m_loaderState.evaluator().engine()->context(), sv); break; } case Value::VariantValueType: value = static_cast(it.value().get())->value(); break; } QVariantMap m = providerConfig.value(name.toString()).toMap(); m.insert(it.key(), value); providerConfig.insert(name.toString(), m); } }; configItemValue->item()->setScope(product.item); collectMap(configItemValue->item(), QualifiedId()); } for (auto it = product.moduleProperties.begin(); it != product.moduleProperties.end(); ++it) { if (!it.key().startsWith(QStringLiteral("moduleProviders."))) continue; const QString provider = it.key().mid(QStringLiteral("moduleProviders.").size()); const QVariantMap providerConfigFromBuildConfig = it.value().toMap(); if (providerConfigFromBuildConfig.empty()) continue; QVariantMap currentMapForProvider = providerConfig.value(provider).toMap(); for (auto propIt = providerConfigFromBuildConfig.begin(); propIt != providerConfigFromBuildConfig.end(); ++propIt) { currentMapForProvider.insert(propIt.key(), propIt.value()); } providerConfig.insert(provider, currentMapForProvider); } product.providerConfig = providerConfig; } std::optional> ModuleProviderLoader::getModuleProviders(Item *item) { while (item) { const auto providers = m_loaderState.evaluator().optionalStringListValue( item, StringConstants::qbsModuleProviders()); if (providers) { return transformed>(*providers, [](const auto &provider) { return QualifiedId::fromString(provider); }); } item = item->parent(); } return std::nullopt; } QString ModuleProviderLoader::findModuleProviderFile( const QualifiedId &name, ModuleProviderLookup lookupType) { for (const QString &path : m_loaderState.itemReader().allSearchPaths()) { QString fullPath = FileInfo::resolvePath(path, QStringLiteral("module-providers")); switch (lookupType) { case ModuleProviderLookup::Named: { const auto result = FileInfo::resolvePath(fullPath, name.toString() + QStringLiteral(".qbs")); if (FileInfo::exists(result)) { fullPath = result; break; } [[fallthrough]]; } case ModuleProviderLookup::Scoped: for (const QString &component : name) fullPath = FileInfo::resolvePath(fullPath, component); fullPath = FileInfo::resolvePath(fullPath, QStringLiteral("provider.qbs")); break; } if (!FileInfo::exists(fullPath)) { qCDebug(lcModuleLoader) << "No module provider found at" << fullPath; continue; } return fullPath; } return {}; } QVariantMap ModuleProviderLoader::evaluateQbsModule(ProductContext &product) const { if (product.providerQbsModule) return *product.providerQbsModule; const QString properties[] = { QStringLiteral("sysroot"), QStringLiteral("toolchain"), }; const auto qbsItemValue = std::static_pointer_cast( product.item->property(StringConstants::qbsModule())); QVariantMap result; for (const auto &property : properties) { const ScopedJsValue val(m_loaderState.evaluator().engine()->context(), m_loaderState.evaluator().value(qbsItemValue->item(), property)); auto value = getJsVariant(m_loaderState.evaluator().engine()->context(), val); if (!value.isValid()) continue; // The xcode module sets qbs.sysroot; the resulting value is bogus before the probes // have run. if (property == QLatin1String("sysroot") && !FileInfo::isAbsolute(value.toString())) continue; result[property] = std::move(value); } return *(product.providerQbsModule = result); } Item *ModuleProviderLoader::createProviderScope( const ProductContext &product, const QVariantMap &qbsModule) { const auto qbsItemValue = std::static_pointer_cast( product.item->property(StringConstants::qbsModule())); Item *fakeQbsModule = Item::create(&m_loaderState.itemPool(), ItemType::Scope); for (auto it = qbsModule.begin(), end = qbsModule.end(); it != end; ++it) { fakeQbsModule->setProperty(it.key(), VariantValue::create(it.value())); } Item *scope = Item::create(&m_loaderState.itemPool(), ItemType::Scope); scope->setFile(qbsItemValue->item()->file()); scope->setProperty(StringConstants::qbsModule(), ItemValue::create(fakeQbsModule)); return scope; } ModuleProviderLoader::EvaluationResult ModuleProviderLoader::evaluateModuleProvider( ProductContext &product, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, const QualifiedId &name, const QString &providerFile, const QVariantMap &moduleConfig, const QVariantMap &qbsModule) { qCDebug(lcModuleLoader) << "Instantiating module provider at" << providerFile; const QString projectBuildDir = product.project->item->variantProperty( StringConstants::buildDirectoryProperty())->value().toString(); const QString searchPathBaseDir = ModuleProviderInfo::outputDirPath(projectBuildDir, name); // include qbs module into hash auto jsConfig = moduleConfig; jsConfig[StringConstants::qbsModule()] = qbsModule; QString outputBaseDir = searchPathBaseDir + QLatin1Char('/') + getConfigHash(jsConfig); Item * const providerItem = m_loaderState.itemReader().setupItemFromFile( providerFile, dependsItemLocation); if (providerItem->type() != ItemType::ModuleProvider) { throw ErrorInfo(Tr::tr("File '%1' declares an item of type '%2', " "but '%3' was expected.") .arg(providerFile, providerItem->typeName(), BuiltinDeclarations::instance().nameForType(ItemType::ModuleProvider))); } Item * const scope = createProviderScope(product, qbsModule); for (auto it = providerItem->properties().begin(); it != providerItem->properties().end(); ++it) it.value()->setScope(scope, {}); providerItem->setProperty( StringConstants::nameProperty(), VariantValue::create(name.toString())); providerItem->setProperty( QStringLiteral("outputBaseDir"), VariantValue::create(outputBaseDir)); providerItem->overrideProperties(moduleConfig, name, m_loaderState.parameters(), m_loaderState.logger()); const bool isEager = m_loaderState.evaluator().boolValue( providerItem, StringConstants::isEagerProperty()); if (!isEager) { providerItem->setProperty( StringConstants::moduleNameProperty(), VariantValue::create(moduleName.toString())); } ProbesResolver(m_loaderState).resolveProbes(product, providerItem); const bool condition = m_loaderState.evaluator().boolValue( providerItem, StringConstants::conditionProperty()); if (!condition) { qCDebug(lcModuleLoader) << "Provider condition is false, skipping"; return {{}, isEager}; } EvalContextSwitcher contextSwitcher( m_loaderState.evaluator().engine(), EvalContext::ModuleProvider); checkPropertyDeclarations(providerItem, m_loaderState); checkAllowedValues(providerItem); auto searchPaths = m_loaderState.evaluator().stringListValue( providerItem, QStringLiteral("relativeSearchPaths")); auto prependBaseDir = [&outputBaseDir](const auto &path) { return QString(outputBaseDir + QLatin1Char('/') + path); }; std::transform(searchPaths.begin(), searchPaths.end(), searchPaths.begin(), prependBaseDir); return {searchPaths, isEager}; } void ModuleProviderLoader::checkAllowedValues(Item *providerItem) { for (const auto &propertyDeclaration : providerItem->propertyDeclarations()) { if (!propertyDeclaration.shouldCheckAllowedValues()) continue; const auto &name = propertyDeclaration.name(); if (name == QStringLiteral("relativeSearchPaths")) continue; const auto value = m_loaderState.evaluator().variantValue(providerItem, name); const auto propertyValue = providerItem->property(name); propertyDeclaration.checkAllowedValues( value, propertyValue->location(), name, m_loaderState); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/localprofiles.cpp0000644000175100001660000001413214776170045022235 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "localprofiles.h" #include "loaderutils.h" #include #include #include #include #include #include #include #include #include namespace qbs::Internal { class LocalProfiles { public: LocalProfiles(LoaderState &loaderState) : m_loaderState(loaderState) {} void collectProfiles(Item *productOrProject, Item *projectScope); private: void handleProfile(Item *profileItem); void evaluateProfileValues(const QualifiedId &namePrefix, Item *item, Item *profileItem, QVariantMap &values); LoaderState &m_loaderState; }; void collectProfilesFromItems(Item *productOrProject, Item *projectScope, LoaderState &loaderState) { LocalProfiles(loaderState).collectProfiles(productOrProject, projectScope); } void LocalProfiles::handleProfile(Item *profileItem) { QVariantMap values; evaluateProfileValues(QualifiedId(), profileItem, profileItem, values); const bool condition = values.take(StringConstants::conditionProperty()).toBool(); if (!condition) return; const QString profileName = values.take(StringConstants::nameProperty()).toString(); if (profileName.isEmpty()) throw ErrorInfo(Tr::tr("Every Profile item must have a name"), profileItem->location()); if (profileName == Profile::fallbackName()) { throw ErrorInfo(Tr::tr("Reserved name '%1' cannot be used for an actual profile.") .arg(profileName), profileItem->location()); } m_loaderState.topLevelProject().addLocalProfile(profileName, values, profileItem->location()); } void LocalProfiles::evaluateProfileValues(const QualifiedId &namePrefix, Item *item, Item *profileItem, QVariantMap &values) { const Item::PropertyMap &props = item->properties(); for (auto it = props.begin(); it != props.end(); ++it) { QualifiedId name = namePrefix; name << it.key(); switch (it.value()->type()) { case Value::ItemValueType: evaluateProfileValues(name, std::static_pointer_cast(it.value())->item(), profileItem, values); break; case Value::VariantValueType: values.insert(name.join(QLatin1Char('.')), std::static_pointer_cast(it.value())->value()); break; case Value::JSSourceValueType: if (item != profileItem) item->setScope(profileItem); const ScopedJsValue sv(m_loaderState.evaluator().engine()->context(), m_loaderState.evaluator().value(item, it.key())); values.insert(name.join(QLatin1Char('.')), getJsVariant(m_loaderState.evaluator().engine()->context(), sv)); break; } } } void LocalProfiles::collectProfiles(Item *productOrProject, Item *projectScope) { Item * scope = productOrProject->type() == ItemType::Project ? projectScope : nullptr; for (auto it = productOrProject->children().begin(); it != productOrProject->children().end();) { Item * const childItem = *it; if (childItem->type() == ItemType::Profile) { if (!scope) { const ItemValuePtr itemValue = ItemValue::create(productOrProject); scope = Item::create(&m_loaderState.itemPool(), ItemType::Scope); scope->setProperty(StringConstants::productVar(), itemValue); scope->setFile(productOrProject->file()); scope->setScope(projectScope); } childItem->setScope(scope); try { handleProfile(childItem); } catch (const ErrorInfo &e) { handlePropertyError(e, m_loaderState.parameters(), m_loaderState.logger()); } it = productOrProject->children().erase(it); // TODO: delete item and scope } else { if (childItem->type() == ItemType::Product) collectProfiles(childItem, projectScope); ++it; } } } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/productscollector.h0000644000175100001660000000452314776170045022621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include namespace qbs::Internal { class Item; class LoaderState; // Traverses the root project item and fills the TopLevelProjectContext with all the // product and sub-project information, including those coming from referenced files. class ProductsCollector { public: ProductsCollector(LoaderState &loaderState); ~ProductsCollector(); void run(Item *rootProject); private: class Private; Pimpl d; }; } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/itemreadervisitorstate.h0000644000175100001660000000575614776170045023662 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMREADERVISITORSTATE_H #define QBS_ITEMREADERVISITORSTATE_H #include #include #include #include namespace qbs { namespace Internal { class Item; class ItemPool; class ItemReaderCache; class Logger; class ItemReaderVisitorState { public: ItemReaderVisitorState(ItemReaderCache &cache, Logger &logger); Logger &logger() { return m_logger; } Item *readFile(const QString &filePath, const QStringList &searchPaths, ItemPool *itemPool); void findDirectoryEntries(const QString &dirPath, QStringList *entries) const; Item *mostDerivingItem() const; void setMostDerivingItem(Item *item); void setDeprecationWarningMode(DeprecationWarningMode mode) { m_deprecationWarningMode = mode; } DeprecationWarningMode deprecationWarningMode() const { return m_deprecationWarningMode; } private: DeprecationWarningMode m_deprecationWarningMode = defaultDeprecationWarningMode(); ItemReaderCache &m_cache; Logger &m_logger; Item *m_mostDerivingItem = nullptr; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/loader/itemreader.cpp0000644000175100001660000002313414776170045021522 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "itemreader.h" #include "itemreadervisitorstate.h" #include "loaderutils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static void makePathsCanonical(QStringList &paths) { Internal::removeIf(paths, [](QString &p) { p = QFileInfo(p).canonicalFilePath(); return p.isEmpty(); }); } ItemReader::ItemReader(LoaderState &loaderState) : m_loaderState(loaderState) {} void ItemReader::init() { m_visitorState = std::make_unique( m_loaderState.topLevelProject().itemReaderCache(), m_loaderState.logger()); m_visitorState->setDeprecationWarningMode(m_loaderState.parameters().deprecationWarningMode()); m_projectFilePath = m_loaderState.parameters().projectFilePath(); setSearchPaths(m_loaderState.parameters().searchPaths()); m_elapsedTime = m_loaderState.parameters().logElapsedTime() ? 0 : -1; } ItemReader::~ItemReader() = default; void ItemReader::setSearchPaths(const QStringList &searchPaths) { qCDebug(lcModuleLoader) << "initial search paths:" << searchPaths; m_searchPaths = searchPaths; makePathsCanonical(m_searchPaths); m_allSearchPaths.clear(); } void ItemReader::pushExtraSearchPaths(const QStringList &extraSearchPaths) { m_extraSearchPaths.push_back(extraSearchPaths); makePathsCanonical(m_extraSearchPaths.back()); m_allSearchPaths.clear(); } void ItemReader::popExtraSearchPaths() { m_extraSearchPaths.pop_back(); m_allSearchPaths.clear(); } const std::vector &ItemReader::extraSearchPathsStack() const { return m_extraSearchPaths; } void ItemReader::setExtraSearchPathsStack(const std::vector &s) { m_extraSearchPaths = s; m_allSearchPaths.clear(); } void ItemReader::clearExtraSearchPathsStack() { m_extraSearchPaths.clear(); m_allSearchPaths.clear(); } const QStringList &ItemReader::allSearchPaths() const { if (m_allSearchPaths.empty()) { std::for_each(m_extraSearchPaths.crbegin(), m_extraSearchPaths.crend(), [this] (const QStringList &paths) { m_allSearchPaths += paths; }); m_allSearchPaths += m_searchPaths; m_allSearchPaths.removeDuplicates(); } return m_allSearchPaths; } Item *ItemReader::readFile(const QString &filePath) { AccumulatingTimer readFileTimer(m_elapsedTime != -1 ? &m_elapsedTime : nullptr); return m_visitorState->readFile(filePath, allSearchPaths(), &m_loaderState.itemPool()); } Item *ItemReader::readFile(const QString &filePath, const CodeLocation &referencingLocation) { try { return readFile(filePath); } catch (const ErrorInfo &e) { if (e.hasLocation()) throw; throw ErrorInfo(e.toString(), referencingLocation); } } void ItemReader::handlePropertyOptions(Item *optionsItem) { Evaluator &evaluator = m_loaderState.evaluator(); const QString name = evaluator.stringValue(optionsItem, StringConstants::nameProperty()); if (name.isEmpty()) { throw ErrorInfo(Tr::tr("PropertyOptions item needs a name property"), optionsItem->location()); } const QString description = evaluator.stringValue( optionsItem, StringConstants::descriptionProperty()); const auto removalVersion = Version::fromString( evaluator.stringValue(optionsItem, StringConstants::removalVersionProperty())); const auto allowedValues = evaluator.stringListValue( optionsItem, StringConstants::allowedValuesProperty()); PropertyDeclaration decl = optionsItem->parent()->propertyDeclaration(name); if (!decl.isValid()) { decl.setName(name); decl.setType(PropertyDeclaration::Variant); } decl.setDescription(description); if (removalVersion.isValid()) { DeprecationInfo di(removalVersion, description); decl.setDeprecationInfo(di); } decl.setAllowedValues(allowedValues); const ValuePtr property = optionsItem->parent()->property(name); if (!property && !decl.isExpired()) { throw ErrorInfo(Tr::tr("PropertyOptions item refers to non-existing property '%1'") .arg(name), optionsItem->location()); } if (property && decl.isExpired()) { ErrorInfo e(Tr::tr("Property '%1' was scheduled for removal in version %2, but " "is still present.") .arg(name, removalVersion.toString()), property->location()); e.append(Tr::tr("Removal version for '%1' specified here.").arg(name), optionsItem->location()); m_visitorState->logger().printWarning(e); } optionsItem->parent()->setPropertyDeclaration(name, decl); } void ItemReader::handleAllPropertyOptionsItems(Item *item) { QList childItems = item->children(); auto childIt = childItems.begin(); while (childIt != childItems.end()) { Item * const child = *childIt; if (child->type() == ItemType::PropertyOptions) { handlePropertyOptions(child); childIt = childItems.erase(childIt); } else { handleAllPropertyOptionsItems(child); ++childIt; } } item->setChildren(childItems); } Item *ItemReader::setupItemFromFile(const QString &filePath, const CodeLocation &referencingLocation) { Item *item = readFile(filePath, referencingLocation); // This is technically not needed, because files are only set up once and then served // from a cache. But it simplifies the checks in item.cpp if we require the locking invariant // to always hold. std::unique_ptr locker; if (item->type() == ItemType::Module) locker = std::make_unique(*item); handleAllPropertyOptionsItems(item); return item; } Item *ItemReader::wrapInProjectIfNecessary(Item *item) { if (item->type() == ItemType::Project) return item; Item *prj = Item::create(&m_loaderState.itemPool(), ItemType::Project); Item::addChild(prj, item); prj->setFile(item->file()); prj->setLocation(item->location()); prj->setupForBuiltinType(m_loaderState.parameters().deprecationWarningMode(), m_visitorState->logger()); return prj; } QStringList ItemReader::readExtraSearchPaths(Item *item, bool *wasSet) { QStringList result; const QStringList paths = m_loaderState.evaluator().stringListValue( item, StringConstants::qbsSearchPathsProperty(), wasSet); const JSSourceValueConstPtr prop = item->sourceProperty( StringConstants::qbsSearchPathsProperty()); // Value can come from within a project file or as an overridden value from the user // (e.g command line). const QString basePath = FileInfo::path(prop ? prop->file()->filePath() : m_projectFilePath); for (const QString &path : paths) result += FileInfo::resolvePath(basePath, path); return result; } SearchPathsManager::SearchPathsManager(ItemReader &itemReader, const QStringList &extraSearchPaths) : m_itemReader(itemReader), m_oldSize(itemReader.extraSearchPathsStack().size()) { if (!extraSearchPaths.isEmpty()) m_itemReader.pushExtraSearchPaths(extraSearchPaths); } SearchPathsManager::~SearchPathsManager() { while (m_itemReader.extraSearchPathsStack().size() > m_oldSize) m_itemReader.popExtraSearchPaths(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/productsresolver.h0000644000175100001660000000375314776170045022500 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once namespace qbs::Internal { class LoaderState; void resolveProducts(LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/projectresolver.h0000644000175100001660000000574714776170045022310 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PROJECTRESOLVER_H #define PROJECTRESOLVER_H #include #include #include #include #include #include #include namespace qbs { class SetupProjectParameters; namespace Internal { class FileTime; class Logger; class ProgressObserver; class ScriptEngine; class StoredModuleProviderInfo; class QBS_AUTOTEST_EXPORT ProjectResolver { public: ProjectResolver(const SetupProjectParameters ¶meters, ScriptEngine *engine, Logger logger); ~ProjectResolver(); void setProgressObserver(ProgressObserver *observer); void setOldProjectProbes(const std::vector &oldProbes); void setOldProductProbes(const QHash> &oldProbes); void setLastResolveTime(const FileTime &time); void setStoredProfiles(const QVariantMap &profiles); void setStoredModuleProviderInfo(const StoredModuleProviderInfo &providerInfo); TopLevelProjectPtr resolve(); private: class Private; Pimpl d; }; } // namespace Internal } // namespace qbs #endif // PROJECTRESOLVER_H qbs-src-2.6.1/src/lib/corelib/loader/projectresolver.cpp0000644000175100001660000005745014776170045022641 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "projectresolver.h" #include "itemreader.h" #include "loaderutils.h" #include "productscollector.h" #include "productsresolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static SetupProjectParameters finalizedProjectParameters(const SetupProjectParameters &in, Logger &logger) { SetupProjectParameters params = in; if (params.topLevelProfile().isEmpty()) { Settings settings(params.settingsDirectory()); QString profileName = settings.defaultProfile(); if (profileName.isEmpty()) { logger.qbsDebug() << Tr::tr("No profile specified and no default profile exists. " "Using default property values."); profileName = Profile::fallbackName(); } params.setTopLevelProfile(profileName); params.expandBuildConfiguration(); } params.finalizeProjectFilePath(); QBS_CHECK(QFileInfo(params.projectFilePath()).isAbsolute()); QBS_CHECK(FileInfo::isAbsolute(params.buildRoot())); return params; } class ProjectResolver::Private { public: Private(const SetupProjectParameters ¶meters, ScriptEngine *engine, Logger &&logger) : setupParams(finalizedProjectParameters(parameters, logger)), engine(engine), logger(std::move(logger)) {} TopLevelProjectPtr resolveTopLevelProject(); void resolveProject(ProjectContext *projectContext); void resolveProjectFully(ProjectContext *projectContext); void resolveSubProject(Item *item, ProjectContext *projectContext); void checkOverriddenValues(); void collectNameFromOverride(const QString &overrideString); void loadTopLevelProjectItem(); void buildProjectTree(); void printProfilingInfo(); const SetupProjectParameters setupParams; ScriptEngine * const engine; mutable Logger logger; ItemPool itemPool; TopLevelProjectContext topLevelProject; LoaderState state{setupParams, topLevelProject, itemPool, *engine, logger}; Item *rootProjectItem = nullptr; }; ProjectResolver::ProjectResolver(const SetupProjectParameters ¶meters, ScriptEngine *engine, Logger logger) : d(makePimpl(parameters, engine, std::move(logger))) { d->logger.storeWarnings(); } ProjectResolver::~ProjectResolver() = default; void ProjectResolver::setProgressObserver(ProgressObserver *observer) { d->state.topLevelProject().setProgressObserver(observer); } void ProjectResolver::setOldProjectProbes(const std::vector &oldProbes) { d->state.topLevelProject().setOldProjectProbes(oldProbes); } void ProjectResolver::setOldProductProbes( const QHash> &oldProbes) { d->state.topLevelProject().setOldProductProbes(oldProbes); } void ProjectResolver::setLastResolveTime(const FileTime &time) { d->state.topLevelProject().setLastResolveTime(time); } void ProjectResolver::setStoredProfiles(const QVariantMap &profiles) { d->state.topLevelProject().setProfileConfigs(profiles); } void ProjectResolver::setStoredModuleProviderInfo(const StoredModuleProviderInfo &providerInfo) { d->state.topLevelProject().setModuleProvidersCache(providerInfo.providers); } static void checkForDuplicateProductNames(const TopLevelProjectConstPtr &project) { const std::vector allProducts = project->allProducts(); for (size_t i = 0; i < allProducts.size(); ++i) { const ResolvedProductConstPtr product1 = allProducts.at(i); const QString productName = product1->uniqueName(); for (size_t j = i + 1; j < allProducts.size(); ++j) { const ResolvedProductConstPtr product2 = allProducts.at(j); if (product2->uniqueName() == productName) { ErrorInfo error; error.append(Tr::tr("Duplicate product name '%1'.").arg(product1->name)); error.append(Tr::tr("First product defined here."), product1->location); error.append(Tr::tr("Second product defined here."), product2->location); throw error; } } } } TopLevelProjectPtr ProjectResolver::resolve() { qCDebug(lcProjectResolver) << "resolving" << d->setupParams.projectFilePath(); d->engine->setEnvironment(d->setupParams.adjustedEnvironment()); d->engine->checkAndClearException({}); d->engine->clearImportsCache(); d->engine->clearRequestedProperties(); d->engine->enableProfiling(d->setupParams.logElapsedTime()); d->logger.clearWarnings(); EvalContextSwitcher evalContextSwitcher(d->engine, EvalContext::PropertyEvaluation); // At this point, we cannot set a sensible total effort, because we know nothing about // the project yet. That's why we use a placeholder here, so the user at least // sees that an operation is starting. The real total effort will be set later when // we have enough information. if (ProgressObserver * const observer = d->state.topLevelProject().progressObserver()) { observer->initialize(Tr::tr("Resolving project for configuration %1") .arg(TopLevelProject::deriveId(d->setupParams.finalBuildConfigurationTree())), 1); observer->addScriptEngine(d->engine); } const FileTime resolveTime = FileTime::currentTime(); TopLevelProjectPtr tlp; try { d->checkOverriddenValues(); d->loadTopLevelProjectItem(); d->buildProjectTree(); tlp = d->resolveTopLevelProject(); } catch (const CancelException &) { throw ErrorInfo(Tr::tr("Project resolving canceled for configuration '%1'.") .arg(TopLevelProject::deriveId( d->setupParams.finalBuildConfigurationTree()))); } tlp->lastStartResolveTime = resolveTime; tlp->lastEndResolveTime = FileTime::currentTime(); // E.g. if the top-level project is disabled. if (ProgressObserver * const observer = d->state.topLevelProject().progressObserver()) { observer->setFinished(); d->printProfilingInfo(); } return tlp; } static void makeSubProjectNamesUniqe(const ResolvedProjectPtr &parentProject) { Set subProjectNames; Set projectsInNeedOfNameChange; for (const ResolvedProjectPtr &p : std::as_const(parentProject->subProjects)) { if (!subProjectNames.insert(p->name).second) projectsInNeedOfNameChange << p; makeSubProjectNamesUniqe(p); } while (!projectsInNeedOfNameChange.empty()) { auto it = projectsInNeedOfNameChange.begin(); while (it != projectsInNeedOfNameChange.end()) { const ResolvedProjectPtr p = *it; p->name += QLatin1Char('_'); if (subProjectNames.insert(p->name).second) { it = projectsInNeedOfNameChange.erase(it); } else { ++it; } } } } TopLevelProjectPtr ProjectResolver::Private::resolveTopLevelProject() { if (ProgressObserver * const observer = state.topLevelProject().progressObserver()) observer->setMaximum(state.topLevelProject().productCount()); TopLevelProjectPtr project = TopLevelProject::create(); project->buildDirectory = TopLevelProject::deriveBuildDirectory( setupParams.buildRoot(), TopLevelProject::deriveId(setupParams.finalBuildConfigurationTree())); if (!state.topLevelProject().projects().empty()) { ProjectContext * const projectContext = state.topLevelProject().projects().front(); QBS_CHECK(projectContext->item == rootProjectItem); projectContext->project = project; resolveProject(projectContext); } resolveProducts(state); ErrorInfo accumulatedErrors; { const auto queuedErrors = state.topLevelProject().queuedErrors(); for (const ErrorInfo &e : queuedErrors.get()) appendError(accumulatedErrors, e); } if (accumulatedErrors.hasError()) throw accumulatedErrors; project->buildSystemFiles.unite(state.topLevelProject().buildSystemFiles()); project->profileConfigs = state.topLevelProject().profileConfigs(); project->codeLinks = state.topLevelProject().codeLinks(); const QVariantMap &profiles = state.topLevelProject().localProfiles(); for (auto it = profiles.begin(); it != profiles.end(); ++it) project->profileConfigs.remove(it.key()); project->probes = state.topLevelProject().projectLevelProbes(); project->moduleProviderInfo.providers = state.topLevelProject().moduleProvidersCache(); project->setBuildConfiguration(setupParams.finalBuildConfigurationTree()); project->overriddenValues = setupParams.overriddenValues(); state.topLevelProject().collectDataFromEngine(*engine); makeSubProjectNamesUniqe(project); checkForDuplicateProductNames(project); project->warningsEncountered << logger.warnings(); project->errorsEncountered << logger.errors(); return project; } void ProjectResolver::Private::resolveProject(ProjectContext *projectContext) { state.topLevelProject().checkCancelation(); if (projectContext->parent) { projectContext->project = ResolvedProject::create(); projectContext->parent->project->subProjects.push_back(projectContext->project); projectContext->project->parentProject = projectContext->parent->project; projectContext->project->enabled = projectContext->parent->project->enabled; } projectContext->project->location = projectContext->item->location(); try { resolveProjectFully(projectContext); } catch (const ErrorInfo &error) { if (!projectContext->project->enabled) { qCDebug(lcProjectResolver) << "error resolving project" << projectContext->project->location << error.toString(); return; } if (setupParams.productErrorMode() == ErrorHandlingMode::Strict) throw; logger.printError(error); } } void ProjectResolver::Private::resolveProjectFully(ProjectContext *projectContext) { Item * const item = projectContext->item; projectContext->project->enabled = projectContext->project->enabled && state.evaluator().boolValue(item, StringConstants::conditionProperty()); projectContext->project->name = state.evaluator().stringValue( item, StringConstants::nameProperty()); if (projectContext->project->name.isEmpty()) projectContext->project->name = FileInfo::baseName(item->location().filePath()); // FIXME: Must also be changed in item? QVariantMap projectProperties; if (!projectContext->project->enabled) { projectProperties.insert(StringConstants::profileProperty(), state.evaluator().stringValue( item, StringConstants::profileProperty())); projectContext->project->setProjectProperties(projectProperties); return; } projectContext->dummyModule = ResolvedModule::create(); for (Item::PropertyDeclarationMap::const_iterator it = item->propertyDeclarations().constBegin(); it != item->propertyDeclarations().constEnd(); ++it) { if (it.value().flags().testFlag(PropertyDeclaration::PropertyNotAvailableInConfig)) continue; const ValueConstPtr v = item->property(it.key()); QBS_ASSERT(v && v->type() != Value::ItemValueType, continue); const ScopedJsValue sv(engine->context(), state.evaluator().value(item, it.key())); projectProperties.insert(it.key(), getJsVariant(engine->context(), sv)); } projectContext->project->setProjectProperties(projectProperties); for (Item * const child : item->children()) { state.topLevelProject().checkCancelation(); try { switch (child->type()) { case ItemType::SubProject: resolveSubProject(child, projectContext); break; case ItemType::FileTagger: resolveFileTagger(state, child, projectContext, nullptr); break; case ItemType::JobLimit: resolveJobLimit(state, child, projectContext, nullptr, nullptr); break; case ItemType::Rule: resolveRule(state, child, projectContext, nullptr, nullptr); break; default: break; } } catch (const ErrorInfo &e) { state.topLevelProject().addQueuedError(e); } } for (ProjectContext * const childContext : projectContext->children) resolveProject(childContext); } void ProjectResolver::Private::resolveSubProject(Item *item, ProjectContext *projectContext) { // If we added a Project child item in ProductsCollector, then the sub-project will be // resolved normally via resolveProject(). Otherwise, it was not loaded, for instance // because its Properties condition was false, and special handling applies. if (item->child(ItemType::Project)) return; ResolvedProjectPtr project = ResolvedProject::create(); project->enabled = false; project->parentProject = projectContext->project; projectContext->project->subProjects << project; if (Item * const propertiesItem = item->child(ItemType::PropertiesInSubProject)) { project->name = state.evaluator().stringValue(propertiesItem, StringConstants::nameProperty()); } } void ProjectResolver::Private::checkOverriddenValues() { static const auto matchesPrefix = [](const QString &key) { static const QStringList prefixes({StringConstants::projectPrefix(), QStringLiteral("projects"), QStringLiteral("products"), QStringLiteral("modules"), StringConstants::moduleProviders(), StringConstants::qbsModule()}); return any_of(prefixes, [&key](const QString &prefix) { return key.startsWith(prefix + QLatin1Char('.')); }); }; const QVariantMap &overriddenValues = state.parameters().overriddenValues(); for (auto it = overriddenValues.begin(); it != overriddenValues.end(); ++it) { if (matchesPrefix(it.key())) { collectNameFromOverride(it.key()); continue; } ErrorInfo e(Tr::tr("Property override key '%1' not understood.").arg(it.key())); e.append(Tr::tr("Please use one of the following:")); e.append(QLatin1Char('\t') + Tr::tr("projects..:value")); e.append(QLatin1Char('\t') + Tr::tr("products..:value")); e.append(QLatin1Char('\t') + Tr::tr("modules..:value")); e.append(QLatin1Char('\t') + Tr::tr("products..." ":value")); e.append(QLatin1Char('\t') + Tr::tr("moduleProviders.." ":value")); handlePropertyError(e, state.parameters(), state.logger()); } } void ProjectResolver::Private::collectNameFromOverride(const QString &overrideString) { const auto extract = [&overrideString](const QString &prefix) { if (!overrideString.startsWith(prefix)) return QString(); const int startPos = prefix.length(); const int endPos = overrideString.lastIndexOf(StringConstants::dot()); if (endPos == -1) return QString(); return overrideString.mid(startPos, endPos - startPos); }; const QString &projectName = extract(StringConstants::projectsOverridePrefix()); if (!projectName.isEmpty()) { state.topLevelProject().addProjectNameUsedInOverrides(projectName); return; } const QString &productName = extract(StringConstants::productsOverridePrefix()); if (!productName.isEmpty()) { state.topLevelProject().addProductNameUsedInOverrides(productName.left( productName.indexOf(StringConstants::dot()))); return; } } void ProjectResolver::Private::loadTopLevelProjectItem() { const QStringList topLevelSearchPaths = state.parameters().finalBuildConfigurationTree() .value(StringConstants::projectPrefix()).toMap() .value(StringConstants::qbsSearchPathsProperty()).toStringList(); SearchPathsManager searchPathsManager(state.itemReader(), topLevelSearchPaths); Item * const root = state.itemReader().setupItemFromFile( state.parameters().projectFilePath(), {}); if (!root) return; switch (root->type()) { case ItemType::Product: rootProjectItem = state.itemReader().wrapInProjectIfNecessary(root); break; case ItemType::Project: rootProjectItem = root; break; default: throw ErrorInfo(Tr::tr("The top-level item must be of type 'Project' or 'Product', but it" " is of type '%1'.").arg(root->typeName()), root->location()); } } void ProjectResolver::Private::buildProjectTree() { state.topLevelProject().setBuildDirectory(TopLevelProject::deriveBuildDirectory( state.parameters().buildRoot(), TopLevelProject::deriveId(state.parameters().finalBuildConfigurationTree()))); rootProjectItem->setProperty(StringConstants::sourceDirectoryProperty(), VariantValue::create(QFileInfo(rootProjectItem->file()->filePath()) .absolutePath())); rootProjectItem->setProperty(StringConstants::buildDirectoryProperty(), VariantValue::create(state.topLevelProject().buildDirectory())); rootProjectItem->setProperty(StringConstants::profileProperty(), VariantValue::create(state.parameters().topLevelProfile())); ProductsCollector(state).run(rootProjectItem); AccumulatingTimer timer(state.parameters().logElapsedTime() ? &state.topLevelProject().timingData().propertyChecking : nullptr); checkPropertyDeclarations(rootProjectItem, state); } void ProjectResolver::Private::printProfilingInfo() { if (!setupParams.logElapsedTime()) return; const auto print = [this](int indent, const QString &pattern, qint64 time) { logger.qbsLog(LoggerInfo, true) << QByteArray(indent, ' ') << pattern.arg(elapsedTimeString(time)); }; print(2, Tr::tr("Project file loading and parsing took %1."), state.itemReader().elapsedTime()); print(2, Tr::tr("Preparing products took %1."), state.topLevelProject().timingData().preparingProducts); print(2, Tr::tr("Setting up Groups took %1."), state.topLevelProject().timingData().groupsSetup); print(2, Tr::tr("Scheduling products took %1."), state.topLevelProject().timingData().schedulingProducts); print(2, Tr::tr("Resolving products took %1."), state.topLevelProject().timingData().resolvingProducts); print(4, Tr::tr("Property evaluation took %1."), state.topLevelProject().timingData().propertyEvaluation); print(4, Tr::tr("Resolving groups (without module property evaluation) took %1."), state.topLevelProject().timingData().groupsResolving); print(4, Tr::tr("Setting up product dependencies took %1."), state.topLevelProject().timingData().dependenciesResolving); print(6, Tr::tr("Running module providers took %1."), state.topLevelProject().timingData().moduleProviders); print(6, Tr::tr("Instantiating modules took %1."), state.topLevelProject().timingData().moduleInstantiation); print(6, Tr::tr("Merging module property values took %1."), state.topLevelProject().timingData().propertyMerging); logger.qbsLog(LoggerInfo, true) << QByteArray(4, ' ') << "There were " << state.topLevelProject().productDeferrals() << " product deferrals with a total of " << state.topLevelProject().productCount() << " products."; print(2, Tr::tr("Running Probes took %1."), state.topLevelProject().timingData().probes); state.logger().qbsLog(LoggerInfo, true) << " " << Tr::tr("%1 probes encountered, %2 configure scripts executed, " "%3 re-used from current run, %4 re-used from earlier run.") .arg(state.topLevelProject().probesEncounteredCount()) .arg(state.topLevelProject().probesRunCount()) .arg(state.topLevelProject().reusedCurrentProbesCount()) .arg(state.topLevelProject().reusedOldProbesCount()); print(2, Tr::tr("Property checking took %1."), state.topLevelProject().timingData().propertyChecking); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/loaderutils.h0000644000175100001660000004526014776170045021401 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { class SetupProjectParameters; namespace Internal { class Evaluator; class ItemPool; class ItemReader; class Logger; class ProductContext; class ProgressObserver; class ProjectContext; class ScriptEngine; using ModulePropertiesPerGroup = std::unordered_map; using FileLocations = QHash, CodeLocation>; enum class Deferral { Allowed, NotAllowed }; enum class ProductDependency { None, Single, Bulk }; class CancelException { }; template struct GuardedData { DataType data; mutable MutexType mutex; }; class TimingData { public: TimingData &operator+=(const TimingData &other); qint64 dependenciesResolving = 0; qint64 moduleProviders = 0; qint64 moduleInstantiation = 0; qint64 propertyMerging = 0; qint64 groupsSetup = 0; qint64 groupsResolving = 0; qint64 preparingProducts = 0; qint64 resolvingProducts = 0; qint64 schedulingProducts = 0; qint64 probes = 0; qint64 propertyEvaluation = 0; qint64 propertyChecking = 0; }; class ItemReaderCache { public: class AstCacheEntry { public: QString code; QbsQmlJS::Engine engine; QbsQmlJS::AST::UiProgram *ast = nullptr; bool addProcessingThread(); void removeProcessingThread(); private: MutexData, std::recursive_mutex> m_processingThreads; }; const Set &filesRead() const { return m_filesRead; } AstCacheEntry &retrieveOrSetupCacheEntry(const QString &filePath, const std::function &setup); const QStringList &retrieveOrSetDirectoryEntries( const QString &dir, const std::function &findOnDisk); private: Set m_filesRead; MutexData>, std::mutex> m_directoryEntries; // TODO: Merge with module dir entries cache? MutexData, std::mutex> m_astCache; }; class DependenciesContext { public: virtual ~DependenciesContext(); virtual std::pair pendingDependency() const = 0; bool dependenciesResolved = false; }; class ProductContext { public: QString uniqueName() const; QString displayName() const; void handleError(const ErrorInfo &error); bool dependenciesResolvingPending() const; std::pair pendingDependency() const; QString name; QString buildDirectory; Item *item = nullptr; Item *scope = nullptr; ProjectContext *project = nullptr; std::unique_ptr shadowProduct; Item *mergedExportItem = nullptr; std::vector probes; ModulePropertiesPerGroup modulePropertiesSetInGroups; ErrorInfo delayedError; QString profileName; QString multiplexConfigurationId; QVariantMap profileModuleProperties; // Tree-ified module properties from profile. QVariantMap moduleProperties; // Tree-ified module properties from profile + overridden values. std::optional providerConfig; std::optional providerQbsModule; QVariantMap defaultParameters; // In Export item. QStringList searchPaths; ResolvedProductPtr product; TimingData timingData; std::unique_ptr dependenciesContext; // This is needed because complex cyclic dependencies that involve Depends.productTypes // may only be detected after a product has already been fully resolved. std::vector> bulkDependencies; // The keys are module prototypes, the values specify whether the module's // condition is true for this product. std::unordered_map modulePrototypeEnabledInfo; int dependsItemCount = -1; }; class TopLevelProjectContext { public: TopLevelProjectContext() = default; TopLevelProjectContext(const TopLevelProjectContext &) = delete; TopLevelProjectContext &operator=(const TopLevelProjectContext &) = delete; ~TopLevelProjectContext(); bool checkItemCondition(Item *item, Evaluator &evaluator); QString sourceCodeForEvaluation(const JSSourceValueConstPtr &value); ScriptFunctionPtr scriptFunctionValue(Item *item, const QString &name); QString sourceCodeAsFunction(const JSSourceValueConstPtr &value, const PropertyDeclaration &decl); void setCanceled() { m_canceled = true; } void checkCancelation(); bool isCanceled() const { return m_canceled; } int productCount() const { return m_productsByName.size(); } void addProductToHandle(const ProductContext &product) { m_productsToHandle.data << &product; } void removeProductToHandle(const ProductContext &product); bool isProductQueuedForHandling(const ProductContext &product) const; int productsToHandleCount() const { return m_productsToHandle.data.size(); } void addDisabledItem(Item *item); bool isDisabledItem(const Item *item) const; void setProgressObserver(ProgressObserver *observer); ProgressObserver *progressObserver() const; void addProject(ProjectContext *project) { m_projects.push_back(project); } const std::vector &projects() const { return m_projects; } using QueuedErrors = MutexData, std::mutex>; void addQueuedError(const ErrorInfo &error); QueuedErrors::UniqueConstGuard queuedErrors() const { return m_queuedErrors.lock(); } void setProfileConfigs(const QVariantMap &profileConfigs) { m_profileConfigs = profileConfigs; } void addProfileConfig(const QString &profileName, const QVariantMap &profileConfig); const QVariantMap &profileConfigs() const { return m_profileConfigs; } std::optional profileConfig(const QString &profileName) const; void addProduct(ProductContext &product); void addProductByType(ProductContext &product, const FileTags &tags); ProductContext *productWithNameAndConstraint( const QString &name, const std::function &constraint); std::vector productsWithNameAndConstraint( const QString &name, const std::function &constraint); std::vector productsWithTypeAndConstraint( const FileTags &tags, const std::function &constraint); std::vector> finishedProductsWithBulkDependency(const FileTag &tag) const; void registerBulkDependencies(ProductContext &product); void addProjectNameUsedInOverrides(const QString &name); const Set &projectNamesUsedInOverrides() const; void addProductNameUsedInOverrides(const QString &name); const Set &productNamesUsedInOverrides() const; void setBuildDirectory(const QString &buildDir) { m_buildDirectory = buildDir; } const QString &buildDirectory() const { return m_buildDirectory; } void addMultiplexConfiguration(const QString &id, const QVariantMap &config); QVariantMap multiplexConfiguration(const QString &id) const; void setLastResolveTime(const FileTime &time) { m_lastResolveTime = time; } const FileTime &lastResolveTime() const { return m_lastResolveTime; } Set buildSystemFiles() const { return m_itemReaderCache.filesRead(); } std::lock_guard moduleProvidersCacheLock(); void setModuleProvidersCache(const ModuleProvidersCache &cache); const ModuleProvidersCache &moduleProvidersCache() const { return m_moduleProvidersCache; } ModuleProviderInfo *moduleProvider(const ModuleProvidersCacheKey &key); ModuleProviderInfo &addModuleProvider(const ModuleProvidersCacheKey &key, const ModuleProviderInfo &provider); void addParameterDeclarations(const Item *moduleProto, const Item::PropertyDeclarationMap &decls); Item::PropertyDeclarationMap parameterDeclarations(Item *moduleProto) const; void setParameters(const Item *moduleProto, const QVariantMap ¶meters); QVariantMap parameters(Item *moduleProto) const; void addCodeLink(const QString &sourceFile, const CodeRange &sourceRange, const CodeLocation &target); CodeLinks codeLinks() const { return m_codeLinks.lock().get(); } // An empty string means no matching module directory was found. QString findModuleDirectory(const QualifiedId &module, const QString &searchPath, const std::function &findOnDisk); QStringList getModuleFilesForDirectory(const QString &dir, const std::function &findOnDisk); void removeModuleFileFromDirectoryCache(const QString &filePath); void addUnknownProfilePropertyError(const Item *moduleProto, const ErrorInfo &error); const std::vector &unknownProfilePropertyErrors(const Item *moduleProto) const; Item *getModulePrototype(const QString &filePath, const QString &profile, const std::function &produce); void addLocalProfile(const QString &name, const QVariantMap &values, const CodeLocation &location); const QVariantMap localProfiles() { return m_localProfiles; } void checkForLocalProfileAsTopLevelProfile(const QString &topLevelProfile); using ProbeFilter = std::function; std::lock_guard probesCacheLock(); void setOldProjectProbes(const std::vector &oldProbes); void setOldProductProbes(const QHash> &oldProbes); void addNewlyResolvedProbe(const ProbeConstPtr &probe); void addProjectLevelProbe(const ProbeConstPtr &probe); const std::vector projectLevelProbes() const; ProbeConstPtr findOldProjectProbe(const QString &id, const ProbeFilter &filter) const; ProbeConstPtr findOldProductProbe(const QString &productName, const ProbeFilter &filter) const; ProbeConstPtr findCurrentProbe(const CodeLocation &location, const ProbeFilter &filter) const; void incrementProbesCount() { ++m_probesInfo.probesEncountered; } void incrementReusedCurrentProbesCount() { ++m_probesInfo.probesCachedCurrent; } void incrementReusedOldProbesCount() { ++m_probesInfo.probesCachedOld; } void incrementRunProbesCount() { ++m_probesInfo.probesRun; } int probesEncounteredCount() const { return m_probesInfo.probesEncountered; } int probesRunCount() const { return m_probesInfo.probesRun; } int reusedOldProbesCount() const { return m_probesInfo.probesCachedOld; } int reusedCurrentProbesCount() const { return m_probesInfo.probesCachedCurrent; } TimingData &timingData() { return m_timingData; } ItemReaderCache &itemReaderCache() { return m_itemReaderCache; } void incProductDeferrals() { ++m_productDeferrals; } int productDeferrals() const { return m_productDeferrals; } void collectDataFromEngine(const ScriptEngine &engine); ItemPool &createItemPool(); private: const ResolvedFileContextPtr &resolvedFileContext(const FileContextConstPtr &ctx); std::vector m_projects; GuardedData> m_productsToHandle; std::multimap m_productsByName; MutexData, std::mutex> m_sourceCode; std::unordered_map m_multiplexConfigsById; MutexData, std::mutex> m_scriptFunctionMap; MutexData, QString>, std::mutex> m_scriptFunctions; std::unordered_map m_fileContextMap; Set m_projectNamesUsedInOverrides; Set m_productNamesUsedInOverrides; MutexData> m_disabledItems; QueuedErrors m_queuedErrors; QString m_buildDirectory; QVariantMap m_profileConfigs; ProgressObserver *m_progressObserver = nullptr; TimingData m_timingData; ModuleProvidersCache m_moduleProvidersCache; std::mutex m_moduleProvidersCacheMutex; QVariantMap m_localProfiles; ItemReaderCache m_itemReaderCache; QHash>> m_reverseBulkDependencies; // For fast look-up when resolving Depends.productTypes. // The contract is that it contains fully handled, error-free, enabled products. MutexData> m_productsByType; // The keys are module prototypes. MutexData> m_parameterDeclarations; MutexData> m_parameters; MutexData>> m_unknownProfilePropertyErrors; // The keys are search path + module name, the values are directories. MutexData, std::optional>, std::mutex> m_modulePathCache; // The keys are file paths, the values are module prototype items accompanied by a profile. MutexData>>, std::mutex> m_modulePrototypes; MutexData>, std::mutex> m_moduleFilesPerDirectory; MutexData m_codeLinks; struct { QHash> oldProjectProbes; QHash> oldProductProbes; QHash> currentProbes; std::vector projectLevelProbes; quint64 probesEncountered = 0; quint64 probesRun = 0; quint64 probesCachedCurrent = 0; quint64 probesCachedOld = 0; } m_probesInfo; std::mutex m_probesMutex; std::vector> m_itemPools; FileTime m_lastResolveTime; std::atomic_bool m_canceled = false; int m_productDeferrals = 0; }; class ProjectContext { public: QString name; Item *item = nullptr; Item *scope = nullptr; TopLevelProjectContext *topLevelProject = nullptr; ProjectContext *parent = nullptr; std::vector children; std::vector products; std::vector searchPathsStack; ResolvedProjectPtr project; std::vector fileTaggers; std::vector rules; JobLimits jobLimits; ResolvedModulePtr dummyModule; }; class ModuleContext { public: ResolvedModulePtr module; JobLimits jobLimits; }; class LoaderState { public: LoaderState(const SetupProjectParameters ¶meters, TopLevelProjectContext &topLevelProject, ItemPool &itemPool, ScriptEngine &engine, Logger logger); ~LoaderState(); Evaluator &evaluator(); ItemPool &itemPool(); ItemReader &itemReader(); Logger &logger(); const SetupProjectParameters ¶meters() const; TopLevelProjectContext &topLevelProject(); private: class Private; Pimpl d; }; // List must be sorted by priority in ascending order. [[nodiscard]] QVariantMap mergeDependencyParameters( std::vector &&candidates); [[nodiscard]] QVariantMap mergeDependencyParameters(const QVariantMap &m1, const QVariantMap &m2); QString fullProductDisplayName(const QString &name, const QString &multiplexId); void adjustParametersScopes(Item *item, Item *scope); void resolveRule(LoaderState &state, Item *item, ProjectContext *projectContext, ProductContext *productContext, ModuleContext *moduleContext); void resolveJobLimit(LoaderState &state, Item *item, ProjectContext *projectContext, ProductContext *productContext, ModuleContext *moduleContext); void resolveFileTagger(LoaderState &state, Item *item, ProjectContext *projectContext, ProductContext *productContext); const FileTag unknownFileTag(); } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/itemreaderastvisitor.h0000644000175100001660000000766114776170045023326 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMREADERASTVISITOR_H #define QBS_ITEMREADERASTVISITOR_H #include #include #include #include #include #include #include namespace qbs { class CodeLocation; namespace Internal { class Item; class ItemPool; class ItemReaderVisitorState; class ModuleItemLocker; class ItemReaderASTVisitor : public QbsQmlJS::AST::Visitor { public: ItemReaderASTVisitor(ItemReaderVisitorState &visitorState, FileContextPtr file, ItemPool *itemPool, Logger &logger); ~ItemReaderASTVisitor(); void checkItemTypes() { doCheckItemTypes(rootItem()); } Item *rootItem() const { return m_item; } private: bool visit(QbsQmlJS::AST::UiProgram *uiProgram) override; bool visit(QbsQmlJS::AST::UiObjectDefinition *ast) override; bool visit(QbsQmlJS::AST::UiPublicMember *ast) override; bool visit(QbsQmlJS::AST::UiScriptBinding *ast) override; bool handleBindingRhs(QbsQmlJS::AST::Statement *statement, const JSSourceValuePtr &value); CodeLocation toCodeLocation(const QbsQmlJS::AST::SourceLocation &location) const; void checkDuplicateBinding(Item *item, const QStringList &bindingName, const QbsQmlJS::AST::SourceLocation &sourceLocation); Item *targetItemForBinding(const QStringList &binding, const JSSourceValueConstPtr &value); static void inheritItem(Item *dst, const Item *src); void checkDeprecationStatus(ItemType itemType, const QString &itemName, const CodeLocation &itemLocation); void doCheckItemTypes(const Item *item); ItemReaderVisitorState &m_visitorState; const FileContextPtr m_file; ItemPool * const m_itemPool; Logger &m_logger; QHash m_typeNameToFile; Item *m_item = nullptr; std::unique_ptr m_moduleItemLocker; ItemType m_instanceItemType = ItemType::ModuleInstancePlaceholder; }; } // namespace Internal } // namespace qbs #endif // QBS_ITEMREADERASTVISITOR_H qbs-src-2.6.1/src/lib/corelib/loader/productresolver.h0000644000175100001660000000472714776170045022317 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once namespace qbs::Internal { enum class Deferral; class LoaderState; class ProductContext; // Responsibilities: // - Resolving dependencies to modules and other products (via DependenciesResolver). // - Module validation. // - Running probes (via ProbesResolver) in Product and Module items. // - Evaluating product and module properties. // - Handling all Product child items, such as FileTaggers, Rules and so on. void resolveProduct(ProductContext &product, Deferral deferral, LoaderState &loaderState); void setupExports(ProductContext &product, LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/moduleinstantiator.h0000644000175100001660000000643214776170045022775 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs::Internal { class Item; class LoaderState; class ProductContext; class QualifiedId; class InstantiationContext { public: ProductContext &product; Item * const loadingItem; const QString &loadingName; Item * const module; Item * const moduleWithSameName; Item * const exportingProduct; const QualifiedId &moduleName; const QString &id; const bool alreadyLoaded; }; // This function is responsible for setting up a proper module instance from a bunch of items: // - Set the item type to ItemType::ModuleInstance (from Module or Export). // - Apply possible command-line overrides for module properties. // - Replace a possible module instance placeholder in the loading item with the actual instance // and merge their values employing the ModulePropertyMerger. // - Setting up the module instance scope. void instantiateModule(const InstantiationContext &context, LoaderState &loaderState); // Helper functions for retrieving/setting module instance items for special purposes. // Note that these will also create the respective item value if it does not exist yet. Item *retrieveModuleInstanceItem(Item *containerItem, const QualifiedId &name, LoaderState &loaderState); Item *retrieveQbsItem(Item *containerItem, LoaderState &loaderState); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/itemreadervisitorstate.cpp0000644000175100001660000001247414776170045024210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "itemreadervisitorstate.h" #include "itemreaderastvisitor.h" #include "loaderutils.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { ItemReaderVisitorState::ItemReaderVisitorState(ItemReaderCache &cache, Logger &logger) : m_cache(cache), m_logger(logger) { } Item *ItemReaderVisitorState::readFile(const QString &filePath, const QStringList &searchPaths, ItemPool *itemPool) { const auto setupCacheEntry = [&](ItemReaderCache::AstCacheEntry &entry) { QFile file(filePath); if (Q_UNLIKELY(!file.open(QFile::ReadOnly))) throw ErrorInfo(Tr::tr("Cannot open '%1'.").arg(filePath)); QTextStream stream(&file); setupDefaultCodec(stream); const QString &code = stream.readAll(); QbsQmlJS::Lexer lexer(&entry.engine); lexer.setCode(code, 1); QbsQmlJS::Parser parser(&entry.engine); file.close(); if (!parser.parse()) { const QList &parserMessages = parser.diagnosticMessages(); if (Q_UNLIKELY(!parserMessages.empty())) { ErrorInfo err; for (const QbsQmlJS::DiagnosticMessage &msg : parserMessages) err.append(msg.message, toCodeLocation(filePath, msg.loc)); throw err; } } entry.code = code; entry.ast = parser.ast(); }; ItemReaderCache::AstCacheEntry &cacheEntry = m_cache.retrieveOrSetupCacheEntry( filePath, setupCacheEntry); const FileContextPtr file = FileContext::create(); file->setFilePath(QFileInfo(filePath).absoluteFilePath()); file->setContent(cacheEntry.code); file->setSearchPaths(searchPaths); ItemReaderASTVisitor astVisitor(*this, file, itemPool, m_logger); { class ProcessingFlagManager { public: ProcessingFlagManager(ItemReaderCache::AstCacheEntry &e, const QString &filePath) : m_cacheEntry(e) { if (!e.addProcessingThread()) throw ErrorInfo(Tr::tr("Loop detected when importing '%1'.").arg(filePath)); } ~ProcessingFlagManager() { m_cacheEntry.removeProcessingThread(); } private: ItemReaderCache::AstCacheEntry &m_cacheEntry; } processingFlagManager(cacheEntry, filePath); cacheEntry.ast->accept(&astVisitor); } astVisitor.checkItemTypes(); return astVisitor.rootItem(); } void ItemReaderVisitorState::findDirectoryEntries(const QString &dirPath, QStringList *entries) const { *entries = m_cache.retrieveOrSetDirectoryEntries(dirPath, [&dirPath] { QStringList fileNames; QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards()); while (dirIter.hasNext()) { dirIter.next(); fileNames << dirIter.fileName(); } return fileNames; }); } Item *ItemReaderVisitorState::mostDerivingItem() const { return m_mostDerivingItem; } void ItemReaderVisitorState::setMostDerivingItem(Item *item) { m_mostDerivingItem = item; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/astimportshandler.h0000644000175100001660000000674514776170045022622 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ASTIMPORTSHANDLER_H #define QBS_ASTIMPORTSHANDLER_H #include #include #include #include #include namespace qbs { class CodeLocation; class Version; namespace Internal { class ItemReaderVisitorState; class JsImport; class Logger; class ASTImportsHandler { public: ASTImportsHandler(ItemReaderVisitorState &visitorState, Logger &logger, const FileContextPtr &file); void handleImports(const QbsQmlJS::AST::UiImportList *uiImportList); QHash typeNameFileMap() const { return m_typeNameToFile; } private: static Version readImportVersion(const QString &str, const CodeLocation &location); bool addPrototype(const QString &fileName, const QString &filePath, const QString &as, bool needsCheck); void checkImportVersion(const QbsQmlJS::AST::SourceLocation &versionToken) const; void collectPrototypes(const QString &path, const QString &as); void collectPrototypesAndJsCollections(const QString &path, const QString &as, const CodeLocation &location); void handleImport(const QbsQmlJS::AST::UiImport *import, bool *baseImported); ItemReaderVisitorState &m_visitorState; Logger &m_logger; const FileContextPtr &m_file; const QString m_directory; QHash m_typeNameToFile; Set m_importAsNames; using JsImportsHash = QHash; JsImportsHash m_jsImports; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/loader/astpropertiesitemhandler.cpp0000644000175100001660000002575714776170045024537 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "astpropertiesitemhandler.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static const QString &autoGeneratedId() { static const QString autoGenerated = QLatin1String("__autoGenerated"); return autoGenerated; } ASTPropertiesItemHandler::ASTPropertiesItemHandler( Item *parentItem, ItemPool &itemPool, Logger &logger) : m_parentItem(parentItem) , m_itemPool(itemPool) , m_logger(logger) { prepareGroup(); } void ASTPropertiesItemHandler::handlePropertiesItems() { // TODO: Simply forbid Properties items to have child items and get rid of this check. if (m_parentItem->type() != ItemType::Properties) setupAlternatives(); } void ASTPropertiesItemHandler::prepareGroup() { if (m_parentItem->type() != ItemType::Group) return; // Syntactic sugar: If we encounter property bindings of the form "product.x.y: z" // (or "module.x.y: z" for groups in modules), we transform them into "x.y: z" // and put them in a newly created Properties item, thus making sure they will be // applied "globally". Item::PropertyMap &props = m_parentItem->properties(); for (auto it = props.begin(); it != props.end(); ++it) { if (it.value()->type() != Value::ItemValueType) continue; const bool hasProductPrefix = it.key() == StringConstants::productVar(); const bool hasModulePrefix = !hasProductPrefix && it.key() == StringConstants::moduleVar(); if (!hasProductPrefix && !hasModulePrefix) continue; Item * const valueItem = static_cast(it.value().get())->item(); Item * const propertiesItem = m_itemPool.allocateItem(ItemType::Properties); propertiesItem->setFile(m_parentItem->file()); propertiesItem->setProperties(valueItem->properties()); propertiesItem->setupForBuiltinType(DeprecationWarningMode::Off, m_logger); propertiesItem->setId(autoGeneratedId()); Item::addChild(m_parentItem, propertiesItem); if (hasModulePrefix) { Item *moduleItem = m_parentItem; while (moduleItem->type() == ItemType::Group) moduleItem = moduleItem->parent(); if (moduleItem->type() != ItemType::Module) { const QString errMsg = Tr::tr("Use of '%1' is only allowed in %2 items.") .arg( it.key(), BuiltinDeclarations::instance().nameForType( ItemType::Module)); const CodeLocation loc = valueItem->properties().first()->location(); throw ErrorInfo(errMsg, loc); } } props.erase(it); break; } } void ASTPropertiesItemHandler::setupAlternatives() { auto it = m_parentItem->m_children.begin(); while (it != m_parentItem->m_children.end()) { Item * const child = *it; bool remove = false; if (child->type() == ItemType::Properties) { handlePropertiesBlock(child); remove = m_parentItem->type() != ItemType::Export; } if (remove) it = m_parentItem->m_children.erase(it); else ++it; } } class PropertiesBlockConverter { public: PropertiesBlockConverter( const JSSourceValue::AltProperty &condition, const JSSourceValue::AltProperty &overrideListProperties, Item *propertiesBlockContainer, const Item *propertiesBlock, ItemPool &pool) : m_propertiesBlockContainer(propertiesBlockContainer) , m_propertiesBlock(propertiesBlock) , m_itemPool(pool) , m_autoGenerated(propertiesBlock->id() == autoGeneratedId()) { m_alternative.condition = condition; m_alternative.overrideListProperties = overrideListProperties; while (m_targetItem->type() == ItemType::Group) m_targetItem = m_targetItem->parent(); } void apply() { doApply(m_propertiesBlockContainer, m_propertiesBlock); } private: JSSourceValue::Alternative m_alternative; Item * const m_propertiesBlockContainer; Item *m_targetItem = m_propertiesBlockContainer; const Item * const m_propertiesBlock; ItemPool &m_itemPool; const bool m_autoGenerated; void doApply(Item *outer, const Item *inner) { for (auto it = inner->properties().constBegin(); it != inner->properties().constEnd(); ++it) { if (inner == m_propertiesBlock && (it.key() == StringConstants::conditionProperty() || it.key() == StringConstants::overrideListPropertiesProperty())) { continue; } if (it.value()->type() == Value::ItemValueType) { Item * const innerVal = std::static_pointer_cast(it.value())->item(); Item * const targetItem = outer == m_propertiesBlockContainer ? m_targetItem : outer; ItemValuePtr outerVal = targetItem->itemProperty(it.key(), m_itemPool); if (!outerVal) { outerVal = ItemValue::create(Item::create(&m_itemPool, innerVal->type()), true); targetItem->setProperty(it.key(), outerVal); } doApply(outerVal->item(), innerVal); } else if (it.value()->type() == Value::JSSourceValueType) { Item * const targetItem = outer == m_propertiesBlockContainer && m_autoGenerated ? m_targetItem : outer; const ValuePtr outerVal = targetItem->property(it.key()); if (Q_UNLIKELY(outerVal && outerVal->type() != Value::JSSourceValueType)) { throw ErrorInfo(Tr::tr("Incompatible value type in unconditional value at %1.") .arg(outerVal->location().toString())); } const JSSourceValuePtr value = std::static_pointer_cast(it.value()); doApply( it.key(), targetItem, std::static_pointer_cast(outerVal), value); if ((outer != m_propertiesBlockContainer || m_autoGenerated) && m_targetItem != m_propertiesBlockContainer) { QBS_CHECK(m_propertiesBlockContainer->type() == ItemType::Group); value->setScope(m_propertiesBlockContainer, {}); } } else { QBS_CHECK(!"Unexpected value type in conditional value."); } } } void doApply(const QString &propertyName, Item *item, JSSourceValuePtr value, const JSSourceValuePtr &conditionalValue) { if (!value) { value = JSSourceValue::create(true); value->setFile(conditionalValue->file()); item->setProperty(propertyName, value); value->setSourceCode(StringConstants::baseVar()); value->setSourceUsesBase(); } m_alternative.value = conditionalValue; if (m_alternative.condition.value == QLatin1String("undefined")) conditionalValue->setFallback(); value->addAlternative(m_alternative); } }; static JSSourceValue::AltProperty getPropertyData(const Item *propertiesItem, const QString &name) { const ValuePtr value = propertiesItem->property(name); if (!value) return {StringConstants::falseValue(), propertiesItem->location()}; if (Q_UNLIKELY(value->type() != Value::JSSourceValueType)) { throw ErrorInfo(Tr::tr("Properties.%1 must be a value binding.").arg(name), propertiesItem->location()); } if (name == StringConstants::overrideListPropertiesProperty()) { const Item *parent = propertiesItem->parent(); while (parent) { if (parent->type() == ItemType::Product) break; parent = parent->parent(); } if (!parent) { throw ErrorInfo(Tr::tr("Properties.overrideListProperties can only be set " "in a Product item.")); } } const JSSourceValuePtr srcval = std::static_pointer_cast(value); return {srcval->sourceCodeForEvaluation(), srcval->location()}; } void ASTPropertiesItemHandler::handlePropertiesBlock(const Item *propertiesItem) { const auto condition = getPropertyData(propertiesItem, StringConstants::conditionProperty()); const auto overrideListProperties = getPropertyData(propertiesItem, StringConstants::overrideListPropertiesProperty()); PropertiesBlockConverter(condition, overrideListProperties, m_parentItem, propertiesItem, m_itemPool).apply(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/loader/productresolver.cpp0000644000175100001660000021055114776170045022644 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "productresolver.h" #include "dependenciesresolver.h" #include "groupshandler.h" #include "loaderutils.h" #include "modulepropertymerger.h" #include "probesresolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs::Internal { class PropertiesEvaluator { public: PropertiesEvaluator(ProductContext &product, LoaderState &loaderState) : m_product(product), m_loaderState(loaderState) {} QVariantMap evaluateProperties(Item *item, bool lookupPrototype, bool checkErrors); QVariantMap evaluateProperties(const Item *item, const Item *propertiesContainer, const QVariantMap &tmplt, bool lookupPrototype, bool checkErrors); void evaluateProperty(const Item *item, const QString &propName, const ValuePtr &propValue, QVariantMap &result, bool checkErrors); private: ProductContext &m_product; LoaderState &m_loaderState; }; // Dependency resolving, Probe execution. // Run for real products and shadow products. class ProductResolverStage1 { public: ProductResolverStage1(ProductContext &product, Deferral deferral, LoaderState &loaderState) : m_product(product), m_loaderState(loaderState), m_deferral(deferral) {} void start(); private: void resolveProbes(); void resolveProbes(Item *item); void runModuleProbes(const Item::Module &module); void updateModulePresentState(const Item::Module &module); bool validateModule(const Item::Module &module); void handleModuleSetupError(const Item::Module &module, const ErrorInfo &error); void checkPropertyDeclarations(); void mergeDependencyParameters(); void checkDependencyParameterDeclarations(const Item *productItem, const QString &productName) const; void collectCodeLinks(); ProductContext &m_product; LoaderState &m_loaderState; const Deferral m_deferral; }; // Setting up ResolvedProduct, incuding property evaluation and handling Product child items. // Run only for real products. class ProductResolverStage2 { public: ProductResolverStage2(ProductContext &product, LoaderState &loaderState) : m_product(product), m_loaderState(loaderState) {} void start(); private: void resolveProductFully(); void createProductConfig(); void resolveGroup(Item *item, ModuleContext *moduleContext); void resolveGroupFully(Item *item, bool isEnabled, ModuleContext *moduleContext); QVariantMap resolveAdditionalModuleProperties(const Item *group, const QVariantMap ¤tValues); SourceArtifactPtr createSourceArtifact(const QString &fileName, const GroupPtr &group, bool wildcard, const CodeLocation &filesLocation, ErrorInfo *errorInfo); void resolveExport(Item *exportItem); std::unique_ptr resolveExportChild(const Item *item, const ExportedModule &module); void setupExportedProperties(const Item *item, const QString &namePrefix, std::vector &properties); QVariantMap evaluateModuleValues(Item *item, bool lookupPrototype = true); void resolveScanner(Item *item, ModuleContext *moduleContext); void resolveModules(); void resolveModule(const QualifiedId &moduleName, Item *item, bool isProduct, const QVariantMap ¶meters, JobLimits &jobLimits); void applyFileTaggers(); void finalizeArtifactProperties(); void collectProductDependencies(); ProductContext &m_product; LoaderState &m_loaderState; GroupConstPtr m_currentGroup; FileLocations m_sourceArtifactLocations; PropertiesEvaluator m_propertiesEvaluator{m_product, m_loaderState}; using ArtifactPropertiesInfo = std::pair>; QHash m_artifactPropertiesPerFilter; }; class ExportsResolver { public: ExportsResolver(ProductContext &product, LoaderState &loaderState) : m_product(product), m_loaderState(loaderState) {} void start(); private: void resolveShadowProduct(); void collectPropertiesForExportItem(Item *productModuleInstance); void collectPropertiesForExportItem(const QualifiedId &moduleName, const ValuePtr &value, Item *moduleInstance, QVariantMap &moduleProps); void collectPropertiesForModuleInExportItem(const Item::Module &module); void adaptExportedPropertyValues(); void collectExportedProductDependencies(); ProductContext &m_product; LoaderState &m_loaderState; PropertiesEvaluator m_propertiesEvaluator{m_product, m_loaderState}; }; void resolveProduct(ProductContext &product, Deferral deferral, LoaderState &loaderState) { try { ProductResolverStage1(product, deferral, loaderState).start(); } catch (const ErrorInfo &err) { if (err.isCancelException()) { loaderState.topLevelProject().setCanceled(); return; } product.handleError(err); } if (product.dependenciesResolvingPending()) return; if (product.name.startsWith(StringConstants::shadowProductPrefix())) return; // TODO: The weird double-forwarded error handling can hopefully be simplified now. try { ProductResolverStage2(product, loaderState).start(); } catch (const ErrorInfo &err) { if (err.isCancelException()) { loaderState.topLevelProject().setCanceled(); return; } loaderState.topLevelProject().addQueuedError(err); } } void setupExports(ProductContext &product, LoaderState &loaderState) { ExportsResolver(product, loaderState).start(); } void ProductResolverStage1::start() { TopLevelProjectContext &topLevelProject = m_loaderState.topLevelProject(); topLevelProject.checkCancelation(); if (m_product.delayedError.hasError()) return; resolveDependencies(m_product, m_deferral, m_loaderState); QBS_CHECK(m_product.dependenciesContext); if (!m_product.dependenciesContext->dependenciesResolved) return; if (m_product.delayedError.hasError()) return; // Run probes for modules and product. resolveProbes(); // After the probes have run, we can switch on the evaluator cache. Evaluator &evaluator = m_loaderState.evaluator(); FileTags fileTags = evaluator.fileTagsValue(m_product.item, StringConstants::typeProperty()); EvalCacheEnabler cacheEnabler(&evaluator, evaluator.stringValue( m_product.item, StringConstants::sourceDirectoryProperty())); // Run module validation scripts. for (const Item::Module &module : m_product.item->modules()) { if (!validateModule(module)) return; fileTags += evaluator.fileTagsValue( module.item, StringConstants::additionalProductTypesProperty()); } // Disable modules that have been pulled in only by now-disabled modules. // Note that this has to happen in the reverse order compared to the other loops, // with the leaves checked last. for (auto it = m_product.item->modules().rbegin(); it != m_product.item->modules().rend(); ++it) updateModulePresentState(*it); // Now do the canonical module property values merge. Note that this will remove // previously attached values from modules that failed validation. // Evaluator cache entries that could potentially change due to this will be purged. doFinalMerge(m_product, m_loaderState); const bool enabled = topLevelProject.checkItemCondition(m_product.item, evaluator); collectCodeLinks(); mergeDependencyParameters(); checkDependencyParameterDeclarations(m_product.item, m_product.name); setupGroups(m_product, m_loaderState); // Collect the full list of fileTags, including the values contributed by modules. if (!m_product.delayedError.hasError() && enabled && !m_product.name.startsWith(StringConstants::shadowProductPrefix())) { topLevelProject.addProductByType(m_product, fileTags); m_product.item->setProperty(StringConstants::typeProperty(), VariantValue::create(sorted(fileTags.toStringList()))); } checkPropertyDeclarations(); } void ProductResolverStage1::resolveProbes() { for (const Item::Module &module : m_product.item->modules()) { runModuleProbes(module); if (m_product.delayedError.hasError()) return; } resolveProbes(m_product.item); } void ProductResolverStage1::resolveProbes(Item *item) { ProbesResolver(m_loaderState).resolveProbes(m_product, item); } void ProductResolverStage1::runModuleProbes(const Item::Module &module) { if (!module.item->isPresentModule()) return; if (module.product && m_loaderState.topLevelProject().isDisabledItem(module.product->item)) { createNonPresentModule(m_loaderState.itemPool(), module.name.toString(), QLatin1String("module's exporting product is disabled"), module.item); return; } try { resolveProbes(module.item); if (module.versionRange.minimum.isValid() || module.versionRange.maximum.isValid()) { if (module.versionRange.maximum.isValid() && module.versionRange.minimum >= module.versionRange.maximum) { throw ErrorInfo(Tr::tr("Impossible version constraint [%1,%2) set for module " "'%3'").arg(module.versionRange.minimum.toString(), module.versionRange.maximum.toString(), module.name.toString())); } const Version moduleVersion = Version::fromString( m_loaderState.evaluator().stringValue(module.item, StringConstants::versionProperty())); if (moduleVersion < module.versionRange.minimum) { throw ErrorInfo(Tr::tr("Module '%1' has version %2, but it needs to be " "at least %3.").arg(module.name.toString(), moduleVersion.toString(), module.versionRange.minimum.toString())); } if (module.versionRange.maximum.isValid() && moduleVersion >= module.versionRange.maximum) { throw ErrorInfo(Tr::tr("Module '%1' has version %2, but it needs to be " "lower than %3.").arg(module.name.toString(), moduleVersion.toString(), module.versionRange.maximum.toString())); } } } catch (const ErrorInfo &error) { handleModuleSetupError(module, error); } } void ProductResolverStage1::updateModulePresentState(const Item::Module &module) { if (!module.item->isPresentModule()) return; if (module.name.first() == StringConstants::qbsModule()) return; bool hasPresentLoadingItem = false; for (const Item::Module::LoadContext &loadContext : module.loadContexts) { const Item * const loadingItem = loadContext.loadingItem(); if (loadingItem == m_product.item) { hasPresentLoadingItem = true; break; } if (!loadingItem->isPresentModule()) continue; if (loadingItem->prototype() && loadingItem->prototype()->type() == ItemType::Export) { QBS_CHECK(loadingItem->prototype()->parent()->type() == ItemType::Product); if (m_loaderState.topLevelProject().isDisabledItem(loadingItem->prototype()->parent())) continue; } hasPresentLoadingItem = true; break; } if (!hasPresentLoadingItem) { createNonPresentModule(m_loaderState.itemPool(), module.name.toString(), QLatin1String("imported only by disabled module(s)"), module.item); } } bool ProductResolverStage1::validateModule(const Item::Module &module) { if (!module.item->isPresentModule()) return true; try { m_loaderState.evaluator().boolValue(module.item, StringConstants::validateProperty()); for (const auto &dep : module.item->modules()) { if (dep.required && !dep.item->isPresentModule()) { throw ErrorInfo(Tr::tr("Module '%1' depends on module '%2', which was not " "loaded successfully") .arg(module.name.toString(), dep.name.toString())); } } } catch (const ErrorInfo &error) { handleModuleSetupError(module, error); if (m_product.delayedError.hasError()) return false; } return true; } void ProductResolverStage1::handleModuleSetupError(const Item::Module &module, const ErrorInfo &error) { if (module.required) { m_product.handleError(error); } else { qCDebug(lcModuleLoader()) << "non-required module" << module.name.toString() << "found, but not usable in product" << m_product.name << error.toString(); createNonPresentModule(m_loaderState.itemPool(), module.name.toString(), QStringLiteral("failed validation"), module.item); } } void ProductResolverStage1::checkPropertyDeclarations() { AccumulatingTimer timer(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.propertyChecking : nullptr); qbs::Internal::checkPropertyDeclarations(m_product.item, m_loaderState); } void ProductResolverStage1::mergeDependencyParameters() { if (m_loaderState.topLevelProject().isDisabledItem(m_product.item)) return; for (Item::Module &module : m_product.item->modules()) { if (module.name.toString() == StringConstants::qbsModule()) continue; if (!module.item->isPresentModule()) continue; using PP = Item::Module::ParametersWithPriority; std::vector priorityList; const QVariantMap defaultParameters = module.product ? module.product->defaultParameters : m_loaderState.topLevelProject().parameters(module.item->prototype()); priorityList.emplace_back(defaultParameters, INT_MIN); for (const Item::Module::LoadContext &context : module.loadContexts) { const QVariantMap ¶meters = context.parameters.first; // Empty parameter maps and inactive loading modules do not contribute to the // final parameter map. if (parameters.isEmpty()) continue; if (context.loadingItem()->type() == ItemType::ModuleInstance && !context.loadingItem()->isPresentModule()) { continue; } // Build a list sorted by priority. static const auto cmp = [](const PP &elem, int prio) { return elem.second < prio; }; const auto it = std::lower_bound(priorityList.begin(), priorityList.end(), context.parameters.second, cmp); priorityList.insert(it, context.parameters); } module.parameters = qbs::Internal::mergeDependencyParameters(std::move(priorityList)); } } class DependencyParameterDeclarationCheck { public: DependencyParameterDeclarationCheck(const QString &productName, const Item *productItem, const TopLevelProjectContext &topLevelProject) : m_productName(productName), m_productItem(productItem), m_topLevelProject(topLevelProject) {} void operator()(const QVariantMap ¶meters) const { check(parameters, QualifiedId()); } private: void check(const QVariantMap ¶meters, const QualifiedId &moduleName) const { for (auto it = parameters.begin(); it != parameters.end(); ++it) { if (it.value().userType() == QMetaType::QVariantMap) { check(it.value().toMap(), QualifiedId(moduleName) << it.key()); } else { const auto &deps = m_productItem->modules(); auto m = std::find_if(deps.begin(), deps.end(), [&moduleName] (const Item::Module &module) { return module.name == moduleName; }); if (m == deps.end()) { const QualifiedId fullName = QualifiedId(moduleName) << it.key(); throw ErrorInfo(Tr::tr("Cannot set parameter '%1', " "because '%2' does not have a dependency on '%3'.") .arg(fullName.toString(), m_productName, moduleName.toString()), m_productItem->location()); } const auto decls = m_topLevelProject.parameterDeclarations( m->item->rootPrototype()); if (!decls.contains(it.key())) { const QualifiedId fullName = QualifiedId(moduleName) << it.key(); throw ErrorInfo(Tr::tr("Parameter '%1' is not declared.") .arg(fullName.toString()), m_productItem->location()); } } } } bool moduleExists(const QualifiedId &name) const { const auto &deps = m_productItem->modules(); return any_of(deps, [&name](const Item::Module &module) { return module.name == name; }); } const QString &m_productName; const Item * const m_productItem; const TopLevelProjectContext &m_topLevelProject; }; void ProductResolverStage1::checkDependencyParameterDeclarations(const Item *productItem, const QString &productName) const { DependencyParameterDeclarationCheck dpdc(productName, productItem, m_loaderState.topLevelProject()); for (const Item::Module &dep : productItem->modules()) { if (!dep.parameters.empty()) dpdc(dep.parameters); } } void ProductResolverStage1::collectCodeLinks() { for (const Item::Module &module : m_product.item->modules()) { if (module.name.first() == StringConstants::qbsModule()) continue; for (const Item::Module::LoadContext &context : module.loadContexts) { m_loaderState.topLevelProject().addCodeLink( context.dependsItem->location().filePath(), context.dependsItem->codeRange(), module.product ? module.product->item->location() : module.item->location()); } } } void ProductResolverStage2::start() { m_loaderState.evaluator().clearPropertyDependencies(); ResolvedProductPtr product = ResolvedProduct::create(); product->enabled = m_product.project->project->enabled; product->moduleProperties = PropertyMapInternal::create(); product->project = m_product.project->project; m_product.product = product; product->location = m_product.item->location(); const auto errorFromDelayedError = [&] { if (m_product.delayedError.hasError()) { ErrorInfo errorInfo; // First item is "main error", gets prepended again in the catch clause. const QList &items = m_product.delayedError.items(); for (int i = 1; i < items.size(); ++i) errorInfo.append(items.at(i)); m_product.delayedError.clear(); return errorInfo; } return ErrorInfo(); }; // Even if we previously encountered an error, try to continue for as long as possible // to provide IDEs with useful data (e.g. the list of files). // If we encounter a follow-up error, suppress it and report the original one instead. try { resolveProductFully(); if (const ErrorInfo error = errorFromDelayedError(); error.hasError()) throw error; } catch (ErrorInfo e) { if (const ErrorInfo error = errorFromDelayedError(); error.hasError()) e = error; QString mainErrorString = !product->name.isEmpty() ? Tr::tr("Error while handling product '%1':").arg(product->name) : Tr::tr("Error while handling product:"); ErrorInfo fullError(mainErrorString, product->location); appendError(fullError, e); if (!product->enabled) { qCDebug(lcProjectResolver) << fullError.toString(); return; } if (m_loaderState.parameters().productErrorMode() == ErrorHandlingMode::Strict) throw fullError; m_loaderState.logger().printError(fullError); m_loaderState.logger().printError(ErrorInfo( Tr::tr("Product '%1' had errors and was disabled.").arg(product->name), product->location)); product->enabled = false; } } void ProductResolverStage2::resolveProductFully() { Item * const item = m_product.item; const ResolvedProductPtr product = m_product.product; Evaluator &evaluator = m_loaderState.evaluator(); product->name = evaluator.stringValue(item, StringConstants::nameProperty()); // product->buildDirectory() isn't valid yet, because the productProperties map is not ready. m_product.buildDirectory = evaluator.stringValue( item, StringConstants::buildDirectoryProperty()); product->multiplexConfigurationId = evaluator.stringValue( item, StringConstants::multiplexConfigurationIdProperty()); qCDebug(lcProjectResolver) << "resolveProduct" << product->uniqueName(); product->enabled = product->enabled && evaluator.boolValue(item, StringConstants::conditionProperty()); const VariantValuePtr type = item->variantProperty(StringConstants::typeProperty()); if (type) product->fileTags = FileTags::fromStringList(type->value().toStringList()); product->targetName = evaluator.stringValue(item, StringConstants::targetNameProperty()); product->sourceDirectory = evaluator.stringValue( item, StringConstants::sourceDirectoryProperty()); product->destinationDirectory = evaluator.stringValue( item, StringConstants::destinationDirProperty()); if (product->destinationDirectory.isEmpty()) { product->destinationDirectory = m_product.buildDirectory; } else { product->destinationDirectory = FileInfo::resolvePath( product->topLevelProject()->buildDirectory, product->destinationDirectory); } product->probes = m_product.probes; createProductConfig(); product->productProperties.insert(StringConstants::destinationDirProperty(), product->destinationDirectory); ModuleProperties::init(evaluator.engine(), evaluator.scriptValue(item), product.get()); QList subItems = item->children(); const ValuePtr filesProperty = item->property(StringConstants::filesProperty()); if (filesProperty) { Item *fakeGroup = Item::create(&m_loaderState.itemPool(), ItemType::Group); fakeGroup->setFile(item->file()); fakeGroup->setLocation(item->location()); fakeGroup->setScope(item); fakeGroup->setProperty(StringConstants::nameProperty(), VariantValue::create(product->name)); fakeGroup->setProperty(StringConstants::filesProperty(), filesProperty); fakeGroup->setProperty(StringConstants::excludeFilesProperty(), item->property(StringConstants::excludeFilesProperty())); fakeGroup->setProperty(StringConstants::overrideTagsProperty(), VariantValue::falseValue()); fakeGroup->setupForBuiltinType(m_loaderState.parameters().deprecationWarningMode(), m_loaderState.logger()); subItems.prepend(fakeGroup); } for (Item * const child : std::as_const(subItems)) { switch (child->type()) { case ItemType::Rule: resolveRule(m_loaderState, child, m_product.project, &m_product, nullptr); break; case ItemType::Scanner: resolveScanner(child, nullptr); break; case ItemType::FileTagger: resolveFileTagger(m_loaderState, child, nullptr, &m_product); break; case ItemType::JobLimit: resolveJobLimit(m_loaderState, child, nullptr, &m_product, nullptr); break; case ItemType::Group: resolveGroup(child, nullptr); break; case ItemType::Export: resolveExport(child); break; default: break; } } for (const ProjectContext *p = m_product.project; p; p = p->parent) { JobLimits tempLimits = p->jobLimits; product->jobLimits = tempLimits.update(product->jobLimits); } resolveModules(); applyFileTaggers(); finalizeArtifactProperties(); for (const RulePtr &rule : m_product.project->rules) { RulePtr clonedRule = rule->clone(); clonedRule->product = product.get(); product->rules.push_back(clonedRule); } collectProductDependencies(); } void ProductResolverStage2::createProductConfig() { EvalCacheEnabler cachingEnabler(&m_loaderState.evaluator(), m_product.product->sourceDirectory); m_product.product->moduleProperties->setValue(evaluateModuleValues(m_product.item)); m_product.product->productProperties = m_propertiesEvaluator.evaluateProperties( m_product.item, m_product.item, QVariantMap(), true, true); } void ProductResolverStage2::resolveGroup(Item *item, ModuleContext *moduleContext) { const bool parentEnabled = m_currentGroup ? m_currentGroup->enabled : m_product.product->enabled; const bool isEnabled = parentEnabled && m_loaderState.evaluator().boolValue(item, StringConstants::conditionProperty()); try { resolveGroupFully(item, isEnabled, moduleContext); } catch (const ErrorInfo &error) { if (!isEnabled) { qCDebug(lcProjectResolver) << "error resolving group at" << item->location() << error.toString(); return; } if (m_loaderState.parameters().productErrorMode() == ErrorHandlingMode::Strict) throw; m_loaderState.logger().printError(error); } } void ProductResolverStage2::resolveGroupFully( Item *item, bool isEnabled, ModuleContext *moduleContext) { AccumulatingTimer groupTimer(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.groupsResolving : nullptr); const auto getGroupPropertyMap = [&](const ArtifactProperties *existingProps) { PropertyMapPtr moduleProperties; bool newPropertyMapRequired = false; if (existingProps) moduleProperties = existingProps->propertyMap(); if (!moduleProperties) { newPropertyMapRequired = true; moduleProperties = m_currentGroup ? m_currentGroup->properties : m_product.product->moduleProperties; } const QVariantMap newModuleProperties = resolveAdditionalModuleProperties( item, moduleProperties->value()); if (!newModuleProperties.empty()) { if (newPropertyMapRequired) moduleProperties = PropertyMapInternal::create(); moduleProperties->setValue(newModuleProperties); } return moduleProperties; }; Evaluator &evaluator = m_loaderState.evaluator(); QStringList files = evaluator.stringListValue(item, StringConstants::filesProperty()); bool fileTagsSet; const FileTags fileTags = evaluator.fileTagsValue(item, StringConstants::fileTagsProperty(), &fileTagsSet); const QStringList fileTagsFilter = evaluator.stringListValue(item, StringConstants::fileTagsFilterProperty()); if (!fileTagsFilter.empty()) { if (Q_UNLIKELY(!files.empty())) throw ErrorInfo(Tr::tr("Group.files and Group.fileTagsFilters are exclusive."), item->location()); if (!isEnabled) return; ArtifactPropertiesInfo &apinfo = m_artifactPropertiesPerFilter[fileTagsFilter]; if (apinfo.first) { const auto it = std::find_if(apinfo.second.cbegin(), apinfo.second.cend(), [item](const CodeLocation &loc) { return item->location().filePath() == loc.filePath(); }); if (it != apinfo.second.cend()) { ErrorInfo error(Tr::tr("Conflicting fileTagsFilter in Group items.")); error.append(Tr::tr("First item"), *it); error.append(Tr::tr("Second item"), item->location()); throw error; } } else { apinfo.first = ArtifactProperties::create(); apinfo.first->setFileTagsFilter(FileTags::fromStringList(fileTagsFilter)); m_product.product->artifactProperties.push_back(apinfo.first); } apinfo.second.push_back(item->location()); apinfo.first->setPropertyMapInternal(getGroupPropertyMap(apinfo.first.get())); apinfo.first->addExtraFileTags(fileTags); return; } QStringList patterns; for (int i = files.size(); --i >= 0;) { if (FileInfo::isPattern(files[i])) patterns.push_back(files.takeAt(i)); } GroupPtr group = ResolvedGroup::create(); bool prefixWasSet = false; group->prefix = evaluator.stringValue(item, StringConstants::prefixProperty(), QString(), &prefixWasSet); if (!prefixWasSet && m_currentGroup) group->prefix = m_currentGroup->prefix; if (!group->prefix.isEmpty()) { for (auto it = files.rbegin(), end = files.rend(); it != end; ++it) it->prepend(group->prefix); } group->location = item->location(); group->enabled = isEnabled; group->properties = getGroupPropertyMap(nullptr); group->fileTags = fileTags; group->overrideTags = evaluator.boolValue(item, StringConstants::overrideTagsProperty()); if (group->overrideTags && fileTagsSet) { if (group->fileTags.empty() ) group->fileTags.insert(unknownFileTag()); } else if (m_currentGroup) { group->fileTags.unite(m_currentGroup->fileTags); } const CodeLocation filesLocation = item->property(StringConstants::filesProperty())->location(); if (filesLocation.line() > 0 || item->location() == m_product.item->location()) group->files.emplace(); const VariantValueConstPtr moduleProp = item->variantProperty( StringConstants::modulePropertyInternal()); if (moduleProp) group->targetOfModule = moduleProp->value().toString(); ErrorInfo fileError; if (!patterns.empty()) { group->wildcards = std::make_unique(); SourceWildCards *wildcards = group->wildcards.get(); wildcards->excludePatterns = evaluator.stringListValue( item, StringConstants::excludeFilesProperty()); wildcards->patterns = patterns; wildcards->prefix = group->prefix; wildcards->baseDir = FileInfo::path(item->file()->filePath()); wildcards->buildDir = m_product.project->project->topLevelProject()->buildDirectory; wildcards->expandPatterns(); for (const QString &fileName : wildcards->expandedFiles) createSourceArtifact(fileName, group, true, filesLocation, &fileError); } for (const QString &fileName : std::as_const(files)) createSourceArtifact(fileName, group, false, filesLocation, &fileError); if (fileError.hasError()) { if (group->enabled) { if (m_loaderState.parameters().productErrorMode() == ErrorHandlingMode::Strict) throw ErrorInfo(fileError); m_loaderState.logger().printError(fileError); } else { qCDebug(lcProjectResolver) << "error for disabled group:" << fileError.toString(); } } group->name = evaluator.stringValue(item, StringConstants::nameProperty()); if (group->name.isEmpty()) group->name = Tr::tr("Group %1").arg(m_product.product->groups.size()); m_product.product->groups.push_back(group); class GroupContextSwitcher { public: GroupContextSwitcher(ProductResolverStage2 &resolver, const GroupConstPtr &newGroup) : m_resolver(resolver), m_oldGroup(resolver.m_currentGroup) { resolver.m_currentGroup = newGroup; } ~GroupContextSwitcher() { m_resolver.m_currentGroup = m_oldGroup; } private: ProductResolverStage2 &m_resolver; const GroupConstPtr m_oldGroup; }; GroupContextSwitcher groupSwitcher(*this, group); for (Item * const childItem : item->children()) { switch (childItem->type()) { case ItemType::FileTagger: if (isEnabled) resolveFileTagger(m_loaderState, childItem, nullptr, &m_product); break; case ItemType::Group: resolveGroup(childItem, moduleContext); break; case ItemType::Rule: if (isEnabled) resolveRule(m_loaderState, childItem, m_product.project, &m_product, moduleContext); break; case ItemType::Scanner: if (isEnabled) resolveScanner(childItem, moduleContext); break; default: break; } } } SourceArtifactPtr ProductResolverStage2::createSourceArtifact( const QString &fileName, const GroupPtr &group, bool wildcard, const CodeLocation &filesLocation, ErrorInfo *errorInfo) { const QString &baseDir = FileInfo::path(group->location.filePath()); const QString absFilePath = QDir::cleanPath(FileInfo::resolvePath(baseDir, fileName)); if (!wildcard && !FileInfo(absFilePath).exists()) { if (errorInfo) errorInfo->append(Tr::tr("File '%1' does not exist.").arg(absFilePath), filesLocation); m_product.product->missingSourceFiles << absFilePath; return {}; } if (group->enabled) { CodeLocation &loc = m_sourceArtifactLocations[ std::make_pair(group->targetOfModule, absFilePath)]; if (loc.isValid()) { if (errorInfo) { errorInfo->append(Tr::tr("Duplicate source file '%1'.").arg(absFilePath)); errorInfo->append(Tr::tr("First occurrence is here."), loc); errorInfo->append(Tr::tr("Next occurrence is here."), filesLocation); } return {}; } loc = filesLocation; } SourceArtifactPtr artifact = SourceArtifactInternal::create(); artifact->absoluteFilePath = absFilePath; artifact->fileTags = group->fileTags; artifact->overrideFileTags = group->overrideTags; artifact->properties = group->properties; artifact->targetOfModule = group->targetOfModule; artifact->fromWildcard = wildcard; QBS_CHECK(group->files); group->files->push_back(artifact); return artifact; } static QualifiedIdSet propertiesToEvaluate(std::deque initialProps, const PropertyDependencies &deps) { std::deque remainingProps = std::move(initialProps); QualifiedIdSet allProperties; while (!remainingProps.empty()) { const QualifiedId prop = remainingProps.front(); remainingProps.pop_front(); const auto insertResult = allProperties.insert(prop); if (!insertResult.second) continue; transform(deps.value(prop), remainingProps, [](const QualifiedId &id) { return id; }); } return allProperties; } QVariantMap ProductResolverStage2::resolveAdditionalModuleProperties( const Item *group, const QVariantMap ¤tValues) { // Step 1: Retrieve the properties directly set in the group const ModulePropertiesPerGroup &mp = m_product.modulePropertiesSetInGroups; const auto it = mp.find(group); if (it == mp.end()) return {}; const QualifiedIdSet &propsSetInGroup = it->second; // Step 2: Gather all properties that depend on these properties. const QualifiedIdSet &propsToEval = propertiesToEvaluate( rangeTo>(propsSetInGroup), m_loaderState.evaluator().propertyDependencies()); // Step 3: Evaluate all these properties and replace their values in the map QVariantMap modulesMap = currentValues; QHash propsPerModule; for (auto fullPropName : propsToEval) { const QString moduleName = QualifiedId(fullPropName.mid(0, fullPropName.size() - 1)).toString(); propsPerModule[moduleName] << fullPropName.last(); } EvalCacheEnabler cachingEnabler(&m_loaderState.evaluator(), m_product.product->sourceDirectory); for (const Item::Module &module : group->modules()) { const QString &fullModName = module.name.toString(); const QStringList propsForModule = propsPerModule.take(fullModName); if (propsForModule.empty()) continue; QVariantMap reusableValues = modulesMap.value(fullModName).toMap(); for (const QString &prop : std::as_const(propsForModule)) reusableValues.remove(prop); modulesMap.insert(fullModName, m_propertiesEvaluator.evaluateProperties( module.item, module.item, reusableValues, true, true)); } return modulesMap; } static QString getLineAtLocation(const CodeLocation &loc, const QString &content) { int pos = 0; int currentLine = 1; while (currentLine < loc.line()) { while (content.at(pos++) != QLatin1Char('\n')) ; ++currentLine; } const int eolPos = content.indexOf(QLatin1Char('\n'), pos); return content.mid(pos, eolPos - pos); } static bool usesImport(const ExportedProperty &prop, const QRegularExpression ®ex) { return prop.sourceCode.indexOf(regex) != -1; } static bool usesImport(const ExportedItem &item, const QRegularExpression ®ex) { return any_of(item.properties, [regex](const ExportedProperty &p) { return usesImport(p, regex); }) || any_of(item.children, [regex](const ExportedItemPtr &child) { return usesImport(*child, regex); }); } static bool usesImport(const ExportedModule &module, const QString &name) { // Imports are used in three ways: // (1) var f = new TextFile(...); // (2) var path = FileInfo.joinPaths(...) // (3) var obj = DataCollection; const QString pattern = QStringLiteral("\\b%1\\b"); const QRegularExpression regex(pattern.arg(name)); // std::regex is much slower return any_of(module.m_properties, [regex](const ExportedProperty &p) { return usesImport(p, regex); }) || any_of(module.children, [regex](const ExportedItemPtr &child) { return usesImport(*child, regex); }); } void ProductResolverStage2::resolveExport(Item *exportItem) { ExportedModule &exportedModule = m_product.product->exportedModule; setupExportedProperties(exportItem, QString(), exportedModule.m_properties); static const auto cmpFunc = [](const ExportedProperty &p1, const ExportedProperty &p2) { return p1.fullName < p2.fullName; }; std::sort(exportedModule.m_properties.begin(), exportedModule.m_properties.end(), cmpFunc); transform(exportItem->children(), exportedModule.children, [&exportedModule, this](const auto &child) { return resolveExportChild(child, exportedModule); }); for (const JsImport &jsImport : exportItem->file()->jsImports()) { if (usesImport(exportedModule, jsImport.scopeName)) { exportedModule.importStatements << getLineAtLocation(jsImport.location, exportItem->file()->content()); } } const auto builtInImports = JsExtensions::extensionNames(); for (const QString &builtinImport: builtInImports) { if (usesImport(exportedModule, builtinImport)) exportedModule.importStatements << QStringLiteral("import qbs.") + builtinImport; } exportedModule.importStatements.sort(); } // TODO: This probably wouldn't be necessary if we had item serialization. std::unique_ptr ProductResolverStage2::resolveExportChild( const Item *item, const ExportedModule &module) { std::unique_ptr exportedItem(new ExportedItem); // This is the type of the built-in base item. It may turn out that we need to support // derived items under Export. In that case, we probably need a new Item member holding // the original type name. exportedItem->name = item->typeName(); transform(item->children(), exportedItem->children, [&module, this](const auto &child) { return resolveExportChild(child, module); }); setupExportedProperties(item, QString(), exportedItem->properties); return exportedItem; } void ProductResolverStage2::setupExportedProperties(const Item *item, const QString &namePrefix, std::vector &properties) { const auto &props = item->properties(); for (auto it = props.cbegin(); it != props.cend(); ++it) { const QString qualifiedName = namePrefix.isEmpty() ? it.key() : namePrefix + QLatin1Char('.') + it.key(); if ((item->type() == ItemType::Export || item->type() == ItemType::Properties) && qualifiedName == StringConstants::prefixMappingProperty()) { continue; } const ValuePtr &v = it.value(); if (v->type() == Value::ItemValueType) { setupExportedProperties(std::static_pointer_cast(v)->item(), qualifiedName, properties); continue; } ExportedProperty exportedProperty; exportedProperty.fullName = qualifiedName; exportedProperty.type = item->propertyDeclaration(it.key()).type(); if (v->type() == Value::VariantValueType) { exportedProperty.sourceCode = toJSLiteral( std::static_pointer_cast(v)->value()); } else { QBS_CHECK(v->type() == Value::JSSourceValueType); const JSSourceValue * const sv = static_cast(v.get()); exportedProperty.sourceCode = sv->sourceCode().toString(); } const ItemDeclaration itemDecl = BuiltinDeclarations::instance().declarationsForType(item->type()); PropertyDeclaration propertyDecl; const auto itemProperties = itemDecl.properties(); for (const PropertyDeclaration &decl : itemProperties) { if (decl.name() == it.key()) { propertyDecl = decl; exportedProperty.isBuiltin = true; break; } } // Do not add built-in properties that were left at their default value. if (!exportedProperty.isBuiltin || m_loaderState.evaluator().isNonDefaultValue(item, it.key())) { properties.push_back(exportedProperty); } } // Order the list of properties, so the output won't look so random. static const auto less = [](const ExportedProperty &p1, const ExportedProperty &p2) -> bool { const int p1ComponentCount = p1.fullName.count(QLatin1Char('.')); const int p2ComponentCount = p2.fullName.count(QLatin1Char('.')); if (p1.isBuiltin && !p2.isBuiltin) return true; if (!p1.isBuiltin && p2.isBuiltin) return false; if (p1ComponentCount < p2ComponentCount) return true; if (p1ComponentCount > p2ComponentCount) return false; return p1.fullName < p2.fullName; }; std::sort(properties.begin(), properties.end(), less); } QVariantMap ProductResolverStage2::evaluateModuleValues(Item *item, bool lookupPrototype) { QVariantMap moduleValues; for (const Item::Module &module : item->modules()) { if (!module.item->isPresentModule()) continue; const QString fullName = module.name.toString(); moduleValues[fullName] = m_propertiesEvaluator.evaluateProperties( module.item, lookupPrototype, true); } return moduleValues; } void ProductResolverStage2::resolveScanner(Item *item, ModuleContext *moduleContext) { Evaluator &evaluator = m_loaderState.evaluator(); if (!evaluator.boolValue(item, StringConstants::conditionProperty())) { qCDebug(lcProjectResolver) << "scanner condition is false"; return; } ResolvedScannerPtr scanner = ResolvedScanner::create(); scanner->module = moduleContext ? moduleContext->module : m_product.project->dummyModule; scanner->inputs = evaluator.fileTagsValue(item, StringConstants::inputsProperty()); scanner->recursive = evaluator.boolValue(item, StringConstants::recursiveProperty()); scanner->searchPathsScript.initialize(m_loaderState.topLevelProject().scriptFunctionValue( item, StringConstants::searchPathsProperty())); scanner->scanScript.initialize(m_loaderState.topLevelProject().scriptFunctionValue( item, StringConstants::scanProperty())); m_product.product->scanners.push_back(scanner); } void ProductResolverStage2::resolveModules() { JobLimits jobLimits; for (const Item::Module &m : m_product.item->modules()) resolveModule(m.name, m.item, m.product, m.parameters, jobLimits); for (int i = 0; i < jobLimits.count(); ++i) { const JobLimit &moduleJobLimit = jobLimits.jobLimitAt(i); if (m_product.product->jobLimits.getLimit(moduleJobLimit.pool()) == -1) m_product.product->jobLimits.setJobLimit(moduleJobLimit); } } void ProductResolverStage2::resolveModule(const QualifiedId &moduleName, Item *item, bool isProduct, const QVariantMap ¶meters, JobLimits &jobLimits) { if (!item->isPresentModule()) return; ModuleContext moduleContext; moduleContext.module = ResolvedModule::create(); const ResolvedModulePtr &module = moduleContext.module; module->name = moduleName.toString(); module->isProduct = isProduct; module->product = m_product.product.get(); module->setupBuildEnvironmentScript.initialize(m_loaderState.topLevelProject() .scriptFunctionValue(item, StringConstants::setupBuildEnvironmentProperty())); module->setupRunEnvironmentScript.initialize(m_loaderState.topLevelProject() .scriptFunctionValue(item, StringConstants::setupRunEnvironmentProperty())); for (const Item::Module &m : item->modules()) { if (m.item->isPresentModule()) module->moduleDependencies += m.name.toString(); } m_product.product->modules.push_back(module); if (!parameters.empty()) m_product.product->moduleParameters[module] = parameters; for (Item *child : item->children()) { switch (child->type()) { case ItemType::Rule: resolveRule(m_loaderState, child, nullptr, &m_product, &moduleContext); break; case ItemType::FileTagger: resolveFileTagger(m_loaderState, child, nullptr, &m_product); break; case ItemType::JobLimit: resolveJobLimit(m_loaderState, child, nullptr, nullptr, &moduleContext); break; case ItemType::Scanner: resolveScanner(child, &moduleContext); break; case ItemType::Group: resolveGroup(child, &moduleContext); break; default: break; } } for (int i = 0; i < moduleContext.jobLimits.count(); ++i) { const JobLimit &newJobLimit = moduleContext.jobLimits.jobLimitAt(i); const int oldLimit = jobLimits.getLimit(newJobLimit.pool()); if (oldLimit == -1 || oldLimit > newJobLimit.limit()) jobLimits.setJobLimit(newJobLimit); } } void ProductResolverStage2::applyFileTaggers() { m_product.product->fileTaggers << m_product.project->fileTaggers; m_product.product->fileTaggers = sorted(m_product.product->fileTaggers, [] (const FileTaggerConstPtr &a, const FileTaggerConstPtr &b) { return a->priority() > b->priority(); }); for (const SourceArtifactPtr &artifact : m_product.product->allEnabledFiles()) { if (!artifact->overrideFileTags || artifact->fileTags.empty()) { const QString fileName = FileInfo::fileName(artifact->absoluteFilePath); const FileTags fileTags = m_product.product->fileTagsForFileName(fileName); artifact->fileTags.unite(fileTags); if (artifact->fileTags.empty()) artifact->fileTags.insert(unknownFileTag()); qCDebug(lcProjectResolver) << "adding file tags" << artifact->fileTags << "to" << fileName; } } } void ProductResolverStage2::finalizeArtifactProperties() { for (const SourceArtifactPtr &artifact : m_product.product->allEnabledFiles()) { for (const auto &artifactProperties : m_product.product->artifactProperties) { if (!artifact->isTargetOfModule() && artifact->fileTags.intersects(artifactProperties->fileTagsFilter())) { // FIXME: Should be merged, not overwritten. artifact->properties = artifactProperties->propertyMap(); } } // Let a positive value of qbs.install imply the file tag "installable". if (artifact->properties->qbsPropertyValue(StringConstants::installProperty()).toBool()) artifact->fileTags += "installable"; } } void ProductResolverStage2::collectProductDependencies() { const ResolvedProductPtr &product = m_product.product; if (!product) return; for (const Item::Module &module : m_product.item->modules()) { if (!module.product) continue; const ResolvedProductPtr &dep = module.product->product; QBS_CHECK(dep); QBS_CHECK(dep != product); product->dependencies << dep; product->dependencyParameters.insert(dep, module.parameters); // TODO: Streamline this with normal module dependencies? } // TODO: We might want to keep the topological sorting and get rid of "module module dependencies". std::sort(product->dependencies.begin(),product->dependencies.end(), [](const ResolvedProductPtr &p1, const ResolvedProductPtr &p2) { return p1->fullDisplayName() < p2->fullDisplayName(); }); } void ExportsResolver::start() { resolveShadowProduct(); collectExportedProductDependencies(); } void ExportsResolver::resolveShadowProduct() { if (!m_product.product->enabled) return; if (!m_product.shadowProduct) return; for (const auto &m : m_product.shadowProduct->item->modules()) { if (m.name.toString() != m_product.product->name) continue; collectPropertiesForExportItem(m.item); for (const auto &dep : m.item->modules()) collectPropertiesForModuleInExportItem(dep); break; } try { adaptExportedPropertyValues(); } catch (const ErrorInfo &) {} } class TempScopeSetter { public: TempScopeSetter(const ValuePtr &value, Item *newScope) : m_value(value), m_oldScope(value->scope()) { value->setScope(newScope, {}); } ~TempScopeSetter() { if (m_value) m_value->setScope(m_oldScope, {}); } TempScopeSetter(const TempScopeSetter &) = delete; TempScopeSetter &operator=(const TempScopeSetter &) = delete; TempScopeSetter &operator=(TempScopeSetter &&) = delete; TempScopeSetter(TempScopeSetter &&other) noexcept : m_value(std::move(other.m_value)), m_oldScope(other.m_oldScope) { other.m_value.reset(); other.m_oldScope = nullptr; } private: ValuePtr m_value; Item *m_oldScope; }; void ExportsResolver::collectPropertiesForExportItem( const QualifiedId &moduleName, const ValuePtr &value, Item *moduleInstance, QVariantMap &moduleProps) { QBS_CHECK(value->type() == Value::ItemValueType); Item * const itemValueItem = std::static_pointer_cast(value)->item(); if (itemValueItem->propertyDeclarations().isEmpty()) { for (const Item::Module &module : moduleInstance->modules()) { if (module.name == moduleName) { itemValueItem->setPropertyDeclarations(module.item->propertyDeclarations()); break; } } } if (itemValueItem->type() == ItemType::ModuleInstancePlaceholder) { struct EvalPreparer { EvalPreparer(Item *valueItem, const QualifiedId &moduleName) : valueItem(valueItem), hadName(!!valueItem->variantProperty(StringConstants::nameProperty())) { if (!hadName) { // Evaluator expects a name here. valueItem->setProperty(StringConstants::nameProperty(), VariantValue::create(moduleName.toString())); } } ~EvalPreparer() { if (!hadName) valueItem->removeProperty(StringConstants::nameProperty()); } Item * const valueItem; const bool hadName; }; EvalPreparer ep(itemValueItem, moduleName); std::vector tss; for (const ValuePtr &v : itemValueItem->properties()) tss.emplace_back(v, moduleInstance); moduleProps.insert(moduleName.toString(), m_propertiesEvaluator.evaluateProperties( itemValueItem, false, false)); return; } QBS_CHECK(itemValueItem->type() == ItemType::ModulePrefix); const Item::PropertyMap &props = itemValueItem->properties(); for (auto it = props.begin(); it != props.end(); ++it) { QualifiedId fullModuleName = moduleName; fullModuleName << it.key(); collectPropertiesForExportItem(fullModuleName, it.value(), moduleInstance, moduleProps); } } void ExportsResolver::collectPropertiesForExportItem(Item *productModuleInstance) { if (!productModuleInstance->isPresentModule()) return; Item * const exportItem = productModuleInstance->prototype(); QBS_CHECK(exportItem); QBS_CHECK(exportItem->type() == ItemType::Export); const ItemDeclaration::Properties exportDecls = BuiltinDeclarations::instance() .declarationsForType(ItemType::Export).properties(); ExportedModule &exportedModule = m_product.product->exportedModule; const auto &props = exportItem->properties(); for (auto it = props.begin(); it != props.end(); ++it) { const auto match = [it](const PropertyDeclaration &decl) { return decl.name() == it.key(); }; if (it.key() != StringConstants::prefixMappingProperty() && std::find_if(exportDecls.begin(), exportDecls.end(), match) != exportDecls.end()) { continue; } if (it.value()->type() == Value::ItemValueType) { collectPropertiesForExportItem(it.key(), it.value(), productModuleInstance, exportedModule.modulePropertyValues); } else { TempScopeSetter tss(it.value(), productModuleInstance); m_propertiesEvaluator.evaluateProperty( exportItem, it.key(), it.value(), exportedModule.propertyValues, false); } } } // Collects module properties assigned to in other (higher-level) modules. void ExportsResolver::collectPropertiesForModuleInExportItem(const Item::Module &module) { if (!module.item->isPresentModule()) return; ExportedModule &exportedModule = m_product.product->exportedModule; if (module.product || module.name.first() == StringConstants::qbsModule()) return; const auto checkName = [module](const ExportedModuleDependency &d) { return module.name.toString() == d.name; }; if (any_of(exportedModule.moduleDependencies, checkName)) return; Item *modulePrototype = module.item->prototype(); while (modulePrototype && modulePrototype->type() != ItemType::Module) modulePrototype = modulePrototype->prototype(); if (!modulePrototype) // Can happen for broken products in relaxed mode. return; ModuleItemLocker locker(*modulePrototype); const Item::PropertyMap &props = modulePrototype->properties(); ExportedModuleDependency dep; dep.name = module.name.toString(); for (auto it = props.begin(); it != props.end(); ++it) { if (it.value()->type() == Value::ItemValueType) collectPropertiesForExportItem(it.key(), it.value(), module.item, dep.moduleProperties); } exportedModule.moduleDependencies.push_back(dep); for (const auto &dep : module.item->modules()) collectPropertiesForModuleInExportItem(dep); } void ExportsResolver::adaptExportedPropertyValues() { QBS_CHECK(m_product.shadowProduct); ExportedModule &m = m_product.product->exportedModule; const QVariantList prefixList = m.propertyValues.take( StringConstants::prefixMappingProperty()).toList(); const QString shadowProductName = m_loaderState.evaluator().stringValue( m_product.shadowProduct->item, StringConstants::nameProperty()); const QString shadowProductBuildDir = m_loaderState.evaluator().stringValue( m_product.shadowProduct->item, StringConstants::buildDirectoryProperty()); QVariantMap prefixMap; for (const QVariant &v : prefixList) { const QVariantMap o = v.toMap(); prefixMap.insert(o.value(QStringLiteral("prefix")).toString(), o.value(QStringLiteral("replacement")).toString()); } const auto valueRefersToImportingProduct = [shadowProductName, shadowProductBuildDir](const QString &value) { return value.toLower().contains(shadowProductName.toLower()) || value.contains(shadowProductBuildDir); }; static const auto stringMapper = [](const QVariantMap &mappings, const QString &value) -> QString { for (auto it = mappings.cbegin(); it != mappings.cend(); ++it) { if (value.startsWith(it.key())) return it.value().toString() + value.mid(it.key().size()); } return value; }; const auto stringListMapper = [&valueRefersToImportingProduct]( const QVariantMap &mappings, const QStringList &value) -> QStringList { QStringList result; result.reserve(value.size()); for (const QString &s : value) { if (!valueRefersToImportingProduct(s)) result.push_back(stringMapper(mappings, s)); } return result; }; const std::function mapper = [&stringListMapper, &mapper]( const QVariantMap &mappings, const QVariant &value) -> QVariant { switch (static_cast(value.userType())) { case QMetaType::QString: return stringMapper(mappings, value.toString()); case QMetaType::QStringList: return stringListMapper(mappings, value.toStringList()); case QMetaType::QVariantMap: { QVariantMap m = value.toMap(); for (auto it = m.begin(); it != m.end(); ++it) it.value() = mapper(mappings, it.value()); return m; } default: return value; } }; for (auto it = m.propertyValues.begin(); it != m.propertyValues.end(); ++it) it.value() = mapper(prefixMap, it.value()); for (auto it = m.modulePropertyValues.begin(); it != m.modulePropertyValues.end(); ++it) it.value() = mapper(prefixMap, it.value()); for (ExportedModuleDependency &dep : m.moduleDependencies) { for (auto it = dep.moduleProperties.begin(); it != dep.moduleProperties.end(); ++it) it.value() = mapper(prefixMap, it.value()); } } void ExportsResolver::collectExportedProductDependencies() { if (!m_product.shadowProduct) return; const ResolvedProductPtr exportingProduct = m_product.product; if (!exportingProduct || !exportingProduct->enabled) return; Item * const importingProductItem = m_product.shadowProduct->item; std::vector> directDeps; for (const Item::Module &m : importingProductItem->modules()) { if (m.name.toString() != exportingProduct->name) continue; for (const Item::Module &dep : m.item->modules()) { if (dep.product) directDeps.emplace_back(dep.product->product, m.parameters); } } for (const auto &dep : directDeps) { if (!contains(exportingProduct->exportedModule.productDependencies, dep.first->uniqueName())) { exportingProduct->exportedModule.productDependencies.push_back( dep.first->uniqueName()); } if (!dep.second.isEmpty()) { exportingProduct->exportedModule.dependencyParameters.insert(dep.first, dep.second); } } auto &productDeps = exportingProduct->exportedModule.productDependencies; std::sort(productDeps.begin(), productDeps.end()); } QVariantMap PropertiesEvaluator::evaluateProperties( const Item *item, const Item *propertiesContainer, const QVariantMap &tmplt, bool lookupPrototype, bool checkErrors) { AccumulatingTimer propEvalTimer(m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.propertyEvaluation : nullptr); QVariantMap result = tmplt; for (auto it = propertiesContainer->properties().begin(); it != propertiesContainer->properties().end(); ++it) { evaluateProperty(item, it.key(), it.value(), result, checkErrors); } return lookupPrototype && propertiesContainer->prototype() && propertiesContainer->prototype()->type() != ItemType::Module ? evaluateProperties(item, propertiesContainer->prototype(), result, true, checkErrors) : result; } QVariantMap PropertiesEvaluator::evaluateProperties(Item *item, bool lookupPrototype, bool checkErrors) { const QVariantMap tmplt; return evaluateProperties(item, item, tmplt, lookupPrototype, checkErrors); } void PropertiesEvaluator::evaluateProperty( const Item *item, const QString &propName, const ValuePtr &propValue, QVariantMap &result, bool checkErrors) { JSContext * const ctx = m_loaderState.evaluator().engine()->context(); switch (propValue->type()) { case Value::ItemValueType: { // Ignore items. Those point to module instances // and are handled in evaluateModuleValues(). break; } case Value::JSSourceValueType: { if (result.contains(propName)) break; const PropertyDeclaration pd = item->propertyDeclaration(propName); if (pd.flags().testFlag(PropertyDeclaration::PropertyNotAvailableInConfig)) { break; } const ScopedJsValue scriptValue(ctx, m_loaderState.evaluator().property(item, propName)); if (JsException ex = m_loaderState.evaluator().engine()->checkAndClearException( propValue->location())) { if (checkErrors) throw ex.toErrorInfo(); } // NOTE: Loses type information if scriptValue.isUndefined == true, // as such QScriptValues become invalid QVariants. QVariant v; if (JS_IsFunction(ctx, scriptValue)) { v = getJsString(ctx, scriptValue); } else { v = getJsVariant(ctx, scriptValue); QVariantMap m = v.toMap(); if (m.contains(StringConstants::importScopeNamePropertyInternal())) { QVariantMap tmp = m; const ScopedJsValue proto(ctx, JS_GetPrototype(ctx, scriptValue)); m = getJsVariant(ctx, proto).toMap(); for (auto it = tmp.begin(); it != tmp.end(); ++it) m.insert(it.key(), it.value()); v = m; } } if (pd.type() == PropertyDeclaration::Path && v.isValid()) { v = v.toString(); } else if (pd.type() == PropertyDeclaration::PathList || pd.type() == PropertyDeclaration::StringList) { v = v.toStringList(); } else if (pd.type() == PropertyDeclaration::VariantList) { v = v.toList(); } // Enforce proper type for undefined values (note that path degrades to string). if (!v.isValid()) v = pd.typedNullValue(); pd.checkAllowedValues(v, propValue->location(), propName, m_loaderState); result[propName] = v; break; } case Value::VariantValueType: { if (result.contains(propName)) break; VariantValuePtr vvp = std::static_pointer_cast(propValue); QVariant v = vvp->value(); const PropertyDeclaration pd = item->propertyDeclaration(propName); if (v.isNull() && !pd.isScalar()) // QTBUG-51237 v = QStringList(); pd.checkAllowedValues(v, propValue->location(), propName, m_loaderState); result[propName] = v; break; } } } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/groupshandler.cpp0000644000175100001660000002671214776170045022263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "groupshandler.h" #include "loaderutils.h" #include "moduleinstantiator.h" #include #include #include #include #include #include #include namespace qbs::Internal { class GroupsHandler { public: GroupsHandler(ProductContext &product, LoaderState &loaderState) : m_product(product), m_loaderState(loaderState) {} void run(); private: void gatherAssignedProperties(ItemValue *iv, const QualifiedId &prefix, QualifiedIdSet &properties); void markModuleTargetGroups(Item *group, const Item::Module &module); void propagateModulesFromParent(Item *group); void handleGroup(Item *group); void adjustScopesInGroupModuleInstances(Item *groupItem, const Item::Module &module); QualifiedIdSet gatherModulePropertiesSetInGroup(const Item *group); ProductContext &m_product; LoaderState &m_loaderState; }; void setupGroups(ProductContext &product, LoaderState &loaderState) { GroupsHandler(product, loaderState).run(); } void GroupsHandler::run() { AccumulatingTimer timer( m_loaderState.parameters().logElapsedTime() ? &m_product.timingData.groupsSetup : nullptr); for (Item * const child : m_product.item->children()) { if (child->type() == ItemType::Group) handleGroup(child); } for (const Item::Module &module : m_product.item->modules()) { if (!module.item->isPresentModule()) continue; for (Item * const child : module.item->children()) { if (child->type() == ItemType::Group) { markModuleTargetGroups(child, module); handleGroup(child); } } } } void GroupsHandler::gatherAssignedProperties(ItemValue *iv, const QualifiedId &prefix, QualifiedIdSet &properties) { const Item::PropertyMap &props = iv->item()->properties(); for (auto it = props.cbegin(); it != props.cend(); ++it) { switch (it.value()->type()) { case Value::JSSourceValueType: properties << (QualifiedId(prefix) << it.key()); break; case Value::ItemValueType: if (iv->item()->type() == ItemType::ModulePrefix) { gatherAssignedProperties(std::static_pointer_cast(it.value()).get(), QualifiedId(prefix) << it.key(), properties); } break; default: break; } } } void GroupsHandler::markModuleTargetGroups(Item *group, const Item::Module &module) { if (group->type() != ItemType::Group) return; if (m_loaderState.evaluator().boolValue(group, StringConstants::filesAreTargetsProperty())) { group->setProperty(StringConstants::modulePropertyInternal(), VariantValue::create(module.name.toString())); } for (Item * const child : group->children()) markModuleTargetGroups(child, module); } // TODO: I don't completely understand this function, and I suspect we do both too much // and too little here. In particular, I'm not sure why we should even have to do anything // with groups that don't attach properties. // Set aside a day or two at some point to fully grasp all the details and rewrite accordingly. void GroupsHandler::propagateModulesFromParent(Item *group) { QBS_CHECK(group->type() == ItemType::Group); QHash moduleInstancesForGroup; // Step 1: "Instantiate" the product's modules for the group. Item * const parentGroupOrProduct = group->parent()->type() == ItemType::ModuleInstance ? m_product.item : group->parent(); for (Item::Module m : parentGroupOrProduct->modules()) { Item * const targetItem = retrieveModuleInstanceItem(group, m.name, m_loaderState); QBS_CHECK(targetItem->type() == ItemType::ModuleInstancePlaceholder); targetItem->setPrototype(m.item); Item * const moduleScope = Item::create(&m_loaderState.itemPool(), ItemType::Scope); moduleScope->setFile(group->file()); moduleScope->setProperties(m.item->scope()->properties()); // "project", "product", ids moduleScope->setScope(group); targetItem->setScope(moduleScope); targetItem->setFile(m.item->file()); // "parent" should point to the group/artifact parent targetItem->setParent(group->parent()); targetItem->setOuterItem(m.item); m.item = targetItem; group->addModule(m); moduleInstancesForGroup.insert(m.name, targetItem); } // Step 2: Make the inter-module references point to the instances created in step 1. for (const Item::Module &module : group->modules()) { Item::Modules adaptedModules; const Item::Modules &oldModules = module.item->prototype()->modules(); for (Item::Module depMod : oldModules) { depMod.item = moduleInstancesForGroup.value(depMod.name); adaptedModules << depMod; if (depMod.name.front() == module.name.front()) continue; const ItemValuePtr &modulePrefix = group->itemProperty(depMod.name.front(), m_loaderState.itemPool()); QBS_CHECK(modulePrefix); module.item->setProperty(depMod.name.front(), modulePrefix); } module.item->setModules(adaptedModules); } const QualifiedIdSet &propsSetInGroup = gatherModulePropertiesSetInGroup(group); if (propsSetInGroup.empty()) return; m_product.modulePropertiesSetInGroups.insert(std::make_pair(group, propsSetInGroup)); // Step 3: Adapt scopes in values. This is potentially necessary if module properties // get assigned on the group level. for (const Item::Module &module : group->modules()) adjustScopesInGroupModuleInstances(group, module); } void GroupsHandler::handleGroup(Item *group) { propagateModulesFromParent(group); m_loaderState.topLevelProject().checkItemCondition(group, m_loaderState.evaluator()); for (Item * const child : group->children()) { if (child->type() == ItemType::Group) handleGroup(child); } } void GroupsHandler::adjustScopesInGroupModuleInstances(Item *groupItem, const Item::Module &module) { if (!module.item->isPresentModule()) return; Item *modulePrototype = module.item->rootPrototype(); QBS_CHECK(modulePrototype->type() == ItemType::Module || modulePrototype->type() == ItemType::Export); const Item::PropertyDeclarationMap &propDecls = modulePrototype->propertyDeclarations(); for (const auto &decl : propDecls) { const QString &propName = decl.name(); // Nothing gets inherited for module properties assigned directly in the group. // In particular, setting a list property overwrites the value from the product's // (or parent group's) instance completely, rather than appending to it // (concatenation happens via outer.concat()). ValuePtr propValue = module.item->ownProperty(propName); if (propValue) { propValue->setScope(module.item->scope(), {}); continue; } // Find the nearest prototype instance that has the value assigned. // The result is either an instance of a parent group (or the parent group's // parent group and so on) or the instance of the product or the module prototype. // In the latter case, we don't have to do anything. const Item *instanceWithProperty = module.item; do { instanceWithProperty = instanceWithProperty->prototype(); QBS_CHECK(instanceWithProperty); propValue = instanceWithProperty->ownProperty(propName); } while (!propValue); QBS_CHECK(propValue); if (propValue->type() != Value::JSSourceValueType) continue; if (propValue->scope()) module.item->setProperty(propName, propValue->clone(m_loaderState.itemPool())); } for (const ValuePtr &prop : module.item->properties()) { if (prop->type() != Value::JSSourceValueType) continue; const auto adjust = [groupItem](const ValuePtr &v) { if (!v->scope()) return; for (const Item::Module &module : groupItem->modules()) { if (v->scope() == module.item->prototype()) { v->setScope(module.item, {}); break; } } }; adjust(prop); const auto candidates = transformed>( prop->candidates(), [this](const ValuePtr &v) { return v->clone(m_loaderState.itemPool()); }); for (const ValuePtr &c : candidates) { adjust(c); } prop->setCandidates(candidates); } } QualifiedIdSet GroupsHandler::gatherModulePropertiesSetInGroup(const Item *group) { QualifiedIdSet propsSetInGroup; const Item::PropertyMap &props = group->properties(); for (auto it = props.cbegin(); it != props.cend(); ++it) { if (it.value()->type() == Value::ItemValueType) { gatherAssignedProperties(std::static_pointer_cast(it.value()).get(), QualifiedId(it.key()), propsSetInGroup); } } return propsSetInGroup; } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/loader/productitemmultiplexer.h0000644000175100001660000000461514776170045023703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs::Internal { class Item; class LoaderState; // Checks whether the product item is to be multiplexed and returns the list of additional // product items. In the normal, non-multiplex case, this list is empty. QList multiplex( const QString &productName, Item *productItem, Item *tempQbsModuleItem, const std::function &dropTempQbsModule, LoaderState &loaderState ); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/tools/0000755000175100001660000000000014776170045016564 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/tools/joblimits.h0000644000175100001660000000634114776170045020735 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JOB_LIMITS_H #define QBS_JOB_LIMITS_H #include "qbs_export.h" #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { class JobLimitPrivate; class JobLimitsPrivate; class PersistentPool; } class QBS_EXPORT JobLimit { public: JobLimit(); JobLimit(const QString &pool, int limit); JobLimit(const JobLimit &other); JobLimit &operator=(const JobLimit &other); ~JobLimit(); QString pool() const; int limit() const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool); private: QSharedDataPointer d; }; class QBS_EXPORT JobLimits { public: JobLimits(); JobLimits(const JobLimits &other); JobLimits &operator=(const JobLimits &other); ~JobLimits(); void setJobLimit(const JobLimit &limit); void setJobLimit(const QString &pool, int limit); int getLimit(const QString &pool) const; bool hasLimit(const QString &pool) const { return getLimit(pool) != -1; } bool isEmpty() const; int count() const; JobLimit jobLimitAt(int i) const; JobLimits &update(const JobLimits &other); void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool); private: QSharedDataPointer d; }; } // namespace qbs #endif // include guard qbs-src-2.6.1/src/lib/corelib/tools/buildgraphlocker.cpp0000644000175100001660000001420614776170045022614 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "buildgraphlocker.h" #include "error.h" #include "hostosinfo.h" #include "processutils.h" #include "progressobserver.h" #include "stringconstants.h" #include #include #include #include #include namespace qbs { namespace Internal { DirectoryManager::DirectoryManager(QString dir, Logger logger) : m_dir(std::move(dir)), m_logger(std::move(logger)) { rememberCreatedDirectories(); } DirectoryManager::~DirectoryManager() { removeEmptyCreatedDirectories(); } void DirectoryManager::rememberCreatedDirectories() { QString parentDir = m_dir; while (!QFileInfo::exists(parentDir)) { m_createdParentDirs.push(parentDir); parentDir = QDir::cleanPath(parentDir + StringConstants::slashDotDot()); } } void DirectoryManager::removeEmptyCreatedDirectories() { QDir root = QDir::root(); while (!m_createdParentDirs.empty()) { const QString parentDir = m_createdParentDirs.front(); m_createdParentDirs.pop(); QDirIterator it(parentDir, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System, QDirIterator::Subdirectories); if (it.hasNext()) break; if (!root.rmdir(parentDir) && m_logger.logSink()) { m_logger.printWarning(ErrorInfo(Tr::tr("Failed to remove empty directory '%1'.") .arg(parentDir))); } } } static void tryCreateBuildDirectory(const QString &buildDir, const QString &buildGraphFilePath) { if (!QDir::root().mkpath(buildDir)) { throw ErrorInfo(Tr::tr("Cannot lock build graph file '%1': Failed to create directory.") .arg(buildGraphFilePath)); } } static bool appNamesAreEqual(const QString &app1, const QString &app2) { return QString::compare(app1, app2, HostOsInfo::fileNameCaseSensitivity()) == 0; } BuildGraphLocker::BuildGraphLocker(const QString &buildGraphFilePath, const Logger &logger, bool waitIndefinitely, ProgressObserver *observer) : m_lockFile(buildGraphFilePath + QStringLiteral(".lock")) , m_logger(logger) , m_dirManager(QFileInfo(buildGraphFilePath).absolutePath(), logger) { if (waitIndefinitely) m_logger.qbsDebug() << "Waiting to acquire lock file..."; m_lockFile.setStaleLockTime(0); int attemptsToGetInfo = 0; do { if (observer && observer->canceled()) break; tryCreateBuildDirectory(m_dirManager.dir(), buildGraphFilePath); if (m_lockFile.tryLock(250)) return; switch (m_lockFile.error()) { case QLockFile::LockFailedError: { if (waitIndefinitely) continue; qint64 pid; QString hostName; QString appName; if (m_lockFile.getLockInfo(&pid, &hostName, &appName)) { if (appNamesAreEqual(appName, processNameByPid(pid))) { throw ErrorInfo(Tr::tr("Cannot lock build graph file '%1': " "Already locked by '%2' (PID %3).") .arg(buildGraphFilePath, appName).arg(pid)); } // The process id was reused by some other process. m_logger.qbsInfo() << Tr::tr("Removing stale lock file."); m_lockFile.removeStaleLockFile(); } break; } case QLockFile::PermissionError: throw ErrorInfo(Tr::tr("Cannot lock build graph file '%1': Permission denied.") .arg(buildGraphFilePath)); case QLockFile::UnknownError: case QLockFile::NoError: throw ErrorInfo(Tr::tr("Cannot lock build graph file '%1' (reason unknown).") .arg(buildGraphFilePath)); } } while (++attemptsToGetInfo < 10 || waitIndefinitely); // This very unlikely case arises if tryLock() repeatedly returns LockFailedError // with the subsequent getLockInfo() failing as well. throw ErrorInfo(Tr::tr("Cannot lock build graph file '%1' (reason unknown).") .arg(buildGraphFilePath)); } BuildGraphLocker::~BuildGraphLocker() { m_lockFile.unlock(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/filetime.cpp0000644000175100001660000001340114776170045021065 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filetime.h" #include #ifdef Q_OS_WIN #include #else #include #endif namespace qbs { namespace Internal { #if defined(Q_OS_WIN) FileTime::FileTime() { static_assert(sizeof(FileTime::InternalType) == sizeof(FILETIME), "FileTime::InternalType has wrong size."); m_fileTime = 0; } FileTime::FileTime(const FileTime::InternalType &ft) : m_fileTime(ft) { } int FileTime::compare(const FileTime &other) const { auto const t1 = reinterpret_cast(&m_fileTime); auto const t2 = reinterpret_cast(&other.m_fileTime); return CompareFileTime(t1, t2); } void FileTime::clear() { m_fileTime = 0; } bool FileTime::isValid() const { return *this != FileTime(); } FileTime FileTime::currentTime() { FileTime result; SYSTEMTIME st; GetSystemTime(&st); auto const ft = reinterpret_cast(&result.m_fileTime); SystemTimeToFileTime(&st, ft); return result; } FileTime FileTime::oldestTime() { SYSTEMTIME st = { 1601, 1, 5, 2, 0, 0, 0, 0 }; FileTime result; auto const ft = reinterpret_cast(&result.m_fileTime); SystemTimeToFileTime(&st, ft); return result; } double FileTime::asDouble() const { return static_cast(m_fileTime); } QString FileTime::toString() const { auto const ft = reinterpret_cast(&m_fileTime); SYSTEMTIME stUTC, stLocal; FileTimeToSystemTime(ft, &stUTC); SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal); const QString result = QStringLiteral("%1.%2.%3 %4:%5:%6") .arg(stLocal.wDay, 2, 10, QLatin1Char('0')).arg(stLocal.wMonth, 2, 10, QLatin1Char('0')).arg(stLocal.wYear) .arg(stLocal.wHour, 2, 10, QLatin1Char('0')).arg(stLocal.wMinute, 2, 10, QLatin1Char('0')).arg(stLocal.wSecond, 2, 10, QLatin1Char('0')); return result; } #else // defined(Q_OS_WIN) // based on https://github.com/qt/qtbase/blob/5.13/src/corelib/kernel/qelapsedtimer_unix.cpp // for details why it is implemented this way, see Qt source code # if !defined(CLOCK_REALTIME) # define CLOCK_REALTIME 0 static inline void qbs_clock_gettime(int, struct timespec *ts) { // support clock_gettime with gettimeofday struct timeval tv; gettimeofday(&tv, 0); ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec * 1000; } # ifdef _POSIX_MONOTONIC_CLOCK # undef _POSIX_MONOTONIC_CLOCK # define _POSIX_MONOTONIC_CLOCK -1 # endif # else static inline void qbs_clock_gettime(clockid_t clock, struct timespec *ts) { clock_gettime(clock, ts); } # endif FileTime::FileTime() { m_fileTime = {0, 0}; } FileTime::FileTime(const FileTime::InternalType &ft) : m_fileTime(ft) { if (m_fileTime.tv_sec == 0) m_fileTime.tv_nsec = 0; // stat() sets only the first member to 0 for non-existing files. } int FileTime::compare(const FileTime &other) const { if (m_fileTime.tv_sec < other.m_fileTime.tv_sec) return -1; if (m_fileTime.tv_sec > other.m_fileTime.tv_sec) return 1; if (m_fileTime.tv_nsec < other.m_fileTime.tv_nsec) return -1; if (m_fileTime.tv_nsec > other.m_fileTime.tv_nsec) return 1; return 0; } void FileTime::clear() { m_fileTime = { 0, 0 }; } bool FileTime::isValid() const { return *this != FileTime(); } FileTime FileTime::currentTime() { InternalType t; qbs_clock_gettime(CLOCK_REALTIME, &t); return t; } FileTime FileTime::oldestTime() { return FileTime({1, 0}); } double FileTime::asDouble() const { return static_cast(m_fileTime.tv_sec); } QString FileTime::toString() const { QDateTime dt; dt.setMSecsSinceEpoch(m_fileTime.tv_sec * 1000 + m_fileTime.tv_nsec / 1000000); return dt.toString(Qt::ISODateWithMs); } #endif // defined(Q_OS_WIN) } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/scannerpluginmanager.cpp0000644000175100001660000000604214776170045023475 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scannerpluginmanager.h" #include #include namespace qbs { namespace Internal { class ScannerPluginManagerPrivate { public: std::map> scannerPlugins; }; ScannerPluginManager::~ScannerPluginManager() = default; ScannerPluginManager *ScannerPluginManager::instance() { static ScannerPluginManager scannerPlugin; return &scannerPlugin; } ScannerPluginManager::ScannerPluginManager() : d(new ScannerPluginManagerPrivate) { } std::vector ScannerPluginManager::scannersForFileTag(const FileTag &fileTag) { auto it = instance()->d->scannerPlugins.find(fileTag); if (it != instance()->d->scannerPlugins.cend()) return it->second; return {}; } void ScannerPluginManager::registerPlugins(ScannerPlugin **plugins) { for (int i = 0; plugins[i] != nullptr; ++i) { const FileTags &fileTags = FileTags::fromStringList( QString::fromLatin1(plugins[i]->fileTags).split(QLatin1Char(','))); for (const FileTag &tag : fileTags) d->scannerPlugins[tag].push_back(plugins[i]); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/projectgeneratormanager.h0000644000175100001660000000515714776170045023655 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECTGENERATORMANAGER_H #define QBS_PROJECTGENERATORMANAGER_H #include #include #include #include namespace qbs { class ProjectGenerator; class QBS_EXPORT ProjectGeneratorManager { public: ~ProjectGeneratorManager(); static ProjectGeneratorManager *instance(); static QStringList loadedGeneratorNames(); static std::shared_ptr findGenerator(const QString &generatorName); static void registerGenerator(const std::shared_ptr &generator); private: ProjectGeneratorManager(); private: QMap > m_generators; }; } // namespace qbs #endif qbs-src-2.6.1/src/lib/corelib/tools/qbspluginmanager.cpp0000644000175100001660000001255214776170045022634 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qbspluginmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { struct QbsPlugin { QbsPluginLoadFunction load; QbsPluginUnloadFunction unload; bool loaded; }; class QbsPluginManagerPrivate { public: std::vector staticPlugins; std::vector libs; }; QbsPluginManager::QbsPluginManager() : d(new QbsPluginManagerPrivate) { } QbsPluginManager::~QbsPluginManager() { unloadStaticPlugins(); for (QLibrary * const lib : std::as_const(d->libs)) { auto unload = reinterpret_cast(lib->resolve("QbsPluginUnload")); if (unload) unload(); lib->unload(); delete lib; } } QbsPluginManager *QbsPluginManager::instance() { static QbsPluginManager instance; return &instance; } void QbsPluginManager::registerStaticPlugin(QbsPluginLoadFunction load, QbsPluginUnloadFunction unload) { if (none_of(d->staticPlugins, [&load](const QbsPlugin &p) { return p.load == load; })) d->staticPlugins.push_back(QbsPlugin { load, unload, false }); } void QbsPluginManager::loadStaticPlugins() { for (const auto &plugin : d->staticPlugins) { if (!plugin.loaded && plugin.load) plugin.load(); } } void QbsPluginManager::unloadStaticPlugins() { for (auto &plugin : d->staticPlugins) { if (plugin.loaded && plugin.unload) plugin.unload(); } d->staticPlugins.clear(); } void QbsPluginManager::loadPlugins(const std::vector &pluginPaths, const Logger &logger) { QStringList filters; if (HostOsInfo::isWindowsHost()) { filters << QStringLiteral("*.dll"); } else if (HostOsInfo::isMacosHost()) { filters << QStringLiteral("*.bundle") << QStringLiteral("*.dylib") << QStringLiteral("*.so"); } else { filters << QStringLiteral("*.so"); } for (const std::string &pluginPath : pluginPaths) { const QString qtPluginPath = QString::fromStdString(pluginPath); qCDebug(lcPluginManager) << "loading plugins from" << QDir::toNativeSeparators(qtPluginPath); QDirIterator it(qtPluginPath, filters, QDir::Files); while (it.hasNext()) { const QString fileName = it.next(); std::unique_ptr lib(new QLibrary(fileName)); if (!lib->load()) { logger.qbsWarning() << Tr::tr("plugin manager: Cannot load plugin '%1': %2") .arg(QDir::toNativeSeparators(fileName), lib->errorString()); continue; } auto load = reinterpret_cast(lib->resolve("QbsPluginLoad")); if (load) { load(); qCDebug(lcPluginManager) << "plugin" << QDir::toNativeSeparators(fileName) << "loaded."; d->libs.push_back(lib.release()); } else { logger.qbsWarning() << Tr::tr("plugin manager: not a qbs plugin"); } } } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/qbsassert.h0000644000175100001660000000557614776170045020761 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_QBSASSERT_H #define QBS_QBSASSERT_H #include "qbs_export.h" namespace qbs { namespace Internal { QBS_EXPORT void writeAssertLocation(const char *condition, const char *file, int line); [[noreturn]] QBS_EXPORT void throwAssertLocation(const char *condition, const char *file, int line); } // namespace Internal } // namespace qbs #define QBS_ASSERT(cond, action)\ if (Q_LIKELY(cond)) {} else {\ ::qbs::Internal::writeAssertLocation(#cond, __FILE__, __LINE__); action;\ } do {} while (0) // The do {} while (0) is here to enforce the use of a semicolon after QBS_ASSERT. // action can also be continue or break. Copied from qtcassert.h in Qt Creator. #define QBS_GUARD(cond) \ (Q_LIKELY(cond) \ ? true \ : (::qbs::Internal::writeAssertLocation(#cond, __FILE__, __LINE__), false)) #define QBS_CHECK(cond)\ do {\ if (Q_LIKELY(cond)) {} else {\ ::qbs::Internal::throwAssertLocation(#cond, __FILE__, __LINE__);\ }\ } while (0) #endif // QBS_QBSASSERT_H qbs-src-2.6.1/src/lib/corelib/tools/joblimits.cpp0000644000175100001660000001202614776170045021265 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "joblimits.h" #include #include #include namespace qbs { namespace Internal { static int transformLimit(int limitFromUser) { return limitFromUser == 0 ? std::numeric_limits::max() : limitFromUser < -1 ? -1 : limitFromUser; } class JobLimitPrivate : public QSharedData { public: JobLimitPrivate(const QString &pool, int limit) : jobLimit(std::make_pair(pool, transformLimit(limit))) { } template void serializationOp(PersistentPool &pool) { pool.serializationOp(jobLimit); } std::pair jobLimit; }; class JobLimitsPrivate : public QSharedData { public: template void serializationOp(PersistentPool &pool) { pool.serializationOp(jobLimits); } std::vector jobLimits; }; } // namespace Internal JobLimit::JobLimit() : JobLimit(QString(), -1) { } JobLimit::JobLimit(const QString &pool, int limit) : d(new Internal::JobLimitPrivate(pool, limit)) { } JobLimit::JobLimit(const JobLimit &other) = default; JobLimit &JobLimit::operator=(const JobLimit &other) = default; JobLimit::~JobLimit() = default; QString JobLimit::pool() const { return d->jobLimit.first; } int JobLimit::limit() const { return d->jobLimit.second; } void JobLimit::load(Internal::PersistentPool &pool) { d->serializationOp(pool); } void JobLimit::store(Internal::PersistentPool &pool) { d->serializationOp(pool); } JobLimits::JobLimits() : d(new Internal::JobLimitsPrivate) { } JobLimits::JobLimits(const JobLimits &other) = default; JobLimits &JobLimits::operator=(const JobLimits &other) = default; JobLimits::~JobLimits() = default; void JobLimits::setJobLimit(const JobLimit &limit) { for (auto ¤tLimit : d->jobLimits) { if (currentLimit.pool() == limit.pool()) { if (currentLimit.limit() != limit.limit()) currentLimit = limit; return; } } d->jobLimits.push_back(limit); } void JobLimits::setJobLimit(const QString &pool, int limit) { setJobLimit(JobLimit(pool, limit)); } int JobLimits::getLimit(const QString &pool) const { for (const JobLimit &l : d->jobLimits) { if (l.pool() == pool) return l.limit(); } return -1; } bool JobLimits::isEmpty() const { return d->jobLimits.empty(); } int JobLimits::count() const { return int(d->jobLimits.size()); } JobLimit JobLimits::jobLimitAt(int i) const { return d->jobLimits.at(i); } JobLimits &JobLimits::update(const JobLimits &other) { if (isEmpty()) { *this = other; } else { for (int i = 0; i < other.count(); ++i) { const JobLimit &l = other.jobLimitAt(i); if (l.limit() != -1) setJobLimit(l); } } return *this; } void JobLimits::load(Internal::PersistentPool &pool) { d->serializationOp(pool); } void JobLimits::store(Internal::PersistentPool &pool) { d->serializationOp(pool); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/applecodesignutils.cpp0000644000175100001660000001406314776170045023172 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "applecodesignutils.h" #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { QByteArray smimeMessageContent(const QByteArray &data) { QCFType decoder = NULL; if (CMSDecoderCreate(&decoder) != noErr) return {}; if (CMSDecoderUpdateMessage(decoder, data.constData(), data.size()) != noErr) return {}; if (CMSDecoderFinalizeMessage(decoder) != noErr) return {}; QCFType content = NULL; if (CMSDecoderCopyContent(decoder, &content) != noErr) return {}; 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: // 1.2.840.113635.100.4.13 - Developer ID Installer: const auto extensions = cert.extensions(); for (const auto &extension : extensions) { if (extension.name() == QStringLiteral("extendedKeyUsage")) { if (!extension.value().toStringList().contains(QStringLiteral("Code Signing"))) return {}; } } const auto subjectInfo = [](const QSslCertificate &cert) { QVariantMap map; const auto attributes = cert.subjectInfoAttributes(); for (const auto &attr : attributes) map.insert(QString::fromUtf8(attr), cert.subjectInfo(attr).front()); return map; }; const auto sha1 = QString::fromLatin1(cert.digest(QCryptographicHash::Sha1).toHex().toUpper()); return { {QStringLiteral("SHA1"), sha1}, {QStringLiteral("subjectInfo"), subjectInfo(cert)}, {QStringLiteral("validAfter"), cert.effectiveDate()}, {QStringLiteral("validBefore"), cert.expiryDate()} }; } QVariantMap identitiesProperties() { // Apple documentation states that the Sec* family of functions are not thread-safe on macOS // https://developer.apple.com/library/mac/documentation/Security/Reference/certifkeytrustservices/ static std::mutex securityMutex; std::lock_guard locker(securityMutex); Q_UNUSED(locker); const void *keys[] = {kSecClass, kSecMatchLimit, kSecAttrCanSign}; const void *values[] = {kSecClassIdentity, kSecMatchLimitAll, kCFBooleanTrue}; QCFType query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); QCFType result = NULL; if (SecItemCopyMatching(query, &result) != errSecSuccess) return {}; QVariantMap items; const auto tryAppend = [&](SecIdentityRef identity) { if (!identity) return; QCFType certificate = NULL; if (SecIdentityCopyCertificate(identity, &certificate) != errSecSuccess) return; QCFType certificateData = SecCertificateCopyData(certificate); if (!certificateData) return; auto props = certificateInfo(QByteArray::fromRawCFData(certificateData)); if (!props.empty()) 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(), i)); } return items; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/visualstudioversioninfo.h0000644000175100001660000000560514776170045023760 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_VISUALSTUDIOVERSIONINFO_H #define QBS_VISUALSTUDIOVERSIONINFO_H #include "qbs_export.h" #include #include #include #include namespace qbs { namespace Internal { class QBS_EXPORT VisualStudioVersionInfo { public: VisualStudioVersionInfo(); VisualStudioVersionInfo(const Version &version); static std::set knownVersions(); bool operator<(const VisualStudioVersionInfo &other) const; bool operator==(const VisualStudioVersionInfo &other) const; bool usesMsBuild() const; bool usesVcBuild() const; bool usesSolutions() const; Version version() const; int marketingVersion() const; QString solutionVersion() const; QString toolsVersion() const; QString platformToolsetVersion() const; private: Version m_version; }; QHashValueType qHash(const VisualStudioVersionInfo &info); } // namespace Internal } // namespace qbs #endif // QBS_VISUALSTUDIOVERSIONINFO_H qbs-src-2.6.1/src/lib/corelib/tools/shellutils.h0000644000175100001660000000731014776170045021126 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Petroules Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SHELLUTILS_H #define QBS_SHELLUTILS_H #include "qbs_export.h" #include "hostosinfo.h" #include #include namespace qbs { namespace Internal { QBS_EXPORT QString shellInterpreter(const QString &filePath); QBS_EXPORT std::string shellQuote(const std::string &arg, HostOsInfo::HostOs os = HostOsInfo::hostOs()); QBS_EXPORT QString shellQuote(const QString &arg, HostOsInfo::HostOs os = HostOsInfo::hostOs()); QBS_EXPORT QString shellQuote(const QStringList &args, HostOsInfo::HostOs os = HostOsInfo::hostOs()); QBS_EXPORT std::string shellQuote(const std::vector &args, HostOsInfo::HostOs os = HostOsInfo::hostOs()); QBS_EXPORT QString shellQuote(const QString &program, const QStringList &args, HostOsInfo::HostOs os = HostOsInfo::hostOs()); class QBS_EXPORT CommandLine { public: void setProgram(const QString &program, bool raw = false); void setProgram(const std::string &program, bool raw = false); void appendArgument(const QString &value); void appendArgument(const std::string &value); void appendArguments(const QList &args); void appendRawArgument(const QString &value); void appendRawArgument(const std::string &value); void appendPathArgument(const QString &value); void clearArguments(); QString toCommandLine(HostOsInfo::HostOs os = HostOsInfo::hostOs()) const; private: struct Argument { Argument(QString value = QString()) : value(std::move(value)) { } QString value; bool isFilePath = false; bool shouldQuote = true; }; bool m_isRawProgram = false; QString m_program; std::vector m_arguments; }; } // namespace Internal } // namespace qbs #endif // QBS_SHELLUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/launcherinterface.cpp0000644000175100001660000001316614776170045022761 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "launcherinterface.h" #include "launcherpackets.h" #include "launchersocket.h" #include "qbsassert.h" #include #include #include #include #include #include #include #ifdef Q_OS_UNIX #include #endif namespace qbs { namespace Internal { class LauncherProcess : public QProcess { public: LauncherProcess(QObject *parent) : QProcess(parent) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_UNIX) setChildProcessModifier([this] { setupChildProcess_impl(); }); #endif } private: #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void setupChildProcess() override { setupChildProcess_impl(); } #endif void setupChildProcess_impl() { #ifdef Q_OS_UNIX const auto pid = static_cast(processId()); setpgid(pid, pid); #endif } }; static QString launcherSocketName() { return QStringLiteral("qbs_processlauncher-%1") .arg(QString::number(qApp->applicationPid())); } LauncherInterface::LauncherInterface() : m_server(new QLocalServer(this)), m_socket(new LauncherSocket(this)) { QObject::connect(m_server, &QLocalServer::newConnection, this, &LauncherInterface::handleNewConnection); } LauncherInterface &LauncherInterface::instance() { static LauncherInterface p; return p; } LauncherInterface::~LauncherInterface() { m_server->disconnect(); } void LauncherInterface::doStart() { if (++m_startRequests > 1) return; const QString &socketName = launcherSocketName(); QLocalServer::removeServer(socketName); if (!m_server->listen(socketName)) { emit errorOccurred(ErrorInfo(m_server->errorString())); return; } m_process = new LauncherProcess(this); connect(m_process, &QProcess::errorOccurred, this, &LauncherInterface::handleProcessError); connect(m_process, static_cast(&QProcess::finished), this, &LauncherInterface::handleProcessFinished); connect(m_process, &QProcess::readyReadStandardError, this, &LauncherInterface::handleProcessStderr); m_process->start(qApp->applicationDirPath() + QLatin1Char('/') + QLatin1String(QBS_RELATIVE_LIBEXEC_PATH) + QLatin1String("/qbs_processlauncher"), QStringList(m_server->fullServerName())); } void LauncherInterface::doStop() { if (--m_startRequests > 0) return; m_server->close(); if (!m_process) return; m_process->disconnect(); m_socket->shutdown(); m_process->waitForFinished(3000); m_process->deleteLater(); m_process = nullptr; } void LauncherInterface::handleNewConnection() { QLocalSocket * const socket = m_server->nextPendingConnection(); if (!socket) return; m_server->close(); m_socket->setSocket(socket); } void LauncherInterface::handleProcessError() { if (m_process->error() == QProcess::FailedToStart) { const QString launcherPathForUser = QDir::toNativeSeparators(QDir::cleanPath(m_process->program())); emit errorOccurred(ErrorInfo(Tr::tr("Failed to start process launcher at '%1': %2") .arg(launcherPathForUser, m_process->errorString()))); } } void LauncherInterface::handleProcessFinished() { emit errorOccurred(ErrorInfo(Tr::tr("Process launcher closed unexpectedly: %1") .arg(m_process->errorString()))); } void LauncherInterface::handleProcessStderr() { qDebug() << "[launcher]" << m_process->readAllStandardError(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/id.h0000644000175100001660000000670714776170045017343 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TOOLS_ID_H #define QBS_TOOLS_ID_H #include "qbs_export.h" #include #include #include #include namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT Id { public: enum { IdsPerPlugin = 10000, ReservedPlugins = 1000 }; Id() : m_id(0) {} Id(int uid) : m_id(uid) {} Id(const char *name); explicit Id(const QByteArray &name); Id withSuffix(int suffix) const; Id withSuffix(const char *name) const; Id withPrefix(const char *name) const; QByteArray name() const; QString toString() const; // Avoid. QVariant toSetting() const; // Good to use. bool isValid() const { return m_id; } bool operator==(Id id) const { return m_id == id.m_id; } bool operator==(const char *name) const; bool operator!=(Id id) const { return m_id != id.m_id; } bool operator!=(const char *name) const { return !operator==(name); } bool operator<(Id id) const { return m_id < id.m_id; } bool operator>(Id id) const { return m_id > id.m_id; } bool alphabeticallyBefore(Id other) const; int uniqueIdentifier() const { return m_id; } static Id fromUniqueIdentifier(int uid) { return {uid}; } static Id fromSetting(const QVariant &variant); // Good to use. private: // Intentionally unimplemented Id(const QLatin1String &); int m_id; }; inline QHashValueType qHash(const Id &id) { return id.uniqueIdentifier(); } } // namespace Internal } // namespace qbs Q_DECLARE_METATYPE(qbs::Internal::Id) Q_DECLARE_METATYPE(QList) #endif // QBS_TOOLS_ID_H qbs-src-2.6.1/src/lib/corelib/tools/processutils.h0000644000175100001660000000423314776170045021476 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROCESSUTILS_H #define QBS_PROCESSUTILS_H #include #include #include namespace qbs { namespace Internal { QString QBS_AUTOTEST_EXPORT processNameByPid(qint64 pid); } // namespace Internal } // namespace qbs #endif // QBS_PROCESSUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/qttools.cpp0000644000175100001660000000610614776170045021000 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qttools.h" #include "porting.h" #include namespace std { size_t hash::operator()(const QVariant &v) const noexcept { switch (v.userType()) { case QMetaType::UnknownType: return 0; case QMetaType::Bool: return std::hash()(v.toBool()); case QMetaType::Int: return std::hash()(v.toInt()); case QMetaType::UInt: return std::hash()(v.toUInt()); case QMetaType::QString: return std::hash()(v.toString()); case QMetaType::QStringList: return std::hash()(v.toStringList()); case QMetaType::QVariantList: return std::hash()(v.toList()); case QMetaType::QVariantMap: return std::hash()(v.toMap()); case QMetaType::QVariantHash: return std::hash()(v.toHash()); default: QBS_ASSERT("Unsupported variant type" && false, return 0); } } } // namespace std QT_BEGIN_NAMESPACE qbs::QHashValueType qHash(const QStringList &list) { qbs::QHashValueType s = 0; for (const QString &n : list) s ^= qHash(n) + 0x9e3779b9 + (s << 6) + (s >> 2); return s; } qbs::QHashValueType qHash(const QProcessEnvironment &env) { return qHash(env.toStringList()); } QT_END_NAMESPACE qbs-src-2.6.1/src/lib/corelib/tools/projectgeneratormanager.cpp0000644000175100001660000000567314776170045024213 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "projectgeneratormanager.h" #include #include #include #include #include #include namespace qbs { using namespace Internal; ProjectGeneratorManager::~ProjectGeneratorManager() = default; ProjectGeneratorManager *ProjectGeneratorManager::instance() { static ProjectGeneratorManager generatorPlugin; return &generatorPlugin; } ProjectGeneratorManager::ProjectGeneratorManager() = default; QStringList ProjectGeneratorManager::loadedGeneratorNames() { return instance()->m_generators.keys(); } std::shared_ptr ProjectGeneratorManager::findGenerator(const QString &generatorName) { return instance()->m_generators.value(generatorName); } void ProjectGeneratorManager::registerGenerator(const std::shared_ptr &generator) { if (!findGenerator(generator->generatorName())) instance()->m_generators.insert(generator->generatorName(), generator); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/buildgraphlocker.h0000644000175100001660000000544214776170045022263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPHLOCKER_H #define QBS_BUILDGRAPHLOCKER_H #include #include #include #include namespace qbs { namespace Internal { class ProgressObserver; class DirectoryManager { public: DirectoryManager(QString dir, Logger logger); ~DirectoryManager(); QString dir() const { return m_dir; } private: void rememberCreatedDirectories(); void removeEmptyCreatedDirectories(); std::queue m_createdParentDirs; const QString m_dir; Logger m_logger; }; class BuildGraphLocker { public: explicit BuildGraphLocker(const QString &buildGraphFilePath, const Logger &logger, bool waitIndefinitely, ProgressObserver *observer); ~BuildGraphLocker(); private: QLockFile m_lockFile; Logger m_logger; DirectoryManager m_dirManager; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/tools/profiling.h0000644000175100001660000000520314776170045020726 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROFILING_H #define QBS_PROFILING_H #include #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { class Logger; QString elapsedTimeString(qint64 elapsedTimeInNs); class TimedActivityLogger { public: TimedActivityLogger(const Logger &logger, const QString &activity, bool enabled); void finishActivity(); ~TimedActivityLogger(); private: class TimedActivityLoggerPrivate; std::unique_ptr d; }; class AccumulatingTimer { public: AccumulatingTimer(qint64 *elapsedTime); ~AccumulatingTimer(); void stop(); private: QElapsedTimer m_timer; qint64 * const m_elapsedTime; }; } // namespace Internal } // namespace qbs #endif // Header guard qbs-src-2.6.1/src/lib/corelib/tools/porting.h0000644000175100001660000000410714776170045020421 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TOOLS_PORTING_H #define QBS_TOOLS_PORTING_H #include namespace qbs { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) using QHashValueType = uint; #else using QHashValueType = size_t; #endif } #endif qbs-src-2.6.1/src/lib/corelib/tools/settingscreator.h0000644000175100001660000000504714776170045022163 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETTINGSCREATOR_H #define QBS_SETTINGSCREATOR_H #include "version.h" #include #include QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE namespace qbs { namespace Internal { class SettingsCreator { public: SettingsCreator(QString baseDir); std::unique_ptr getQSettings(); private: void migrate(); void createQSettings(); Version predecessor() const; QString m_settingsBaseDir; QString m_newSettingsDir; QString m_settingsFileName; QString m_newSettingsFilePath; std::unique_ptr m_settings; const Version m_qbsVersion; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/tools/settingsrepresentation.cpp0000644000175100001660000000672114776170045024121 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "settingsrepresentation.h" #include "jsliterals.h" #include #include namespace qbs { QString settingsValueToRepresentation(const QVariant &value) { return toJSLiteral(value); } static QVariant variantFromString(const QString &str, bool &ok) { // ### use Qt5's JSON reader at some point. class DummyLogSink : public ILogSink { void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } } logSink; Internal::Logger logger(&logSink); const auto engine = Internal::ScriptEngine::create(logger, {}); Internal::ScopedJsValue sv( engine->context(), engine->evaluate(Internal::JsValueOwner::Caller, QLatin1String("(function(){return ") + str + QLatin1String(";})()"))); ok = !engine->checkAndClearException({}); return Internal::getJsVariant(engine->context(), sv); } QVariant representationToSettingsValue(const QString &representation) { bool ok; QVariant variant = variantFromString(representation, ok); // We have no floating-point properties, so this is most likely intended to be a string. if (static_cast(variant.userType()) == QMetaType::Float || static_cast(variant.userType()) == QMetaType::Double) { variant = variantFromString(QLatin1Char('"') + representation + QLatin1Char('"'), ok); } if (ok) return variant; // If it's not valid JavaScript, interpret the value as a string. return representation; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/jsonhelper.h0000644000175100001660000000660714776170045021117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JSON_HELPER_H #define QBS_JSON_HELPER_H #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { template inline T fromJson(const QJsonValue &v); template<> inline bool fromJson(const QJsonValue &v) { return v.toBool(); } template<> inline int fromJson(const QJsonValue &v) { return v.toInt(); } template<> inline QString fromJson(const QJsonValue &v) { return v.toString(); } template<> inline QStringList fromJson(const QJsonValue &v) { const QJsonArray &jsonList = v.toArray(); return transformed(jsonList, [](const auto &v) { return v.toString(); }); } template<> inline QVariantMap fromJson(const QJsonValue &v) { return v.toObject().toVariantMap(); } template<> inline QProcessEnvironment fromJson(const QJsonValue &v) { const QJsonObject obj = v.toObject(); QProcessEnvironment env; for (auto it = obj.begin(); it != obj.end(); ++it) env.insert(it.key(), it.value().toString()); return env; } template inline void setValueFromJson(T &targetValue, const QJsonObject &data, const char *jsonProperty) { const auto it = data.find(QLatin1String(jsonProperty)); if (it != data.end()) targetValue = fromJson(*it); } } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/id.cpp0000644000175100001660000001553414776170045017674 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "id.h" #include "qbsassert.h" #include #include #include #include namespace qbs { namespace Internal { /*! \class qbs::Internal::Id \brief The class Id encapsulates an identifier that is unique within a specific running process, using the qbs library. \c{Id} is used as facility to identify objects of interest in a more typesafe and faster manner than a plain \c QString or \c QByteArray would provide. An id is internally represented as a 32 bit integer (its \c UID) and associated with a plain 7-bit-clean ASCII name used for display and persistency. This class is copied from Qt Creator. */ class StringHolder { public: StringHolder() = default; StringHolder(const char *s, int length) : n(length), str(s) { if (!n) length = n = int(qstrlen(s)); h = 0; while (length--) { h = (h << 4) + *s++; h ^= (h & 0xf0000000) >> 23; h &= 0x0fffffff; } } int n = 0; const char *str = nullptr; uint h = 0; }; static bool operator==(const StringHolder &sh1, const StringHolder &sh2) { // sh.n is unlikely to discriminate better than the hash. return sh1.h == sh2.h && sh1.str && sh2.str && strcmp(sh1.str, sh2.str) == 0; } QHashValueType qHash(const StringHolder &sh) { return sh.h; } struct IdCache : public QHash { #ifndef QBS_ALLOW_STATIC_LEAKS ~IdCache() { for (IdCache::iterator it = begin(); it != end(); ++it) delete[](const_cast(it.key().str)); } #endif }; static int firstUnusedId = Id::IdsPerPlugin * Id::ReservedPlugins; static QHash stringFromId; static IdCache idFromString; static std::mutex mutex; static QByteArray getStringFromId(int id) { std::lock_guard lock(mutex); return stringFromId.value(id).str; } static int theId(const char *str, int n = 0) { QBS_ASSERT(str && *str, return 0); StringHolder sh(str, n); std::lock_guard lock(mutex); int res = idFromString.value(sh, 0); if (res == 0) { res = firstUnusedId++; sh.str = qstrdup(sh.str); idFromString[sh] = res; stringFromId[res] = sh; } return res; } static int theId(const QByteArray &ba) { return theId(ba.constData(), ba.size()); } /*! \fn qbs::Internal::Id(int uid) \brief Constructs an id given a UID. The UID is an integer value that is unique within the running process. It is the callers responsibility to ensure the uniqueness of the passed integer. The recommended approach is to use \c{registerId()} with an value taken from the plugin's private range. \sa registerId() */ /*! Constructs an id given its associated name. The internal representation will be unspecified, but consistent within a process. */ Id::Id(const char *name) : m_id(theId(name, 0)) {} /*! \overload */ Id::Id(const QByteArray &name) : m_id(theId(name)) {} /*! Returns an internal representation of the id. */ QByteArray Id::name() const { return getStringFromId(m_id); } /*! Returns a string representation of the id suitable for UI display. This should not be used to create a persistent version of the Id, use \c{toSetting()} instead. \sa fromString(), toSetting() */ QString Id::toString() const { return QString::fromUtf8(getStringFromId(m_id)); } /*! Returns a persistent value representing the id which is suitable to be stored in QSettings. \sa fromSetting() */ QVariant Id::toSetting() const { return QString::fromUtf8(getStringFromId(m_id)); } /*! Reconstructs an id from a persistent value. \sa toSetting() */ Id Id::fromSetting(const QVariant &variant) { const QByteArray ba = variant.toString().toUtf8(); if (ba.isEmpty()) return {}; return {theId(ba)}; } /*! Constructs a derived id. This can be used to construct groups of ids logically belonging together. The associated internal name will be generated by appending \c{suffix}. */ Id Id::withSuffix(int suffix) const { const QByteArray ba = name() + QByteArray::number(suffix); return {ba.constData()}; } /*! \overload */ Id Id::withSuffix(const char *suffix) const { const QByteArray ba = name() + suffix; return {ba.constData()}; } /*! Constructs a derived id. This can be used to construct groups of ids logically belonging together. The associated internal name will be generated by prepending \c{prefix}. */ Id Id::withPrefix(const char *prefix) const { const QByteArray ba = prefix + name(); return {ba.constData()}; } bool Id::operator==(const char *name) const { const auto string = getStringFromId(m_id); if (!string.isNull() && name) return strcmp(string.data(), name) == 0; return false; } bool Id::alphabeticallyBefore(Id other) const { return toString().compare(other.toString(), Qt::CaseInsensitive) < 0; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/mutexdata.h0000644000175100001660000000752614776170045020743 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include namespace qbs { namespace Internal { // adapted version of https://github.com/dragazo/rustex/blob/master/rustex.h // a data with a mutually exclusive access template class MutexData { public: template typename LockType> class ReferenceGuard { friend class MutexData; template ReferenceGuard(U &&data) noexcept : m_ptr(std::addressof(data.m_data)) , m_lock(data.m_mutex) {} public: ReferenceGuard(const ReferenceGuard &) = delete; ReferenceGuard(ReferenceGuard &&) = default; ReferenceGuard &operator=(const ReferenceGuard &) = delete; ReferenceGuard &operator=(ReferenceGuard &&) = default; T &get() const noexcept { return *m_ptr; } T &data() const noexcept { return *m_ptr; } operator T &() const noexcept { return *m_ptr; } private: T *m_ptr; LockType m_lock; }; using UniqueMutableGuard = ReferenceGuard; using UniqueConstGuard = ReferenceGuard; using SharedGuard = ReferenceGuard; template< typename ...Args, std::enable_if_t, int> = 0 > explicit MutexData(Args &&...args) : m_data(std::forward(args)...) {} [[nodiscard]] UniqueMutableGuard lock() noexcept { return UniqueMutableGuard{*this}; } [[nodiscard]] UniqueConstGuard lock() const noexcept { return UniqueConstGuard{*this}; } template< typename U = MutexType, std::enable_if_t, int> = 0 > [[nodiscard]] SharedGuard lock_shared() const noexcept { return SharedGuard{*this}; } private: DataType m_data; mutable MutexType m_mutex; }; } // namespace qbs } // namespace Internal qbs-src-2.6.1/src/lib/corelib/tools/processresult.h0000644000175100001660000000563214776170045021660 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROCESSRESULT_H #define QBS_PROCESSRESULT_H #include "qbs_export.h" #include #include #include #include QT_BEGIN_NAMESPACE class QJsonObject; QT_END_NAMESPACE namespace qbs { namespace Internal { class ProcessCommandExecutor; class ProcessResultPrivate; } class QBS_EXPORT ProcessResult { friend class qbs::Internal::ProcessCommandExecutor; public: ProcessResult(); ProcessResult(const ProcessResult &other); ProcessResult &operator=(const ProcessResult &other); ~ProcessResult(); QJsonObject toJson() const; bool success() const; QString executableFilePath() const; QStringList arguments() const; QString workingDirectory() const; QProcess::ProcessError error() const; int exitCode() const; QStringList stdOut() const; QStringList stdErr() const; private: QExplicitlySharedDataPointer d; }; } // namespace qbs Q_DECLARE_METATYPE(qbs::ProcessResult) #endif // QBS_PROCESSRESULT_H qbs-src-2.6.1/src/lib/corelib/tools/generateoptions.h0000644000175100001660000000503514776170045022146 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_GENERATEOPTIONS_H #define QBS_GENERATEOPTIONS_H #include "qbs_export.h" #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { class GenerateOptionsPrivate; } class QBS_EXPORT GenerateOptions { public: GenerateOptions(); GenerateOptions(const GenerateOptions &other); GenerateOptions &operator=(const GenerateOptions &other); ~GenerateOptions(); QString generatorName() const; void setGeneratorName(const QString &generatorName); private: QSharedDataPointer d; }; } // namespace qbs #endif // QBS_GENERATEOPTIONS_H qbs-src-2.6.1/src/lib/corelib/tools/error.cpp0000644000175100001660000002362714776170045020433 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "error.h" #include "persistence.h" #include "stringconstants.h" #include "setupprojectparameters.h" #include "logging/logger.h" #include #include #include #include #include #include #include #include namespace qbs { class ErrorItem::ErrorItemPrivate : public QSharedData { public: template void serializationOp(Internal::PersistentPool &pool) { pool.serializationOp(description, codeLocation, isBacktraceItem); } void load(Internal::PersistentPool &pool) { serializationOp(pool); } void store(Internal::PersistentPool &pool) { serializationOp(pool); } QString description; CodeLocation codeLocation; bool isBacktraceItem = false; }; /*! * \class ErrorData * \brief The \c ErrorData class describes (part of) an error resulting from a qbs operation. * It is always delivered as part of an \c Error. * \sa Error */ ErrorItem::ErrorItem() : d(new ErrorItemPrivate) { } ErrorItem::ErrorItem(ErrorItem &&rhs) noexcept = default; 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) = default; ErrorItem &ErrorItem::operator=(const ErrorItem &other) = default; ErrorItem &ErrorItem::operator=(ErrorItem &&other) noexcept = default; ErrorItem::~ErrorItem() = default; QString ErrorItem::description() const { return d->description; } CodeLocation ErrorItem::codeLocation() const { return d->codeLocation; } bool ErrorItem::isBacktraceItem() const { return d->isBacktraceItem; } void ErrorItem::load(Internal::PersistentPool &pool) { pool.load(*d); } void ErrorItem::store(Internal::PersistentPool &pool) const { pool.store(*d); } /*! * \fn const QString &ErrorData::description() const * \brief A general description of the error. */ /*! * \fn const QString &ErrorData::codeLocation() const * \brief The location at which file in which the error occurred. * \note This information might not be applicable, in which case location().isValid() returns false */ /*! * \brief A full textual description of the error using all available information. */ QString ErrorItem::toString() const { QString str = codeLocation().toString(); if (!str.isEmpty()) str += QLatin1Char(' '); return str += description(); } QJsonObject ErrorItem::toJson() const { QJsonObject data; data.insert(Internal::StringConstants::descriptionProperty(), description()); data.insert(Internal::StringConstants::locationKey(), codeLocation().toJson()); return data; } class ErrorInfo::ErrorInfoPrivate : public QSharedData { public: ErrorInfoPrivate() : internalError(false) { } template void completeSerializationOp(Internal::PersistentPool &pool) { pool.serializationOp(items, internalError); } QList items; bool internalError; }; /*! * \class Error * \brief Represents an error resulting from a qbs operation. * It is made up of one or more \c ErrorData objects. * \sa ErrorData */ ErrorInfo::ErrorInfo() : d(new ErrorInfoPrivate) { } ErrorInfo::ErrorInfo(const ErrorInfo &rhs) = default; ErrorInfo::ErrorInfo(ErrorInfo &&rhs) noexcept = default; ErrorInfo::ErrorInfo(const QString &description, const CodeLocation &location, bool internalError) : d(new ErrorInfoPrivate) { append(description, location); d->internalError = internalError; } ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace) : d(new ErrorInfoPrivate) { append(description); for (const QString &traceLine : backtrace) { if (traceLine.contains(QStringLiteral(""))) continue; static const std::regex regexpWithFunc("^(.+) at [^(]*\\((.+):(\\-?[0-9]+)\\)$"); static const std::regex regexpWithoutFunc("^(.+) at (.+):(\\-?[0-9]+)$"); std::smatch match; const std::string tl = traceLine.toStdString(); bool hasMatch = std::regex_match(tl, match, regexpWithFunc); if (!hasMatch) hasMatch = std::regex_match(tl, match, regexpWithoutFunc); if (hasMatch) { const QString message = QString::fromStdString(match[1]).trimmed(); const QString file = QString::fromStdString(match[2]); const QString line = QString::fromStdString(match[3]); const CodeLocation location(file, line.toInt()); appendBacktrace(message, CodeLocation(file, line.toInt())); } } } ErrorInfo &ErrorInfo::operator=(ErrorInfo &&other) noexcept = default; ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) = default; ErrorInfo::~ErrorInfo() = default; void ErrorInfo::appendBacktrace(const QString &description, const CodeLocation &location) { d->items.push_back(ErrorItem(description, location, true)); } void ErrorInfo::append(const ErrorItem &item) { d->items.push_back(item); } void ErrorInfo::append(const QString &description, const CodeLocation &location) { d->items.push_back(ErrorItem(description, location)); } void ErrorInfo::prepend(const QString &description, const CodeLocation &location) { d->items.prepend(ErrorItem(description, location)); } /*! * \brief A list of concrete error description. * Most often, there will be one element in this list, but there can be more e.g. to illustrate * how an error condition propagates through several source files. */ const QList ErrorInfo::items() const { return d->items; } void ErrorInfo::clear() { d->items.clear(); } /*! * \brief A complete textual description of the error. * All "sub-errors" will be represented. * \sa Error::entries() */ QString ErrorInfo::toString() const { QStringList lines; for (const ErrorItem &e : std::as_const(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.push_back(QLatin1Char('\t') + line); } else { lines.push_back(e.toString()); } } return lines.join(QLatin1Char('\n')); } QJsonObject ErrorInfo::toJson() const { QJsonObject data; data.insert(QLatin1String("is-internal"), isInternalError()); QJsonArray itemsArray; for (const ErrorItem &item : items()) itemsArray.append(item.toJson()); data.insert(QLatin1String("items"), itemsArray); return data; } /*! * \brief Returns true if this error represents a bug in qbs, false otherwise. */ bool ErrorInfo::isInternalError() const { return d->internalError; } bool ErrorInfo::hasLocation() const { return Internal::any_of(d->items, [](const ErrorItem &ei) { return ei.codeLocation().isValid(); }); } bool ErrorInfo::isCancelException() const { return Internal::any_of(d->items, [](const ErrorItem &ei) { return ei.description() == QLatin1String("interrupted"); }); } void ErrorInfo::load(Internal::PersistentPool &pool) { pool.load(*d); } void ErrorInfo::store(Internal::PersistentPool &pool) const { pool.store(*d); } void appendError(ErrorInfo &dst, const ErrorInfo &src) { const QList &sourceItems = src.items(); for (const ErrorItem &item : sourceItems) dst.append(item); } void handlePropertyError( const ErrorInfo &error, const SetupProjectParameters ¶ms, Internal::Logger &logger) { if (params.propertyCheckingMode() == ErrorHandlingMode::Strict) throw error; logger.printError(error); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/qbs_export.h0000644000175100001660000000543214776170045021127 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_EXPORT_H #define QBS_EXPORT_H #if defined(_WIN32) || defined(WIN32) # define QBS_DECL_EXPORT __declspec(dllexport) # define QBS_DECL_IMPORT __declspec(dllimport) #else # define QBS_DECL_EXPORT __attribute__((visibility("default"))) # define QBS_DECL_IMPORT __attribute__((visibility("default"))) # endif #ifdef QBS_STATIC_LIB # define QBS_EXPORT # define QBS_AUTOTEST_EXPORT #else # ifdef QBS_LIBRARY # define QBS_EXPORT QBS_DECL_EXPORT # ifdef QBS_WITH_TESTS # define QBS_AUTOTEST_EXPORT QBS_DECL_EXPORT # else # define QBS_AUTOTEST_EXPORT # endif # else # define QBS_EXPORT QBS_DECL_IMPORT # ifdef QBS_WITH_TESTS # define QBS_AUTOTEST_EXPORT QBS_DECL_IMPORT # else # define QBS_AUTOTEST_EXPORT # endif # endif #endif #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(disable: 4251) #endif #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/tools/persistence.cpp0000644000175100001660000001654314776170045021625 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "persistence.h" #include "fileinfo.h" #include #include #include namespace qbs { namespace Internal { static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-137"; NoBuildGraphError::NoBuildGraphError(const QString &filePath) : ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.") .arg(FileInfo::completeBaseName(filePath), QDir::toNativeSeparators(filePath))) { } PersistentPool::PersistentPool(Logger &logger) : m_logger(logger) { Q_UNUSED(m_logger); m_stream.setVersion(QDataStream::Qt_4_8); } PersistentPool::~PersistentPool() = default; void PersistentPool::load(const QString &filePath) { std::unique_ptr file(new QFile(filePath)); if (!file->exists()) throw NoBuildGraphError(filePath); if (!file->open(QFile::ReadOnly)) { throw ErrorInfo(Tr::tr("Could not open open build graph file '%1': %2") .arg(filePath, file->errorString())); } m_stream.setDevice(file.get()); QByteArray magic; m_stream >> magic; if (magic != QBS_PERSISTENCE_MAGIC) { m_stream.setDevice(nullptr); throw ErrorInfo(Tr::tr("Cannot use stored build graph at '%1': Incompatible file format. " "Expected magic token '%2', got '%3'.") .arg(filePath, QLatin1String(QBS_PERSISTENCE_MAGIC), QString::fromLatin1(magic))); } m_stream >> m_headData.projectConfig; m_file = std::move(file); m_loadedRaw.clear(); m_loaded.clear(); m_storageIndices.clear(); m_stringStorage.clear(); m_inverseStringStorage.clear(); } void PersistentPool::setupWriteStream(const QString &filePath) { QString dirPath = FileInfo::path(filePath); if (!FileInfo::exists(dirPath) && !QDir().mkpath(dirPath)) { throw ErrorInfo(Tr::tr("Failure storing build graph: Cannot create directory '%1'.") .arg(dirPath)); } if (QFile::exists(filePath) && !QFile::remove(filePath)) { throw ErrorInfo(Tr::tr("Failure storing build graph: Cannot remove old file '%1'") .arg(filePath)); } QBS_CHECK(!QFile::exists(filePath)); std::unique_ptr file(new QFile(filePath)); if (!file->open(QFile::WriteOnly)) { throw ErrorInfo(Tr::tr("Failure storing build graph: " "Cannot open file '%1' for writing: %2").arg(filePath, file->errorString())); } m_stream.setDevice(file.get()); m_file = std::move(file); m_stream << QByteArray(qstrlen(QBS_PERSISTENCE_MAGIC), 0) << m_headData.projectConfig; m_lastStoredObjectId = 0; m_lastStoredStringId = 0; m_lastStoredEnvId = 0; m_lastStoredStringListId = 0; } void PersistentPool::finalizeWriteStream() { if (m_stream.status() != QDataStream::Ok) throw ErrorInfo(Tr::tr("Failure serializing build graph.")); m_stream.device()->seek(0); m_stream << QByteArray(QBS_PERSISTENCE_MAGIC); if (m_stream.status() != QDataStream::Ok) throw ErrorInfo(Tr::tr("Failure serializing build graph.")); const auto file = static_cast(m_stream.device()); if (!file->flush()) { file->close(); file->remove(); throw ErrorInfo(Tr::tr("Failure serializing build graph: %1").arg(file->errorString())); } } void PersistentPool::storeVariant(const QVariant &variant) { if (variant.isNull()) { m_stream << quint32(QMetaType::User); m_stream << variant; return; } const auto type = static_cast(variant.userType()); m_stream << type; switch (type) { case QMetaType::QString: store(variant.toString()); break; case QMetaType::QStringList: store(variant.toStringList()); break; case QMetaType::QVariantList: store(variant.toList()); break; case QMetaType::QVariantMap: store(variant.toMap()); break; default: m_stream << variant; } } QVariant PersistentPool::loadVariant() { const auto type = load(); QVariant value; switch (type) { case QMetaType::QString: value = load(); break; case QMetaType::QStringList: value = load(); break; case QMetaType::QVariantList: value = load(); break; case QMetaType::QVariantMap: value = load(); break; default: m_stream >> value; } return value; } void PersistentPool::clear() { m_loaded.clear(); m_storageIndices.clear(); m_stringStorage.clear(); m_inverseStringStorage.clear(); } void PersistentPool::doLoadValue(QString &s) { m_stream >> s; } void PersistentPool::doLoadValue(QStringList &l) { int size; m_stream >> size; for (int i = 0; i < size; ++i) l << load(); } void PersistentPool::doLoadValue(QProcessEnvironment &env) { const auto keys = load(); for (const QString &key : keys) env.insert(key, load()); } void PersistentPool::doStoreValue(const QString &s) { m_stream << s; } void PersistentPool::doStoreValue(const QStringList &l) { m_stream << int(l.size()); for (const QString &s : l) store(s); } void PersistentPool::doStoreValue(const QProcessEnvironment &env) { const QStringList &keys = env.keys(); store(keys); for (const QString &key : keys) store(env.value(key)); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/stlutils.h0000644000175100001660000001774414776170045020635 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_STLUTILS_H #define QBS_STLUTILS_H #include #include namespace qbs { namespace Internal { template auto sorted(C &&container) { using R = std::remove_cv_t>; R result(std::forward(container)); std::sort(std::begin(result), std::end(result)); return result; } template auto sorted(C &&container, Pred &&pred) { using R = std::remove_cv_t>; R result(std::forward(container)); std::sort(std::begin(result), std::end(result), std::forward(pred)); return result; } template To transformed(const From &from, Op op) { To to; to.reserve(int(from.size())); std::transform(std::cbegin(from), std::cend(from), std::back_inserter(to), std::move(op)); return to; } template void transform(C &&container, Op op) { std::transform(std::begin(container), std::end(container), std::begin(container), std::move(op)); } template void transform(const From &from, To &&to, Op op) { std::transform(std::cbegin(from), std::cend(from), std::back_inserter(to), std::move(op)); } template bool contains(const C &container, const T &v) { const auto &end = std::cend(container); return std::find(std::cbegin(container), end, v) != end; } template bool contains(const T (&container)[N], const U &v) { const auto &end = std::cend(container); return std::find(std::cbegin(container), end, v) != end; } template bool containsKey(const C &container, const typename C::key_type &v) { const auto &end = container.cend(); return container.find(v) != end; } template typename C::mapped_type mapValue( const C &container, const typename C::key_type &key, const typename C::mapped_type &value = typename C::mapped_type()) { const auto end = container.cend(); const auto it = container.find(key); return it != end ? it->second : value; } template bool removeOne(C &container, const typename C::value_type &v) { auto end = std::end(container); auto it = std::find(std::begin(container), end, v); if (it == end) return false; container.erase(it); return true; } template void removeAll(C &container, const typename C::value_type &v) { container.erase(std::remove(std::begin(container), std::end(container), v), std::end(container)); } template void removeIf(C &container, const Pred &pred) { container.erase(std::remove_if(std::begin(container), std::end(container), pred), std::end(container)); } template bool any_of(const Container &container, const UnaryPredicate &predicate) { return std::any_of(std::begin(container), std::end(container), predicate); } template bool all_of(const Container &container, const UnaryPredicate &predicate) { return std::all_of(std::begin(container), std::end(container), predicate); } template bool none_of(const Container &container, const UnaryPredicate &predicate) { return std::none_of(std::begin(container), std::end(container), predicate); } template It binaryFind(It begin, It end, const T &value, Compare comp) { const auto it = std::lower_bound(begin, end, value, comp); if (it == end || comp(value, *it)) return end; return it; } template It binaryFind(It begin, It end, const T &value) { return binaryFind(begin, end, value, std::less()); } template C &operator<<(C &container, const typename C::value_type &v) { container.push_back(v); return container; } template C &operator<<(C &container, const C &other) { container.insert(container.end(), other.cbegin(), other.cend()); return container; } // based on http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0814r0.pdf template void hashCombineHelper(size_t &seed, const T &val) { seed ^= std::hash()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } template size_t hashCombine(const Types &... args) { size_t seed = 0; (hashCombineHelper(seed, args), ...); // create hash value with seed over all args return seed; return seed; } template size_t hashRange(It first, It last) { size_t seed = 0; for (; first != last; ++first) hashCombineHelper(seed, *first); return seed; } template size_t hashRange(R &&range) { return hashRange(std::begin(range), std::end(range)); } // based on qcontainertools_impl.h template using IfIsForwardIterator_t = typename std::enable_if_t< std::is_convertible_v< typename std::iterator_traits::iterator_category, std::forward_iterator_tag>, bool>; template using IfIsNotForwardIterator = typename std::enable_if_t< !std::is_convertible_v< typename std::iterator_traits::iterator_category, std::forward_iterator_tag>, bool>; template = true> void reserveIfForwardIterator(Container *, InputIterator, InputIterator) { } template = true> void reserveIfForwardIterator(Container *c, ForwardIterator f, ForwardIterator l) { c->reserve(static_cast(std::distance(f, l))); } // similar to ranges::to proposal // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1206r1.pdf template C rangeTo(R &&r) { return C(std::begin(r), std::end(r)); } template constexpr std::underlying_type_t toUnderlying(Enum e) noexcept { return static_cast>(e); } } // namespace Internal } // namespace qbs #endif // QBS_STLUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/commandechomode.h0000644000175100001660000000501514776170045022060 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_COMMANDECHOMODE_H #define QBS_COMMANDECHOMODE_H #include "qbs_export.h" #include #include namespace qbs { enum CommandEchoMode { CommandEchoModeSilent, CommandEchoModeSummary, CommandEchoModeCommandLine, CommandEchoModeCommandLineWithEnvironment, CommandEchoModeInvalid, }; QBS_EXPORT CommandEchoMode defaultCommandEchoMode(); QBS_EXPORT QString commandEchoModeName(CommandEchoMode mode); QBS_EXPORT CommandEchoMode commandEchoModeFromName(const QString &name); QBS_EXPORT QStringList allCommandEchoModeStrings(); } // namespace qbs #endif // QBS_COMMANDECHOMODE_H qbs-src-2.6.1/src/lib/corelib/tools/span.h0000644000175100001660000000542314776170045017702 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SPAN_H #define QBS_SPAN_H #include // The (Apple) Clang implementation of span is incomplete until LLVM 15 / Xcode 14.3 / macOS 13 #if __cplusplus >= 202002L \ && !(defined(__apple_build_version__) && __apple_build_version__ < 14030022) #include namespace qbs { namespace Internal { using std::as_bytes; using std::as_writable_bytes; using std::get; using std::span; } // namespace Internal } // namespace qbs #else QT_WARNING_PUSH #if defined(Q_CC_MSVC) #pragma system_header #elif defined(Q_CC_GNU) || defined(Q_CC_CLANG) #pragma GCC system_header #endif // disable automatic usage of std::span in span-lite // since we make that decision ourselves at the top of this header #define span_CONFIG_SELECT_SPAN span_SPAN_NONSTD #include namespace qbs { namespace Internal { using namespace nonstd; } // namespace Internal } // namespace qbs QT_WARNING_POP #endif #endif // QBS_SPAN_Hqbs-src-2.6.1/src/lib/corelib/tools/generateoptions.cpp0000644000175100001660000000603714776170045022504 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "generateoptions.h" #include #include namespace qbs { namespace Internal { class GenerateOptionsPrivate : public QSharedData { public: GenerateOptionsPrivate() : generatorName() {} QString generatorName; }; } // namespace Internal /*! * \class GenerateOptions * \brief The \c GenerateOptions class comprises parameters that influence the behavior of * generate operations. */ GenerateOptions::GenerateOptions() : d(new Internal::GenerateOptionsPrivate) { } GenerateOptions::GenerateOptions(const GenerateOptions &other) = default; GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other) = default; GenerateOptions::~GenerateOptions() = default; /*! * Returns the name of the generator used to create the external build system files. * The default is empty. */ QString GenerateOptions::generatorName() const { return d->generatorName; } /*! * \brief Sets the name of the generator used to create the external build system files. */ void GenerateOptions::setGeneratorName(const QString &generatorName) { d->generatorName = generatorName; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/executablefinder.h0000644000175100001660000000562114776170045022252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_EXECUTABLEFINDER_H #define QBS_EXECUTABLEFINDER_H #include #include namespace qbs { namespace Internal { /*! * \brief Helper class for finding an executable in the PATH of the build environment. */ class ExecutableFinder { public: ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env); QString findExecutable(const QString &path, const QString &workingDirPath); private: static QStringList m_executableSuffixes; QString findBySuffix(const QString &filePath) const; bool candidateCheck(const QString &directory, const QString &program, QString &fullProgramPath) const; QString findInPath(const QString &filePath, const QString &workingDirPath) const; QString cachedFilePath(const QString &filePath) const; void cacheFilePath(const QString &filePaht, const QString &filePath) const; ResolvedProductPtr m_product; const QProcessEnvironment m_environment; }; } // namespace Internal } // namespace qbs #endif // QBS_EXECUTABLEFINDER_H qbs-src-2.6.1/src/lib/corelib/tools/installoptions.cpp0000644000175100001660000001653114776170045022360 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "installoptions.h" #include "jsonhelper.h" #include "stringconstants.h" #include #include #include namespace qbs { namespace Internal { class InstallOptionsPrivate : public QSharedData { public: InstallOptionsPrivate() : useSysroot(false), removeExisting(false), dryRun(false), keepGoing(false), logElapsedTime(false) {} QString installRoot; bool useSysroot; bool removeExisting; bool dryRun; bool keepGoing; bool logElapsedTime; }; QString effectiveInstallRoot(const InstallOptions &options, const TopLevelProject *project) { QString installRoot = options.installRoot(); if (!installRoot.isEmpty()) return installRoot; if (options.installIntoSysroot()) { return project->buildConfiguration().value(StringConstants::qbsModule()).toMap() .value(QStringLiteral("sysroot")).toString(); } return project->buildConfiguration().value(StringConstants::qbsModule()).toMap() .value(StringConstants::installRootProperty()).toString(); } } // namespace Internal /*! * \class InstallOptions * \brief The \c InstallOptions class comprises parameters that influence the behavior of * install operations. */ InstallOptions::InstallOptions() : d(new Internal::InstallOptionsPrivate) { } InstallOptions::InstallOptions(const InstallOptions &other) = default; InstallOptions::InstallOptions(InstallOptions &&other) Q_DECL_NOEXCEPT = default; InstallOptions &InstallOptions::operator=(const InstallOptions &other) = default; InstallOptions &InstallOptions::operator=(InstallOptions &&other) Q_DECL_NOEXCEPT = default; InstallOptions::~InstallOptions() = default; /*! * \brief The default install root, relative to the build directory. */ QString InstallOptions::defaultInstallRoot() { return QStringLiteral("install-root"); } /*! * Returns the base directory for the installation. * The \c qbs.installPrefix path is relative to this root. If the string is empty, either the value of * qbs.sysroot or "/install-root" will be used, depending on what \c installIntoSysroot() * returns. * The default is empty. */ QString InstallOptions::installRoot() const { return d->installRoot; } /*! * \brief Sets the base directory for the installation. * \note The argument must either be an empty string or an absolute path to a directory * (which might not yet exist, in which case it will be created). */ void InstallOptions::setInstallRoot(const QString &installRoot) { d->installRoot = QDir::cleanPath(installRoot); if (!QDir(installRoot).isRoot()) { while (d->installRoot.endsWith(QLatin1Char('/'))) d->installRoot.chop(1); } } /*! * Returns whether to use the sysroot as the default install root. * The default is false. */ bool InstallOptions::installIntoSysroot() const { return d->useSysroot; } void InstallOptions::setInstallIntoSysroot(bool useSysroot) { d->useSysroot = useSysroot; } /*! * \brief Returns true iff an existing installation will be removed prior to installing. * The default is false. */ bool InstallOptions::removeExistingInstallation() const { return d->removeExisting; } /*! * Controls whether to remove an existing installation before installing. * \note qbs may do some safety checks and refuse to remove certain directories such as * a user's home directory. You should still be careful with this option, since it * deletes recursively. */ void InstallOptions::setRemoveExistingInstallation(bool removeExisting) { d->removeExisting = removeExisting; } /*! * \brief Returns true iff qbs will not actually copy any files, but just show what would happen. * The default is false. */ bool InstallOptions::dryRun() const { return d->dryRun; } /*! * \brief Controls whether installation will actually take place. * If the argument is true, then qbs will emit information about which files would be copied * instead of actually doing it. */ void InstallOptions::setDryRun(bool dryRun) { d->dryRun = dryRun; } /*! * Returns true iff installation will continue if an error occurs. * The default is false. */ bool InstallOptions::keepGoing() const { return d->keepGoing; } /*! * \brief Controls whether to abort on errors. * If the argument is true, then if a file cannot be copied e.g. due to a permission problem, * a warning will be printed and the installation will continue. If the argument is false, * then the installation will abort immediately in case of an error. */ void InstallOptions::setKeepGoing(bool keepGoing) { d->keepGoing = keepGoing; } /*! * \brief Returns true iff the time the operation takes will be logged. * The default is false. */ bool InstallOptions::logElapsedTime() const { return d->logElapsedTime; } /*! * \brief Controls whether the installation time will be measured and logged. */ void InstallOptions::setLogElapsedTime(bool logElapsedTime) { d->logElapsedTime = logElapsedTime; } qbs::InstallOptions qbs::InstallOptions::fromJson(const QJsonObject &data) { using namespace Internal; InstallOptions opt; setValueFromJson(opt.d->installRoot, data, "install-root"); setValueFromJson(opt.d->useSysroot, data, "use-sysroot"); setValueFromJson(opt.d->removeExisting, data, "clean-install-root"); setValueFromJson(opt.d->dryRun, data, "dry-run"); setValueFromJson(opt.d->keepGoing, data, "keep-going"); setValueFromJson(opt.d->logElapsedTime, data, "log-time"); return opt; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/toolchains.h0000644000175100001660000000423514776170045021104 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TOOLCHAINS_H #define QBS_TOOLCHAINS_H #include "qbs_export.h" #include namespace qbs { QBS_EXPORT QStringList canonicalToolchain(const QStringList &toolchain); QBS_EXPORT QStringList canonicalToolchain(const QString &toolchainName); } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/tools/applecodesignutils.h0000644000175100001660000000434114776170045022635 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_APPLECODESIGNUTILS_H #define QBS_APPLECODESIGNUTILS_H #include "qbs_export.h" #include namespace qbs { namespace Internal { QByteArray smimeMessageContent(const QByteArray &data); QVariantMap certificateInfo(const QByteArray &data); QVariantMap identitiesProperties(); } // namespace Internal } // namespace qbs #endif // QBS_APPLECODESIGNUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/set.h0000644000175100001660000003211014776170045017525 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SET_H #define QBS_SET_H #include #include #include #ifdef QT_CORE_LIB #include #include #endif #include #include #include #include #include #include namespace qbs { namespace Internal { template class Set; template Set operator&(const Set &set1, const Set &set2); template Set operator-(const Set &set1, const Set &set2); namespace helper { template struct SortAfterLoad { static const bool required = false; }; template struct SortAfterLoad { static const bool required = true; }; template struct SortAfterLoad> { static const bool required = true; }; } template class Set { public: using const_iterator = typename std::vector::const_iterator; using iterator = typename std::vector::iterator; using reverse_iterator = typename std::vector::reverse_iterator; using const_reverse_iterator = typename std::vector::const_reverse_iterator; using size_type = typename std::vector::size_type; using value_type = T; using difference_type = typename std::vector::difference_type; using pointer = typename std::vector::pointer; using const_pointer = typename std::vector::const_pointer; using reference = typename std::vector::reference; using const_reference = typename std::vector::const_reference; iterator begin() { return m_data.begin(); } iterator end() { return m_data.end(); } reverse_iterator rbegin() { return m_data.rbegin(); } reverse_iterator rend() { return m_data.rend(); } const_reverse_iterator rbegin() const { return m_data.rbegin(); } const_reverse_iterator rend() const { return m_data.rend(); } const_reverse_iterator crbegin() const { return m_data.crbegin(); } const_reverse_iterator crend() const { return m_data.crend(); } const_iterator begin() const { return m_data.begin(); } const_iterator end() const { return m_data.end(); } const_iterator cbegin() const { return m_data.cbegin(); } const_iterator cend() const { return m_data.cend(); } const_iterator constBegin() const { return m_data.cbegin(); } const_iterator constEnd() const { return m_data.cend(); } Set() = default; Set(const std::initializer_list &list); template Set(InputIterator first, InputIterator last); Set &unite(const Set &other); Set &operator+=(const Set &other) { return unite(other); } Set &operator|=(const Set &other) { return unite(other); } Set &subtract(const Set &other); Set &operator-=(const Set &other) { return subtract(other); } Set &intersect(const Set &other); Set &operator&=(const Set &other) { return intersect(other); } Set &operator&=(const T &v) { return intersect(Set{ v }); } iterator find(const T &v) { return binaryFind(m_data.begin(), m_data.end(), v); } const_iterator find(const T &v) const { return binaryFind(m_data.cbegin(), m_data.cend(), v); } std::pair insert(const T &v); Set &operator+=(const T &v) { insert(v); return *this; } Set &operator|=(const T &v) { return operator+=(v); } Set &operator<<(const T &v) { return operator+=(v); } bool contains(const T &v) const { return std::binary_search(cbegin(), cend(), v); } bool contains(const Set &other) const; bool empty() const { return m_data.empty(); } size_type size() const { return m_data.size(); } size_type capacity() const { return m_data.capacity(); } bool intersects(const Set &other) const; bool remove(const T &v); void operator-=(const T &v) { remove(v); } iterator erase(iterator it) { return m_data.erase(it); } iterator erase(iterator first, iterator last) { return m_data.erase(first, last); } void clear() { m_data.clear(); } void reserve(size_type size) { m_data.reserve(size); } void swap(Set &other) { m_data.swap(other.m_data); } void load(PersistentPool &pool); void store(PersistentPool &pool) const; #ifdef QT_CORE_LIB QStringList toStringList() const; QString toString(const T& value) const { return value.toString(); } QString toString() const; #endif template static Set filtered(const Set &s); bool operator==(const Set &other) const { return m_data == other.m_data; } bool operator!=(const Set &other) const { return m_data != other.m_data; } private: friend Set operator&<>(const Set &set1, const Set &set2); friend Set operator-<>(const Set &set1, const Set &set2); void sort() { std::sort(m_data.begin(), m_data.end()); } T loadElem(PersistentPool &pool) { return pool.load(); } void storeElem(PersistentPool &pool, const T &v) const { pool.store(v); } bool sortAfterLoadRequired() const { return helper::SortAfterLoad::required; } iterator asMutableIterator(const_iterator cit); std::vector m_data; }; template Set::Set(const std::initializer_list &list) : m_data(list) { sort(); const auto last = std::unique(m_data.begin(), m_data.end()); m_data.erase(last, m_data.end()); } template template Set::Set(InputIterator first, InputIterator last) { reserveIfForwardIterator(&m_data, first, last); std::copy(first, last, std::back_inserter(m_data)); sort(); } template Set &Set::intersect(const Set &other) { auto it = begin(); auto otherIt = other.cbegin(); while (it != end()) { if (otherIt == other.cend()) { m_data.erase(it, end()); break; } if (*it < *otherIt) { it = erase(it); continue; } if (!(*otherIt < *it)) ++it; ++otherIt; } return *this; } template std::pair::iterator, bool> Set::insert(const T &v) { const auto it = std::lower_bound(m_data.begin(), m_data.end(), v); if (it == m_data.end() || v < *it) return std::make_pair(m_data.insert(it, v), true); return std::make_pair(it, false); } template bool Set::contains(const Set &other) const { auto it = cbegin(); auto otherIt = other.cbegin(); while (otherIt != other.cend()) { if (it == cend() || *otherIt < *it) return false; if (!(*it < *otherIt)) ++otherIt; ++it; } return true; } template bool Set::intersects(const Set &other) const { auto it = cbegin(); auto itOther = other.cbegin(); while (it != cend() && itOther != other.cend()) { if (*it < *itOther) ++it; else if (*itOther < *it) ++itOther; else return true; } return false; } template Set &Set::unite(const Set &other) { if (other.empty()) return *this; if (empty()) { m_data = other.m_data; return *this; } auto lowerBound = m_data.begin(); for (auto otherIt = other.cbegin(); otherIt != other.cend(); ++otherIt) { lowerBound = std::lower_bound(lowerBound, m_data.end(), *otherIt); if (lowerBound == m_data.end()) { m_data.reserve(size() + std::distance(otherIt, other.cend())); std::copy(otherIt, other.cend(), std::back_inserter(m_data)); return *this; } if (*otherIt < *lowerBound) lowerBound = m_data.insert(lowerBound, *otherIt); } return *this; } template bool Set::remove(const T &v) { const auto it = std::lower_bound(m_data.cbegin(), m_data.cend(), v); if (it != m_data.cend() && !(v < *it)) { m_data.erase(asMutableIterator(it)); return true; } return false; } template void Set::load(PersistentPool &pool) { clear(); int i = pool.load(); reserve(i); for (; --i >= 0;) m_data.push_back(loadElem(pool)); if (sortAfterLoadRequired()) sort(); } template void Set::store(PersistentPool &pool) const { pool.store(static_cast(size())); std::for_each(m_data.cbegin(), m_data.cend(), std::bind(&Set::storeElem, this, std::ref(pool), std::placeholders::_1)); } #ifdef QT_CORE_LIB template QStringList Set::toStringList() const { return transformed(*this, [this](const T &e) { return toString(e); }); } template QString Set::toString() const { return QLatin1Char('[') + toStringList().join(QLatin1String(", ")) + QLatin1Char(']'); } template<> inline QString Set::toString(const QString &value) const { return value; } #endif template typename Set::iterator Set::asMutableIterator(typename Set::const_iterator cit) { const auto offset = std::distance(cbegin(), cit); return begin() + offset; } template template Set Set::filtered(const Set &s) { static_assert(std::is_pointer_v, "Set::filtered() assumes pointer types"); static_assert(std::is_pointer_v, "Set::filtered() assumes pointer types"); Set filteredSet; for (auto &u : s) { if (hasDynamicType>(u)) filteredSet.m_data.push_back(static_cast(u)); } return filteredSet; } template Set &Set::subtract(const Set &other) { if (empty() || other.empty()) return *this; auto lowerBound = m_data.begin(); for (auto otherIt = other.cbegin(); otherIt != other.cend(); ++otherIt) { lowerBound = std::lower_bound(lowerBound, m_data.end(), *otherIt); if (lowerBound == m_data.end()) return *this; if (!(*otherIt < *lowerBound)) lowerBound = m_data.erase(lowerBound); } return *this; } template Set operator+(const Set &set1, const Set &set2) { Set result = set1; return result += set2; } template Set operator|(const Set &set1, const Set &set2) { return set1 + set2; } template Set operator-(const Set &set1, const Set &set2) { if (set1.empty() || set2.empty()) return set1; Set result; auto it1 = set1.cbegin(); auto it2 = set2.cbegin(); while (it1 != set1.cend()) { if (it2 == set2.cend()) { std::copy(it1, set1.cend(), std::back_inserter(result.m_data)); break; } if (*it1 < *it2) { result.m_data.push_back(*it1++); } else if (*it2 < *it1) { ++it2; } else { ++it1; ++it2; } } return result; } template Set operator&(const Set &set1, const Set &set2) { Set result; auto it1 = set1.cbegin(); auto it2 = set2.cbegin(); while (it1 != set1.cend() && it2 != set2.cend()) { if (*it1 < *it2) { ++it1; continue; } if (*it2 < *it1) { ++it2; continue; } result.m_data.push_back(*it1); ++it1; ++it2; } return result; } } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/launcherpackets.h0000644000175100001660000001176614776170045022124 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LAUNCHERPACKETS_H #define QBS_LAUNCHERPACKETS_H #include #include #include QT_BEGIN_NAMESPACE class QByteArray; QT_END_NAMESPACE namespace qbs { namespace Internal { enum class LauncherPacketType { Shutdown, StartProcess, StopProcess, ProcessError, ProcessFinished }; class PacketParser { public: class InvalidPacketSizeException { public: InvalidPacketSizeException(int size) : size(size) { } const int size; }; void setDevice(QIODevice *device); bool parse(); LauncherPacketType type() const { return m_type; } quintptr token() const { return m_token; } const QByteArray &packetData() const { return m_packetData; } private: QDataStream m_stream; LauncherPacketType m_type = LauncherPacketType::Shutdown; quintptr m_token = 0; QByteArray m_packetData; int m_sizeOfNextPacket = -1; }; class LauncherPacket { public: virtual ~LauncherPacket(); template static Packet extractPacket(quintptr token, const QByteArray &data) { Packet p(token); p.deserialize(data); return p; } QByteArray serialize() const; void deserialize(const QByteArray &data); const LauncherPacketType type; const quintptr token = 0; protected: LauncherPacket(LauncherPacketType type, quintptr token) : type(type), token(token) { } private: virtual void doSerialize(QDataStream &stream) const = 0; virtual void doDeserialize(QDataStream &stream) = 0; }; class StartProcessPacket : public LauncherPacket { public: StartProcessPacket(quintptr token); QString command; QStringList arguments; QString workingDir; QStringList env; private: void doSerialize(QDataStream &stream) const override; void doDeserialize(QDataStream &stream) override; }; class StopProcessPacket : public LauncherPacket { public: StopProcessPacket(quintptr token); private: void doSerialize(QDataStream &stream) const override; void doDeserialize(QDataStream &stream) override; }; class ShutdownPacket : public LauncherPacket { public: ShutdownPacket(); private: void doSerialize(QDataStream &stream) const override; void doDeserialize(QDataStream &stream) override; }; class ProcessErrorPacket : public LauncherPacket { public: ProcessErrorPacket(quintptr token); QProcess::ProcessError error = QProcess::UnknownError; QString errorString; private: void doSerialize(QDataStream &stream) const override; void doDeserialize(QDataStream &stream) override; }; class ProcessFinishedPacket : public LauncherPacket { public: ProcessFinishedPacket(quintptr token); QString errorString; QByteArray stdOut; QByteArray stdErr; QProcess::ExitStatus exitStatus = QProcess::ExitStatus::NormalExit; QProcess::ProcessError error = QProcess::ProcessError::UnknownError; int exitCode = 0; private: void doSerialize(QDataStream &stream) const override; void doDeserialize(QDataStream &stream) override; }; } // namespace Internal } // namespace qbs Q_DECLARE_METATYPE(qbs::Internal::LauncherPacketType); #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/preferences.h0000644000175100001660000000601314776170045021236 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PREFERENCES_H #define QBS_PREFERENCES_H #include "qbs_export.h" #include "commandechomode.h" #include "joblimits.h" #include "settings.h" #include #include namespace qbs { class Settings; class QBS_EXPORT Preferences { public: explicit Preferences(Settings *settings, QString profileName = QString()); Preferences(Settings *settings, QVariantMap profileContents); bool useColoredOutput() const; int jobs() const; QString shell() const; QString defaultBuildDirectory() const; CommandEchoMode defaultEchoMode() const; QStringList searchPaths(const QString &baseDir = QString()) const; QStringList pluginPaths(const QString &baseDir = QString()) const; JobLimits jobLimits() const; private: QVariant getPreference(const QString &key, const QVariant &defaultValue = QVariant()) const; QStringList pathList(const QString &key, const QString &defaultValue) const; bool ignoreSystemSearchPaths() const; Settings::Scopes scopesForSearchPaths() const; Settings *m_settings; QString m_profile; QVariantMap m_profileContents; }; } // namespace qbs #endif // Header guard qbs-src-2.6.1/src/lib/corelib/tools/setupprojectparameters.cpp0000644000175100001660000006133714776170045024115 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "setupprojectparameters.h" #include "buildoptions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { /*! * \class SetupProjectParameters * \brief The \c SetupProjectParameters class comprises data required to set up a qbs project. */ class SetupProjectParametersPrivate : public QSharedData { public: SetupProjectParametersPrivate() : overrideBuildGraphData(false) , dryRun(false) , logElapsedTime(false) , forceProbeExecution(false) , waitLockBuildGraph(false) , restoreBehavior(SetupProjectParameters::RestoreAndTrackChanges) , propertyCheckingMode(ErrorHandlingMode::Strict) , productErrorMode(ErrorHandlingMode::Strict) { } QString projectFilePath; QString topLevelProfile; QString configurationName = QLatin1String("default"); QString buildRoot; QStringList searchPaths; QStringList pluginPaths; QString libexecPath; QString settingsBaseDir; QVariantMap overriddenValues; QVariantMap buildConfiguration; mutable QVariantMap buildConfigurationTree; mutable QVariantMap overriddenValuesTree; mutable QVariantMap finalBuildConfigTree; int maxJobCount = 0; bool overrideBuildGraphData; bool dryRun; bool logElapsedTime; bool forceProbeExecution; bool waitLockBuildGraph; SetupProjectParameters::RestoreBehavior restoreBehavior; ErrorHandlingMode propertyCheckingMode; ErrorHandlingMode productErrorMode; DeprecationWarningMode deprecationWarningMode = defaultDeprecationWarningMode(); QProcessEnvironment environment; }; } // namespace Internal using namespace Internal; SetupProjectParameters::SetupProjectParameters() : d(new SetupProjectParametersPrivate) { } SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) = default; SetupProjectParameters::SetupProjectParameters( SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; SetupProjectParameters::~SetupProjectParameters() = default; SetupProjectParameters &SetupProjectParameters::operator=( const SetupProjectParameters &other) = default; namespace Internal { template<> ErrorHandlingMode fromJson(const QJsonValue &v) { if (v.toString() == QLatin1String("relaxed")) return ErrorHandlingMode::Relaxed; return ErrorHandlingMode::Strict; } template<> DeprecationWarningMode fromJson(const QJsonValue &v) { return deprecationWarningModeFromName(v.toString()); } template<> SetupProjectParameters::RestoreBehavior fromJson(const QJsonValue &v) { const QString value = v.toString(); if (value == QLatin1String("restore-only")) return SetupProjectParameters::RestoreOnly; if (value == QLatin1String("resolve-only")) return SetupProjectParameters::ResolveOnly; if (value == QLatin1String("restore-and-resolve")) return SetupProjectParameters::RestoreAndResolve; return SetupProjectParameters::RestoreAndTrackChanges; } } // namespace Internal SetupProjectParameters SetupProjectParameters::fromJson(const QJsonObject &data) { using namespace Internal; SetupProjectParameters params; setValueFromJson(params.d->topLevelProfile, data, "top-level-profile"); setValueFromJson(params.d->configurationName, data, "configuration-name"); setValueFromJson(params.d->projectFilePath, data, "project-file-path"); setValueFromJson(params.d->buildRoot, data, "build-root"); setValueFromJson(params.d->settingsBaseDir, data, "settings-directory"); setValueFromJson(params.d->maxJobCount, data, "max-job-count"); if (params.maxJobCount() <= 0) params.setMaxJobCount(BuildOptions::defaultMaxJobCount()); setValueFromJson(params.d->overriddenValues, data, "overridden-properties"); setValueFromJson(params.d->dryRun, data, "dry-run"); setValueFromJson(params.d->logElapsedTime, data, "log-time"); setValueFromJson(params.d->forceProbeExecution, data, "force-probe-execution"); setValueFromJson(params.d->waitLockBuildGraph, data, "wait-lock-build-graph"); setValueFromJson(params.d->environment, data, "environment"); setValueFromJson(params.d->restoreBehavior, data, "restore-behavior"); setValueFromJson(params.d->propertyCheckingMode, data, "error-handling-mode"); setValueFromJson(params.d->deprecationWarningMode, data, "deprecation-warning-mode"); params.d->productErrorMode = params.d->propertyCheckingMode; return params; } SetupProjectParameters &SetupProjectParameters::operator=(SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; /*! * \brief Returns the name of the top-level profile for building the project. */ QString SetupProjectParameters::topLevelProfile() const { return d->topLevelProfile; } /*! * \brief Sets the top-level profile for building the project. */ void SetupProjectParameters::setTopLevelProfile(const QString &profile) { d->buildConfigurationTree.clear(); d->finalBuildConfigTree.clear(); d->topLevelProfile = profile; } /*! * Returns the name of the current project build configuration. */ QString SetupProjectParameters::configurationName() const { return d->configurationName; } /*! * Sets the name of the current project build configuration to an arbitrary user-specified name, * \a configurationName. */ void SetupProjectParameters::setConfigurationName(const QString &configurationName) { d->buildConfigurationTree.clear(); d->finalBuildConfigTree.clear(); d->configurationName = configurationName; } /*! * \brief Returns the absolute path to the qbs project file. * This file typically has a ".qbs" suffix. */ QString SetupProjectParameters::projectFilePath() const { return d->projectFilePath; } /*! * \brief Sets the path to the main project file. * \note The argument must be an absolute file path. */ void SetupProjectParameters::setProjectFilePath(const QString &projectFilePath) { d->projectFilePath = projectFilePath; const QString canonicalProjectFilePath = QFileInfo(d->projectFilePath).canonicalFilePath(); if (!canonicalProjectFilePath.isEmpty()) d->projectFilePath = canonicalProjectFilePath; } void SetupProjectParameters::finalizeProjectFilePath() { QString filePath = projectFilePath(); if (filePath.isEmpty()) filePath = QDir::currentPath(); const QFileInfo projectFileInfo(filePath); if (!projectFileInfo.exists()) throw ErrorInfo(Tr::tr("Project file '%1' cannot be found.").arg(filePath)); if (projectFileInfo.isRelative()) filePath = projectFileInfo.absoluteFilePath(); if (projectFileInfo.isFile()) { setProjectFilePath(filePath); return; } if (!projectFileInfo.isDir()) throw ErrorInfo(Tr::tr("Project file '%1' has invalid type.").arg(filePath)); const QStringList &actualFileNames = QDir(filePath).entryList(StringConstants::qbsFileWildcards(), QDir::Files); if (actualFileNames.empty()) { QString error; if (projectFilePath().isEmpty()) error = Tr::tr("No project file given and none found in current directory.\n"); else error = Tr::tr("No project file found in directory '%1'.").arg(filePath); throw ErrorInfo(error); } if (actualFileNames.size() > 1) { throw ErrorInfo(Tr::tr("More than one project file found in directory '%1'.") .arg(filePath)); } filePath.append(QLatin1Char('/')).append(actualFileNames.front()); filePath = QDir::current().filePath(filePath); filePath = QDir::cleanPath(filePath); setProjectFilePath(filePath); } /*! * \brief Returns the base path of where to put the build artifacts and store the build graph. */ QString SetupProjectParameters::buildRoot() const { return d->buildRoot; } /*! * \brief Sets the base path of where to put the build artifacts and store the build graph. * The same base path can be used for several build profiles of the same project without them * interfering with each other. * It might look as if this parameter would not be needed at the time of setting up the project, * but keep in mind that the project information could already exist on disk, in which case * loading it will be much faster than setting up the project from scratch. * \note The argument must be an absolute path to a directory. */ void SetupProjectParameters::setBuildRoot(const QString &buildRoot) { d->buildRoot = buildRoot; // Calling mkpath() may be necessary to get the canonical build root, but if we do it, // it must be reverted immediately afterwards as not to create directories needlessly, // e.g in the case of a dry run build. DirectoryManager dirManager(buildRoot, Logger()); // We don't do error checking here, as this is not a convenient place to report an error. // If creation of the build directory is not possible, we will get sensible error messages // later, e.g. from the code that attempts to store the build graph. QDir::root().mkpath(buildRoot); const QString canonicalBuildRoot = QFileInfo(d->buildRoot).canonicalFilePath(); if (!canonicalBuildRoot.isEmpty()) d->buildRoot = canonicalBuildRoot; } /*! * \brief Where to look for modules and items to import. */ QStringList SetupProjectParameters::searchPaths() const { return d->searchPaths; } /*! * \brief Sets the information about where to look for modules and items to import. * \note The elements of the list must be absolute paths to directories. */ void SetupProjectParameters::setSearchPaths(const QStringList &searchPaths) { d->searchPaths = searchPaths; } /*! * \brief Where to look for plugins. */ QStringList SetupProjectParameters::pluginPaths() const { return d->pluginPaths; } /*! * \brief Sets the information about where to look for plugins. * \note The elements of the list must be absolute paths to directories. */ void SetupProjectParameters::setPluginPaths(const QStringList &pluginPaths) { d->pluginPaths = pluginPaths; } /*! * \brief Where to look for internal binaries. */ QString SetupProjectParameters::libexecPath() const { return d->libexecPath; } /*! * \brief Sets the information about where to look for internal binaries. * \note \p libexecPath must be an absolute path. */ void SetupProjectParameters::setLibexecPath(const QString &libexecPath) { d->libexecPath = libexecPath; } /*! * \brief The base directory for qbs settings. * This value is used to locate profiles and preferences. */ QString SetupProjectParameters::settingsDirectory() const { return d->settingsBaseDir; } /*! * \brief Sets the base directory for qbs settings. * \param settingsBaseDir Will be used to locate profiles and preferences. */ void SetupProjectParameters::setSettingsDirectory(const QString &settingsBaseDir) { d->settingsBaseDir = settingsBaseDir; } /*! * \brief Returns the maximum number of threads to employ when resolving the project. * If the value is not valid (i.e. <= 0), a sensible one will be derived from the number of * available processor cores. * The default is 0. * \sa BuildOptions::defaultMaxJobCount */ int SetupProjectParameters::maxJobCount() const { return d->maxJobCount; } /*! * \brief Controls how many threads to employ when resolving the project. * A value <= 0 leaves the decision to qbs. */ void SetupProjectParameters::setMaxJobCount(int jobCount) { d->maxJobCount = jobCount; } /*! * Returns the overridden values of the build configuration. */ QVariantMap SetupProjectParameters::overriddenValues() const { return d->overriddenValues; } /*! * Set the overridden values of the build configuration. */ void SetupProjectParameters::setOverriddenValues(const QVariantMap &values) { d->overriddenValues = values; d->overriddenValuesTree.clear(); d->finalBuildConfigTree.clear(); } static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree) { if (!valueTree->empty() || values.empty()) return; valueTree->clear(); for (QVariantMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) { const QString &name = it.key(); int idx = name.lastIndexOf(QLatin1Char('.')); const QStringList nameElements = (idx == -1) ? QStringList() << name : QStringList() << name.left(idx) << name.mid(idx + 1); setConfigProperty(*valueTree, nameElements, it.value()); } } QVariantMap SetupProjectParameters::overriddenValuesTree() const { provideValuesTree(d->overriddenValues, &d->overriddenValuesTree); return d->overriddenValuesTree; } /*! * \brief Returns the build configuration. * Overridden values are not taken into account. */ QVariantMap SetupProjectParameters::buildConfiguration() const { return d->buildConfiguration; } /*! * \brief Returns the build configuration in tree form. * Overridden values are not taken into account. */ QVariantMap SetupProjectParameters::buildConfigurationTree() const { provideValuesTree(d->buildConfiguration, &d->buildConfigurationTree); return d->buildConfigurationTree; } static QVariantMap expandedBuildConfigurationInternal(const Profile &profile, const QString &configurationName) { QVariantMap buildConfig; // (1) Values from profile, if given. if (profile.exists() && profile.name() != Profile::fallbackName()) { ErrorInfo err; const QStringList profileKeys = profile.allKeys(Profile::KeySelectionRecursive, &err); if (err.hasError()) throw err; if (profileKeys.empty()) throw ErrorInfo(Tr::tr("Unknown or empty profile '%1'.").arg(profile.name())); for (const QString &profileKey : profileKeys) { buildConfig.insert(profileKey, profile.value(profileKey, QVariant(), &err)); if (err.hasError()) throw err; } } // (2) Build configuration name. if (configurationName.isEmpty()) throw ErrorInfo(Tr::tr("No build configuration name set.")); buildConfig.insert(QStringLiteral("qbs.configurationName"), configurationName); return buildConfig; } QVariantMap SetupProjectParameters::expandedBuildConfiguration(const Profile &profile, const QString &configurationName, ErrorInfo *errorInfo) { try { return expandedBuildConfigurationInternal(profile, configurationName); } catch (const ErrorInfo &err) { if (errorInfo) *errorInfo = err; return {}; } } /*! * \brief Expands the build configuration. * * Expansion is the process by which the build configuration is completed based on the settings * in \c settingsDirectory(). E.g. the information configured in a profile is filled into the build * configuration by this step. * * This method returns an Error. The list of entries in this error will be empty is the * expansion was successful. */ ErrorInfo SetupProjectParameters::expandBuildConfiguration() { ErrorInfo err; Settings settings(d->settingsBaseDir); Profile profile(topLevelProfile(), &settings); QVariantMap expandedConfig = expandedBuildConfiguration(profile, configurationName(), &err); if (err.hasError()) return err; if (!qVariantMapsEqual(d->buildConfiguration, expandedConfig)) { d->buildConfigurationTree.clear(); d->buildConfiguration = expandedConfig; } return err; } QVariantMap SetupProjectParameters::finalBuildConfigurationTree(const QVariantMap &buildConfig, const QVariantMap &overriddenValues) { QVariantMap flatBuildConfig = buildConfig; for (QVariantMap::ConstIterator it = overriddenValues.constBegin(); it != overriddenValues.constEnd(); ++it) { flatBuildConfig.insert(it.key(), it.value()); } QVariantMap buildConfigTree; provideValuesTree(flatBuildConfig, &buildConfigTree); return buildConfigTree; } /*! * \brief Returns the build configuration in tree form, with overridden values taken into account. */ QVariantMap SetupProjectParameters::finalBuildConfigurationTree() const { if (d->finalBuildConfigTree.empty()) { d->finalBuildConfigTree = finalBuildConfigurationTree(buildConfiguration(), overriddenValues()); } return d->finalBuildConfigTree; } /*! * \brief if true, qbs will not store the build graph of the resolved project. */ bool SetupProjectParameters::dryRun() const { return d->dryRun; } /*! * \brief Controls whether the build graph will be stored. * If the argument is true, qbs will not store the build graph after resolving the project. * The default is false. */ void SetupProjectParameters::setDryRun(bool dryRun) { d->dryRun = dryRun; } /*! * \brief Returns true iff the time the operation takes should be logged */ bool SetupProjectParameters::logElapsedTime() const { return d->logElapsedTime; } /*! * Controls whether to log the time taken up for resolving the project. * The default is false. */ void SetupProjectParameters::setLogElapsedTime(bool logElapsedTime) { d->logElapsedTime = logElapsedTime; } /*! * \brief Returns true iff probes should be re-run. */ bool SetupProjectParameters::forceProbeExecution() const { return d->forceProbeExecution; } /*! * Controls whether to re-run probes even if they do not appear to be outdated. * This option only has an effect if \c restoreBehavior() is \c RestoreAndTrackChanges. */ void SetupProjectParameters::setForceProbeExecution(bool force) { d->forceProbeExecution = force; } /*! * \brief Returns true if qbs should wait for the build graph lock to become available, * otherwise qbs will exit immediately if the lock cannot be acquired. */ bool SetupProjectParameters::waitLockBuildGraph() const { return d->waitLockBuildGraph; } /*! * Controls whether to wait indefinitely for the build graph lock to be released. * This allows multiple conflicting qbs processes to be spawned simultaneously. */ void SetupProjectParameters::setWaitLockBuildGraph(bool wait) { d->waitLockBuildGraph = wait; } /*! * \brief Gets the environment used while resolving the project. */ QProcessEnvironment SetupProjectParameters::environment() const { return d->environment; } /*! * \brief Sets the environment used while resolving the project. */ void SetupProjectParameters::setEnvironment(const QProcessEnvironment &env) { d->environment = env; } QProcessEnvironment SetupProjectParameters::adjustedEnvironment() const { QProcessEnvironment result = environment(); const QVariantMap environmentFromProfile = buildConfigurationTree().value(QStringLiteral("buildEnvironment")).toMap(); for (QVariantMap::const_iterator it = environmentFromProfile.begin(); it != environmentFromProfile.end(); ++it) { result.insert(it.key(), it.value().toString()); } return result; } /*! * \enum SetupProjectParamaters::RestoreBehavior * This enum type specifies how to deal with existing on-disk build information. * \value RestoreOnly Indicates that a stored build graph is to be loaded and the information * therein assumed to be up to date. It is then considered an error if no * such build graph exists. * \value ResolveOnly Indicates that no attempt should be made to restore an existing build graph. * Instead, the project is to be resolved from scratch. * \value RestoreAndTrackChanges Indicates that the build graph should be restored from disk * if possible and otherwise set up from scratch. In the first case, * (parts of) the project might still be re-resolved if certain * parameters have changed (e.g. environment variables used in the * project files). */ /*! * Returns information about how restored build data will be handled. */ SetupProjectParameters::RestoreBehavior SetupProjectParameters::restoreBehavior() const { return d->restoreBehavior; } /*! * Controls how restored build data will be handled. */ void SetupProjectParameters::setRestoreBehavior(SetupProjectParameters::RestoreBehavior behavior) { d->restoreBehavior = behavior; } /*! * Returns true if and only if environment, project file path and overridden property values * should be taken from this object even if a build graph already exists. * If this function returns \c false and a build graph exists, then it is an error to provide a * project file path or overridden property values that differ from the respective values * in the build graph. */ bool SetupProjectParameters::overrideBuildGraphData() const { return d->overrideBuildGraphData; } /*! * If \c doOverride is true, then environment, project file path and overridden property values * are taken from this object rather than from the build graph. * The default is \c false. */ void SetupProjectParameters::setOverrideBuildGraphData(bool doOverride) { d->overrideBuildGraphData = doOverride; } /*! * \enum ErrorHandlingMode * This enum type specifies how \QBS should behave if errors occur during project resolving. * \value ErrorHandlingMode::Strict Project resolving will stop with an error message. * \value ErrorHandlingMode::Relaxed Project resolving will continue (if possible), and a warning * will be printed. */ /*! * Indicates how to handle unknown properties. */ ErrorHandlingMode SetupProjectParameters::propertyCheckingMode() const { return d->propertyCheckingMode; } /*! * Controls how to handle unknown properties. * The default is \c PropertyCheckingRelaxed. */ void SetupProjectParameters::setPropertyCheckingMode(ErrorHandlingMode mode) { d->propertyCheckingMode = mode; } /*! * \brief Indicates how errors occurring during product resolving are handled. */ ErrorHandlingMode SetupProjectParameters::productErrorMode() const { return d->productErrorMode; } /*! * \brief Specifies whether an error occurring during product resolving should be fatal or not. * \note Not all errors can be ignored; this setting is mainly intended for things such as * missing dependencies or references to non-existing source files. */ void SetupProjectParameters::setProductErrorMode(ErrorHandlingMode mode) { d->productErrorMode = mode; } /*! * \brief Indicates how deprecated constructs are handled. */ DeprecationWarningMode SetupProjectParameters::deprecationWarningMode() const { return d->deprecationWarningMode; } /*! * \brief Specifies the behavior on encountering deprecated constructs. */ void SetupProjectParameters::setDeprecationWarningMode(DeprecationWarningMode mode) { d->deprecationWarningMode = mode; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/profiling.cpp0000644000175100001660000000740214776170045021264 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "profiling.h" #include #include #include namespace qbs { namespace Internal { class TimedActivityLogger::TimedActivityLoggerPrivate { public: Logger logger; QString activity; QElapsedTimer timer; }; TimedActivityLogger::TimedActivityLogger(const Logger &logger, const QString &activity, bool enabled) : d(nullptr) { if (!enabled) return; d = std::make_unique(); d->logger = logger; d->activity = activity; d->logger.qbsLog(LoggerInfo, true) << Tr::tr("Starting activity '%2'.").arg(activity); d->timer.start(); } void TimedActivityLogger::finishActivity() { if (!d) return; const QString timeString = elapsedTimeString(d->timer.nsecsElapsed()); d->logger.qbsLog(LoggerInfo, true) << Tr::tr("Activity '%2' took %3.").arg(d->activity, timeString); d.reset(); } TimedActivityLogger::~TimedActivityLogger() { finishActivity(); } AccumulatingTimer::AccumulatingTimer(qint64 *elapsedTime) : m_elapsedTime(elapsedTime) { if (elapsedTime) m_timer.start(); } AccumulatingTimer::~AccumulatingTimer() { stop(); } void AccumulatingTimer::stop() { if (!m_timer.isValid()) return; *m_elapsedTime += m_timer.nsecsElapsed(); m_timer.invalidate(); } QString elapsedTimeString(qint64 elapsedTimeInNs) { qint64 ms = elapsedTimeInNs / (1000ll * 1000ll); qint64 s = ms/1000; ms -= s*1000; qint64 m = s/60; s -= m*60; const qint64 h = m/60; m -= h*60; QString timeString = QStringLiteral("%1ms").arg(ms); if (h || m || s) timeString.prepend(QStringLiteral("%1s, ").arg(s)); if (h || m) timeString.prepend(QStringLiteral("%1m, ").arg(m)); if (h) timeString.prepend(QStringLiteral("%1h, ").arg(h)); return timeString; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/scripttools.cpp0000644000175100001660000002601314776170045021657 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scripttools.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value) { if (name.length() == 1) { cfg.insert(name.front(), value); } else { QVariant &subCfg = cfg[name.front()]; QVariantMap subCfgMap = subCfg.toMap(); setConfigProperty(subCfgMap, name.mid(1), value); subCfg = subCfgMap; } } QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name) { if (name.length() == 1) return cfg.value(name.front()); return getConfigProperty(cfg.value(name.front()).toMap(), name.mid(1)); } TemporaryGlobalObjectSetter::TemporaryGlobalObjectSetter( ScriptEngine *engine, const JSValue &object) : m_engine(engine), m_oldGlobalObject(engine->globalObject()) { engine->setGlobalObject(object); } TemporaryGlobalObjectSetter::~TemporaryGlobalObjectSetter() { m_engine->setGlobalObject(m_oldGlobalObject); } JsException::JsException(JsException &&other) noexcept : m_ctx(other.m_ctx), m_exception(other.m_exception), m_fallbackLocation(std::move(other.m_fallbackLocation)) { other.m_exception = JS_NULL; } JsException::~JsException() { JS_FreeValue(m_ctx, m_exception); } QString JsException::message() const { if (JS_IsError(m_ctx, m_exception)) return getJsStringProperty(m_ctx, m_exception, QStringLiteral("message")); const QVariant v = getJsVariant(m_ctx, m_exception); switch (static_cast(v.userType())) { case QMetaType::QVariantMap: return QString::fromUtf8(QJsonDocument(QJsonObject::fromVariantMap(v.toMap())) .toJson(QJsonDocument::Indented)); case QMetaType::QStringList: return QString::fromUtf8(QJsonDocument(QJsonArray::fromStringList(v.toStringList())) .toJson(QJsonDocument::Indented)); case QMetaType::QVariantList: return QString::fromUtf8(QJsonDocument(QJsonArray::fromVariantList(v.toList())) .toJson(QJsonDocument::Indented)); default: return v.toString(); } } const QStringList JsException::stackTrace() const { return getJsStringProperty(m_ctx, m_exception, QLatin1String("stack")) .split(QLatin1Char('\n'), Qt::SkipEmptyParts); } ErrorInfo JsException::toErrorInfo() const { const QString msg = message(); ErrorInfo e(msg, stackTrace()); if (e.hasLocation() || !m_fallbackLocation.isValid()) return e; return {msg, m_fallbackLocation}; } void defineJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val) { JS_DefinePropertyValueStr(ctx, obj, prop.toUtf8().constData(), val, 0); } JSValue getJsProperty(JSContext *ctx, JSValue obj, const QString &prop) { return JS_GetPropertyStr(ctx, obj, prop.toUtf8().constData()); } void setJsProperty(JSContext *ctx, JSValueConst obj, std::string_view prop, JSValue val) { JS_SetPropertyStr(ctx, obj, prop.data(), val); } void setJsProperty(JSContext *ctx, JSValue obj, const QString &prop, JSValue val) { const auto propUtf8 = prop.toUtf8(); setJsProperty(ctx, obj, std::string_view{propUtf8.data(), size_t(propUtf8.size())}, val); } void setJsProperty(JSContext *ctx, JSValue obj, const QString &prop, const QString &val) { setJsProperty(ctx, obj, prop, makeJsString(ctx, val)); } void handleJsProperties(JSContext *ctx, JSValue obj, const std::function &handler) { struct PropsHolder { PropsHolder(JSContext *ctx) : ctx(ctx) {} ~PropsHolder() { for (uint32_t i = 0; i < count; ++i) JS_FreeAtom(ctx, props[i].atom); js_free(ctx, props); } JSContext * const ctx; JSPropertyEnum *props = nullptr; uint32_t count = 0; } propsHolder(ctx); JS_GetOwnPropertyNames(ctx, &propsHolder.props, &propsHolder.count, obj, JS_GPN_STRING_MASK); for (uint32_t i = 0; i < propsHolder.count; ++i) { JSPropertyDescriptor desc{0, JS_UNDEFINED, JS_UNDEFINED, JS_UNDEFINED}; JS_GetOwnProperty(ctx, &desc, obj, propsHolder.props[i].atom); const ScopedJsValueList valueHolder(ctx, {desc.value, desc.getter, desc.setter}); handler(propsHolder.props[i].atom, desc); } } QString getJsString(JSContext *ctx, JSValueConst val) { size_t strLen; const char * const str = JS_ToCStringLen(ctx, &strLen, val); QString s = QString::fromUtf8(str, strLen); JS_FreeCString(ctx, str); return s; } QString getJsStringProperty(JSContext *ctx, JSValue obj, const QString &prop) { const ScopedJsValue sv(ctx, getJsProperty(ctx, obj, prop)); return getJsString(ctx, sv); } int getJsIntProperty(JSContext *ctx, JSValue obj, const QString &prop) { return JS_VALUE_GET_INT(getJsProperty(ctx, obj, prop)); } bool getJsBoolProperty(JSContext *ctx, JSValue obj, const QString &prop) { return JS_VALUE_GET_BOOL(getJsProperty(ctx, obj, prop)); } JSValue makeJsArrayBuffer(JSContext *ctx, const QByteArray &s) { return ScriptEngine::engineForContext(ctx)->asJsValue(s); } JSValue makeJsString(JSContext *ctx, const QString &s) { return ScriptEngine::engineForContext(ctx)->asJsValue(s); } JSValue makeJsStringList(JSContext *ctx, const QStringList &l) { return ScriptEngine::engineForContext(ctx)->asJsValue(l); } JSValue throwError(JSContext *ctx, const QString &message) { return JS_Throw(ctx, makeJsString(ctx, message)); } QStringList getJsStringList(JSContext *ctx, JSValue val) { if (JS_IsString(val)) return {getJsString(ctx, val)}; if (!JS_IsArray(ctx, val)) return {}; const int size = getJsIntProperty(ctx, val, QLatin1String("length")); QStringList l; for (int i = 0; i < size; ++i) { const ScopedJsValue elem(ctx, JS_GetPropertyUint32(ctx, val, i)); l << getJsString(ctx, elem); } return l; } JSValue makeJsVariant(JSContext *ctx, const QVariant &v, quintptr id) { return ScriptEngine::engineForContext(ctx)->asJsValue(v, id); } JSValue makeJsVariantList(JSContext *ctx, const QVariantList &l, quintptr id) { return ScriptEngine::engineForContext(ctx)->asJsValue(l, id); } JSValue makeJsVariantMap(JSContext *ctx, const QVariantMap &m, quintptr id) { return ScriptEngine::engineForContext(ctx)->asJsValue(m, id); } static QVariant getJsVariantImpl(JSContext *ctx, JSValue val, QList path) { if (JS_IsString(val)) return getJsString(ctx, val); if (JS_IsBool(val)) return bool(JS_VALUE_GET_BOOL(val)); if (JS_IsArrayBuffer(val)) { size_t size = 0; const auto data = JS_GetArrayBuffer(ctx, &size, val); if (!data || !size) return QByteArray(); return QByteArray(reinterpret_cast(data), size); } if (JS_IsArray(ctx, val)) { if (path.contains(val)) return {}; path << val; QVariantList l; const int size = getJsIntProperty(ctx, val, QLatin1String("length")); for (int i = 0; i < size; ++i) { const ScopedJsValue sv(ctx, JS_GetPropertyUint32(ctx, val, i)); l << getJsVariantImpl(ctx, sv, path); } return l; } if (JS_IsDate(val)) { ScopedJsValue toString(ctx, getJsProperty(ctx, val, QLatin1String("toISOString"))); if (!JS_IsFunction(ctx, toString)) return {}; ScopedJsValue dateString(ctx, JS_Call(ctx, toString, val, 0, nullptr)); if (!JS_IsString(dateString)) return {}; return QDateTime::fromString(getJsString(ctx, dateString), Qt::ISODateWithMs); } if (JS_IsObject(val)) { if (path.contains(val)) return {}; path << val; QVariantMap map; handleJsProperties(ctx, val, [ctx, &map, path](const JSAtom &prop, const JSPropertyDescriptor &desc) { map.insert(getJsString(ctx, prop), getJsVariantImpl(ctx, desc.value, path)); }); return map; } const auto tag = JS_VALUE_GET_TAG(val); if (tag == JS_TAG_INT) return JS_VALUE_GET_INT(val); else if (JS_TAG_IS_FLOAT64(tag)) return JS_VALUE_GET_FLOAT64(val); return {}; } QVariant getJsVariant(JSContext *ctx, JSValue val) { return getJsVariantImpl(ctx, val, {}); } QStringList getJsStringListProperty(JSContext *ctx, JSValue obj, const QString &prop) { JSValue array = getJsProperty(ctx, obj, prop); QStringList list = getJsStringList(ctx, array); JS_FreeValue(ctx, array); return list; } QVariant getJsVariantProperty(JSContext *ctx, JSValue obj, const QString &prop) { const JSValue vv = getJsProperty(ctx, obj, prop); QVariant v = getJsVariant(ctx, vv); JS_FreeValue(ctx, vv); return v; } QString getJsString(JSContext *ctx, JSAtom atom) { const ScopedJsValue atomString(ctx, JS_AtomToString(ctx, atom)); return getJsString(ctx, atomString); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/dynamictypecheck.h0000644000175100001660000000352214776170045022263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef QBS_DYNAMICTYPECHECK_H #define QBS_DYNAMICTYPECHECK_H namespace qbs { namespace Internal { // Generic implementation would use dynamic_cast. Don't implement unless it becomes necessary. template inline bool hasDynamicType(const StaticType *); } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/qbsassert.cpp0000644000175100001660000000460314776170045021302 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qbsassert.h" #include "error.h" #include namespace qbs { namespace Internal { void writeAssertLocation(const char *condition, const char *file, int line) { qDebug("SOFT ASSERT: %s in %s:%d", condition, file, line); } void throwAssertLocation(const char *condition, const char *file, int line) { throw ErrorInfo(QStringLiteral("ASSERT: %1").arg(QLatin1String(condition)), CodeLocation(QString::fromLocal8Bit(file), line, -1, false), true); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/scannerpluginmanager.h0000644000175100001660000000476614776170045023155 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PLUGINS_SCANNER_H #define QBS_PLUGINS_SCANNER_H #include "qbs_export.h" #include #include class ScannerPlugin; namespace qbs { namespace Internal { class FileTag; class ScannerPluginManagerPrivate; class QBS_EXPORT ScannerPluginManager { public: ~ScannerPluginManager(); static ScannerPluginManager *instance(); static std::vector scannersForFileTag(const FileTag &fileTag); void registerPlugins(ScannerPlugin **plugins); private: ScannerPluginManager(); std::unique_ptr d; }; } // namespace Internal } // namespace qbs #endif // QBS_PLUGINS_SCANNER_H qbs-src-2.6.1/src/lib/corelib/tools/setupprojectparameters.h0000644000175100001660000001304414776170045023552 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETUPPROJECTPARAMETERS_H #define QBS_SETUPPROJECTPARAMETERS_H #include "qbs_export.h" #include #include #include #include QT_BEGIN_NAMESPACE class QProcessEnvironment; using QVariantMap = QMap; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; namespace Internal { class SetupProjectParametersPrivate; } enum class ErrorHandlingMode { Strict, Relaxed }; class QBS_EXPORT SetupProjectParameters { public: SetupProjectParameters(); SetupProjectParameters(const SetupProjectParameters &other); SetupProjectParameters(SetupProjectParameters &&other) Q_DECL_NOEXCEPT; ~SetupProjectParameters(); SetupProjectParameters &operator=(const SetupProjectParameters &other); SetupProjectParameters &operator=(SetupProjectParameters &&other) Q_DECL_NOEXCEPT; static SetupProjectParameters fromJson(const QJsonObject &data); QString topLevelProfile() const; void setTopLevelProfile(const QString &profile); QString configurationName() const; void setConfigurationName(const QString &configurationName); QString projectFilePath() const; void setProjectFilePath(const QString &projectFilePath); void finalizeProjectFilePath(); QString buildRoot() const; void setBuildRoot(const QString &buildRoot); QStringList searchPaths() const; void setSearchPaths(const QStringList &searchPaths); QStringList pluginPaths() const; void setPluginPaths(const QStringList &pluginPaths); QString libexecPath() const; void setLibexecPath(const QString &libexecPath); QString settingsDirectory() const; void setSettingsDirectory(const QString &settingsBaseDir); int maxJobCount() const; void setMaxJobCount(int jobCount); QVariantMap overriddenValues() const; void setOverriddenValues(const QVariantMap &values); QVariantMap overriddenValuesTree() const; static QVariantMap expandedBuildConfiguration(const Profile &profile, const QString &configurationName, ErrorInfo *errorInfo = nullptr); ErrorInfo expandBuildConfiguration(); QVariantMap buildConfiguration() const; QVariantMap buildConfigurationTree() const; static QVariantMap finalBuildConfigurationTree(const QVariantMap &buildConfig, const QVariantMap &overriddenValues); QVariantMap finalBuildConfigurationTree() const; bool overrideBuildGraphData() const; void setOverrideBuildGraphData(bool doOverride); bool dryRun() const; void setDryRun(bool dryRun); bool logElapsedTime() const; void setLogElapsedTime(bool logElapsedTime); bool forceProbeExecution() const; void setForceProbeExecution(bool force); bool waitLockBuildGraph() const; void setWaitLockBuildGraph(bool wait); QProcessEnvironment environment() const; void setEnvironment(const QProcessEnvironment &env); QProcessEnvironment adjustedEnvironment() const; enum RestoreBehavior { RestoreOnly, ResolveOnly, RestoreAndTrackChanges, RestoreAndResolve }; RestoreBehavior restoreBehavior() const; void setRestoreBehavior(RestoreBehavior behavior); ErrorHandlingMode propertyCheckingMode() const; void setPropertyCheckingMode(ErrorHandlingMode mode); ErrorHandlingMode productErrorMode() const; void setProductErrorMode(ErrorHandlingMode mode); DeprecationWarningMode deprecationWarningMode() const; void setDeprecationWarningMode(DeprecationWarningMode mode); private: QSharedDataPointer d; }; } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/scripttools.h0000644000175100001660000001772214776170045021333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SCRIPTTOOLS_H #define QBS_SCRIPTTOOLS_H #include "codelocation.h" #include "porting.h" #include "qbs_export.h" #include #include #include #include #include #include #include namespace qbs { class ErrorInfo; namespace Internal { class ScriptEngine; using JSValueList = std::vector; void defineJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val); JSValue getJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop); void setJsProperty(JSContext *ctx, JSValueConst obj, std::string_view prop, JSValue val); void setJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val); void setJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, const QString &val); QString getJsStringProperty(JSContext *ctx, JSValueConst obj, const QString &prop); QStringList getJsStringListProperty(JSContext *ctx, JSValueConst obj, const QString &prop); int getJsIntProperty(JSContext *ctx, JSValueConst obj, const QString &prop); bool getJsBoolProperty(JSContext *ctx, JSValueConst obj, const QString &prop); QVariant getJsVariantProperty(JSContext *ctx, JSValueConst obj, const QString &prop); QString getJsString(JSContext *ctx, JSValueConst val); QString getJsString(JSContext *ctx, JSAtom atom); QBS_AUTOTEST_EXPORT QVariant getJsVariant(JSContext *ctx, JSValueConst val); JSValue makeJsArrayBuffer(JSContext *ctx, const QByteArray &s); JSValue makeJsString(JSContext *ctx, const QString &s); JSValue makeJsStringList(JSContext *ctx, const QStringList &l); JSValue makeJsVariant(JSContext *ctx, const QVariant &v, quintptr id = 0); JSValue makeJsVariantList(JSContext *ctx, const QVariantList &l, quintptr id = 0); JSValue makeJsVariantMap(JSContext *ctx, const QVariantMap &m, quintptr id = 0); QStringList getJsStringList(JSContext *ctx, JSValueConst val); JSValue throwError(JSContext *ctx, const QString &message); using PropertyHandler = std::function; void handleJsProperties(JSContext *ctx, JSValueConst obj, const PropertyHandler &handler); inline quintptr jsObjectId(const JSValue &val) { return quintptr(JS_VALUE_GET_OBJ(val)); } template void attachPointerTo(JSValue &scriptValue, T *ptr) { JS_SetOpaque(scriptValue, const_cast *>(ptr)); } template T *attachedPointer(const JSValue &scriptValue, JSClassID id) { return reinterpret_cast(JS_GetOpaque(scriptValue, id)); } class TemporaryGlobalObjectSetter { public: TemporaryGlobalObjectSetter(ScriptEngine *engine, const JSValue &object); ~TemporaryGlobalObjectSetter(); private: ScriptEngine * const m_engine; const JSValue m_oldGlobalObject; }; class ScopedJsValue { public: ScopedJsValue(JSContext *ctx, JSValue v) : m_context(ctx), m_value(v) {} void setValue(JSValue v) { JS_FreeValue(m_context, m_value); m_value = v; } ~ScopedJsValue() { JS_FreeValue(m_context, m_value); } operator JSValue() const { return m_value; } JSValue release() { const JSValue v = m_value; m_value = JS_UNDEFINED; return v; } void reset(JSValue v) { JS_FreeValue(m_context, m_value); m_value = v; } ScopedJsValue(const ScopedJsValue &) = delete; ScopedJsValue &operator=(const ScopedJsValue &) = delete; ScopedJsValue(ScopedJsValue && other) : m_context(other.m_context), m_value(other.m_value) { other.m_value = JS_UNDEFINED; } private: JSContext * const m_context; JSValue m_value; }; class ScopedJsValueList { public: ScopedJsValueList(JSContext *ctx, const JSValueList &l) : m_context(ctx), m_list(l) {} ~ScopedJsValueList() { for (const JSValue v : m_list) JS_FreeValue(m_context, v); } operator JSValueList() const { return m_list; } ScopedJsValueList(const ScopedJsValueList &) = delete; ScopedJsValueList &operator=(const ScopedJsValueList &) = delete; ScopedJsValueList(ScopedJsValueList && other) noexcept : m_context(other.m_context), m_list(std::move(other.m_list)) { other.m_list.clear(); } private: JSContext * const m_context; JSValueList m_list; }; class ScopedJsAtom { public: ScopedJsAtom(JSContext *ctx, JSAtom a) : m_context(ctx), m_atom(a) {} ScopedJsAtom(JSContext *ctx, const QByteArray &s) : ScopedJsAtom(ctx, JS_NewAtom(ctx, s.constData())) {} ScopedJsAtom(JSContext *ctx, const QString &s) : ScopedJsAtom(ctx, s.toUtf8()) {} ~ScopedJsAtom() { JS_FreeAtom(m_context, m_atom); } operator JSAtom() const { return m_atom; } ScopedJsAtom(const ScopedJsAtom &) = delete; ScopedJsAtom&operator=(const ScopedJsAtom &) = delete; ScopedJsAtom(ScopedJsAtom &&other) : m_context(other.m_context), m_atom(other.m_atom) { other.m_atom = 0; } private: JSContext * const m_context; JSAtom m_atom; }; class QBS_AUTOTEST_EXPORT JsException { public: JsException(JSContext *ctx, JSValue ex, const CodeLocation &fallbackLocation) : m_ctx(ctx), m_exception(ex), m_fallbackLocation(fallbackLocation) {} JsException(JsException && other) noexcept; ~JsException(); JsException(const JsException &) = delete; JsException &operator=(const JsException &) = delete; operator bool() const { return !JS_IsNull(m_exception); } QString message() const; const QStringList stackTrace() const; ErrorInfo toErrorInfo() const; private: JSContext *m_ctx; JSValue m_exception; CodeLocation m_fallbackLocation; }; void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value); QVariant QBS_AUTOTEST_EXPORT getConfigProperty(const QVariantMap &cfg, const QStringList &name); } // namespace Internal } // namespace qbs // Only to be used for objects! #ifndef JS_NAN_BOXING inline bool operator==(JSValue v1, JSValue v2) { return v1.u.ptr == v2.u.ptr; } inline bool operator!=(JSValue v1, JSValue v2) { return !(v1 == v2); } inline bool operator<(JSValue v1, JSValue v2) { return v1.u.ptr < v2.u.ptr; } inline qbs::QHashValueType qHash(const JSValue &v) { return QT_PREPEND_NAMESPACE(qHash)(v.u.ptr); } #endif #endif // QBS_SCRIPTTOOLS_H qbs-src-2.6.1/src/lib/corelib/tools/buildoptions.cpp0000644000175100001660000003324314776170045022010 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "buildoptions.h" #include "jsonhelper.h" #include #include #include namespace qbs { namespace Internal { class BuildOptionsPrivate : public QSharedData { public: BuildOptionsPrivate() : maxJobCount(0), dryRun(false), keepGoing(false), forceTimestampCheck(false), forceOutputCheck(false), logElapsedTime(false), echoMode(defaultCommandEchoMode()), install(true), removeExistingInstallation(false), onlyExecuteRules(false) { } QStringList changedFiles; QStringList filesToConsider; QStringList activeFileTags; JobLimits jobLimits; QString settingsDir; int maxJobCount; bool dryRun; bool keepGoing; bool forceTimestampCheck; bool forceOutputCheck; bool logElapsedTime; CommandEchoMode echoMode; bool install; bool removeExistingInstallation; bool onlyExecuteRules; bool jobLimitsFromProjectTakePrecedence = false; }; } // namespace Internal /*! * \class BuildOptions * \brief The \c BuildOptions class comprises parameters that influence the behavior of * build and clean operations. */ /*! * \brief Creates a \c BuildOptions object and initializes its members to sensible default values. */ BuildOptions::BuildOptions() : d(new Internal::BuildOptionsPrivate) { } BuildOptions::BuildOptions(const BuildOptions &other) = default; BuildOptions &BuildOptions::operator=(const BuildOptions &other) = default; BuildOptions::~BuildOptions() = default; /*! * \brief If non-empty, qbs pretends that only these files have changed. * By default, this list is empty. */ QStringList BuildOptions::changedFiles() const { return d->changedFiles; } /*! * \brief If the given list is empty, qbs will pretend only the listed files are changed. * \note The list elements must be absolute file paths. */ void BuildOptions::setChangedFiles(const QStringList &changedFiles) { d->changedFiles = changedFiles; } /*! * \brief The list of files to consider. * \sa setFilesToConsider. * By default, this list is empty. */ QStringList BuildOptions::filesToConsider() const { return d->filesToConsider; } /*! * \brief If the given list is non-empty, qbs will run only commands whose rule has at least one * of these files as an input. * \note The list elements must be absolute file paths. */ void BuildOptions::setFilesToConsider(const QStringList &files) { d->filesToConsider = files; } /*! * \brief The list of active file tags. * \sa setActiveFileTags */ QStringList BuildOptions::activeFileTags() const { return d->activeFileTags; } /*! * \brief Set the list of active file tags. * If this list is non-empty, then every transformer with non-matching output file tags is skipped. * E.g. call \c setFilesToConsider() with "foo.cpp" and \c setActiveFileTags() with "obj" to * run the compiler on foo.cpp without further processing like linking. * \sa activeFileTags */ void BuildOptions::setActiveFileTags(const QStringList &fileTags) { d->activeFileTags = fileTags; } /*! * \brief Returns the default value for \c maxJobCount. * This value will be used when \c maxJobCount has not been set explicitly. */ int BuildOptions::defaultMaxJobCount() { return QThread::idealThreadCount(); } /*! * \brief Returns the maximum number of build commands to run concurrently. * If the value is not valid (i.e. <= 0), a sensible one will be derived at build time * from the number of available processor cores at build time. * The default is 0. * \sa BuildOptions::defaultMaxJobCount */ int BuildOptions::maxJobCount() const { return d->maxJobCount; } /*! * \brief Controls how many build commands can be run in parallel. * A value <= 0 leaves the decision to qbs. */ void BuildOptions::setMaxJobCount(int jobCount) { d->maxJobCount = jobCount; } /*! * \brief The base directory for qbs settings. * This value is used to locate profiles and preferences. */ QString BuildOptions::settingsDirectory() const { return d->settingsDir; } /*! * \brief Sets the base directory for qbs settings. * \param settingsBaseDir Will be used to locate profiles and preferences. */ void BuildOptions::setSettingsDirectory(const QString &settingsBaseDir) { d->settingsDir = settingsBaseDir; } JobLimits BuildOptions::jobLimits() const { return d->jobLimits; } void BuildOptions::setJobLimits(const JobLimits &jobLimits) { d->jobLimits = jobLimits; } bool BuildOptions::projectJobLimitsTakePrecedence() const { return d->jobLimitsFromProjectTakePrecedence; } void BuildOptions::setProjectJobLimitsTakePrecedence(bool toggle) { d->jobLimitsFromProjectTakePrecedence = toggle; } /*! * \brief Returns true iff qbs will not actually execute any commands, but just show what * would happen. * The default is false. */ bool BuildOptions::dryRun() const { return d->dryRun; } /*! * \brief Controls whether qbs will actually build something. * If the argument is true, qbs will just emit information about what it would do. Otherwise, * the build is actually done. * \note After you build with this setting enabled, the next call to \c build() on the same * \c Project object will do nothing, since the internal state needs to be updated the same way * as if an actual build had happened. You'll need to create a new \c Project object to do * a real build afterwards. */ void BuildOptions::setDryRun(bool dryRun) { d->dryRun = dryRun; } /*! * \brief Returns true iff a build will continue after an error. * E.g. a failed compile command will result in a warning message being printed, instead of * stopping the build process right away. However, there might still be fatal errors after which the * build process cannot continue. * The default is \c false. */ bool BuildOptions::keepGoing() const { return d->keepGoing; } /*! * \brief Controls whether a qbs will try to continue building after an error has occurred. */ void BuildOptions::setKeepGoing(bool keepGoing) { d->keepGoing = keepGoing; } /*! * \brief Returns true if qbs is to use physical timestamps instead of the timestamps stored in the * build graph. * The default is \c false. */ bool BuildOptions::forceTimestampCheck() const { return d->forceTimestampCheck; } /*! * \brief Controls whether qbs should use physical timestamps for up-to-date checks. */ void BuildOptions::setForceTimestampCheck(bool enabled) { d->forceTimestampCheck = enabled; } /*! * \brief Returns true if qbs will test whether rules actually create their * declared output artifacts. * The default is \c false. */ bool BuildOptions::forceOutputCheck() const { return d->forceOutputCheck; } /*! * \brief Controls whether qbs should test whether rules actually create their * declared output artifacts. Enabling this may introduce some small I/O overhead during the build. */ void BuildOptions::setForceOutputCheck(bool enabled) { d->forceOutputCheck = enabled; } /*! * \brief Returns true iff the time the operation takes will be logged. * The default is \c false. */ bool BuildOptions::logElapsedTime() const { return d->logElapsedTime; } /*! * \brief Controls whether the build time will be measured and logged. */ void BuildOptions::setLogElapsedTime(bool log) { d->logElapsedTime = log; } /*! * \brief The kind of output that is displayed when executing commands. */ CommandEchoMode BuildOptions::echoMode() const { return d->echoMode; } /*! * \brief Controls the kind of output that is displayed when executing commands. */ void BuildOptions::setEchoMode(CommandEchoMode echoMode) { d->echoMode = echoMode; } /*! * \brief Returns true iff installation should happen as part of the build. * The default is \c true. */ bool BuildOptions::install() const { return d->install; } /*! * \brief Controls whether to install artifacts as part of the build process. */ void BuildOptions::setInstall(bool install) { d->install = install; } /*! * \brief Returns true iff an existing installation will be removed prior to building. * The default is false. */ bool BuildOptions::removeExistingInstallation() const { return d->removeExistingInstallation; } /*! * Controls whether to remove an existing installation before installing. * \note qbs may do some safety checks and refuse to remove certain directories such as * a user's home directory. You should still be careful with this option, since it * deletes recursively. */ void BuildOptions::setRemoveExistingInstallation(bool removeExisting) { d->removeExistingInstallation = removeExisting; } /*! * \brief Returns true iff instead of a full build, only the rules of the project will be run. * The default is false. */ bool BuildOptions::executeRulesOnly() const { return d->onlyExecuteRules; } /*! * If \a onlyRules is \c true, then no artifacts are built, but only rules are being executed. * \note If the project contains highly dynamic rules that depend on output artifacts of child * rules being already present, then the associated build job may fail even though * the project is perfectly valid. Callers need to take this into consideration. */ void BuildOptions::setExecuteRulesOnly(bool onlyRules) { d->onlyExecuteRules = onlyRules; } bool operator==(const BuildOptions &bo1, const BuildOptions &bo2) { return bo1.changedFiles() == bo2.changedFiles() && bo1.dryRun() == bo2.dryRun() && bo1.keepGoing() == bo2.keepGoing() && bo1.logElapsedTime() == bo2.logElapsedTime() && bo1.echoMode() == bo2.echoMode() && bo1.maxJobCount() == bo2.maxJobCount() && bo1.install() == bo2.install() && bo1.removeExistingInstallation() == bo2.removeExistingInstallation(); } namespace Internal { template<> JobLimits fromJson(const QJsonValue &limitsData) { JobLimits limits; const QJsonArray &limitsArray = limitsData.toArray(); for (const auto &value : limitsArray) { const QJsonObject limitData = value.toObject(); QString pool; int limit = 0; setValueFromJson(pool, limitData, "pool"); setValueFromJson(limit, limitData, "limit"); if (!pool.isEmpty() && limit > 0) limits.setJobLimit(pool, limit); } return limits; } template<> CommandEchoMode fromJson(const QJsonValue &modeData) { const QString modeString = modeData.toString(); if (modeString == QLatin1String("silent")) return CommandEchoModeSilent; if (modeString == QLatin1String("command-line")) return CommandEchoModeCommandLine; if (modeString == QLatin1String("command-line-with-environment")) return CommandEchoModeCommandLineWithEnvironment; return CommandEchoModeSummary; } } // namespace Internal qbs::BuildOptions qbs::BuildOptions::fromJson(const QJsonObject &data) { using namespace Internal; BuildOptions opt; setValueFromJson(opt.d->changedFiles, data, "changed-files"); setValueFromJson(opt.d->filesToConsider, data, "files-to-consider"); setValueFromJson(opt.d->activeFileTags, data, "active-file-tags"); setValueFromJson(opt.d->jobLimits, data, "job-limits"); setValueFromJson(opt.d->maxJobCount, data, "max-job-count"); setValueFromJson(opt.d->dryRun, data, "dry-run"); setValueFromJson(opt.d->keepGoing, data, "keep-going"); setValueFromJson(opt.d->forceTimestampCheck, data, "check-timestamps"); setValueFromJson(opt.d->forceOutputCheck, data, "check-outputs"); setValueFromJson(opt.d->logElapsedTime, data, "log-time"); setValueFromJson(opt.d->echoMode, data, "command-echo-mode"); setValueFromJson(opt.d->install, data, "install"); setValueFromJson(opt.d->removeExistingInstallation, data, "clean-install-root"); setValueFromJson(opt.d->onlyExecuteRules, data, "only-execute-rules"); setValueFromJson(opt.d->jobLimitsFromProjectTakePrecedence, data, "enforce-project-job-limits"); return opt; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/buildoptions.h0000644000175100001660000001004714776170045021452 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDOPTIONS_H #define QBS_BUILDOPTIONS_H #include "qbs_export.h" #include "commandechomode.h" #include "joblimits.h" #include #include QT_BEGIN_NAMESPACE class QJsonObject; QT_END_NAMESPACE namespace qbs { namespace Internal { class BuildOptionsPrivate; } class QBS_EXPORT BuildOptions { public: BuildOptions(); BuildOptions(const BuildOptions &other); BuildOptions &operator=(const BuildOptions &other); ~BuildOptions(); static BuildOptions fromJson(const QJsonObject &data); QStringList filesToConsider() const; void setFilesToConsider(const QStringList &files); QStringList changedFiles() const; void setChangedFiles(const QStringList &changedFiles); QStringList activeFileTags() const; void setActiveFileTags(const QStringList &fileTags); static int defaultMaxJobCount(); int maxJobCount() const; void setMaxJobCount(int jobCount); QString settingsDirectory() const; void setSettingsDirectory(const QString &settingsBaseDir); JobLimits jobLimits() const; void setJobLimits(const JobLimits &jobLimits); bool projectJobLimitsTakePrecedence() const; void setProjectJobLimitsTakePrecedence(bool toggle); bool dryRun() const; void setDryRun(bool dryRun); bool keepGoing() const; void setKeepGoing(bool keepGoing); bool forceTimestampCheck() const; void setForceTimestampCheck(bool enabled); bool forceOutputCheck() const; void setForceOutputCheck(bool enabled); bool logElapsedTime() const; void setLogElapsedTime(bool log); CommandEchoMode echoMode() const; void setEchoMode(CommandEchoMode echoMode); bool install() const; void setInstall(bool install); bool removeExistingInstallation() const; void setRemoveExistingInstallation(bool removeExisting); bool executeRulesOnly() const; void setExecuteRulesOnly(bool onlyRules); private: QSharedDataPointer d; }; bool operator==(const BuildOptions &bo1, const BuildOptions &bo2); inline bool operator!=(const BuildOptions &bo1, const BuildOptions &bo2) { return !(bo1 == bo2); } } // namespace qbs #endif // QBS_BUILDOPTIONS_H qbs-src-2.6.1/src/lib/corelib/tools/shellutils.cpp0000644000175100001660000002071514776170045021465 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Petroules Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "shellutils.h" #include "pathutils.h" #include "qttools.h" #include #include #include namespace qbs { namespace Internal { QString shellInterpreter(const QString &filePath) { QFile file(filePath); if (file.open(QIODevice::ReadOnly)) { QTextStream ts(&file); const QString shebang = ts.readLine(); if (shebang.startsWith(QLatin1String("#!"))) { return (shebang.mid(2).split(QRegularExpression(QStringLiteral("\\s")), Qt::SkipEmptyParts) << QString()).front(); } } return {}; } // isSpecialChar, hasSpecialChars, shellQuoteUnix, shellQuoteWin: // all from qtbase/qmake/library/ioutils.cpp inline static bool isSpecialChar(ushort c, const uchar (&iqm)[16]) { return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); } inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) { for (auto it = arg.crbegin(), end = arg.crend(); it != end; ++it) { if (isSpecialChar(it->unicode(), iqm)) return true; } return false; } static QString shellQuoteUnix(const QString &arg) { // Chars that should be quoted (TM). This includes: static const uchar iqm[] = { 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78 }; // 0-32 \'"$`<>|;&(){}*?#!~[] if (!arg.length()) return QStringLiteral("''"); QString ret(arg); if (hasSpecialChars(ret, iqm)) { ret.replace(QLatin1Char('\''), QLatin1String("'\\''")); ret.prepend(QLatin1Char('\'')); ret.append(QLatin1Char('\'')); } return ret; } static QString shellQuoteWin(const QString &arg) { // Chars that should be quoted (TM). This includes: // - control chars & space // - the shell meta chars "&()<>^| // - the potential separators ,;= static const uchar iqm[] = { 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 }; // Shell meta chars that need escaping. static const uchar ism[] = { 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 }; // &()<>^| if (!arg.length()) return QStringLiteral("\"\""); QString ret(arg); if (hasSpecialChars(ret, iqm)) { // The process-level standard quoting allows escaping quotes with backslashes (note // that backslashes don't escape themselves, unless they are followed by a quote). // Consequently, quotes are escaped and their preceding backslashes are doubled. ret.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); // Trailing backslashes must be doubled as well, as they are followed by a quote. ret.replace(QRegularExpression(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1")); // However, the shell also interprets the command, and no backslash-escaping exists // there - a quote always toggles the quoting state, but is nonetheless passed down // to the called process verbatim. In the unquoted state, the circumflex escapes // meta chars (including itself and quotes), and is removed from the command. bool quoted = true; for (int i = 0; i < ret.length(); i++) { QChar c = ret.unicode()[i]; if (c.unicode() == '"') quoted = !quoted; else if (!quoted && isSpecialChar(c.unicode(), ism)) ret.insert(i++, QLatin1Char('^')); } if (!quoted) ret.append(QLatin1Char('^')); ret.append(QLatin1Char('"')); ret.prepend(QLatin1Char('"')); } return ret; } QString shellQuote(const QString &arg, HostOsInfo::HostOs os) { return os == HostOsInfo::HostOsWindows ? shellQuoteWin(arg) : shellQuoteUnix(arg); } std::string shellQuote(const std::string &arg, HostOsInfo::HostOs os) { return shellQuote(QString::fromStdString(arg), os).toStdString(); } QString shellQuote(const QStringList &args, HostOsInfo::HostOs os) { QString result; if (!args.empty()) { result += shellQuote(args.at(0), os); for (int i = 1; i < args.size(); ++i) result += QLatin1Char(' ') + shellQuote(args.at(i), os); } return result; } std::string shellQuote(const std::vector &args, HostOsInfo::HostOs os) { std::string result; if (!args.empty()) { auto it = args.cbegin(); const auto end = args.cend(); result += shellQuote(*it++, os); for (; it != end; ++it) { result.push_back(' '); result.append(shellQuote(*it, os)); } } return result; } QString shellQuote(const QString &program, const QStringList &args, HostOsInfo::HostOs os) { QString result = shellQuote(program, os); if (!args.empty()) result += QLatin1Char(' ') + shellQuote(args, os); return result; } void CommandLine::setProgram(const QString &program, bool raw) { m_program = program; m_isRawProgram = raw; } void CommandLine::setProgram(const std::string &program, bool raw) { m_program = QString::fromStdString(program); m_isRawProgram = raw; } void CommandLine::appendArgument(const QString &value) { m_arguments.emplace_back(value); } void CommandLine::appendArgument(const std::string &value) { m_arguments.emplace_back(QString::fromStdString(value)); } void CommandLine::appendArguments(const QList &args) { for (const QString &arg : args) appendArgument(arg); } void CommandLine::appendRawArgument(const QString &value) { Argument arg(value); arg.shouldQuote = false; m_arguments.push_back(arg); } void CommandLine::appendRawArgument(const std::string &value) { appendRawArgument(QString::fromStdString(value)); } void CommandLine::appendPathArgument(const QString &value) { Argument arg(value); arg.isFilePath = true; m_arguments.push_back(arg); } void CommandLine::clearArguments() { m_arguments.clear(); } QString CommandLine::toCommandLine(HostOsInfo::HostOs os) const { QString result = PathUtils::toNativeSeparators(m_program, os); if (!m_isRawProgram) result = shellQuote(result, os); for (const Argument &arg : m_arguments) { const QString value = arg.isFilePath ? PathUtils::toNativeSeparators(arg.value, os) : arg.value; result += QLatin1Char(' ') + (arg.shouldQuote ? shellQuote(value, os) : value); } return result; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/version.cpp0000644000175100001660000000732314776170045020762 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "version.h" #include #include namespace qbs { Version Version::fromString(const QString &versionString, bool buildNumberAllowed) { QString pattern = QStringLiteral("(\\d+)"); // At least one number. for (int i = 0; i < 2; ++i) pattern += QStringLiteral("(?:\\.(\\d+))?"); // Followed by a dot and a number up to two times. if (buildNumberAllowed) pattern += QStringLiteral("(?:[-.](\\d+))?"); // And possibly a dash or dot followed by the build number. const QRegularExpression rex(QRegularExpression::anchoredPattern(pattern)); const QRegularExpressionMatch match = rex.match(versionString); if (!match.hasMatch()) return Version{}; const int majorNr = match.captured(1).toInt(); const int minorNr = match.lastCapturedIndex() >= 2 ? match.captured(2).toInt() : 0; const int patchNr = match.lastCapturedIndex() >= 3 ? match.captured(3).toInt() : 0; const int buildNr = match.lastCapturedIndex() >= 4 ? match.captured(4).toInt() : 0; return Version{majorNr, minorNr, patchNr, buildNr}; } QString Version::toString(const QChar &separator, const QChar &buildSeparator) const { if (m_build) { return QStringLiteral("%1%5%2%5%3%6%4") .arg(QString::number(m_major), QString::number(m_minor), QString::number(m_patch), QString::number(m_build), separator, buildSeparator); } return QStringLiteral("%1%4%2%4%3") .arg(QString::number(m_major), QString::number(m_minor), QString::number(m_patch), separator); } VersionRange &VersionRange::narrowDown(const VersionRange &other) { if (other.minimum > minimum) minimum = other.minimum; if (other.maximum.isValid() && other.maximum < maximum) maximum = other.maximum; return *this; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/clangclinfo.h0000644000175100001660000000431314776170045021215 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef QBS_CLANGCLINFO_H #define QBS_CLANGCLINFO_H #include "logging/logger.h" #include #include namespace qbs { namespace Internal { class ClangClInfo { public: QString toolchainInstallPath; QString vcvarsallPath; bool isEmpty() const { return toolchainInstallPath.isEmpty() && vcvarsallPath.isEmpty(); } QBS_EXPORT QVariantMap toVariantMap() const; QBS_EXPORT static ClangClInfo fromCompilerFilePath(const QString &path, Logger &logger); QBS_EXPORT static std::vector installedCompilers( const std::vector &extraPaths, qbs::Internal::Logger &logger); }; } // namespace Internal } // namespace qbs #endif // QBS_CLANGCLINFO_H qbs-src-2.6.1/src/lib/corelib/tools/codelocation.cpp0000644000175100001660000001367614776170045021750 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "codelocation.h" #include #include #include #include #include #include #include #include #include #include #include namespace qbs { CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, bool checkPath) { QBS_ASSERT(!checkPath || Internal::FileInfo::isAbsolute(aFilePath), qDebug() << aFilePath); m_filePath = aFilePath; m_line = aLine; m_column = aColumn; } QString CodeLocation::toString() const { QString str; if (isValid()) { str = QDir::toNativeSeparators(filePath()); QString lineAndColumn; if (line() > 0 && !str.contains(QRegularExpression(QStringLiteral(":[0-9]+$")))) lineAndColumn += QLatin1Char(':') + QString::number(line()); if (column() > 0 && !str.contains(QRegularExpression(QStringLiteral(":[0-9]+:[0-9]+$")))) lineAndColumn += QLatin1Char(':') + QString::number(column()); str += lineAndColumn; } return str; } QJsonObject CodeLocation::toJson() const { QJsonObject obj; if (!filePath().isEmpty()) obj.insert(Internal::StringConstants::filePathKey(), filePath()); if (line() != -1) obj.insert(QStringLiteral("line"), line()); if (column() != -1) obj.insert(QStringLiteral("column"), column()); return obj; } void CodeLocation::load(Internal::PersistentPool &pool) { const bool isValid = pool.load(); if (!isValid) return; pool.load(m_filePath); pool.load(m_line); pool.load(m_column); } void CodeLocation::store(Internal::PersistentPool &pool) const { if (isValid()) { pool.store(true); pool.store(m_filePath); pool.store(m_line); pool.store(m_column); } else { pool.store(false); } } bool operator==(const CodeLocation &cl1, const CodeLocation &cl2) { return cl1.filePath() == cl2.filePath() && cl1.line() == cl2.line() && cl1.column() == cl2.column(); } bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2) { return !(cl1 == cl2); } QDebug operator<<(QDebug debug, const CodeLocation &location) { return debug << location.toString(); } bool operator<(const CodeLocation &cl1, const CodeLocation &cl2) { return cl1.toString() < cl2.toString(); } void CodePosition::load(Internal::PersistentPool &pool) { pool.load(m_line, m_column); } void CodePosition::store(Internal::PersistentPool &pool) const { pool.store(m_line, m_column); } bool operator==(const CodePosition &pos1, const CodePosition &pos2) { return pos1.line() == pos2.line() && pos1.column() == pos2.column(); } bool operator!=(const CodePosition &pos1, const CodePosition &pos2) { return !(pos1 == pos2); } bool operator<(const CodePosition &pos1, const CodePosition &pos2) { const int lineDiff = pos1.line() - pos2.line(); if (lineDiff < 0) return true; if (lineDiff > 0) return false; return pos1.column() < pos2.column(); } bool operator>(const CodePosition &pos1, const CodePosition &pos2) { return pos2 < pos1; } bool operator<=(const CodePosition &pos1, const CodePosition &pos2) { return !(pos1 > pos2); } bool operator>=(const CodePosition &pos1, const CodePosition &pos2) { return !(pos1 < pos2); } CodeRange::CodeRange(const CodePosition &start, const CodePosition &end) : m_start(start), m_end(end) {} void CodeRange::load(Internal::PersistentPool &pool) { pool.load(m_start, m_end); } void CodeRange::store(Internal::PersistentPool &pool) const { pool.store(m_start, m_end); } bool CodeRange::contains(const CodePosition &pos) const { return start() <= pos && end() > pos; } bool operator==(const CodeRange &r1, const CodeRange &r2) { return r1.start() == r2.start() && r1.end() == r2.end(); } bool operator!=(const CodeRange &r1, const CodeRange &r2) { return !(r1 == r2); } bool operator<(const CodeRange &r1, const CodeRange &r2) { return r1.start() < r2.start(); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/cleanoptions.h0000644000175100001660000000536314776170045021442 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_CLEANOPTIONS_H #define QBS_CLEANOPTIONS_H #include "qbs_export.h" #include QT_BEGIN_NAMESPACE class QJsonObject; QT_END_NAMESPACE namespace qbs { namespace Internal { class CleanOptionsPrivate; } class QBS_EXPORT CleanOptions { public: CleanOptions(); CleanOptions(const CleanOptions &other); CleanOptions(CleanOptions &&other) Q_DECL_NOEXCEPT; CleanOptions &operator=(const CleanOptions &other); CleanOptions &operator=(CleanOptions &&other) Q_DECL_NOEXCEPT; ~CleanOptions(); static CleanOptions fromJson(const QJsonObject &data); bool dryRun() const; void setDryRun(bool dryRun); bool keepGoing() const; void setKeepGoing(bool keepGoing); bool logElapsedTime() const; void setLogElapsedTime(bool log); private: QSharedDataPointer d; }; } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/settingsrepresentation.h0000644000175100001660000000435514776170045023567 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETTINGSREPRESENTATION_H #define QBS_SETTINGSREPRESENTATION_H #include #include #include namespace qbs { QBS_EXPORT QString settingsValueToRepresentation(const QVariant &value); QBS_EXPORT QVariant representationToSettingsValue(const QString &representation); } // namespace qbs #endif // QBS_SETTINGSREPRESENTATION_H qbs-src-2.6.1/src/lib/corelib/tools/toolchains.cpp0000644000175100001660000001147314776170045021441 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "toolchains.h" #include "stringconstants.h" #include namespace qbs { namespace Internal { static const QString clangToolchain() { return QStringLiteral("clang"); } static const QString clangClToolchain() { return QStringLiteral("clang-cl"); } static const QString gccToolchain() { return QStringLiteral("gcc"); } static const QString llvmToolchain() { return QStringLiteral("llvm"); } static const QString mingwToolchain() { return QStringLiteral("mingw"); } static const QString msvcToolchain() { return QStringLiteral("msvc"); } static const QString emscriptenToolchain() { return QStringLiteral("emscripten"); } } // namespace Internal using namespace Internal; QStringList canonicalToolchain(const QStringList &toolchain) { static const QStringList knownToolchains{ StringConstants::xcode(), clangToolchain(), llvmToolchain(), mingwToolchain(), gccToolchain(), clangClToolchain(), msvcToolchain(), emscriptenToolchain()}; // Canonicalize each toolchain in the toolchain list, // which gets us the aggregate canonicalized (unsorted) list QStringList toolchains; for (const QString &toolchainName : toolchain) toolchains << canonicalToolchain(toolchainName); toolchains.removeDuplicates(); // Find all known toolchains in the canonicalized list, // removing them from the main list as we go. QStringList usedKnownToolchains; for (int i = 0; i < toolchains.size(); ++i) { if (knownToolchains.contains(toolchains[i])) { usedKnownToolchains << toolchains[i]; toolchains.removeAt(i--); } } // Sort the list of known toolchains into their canonical order. std::sort(usedKnownToolchains.begin(), usedKnownToolchains.end(), []( const QString &a, const QString &b) { return knownToolchains.indexOf(a) < knownToolchains.indexOf(b); }); // Re-add the known toolchains to the main list (the custom ones go first). toolchains << usedKnownToolchains; // The toolchain list still needs further validation as it may contain mututally exclusive // toolchain types (for example, llvm and msvc). return toolchains; } QStringList canonicalToolchain(const QString &name) { const QString &toolchainName = name.toLower(); QStringList toolchains(toolchainName); if (toolchainName == StringConstants::xcode()) { toolchains << canonicalToolchain(clangToolchain()); } else if (toolchainName == clangToolchain()) { toolchains << canonicalToolchain(llvmToolchain()); } else if (toolchainName == llvmToolchain() || toolchainName == mingwToolchain() || toolchainName == emscriptenToolchain()) { toolchains << canonicalToolchain(QStringLiteral("gcc")); } else if (toolchainName == clangClToolchain()) { toolchains << canonicalToolchain(msvcToolchain()); } return toolchains; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/architectures.cpp0000644000175100001660000001336414776170045022144 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Petroules Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "architectures.h" #include "stringconstants.h" #include #include namespace qbs { using namespace Internal; QString canonicalTargetArchitecture(const QString &architecture, const QString &endianness, const QString &vendor, const QString &system, const QString &abi) { QString arch = canonicalArchitecture(architecture); const bool isApple = (vendor == QStringLiteral("apple") || system == QStringLiteral("darwin") || system == QStringLiteral("macosx") || system == QStringLiteral("ios") || system == QStringLiteral("tvos") || system == QStringLiteral("watchos") || abi == QStringLiteral("macho")); const bool isQnx = (system == QStringLiteral("nto") || abi.startsWith(QStringLiteral("qnx"))); if (arch == QStringLiteral("armv7a")) { if (isApple) return StringConstants::armv7Arch(); if (isQnx) return StringConstants::armArch(); } if (arch == StringConstants::arm64Arch() && isQnx) return StringConstants::aarch64Arch(); if (arch == StringConstants::x86Arch()) { if (isQnx) return StringConstants::i586Arch(); return StringConstants::i386Arch(); } if (arch == StringConstants::mipsArch() || arch == StringConstants::mips64Arch()) { if (endianness == QStringLiteral("big")) return arch + QStringLiteral("eb"); if (endianness == QStringLiteral("little")) return arch + QStringLiteral("el"); } if (arch == StringConstants::ppcArch()) return StringConstants::powerPcArch(); if (arch == StringConstants::ppc64Arch() && endianness == QStringLiteral("little")) return arch + QStringLiteral("le"); return arch; } QString canonicalArchitecture(const QString &architecture) { QMap archMap; archMap.insert(StringConstants::x86Arch(), QStringList() << StringConstants::i386Arch() << QStringLiteral("i486") << StringConstants::i586Arch() << QStringLiteral("i686") << QStringLiteral("ia32") << QStringLiteral("ia-32") << QStringLiteral("x86_32") << QStringLiteral("x86-32") << QStringLiteral("intel32") << QStringLiteral("mingw32")); archMap.insert(StringConstants::x86_64Arch(), QStringList() << QStringLiteral("x86-64") << QStringLiteral("x64") << StringConstants::amd64Arch() << QStringLiteral("ia32e") << QStringLiteral("em64t") << QStringLiteral("intel64") << QStringLiteral("mingw64")); archMap.insert(StringConstants::arm64Arch(), QStringList() << StringConstants::aarch64Arch()); archMap.insert(QStringLiteral("ia64"), QStringList() << QStringLiteral("ia-64") << QStringLiteral("itanium")); archMap.insert(StringConstants::ppcArch(), QStringList() << StringConstants::powerPcArch()); archMap.insert(StringConstants::ppc64Arch(), QStringList() << QStringLiteral("ppc64le") << QStringLiteral("powerpc64") << QStringLiteral("powerpc64le")); archMap.insert(StringConstants::mipsArch(), QStringList() << QStringLiteral("mipseb") << QStringLiteral("mipsel")); archMap.insert(StringConstants::mips64Arch(), QStringList() << QStringLiteral("mips64eb") << QStringLiteral("mips64el")); for (auto i = archMap.cbegin(), end = archMap.cend(); i != end; ++i) { if (i.value().contains(architecture.toLower())) return i.key(); } return architecture; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/preferences.cpp0000644000175100001660000001621314776170045021574 0ustar runnerdocker#include /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "preferences.h" #include "buildoptions.h" #include "hostosinfo.h" #include "profile.h" #include "stringconstants.h" namespace qbs { /*! * \class Preferences * \brief The \c Preferences class gives access to all general qbs preferences. * If a non-empty \c profileName is given, the profile's preferences take precedence over global * ones. Otherwise, the global preferences are used. */ Preferences::Preferences(Settings *settings, QString profileName) : m_settings(settings), m_profile(std::move(profileName)) { } Preferences::Preferences(Settings *settings, QVariantMap profileContents) : m_settings(settings), m_profileContents(std::move(profileContents)) { } /*! * \brief Returns true <=> colored output should be used for printing messages. * This is only relevant for command-line frontends. */ bool Preferences::useColoredOutput() const { return getPreference(QStringLiteral("useColoredOutput"), true).toBool(); } /*! * \brief Returns the number of parallel jobs to use for building. * Uses a sensible default value if there is no such setting. */ int Preferences::jobs() const { return getPreference(QStringLiteral("jobs"), BuildOptions::defaultMaxJobCount()).toInt(); } /*! * \brief Returns the shell to use for the "qbs shell" command. * This is only relevant for command-line frontends. */ QString Preferences::shell() const { return getPreference(QStringLiteral("shell")).toString(); } /*! * \brief Returns the default build directory used by Qbs if none is specified. */ QString Preferences::defaultBuildDirectory() const { return getPreference(QStringLiteral("defaultBuildDirectory")).toString(); } /*! * \brief Returns the default echo mode used by Qbs if none is specified. */ CommandEchoMode Preferences::defaultEchoMode() const { return commandEchoModeFromName(getPreference(QStringLiteral("defaultEchoMode")).toString()); } /*! * \brief Returns the list of paths where qbs looks for modules and imports. * In addition to user-supplied locations, they will also be looked up at \c{baseDir}/share/qbs. */ QStringList Preferences::searchPaths(const QString &baseDir) const { return pathList(Internal::StringConstants::qbsSearchPathsProperty(), baseDir + QLatin1String("/share/qbs")); } /*! * \brief Returns the list of paths where qbs looks for plugins. * In addition to user-supplied locations, they will be looked up at \c{baseDir}/qbs/plugins. */ QStringList Preferences::pluginPaths(const QString &baseDir) const { return pathList(QStringLiteral("pluginsPath"), baseDir + QStringLiteral("/qbs/plugins")); } /*! * \brief Returns the per-pool job limits. */ JobLimits Preferences::jobLimits() const { const QString prefix = QStringLiteral("preferences.jobLimit"); JobLimits limits; const auto keys = m_settings->allKeysWithPrefix(prefix, Settings::allScopes()); for (const QString &key : keys) { limits.setJobLimit(key, m_settings->value(prefix + QLatin1Char('.') + key, Settings::allScopes()).toInt()); } const QString fullPrefix = prefix + QLatin1Char('.'); if (!m_profile.isEmpty()) { Profile p(m_profile, m_settings, m_profileContents); const auto keys = p.allKeys(Profile::KeySelectionRecursive); for (const QString &key : keys) { if (!key.startsWith(fullPrefix)) continue; const QString jobPool = key.mid(fullPrefix.size()); const int limit = p.value(key).toInt(); if (limit >= 0) limits.setJobLimit(jobPool, limit); } } return limits; } QVariant Preferences::getPreference(const QString &key, const QVariant &defaultValue) const { static const QString keyPrefix = QStringLiteral("preferences"); const QString fullKey = keyPrefix + QLatin1Char('.') + key; const bool isSearchPaths = key == Internal::StringConstants::qbsSearchPathsProperty(); if (!m_profile.isEmpty()) { QVariant value = Profile(m_profile, m_settings).value(fullKey); if (value.isValid()) { if (isSearchPaths) { // Merge with top-level value. value = value.toStringList() + m_settings->value( fullKey, scopesForSearchPaths()).toStringList(); } return value; } } QVariant value = m_profileContents.value(keyPrefix).toMap().value(key); if (value.isValid()) { if (isSearchPaths) {// Merge with top-level value value = value.toStringList() + m_settings->value( fullKey, scopesForSearchPaths()).toStringList(); } return value; } return m_settings->value(fullKey, isSearchPaths ? scopesForSearchPaths() : Settings::allScopes(), defaultValue); } QStringList Preferences::pathList(const QString &key, const QString &defaultValue) const { QStringList paths = getPreference(key).toStringList(); paths << defaultValue; return paths; } bool Preferences::ignoreSystemSearchPaths() const { return getPreference(QStringLiteral("ignoreSystemSearchPaths")).toBool(); } Settings::Scopes Preferences::scopesForSearchPaths() const { return ignoreSystemSearchPaths() ? Settings::UserScope : Settings::allScopes(); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/qbsprocess.h0000644000175100001660000000763214776170045021131 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_QBSPROCESS_H #define QBS_QBSPROCESS_H #include "launcherpackets.h" #include #include #include #include namespace qbs { namespace Internal { class QbsProcess : public QObject { Q_OBJECT public: explicit QbsProcess(QObject *parent = nullptr); QProcess::ProcessState state() const { return m_state; } void setProcessEnvironment(const QProcessEnvironment &env) { m_environment = env; } void setWorkingDirectory(const QString &workingDir) { m_workingDirectory = workingDir; } QString workingDirectory() const { return m_workingDirectory; } void start(const QString &command, const QStringList &arguments); void cancel(); QByteArray readAllStandardOutput(); QByteArray readAllStandardError(); int exitCode() const { return m_exitCode; } QProcess::ProcessError error() const { return m_error; } QString errorString() const { return m_errorString; } signals: void errorOccurred(QProcess::ProcessError error); void finished(int exitCode); private: void doStart(); void sendPacket(const LauncherPacket &packet); QByteArray readAndClear(QByteArray &data); void handleSocketError(const QString &message); void handlePacket(qbs::Internal::LauncherPacketType type, quintptr token, const QByteArray &payload); void handleErrorPacket(const QByteArray &packetData); void handleFinishedPacket(const QByteArray &packetData); void handleSocketReady(); quintptr token() const { return reinterpret_cast(this); } QString m_command; QStringList m_arguments; QProcessEnvironment m_environment; QString m_workingDirectory; QByteArray m_stdout; QByteArray m_stderr; QString m_errorString; QProcess::ProcessError m_error = QProcess::UnknownError; QProcess::ProcessState m_state = QProcess::NotRunning; int m_exitCode = 0; int m_connectionAttempts = 0; bool m_socketError = false; }; } // namespace Internal } // namespace qbs #endif // QBSPROCESS_H qbs-src-2.6.1/src/lib/corelib/tools/qbspluginmanager.h0000644000175100001660000000607414776170045022303 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PLUGINS_H #define QBS_PLUGINS_H #include "qbs_export.h" #include #include #include namespace qbs { namespace Internal { class Logger; typedef void (*QbsPluginLoadFunction)(); typedef void (*QbsPluginUnloadFunction)(); class QbsPluginManagerPrivate; class QBS_EXPORT QbsPluginManager { public: ~QbsPluginManager(); static QbsPluginManager *instance(); void registerStaticPlugin(QbsPluginLoadFunction, QbsPluginUnloadFunction); void loadStaticPlugins(); void unloadStaticPlugins(); void loadPlugins(const std::vector &paths, const Logger &logger); protected: QbsPluginManager(); private: std::unique_ptr d; }; } // namespace Internal } // namespace qbs #ifdef QBS_STATIC_LIB #define QBS_REGISTER_STATIC_PLUGIN(exportmacro, name, load, unload) \ extern "C" bool qbs_static_plugin_register_##name = [] { \ qbs::Internal::QbsPluginManager::instance()->registerStaticPlugin(load, unload); \ return true; \ }(); #else #define QBS_REGISTER_STATIC_PLUGIN(exportmacro, name, load, unload) \ exportmacro void QbsPluginLoad() { load(); } \ exportmacro void QbsPluginUnload() { unload(); } #endif #endif qbs-src-2.6.1/src/lib/corelib/tools/iosutils.h0000644000175100001660000000717214776170045020617 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_IOSUTILS_H #define QBS_IOSUTILS_H #include #include #include #if defined(_WIN32) && defined(_MSC_VER) #include #include #define QBS_RENAME_IMPL ::_wrename #define QBS_UNLINK_IMPL ::_wunlink using qbs_filesystem_path_string_type = std::wstring; #else #include #define QBS_RENAME_IMPL ::rename #define QBS_UNLINK_IMPL ::unlink using qbs_filesystem_path_string_type = std::string; #endif namespace qbs { namespace Internal { static inline bool fwrite(const char *values, size_t nitems, std::ostream *stream) { if (!stream) return false; stream->write(values, nitems); return stream->good(); } template bool fwrite(const C &container, std::ostream *stream) { return fwrite(&*(std::begin(container)), container.size(), stream); } static inline bool fwrite(const char *s, std::ostream *stream) { return fwrite(s, strlen(s), stream); } static inline qbs_filesystem_path_string_type utf8_to_native_path(const std::string &str) { #if defined(_WIN32) && defined(_MSC_VER) const int size = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); std::wstring result(size, 0); MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), result.data(), size); return result; #else return str; #endif } static inline int rename(const std::string &oldName, const std::string &newName) { const auto wOldName = utf8_to_native_path(oldName); const auto wNewName = utf8_to_native_path(newName); return QBS_RENAME_IMPL(wOldName.c_str(), wNewName.c_str()); } static inline int unlink(const std::string &name) { const auto wName = utf8_to_native_path(name); return QBS_UNLINK_IMPL(wName.c_str()); } } // namespace Internal } // namespace qbs #endif // QBS_IOSUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/settingscreator.cpp0000644000175100001660000001166514776170045022521 0ustar runnerdocker#include #include /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "settingscreator.h" #include "fileinfo.h" #include "hostosinfo.h" #include #include #include #include namespace qbs { namespace Internal { namespace { QString getBaseDir(QString baseDir) { if (!baseDir.isEmpty()) return baseDir; const char key[] = "QBS_SETTINGS_DIR"; if (qEnvironmentVariableIsSet(key)) return QLatin1String(qgetenv(key)); return {}; } } // namespace static QSettings::Format format() { return HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat; } SettingsCreator::SettingsCreator(QString baseDir) : m_settingsBaseDir(getBaseDir(std::move(baseDir))) , m_qbsVersion(Version::fromString(QLatin1String(QBS_VERSION))) { } std::unique_ptr SettingsCreator::getQSettings() { createQSettings(); migrate(); return std::move(m_settings); } void SettingsCreator::migrate() { if (!m_settings->allKeys().empty()) // We already have settings for this qbs version. return; m_settings.reset(); // Find settings from highest qbs version lower than this one and copy all settings data. const Version thePredecessor = predecessor(); QString oldSettingsDir = m_settingsBaseDir; if (thePredecessor.isValid()) oldSettingsDir.append(QLatin1String("/qbs/")).append(thePredecessor.toString()); const QString oldSettingsFilePath = oldSettingsDir + QLatin1Char('/') + m_settingsFileName; if (QFileInfo::exists(oldSettingsFilePath) && (!QDir::root().mkpath(m_newSettingsDir) || !QFile::copy(oldSettingsFilePath, m_newSettingsFilePath))) { qWarning() << "Error in settings migration: Could not copy" << oldSettingsFilePath << "to" << m_newSettingsFilePath; } m_settings = std::make_unique(m_newSettingsFilePath, format()); } void SettingsCreator::createQSettings() { std::unique_ptr tmp(m_settingsBaseDir.isEmpty() ? new QSettings(format(), QSettings::UserScope, QStringLiteral("QtProject"), QStringLiteral("qbs")) : new QSettings(m_settingsBaseDir + QLatin1String("/qbs.conf"), format())); const QFileInfo fi(tmp->fileName()); m_settingsBaseDir = fi.path(); m_newSettingsDir = m_settingsBaseDir + QLatin1String("/qbs/") + m_qbsVersion.toString(); m_settingsFileName = fi.fileName(); m_newSettingsFilePath = m_newSettingsDir + QLatin1Char('/') + m_settingsFileName; m_settings = std::make_unique(m_newSettingsFilePath, tmp->format()); } Version SettingsCreator::predecessor() const { QDirIterator dit(m_settingsBaseDir + QLatin1String("/qbs")); Version thePredecessor; while (dit.hasNext()) { dit.next(); const auto currentVersion = Version::fromString(dit.fileName()); if (currentVersion > thePredecessor && currentVersion < m_qbsVersion) thePredecessor = currentVersion; } return thePredecessor; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/cleanoptions.cpp0000644000175100001660000001161014776170045021765 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "cleanoptions.h" #include "jsonhelper.h" #include namespace qbs { namespace Internal { class CleanOptionsPrivate : public QSharedData { public: CleanOptionsPrivate() : dryRun(false), keepGoing(false), logElapsedTime(false) { } bool dryRun; bool keepGoing; bool logElapsedTime; }; } // namespace Internal /*! * \class CleanOptions * \brief The \c CleanOptions class comprises parameters that influence the behavior of * cleaning operations. */ /*! * \enum CleanOptions::CleanType * This enum type specifies which kind of build artifacts to remove. * \value CleanupAll Indicates that all files created by the build process should be removed. * \value CleanupTemporaries Indicates that only intermediate build artifacts should be removed. * If, for example, the product to clean up for is a Linux shared library, the .so file * would be left on the disk, but the .o files would be removed. */ CleanOptions::CleanOptions() : d(new Internal::CleanOptionsPrivate) { } CleanOptions::CleanOptions(const CleanOptions &other) = default; CleanOptions::CleanOptions(CleanOptions &&other) Q_DECL_NOEXCEPT = default; CleanOptions &CleanOptions::operator=(const CleanOptions &other) = default; CleanOptions &CleanOptions::operator=(CleanOptions &&other) Q_DECL_NOEXCEPT = default; CleanOptions::~CleanOptions() = default; /*! * \brief Returns true iff qbs will not actually remove any files, but just show what would happen. * The default is false. */ bool CleanOptions::dryRun() const { return d->dryRun; } /*! * \brief Controls whether clean-up will actually take place. * If the argument is true, then qbs will emit information about which files would be removed * instead of actually doing it. */ void CleanOptions::setDryRun(bool dryRun) { d->dryRun = dryRun; } /*! * Returns true iff clean-up will continue if an error occurs. * The default is false. */ bool CleanOptions::keepGoing() const { return d->keepGoing; } /*! * \brief Controls whether to abort on errors. * If the argument is true, then if a file cannot be removed e.g. due to a permission problem, * a warning will be printed and the clean-up will continue. If the argument is false, * then the clean-up will abort immediately in case of an error. */ void CleanOptions::setKeepGoing(bool keepGoing) { d->keepGoing = keepGoing; } /*! * \brief Returns true iff the time the operation takes will be logged. * The default is false. */ bool CleanOptions::logElapsedTime() const { return d->logElapsedTime; } /*! * \brief Controls whether the clean-up time will be measured and logged. */ void CleanOptions::setLogElapsedTime(bool log) { d->logElapsedTime = log; } qbs::CleanOptions qbs::CleanOptions::fromJson(const QJsonObject &data) { CleanOptions opt; using namespace Internal; setValueFromJson(opt.d->dryRun, data, "dry-run"); setValueFromJson(opt.d->keepGoing, data, "keep-going"); setValueFromJson(opt.d->logElapsedTime, data, "log-time"); return opt; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/persistence.h0000644000175100001660000004247714776170045021277 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PERSISTENCE #define QBS_PERSISTENCE #include "error.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class NoBuildGraphError : public ErrorInfo { public: NoBuildGraphError(const QString &filePath); }; template struct PPHelper; class PersistentPool { public: PersistentPool(Logger &logger); ~PersistentPool(); class HeadData { public: QVariantMap projectConfig; }; template void store(const Types &...args) { (... , PPHelper::store(args, this)); } template void load(Types &...args) { (... , PPHelper::load(args, this)); } template T load() { T tmp; PPHelper::load(tmp, this); return tmp; } enum OpType { Store, Load }; template void serializationOp(const Types &...args) { static_assert(type == Store); store(args...); } template void serializationOp(Types &...args) { if constexpr(type == Store) store(args...); else load(args...); } void load(const QString &filePath); void setupWriteStream(const QString &filePath); void finalizeWriteStream(); void clear(); const HeadData &headData() const { return m_headData; } void setHeadData(const HeadData &hd) { m_headData = hd; } private: using PersistentObjectId = int; template T *idLoad(); template std::shared_ptr idLoadS(); template T idLoadValue(); void doLoadValue(QString &s); void doLoadValue(QStringList &l); void doLoadValue(QProcessEnvironment &env); template void storeSharedObject(const T *object); void storeVariant(const QVariant &variant); QVariant loadVariant(); template void idStoreValue(const T &value); void doStoreValue(const QString &s); void doStoreValue(const QStringList &l); void doStoreValue(const QProcessEnvironment &env); template std::vector &idStorage(); template QHash &idMap(); template PersistentObjectId &lastStoredId(); static const inline PersistentObjectId ValueNotFoundId = -1; static const inline PersistentObjectId EmptyValueId = -2; static const inline PersistentObjectId NullValueId = -3; std::unique_ptr m_file; QDataStream m_stream; HeadData m_headData; std::vector m_loadedRaw; std::vector> m_loaded; std::unordered_map m_storageIndices; PersistentObjectId m_lastStoredObjectId = 0; std::vector m_stringStorage; QHash m_inverseStringStorage; PersistentObjectId m_lastStoredStringId = 0; std::vector m_envStorage; QHash m_inverseEnvStorage; PersistentObjectId m_lastStoredEnvId = 0; std::vector m_stringListStorage; QHash m_inverseStringListStorage; PersistentObjectId m_lastStoredStringListId = 0; Logger &m_logger; template friend struct PPHelper; }; template inline const void *uniqueAddress(const T *t) { return t; } template inline void PersistentPool::storeSharedObject(const T *object) { if (!object) { m_stream << -1; return; } const void * const addr = uniqueAddress(object); const auto found = m_storageIndices.find(addr); if (found == m_storageIndices.end()) { PersistentObjectId id = m_lastStoredObjectId++; m_storageIndices[addr] = id; m_stream << id; store(*object); } else { m_stream << found->second; } } template inline T *PersistentPool::idLoad() { PersistentObjectId id; m_stream >> id; if (id < 0) return nullptr; if (id < static_cast(m_loadedRaw.size())) return static_cast(m_loadedRaw.at(id)); auto i = m_loadedRaw.size(); m_loadedRaw.resize(id + 1); for (; i < m_loadedRaw.size(); ++i) m_loadedRaw[i] = nullptr; const auto t = new T; m_loadedRaw[id] = t; load(*t); return t; } template<> inline std::vector &PersistentPool::idStorage() { return m_stringStorage; } template<> inline QHash &PersistentPool::idMap() { return m_inverseStringStorage; } template<> inline PersistentPool::PersistentObjectId &PersistentPool::lastStoredId() { return m_lastStoredStringId; } template<> inline std::vector &PersistentPool::idStorage() { return m_stringListStorage; } template<> inline QHash &PersistentPool::idMap() { return m_inverseStringListStorage; } template<> inline PersistentPool::PersistentObjectId &PersistentPool::lastStoredId() { return m_lastStoredStringListId; } template<> inline std::vector &PersistentPool::idStorage() { return m_envStorage; } template<> inline QHash &PersistentPool::idMap() { return m_inverseEnvStorage; } template<> inline PersistentPool::PersistentObjectId &PersistentPool::lastStoredId() { return m_lastStoredEnvId; } template inline std::shared_ptr PersistentPool::idLoadS() { PersistentObjectId id; m_stream >> id; if (id < 0) return std::shared_ptr(); if (id < static_cast(m_loaded.size())) return std::static_pointer_cast(m_loaded.at(id)); m_loaded.resize(id + 1); const std::shared_ptr t = T::create(); m_loaded[id] = t; load(*t); return t; } template inline T PersistentPool::idLoadValue() { int id; m_stream >> id; if (id == NullValueId) return T(); if (id == EmptyValueId) { if constexpr (std::is_same_v) return QString(0, QChar()); return T(); } QBS_CHECK(id >= 0); if (id >= static_cast(idStorage().size())) { T value; doLoadValue(value); idStorage().resize(id + 1); idStorage()[id] = value; return value; } return idStorage().at(id); } template void PersistentPool::idStoreValue(const T &value) { if constexpr (std::is_same_v) { if (value.isNull()) { m_stream << NullValueId; return; } } if (value.isEmpty()) { m_stream << EmptyValueId; return; } int id = idMap().value(value, ValueNotFoundId); if (id < 0) { id = lastStoredId()++; idMap().insert(value, id); m_stream << id; doStoreValue(value); } else { m_stream << id; } } // We need a helper class template, because we require partial specialization for some of // the aggregate types, which is not possible with function templates. // The generic implementation assumes that T is of class type and has load() and store() // member functions. template struct PPHelper { static void store(const T &object, PersistentPool *pool) { const_cast(object).store(*pool); } static void load(T &object, PersistentPool *pool) { object.load(*pool); } }; /***** Specializations of Helper class *****/ template struct PPHelper)>>> { static void store(const T &value, PersistentPool *pool) { const_cast(value).template completeSerializationOp(*pool); } static void load(T &value, PersistentPool *pool) { value.template completeSerializationOp(*pool); } }; template struct PPHelper>> { static void store(const T &value, PersistentPool *pool) { pool->m_stream << value; } static void load(T &value, PersistentPool *pool) { pool->m_stream >> value; } }; template<> struct PPHelper { static void store(long value, PersistentPool *pool) { pool->m_stream << qint64(value); } static void load(long &value, PersistentPool *pool) { qint64 v; pool->m_stream >> v; value = long(v); } }; template struct PPHelper>> { using U = std::underlying_type_t; static void store(const T &value, PersistentPool *pool) { pool->m_stream << static_cast(value); } static void load(T &value, PersistentPool *pool) { pool->m_stream >> reinterpret_cast(value); } }; template struct PPHelper> { static void store(const std::shared_ptr &value, PersistentPool *pool) { pool->store(value.get()); } static void load(std::shared_ptr &value, PersistentPool *pool) { value = pool->idLoadS>(); } }; template struct PPHelper> { static void store(const std::unique_ptr &value, PersistentPool *pool) { pool->store(value.get()); } static void load(std::unique_ptr &ptr, PersistentPool *pool) { ptr.reset(pool->idLoad>()); } }; template struct PPHelper { static void store(const T *value, PersistentPool *pool) { pool->storeSharedObject(value); } static void load(T* &value, PersistentPool *pool) { value = pool->idLoad(); } }; template struct PPHelper || std::is_same_v || std::is_same_v>> { static void store(const T &v, PersistentPool *pool) { pool->idStoreValue(v); } static void load(T &v, PersistentPool *pool) { v = pool->idLoadValue(); } }; template<> struct PPHelper { static void store(const QVariant &v, PersistentPool *pool) { pool->storeVariant(v); } static void load(QVariant &v, PersistentPool *pool) { v = pool->loadVariant(); } }; template<> struct PPHelper { static void store(const QRegularExpression &re, PersistentPool *pool) { pool->store(re.pattern()); } static void load(QRegularExpression &re, PersistentPool *pool) { re.setPattern(pool->load()); } }; template struct PPHelper> { static void store(const std::pair &pair, PersistentPool *pool) { pool->store(pair.first); pool->store(pair.second); } static void load(std::pair &pair, PersistentPool *pool) { pool->load(pair.first); pool->load(pair.second); } }; template struct PPHelper> { template static void storeHelper( std::index_sequence, const std::tuple &tuple, PersistentPool *pool) { (pool->store(std::get(tuple)), ...); } static void store(const std::tuple &tuple, PersistentPool *pool) { storeHelper(std::make_index_sequence(), tuple, pool); } template static void loadHelper( std::index_sequence, std::tuple &tuple, PersistentPool *pool) { (pool->load(std::get(tuple)), ...); } static void load(std::tuple &tuple, PersistentPool * pool) { loadHelper(std::make_index_sequence(), tuple, pool); } }; template struct PPHelper> { using Int = typename QFlags::Int; static void store(const QFlags &flags, PersistentPool *pool) { pool->store(flags); } static void load(QFlags &flags, PersistentPool *pool) { flags = QFlags(pool->load()); } }; template struct IsSimpleContainer : std::false_type { }; template struct IsSimpleContainer> : std::true_type { }; template<> struct IsSimpleContainer : std::false_type { }; template struct IsSimpleContainer> : std::true_type { }; template struct PPHelper::value>> { static void store(const T &container, PersistentPool *pool) { pool->store(int(container.size())); for (auto it = container.cbegin(); it != container.cend(); ++it) pool->store(*it); } static void load(T &container, PersistentPool *pool) { const int count = pool->load(); container.clear(); container.reserve(count); for (int i = count; --i >= 0;) container.push_back(pool->load()); } }; template struct IsKeyValueContainer : std::false_type { }; template struct IsKeyValueContainer> : std::true_type { }; template struct IsKeyValueContainer> : std::true_type { }; template struct PPHelper::value>> { static void store(const T &container, PersistentPool *pool) { pool->store(int(container.size())); for (auto it = container.cbegin(); it != container.cend(); ++it) { pool->store(it.key()); pool->store(it.value()); } } static void load(T &container, PersistentPool *pool) { container.clear(); const int count = pool->load(); for (int i = 0; i < count; ++i) { const auto &key = pool->load(); const auto &value = pool->load(); container.insert(key, value); } } }; template struct PPHelper> { static void store(const std::unordered_map &map, PersistentPool *pool) { pool->store(quint32(map.size())); for (auto it = map.cbegin(); it != map.cend(); ++it) pool->store(*it); } static void load(std::unordered_map &map, PersistentPool *pool) { map.clear(); const auto count = pool->load(); for (std::size_t i = 0; i < count; ++i) map.insert(pool->load>()); } }; template struct PPHelper> { static const inline int ValueMarker = -2; static const inline int NoValueMarker = -1; static void store(const std::optional &v, PersistentPool *pool) { if (v) { pool->store(ValueMarker); pool->store(*v); } else { pool->store(NoValueMarker); } } static void load(std::optional &v, PersistentPool *pool) { const int marker = pool->load(); if (marker == ValueMarker) v = pool->load(); } }; } // namespace Internal } // namespace qbs #endif qbs-src-2.6.1/src/lib/corelib/tools/executablefinder.cpp0000644000175100001660000001276614776170045022615 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "executablefinder.h" #include "fileinfo.h" #include "hostosinfo.h" #include "qttools.h" #include "stringconstants.h" #include #include namespace qbs { namespace Internal { static QStringList populateExecutableSuffixes() { QStringList result; result << QString(); if (HostOsInfo::isWindowsHost()) { result << QStringLiteral(".com") << QStringLiteral(".exe") << QStringLiteral(".bat") << QStringLiteral(".cmd"); } return result; } QStringList ExecutableFinder::m_executableSuffixes = populateExecutableSuffixes(); ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env) : m_product(std::move(product)) , m_environment(env) // QProcessEnvironment doesn't have move-ctor, copy here { } QString ExecutableFinder::findExecutable(const QString &path, const QString &workingDirPath) { QString filePath = QDir::fromNativeSeparators(path); //if (FileInfo::fileName(filePath) == filePath) if (!FileInfo::isAbsolute(filePath)) return findInPath(filePath, workingDirPath); if (HostOsInfo::isWindowsHost()) return findBySuffix(filePath); return filePath; } QString ExecutableFinder::findBySuffix(const QString &filePath) const { QString fullProgramPath = cachedFilePath(filePath); if (!fullProgramPath.isEmpty()) return fullProgramPath; fullProgramPath = filePath; qCDebug(lcExec) << "looking for executable by suffix" << fullProgramPath; const QString emptyDirectory; candidateCheck(emptyDirectory, fullProgramPath, fullProgramPath); cacheFilePath(filePath, fullProgramPath); return fullProgramPath; } bool ExecutableFinder::candidateCheck(const QString &directory, const QString &program, QString &fullProgramPath) const { for (const QString &suffix : std::as_const(m_executableSuffixes)) { QString candidate = directory + program + suffix; qCDebug(lcExec) << "candidate:" << candidate; QFileInfo fi(candidate); if (fi.isFile() && fi.isExecutable()) { fullProgramPath = candidate; return true; } } return false; } QString ExecutableFinder::findInPath(const QString &filePath, const QString &workingDirPath) const { QString fullProgramPath = cachedFilePath(filePath); if (!fullProgramPath.isEmpty()) return fullProgramPath; fullProgramPath = filePath; qCDebug(lcExec) << "looking for executable in PATH" << fullProgramPath; QStringList pathEnv = m_environment.value(StringConstants::pathEnvVar()) .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); if (HostOsInfo::isWindowsHost()) pathEnv.prepend(StringConstants::dot()); for (QString directory : std::as_const(pathEnv)) { if (directory == StringConstants::dot()) directory = workingDirPath; if (!directory.isEmpty()) { const QChar lastChar = directory.at(directory.size() - 1); if (lastChar != QLatin1Char('/') && lastChar != QLatin1Char('\\')) directory.append(QLatin1Char('/')); } if (candidateCheck(directory, fullProgramPath, fullProgramPath)) break; } cacheFilePath(filePath, fullProgramPath); return fullProgramPath; } QString ExecutableFinder::cachedFilePath(const QString &filePath) const { return m_product ? m_product->cachedExecutablePath(filePath) : QString(); } void ExecutableFinder::cacheFilePath(const QString &filePath, const QString &fullFilePath) const { if (m_product) m_product->cacheExecutablePath(filePath, fullFilePath); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/pathutils.h0000644000175100001660000000461714776170045020762 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PATHUTILS_H #define QBS_PATHUTILS_H #include "hostosinfo.h" #include "qbs_export.h" namespace qbs { namespace Internal { class PathUtils { public: static QString toNativeSeparators(const QString &s, HostOsInfo::HostOs os = HostOsInfo::hostOs()) { QString value = s; if (os == HostOsInfo::HostOsWindows) value.replace(QLatin1Char('/'), HostOsInfo::pathSeparator(os)); return value; } }; } // namespace Internal } // namespace qbs #endif // QBS_PATHUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/qttools.h0000644000175100001660000001455214776170045020451 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBSQTTOOLS_H #define QBSQTTOOLS_H #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QProcessEnvironment; QT_END_NAMESPACE namespace std { template struct hash> { size_t operator()(const pair &x) const { return std::hash()(x.first) ^ std::hash()(x.second); } }; template struct hash> { private: template static size_t helper(std::index_sequence, const std::tuple &tuple) noexcept { size_t seed = 0; (qbs::Internal::hashCombineHelper(seed, std::get(tuple)), ...); return seed; } public: size_t operator()(const std::tuple & tuple) const noexcept { return helper(std::make_index_sequence(), tuple); } }; template<> struct hash { std::size_t operator()(const QStringList &s) const noexcept { return qbs::Internal::hashRange(s); } }; template<> struct hash { size_t operator()(const QVariant &v) const noexcept; }; template<> struct hash { size_t operator()(const QVariantList &v) const noexcept { return qbs::Internal::hashRange(v); } }; template<> struct hash { size_t operator()(const QVariantMap &v) const noexcept { return qbs::Internal::hashRange(v); } }; template<> struct hash { size_t operator()(const QVariantHash &v) const noexcept { return qbs::Internal::hashRange(v); } }; } // namespace std QT_BEGIN_NAMESPACE qbs::QHashValueType qHash(const QStringList &list); qbs::QHashValueType qHash(const QProcessEnvironment &env); template qbs::QHashValueType qHash(const std::tuple &tuple) { return std::hash>()(tuple) % std::numeric_limits::max(); } inline qbs::QHashValueType qHash(const QVariant &v) { return std::hash()(v) % std::numeric_limits::max(); } inline qbs::QHashValueType qHash(const QVariantMap &v) { return std::hash()(v) % std::numeric_limits::max(); } inline qbs::QHashValueType qHash(const QVariantHash &v) { return std::hash()(v) % std::numeric_limits::max(); } QT_END_NAMESPACE namespace qbs { template QSet toSet(const QList &list) { return QSet(list.begin(), list.end()); } template QList toList(const QSet &set) { return QList(set.begin(), set.end()); } template QHash &unite(QHash &h, const QHash &other) { h.insert(other); return h; } inline void setupDefaultCodec(QTextStream &stream) { #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) stream.setCodec("UTF-8"); #else Q_UNUSED(stream); #endif } inline bool qVariantCanConvert(const QVariant &variant, int typeId) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) return variant.canConvert(QMetaType(typeId)); #else return variant.canConvert(typeId); // deprecated in Qt6 #endif } inline bool qVariantConvert(QVariant &variant, int typeId) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) return variant.convert(QMetaType(typeId)); #else return variant.convert(typeId); // deprecated in Qt6 #endif } inline QMetaType::Type qVariantType(const QVariant &v) { return static_cast( #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) v.metaType().id() #else v.type() #endif ); } template inline QVariant typedNullVariant() { const auto metaType = QMetaType::fromType(); #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) return QVariant(metaType, nullptr); #else return QVariant(static_cast(metaType.id())); #endif } inline bool qVariantsEqual(const QVariant &v1, const QVariant &v2) { return v1.isNull() == v2.isNull() && v1 == v2; } inline bool qVariantMapsEqual(const QVariantMap &m1, const QVariantMap &m2) { if (m1.size() != m2.size()) return false; if (m1.isSharedWith(m2)) return true; auto it1 = m1.cbegin(); auto it2 = m2.cbegin(); while (it1 != m1.cend()) { if (it1.key() != it2.key() || !qVariantsEqual(it1.value(), it2.value())) return false; ++it2; ++it1; } return true; } } // namespace qbs #endif // QBSQTTOOLS_H qbs-src-2.6.1/src/lib/corelib/tools/clangclinfo.cpp0000644000175100001660000001473614776170045021562 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "clangclinfo.h" #include "hostosinfo.h" #include "msvcinfo.h" #include "stlutils.h" namespace qbs { namespace Internal { static std::vector compatibleMsvcs(Logger &logger) { auto msvcs = MSVCInstallInfo::installedMSVCs(logger); auto filter = [](const MSVCInstallInfo &info) { const auto versions = info.version.split(QLatin1Char('.')); if (versions.empty()) return true; bool ok = false; const int major = versions.at(0).toInt(&ok); return !ok || major < 15; // support MSVC2017 and above }; Internal::removeIf(msvcs, filter); for (const auto &msvc: msvcs) { auto vcvarsallPath = msvc.findVcvarsallBat(); if (vcvarsallPath.isEmpty()) continue; } return msvcs; } static QString findCompatibleVcsarsallBat(const std::vector &msvcs) { for (const auto &msvc: msvcs) { auto vcvarsallPath = msvc.findVcvarsallBat(); if (!vcvarsallPath.isEmpty()) return vcvarsallPath; } return {}; } static QString wow6432Key() { #ifdef Q_OS_WIN64 return QStringLiteral("\\Wow6432Node"); #else return {}; #endif } static QString getToolchainInstallPath(const QFileInfo &compiler) { return compiler.path(); // 1 level up } QVariantMap ClangClInfo::toVariantMap() const { return { {QStringLiteral("toolchainInstallPath"), toolchainInstallPath}, {QStringLiteral("vcvarsallPath"), vcvarsallPath}, }; } ClangClInfo ClangClInfo::fromCompilerFilePath(const QString &path, Logger &logger) { const auto compilerName = QStringLiteral("clang-cl"); const auto vcvarsallPath = findCompatibleVcsarsallBat(compatibleMsvcs(logger)); if (vcvarsallPath.isEmpty()) { logger.qbsWarning() << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") .arg(compilerName); return {}; } return {getToolchainInstallPath(QFileInfo(path)), vcvarsallPath}; } std::vector ClangClInfo::installedCompilers( const std::vector &extraPaths, Logger &logger) { std::vector compilerPaths; compilerPaths.reserve(extraPaths.size()); std::copy_if(extraPaths.begin(), extraPaths.end(), std::back_inserter(compilerPaths), [](const QString &path){ return !path.isEmpty(); }); const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); const QSettings registry( QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()), QSettings::NativeFormat); const auto key = QStringLiteral("."); if (registry.contains(key)) { const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString()) + QStringLiteral("/bin/") + compilerName; if (QFileInfo::exists(compilerPath) && !contains(compilerPaths, compilerPath)) compilerPaths.push_back(compilerPath); } // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit) // but uninstalled one - in that case, registry will be empty static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"}; for (const auto &envVar : envVarCandidates) { const auto value = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName; if (QFileInfo::exists(compilerPath) && !contains(compilerPaths, compilerPath)) compilerPaths.push_back(compilerPath); } const auto msvcs = compatibleMsvcs(logger); const auto vcvarsallPath = findCompatibleVcsarsallBat(msvcs); if (vcvarsallPath.isEmpty()) { logger.qbsWarning() << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") .arg(compilerName); return {}; } std::vector result; result.reserve(compilerPaths.size() + msvcs.size()); transform(compilerPaths, result, [&vcvarsallPath](const auto &path) { return ClangClInfo{getToolchainInstallPath(QFileInfo(path)), vcvarsallPath}; }); // If we didn't find custom LLVM installation, try to find if it's installed with Visual Studio for (const auto &msvc : msvcs) { const auto compilerPath = QStringLiteral("%1/VC/Tools/Llvm/bin/%2") .arg(msvc.installDir, compilerName); if (QFileInfo::exists(compilerPath)) { const auto vcvarsallPath = msvc.findVcvarsallBat(); if (vcvarsallPath.isEmpty()) { logger.qbsWarning() << Tr::tr("Found LLVM in %1, but vcvarsall.bat is missing.") .arg(msvc.installDir); } result.push_back({getToolchainInstallPath(QFileInfo(compilerPath)), vcvarsallPath}); } } return result; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/visualstudioversioninfo.cpp0000644000175100001660000001347714776170045024321 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "visualstudioversioninfo.h" #include #include #include namespace qbs { namespace Internal { VisualStudioVersionInfo::VisualStudioVersionInfo() = default; VisualStudioVersionInfo::VisualStudioVersionInfo(const Version &version) : m_version(version) { QBS_CHECK(version.minorVersion() == 0 || version == Version(7, 1) || version.majorVersion() >= 15); } std::set VisualStudioVersionInfo::knownVersions() { static const std::set known = { Version(17), Version(16), Version(15), Version(14), Version(12), Version(11), Version(10), Version(9), Version(8), Version(7, 1), Version(7), Version(6) }; return known; } bool VisualStudioVersionInfo::operator<(const VisualStudioVersionInfo &other) const { return m_version < other.m_version; } bool VisualStudioVersionInfo::operator==(const VisualStudioVersionInfo &other) const { return m_version == other.m_version; } bool VisualStudioVersionInfo::usesMsBuild() const { return m_version.majorVersion() >= 10; } bool VisualStudioVersionInfo::usesVcBuild() const { return m_version.majorVersion() <= 9; } bool VisualStudioVersionInfo::usesSolutions() const { return m_version.majorVersion() >= 7; } Version VisualStudioVersionInfo::version() const { return m_version; } int VisualStudioVersionInfo::marketingVersion() const { switch (m_version.majorVersion()) { case 6: return 6; case 7: switch (m_version.minorVersion()) { case 0: return 2002; case 1: return 2003; default: Q_UNREACHABLE(); } break; case 8: return 2005; case 9: return 2008; case 10: return 2010; case 11: return 2012; case 12: return 2013; case 14: return 2015; case 15: return 2017; case 16: return 2019; case 17: return 2022; default: qWarning() << QStringLiteral("unrecognized Visual Studio version: ") << m_version.toString(); return 0; } } QString VisualStudioVersionInfo::solutionVersion() const { // Visual Studio 2012 finally stabilized the solution version if (m_version >= Version(11)) return QStringLiteral("12.00"); if (m_version >= Version(8)) return QStringLiteral("%1.00").arg(m_version.majorVersion() + 1); if (m_version >= Version(7, 1)) return QStringLiteral("8.00"); if (m_version >= Version(7)) return QStringLiteral("7.00"); // these versions do not use solution files // Visual Studio 6 uses .dsw files which are format version 6.00 but these are different Q_ASSERT(!usesSolutions()); Q_UNREACHABLE(); } QString VisualStudioVersionInfo::toolsVersion() const { // "https://msdn.microsoft.com/en-us/library/bb383796.aspx" // Starting in Visual Studio 2013, the MSBuild Toolset version is the same as the Visual Studio // version number"... again if (m_version >= Version(12)) return QStringLiteral("%1.0").arg(m_version.majorVersion()); if (m_version >= Version(10)) return QStringLiteral("4.0"); // pre-MSBuild return QStringLiteral("%1,00").arg(m_version.majorVersion()); } QString VisualStudioVersionInfo::platformToolsetVersion() const { static std::pair table[] = { {17, QStringLiteral("v143")}, // VS 2022 {16, QStringLiteral("v142")}, // VS 2019 {15, QStringLiteral("v141")} // VS 2017 }; for (const auto &p : table) { if (p.first == m_version.majorVersion()) return p.second; } return QStringLiteral("v%1").arg(m_version.majorVersion() * 10); } QHashValueType qHash(const VisualStudioVersionInfo &info) { return qHash(info.version().toString()); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/codelocation.h0000644000175100001660000001346014776170045021404 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SOURCELOCATION_H #define QBS_SOURCELOCATION_H #include "qbs_export.h" #include #include QT_BEGIN_NAMESPACE class QDataStream; class QJsonObject; class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { class PersistentPool; } class QBS_EXPORT CodeLocation { friend QBS_EXPORT bool operator==(const CodeLocation &cl1, const CodeLocation &cl2); public: CodeLocation() = default; explicit CodeLocation( const QString &aFilePath, int aLine = -1, int aColumn = -1, bool checkPath = true); const QString &filePath() const noexcept { return m_filePath; } int line() const noexcept { return m_line; } int column() const noexcept { return m_column; } bool isValid() const noexcept { return !m_filePath.isEmpty(); } QString toString() const; QJsonObject toJson() const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; private: QString m_filePath; int m_line = 0; int m_column = 0; }; QBS_EXPORT bool operator==(const CodeLocation &cl1, const CodeLocation &cl2); QBS_EXPORT bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2); QBS_EXPORT bool operator<(const CodeLocation &cl1, const CodeLocation &cl2); inline auto qHash(const CodeLocation &cl) { return qHash(cl.toString()); } QDebug operator<<(QDebug debug, const CodeLocation &location); class QBS_EXPORT CodePosition { public: CodePosition(int line, int column) : m_line(line), m_column(column) {} CodePosition() = default; CodePosition(const CodePosition &other) = default; CodePosition(CodePosition &&other) = default; CodePosition &operator=(const CodePosition &other) = default; CodePosition &operator=(CodePosition &&other) = default; int line() const { return m_line; } void setLine(int newLine) { m_line = newLine; } int column() const { return m_column; } void setColumn(int newColumn) { m_column = newColumn; } void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; private: int m_line = 0; int m_column = 0; }; QBS_EXPORT bool operator==(const CodePosition &pos1, const CodePosition &pos2); QBS_EXPORT bool operator!=(const CodePosition &pos1, const CodePosition &pos2); QBS_EXPORT bool operator<(const CodePosition &pos1, const CodePosition &pos2); QBS_EXPORT bool operator>(const CodePosition &pos1, const CodePosition &pos2); QBS_EXPORT bool operator<=(const CodePosition &pos1, const CodePosition &pos2); QBS_EXPORT bool operator>=(const CodePosition &pos1, const CodePosition &pos2); inline auto qHash(const CodePosition &pos) { return QT_PREPEND_NAMESPACE(qHash)(pos.line()) ^ QT_PREPEND_NAMESPACE(qHash)(pos.column()); } class QBS_EXPORT CodeRange { public: CodeRange(const CodePosition &start, const CodePosition &end); CodeRange() = default; CodeRange(const CodeRange &other) = default; CodeRange(CodeRange &&other) = default; CodeRange &operator=(const CodeRange &other) = default; CodeRange &operator=(CodeRange &&other) = default; const CodePosition &start() const & { return m_start; } const CodePosition &end() const & { return m_end; } CodePosition start() && { return std::move(m_start); } CodePosition end() && { return std::move(m_end); } bool contains(const CodePosition &pos) const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; private: CodePosition m_start; CodePosition m_end; }; QBS_EXPORT bool operator==(const CodeRange &r1, const CodeRange &r2); QBS_EXPORT bool operator!=(const CodeRange &r1, const CodeRange &r2); QBS_EXPORT bool operator<(const CodeRange &r1, const CodeRange &r2); inline auto qHash(const CodeRange &range) { return qHash(range.start()) ^ qHash(range.end()); } using CodeLinksInFile = QHash>; using CodeLinks = QHash; } // namespace qbs #endif // QBS_SOURCELOCATION_H qbs-src-2.6.1/src/lib/corelib/tools/jsliterals.h0000644000175100001660000000443014776170045021112 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JSLITERALS_H #define QBS_JSLITERALS_H #include "qbs_export.h" #include #include #include namespace qbs { QBS_EXPORT QString toJSLiteral(const bool b); QBS_EXPORT QString toJSLiteral(const QString &str); QBS_EXPORT QString toJSLiteral(const QStringList &strs); QBS_EXPORT QString toJSLiteral(const QVariant &val); } // namespace qbs #endif // QBS_JSLITERALS_H qbs-src-2.6.1/src/lib/corelib/tools/processresult_p.h0000644000175100001660000000464714776170045022204 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROCESSRESULT_P_H #define QBS_PROCESSRESULT_P_H #include #include #include namespace qbs { namespace Internal { class ProcessResultPrivate : public QSharedData { public: bool success = false; QString executableFilePath; QStringList arguments; QString workingDirectory; QProcess::ProcessError error = QProcess::ProcessError::UnknownError; int exitCode = 0; QStringList stdOut; QStringList stdErr; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/tools/progressobserver.cpp0000644000175100001660000001012514776170045022703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "progressobserver.h" namespace qbs { namespace Internal { /*! * \class ProgressObserver * The \c ProgressObserver class is used in long running qbs operations. It serves two purposes: * Firstly, it allows operations to indicate progress to a client. Secondly, a client can * signal to an operation that is should exit prematurely. * Clients of the qbs library are supposed to subclass this class and implement the virtual * functions in a way that lets users know about the current operation and its progress. */ /*! * \fn virtual void initialize(const QString &task, int maximum) = 0 * \brief Indicates that a new operation is starting. * Library code calls this function to indicate that it is starting a new task. * The \a task parameter is a textual description of that task suitable for presentation to a user. * The \a maximum parameter is an estimate of the maximum effort the operation is going to take. * This is helpful if the client wants to set up some sort of progress bar showing the * percentage of the work already done. */ /*! * \fn virtual void setProgressValue(int value) = 0 * \brief Sets the new progress value. * Library code calls this function to indicate that the current operation has progressed. * It will try hard to ensure that \a value will not exceed \c maximum(). * \sa ProgressObserver::maximum(). */ /*! * \fn virtual int progressValue() = 0 * \brief The current progress value. * Will typically reflect the \a value from the last call to \c setProgressValue() and should not * exceed \c maximum(). * \sa setProgressvalue() * \sa maximum() */ void ProgressObserver::incrementProgressValue(int increment) { setProgressValue(progressValue() + increment); } /*! * \fn virtual bool canceled() const = 0 * \brief Indicates whether the current operation should be canceled. * Library code will periodically call this function and abort the current operation * if it returns true. */ /*! * \fn virtual int maximum() const = 0 * \brief The expected maximum progress value. * This will typically be the value of \c maximum passed to \c initialize(). * \sa ProgressObserver::initialize() */ void ProgressObserver::setFinished() { setProgressValue(maximum()); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/filesaver.h0000644000175100001660000000507414776170045020723 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FILESAVER_H #define FILESAVER_H #include "qbs_export.h" #include #include #include #include namespace qbs { namespace Internal { /*! * QSaveFile wrapper which doesn't update the target file if the contents are unchanged. */ class QBS_EXPORT FileSaver { public: FileSaver(std::string filePath, bool overwriteIfUnchanged = false); std::ostream *device(); bool open(); bool commit(); bool write(std::string_view data); private: std::string m_oldFileContents; std::shared_ptr m_memoryDevice; const std::string m_filePath; const bool m_overwriteIfUnchanged; }; } // namespace Internal } // namespace qbs #endif // FILESAVER_H qbs-src-2.6.1/src/lib/corelib/tools/launcherpackets.cpp0000644000175100001660000001247514776170045022455 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "launcherpackets.h" #include #include namespace qbs { namespace Internal { LauncherPacket::~LauncherPacket() = default; QByteArray LauncherPacket::serialize() const { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << static_cast(0) << static_cast(type) << token; doSerialize(stream); stream.device()->reset(); stream << static_cast(data.size() - sizeof(int)); return data; } void LauncherPacket::deserialize(const QByteArray &data) { QDataStream stream(data); doDeserialize(stream); } StartProcessPacket::StartProcessPacket(quintptr token) : LauncherPacket(LauncherPacketType::StartProcess, token) { } void StartProcessPacket::doSerialize(QDataStream &stream) const { stream << command << arguments << workingDir << env; } void StartProcessPacket::doDeserialize(QDataStream &stream) { stream >> command >> arguments >> workingDir >> env; } StopProcessPacket::StopProcessPacket(quintptr token) : LauncherPacket(LauncherPacketType::StopProcess, token) { } void StopProcessPacket::doSerialize(QDataStream &stream) const { Q_UNUSED(stream); } void StopProcessPacket::doDeserialize(QDataStream &stream) { Q_UNUSED(stream); } ProcessErrorPacket::ProcessErrorPacket(quintptr token) : LauncherPacket(LauncherPacketType::ProcessError, token) { } void ProcessErrorPacket::doSerialize(QDataStream &stream) const { stream << static_cast(error) << errorString; } void ProcessErrorPacket::doDeserialize(QDataStream &stream) { quint8 e; stream >> e; error = static_cast(e); stream >> errorString; } ProcessFinishedPacket::ProcessFinishedPacket(quintptr token) : LauncherPacket(LauncherPacketType::ProcessFinished, token) { } void ProcessFinishedPacket::doSerialize(QDataStream &stream) const { stream << errorString << stdOut << stdErr << static_cast(exitStatus) << static_cast(error) << exitCode; } void ProcessFinishedPacket::doDeserialize(QDataStream &stream) { stream >> errorString >> stdOut >> stdErr; quint8 val; stream >> val; exitStatus = static_cast(val); stream >> val; error = static_cast(val); stream >> exitCode; } ShutdownPacket::ShutdownPacket() : LauncherPacket(LauncherPacketType::Shutdown, 0) { } void ShutdownPacket::doSerialize(QDataStream &stream) const { Q_UNUSED(stream); } void ShutdownPacket::doDeserialize(QDataStream &stream) { Q_UNUSED(stream); } void PacketParser::setDevice(QIODevice *device) { m_stream.setDevice(device); m_sizeOfNextPacket = -1; } bool PacketParser::parse() { static const int commonPayloadSize = static_cast(1 + sizeof(quintptr)); if (m_sizeOfNextPacket == -1) { if (m_stream.device()->bytesAvailable() < static_cast(sizeof m_sizeOfNextPacket)) return false; m_stream >> m_sizeOfNextPacket; if (m_sizeOfNextPacket < commonPayloadSize) throw InvalidPacketSizeException(m_sizeOfNextPacket); } if (m_stream.device()->bytesAvailable() < m_sizeOfNextPacket) return false; quint8 type; m_stream >> type; m_type = static_cast(type); m_stream >> m_token; m_packetData = m_stream.device()->read(m_sizeOfNextPacket - commonPayloadSize); m_sizeOfNextPacket = -1; return true; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/vsenvironmentdetector.cpp0000644000175100001660000002414314776170045023743 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "vsenvironmentdetector.h" #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #endif namespace qbs { namespace Internal { static QString windowsSystem32Path() { #ifdef Q_OS_WIN wchar_t str[UNICODE_STRING_MAX_CHARS]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_SYSTEM, NULL, 0, str))) return QString::fromUtf16(reinterpret_cast(str)); #endif return {}; } VsEnvironmentDetector::VsEnvironmentDetector(QString vcvarsallPath) : m_windowsSystemDirPath(windowsSystem32Path()) , m_vcvarsallPath(std::move(vcvarsallPath)) { } bool VsEnvironmentDetector::start(MSVC *msvc) { return start(std::vector{ msvc }); } bool VsEnvironmentDetector::start(std::vector msvcs) { std::sort(msvcs.begin(), msvcs.end(), [] (const MSVC *a, const MSVC *b) -> bool { return a->vcInstallPath < b->vcInstallPath; }); std::vector compatibleMSVCs; QString lastVcInstallPath; bool someMSVCDetected = false; for (MSVC * const msvc : msvcs) { if (lastVcInstallPath != msvc->vcInstallPath) { lastVcInstallPath = msvc->vcInstallPath; if (!compatibleMSVCs.empty()) { if (startDetection(compatibleMSVCs)) someMSVCDetected = true; compatibleMSVCs.clear(); } } compatibleMSVCs.push_back(msvc); } if (startDetection(compatibleMSVCs)) someMSVCDetected = true; return someMSVCDetected; } QString VsEnvironmentDetector::findVcVarsAllBat(const MSVC &msvc, std::vector &searchedPaths) const { // ### We can only rely on MSVC.vcInstallPath being set // when this is called from utilitiesextension.cpp :-( // If we knew the vsInstallPath at this point we could just use that // instead of searching for vcvarsall.bat candidates. QDir dir(msvc.vcInstallPath); for (;;) { if (!dir.cdUp()) return {}; if (dir.dirName() == QLatin1String("VC")) break; } const QString vcvarsallbat = QStringLiteral("vcvarsall.bat"); QString path = vcvarsallbat; QString fullPath = dir.absoluteFilePath(path); if (dir.exists(path)) return fullPath; searchedPaths.push_back(fullPath); path = QStringLiteral("Auxiliary/Build/") + vcvarsallbat; fullPath = dir.absoluteFilePath(path); if (dir.exists(path)) return fullPath; searchedPaths.push_back(fullPath); return {}; } bool VsEnvironmentDetector::startDetection(const std::vector &compatibleMSVCs) { std::vector searchedPaths; if (!m_vcvarsallPath.isEmpty() && !QFileInfo::exists(m_vcvarsallPath)) { m_errorString = Tr::tr("%1 does not exist.").arg(m_vcvarsallPath); return false; } const auto vcvarsallbat = !m_vcvarsallPath.isEmpty() ? m_vcvarsallPath : findVcVarsAllBat(**compatibleMSVCs.begin(), searchedPaths); if (vcvarsallbat.isEmpty()) { if (!searchedPaths.empty()) { m_errorString = Tr::tr( "Cannot find 'vcvarsall.bat' at any of the following locations:\n\t") + join(searchedPaths, QStringLiteral("\n\t")); } else { m_errorString = Tr::tr("Cannot find 'vcvarsall.bat'."); } return false; } QTemporaryFile tmpFile(QDir::tempPath() + QLatin1Char('/') + QStringLiteral("XXXXXX.bat")); if (!tmpFile.open()) { m_errorString = Tr::tr("Cannot open temporary file '%1' for writing.").arg( tmpFile.fileName()); return false; } writeBatchFile(&tmpFile, vcvarsallbat, compatibleMSVCs); tmpFile.flush(); QProcess process; static const QString shellFilePath = QStringLiteral("cmd.exe"); process.start(shellFilePath, QStringList() << QStringLiteral("/C") << tmpFile.fileName()); if (!process.waitForStarted()) { m_errorString = Tr::tr("Failed to start '%1'.").arg(shellFilePath); return false; } process.waitForFinished(-1); if (process.exitStatus() != QProcess::NormalExit) { m_errorString = Tr::tr("Process '%1' did not exit normally.").arg(shellFilePath); return false; } if (process.exitCode() != 0) { m_errorString = Tr::tr("Failed to detect Visual Studio environment."); return false; } parseBatOutput(process.readAllStandardOutput(), compatibleMSVCs); return true; } static void batClearVars(QTextStream &s, const QStringList &varnames) { for (const QString &varname : varnames) s << "set " << varname << '=' << Qt::endl; } static void batPrintVars(QTextStream &s, const QStringList &varnames) { for (const QString &varname : varnames) s << "echo " << varname << "=%" << varname << '%' << Qt::endl; } static QString vcArchitecture(const MSVC *msvc) { QString vcArch = msvc->architecture; if (msvc->architecture == StringConstants::armv7Arch()) vcArch = StringConstants::armArch(); if (msvc->architecture == StringConstants::x86_64Arch()) vcArch = StringConstants::amd64Arch(); const QString hostPrefixes[] = { StringConstants::x86Arch(), QStringLiteral("amd64_"), QStringLiteral("x86_") }; for (const QString &hostPrefix : hostPrefixes) { if (QFile::exists(msvc->clPathForArchitecture(hostPrefix + vcArch))) { vcArch.prepend(hostPrefix); break; } } return vcArch; } void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcvarsallbat, const std::vector &msvcs) const { const QStringList varnames = QStringList() << StringConstants::pathEnvVar() << QStringLiteral("INCLUDE") << QStringLiteral("LIB") << QStringLiteral("WindowsSdkDir") << QStringLiteral("WindowsSDKVersion") << QStringLiteral("VSINSTALLDIR"); QTextStream s(device); using Qt::endl; s << "@echo off" << endl; // Avoid execution of powershell (in vsdevcmd.bat), which is not in the cleared PATH s << "set VSCMD_SKIP_SENDTELEMETRY=1" << endl; for (const MSVC *msvc : msvcs) { s << "echo --" << msvc->architecture << "--" << endl << "setlocal" << endl; batClearVars(s, varnames); s << "set PATH=" << m_windowsSystemDirPath << endl; // vcvarsall.bat needs tools from here s << "call \"" << vcvarsallbat << "\" " << vcArchitecture(msvc); if (!msvc->sdkVersion.isEmpty()) s << " " << msvc->sdkVersion; const auto vcVarsVer = MSVC::vcVariablesVersionFromBinPath(msvc->binPath); if (!vcVarsVer.isEmpty()) s << " -vcvars_ver=" << vcVarsVer; s << " || exit /b 1" << endl; batPrintVars(s, varnames); s << "endlocal" << endl; } } void VsEnvironmentDetector::parseBatOutput(const QByteArray &output, std::vector msvcs) { QString arch; QProcessEnvironment *targetEnv = nullptr; const auto lines = output.split('\n'); for (QByteArray line : lines) { line = line.trimmed(); if (line.isEmpty()) continue; if (line.startsWith("--") && line.endsWith("--")) { line.remove(0, 2); line.chop(2); arch = QString::fromLocal8Bit(line); targetEnv = &msvcs.front()->environment; msvcs.erase(msvcs.begin()); } else { int idx = line.indexOf('='); if (idx < 0) continue; QBS_CHECK(targetEnv); const QString name = QString::fromLocal8Bit(line.left(idx)); QString value = QString::fromLocal8Bit(line.mid(idx + 1)); if (name.compare(StringConstants::pathEnvVar(), Qt::CaseInsensitive) == 0) value.remove(m_windowsSystemDirPath); if (value.endsWith(QLatin1Char(';'))) value.chop(1); targetEnv->insert(name, value); } } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/deprecationwarningmode.cpp0000644000175100001660000000753714776170045024034 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "deprecationwarningmode.h" /*! * \enum DeprecationWarningMode * This enum type specifies how \QBS should behave on encountering deprecated items or properties. * \value DeprecationWarningMode::Error Project resolving will stop with an error message. * \value DeprecationWarningMode::On A warning will be printed. * \value DeprecationWarningMode::BeforeRemoval A warning will be printed if and only if this is * the last \QBS version before the removal version. This is the default behavior. * \note If the removal version's minor version number is zero, the behavior is * the same as for ErrorHandlingMode::On. * \value DeprecationWarningMode::Off No warnings will be emitted for deprecated constructs. */ namespace qbs { DeprecationWarningMode defaultDeprecationWarningMode() { return DeprecationWarningMode::BeforeRemoval; } QString deprecationWarningModeName(DeprecationWarningMode mode) { switch (mode) { case DeprecationWarningMode::Error: return QStringLiteral("error"); case DeprecationWarningMode::On: return QStringLiteral("on"); case DeprecationWarningMode::BeforeRemoval: return QStringLiteral("before-removal"); case DeprecationWarningMode::Off: return QStringLiteral("off"); default: break; } return {}; } DeprecationWarningMode deprecationWarningModeFromName(const QString &name) { DeprecationWarningMode mode = defaultDeprecationWarningMode(); for (int i = 0; i <= int(DeprecationWarningMode::Sentinel); ++i) { if (deprecationWarningModeName(static_cast(i)) == name) { mode = static_cast(i); break; } } return mode; } QStringList allDeprecationWarningModeStrings() { QStringList result; for (int i = 0; i <= int(DeprecationWarningMode::Sentinel); ++i) result << deprecationWarningModeName(static_cast(i)); return result; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/launchersocket.h0000644000175100001660000000600514776170045021750 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LAUNCHERSOCKET_H #define QBS_LAUNCHERSOCKET_H #include "launcherpackets.h" #include #include #include QT_BEGIN_NAMESPACE class QLocalSocket; QT_END_NAMESPACE namespace qbs { namespace Internal { class LauncherInterface; class LauncherSocket : public QObject { Q_OBJECT friend class LauncherInterface; public: bool isReady() const { return m_socket.load(); } void sendData(const QByteArray &data); signals: void ready(); void errorOccurred(const QString &error); void packetArrived(qbs::Internal::LauncherPacketType type, quintptr token, const QByteArray &payload); private: LauncherSocket(QObject *parent); void setSocket(QLocalSocket *socket); void shutdown(); void handleSocketError(); void handleSocketDataAvailable(); void handleSocketDisconnected(); void handleError(const QString &error); void handleRequests(); std::atomic m_socket{nullptr}; PacketParser m_packetParser; std::vector m_requests; std::mutex m_requestsMutex; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/launchersocket.cpp0000644000175100001660000001157214776170045022310 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "launchersocket.h" #include "qbsassert.h" #include "qttools.h" #include #include #include namespace qbs { namespace Internal { LauncherSocket::LauncherSocket(QObject *parent) : QObject(parent) { qRegisterMetaType(); qRegisterMetaType("quintptr"); } void LauncherSocket::sendData(const QByteArray &data) { if (!isReady()) return; std::lock_guard locker(m_requestsMutex); m_requests.push_back(data); if (m_requests.size() == 1) QTimer::singleShot(0, this, &LauncherSocket::handleRequests); } void LauncherSocket::shutdown() { const auto socket = m_socket.exchange(nullptr); if (!socket) return; socket->disconnect(); socket->write(ShutdownPacket().serialize()); socket->waitForBytesWritten(1000); socket->deleteLater(); } void LauncherSocket::setSocket(QLocalSocket *socket) { QBS_ASSERT(!m_socket, return); m_socket.store(socket); m_packetParser.setDevice(m_socket); connect(m_socket, &QLocalSocket::errorOccurred, this, &LauncherSocket::handleSocketError); connect(m_socket, &QLocalSocket::readyRead, this, &LauncherSocket::handleSocketDataAvailable); connect(m_socket, &QLocalSocket::disconnected, this, &LauncherSocket::handleSocketDisconnected); emit ready(); } void LauncherSocket::handleSocketError() { auto socket = m_socket.load(); if (socket->error() != QLocalSocket::PeerClosedError) handleError(Tr::tr("Socket error: %1").arg(socket->errorString())); } void LauncherSocket::handleSocketDataAvailable() { try { if (!m_packetParser.parse()) return; } catch (const PacketParser::InvalidPacketSizeException &e) { handleError(Tr::tr("Internal protocol error: invalid packet size %1.").arg(e.size)); return; } switch (m_packetParser.type()) { case LauncherPacketType::ProcessError: case LauncherPacketType::ProcessFinished: emit packetArrived(m_packetParser.type(), m_packetParser.token(), m_packetParser.packetData()); break; default: handleError(Tr::tr("Internal protocol error: invalid packet type %1.") .arg(static_cast(m_packetParser.type()))); return; } handleSocketDataAvailable(); } void LauncherSocket::handleSocketDisconnected() { handleError(Tr::tr("Launcher socket closed unexpectedly")); } void LauncherSocket::handleError(const QString &error) { const auto socket = m_socket.exchange(nullptr); socket->disconnect(); socket->deleteLater(); emit errorOccurred(error); } void LauncherSocket::handleRequests() { const auto socket = m_socket.load(); QBS_ASSERT(socket, return); std::lock_guard locker(m_requestsMutex); for (const QByteArray &request : std::as_const(m_requests)) socket->write(request); m_requests.clear(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/msvcinfo.cpp0000644000175100001660000006601014776170045021117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "msvcinfo.h" #include "visualstudioversioninfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #endif #include #include #include using namespace qbs; using namespace qbs::Internal; static std::recursive_mutex envMutex; static QString mkStr(const char *s) { return QString::fromLocal8Bit(s); } static QString mkStr(const QByteArray &ba) { return mkStr(ba.constData()); } class TemporaryEnvChanger { public: TemporaryEnvChanger(const QProcessEnvironment &envChanges) : m_locker(envMutex) { QProcessEnvironment currentEnv = QProcessEnvironment::systemEnvironment(); const auto keys = envChanges.keys(); for (const QString &key : keys) { m_changesToRestore.insert(key, currentEnv.value(key)); qputenv(qPrintable(key), qPrintable(envChanges.value(key))); } } ~TemporaryEnvChanger() { const auto keys = m_changesToRestore.keys(); for (const QString &key : keys) qputenv(qPrintable(key), qPrintable(m_changesToRestore.value(key))); } private: QProcessEnvironment m_changesToRestore; std::lock_guard m_locker; }; static QByteArray runProcess(const QString &exeFilePath, const QStringList &args, const QProcessEnvironment &env = QProcessEnvironment(), bool allowFailure = false, const QByteArray &pipeData = QByteArray()) { TemporaryEnvChanger envChanger(env); QProcess process; process.start(exeFilePath, args); if (!process.waitForStarted()) throw ErrorInfo(mkStr("Could not start %1 (%2)").arg(exeFilePath, process.errorString())); if (!pipeData.isEmpty()) { process.write(pipeData); process.closeWriteChannel(); } if (!process.waitForFinished(-1) || process.exitStatus() != QProcess::NormalExit) throw ErrorInfo(mkStr("Could not run %1 (%2)").arg(exeFilePath, process.errorString())); if (process.exitCode() != 0 && !allowFailure) { ErrorInfo e(mkStr("Process '%1' failed with exit code %2.") .arg(exeFilePath).arg(process.exitCode())); const QByteArray stdErr = process.readAllStandardError(); if (!stdErr.isEmpty()) e.append(mkStr("stderr was: %1").arg(mkStr(stdErr))); const QByteArray stdOut = process.readAllStandardOutput(); if (!stdOut.isEmpty()) e.append(mkStr("stdout was: %1").arg(mkStr(stdOut))); throw e; } return process.readAllStandardOutput().trimmed(); } class DummyFile { public: DummyFile(QString fp) : filePath(std::move(fp)) { } ~DummyFile() { QFile::remove(filePath); } const QString filePath; }; #ifdef Q_OS_WIN static QStringList parseCommandLine(const QString &commandLine) { const auto buf = std::make_unique(size_t(commandLine.size()) + 1); buf[size_t(commandLine.toWCharArray(buf.get()))] = 0; int argCount = 0; const auto argsDeleter = [](LPWSTR *p){ LocalFree(p); }; const auto args = std::unique_ptr( CommandLineToArgvW(buf.get(), &argCount), argsDeleter); if (!args) throw ErrorInfo(mkStr("Could not parse command line arguments: ") + commandLine); QStringList list; list.reserve(argCount); for (int i = 0; i < argCount; ++i) list.push_back(QString::fromWCharArray(args[size_t(i)])); return list; } #endif static QVariantMap getMsvcDefines(const QString &compilerFilePath, const QProcessEnvironment &compilerEnv, MSVC::CompilerLanguage language) { #ifdef Q_OS_WIN QString backendSwitch, languageSwitch; switch (language) { case MSVC::CLanguage: backendSwitch = QStringLiteral("/B1"); languageSwitch = QStringLiteral("/TC"); break; case MSVC::CPlusPlusLanguage: backendSwitch = QStringLiteral("/Bx"); languageSwitch = QStringLiteral("/TP"); break; } const QByteArray commands("set MSC_CMD_FLAGS\n"); QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList() << QStringLiteral("/nologo") << backendSwitch << qEnvironmentVariable("COMSPEC") << QStringLiteral("/c") << languageSwitch << QStringLiteral("/Zs") << QStringLiteral("NUL"), compilerEnv, true, commands)).split(QLatin1Char('\n')); auto findResult = std::find_if(out.cbegin(), out.cend(), [] (const QString &line) { return line.startsWith(QLatin1String("MSC_CMD_FLAGS=")); }); if (findResult == out.cend()) { throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ") + out.join(QLatin1Char('\n'))); } QVariantMap map; const QStringList args = parseCommandLine(findResult->trimmed()); for (const QString &arg : args) { if (!arg.startsWith(QStringLiteral("-D"))) continue; int idx = arg.indexOf(QLatin1Char('='), 2); if (idx > 2) map.insert(arg.mid(2, idx - 2), arg.mid(idx + 1)); else map.insert(arg.mid(2), QVariant()); } return map; #else Q_UNUSED(compilerFilePath); Q_UNUSED(compilerEnv); Q_UNUSED(language); return {}; #endif } /*! \internal clang-cl does not support gcc and msvc ways to dump a macros, so we have to use original clang.exe directly */ static QVariantMap getClangClDefines( const QString &compilerFilePath, const QProcessEnvironment &compilerEnv, MSVC::CompilerLanguage language, const QString &arch) { #ifdef Q_OS_WIN QFileInfo clInfo(compilerFilePath); QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang-cl.exe")); if (!clangInfo.exists()) throw ErrorInfo(QStringLiteral("%1 does not exist").arg(clangInfo.absoluteFilePath())); QStringList args = { QStringLiteral("/d1PP"), // dump macros QStringLiteral("/E") // preprocess to stdout }; if (language == MSVC::CLanguage) args.append(QStringLiteral("/TC")); else if (language == MSVC::CPlusPlusLanguage) args.append(QStringLiteral("/TP")); if (arch == QLatin1String("x86")) args.append(QStringLiteral("-m32")); else if (arch == QLatin1String("x86_64")) args.append(QStringLiteral("-m64")); args.append(QStringLiteral("NUL")); // filename const auto lines = QString::fromLocal8Bit( runProcess( clangInfo.absoluteFilePath(), args, compilerEnv, true)).split(QLatin1Char('\n')); QVariantMap result; for (const auto &line: lines) { static const auto defineString = QLatin1String("#define "); if (!line.startsWith(defineString)) continue; QStringView view(line.data() + defineString.size()); const auto it = std::find(view.begin(), view.end(), QLatin1Char(' ')); if (it == view.end()) { throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ") + lines.join(QLatin1Char('\n'))); } QStringView key(view.begin(), it); QStringView value(it + 1, view.end()); result.insert(key.toString(), value.isEmpty() ? QVariant() : QVariant(value.toString())); } if (result.isEmpty()) { throw ErrorInfo(QStringLiteral("Cannot determine macroses from compiler frontend output: ") + lines.join(QLatin1Char('\n'))); } return result; #else Q_UNUSED(compilerFilePath); Q_UNUSED(compilerEnv); Q_UNUSED(language); Q_UNUSED(arch); return {}; #endif } static QString formatVswhereOutput(const QString &out, const QString &err) { QString ret; if (!out.isEmpty()) { ret.append(Tr::tr("stdout")).append(QLatin1String(":\n")); const auto lines = out.split(QLatin1Char('\n')); for (const QString &line : lines) ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n')); } if (!err.isEmpty()) { ret.append(Tr::tr("stderr")).append(QLatin1String(":\n")); const auto lines = err.split(QLatin1Char('\n')); for (const QString &line : lines) ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n')); } return ret; } static QString wow6432Key() { #ifdef Q_OS_WIN64 return QStringLiteral("\\Wow6432Node"); #else return {}; #endif } static QString vswhereFilePath() { static const std::vector envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"}; for (const char * const envVar : envVarCandidates) { const QString value = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); QString cmd = value + QStringLiteral("/Microsoft Visual Studio/Installer/vswhere.exe"); if (QFileInfo(cmd).exists()) return cmd; } return {}; } enum class ProductType { VisualStudio, BuildTools }; static std::vector retrieveInstancesFromVSWhere( ProductType productType, Logger &logger) { std::vector result; const QString cmd = vswhereFilePath(); if (cmd.isEmpty()) return result; QProcess vsWhere; QStringList args = productType == ProductType::VisualStudio ? QStringList({QStringLiteral("-all"), QStringLiteral("-legacy"), QStringLiteral("-prerelease")}) : QStringList({QStringLiteral("-products"), QStringLiteral("Microsoft.VisualStudio.Product.BuildTools")}); args << QStringLiteral("-format") << QStringLiteral("json") << QStringLiteral("-utf8"); vsWhere.start(cmd, args); if (!vsWhere.waitForStarted(-1)) return result; if (!vsWhere.waitForFinished(-1)) { logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(": ")) .append(vsWhere.errorString()); return result; } if (vsWhere.exitCode() != 0) { const QString stdOut = QString::fromLocal8Bit(vsWhere.readAllStandardOutput()); const QString stdErr = QString::fromLocal8Bit(vsWhere.readAllStandardError()); logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(".\n")) .append(formatVswhereOutput(stdOut, stdErr)); return result; } QJsonParseError parseError{}; QJsonDocument jsonOutput = QJsonDocument::fromJson(vsWhere.readAllStandardOutput(), &parseError); if (parseError.error != QJsonParseError::NoError) { logger.qbsWarning() << Tr::tr("The vswhere tool produced invalid JSON output: %1") .arg(parseError.errorString()); return result; } const auto jsonArray = jsonOutput.array(); for (const auto &value : jsonArray) { const QJsonObject o = value.toObject(); MSVCInstallInfo info; info.version = o.value(QStringLiteral("installationVersion")).toString(); if (productType == ProductType::BuildTools) { // For build tools, the version is e.g. "15.8.28010.2036", rather than "15.0". const int dotIndex = info.version.indexOf(QLatin1Char('.')); if (dotIndex != -1) info.version = info.version.left(dotIndex); } info.installDir = o.value(QStringLiteral("installationPath")).toString(); if (!info.version.isEmpty() && !info.installDir.isEmpty()) result.push_back(info); } return result; } static std::vector installedMSVCsFromVsWhere(Logger &logger) { const std::vector vsInstallations = retrieveInstancesFromVSWhere(ProductType::VisualStudio, logger); const std::vector buildToolInstallations = retrieveInstancesFromVSWhere(ProductType::BuildTools, logger); std::vector all; std::copy(vsInstallations.begin(), vsInstallations.end(), std::back_inserter(all)); std::copy(buildToolInstallations.begin(), buildToolInstallations.end(), std::back_inserter(all)); return all; } static std::vector installedMSVCsFromRegistry() { std::vector result; // Detect Visual Studio const QSettings vsRegistry( QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + QStringLiteral("\\Microsoft\\VisualStudio\\SxS\\VS7"), QSettings::NativeFormat); const auto vsNames = vsRegistry.childKeys(); for (const QString &vsName : vsNames) { MSVCInstallInfo entry; entry.version = vsName; entry.installDir = vsRegistry.value(vsName).toString(); result.push_back(entry); } // Detect Visual C++ Build Tools QSettings vcbtRegistry( QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + QStringLiteral("\\Microsoft\\VisualCppBuildTools"), QSettings::NativeFormat); const QStringList &vcbtRegistryChildGroups = vcbtRegistry.childGroups(); for (const QString &childGroup : vcbtRegistryChildGroups) { vcbtRegistry.beginGroup(childGroup); bool ok; int installed = vcbtRegistry.value(QStringLiteral("Installed")).toInt(&ok); if (ok && installed) { MSVCInstallInfo entry; entry.version = childGroup; const QSettings vsRegistry( QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + QStringLiteral("\\Microsoft\\VisualStudio\\") + childGroup + QStringLiteral("\\Setup\\VC"), QSettings::NativeFormat); entry.installDir = vsRegistry.value(QStringLiteral("ProductDir")).toString(); result.push_back(entry); } vcbtRegistry.endGroup(); } return result; } /* Returns the list of compilers present in all MSVC installations (Visual Studios or Build Tools) without the architecture, e.g. [VC\Tools\MSVC\14.16.27023, VC\Tools\MSVC\14.14.26428, ...] */ static std::vector installedCompilersHelper(Logger &logger) { std::vector msvcs; std::vector installInfos = installedMSVCsFromVsWhere(logger); if (installInfos.empty()) installInfos = installedMSVCsFromRegistry(); for (const MSVCInstallInfo &installInfo : installInfos) { MSVC msvc; msvc.internalVsVersion = Version::fromString(installInfo.version, true); if (!msvc.internalVsVersion.isValid()) continue; QDir vsInstallDir(installInfo.installDir); msvc.vsInstallPath = vsInstallDir.absolutePath(); if (vsInstallDir.dirName() != QStringLiteral("VC") && !vsInstallDir.cd(QStringLiteral("VC"))) { continue; } msvc.version = QString::number(Internal::VisualStudioVersionInfo( msvc.internalVsVersion).marketingVersion()); if (msvc.version.isEmpty()) { logger.qbsWarning() << Tr::tr("Unknown MSVC version %1 found.").arg(installInfo.version); continue; } if (msvc.internalVsVersion.majorVersion() < 15) { QDir vcInstallDir = vsInstallDir; if (!vcInstallDir.cd(QStringLiteral("bin"))) continue; msvc.vcInstallPath = vcInstallDir.absolutePath(); msvcs.push_back(msvc); } else { QDir vcInstallDir = vsInstallDir; vcInstallDir.cd(QStringLiteral("Tools/MSVC")); const auto vcVersionStrs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); std::vector vcVersions; vcVersions.reserve(vcVersionStrs.size()); for (const QString &vcVersionStr : vcVersionStrs) { const Version vcVersion = Version::fromString(vcVersionStr); if (!vcVersion.isValid()) continue; vcVersions.push_back(vcVersion); } // sort the versions so the new one comes first std::sort(vcVersions.begin(), vcVersions.end(), std::greater<>()); for (const Version &vcVersion : vcVersions) { QDir specificVcInstallDir = vcInstallDir; if (!specificVcInstallDir.cd(vcVersion.toString()) || !specificVcInstallDir.cd(QStringLiteral("bin"))) { continue; } msvc.vcInstallPath = specificVcInstallDir.absolutePath(); msvcs.push_back(msvc); } } } return msvcs; } void MSVC::init() { determineCompilerVersion(); } /*! \internal Returns the architecture detected from the compiler path. */ QString MSVC::architectureFromClPath(const QString &clPath) { const auto parentDir = QFileInfo(clPath).absolutePath(); auto parentDirName = QFileInfo(parentDir).fileName().toLower(); // can be the case when cl.exe is present within the Windows SDK installation... but can it? if (parentDirName == QLatin1String("bin")) return QStringLiteral("x86"); return parentDirName; } QString MSVC::vcVariablesVersionFromBinPath(const QString &binPath) { const auto binDirName = QFileInfo(binPath).fileName().toLower(); // the case when cl.exe is present within the Windows SDK installation if (binDirName == QLatin1String("bin")) return {}; // binPath is something like // Microsoft Visual Studio 14.0/VC/bin/amd64_x86 // or // Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/bin/Hostx64/x64 QDir dir(binPath); dir.cdUp(); // older Visual Studios do not support multiple compiler versions if (dir.dirName().toLower() == QLatin1String("bin")) return {}; dir.cdUp(); dir.cdUp(); return dir.dirName(); } QString MSVC::canonicalArchitecture(const QString &arch) { if (arch == QLatin1String("x64") || arch == QLatin1String("amd64")) return QStringLiteral("x86_64"); return arch; } std::pair MSVC::getHostTargetArchPair(const QString &arch) { QString hostArch; QString targetArch; const int index = arch.indexOf(QLatin1Char('_')); if (index != -1) { hostArch = arch.mid(0, index); targetArch = arch.mid(index); } else { hostArch = arch; targetArch = arch; } return {canonicalArchitecture(hostArch), canonicalArchitecture(targetArch)}; } QString MSVC::binPathForArchitecture(const QString &arch) const { QString archSubDir; if (arch != StringConstants::x86Arch()) archSubDir = arch; return QDir::cleanPath(vcInstallPath + QLatin1Char('/') + pathPrefix + QLatin1Char('/') + archSubDir); } static QString clExeSuffix() { return QStringLiteral("/cl.exe"); } QString MSVC::clPathForArchitecture(const QString &arch) const { return binPathForArchitecture(arch) + clExeSuffix(); } QVariantMap MSVC::compilerDefines(const QString &compilerFilePath, MSVC::CompilerLanguage language) const { const auto compilerName = QFileInfo(compilerFilePath).fileName().toLower(); if (compilerName == QLatin1String("clang-cl.exe")) return getClangClDefines(compilerFilePath, environment, language, architecture); return getMsvcDefines(compilerFilePath, environment, language); } std::vector MSVC::findSupportedArchitectures(const MSVC &msvc) { std::vector result; auto addResult = [&result](const MSVCArchInfo &ai) { if (QFile::exists(ai.binPath + QLatin1String("/cl.exe"))) result.push_back(ai); }; if (msvc.internalVsVersion.majorVersion() < 15) { static const QStringList knownArchitectures = QStringList() << QStringLiteral("x86") << QStringLiteral("amd64_x86") << QStringLiteral("amd64") << QStringLiteral("x86_amd64") << QStringLiteral("ia64") << QStringLiteral("x86_ia64") << QStringLiteral("x86_arm") << QStringLiteral("amd64_arm"); for (const QString &knownArchitecture : knownArchitectures) { MSVCArchInfo ai; ai.arch = knownArchitecture; ai.binPath = msvc.binPathForArchitecture(knownArchitecture); addResult(ai); } } else { QDir vcInstallDir(msvc.vcInstallPath); const auto hostArchs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QString &hostArch : hostArchs) { QDir subdir = vcInstallDir; if (!subdir.cd(hostArch)) continue; const QString shortHostArch = hostArch.mid(4).toLower(); const auto archs = subdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QString &arch : archs) { MSVCArchInfo ai; ai.binPath = subdir.absoluteFilePath(arch); if (shortHostArch == arch) ai.arch = arch; else ai.arch = shortHostArch + QLatin1Char('_') + arch; addResult(ai); } } } return result; } QVariantMap MSVC::toVariantMap() const { return { {QStringLiteral("version"), version}, {QStringLiteral("internalVsVersion"), internalVsVersion.toString()}, {QStringLiteral("vsInstallPath"), vsInstallPath}, {QStringLiteral("vcInstallPath"), vcInstallPath}, {QStringLiteral("binPath"), binPath}, {QStringLiteral("architecture"), architecture}, }; } /*! \internal Returns the list of all compilers present in all MSVC installations separated by host/target arch, e.g. [ VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64, VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86, VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm, VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm64, VC\Tools\MSVC\14.16.27023\bin\Hostx86\x64, ... ] \note that MSVC.architecture can be either "x64" or "amd64" (depending on the MSVC version) in case of 64-bit platform (but we use the "x86_64" name...) */ std::vector MSVC::installedCompilers(Logger &logger) { std::vector msvcs; const auto instMsvcs = installedCompilersHelper(logger); for (const MSVC &msvc : instMsvcs) { if (msvc.internalVsVersion.majorVersion() < 15) { // Check existence of various install scripts const QString vcvars32bat = msvc.vcInstallPath + QLatin1String("/vcvars32.bat"); if (!QFileInfo(vcvars32bat).isFile()) continue; } const auto ais = findSupportedArchitectures(msvc); transform(ais, msvcs, [&msvc](const auto &ai) { MSVC specificMSVC = msvc; specificMSVC.architecture = ai.arch; specificMSVC.binPath = ai.binPath; return specificMSVC; }); } return msvcs; } void MSVC::determineCompilerVersion() { QString cppFilePath; { QTemporaryFile cppFile(QDir::tempPath() + QLatin1String("/qbsXXXXXX.cpp")); cppFile.setAutoRemove(false); if (!cppFile.open()) { throw ErrorInfo(mkStr("Could not create temporary file (%1)") .arg(cppFile.errorString())); } cppFilePath = cppFile.fileName(); cppFile.write("_MSC_FULL_VER"); cppFile.close(); } DummyFile fileDeleter(cppFilePath); std::lock_guard locker(envMutex); const QByteArray origPath = qgetenv("PATH"); QByteArray tempPath = environment.value(StringConstants::pathEnvVar()).toLatin1() + ';' + origPath; qputenv("PATH", tempPath); QByteArray versionStr = runProcess( binPath + clExeSuffix(), QStringList() << QStringLiteral("/nologo") << QStringLiteral("/EP") << QDir::toNativeSeparators(cppFilePath)); qputenv("PATH", origPath); compilerVersion = Version(versionStr.mid(0, 2).toInt(), versionStr.mid(2, 2).toInt(), versionStr.mid(4).toInt()); } QString MSVCInstallInfo::findVcvarsallBat() const { static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat"); // 2015, 2013 and 2012 static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat"); QDir dir(installDir); if (dir.exists(vcvarsall2017)) return dir.absoluteFilePath(vcvarsall2017); if (dir.exists(vcvarsallOld)) return dir.absoluteFilePath(vcvarsallOld); return {}; } std::vector MSVCInstallInfo::installedMSVCs(Logger &logger) { auto installInfos = installedMSVCsFromVsWhere(logger); if (installInfos.empty()) return installedMSVCsFromRegistry(); return installInfos; } qbs-src-2.6.1/src/lib/corelib/tools/installoptions.h0000644000175100001660000000640014776170045022017 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_INSTALLOPTIONS_H #define QBS_INSTALLOPTIONS_H #include "qbs_export.h" #include QT_BEGIN_NAMESPACE class QJsonObject; class QString; QT_END_NAMESPACE namespace qbs { class InstallOptions; namespace Internal { class InstallOptionsPrivate; class TopLevelProject; QString effectiveInstallRoot(const InstallOptions &options, const TopLevelProject *project); } class QBS_EXPORT InstallOptions { public: InstallOptions(); InstallOptions(const InstallOptions &other); InstallOptions(InstallOptions &&other) Q_DECL_NOEXCEPT; InstallOptions &operator=(const InstallOptions &other); InstallOptions &operator=(InstallOptions &&other) Q_DECL_NOEXCEPT; ~InstallOptions(); static InstallOptions fromJson(const QJsonObject &data); static QString defaultInstallRoot(); QString installRoot() const; void setInstallRoot(const QString &installRoot); bool installIntoSysroot() const; void setInstallIntoSysroot(bool useSysroot); bool removeExistingInstallation() const; void setRemoveExistingInstallation(bool removeExisting); bool dryRun() const; void setDryRun(bool dryRun); bool keepGoing() const; void setKeepGoing(bool keepGoing); bool logElapsedTime() const; void setLogElapsedTime(bool logElapsedTime); private: QSharedDataPointer d; }; } // namespace qbs #endif // QBS_INSTALLOPTIONS_H qbs-src-2.6.1/src/lib/corelib/tools/weakpointer.h0000644000175100001660000000667714776170045021305 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_WEAKPOINTER_H #define QBS_WEAKPOINTER_H #include namespace qbs { namespace Internal { template class WeakPointer : public std::weak_ptr { public: WeakPointer() : std::weak_ptr() {} WeakPointer(const std::shared_ptr &sharedPointer) : std::weak_ptr(sharedPointer) {} template WeakPointer(const std::shared_ptr &sp) : std::weak_ptr(sp) { } T *get() const { auto p = std::weak_ptr::lock(); return p.get(); } operator bool() const { return !std::weak_ptr::expired(); } bool operator!() const { return std::weak_ptr::expired(); } operator T*() const { return checkedData(); } T *operator->() const { return checkedData(); } T operator*() const { return *checkedData(); } private: T *checkedData() const { T * const d = get(); Q_ASSERT(d); // Calling code is not expecting this situation. return d; } }; template bool operator==(const WeakPointer &a, const WeakPointer &b) { return a.get() == b.get(); } template bool operator!=(const WeakPointer &a, const WeakPointer &b) { return a.get() != b.get(); } template bool operator==(const WeakPointer &a, const std::shared_ptr &b) { return a.lock() == b; } template bool operator!=(const WeakPointer &a, const std::shared_ptr &b) { return a.lock() != b; } } // namespace Internal } // namespace qbs #endif // QBS_WEAKPOINTER_H qbs-src-2.6.1/src/lib/corelib/tools/fileinfo.cpp0000644000175100001660000004627414776170045021100 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "fileinfo.h" #include #include #include #include #include #include #include #include #include #if defined(Q_OS_UNIX) #include #include #include #elif defined(Q_OS_WIN) #include #endif namespace qbs { namespace Internal { QString FileInfo::fileName(const QString &fp) { int last = fp.lastIndexOf(QLatin1Char('/')); if (last < 0) return fp; return fp.mid(last + 1); } QString FileInfo::baseName(const QString &fp) { QString fn = fileName(fp); int dot = fn.indexOf(QLatin1Char('.')); if (dot < 0) return fn; return fn.mid(0, dot); } QString FileInfo::completeBaseName(const QString &fp) { QString fn = fileName(fp); int dot = fn.lastIndexOf(QLatin1Char('.')); if (dot < 0) return fn; return fn.mid(0, dot); } QString FileInfo::suffix(const QString &fp) { QString fn = fileName(fp); int dot = fn.lastIndexOf(QLatin1Char('.')); if (dot < 0) return fn; return fn.mid(dot + 1); } QString FileInfo::completeSuffix(const QString &fp) { QString fn = fileName(fp); int dot = fn.indexOf(QLatin1Char('.')); if (dot < 0) return fn; return fn.mid(dot + 1); } QString FileInfo::path(const QString &fp, HostOsInfo::HostOs hostOs) { if (fp.isEmpty()) return {}; int last = fp.lastIndexOf(QLatin1Char('/')); if (last < 0) return StringConstants::dot(); QString p = QDir::cleanPath(fp.mid(0, last)); if (p.isEmpty() || (hostOs == HostOsInfo::HostOsWindows && p.length() == 2 && p.at(0).isLetter() && p.at(1) == QLatin1Char(':'))) { // Make sure we don't return Windows drive roots without an ending slash. // Those paths are considered relative. p.append(QLatin1Char('/')); } return p; } void FileInfo::splitIntoDirectoryAndFileName(const QString &filePath, QString *dirPath, QString *fileName) { int idx = filePath.lastIndexOf(QLatin1Char('/')); if (idx < 0) { dirPath->clear(); *fileName = filePath; return; } *dirPath = filePath.left(idx); *fileName = filePath.mid(idx + 1); } void FileInfo::splitIntoDirectoryAndFileName(const QString &filePath, QStringView *dirPath, QStringView *fileName) { int idx = filePath.lastIndexOf(QLatin1Char('/')); if (idx < 0) { *dirPath = QStringView(); *fileName = QStringView(filePath); return; } *dirPath = QStringView(filePath).left(idx); *fileName = QStringView(filePath).mid(idx + 1); } bool FileInfo::exists(const QString &fp) { return FileInfo(fp).exists(); } // Whether a path is the special "current drive path" path type, // which is neither truly relative nor absolute static bool isCurrentDrivePath(const QString &path, HostOsInfo::HostOs hostOs) { return hostOs == HostOsInfo::HostOsWindows ? path.size() == 2 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter() : false; } // from creator/src/shared/proparser/ioutils.cpp bool FileInfo::isAbsolute(const QString &path, HostOsInfo::HostOs hostOs) { const int n = path.size(); if (n == 0) return false; const QChar at0 = path.at(0); if (at0 == QLatin1Char('/')) return true; if (hostOs == HostOsInfo::HostOsWindows) { if (at0 == QLatin1Char('\\')) return true; // Unlike QFileInfo, this won't accept a relative path with a drive letter. // Such paths result in a royal mess anyway ... if (n >= 3 && path.at(1) == QLatin1Char(':') && at0.isLetter() && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) return true; } return false; } bool FileInfo::isPattern(QStringView str) { return Internal::any_of(str, [](const auto &ch) { return (ch == QLatin1Char('*') || ch == QLatin1Char('?') || ch == QLatin1Char(']') || ch == QLatin1Char('[')); }); } /** * Concatenates the paths \a base and \a rel. * Base must be an absolute path. * Double dots at the start of \a rel are handled. * This function assumes that both paths are clean, that is they don't contain * double slashes or redundant dot parts. */ QString FileInfo::resolvePath(const QString &base, const QString &rel, HostOsInfo::HostOs hostOs) { QBS_ASSERT(isAbsolute(base, hostOs) && !isCurrentDrivePath(rel, hostOs), qDebug("base: %s, rel: %s", qPrintable(base), qPrintable(rel)); return {}); if (isAbsolute(rel, hostOs)) return rel; if (rel.size() == 1 && rel.at(0) == QLatin1Char('.')) return base; if (rel.size() == 1 && rel.at(0) == QLatin1Char('~')) return QDir::homePath(); if (rel.startsWith(StringConstants::tildeSlash())) return QDir::homePath() + rel.mid(1); QString r = base; if (r.endsWith(QLatin1Char('/'))) r.chop(1); QString s = rel; while (s.startsWith(QStringLiteral("../"))) { s.remove(0, 3); int idx = r.lastIndexOf(QLatin1Char('/')); if (idx >= 0) r.truncate(idx); } if (s == StringConstants::dotDot()) { int idx = r.lastIndexOf(QLatin1Char('/')); if (idx >= 0) r.truncate(idx); s.clear(); } if (!s.isEmpty() || isCurrentDrivePath(r, hostOs)) { r.reserve(r.length() + 1 + s.length()); r += QLatin1Char('/'); r += s; } return r; } #ifdef Q_OS_WIN static QString prependLongPathPrefix(const QString &absolutePath) { QString nativePath = QDir::toNativeSeparators(absolutePath); if (nativePath.startsWith(QStringLiteral("\\\\"))) nativePath.remove(0, 1).prepend(QLatin1String("UNC")); nativePath.prepend(QLatin1String("\\\\?\\")); return nativePath; } #endif bool FileInfo::isFileCaseCorrect(const QString &filePath) { #if defined(Q_OS_WIN) // QFileInfo::canonicalFilePath() does not return the real case of the file path on Windows. QFileInfo fi(filePath); const QString absolute = prependLongPathPrefix(fi.absoluteFilePath()); WIN32_FIND_DATA fd; HANDLE hFindFile = ::FindFirstFile((wchar_t*)absolute.utf16(), &fd); if (hFindFile == INVALID_HANDLE_VALUE) return false; const QString actualFileName = QString::fromWCharArray(fd.cFileName); FindClose(hFindFile); return actualFileName == fi.fileName(); #elif defined(Q_OS_DARWIN) QFileInfo fi(filePath); return fi.fileName() == fileName(fi.canonicalFilePath()); #else Q_UNUSED(filePath) return true; #endif } bool FileInfo::fileExists(const QFileInfo &fi) { return fi.isSymLink() || fi.exists(); } #if defined(Q_OS_WIN) #define z(x) reinterpret_cast(const_cast(&x)) FileInfo::FileInfo(const QString &fileName) { static_assert(sizeof(FileInfo::InternalStatType) == sizeof(WIN32_FILE_ATTRIBUTE_DATA), "FileInfo::InternalStatType has wrong size."); QString filePath = fileName; // The extended-length path prefix cannot be used with a relative path, so make it absolute if (!isAbsolute(filePath)) filePath = QDir::currentPath() + QDir::separator() + filePath; filePath = prependLongPathPrefix(QDir::cleanPath(filePath)); if (!GetFileAttributesEx(reinterpret_cast(filePath.utf16()), GetFileExInfoStandard, &m_stat)) { ZeroMemory(z(m_stat), sizeof(WIN32_FILE_ATTRIBUTE_DATA)); z(m_stat)->dwFileAttributes = INVALID_FILE_ATTRIBUTES; } } bool FileInfo::exists() const { return z(m_stat)->dwFileAttributes != INVALID_FILE_ATTRIBUTES; } FileTime FileInfo::lastModified() const { const FileTime::InternalType* ft_it; ft_it = reinterpret_cast(&z(m_stat)->ftLastWriteTime); return {*ft_it}; } FileTime FileInfo::lastStatusChange() const { return lastModified(); } bool FileInfo::isDir() const { return exists() && z(m_stat)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; } static QString resolveSymlinks(const QString &fileName) { QFileInfo fi(fileName); while (fi.isSymLink()) fi.setFile(fi.dir(), fi.symLinkTarget()); return fi.absoluteFilePath(); } QString applicationDirPath() { static const QString appDirPath = FileInfo::path(resolveSymlinks(QCoreApplication::applicationFilePath())); return appDirPath; } #elif defined(Q_OS_UNIX) namespace GetFileTimes { enum TimeType { LastModified, LastStatusChanged }; // SFINAE magic inspired by // https://github.com/qt/qtbase/blob/5.13/src/corelib/io/qfilesystemengine_unix.cpp template< TimeType type, typename T, std::enable_if_t<(&T::st_mtim, &T::st_ctim, true), int> = 0> static inline FileTime get(const T &stat) { if constexpr (type == LastModified) return stat.st_mtim; else if constexpr (type == LastStatusChanged) return stat.st_ctim; } // we are interested in real members, not compatibility macros # if defined(st_mtimespec) # undef st_mtimespec # endif # if defined(st_ctimespec) # undef st_ctimespec # endif template< TimeType type, typename T, std::enable_if_t<(&T::st_mtimespec, &T::st_ctimespec, true), int> = 0> static inline FileTime get(const T &stat) { if constexpr (type == LastModified) return stat.st_mtimespec; else if constexpr (type == LastStatusChanged) return stat.st_ctimespec; } # if defined(st_mtimensec) # undef st_mtimensec # endif # if defined(st_ctimensec) # undef st_ctimensec # endif template< TimeType type, typename T, std::enable_if_t<(&T::st_mtimensec, &T::st_ctimensec, true), int> = 0> static inline FileTime get(const T &stat) { if constexpr (type == LastModified) return FileTime::InternalType{stat.st_mtime, stat.st_mtimensec}; else if constexpr (type == LastStatusChanged) return FileTime::InternalType{stat.st_ctime, stat.st_ctimensec}; } } // namespace GetFileTimes FileInfo::FileInfo(const QString &fileName) { if (stat(fileName.toLocal8Bit().constData(), &m_stat) == -1) { m_stat.st_mtime = 0; m_stat.st_mode = 0; } } bool FileInfo::exists() const { return m_stat.st_mode != 0; } FileTime FileInfo::lastModified() const { return GetFileTimes::get(m_stat); } FileTime FileInfo::lastStatusChange() const { return GetFileTimes::get(m_stat); } bool FileInfo::isDir() const { return S_ISDIR(m_stat.st_mode); } #endif // adapted from qtc/plugins/vcsbase/cleandialog.cpp bool removeFileRecursion(const QFileInfo &f, QString *errorMessage) { if (!FileInfo::fileExists(f)) return true; if (f.isDir() && !f.isSymLink()) { const QDir dir(f.absoluteFilePath()); // QDir::System is needed for broken symlinks. const auto fileInfos = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); for (const QFileInfo &fi : fileInfos) removeFileRecursion(fi, errorMessage); QDir parent = f.absoluteDir(); if (!parent.rmdir(f.fileName())) { errorMessage->append(Tr::tr("The directory %1 could not be deleted."). arg(QDir::toNativeSeparators(f.absoluteFilePath()))); return false; } } else { QFile file(f.absoluteFilePath()); file.setPermissions(f.permissions() | QFile::WriteUser); if (!file.remove()) { if (!errorMessage->isEmpty()) errorMessage->append(QLatin1Char('\n')); errorMessage->append(Tr::tr("The file %1 could not be deleted."). arg(QDir::toNativeSeparators(f.absoluteFilePath()))); return false; } } return true; } bool removeDirectoryWithContents(const QString &path, QString *errorMessage) { QFileInfo f(path); if (f.exists() && !f.isDir()) { *errorMessage = Tr::tr("%1 is not a directory.").arg(QDir::toNativeSeparators(path)); return false; } return removeFileRecursion(f, errorMessage); } /*! * Returns the stored link target of the symbolic link \a{filePath}. * Unlike QFileInfo::symLinkTarget, this will not make the link target an absolute path. */ static QByteArray storedLinkTarget(const QString &filePath) { // A nasty workaround for GCC13 bug (see QTBUG-103782), it complains about type punning // in Qt5 QByteArray::Data, so we use std::vector as a buffer to readlink below. // See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105709 std::vector result; #ifdef Q_OS_UNIX const QByteArray nativeFilePath = QFile::encodeName(filePath); ssize_t len; while (true) { struct stat sb{}; if (lstat(nativeFilePath.constData(), &sb)) { qWarning("storedLinkTarget: lstat for %s failed with error code %d", nativeFilePath.constData(), errno); return {}; } result.resize(sb.st_size); len = readlink(nativeFilePath.constData(), result.data(), sb.st_size + 1); if (len < 0) { qWarning("storedLinkTarget: readlink for %s failed with error code %d", nativeFilePath.constData(), errno); return {}; } if (len < sb.st_size) { result.resize(len); break; } if (len == sb.st_size) break; } #else Q_UNUSED(filePath); #endif // Q_OS_UNIX return {result.data(), static_cast().size())>(result.size())}; } static bool createSymLink(const QByteArray &path1, const QString &path2) { #ifdef Q_OS_UNIX const QByteArray newPath = QFile::encodeName(path2); unlink(newPath.constData()); return symlink(path1.constData(), newPath.constData()) == 0; #else Q_UNUSED(path1); Q_UNUSED(path2); return false; #endif // Q_OS_UNIX } /*! Copies the directory specified by \a srcFilePath recursively to \a tgtFilePath. \a tgtFilePath will contain the target directory, which will be created. Example usage: \code QString error; book ok = Utils::FileUtils::copyRecursively("/foo/bar", "/foo/baz", &error); if (!ok) qDebug() << error; \endcode This will copy the contents of /foo/bar into to the baz directory under /foo, which will be created in the process. \return Whether the operation succeeded. \note Function was adapted from qtc/src/libs/fileutils.cpp */ bool copyFileRecursion(const QString &srcFilePath, const QString &tgtFilePath, bool preserveSymLinks, bool copyDirectoryContents, QString *errorMessage) { QFileInfo srcFileInfo(srcFilePath); QFileInfo tgtFileInfo(tgtFilePath); const QString targetDirPath = tgtFileInfo.absoluteDir().path(); if (!QDir::root().mkpath(targetDirPath)) { *errorMessage = Tr::tr("The directory '%1' could not be created.") .arg(QDir::toNativeSeparators(targetDirPath)); return false; } if (HostOsInfo::isAnyUnixHost() && preserveSymLinks && srcFileInfo.isSymLink()) { // For now, disable symlink preserving copying on Windows. // MS did a good job to prevent people from using symlinks - even if they are supported. if (!createSymLink(storedLinkTarget(srcFilePath), tgtFilePath)) { *errorMessage = Tr::tr("The symlink '%1' could not be created.") .arg(tgtFilePath); return false; } } else if (srcFileInfo.isDir()) { if (copyDirectoryContents) { QDir sourceDir(srcFilePath); const QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); for (const QString &fileName : fileNames) { const QString newSrcFilePath = srcFilePath + QLatin1Char('/') + fileName; const QString newTgtFilePath = tgtFilePath + QLatin1Char('/') + fileName; if (!copyFileRecursion(newSrcFilePath, newTgtFilePath, preserveSymLinks, copyDirectoryContents, errorMessage)) return false; } } else { if (tgtFileInfo.exists() && srcFileInfo.lastModified() <= tgtFileInfo.lastModified()) return true; return QDir::root().mkpath(tgtFilePath); } } else { if (tgtFileInfo.exists() && srcFileInfo.lastModified() <= tgtFileInfo.lastModified()) return true; QFile file(srcFilePath); QFile targetFile(tgtFilePath); if (targetFile.exists()) { targetFile.setPermissions(targetFile.permissions() | QFile::WriteUser); if (!targetFile.remove()) { *errorMessage = Tr::tr("Could not remove file '%1'. %2") .arg(QDir::toNativeSeparators(tgtFilePath), targetFile.errorString()); } } if (!file.copy(tgtFilePath)) { *errorMessage = Tr::tr("Could not copy file '%1' to '%2'. %3") .arg(QDir::toNativeSeparators(srcFilePath), QDir::toNativeSeparators(tgtFilePath), file.errorString()); return false; } } return true; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/error.h0000644000175100001660000001120514776170045020065 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ERROR #define QBS_ERROR #include "codelocation.h" #include #include #include #include QT_BEGIN_NAMESPACE class QJsonObject; QT_END_NAMESPACE namespace qbs { namespace Internal { class PersistentPool; class Logger; } // namespace Internal class CodeLocation; class SetupProjectParameters; class QBS_EXPORT ErrorItem { friend class ErrorInfo; public: ErrorItem(); ErrorItem(const ErrorItem &rhs); ErrorItem(ErrorItem &&rhs) noexcept; ErrorItem &operator=(const ErrorItem &other); ErrorItem &operator=(ErrorItem &&other) noexcept; ~ErrorItem(); QString description() const; CodeLocation codeLocation() const; QString toString() const; QJsonObject toJson() const; bool isBacktraceItem() const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; private: ErrorItem(const QString &description, const CodeLocation &codeLocation, bool isBacktraceItem = false); class ErrorItemPrivate; QExplicitlySharedDataPointer d; }; class QBS_EXPORT ErrorInfo { public: ErrorInfo(); ErrorInfo(const ErrorInfo &rhs); ErrorInfo(ErrorInfo &&rhs) noexcept; ErrorInfo(const QString &description, const CodeLocation &location = CodeLocation(), bool internalError = false); ErrorInfo(const QString &description, const QStringList &backtrace); ErrorInfo &operator=(const ErrorInfo &other); ErrorInfo &operator=(ErrorInfo &&other) noexcept; ~ErrorInfo(); void appendBacktrace(const QString &description, const CodeLocation &location = CodeLocation()); void append(const ErrorItem &item); void append(const QString &description, const CodeLocation &location = CodeLocation()); void prepend(const QString &description, const CodeLocation &location = CodeLocation()); const QList items() const; bool hasError() const { return !items().empty(); } void clear(); QString toString() const; QJsonObject toJson() const; bool isInternalError() const; bool hasLocation() const; bool isCancelException() const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; private: class ErrorInfoPrivate; QSharedDataPointer d; }; void appendError(ErrorInfo &dst, const ErrorInfo &src); void handlePropertyError( const ErrorInfo &error, const SetupProjectParameters ¶ms, Internal::Logger &logger); inline auto qHash(const ErrorInfo &e) { return qHash(e.toString()); } inline bool operator==(const ErrorInfo &e1, const ErrorInfo &e2) { return e1.toString() == e2.toString(); } } // namespace qbs Q_DECLARE_METATYPE(qbs::ErrorInfo) #endif // QBS_ERROR qbs-src-2.6.1/src/lib/corelib/tools/commandechomode.cpp0000644000175100001660000000716014776170045022416 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandechomode.h" #include #include /*! * \enum CommandEchoMode * This enum type specifies the kind of output to display when executing commands. * \value CommandEchoModeSilent Indicates that no output will be printed. * \value CommandEchoModeSummary Indicates that descriptions will be printed. * \value CommandEchoModeCommandLine Indidcates that full command line invocations will be printed. * \value CommandEchoModeCommandLineWithEnvironment Indidcates that full command line invocations, * including environment variables, will be printed. */ namespace qbs { CommandEchoMode defaultCommandEchoMode() { return CommandEchoModeSummary; } QString commandEchoModeName(CommandEchoMode mode) { switch (mode) { case CommandEchoModeSilent: return QStringLiteral("silent"); case CommandEchoModeSummary: return QStringLiteral("summary"); case CommandEchoModeCommandLine: return QStringLiteral("command-line"); case CommandEchoModeCommandLineWithEnvironment: return QStringLiteral("command-line-with-environment"); default: break; } return {}; } CommandEchoMode commandEchoModeFromName(const QString &name) { CommandEchoMode mode = defaultCommandEchoMode(); for (int i = 0; i < CommandEchoModeInvalid; ++i) { if (commandEchoModeName(static_cast(i)) == name) { mode = static_cast(i); break; } } return mode; } QStringList allCommandEchoModeStrings() { QStringList result; for (int i = 0; i < CommandEchoModeInvalid; ++i) result << commandEchoModeName(static_cast(i)); return result; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/progressobserver.h0000644000175100001660000000557214776170045022362 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROGRESSOBSERVER_H #define QBS_PROGRESSOBSERVER_H #include #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { class ScriptEngine; class ProgressObserver { public: virtual ~ProgressObserver() = default; virtual void initialize(const QString &task, int maximum) = 0; virtual void setProgressValue(int value) = 0; virtual int progressValue() = 0; virtual bool canceled() const = 0; virtual void setMaximum(int maximum) = 0; virtual int maximum() const = 0; void incrementProgressValue(int increment = 1); // Call this to ensure that the progress bar always goes to 100%. void setFinished(); void addScriptEngine(ScriptEngine *engine) { m_scriptEngines.push_back(engine); } protected: const std::vector &scriptEngines() const { return m_scriptEngines; } private: std::vector m_scriptEngines; }; } // namespace Internal } // namespace qbs #endif // QBS_PROGRESSOBSERVER_H qbs-src-2.6.1/src/lib/corelib/tools/pimpl.h0000644000175100001660000000442614776170045020064 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PIMPL_H #define PIMPL_H #include #include namespace qbs { namespace Internal { template using Pimpl = KDToolBox::propagate_const>; template Pimpl makePimpl(Args&&... args) { return Pimpl(std::make_unique(std::forward(args)...)); } } // namespace Internal } // namespace qbs #endif // PIMPL_H qbs-src-2.6.1/src/lib/corelib/tools/architectures.h0000644000175100001660000000467414776170045021615 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ARCHITECTURES_H #define QBS_ARCHITECTURES_H #include "qbs_export.h" #include namespace qbs { QBS_EXPORT QString canonicalTargetArchitecture(const QString &architecture, const QString &endianness, const QString &vendor, const QString &system, const QString &abi); QBS_EXPORT QString canonicalArchitecture(const QString &architecture); } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/tools/settings.h0000644000175100001660000000765514776170045020612 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETTINGS_H #define QBS_SETTINGS_H #include "qbs_export.h" #include #include #include #include QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE namespace qbs { class QBS_EXPORT Settings { public: // The "pure" base directory without any version scope. Empty string means "system default". Settings(const QString &baseDir); Settings(const QString &baseDir, const QString &systemBaseDir); ~Settings(); enum Scope { UserScope = 0x1, SystemScope = 0x2 }; Q_DECLARE_FLAGS(Scopes, Scope) static Scopes allScopes() { return {UserScope, SystemScope}; } QVariant value(const QString &key, Scopes scopes, const QVariant &defaultValue = QVariant()) const; QStringList allKeys(Scopes scopes) const; QStringList directChildren(const QString &parentGroup, Scopes scopes) const; // Keys and groups. QStringList allKeysWithPrefix(const QString &group, Scopes scopes) const; void setValue(const QString &key, const QVariant &value); void remove(const QString &key); void clear(); void sync(); void setScopeForWriting(Scope scope) { m_scopeForWriting = scope; } Scope scopeForWriting() const { return m_scopeForWriting; } QString defaultProfile() const; QStringList profiles() const; QString fileName() const; QString baseDirectory() const { return m_baseDir; } // As passed into the constructor. static QString defaultSystemSettingsBaseDir(); private: QString internalRepresentation(const QString &externalKey) const; QString externalRepresentation(const QString &internalKey) const; void fixupKeys(QStringList &keys) const; QSettings *settingsForScope(Scope scope) const; QSettings *targetForWriting() const; void checkForWriteError(); const std::unique_ptr m_settings; const std::unique_ptr m_systemSettings; const QString m_baseDir; Scope m_scopeForWriting = UserScope; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Settings::Scopes) } // namespace qbs #endif // QBS_SETTINGS_H qbs-src-2.6.1/src/lib/corelib/tools/launcherinterface.h0000644000175100001660000000557714776170045022435 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LAUNCHERINTERFACE_H #define QBS_LAUNCHERINTERFACE_H #include QT_BEGIN_NAMESPACE class QLocalServer; QT_END_NAMESPACE namespace qbs { class ErrorInfo; namespace Internal { class LauncherProcess; class LauncherSocket; class LauncherInterface : public QObject { Q_OBJECT public: static LauncherInterface &instance(); ~LauncherInterface() override; static void startLauncher() { instance().doStart(); } static void stopLauncher() { instance().doStop(); } static LauncherSocket *socket() { return instance().m_socket; } signals: void errorOccurred(const ErrorInfo &error); private: LauncherInterface(); void doStart(); void doStop(); void handleNewConnection(); void handleProcessError(); void handleProcessFinished(); void handleProcessStderr(); QLocalServer * const m_server; LauncherSocket * const m_socket; LauncherProcess * m_process = nullptr; int m_startRequests = 0; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/filesaver.cpp0000644000175100001660000000736214776170045021260 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filesaver.h" #include "stlutils.h" #include #include #include namespace qbs { namespace Internal { FileSaver::FileSaver(std::string filePath, bool overwriteIfUnchanged) : m_filePath(std::move(filePath)), m_overwriteIfUnchanged(overwriteIfUnchanged) { } std::ostream *FileSaver::device() { return m_memoryDevice.get(); } bool FileSaver::open() { if (!m_overwriteIfUnchanged) { std::ifstream file(utf8_to_native_path(m_filePath)); if (file.is_open()) m_oldFileContents.assign(std::istreambuf_iterator(file), std::istreambuf_iterator()); else m_oldFileContents.clear(); } m_memoryDevice = std::make_shared(); return true; } bool FileSaver::commit() { if (!device()) return false; device()->flush(); if (!device()->good()) return false; const std::string newFileContents = m_memoryDevice->str(); if (!m_overwriteIfUnchanged && m_oldFileContents == newFileContents) return true; // no need to write unchanged data const std::string tempFilePath = m_filePath + "~"; std::ofstream tempFile(utf8_to_native_path(tempFilePath)); if (!tempFile.is_open()) return false; tempFile.write(newFileContents.data(), newFileContents.size()); tempFile.close(); if (!tempFile.good()) return false; if (Internal::rename(tempFilePath, m_filePath) != 0) { if (errno != EEXIST) return false; if (Internal::unlink(m_filePath) != 0) return false; return Internal::rename(tempFilePath, m_filePath) == 0; } return true; } bool FileSaver::write(std::string_view data) { return Internal::fwrite(data.data(), data.size(), device()); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/fileinfo.h0000644000175100001660000000773514776170045020544 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FILEINFO_H #define QBS_FILEINFO_H #include "filetime.h" #include "hostosinfo.h" #include "qbs_export.h" #if defined(Q_OS_UNIX) #include #endif #include QT_FORWARD_DECLARE_CLASS(QFileInfo) namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT FileInfo { public: FileInfo(const QString &fileName); bool exists() const; FileTime lastModified() const; FileTime lastStatusChange() const; bool isDir() const; static QString fileName(const QString &fp); static QString baseName(const QString &fp); static QString completeBaseName(const QString &fp); static QString suffix(const QString &fp); static QString completeSuffix(const QString &fp); static QString path(const QString &fp, HostOsInfo::HostOs hostOs = HostOsInfo::hostOs()); static void splitIntoDirectoryAndFileName(const QString &filePath, QString *dirPath, QString *fileName); static void splitIntoDirectoryAndFileName(const QString &filePath, QStringView *dirPath, QStringView *fileName); static bool exists(const QString &fp); static bool isAbsolute(const QString &fp, HostOsInfo::HostOs hostOs = HostOsInfo::hostOs()); static bool isPattern(QStringView str); static QString resolvePath(const QString &base, const QString &rel, HostOsInfo::HostOs hostOs = HostOsInfo::hostOs()); static bool isFileCaseCorrect(const QString &filePath); // Symlink-correct check. static bool fileExists(const QFileInfo &fi); private: #if defined(Q_OS_WIN) struct InternalStatType { quint8 z[36]; }; #elif defined(Q_OS_UNIX) using InternalStatType = struct stat; #else # error unknown platform #endif InternalStatType m_stat{}; }; bool removeFileRecursion(const QFileInfo &f, QString *errorMessage); bool QBS_AUTOTEST_EXPORT removeDirectoryWithContents(const QString &path, QString *errorMessage); bool QBS_AUTOTEST_EXPORT copyFileRecursion( const QString &sourcePath, const QString &targetPath, bool preserveSymLinks, bool copyDirectoryContents, QString *errorMessage); } // namespace Internal } // namespace qbs #endif qbs-src-2.6.1/src/lib/corelib/tools/profile.h0000644000175100001660000000751014776170045020400 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROFILE_H #define QBS_PROFILE_H #include "qbs_export.h" #include #include #include namespace qbs { class ErrorInfo; class Settings; class QBS_EXPORT Profile { public: Profile(QString name, Settings *settings, QVariantMap profiles = QVariantMap()); bool exists() const; QVariant value(const QString &key, const QVariant &defaultValue = QVariant(), ErrorInfo *error = nullptr) const; void setValue(const QString &key, const QVariant &value); void remove(const QString &key); QString name() const; QString baseProfile() const; void setBaseProfile(const QString &baseProfile); void removeBaseProfile(); void removeProfile(); enum KeySelection { KeySelectionRecursive, KeySelectionNonRecursive }; QStringList allKeys(KeySelection selection, ErrorInfo *error = nullptr) const; static QString cleanName(const QString &name); static QString fallbackName() { return QStringLiteral("none"); } private: static QString baseProfileKey(); void checkBaseProfileExistence(const Profile &baseProfile) const; QString profileKey() const; QVariant localValue(const QString &key) const; QString fullyQualifiedKey(const QString &key) const; QVariant possiblyInheritedValue(const QString &key, const QVariant &defaultValue, QStringList profileChain) const; QStringList allKeysInternal(KeySelection selection, QStringList profileChain) const; void extendAndCheckProfileChain(QStringList &chain) const; QString m_name; Settings *m_settings; QVariantMap m_values; QVariantMap m_profiles; }; namespace Internal { // Exported for autotests. class QBS_EXPORT TemporaryProfile { public: TemporaryProfile(const QString &name, Settings *settings) : p(name, settings) {} ~TemporaryProfile() { p.removeProfile(); } Profile p; }; } // namespace Internal } // namespace qbs #endif // Header guard qbs-src-2.6.1/src/lib/corelib/tools/profile.cpp0000644000175100001660000001741114776170045020734 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "profile.h" #include "qbsassert.h" #include "settings.h" #include "stringconstants.h" #include #include namespace qbs { /*! * \class Profile * \brief The \c Profile class gives access to the settings of a given profile. */ /*! * \enum Profile::KeySelection * This enum type specifies whether to enumerate keys recursively. * \value KeySelectionRecursive Indicates that key enumeration should happen recursively, i.e. * it should go up the base profile chain. * \value KeySelectionNonRecursive Indicates that only keys directly attached to a profile * should be listed. */ /*! * \brief Creates an object giving access to the settings for profile \c name. */ Profile::Profile(QString name, Settings *settings, QVariantMap profiles) : m_name(std::move(name)), m_settings(settings), m_values(profiles.value(m_name).toMap()), m_profiles(std::move(profiles)) { QBS_ASSERT(m_name == cleanName(m_name), return); } bool Profile::exists() const { return m_name == fallbackName() || !m_values.empty() || !m_settings->allKeysWithPrefix(profileKey(), Settings::allScopes()).empty(); } /*! * \brief Returns the value for property \c key in this profile. */ QVariant Profile::value(const QString &key, const QVariant &defaultValue, ErrorInfo *error) const { try { return possiblyInheritedValue(key, defaultValue, QStringList()); } catch (const ErrorInfo &e) { if (error) *error = e; return {}; } } /*! * \brief Gives value \c value to the property \c key in this profile. */ void Profile::setValue(const QString &key, const QVariant &value) { m_settings->setValue(fullyQualifiedKey(key), value); if (key == baseProfileKey()) { QBS_ASSERT(value.toString() == cleanName(value.toString()), return); } } /*! * \brief Removes a key and the associated value from this profile. */ void Profile::remove(const QString &key) { m_settings->remove(fullyQualifiedKey(key)); } /*! * \brief Returns the name of this profile. */ QString Profile::name() const { return m_name; } /*! * \brief Returns all property keys in this profile. * If and only if selection is Profile::KeySelectionRecursive, this will also list keys defined * in base profiles. */ QStringList Profile::allKeys(KeySelection selection, ErrorInfo *error) const { try { return allKeysInternal(selection, QStringList()); } catch (const ErrorInfo &e) { if (error) *error = e; return {}; } } /*! * \brief Returns the name of this profile's base profile. * The returned value is empty if the profile does not have a base profile. */ QString Profile::baseProfile() const { return localValue(baseProfileKey()).toString(); } /*! * \brief Sets a new base profile for this profile. */ void Profile::setBaseProfile(const QString &baseProfile) { setValue(baseProfileKey(), baseProfile); } /*! * \brief Removes this profile's base profile setting. */ void Profile::removeBaseProfile() { remove(baseProfileKey()); } /*! * \brief Removes this profile from the settings. */ void Profile::removeProfile() { m_settings->remove(profileKey()); } /*! * \brief Returns a string suitiable as a profile name. * Removes all dots and replaces them with hyphens. */ QString Profile::cleanName(const QString &name) { QString newName = name; return newName.replace(QLatin1Char('.'), QLatin1Char('-')); } QString Profile::profileKey() const { return Internal::StringConstants::profilesSettingsPrefix() + m_name; } QString Profile::baseProfileKey() { return Internal::StringConstants::baseProfileProperty(); } void Profile::checkBaseProfileExistence(const Profile &baseProfile) const { if (!baseProfile.exists()) throw ErrorInfo(Internal::Tr::tr("Profile \"%1\" has a non-existent base profile \"%2\".").arg( name(), baseProfile.name())); } QVariant Profile::localValue(const QString &key) const { QVariant val = m_values.value(key); if (!val.isValid()) val = m_settings->value(fullyQualifiedKey(key), Settings::allScopes()); return val; } QString Profile::fullyQualifiedKey(const QString &key) const { return profileKey() + QLatin1Char('.') + key; } QVariant Profile::possiblyInheritedValue(const QString &key, const QVariant &defaultValue, QStringList profileChain) const { extendAndCheckProfileChain(profileChain); QVariant v = localValue(key); if (v.isValid()) return v; const QString baseProfileName = baseProfile(); if (baseProfileName.isEmpty()) return defaultValue; Profile parentProfile(baseProfileName, m_settings, m_profiles); checkBaseProfileExistence(parentProfile); return parentProfile.possiblyInheritedValue(key, defaultValue, profileChain); } QStringList Profile::allKeysInternal(Profile::KeySelection selection, QStringList profileChain) const { extendAndCheckProfileChain(profileChain); QStringList keys = m_values.keys(); if (keys.empty()) keys = m_settings->allKeysWithPrefix(profileKey(), Settings::allScopes()); if (selection == KeySelectionNonRecursive) return keys; const QString baseProfileName = baseProfile(); if (baseProfileName.isEmpty()) return keys; Profile parentProfile(baseProfileName, m_settings, m_profiles); checkBaseProfileExistence(parentProfile); keys += parentProfile.allKeysInternal(KeySelectionRecursive, profileChain); keys.removeDuplicates(); keys.removeOne(baseProfileKey()); keys.sort(); return keys; } void Profile::extendAndCheckProfileChain(QStringList &chain) const { chain << m_name; if (Q_UNLIKELY(chain.count(m_name) > 1)) { throw ErrorInfo(Internal::Tr::tr("Circular profile inheritance. Cycle is '%1'.") .arg(chain.join(QLatin1String(" -> ")))); } } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/settingsmodel.h0000644000175100001660000000705014776170045021620 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SETTINGSMODEL_H #define QBS_SETTINGSMODEL_H #include #include #include #include #include namespace qbs { class QBS_EXPORT SettingsModel : public QAbstractItemModel { Q_OBJECT public: SettingsModel(const QString &settingsDir, Settings::Scope scope, QObject *parent = nullptr); ~SettingsModel() override; int keyColumn() const { return 0; } int valueColumn() const { return 1; } bool hasUnsavedChanges() const; void setEditable(bool isEditable); void setAdditionalProperties(const QVariantMap &properties); // Flat map. void reload(); void save(); void updateSettingsDir(const QString &settingsDir); void addNewKey(const QModelIndex &parent); void removeKey(const QModelIndex &index); Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; private: class SettingsModelPrivate; const std::unique_ptr d; }; } // namespace qbs #endif // QBS_SETTINGSMODEL_H qbs-src-2.6.1/src/lib/corelib/tools/settings.cpp0000644000175100001660000002103414776170045021130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "settings.h" #include "error.h" #include "profile.h" #include "settingscreator.h" #include #include #include #include #include namespace qbs { using namespace Internal; QString Settings::defaultSystemSettingsBaseDir() { switch (HostOsInfo::hostOs()) { case HostOsInfo::HostOsWindows: { const char key[] = "ALLUSERSAPPDATA"; if (qEnvironmentVariableIsSet(key)) return QLatin1String(key); return QStringLiteral("C:/ProgramData"); } case HostOsInfo::HostOsMacos: return QStringLiteral("/Library/Application Support"); case HostOsInfo::HostOsLinux: case HostOsInfo::HostOsOtherUnix: return QStringLiteral("/etc/xdg"); default: return {}; } } static QString systemSettingsBaseDir() { #ifdef QBS_ENABLE_UNIT_TESTS const char key[] = "QBS_AUTOTEST_SYSTEM_SETTINGS_DIR"; if (qEnvironmentVariableIsSet(key)) return QLatin1String(qgetenv(key)); #endif #ifdef QBS_SYSTEM_SETTINGS_DIR return QLatin1String(QBS_SYSTEM_SETTINGS_DIR); #else return Settings::defaultSystemSettingsBaseDir() + QStringLiteral("/qbs"); #endif } Settings::Settings(const QString &baseDir) : Settings(baseDir, systemSettingsBaseDir()) { } Settings::Settings(const QString &baseDir, const QString &systemBaseDir) : m_settings(SettingsCreator(baseDir).getQSettings()), m_systemSettings(std::make_unique(systemBaseDir + QStringLiteral("/qbs.conf"), QSettings::IniFormat)), m_baseDir(baseDir) { // Actual qbs settings are stored transparently within a group, because QSettings // can see non-qbs fallback settings e.g. from QtProject that we're not interested in. m_settings->beginGroup(QStringLiteral("org/qt-project/qbs")); } Settings::~Settings() = default; QVariant Settings::value(const QString &key, Scopes scopes, const QVariant &defaultValue) const { QVariant userValue; if (scopes & UserScope) userValue = m_settings->value(internalRepresentation(key)); QVariant systemValue; if (scopes & SystemScope) systemValue = m_systemSettings->value(internalRepresentation(key)); if (!userValue.isValid()) { if (systemValue.isValid()) return systemValue; return defaultValue; } if (!systemValue.isValid()) return userValue; if (static_cast(userValue.userType()) == QMetaType::QStringList) return userValue.toStringList() + systemValue.toStringList(); if (static_cast(userValue.userType()) == QMetaType::QVariantList) return userValue.toList() + systemValue.toList(); return userValue; } QStringList Settings::allKeys(Scopes scopes) const { QStringList keys; if (scopes & UserScope) keys = m_settings->allKeys(); if (scopes & SystemScope) keys += m_systemSettings->allKeys(); fixupKeys(keys); return keys; } QStringList Settings::directChildren(const QString &parentGroup, Scopes scopes) const { auto helper = [this, &parentGroup](const Scope scope) { QSettings * const settings = settingsForScope(scope); settings->beginGroup(internalRepresentation(parentGroup)); QStringList children = settings->childGroups(); children << settings->childKeys(); settings->endGroup(); return children; }; QStringList children; if (scopes & UserScope) children += helper(UserScope); if (scopes & SystemScope) children += helper(SystemScope); fixupKeys(children); return children; } QStringList Settings::allKeysWithPrefix(const QString &group, Scopes scopes) const { QStringList keys; if (scopes & UserScope) { m_settings->beginGroup(internalRepresentation(group)); keys = m_settings->allKeys(); m_settings->endGroup(); } if (scopes & SystemScope) { m_systemSettings->beginGroup(internalRepresentation(group)); keys += m_systemSettings->allKeys(); m_systemSettings->endGroup(); } fixupKeys(keys); return keys; } void Settings::setValue(const QString &key, const QVariant &value) { if (key.startsWith(StringConstants::profilesSettingsPrefix() + Profile::fallbackName())) { throw ErrorInfo(Tr::tr("Invalid use of special profile name '%1'.") .arg(Profile::fallbackName())); } targetForWriting()->setValue(internalRepresentation(key), value); checkForWriteError(); } void Settings::remove(const QString &key) { targetForWriting()->remove(internalRepresentation(key)); checkForWriteError(); } void Settings::clear() { targetForWriting()->clear(); checkForWriteError(); } void Settings::sync() { targetForWriting()->sync(); } QString Settings::defaultProfile() const { return value(QStringLiteral("defaultProfile"), allScopes()).toString(); } QStringList Settings::profiles() const { QStringList result; if (m_scopeForWriting == UserScope) { m_settings->beginGroup(StringConstants::profilesSettingsKey()); result = m_settings->childGroups(); m_settings->endGroup(); } m_systemSettings->beginGroup(StringConstants::profilesSettingsKey()); result += m_systemSettings->childGroups(); m_systemSettings->endGroup(); result.removeDuplicates(); return result; } QString Settings::fileName() const { return targetForWriting()->fileName(); } QString Settings::internalRepresentation(const QString &externalKey) const { QString internalKey = externalKey; return internalKey.replace(QLatin1Char('.'), QLatin1Char('/')); } QString Settings::externalRepresentation(const QString &internalKey) const { QString externalKey = internalKey; return externalKey.replace(QLatin1Char('/'), QLatin1Char('.')); } void Settings::fixupKeys(QStringList &keys) const { keys.sort(); keys.removeDuplicates(); for (auto &key : keys) key = externalRepresentation(key); } QSettings *Settings::settingsForScope(Settings::Scope scope) const { return scope == UserScope ? m_settings.get() : m_systemSettings.get(); } QSettings *Settings::targetForWriting() const { return settingsForScope(m_scopeForWriting); } void Settings::checkForWriteError() { if (m_scopeForWriting == SystemScope && m_systemSettings->status() == QSettings::NoError) { sync(); if (m_systemSettings->status() == QSettings::AccessError) throw ErrorInfo(Tr::tr("Failure writing system settings file '%1': " "You do not have permission to write to that location.") .arg(fileName())); } } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/vsenvironmentdetector.h0000644000175100001660000000564614776170045023417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_VSENVIRONMENTDETECTOR_H #define QBS_VSENVIRONMENTDETECTOR_H #include "qbs_export.h" #include "msvcinfo.h" #include QT_BEGIN_NAMESPACE class QIODevice; QT_END_NAMESPACE namespace qbs { namespace Internal { class MSVC; class QBS_EXPORT VsEnvironmentDetector { public: explicit VsEnvironmentDetector(QString vcvarsallPath = {}); bool start(MSVC *msvc); bool start(std::vector msvcs); QString errorString() const { return m_errorString; } private: QString findVcVarsAllBat(const MSVC &msvc, std::vector &searchedPaths) const; bool startDetection(const std::vector &compatibleMSVCs); void writeBatchFile(QIODevice *device, const QString &vcvarsallbat, const std::vector &msvcs) const; void parseBatOutput(const QByteArray &output, std::vector msvcs); const QString m_windowsSystemDirPath; const QString m_vcvarsallPath; const QString m_vcVariablesVersion; QString m_errorString; }; } // namespace Internal } // namespace qbs #endif // QBS_VSENVIRONMENTDETECTOR_H qbs-src-2.6.1/src/lib/corelib/tools/qbsprocess.cpp0000644000175100001660000001315014776170045021454 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qbsprocess.h" #include "launcherinterface.h" #include "launchersocket.h" #include "qbsassert.h" #include #include #include namespace qbs { namespace Internal { QbsProcess::QbsProcess(QObject *parent) : QObject(parent) { connect(LauncherInterface::socket(), &LauncherSocket::ready, this, &QbsProcess::handleSocketReady); connect(LauncherInterface::socket(), &LauncherSocket::errorOccurred, this, &QbsProcess::handleSocketError); connect(LauncherInterface::socket(), &LauncherSocket::packetArrived, this, &QbsProcess::handlePacket); } void QbsProcess::start(const QString &command, const QStringList &arguments) { if (m_socketError) { m_error = QProcess::FailedToStart; emit errorOccurred(m_error); return; } m_command = command; m_arguments = arguments; m_state = QProcess::Starting; if (LauncherInterface::socket()->isReady()) doStart(); } void QbsProcess::doStart() { m_state = QProcess::Running; StartProcessPacket p(token()); p.command = m_command; p.arguments = m_arguments; p.env = m_environment.toStringList(); p.workingDir = m_workingDirectory; sendPacket(p); } void QbsProcess::cancel() { switch (m_state) { case QProcess::NotRunning: break; case QProcess::Starting: m_errorString = Tr::tr("Process canceled before it was started."); m_error = QProcess::FailedToStart; m_state = QProcess::NotRunning; emit errorOccurred(m_error); break; case QProcess::Running: sendPacket(StopProcessPacket(token())); break; } } QByteArray QbsProcess::readAllStandardOutput() { return readAndClear(m_stdout); } QByteArray QbsProcess::readAllStandardError() { return readAndClear(m_stderr); } void QbsProcess::sendPacket(const LauncherPacket &packet) { LauncherInterface::socket()->sendData(packet.serialize()); } QByteArray QbsProcess::readAndClear(QByteArray &data) { QByteArray tmp = data; data.clear(); return tmp; } void QbsProcess::handlePacket(LauncherPacketType type, quintptr token, const QByteArray &payload) { if (token != this->token()) return; switch (type) { case LauncherPacketType::ProcessError: handleErrorPacket(payload); break; case LauncherPacketType::ProcessFinished: handleFinishedPacket(payload); break; default: QBS_ASSERT(false, break); } } void QbsProcess::handleSocketReady() { m_socketError = false; if (m_state == QProcess::Starting) doStart(); } void QbsProcess::handleSocketError(const QString &message) { m_socketError = true; m_errorString = Tr::tr("Internal socket error: %1").arg(message); if (m_state != QProcess::NotRunning) { m_state = QProcess::NotRunning; m_error = QProcess::FailedToStart; emit errorOccurred(m_error); } } void QbsProcess::handleErrorPacket(const QByteArray &packetData) { QBS_ASSERT(m_state != QProcess::NotRunning, return); const auto packet = LauncherPacket::extractPacket(token(), packetData); m_error = packet.error; m_errorString = packet.errorString; m_state = QProcess::NotRunning; emit errorOccurred(m_error); } void QbsProcess::handleFinishedPacket(const QByteArray &packetData) { QBS_ASSERT(m_state == QProcess::Running, return); m_state = QProcess::NotRunning; const auto packet = LauncherPacket::extractPacket(token(), packetData); m_exitCode = packet.exitCode; m_stdout = packet.stdOut; m_stderr = packet.stdErr; m_errorString = packet.errorString; emit finished(m_exitCode); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/stringconstants.h0000644000175100001660000003142314776170045022203 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_STRINGCONSTANTS_H #define QBS_STRINGCONSTANTS_H #include #define QBS_CONSTANT(type, name, value) \ static const type &name() { \ static const type var{QLatin1String(value)}; \ return var; \ } #define QBS_STRING_CONSTANT(name, value) QBS_CONSTANT(QString, name, value) #define QBS_STRINGLIST_CONSTANT(name, value) QBS_CONSTANT(QStringList, name, value) namespace qbs { namespace Internal { class StringConstants { public: static const QString &cppModule() { return cpp(); } static const QString &qbsModule() { return qbs(); } QBS_STRING_CONSTANT(aggregateProperty, "aggregate") QBS_STRING_CONSTANT(additionalProductTypesProperty, "additionalProductTypes") QBS_STRING_CONSTANT(allowedValuesProperty, "allowedValues") QBS_STRING_CONSTANT(alwaysUpdatedProperty, "alwaysUpdated") QBS_STRING_CONSTANT(alwaysRunProperty, "alwaysRun") QBS_STRING_CONSTANT(artifactsProperty, "artifacts") QBS_STRING_CONSTANT(auxiliaryInputsProperty, "auxiliaryInputs") QBS_STRING_CONSTANT(auxiliaryInputsFromDependenciesProperty, "auxiliaryInputsFromDependencies") QBS_STRING_CONSTANT(baseNameProperty, "baseName") QBS_STRING_CONSTANT(baseProfileProperty, "baseProfile") QBS_STRING_CONSTANT(buildDirectoryProperty, "buildDirectory") QBS_STRING_CONSTANT(buildDirectoryKey, "build-directory") QBS_STRING_CONSTANT(builtByDefaultProperty, "builtByDefault") QBS_STRING_CONSTANT(classNameProperty, "className") QBS_STRING_CONSTANT(completeBaseNameProperty, "completeBaseName") QBS_STRING_CONSTANT(conditionProperty, "condition") QBS_STRING_CONSTANT(configurationNameProperty, "configurationName") QBS_STRING_CONSTANT(configureProperty, "configure") QBS_STRING_CONSTANT(consoleApplicationProperty, "consoleApplication") QBS_STRING_CONSTANT(dependenciesProperty, "dependencies") QBS_STRING_CONSTANT(descriptionProperty, "description") QBS_STRING_CONSTANT(destinationDirProperty, "destinationDirectory") QBS_STRING_CONSTANT(excludeFilesProperty, "excludeFiles") QBS_STRING_CONSTANT(excludedAuxiliaryInputsProperty, "excludedAuxiliaryInputs") QBS_STRING_CONSTANT(excludedInputsProperty, "excludedInputs") static const QString &explicitlyDependsOnProperty() { return explicitlyDependsOn(); } static const QString &explicitlyDependsOnFromDependenciesProperty() { return explicitlyDependsOnFromDependencies(); } QBS_STRING_CONSTANT(enableFallbackProperty, "enableFallback") static const QString &fileNameProperty() { return fileName(); } static const QString &filePathProperty() { return filePath(); } static const QString &filePathVar() { return filePath(); } QBS_STRING_CONSTANT(filePathKey, "file-path") QBS_STRING_CONSTANT(fileTagsFilterProperty, "fileTagsFilter") QBS_STRING_CONSTANT(fileTagsProperty, "fileTags") QBS_STRING_CONSTANT(filesProperty, "files") QBS_STRING_CONSTANT(filesAreTargetsProperty, "filesAreTargets") QBS_STRING_CONSTANT(foundProperty, "found") QBS_STRING_CONSTANT(fullDisplayNameKey, "full-display-name") QBS_STRING_CONSTANT(imports, "imports") static const QString &importsDir() { return imports(); } static const QString &importsProperty() { return imports(); } QBS_STRING_CONSTANT(inheritPropertiesProperty, "inheritProperties") static const QString &inputsProperty() { return inputs(); } QBS_STRING_CONSTANT(inputsFromDependenciesProperty, "inputsFromDependencies") static const QString &installProperty() { return install(); } QBS_STRING_CONSTANT(installRootProperty, "installRoot") QBS_STRING_CONSTANT(installPrefixProperty, "installPrefix") QBS_STRING_CONSTANT(installDirProperty, "installDir") QBS_STRING_CONSTANT(installSourceBaseProperty, "installSourceBase") QBS_STRING_CONSTANT(isEnabledKey, "is-enabled") QBS_STRING_CONSTANT(isEagerProperty, "isEager") QBS_STRING_CONSTANT(jobCountProperty, "jobCount") QBS_STRING_CONSTANT(jobPoolProperty, "jobPool") QBS_STRING_CONSTANT(lengthProperty, "length") QBS_STRING_CONSTANT(limitToSubProjectProperty, "limitToSubProject") QBS_STRING_CONSTANT(locationKey, "location") QBS_STRING_CONSTANT(messageKey, "message") QBS_STRING_CONSTANT(minimumQbsVersionProperty, "minimumQbsVersion") QBS_STRING_CONSTANT(moduleVar, "module") QBS_STRING_CONSTANT(moduleNameProperty, "moduleName") QBS_STRING_CONSTANT(modulePropertiesKey, "module-properties") QBS_STRING_CONSTANT(moduleProviders, "moduleProviders") QBS_STRING_CONSTANT(multiplexByQbsPropertiesProperty, "multiplexByQbsProperties") QBS_STRING_CONSTANT(multiplexConfigurationIdProperty, "multiplexConfigurationId") QBS_STRING_CONSTANT(multiplexConfigurationIdsProperty, "multiplexConfigurationIds") QBS_STRING_CONSTANT(multiplexProperty, "multiplex") QBS_STRING_CONSTANT(multiplexedProperty, "multiplexed") QBS_STRING_CONSTANT(multiplexedTypeProperty, "multiplexedType") QBS_STRING_CONSTANT(nameProperty, "name") QBS_STRING_CONSTANT(outputArtifactsProperty, "outputArtifacts") QBS_STRING_CONSTANT(outputFileTagsProperty, "outputFileTags") QBS_STRING_CONSTANT(overrideTagsProperty, "overrideTags") QBS_STRING_CONSTANT(overrideListPropertiesProperty, "overrideListProperties") QBS_STRING_CONSTANT(parametersProperty, "parameters") static const QString &pathProperty() { return path(); } QBS_STRING_CONSTANT(patternsProperty, "patterns") QBS_STRING_CONSTANT(prefixMappingProperty, "prefixMapping") QBS_STRING_CONSTANT(prefixProperty, "prefix") QBS_STRING_CONSTANT(prepareProperty, "prepare") QBS_STRING_CONSTANT(presentProperty, "present") QBS_STRING_CONSTANT(priorityProperty, "priority") QBS_STRING_CONSTANT(profileProperty, "profile") static const QString &profilesProperty() { return profiles(); } QBS_STRING_CONSTANT(productTypesProperty, "productTypes") QBS_STRING_CONSTANT(productsKey, "products") QBS_STRING_CONSTANT(qbsModuleProviders, "qbsModuleProviders") QBS_STRING_CONSTANT(qbsSearchPathsProperty, "qbsSearchPaths") QBS_STRING_CONSTANT(referencesProperty, "references") QBS_STRING_CONSTANT(recursiveProperty, "recursive") QBS_STRING_CONSTANT(requiredProperty, "required") QBS_STRING_CONSTANT(requiresInputsProperty, "requiresInputs") QBS_STRING_CONSTANT(removalVersionProperty, "removalVersion") QBS_STRING_CONSTANT(scanProperty, "scan") QBS_STRING_CONSTANT(searchPathsProperty, "searchPaths") QBS_STRING_CONSTANT(setupBuildEnvironmentProperty, "setupBuildEnvironment") QBS_STRING_CONSTANT(setupRunEnvironmentProperty, "setupRunEnvironment") QBS_STRING_CONSTANT(shadowProductPrefix, "__shadow__") QBS_STRING_CONSTANT(sourceCodeProperty, "sourceCode") QBS_STRING_CONSTANT(sourceDirectoryProperty, "sourceDirectory") QBS_STRING_CONSTANT(submodulesProperty, "submodules") QBS_STRING_CONSTANT(targetNameProperty, "targetName") static const QString &typeProperty() { return type(); } QBS_STRING_CONSTANT(type, "type") QBS_STRING_CONSTANT(validateProperty, "validate") QBS_STRING_CONSTANT(versionProperty, "version") QBS_STRING_CONSTANT(versionAtLeastProperty, "versionAtLeast") QBS_STRING_CONSTANT(versionBelowProperty, "versionBelow") QBS_STRING_CONSTANT(importScopeNamePropertyInternal, "_qbs_importScopeName") QBS_STRING_CONSTANT(modulePropertyInternal, "__module") QBS_STRING_CONSTANT(dataPropertyInternal, "_qbs_data") QBS_STRING_CONSTANT(qbsSourceDirPropertyInternal, "_qbs_sourceDir") static const char *qbsProcEnvVarInternal() { return "_qbs_procenv"; } static const QString &projectPrefix() { return project(); } static const QString &productValue() { return product(); } QBS_STRING_CONSTANT(projectsOverridePrefix, "projects.") QBS_STRING_CONSTANT(productsOverridePrefix, "products.") QBS_STRING_CONSTANT(baseVar, "base") static const QString &explicitlyDependsOnVar() { return explicitlyDependsOn(); } QBS_STRING_CONSTANT(inputVar, "input") static const QString &inputsVar() { return inputs(); } QBS_STRING_CONSTANT(originalVar, "original") QBS_STRING_CONSTANT(outerVar, "outer") QBS_STRING_CONSTANT(outputVar, "output") QBS_STRING_CONSTANT(outputsVar, "outputs") static const QString &productVar() { return product(); } static const QString &projectVar() { return project(); } static const QString &filePathGlobalVar() { return filePath(); } static const QString &pathGlobalVar() { return path(); } static const QString &pathType() { return path(); } static const QString &fileInfoFileName() { return fileName(); } static const QString &fileInfoPath() { return path(); } static const QString &androidInstallCommand() { return install(); } static const QString &simctlInstallCommand() { return install(); } static const QString &profilesSettingsKey() { return profiles(); } QBS_STRING_CONSTANT(emptyArrayValue, "[]") QBS_STRING_CONSTANT(falseValue, "false") QBS_STRING_CONSTANT(trueValue, "true") QBS_STRING_CONSTANT(undefinedValue, "undefined") QBS_STRING_CONSTANT(javaScriptCommandType, "JavaScriptCommand") QBS_STRING_CONSTANT(commandType, "Command") QBS_STRING_CONSTANT(pathEnvVar, "PATH") QBS_STRING_CONSTANT(dot, ".") QBS_STRING_CONSTANT(dotDot, "..") QBS_STRING_CONSTANT(slashDotDot, "/..") QBS_STRING_CONSTANT(star, "*") QBS_STRING_CONSTANT(tildeSlash, "~/") QBS_STRINGLIST_CONSTANT(qbsFileWildcards, "*.qbs") QBS_STRINGLIST_CONSTANT(jsFileWildcards, "*.js") static const QString &cppLang() { return cpp(); } QBS_STRING_CONSTANT(xcode, "xcode") QBS_STRING_CONSTANT(aarch64Arch, "aarch64") QBS_STRING_CONSTANT(amd64Arch, "amd64") QBS_STRING_CONSTANT(armArch, "arm") QBS_STRING_CONSTANT(arm64Arch, "arm64") QBS_STRING_CONSTANT(armv7Arch, "armv7") QBS_STRING_CONSTANT(i386Arch, "i386") QBS_STRING_CONSTANT(i586Arch, "i586") QBS_STRING_CONSTANT(mipsArch, "mips") QBS_STRING_CONSTANT(mips64Arch, "mips64") QBS_STRING_CONSTANT(powerPcArch, "powerpc") QBS_STRING_CONSTANT(ppcArch, "ppc") QBS_STRING_CONSTANT(ppc64Arch, "ppc64") QBS_STRING_CONSTANT(x86Arch, "x86") QBS_STRING_CONSTANT(x86_64Arch, "x86_64") QBS_STRING_CONSTANT(profilesSettingsPrefix, "profiles.") private: QBS_STRING_CONSTANT(cpp, "cpp") QBS_STRING_CONSTANT(explicitlyDependsOn, "explicitlyDependsOn") QBS_STRING_CONSTANT(explicitlyDependsOnFromDependencies, "explicitlyDependsOnFromDependencies") QBS_STRING_CONSTANT(fileName, "fileName") QBS_STRING_CONSTANT(filePath, "filePath") QBS_STRING_CONSTANT(inputs, "inputs") QBS_STRING_CONSTANT(install, "install") QBS_STRING_CONSTANT(path, "path") QBS_STRING_CONSTANT(product, "product") QBS_STRING_CONSTANT(profiles, "profiles") QBS_STRING_CONSTANT(project, "project") QBS_STRING_CONSTANT(qbs, "qbs") }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/tools/processresult.cpp0000644000175100001660000001135314776170045022210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "processresult.h" #include "processresult_p.h" #include #include /*! * \class SetupProjectParameters * \brief The \c ProcessResult class describes a finished qbs process command. */ namespace qbs { ProcessResult::ProcessResult() : d(new Internal::ProcessResultPrivate) { } ProcessResult::ProcessResult(const ProcessResult &other) = default; ProcessResult &ProcessResult::operator=(const ProcessResult &other) = default; ProcessResult::~ProcessResult() = default; /*! * \brief Returns true iff the command finished successfully. */ bool ProcessResult::success() const { return d->success; } /*! * \brief Returns the file path of the executable that was run. */ QString ProcessResult::executableFilePath() const { return d->executableFilePath; } /*! * \brief Returns the command-line arguments with which the command was invoked. */ QStringList ProcessResult::arguments() const { return d->arguments; } /*! * \brief Returns the working directory of the invoked command. */ QString ProcessResult::workingDirectory() const { return d->workingDirectory; } /*! * \brief Returns the error status of the process. If no error occurred, the value * is \c Process::UnknownError. */ QProcess::ProcessError ProcessResult::error() const { return d->error; } /*! * \brief Returns the exit code of the command. */ int ProcessResult::exitCode() const { return d->exitCode; } /*! * \brief Returns the data the command wrote to the standard output channel. */ QStringList ProcessResult::stdOut() const { return d->stdOut; } /*! * \brief Returns the data the command wrote to the standard error channel. */ QStringList ProcessResult::stdErr() const { return d->stdErr; } static QJsonValue processErrorToJson(QProcess::ProcessError error) { switch (error) { case QProcess::FailedToStart: return QLatin1String("failed-to-start"); case QProcess::Crashed: return QLatin1String("crashed"); case QProcess::Timedout: return QLatin1String("timed-out"); case QProcess::WriteError: return QLatin1String("write-error"); case QProcess::ReadError: return QLatin1String("read-error"); case QProcess::UnknownError: return QStringLiteral("unknown-error"); } return {}; // For dumb compilers. } QJsonObject qbs::ProcessResult::toJson() const { return QJsonObject{ {QStringLiteral("success"), success()}, {QStringLiteral("executable-file-path"), executableFilePath()}, {QStringLiteral("arguments"), QJsonArray::fromStringList(arguments())}, {QStringLiteral("working-directory"), workingDirectory()}, {QStringLiteral("error"), processErrorToJson(error())}, {QStringLiteral("exit-code"), exitCode()}, {QStringLiteral("stdout"), QJsonArray::fromStringList(stdOut())}, {QStringLiteral("stderr"), QJsonArray::fromStringList(stdErr())} }; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/deprecationwarningmode.h0000644000175100001660000000465314776170045023475 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_DEPRECATIONWARNINGMODE_H #define QBS_DEPRECATIONWARNINGMODE_H #include "qbs_export.h" #include namespace qbs { enum class DeprecationWarningMode { Error, On, BeforeRemoval, Off, Sentinel = Off }; QBS_EXPORT DeprecationWarningMode defaultDeprecationWarningMode(); QBS_EXPORT QString deprecationWarningModeName(DeprecationWarningMode mode); QBS_EXPORT DeprecationWarningMode deprecationWarningModeFromName(const QString &name); QBS_EXPORT QStringList allDeprecationWarningModeStrings(); } // namespace qbs #endif // QBS_DEPRECATIONWARNINGMODE_H qbs-src-2.6.1/src/lib/corelib/tools/filetime.h0000644000175100001660000000703414776170045020537 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FILETIME_H #define QBS_FILETIME_H #include "persistence.h" #include #include #if defined(Q_OS_UNIX) #include #endif // Q_OS_UNIX namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT FileTime { public: #if defined(Q_OS_UNIX) using InternalType = timespec; #elif defined(Q_OS_WIN) using InternalType = quint64; #else # error unknown platform #endif FileTime(); FileTime(const InternalType &ft); bool operator<(const FileTime &rhs) const { return compare(rhs) < 0; } bool operator>(const FileTime &rhs) const { return compare(rhs) > 0; } bool operator<=(const FileTime &rhs) const { return !operator>(rhs); } bool operator>=(const FileTime &rhs) const { return !operator<(rhs); } bool operator==(const FileTime &rhs) const { return compare(rhs) == 0; } bool operator!= (const FileTime &rhs) const { return !operator==(rhs); } int compare(const FileTime &other) const; void clear(); bool isValid() const; QString toString() const; static FileTime currentTime(); static FileTime oldestTime(); double asDouble() const; template void completeSerializationOp(PersistentPool &pool) { #if !defined(Q_OS_WIN) pool.serializationOp(m_fileTime.tv_sec, m_fileTime.tv_nsec); #else pool.serializationOp(m_fileTime); #endif } private: InternalType m_fileTime{}; }; } // namespace Internal } // namespace qbs QT_BEGIN_NAMESPACE inline QDebug operator<<(QDebug dbg, const qbs::Internal::FileTime &t) { dbg.nospace() << t.toString(); return dbg.space(); } QT_END_NAMESPACE #endif // QBS_FILETIME_H qbs-src-2.6.1/src/lib/corelib/tools/stringutils.h0000644000175100001660000000671314776170045021333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_STRINGUTILS_H #define QBS_STRINGUTILS_H #include #include #include #include namespace qbs { namespace Internal { template typename C::value_type join(const C &container, const typename C::value_type &separator) { typename C::value_type out; if (!container.empty()) { auto it = container.cbegin(); auto end = container.cend(); out.append(*it++); for (; it != end; ++it) { out.append(separator); out.append(*it); } } return out; } template typename C::value_type join(const C &container, typename C::value_type::value_type separator) { typename C::value_type s; s.push_back(separator); return join(container, s); } static inline std::string trimmed(const std::string &s) { // trim from start static const auto ltrim = [](std::string &s) -> std::string & { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c){ return !std::isspace(c); })); return s; }; // trim from end static const auto rtrim = [](std::string &s) -> std::string & { s.erase(std::find_if(s.rbegin(), s.rend(), [](char c){ return !std::isspace(c); }).base(), s.end()); return s; }; // trim from both ends static const auto trim = [](std::string &s) -> std::string & { return ltrim(rtrim(s)); }; std::string copy = s; return trim(copy); } } // namespace Internal } // namespace qbs #ifdef Q_DECLARE_METATYPE Q_DECLARE_METATYPE(std::string) #endif #endif // QBS_STRINGUTILS_H qbs-src-2.6.1/src/lib/corelib/tools/jsliterals.cpp0000644000175100001660000000763414776170045021456 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsliterals.h" #include #include #include namespace qbs { QString toJSLiteral(const bool b) { return b ? Internal::StringConstants::trueValue() : Internal::StringConstants::falseValue(); } QString toJSLiteral(const QString &str) { QString js = str; js.replace(QRegularExpression(QLatin1String("([\\\\\"])")), QLatin1String("\\\\1")); js.prepend(QLatin1Char('"')); js.append(QLatin1Char('"')); return js; } QString toJSLiteral(const QStringList &strs) { QString js = QStringLiteral("["); for (int i = 0; i < strs.size(); ++i) { if (i != 0) js.append(QLatin1String(", ")); js.append(toJSLiteral(strs.at(i))); } js.append(QLatin1Char(']')); return js; } QString toJSLiteral(const QVariant &val) { if (!val.isValid()) return Internal::StringConstants::undefinedValue(); if (val.userType() == QMetaType::QVariantList || val.userType() == QMetaType::QStringList) { QString res; const auto list = val.toList(); for (const QVariant &child : list) { if (res.length()) res.append(QLatin1String(", ")); res.append(toJSLiteral(child)); } res.prepend(QLatin1Char('[')); res.append(QLatin1Char(']')); return res; } if (val.userType() == QMetaType::QVariantMap) { const QVariantMap &vm = val.toMap(); QString str = QStringLiteral("{"); for (QVariantMap::const_iterator it = vm.begin(); it != vm.end(); ++it) { if (it != vm.begin()) str += QLatin1Char(','); str += toJSLiteral(it.key()) + QLatin1Char(':') + toJSLiteral(it.value()); } str += QLatin1Char('}'); return str; } if (val.userType() == QMetaType::Bool) return toJSLiteral(val.toBool()); if (qVariantCanConvert(val, QMetaType::QString)) return toJSLiteral(val.toString()); return QStringLiteral("Unconvertible type %1").arg(QLatin1String(val.typeName())); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/msvcinfo.h0000644000175100001660000001101614776170045020560 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_MSVCINFO_H #define QBS_MSVCINFO_H #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class Logger; struct MSVCArchInfo { QString arch; QString binPath; }; /** * Represents one MSVC installation for one specific target architecture. * There are potentially multiple MSVCs in one Visual Studio installation. */ class MSVC { public: enum CompilerLanguage { CLanguage = 0, CPlusPlusLanguage = 1 }; QString version; Version internalVsVersion; Version compilerVersion; QString vsInstallPath; QString vcInstallPath; QString binPath; QString pathPrefix; QString architecture; QString sdkVersion; QProcessEnvironment environment; MSVC() = default; MSVC(const QString &clPath, QString arch, QString sdkVersion = {}): architecture(std::move(arch)), sdkVersion(std::move(sdkVersion)) { QDir parentDir = QFileInfo(clPath).dir(); binPath = parentDir.absolutePath(); QString parentDirName = parentDir.dirName().toLower(); if (parentDirName != QLatin1String("bin")) parentDir.cdUp(); vcInstallPath = parentDir.path(); } QBS_EXPORT void init(); QBS_EXPORT static QString architectureFromClPath(const QString &clPath); QBS_EXPORT static QString vcVariablesVersionFromBinPath(const QString &binPath); QBS_EXPORT static QString canonicalArchitecture(const QString &arch); QBS_EXPORT static std::pair getHostTargetArchPair(const QString &arch); QBS_EXPORT QString binPathForArchitecture(const QString &arch) const; QBS_EXPORT QString clPathForArchitecture(const QString &arch) const; QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath, CompilerLanguage language) const; QBS_EXPORT static std::vector findSupportedArchitectures(const MSVC &msvc); QBS_EXPORT QVariantMap toVariantMap() const; QBS_EXPORT static std::vector installedCompilers(Logger &logger); private: void determineCompilerVersion(); }; class WinSDK : public MSVC { public: bool isDefault = false; WinSDK() { pathPrefix = QStringLiteral("bin"); } }; struct QBS_EXPORT MSVCInstallInfo { QString version; QString installDir; QString findVcvarsallBat() const; static std::vector installedMSVCs(Logger &logger); }; } // namespace Internal } // namespace qbs #endif // QBS_MSVCINFO_H qbs-src-2.6.1/src/lib/corelib/tools/processutils.cpp0000644000175100001660000001110214776170045022022 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "processutils.h" #if defined(Q_OS_WIN) # define PSAPI_VERSION 1 // To use GetModuleFileNameEx from Psapi.lib on all Win versions. # include # include #elif defined(Q_OS_DARWIN) # include #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD) # include "fileinfo.h" # include # include #elif defined(Q_OS_BSD4) # include # include # include # include # if !defined(Q_OS_NETBSD) # include # endif #else # error Missing implementation of processNameByPid for this platform. #endif namespace qbs { namespace Internal { QString processNameByPid(qint64 pid) { #if defined(Q_OS_WIN) HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, DWORD(pid)); if (!hProcess) return {}; wchar_t buf[UNICODE_STRING_MAX_CHARS]; const DWORD length = GetModuleFileNameEx(hProcess, NULL, buf, sizeof(buf) / sizeof(wchar_t)); CloseHandle(hProcess); if (!length) return {}; QString name = QString::fromWCharArray(buf, length); int i = name.lastIndexOf(QLatin1Char('\\')); if (i >= 0) name.remove(0, i + 1); i = name.lastIndexOf(QLatin1Char('.')); if (i >= 0) name.truncate(i); return name; #elif defined(Q_OS_DARWIN) char name[1024]; proc_name(pid, name, sizeof(name) / sizeof(char)); return QString::fromUtf8(name); #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD) char exePath[64]; #ifdef PATH_MAX char buf[PATH_MAX]; #else char buf[4096]; #endif memset(buf, 0, sizeof(buf)); std::sprintf(exePath, "/proc/%lld/exe", pid); if (readlink(exePath, buf, sizeof(buf)) < 0) return {}; return FileInfo::fileName(QString::fromUtf8(buf)); #elif defined(Q_OS_BSD4) # if defined(Q_OS_NETBSD) struct kinfo_proc2 kp; int mib[6] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, (int)pid, sizeof(struct kinfo_proc2), 1 }; # elif defined(Q_OS_OPENBSD) struct kinfo_proc kp; int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid, sizeof(struct kinfo_proc), 1 }; # else struct kinfo_proc kp; int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid }; # endif size_t len = sizeof(kp); u_int mib_len = sizeof(mib)/sizeof(u_int); if (sysctl(mib, mib_len, &kp, &len, NULL, 0) < 0) return {}; # if defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) if (kp.p_pid != pid) return {}; QString name = QFile::decodeName(kp.p_comm); # else if (kp.ki_pid != pid) return {}; QString name = QFile::decodeName(kp.ki_comm); # endif return name; #else Q_UNUSED(pid); return {}; #endif } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/tools/version.h0000644000175100001660000001151514776170045020425 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_VERSION_H #define QBS_VERSION_H #include "qbs_export.h" #include #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { class Version { public: constexpr explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0, int buildNr = 0) : m_major(majorVersion), m_minor(minorVersion), m_patch(patchLevel), m_build(buildNr) { } constexpr bool isValid() const { return m_major || m_minor || m_patch || m_build; } constexpr int majorVersion() const { return m_major; } constexpr void setMajorVersion(int majorVersion) { m_major = majorVersion; } constexpr int minorVersion() const { return m_minor; } constexpr void setMinorVersion(int minorVersion) { m_minor = minorVersion;} constexpr int patchLevel() const { return m_patch; } constexpr void setPatchLevel(int patchLevel) { m_patch = patchLevel; } constexpr int buildNumber() const { return m_build; } constexpr void setBuildNumber(int nr) { m_build = nr; } static QBS_EXPORT Version fromString(const QString &versionString, bool buildNumberAllowed = false); QString QBS_EXPORT toString(const QChar &separator = QLatin1Char('.'), const QChar &buildSeparator = QLatin1Char('-')) const; private: int m_major; int m_minor; int m_patch; int m_build; }; class VersionRange { public: constexpr VersionRange() = default; constexpr VersionRange(const Version &minVersion, const Version &maxVersion) : minimum(minVersion), maximum(maxVersion) { } Version minimum; Version maximum; // exclusive VersionRange &narrowDown(const VersionRange &other); }; constexpr inline int compare(const Version &lhs, const Version &rhs) { if (lhs.majorVersion() < rhs.majorVersion()) return -1; if (lhs.majorVersion() > rhs.majorVersion()) return 1; if (lhs.minorVersion() < rhs.minorVersion()) return -1; if (lhs.minorVersion() > rhs.minorVersion()) return 1; if (lhs.patchLevel() < rhs.patchLevel()) return -1; if (lhs.patchLevel() > rhs.patchLevel()) return 1; if (lhs.buildNumber() < rhs.buildNumber()) return -1; if (lhs.buildNumber() > rhs.buildNumber()) return 1; return 0; } constexpr inline bool operator==(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) == 0; } constexpr inline bool operator!=(const Version &lhs, const Version &rhs) { return !operator==(lhs, rhs); } constexpr inline bool operator<(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) < 0; } constexpr inline bool operator>(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) > 0; } constexpr inline bool operator<=(const Version &lhs, const Version &rhs) { return !operator>(lhs, rhs); } constexpr inline bool operator>=(const Version &lhs, const Version &rhs) { return !operator<(lhs, rhs); } } // namespace qbs #endif // QBS_VERSION_H qbs-src-2.6.1/src/lib/corelib/tools/propagate_const.h0000644000175100001660000003466214776170045022140 0ustar runnerdocker/**************************************************************************** ** MIT License ** ** Copyright (C) 2022-2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** Author: Giuseppe D'Angelo ** ** This file is part of KDToolBox (https://github.com/KDAB/KDToolBox). ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal ** in the Software without restriction, including without limitation the rights ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ** copies of the Software, ** and to permit persons to whom the Software is ** furnished to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice (including the next paragraph) ** shall be included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ** LIABILITY, WHETHER IN AN ACTION OF ** CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ****************************************************************************/ #ifndef KDTOOLBOX_PROPAGATE_CONST #define KDTOOLBOX_PROPAGATE_CONST #include #include #include // Our SFINAE is too noisy and clang-format gets confused. // clang-format off namespace KDToolBox { template class propagate_const; namespace detail { // Type traits to detect propagate_const specializations template struct is_propagate_const : std::false_type { }; template struct is_propagate_const> : std::true_type { }; // Using SFINAE in a base class to constrain the conversion operators. // Otherwise, if we make them function templates and apply SFINAE directly on // them, we would not be able to do certain conversions (cf. // [over.ics.user/3]). template using propagate_const_element_type = std::remove_reference_t())>; // Const conversion. // NON-STANDARD: checks that `const T` is convertible, not `T`. // See https://wg21.link/lwg3812 template , std::is_convertible *> > > struct propagate_const_const_conversion_operator_base { }; template struct propagate_const_const_conversion_operator_base { constexpr operator const propagate_const_element_type *() const; }; // Non-const conversion template , std::is_convertible *> > > struct propagate_const_non_const_conversion_operator_base { }; template struct propagate_const_non_const_conversion_operator_base { constexpr operator propagate_const_element_type *(); }; template struct propagate_const_base : propagate_const_const_conversion_operator_base, propagate_const_non_const_conversion_operator_base {}; } // namespace detail /* TODO: This code could benefit from a C++20 overhaul: * concepts * three-way comparisons * explicit(bool) However we can't depend on C++20 yet... */ template class propagate_const : public detail::propagate_const_base { public: using element_type = detail::propagate_const_element_type; // Special member functions propagate_const() = default; propagate_const(propagate_const &&) = default; propagate_const &operator=(propagate_const &&) = default; propagate_const(const propagate_const &) = delete; propagate_const &operator=(const propagate_const &) = delete; ~propagate_const() = default; // Constructor from values template < typename U, std::enable_if_t< // This constructor is enabled if: std::conjunction_v< std::is_constructible, // 1) we can build a T from a U, std::negation>>, // 2) we are not making a // converting constructor, std::is_convertible // 3) and the conversion from U to T is implicit; >, bool> = true> /* implicit */ // then, this constructor is implicit too. propagate_const(U &&other) : m_t(std::forward(other)) { } template < typename U, std::enable_if_t< // This constructor is enabled if: std::conjunction_v< std::is_constructible, // 1) we can build a T from a U, std::negation>>, // 2) we are not making a // converting constructor, std::negation> // 3) and the conversion from U to T is // explicit; >, bool> = true> explicit // then, this constructor is explicit. propagate_const(U &&other) : m_t(std::forward(other)) { } // Constructors from other propagate_const (converting constructors) template , // 1) we can do the conversion, std::is_convertible // 2) and the conversion is implicit; >, bool> = true> /* implicit */ // then, this constructor is implicit. constexpr propagate_const(propagate_const &&other) : m_t(std::move(get_underlying(other))) { } template , // 1) we can do the conversion, std::negation> // 2) and the // conversion is // explicit; >, bool> = true> explicit // then, this constructor is explicit. constexpr propagate_const(propagate_const &&other) : m_t(std::move(get_underlying(other))) { } // Converting assignment template , // the conversion from U to T is implicit bool> = true> constexpr propagate_const &operator=(propagate_const &&other) { m_t = std::move(get_underlying(other)); return *this; } template , // 1) the conversion from U to T is implicit, std::negation>> // 2) and U is not a // propagate_const >, bool> = true> constexpr propagate_const &operator=(U &&other) { m_t = std::forward(other); return *this; } // Swap constexpr void swap(propagate_const &other) noexcept(std::is_nothrow_swappable_v) { using std::swap; swap(m_t, other.m_t); } // Const observers constexpr explicit operator bool() const { return static_cast(m_t); } constexpr const element_type *get() const { return get_impl(m_t); } constexpr const element_type &operator*() const { return *get(); } constexpr const element_type *operator->() const { return get(); } // Non-const observers constexpr element_type *get() { return get_impl(m_t); } constexpr element_type &operator*() { return *get(); } constexpr element_type *operator->() { return get(); } // Non-member utilities: extract the contained object template friend constexpr auto &get_underlying(propagate_const &p); template friend constexpr const auto &get_underlying(const propagate_const &p); private: // Implementation of get() that works with raw pointers and smart // pointers. Similar to std::to_address, but to_address is C++20, // and propagate_const spec does not match it. template static constexpr element_type *get_impl(U *u) { return u; } template static constexpr element_type *get_impl(U &u) { return u.get(); } template static constexpr const element_type *get_impl(const U *u) { return u; } template static constexpr const element_type *get_impl(const U &u) { return u.get(); } T m_t; }; // Swap template , bool> = true> constexpr void swap(propagate_const &lhs, propagate_const &rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } // Implementation of get_underlying template constexpr auto &get_underlying(propagate_const &p) { return p.m_t; } template constexpr const auto &get_underlying(const propagate_const &p) { return p.m_t; } // Implementation of the conversion operators template constexpr detail::propagate_const_const_conversion_operator_base ::operator const detail::propagate_const_element_type *() const { return static_cast *>(this)->get(); } template constexpr detail::propagate_const_non_const_conversion_operator_base ::operator detail::propagate_const_element_type *() { return static_cast *>(this)->get(); } // Comparisons. As per spec, they're free function templates. // Comparisons against nullptr. template constexpr bool operator==(const propagate_const &p, std::nullptr_t) { return get_underlying(p) == nullptr; } template constexpr bool operator!=(const propagate_const &p, std::nullptr_t) { return get_underlying(p) != nullptr; } template constexpr bool operator==(std::nullptr_t, const propagate_const &p) { return nullptr == get_underlying(p); } template constexpr bool operator!=(std::nullptr_t, const propagate_const &p) { return nullptr == get_underlying(p); } // Comparisons between propagate_const #define DEFINE_PROPAGATE_CONST_COMPARISON_OP(op) \ template \ constexpr bool operator op (const propagate_const &lhs, const propagate_const &rhs) \ { \ return get_underlying(lhs) op get_underlying(rhs); \ } \ DEFINE_PROPAGATE_CONST_COMPARISON_OP(==) DEFINE_PROPAGATE_CONST_COMPARISON_OP(!=) DEFINE_PROPAGATE_CONST_COMPARISON_OP(<) DEFINE_PROPAGATE_CONST_COMPARISON_OP(<=) DEFINE_PROPAGATE_CONST_COMPARISON_OP(>) DEFINE_PROPAGATE_CONST_COMPARISON_OP(>=) #undef DEFINE_PROPAGATE_CONST_COMPARISON_OP // Comparisons against other (smart) pointers #define DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(op) \ template \ constexpr bool operator op (const propagate_const &lhs, const U &rhs) \ { \ return get_underlying(lhs) op rhs; \ } \ template \ constexpr bool operator op (const T &lhs, const propagate_const &rhs) \ { \ return lhs op get_underlying(rhs); \ } \ DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(==) DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(!=) DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(<) DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(<=) DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(>) DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(>=) #undef DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP } // namespace KDToolBox // std::hash specialization namespace std { template struct hash> { constexpr size_t operator()(const KDToolBox::propagate_const &t) const noexcept(noexcept(hash{}(get_underlying(t)))) { return hash{}(get_underlying(t)); } }; #define DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(COMP) \ template \ struct COMP> \ { \ constexpr bool operator()(const KDToolBox::propagate_const &lhs, \ const KDToolBox::propagate_const &rhs) \ { \ return COMP{}(get_underlying(lhs), get_underlying(rhs)); \ } \ }; \ DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(equal_to) DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(not_equal_to) DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(less) DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(greater) DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(less_equal) DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(greater_equal) #undef DEFINE_COMP_OBJECT_SPECIALIZATION } // namespace std #endif // KDTOOLBOX_PROPAGATE_CONST qbs-src-2.6.1/src/lib/corelib/tools/hostosinfo.h0000644000175100001660000002411214776170045021130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_HOSTOSINFO_H #define QBS_HOSTOSINFO_H #include "qbs_export.h" #include "stlutils.h" #include "version.h" #include #include #include #include #include #if defined(Q_OS_WIN) #define QBS_HOST_EXE_SUFFIX ".exe" #define QBS_HOST_DYNAMICLIB_PREFIX "" #define QBS_HOST_DYNAMICLIB_SUFFIX ".dll" #elif defined(Q_OS_DARWIN) #define QBS_HOST_EXE_SUFFIX "" #define QBS_HOST_DYNAMICLIB_PREFIX "lib" #define QBS_HOST_DYNAMICLIB_SUFFIX ".dylib" #else #define QBS_HOST_EXE_SUFFIX "" #define QBS_HOST_DYNAMICLIB_PREFIX "lib" #define QBS_HOST_DYNAMICLIB_SUFFIX ".so" #endif // Q_OS_WIN namespace qbs { namespace Internal { class HostOsInfo { public: // Add more as needed. enum HostOs { HostOsWindows, HostOsLinux, HostOsMacos, HostOsOtherUnix, HostOsOther }; static inline QString hostOSIdentifier(); static inline QString hostOSArchitecture(); static inline std::vector hostOSIdentifiers(); static inline std::vector canonicalOSIdentifiers(const QString &os); static inline HostOs hostOs(); static inline Version hostOsVersion() { Version v; if (HostOsInfo::isWindowsHost()) { QSettings settings(QStringLiteral("HKEY_LOCAL_MACHINE\\Software\\" "Microsoft\\Windows NT\\CurrentVersion"), QSettings::NativeFormat); v = v.fromString(settings.value(QStringLiteral("CurrentVersion")).toString() + QLatin1Char('.') + settings.value(QStringLiteral("CurrentBuildNumber")).toString()); Q_ASSERT(v.isValid()); } else if (HostOsInfo::isMacosHost()) { QSettings settings(QStringLiteral("/System/Library/CoreServices/SystemVersion.plist"), QSettings::NativeFormat); v = v.fromString(settings.value(QStringLiteral("ProductVersion")).toString()); Q_ASSERT(v.isValid()); } return v; } static QString hostOsBuildVersion() { QString v; if (HostOsInfo::isWindowsHost()) { QSettings settings(QStringLiteral("HKEY_LOCAL_MACHINE\\Software\\" "Microsoft\\Windows NT\\CurrentVersion"), QSettings::NativeFormat); v = settings.value(QStringLiteral("CurrentBuildNumber")).toString(); } else if (HostOsInfo::isMacosHost()) { QSettings serverSettings(QStringLiteral( "/System/Library/CoreServices/ServerVersion.plist"), QSettings::NativeFormat); v = serverSettings.value(QStringLiteral("ProductBuildVersion")).toString(); if (v.isNull()) { QSettings systemSettings(QStringLiteral( "/System/Library/CoreServices/SystemVersion.plist"), QSettings::NativeFormat); v = systemSettings.value(QStringLiteral("ProductBuildVersion")).toString(); } } return v; } static bool isWindowsHost() { return hostOs() == HostOsWindows; } static bool isLinuxHost() { return hostOs() == HostOsLinux; } static bool isMacosHost() { return hostOs() == HostOsMacos; } static inline bool isAnyUnixHost(); static inline QString rfc1034Identifier(const QString &str); static QString appendExecutableSuffix(const QString &executable) { QString finalName = executable; if (isWindowsHost()) finalName += QLatin1String(QBS_HOST_EXE_SUFFIX); return finalName; } static QString stripExecutableSuffix(const QString &executable) { constexpr QLatin1String suffix(QBS_HOST_EXE_SUFFIX, sizeof(QBS_HOST_EXE_SUFFIX) - 1); return !suffix.isEmpty() && executable.endsWith(suffix) ? executable.chopped(suffix.size()) : executable; } static QString dynamicLibraryName(const QString &libraryBaseName) { return QLatin1String(QBS_HOST_DYNAMICLIB_PREFIX) + libraryBaseName + QLatin1String(QBS_HOST_DYNAMICLIB_SUFFIX); } static Qt::CaseSensitivity fileNameCaseSensitivity() { return isWindowsHost() ? Qt::CaseInsensitive: Qt::CaseSensitive; } static QString libraryPathEnvironmentVariable() { if (isWindowsHost()) return QStringLiteral("PATH"); if (isMacosHost()) return QStringLiteral("DYLD_LIBRARY_PATH"); return QStringLiteral("LD_LIBRARY_PATH"); } static QChar pathListSeparator(HostOsInfo::HostOs hostOs = HostOsInfo::hostOs()) { return hostOs == HostOsWindows ? QLatin1Char(';') : QLatin1Char(':'); } static QChar pathSeparator(HostOsInfo::HostOs hostOs = HostOsInfo::hostOs()) { return hostOs == HostOsWindows ? QLatin1Char('\\') : QLatin1Char('/'); } static Qt::KeyboardModifier controlModifier() { return isMacosHost() ? Qt::MetaModifier : Qt::ControlModifier; } }; QString HostOsInfo::hostOSIdentifier() { #if defined(__APPLE__) return QStringLiteral("macos"); #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) return QStringLiteral("windows"); #elif defined(_AIX) return QStringLiteral("aix"); #elif defined(hpux) || defined(__hpux) return QStringLiteral("hpux"); #elif defined(__sun) || defined(sun) return QStringLiteral("solaris"); #elif defined(__linux__) || defined(__linux) return QStringLiteral("linux"); #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) return QStringLiteral("freebsd"); #elif defined(__NetBSD__) return QStringLiteral("netbsd"); #elif defined(__OpenBSD__) return QStringLiteral("openbsd"); #elif defined(__GNU__) return QStringLiteral("hurd"); #elif defined(__HAIKU__) return QStringLiteral("haiku"); #else #warning "Qbs has not been ported to this OS - see http://qbs.io/" return {}; #endif } QString HostOsInfo::hostOSArchitecture() { const auto cpuArch = QSysInfo::currentCpuArchitecture(); if (cpuArch == QLatin1String("i386")) return QStringLiteral("x86"); return cpuArch; } std::vector HostOsInfo::hostOSIdentifiers() { return canonicalOSIdentifiers(hostOSIdentifier()); } std::vector HostOsInfo::canonicalOSIdentifiers(const QString &name) { std::vector list { name }; if (contains({u"ios-simulator"}, name)) list << canonicalOSIdentifiers(QStringLiteral("ios")); if (contains({u"tvos-simulator"}, name)) list << canonicalOSIdentifiers(QStringLiteral("tvos")); if (contains({u"watchos-simulator"}, name)) list << canonicalOSIdentifiers(QStringLiteral("watchos")); if (contains({u"macos", u"ios", u"tvos", u"watchos"}, name)) list << canonicalOSIdentifiers(QStringLiteral("darwin")); if (contains({u"darwin", u"freebsd", u"netbsd", u"openbsd"}, name)) list << canonicalOSIdentifiers(QStringLiteral("bsd")); if (contains({u"android"}, name)) list << canonicalOSIdentifiers(QStringLiteral("linux")); // Note: recognized non-Unix platforms include: windows, haiku, vxworks if (contains({u"bsd", u"aix", u"hpux", u"solaris", u"linux", u"hurd", u"qnx", u"integrity"}, name)) list << canonicalOSIdentifiers(QStringLiteral("unix")); return list; } HostOsInfo::HostOs HostOsInfo::hostOs() { #if defined(Q_OS_WIN) return HostOsWindows; #elif defined(Q_OS_LINUX) return HostOsLinux; #elif defined(Q_OS_DARWIN) return HostOsMacos; #elif defined(Q_OS_UNIX) return HostOsOtherUnix; #else return HostOsOther; #endif } bool HostOsInfo::isAnyUnixHost() { #ifdef Q_OS_UNIX return true; #else return false; #endif } QString HostOsInfo::rfc1034Identifier(const QString &str) { QString s = str; for (QChar &ch : s) { const char c = ch.toLatin1(); const bool okChar = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.'; if (!okChar) ch = QChar::fromLatin1('-'); } return s; } } // namespace Internal } // namespace qbs #endif // QBS_HOSTOSINFO_H qbs-src-2.6.1/src/lib/corelib/tools/settingsmodel.cpp0000644000175100001660000003027114776170045022154 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "settingsmodel.h" #include "settingsrepresentation.h" #include #include #include #include #include #include #include #ifdef QT_GUI_LIB #include #endif #include namespace qbs { namespace Internal { struct Node { Node() : parent(nullptr), isFromSettings(true) {} ~Node() { qDeleteAll(children); } QString uniqueChildName() const; bool hasDirectChildWithName(const QString &name) const; QString name; QString value; Node *parent; QList children; bool isFromSettings; }; QString Node::uniqueChildName() const { QString newName = QStringLiteral("newkey"); bool unique; do { unique = true; for (const Node *childNode : std::as_const(children)) { if (childNode->name == newName) { unique = false; newName += QLatin1Char('_'); break; } } } while (!unique); return newName; } bool Node::hasDirectChildWithName(const QString &name) const { return Internal::any_of(children, [&name](const auto &child){ return child->name == name; }); } } // namespace Internal using Internal::Node; class SettingsModel::SettingsModelPrivate { public: SettingsModelPrivate() : dirty(false), editable(true) {} void readSettings(); void addNodeFromSettings(Node *parentNode, const QString &fullyQualifiedName); void addNode(Node *parentNode, const QString ¤tNamePart, const QStringList &restOfName, const QVariant &value); void doSave(const Node *node, const QString &prefix); Node *indexToNode(const QModelIndex &index); Settings::Scope scope() const { return settings->scopeForWriting(); } Node rootNode; std::unique_ptr settings; QVariantMap additionalProperties; bool dirty; bool editable; }; SettingsModel::SettingsModel(const QString &settingsDir, Settings::Scope scope, QObject *parent) : QAbstractItemModel(parent), d(std::make_unique()) { d->settings = std::make_unique(settingsDir); d->settings->setScopeForWriting(scope); d->readSettings(); } SettingsModel::~SettingsModel() = default; void SettingsModel::reload() { beginResetModel(); d->readSettings(); endResetModel(); } void SettingsModel::save() { if (!d->dirty) return; d->settings->clear(); d->doSave(&d->rootNode, QString()); d->dirty = false; } void SettingsModel::updateSettingsDir(const QString &settingsDir) { const Settings::Scope scope = d->scope(); beginResetModel(); d->settings = std::make_unique(settingsDir); d->settings->setScopeForWriting(scope); d->readSettings(); endResetModel(); } void SettingsModel::addNewKey(const QModelIndex &parent) { Node *parentNode = d->indexToNode(parent); if (!parentNode) return; const auto newNode = new Node; newNode->parent = parentNode; newNode->name = parentNode->uniqueChildName(); beginInsertRows(parent, parentNode->children.size(), parentNode->children.size()); parentNode->children << newNode; endInsertRows(); d->dirty = true; } void SettingsModel::removeKey(const QModelIndex &index) { Node * const node = d->indexToNode(index); if (!node || node == &d->rootNode) return; const int positionInParent = node->parent->children.indexOf(node); beginRemoveRows(parent(index), positionInParent, positionInParent); node->parent->children.removeAt(positionInParent); delete node; endRemoveRows(); d->dirty = true; } bool SettingsModel::hasUnsavedChanges() const { return d->dirty; } void SettingsModel::setEditable(bool isEditable) { d->editable = isEditable; } void SettingsModel::setAdditionalProperties(const QVariantMap &properties) { d->additionalProperties = properties; reload(); } Qt::ItemFlags SettingsModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; const Qt::ItemFlags flags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); if (index.column() == keyColumn()) { if (d->editable) return flags | Qt::ItemIsEditable; return flags; } if (index.column() == valueColumn()) { const Node * const node = d->indexToNode(index); if (!node) return Qt::NoItemFlags; // Only leaf nodes have values. return d->editable && node->children.empty() ? flags | Qt::ItemIsEditable : flags; } return {}; } QVariant SettingsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation != Qt::Horizontal) return {}; if (role != Qt::DisplayRole) return {}; if (section == keyColumn()) return tr("Key"); if (section == valueColumn()) return tr("Value"); return {}; } int SettingsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2; } int SettingsModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; const Node * const node = d->indexToNode(parent); Q_ASSERT(node); return node->children.size(); } QVariant SettingsModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ForegroundRole) return {}; const Node * const node = d->indexToNode(index); if (!node) return {}; if (role == Qt::ForegroundRole) { #ifdef QT_GUI_LIB if (index.column() == valueColumn() && !node->isFromSettings) return QBrush(Qt::red); #endif return {}; } if (index.column() == keyColumn()) return node->name; if (index.column() == valueColumn() && node->children.empty()) return node->value; return {}; } bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || role != Qt::EditRole) return false; Node * const node = d->indexToNode(index); if (!node) return false; const QString valueString = value.toString(); QString *toChange = nullptr; if (index.column() == keyColumn() && !valueString.isEmpty() && !node->parent->hasDirectChildWithName(valueString) && (node->parent->parent != &d->rootNode || node->parent->name != Internal::StringConstants::profilesSettingsKey() || valueString != Profile::fallbackName())) { toChange = &node->name; } else if (index.column() == valueColumn() && valueString != node->value) { toChange = &node->value; } if (toChange) { *toChange = valueString; emit dataChanged(index, index); d->dirty = true; } return toChange; } QModelIndex SettingsModel::index(int row, int column, const QModelIndex &parent) const { const Node * const parentNode = d->indexToNode(parent); Q_ASSERT(parentNode); if (parentNode->children.size() <= row) return {}; return createIndex(row, column, parentNode->children.at(row)); } QModelIndex SettingsModel::parent(const QModelIndex &child) const { const auto childNode = static_cast(child.internalPointer()); Q_ASSERT(childNode); Node * const parentNode = childNode->parent; if (parentNode == &d->rootNode) return {}; const Node * const grandParentNode = parentNode->parent; Q_ASSERT(grandParentNode); return createIndex(grandParentNode->children.indexOf(parentNode), 0, parentNode); } void SettingsModel::SettingsModelPrivate::readSettings() { qDeleteAll(rootNode.children); rootNode.children.clear(); const auto topLevelKeys = settings->directChildren(QString(), scope()); for (const QString &topLevelKey : topLevelKeys) addNodeFromSettings(&rootNode, topLevelKey); for (QVariantMap::ConstIterator it = additionalProperties.constBegin(); it != additionalProperties.constEnd(); ++it) { const QStringList nameAsList = it.key().split(QLatin1Char('.'), Qt::SkipEmptyParts); addNode(&rootNode, nameAsList.front(), nameAsList.mid(1), it.value()); } dirty = false; } static Node *createNode(Node *parentNode, const QString &name) { const auto node = new Node; node->name = name; node->parent = parentNode; parentNode->children.push_back(node); return node; } void SettingsModel::SettingsModelPrivate::addNodeFromSettings(Node *parentNode, const QString &fullyQualifiedName) { const QString &nodeName = fullyQualifiedName.mid(fullyQualifiedName.lastIndexOf(QLatin1Char('.')) + 1); Node * const node = createNode(parentNode, nodeName); node->value = settingsValueToRepresentation(settings->value(fullyQualifiedName, scope())); const auto childKeys = settings->directChildren(fullyQualifiedName, scope()); for (const QString &childKey : childKeys) addNodeFromSettings(node, fullyQualifiedName + QLatin1Char('.') + childKey); dirty = true; } void SettingsModel::SettingsModelPrivate::addNode(qbs::Internal::Node *parentNode, const QString ¤tNamePart, const QStringList &restOfName, const QVariant &value) { Node *currentNode = nullptr; for (Node * const n : std::as_const(parentNode->children)) { if (n->name == currentNamePart) { currentNode = n; break; } } if (!currentNode) currentNode = createNode(parentNode, currentNamePart); if (restOfName.empty()) { currentNode->value = settingsValueToRepresentation(value); currentNode->isFromSettings = false; } else { addNode(currentNode, restOfName.front(), restOfName.mid(1), value); } } void SettingsModel::SettingsModelPrivate::doSave(const Node *node, const QString &prefix) { if (node->children.empty()) { settings->setValue(prefix + node->name, representationToSettingsValue(node->value)); return; } const QString newPrefix = prefix + node->name + QLatin1Char('.'); for (const Node * const child : std::as_const(node->children)) doSave(child, newPrefix); } Node *SettingsModel::SettingsModelPrivate::indexToNode(const QModelIndex &index) { return index.isValid() ? static_cast(index.internalPointer()) : &rootNode; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/0000755000175100001660000000000014776170045017207 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/language/language.h0000644000175100001660000006420514776170045021152 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LANGUAGE_H #define QBS_LANGUAGE_H #include "filetags.h" #include "forward_decls.h" #include "jsimports.h" #include "moduleproviderinfo.h" #include "propertydeclaration.h" #include "resolvedfilecontext.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class BuildGraphLocker; class BuildGraphLoader; class BuildGraphVisitor; class ScriptEngine; class FileTagger { public: static FileTaggerPtr create() { return FileTaggerPtr(new FileTagger); } static FileTaggerPtr create(const QStringList &patterns, const FileTags &fileTags, int priority) { return FileTaggerPtr(new FileTagger(patterns, fileTags, priority)); } const QList &patterns() const { return m_patterns; } const FileTags &fileTags() const { return m_fileTags; } int priority() const { return m_priority; } template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_patterns, m_fileTags, m_priority); } private: FileTagger(const QStringList &patterns, FileTags fileTags, int priority); FileTagger() = default; void setPatterns(const QStringList &patterns); QList m_patterns; FileTags m_fileTags; int m_priority = 0; }; class Probe { public: static ProbePtr create() { return ProbePtr(new Probe); } static ProbeConstPtr create( const QString &globalId, const CodeLocation &location, bool condition, const QString &configureScript, const QVariantMap &initialProperties, const QMap &values, const std::vector &importedFilesUsed) { return ProbeConstPtr(new Probe( globalId, location, condition, configureScript, initialProperties, values, importedFilesUsed)); } const QString &globalId() const { return m_globalId; } bool condition() const { return m_condition; } const CodeLocation &location() const { return m_location; } const QString &configureScript() const { return m_configureScript; } const QVariantMap &initialProperties() const { return m_initialProperties; } const QMap &values() const { return m_values; } const std::vector &importedFilesUsed() const { return m_importedFilesUsed; } bool needsReconfigure(const FileTime &referenceTime) const; template void completeSerializationOp(PersistentPool &pool) { QVariantMap properties; if constexpr (opType == PersistentPool::OpType::Store) properties = storeValues(); pool.serializationOp( m_globalId, m_location, m_condition, m_configureScript, properties, m_initialProperties, m_importedFilesUsed); if constexpr (opType == PersistentPool::OpType::Load) restoreValues(properties); } private: Probe() = default; Probe( QString globalId, const CodeLocation &location, bool condition, QString configureScript, QVariantMap initialProperties, QMap values, std::vector importedFilesUsed) : m_globalId(std::move(globalId)) , m_location(location) , m_configureScript(std::move(configureScript)) , m_initialProperties(std::move(initialProperties)) , m_values(std::move(values)) , m_importedFilesUsed(std::move(importedFilesUsed)) , m_condition(condition) {} void restoreValues(const QVariantMap &properties); QVariantMap storeValues() const; QString m_globalId; CodeLocation m_location; QString m_configureScript; QVariantMap m_initialProperties; QMap m_values; std::vector m_importedFilesUsed; bool m_condition = false; }; class RuleArtifact { public: static RuleArtifactPtr create() { return RuleArtifactPtr(new RuleArtifact); } QString filePath; FileTags fileTags; bool alwaysUpdated; CodeLocation location; CodeLocation filePathLocation; class Binding { public: QStringList name; QString code; CodeLocation location; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(name, code, location); } bool operator<(const Binding &other) const { if (name == other.name) { if (code == other.code) return location < other.location; return code < other.code; } return name < other.name; } }; std::vector bindings; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(filePath, fileTags, alwaysUpdated, location, filePathLocation, bindings); } private: RuleArtifact() : alwaysUpdated(true) {} }; QHashValueType qHash(const RuleArtifact::Binding &b); bool operator==(const RuleArtifact::Binding &b1, const RuleArtifact::Binding &b2); inline bool operator!=(const RuleArtifact::Binding &b1, const RuleArtifact::Binding &b2) { return !(b1 == b2); } bool operator==(const RuleArtifact &a1, const RuleArtifact &a2); inline bool operator!=(const RuleArtifact &a1, const RuleArtifact &a2) { return !(a1 == a2); } class SourceArtifactInternal { public: static SourceArtifactPtr create() { return SourceArtifactPtr(new SourceArtifactInternal); } bool isTargetOfModule() const { return !targetOfModule.isEmpty(); } QString absoluteFilePath; FileTags fileTags; bool overrideFileTags; QString targetOfModule; PropertyMapPtr properties; bool fromWildcard; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(absoluteFilePath, fileTags, overrideFileTags, properties, targetOfModule, fromWildcard); } private: SourceArtifactInternal() : overrideFileTags(true) {} }; bool operator==(const SourceArtifactInternal &sa1, const SourceArtifactInternal &sa2); inline bool operator!=(const SourceArtifactInternal &sa1, const SourceArtifactInternal &sa2) { return !(sa1 == sa2); } class SourceWildCards { public: void expandPatterns(); bool hasChangedSinceExpansion() const; // to be restored by the owning class QString prefix; QString baseDir; QString buildDir; Set expandedFiles; // stored QStringList patterns; QStringList excludePatterns; std::vector> dirTimeStamps; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(patterns, excludePatterns, dirTimeStamps); } private: Set expandPatterns(const QStringList &patterns); void expandPatterns(Set &result, const QStringList &parts, const QString &baseDir); }; class QBS_AUTOTEST_EXPORT ResolvedGroup { public: static GroupPtr create() { return GroupPtr(new ResolvedGroup); } CodeLocation location; QString name; bool enabled = true; QString prefix; std::optional> files; std::unique_ptr wildcards; PropertyMapPtr properties; FileTags fileTags; QString targetOfModule; bool overrideTags = false; void restoreWildcards(const QString &buildDir); template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(name, enabled, location, prefix, files, wildcards, properties, fileTags, targetOfModule, overrideTags); } }; class ScriptFunction { public: static ScriptFunctionPtr create() { return ScriptFunctionPtr(new ScriptFunction); } ~ScriptFunction(); QString sourceCode; CodeLocation location; ResolvedFileContextConstPtr fileContext; bool isValid() const; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(sourceCode, location, fileContext); } private: ScriptFunction(); }; bool operator==(const ScriptFunction &a, const ScriptFunction &b); inline bool operator!=(const ScriptFunction &a, const ScriptFunction &b) { return !(a == b); } bool operator==(const PrivateScriptFunction &a, const PrivateScriptFunction &b); class PrivateScriptFunction { friend bool operator==(const PrivateScriptFunction &a, const PrivateScriptFunction &b); public: void initialize(const ScriptFunctionPtr &sharedData) { m_sharedData = sharedData; } JSValue getFunction(ScriptEngine *engine, const QString &errorMessage) const; QString &sourceCode() const { return m_sharedData->sourceCode; } CodeLocation &location() const { return m_sharedData->location; } ResolvedFileContextConstPtr &fileContext() const { return m_sharedData->fileContext; } bool isValid() const { return m_sharedData->isValid(); } template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_sharedData); } private: ScriptFunctionPtr m_sharedData; mutable JSValue scriptFunction = JS_UNDEFINED; // not stored }; bool operator==(const PrivateScriptFunction &a, const PrivateScriptFunction &b); inline bool operator!=(const PrivateScriptFunction &a, const PrivateScriptFunction &b) { return !(a == b); } class ResolvedModule { public: static ResolvedModulePtr create() { return ResolvedModulePtr(new ResolvedModule); } QString name; QStringList moduleDependencies; // TODO: Still needed? PrivateScriptFunction setupBuildEnvironmentScript; PrivateScriptFunction setupRunEnvironmentScript; ResolvedProduct *product = nullptr; bool isProduct = false; static QStringList argumentNamesForSetupBuildEnv(); static QStringList argumentNamesForSetupRunEnv(); template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(name, moduleDependencies, setupBuildEnvironmentScript, setupRunEnvironmentScript, isProduct); } private: ResolvedModule() = default; }; bool operator==(const ResolvedModule &m1, const ResolvedModule &m2); inline bool operator!=(const ResolvedModule &m1, const ResolvedModule &m2) { return !(m1 == m2); } /** * Per default each rule is a "non-multiplex rule". * * A "multiplex rule" creates one transformer that takes all * input artifacts with the matching input file tag and creates * one or more artifacts. (e.g. linker rule) * * A "non-multiplex rule" creates one transformer per matching input file. */ class Rule { public: static RulePtr create() { return RulePtr(new Rule); } RulePtr clone() const; ResolvedProduct *product = nullptr; // The owning product. ResolvedModuleConstPtr module; QString name; PrivateScriptFunction prepareScript; FileTags outputFileTags; // unused, if artifacts is non-empty PrivateScriptFunction outputArtifactsScript; // unused, if artifacts is non-empty FileTags inputs; FileTags auxiliaryInputs; FileTags auxiliaryInputsFromDependencies; FileTags excludedInputs; FileTags inputsFromDependencies; FileTags explicitlyDependsOn; FileTags explicitlyDependsOnFromDependencies; bool multiplex = false; bool requiresInputs = false; std::vector artifacts; // unused, if outputFileTags/outputArtifactsScript is non-empty bool alwaysRun = false; // members that we don't need to save int ruleGraphId = -1; static QStringList argumentNamesForOutputArtifacts(); static QStringList argumentNamesForPrepare(); QString toString() const; FileTags staticOutputFileTags() const; FileTags collectedOutputFileTags() const; bool isDynamic() const; bool declaresInputs() const; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp( name, prepareScript, outputArtifactsScript, module, inputs, outputFileTags, auxiliaryInputs, auxiliaryInputsFromDependencies, excludedInputs, inputsFromDependencies, explicitlyDependsOn, explicitlyDependsOnFromDependencies, multiplex, requiresInputs, alwaysRun, artifacts); } private: Rule() = default; }; bool operator==(const Rule &r1, const Rule &r2); inline bool operator!=(const Rule &r1, const Rule &r2) { return !(r1 == r2); } bool ruleListsAreEqual(const std::vector &l1, const std::vector &l2); class ResolvedScanner { public: static ResolvedScannerPtr create() { return ResolvedScannerPtr(new ResolvedScanner); } ResolvedModuleConstPtr module; FileTags inputs; bool recursive; PrivateScriptFunction searchPathsScript; PrivateScriptFunction scanScript; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(module, inputs, recursive, searchPathsScript, scanScript); } private: ResolvedScanner() : recursive(false) {} }; class ExportedProperty { public: template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(fullName, type, sourceCode, isBuiltin); } QString fullName; PropertyDeclaration::Type type = PropertyDeclaration::Type::UnknownType; QString sourceCode; bool isBuiltin = false; }; bool operator==(const ExportedProperty &p1, const ExportedProperty &p2); inline bool operator!=(const ExportedProperty &p1, const ExportedProperty &p2) { return !(p1 == p2); } class ExportedItem { public: template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(name, properties, children); } static ExportedItemPtr create() { return std::make_shared(); } QString name; std::vector properties; std::vector children; }; bool equals(const std::vector &l1, const std::vector &l2); bool operator==(const ExportedItem &i1, const ExportedItem &i2); inline bool operator!=(const ExportedItem &i1, const ExportedItem &i2) { return !(i1 == i2); } class ExportedModuleDependency { public: template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(name, moduleProperties); }; QString name; QVariantMap moduleProperties; }; bool operator==(const ExportedModuleDependency &d1, const ExportedModuleDependency &d2); inline bool operator!=(const ExportedModuleDependency &d1, const ExportedModuleDependency &d2) { return !(d1 == d2); } class ExportedModule { public: template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(propertyValues, modulePropertyValues, children, productDependencies, moduleDependencies, m_properties, dependencyParameters, importStatements); }; QVariantMap propertyValues; QVariantMap modulePropertyValues; std::vector children; std::vector productDependencies; std::vector moduleDependencies; std::vector m_properties; QMap dependencyParameters; QStringList importStatements; }; bool operator==(const ExportedModule &m1, const ExportedModule &m2); inline bool operator!=(const ExportedModule &m1, const ExportedModule &m2) { return !(m1 == m2); } class TopLevelProject; class ScriptEngine; class QBS_AUTOTEST_EXPORT ResolvedProduct { public: static ResolvedProductPtr create() { return ResolvedProductPtr(new ResolvedProduct); } ~ResolvedProduct(); bool enabled; FileTags fileTags; QString name; QString targetName; QString multiplexConfigurationId; QString sourceDirectory; QString destinationDirectory; CodeLocation location; WeakPointer project; QVariantMap productProperties; PropertyMapPtr moduleProperties; std::vector rules; std::vector dependencies; QHash dependencyParameters; std::vector fileTaggers; JobLimits jobLimits; std::vector modules; QHash moduleParameters; std::vector scanners; std::vector groups; std::vector probes; std::vector artifactProperties; QStringList missingSourceFiles; std::unique_ptr buildData; ExportedModule exportedModule; QProcessEnvironment buildEnvironment; // must not be saved QProcessEnvironment runEnvironment; // must not be saved void accept(BuildGraphVisitor *visitor) const; std::vector allFiles() const; std::vector allEnabledFiles() const; FileTags fileTagsForFileName(const QString &fileName) const; ArtifactSet lookupArtifactsByFileTag(const FileTag &tag) const; ArtifactSet lookupArtifactsByFileTags(const FileTags &tags) const; ArtifactSet targetArtifacts() const; TopLevelProject *topLevelProject() const; static QString uniqueName(const QString &name, const QString &multiplexConfigurationId); QString uniqueName() const; QString fullDisplayName() const; QString profile() const; QStringList generatedFiles(const QString &baseFile, bool recursive, const FileTags &tags) const; static QString deriveBuildDirectoryName(const QString &name, const QString &multiplexConfigurationId); QString buildDirectory() const; bool isInParentProject(const ResolvedProductConstPtr &other) const; bool builtByDefault() const; void cacheExecutablePath(const QString &origFilePath, const QString &fullFilePath); QString cachedExecutablePath(const QString &origFilePath) const; void load(PersistentPool &pool); void store(PersistentPool &pool); private: ResolvedProduct(); template void serializationOp(PersistentPool &pool) { pool.serializationOp(enabled, fileTags, name, multiplexConfigurationId, targetName, sourceDirectory, destinationDirectory, missingSourceFiles, location, productProperties, moduleProperties, rules, dependencies, dependencyParameters, fileTaggers, modules, moduleParameters, scanners, groups, artifactProperties, probes, exportedModule, buildData, jobLimits); } QHash m_executablePathCache; mutable std::mutex m_executablePathCacheLock; }; class QBS_AUTOTEST_EXPORT ResolvedProject { public: virtual ~ResolvedProject(); static ResolvedProjectPtr create() { return ResolvedProjectPtr(new ResolvedProject); } QString name; CodeLocation location; bool enabled; std::vector products; std::vector subProjects; WeakPointer parentProject; void accept(BuildGraphVisitor *visitor) const; void setProjectProperties(const QVariantMap &config) { m_projectProperties = config; } const QVariantMap &projectProperties() const { return m_projectProperties; } TopLevelProject *topLevelProject(); std::vector allSubProjects() const; std::vector allProducts() const; virtual void load(PersistentPool &pool); virtual void store(PersistentPool &pool); protected: ResolvedProject(); private: template void serializationOp(PersistentPool &pool) { pool.serializationOp(name, location, enabled, products, subProjects, m_projectProperties); } QVariantMap m_projectProperties; TopLevelProject *m_topLevelProject; }; class QBS_AUTOTEST_EXPORT TopLevelProject : public ResolvedProject { friend class BuildGraphLoader; public: ~TopLevelProject() override; static TopLevelProjectPtr create() { return TopLevelProjectPtr(new TopLevelProject); } static QString deriveId(const QVariantMap &config); static QString deriveBuildDirectory(const QString &buildRoot, const QString &id); QString buildDirectory; // Not saved QProcessEnvironment environment; std::vector probes; StoredModuleProviderInfo moduleProviderInfo; QHash canonicalFilePathResults; // Results of calls to "File.canonicalFilePath()." QHash fileExistsResults; // Results of calls to "File.exists()". QHash, QStringList> directoryEntriesResults; // Results of calls to "File.directoryEntries()". QHash fileLastModifiedResults; // Results of calls to "File.lastModified()". CodeLinks codeLinks; std::unique_ptr buildData; BuildGraphLocker *bgLocker; // This holds the system-wide build graph file lock. bool locked; // This is the API-level lock for the project instance. Set buildSystemFiles; FileTime lastStartResolveTime; FileTime lastEndResolveTime; QList warningsEncountered; QList errorsEncountered; void setBuildConfiguration(const QVariantMap &config); const QVariantMap &buildConfiguration() const { return m_buildConfiguration; } QString id() const { return m_id; } QString profile() const; void makeModuleProvidersNonTransient(); QVariantMap fullProfileConfigsTree() const; // Tree-ified + overridden values QVariantMap profileConfigs; QVariantMap overriddenValues; QString buildGraphFilePath() const; void store(Logger logger); private: TopLevelProject(); template void serializationOp(PersistentPool &pool) { pool.serializationOp( m_id, canonicalFilePathResults, fileExistsResults, directoryEntriesResults, fileLastModifiedResults, environment, probes, profileConfigs, overriddenValues, buildSystemFiles, lastStartResolveTime, lastEndResolveTime, warningsEncountered, errorsEncountered, buildData, moduleProviderInfo, codeLinks); } void load(PersistentPool &pool) override; void store(PersistentPool &pool) override; void cleanupModuleProviderOutput(); QString m_id; QVariantMap m_buildConfiguration; }; bool artifactPropertyListsAreEqual(const std::vector &l1, const std::vector &l2); } // namespace Internal } // namespace qbs QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(qbs::Internal::JsImport, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(qbs::Internal::RuleArtifact::Binding, Q_MOVABLE_TYPE); QT_END_NAMESPACE #endif // QBS_LANGUAGE_H qbs-src-2.6.1/src/lib/corelib/language/artifactproperties.cpp0000644000175100001660000000524614776170045023634 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "artifactproperties.h" #include namespace qbs { namespace Internal { ArtifactPropertiesPtr ArtifactProperties::create() { return ArtifactPropertiesPtr(new ArtifactProperties); } ArtifactProperties::ArtifactProperties() = default; FileTags ArtifactProperties::extraFileTags() const { return m_extraFileTags; } void ArtifactProperties::addExtraFileTags(const FileTags &extraFileTags) { m_extraFileTags.unite(extraFileTags); } bool operator==(const ArtifactProperties &ap1, const ArtifactProperties &ap2) { return ap1.fileTagsFilter() == ap2.fileTagsFilter() && ap1.extraFileTags() == ap2.extraFileTags() && !ap1.propertyMap() == !ap2.propertyMap() && *ap1.propertyMap() == *ap2.propertyMap(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/deprecationinfo.h0000644000175100001660000001123114776170045022527 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_DEPRECATIONINFO_H #define QBS_DEPRECATIONINFO_H #include #include #include #include #include #include #include namespace qbs { namespace Internal { class DeprecationInfo { public: explicit DeprecationInfo(const Version &removalVersion, QString additionalUserInfo = QString()) : m_removalVersion(removalVersion) , m_additionalUserInfo(std::move(additionalUserInfo)) {} DeprecationInfo() = default; static bool isLastVersionBeforeRemoval(const Version &removalVersion) { const Version next( LanguageInfo::qbsVersion().majorVersion(), LanguageInfo::qbsVersion().minorVersion() + 1); return removalVersion == next || removalVersion.minorVersion() == 0; } bool isValid() const { return m_removalVersion.isValid(); } Version removalVersion() const { return m_removalVersion; } ErrorInfo checkForDeprecation(DeprecationWarningMode mode, const QString &name, const CodeLocation &loc, bool isItem, Logger &logger) const { if (!isValid()) return {}; const Version qbsVersion = LanguageInfo::qbsVersion(); if (removalVersion() <= qbsVersion) { const QString msgTemplate = isItem ? Tr::tr("The item '%1' can no longer be used. It was removed in Qbs %2.") : Tr::tr("The property '%1' can no longer be used. It was removed in Qbs %2."); ErrorInfo error(msgTemplate.arg(name, removalVersion().toString()), loc); if (!m_additionalUserInfo.isEmpty()) error.append(m_additionalUserInfo); return error; } const QString msgTemplate = isItem ? Tr::tr("The item '%1' is deprecated and will be removed in Qbs %2.") : Tr::tr("The property '%1' is deprecated and will be removed in Qbs %2."); ErrorInfo error(msgTemplate.arg(name, removalVersion().toString()), loc); if (!m_additionalUserInfo.isEmpty()) error.append(m_additionalUserInfo); switch (mode) { case DeprecationWarningMode::Error: return error; case DeprecationWarningMode::On: logger.printWarning(error); break; case DeprecationWarningMode::BeforeRemoval: if (isLastVersionBeforeRemoval(removalVersion())) logger.printWarning(error); break; case DeprecationWarningMode::Off: break; } return {}; } private: Version m_removalVersion; QString m_additionalUserInfo; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/language/filecontextbase.h0000644000175100001660000000566014776170045022546 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FILECONTEXTBASE_H #define QBS_FILECONTEXTBASE_H #include "jsimports.h" namespace qbs { namespace Internal { class FileContextBase { public: void setFilePath(const QString &filePath) { m_filePath = filePath; } QString filePath() const { return m_filePath; } void addJsImport(const JsImport &jsImport) { m_jsImports.push_back(jsImport); } const JsImports &jsImports() const { return m_jsImports; } void addJsExtension(const QString &extension) { m_jsExtensions << extension; } QStringList jsExtensions() const { return m_jsExtensions; } void setSearchPaths(const QStringList &paths) { m_searchPaths = paths; } QStringList searchPaths() const { return m_searchPaths; } QString dirPath() const; protected: FileContextBase() = default; FileContextBase(const FileContextBase &other) = default; FileContextBase(FileContextBase &&other) = default; QString m_filePath; JsImports m_jsImports; QStringList m_jsExtensions; QStringList m_searchPaths; }; } // namespace Internal } // namespace qbs #endif // QBS_FILECONTEXTBASE_H qbs-src-2.6.1/src/lib/corelib/language/builtindeclarations.h0000644000175100001660000000675714776170045023436 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILTINDECLARATIONS_H #define QBS_BUILTINDECLARATIONS_H #include "itemdeclaration.h" #include "itemtype.h" #include #include #include #include #include namespace qbs { namespace Internal { class BuiltinDeclarations { public: static const BuiltinDeclarations &instance(); Version languageVersion() const; QStringList allTypeNames() const; ItemDeclaration declarationsForType(ItemType type) const; ItemType typeForName(const QString &typeName, const CodeLocation &location = CodeLocation()) const; QString nameForType(ItemType itemType) const; QStringList argumentNamesForScriptFunction(ItemType itemType, const QString &scriptName) const; protected: BuiltinDeclarations(); private: void insert(const ItemDeclaration &decl); void addArtifactItem(); void addDependsItem(); void addExportItem(); void addFileTaggerItem(); void addGroupItem(); void addJobLimitItem(); void addModuleItem(); void addModuleProviderItem(); static ItemDeclaration moduleLikeItem(ItemType type); void addProbeItem(); void addProductItem(); void addProfileItem(); void addProjectItem(); void addPropertiesItem(); void addPropertyOptionsItem(); void addRuleItem(); void addSubprojectItem(); void addTransformerItem(); void addScannerItem(); const Version m_languageVersion; QMap m_builtins; const QHash m_typeMap; }; } // namespace Internal } // namespace qbs #endif // QBS_BUILTINDECLARATIONS_H qbs-src-2.6.1/src/lib/corelib/language/itemobserver.h0000644000175100001660000000422414776170045022070 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMOBSERVER_H #define QBS_ITEMOBSERVER_H namespace qbs { namespace Internal { class Item; class ItemObserver { public: virtual ~ItemObserver() = default; virtual void onItemPropertyChanged(Item *item) = 0; }; } // namespace Internal } // namespace qbs #endif // QBS_ITEMOBSERVER_H qbs-src-2.6.1/src/lib/corelib/language/preparescriptobserver.h0000644000175100001660000000725214776170045024021 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PREPARESCRIPTOBSERVER_H #define QBS_PREPARESCRIPTOBSERVER_H #include "qualifiedid.h" #include "scriptpropertyobserver.h" #include #include #include #include namespace qbs { namespace Internal { class ResolvedProduct; class ScriptEngine; class PrepareScriptObserver : public ScriptPropertyObserver { public: PrepareScriptObserver(ScriptEngine *engine, UnobserveMode unobserveMode); void addProjectObjectId(qint64 projectId, const QString &projectName) { m_projectObjectIds.insert(std::make_pair(projectId, projectName)); } void addExportsObjectId(qint64 exportsId, const ResolvedProduct *product) { m_exportsObjectIds.insert(std::make_pair(exportsId, product)); } void addArtifactId(qint64 artifactId) { m_artifactIds.insert(artifactId); } bool addImportId(quintptr importId) { return m_importIds.insert(importId).second; } void clearImportIds() { m_importIds.clear(); } void addParameterObjectId(qint64 id, const QString &productName, const QString &depName, const QualifiedId &moduleName) { const QString depAndModuleName = depName + QLatin1Char(':') + moduleName.toString(); const auto value = std::make_pair(productName, depAndModuleName); m_parameterObjects.insert(std::make_pair(id, value)); } void onPropertyRead(const JSValue &object, const QString &name, const JSValue &value) override; private: std::unordered_map m_projectObjectIds; std::unordered_map> m_parameterObjects; std::unordered_map m_exportsObjectIds; Set m_importIds; Set m_artifactIds; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/language/resolvedfilecontext.cpp0000644000175100001660000000454714776170045024015 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "resolvedfilecontext.h" #include "jsimports.h" #include namespace qbs { namespace Internal { ResolvedFileContext::ResolvedFileContext(const FileContextBase &ctx) : FileContextBase(ctx) { } bool operator==(const ResolvedFileContext &a, const ResolvedFileContext &b) { return a.filePath() == b.filePath() && toSet(a.jsExtensions()) == toSet(b.jsExtensions()) && sorted(a.jsImports()) == sorted(b.jsImports()); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/propertymapinternal.h0000644000175100001660000000675314776170045023512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROPERTYMAPINTERNAL_H #define QBS_PROPERTYMAPINTERNAL_H #include "forward_decls.h" #include #include #include namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT PropertyMapInternal { public: static PropertyMapPtr create() { return PropertyMapPtr(new PropertyMapInternal); } PropertyMapPtr clone() const { return PropertyMapPtr(new PropertyMapInternal(*this)); } const QVariantMap &value() const { return m_value; } QVariant moduleProperty(const QString &moduleName, const QString &key, bool *isPresent = nullptr) const; QVariant qbsPropertyValue(const QString &key) const; // Convenience function. QVariant property(const QStringList &name) const; void setValue(const QVariantMap &value); template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_value); } private: friend bool operator==(const PropertyMapInternal &lhs, const PropertyMapInternal &rhs); PropertyMapInternal(); PropertyMapInternal(const PropertyMapInternal &other); QVariantMap m_value; }; inline bool operator==(const PropertyMapInternal &lhs, const PropertyMapInternal &rhs) { return qVariantsEqual(lhs.m_value, rhs.m_value); } QVariant QBS_AUTOTEST_EXPORT moduleProperty(const QVariantMap &properties, const QString &moduleName, const QString &key, bool *isPresent = nullptr); } // namespace Internal } // namespace qbs #endif // QBS_PROPERTYMAPINTERNAL_H qbs-src-2.6.1/src/lib/corelib/language/property.cpp0000644000175100001660000000455314776170045021606 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "property.h" namespace qbs { namespace Internal { bool operator<(const Property &p1, const Property &p2) { int cmpResult = QString::compare(p1.productName, p2.productName); if (cmpResult < 0) return true; if (cmpResult > 0) return false; cmpResult = QString::compare(p1.moduleName, p2.moduleName); if (cmpResult < 0) return true; if (cmpResult > 0) return false; return p1.propertyName < p2.propertyName; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/preparescriptobserver.cpp0000644000175100001660000001002714776170045024346 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "preparescriptobserver.h" #include "property.h" #include "scriptengine.h" #include #include #include #include #include namespace qbs { namespace Internal { PrepareScriptObserver::PrepareScriptObserver(ScriptEngine *engine, UnobserveMode unobserveMode) : ScriptPropertyObserver(engine, unobserveMode) { } void PrepareScriptObserver::onPropertyRead(const JSValue &object, const QString &name, const JSValue &value) { JSContext * const ctx = engine()->context(); const auto objectId = jsObjectId(object); const auto projectIt = m_projectObjectIds.find(objectId); if (projectIt != m_projectObjectIds.cend()) { engine()->addPropertyRequestedInScript( Property(projectIt->second, QString(), name, getJsVariant(ctx, value), Property::PropertyInProject)); return; } if (m_importIds.contains(objectId)) { engine()->addImportRequestedInScript(jsObjectId(object)); return; } const auto exportsIt = m_exportsObjectIds.find(jsObjectId(object)); if (exportsIt != m_exportsObjectIds.cend()) { engine()->addRequestedExport(exportsIt->second); return; } const auto it = m_parameterObjects.find(objectId); if (it != m_parameterObjects.cend()) { engine()->addPropertyRequestedInScript( Property(it->second.first, it->second.second, name, getJsVariant(ctx, value), Property::PropertyInParameters)); } if (name == StringConstants::fileTagsProperty() && m_artifactIds.contains(objectId)) { const Artifact * const artifact = attachedPointer(object, engine()->dataWithPtrClass()); QBS_CHECK(artifact); const Property p(artifact->product->uniqueName(), QString(), name, getJsVariant(ctx, value), Property::PropertyInArtifact); engine()->addPropertyRequestedFromArtifact(artifact, p); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/asttools.h0000644000175100001660000000461514776170045021236 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ASTTOOLS_H #define QBS_ASTTOOLS_H #include #include #include namespace qbs { namespace Internal { QStringList toStringList(QbsQmlJS::AST::UiQualifiedId *qid); CodeLocation toCodeLocation(const QString &filePath, const QbsQmlJS::AST::SourceLocation &location); QString textOf(const QString &source, QbsQmlJS::AST::Node *node); QStringView textViewOf(const QString &source, QbsQmlJS::AST::Node *node); } // namespace Internal } // namespace qbs #endif // QBS_ASTTOOLS_H qbs-src-2.6.1/src/lib/corelib/language/scriptpropertyobserver.h0000644000175100001660000000543214776170045024245 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SCRIPTPROPERTYOBSERVER_H #define QBS_SCRIPTPROPERTYOBSERVER_H #include #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { class ScriptEngine; enum class UnobserveMode { Enabled, Disabled }; class ScriptPropertyObserver { public: ScriptPropertyObserver(ScriptEngine *engine, UnobserveMode unobserveMode) : m_engine(engine), m_unobserveMode(unobserveMode) {} UnobserveMode unobserveMode() const { return m_unobserveMode; } virtual ~ScriptPropertyObserver(); virtual void onPropertyRead(const JSValue &object, const QString &name, const JSValue &value) = 0; protected: ScriptEngine * engine() const { return m_engine; } private: ScriptEngine * const m_engine; const UnobserveMode m_unobserveMode; }; } // namespace Internal } // namespace qbs #endif // QBS_SCRIPTPROPERTYOBSERVER_H qbs-src-2.6.1/src/lib/corelib/language/property.h0000644000175100001660000000672114776170045021252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROPERTY_H #define QBS_PROPERTY_H #include #include #include #include namespace qbs { namespace Internal { class Property { public: enum Kind { PropertyInModule, PropertyInProduct, PropertyInProject, PropertyInParameters, PropertyInArtifact, }; Property() : kind(PropertyInModule) { } Property(QString product, QString module, QString property, QVariant v, Kind k) : productName(std::move(product)) , moduleName(std::move(module)) , propertyName(std::move(property)) , value(std::move(v)) , kind(k) { } template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(productName, moduleName, propertyName, value, kind); } QString productName; // In case of kind == PropertyInProject, this is the project name. QString moduleName; QString propertyName; QVariant value; Kind kind; }; inline bool operator==(const Property &p1, const Property &p2) { return p1.productName == p2.productName && p1.moduleName == p2.moduleName && p1.propertyName == p2.propertyName; } bool operator<(const Property &p1, const Property &p2); inline auto qHash(const Property &p) { return QT_PREPEND_NAMESPACE(qHash)(p.productName + p.moduleName + p.propertyName); } using PropertySet = Set; using PropertyHash = QHash; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/language/language.cpp0000644000175100001660000007743414776170045021515 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "language.h" #include "artifactproperties.h" #include "builtindeclarations.h" #include "propertymapinternal.h" #include "scriptengine.h" #include #include #include #include #include // TODO: Move to language? #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { template bool equals(const T *v1, const T *v2) { if (v1 == v2) return true; if (!v1 != !v2) return false; return *v1 == *v2; } /*! * \class FileTagger * \brief The \c FileTagger class maps 1:1 to the respective item in a qbs source file. */ FileTagger::FileTagger(const QStringList &patterns, FileTags fileTags, int priority) : m_fileTags(std::move(fileTags)), m_priority(priority) { setPatterns(patterns); } void FileTagger::setPatterns(const QStringList &patterns) { m_patterns.clear(); for (const QString &pattern : patterns) { QBS_CHECK(!pattern.isEmpty()); m_patterns << QRegularExpression(QRegularExpression::wildcardToRegularExpression(pattern)); } } bool Probe::needsReconfigure(const FileTime &referenceTime) const { const auto criterion = [referenceTime](const QString &filePath) { FileInfo fi(filePath); return !fi.exists() || fi.lastModified() > referenceTime; }; return Internal::any_of(m_importedFilesUsed, criterion); } void Probe::restoreValues(const QVariantMap &properties) { for (auto it = properties.begin(), end = properties.end(); it != end; ++it) { m_values[it.key()] = VariantValue::createStored(it.value()); } } QVariantMap Probe::storeValues() const { QVariantMap result; for (auto it = m_values.begin(), end = m_values.end(); it != end; ++it) { result[it.key()] = it.value()->value(); } return result; } /*! * \class SourceArtifact * \brief The \c SourceArtifact class represents a source file. * Everything except the file path is inherited from the surrounding \c ResolvedGroup. * (TODO: Not quite true. Artifacts in transformers will be generated by the transformer, but are * still represented as source artifacts. We may or may not want to change this; if we do, * SourceArtifact could simply have a back pointer to the group in addition to the file path.) * \sa ResolvedGroup */ /*! * \class ResolvedGroup * \brief The \c ResolvedGroup class corresponds to the Group item in a qbs source file. */ /*! * \variable ResolvedGroup::files * \brief The files listed in the group item's "files" binding. */ /*! * \variable ResolvedGroup::wildcards * \brief Represents the wildcard patterns in this group's "files" binding. * If no wildcards are specified there, this variable is null. * \sa SourceWildCards */ /*! * \class RuleArtifact * \brief The \c RuleArtifact class represents an Artifact item encountered in the context * of a Rule item. * When applying the rule, one \c Artifact object will be constructed from each \c RuleArtifact * object. During that process, the \c RuleArtifact's bindings are evaluated and the results * are inserted into the corresponding \c Artifact's properties. * \sa Rule */ /*! * \class ScriptFunction * \brief The \c ScriptFunction class represents the JavaScript code found in the "prepare" binding * of a \c Rule item in a qbs file. * \sa Rule */ ScriptFunction::ScriptFunction() = default; ScriptFunction::~ScriptFunction() = default; /*! * \variable ScriptFunction::script * \brief The actual Javascript code, taken verbatim from the qbs source file. */ /*! * \variable ScriptFunction::location * \brief The exact location of the script in the qbs source file. * This is mostly needed for diagnostics. */ bool ScriptFunction::isValid() const { return location.line() != -1; } bool operator==(const ScriptFunction &a, const ScriptFunction &b) { return a.sourceCode == b.sourceCode && a.location == b.location && equals(a.fileContext.get(), b.fileContext.get()); } QStringList ResolvedModule::argumentNamesForSetupBuildEnv() { static const QStringList argNames = BuiltinDeclarations::instance() .argumentNamesForScriptFunction(ItemType::Module, StringConstants::setupBuildEnvironmentProperty()); return argNames; } QStringList ResolvedModule::argumentNamesForSetupRunEnv() { static const QStringList argNames = BuiltinDeclarations::instance() .argumentNamesForScriptFunction(ItemType::Module, StringConstants::setupRunEnvironmentProperty()); return argNames; } bool operator==(const ResolvedModule &m1, const ResolvedModule &m2) { return m1.name == m2.name && m1.isProduct == m2.isProduct && toSet(m1.moduleDependencies) == toSet(m2.moduleDependencies) && m1.setupBuildEnvironmentScript == m2.setupBuildEnvironmentScript && m1.setupRunEnvironmentScript == m2.setupRunEnvironmentScript; } RulePtr Rule::clone() const { return std::make_shared(*this); } QStringList Rule::argumentNamesForOutputArtifacts() { static const QStringList argNames = BuiltinDeclarations::instance() .argumentNamesForScriptFunction(ItemType::Rule, StringConstants::outputArtifactsProperty()); return argNames; } QStringList Rule::argumentNamesForPrepare() { static const QStringList argNames = BuiltinDeclarations::instance() .argumentNamesForScriptFunction(ItemType::Rule, StringConstants::prepareProperty()); return argNames; } QString Rule::toString() const { QStringList outputTagsSorted = collectedOutputFileTags().toStringList(); outputTagsSorted.sort(); FileTags inputTags = inputs; inputTags.unite(inputsFromDependencies); QStringList inputTagsSorted = inputTags.toStringList(); inputTagsSorted.sort(); return QLatin1Char('[') + outputTagsSorted.join(QLatin1Char(',')) + QLatin1String("][") + inputTagsSorted.join(QLatin1Char(',')) + QLatin1Char(']'); } FileTags Rule::staticOutputFileTags() const { FileTags result; for (const auto &artifact : artifacts) result.unite(artifact->fileTags); return result; } FileTags Rule::collectedOutputFileTags() const { FileTags result = outputFileTags.empty() ? staticOutputFileTags() : outputFileTags; for (const auto &ap : product->artifactProperties) { if (ap->fileTagsFilter().intersects(result)) result += ap->extraFileTags(); } return result; } bool Rule::isDynamic() const { return outputArtifactsScript.isValid(); } bool Rule::declaresInputs() const { return !inputs.empty() || !inputsFromDependencies.empty(); } ResolvedProduct::ResolvedProduct() : enabled(true) { } ResolvedProduct::~ResolvedProduct() = default; void ResolvedProduct::accept(BuildGraphVisitor *visitor) const { if (!buildData) return; for (BuildGraphNode * const node : std::as_const(buildData->rootNodes())) node->accept(visitor); } /*! * \brief Returns all files of all groups as source artifacts. * This includes the expanded list of wildcards. */ std::vector ResolvedProduct::allFiles() const { std::vector lst; for (const auto &group : groups) { if (group->files) lst << *group->files; } return lst; } /*! * \brief Returns all files of all enabled groups as source artifacts. * \sa ResolvedProduct::allFiles() */ std::vector ResolvedProduct::allEnabledFiles() const { std::vector lst; for (const auto &group : groups) { if (group->enabled && group->files) lst << *group->files; } return lst; } FileTags ResolvedProduct::fileTagsForFileName(const QString &fileName) const { FileTags result; std::unique_ptr priority; for (const FileTaggerConstPtr &tagger : std::as_const(fileTaggers)) { for (const QRegularExpression &pattern : tagger->patterns()) { if (pattern.match(fileName).hasMatch()) { if (priority) { if (*priority != tagger->priority()) { // The taggers are expected to be sorted by priority. QBS_ASSERT(*priority > tagger->priority(), return result); return result; } } else { priority = std::make_unique(tagger->priority()); } result.unite(tagger->fileTags()); break; } } } return result; } void ResolvedProduct::load(PersistentPool &pool) { serializationOp(pool); for (const RulePtr &rule : rules) rule->product = this; for (const ResolvedModulePtr &module : modules) module->product = this; for (const auto &group: groups) group->restoreWildcards(buildDirectory()); } void ResolvedProduct::store(PersistentPool &pool) { serializationOp(pool); } ArtifactSet ResolvedProduct::lookupArtifactsByFileTag(const FileTag &tag) const { QBS_CHECK(buildData); 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); ArtifactSet taSet; for (Artifact * const a : buildData->rootArtifacts()) { QBS_CHECK(a->fileTags().intersects(fileTags)); taSet << a; } return taSet; } TopLevelProject *ResolvedProduct::topLevelProject() const { return project->topLevelProject(); } QString ResolvedProduct::uniqueName(const QString &name, const QString &multiplexConfigurationId) { QString result = name; if (!multiplexConfigurationId.isEmpty()) result.append(QLatin1Char('.')).append(multiplexConfigurationId); return result; } QString ResolvedProduct::uniqueName() const { return uniqueName(name, multiplexConfigurationId); } QString ResolvedProduct::fullDisplayName() const { return fullProductDisplayName(name, multiplexConfigurationId); } QString ResolvedProduct::profile() const { return moduleProperties->qbsPropertyValue(StringConstants::profileProperty()).toString(); } static QStringList findGeneratedFiles(const Artifact *base, bool recursive, const FileTags &tags) { QStringList result; for (const Artifact *parent : base->parentArtifacts()) { if (tags.empty() || parent->fileTags().intersects(tags)) result << parent->filePath(); if (recursive) result << findGeneratedFiles(parent, true, tags); } return result; } QStringList ResolvedProduct::generatedFiles(const QString &baseFile, bool recursive, const FileTags &tags) const { ProductBuildData *data = buildData.get(); if (!data) return {}; for (const Artifact *art : filterByType(data->allNodes())) { if (art->filePath() == baseFile) return findGeneratedFiles(art, recursive, tags); } return {}; } QString ResolvedProduct::deriveBuildDirectoryName(const QString &name, const QString &multiplexConfigurationId) { QString dirName = uniqueName(name, multiplexConfigurationId); const QByteArray hash = QCryptographicHash::hash(dirName.toUtf8(), QCryptographicHash::Sha1); return HostOsInfo::rfc1034Identifier(dirName) .append(QLatin1Char('.')) .append(QString::fromLatin1(hash.toHex().left(8))); } QString ResolvedProduct::buildDirectory() const { return productProperties.value(StringConstants::buildDirectoryProperty()).toString(); } bool ResolvedProduct::isInParentProject(const ResolvedProductConstPtr &other) const { for (const ResolvedProject *otherParent = other->project.get(); otherParent; otherParent = otherParent->parentProject.get()) { if (otherParent == project.get()) return true; } return false; } bool ResolvedProduct::builtByDefault() const { return productProperties.value(StringConstants::builtByDefaultProperty(), true).toBool(); } void ResolvedProduct::cacheExecutablePath(const QString &origFilePath, const QString &fullFilePath) { std::lock_guard locker(m_executablePathCacheLock); m_executablePathCache.insert(origFilePath, fullFilePath); } QString ResolvedProduct::cachedExecutablePath(const QString &origFilePath) const { std::lock_guard locker(m_executablePathCacheLock); return m_executablePathCache.value(origFilePath); } void ResolvedGroup::restoreWildcards(const QString &buildDir) { if (!files) return; if (wildcards) { wildcards->buildDir = buildDir; wildcards->prefix = prefix; wildcards->baseDir = FileInfo::path(location.filePath()); for (const auto &sourceArtifact : *files) { if (sourceArtifact->fromWildcard) wildcards->expandedFiles += sourceArtifact->absoluteFilePath; } } } ResolvedProject::ResolvedProject() : enabled(true), m_topLevelProject(nullptr) { } ResolvedProject::~ResolvedProject() = default; void ResolvedProject::accept(BuildGraphVisitor *visitor) const { for (const ResolvedProductPtr &product : products) product->accept(visitor); for (const ResolvedProjectPtr &subProject : std::as_const(subProjects)) subProject->accept(visitor); } TopLevelProject *ResolvedProject::topLevelProject() { if (m_topLevelProject) return m_topLevelProject; if (parentProject.expired()) { m_topLevelProject = static_cast(this); return m_topLevelProject; } m_topLevelProject = parentProject->topLevelProject(); return m_topLevelProject; } std::vector ResolvedProject::allSubProjects() const { std::vector projectList = subProjects; for (const auto &subProject : subProjects) projectList << subProject->allSubProjects(); return projectList; } std::vector ResolvedProject::allProducts() const { std::vector productList = products; for (const auto &subProject : std::as_const(subProjects)) productList << subProject->allProducts(); return productList; } void ResolvedProject::load(PersistentPool &pool) { serializationOp(pool); std::for_each(products.cbegin(), products.cend(), [](const ResolvedProductPtr &p) { if (!p->buildData) return; for (BuildGraphNode * const node : std::as_const(p->buildData->allNodes())) { node->product = p; // restore parent links for (BuildGraphNode * const child : std::as_const(node->children)) child->parents.insert(node); } }); } void ResolvedProject::store(PersistentPool &pool) { serializationOp(pool); } TopLevelProject::TopLevelProject() : bgLocker(nullptr), locked(false), lastStartResolveTime(FileTime::oldestTime()) { } TopLevelProject::~TopLevelProject() { cleanupModuleProviderOutput(); delete bgLocker; } QString TopLevelProject::deriveId(const QVariantMap &config) { const QVariantMap qbsProperties = config.value(StringConstants::qbsModule()).toMap(); QString configurationName = qbsProperties.value( StringConstants::configurationNameProperty()).toString(); return configurationName; } QString TopLevelProject::deriveBuildDirectory(const QString &buildRoot, const QString &id) { return buildRoot + QLatin1Char('/') + id; } void TopLevelProject::setBuildConfiguration(const QVariantMap &config) { m_buildConfiguration = config; m_id = deriveId(config); } QString TopLevelProject::profile() const { return projectProperties().value(StringConstants::profileProperty()).toString(); } void TopLevelProject::makeModuleProvidersNonTransient() { for (auto &item : moduleProviderInfo.providers) item.second.transientOutput = false; } QVariantMap TopLevelProject::fullProfileConfigsTree() const { QVariantMap tree; for (auto it = profileConfigs.cbegin(); it != profileConfigs.cend(); ++it) { tree.insert(it.key(), SetupProjectParameters::finalBuildConfigurationTree( it.value().toMap(), overriddenValues)); } return tree; } QString TopLevelProject::buildGraphFilePath() const { return ProjectBuildData::deriveBuildGraphFilePath(buildDirectory, id()); } void TopLevelProject::store(Logger logger) { // TODO: Use progress observer here. if (!buildData) return; if (!buildData->isDirty()) { qCDebug(lcBuildGraph) << "build graph is unchanged in project" << id(); return; } makeModuleProvidersNonTransient(); const QString fileName = buildGraphFilePath(); qCDebug(lcBuildGraph) << "storing:" << fileName; PersistentPool pool(logger); PersistentPool::HeadData headData; headData.projectConfig = buildConfiguration(); pool.setHeadData(headData); pool.setupWriteStream(fileName); store(pool); pool.finalizeWriteStream(); buildData->setClean(); } void TopLevelProject::load(PersistentPool &pool) { ResolvedProject::load(pool); serializationOp(pool); QBS_CHECK(buildData); } void TopLevelProject::store(PersistentPool &pool) { ResolvedProject::store(pool); serializationOp(pool); } void TopLevelProject::cleanupModuleProviderOutput() { QString error; for (const auto &item : std::as_const(moduleProviderInfo.providers)) { const ModuleProviderInfo &m = item.second; if (m.transientOutput) { if (!removeDirectoryWithContents(m.outputDirPath(buildDirectory), &error)) qCWarning(lcBuildGraph) << "Error removing module provider output:" << error; } } QDir moduleProviderBaseDir(buildDirectory + QLatin1Char('/') + ModuleProviderInfo::outputBaseDirName()); if (moduleProviderBaseDir.exists() && moduleProviderBaseDir.isEmpty() && !removeDirectoryWithContents(moduleProviderBaseDir.path(), &error)) { qCWarning(lcBuildGraph) << "Error removing module provider output:" << error; } } /*! * \class SourceWildCards * \brief Objects of the \c SourceWildCards class result from giving wildcards in a * \c ResolvedGroup's "files" binding. * \sa ResolvedGroup */ /*! * \variable SourceWildCards::prefix * \brief Inherited from the \c ResolvedGroup * \sa ResolvedGroup */ /*! * \variable SourceWildCards::patterns * \brief All elements of the \c ResolvedGroup's "files" binding that contain wildcards. * \sa ResolvedGroup */ /*! * \variable SourceWildCards::excludePatterns * \brief Corresponds to the \c ResolvedGroup's "excludeFiles" binding. * \sa ResolvedGroup */ /*! * \variable SourceWildCards::files * \brief The \c SourceArtifacts resulting from the expanded list of matching files. */ void SourceWildCards::expandPatterns() { dirTimeStamps.clear(); expandedFiles = expandPatterns(patterns) - expandPatterns(excludePatterns); } Set SourceWildCards::expandPatterns(const QStringList &patterns) { Set files; QString expandedPrefix = prefix; if (expandedPrefix.startsWith(StringConstants::tildeSlash())) expandedPrefix.replace(0, 1, QDir::homePath()); for (QString pattern : patterns) { pattern.prepend(expandedPrefix); pattern.replace(QLatin1Char('\\'), QLatin1Char('/')); QStringList parts = pattern.split(QLatin1Char('/'), Qt::SkipEmptyParts); if (FileInfo::isAbsolute(pattern)) { QString rootDir; if (HostOsInfo::isWindowsHost() && pattern.at(0) != QLatin1Char('/')) { rootDir = parts.takeFirst(); if (!rootDir.endsWith(QLatin1Char('/'))) rootDir.append(QLatin1Char('/')); } else { rootDir = QLatin1Char('/'); } expandPatterns(files, parts, rootDir); } else { expandPatterns(files, parts, baseDir); } } return files; } void SourceWildCards::expandPatterns(Set &result, const QStringList &parts, const QString &baseDir) { // People might build directly in the project source directory. This is okay, since // we keep the build data in a "container" directory. However, we must make sure we don't // match any generated files therein as source files. if (baseDir.startsWith(buildDir)) return; QStringList changed_parts = parts; bool recursive = false; QString part = changed_parts.takeFirst(); while (part == QStringLiteral("**")) { recursive = true; if (changed_parts.empty()) { part = StringConstants::star(); break; } part = changed_parts.takeFirst(); } const bool isDir = !changed_parts.empty(); const QString &filePattern = part; const QDirIterator::IteratorFlags itFlags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; QDir::Filters itFilters = isDir ? QDir::Dirs : QDir::Files | QDir::System | QDir::Dirs; // This one is needed to get symbolic links to directories if (FileInfo::isPattern(filePattern)) { if (!recursive) dirTimeStamps.emplace_back(baseDir, FileInfo(baseDir).lastModified()); } else if (isDir) { itFilters |= QDir::Hidden; } if (filePattern != StringConstants::dotDot() && filePattern != StringConstants::dot()) itFilters |= QDir::NoDotAndDotDot; QDirIterator it(baseDir, QStringList(filePattern), itFilters, itFlags); while (it.hasNext()) { const QString filePath = it.next(); const QString parentDir = it.fileInfo().dir().path(); if (parentDir.startsWith(buildDir)) continue; // See above. if (!isDir && it.fileInfo().isDir() && !it.fileInfo().isSymLink()) continue; if (isDir) expandPatterns(result, changed_parts, filePath); else result += QDir::cleanPath(filePath); } } bool SourceWildCards::hasChangedSinceExpansion() const { const bool reExpansionRequired = Internal::any_of(dirTimeStamps, [](const std::pair &pair) { return FileInfo(pair.first).lastModified() > pair.second; }); if (reExpansionRequired) return true; auto wc = *this; wc.expandPatterns(); return this->expandedFiles != wc.expandedFiles; } template QMap listToMap(const L &list) { using V = typename L::value_type; QMap map; for (const V &elem : list) map.insert(keyFromElem(elem), elem); return map; } template bool listsAreEqual(const L &l1, const L &l2) { if (l1.size() != l2.size()) return false; using V = typename L::value_type; const QMap map1 = listToMap(l1); const QMap map2 = listToMap(l2); const auto keys = map1.keys(); return Internal::all_of(keys, [&map1, &map2](const auto &key) { const V &value2 = map2.value(key); if (!value2) return false; return equals(map1.value(key).get(), value2.get()); }); } QString keyFromElem(const SourceArtifactPtr &sa) { return sa->absoluteFilePath; } QString keyFromElem(const RulePtr &r) { QString key = r->toString() + r->prepareScript.sourceCode(); if (r->outputArtifactsScript.isValid()) key += r->outputArtifactsScript.sourceCode(); for (const auto &a : r->artifacts) key += a->filePath; return key; } QString keyFromElem(const ArtifactPropertiesPtr &ap) { QStringList lst = ap->fileTagsFilter().toStringList(); lst.sort(); return lst.join(QLatin1Char(',')); } bool operator==(const SourceArtifactInternal &sa1, const SourceArtifactInternal &sa2) { return sa1.absoluteFilePath == sa2.absoluteFilePath && sa1.fileTags == sa2.fileTags && sa1.overrideFileTags == sa2.overrideFileTags && sa1.targetOfModule == sa2.targetOfModule && !sa1.properties == !sa2.properties && *sa1.properties == *sa2.properties; } bool operator==(const Rule &r1, const Rule &r2) { if (r1.artifacts.size() != r2.artifacts.size()) return false; for (size_t i = 0; i < r1.artifacts.size(); ++i) { if (!equals(r1.artifacts.at(i).get(), r2.artifacts.at(i).get())) return false; } return r1.module->name == r2.module->name && r1.prepareScript == r2.prepareScript && r1.outputArtifactsScript == r2.outputArtifactsScript && r1.inputs == r2.inputs && r1.outputFileTags == r2.outputFileTags && r1.auxiliaryInputs == r2.auxiliaryInputs && r1.auxiliaryInputsFromDependencies == r2.auxiliaryInputsFromDependencies && r1.excludedInputs == r2.excludedInputs && r1.inputsFromDependencies == r2.inputsFromDependencies && r1.explicitlyDependsOn == r2.explicitlyDependsOn && r1.explicitlyDependsOnFromDependencies == r2.explicitlyDependsOnFromDependencies && r1.multiplex == r2.multiplex && r1.requiresInputs == r2.requiresInputs && r1.alwaysRun == r2.alwaysRun; } bool ruleListsAreEqual(const std::vector &l1, const std::vector &l2) { return listsAreEqual(l1, l2); } bool operator==(const RuleArtifact &a1, const RuleArtifact &a2) { return a1.filePath == a2.filePath && a1.fileTags == a2.fileTags && a1.alwaysUpdated == a2.alwaysUpdated && rangeTo>(a1.bindings) == rangeTo>(a2.bindings); } bool operator==(const RuleArtifact::Binding &b1, const RuleArtifact::Binding &b2) { return b1.code == b2.code && b1.name == b2.name; } QHashValueType qHash(const RuleArtifact::Binding &b) { return qHash(std::make_pair(b.code, b.name.join(QLatin1Char(',')))); } bool artifactPropertyListsAreEqual(const std::vector &l1, const std::vector &l2) { return listsAreEqual(l1, l2); } bool operator==(const PrivateScriptFunction &a, const PrivateScriptFunction &b) { return equals(a.m_sharedData.get(), b.m_sharedData.get()); } bool operator==(const ExportedProperty &p1, const ExportedProperty &p2) { return p1.fullName == p2.fullName && p1.type == p2.type && p1.sourceCode == p2.sourceCode && p1.isBuiltin == p2.isBuiltin; } bool operator==(const ExportedModuleDependency &d1, const ExportedModuleDependency &d2) { return d1.name == d2.name && qVariantMapsEqual(d1.moduleProperties, d2.moduleProperties); } bool equals(const std::vector &l1, const std::vector &l2) { static const auto cmp = [](const ExportedItemPtr &p1, const ExportedItemPtr &p2) { return *p1 == *p2; }; return l1.size() == l2.size() && std::equal(l1.cbegin(), l1.cend(), l2.cbegin(), cmp); } bool operator==(const ExportedItem &i1, const ExportedItem &i2) { return i1.name == i2.name && i1.properties == i2.properties && equals(i1.children, i2.children); } bool operator==(const ExportedModule &m1, const ExportedModule &m2) { static const auto depMapsEqual = [](const QMap &m1, const QMap &m2) { if (m1.size() != m2.size()) return false; for (auto it1 = m1.cbegin(), it2 = m2.cbegin(); it1 != m1.cend(); ++it1, ++it2) { if (it1.key()->name != it2.key()->name) return false; if (!qVariantMapsEqual(it1.value(), it2.value())) return false; } return true; }; return qVariantMapsEqual(m1.propertyValues, m2.propertyValues) && qVariantMapsEqual(m1.modulePropertyValues, m2.modulePropertyValues) && equals(m1.children, m2.children) && m1.m_properties == m2.m_properties && m1.importStatements == m2.importStatements && m1.productDependencies.size() == m2.productDependencies.size() && m1.productDependencies == m2.productDependencies && depMapsEqual(m1.dependencyParameters, m2.dependencyParameters); } JSValue PrivateScriptFunction::getFunction(ScriptEngine *engine, const QString &errorMessage) const { if (JS_IsUndefined(scriptFunction)) { ScopedJsValue val(engine->context(), engine->evaluate(JsValueOwner::Caller, sourceCode(), location().filePath(), location().line())); if (Q_UNLIKELY(!JS_IsFunction(engine->context(), val))) throw ErrorInfo(errorMessage, location()); scriptFunction = val.release(); engine->addExternallyCachedValue(&scriptFunction); } else { QBS_CHECK(JS_IsFunction(engine->context(), scriptFunction)); } return scriptFunction; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/filecontext.cpp0000644000175100001660000000437214776170045022245 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filecontext.h" #include "item.h" namespace qbs { namespace Internal { FileContext::FileContext() : m_idScope(nullptr) { } FileContextPtr FileContext::create() { return FileContextPtr(new FileContext); } void FileContext::ensureIdScope(ItemPool *itemPool) { if (!m_idScope) m_idScope = Item::create(itemPool, ItemType::IdScope); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/scriptengine.h0000644000175100001660000004427114776170045022062 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_SCRIPTENGINE_H #define QBS_SCRIPTENGINE_H #include "forward_decls.h" #include "property.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { class Version; namespace Internal { class Artifact; class Evaluator; class JsImport; class PrepareScriptObserver; class RuleNode; class ScriptImporter; class ScriptPropertyObserver; enum class EvalContext { PropertyEvaluation, ProbeExecution, ModuleProvider, RuleExecution, JsCommand }; class DubiousContext { public: enum Suggestion { NoSuggestion, SuggestMoving }; DubiousContext(EvalContext c, Suggestion s = NoSuggestion) : context(c), suggestion(s) { } EvalContext context; Suggestion suggestion; }; using DubiousContextList = std::vector; enum class JsValueOwner { Caller, ScriptEngine }; // TODO: This smells like cheating. Should always be Caller. enum class ObserveMode { Enabled, Disabled }; class QBS_AUTOTEST_EXPORT ScriptEngine { struct PrivateTag {}; public: ScriptEngine(Logger &logger, EvalContext evalContext, PrivateTag); ~ScriptEngine(); static std::unique_ptr create(Logger &logger, EvalContext evalContext); static ScriptEngine *engineForRuntime(const JSRuntime *runtime); static ScriptEngine *engineForContext(const JSContext *ctx); static LookupResult doExtraScopeLookup(JSContext *ctx, JSAtom prop); void reset(); Logger &logger() const { return m_logger; } void import(const FileContextBaseConstPtr &fileCtx, JSValue &targetObject, ObserveMode observeMode); void clearImportsCache(); void registerEvaluator(Evaluator *evaluator); void unregisterEvaluator(const Evaluator *evaluator); Evaluator *evaluator() const { return m_evaluator; } void setEvalContext(EvalContext c) { m_evalContext = c; } EvalContext evalContext() const { return m_evalContext; } void checkContext(const QString &operation, const DubiousContextList &dubiousContexts); void setSetupProjectParameters(const SetupProjectParameters ¶ms) { m_setupParams = params; } void handleDeprecation( const Version &removalVersion, const QString &message, const CodeLocation &loc); void addPropertyRequestedInScript(const Property &property) { m_propertiesRequestedInScript += property; } void addDependenciesArrayRequested(const ResolvedProduct *p) { m_productsWithRequestedDependencies.insert(p); } void setArtifactsMapRequested(const ResolvedProduct *product, bool forceUpdate) { m_requestedArtifacts.setAllArtifactTags(product, forceUpdate); } void setArtifactSetRequestedForTag(const ResolvedProduct *product, const FileTag &tag) { m_requestedArtifacts.setArtifactsForTag(product, tag); } void setNonExistingArtifactSetRequested(const ResolvedProduct *product, const QString &tag) { m_requestedArtifacts.setNonExistingTagRequested(product, tag); } void setArtifactsEnumerated(const ResolvedProduct *product) { m_requestedArtifacts.setArtifactsEnumerated(product); } void addPropertyRequestedFromArtifact(const Artifact *artifact, const Property &property); void addRequestedExport(const ResolvedProduct *product) { m_requestedExports.insert(product); } void clearRequestedProperties(); PropertySet propertiesRequestedInScript() const { return m_propertiesRequestedInScript; } QHash propertiesRequestedFromArtifact() const { return m_propertiesRequestedFromArtifact; } Set productsWithRequestedDependencies() const { return m_productsWithRequestedDependencies; } RequestedDependencies requestedDependencies() const { return RequestedDependencies(m_productsWithRequestedDependencies); } RequestedArtifacts requestedArtifacts() const { return m_requestedArtifacts; } Set requestedExports() const { return m_requestedExports; } void addImportRequestedInScript(quintptr importValueId); std::vector importedFilesUsedInScript() const; void addExternallyCachedValue(JSValue *v) { m_externallyCachedValues.push_back(v); } void setUsesIo() { m_usesIo = true; } void clearUsesIo() { m_usesIo = false; } bool usesIo() const { return m_usesIo; } void enableProfiling(bool enable); void setPropertyCacheEnabled(bool enable) { m_propertyCacheEnabled = enable; } bool isPropertyCacheEnabled() const { return m_propertyCacheEnabled; } void addToPropertyCache(const QString &moduleName, const QString &propertyName, const PropertyMapConstPtr &propertyMap, const QVariant &value); QVariant retrieveFromPropertyCache(const QString &moduleName, const QString &propertyName, const PropertyMapConstPtr &propertyMap); void setObservedProperty(JSValue &object, const QString &name, const JSValue &value); void unobserveProperties(); PrepareScriptObserver *observer() const { return m_observer.get(); } QProcessEnvironment environment() const; void setEnvironment(const QProcessEnvironment &env); void addCanonicalFilePathResult(const QString &filePath, const QString &resultFilePath); void addFileExistsResult(const QString &filePath, bool exists); void addDirectoryEntriesResult(const QString &path, QDir::Filters filters, const QStringList &entries); void addFileLastModifiedResult(const QString &filePath, const FileTime &fileTime); QHash canonicalFilePathResults() const { return m_canonicalFilePathResult; } QHash fileExistsResults() const { return m_fileExistsResult; } QHash, QStringList> directoryEntriesResults() const { return m_directoryEntriesResult; } QHash fileLastModifiedResults() const { return m_fileLastModifiedResult; } Set imports() const; JSValue newObject() const; JSValue newArray(int length, JsValueOwner owner); void takeOwnership(JSValue v); JSValue undefinedValue() const { return JS_UNDEFINED; } JSValue toScriptValue(const QVariant &v, quintptr id = 0) { return asJsValue(v, id); } JSValue evaluate( JsValueOwner resultOwner, const QString &code, const QString &filePath = QString(), int line = 1, qbs::Internal::span scopeChain = {}); void setLastLookupStatus(bool success) { m_lastLookupWasSuccess = success; } JSContext *context() const { return m_context; } JSValue globalObject() const { return m_globalObject; } void setGlobalObject(JSValue obj) { m_globalObject = obj; } void handleJsProperties(JSValueConst obj, const PropertyHandler &handler); ScopedJsValueList argumentList(const QStringList &argumentNames, const JSValue &context) const; using GetProperty = int (*)(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop); using GetPropertyNames = int (*)(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj); JSClassID registerClass(const char *name, JSClassCall *constructor, JSClassFinalizer *finalizer, JSValue scope, GetPropertyNames getPropertyNames = nullptr, GetProperty getProperty = nullptr); JSClassID getClassId(const char *name) const; JsException checkAndClearException(const CodeLocation &fallbackLocation) const; JSValue throwError(const QString &message) const; void cancel(); // The active flag is different from QScriptEngine::isEvaluating. // It is set and cleared externally for example by the rule execution code. bool isActive() const { return m_active; } void setActive(bool on) { m_active = on; } JSClassID modulePropertyScriptClass() const; void setModulePropertyScriptClass(JSClassID modulePropertyScriptClass); JSClassID productPropertyScriptClass() const { return m_productPropertyScriptClass; } void setProductPropertyScriptClass(JSClassID productPropertyScriptClass) { m_productPropertyScriptClass = productPropertyScriptClass; } JSClassID artifactsScriptClass(int index) const { return m_artifactsScriptClass[index]; } void setArtifactsScriptClass(int index, JSClassID artifactsScriptClass) { m_artifactsScriptClass[index] = artifactsScriptClass; } JSValue artifactsMapScriptValue(const ResolvedProduct *product); void setArtifactsMapScriptValue(const ResolvedProduct *product, JSValue value); JSValue artifactsMapScriptValue(const ResolvedModule *module); void setArtifactsMapScriptValue(const ResolvedModule *module, JSValue value); JSValue getArtifactProperty(JSValue obj, const std::function &propGetter); JSValue& baseProductScriptValue(const ResolvedProduct *product) { return m_baseProductScriptValues[product]; } JSValue &projectScriptValue(const ResolvedProject *project) { return m_projectScriptValues[project]; } JSValue &baseModuleScriptValue(const ResolvedModule *module) { return m_baseModuleScriptValues[module]; } JSValue getArtifactScriptValue(Artifact *a, const QString &moduleName, const std::function &setup); void releaseInputArtifactScriptValues(const RuleNode *ruleNode); const JSValueList &contextStack() const { return m_contextStack; } JSClassID dataWithPtrClass() const { return m_dataWithPtrClass; } JSValue getInternalExtension(const char *name) const; void addInternalExtension(const char *name, JSValue ext); JSValue asJsValue(const QVariant &v, quintptr id = 0, bool frozen = false); JSValue asJsValue(const QByteArray &s); JSValue asJsValue(const QString &s); JSValue asJsValue(const QStringList &l); JSValue asJsValue(const QVariantList &l, quintptr id = 0, bool frozen = false); JSValue asJsValue(const QVariantMap &m, quintptr id = 0, bool frozen = false); QVariant property(const char *name) const { return m_properties.value(QLatin1String(name)); } void setProperty(const char *k, const QVariant &v) { m_properties.insert(QLatin1String(k), v); } private: class Importer { public: Importer(ScriptEngine &engine, const FileContextBaseConstPtr &fileCtx, JSValue &targetObject, ObserveMode observeMode); ~Importer(); void run(); private: ScriptEngine &m_engine; const FileContextBaseConstPtr &m_fileCtx; JSValue &m_targetObject; }; static int interruptor(JSRuntime *rt, void *opaqueEngine); bool gatherFileResults() const; void setMaxStackSize(); void setPropertyOnGlobalObject(const QString &property, JSValue value); void installQbsBuiltins(); void extendJavaScriptBuiltins(); void installConsoleFunction(JSValue consoleObj, const QString &name, LoggerLevel level); void installImportFunctions(JSValue importScope); void uninstallImportFunctions(); void import(const JsImport &jsImport, JSValue &targetObject); void observeImport(JSValue &jsImport); void importFile(const QString &filePath, JSValue targetObject); static JSValue js_require(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); JSValue mergeExtensionObjects(const JSValueList &lst); JSValue loadInternalExtension(const QString &uri); static void handleUndefinedFound(JSContext *ctx); static void handleFunctionEntered(JSContext *ctx, JSValue this_obj); static void handleFunctionExited(JSContext *ctx); class PropertyCacheKey { public: PropertyCacheKey(QString moduleName, QString propertyName, PropertyMapConstPtr propertyMap); private: const QString m_moduleName; const QString m_propertyName; const PropertyMapConstPtr m_propertyMap; friend bool operator==(const PropertyCacheKey &lhs, const PropertyCacheKey &rhs); friend QHashValueType qHash(const ScriptEngine::PropertyCacheKey &k, QHashValueType seed); }; friend bool operator==(const PropertyCacheKey &lhs, const PropertyCacheKey &rhs); friend QHashValueType qHash(const ScriptEngine::PropertyCacheKey &k, QHashValueType seed); JSRuntime * const m_jsRuntime = JS_NewRuntime(); JSContext * const m_context = JS_NewContext(m_jsRuntime); JSValue m_globalObject = JS_NULL; ScriptImporter *m_scriptImporter; JSClassID m_modulePropertyScriptClass = 0; JSClassID m_productPropertyScriptClass = 0; JSClassID m_artifactsScriptClass[2] = {0, 0}; JSClassID m_dataWithPtrClass = 0; Evaluator *m_evaluator = nullptr; QHash m_jsImportCache; std::unordered_map m_jsFileCache; bool m_propertyCacheEnabled = true; bool m_active = false; std::atomic_bool m_canceling = false; QHash m_propertyCache; PropertySet m_propertiesRequestedInScript; QHash m_propertiesRequestedFromArtifact; Logger &m_logger; QProcessEnvironment m_environment; QHash m_canonicalFilePathResult; QHash m_fileExistsResult; QHash, QStringList> m_directoryEntriesResult; QHash m_fileLastModifiedResult; std::stack m_currentDirPathStack; std::stack m_extensionSearchPathsStack; std::stack> m_evalPositions; JSValue m_qbsObject = JS_UNDEFINED; qint64 m_elapsedTimeImporting = -1; bool m_usesIo = false; EvalContext m_evalContext; const std::unique_ptr m_observer; std::vector> m_observedProperties; JSValueList m_requireResults; std::unordered_map> m_filePathsPerImport; std::vector m_importsRequestedInScript; Set m_productsWithRequestedDependencies; RequestedArtifacts m_requestedArtifacts; Set m_requestedExports; ObserveMode m_observeMode = ObserveMode::Disabled; std::unordered_map m_baseProductScriptValues; std::unordered_map m_productArtifactsMapScriptValues; std::unordered_map m_moduleArtifactsMapScriptValues; std::unordered_map m_projectScriptValues; std::unordered_map m_baseModuleScriptValues; std::vector> m_scopeChains; JSValueList m_contextStack; QHash m_exoticMethods; QHash m_classes; QHash m_internalExtensions; QHash m_stringCache; QHash m_jsValueCache; QHash m_evalResults; std::vector m_externallyCachedValues; QHash, JSValue> m_artifactsScriptValues; QVariantMap m_properties; std::recursive_mutex m_artifactsMutex; std::optional m_setupParams; bool m_lastLookupWasSuccess = false; }; class EvalContextSwitcher { public: EvalContextSwitcher(ScriptEngine *engine, EvalContext newContext) : m_engine(engine), m_oldContext(engine->evalContext()) { engine->setEvalContext(newContext); } ~EvalContextSwitcher() { m_engine->setEvalContext(m_oldContext); } private: ScriptEngine * const m_engine; const EvalContext m_oldContext; }; } // namespace Internal } // namespace qbs #endif // QBS_SCRIPTENGINE_H qbs-src-2.6.1/src/lib/corelib/language/itemdeclaration.cpp0000644000175100001660000000521114776170045023056 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "itemdeclaration.h" namespace qbs { namespace Internal { ItemDeclaration::ItemDeclaration(ItemType type) : m_type(type) { } ItemDeclaration &ItemDeclaration::operator<<(const PropertyDeclaration &decl) { m_properties.push_back(decl); return *this; } bool ItemDeclaration::isChildTypeAllowed(ItemType type) const { if (m_type > ItemType::LastActualItem || type > ItemType::LastActualItem) return true; return m_allowedChildTypes.contains(type); } ErrorInfo ItemDeclaration::checkForDeprecation(DeprecationWarningMode mode, const QString &name, const CodeLocation &loc, Logger &logger) const { return deprecationInfo().checkForDeprecation(mode, name, loc, true, logger); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/filetags.h0000644000175100001660000000570514776170045021165 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FILETAGS_H #define QBS_FILETAGS_H #include #include #include #include namespace qbs { namespace Internal { class PersistentPool; class FileTag : public Id { public: FileTag() : Id() {} FileTag(const Id &other) : Id(other) {} FileTag(const char *str) : Id(str) {} explicit FileTag(const QByteArray &ba) : Id(ba) {} void clear(); void store(PersistentPool &pool) const; void load(PersistentPool &pool); }; template<> inline bool Set::sortAfterLoadRequired() const { return true; } QDebug operator<<(QDebug debug, const FileTag &tag); class FileTags : public Set { public: FileTags() : Set() {} FileTags(const std::initializer_list &list) : Set(list) {} static FileTags fromStringList(const QStringList &strings); }; LogWriter operator <<(LogWriter w, const FileTags &tags); QDebug operator<<(QDebug debug, const FileTags &tags); } // namespace Internal } // namespace qbs #endif // QBS_FILETAGS_H qbs-src-2.6.1/src/lib/corelib/language/scriptimporter.cpp0000644000175100001660000001253214776170045023004 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scriptimporter.h" #include "evaluator.h" #include "scriptengine.h" #include #include #include #include #include namespace qbs { namespace Internal { class IdentifierExtractor : private QbsQmlJS::AST::Visitor { public: void start(QbsQmlJS::AST::Node *node) { m_first = true; m_barrier = false; m_suffix += QLatin1String("\nreturn {"); if (node) node->accept(this); m_suffix += QLatin1String("}})()"); } const QString &suffix() const { return m_suffix; } private: bool visit(QbsQmlJS::AST::SourceElements *) override { // Only consider the top level of source elements. if (m_barrier) return false; m_barrier = true; return true; } void endVisit(QbsQmlJS::AST::SourceElements *) override { m_barrier = false; } bool visit(QbsQmlJS::AST::FunctionSourceElement *fse) override { add(fse->declaration->name); return false; } bool visit(QbsQmlJS::AST::VariableDeclaration *vd) override { add(vd->name); return false; } void add(QStringView name) { if (m_first) { m_first = false; m_suffix.reserve(m_suffix.length() + name.length() * 2 + 1); } else { m_suffix.reserve(m_suffix.length() + name.length() * 2 + 2); m_suffix += QLatin1Char(','); } // ugly, but qt5 does not have append overload for QStringView m_suffix.append(name.data(), name.size()); m_suffix.append(QLatin1Char(':')); m_suffix.append(name.data(), name.size()); } bool m_first = false; bool m_barrier = false; QString m_suffix; }; ScriptImporter::ScriptImporter(ScriptEngine *scriptEngine) : m_engine(scriptEngine) { } JSValue ScriptImporter::importSourceCode(const QString &sourceCode, const QString &filePath, JSValue &targetObject) { Q_ASSERT(JS_IsObject(targetObject)); // The targetObject doesn't get overwritten but enhanced by the contents of the .js file. // This is necessary for library imports that consist of multiple js files. QString &code = m_sourceCodeCache[filePath]; if (code.isEmpty()) { QbsQmlJS::Engine engine; QbsQmlJS::Lexer lexer(&engine); lexer.setCode(sourceCode, 1, false); QbsQmlJS::Parser parser(&engine); if (!parser.parseProgram()) { throw ErrorInfo(parser.errorMessage(), CodeLocation(filePath, parser.errorLineNumber(), parser.errorColumnNumber())); } IdentifierExtractor extractor; extractor.start(parser.rootNode()); code = QLatin1String("(function(){\n") + sourceCode + extractor.suffix(); } ScopedJsValue result(m_engine->context(), m_engine->evaluate(JsValueOwner::Caller, code, filePath, 0)); throwOnEvaluationError(m_engine, [&filePath] () { return CodeLocation(filePath, 0); }); copyProperties(m_engine->context(), result, targetObject); return result.release(); } void ScriptImporter::copyProperties(JSContext *ctx, const JSValue &src, JSValue &dst) { handleJsProperties(ctx, src, [ctx, &dst](const JSAtom &name, const JSPropertyDescriptor &desc) { JS_SetProperty(ctx, dst, name, JS_DupValue(ctx, desc.value)); }); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/itempool.cpp0000644000175100001660000000434314776170045021547 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "itempool.h" #include "item.h" namespace qbs { namespace Internal { ItemPool::ItemPool() = default; ItemPool::~ItemPool() { for (Item *item : m_items) item->~Item(); } Item *ItemPool::allocateItem(const ItemType &type) { const auto item = new (&m_pool) Item(type); m_items.push_back(item); return item; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/propertymapinternal.cpp0000644000175100001660000001001214776170045024024 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "propertymapinternal.h" #include #include #include namespace qbs { namespace Internal { /*! * \class PropertyMapInternal * \brief The \c PropertyMapInternal class contains a set of properties and their values. * An instance of this class is attached to every \c ResolvedProduct. * \c ResolvedGroups inherit their properties from the respective \c ResolvedProduct, \c SourceArtifacts * inherit theirs from the respective \c ResolvedGroup. \c ResolvedGroups can override the value of an * inherited property, \c SourceArtifacts cannot. If a property value is overridden, a new * \c PropertyMapInternal object is allocated, otherwise the pointer is shared. * \sa ResolvedGroup * \sa ResolvedProduct * \sa SourceArtifact */ PropertyMapInternal::PropertyMapInternal() = default; PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) = default; QVariant PropertyMapInternal::moduleProperty(const QString &moduleName, const QString &key, bool *isPresent) const { return ::qbs::Internal::moduleProperty(m_value, moduleName, key, isPresent); } QVariant PropertyMapInternal::qbsPropertyValue(const QString &key) const { return moduleProperty(StringConstants::qbsModule(), key); } QVariant PropertyMapInternal::property(const QStringList &name) const { return getConfigProperty(m_value, name); } void PropertyMapInternal::setValue(const QVariantMap &map) { m_value = map; } QVariant moduleProperty(const QVariantMap &properties, const QString &moduleName, const QString &key, bool *isPresent) { const auto moduleIt = properties.find(moduleName); if (moduleIt == properties.end()) { if (isPresent) *isPresent = false; return {}; } const QVariantMap &moduleMap = moduleIt.value().toMap(); const auto propertyIt = moduleMap.find(key); if (propertyIt == moduleMap.end()) { if (isPresent) *isPresent = false; return {}; } if (isPresent) *isPresent = true; return propertyIt.value(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/scriptpropertyobserver.cpp0000644000175100001660000000420514776170045024575 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scriptpropertyobserver.h" #include "scriptengine.h" namespace qbs { namespace Internal { ScriptPropertyObserver::~ScriptPropertyObserver() { if (m_unobserveMode == UnobserveMode::Enabled) m_engine->unobserveProperties(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/artifactproperties.h0000644000175100001660000000612214776170045023273 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ARTIFACTPROPERTIES_H #define QBS_ARTIFACTPROPERTIES_H #include "filetags.h" #include "forward_decls.h" #include namespace qbs { namespace Internal { class ArtifactProperties { public: static ArtifactPropertiesPtr create(); void setFileTagsFilter(const FileTags &filter) { m_fileTagsFilter = filter; } FileTags fileTagsFilter() const { return m_fileTagsFilter; } PropertyMapPtr propertyMap() const { return m_propertyMap; } void setPropertyMapInternal(const PropertyMapPtr &pmap) { m_propertyMap = pmap; } FileTags extraFileTags() const; void addExtraFileTags(const FileTags &extraFileTags); template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_fileTagsFilter, m_extraFileTags, m_propertyMap); } private: ArtifactProperties(); FileTags m_fileTagsFilter; FileTags m_extraFileTags; PropertyMapPtr m_propertyMap; }; bool operator==(const ArtifactProperties &ap1, const ArtifactProperties &ap2); inline bool operator!=(const ArtifactProperties &ap1, const ArtifactProperties &ap2) { return !(ap1 == ap2); } } // namespace Internal } // namespace qbs #endif // QBS_ARTIFACTPROPERTIES_H qbs-src-2.6.1/src/lib/corelib/language/identifiersearch.cpp0000644000175100001660000000532714776170045023232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "identifiersearch.h" #include namespace qbs { namespace Internal { IdentifierSearch::IdentifierSearch() = default; void IdentifierSearch::start(QbsQmlJS::AST::Node *node) { for (auto it = m_requests.cbegin(); it != m_requests.cend(); ++it) *it.value() = false; m_numberOfFoundIds = 0; node->accept(this); } void IdentifierSearch::add(const QString &name, bool *found) { m_requests.insert(name, found); } bool IdentifierSearch::preVisit(QbsQmlJS::AST::Node *) { return m_numberOfFoundIds < m_requests.size(); } bool IdentifierSearch::visit(QbsQmlJS::AST::IdentifierExpression *e) { bool *found = m_requests.value(e->name.toString()); if (found && !*found) { *found = true; m_numberOfFoundIds++; } return m_numberOfFoundIds < m_requests.size(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/filecontext.h0000644000175100001660000000501514776170045021705 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FILECONTEXT_H #define QBS_FILECONTEXT_H #include "filecontextbase.h" #include "forward_decls.h" #include namespace qbs { namespace Internal { class Item; class ItemPool; class FileContext : public FileContextBase { public: static FileContextPtr QBS_AUTOTEST_EXPORT create(); void setContent(const QString &content) { m_content = content; } const QString &content() const { return m_content; } Item *idScope() const { return m_idScope; } void ensureIdScope(ItemPool *itemPool); private: FileContext(); QString m_content; Item *m_idScope; }; } // namespace Internal } // namespace qbs #endif // QBS_FILECONTEXT_H qbs-src-2.6.1/src/lib/corelib/language/evaluator.h0000644000175100001660000001416514776170045021371 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_EVALUATOR_H #define QBS_EVALUATOR_H #include "forward_decls.h" #include "itemobserver.h" #include "qualifiedid.h" #include #include #include #include #include #include namespace qbs { namespace Internal { class EvaluationData; class FileTags; class Logger; class PropertyDeclaration; class ScriptEngine; class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver { friend class SVConverter; public: Evaluator(ScriptEngine *scriptEngine); ~Evaluator() override; ScriptEngine *engine() const { return m_scriptEngine; } JSClassID classId() const { return m_scriptClass; } JSValue property(const Item *item, const QString &name); JSValue value(const Item *item, const QString &name, bool *propertySet = nullptr); bool boolValue(const Item *item, const QString &name, bool *propertyWasSet = nullptr); int intValue(const Item *item, const QString &name, int defaultValue = 0, bool *propertyWasSet = nullptr); FileTags fileTagsValue(const Item *item, const QString &name, bool *propertySet = nullptr); QString stringValue(const Item *item, const QString &name, const QString &defaultValue = QString(), bool *propertyWasSet = nullptr); QStringList stringListValue(const Item *item, const QString &name, bool *propertyWasSet = nullptr); std::optional optionalStringListValue(const Item *item, const QString &name, bool *propertyWasSet = nullptr); QVariant variantValue(const Item *item, const QString &name, bool *propertySet = nullptr); void convertToPropertyType(const PropertyDeclaration& decl, const CodeLocation &loc, JSValue &v); JSValue scriptValue(const Item *item); struct FileContextScopes { JSValue fileScope = JS_UNDEFINED; JSValue importScope = JS_UNDEFINED; }; FileContextScopes fileContextScopes(const FileContextConstPtr &file); void setCachingEnabled(bool enabled) { m_valueCacheEnabled = enabled; } bool cachingEnabled() const { return m_valueCacheEnabled; } void clearCache(const Item *item); void invalidateCache(const Item *item); void clearCacheIfInvalidated(EvaluationData &edata); PropertyDependencies &propertyDependencies() { return m_propertyDependencies; } void clearPropertyDependencies() { m_propertyDependencies.clear(); } std::stack &requestedProperties() { return m_requestedProperties; } void handleEvaluationError(const Item *item, const QString &name); QString pathPropertiesBaseDir() const { return m_pathPropertiesBaseDir; } void setPathPropertiesBaseDir(const QString &dirPath) { m_pathPropertiesBaseDir = dirPath; } void clearPathPropertiesBaseDir() { m_pathPropertiesBaseDir.clear(); } bool isNonDefaultValue(const Item *item, const QString &name) const; private: void onItemPropertyChanged(Item *item) override { invalidateCache(item); } JSValue evaluateProperty(const Item *item, const QString &name, bool *propertyWasSet); void clearCache(EvaluationData &edata); ScriptEngine * const m_scriptEngine; const JSClassID m_scriptClass; mutable QHash m_scriptValueMap; mutable QHash m_fileContextScopesMap; QString m_pathPropertiesBaseDir; PropertyDependencies m_propertyDependencies; std::stack m_requestedProperties; std::mutex m_cacheInvalidationMutex; Set m_invalidatedCaches; bool m_valueCacheEnabled = false; }; void throwOnEvaluationError(ScriptEngine *engine, const std::function &provideFallbackCodeLocation); class EvalCacheEnabler { public: EvalCacheEnabler(Evaluator *evaluator, const QString &baseDir) : m_evaluator(evaluator) { m_evaluator->setCachingEnabled(true); m_evaluator->setPathPropertiesBaseDir(baseDir); } ~EvalCacheEnabler() { reset(); } void reset() { m_evaluator->setCachingEnabled(false); m_evaluator->clearPathPropertiesBaseDir(); } private: Evaluator * const m_evaluator; }; } // namespace Internal } // namespace qbs #endif // QBS_EVALUATOR_H qbs-src-2.6.1/src/lib/corelib/language/moduleproviderinfo.h0000644000175100001660000000766714776170045023314 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_MODULEPROVIDERINFO_H #define QBS_MODULEPROVIDERINFO_H #include "qualifiedid.h" #include #include #include #include #include namespace qbs { namespace Internal { class ModuleProviderInfo { public: ModuleProviderInfo() = default; ModuleProviderInfo(QualifiedId name, QVariantMap config, QStringList searchPaths, bool transientOutput) : name(std::move(name)) , config(std::move(config)) , searchPaths(std::move(searchPaths)) , transientOutput(transientOutput) {} static QString outputBaseDirName() { return QStringLiteral("genmodules"); } static QString outputDirPath(const QString &baseDir, const QualifiedId &name) { return baseDir + QLatin1Char('/') + outputBaseDirName() + QLatin1Char('/') + name.toString(); } QString outputDirPath(const QString &baseDir) const { return outputDirPath(baseDir, name); } template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp( reinterpret_cast(name), config, providerFile, searchPaths); } QualifiedId name; QVariantMap config; QString providerFile; bool isEager{true}; QStringList searchPaths; QHash searchPathsByModule; bool transientOutput = false; // Not to be serialized. }; using ModuleProvidersCacheKey = std::tuple< QString /*name*/, QString /*moduleName*/, QVariantMap /*config*/, QVariantMap /*qbsModule*/, int /*lookup*/ >; using ModuleProvidersCache = std::unordered_map; // Persistent info stored between sessions class StoredModuleProviderInfo { public: ModuleProvidersCache providers; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(providers); } }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/language/builtindeclarations.cpp0000644000175100001660000006775614776170045023777 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "builtindeclarations.h" #include "deprecationinfo.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { class AClassWithPublicConstructor : public BuiltinDeclarations { }; Q_GLOBAL_STATIC(AClassWithPublicConstructor, theInstance) const char QBS_LANGUAGE_VERSION[] = "1.0"; BuiltinDeclarations::BuiltinDeclarations() : m_languageVersion(Version::fromString(QLatin1String(QBS_LANGUAGE_VERSION))) , m_typeMap(std::initializer_list>({ { QStringLiteral("Artifact"), ItemType::Artifact }, { QStringLiteral("Depends"), ItemType::Depends }, { QStringLiteral("Export"), ItemType::Export }, { QStringLiteral("FileTagger"), ItemType::FileTagger }, { QStringLiteral("Group"), ItemType::Group }, { QStringLiteral("JobLimit"), ItemType::JobLimit }, { QStringLiteral("Module"), ItemType::Module }, { QStringLiteral("ModuleProvider"), ItemType::ModuleProvider }, { QStringLiteral("Parameter"), ItemType::Parameter }, { QStringLiteral("Parameters"), ItemType::Parameters }, { QStringLiteral("Probe"), ItemType::Probe }, { QStringLiteral("Product"), ItemType::Product }, { QStringLiteral("Profile"), ItemType::Profile }, { QStringLiteral("Project"), ItemType::Project }, { QStringLiteral("Properties"), ItemType::Properties }, // Callers have to handle the SubProject case. { QStringLiteral("PropertyOptions"), ItemType::PropertyOptions }, { QStringLiteral("Rule"), ItemType::Rule }, { QStringLiteral("Scanner"), ItemType::Scanner }, { QStringLiteral("SubProject"), ItemType::SubProject }, { QStringLiteral("Transformer"), ItemType::Transformer } })) { addArtifactItem(); addDependsItem(); addExportItem(); addFileTaggerItem(); addGroupItem(); addJobLimitItem(); addModuleItem(); addModuleProviderItem(); addProbeItem(); addProductItem(); addProfileItem(); addProjectItem(); addPropertiesItem(); addPropertyOptionsItem(); addRuleItem(); addSubprojectItem(); addTransformerItem(); addScannerItem(); } const BuiltinDeclarations &BuiltinDeclarations::instance() { return *theInstance; } Version BuiltinDeclarations::languageVersion() const { return m_languageVersion; } QStringList BuiltinDeclarations::allTypeNames() const { return m_typeMap.keys(); } ItemDeclaration BuiltinDeclarations::declarationsForType(ItemType type) const { return m_builtins.value(type); } ItemType BuiltinDeclarations::typeForName(const QString &typeName, const CodeLocation &location) const { const auto it = m_typeMap.constFind(typeName); if (it == m_typeMap.constEnd()) throw ErrorInfo(Tr::tr("Unexpected item type '%1'.").arg(typeName), location); return it.value(); } QString BuiltinDeclarations::nameForType(ItemType itemType) const { // Iterating is okay here, as this mapping is not used in hot code paths. if (itemType == ItemType::PropertiesInSubProject) return QStringLiteral("Properties"); for (auto it = m_typeMap.constBegin(); it != m_typeMap.constEnd(); ++it) { if (it.value() == itemType) return it.key(); } QBS_CHECK(false); return {}; } QStringList BuiltinDeclarations::argumentNamesForScriptFunction(ItemType itemType, const QString &scriptName) const { const ItemDeclaration itemDecl = declarationsForType(itemType); const auto properties = itemDecl.properties(); for (const PropertyDeclaration &propDecl : properties) { if (propDecl.name() == scriptName) return propDecl.functionArgumentNames(); } QBS_CHECK(false); return {}; } void BuiltinDeclarations::insert(const ItemDeclaration &decl) { m_builtins.insert(decl.type(), decl); } static PropertyDeclaration conditionProperty() { return { StringConstants::conditionProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()}; } static PropertyDeclaration alwaysRunProperty() { return { StringConstants::alwaysRunProperty(), PropertyDeclaration::Boolean, StringConstants::falseValue()}; } static PropertyDeclaration nameProperty() { return {StringConstants::nameProperty(), PropertyDeclaration::String}; } static PropertyDeclaration buildDirProperty() { return {StringConstants::buildDirectoryProperty(), PropertyDeclaration::Path}; } static PropertyDeclaration prepareScriptProperty() { PropertyDeclaration decl(StringConstants::prepareProperty(), PropertyDeclaration::Variant, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); decl.setFunctionArgumentNames( QStringList() << StringConstants::projectVar() << StringConstants::productValue() << StringConstants::inputsVar() << StringConstants::outputsVar() << StringConstants::inputVar() << StringConstants::outputVar() << StringConstants::explicitlyDependsOnVar()); return decl; } static PropertyDeclaration priorityProperty() { return {StringConstants::priorityProperty(), PropertyDeclaration::Integer}; } void BuiltinDeclarations::addArtifactItem() { ItemDeclaration item(ItemType::Artifact); PropertyDeclaration conditionDecl = conditionProperty(); conditionDecl.setDeprecationInfo(DeprecationInfo(Version(1, 4), Tr::tr("If you need " "dynamic artifacts, use the Rule.outputArtifacts script instead of Artifact items."))); item << conditionDecl; PropertyDeclaration fileNameDecl(StringConstants::fileNameProperty(), PropertyDeclaration::String); fileNameDecl.setDeprecationInfo(DeprecationInfo(Version(1, 4), Tr::tr("Please use 'filePath' instead."))); item << fileNameDecl; item << PropertyDeclaration(StringConstants::filePathProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::fileTagsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::alwaysUpdatedProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()); insert(item); } void BuiltinDeclarations::addDependsItem() { ItemDeclaration item(ItemType::Depends); item << conditionProperty(); item << nameProperty(); item << PropertyDeclaration(StringConstants::submodulesProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::requiredProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()); item << PropertyDeclaration(StringConstants::versionAtLeastProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::versionBelowProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::profilesProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::productTypesProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::limitToSubProjectProperty(), PropertyDeclaration::Boolean, StringConstants::falseValue()); item << PropertyDeclaration( StringConstants::multiplexConfigurationIdsProperty(), PropertyDeclaration::StringList, QString(), PropertyDeclaration::ReadOnlyFlag); insert(item); } void BuiltinDeclarations::addExportItem() { ItemDeclaration item = moduleLikeItem(ItemType::Export); item << PropertyDeclaration(StringConstants::prefixMappingProperty(), PropertyDeclaration::Variant); auto allowedChildTypes = item.allowedChildTypes(); allowedChildTypes.insert(ItemType::Properties); item.setAllowedChildTypes(allowedChildTypes); insert(item); } void BuiltinDeclarations::addFileTaggerItem() { ItemDeclaration item(ItemType::FileTagger); item << conditionProperty(); item << PropertyDeclaration(StringConstants::patternsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::fileTagsProperty(), PropertyDeclaration::StringList); item << priorityProperty(); insert(item); } void BuiltinDeclarations::addGroupItem() { ItemDeclaration item(ItemType::Group); item.setAllowedChildTypes( {ItemType::Depends, ItemType::FileTagger, ItemType::Group, ItemType::Rule, ItemType::Scanner}); item << conditionProperty(); item << PropertyDeclaration(StringConstants::nameProperty(), PropertyDeclaration::String, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::filesProperty(), PropertyDeclaration::PathList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::fileTagsFilterProperty(), PropertyDeclaration::StringList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::excludeFilesProperty(), PropertyDeclaration::PathList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::fileTagsProperty(), PropertyDeclaration::StringList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::prefixProperty(), PropertyDeclaration::String, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::overrideTagsProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::filesAreTargetsProperty(), PropertyDeclaration::Boolean, StringConstants::falseValue(), PropertyDeclaration::PropertyNotAvailableInConfig); insert(item); } void BuiltinDeclarations::addJobLimitItem() { ItemDeclaration item(ItemType::JobLimit); item << conditionProperty(); item << PropertyDeclaration(StringConstants::jobPoolProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::jobCountProperty(), PropertyDeclaration::Integer); insert(item); } void BuiltinDeclarations::addModuleItem() { ItemDeclaration item = moduleLikeItem(ItemType::Module); item << priorityProperty(); insert(item); } void BuiltinDeclarations::addModuleProviderItem() { ItemDeclaration item(ItemType::ModuleProvider); item << nameProperty() << conditionProperty() << PropertyDeclaration(QStringLiteral("outputBaseDir"), PropertyDeclaration::String) << PropertyDeclaration(StringConstants::isEagerProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()) << PropertyDeclaration(StringConstants::moduleNameProperty(), PropertyDeclaration::String) << PropertyDeclaration(QStringLiteral("relativeSearchPaths"), PropertyDeclaration::StringList); item.setAllowedChildTypes({ItemType::PropertyOptions, ItemType::Probe}); insert(item); } ItemDeclaration BuiltinDeclarations::moduleLikeItem(ItemType type) { ItemDeclaration item(type); item.setAllowedChildTypes({ItemType::Depends, ItemType::FileTagger, ItemType::Group, ItemType::JobLimit, ItemType::Parameter, ItemType::Parameters, ItemType::Probe, ItemType::PropertyOptions, ItemType::Rule, ItemType::Scanner}); PropertyDeclaration nameDecl = nameProperty(); PropertyDeclaration::Flags nameFlags = nameDecl.flags(); nameFlags |= PropertyDeclaration::ReadOnlyFlag; nameDecl.setFlags(nameFlags); item << nameDecl; item << conditionProperty(); PropertyDeclaration setupBuildEnvDecl(StringConstants::setupBuildEnvironmentProperty(), PropertyDeclaration::Variant, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); setupBuildEnvDecl.setFunctionArgumentNames(QStringList{StringConstants::projectVar(), StringConstants::productVar()}); item << setupBuildEnvDecl; PropertyDeclaration setupRunEnvDecl(StringConstants::setupRunEnvironmentProperty(), PropertyDeclaration::Variant, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); setupRunEnvDecl.setFunctionArgumentNames(QStringList{StringConstants::projectVar(), StringConstants::productVar()}); item << setupRunEnvDecl; item << PropertyDeclaration(StringConstants::validateProperty(), PropertyDeclaration::Boolean, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::additionalProductTypesProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::versionProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::presentProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()); return item; } void BuiltinDeclarations::addProbeItem() { ItemDeclaration item(ItemType::Probe); item << conditionProperty(); item << PropertyDeclaration(StringConstants::foundProperty(), PropertyDeclaration::Boolean, StringConstants::falseValue()); item << PropertyDeclaration(StringConstants::configureProperty(), PropertyDeclaration::Variant, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); insert(item); } void BuiltinDeclarations::addProductItem() { ItemDeclaration item(ItemType::Product); item.setAllowedChildTypes( {ItemType::Depends, ItemType::Export, ItemType::FileTagger, ItemType::Group, ItemType::JobLimit, ItemType::Probe, ItemType::Profile, ItemType::PropertyOptions, ItemType::Rule, ItemType::Scanner}); item << conditionProperty(); item << PropertyDeclaration(StringConstants::typeProperty(), PropertyDeclaration::StringList, StringConstants::emptyArrayValue()); item << nameProperty(); item << PropertyDeclaration(StringConstants::builtByDefaultProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()); PropertyDeclaration profilesDecl(StringConstants::profilesProperty(), PropertyDeclaration::StringList); profilesDecl.setDeprecationInfo(DeprecationInfo(Version::fromString(QStringLiteral("1.9.0")), Tr::tr("Use qbs.profiles instead."))); item << profilesDecl; item << PropertyDeclaration(StringConstants::targetNameProperty(), PropertyDeclaration::String, QStringLiteral("new String(name)" ".replace(/[/\\\\?%*:|\"<>]/g, '_').valueOf()")); item << buildDirProperty(); item << PropertyDeclaration(StringConstants::destinationDirProperty(), PropertyDeclaration::String, StringConstants::buildDirectoryProperty()); item << PropertyDeclaration(StringConstants::consoleApplicationProperty(), PropertyDeclaration::Boolean); item << PropertyDeclaration(StringConstants::filesProperty(), PropertyDeclaration::PathList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::excludeFilesProperty(), PropertyDeclaration::PathList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::qbsSearchPathsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::versionProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::multiplexByQbsPropertiesProperty(), PropertyDeclaration::StringList, QStringLiteral("[\"profiles\"]")); item << PropertyDeclaration(StringConstants::multiplexedTypeProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::aggregateProperty(), PropertyDeclaration::Boolean); item << PropertyDeclaration(StringConstants::multiplexedProperty(), PropertyDeclaration::Boolean, QString(), PropertyDeclaration::ReadOnlyFlag); item << PropertyDeclaration(StringConstants::multiplexConfigurationIdProperty(), PropertyDeclaration::String, QString(), PropertyDeclaration::ReadOnlyFlag); item << PropertyDeclaration(StringConstants::qbsModuleProviders(), PropertyDeclaration::StringList); insert(item); } void BuiltinDeclarations::addProfileItem() { ItemDeclaration item(ItemType::Profile); item << conditionProperty(); item << nameProperty(); item << PropertyDeclaration(StringConstants::baseProfileProperty(), PropertyDeclaration::String); insert(item); } void BuiltinDeclarations::addProjectItem() { ItemDeclaration item(ItemType::Project); item.setAllowedChildTypes(ItemDeclaration::TypeNames() << ItemType::Project << ItemType::PropertyOptions << ItemType::SubProject << ItemType::Product << ItemType::Profile << ItemType::Probe << ItemType::FileTagger << ItemType::JobLimit << ItemType::Rule); item << nameProperty(); item << conditionProperty(); item << buildDirProperty(); item << PropertyDeclaration(StringConstants::minimumQbsVersionProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::sourceDirectoryProperty(), PropertyDeclaration::Path); item << PropertyDeclaration(StringConstants::profileProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::referencesProperty(), PropertyDeclaration::PathList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::qbsSearchPathsProperty(), PropertyDeclaration::StringList, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); item << PropertyDeclaration(StringConstants::qbsModuleProviders(), PropertyDeclaration::StringList); insert(item); } void BuiltinDeclarations::addPropertiesItem() { ItemDeclaration item(ItemType::Properties); item << conditionProperty(); insert(item); } void BuiltinDeclarations::addPropertyOptionsItem() { ItemDeclaration item(ItemType::PropertyOptions); item << nameProperty(); item << PropertyDeclaration(StringConstants::allowedValuesProperty(), PropertyDeclaration::Variant); item << PropertyDeclaration(StringConstants::descriptionProperty(), PropertyDeclaration::String); item << PropertyDeclaration(StringConstants::removalVersionProperty(), PropertyDeclaration::String); insert(item); } void BuiltinDeclarations::addRuleItem() { ItemDeclaration item(ItemType::Rule); item.setAllowedChildTypes(ItemDeclaration::TypeNames() << ItemType::Artifact); item << conditionProperty(); item << alwaysRunProperty(); item << PropertyDeclaration(StringConstants::multiplexProperty(), PropertyDeclaration::Boolean, StringConstants::falseValue()); item << PropertyDeclaration(StringConstants::requiresInputsProperty(), PropertyDeclaration::Boolean); item << nameProperty(); item << PropertyDeclaration(StringConstants::inputsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::outputFileTagsProperty(), PropertyDeclaration::StringList); PropertyDeclaration outputArtifactsDecl(StringConstants::outputArtifactsProperty(), PropertyDeclaration::Variant, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); outputArtifactsDecl.setFunctionArgumentNames( QStringList() << StringConstants::projectVar() << StringConstants::productVar() << StringConstants::inputsVar() << StringConstants::inputVar()); item << outputArtifactsDecl; PropertyDeclaration usingsDecl(QStringLiteral("usings"), PropertyDeclaration::StringList); usingsDecl.setDeprecationInfo(DeprecationInfo(Version(1, 5), Tr::tr("Use 'inputsFromDependencies' instead"))); item << usingsDecl; item << PropertyDeclaration(StringConstants::inputsFromDependenciesProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::auxiliaryInputsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration( StringConstants::auxiliaryInputsFromDependenciesProperty(), PropertyDeclaration::StringList); PropertyDeclaration excludedAuxInputs(StringConstants::excludedAuxiliaryInputsProperty(), PropertyDeclaration::StringList); excludedAuxInputs.setDeprecationInfo(DeprecationInfo(Version(1, 14), Tr::tr("Use 'excludedInputs' instead"))); item << excludedAuxInputs; item << PropertyDeclaration(StringConstants::excludedInputsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::explicitlyDependsOnProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::explicitlyDependsOnFromDependenciesProperty(), PropertyDeclaration::StringList); item << prepareScriptProperty(); insert(item); } void BuiltinDeclarations::addSubprojectItem() { ItemDeclaration item(ItemType::SubProject); item.setAllowedChildTypes(ItemDeclaration::TypeNames() << ItemType::Project // needed, because we're adding this internally << ItemType::PropertiesInSubProject << ItemType::PropertyOptions); item << conditionProperty(); item << PropertyDeclaration(StringConstants::filePathProperty(), PropertyDeclaration::Path); item << PropertyDeclaration(StringConstants::inheritPropertiesProperty(), PropertyDeclaration::Boolean, StringConstants::trueValue()); insert(item); } void BuiltinDeclarations::addTransformerItem() { ItemDeclaration item(ItemType::Transformer); item.setDeprecationInfo(DeprecationInfo(Version(1, 7), Tr::tr("Use the 'Rule' item instead."))); item.setAllowedChildTypes(ItemDeclaration::TypeNames() << ItemType::Artifact); item << conditionProperty(); item << alwaysRunProperty(); item << PropertyDeclaration(StringConstants::inputsProperty(), PropertyDeclaration::PathList); item << prepareScriptProperty(); item << PropertyDeclaration(StringConstants::explicitlyDependsOnProperty(), PropertyDeclaration::StringList); insert(item); } void BuiltinDeclarations::addScannerItem() { ItemDeclaration item(ItemType::Scanner); item << conditionProperty(); item << PropertyDeclaration(StringConstants::inputsProperty(), PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::recursiveProperty(), PropertyDeclaration::Boolean, StringConstants::falseValue()); PropertyDeclaration searchPaths(StringConstants::searchPathsProperty(), PropertyDeclaration::StringList); searchPaths.setFunctionArgumentNames( QStringList() << StringConstants::projectVar() << StringConstants::productVar() << StringConstants::inputVar()); item << searchPaths; PropertyDeclaration scan(StringConstants::scanProperty(), PropertyDeclaration::Variant, QString(), PropertyDeclaration::PropertyNotAvailableInConfig); scan.setFunctionArgumentNames( QStringList() << StringConstants::projectVar() << StringConstants::productVar() << StringConstants::inputVar() << StringConstants::filePathVar()); item << scan; insert(item); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/identifiersearch.h0000644000175100001660000000512614776170045022674 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_IDENTIFIERSEARCHVISITOR_H #define QBS_IDENTIFIERSEARCHVISITOR_H #include #include #include #include #include namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT IdentifierSearch : private QbsQmlJS::AST::Visitor { public: IdentifierSearch(); void start(QbsQmlJS::AST::Node *node); void add(const QString &name, bool *found); private: bool preVisit(QbsQmlJS::AST::Node *) override; bool visit(QbsQmlJS::AST::IdentifierExpression *e) override; QMap m_requests; int m_numberOfFoundIds = 0; }; } // namespace Internal } // namespace qbs #endif // QBS_IDENTIFIERSEARCHVISITOR_H qbs-src-2.6.1/src/lib/corelib/language/propertydeclaration.h0000644000175100001660000001124614776170045023456 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROPERTYDECLARATION_H #define QBS_PROPERTYDECLARATION_H #include #include #include QT_BEGIN_NAMESPACE class QVariant; QT_END_NAMESPACE namespace qbs { class CodeLocation; class ErrorInfo; namespace Internal { class DeprecationInfo; class PropertyDeclarationData; class Item; class LoaderState; class Logger; class PropertyDeclaration { public: enum Type { UnknownType, Boolean, Integer, Path, PathList, String, StringList, Variant, VariantList, }; enum Flag { DefaultFlags = 0, ReadOnlyFlag = 0x1, PropertyNotAvailableInConfig = 0x2 // Is this property part of a project, product or file configuration? }; Q_DECLARE_FLAGS(Flags, Flag) PropertyDeclaration(); PropertyDeclaration(const QString &name, Type type, const QString &initialValue = QString(), Flags flags = DefaultFlags); PropertyDeclaration(const PropertyDeclaration &other); ~PropertyDeclaration(); PropertyDeclaration &operator=(const PropertyDeclaration &other); bool isValid() const; bool isScalar() const; static Type propertyTypeFromString(const QString &typeName); QString typeString() const; static QString typeString(Type t); const QString &name() const; void setName(const QString &name); Type type() const; void setType(Type t); Flags flags() const; void setFlags(Flags f); const QStringList &allowedValues() const; void setAllowedValues(const QStringList &v); const QString &description() const; void setDescription(const QString &str); const QString &initialValueSource() const; void setInitialValueSource(const QString &str); const QStringList &functionArgumentNames() const; void setFunctionArgumentNames(const QStringList &lst); bool isDeprecated() const; bool isExpired() const; const DeprecationInfo &deprecationInfo() const; void setDeprecationInfo(const DeprecationInfo &deprecationInfo); ErrorInfo checkForDeprecation(DeprecationWarningMode mode, const CodeLocation &loc, Logger &logger) const; static QVariant convertToPropertyType( const QVariant &v, Type t, const QStringList &namePrefix, const QString &key); QVariant typedNullValue() const; bool shouldCheckAllowedValues() const; void checkAllowedValues( const QVariant &value, const CodeLocation &loc, const QString &key, LoaderState &loaderState) const; private: QSharedDataPointer d; }; void checkPropertyDeclarations(Item *topLevelItem, LoaderState &loaderState); } // namespace Internal } // namespace qbs #endif // QBS_PROPERTYDECLARATION_H qbs-src-2.6.1/src/lib/corelib/language/forward_decls.h0000644000175100001660000001306714776170045022205 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LANG_FORWARD_DECLS_H #define QBS_LANG_FORWARD_DECLS_H #include namespace qbs { namespace Internal { enum class ObserveMode; class Value; using ValuePtr = std::shared_ptr; using ValueConstPtr = std::shared_ptr; class ItemValue; using ItemValuePtr = std::shared_ptr; using ItemValueConstPtr = std::shared_ptr; class JSSourceValue; using JSSourceValuePtr = std::shared_ptr; using JSSourceValueConstPtr = std::shared_ptr; class VariantValue; using VariantValuePtr = std::shared_ptr; using VariantValueConstPtr = std::shared_ptr; class FileContext; using FileContextPtr = std::shared_ptr; using FileContextConstPtr = std::shared_ptr; class FileContextBase; using FileContextBasePtr = std::shared_ptr; using FileContextBaseConstPtr = std::shared_ptr; class Probe; using ProbePtr = std::shared_ptr; using ProbeConstPtr = std::shared_ptr; class PropertyMapInternal; using PropertyMapPtr = std::shared_ptr; using PropertyMapConstPtr = std::shared_ptr; class FileTagger; using FileTaggerPtr = std::shared_ptr; using FileTaggerConstPtr = std::shared_ptr; class ResolvedProduct; using ResolvedProductPtr = std::shared_ptr; using ResolvedProductConstPtr = std::shared_ptr; class ResolvedProject; using ResolvedProjectPtr = std::shared_ptr; using ResolvedProjectConstPtr = std::shared_ptr; class TopLevelProject; using TopLevelProjectPtr = std::shared_ptr; using TopLevelProjectConstPtr = std::shared_ptr; class ResolvedFileContext; using ResolvedFileContextPtr = std::shared_ptr; using ResolvedFileContextConstPtr = std::shared_ptr; class Rule; using RulePtr = std::shared_ptr; using RuleConstPtr = std::shared_ptr; class ResolvedScanner; using ResolvedScannerPtr = std::shared_ptr; using ResolvedScannerConstPtr = std::shared_ptr; class SourceArtifactInternal; using SourceArtifactPtr = std::shared_ptr; using SourceArtifactConstPtr = std::shared_ptr; class ScriptFunction; using ScriptFunctionPtr = std::shared_ptr; using ScriptFunctionConstPtr = std::shared_ptr; class PrivateScriptFunction; class RuleArtifact; using RuleArtifactPtr = std::shared_ptr; using RuleArtifactConstPtr = std::shared_ptr; class ResolvedModule; using ResolvedModulePtr = std::shared_ptr; using ResolvedModuleConstPtr = std::shared_ptr; class ResolvedGroup; using GroupPtr = std::shared_ptr; using GroupConstPtr = std::shared_ptr; class ArtifactProperties; using ArtifactPropertiesPtr = std::shared_ptr; using ArtifactPropertiesConstPtr = std::shared_ptr; class ExportedItem; using ExportedItemPtr = std::shared_ptr; class ExportedModule; class ExportedModuleDependency; class ExportedProperty; class PersistentPool; } // namespace Internal } // namespace qbs #ifdef QT_CORE_LIB #include "../tools/porting.h" #include namespace qbs { namespace Internal { template inline static QHashValueType qHash(const std::shared_ptr &p, QHashValueType seed = 0) { return ::qHash(p.get(), seed); } } // namespace Internal } // namespace qbs #endif #endif // QBS_LANG_FORWARD_DECLS_H qbs-src-2.6.1/src/lib/corelib/language/itemtype.h0000644000175100001660000000535514776170045021230 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMTYPE_H #define QBS_ITEMTYPE_H #include namespace qbs { namespace Internal { enum class ItemType { // Actual user-visible items. FirstActualItem, Artifact = FirstActualItem, Depends, Export, FileTagger, Group, JobLimit, Module, ModuleProvider, Parameter, Parameters, Probe, Product, Profile, Project, Properties, PropertiesInSubProject, PropertyOptions, Rule, Scanner, SubProject, Transformer, LastActualItem = Transformer, // Internal items created mainly by the module loader. IdScope, ModuleInstance, ModuleInstancePlaceholder, ModuleParameters, ModulePrefix, Outer, Scope, Unknown }; inline auto qHash(ItemType t) { return QT_PREPEND_NAMESPACE(qHash)(uint(t)); } } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/language/qualifiedid.h0000644000175100001660000000514514776170045021645 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_QUALIFIEDID_H #define QBS_QUALIFIEDID_H #include #include #include namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT QualifiedId : public QStringList { public: QualifiedId(); QualifiedId(const QString &singlePartName); QualifiedId(const QStringList &nameParts); static QualifiedId fromString(const QString &str); QString toString() const; }; inline auto qHash(const QualifiedId &qid) { return qHash(qid.toString()); } using QualifiedIdSet = Set; // Values are the properties with a dependency on the key property using PropertyDependencies = QHash; } // namespace Internal } // namespace qbs #endif // QBS_QUALIFIEDID_H qbs-src-2.6.1/src/lib/corelib/language/value.h0000644000175100001660000002245514776170045020504 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_VALUE_H #define QBS_VALUE_H #include "forward_decls.h" #include #include #include #include #include namespace qbs { namespace Internal { class Item; class ItemPool; class ItemValue; class JSSourceValue; class VariantValue; template class ValueHandler { public: T handle(Value *v); private: virtual T doHandle(JSSourceValue *value) = 0; virtual T doHandle(ItemValue *value) = 0; virtual T doHandle(VariantValue *value) = 0; }; class Value { public: enum Type { JSSourceValueType, ItemValueType, VariantValueType }; enum Flag { NoFlags = 0x00, SourceUsesBase = 0x01, SourceUsesOuter = 0x02, SourceUsesOriginal = 0x04, HasFunctionForm = 0x08, ExclusiveListValue = 0x10, BuiltinDefaultValue = 0x20, OriginPropertiesBlock = 0x40, OriginProfile = 0x80, OriginCommandLine = 0x100, Fallback = 0x200, }; Q_DECLARE_FLAGS(Flags, Flag) Value(Type t, bool createdByPropertiesBlock); Value(const Value &other) = default; virtual ~Value(); Type type() const { return m_type; } template T apply(ValueHandler *handler) { return handler->handle(this); }; virtual ValuePtr clone(ItemPool &) const = 0; virtual CodeLocation location() const { return {}; } Item *scope() const { return m_scope; } virtual void setScope(Item *scope, const QString &scopeName); QString scopeName() const { return m_scopeName; } int priority(const Item *productItem) const; virtual void resetPriority(); void addCandidate(const ValuePtr &v) { m_candidates.push_back(v); } const std::vector &candidates() const { return m_candidates; } void setCandidates(const std::vector &candidates) { m_candidates = candidates; } void removeExpiredCandidates(const Item *productItem); void sortCandidates(const std::function &less); bool createdByPropertiesBlock() const { return m_flags & OriginPropertiesBlock; } void setFallback() { m_flags |= Fallback; } bool isFallback() const { return m_flags & Fallback; } void markAsSetByProfile() { m_flags |= OriginProfile; } bool setByProfile() const { return m_flags & OriginProfile; } void markAsSetByCommandLine() { m_flags |= OriginCommandLine; } bool setByCommandLine() const { return m_flags & OriginCommandLine; } bool setInternally() const; bool expired(const Item *productItem) const { return priority(productItem) == 0; } void setSourceUsesBase() { m_flags |= SourceUsesBase; } bool sourceUsesBase() const { return m_flags.testFlag(SourceUsesBase); } void setSourceUsesOuter() { m_flags |= SourceUsesOuter; } bool sourceUsesOuter() const { return m_flags.testFlag(SourceUsesOuter); } void setSourceUsesOriginal() { m_flags |= SourceUsesOriginal; } bool sourceUsesOriginal() const { return m_flags.testFlag(SourceUsesOriginal); } void setHasFunctionForm() { m_flags |= HasFunctionForm; } bool hasFunctionForm() const { return m_flags.testFlag(HasFunctionForm); } void setIsExclusiveListValue() { m_flags |= ExclusiveListValue; } bool isExclusiveListValue() { return m_flags.testFlag(ExclusiveListValue); } void setIsBuiltinDefaultValue() { m_flags |= BuiltinDefaultValue; } bool isBuiltinDefaultValue() const { return m_flags.testFlag(BuiltinDefaultValue); } private: int calculatePriority(const Item *productItem) const; const Type m_type; Item *m_scope = nullptr; QString m_scopeName; std::vector m_candidates; Flags m_flags; mutable int m_priority = -1; }; class JSSourceValue : public Value { friend class ItemReaderASTVisitor; public: explicit JSSourceValue(bool createdByPropertiesBlock); JSSourceValue(const JSSourceValue &other, ItemPool &pool); static JSSourceValuePtr QBS_AUTOTEST_EXPORT create(bool createdByPropertiesBlock = false); ~JSSourceValue() override; ValuePtr clone(ItemPool &pool) const override; void setSourceCode(QStringView sourceCode) { m_sourceCode = sourceCode; } QStringView sourceCode() const { return m_sourceCode; } QString sourceCodeForEvaluation() const; void setLocation(int line, int column); int line() const { return m_line; } int column() const { return m_column; } CodeLocation location() const override; void setFile(const FileContextPtr &file) { m_file = file; } const FileContextPtr &file() const { return m_file; } const JSSourceValuePtr &baseValue() const { return m_baseValue; } void setBaseValue(const JSSourceValuePtr &v) { m_baseValue = v; } struct Alternative { struct PropertyData { PropertyData() = default; PropertyData(QString v, const CodeLocation &l) : value(std::move(v)), location(l) {} QString value; CodeLocation location; }; Alternative() = default; Alternative(PropertyData c, PropertyData o, JSSourceValuePtr v) : condition(std::move(c)), overrideListProperties(std::move(o)), value(std::move(v)) {} Alternative clone(ItemPool &pool) const { return Alternative(condition, overrideListProperties, std::static_pointer_cast(value->clone(pool))); } PropertyData condition; PropertyData overrideListProperties; JSSourceValuePtr value; }; using AltProperty = Alternative::PropertyData; const std::vector &alternatives() const { return m_alternatives; } void addAlternative(const Alternative &alternative); void clearAlternatives(); void setScope(Item *scope, const QString &scopeName) override; void resetPriority() override; private: QStringView m_sourceCode; int m_line; int m_column; FileContextPtr m_file; JSSourceValuePtr m_baseValue; std::vector m_alternatives; }; class ItemValue : public Value { public: ItemValue(Item *item, bool createdByPropertiesBlock); static ItemValuePtr create(Item *item, bool createdByPropertiesBlock = false); Item *item() const { return m_item; } void setItem(Item *item) { m_item = item; } private: ValuePtr clone(ItemPool &pool) const override; Item *m_item; }; class VariantValue : public Value { public: explicit VariantValue(QVariant v); VariantValue(const VariantValue &v) = default; static VariantValuePtr create(const QVariant &v = QVariant()); static VariantValuePtr createStored(const QVariant &v = QVariant()); ValuePtr clone(ItemPool &) const override; const QVariant &value() const { return m_value; } virtual quintptr id() const { return 0; } static const VariantValuePtr &falseValue(); static const VariantValuePtr &trueValue(); static const VariantValuePtr &invalidValue(); private: QVariant m_value; }; template inline T ValueHandler::handle(Value *v) { switch (v->type()) { case Value::JSSourceValueType: return doHandle(static_cast(v)); case Value::ItemValueType: return doHandle(static_cast(v)); case Value::VariantValueType: return doHandle(static_cast(v)); } if constexpr (!std::is_same_v) return {}; } } // namespace Internal } // namespace qbs #endif // QBS_VALUE_H qbs-src-2.6.1/src/lib/corelib/language/scriptimporter.h0000644000175100001660000000471014776170045022450 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SCRIPTIMPORTER_H #define SCRIPTIMPORTER_H #include #include namespace qbs { namespace Internal { class ScriptEngine; class ScriptImporter { public: ScriptImporter(ScriptEngine *scriptEngine); JSValue importSourceCode(const QString &sourceCode, const QString &filePath, JSValue &targetObject); static void copyProperties(JSContext *ctx, const JSValue &src, JSValue &dst); private: ScriptEngine *m_engine; QHash m_sourceCodeCache; }; } // namespace Internal } // namespace qbs #endif // SCRIPTIMPORTER_H qbs-src-2.6.1/src/lib/corelib/language/scriptengine.cpp0000644000175100001660000012204214776170045022406 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scriptengine.h" #include "deprecationinfo.h" #include "filecontextbase.h" #include "jsimports.h" #include "preparescriptobserver.h" #include "scriptimporter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { const bool debugJSImports = false; bool operator==(const ScriptEngine::PropertyCacheKey &lhs, const ScriptEngine::PropertyCacheKey &rhs) { return lhs.m_propertyMap == rhs.m_propertyMap && lhs.m_moduleName == rhs.m_moduleName && lhs.m_propertyName == rhs.m_propertyName; } static QHashValueType combineHash(QHashValueType h1, QHashValueType h2, QHashValueType seed) { // stolen from qHash(QPair) return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed; } QHashValueType qHash(const ScriptEngine::PropertyCacheKey &k, QHashValueType seed = 0) { return combineHash(qHash(k.m_moduleName), combineHash(qHash(k.m_propertyName), qHash(k.m_propertyMap), seed), seed); } ScriptEngine::ScriptEngine(Logger &logger, EvalContext evalContext, PrivateTag) : m_scriptImporter(new ScriptImporter(this)), m_logger(logger), m_evalContext(evalContext), m_observer(new PrepareScriptObserver(this, UnobserveMode::Disabled)) { setMaxStackSize(); JS_SetRuntimeOpaque(m_jsRuntime, this); JS_SetInterruptHandler(m_jsRuntime, interruptor, this); setScopeLookup(m_context, &ScriptEngine::doExtraScopeLookup); setFoundUndefinedHandler(m_context, &ScriptEngine::handleUndefinedFound); setFunctionEnteredHandler(m_context, &ScriptEngine::handleFunctionEntered); setFunctionExitedHandler(m_context, &ScriptEngine::handleFunctionExited); m_dataWithPtrClass = registerClass("__data", nullptr, nullptr, JS_UNDEFINED); installQbsBuiltins(); extendJavaScriptBuiltins(); } std::unique_ptr ScriptEngine::create(Logger &logger, EvalContext evalContext) { return std::make_unique(logger, evalContext, PrivateTag()); } ScriptEngine *ScriptEngine::engineForRuntime(const JSRuntime *runtime) { return static_cast(JS_GetRuntimeOpaque(const_cast(runtime))); } ScriptEngine *ScriptEngine::engineForContext(const JSContext *ctx) { return engineForRuntime(JS_GetRuntime(const_cast(ctx))); } LookupResult ScriptEngine::doExtraScopeLookup(JSContext *ctx, JSAtom prop) { static const LookupResult fail{JS_UNDEFINED, JS_UNDEFINED, false}; ScriptEngine * const engine = engineForContext(ctx); engine->m_lastLookupWasSuccess = false; auto handleScope = [ctx, prop, engine](const JSValue &scope) -> LookupResult { const JSValue v = JS_GetProperty(ctx, scope, prop); if (!JS_IsUndefined(v) || engine->m_lastLookupWasSuccess) { engine->m_lastLookupWasSuccess = false; return {v, scope, true}; } return fail; }; if (!engine->m_scopeChains.empty()) { const auto scopes = engine->m_scopeChains.back(); for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) { const auto res = handleScope(*it); if (res.useResult) return res; } } if (JS_IsObject(engine->m_globalObject)) return handleScope(engine->m_globalObject); return fail; } void ScriptEngine::handleUndefinedFound(JSContext *ctx) { engineForContext(ctx)->setLastLookupStatus(true); } void ScriptEngine::handleFunctionEntered(JSContext *ctx, JSValue this_obj) { ScriptEngine::engineForContext(ctx)->m_contextStack.push_back(this_obj); } void ScriptEngine::handleFunctionExited(JSContext *ctx) { ScriptEngine::engineForContext(ctx)->m_contextStack.pop_back(); } ScriptEngine::~ScriptEngine() { reset(); delete m_scriptImporter; if (m_elapsedTimeImporting != -1) { m_logger.qbsLog(LoggerInfo, true) << Tr::tr("Setting up imports took %1.") .arg(elapsedTimeString(m_elapsedTimeImporting)); } for (const auto &ext : std::as_const(m_internalExtensions)) JS_FreeValue(m_context, ext); for (const JSValue &s : std::as_const(m_stringCache)) JS_FreeValue(m_context, s); for (JSValue * const externalRef : std::as_const(m_externallyCachedValues)) { JS_FreeValue(m_context, *externalRef); *externalRef = JS_UNDEFINED; } setPropertyOnGlobalObject(QLatin1String("console"), JS_UNDEFINED); JS_FreeContext(m_context); JS_FreeRuntime(m_jsRuntime); } void ScriptEngine::reset() { // TODO: Check whether we can keep file and imports cache. // We'd have to find a solution for the scope name problem then. clearImportsCache(); for (const auto &e : std::as_const(m_jsFileCache)) JS_FreeValue(m_context, e.second); m_jsFileCache.clear(); for (const JSValue &s : std::as_const(m_jsValueCache)) JS_FreeValue(m_context, s); m_jsValueCache.clear(); for (auto it = m_evalResults.cbegin(); it != m_evalResults.cend(); ++it) { for (int i = 0; i < it.value(); ++i) JS_FreeValue(m_context, it.key()); } m_evalResults.clear(); for (const auto &e : std::as_const(m_projectScriptValues)) JS_FreeValue(m_context, e.second); m_projectScriptValues.clear(); for (const auto &e : std::as_const(m_baseProductScriptValues)) JS_FreeValue(m_context, e.second); m_baseProductScriptValues.clear(); for (const auto &e : std::as_const(m_productArtifactsMapScriptValues)) JS_FreeValue(m_context, e.second); m_productArtifactsMapScriptValues.clear(); for (const auto &e : std::as_const(m_moduleArtifactsMapScriptValues)) JS_FreeValue(m_context, e.second); m_moduleArtifactsMapScriptValues.clear(); for (const auto &e : std::as_const(m_baseModuleScriptValues)) JS_FreeValue(m_context, e.second); m_baseModuleScriptValues.clear(); for (auto it = m_artifactsScriptValues.cbegin(); it != m_artifactsScriptValues.cend(); ++it) { it.key().first->setDeregister({}); JS_FreeValue(m_context, it.value()); } m_artifactsScriptValues.clear(); m_logger.clearWarnings(); } void ScriptEngine::import(const FileContextBaseConstPtr &fileCtx, JSValue &targetObject, ObserveMode observeMode) { Importer(*this, fileCtx, targetObject, observeMode).run(); } void ScriptEngine::import(const JsImport &jsImport, JSValue &targetObject) { QBS_ASSERT(JS_IsObject(targetObject), return); if (debugJSImports) qDebug() << "[ENGINE] import into " << jsImport.scopeName; JSValue jsImportValue = m_jsImportCache.value(jsImport); if (JS_IsObject(jsImportValue)) { if (debugJSImports) qDebug() << "[ENGINE] " << jsImport.filePaths << " (cache hit)"; } else { if (debugJSImports) qDebug() << "[ENGINE] " << jsImport.filePaths << " (cache miss)"; ScopedJsValue scopedImportValue(m_context, JS_NewObject(m_context)); for (const QString &filePath : jsImport.filePaths) importFile(filePath, scopedImportValue); jsImportValue = scopedImportValue.release(); m_jsImportCache.insert(jsImport, jsImportValue); std::vector &filePathsForScriptValue = m_filePathsPerImport[jsObjectId(jsImportValue)]; transform(jsImport.filePaths, filePathsForScriptValue, [](const auto &fp) { return fp; }); } JSValue sv = JS_NewObjectProto(m_context, jsImportValue); setJsProperty(m_context, sv, StringConstants::importScopeNamePropertyInternal(), jsImport.scopeName); setJsProperty(m_context, targetObject, jsImport.scopeName, sv); if (m_observeMode == ObserveMode::Enabled) observeImport(jsImportValue); } void ScriptEngine::observeImport(JSValue &jsImport) { if (!m_observer->addImportId(quintptr((JS_VALUE_GET_OBJ(jsImport))))) return; handleJsProperties(jsImport, [this, &jsImport](const JSAtom &name, const JSPropertyDescriptor &desc) { if (!JS_IsFunction(m_context, desc.value)) return; const char *const nameStr = JS_AtomToCString(m_context, name); setObservedProperty(jsImport, QString::fromUtf8(nameStr, std::strlen(nameStr)), desc.value); JS_FreeCString(m_context, nameStr); }); } void ScriptEngine::clearImportsCache() { for (const auto &jsImport : std::as_const(m_jsImportCache)) JS_FreeValue(m_context, jsImport); m_jsImportCache.clear(); m_filePathsPerImport.clear(); m_observer->clearImportIds(); } void ScriptEngine::registerEvaluator(Evaluator *evaluator) { QBS_ASSERT(!m_evaluator, return); m_evaluator = evaluator; } void ScriptEngine::unregisterEvaluator(const Evaluator *evaluator) { QBS_ASSERT(m_evaluator == evaluator, return); m_evaluator = nullptr; } void ScriptEngine::checkContext(const QString &operation, const DubiousContextList &dubiousContexts) { for (const DubiousContext &info : dubiousContexts) { if (info.context != evalContext()) continue; QString warning; switch (info.context) { case EvalContext::PropertyEvaluation: warning = Tr::tr("Suspicious use of %1 during property evaluation.").arg(operation); if (info.suggestion == DubiousContext::SuggestMoving) warning += QLatin1Char(' ') + Tr::tr("Should this call be in a Probe instead?"); break; case EvalContext::RuleExecution: warning = Tr::tr("Suspicious use of %1 during rule execution.").arg(operation); if (info.suggestion == DubiousContext::SuggestMoving) { warning += QLatin1Char(' ') + Tr::tr("Should this call be in a JavaScriptCommand instead?"); } break; case EvalContext::ModuleProvider: case EvalContext::ProbeExecution: case EvalContext::JsCommand: QBS_ASSERT(false, continue); break; } if (!m_evalPositions.empty()) { const JSValue exVal = JS_NewObject(m_context); const auto &[file, line] = m_evalPositions.top(); build_backtrace(m_context, exVal, file.toUtf8().constData(), line, 0); const JsException ex(m_context, exVal, {}); m_logger.printWarning(ErrorInfo(warning, ex.stackTrace())); } else { m_logger.printWarning(ErrorInfo(warning)); } return; } } void ScriptEngine::handleDeprecation( const Version &removalVersion, const QString &message, const CodeLocation &loc) { if (!m_setupParams) return; switch (m_setupParams->deprecationWarningMode()) { case DeprecationWarningMode::Error: throw ErrorInfo(message, loc); case DeprecationWarningMode::BeforeRemoval: if (!DeprecationInfo::isLastVersionBeforeRemoval(removalVersion)) break; [[fallthrough]]; case DeprecationWarningMode::On: m_logger.printWarning(ErrorInfo(message, loc)); break; case DeprecationWarningMode::Off: break; } } void ScriptEngine::addPropertyRequestedFromArtifact(const Artifact *artifact, const Property &property) { m_propertiesRequestedFromArtifact[artifact->filePath()] << property; } void ScriptEngine::addImportRequestedInScript(quintptr importValueId) { // Import list is assumed to be small, so let's not use a set. if (!contains(m_importsRequestedInScript, importValueId)) m_importsRequestedInScript.push_back(importValueId); } std::vector ScriptEngine::importedFilesUsedInScript() const { std::vector files; for (qint64 usedImport : m_importsRequestedInScript) { const auto it = m_filePathsPerImport.find(usedImport); QBS_CHECK(it != m_filePathsPerImport.cend()); const std::vector &filePathsForImport = it->second; for (const QString &fp : filePathsForImport) if (!contains(files, fp)) files.push_back(fp); } return files; } void ScriptEngine::enableProfiling(bool enable) { m_elapsedTimeImporting = enable ? 0 : -1; } void ScriptEngine::addToPropertyCache(const QString &moduleName, const QString &propertyName, const PropertyMapConstPtr &propertyMap, const QVariant &value) { m_propertyCache.insert(PropertyCacheKey(moduleName, propertyName, propertyMap), value); } QVariant ScriptEngine::retrieveFromPropertyCache(const QString &moduleName, const QString &propertyName, const PropertyMapConstPtr &propertyMap) { return m_propertyCache.value(PropertyCacheKey(moduleName, propertyName, propertyMap)); } static JSValue js_observedGet(JSContext *ctx, JSValueConst, int, JSValueConst *, int, JSValue *data) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); engine->observer()->onPropertyRead(data[0], getJsString(ctx, data[1]), data[2]); return JS_DupValue(engine->context(), data[2]); } void ScriptEngine::setObservedProperty(JSValue &object, const QString &name, const JSValue &value) { ScopedJsValue jsName(m_context, makeJsString(m_context, name)); JSValueList funcData{object, jsName, value}; JSValue getterFunc = JS_NewCFunctionData(m_context, &js_observedGet, 0, 0, 3, funcData.data()); const ScopedJsAtom nameAtom(m_context, name); JS_DefinePropertyGetSet(m_context, object, nameAtom, getterFunc, JS_UNDEFINED, JS_PROP_HAS_GET | JS_PROP_ENUMERABLE); if (m_observer->unobserveMode() == UnobserveMode::Enabled) m_observedProperties.emplace_back(object, name, value); } void ScriptEngine::unobserveProperties() { for (auto &elem : m_observedProperties) { JSValue &object = std::get<0>(elem); const QString &name = std::get<1>(elem); const JSValue &value = std::get<2>(elem); const ScopedJsAtom jsName(m_context, name); JS_DefineProperty(m_context, object, jsName, value, JS_UNDEFINED, JS_UNDEFINED, JS_PROP_HAS_VALUE); } m_observedProperties.clear(); } QProcessEnvironment ScriptEngine::environment() const { return m_environment; } void ScriptEngine::setEnvironment(const QProcessEnvironment &env) { m_environment = env; } void ScriptEngine::importFile(const QString &filePath, JSValue targetObject) { AccumulatingTimer importTimer(m_elapsedTimeImporting != -1 ? &m_elapsedTimeImporting : nullptr); JSValue &evaluationResult = m_jsFileCache[filePath]; if (JS_IsObject(evaluationResult)) { ScriptImporter::copyProperties(m_context, evaluationResult, targetObject); return; } QFile file(filePath); if (Q_UNLIKELY(!file.open(QFile::ReadOnly))) throw ErrorInfo(Tr::tr("Cannot open '%1'.").arg(filePath)); QTextStream stream(&file); setupDefaultCodec(stream); const QString sourceCode = stream.readAll(); file.close(); m_currentDirPathStack.push(FileInfo::path(filePath)); evaluationResult = m_scriptImporter->importSourceCode(sourceCode, filePath, targetObject); m_currentDirPathStack.pop(); } static QString findExtensionDir(const QStringList &searchPaths, const QString &extensionPath) { for (const QString &searchPath : searchPaths) { QString dirPath = searchPath + QStringLiteral("/imports/") + extensionPath; QFileInfo fi(dirPath); if (fi.exists() && fi.isDir()) return dirPath; } return {}; } JSValue ScriptEngine::mergeExtensionObjects(const JSValueList &lst) { JSValue result = JS_UNDEFINED; for (const JSValue &v : lst) { if (!JS_IsObject(result)) { result = v; continue; } ScriptImporter::copyProperties(m_context, v, result); JS_FreeValue(m_context, v); } return result; } JSValue ScriptEngine::getInternalExtension(const char *name) const { const auto cached = m_internalExtensions.constFind(QLatin1String(name)); if (cached != m_internalExtensions.constEnd()) return JS_DupValue(m_context, cached.value()); return JS_UNDEFINED; } void ScriptEngine::addInternalExtension(const char *name, JSValue ext) { m_internalExtensions.insert(QLatin1String(name), JS_DupValue(m_context, ext)); } JSValue ScriptEngine::asJsValue(const QVariant &v, quintptr id, bool frozen) { if (v.isNull()) return JS_UNDEFINED; switch (static_cast(v.userType())) { case QMetaType::QByteArray: return asJsValue(v.toByteArray()); case QMetaType::QString: return asJsValue(v.toString()); case QMetaType::QStringList: return asJsValue(v.toStringList()); case QMetaType::QVariantList: return asJsValue(v.toList(), id, frozen); case QMetaType::Int: case QMetaType::UInt: return JS_NewInt32(m_context, v.toInt()); case QMetaType::Long: case QMetaType::ULong: case QMetaType::LongLong: case QMetaType::ULongLong: return JS_NewInt64(m_context, v.toInt()); case QMetaType::Bool: return JS_NewBool(m_context, v.toBool()); case QMetaType::QDateTime: return JS_NewDate(m_context, v.toDateTime().toMSecsSinceEpoch()); case QMetaType::QVariantMap: return asJsValue(v.toMap(), id, frozen); default: return JS_UNDEFINED; } } JSValue ScriptEngine::asJsValue(const QByteArray &s) { return JS_NewArrayBufferCopy( m_context, reinterpret_cast(s.constData()), s.size()); } JSValue ScriptEngine::asJsValue(const QString &s) { const auto it = m_stringCache.constFind(s); if (it != m_stringCache.constEnd()) return JS_DupValue(m_context, it.value()); const JSValue sv = JS_NewString(m_context, s.toUtf8().constData()); m_stringCache.insert(s, sv); return JS_DupValue(m_context, sv); } JSValue ScriptEngine::asJsValue(const QStringList &l) { JSValue array = JS_NewArray(m_context); setJsProperty(m_context, array, std::string_view("length"), JS_NewInt32(m_context, l.size())); for (int i = 0; i < l.size(); ++i) JS_SetPropertyUint32(m_context, array, i, asJsValue(l.at(i))); return array; } JSValue ScriptEngine::asJsValue(const QVariantMap &m, quintptr id, bool frozen) { const auto it = id ? m_jsValueCache.constFind(id) : m_jsValueCache.constEnd(); if (it != m_jsValueCache.constEnd()) return JS_DupValue(m_context, it.value()); frozen = id || frozen; JSValue obj = JS_NewObject(m_context); for (auto it = m.begin(); it != m.end(); ++it) setJsProperty(m_context, obj, it.key(), asJsValue(it.value(), 0, frozen)); if (frozen) JS_ObjectSeal(m_context, obj, true); if (!id) return obj; m_jsValueCache[id] = obj; return JS_DupValue(m_context, obj); } void ScriptEngine::setPropertyOnGlobalObject(const QString &property, JSValue value) { const ScopedJsValue globalObject(m_context, JS_GetGlobalObject(m_context)); setJsProperty(m_context, globalObject, property, value); } JSValue ScriptEngine::asJsValue(const QVariantList &l, quintptr id, bool frozen) { const auto it = id ? m_jsValueCache.constFind(id) : m_jsValueCache.constEnd(); if (it != m_jsValueCache.constEnd()) return JS_DupValue(m_context, it.value()); frozen = id || frozen; JSValue array = JS_NewArray(m_context); setJsProperty(m_context, array, std::string_view("length"), JS_NewInt32(m_context, l.size())); for (int i = 0; i < l.size(); ++i) JS_SetPropertyUint32(m_context, array, i, asJsValue(l.at(i), 0, frozen)); if (frozen) JS_ObjectSeal(m_context, array, true); if (!id) return array; m_jsValueCache[id] = array; return JS_DupValue(m_context, array); } JSValue ScriptEngine::loadInternalExtension(const QString &uri) { const QString name = uri.mid(4); // remove the "qbs." part const auto cached = m_internalExtensions.constFind(name); if (cached != m_internalExtensions.constEnd()) return cached.value(); JSValue extensionObj = JsExtensions::loadExtension(this, name); if (!JS_IsObject(extensionObj)) return throwError(Tr::tr("loadExtension: cannot load extension '%1'.").arg(uri)); m_internalExtensions.insert(name, extensionObj); return extensionObj; } JSValue ScriptEngine::js_require(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int, JSValue *func_data) { Q_UNUSED(this_val) ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); QBS_ASSERT(engine, return JS_EXCEPTION); if (argc < 1) return engine->throwError(Tr::tr("The require function requires a module name or path.")); const QString moduleName = getJsString(ctx, argv[0]); // First try to load a named module if the argument doesn't look like a file path if (!moduleName.contains(QLatin1Char('/'))) { if (engine->m_extensionSearchPathsStack.empty()) return engine->throwError(Tr::tr("require: internal error. No search paths.")); if (engine->m_logger.debugEnabled()) { engine->m_logger.qbsDebug() << "[require] loading extension " << moduleName; } QString moduleNameAsPath = moduleName; moduleNameAsPath.replace(QLatin1Char('.'), QLatin1Char('/')); const QStringList searchPaths = engine->m_extensionSearchPathsStack.top(); const QString dirPath = findExtensionDir(searchPaths, moduleNameAsPath); if (dirPath.isEmpty()) { if (moduleName.startsWith(QStringLiteral("qbs."))) return JS_DupValue(ctx, engine->loadInternalExtension(moduleName)); } else { QDirIterator dit(dirPath, StringConstants::jsFileWildcards(), QDir::Files | QDir::Readable); JSValueList values; std::vector filePaths; try { while (dit.hasNext()) { const QString filePath = dit.next(); if (engine->m_logger.debugEnabled()) { engine->m_logger.qbsDebug() << "[require] importing file " << filePath; } ScopedJsValue obj(engine->context(), engine->newObject()); engine->importFile(filePath, obj); values << obj.release(); filePaths.push_back(filePath); } } catch (const ErrorInfo &e) { return engine->throwError(e.toString()); } if (!values.empty()) { const JSValue mergedValue = engine->mergeExtensionObjects(values); engine->m_requireResults.push_back(mergedValue); engine->m_filePathsPerImport[jsObjectId(mergedValue)] = filePaths; return mergedValue; } } // The module name might be a file name component, which is assumed to be to a JavaScript // file located in the current directory search path; try that next } if (engine->m_currentDirPathStack.empty()) return engine->throwError(Tr::tr("require: internal error. No current directory.")); JSValue result; try { const QString filePath = FileInfo::resolvePath(engine->m_currentDirPathStack.top(), moduleName); static const QString scopeNamePrefix = QStringLiteral("_qbs_scope_"); const QString scopeName = scopeNamePrefix + QString::number(qHash(filePath), 16); result = getJsProperty(ctx, func_data[0], scopeName); if (JS_IsObject(result)) return result; // Same JS file imported from same qbs file via different JS files (e.g. codesign.js from DarwinGCC.qbs via gcc.js and darwin.js). ScopedJsValue scopedResult(engine->context(), engine->newObject()); engine->importFile(filePath, scopedResult); result = scopedResult.release(); setJsProperty(ctx, result, StringConstants::importScopeNamePropertyInternal(), scopeName); setJsProperty(ctx, func_data[0], scopeName, result); engine->m_requireResults.push_back(result); engine->m_filePathsPerImport[jsObjectId(JS_DupValue(ctx, result))] = { filePath }; } catch (const ErrorInfo &e) { result = engine->throwError(e.toString()); } return result; } JSClassID ScriptEngine::modulePropertyScriptClass() const { return m_modulePropertyScriptClass; } void ScriptEngine::setModulePropertyScriptClass(JSClassID modulePropertyScriptClass) { m_modulePropertyScriptClass = modulePropertyScriptClass; } template JSValue getScriptValue(JSContext *ctx, const T *t, const std::unordered_map &map) { const auto it = map.find(t); return it == map.end() ? JS_UNDEFINED : JS_DupValue(ctx, it->second); } template void setScriptValue(JSContext *ctx, const T *t, JSValue value, std::unordered_map &map) { value = JS_DupValue(ctx, value); const auto it = map.find(t); if (it == map.end()) { map.insert(std::make_pair(t, value)); return; } JS_FreeValue(ctx, it->second); it->second = value; } JSValue ScriptEngine::artifactsMapScriptValue(const ResolvedProduct *product) { return getScriptValue(m_context, product, m_productArtifactsMapScriptValues); } void ScriptEngine::setArtifactsMapScriptValue(const ResolvedProduct *product, JSValue value) { setScriptValue(m_context, product, value, m_productArtifactsMapScriptValues); } JSValue ScriptEngine::artifactsMapScriptValue(const ResolvedModule *module) { return getScriptValue(m_context, module, m_moduleArtifactsMapScriptValues); } void ScriptEngine::setArtifactsMapScriptValue(const ResolvedModule *module, JSValue value) { setScriptValue(m_context, module, value, m_moduleArtifactsMapScriptValues); } JSValue ScriptEngine::getArtifactProperty(JSValue obj, const std::function &propGetter) { std::lock_guard lock(m_artifactsMutex); const Artifact * const a = attachedPointer(obj, dataWithPtrClass()); return a ? propGetter(a) : JS_EXCEPTION; } void ScriptEngine::addCanonicalFilePathResult(const QString &filePath, const QString &resultFilePath) { if (gatherFileResults()) m_canonicalFilePathResult.insert(filePath, resultFilePath); } void ScriptEngine::addFileExistsResult(const QString &filePath, bool exists) { if (gatherFileResults()) m_fileExistsResult.insert(filePath, exists); } void ScriptEngine::addDirectoryEntriesResult(const QString &path, QDir::Filters filters, const QStringList &entries) { if (gatherFileResults()) { m_directoryEntriesResult.insert( std::pair(path, static_cast(filters)), entries); } } void ScriptEngine::addFileLastModifiedResult(const QString &filePath, const FileTime &fileTime) { if (gatherFileResults()) m_fileLastModifiedResult.insert(filePath, fileTime); } Set ScriptEngine::imports() const { Set filePaths; for (auto it = m_jsImportCache.cbegin(); it != m_jsImportCache.cend(); ++it) { const JsImport &jsImport = it.key(); for (const QString &filePath : jsImport.filePaths) filePaths << filePath; } for (const auto &kv : m_filePathsPerImport) { for (const QString &fp : kv.second) filePaths << fp; } return filePaths; } JSValue ScriptEngine::newObject() const { return JS_NewObject(m_context); } JSValue ScriptEngine::newArray(int length, JsValueOwner owner) { JSValue arr = JS_NewArray(m_context); JS_SetPropertyStr(m_context, arr, "length", JS_NewInt32(m_context, length)); if (owner == JsValueOwner::ScriptEngine) ++m_evalResults[arr]; return arr; } JSValue ScriptEngine::evaluate( JsValueOwner resultOwner, const QString &code, const QString &filePath, int line, qbs::Internal::span scopeChain) { m_scopeChains.emplace_back(scopeChain); const QByteArray &codeStr = code.toUtf8(); m_evalPositions.emplace(filePath, line); const JSValue v = JS_EvalThis(m_context, globalObject(), codeStr.constData(), codeStr.length(), filePath.toUtf8().constData(), line, JS_EVAL_TYPE_GLOBAL); m_evalPositions.pop(); m_scopeChains.pop_back(); if (resultOwner == JsValueOwner::ScriptEngine && JS_VALUE_HAS_REF_COUNT(v)) ++m_evalResults[v]; return v; } void ScriptEngine::handleJsProperties(JSValue obj, const PropertyHandler &handler) { qbs::Internal::handleJsProperties(m_context, obj, handler); } ScopedJsValueList ScriptEngine::argumentList(const QStringList &argumentNames, const JSValue &context) const { JSValueList result; for (const auto &name : argumentNames) result.push_back(getJsProperty(m_context, context, name)); return {m_context, result}; } JSClassID ScriptEngine::registerClass(const char *name, JSClassCall *constructor, JSClassFinalizer *finalizer, JSValue scope, GetPropertyNames getPropertyNames, GetProperty getProperty) { JSClassID id = 0; const auto classIt = m_classes.constFind(QLatin1String(name)); if (classIt == m_classes.constEnd()) { JS_NewClassID(&id); const auto it = getProperty ? m_exoticMethods.insert(id, JSClassExoticMethods{getProperty, getPropertyNames}) : m_exoticMethods.end(); JSClassDef jsClass{name, finalizer, nullptr, constructor, it != m_exoticMethods.end() ? &it.value() : nullptr}; const int status = JS_NewClass(m_jsRuntime, id, &jsClass); QBS_ASSERT(status == 0, return 0); m_classes.insert(QLatin1String(name), id); } else { id = classIt.value(); } if (!JS_IsUndefined(scope)) { const JSValue classObj = JS_NewObjectClass(m_context, id); JS_SetConstructorBit(m_context, classObj, constructor != nullptr); JS_SetPropertyStr(m_context, scope, name, classObj); } return id; } JSClassID ScriptEngine::getClassId(const char *name) const { return m_classes.value(QLatin1String(name)); } JSValue ScriptEngine::throwError(const QString &message) const { return qbs::Internal::throwError(m_context, message); } void ScriptEngine::cancel() { m_canceling = true; } int ScriptEngine::interruptor(JSRuntime *, void *opaqueEngine) { const auto engine = reinterpret_cast(opaqueEngine); if (engine->m_canceling) { engine->m_canceling = false; return 1; } return 0; } bool ScriptEngine::gatherFileResults() const { return evalContext() == EvalContext::PropertyEvaluation || evalContext() == EvalContext::ProbeExecution; } void ScriptEngine::setMaxStackSize() { size_t stackSize = 0; // Turn check off by default. bool ok; const int stackSizeFromEnv = qEnvironmentVariableIntValue("QBS_MAX_JS_STACK_SIZE", &ok); if (ok && stackSizeFromEnv >= 0) stackSize = stackSizeFromEnv; JS_SetMaxStackSize(m_jsRuntime, stackSize); } JSValue ScriptEngine::getArtifactScriptValue(Artifact *a, const QString &moduleName, const std::function &setup) { std::lock_guard lock(m_artifactsMutex); const auto it = m_artifactsScriptValues.constFind(qMakePair(a, moduleName)); if (it != m_artifactsScriptValues.constEnd()) return JS_DupValue(m_context, *it); a->setDeregister([this](const Artifact *a) { const std::lock_guard lock(m_artifactsMutex); for (auto it = m_artifactsScriptValues.begin(); it != m_artifactsScriptValues.end(); ) { if (it.key().first == a) { JS_SetOpaque(it.value(), nullptr); JS_FreeValue(m_context, it.value()); it = m_artifactsScriptValues.erase(it); } else { ++it; } } }); JSValue obj = JS_NewObjectClass(context(), dataWithPtrClass()); attachPointerTo(obj, a); setup(obj); m_artifactsScriptValues.insert(qMakePair(a, moduleName), JS_DupValue(m_context, obj)); return obj; } void ScriptEngine::releaseInputArtifactScriptValues(const RuleNode *ruleNode) { for (auto it = m_artifactsScriptValues.begin(); it != m_artifactsScriptValues.end();) { Artifact * const a = it.key().first; if (ruleNode->children.contains(a)) { a->setDeregister({}); JS_FreeValue(m_context, it.value()); it = m_artifactsScriptValues.erase(it); } else { ++it; } } } class JSTypeExtender { public: JSTypeExtender(ScriptEngine *engine, const QString &typeName) : m_engine(engine) { const ScopedJsValue globalObject(engine->context(), JS_GetGlobalObject(engine->context())); const ScopedJsValue type(engine->context(), getJsProperty(engine->context(), globalObject, typeName)); m_proto = getJsProperty(engine->context(), type, QStringLiteral("prototype")); QBS_ASSERT(JS_IsObject(m_proto), return); } ~JSTypeExtender() { JS_FreeValue(m_engine->context(), m_proto); } void addFunction(const QString &name, const QString &code) { const JSValue f = m_engine->evaluate(JsValueOwner::Caller, code); QBS_ASSERT(JS_IsFunction(m_engine->context(), f), return); JS_DefinePropertyValueStr(m_engine->context(), m_proto, name.toUtf8().constData(), f, 0); } private: ScriptEngine * const m_engine; JSValue m_proto = JS_UNDEFINED; }; static JSValue js_consoleFunc(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv, int level) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); QBS_ASSERT(engine, return JS_EXCEPTION); if (Q_UNLIKELY(argc != 1)) return engine->throwError(Tr::tr("The console functions expect 1 argument.")); engine->logger().qbsLog(static_cast(level)) << getJsString(ctx, argv[0]); return engine->undefinedValue(); } void ScriptEngine::installQbsBuiltins() { const JSValue consoleObj = newObject(); setPropertyOnGlobalObject(QLatin1String("console"), consoleObj); installConsoleFunction(consoleObj, QStringLiteral("debug"), LoggerDebug); installConsoleFunction(consoleObj, QStringLiteral("error"), LoggerError); installConsoleFunction(consoleObj, QStringLiteral("info"), LoggerInfo); installConsoleFunction(consoleObj, QStringLiteral("log"), LoggerDebug); installConsoleFunction(consoleObj, QStringLiteral("warn"), LoggerWarning); } void ScriptEngine::extendJavaScriptBuiltins() { JSTypeExtender arrayExtender(this, QStringLiteral("Array")); arrayExtender.addFunction(QStringLiteral("contains"), QStringLiteral("(function(e){return this.indexOf(e) !== -1;})")); arrayExtender.addFunction(QStringLiteral("containsAll"), QStringLiteral("(function(e){var $this = this;" "return e.every(function (v) { return $this.contains(v) });})")); arrayExtender.addFunction(QStringLiteral("containsAny"), QStringLiteral("(function(e){var $this = this;" "return e.some(function (v) { return $this.contains(v) });})")); arrayExtender.addFunction(QStringLiteral("uniqueConcat"), QStringLiteral("(function(other){" "var r = this.concat();" "var s = {};" "r.forEach(function(x){ s[x] = true; });" "other.forEach(function(x){" "if (!s[x]) {" "s[x] = true;" "r.push(x);" "}" "});" "return r;})")); JSTypeExtender stringExtender(this, QStringLiteral("String")); stringExtender.addFunction(QStringLiteral("contains"), QStringLiteral("(function(e){return this.indexOf(e) !== -1;})")); } void ScriptEngine::installConsoleFunction(JSValue consoleObj, const QString &name, LoggerLevel level) { JS_SetPropertyStr(m_context, consoleObj, name.toUtf8().constData(), JS_NewCFunctionMagic(m_context, js_consoleFunc, name.toUtf8().constData(), 1, JS_CFUNC_generic_magic, level)); } static QString requireString() { return QStringLiteral("require"); } void ScriptEngine::installImportFunctions(JSValue importScope) { const JSValue require = JS_NewCFunctionData(m_context, js_require, 1, 0, 1, &importScope); setPropertyOnGlobalObject(requireString(), require); } void ScriptEngine::uninstallImportFunctions() { setPropertyOnGlobalObject(requireString(), JS_UNDEFINED); } ScriptEngine::PropertyCacheKey::PropertyCacheKey(QString moduleName, QString propertyName, PropertyMapConstPtr propertyMap) : m_moduleName(std::move(moduleName)) , m_propertyName(std::move(propertyName)) , m_propertyMap(std::move(propertyMap)) { } JsException ScriptEngine::checkAndClearException(const CodeLocation &fallbackLocation) const { return {m_context, JS_GetException(m_context), fallbackLocation}; } void ScriptEngine::clearRequestedProperties() { m_propertiesRequestedInScript.clear(); m_propertiesRequestedFromArtifact.clear(); m_importsRequestedInScript.clear(); m_productsWithRequestedDependencies.clear(); m_requestedArtifacts.clear(); m_requestedExports.clear(); }; void ScriptEngine::takeOwnership(JSValue v) { ++m_evalResults[v]; } ScriptEngine::Importer::Importer( ScriptEngine &engine, const FileContextBaseConstPtr &fileCtx, JSValue &targetObject, ObserveMode observeMode) : m_engine(engine), m_fileCtx(fileCtx), m_targetObject(targetObject) { m_engine.installImportFunctions(targetObject); m_engine.m_currentDirPathStack.push(FileInfo::path(fileCtx->filePath())); m_engine.m_extensionSearchPathsStack.push(fileCtx->searchPaths()); m_engine.m_observeMode = observeMode; } ScriptEngine::Importer::~Importer() { m_engine.m_requireResults.clear(); m_engine.m_currentDirPathStack.pop(); m_engine.m_extensionSearchPathsStack.pop(); m_engine.uninstallImportFunctions(); } void ScriptEngine::Importer::run() { for (const JsImport &jsImport : m_fileCtx->jsImports()) m_engine.import(jsImport, m_targetObject); if (m_engine.m_observeMode == ObserveMode::Enabled) { for (JSValue &sv : m_engine.m_requireResults) m_engine.observeImport(sv); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/item.cpp0000644000175100001660000004576314776170045020670 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "item.h" #include "builtindeclarations.h" #include "filecontext.h" #include "itemobserver.h" #include "itempool.h" #include "value.h" #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { Item *Item::create(ItemPool *pool, ItemType type) { return pool->allocateItem(type); } Item *Item::clone(ItemPool &pool) const { assertModuleLocked(); Item *dup = create(&pool, type()); dup->m_id = m_id; dup->m_location = m_location; dup->m_endPosition = m_endPosition; dup->m_prototype = m_prototype; dup->m_scope = m_scope; dup->m_outerItem = m_outerItem; dup->m_parent = m_parent; dup->m_file = m_file; dup->m_propertyDeclarations = m_propertyDeclarations; dup->m_modules = m_modules; dup->m_children.reserve(m_children.size()); for (const Item * const child : std::as_const(m_children)) { Item *clonedChild = child->clone(pool); clonedChild->m_parent = dup; dup->m_children.push_back(clonedChild); } for (PropertyMap::const_iterator it = m_properties.constBegin(); it != m_properties.constEnd(); ++it) { dup->m_properties.insert(it.key(), it.value()->clone(pool)); } adaptScopesOfClonedAlternatives(dup); return dup; } Item *Item::rootPrototype() { Item *proto = this; while (proto->prototype()) proto = proto->prototype(); return proto; } QString Item::typeName() const { switch (type()) { case ItemType::IdScope: return QStringLiteral("[IdScope]"); case ItemType::ModuleInstance: return QStringLiteral("[ModuleInstance]"); case ItemType::ModuleInstancePlaceholder: return QStringLiteral("[ModuleInstancePlaceholder]"); case ItemType::ModuleParameters: return QStringLiteral("[ModuleParametersInstance]"); case ItemType::ModulePrefix: return QStringLiteral("[ModulePrefix]"); case ItemType::Outer: return QStringLiteral("[Outer]"); case ItemType::Scope: return QStringLiteral("[Scope]"); default: return BuiltinDeclarations::instance().nameForType(type()); } } bool Item::hasProperty(const QString &name) const { assertModuleLocked(); const Item *item = this; do { if (item->m_properties.contains(name)) return true; item = item->m_prototype; } while (item); return false; } bool Item::hasOwnProperty(const QString &name) const { assertModuleLocked(); return m_properties.contains(name); } ValuePtr Item::property(const QString &name) const { assertModuleLocked(); ValuePtr value; const Item *item = this; do { value = item->m_properties.value(name); if (value) break; item = item->m_prototype; } while (item); return value; } ValuePtr Item::ownProperty(const QString &name) const { assertModuleLocked(); return m_properties.value(name); } ItemValuePtr Item::itemProperty(const QString &name, ItemPool &pool, const Item *itemTemplate) { return itemProperty(name, itemTemplate, ItemValueConstPtr(), pool); } ItemValuePtr Item::itemProperty(const QString &name, const ItemValueConstPtr &value, ItemPool &pool) { return itemProperty(name, value->item(), value, pool); } ItemValuePtr Item::itemProperty(const QString &name, const Item *itemTemplate, const ItemValueConstPtr &itemValue, ItemPool &pool) { const ValuePtr v = property(name); if (v && v->type() == Value::ItemValueType) return std::static_pointer_cast(v); if (!itemTemplate) return {}; const bool createdByPropertiesBlock = itemValue && itemValue->createdByPropertiesBlock(); ItemValuePtr result = ItemValue::create(Item::create(&pool, itemTemplate->type()), createdByPropertiesBlock); setProperty(name, result); return result; } // Such scopes were potentially set up in PropertiesBlockConverter. void Item::adaptScopesOfClonedAlternatives(Item *clone) const { if (m_type != ItemType::Module && m_type != ItemType::Product) return; std::unordered_map> valuesPerGroupScope; const std::function collectScopedValues = [&](const PropertyMap &props) { for (const auto &prop : props) { switch (prop->type()) { case Value::VariantValueType: break; case Value::ItemValueType: collectScopedValues(static_cast(prop.get())->item()->properties()); break; case Value::JSSourceValueType: for (const JSSourceValue::Alternative &alt : static_cast(prop.get())->alternatives()) { if (alt.value->scope() && alt.value->scope()->type() == ItemType::Group) valuesPerGroupScope[alt.value->scope()].push_back(alt.value.get()); } break; } } }; const std::function getClonedGroup = [&](Item *group, const Item *parent, const Item *clonedParent) -> Item * { for (int i = 0; i < int(parent->m_children.size()); ++i) { Item * const child = parent->m_children.at(i); Item * const clonedChild = clonedParent->m_children.at(i); QBS_CHECK(child->type() == clonedChild->type()); if (child == group) return clonedChild; if (child->type() == ItemType::Group) { if (Item * const clonedGroup = getClonedGroup(group, child, clonedChild)) return clonedGroup; } } return nullptr; }; collectScopedValues(clone->m_properties); for (const auto &[group, values] : valuesPerGroupScope) { Item * const clonedGroup = getClonedGroup(group, this, clone); QBS_CHECK(clonedGroup); for (JSSourceValue * const v : values) { QBS_CHECK(v->scope() == group); v->setScope(clonedGroup, {}); } } } JSSourceValuePtr Item::sourceProperty(const QString &name) const { ValuePtr v = property(name); if (!v || v->type() != Value::JSSourceValueType) return {}; return std::static_pointer_cast(v); } VariantValuePtr Item::variantProperty(const QString &name) const { ValuePtr v = property(name); if (!v || v->type() != Value::VariantValueType) return {}; return std::static_pointer_cast(v); } bool Item::isOfTypeOrhasParentOfType(ItemType type) const { const Item *item = this; do { if (item->type() == type) return true; item = item->parent(); } while (item); return false; } void Item::addObserver(ItemObserver *observer) const { // Cached Module properties never change. if (m_type == ItemType::Module) return; std::lock_guard lock(m_observersMutex); if (!qEnvironmentVariableIsEmpty("QBS_SANITY_CHECKS")) QBS_CHECK(!contains(m_observers, observer)); m_observers << observer; } void Item::removeObserver(ItemObserver *observer) const { if (m_type == ItemType::Module) return; std::lock_guard lock(m_observersMutex); const auto it = std::find(m_observers.begin(), m_observers.end(), observer); QBS_CHECK(it != m_observers.end()); m_observers.erase(it); } PropertyDeclaration Item::propertyDeclaration(const QString &name, bool allowExpired) const { auto it = m_propertyDeclarations.find(name); if (it != m_propertyDeclarations.end()) return it.value(); if (allowExpired) { it = m_expiredPropertyDeclarations.find(name); if (it != m_expiredPropertyDeclarations.end()) return it.value(); } return m_prototype ? m_prototype->propertyDeclaration(name) : PropertyDeclaration(); } void Item::addModule(const Item::Module &module) { if (!qEnvironmentVariableIsEmpty("QBS_SANITY_CHECKS")) { QBS_CHECK(none_of(m_modules, [&](const Module &m) { if (m.name != module.name) return false; if (!!module.product != !!m.product) return true; if (!module.product) return true; if (module.product->multiplexConfigurationId == m.product->multiplexConfigurationId && module.product->profileName == m.product->profileName) { return true; } return false; })); } m_modules.push_back(module); } void Item::setProperty(const QString &name, const ValuePtr &value) { assertModuleLocked(); m_properties.insert(name, value); std::lock_guard lock(m_observersMutex); for (ItemObserver * const observer : m_observers) observer->onItemPropertyChanged(this); } void Item::dump() const { dump(0); } bool Item::isPresentModule() const { // Initial value is "true" as JS source, overwritten one is always QVariant(false). const ValueConstPtr v = property(StringConstants::presentProperty()); return v && v->type() == Value::JSSourceValueType; } bool Item::isFallbackModule() const { return hasProperty(QLatin1String("__fallback")); } void Item::setupForBuiltinType(DeprecationWarningMode deprecationMode, Logger &logger) { assertModuleLocked(); const BuiltinDeclarations &builtins = BuiltinDeclarations::instance(); const auto properties = builtins.declarationsForType(type()).properties(); for (const PropertyDeclaration &pd : properties) { m_propertyDeclarations.insert(pd.name(), pd); const ValuePtr value = m_properties.value(pd.name()); if (!value) { if (pd.isDeprecated()) continue; JSSourceValuePtr sourceValue = JSSourceValue::create(); sourceValue->setIsBuiltinDefaultValue(); sourceValue->setFile(file()); sourceValue->setSourceCode(pd.initialValueSource().isEmpty() ? StringConstants::undefinedValue() : pd.initialValueSource()); m_properties.insert(pd.name(), sourceValue); } else if (ErrorInfo error = pd.checkForDeprecation(deprecationMode, value->location(), logger); error.hasError()) { throw error; } } } void Item::copyProperty(const QString &propertyName, Item *target) const { target->setProperty(propertyName, property(propertyName)); } void Item::overrideProperties(const QVariantMap &config, const QString &key, const SetupProjectParameters ¶meters, Logger &logger) { const QVariant configMap = config.value(key); if (configMap.isNull()) return; overrideProperties(configMap.toMap(), QualifiedId(key), parameters, logger); } static const char *valueType(const Value *v) { switch (v->type()) { case Value::JSSourceValueType: return "JS source"; case Value::ItemValueType: return "Item"; case Value::VariantValueType: return "Variant"; } return ""; // For dumb compilers. } void Item::dump(int indentation) const { const QByteArray indent(indentation, ' '); qDebug("%stype: %s, pointer value: %p", indent.constData(), qPrintable(typeName()), this); if (!m_properties.empty()) qDebug("%sproperties:", indent.constData()); for (auto it = m_properties.constBegin(); it != m_properties.constEnd(); ++it) { const QByteArray nextIndent(indentation + 4, ' '); qDebug("%skey: %s, value type: %s", nextIndent.constData(), qPrintable(it.key()), valueType(it.value().get())); switch (it.value()->type()) { case Value::JSSourceValueType: qDebug("%svalue: %s", nextIndent.constData(), qPrintable(std::static_pointer_cast(it.value())->sourceCodeForEvaluation())); break; case Value::ItemValueType: qDebug("%svalue:", nextIndent.constData()); std::static_pointer_cast(it.value())->item()->dump(indentation + 8); break; case Value::VariantValueType: qDebug("%svalue: %s", nextIndent.constData(), qPrintable(std::static_pointer_cast(it.value())->value().toString())); break; } } if (!m_children.empty()) qDebug("%schildren:", indent.constData()); for (const Item * const child : std::as_const(m_children)) child->dump(indentation + 4); if (prototype()) { qDebug("%sprototype:", indent.constData()); prototype()->dump(indentation + 4); } } void Item::lockModule() const { QBS_CHECK(m_type == ItemType::Module); m_moduleMutex.lock(); #ifndef NDEBUG QBS_CHECK(!m_moduleLocked); m_moduleLocked = true; #endif } void Item::unlockModule() const { QBS_CHECK(m_type == ItemType::Module); #ifndef NDEBUG QBS_CHECK(m_moduleLocked); m_moduleLocked = false; #endif m_moduleMutex.unlock(); } // This safeguard verifies that all contexts which access Module properties have really // acquired the lock via ModuleItemLocker, as they must. void Item::assertModuleLocked() const { #ifndef NDEBUG if (m_type == ItemType::Module) QBS_CHECK(m_moduleLocked); #endif } void Item::removeProperty(const QString &name) { assertModuleLocked(); m_properties.remove(name); } Item *Item::child(ItemType type, bool checkForMultiple) const { Item *child = nullptr; for (Item * const currentChild : children()) { if (currentChild->type() == type) { if (!checkForMultiple) return currentChild; if (child) { ErrorInfo error(Tr::tr("Multiple instances of item '%1' found where at most one " "is allowed.") .arg(BuiltinDeclarations::instance().nameForType(type))); error.append(Tr::tr("First item"), child->location()); error.append(Tr::tr("Second item"), currentChild->location()); throw error; } child = currentChild; } } return child; } void Item::addChild(Item *parent, Item *child) { parent->m_children.push_back(child); child->setParent(parent); } void Item::removeChild(Item *parent, Item *child) { parent->m_children.removeOne(child); child->setParent(nullptr); } void Item::setPropertyDeclaration(const QString &name, const PropertyDeclaration &declaration) { if (declaration.isExpired()) { m_propertyDeclarations.remove(name); m_expiredPropertyDeclarations.insert(name, declaration); } else { m_propertyDeclarations.insert(name, declaration); } } void Item::setPropertyDeclarations(const Item::PropertyDeclarationMap &decls) { m_propertyDeclarations = decls; } void Item::overrideProperties( const QVariantMap &overridden, const QualifiedId &namePrefix, const SetupProjectParameters ¶meters, Logger &logger) { if (overridden.isEmpty()) return; for (QVariantMap::const_iterator it = overridden.constBegin(); it != overridden.constEnd(); ++it) { const PropertyDeclaration decl = propertyDeclaration(it.key()); if (!decl.isValid()) { ErrorInfo error(Tr::tr("Unknown property: %1.%2"). arg(namePrefix.toString(), it.key())); handlePropertyError(error, parameters, logger); continue; } const auto overridenValue = VariantValue::create(PropertyDeclaration::convertToPropertyType( it.value(), decl.type(), namePrefix, it.key())); overridenValue->markAsSetByCommandLine(); setProperty(it.key(), overridenValue); } } void Item::setModules(const Modules &modules) { m_modules = modules; } Item *createNonPresentModule(ItemPool &pool, const QString &name, const QString &reason, Item *module) { qCDebug(lcModuleLoader) << "Non-required module '" << name << "' not loaded (" << reason << ")." << "Creating dummy module for presence check."; if (!module) { module = Item::create(&pool, ItemType::ModuleInstance); module->setFile(FileContext::create()); module->setProperty(StringConstants::nameProperty(), VariantValue::create(name)); } module->setType(ItemType::ModuleInstance); module->setProperty(StringConstants::presentProperty(), VariantValue::falseValue()); return module; } void setScopeForDescendants(Item *item, Item *scope, bool insertIds) { for (Item * const child : item->children()) { child->setScope(scope); if (insertIds && !child->id().isEmpty()) scope->setProperty(child->id(), ItemValue::create(child)); setScopeForDescendants(child, scope, insertIds); } } CodeRange Item::codeRange() const { return {{m_location.line(), m_location.column()}, m_endPosition}; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/itemdeclaration.h0000644000175100001660000000636014776170045022531 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMDECLARATION_H #define QBS_ITEMDECLARATION_H #include "deprecationinfo.h" #include "itemtype.h" #include "propertydeclaration.h" #include #include namespace qbs { namespace Internal { class ItemDeclaration { public: ItemDeclaration(ItemType type = ItemType::Unknown); ItemType type() const { return m_type; } using Properties = QList; void setProperties(const Properties &props) { m_properties = props; } Properties properties() const { return m_properties; } void setDeprecationInfo(const DeprecationInfo &di) { m_deprecationInfo = di; } DeprecationInfo deprecationInfo() const { return m_deprecationInfo; } ItemDeclaration &operator<<(const PropertyDeclaration &decl); using TypeNames = Set; void setAllowedChildTypes(const TypeNames &typeNames) { m_allowedChildTypes = typeNames; } const TypeNames &allowedChildTypes() const { return m_allowedChildTypes; } bool isChildTypeAllowed(ItemType type) const; ErrorInfo checkForDeprecation(DeprecationWarningMode mode, const QString &name, const CodeLocation &loc, Logger &logger) const; private: ItemType m_type; Properties m_properties; TypeNames m_allowedChildTypes; DeprecationInfo m_deprecationInfo; }; } // namespace Internal } // namespace qbs #endif // QBS_ITEMDECLARATION_H qbs-src-2.6.1/src/lib/corelib/language/filecontextbase.cpp0000644000175100001660000000410214776170045023067 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filecontextbase.h" #include namespace qbs { namespace Internal { QString FileContextBase::dirPath() const { return FileInfo::path(m_filePath); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/value.cpp0000644000175100001660000001777714776170045021052 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "value.h" #include "filecontext.h" #include "item.h" #include #include #include namespace qbs { namespace Internal { Value::Value(Type t, bool createdByPropertiesBlock) : m_type(t) { if (createdByPropertiesBlock) m_flags |= OriginPropertiesBlock; } Value::~Value() = default; void Value::setScope(Item *scope, const QString &scopeName) { m_scope = scope; m_scopeName = scopeName; } int Value::priority(const Item *productItem) const { if (m_priority == -1) m_priority = calculatePriority(productItem); return m_priority; } int Value::calculatePriority(const Item *productItem) const { if (setInternally()) return INT_MAX; if (setByCommandLine()) return INT_MAX - 1; if (setByProfile()) return 2; if (!scope()) return 1; if (scope()->type() == ItemType::Product) return INT_MAX - 2; if (!scope()->isPresentModule()) return 0; const auto it = std::find_if( productItem->modules().begin(), productItem->modules().end(), [this](const Item::Module &m) { return m.item == scope(); }); QBS_CHECK(it != productItem->modules().end()); return INT_MAX - 3 - it->maxDependsChainLength; } void Value::resetPriority() { m_priority = -1; for (const ValuePtr &v : m_candidates) v->resetPriority(); } void Value::removeExpiredCandidates(const Item *productItem) { removeIf(m_candidates, [productItem](const ValuePtr &v) { return v->expired(productItem); }); } void Value::sortCandidates(const std::function &less) { m_candidates = sorted(m_candidates, less); } bool Value::setInternally() const { return type() == VariantValueType && !setByProfile() && !setByCommandLine(); } JSSourceValue::JSSourceValue(bool createdByPropertiesBlock) : Value(JSSourceValueType, createdByPropertiesBlock) , m_line(-1) , m_column(-1) { } JSSourceValue::JSSourceValue(const JSSourceValue &other, ItemPool &pool) : Value(other) { m_sourceCode = other.m_sourceCode; m_line = other.m_line; m_column = other.m_column; m_file = other.m_file; m_baseValue = other.m_baseValue ? std::static_pointer_cast(other.m_baseValue->clone(pool)) : JSSourceValuePtr(); m_alternatives = transformed>( other.m_alternatives, [&pool](const auto &alternative) { return alternative.clone(pool); }); } JSSourceValuePtr JSSourceValue::create(bool createdByPropertiesBlock) { return std::make_shared(createdByPropertiesBlock); } JSSourceValue::~JSSourceValue() = default; ValuePtr JSSourceValue::clone(ItemPool &pool) const { return std::make_shared(*this, pool); } QString JSSourceValue::sourceCodeForEvaluation() const { if (!hasFunctionForm()) return m_sourceCode.toString(); // rewrite blocks to be able to use return statements in property assignments static const QString prefix = QStringLiteral("(function()"); static const QString suffix = QStringLiteral(")()"); return prefix + m_sourceCode.toString() + suffix; } void JSSourceValue::setLocation(int line, int column) { m_line = line; m_column = column; } CodeLocation JSSourceValue::location() const { return CodeLocation(m_file->filePath(), m_line, m_column); } void JSSourceValue::addAlternative(const Alternative &alternative) { if (!m_alternatives.empty() && m_alternatives.back().value->isFallback()) { QBS_CHECK(!alternative.value->isFallback()); m_alternatives.insert(std::prev(m_alternatives.end()), alternative); } else { m_alternatives.push_back(alternative); } } void JSSourceValue::clearAlternatives() { m_alternatives.clear(); } void JSSourceValue::setScope(Item *scope, const QString &scopeName) { Value::setScope(scope, scopeName); if (m_baseValue) m_baseValue->setScope(scope, scopeName); for (const JSSourceValue::Alternative &a : m_alternatives) { if (!a.value->scope()) a.value->setScope(scope, scopeName); } } void JSSourceValue::resetPriority() { Value::resetPriority(); if (m_baseValue) m_baseValue->resetPriority(); for (const JSSourceValue::Alternative &a : m_alternatives) a.value->resetPriority(); } ItemValue::ItemValue(Item *item, bool createdByPropertiesBlock) : Value(ItemValueType, createdByPropertiesBlock) , m_item(item) { QBS_CHECK(m_item); } ItemValuePtr ItemValue::create(Item *item, bool createdByPropertiesBlock) { return std::make_shared(item, createdByPropertiesBlock); } ValuePtr ItemValue::clone(ItemPool &pool) const { return create(m_item->clone(pool), createdByPropertiesBlock()); } class StoredVariantValue : public VariantValue { public: explicit StoredVariantValue(QVariant v) : VariantValue(std::move(v)) {} quintptr id() const override { return quintptr(this); } }; VariantValue::VariantValue(QVariant v) : Value(VariantValueType, false) , m_value(std::move(v)) { } template VariantValuePtr createImpl(const QVariant &v) { if (!v.isValid()) return VariantValue::invalidValue(); if (static_cast(v.userType()) == QMetaType::Bool) return v.toBool() ? VariantValue::trueValue() : VariantValue::falseValue(); return std::make_shared(v); } VariantValuePtr VariantValue::create(const QVariant &v) { return createImpl(v); } VariantValuePtr VariantValue::createStored(const QVariant &v) { return createImpl(v); } ValuePtr VariantValue::clone(ItemPool &) const { return std::make_shared(*this); } const VariantValuePtr &VariantValue::falseValue() { static const VariantValuePtr v = std::make_shared(false); return v; } const VariantValuePtr &VariantValue::trueValue() { static const VariantValuePtr v = std::make_shared(true); return v; } const VariantValuePtr &VariantValue::invalidValue() { static const VariantValuePtr v = std::make_shared(QVariant()); return v; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/jsimports.h0000644000175100001660000000600314776170045021411 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JSIMPORTS_H #define QBS_JSIMPORTS_H #include #include #include #include #include #include namespace qbs { namespace Internal { /** * Represents JavaScript import of the form * import 'fileOrDirectory' as scopeName * * There can be several filenames per scope * if we import a whole directory. */ class JsImport { public: QString scopeName; QStringList filePaths; CodeLocation location; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(scopeName, filePaths, location); } }; inline auto qHash(const JsImport &jsi) { return qHash(jsi.scopeName); } inline bool operator<(const JsImport &lhs, const JsImport &rhs) { return lhs.scopeName < rhs.scopeName; } inline bool operator==(const JsImport &jsi1, const JsImport &jsi2) { return jsi1.scopeName == jsi2.scopeName && toSet(jsi1.filePaths) == toSet(jsi2.filePaths); } using JsImports = std::vector; } // namespace Internal } // namespace qbs #endif // QBS_JSIMPORTS_H qbs-src-2.6.1/src/lib/corelib/language/qualifiedid.cpp0000644000175100001660000000456614776170045022206 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qualifiedid.h" #include namespace qbs { namespace Internal { QualifiedId::QualifiedId() = default; QualifiedId::QualifiedId(const QString &singlePartName) : QStringList(singlePartName) { } QualifiedId::QualifiedId(const QStringList &nameParts) : QStringList(nameParts) { } QualifiedId QualifiedId::fromString(const QString &str) { return {str.split(QLatin1Char('.'))}; } QString QualifiedId::toString() const { return join(QLatin1Char('.')); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/itempool.h0000644000175100001660000000453714776170045021221 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEMPOOL_H #define QBS_ITEMPOOL_H #include #include #include namespace qbs { namespace Internal { class Item; enum class ItemType; class QBS_AUTOTEST_EXPORT ItemPool { Q_DISABLE_COPY(ItemPool) public: ItemPool(); ~ItemPool(); Item *allocateItem(const ItemType &type); private: QbsQmlJS::MemoryPool m_pool; std::vector m_items; }; } // namespace Internal } // namespace qbs #endif // QBS_ITEMPOOL_H qbs-src-2.6.1/src/lib/corelib/language/filetags.cpp0000644000175100001660000000605014776170045021512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filetags.h" #include #include namespace qbs { namespace Internal { void FileTag::clear() { Id::operator=(Id()); } void FileTag::store(PersistentPool &pool) const { pool.store(toString()); } void FileTag::load(PersistentPool &pool) { *this = FileTag(pool.load().toUtf8()); } QDebug operator<<(QDebug debug, const FileTag &tag) { QDebugStateSaver saver(debug); return debug.resetFormat().noquote() << tag.toString(); } FileTags FileTags::fromStringList(const QStringList &strings) { FileTags result; for (const QString &str : strings) result += FileTag(str.toUtf8()); return result; } LogWriter operator <<(LogWriter w, const FileTags &tags) { bool firstLoop = true; w.write('('); for (const FileTag &tag : tags) { if (firstLoop) firstLoop = false; else w.write(QStringLiteral(", ")); w.write(tag.toString()); } w.write(')'); return w; } QDebug operator<<(QDebug debug, const FileTags &tags) { QDebugStateSaver saver(debug); return debug.resetFormat().noquote() << tags.toStringList(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/resolvedfilecontext.h0000644000175100001660000000566714776170045023466 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RESOLVEDFILECONTEXT_H #define QBS_RESOLVEDFILECONTEXT_H #include "forward_decls.h" #include "filecontextbase.h" #include namespace qbs { namespace Internal { class ResolvedFileContext : public FileContextBase { public: static ResolvedFileContextPtr create() { return ResolvedFileContextPtr(new ResolvedFileContext); } static ResolvedFileContextPtr create(const FileContextBase &baseContext) { return ResolvedFileContextPtr(new ResolvedFileContext(baseContext)); } template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_filePath, m_jsExtensions, m_searchPaths, m_jsImports); } private: ResolvedFileContext() = default; ResolvedFileContext(const FileContextBase &ctx); }; bool operator==(const ResolvedFileContext &a, const ResolvedFileContext &b); inline bool operator!=(const ResolvedFileContext &a, const ResolvedFileContext &b) { return !(a == b); } } // namespace Internal } // namespace qbs #endif // QBS_RESOLVEDFILECONTEXT_H qbs-src-2.6.1/src/lib/corelib/language/evaluator.cpp0000644000175100001660000012317314776170045021724 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "evaluator.h" #include "builtindeclarations.h" #include "filecontext.h" #include "filetags.h" #include "item.h" #include "scriptengine.h" #include "value.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class EvaluationData { public: const Item *item = nullptr; mutable QHash valueCache; }; enum class ConversionType { Full, ElementsOnly }; static void convertToPropertyType_impl( ScriptEngine *engine, const QString &pathPropertiesBaseDir, const Item *item, const PropertyDeclaration &decl, const Value *value, const CodeLocation &location, ConversionType conversionType, JSValue &v); static int getEvalPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj); static int getEvalProperty(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop); static int getEvalPropertySafe(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop); static bool debugProperties = false; static JSValue handleDeprecatedPathResolving(ScriptEngine &engine, const Value &val) { const QString warning = Tr::tr( "Resolving path properties relative to the exporting product's location is " "deprecated.\nIn future versions of qbs, such properties will be resolved relative to the " "importing product's location.\n" "Explicitly use exportingProduct.sourceDirectory instead."); try { engine.handleDeprecation(Version(2, 7), warning, val.location()); } catch (const ErrorInfo &e) { return engine.throwError(e.toString()); } return JS_UNDEFINED; } Evaluator::Evaluator(ScriptEngine *scriptEngine) : m_scriptEngine(scriptEngine) , m_scriptClass(scriptEngine->registerClass("Evaluator", nullptr, nullptr, JS_UNDEFINED, getEvalPropertyNames, getEvalPropertySafe)) { scriptEngine->registerEvaluator(this); scriptEngine->logger().storeWarnings(); } Evaluator::~Evaluator() { Set valuesToFree; for (const auto &data : std::as_const(m_scriptValueMap)) { const auto evalData = attachedPointer(data, m_scriptClass); valuesToFree << data; for (const JSValue cachedValue : evalData->valueCache) JS_FreeValue(m_scriptEngine->context(), cachedValue); evalData->item->removeObserver(this); delete evalData; } for (const auto &scopes : std::as_const(m_fileContextScopesMap)) { valuesToFree << scopes.fileScope; valuesToFree << scopes.importScope; } for (const JSValue v : std::as_const(valuesToFree)) { JS_FreeValue(m_scriptEngine->context(), v); } m_scriptEngine->unregisterEvaluator(this); } JSValue Evaluator::property(const Item *item, const QString &name) { return getJsProperty(m_scriptEngine->context(), scriptValue(item), name); } JSValue Evaluator::value(const Item *item, const QString &name, bool *propertyWasSet) { return evaluateProperty(item, name, propertyWasSet); } bool Evaluator::boolValue(const Item *item, const QString &name, bool *propertyWasSet) { const ScopedJsValue sv(m_scriptEngine->context(), value(item, name, propertyWasSet)); return JS_ToBool(m_scriptEngine->context(), sv); } int Evaluator::intValue(const Item *item, const QString &name, int defaultValue, bool *propertyWasSet) { const JSValue v = evaluateProperty(item, name, propertyWasSet); if (JS_IsUndefined(v)) return defaultValue; qint32 n; JS_ToInt32(m_scriptEngine->context(), &n, v); return n; } FileTags Evaluator::fileTagsValue(const Item *item, const QString &name, bool *propertySet) { return FileTags::fromStringList(stringListValue(item, name, propertySet)); } QString Evaluator::stringValue(const Item *item, const QString &name, const QString &defaultValue, bool *propertyWasSet) { const ScopedJsValue v(m_scriptEngine->context(), evaluateProperty(item, name, propertyWasSet)); return JS_IsUndefined(v) ? defaultValue : getJsString(m_scriptEngine->context(), v); } static QStringList toStringList(ScriptEngine *engine, const JSValue &scriptValue) { if (JS_IsString(scriptValue)) return {getJsString(engine->context(), scriptValue)}; if (JS_IsArray(engine->context(), scriptValue)) { QStringList lst; int i = 0; for (;;) { JSValue elem = JS_GetPropertyUint32(engine->context(), scriptValue, i++); if (JS_IsUndefined(elem)) break; lst.push_back(getJsString(engine->context(), elem)); JS_FreeValue(engine->context(), elem); } return lst; } return {}; } QStringList Evaluator::stringListValue(const Item *item, const QString &name, bool *propertyWasSet) { const auto result = optionalStringListValue(item, name, propertyWasSet); return result ? *result : QStringList(); } std::optional Evaluator::optionalStringListValue( const Item *item, const QString &name, bool *propertyWasSet) { const ScopedJsValue v(m_scriptEngine->context(), property(item, name)); handleEvaluationError(item, name); if (propertyWasSet) *propertyWasSet = isNonDefaultValue(item, name); if (JS_IsUndefined(v)) return std::nullopt; return toStringList(m_scriptEngine, v); } QVariant Evaluator::variantValue(const Item *item, const QString &name, bool *propertySet) { const ScopedJsValue jsValue(m_scriptEngine->context(), property(item, name)); handleEvaluationError(item, name); if (propertySet) *propertySet = isNonDefaultValue(item, name); return getJsVariant(m_scriptEngine->context(), jsValue); } bool Evaluator::isNonDefaultValue(const Item *item, const QString &name) const { const ValueConstPtr v = item->property(name); return v && (v->type() != Value::JSSourceValueType || !static_cast(v.get())->isBuiltinDefaultValue()); } void Evaluator::convertToPropertyType(const PropertyDeclaration &decl, const CodeLocation &loc, JSValue &v) { convertToPropertyType_impl( engine(), QString(), nullptr, decl, nullptr, loc, ConversionType::Full, v); } JSValue Evaluator::scriptValue(const Item *item) { JSValue &scriptValue = m_scriptValueMap[item]; if (JS_IsObject(scriptValue)) { // already initialized return scriptValue; } const auto edata = new EvaluationData; edata->item = item; edata->item->addObserver(this); scriptValue = JS_NewObjectClass(m_scriptEngine->context(), m_scriptClass); attachPointerTo(scriptValue, edata); return scriptValue; } void Evaluator::handleEvaluationError(const Item *item, const QString &name) { throwOnEvaluationError(m_scriptEngine, [&item, &name] () { const ValueConstPtr &value = item->property(name); return value ? value->location() : CodeLocation(); }); } JSValue Evaluator::evaluateProperty(const Item *item, const QString &name, bool *propertyWasSet) { const JSValue result = property(item, name); ScopedJsValue valMgr(m_scriptEngine->context(), result); handleEvaluationError(item, name); valMgr.release(); if (propertyWasSet) *propertyWasSet = isNonDefaultValue(item, name); return result; } Evaluator::FileContextScopes Evaluator::fileContextScopes(const FileContextConstPtr &file) { FileContextScopes &result = m_fileContextScopesMap[file]; if (!JS_IsObject(result.fileScope)) { if (file->idScope()) result.fileScope = scriptValue(file->idScope()); else result.fileScope = m_scriptEngine->newObject(); setJsProperty(m_scriptEngine->context(), result.fileScope, StringConstants::filePathGlobalVar(), file->filePath()); setJsProperty(m_scriptEngine->context(), result.fileScope, StringConstants::pathGlobalVar(), file->dirPath()); } if (!JS_IsObject(result.importScope)) { try { ScopedJsValue importScope(m_scriptEngine->context(), m_scriptEngine->newObject()); setupScriptEngineForFile(m_scriptEngine, file, importScope, ObserveMode::Enabled); result.importScope = importScope.release(); } catch (const ErrorInfo &e) { result.importScope = throwError(m_scriptEngine->context(), e.toString()); } } return result; } // This is the only function in this class that can be called from a thread that is not // the evaluating one. For this reason, we do not clear the cache here, as that would // incur enourmous synchronization overhead. Instead, we mark the item's cache as invalidated // and do the actual clearing only at the very few places where the cache is actually accessed. void Evaluator::invalidateCache(const Item *item) { std::lock_guard lock(m_cacheInvalidationMutex); m_invalidatedCaches << item; } void Evaluator::clearCache(const Item *item) { std::lock_guard lock(m_cacheInvalidationMutex); if (const auto data = attachedPointer(m_scriptValueMap.value(item), m_scriptEngine->dataWithPtrClass())) { clearCache(*data); m_invalidatedCaches.remove(data->item); } } void Evaluator::clearCacheIfInvalidated(EvaluationData &edata) { std::lock_guard lock(m_cacheInvalidationMutex); if (const auto it = m_invalidatedCaches.find(edata.item); it != m_invalidatedCaches.end()) { clearCache(edata); m_invalidatedCaches.erase(it); } } void Evaluator::clearCache(EvaluationData &edata) { for (const auto value : std::as_const(edata.valueCache)) JS_FreeValue(m_scriptEngine->context(), value); edata.valueCache.clear(); } void throwOnEvaluationError(ScriptEngine *engine, const std::function &provideFallbackCodeLocation) { if (JsException ex = engine->checkAndClearException(provideFallbackCodeLocation())) throw ex.toErrorInfo(); } static void makeTypeError(ScriptEngine *engine, const ErrorInfo &error, JSValue &v) { v = throwError(engine->context(), error.toString()); } static void makeTypeError(ScriptEngine *engine, const PropertyDeclaration &decl, const CodeLocation &location, JSValue &v) { const ErrorInfo error(Tr::tr("Value assigned to property '%1' does not have type '%2'.") .arg(decl.name(), decl.typeString()), location); makeTypeError(engine, error, v); } static void convertToPropertyType_impl( ScriptEngine *engine, const QString &pathPropertiesBaseDir, const Item *item, const PropertyDeclaration &decl, const Value *value, const CodeLocation &location, ConversionType conversionType, JSValue &v) { JSContext * const ctx = engine->context(); if (JS_IsUninitialized(v) || JS_IsUndefined(v) || JS_IsError(ctx, v) || JS_IsException(v)) return; if (!decl.isScalar() && !JS_IsArray(ctx, v) && conversionType == ConversionType::ElementsOnly) { const auto correspondingType = [](const PropertyDeclaration &decl) { switch (decl.type()) { case PropertyDeclaration::StringList: return PropertyDeclaration::String; case PropertyDeclaration::PathList: return PropertyDeclaration::Path; case PropertyDeclaration::VariantList: return PropertyDeclaration::Variant; default: QBS_CHECK(false); }; }; PropertyDeclaration elemDecl = decl; elemDecl.setType(correspondingType(decl)); convertToPropertyType_impl( engine, pathPropertiesBaseDir, item, elemDecl, value, location, conversionType, v); } QString actualBaseDir; bool baseDirIsFromExport = false; if (decl.type() == PropertyDeclaration::Path || decl.type() == PropertyDeclaration::PathList) { actualBaseDir = pathPropertiesBaseDir; if (const Item * const baseDirItem = value && value->scope() ? value->scope() : item) { if (const VariantValueConstPtr v = baseDirItem->variantProperty( StringConstants::qbsSourceDirPropertyInternal())) { actualBaseDir = v->value().toString(); baseDirIsFromExport = true; } if (actualBaseDir.isEmpty() && baseDirItem->type() == ItemType::Product) { if (const VariantValueConstPtr itemSourceDir = baseDirItem->variantProperty( StringConstants::sourceDirectoryProperty())) { actualBaseDir = itemSourceDir->value().toString(); } } } } switch (decl.type()) { case PropertyDeclaration::UnknownType: case PropertyDeclaration::Variant: break; case PropertyDeclaration::Boolean: if (!JS_IsBool(v)) v = JS_NewBool(ctx, JS_ToBool(ctx, v)); break; case PropertyDeclaration::Integer: if (!JS_IsNumber(v)) makeTypeError(engine, decl, location, v); break; case PropertyDeclaration::Path: if (!JS_IsString(v)) { makeTypeError(engine, decl, location, v); break; } if (!actualBaseDir.isEmpty()) { const QString rawPath = getJsString(ctx, v); if (baseDirIsFromExport && !FileInfo::isAbsolute(rawPath)) { const JSValue error = handleDeprecatedPathResolving(*engine, *value); if (JS_IsError(engine->context(), error)) { v = error; return; } } v = engine->toScriptValue( QDir::cleanPath(FileInfo::resolvePath(actualBaseDir, rawPath))); JS_FreeValue(ctx, v); } break; case PropertyDeclaration::String: if (!JS_IsString(v)) makeTypeError(engine, decl, location, v); break; case PropertyDeclaration::PathList: case PropertyDeclaration::StringList: { if (!JS_IsArray(ctx, v)) { JSValue x = engine->newArray(1, JsValueOwner::ScriptEngine); JS_SetPropertyUint32(ctx, x, 0, JS_DupValue(ctx, v)); v = x; } const quint32 c = getJsIntProperty(ctx, v, StringConstants::lengthProperty()); for (quint32 i = 0; i < c; ++i) { const ScopedJsValue elem(ctx, JS_GetPropertyUint32(ctx, v, i)); if (JS_IsUndefined(elem)) { ErrorInfo error(Tr::tr("Element at index %1 of list property '%2' is undefined. " "String expected.").arg(i).arg(decl.name()), location); makeTypeError(engine, error, v); break; } if (JS_IsNull(elem)) { ErrorInfo error(Tr::tr("Element at index %1 of list property '%2' is null. " "String expected.").arg(i).arg(decl.name()), location); makeTypeError(engine, error, v); break; } if (!JS_IsString(elem)) { ErrorInfo error(Tr::tr("Element at index %1 of list property '%2' does not have " "string type.").arg(i).arg(decl.name()), location); makeTypeError(engine, error, v); break; } if (actualBaseDir.isEmpty()) continue; const QString rawPath = getJsString(ctx, elem); if (baseDirIsFromExport && !FileInfo::isAbsolute(rawPath)) { const JSValue error = handleDeprecatedPathResolving(*engine, *value); if (JS_IsError(engine->context(), error)) { v = error; return; } } const JSValue newElem = engine->toScriptValue( QDir::cleanPath(FileInfo::resolvePath(actualBaseDir, rawPath))); JS_SetPropertyUint32(ctx, v, i, newElem); } break; } case PropertyDeclaration::VariantList: if (!JS_IsArray(ctx, v)) { JSValue x = engine->newArray(1, JsValueOwner::ScriptEngine); JS_SetPropertyUint32(ctx, x, 0, JS_DupValue(ctx, v)); v = x; } break; } } static int getEvalPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValue obj) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const Evaluator * const evaluator = engine->evaluator(); const auto data = attachedPointer(obj, evaluator->classId()); if (!data) return -1; const Item::PropertyMap &map = data->item->properties(); *plen = map.size(); if (!map.isEmpty()) { *ptab = reinterpret_cast(js_malloc(ctx, *plen * sizeof **ptab)); JSPropertyEnum *entry = *ptab; for (auto it = map.cbegin(); it != map.cend(); ++it, ++entry) { entry->atom = JS_NewAtom(ctx, it.key().toUtf8().constData()); entry->is_enumerable = 1; } } else { *ptab = nullptr; } return 0; } static void convertToPropertyType( ScriptEngine *engine, const Item *item, const PropertyDeclaration &decl, const Value *value, ConversionType conversionType, JSValue &v) { if (value->type() == Value::VariantValueType && JS_IsUndefined(v) && !decl.isScalar()) { v = engine->newArray(0, JsValueOwner::ScriptEngine); // QTBUG-51237 return; } convertToPropertyType_impl( engine, engine->evaluator()->pathPropertiesBaseDir(), item, decl, value, value->location(), conversionType, v); } class PropertyStackManager { public: PropertyStackManager(const Item *itemOfProperty, const QString &name, const Value *value, std::stack &requestedProperties, PropertyDependencies &propertyDependencies) : m_requestedProperties(requestedProperties) { if (value->type() == Value::JSSourceValueType && (itemOfProperty->type() == ItemType::ModuleInstance || itemOfProperty->type() == ItemType::Module || itemOfProperty->type() == ItemType::Export)) { const VariantValueConstPtr varValue = itemOfProperty->variantProperty(StringConstants::nameProperty()); if (!varValue) return; m_stackUpdate = true; const QualifiedId fullPropName = QualifiedId::fromString(varValue->value().toString()) << name; if (!requestedProperties.empty()) propertyDependencies[fullPropName].insert(requestedProperties.top()); m_requestedProperties.push(fullPropName); } } ~PropertyStackManager() { if (m_stackUpdate) m_requestedProperties.pop(); } private: std::stack &m_requestedProperties; bool m_stackUpdate = false; }; class ValueEvaluator : ValueHandler { public: ValueEvaluator( Evaluator &evaluator, JSValue obj, const ValuePtr &v, const Item &item, const Item &itemOfProperty, const PropertyDeclaration &decl) : m_evaluator(evaluator) , m_engine(*evaluator.engine()) , m_object(obj) , m_value(*v) , m_item(item) , m_itemOfProperty(itemOfProperty) , m_decl(decl) { } JSValue eval() { JSValue result = m_value.apply(this); if (JS_IsUninitialized(result)) result = JS_UNDEFINED; convertToPropertyType(&m_engine, &m_item, m_decl, &m_value, ConversionType::Full, result); return result; } private: class ScopeChain { public: ScopeChain(Evaluator &evaluator) : m_evaluator(evaluator) {} void pushScope(const JSValue &scope) { if (JS_IsObject(scope)) m_chain << scope; } void pushScopeRecursively(const Item *scope) { if (scope) { pushScopeRecursively(scope->scope()); pushScope(m_evaluator.scriptValue(scope)); } } qbs::Internal::span chain() const { return m_chain; } private: Evaluator &m_evaluator; QVarLengthArray m_chain; }; void setupConvenienceProperty(const QString &conveniencePropertyName, JSValue *extraScope, const JSValue &scriptValue) { if (!JS_IsObject(*extraScope)) *extraScope = m_engine.newObject(); const PropertyDeclaration::Type type = m_decl.type(); const bool isArray = type == PropertyDeclaration::StringList || type == PropertyDeclaration::PathList || type == PropertyDeclaration::Variant // TODO: Why? || type == PropertyDeclaration::VariantList; JSValue valueToSet = JS_DupValue(m_engine.context(), scriptValue); if (isArray && (JS_IsUninitialized(valueToSet) || JS_IsUndefined(valueToSet))) valueToSet = m_engine.newArray(0, JsValueOwner::Caller); setJsProperty(m_engine.context(), *extraScope, conveniencePropertyName, valueToSet); } JSValue createExtraScope(const JSSourceValue *value, Item *outerItem, JSValue *outerScriptValue) { JSValue extraScope = JS_UNINITIALIZED; if (value->sourceUsesBase()) { JSValue baseValue = JS_UNINITIALIZED; if (value->baseValue()) { baseValue = ValueEvaluator( m_evaluator, m_object, value->baseValue(), m_item, m_itemOfProperty, m_decl) .eval(); } setupConvenienceProperty(StringConstants::baseVar(), &extraScope, baseValue); } if (value->sourceUsesOuter()) { JSValue v = JS_UNINITIALIZED; bool doSetup = false; if (outerItem) { v = m_evaluator.property(outerItem, m_decl.name()); if (JsException ex = m_engine.checkAndClearException({})) return m_engine.throwError(ex.toErrorInfo().toString()); doSetup = true; JS_FreeValue(m_engine.context(), v); } else if (outerScriptValue) { doSetup = true; v = *outerScriptValue; } if (doSetup) setupConvenienceProperty(StringConstants::outerVar(), &extraScope, v); } if (value->sourceUsesOriginal()) { JSValue originalJs = JS_UNINITIALIZED; ScopedJsValue originalMgr(m_engine.context(), JS_UNDEFINED); if (m_decl.isScalar()) { const Item *item = &m_itemOfProperty; if (item->type() != ItemType::ModuleInstance && item->type() != ItemType::ModuleInstancePlaceholder) { const QString errorMessage = Tr::tr("The special value 'original' can only " "be used with module properties."); return throwError(m_engine.context(), errorMessage); } if (!value->scope()) { const QString errorMessage = Tr::tr("The special value 'original' cannot " "be used on the right-hand side of a property declaration."); return throwError(m_engine.context(), errorMessage); } ValuePtr original; for (const ValuePtr &v : m_value.candidates()) { if (!v->scope()) { original = v; break; } } // This can happen when resolving shadow products. The error will be ignored // in that case. if (!original) { const QString errorMessage = Tr::tr("Error setting up 'original'."); return throwError(m_engine.context(), errorMessage); } originalJs = ValueEvaluator(m_evaluator, m_object, original, m_item, *item, m_decl).eval(); } else { originalJs = m_engine.newArray(0, JsValueOwner::Caller); originalMgr.setValue(originalJs); } setupConvenienceProperty(StringConstants::originalVar(), &extraScope, originalJs); } return extraScope; } JSValue mergeValues(const JSValueList &lst) { JSValue result = m_engine.newArray(int(lst.size()), JsValueOwner::ScriptEngine); quint32 k = 0; JSContext * const ctx = m_engine.context(); for (const JSValue &v : std::as_const(lst)) { QBS_ASSERT(!JS_IsError(ctx, v), continue); if (JS_IsArray(ctx, v)) { const quint32 vlen = getJsIntProperty(ctx, v, StringConstants::lengthProperty()); for (quint32 j = 0; j < vlen; ++j) JS_SetPropertyUint32(ctx, result, k++, JS_GetPropertyUint32(ctx, v, j)); JS_FreeValue(ctx, v); } else { JS_SetPropertyUint32(ctx, result, k++, v); } } setJsProperty(ctx, result, StringConstants::lengthProperty(), JS_NewInt32(ctx, k)); return result; } JSValue handleAlternatives(JSSourceValue *value) { if (!m_decl.isScalar() && !value->createdByPropertiesBlock() && !value->alternatives().empty()) { const QString warning = Tr::tr("Using list properties as fallback values is deprecated.\n" "In future versions of qbs, such properties will be considered " "unconditionally.\n" "If you want to keep the current semantics for this value, use a fallback " "%1 item.") .arg(BuiltinDeclarations::instance().nameForType(ItemType::Properties)); try { m_engine.handleDeprecation(Version(2, 7), warning, value->location()); } catch (const ErrorInfo &e) { return m_engine.throwError(e.toString()); } } JSValue outerScriptValue = JS_UNDEFINED; JSValueList lst; for (const JSSourceValue::Alternative &alternative : value->alternatives()) { if (alternative.value->isFallback() && !lst.empty()) break; if (alternative.value->sourceUsesOuter() && !m_itemOfProperty.outerItem() && JS_IsUndefined(outerScriptValue)) { outerScriptValue = evaluateJSSourceValue(value, nullptr); if (JS_IsError(m_engine.context(), outerScriptValue)) { const ScopedJsValueList l(m_engine.context(), lst); return outerScriptValue; } } const JSValue v = evaluateJSSourceValue( alternative.value.get(), m_itemOfProperty.outerItem(), &alternative, value, &outerScriptValue); if (JS_IsUninitialized(v)) continue; if (m_decl.isScalar()) return v; if (!JS_IsUndefined(v)) lst << JS_DupValue(m_engine.context(), v); } return lst.empty() ? JS_UNINITIALIZED : mergeValues(lst); } JSValue mergeWithCandidates(const JSSourceValue *value, JSValue result) { if (value->candidates().empty()) return result; JSValueList lst; if (!JS_IsUninitialized(result) && !JS_IsUndefined(result)) lst << JS_DupValue(m_engine.context(), result); for (const ValuePtr &next : value->candidates()) { JSValue v = next->apply(this); if (JsException ex = m_engine.checkAndClearException({})) { const ScopedJsValueList l(m_engine.context(), lst); return m_engine.throwError(ex.toErrorInfo().toString()); } if (JS_IsUninitialized(v) || JS_IsUndefined(v)) continue; convertToPropertyType( &m_engine, &m_item, m_decl, next.get(), ConversionType::ElementsOnly, v); lst.push_back(JS_DupValue(m_engine.context(), v)); } return lst.empty() ? result : mergeValues(lst); } JSValue doHandle(JSSourceValue *value) override { JSValue result = handleAlternatives(value); if (JS_IsUninitialized(result)) { result = evaluateJSSourceValue(value, m_itemOfProperty.outerItem()); if (JS_IsError(m_engine.context(), result)) return result; } else if (value->isExclusiveListValue()) { return result; } if (m_decl.isScalar()) { if (!JS_IsUninitialized(result) || !value->createdByPropertiesBlock()) return result; for (const ValuePtr &candidate : value->candidates()) { const JSValue v = candidate->apply(this); if (!JS_IsUninitialized(v)) return v; } return JS_UNINITIALIZED; } return mergeWithCandidates(value, result); } JSValue evaluateJSSourceValue( const JSSourceValue *value, Item *outerItem, const JSSourceValue::Alternative *alternative = nullptr, JSSourceValue *elseCaseValue = nullptr, JSValue *outerScriptValue = nullptr) { QBS_ASSERT(!alternative || value == alternative->value.get(), return JS_UNINITIALIZED); for (Item *group = alternative ? alternative->value->scope() : nullptr; group && group->type() == ItemType::Group; group = group->parent()) { if (!m_evaluator.boolValue(group, StringConstants::conditionProperty())) return JS_UNINITIALIZED; } ScopeChain scopeChain(m_evaluator); const JSValue maybeExtraScope = createExtraScope(value, outerItem, outerScriptValue); if (JS_IsError(m_engine.context(), maybeExtraScope)) return maybeExtraScope; const ScopedJsValue extraScopeMgr(m_engine.context(), maybeExtraScope); const Evaluator::FileContextScopes fileCtxScopes = m_evaluator.fileContextScopes( value->file()); if (JsException ex = m_engine.checkAndClearException({})) return m_engine.throwError(ex.toErrorInfo().toString()); scopeChain.pushScope(fileCtxScopes.fileScope); scopeChain.pushScopeRecursively(m_item.scope()); if ((m_itemOfProperty.type() != ItemType::ModuleInstance && m_itemOfProperty.type() != ItemType::ModuleInstancePlaceholder) || !value->scope()) { scopeChain.pushScope(m_object); } scopeChain.pushScopeRecursively(value->scope()); scopeChain.pushScope(maybeExtraScope); scopeChain.pushScope(fileCtxScopes.importScope); if (alternative) { ScopedJsValue sv( m_engine.context(), alternative->value->isFallback() ? JS_NewBool(m_engine.context(), 1) : m_engine.evaluate( JsValueOwner::Caller, alternative->condition.value, {}, 1, scopeChain.chain())); if (JsException ex = m_engine.checkAndClearException(alternative->condition.location)) { // This handles cases like the following: // Depends { name: "cpp" } // Properties { // condition: qbs.targetOS.contains("darwin") // bundle.isBundle: false // } // On non-Darwin platforms, bundle never gets instantiated, and thus bundle.isBundle // has no scope, so the qbs item in the condition is not found. // TODO: Ideally, we would never evaluate values in placeholder items, but // there are currently several contexts where we do that, e.g. Export // and Group items. Perhaps change that, or try to collect all such // exceptions and don't try to evaluate other cases. if (m_itemOfProperty.type() == ItemType::ModuleInstancePlaceholder) return JS_UNDEFINED; return m_engine.throwError(ex.toErrorInfo().toString()); } // The condition is false. Try the next alternative or the else value. if (!JS_ToBool(m_engine.context(), sv)) return JS_UNINITIALIZED; sv.reset(m_engine.evaluate( JsValueOwner::Caller, alternative->overrideListProperties.value, {}, 1, scopeChain.chain())); if (JsException ex = m_engine.checkAndClearException( alternative->overrideListProperties.location)) { return m_engine.throwError(ex.toErrorInfo().toString()); } if (JS_ToBool(m_engine.context(), sv)) elseCaseValue->setIsExclusiveListValue(); } return m_engine.evaluate( JsValueOwner::ScriptEngine, value->sourceCodeForEvaluation(), value->file()->filePath(), value->line(), scopeChain.chain()); } JSValue doHandle(ItemValue *value) override { const JSValue result = m_evaluator.scriptValue(value->item()); if (JS_IsUninitialized(result)) qDebug() << "SVConverter returned invalid script value."; return result; } JSValue doHandle(VariantValue *variantValue) override { const JSValue result = m_engine.toScriptValue(variantValue->value(), variantValue->id()); m_engine.takeOwnership(result); return result; } Evaluator &m_evaluator; ScriptEngine &m_engine; const JSValue m_object; Value &m_value; const Item &m_item; const Item &m_itemOfProperty; const PropertyDeclaration m_decl; }; static QString resultToString(JSContext *ctx, const JSValue &scriptValue) { if (JS_IsUndefined(scriptValue)) return QLatin1String("undefined"); if (JS_IsArray(ctx, scriptValue)) return getJsStringList(ctx, scriptValue).join(QLatin1Char(',')); if (JS_IsObject(scriptValue)) { return QStringLiteral("[Object: ") + QString::number(jsObjectId(scriptValue)) + QLatin1Char(']'); } return getJsVariant(ctx, scriptValue).toString(); } struct EvalResult { JSValue v = JS_UNDEFINED; bool found = false; }; static EvalResult getEvalProperty( Evaluator &evaluator, JSValue obj, const Item *item, const QString &name, EvaluationData *data) { ScriptEngine &engine = *evaluator.engine(); const bool isModuleInstance = item->type() == ItemType::ModuleInstance || item->type() == ItemType::ModuleInstancePlaceholder; for (; item; item = item->prototype()) { if (isModuleInstance && (item->type() == ItemType::Module || item->type() == ItemType::Export)) { break; // There's no property in a prototype that's not also in the instance. } const ValuePtr value = item->ownProperty(name); if (!value) continue; const Item * const itemOfProperty = item; // The item that owns the property. PropertyStackManager propStackmanager( itemOfProperty, name, value.get(), evaluator.requestedProperties(), evaluator.propertyDependencies()); if (evaluator.cachingEnabled()) { evaluator.clearCacheIfInvalidated(*data); const auto result = data->valueCache.constFind(name); if (result != data->valueCache.constEnd()) { if (debugProperties) qDebug() << "[SC] cache hit " << name << ": " << resultToString(engine.context(), *result); return {*result, true}; } } const JSValue result = ValueEvaluator( evaluator, obj, value, *data->item, *itemOfProperty, itemOfProperty->propertyDeclaration(name)) .eval(); if (debugProperties) qDebug() << "[SC] cache miss " << name << ": " << resultToString(engine.context(), result); if (evaluator.cachingEnabled()) { evaluator.clearCacheIfInvalidated(*data); const auto it = data->valueCache.find(name); if (it != data->valueCache.end()) { JS_FreeValue(engine.context(), it.value()); it.value() = JS_DupValue(engine.context(), result); } else { data->valueCache.insert(name, JS_DupValue(engine.context(), result)); } } return {result, true}; } return {JS_UNDEFINED, false}; } static int getEvalProperty(JSContext *ctx, JSPropertyDescriptor *desc, JSValue obj, JSAtom prop) { if (desc) { desc->getter = desc->setter = desc->value = JS_UNDEFINED; desc->flags = JS_PROP_ENUMERABLE; } ScriptEngine &engine = *ScriptEngine::engineForContext(ctx); Evaluator &evaluator = *engine.evaluator(); const auto data = attachedPointer(obj, evaluator.classId()); const QString name = getJsString(ctx, prop); if (debugProperties) qDebug() << "[SC] queryProperty " << jsObjectId(obj) << " " << name; if (name == QStringLiteral("parent")) { if (desc) { Item * const parent = data->item->parent(); desc->value = parent ? JS_DupValue(ctx, evaluator.scriptValue(data->item->parent())) : JS_UNDEFINED; } return 1; } if (!data) { if (debugProperties) qDebug() << "[SC] queryProperty: no data attached"; engine.setLastLookupStatus(false); return -1; } EvalResult result = getEvalProperty(evaluator, obj, data->item, name, data); if (!result.found && data->item->parent()) { if (debugProperties) qDebug() << "[SC] queryProperty: query parent"; const Item * const parentItem = data->item->parent(); result = getEvalProperty( evaluator, evaluator.scriptValue(parentItem), parentItem, name, data); } if (result.found) { if (desc) desc->value = JS_DupValue(ctx, result.v); engine.setLastLookupStatus(true); return 1; } if (debugProperties) qDebug() << "[SC] queryProperty: no such property"; engine.setLastLookupStatus(false); return 0; } static int getEvalPropertySafe(JSContext *ctx, JSPropertyDescriptor *desc, JSValue obj, JSAtom prop) { try { return getEvalProperty(ctx, desc, obj, prop); } catch (const ErrorInfo &e) { ScopedJsValue error(ctx, throwError(ctx, e.toString())); return -1; } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/asttools.cpp0000644000175100001660000000553014776170045021566 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "asttools.h" #include namespace qbs { namespace Internal { QStringList toStringList(QbsQmlJS::AST::UiQualifiedId *qid) { QStringList result; for (; qid; qid = qid->next) result.push_back(qid->name.toString()); return result; } CodeLocation toCodeLocation(const QString &filePath, const QbsQmlJS::AST::SourceLocation &location) { return CodeLocation(filePath, location.startLine, location.startColumn); } QString textOf(const QString &source, QbsQmlJS::AST::Node *node) { if (!node) return {}; return source.mid(node->firstSourceLocation().begin(), int(node->lastSourceLocation().end() - node->firstSourceLocation().begin())); } QStringView textViewOf(const QString &source, QbsQmlJS::AST::Node *node) { const quint32 firstBegin = node->firstSourceLocation().begin(); return QStringView(source).mid(firstBegin, int(node->lastSourceLocation().end() - firstBegin)); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/language/item.h0000644000175100001660000002515414776170045020325 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ITEM_H #define QBS_ITEM_H #include "forward_decls.h" #include "itemtype.h" #include "propertydeclaration.h" #include "qualifiedid.h" #include #include #include #include #include #include #include #include #include #include #include namespace qbs { class SetupProjectParameters; namespace Internal { class ItemObserver; class ItemPool; class Logger; class ModuleItemLocker; class ProductContext; class QBS_AUTOTEST_EXPORT Item : public QbsQmlJS::Managed { friend class ASTPropertiesItemHandler; friend class ItemPool; friend class ItemReaderASTVisitor; friend class ModuleItemLocker; Q_DISABLE_COPY(Item) Item(ItemType type) : m_type(type) {} public: struct Module { QualifiedId name; Item *item = nullptr; ProductContext *product = nullptr; // Set if and only if the dep is a product. // All the sites that declared an explicit dependency on this module. Can contain any // number of module instances and at most one product. using ParametersWithPriority = std::pair; struct LoadContext { LoadContext(Item *dependsItem, const ParametersWithPriority ¶meters) : dependsItem(dependsItem), parameters(parameters) {} LoadContext(Item *dependsItem, ParametersWithPriority &¶meters) : dependsItem(dependsItem), parameters(std::move(parameters)) {} LoadContext(const LoadContext &) = default; LoadContext(LoadContext &&) = default; LoadContext &operator=(const LoadContext &) = default; LoadContext &operator=(LoadContext &&) = default; Item *loadingItem() const { if (!dependsItem) return nullptr; Item *loadingItem = dependsItem->parent(); while (loadingItem->type() == ItemType::Group) loadingItem = loadingItem->parent(); QBS_CHECK( loadingItem->type() == ItemType::ModuleInstance || loadingItem->type() == ItemType::Product); return loadingItem; } Item *dependsItem; ParametersWithPriority parameters; }; std::vector loadContexts; QVariantMap parameters; VersionRange versionRange; // The shorter this value, the "closer to the product" we consider the module, // and the higher its precedence is when merging property values. int maxDependsChainLength = 0; bool required = true; }; using Modules = std::vector; using PropertyDeclarationMap = QMap; using PropertyMap = QMap; static Item *create(ItemPool *pool, ItemType type); Item *clone(ItemPool &pool) const; const QString &id() const { return m_id; } const CodeLocation &location() const { return m_location; } CodeRange codeRange() const; Item *prototype() const { return m_prototype; } Item *rootPrototype(); Item *scope() const { return m_scope; } Item *outerItem() const { return m_outerItem; } Item *parent() const { return m_parent; } const FileContextPtr &file() const { return m_file; } const QList &children() const { return m_children; } QList &children() { return m_children; } Item *child(ItemType type, bool checkForMultiple = true) const; const PropertyMap &properties() const { assertModuleLocked(); return m_properties; } PropertyMap &properties() { assertModuleLocked(); return m_properties; } const PropertyDeclarationMap &propertyDeclarations() const { return m_propertyDeclarations; } PropertyDeclaration propertyDeclaration(const QString &name, bool allowExpired = true) const; // The list of modules is ordered such that dependencies appear before the modules // depending on them. const Modules &modules() const { return m_modules; } Modules &modules() { return m_modules; } void addModule(const Module &module); void removeModules() { m_modules.clear(); } void setModules(const Modules &modules); ItemType type() const { return m_type; } void setType(ItemType type) { m_type = type; } QString typeName() const; bool hasProperty(const QString &name) const; bool hasOwnProperty(const QString &name) const; ValuePtr property(const QString &name) const; ValuePtr ownProperty(const QString &name) const; ItemValuePtr itemProperty(const QString &name, ItemPool &pool, const Item *itemTemplate = nullptr); ItemValuePtr itemProperty(const QString &name, const ItemValueConstPtr &value, ItemPool &pool); JSSourceValuePtr sourceProperty(const QString &name) const; VariantValuePtr variantProperty(const QString &name) const; bool isOfTypeOrhasParentOfType(ItemType type) const; void addObserver(ItemObserver *observer) const; void removeObserver(ItemObserver *observer) const; void setProperty(const QString &name, const ValuePtr &value); void setProperties(const PropertyMap &props) { assertModuleLocked(); m_properties = props; } void removeProperty(const QString &name); void setPropertyDeclaration(const QString &name, const PropertyDeclaration &declaration); void setPropertyDeclarations(const PropertyDeclarationMap &decls); void setLocation(const CodeLocation &location) { m_location = location; } void setEndPosition(const CodePosition &position) { m_endPosition = position; } void setPrototype(Item *prototype) { m_prototype = prototype; } void setFile(const FileContextPtr &file) { m_file = file; } void setId(const QString &id) { m_id = id; } void setScope(Item *item) { m_scope = item; } void setOuterItem(Item *item) { m_outerItem = item; } void setChildren(const QList &children) { m_children = children; } void setParent(Item *item) { m_parent = item; } void childrenReserve(int size) { m_children.reserve(size); } static void addChild(Item *parent, Item *child); static void removeChild(Item *parent, Item *child); void dump() const; bool isPresentModule() const; bool isFallbackModule() const; void setupForBuiltinType(DeprecationWarningMode deprecationMode, Logger &logger); void copyProperty(const QString &propertyName, Item *target) const; void overrideProperties( const QVariantMap &config, const QString &key, const SetupProjectParameters ¶meters, Logger &logger); void overrideProperties( const QVariantMap &config, const QualifiedId &namePrefix, const SetupProjectParameters ¶meters, Logger &logger); private: ItemValuePtr itemProperty(const QString &name, const Item *itemTemplate, const ItemValueConstPtr &itemValue, ItemPool &pool); void adaptScopesOfClonedAlternatives(Item *clone) const; void dump(int indentation) const; void lockModule() const; void unlockModule() const; void assertModuleLocked() const; mutable std::vector m_observers; mutable std::mutex m_observersMutex; QString m_id; CodeLocation m_location; CodePosition m_endPosition; Item *m_prototype = nullptr; Item *m_scope = nullptr; Item *m_outerItem = nullptr; Item *m_parent = nullptr; QList m_children; FileContextPtr m_file; PropertyMap m_properties; PropertyDeclarationMap m_propertyDeclarations; PropertyDeclarationMap m_expiredPropertyDeclarations; Modules m_modules; ItemType m_type; mutable std::mutex m_moduleMutex; #ifndef NDEBUG mutable std::atomic_bool m_moduleLocked = false; #endif }; inline bool operator<(const Item::Module &m1, const Item::Module &m2) { return m1.name < m2.name; } Item *createNonPresentModule(ItemPool &pool, const QString &name, const QString &reason, Item *module); void setScopeForDescendants(Item *item, Item *scope, bool insertIds); // This mechanism is needed because Module items are shared between products (not doing so // would be prohibitively expensive). // The competing accesses are between // - Attaching a temporary qbs module for evaluating the Module condition. // - Cloning the module when creating an instance. // - Directly accessing Module properties, which happens rarely (as opposed to properties of // an instance). class ModuleItemLocker { public: ModuleItemLocker(const Item &item) : m_item(item) { item.lockModule(); } ~ModuleItemLocker() { m_item.unlockModule(); } private: const Item &m_item; }; } // namespace Internal } // namespace qbs #endif // QBS_ITEM_H qbs-src-2.6.1/src/lib/corelib/language/propertydeclaration.cpp0000644000175100001660000004113614776170045024012 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "propertydeclaration.h" #include "deprecationinfo.h" #include "filecontext.h" #include "item.h" #include "qualifiedid.h" #include "value.h" #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { // returns QMetaType::UnknownType for types that do not need conversion static QMetaType::Type variantType(PropertyDeclaration::Type t) { switch (t) { case PropertyDeclaration::UnknownType: break; case PropertyDeclaration::Boolean: return QMetaType::Bool; case PropertyDeclaration::Integer: return QMetaType::Int; case PropertyDeclaration::Path: return QMetaType::QString; case PropertyDeclaration::PathList: return QMetaType::QStringList; case PropertyDeclaration::String: return QMetaType::QString; case PropertyDeclaration::StringList: return QMetaType::QStringList; case PropertyDeclaration::VariantList: return QMetaType::QVariantList; case PropertyDeclaration::Variant: break; } return QMetaType::UnknownType; } class PropertyDeclarationData : public QSharedData { public: PropertyDeclarationData() : type(PropertyDeclaration::UnknownType) , flags(PropertyDeclaration::DefaultFlags) { } QString name; PropertyDeclaration::Type type; PropertyDeclaration::Flags flags; QStringList allowedValues; QString description; QString initialValueSource; QStringList functionArgumentNames; DeprecationInfo deprecationInfo; }; PropertyDeclaration::PropertyDeclaration() : d(new PropertyDeclarationData) { } PropertyDeclaration::PropertyDeclaration(const QString &name, Type type, const QString &initialValue, Flags flags) : d(new PropertyDeclarationData) { d->name = name; d->type = type; d->initialValueSource = initialValue; d->flags = flags; } PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) = default; PropertyDeclaration::~PropertyDeclaration() = default; PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) = default; bool PropertyDeclaration::isValid() const { return d && d->type != UnknownType; } bool PropertyDeclaration::isScalar() const { // ### Should be determined by a PropertyOption in the future. return d->type != PathList && d->type != StringList && d->type != VariantList; } static QString boolString() { return QStringLiteral("bool"); } static QString intString() { return QStringLiteral("int"); } static QString pathListString() { return QStringLiteral("pathList"); } static QString stringString() { return QStringLiteral("string"); } static QString stringListString() { return QStringLiteral("stringList"); } static QString varString() { return QStringLiteral("var"); } static QString variantString() { return QStringLiteral("variant"); } static QString varListString() { return QStringLiteral("varList"); } PropertyDeclaration::Type PropertyDeclaration::propertyTypeFromString(const QString &typeName) { if (typeName == boolString()) return PropertyDeclaration::Boolean; if (typeName == intString()) return PropertyDeclaration::Integer; if (typeName == StringConstants::pathType()) return PropertyDeclaration::Path; if (typeName == pathListString()) return PropertyDeclaration::PathList; if (typeName == stringString()) return PropertyDeclaration::String; if (typeName == stringListString()) return PropertyDeclaration::StringList; if (typeName == varString() || typeName == variantString()) return PropertyDeclaration::Variant; if (typeName == varListString()) return PropertyDeclaration::VariantList; return PropertyDeclaration::UnknownType; } QString PropertyDeclaration::typeString() const { return typeString(type()); } QString PropertyDeclaration::typeString(PropertyDeclaration::Type t) { switch (t) { case Boolean: return boolString(); case Integer: return intString(); case Path: return StringConstants::pathType(); case PathList: return pathListString(); case String: return stringString(); case StringList: return stringListString(); case Variant: return variantString(); case VariantList: return varListString(); case UnknownType: return QStringLiteral("unknown"); } Q_UNREACHABLE(); // For stupid compilers. } const QString &PropertyDeclaration::name() const { return d->name; } void PropertyDeclaration::setName(const QString &name) { d->name = name; } PropertyDeclaration::Type PropertyDeclaration::type() const { return d->type; } void PropertyDeclaration::setType(PropertyDeclaration::Type t) { d->type = t; } PropertyDeclaration::Flags PropertyDeclaration::flags() const { return d->flags; } void PropertyDeclaration::setFlags(Flags f) { d->flags = f; } const QStringList &PropertyDeclaration::allowedValues() const { return d->allowedValues; } void PropertyDeclaration::setAllowedValues(const QStringList &v) { d->allowedValues = v; } const QString &PropertyDeclaration::description() const { return d->description; } void PropertyDeclaration::setDescription(const QString &str) { d->description = str; } const QString &PropertyDeclaration::initialValueSource() const { return d->initialValueSource; } void PropertyDeclaration::setInitialValueSource(const QString &str) { d->initialValueSource = str; } const QStringList &PropertyDeclaration::functionArgumentNames() const { return d->functionArgumentNames; } void PropertyDeclaration::setFunctionArgumentNames(const QStringList &lst) { d->functionArgumentNames = lst; } bool PropertyDeclaration::isDeprecated() const { return d->deprecationInfo.isValid(); } bool PropertyDeclaration::isExpired() const { return isDeprecated() && deprecationInfo().removalVersion() <= LanguageInfo::qbsVersion(); } const DeprecationInfo &PropertyDeclaration::deprecationInfo() const { return d->deprecationInfo; } void PropertyDeclaration::setDeprecationInfo(const DeprecationInfo &deprecationInfo) { d->deprecationInfo = deprecationInfo; } ErrorInfo PropertyDeclaration::checkForDeprecation(DeprecationWarningMode mode, const CodeLocation &loc, Logger &logger) const { return deprecationInfo().checkForDeprecation(mode, name(), loc, false, logger); } QVariant PropertyDeclaration::convertToPropertyType(const QVariant &v, Type t, const QStringList &namePrefix, const QString &key) { if (v.isNull() || !v.isValid()) return v; const auto vt = variantType(t); if (vt == QMetaType::UnknownType) return v; // Handle the foo,bar,bla stringlist syntax. if (t == PropertyDeclaration::StringList && v.userType() == QMetaType::QString) return v.toString().split(QLatin1Char(',')); QVariant c = v; if (!qVariantConvert(c, vt)) { QStringList name = namePrefix; name << key; throw ErrorInfo(Tr::tr("Value '%1' of property '%2' has incompatible type.") .arg(v.toString(), name.join(QLatin1Char('.')))); } return c; } QVariant PropertyDeclaration::typedNullValue() const { switch (type()) { case PropertyDeclaration::Boolean: return typedNullVariant(); case PropertyDeclaration::Integer: return typedNullVariant(); case PropertyDeclaration::VariantList: return typedNullVariant(); case PropertyDeclaration::String: case PropertyDeclaration::Path: return typedNullVariant(); case PropertyDeclaration::StringList: case PropertyDeclaration::PathList: return typedNullVariant(); default: return {}; } } bool PropertyDeclaration::shouldCheckAllowedValues() const { return isValid() && (d->type == PropertyDeclaration::String || d->type == PropertyDeclaration::StringList) && !d->allowedValues.empty(); } void PropertyDeclaration::checkAllowedValues( const QVariant &value, const CodeLocation &loc, const QString &key, LoaderState &loaderState) const { const auto type = d->type; if (!shouldCheckAllowedValues()) return; if (value.isNull()) return; const auto &allowedValues = d->allowedValues; const auto checkValue = [&loc, &allowedValues, &key, &loaderState](const QString &value) { if (!allowedValues.contains(value)) { const auto message = Tr::tr("Value '%1' is not allowed for property '%2'.") .arg(value, key); ErrorInfo error(message, loc); handlePropertyError(error, loaderState.parameters(), loaderState.logger()); } }; if (type == PropertyDeclaration::StringList) { const auto strings = value.toStringList(); for (const auto &string: strings) { checkValue(string); } } else if (type == PropertyDeclaration::String) { checkValue(value.toString()); } } namespace { class PropertyDeclarationCheck : public ValueHandler { public: PropertyDeclarationCheck(LoaderState &loaderState) : m_loaderState(loaderState) {} void operator()(Item *item) { m_checkingProject = item->type() == ItemType::Project; handleItem(item); } private: void doHandle(JSSourceValue *value) override { if (!value->createdByPropertiesBlock()) { const ErrorInfo error(Tr::tr("Property '%1' is not declared.") .arg(m_currentName), value->location()); handlePropertyError(error, m_loaderState.parameters(), m_loaderState.logger()); } } void doHandle(ItemValue *value) override { if (checkItemValue(value)) handleItem(value->item()); } bool checkItemValue(ItemValue *value) { // TODO: Remove once QBS-1030 is fixed. if (parentItem()->type() == ItemType::Artifact) return false; if (parentItem()->type() == ItemType::Properties) return false; // TODO: Check where the in-between module instances come from. if (value->item()->type() == ItemType::ModuleInstancePlaceholder) { for (auto it = m_parentItems.rbegin(); it != m_parentItems.rend(); ++it) { if ((*it)->type() == ItemType::Group) return false; if ((*it)->type() == ItemType::ModulePrefix) continue; break; } } if (value->item()->type() != ItemType::ModuleInstance && value->item()->type() != ItemType::ModulePrefix && (!parentItem()->file() || !parentItem()->file()->idScope() || !parentItem()->file()->idScope()->hasProperty(m_currentName)) && !value->createdByPropertiesBlock()) { CodeLocation location = value->location(); for (int i = int(m_parentItems.size() - 1); !location.isValid() && i >= 0; --i) location = m_parentItems.at(i)->location(); const ErrorInfo error(Tr::tr("Item '%1' is not declared. " "Did you forget to add a Depends item?") .arg(m_currentModuleName.toString()), location); handlePropertyError(error, m_loaderState.parameters(), m_loaderState.logger()); return false; } return true; } void handleItem(Item *item) { if (m_checkingProject && item->type() == ItemType::Product) return; if (!m_handledItems.insert(item).second) return; if (item->type() == ItemType::Module || item->type() == ItemType::Export || (item->type() == ItemType::ModuleInstance && !item->isPresentModule()) || item->type() == ItemType::Properties // The Properties child of a SubProject item is not a regular item. || item->type() == ItemType::PropertiesInSubProject || m_loaderState.topLevelProject().isDisabledItem(item)) { return; } m_parentItems.push_back(item); for (Item::PropertyMap::const_iterator it = item->properties().constBegin(); it != item->properties().constEnd(); ++it) { if (item->type() == ItemType::Product && it.key() == StringConstants::moduleProviders() && it.value()->type() == Value::ItemValueType) continue; const PropertyDeclaration decl = item->propertyDeclaration(it.key()); if (decl.isValid()) { const ErrorInfo deprecationError = decl.checkForDeprecation( m_loaderState.parameters().deprecationWarningMode(), it.value()->location(), m_loaderState.logger()); if (deprecationError.hasError()) { handlePropertyError(deprecationError, m_loaderState.parameters(), m_loaderState.logger()); } continue; } m_currentName = it.key(); const QualifiedId oldModuleName = m_currentModuleName; if (parentItem()->type() != ItemType::ModulePrefix) m_currentModuleName.clear(); m_currentModuleName.push_back(m_currentName); it.value()->apply(this); m_currentModuleName = oldModuleName; } m_parentItems.pop_back(); for (Item * const child : item->children()) { switch (child->type()) { case ItemType::Export: case ItemType::Depends: case ItemType::Parameter: case ItemType::Parameters: break; case ItemType::Group: if (item->type() == ItemType::Module || item->type() == ItemType::ModuleInstance) break; Q_FALLTHROUGH(); default: handleItem(child); } } } void doHandle(VariantValue *) override { /* only created internally - no need to check */ } Item *parentItem() const { return m_parentItems.back(); } LoaderState &m_loaderState; Set m_handledItems; std::vector m_parentItems; QualifiedId m_currentModuleName; QString m_currentName; bool m_checkingProject = false; }; } // namespace void checkPropertyDeclarations(Item *topLevelItem, LoaderState &loaderState) { (PropertyDeclarationCheck(loaderState))(topLevelItem); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/0000755000175100001660000000000014776170045017575 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/generators/generatableprojectiterator.h0000644000175100001660000000475014776170045025366 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GENERATABLEPROJECTITERATOR_H #define GENERATABLEPROJECTITERATOR_H #include "generatordata.h" #include "igeneratableprojectvisitor.h" namespace qbs { class QBS_EXPORT GeneratableProjectIterator { GeneratableProject project; public: GeneratableProjectIterator(GeneratableProject project); void accept(IGeneratableProjectVisitor *visitor); private: void accept(const GeneratableProject &project, const GeneratableProjectData &parentProjectData, const GeneratableProjectData &projectData, IGeneratableProjectVisitor *visitor); }; } // namespace qbs #endif // GENERATABLEPROJECTITERATOR_H qbs-src-2.6.1/src/lib/corelib/generators/generatorutils.cpp0000644000175100001660000002203514776170045023352 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "generatorutils.h" #include namespace qbs { namespace gen { namespace utils { QString architectureName(Architecture arch) { switch (arch) { case Architecture::Arm: return QStringLiteral("arm"); case Architecture::Avr: return QStringLiteral("avr"); case Architecture::Mcs51: return QStringLiteral("mcs51"); default: return QStringLiteral("unknown"); } } Architecture architecture(const Project &qbsProject) { const auto qbsArch = qbsProject.projectConfiguration() .value(Internal::StringConstants::qbsModule()).toMap() .value(QStringLiteral("architecture")).toString(); if (qbsArch == QLatin1String("arm")) return Architecture::Arm; if (qbsArch == QLatin1String("avr")) return Architecture::Avr; if (qbsArch == QLatin1String("mcs51")) return Architecture::Mcs51; if (qbsArch == QLatin1String("stm8")) return Architecture::Stm8; if (qbsArch == QLatin1String("msp430")) return Architecture::Msp430; return Architecture::Unknown; } QString buildConfigurationName(const Project &qbsProject) { return qbsProject.projectConfiguration() .value(Internal::StringConstants::qbsModule()).toMap() .value(QStringLiteral("configurationName")).toString(); } int debugInformation(const ProductData &qbsProduct) { return qbsProduct.moduleProperties().getModuleProperty( Internal::StringConstants::qbsModule(), QStringLiteral("debugInformation")) .toInt(); } QString buildRootPath(const Project &qbsProject) { QDir dir(qbsProject.projectData().buildDirectory()); dir.cdUp(); return dir.absolutePath(); } QString relativeFilePath(const QString &baseDirectory, const QString &fullFilePath) { return QDir(baseDirectory).relativeFilePath(fullFilePath); } QString binaryOutputDirectory(const QString &baseDirectory, const ProductData &qbsProduct) { return QDir(baseDirectory).relativeFilePath( qbsProduct.buildDirectory()) + QLatin1String("/bin"); } QString objectsOutputDirectory(const QString &baseDirectory, const ProductData &qbsProduct) { return QDir(baseDirectory).relativeFilePath( qbsProduct.buildDirectory()) + QLatin1String("/obj"); } QString listingOutputDirectory(const QString &baseDirectory, const ProductData &qbsProduct) { return QDir(baseDirectory).relativeFilePath( qbsProduct.buildDirectory()) + QLatin1String("/lst"); } std::vector dependenciesOf(const ProductData &qbsProduct, const GeneratableProject &genProject, const QString &configurationName) { std::vector result; const auto &depsNames = qbsProduct.dependencies(); for (const auto &product : std::as_const(genProject.products)) { const auto pt = product.type(); if (!pt.contains(QLatin1String("staticlibrary"))) continue; const auto pn = product.name(); if (!depsNames.contains(pn)) continue; result.push_back(product.data.value(configurationName)); } return result; } QString targetBinary(const ProductData &qbsProduct) { const auto &type = qbsProduct.type(); if (type.contains(QLatin1String("application"))) { return QFileInfo(qbsProduct.targetExecutable()).fileName(); } if (type.contains(QLatin1String("staticlibrary"))) { for (const auto &artifact : qbsProduct.targetArtifacts()) { if (artifact.fileTags().contains(QLatin1String("staticlibrary"))) return QFileInfo(artifact.filePath()).fileName(); } } return {}; } QString targetBinaryPath(const QString &baseDirectory, const ProductData &qbsProduct) { return binaryOutputDirectory(baseDirectory, qbsProduct) + QLatin1Char('/') + targetBinary(qbsProduct); } QString cppStringModuleProperty(const PropertyMap &qbsProps, const QString &propertyName) { return qbsProps.getModuleProperty( Internal::StringConstants::cppModule(), propertyName).toString().trimmed(); } bool cppBooleanModuleProperty(const PropertyMap &qbsProps, const QString &propertyName) { return qbsProps.getModuleProperty( Internal::StringConstants::cppModule(), propertyName).toBool(); } int cppIntegerModuleProperty(const PropertyMap &qbsProps, const QString &propertyName) { return qbsProps.getModuleProperty( Internal::StringConstants::cppModule(), propertyName).toInt(); } QStringList cppStringModuleProperties(const PropertyMap &qbsProps, const QStringList &propertyNames) { QStringList properties; for (const auto &propertyName : propertyNames) { const auto entries = qbsProps.getModuleProperty(Internal::StringConstants::cppModule(), propertyName).toStringList(); Internal::transform(entries, properties, [](const auto &entry) { return entry.trimmed(); }); } return properties; } QVariantList cppVariantModuleProperties(const PropertyMap &qbsProps, const QStringList &propertyNames) { QVariantList properties; for (const auto &propertyName : propertyNames) { properties << qbsProps.getModuleProperty( Internal::StringConstants::cppModule(), propertyName).toList(); } return properties; } static QString parseFlagValue(const QString &flagKey, QStringList::const_iterator &flagIt, const QStringList::const_iterator &flagEnd) { if (flagIt->contains(QLatin1Char('='))) { // In this case an option is in form of 'flagKey='. const auto parts = flagIt->split(QLatin1Char('=')); if (parts.count() == 2) return parts.at(1).trimmed(); } else if (flagKey < *flagIt) { // In this case an option is in form of 'flagKey'. return flagIt->mid(flagKey.size()).trimmed(); } else { // In this case an option is in form of 'flagKey '. ++flagIt; if (flagIt < flagEnd && !flagIt->startsWith(QLatin1Char('-'))) return (*flagIt).trimmed(); } return {}; } QString firstFlagValue(const QStringList &flags, const QString &flagKey) { const auto flagBegin = flags.cbegin(); const auto flagEnd = flags.cend(); auto flagIt = std::find_if(flagBegin, flagEnd, [flagKey](const QString &flag) { return flag == flagKey || flag.startsWith(flagKey); }); if (flagIt == flagEnd) return {}; return parseFlagValue(flagKey, flagIt, flagEnd); } QStringList allFlagValues(const QStringList &flags, const QString &flagKey) { QStringList values; const auto flagEnd = flags.cend(); for (auto flagIt = flags.cbegin(); flagIt < flagEnd; ++flagIt) { if (*flagIt == flagKey || flagIt->startsWith(flagKey)) { const QString value = parseFlagValue(flagKey, flagIt, flagEnd); if (!value.isEmpty()) values.push_back(value); } } return values; } } // namespace utils } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlproperty.h0000644000175100001660000000546214776170045022362 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_XML_PROPERTY_H #define GENERATORS_XML_PROPERTY_H #include #include #include namespace qbs { namespace gen { namespace xml { class INodeVisitor; class QBS_EXPORT Property { Q_DISABLE_COPY(Property) public: Property() = default; explicit Property(QByteArray name, QVariant value); virtual ~Property() = default; QByteArray name() const { return m_name; } void setName(QByteArray name) { m_name = std::move(name); } QVariant value() const { return m_value; } void setValue(QVariant value) { m_value = std::move(value); } template T *appendChild(std::unique_ptr child) { const auto p = child.get(); m_children.push_back(std::move(child)); return p; } template T *appendChild(Args&&... args) { return appendChild(std::make_unique(std::forward(args)...)); } virtual void accept(INodeVisitor *visitor) const; protected: const std::vector> &children() const { return m_children; } private: QByteArray m_name; QVariant m_value; std::vector> m_children; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_PROPERTY_H qbs-src-2.6.1/src/lib/corelib/generators/xmlproperty.cpp0000644000175100001660000000374414776170045022716 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "ixmlnodevisitor.h" #include "xmlproperty.h" namespace qbs { namespace gen { namespace xml { Property::Property(QByteArray name, QVariant value) { setName(std::move(name)); setValue(std::move(value)); } void Property::accept(INodeVisitor *visitor) const { visitor->visitPropertyStart(this); for (const auto &child : children()) child->accept(visitor); visitor->visitPropertyEnd(this); } } // namespace xml } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/generator.h0000644000175100001660000000665214776170045021745 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GENERATORPLUGIN_H #define GENERATORPLUGIN_H #include "generatordata.h" #include #include #include namespace qbs { class ProjectGeneratorPrivate; /*! * \class ProjectGenerator * \brief The \c ProjectGenerator class is an abstract base class for generators which generate * arbitrary output given a resolved Qbs project. */ class QBS_EXPORT ProjectGenerator : public QObject { Q_OBJECT Q_DISABLE_COPY(ProjectGenerator) public: ~ProjectGenerator() override; /*! * Returns the name of the generator used to create the external build system files. */ virtual QString generatorName() const = 0; ErrorInfo generate(const QList &projects, const QList &buildConfigurations, const InstallOptions &installOptions, const QString &qbsSettingsDir, const Internal::Logger &logger); const GeneratableProject project() const; QFileInfo qbsExecutableFilePath() const; QString qbsSettingsDir() const; protected: ProjectGenerator(); const Internal::Logger &logger() const; private: virtual void generate() = 0; QList projects() const; QList buildConfigurations() const; QVariantMap buildConfiguration(const Project &project) const; QStringList buildConfigurationCommandLine(const Project &project) const; const std::unique_ptr d; }; } // namespace qbs #endif // GENERATORPLUGIN_H qbs-src-2.6.1/src/lib/corelib/generators/generatorversioninfo.h0000644000175100001660000000565014776170045024224 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GENERATORS_VERSION_INFO_H #define GENERATORS_VERSION_INFO_H #include "generatorutils.h" #include #include #include namespace qbs { namespace gen { class QBS_EXPORT VersionInfo { public: constexpr VersionInfo(const Version &version, utils::ArchitectureFlags archs) : m_version(version), m_archs(archs) { } constexpr bool operator<(const VersionInfo &other) const { return m_version < other.m_version; } constexpr bool operator==(const VersionInfo &other) const { return m_version == other.m_version && m_archs == other.m_archs; } constexpr Version version() const { return m_version; } constexpr bool containsArchitecture(utils::Architecture arch) const { return m_archs & arch; } int marketingVersion() const; private: Version m_version; utils::ArchitectureFlags m_archs; }; inline auto qHash(const VersionInfo &info) { return qHash(info.version().toString()); } } // namespace gen } // namespace qbs #endif // GENERATORS_VERSION_INFO_H qbs-src-2.6.1/src/lib/corelib/generators/xmlproject.h0000644000175100001660000000360714776170045022143 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_XML_PROJECT_H #define GENERATORS_XML_PROJECT_H #include "xmlproperty.h" #include #include namespace qbs { namespace gen { namespace xml { class QBS_EXPORT Project : public Property { public: void accept(INodeVisitor *visitor) const final; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_PROJECT_H qbs-src-2.6.1/src/lib/corelib/generators/generatordata.h0000644000175100001660000001374214776170045022575 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GENERATORDATA_H #define GENERATORDATA_H #include #include #include #include #include #include #include namespace qbs { using GeneratableProjectMap = QMap; template struct IMultiplexableContainer { QMap data; template T uniqueValue(const std::function &func, const QString &errorMessage) const { if (data.empty()) return T(); auto it = data.begin(), end = data.end(); auto value = func(*it++); for (; it != end; ++it) { if (value != func(*it)) throw ErrorInfo(errorMessage); } return value; } void forEach(const std::function &func) const { for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) func(it.key(), it.value()); } void forEach(const std::function &func) const { for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) func(it.key().toStdString(), it.value()); } const U operator[](const QString &configurationName) const { return data[configurationName]; } const U operator[](const std::string &configurationName) const { return data[QString::fromStdString(configurationName)]; } bool isValid() const { return !data.empty(); } protected: IMultiplexableContainer() = default; }; struct QBS_EXPORT GeneratableProductData : public IMultiplexableContainer { QString name() const; CodeLocation location() const; QStringList dependencies() const; QStringList type() const; QString buildDirectory() const; }; struct QBS_EXPORT GeneratableProjectData : public IMultiplexableContainer { struct Id { private: friend struct GeneratableProjectData; Id() = default; QString value; public: bool operator<(const Id &id) const { return value < id.value; } }; QList subProjects; QList products; QString name() const; CodeLocation location() const; Id uniqueName() const; }; struct QBS_EXPORT GeneratableProject : public GeneratableProjectData { GeneratableProjectMap projects; QMap buildConfigurations; QMap commandLines; InstallOptions installOptions; QDir baseBuildDirectory() const; QFileInfo filePath() const; bool hasMultipleConfigurations() const; QStringList commandLine() const; void forEach(const std::function &func) const { for (auto it = projects.cbegin(), end = projects.cend(); it != end; ++it) func(it.key(), it.value()); } void forEach(const std::function &func) const { for (auto it = projects.cbegin(), end = projects.cend(); it != end; ++it) func(it.key().toStdString(), it.value()); } const Project operator[](const QString &configurationName) const { return projects[configurationName]; } const Project operator[](const std::string &configurationName) const { return projects[QString::fromStdString(configurationName)]; } bool isValid() const { return !data.empty() && !projects.empty(); } const ProjectData projectData(const QString &configurationName) const { return data[configurationName]; } const ProjectData projectData(const std::string &configurationName) const { return data[QString::fromStdString(configurationName)]; } }; } // namespace qbs #endif // GENERATORDATA_H qbs-src-2.6.1/src/lib/corelib/generators/generator.cpp0000644000175100001660000002012314776170045022265 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "generator.h" #include #include #include #include #include #include #include namespace qbs { class ProjectGeneratorPrivate { public: QList projects; QList buildConfigurations; InstallOptions installOptions; QString qbsSettingsDir; Internal::Logger logger = Internal::Logger(nullptr); }; ProjectGenerator::ProjectGenerator() : d(std::make_unique()) { } ProjectGenerator::~ProjectGenerator() = default; static QString _configurationName(const Project &project) { return project.projectConfiguration() .value(Internal::StringConstants::qbsModule()).toMap() .value(Internal::StringConstants::configurationNameProperty()).toString(); } static QString _configurationName(const QVariantMap &buildConfiguration) { return buildConfiguration.value(QStringLiteral("qbs.configurationName")).toString(); } ErrorInfo ProjectGenerator::generate(const QList &projects, const QList &buildConfigurations, const InstallOptions &installOptions, const QString &qbsSettingsDir, const Internal::Logger &logger) { d->projects = Internal::sorted(projects, [](const Project &lhs, const Project &rhs) { return _configurationName(lhs) < _configurationName(rhs); }); d->buildConfigurations = Internal::sorted( buildConfigurations, [](const QVariantMap &lhs, const QVariantMap &rhs) { return _configurationName(lhs) < _configurationName(rhs); }); d->installOptions = installOptions; d->qbsSettingsDir = qbsSettingsDir; d->logger = logger; try { generate(); } catch (const ErrorInfo &e) { return e; } return {}; } QList ProjectGenerator::projects() const { return d->projects; } QList ProjectGenerator::buildConfigurations() const { return d->buildConfigurations; } QVariantMap ProjectGenerator::buildConfiguration(const Project &project) const { int idx = d->projects.indexOf(project); if (idx < 0) return {}; return d->buildConfigurations.at(idx); } QStringList ProjectGenerator::buildConfigurationCommandLine(const Project &project) const { QVariantMap config = buildConfiguration(project); const QString name = config.take(QStringLiteral("qbs.configurationName")).toString(); if (name.isEmpty()) throw ErrorInfo(QStringLiteral("Can't find configuration name for project")); QStringList commandLineParameters; commandLineParameters += QStringLiteral("config:") + name; for (auto it = config.cbegin(), end = config.cend(); it != end; ++it) commandLineParameters += it.key() + QStringLiteral(":") + it.value().toString(); return commandLineParameters; } // Count the number of products in the project (singular) // Precondition: each project data (i.e. per-configuration project data) // has the same number of products. static int _productCount(const QList &projects) { int count = -1; for (const auto &project : projects) { int oldCount = count; count = project.products().size(); QBS_CHECK(oldCount == -1 || oldCount == count); } return count; } static int _subprojectCount(const QList &projects) { int count = -1; for (const auto &project : projects) { int oldCount = count; count = project.subProjects().size(); QBS_CHECK(oldCount == -1 || oldCount == count); } return count; } static GeneratableProjectData _reduceProjectConfigurations( const QMap &map) { GeneratableProjectData gproject; // Add the project's project data for each configuration for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) gproject.data.insert(it.key(), it.value()); // Add the project's products... for (int i = 0; i < _productCount(map.values()); ++i) { GeneratableProductData prod; // once for each configuration for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) prod.data.insert(it.key(), it.value().products().at(i)); gproject.products.push_back(prod); } // Add the project's subprojects... for (int i = 0; i < _subprojectCount(map.values()); ++i) { QMap subprojectMap; // once for each configuration for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) subprojectMap.insert(it.key(), it.value().subProjects().at(i)); gproject.subProjects.push_back(_reduceProjectConfigurations(subprojectMap)); } return gproject; } const GeneratableProject ProjectGenerator::project() const { QMap rootProjects; GeneratableProject proj; for (const auto &project : std::as_const(d->projects)) { const QString configurationName = _configurationName(project); rootProjects.insert(configurationName, project.projectData()); proj.projects.insert(configurationName, project); proj.buildConfigurations.insert(configurationName, buildConfiguration(project)); proj.commandLines.insert(configurationName, buildConfigurationCommandLine(project)); } auto p = _reduceProjectConfigurations(rootProjects); proj.data = p.data; proj.products = p.products; proj.subProjects = p.subProjects; proj.installOptions = d->installOptions; return proj; } QFileInfo ProjectGenerator::qbsExecutableFilePath() const { const QString qbsInstallDir = QString::fromLocal8Bit(qgetenv("QBS_INSTALL_DIR")); auto file = QFileInfo(Internal::HostOsInfo::appendExecutableSuffix( !qbsInstallDir.isEmpty() ? QString(qbsInstallDir + QStringLiteral("/bin/qbs")) : QString(QCoreApplication::applicationDirPath() + QStringLiteral("/qbs")))); QBS_CHECK(file.isAbsolute() && file.exists()); return file; } QString ProjectGenerator::qbsSettingsDir() const { return d->qbsSettingsDir; } const Internal::Logger &ProjectGenerator::logger() const { return d->logger; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlprojectwriter.cpp0000644000175100001660000000570614776170045023735 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "xmlproject.h" #include "xmlprojectwriter.h" #include "xmlproperty.h" #include "xmlpropertygroup.h" #include #include namespace qbs { namespace gen { namespace xml { ProjectWriter::ProjectWriter(std::ostream *device) : m_device(device) { m_writer = std::make_unique(&m_buffer); m_writer->setAutoFormatting(true); } bool ProjectWriter::write(const Project *project) { m_buffer.clear(); m_writer->writeStartDocument(); project->accept(this); m_writer->writeEndDocument(); if (m_writer->hasError()) return false; m_device->write(&*std::begin(m_buffer), m_buffer.size()); return m_device->good(); } void ProjectWriter::visitPropertyStart(const Property *property) { const auto value = property->value().toString(); const auto name = QString::fromUtf8(property->name()); m_writer->writeTextElement(name, value); } void ProjectWriter::visitPropertyEnd(const Property *property) { Q_UNUSED(property) } void ProjectWriter::visitPropertyGroupStart(const PropertyGroup *propertyGroup) { const auto name = QString::fromUtf8(propertyGroup->name()); m_writer->writeStartElement(name); } void ProjectWriter::visitPropertyGroupEnd(const PropertyGroup *propertyGroup) { Q_UNUSED(propertyGroup) m_writer->writeEndElement(); } QXmlStreamWriter *ProjectWriter::writer() const { return m_writer.get(); } } // namespace xml } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlworkspace.cpp0000644000175100001660000000463014776170045023023 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "ixmlnodevisitor.h" #include "xmlproperty.h" #include "xmlpropertygroup.h" #include "xmlworkspace.h" namespace qbs { namespace gen { namespace xml { Workspace::Workspace(const QString &workspacePath) : m_baseDirectory(QFileInfo(workspacePath).absoluteDir()) { } void Workspace::accept(INodeVisitor *visitor) const { visitor->visitWorkspaceStart(this); for (const auto &child : children()) child->accept(visitor); visitor->visitWorkspaceEnd(this); } } // namespace xml } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/igeneratableprojectvisitor.h0000644000175100001660000000772214776170045025407 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef IGENERATABLEPROJECTVISITOR_H #define IGENERATABLEPROJECTVISITOR_H #include "generatordata.h" namespace qbs { class IGeneratableProjectVisitor { public: virtual ~IGeneratableProjectVisitor() = default; // Collapsed configurations virtual void visitProject(const GeneratableProject &project) { Q_UNUSED(project); } virtual void visitProjectData(const GeneratableProject &project, const GeneratableProjectData &parentProjectData, const GeneratableProjectData &projectData) { Q_UNUSED(project); Q_UNUSED(parentProjectData); Q_UNUSED(projectData); } virtual void visitProjectData(const GeneratableProject &project, const GeneratableProjectData &projectData) { Q_UNUSED(project); Q_UNUSED(projectData); } virtual void visitProduct(const GeneratableProject &project, const GeneratableProjectData &projectData, const GeneratableProductData &productData) { Q_UNUSED(project); Q_UNUSED(projectData); Q_UNUSED(productData); } // Expanded configurations virtual void visitProject(const Project &project, const QString &configuration) { Q_UNUSED(project); Q_UNUSED(configuration); } virtual void visitProjectData(const ProjectData &parentProjectData, const ProjectData &projectData, const QString &configuration) { Q_UNUSED(parentProjectData); Q_UNUSED(projectData); Q_UNUSED(configuration); } virtual void visitProjectData(const ProjectData &projectData, const QString &configuration) { Q_UNUSED(projectData); Q_UNUSED(configuration); } virtual void visitProduct(const ProductData &productData, const QString &configuration) { Q_UNUSED(productData); Q_UNUSED(configuration); } }; } // namespace qbs #endif // IGENERATABLEPROJECTVISITOR_H qbs-src-2.6.1/src/lib/corelib/generators/xmlpropertygroup.h0000644000175100001660000000517714776170045023442 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_XML_PROPERTY_GROUP_H #define GENERATORS_XML_PROPERTY_GROUP_H #include "generatorversioninfo.h" #include "xmlproperty.h" #include #include namespace qbs { class ProductData; class Project; namespace gen { namespace xml { class QBS_EXPORT PropertyGroup : public Property { public: explicit PropertyGroup(QByteArray name); void appendProperty(QByteArray name, QVariant value); void appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep = QLatin1Char(',')); void accept(INodeVisitor *visitor) const final; }; class PropertyGroupFactory { public: virtual ~PropertyGroupFactory() = default; virtual bool canCreate(utils::Architecture arch, const Version &version) const = 0; virtual std::unique_ptr create( const qbs::Project &qbsProject, const qbs::ProductData &qbsProduct, const std::vector &qbsProductDeps) const = 0; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_PROPERTY_GROUP_H qbs-src-2.6.1/src/lib/corelib/generators/ixmlnodevisitor.h0000644000175100001660000000506214776170045023210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_XML_INODE_VISITOR_H #define GENERATORS_XML_INODE_VISITOR_H #include #include namespace qbs { namespace gen { namespace xml { class Project; class Property; class PropertyGroup; class Workspace; class QBS_EXPORT INodeVisitor { public: virtual ~INodeVisitor() = default; virtual void visitWorkspaceStart(const Workspace *workspace) { Q_UNUSED(workspace) } virtual void visitWorkspaceEnd(const Workspace *workspace) { Q_UNUSED(workspace) } virtual void visitProjectStart(const Project *project) { Q_UNUSED(project) } virtual void visitProjectEnd(const Project *project) { Q_UNUSED(project) } virtual void visitPropertyStart(const Property *property) = 0; virtual void visitPropertyEnd(const Property *property) = 0; virtual void visitPropertyGroupStart(const PropertyGroup *propertyGroup) = 0; virtual void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) = 0; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_INODE_VISITOR_H qbs-src-2.6.1/src/lib/corelib/generators/xmlworkspacewriter.h0000644000175100001660000000467514776170045023736 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_XML_WORKSPACE_WRITER_H #define GENERATORS_XML_WORKSPACE_WRITER_H #include "ixmlnodevisitor.h" #include #include namespace qbs { namespace gen { namespace xml { class QBS_EXPORT WorkspaceWriter : public INodeVisitor { Q_DISABLE_COPY(WorkspaceWriter) public: explicit WorkspaceWriter(std::ostream *device); bool write(const Workspace *workspace); protected: QXmlStreamWriter *writer() const; private: void visitPropertyStart(const Property *property) final; void visitPropertyEnd(const Property *property) final; void visitPropertyGroupStart(const PropertyGroup *propertyGroup) final; void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) final; std::ostream *m_device = nullptr; QByteArray m_buffer; std::unique_ptr m_writer; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_WORKSPACE_WRITER_H qbs-src-2.6.1/src/lib/corelib/generators/generatorutils.h0000644000175100001660000001065214776170045023021 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_UTILS_H #define GENERATORS_UTILS_H #include #include #include namespace qbs { namespace gen { namespace utils { enum class Architecture { Unknown = 0, Arm = 1 << 1, Avr = 1 << 2, Mcs51 = 1 << 3, Stm8 = 1 << 4, Msp430 = 1 << 5 }; Q_DECLARE_FLAGS(ArchitectureFlags, Architecture) Q_DECLARE_OPERATORS_FOR_FLAGS(ArchitectureFlags) QBS_EXPORT QString architectureName(Architecture arch); QBS_EXPORT Architecture architecture(const Project &qbsProject); QBS_EXPORT QString buildConfigurationName(const Project &qbsProject); QBS_EXPORT int debugInformation(const ProductData &qbsProduct); QBS_EXPORT QString buildRootPath(const Project &qbsProject); QBS_EXPORT QString relativeFilePath(const QString &baseDirectory, const QString &fullFilePath); QBS_EXPORT QString binaryOutputDirectory(const QString &baseDirectory, const ProductData &qbsProduct); QBS_EXPORT QString objectsOutputDirectory(const QString &baseDirectory, const ProductData &qbsProduct); QBS_EXPORT QString listingOutputDirectory(const QString &baseDirectory, const ProductData &qbsProduct); QBS_EXPORT std::vector dependenciesOf(const ProductData &qbsProduct, const GeneratableProject &genProject, const QString &configurationName); QBS_EXPORT QString targetBinary(const ProductData &qbsProduct); QBS_EXPORT QString targetBinaryPath(const QString &baseDirectory, const ProductData &qbsProduct); QBS_EXPORT QString cppStringModuleProperty(const PropertyMap &qbsProps, const QString &propertyName); QBS_EXPORT bool cppBooleanModuleProperty(const PropertyMap &qbsProps, const QString &propertyName); QBS_EXPORT int cppIntegerModuleProperty(const PropertyMap &qbsProps, const QString &propertyName); QBS_EXPORT QStringList cppStringModuleProperties(const PropertyMap &qbsProps, const QStringList &propertyNames); QBS_EXPORT QVariantList cppVariantModuleProperties(const PropertyMap &qbsProps, const QStringList &propertyNames); QBS_EXPORT QString firstFlagValue(const QStringList &flags, const QString &flagKey); QBS_EXPORT QStringList allFlagValues(const QStringList &flags, const QString &flagKey); template bool inBounds(const T &value, const T &low, const T &high) { return !(value < low) && !(high < value); } } // namespace utils } // namespace gen } // namespace qbs #endif // GENERATORS_UTILS_H qbs-src-2.6.1/src/lib/corelib/generators/generatableprojectiterator.cpp0000644000175100001660000000677414776170045025731 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "generatableprojectiterator.h" namespace qbs { GeneratableProjectIterator::GeneratableProjectIterator(GeneratableProject project) : project(std::move(project)) { } void GeneratableProjectIterator::accept(IGeneratableProjectVisitor *visitor) { visitor->visitProject(project); for (auto it = project.projects.cbegin(), end = project.projects.cend(); it != end; ++it) visitor->visitProject(it.value(), it.key()); accept(project, GeneratableProjectData(), project, visitor); } void GeneratableProjectIterator::accept(const GeneratableProject &project, const GeneratableProjectData &parentProjectData, const GeneratableProjectData &projectData, IGeneratableProjectVisitor *visitor) { visitor->visitProjectData(project, parentProjectData, projectData); visitor->visitProjectData(project, projectData); for (auto it = projectData.data.cbegin(), end = projectData.data.cend(); it != end; ++it) { visitor->visitProjectData(parentProjectData.data.value(it.key()), it.value(), it.key()); visitor->visitProjectData(it.value(), it.key()); } for (const auto &subProject : projectData.subProjects) { accept(project, projectData, subProject, visitor); } for (const auto &productDataMap : projectData.products) { visitor->visitProduct(project, projectData, productDataMap); for (auto it = productDataMap.data.cbegin(), end = productDataMap.data.cend(); it != end; ++it) { visitor->visitProduct(it.value(), it.key()); } } } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlprojectwriter.h0000644000175100001660000000465514776170045023404 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef GENERATORS_XML_PROJECT_WRITER_H #define GENERATORS_XML_PROJECT_WRITER_H #include "ixmlnodevisitor.h" #include #include namespace qbs { namespace gen { namespace xml { class QBS_EXPORT ProjectWriter : public INodeVisitor { Q_DISABLE_COPY(ProjectWriter) public: explicit ProjectWriter(std::ostream *device); bool write(const Project *project); protected: QXmlStreamWriter *writer() const; private: void visitPropertyStart(const Property *property) final; void visitPropertyEnd(const Property *property) final; void visitPropertyGroupStart(const PropertyGroup *propertyGroup) final; void visitPropertyGroupEnd(const PropertyGroup *propertyGroup) final; std::ostream *m_device = nullptr; QByteArray m_buffer; std::unique_ptr m_writer; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_PROJECT_WRITER_H qbs-src-2.6.1/src/lib/corelib/generators/xmlworkspace.h0000644000175100001660000000466314776170045022476 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GENERATORS_XML_WWORKSPACE_H #define GENERATORS_XML_WWORKSPACE_H #include "xmlproperty.h" #include #include namespace qbs { namespace gen { namespace xml { class QBS_EXPORT Workspace : public Property { public: explicit Workspace(const QString &workspacePath); void accept(INodeVisitor *visitor) const final; virtual void addProject(const QString &projectPath) = 0; protected: const QDir m_baseDirectory; }; } // namespace xml } // namespace gen } // namespace qbs #endif // GENERATORS_XML_WWORKSPACE_H qbs-src-2.6.1/src/lib/corelib/generators/generatordata.cpp0000644000175100001660000001241014776170045023117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "generatordata.h" #include #include #include namespace qbs { QString GeneratableProductData::name() const { return uniqueValue(&ProductData::name, QStringLiteral("Products with different names per configuration are not " "compatible with this generator. " "Consider using the targetName property instead.")); } CodeLocation GeneratableProductData::location() const { return uniqueValue(&ProductData::location, QStringLiteral("GeneratableProductData::location: internal bug; this should not happen.")); } QStringList GeneratableProductData::dependencies() const { return uniqueValue(&ProductData::dependencies, QStringLiteral("Products with different dependency lists per configuration are not " "compatible with this generator.")); } QStringList GeneratableProductData::type() const { return uniqueValue(&ProductData::type, QStringLiteral("Products with different types per configuration are not " "compatible with this generator.")); } QString GeneratableProductData::buildDirectory() const { return uniqueValue(&ProductData::buildDirectory, QStringLiteral("GeneratableProductData::buildDirectory: " "internal bug; this should not happen.")); } QString GeneratableProjectData::name() const { return uniqueValue(&ProjectData::name, QStringLiteral("Projects with different names per configuration are not " "compatible with this generator.")); } CodeLocation GeneratableProjectData::location() const { CodeLocation location; for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) { CodeLocation oldLocation = location; location = it.value().location(); if (oldLocation.isValid() && oldLocation != location) throw ErrorInfo(QStringLiteral("Projects with different code locations " "per configuration are not compatible with this " "generator.")); } return location; } GeneratableProjectData::Id GeneratableProjectData::uniqueName() const { GeneratableProjectData::Id id; id.value = name() + QLatin1Char('-') + location().toString(); return id; } QDir GeneratableProject::baseBuildDirectory() const { Internal::Set baseBuildDirectory; for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) { QDir dir(it.value().buildDirectory()); dir.cdUp(); baseBuildDirectory.insert(dir.absolutePath()); } Q_ASSERT(baseBuildDirectory.size() == 1); return *baseBuildDirectory.begin(); } QFileInfo GeneratableProject::filePath() const { Internal::Set filePath; for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) filePath.insert(it.value().location().filePath()); Q_ASSERT(filePath.size() == 1); return QFileInfo(*filePath.begin()); } bool GeneratableProject::hasMultipleConfigurations() const { return projects.size() > 1; } QStringList GeneratableProject::commandLine() const { QStringList combinedCommandLine; for (auto it = commandLines.cbegin(), end = commandLines.cend(); it != end; ++it) combinedCommandLine << it.value(); return combinedCommandLine; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/generatorversioninfo.cpp0000644000175100001660000000406514776170045024556 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "generatorversioninfo.h" namespace qbs { namespace gen { int VersionInfo::marketingVersion() const { return m_version.majorVersion(); } } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlproject.cpp0000644000175100001660000000355114776170045022474 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "xmlproject.h" #include "ixmlnodevisitor.h" namespace qbs { namespace gen { namespace xml { void Project::accept(INodeVisitor *visitor) const { visitor->visitProjectStart(this); for (const auto &child : children()) child->accept(visitor); visitor->visitProjectEnd(this); } } // namespace xml } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlpropertygroup.cpp0000644000175100001660000000444714776170045023774 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "ixmlnodevisitor.h" #include "xmlpropertygroup.h" namespace qbs { namespace gen { namespace xml { PropertyGroup::PropertyGroup(QByteArray name) { setName(std::move(name)); } void PropertyGroup::appendProperty(QByteArray name, QVariant value) { appendChild(std::move(name), std::move(value)); } void PropertyGroup::appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep) { const auto line = values.join(sep); appendProperty(std::move(key), QVariant::fromValue(line)); } void PropertyGroup::accept(INodeVisitor *visitor) const { visitor->visitPropertyGroupStart(this); for (const auto &child : children()) child->accept(visitor); visitor->visitPropertyGroupEnd(this); } } // namespace xml } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/generators/xmlworkspacewriter.cpp0000644000175100001660000000574014776170045024263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "xmlproperty.h" #include "xmlpropertygroup.h" #include "xmlworkspace.h" #include "xmlworkspacewriter.h" #include #include namespace qbs { namespace gen { namespace xml { WorkspaceWriter::WorkspaceWriter(std::ostream *device) : m_device(device) { m_writer = std::make_unique(&m_buffer); m_writer->setAutoFormatting(true); } bool WorkspaceWriter::write(const Workspace *workspace) { m_buffer.clear(); m_writer->writeStartDocument(); workspace->accept(this); m_writer->writeEndDocument(); if (m_writer->hasError()) return false; m_device->write(&*std::begin(m_buffer), m_buffer.size()); return m_device->good(); } void WorkspaceWriter::visitPropertyStart(const Property *property) { const auto value = property->value().toString(); const auto name = QString::fromUtf8(property->name()); m_writer->writeTextElement(name, value); } void WorkspaceWriter::visitPropertyEnd(const Property *property) { Q_UNUSED(property) } void WorkspaceWriter::visitPropertyGroupStart(const PropertyGroup *propertyGroup) { const auto name = QString::fromUtf8(propertyGroup->name()); m_writer->writeStartElement(name); } void WorkspaceWriter::visitPropertyGroupEnd(const PropertyGroup *propertyGroup) { Q_UNUSED(propertyGroup) m_writer->writeEndElement(); } QXmlStreamWriter *WorkspaceWriter::writer() const { return m_writer.get(); } } // namespace xml } // namespace gen } // namespace qbs qbs-src-2.6.1/src/lib/corelib/cppscanner/0000755000175100001660000000000014776170045017560 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/cppscanner/Token.cpp0000644000175100001660000001366114776170045021353 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Copyright (c) 2008 Roberto Raggi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "Token.h" #ifndef CPLUSPLUS_NO_PARSER # include "Literals.h" #endif using namespace CPlusPlus; static const char *token_names[] = { (""), (""), (""), (""), (""), (""), (""), (""), (""), (""), (""), (""), ("<@string literal>"), (""), ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"), (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"), ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="), ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"), ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"), ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="), ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"), ("class"), ("const"), ("const_cast"), ("continue"), ("default"), ("delete"), ("do"), ("double"), ("dynamic_cast"), ("else"), ("enum"), ("explicit"), ("export"), ("extern"), ("false"), ("float"), ("for"), ("friend"), ("goto"), ("if"), ("inline"), ("int"), ("long"), ("mutable"), ("namespace"), ("new"), ("operator"), ("private"), ("protected"), ("public"), ("register"), ("reinterpret_cast"), ("return"), ("short"), ("signed"), ("sizeof"), ("static"), ("static_cast"), ("struct"), ("switch"), ("template"), ("this"), ("throw"), ("true"), ("try"), ("typedef"), ("typeid"), ("typename"), ("union"), ("unsigned"), ("using"), ("virtual"), ("void"), ("volatile"), ("wchar_t"), ("while"), // gnu ("__attribute__"), ("__typeof__"), // objc @keywords ("@catch"), ("@class"), ("@compatibility_alias"), ("@defs"), ("@dynamic"), ("@encode"), ("@end"), ("@finally"), ("@implementation"), ("@interface"), ("@not_keyword"), ("@optional"), ("@package"), ("@private"), ("@property"), ("@protected"), ("@protocol"), ("@public"), ("@required"), ("@selector"), ("@synchronized"), ("@synthesize"), ("@throw"), ("@try"), // Qt keywords ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots"), ("Q_FOREACH"), ("Q_D"), ("Q_Q"), ("Q_INVOKABLE"), ("Q_PROPERTY"), ("Q_INTERFACES"), ("Q_ENUMS"), ("Q_FLAGS"), ("Q_PRIVATE_SLOT"), ("Q_DECLARE_INTERFACE"), ("Q_OBJECT"), ("Q_GADGET"), ("Q_NAMESPACE"), }; void Token::reset() { f = {}; offset = 0; ptr = nullptr; } const char *Token::name(int kind) { return token_names[kind]; } #ifndef CPLUSPLUS_NO_PARSER const char *Token::spell() const { switch (f.kind) { case T_IDENTIFIER: return identifier->chars(); case T_NUMERIC_LITERAL: case T_CHAR_LITERAL: case T_STRING_LITERAL: case T_AT_STRING_LITERAL: case T_ANGLE_STRING_LITERAL: case T_WIDE_CHAR_LITERAL: case T_WIDE_STRING_LITERAL: return literal->chars(); default: return token_names[f.kind]; } // switch } #endif qbs-src-2.6.1/src/lib/corelib/cppscanner/Lexer.cpp0000644000175100001660000004275114776170045021354 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Copyright (c) 2008 Roberto Raggi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "Lexer.h" #include namespace CPlusPlus { Lexer::Lexer(const char *firstChar, const char *lastChar) : _state(State_Default), _currentLine(1) { setSource(firstChar, lastChar); } void Lexer::setSource(const char *firstChar, const char *lastChar) { _firstChar = firstChar; _lastChar = lastChar; _currentChar = _firstChar - 1; _tokenStart = _currentChar; _yychar = '\n'; } void Lexer::setStartWithNewline(bool enabled) { if (enabled) _yychar = '\n'; else _yychar = ' '; } int Lexer::state() const { return _state; } void Lexer::setState(int state) { _state = state; } bool Lexer::qtMocRunEnabled() const { return f._qtMocRunEnabled; } void Lexer::setQtMocRunEnabled(bool onoff) { f._qtMocRunEnabled = onoff; } bool Lexer::cxx0xEnabled() const { return f._cxx0xEnabled; } void Lexer::setCxxOxEnabled(bool onoff) { f._cxx0xEnabled = onoff; } bool Lexer::objCEnabled() const { return f._objCEnabled; } void Lexer::setObjCEnabled(bool onoff) { f._objCEnabled = onoff; } bool Lexer::isIncremental() const { return f._isIncremental; } void Lexer::setIncremental(bool isIncremental) { f._isIncremental = isIncremental; } bool Lexer::scanCommentTokens() const { return f._scanCommentTokens; } void Lexer::setScanCommentTokens(bool onoff) { f._scanCommentTokens = onoff; } void Lexer::setScanAngleStringLiteralTokens(bool onoff) { f._scanAngleStringLiteralTokens = onoff; } void Lexer::pushLineStartOffset() { ++_currentLine; } unsigned Lexer::tokenOffset() const { return _tokenStart - _firstChar; } unsigned Lexer::tokenLength() const { return _currentChar - _tokenStart; } const char *Lexer::tokenBegin() const { return _tokenStart; } const char *Lexer::tokenEnd() const { return _currentChar; } unsigned Lexer::currentLine() const { return _currentLine; } void Lexer::scan(Token *tok) { tok->reset(); scan_helper(tok); tok->f.length = _currentChar - _tokenStart; } void Lexer::scan_helper(Token *tok) { _Lagain: while (_yychar && std::isspace(_yychar)) { if (_yychar == '\n') { tok->f.joined = false; tok->f.newline = true; } else { tok->f.whitespace = true; } yyinp(); } tok->lineno = _currentLine; _tokenStart = _currentChar; tok->offset = _currentChar - _firstChar; if (_state == State_MultiLineComment || _state == State_MultiLineDoxyComment) { const int originalState = _state; if (! _yychar) { tok->f.kind = T_EOF_SYMBOL; return; } while (_yychar) { if (_yychar != '*') yyinp(); else { yyinp(); if (_yychar == '/') { yyinp(); _state = State_Default; break; } } } if (! f._scanCommentTokens) goto _Lagain; else if (originalState == State_MultiLineComment) tok->f.kind = T_COMMENT; else tok->f.kind = T_DOXY_COMMENT; return; // done } if (! _yychar) { tok->f.kind = T_EOF_SYMBOL; return; } unsigned char ch = _yychar; yyinp(); switch (ch) { case '\\': while (_yychar != '\n' && std::isspace(_yychar)) yyinp(); // ### assert(! _yychar || _yychar == '\n'); if (_yychar == '\n') { tok->f.joined = true; tok->f.newline = false; yyinp(); } goto _Lagain; case '"': case '\'': { const unsigned char quote = ch; tok->f.kind = quote == '"' ? T_STRING_LITERAL : T_CHAR_LITERAL; while (_yychar && _yychar != quote) { if (_yychar == '\n') break; if (_yychar != '\\') yyinp(); else { yyinp(); // skip `\\' if (_yychar) yyinp(); } } // assert(_yychar == quote); if (_yychar == quote) yyinp(); } break; case '{': tok->f.kind = T_LBRACE; break; case '}': tok->f.kind = T_RBRACE; break; case '[': tok->f.kind = T_LBRACKET; break; case ']': tok->f.kind = T_RBRACKET; break; case '#': if (_yychar == '#') { tok->f.kind = T_POUND_POUND; yyinp(); } else { tok->f.kind = T_POUND; } break; case '(': tok->f.kind = T_LPAREN; break; case ')': tok->f.kind = T_RPAREN; break; case ';': tok->f.kind = T_SEMICOLON; break; case ':': if (_yychar == ':') { yyinp(); tok->f.kind = T_COLON_COLON; } else { tok->f.kind = T_COLON; } break; case '.': if (_yychar == '*') { yyinp(); tok->f.kind = T_DOT_STAR; } else if (_yychar == '.') { yyinp(); // ### assert(_yychar); if (_yychar == '.') { yyinp(); tok->f.kind = T_DOT_DOT_DOT; } else { tok->f.kind = T_ERROR; } } else if (std::isdigit(_yychar)) { do { if (_yychar == 'e' || _yychar == 'E') { yyinp(); if (_yychar == '-' || _yychar == '+') { yyinp(); // ### assert(std::isdigit(_yychar)); } } else if (std::isalnum(_yychar) || _yychar == '.') { yyinp(); } else { break; } } while (_yychar); tok->f.kind = T_NUMERIC_LITERAL; } else { tok->f.kind = T_DOT; } break; case '?': tok->f.kind = T_QUESTION; break; case '+': if (_yychar == '+') { yyinp(); tok->f.kind = T_PLUS_PLUS; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_PLUS_EQUAL; } else { tok->f.kind = T_PLUS; } break; case '-': if (_yychar == '-') { yyinp(); tok->f.kind = T_MINUS_MINUS; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_MINUS_EQUAL; } else if (_yychar == '>') { yyinp(); if (_yychar == '*') { yyinp(); tok->f.kind = T_ARROW_STAR; } else { tok->f.kind = T_ARROW; } } else { tok->f.kind = T_MINUS; } break; case '*': if (_yychar == '=') { yyinp(); tok->f.kind = T_STAR_EQUAL; } else { tok->f.kind = T_STAR; } break; case '/': if (_yychar == '/') { yyinp(); bool doxy = false; if (_yychar == '/' || _yychar == '!') { yyinp(); if (_yychar == '<') yyinp(); if (_yychar != '\n' && std::isspace(_yychar)) doxy = true; } while (_yychar && _yychar != '\n') yyinp(); if (! f._scanCommentTokens) goto _Lagain; tok->f.kind = doxy ? T_CPP_DOXY_COMMENT : T_CPP_COMMENT; } else if (_yychar == '*') { yyinp(); bool doxy = false; if (_yychar == '*' || _yychar == '!') { const unsigned char ch = _yychar; yyinp(); if (ch == '*' && _yychar == '/') goto _Ldone; if (_yychar == '<') yyinp(); if (! _yychar || std::isspace(_yychar)) doxy = true; } while (_yychar) { if (_yychar != '*') { yyinp(); } else { yyinp(); if (_yychar == '/') break; } } _Ldone: if (_yychar) yyinp(); else _state = doxy ? State_MultiLineDoxyComment : State_MultiLineComment; if (! f._scanCommentTokens) goto _Lagain; tok->f.kind = doxy ? T_DOXY_COMMENT : T_COMMENT; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_SLASH_EQUAL; } else { tok->f.kind = T_SLASH; } break; case '%': if (_yychar == '=') { yyinp(); tok->f.kind = T_PERCENT_EQUAL; } else { tok->f.kind = T_PERCENT; } break; case '^': if (_yychar == '=') { yyinp(); tok->f.kind = T_CARET_EQUAL; } else { tok->f.kind = T_CARET; } break; case '&': if (_yychar == '&') { yyinp(); tok->f.kind = T_AMPER_AMPER; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_AMPER_EQUAL; } else { tok->f.kind = T_AMPER; } break; case '|': if (_yychar == '|') { yyinp(); tok->f.kind = T_PIPE_PIPE; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_PIPE_EQUAL; } else { tok->f.kind = T_PIPE; } break; case '~': if (_yychar == '=') { yyinp(); tok->f.kind = T_TILDE_EQUAL; } else { tok->f.kind = T_TILDE; } break; case '!': if (_yychar == '=') { yyinp(); tok->f.kind = T_EXCLAIM_EQUAL; } else { tok->f.kind = T_EXCLAIM; } break; case '=': if (_yychar == '=') { yyinp(); tok->f.kind = T_EQUAL_EQUAL; } else { tok->f.kind = T_EQUAL; } break; case '<': if (f._scanAngleStringLiteralTokens) { //const char *yytext = _currentChar; while (_yychar && _yychar != '>') yyinp(); //int yylen = _currentChar - yytext; // ### assert(_yychar == '>'); if (_yychar == '>') yyinp(); tok->f.kind = T_ANGLE_STRING_LITERAL; } else if (_yychar == '<') { yyinp(); if (_yychar == '=') { yyinp(); tok->f.kind = T_LESS_LESS_EQUAL; } else tok->f.kind = T_LESS_LESS; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_LESS_EQUAL; } else { tok->f.kind = T_LESS; } break; case '>': if (_yychar == '>') { yyinp(); if (_yychar == '=') { yyinp(); tok->f.kind = T_GREATER_GREATER_EQUAL; } else tok->f.kind = T_LESS_LESS; tok->f.kind = T_GREATER_GREATER; } else if (_yychar == '=') { yyinp(); tok->f.kind = T_GREATER_EQUAL; } else { tok->f.kind = T_GREATER; } break; case ',': tok->f.kind = T_COMMA; break; default: { if (f._objCEnabled) { if (ch == '@' && _yychar >= 'a' && _yychar <= 'z') { //const char *yytext = _currentChar; do { yyinp(); if (!isalnum(_yychar) && _yychar != '_' && _yychar != '$') break; } while (_yychar); // const int yylen = _currentChar - yytext; //tok->f.kind = classifyObjCAtKeyword(yytext, yylen); /// ### FIXME break; } if (ch == '@' && _yychar == '"') { // objc @string literals ch = _yychar; yyinp(); tok->f.kind = T_AT_STRING_LITERAL; //const char *yytext = _currentChar; while (_yychar && _yychar != '"') { if (_yychar != '\\') yyinp(); else { yyinp(); // skip `\\' if (_yychar) yyinp(); } } // assert(_yychar == '"'); //int yylen = _currentChar - yytext; if (_yychar == '"') yyinp(); break; } } if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) { // wide char/string literals ch = _yychar; yyinp(); const unsigned char quote = ch; tok->f.kind = quote == '"' ? T_WIDE_STRING_LITERAL : T_WIDE_CHAR_LITERAL; //const char *yytext = _currentChar; while (_yychar && _yychar != quote) { if (_yychar != '\\') yyinp(); else { yyinp(); // skip `\\' if (_yychar) yyinp(); } } // assert(_yychar == quote); //int yylen = _currentChar - yytext; if (_yychar == quote) yyinp(); } else if (std::isalpha(ch) || ch == '_' || ch == '$') { //const char *yytext = _currentChar - 1; while (std::isalnum(_yychar) || _yychar == '_' || _yychar == '$') yyinp(); //int yylen = _currentChar - yytext; tok->f.kind = T_IDENTIFIER; break; } else if (std::isdigit(ch)) { //const char *yytext = _currentChar - 1; while (_yychar) { if (_yychar == 'e' || _yychar == 'E') { yyinp(); if (_yychar == '-' || _yychar == '+') { yyinp(); // ### assert(std::isdigit(_yychar)); } } else if (std::isalnum(_yychar) || _yychar == '.') { yyinp(); } else { break; } } //int yylen = _currentChar - yytext; tok->f.kind = T_NUMERIC_LITERAL; break; } else { tok->f.kind = T_ERROR; break; } } // default } // switch } } // namespace CPlusPlus qbs-src-2.6.1/src/lib/corelib/cppscanner/Lexer.h0000644000175100001660000001251314776170045021012 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Copyright (c) 2008 Roberto Raggi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #ifndef CPLUSPLUS_LEXER_H #define CPLUSPLUS_LEXER_H #include "CPlusPlusForwardDeclarations.h" #include "Token.h" namespace CPlusPlus { class CPLUSPLUS_EXPORT Lexer { Lexer(const Lexer &other); void operator =(const Lexer &other); public: enum State { State_Default, State_MultiLineComment, State_MultiLineDoxyComment }; Lexer(const char *firstChar, const char *lastChar); bool qtMocRunEnabled() const; void setQtMocRunEnabled(bool onoff); bool cxx0xEnabled() const; void setCxxOxEnabled(bool onoff); bool objCEnabled() const; void setObjCEnabled(bool onoff); void scan(Token *tok); inline void operator()(Token *tok) { scan(tok); } unsigned tokenOffset() const; unsigned tokenLength() const; const char *tokenBegin() const; const char *tokenEnd() const; unsigned currentLine() const; bool scanCommentTokens() const; void setScanCommentTokens(bool onoff); bool scanAngleStringLiteralTokens() const; void setScanAngleStringLiteralTokens(bool onoff); void setStartWithNewline(bool enabled); int state() const; void setState(int state); bool isIncremental() const; void setIncremental(bool isIncremental); private: void scan_helper(Token *tok); void setSource(const char *firstChar, const char *lastChar); static int classify(const char *string, int length, bool q, bool cxx0x); static int classifyObjCAtKeyword(const char *s, int n); static int classifyOperator(const char *string, int length); inline void yyinp() { if (++_currentChar == _lastChar) _yychar = 0; else { _yychar = *_currentChar; if (_yychar == '\n') pushLineStartOffset(); } } void pushLineStartOffset(); private: struct Flags { unsigned _isIncremental: 1; unsigned _scanCommentTokens: 1; unsigned _scanAngleStringLiteralTokens: 1; unsigned _qtMocRunEnabled: 1; unsigned _cxx0xEnabled: 1; unsigned _objCEnabled: 1; }; const char *_firstChar = nullptr; const char *_currentChar = nullptr; const char *_lastChar = nullptr; const char *_tokenStart = nullptr; unsigned char _yychar = 0; int _state = 0; Flags f{}; unsigned _currentLine = 0; }; } // end of namespace CPlusPlus #endif // CPLUSPLUS_LEXER_H qbs-src-2.6.1/src/lib/corelib/cppscanner/cppscanner.cpp0000644000175100001660000002622014776170045022422 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "cppscanner.h" #include "../../plugins/scanner/scanner.h" #include "Lexer.h" #include #include namespace qbs::Internal { using namespace CPlusPlus; class TokenComparator { const char * const m_fileContent; public: TokenComparator(const char *fileContent) : m_fileContent(fileContent) {} bool equals(const Token &tk, const QLatin1String &literal) const { return static_cast(tk.length()) == literal.size() && memcmp(m_fileContent + tk.begin(), literal.data(), literal.size()) == 0; } QByteArray toByteArray(const Token &tk) const { const auto ptr = m_fileContent + tk.begin(); const auto len = tk.length(); return {ptr, int(len)}; } }; static void doScanCppFile( CppScannerContext &context, CPlusPlus::Lexer &yylex, bool scanForFileTags, bool scanForDependencies) { const QLatin1String includeLiteral("include"); const QLatin1String importLiteral("import"); const QLatin1String exportLiteral("export"); const QLatin1String moduleLiteral("module"); const QLatin1String defineLiteral("define"); const QLatin1String qobjectLiteral("Q_OBJECT"); const QLatin1String qgadgetLiteral("Q_GADGET"); const QLatin1String qnamespaceLiteral("Q_NAMESPACE"); const QLatin1String pluginMetaDataLiteral("Q_PLUGIN_METADATA"); const TokenComparator tc(context.fileContent.data()); Token tk; Token oldTk; ScanResult scanResult; yylex(&tk); auto stepLexer = [&]() mutable { oldTk = tk; yylex(&tk); }; auto parseModule = [&]() mutable { auto mod = tc.toByteArray(tk); while (tk.isNot(T_EOF_SYMBOL) && tk.isNot(T_SEMICOLON)) { stepLexer(); if (tk.is(T_DOT)) { stepLexer(); mod += '.'; mod += tc.toByteArray(tk); } else if (tk.is(T_COLON)) { stepLexer(); mod += ':'; mod += tc.toByteArray(tk); break; } } if (context.fileType == CppScannerContext::FileType::FT_CPPM) context.providesModule = mod; else context.requiresModules << mod; }; auto parseImport = [&]() mutable { if (tk.is(T_COLON)) { stepLexer(); if (!context.providesModule.isEmpty()) { const auto getModuleName = [](const QByteArray &moduleOrPartition) -> QByteArray { const auto index = moduleOrPartition.indexOf(':'); if (index == -1) return moduleOrPartition; return moduleOrPartition.mid(0, index); }; context.requiresModules << getModuleName(context.providesModule) + ':' + tc.toByteArray(tk); } return; } bool isGlobal = false; if (tk.is(T_LESS)) { stepLexer(); isGlobal = true; } auto mod = tc.toByteArray(tk); while (tk.isNot(T_EOF_SYMBOL) && tk.isNot(T_SEMICOLON) && tk.isNot(T_GREATER)) { stepLexer(); if (tk.is(T_DOT)) { stepLexer(); mod += '.'; mod += tc.toByteArray(tk); } } if (isGlobal) { mod = '<' + mod + '>'; } context.requiresModules << mod; }; while (tk.isNot(T_EOF_SYMBOL)) { if (scanForDependencies && tk.newline() && tk.is(T_IDENTIFIER)) { if (tc.equals(tk, moduleLiteral)) { stepLexer(); if (tk.isNot(T_SEMICOLON)) parseModule(); continue; } else if (tc.equals(tk, importLiteral)) { stepLexer(); parseImport(); continue; } else if (tc.equals(tk, exportLiteral)) { stepLexer(); if (tc.equals(tk, moduleLiteral)) { stepLexer(); parseModule(); context.isInterface = true; continue; } else if (tc.equals(tk, importLiteral)) { stepLexer(); parseImport(); continue; } } } if (tk.newline() && tk.is(T_POUND)) { yylex(&tk); if (scanForDependencies && !tk.newline() && tk.is(T_IDENTIFIER)) { if (tc.equals(tk, includeLiteral) || tc.equals(tk, importLiteral)) { yylex.setScanAngleStringLiteralTokens(true); yylex(&tk); yylex.setScanAngleStringLiteralTokens(false); if (!tk.newline() && (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))) { if (tk.is(T_STRING_LITERAL)) scanResult.flags = SC_LOCAL_INCLUDE_FLAG; else scanResult.flags = SC_GLOBAL_INCLUDE_FLAG; scanResult.fileName = context.fileContent.substr( tk.begin() + 1, size_t(tk.length() - 2)); context.includedFiles.push_back(scanResult); } } } } else if (tk.is(T_IDENTIFIER)) { if (scanForFileTags) { if (oldTk.is(T_IDENTIFIER) && tc.equals(oldTk, defineLiteral)) { // Someone was clever and redefined Q_OBJECT or Q_PLUGIN_METADATA. // Example: iplugin.h in Qt Creator. } else { if (tc.equals(tk, qobjectLiteral) || tc.equals(tk, qgadgetLiteral) || tc.equals(tk, qnamespaceLiteral)) { context.hasQObjectMacro = true; } else if (tc.equals(tk, pluginMetaDataLiteral)) { context.hasPluginMetaDataMacro = true; } if (!scanForDependencies && context.hasQObjectMacro && (context.hasPluginMetaDataMacro || context.fileType == CppScannerContext::FT_CPP || context.fileType == CppScannerContext::FT_OBJCPP)) break; } } } stepLexer(); } } bool scanCppFile( CppScannerContext &context, QStringView filePath, std::string_view fileTags, bool scanForFileTags, bool scanForDependencies) { context.fileName = filePath.toString(); const QList &tagList = QByteArray::fromRawData(fileTags.data(), fileTags.size()).split(','); if (tagList.contains("hpp")) context.fileType = CppScannerContext::FT_HPP; else if (tagList.contains("cpp")) context.fileType = CppScannerContext::FT_CPP; else if (tagList.contains("cppm")) context.fileType = CppScannerContext::FT_CPPM; else if (tagList.contains("objcpp")) context.fileType = CppScannerContext::FT_OBJCPP; else context.fileType = CppScannerContext::FT_UNKNOWN; size_t mapl = 0; #ifdef Q_OS_UNIX QString filePathS = context.fileName; context.fd = ::open(qPrintable(filePathS), O_RDONLY); if (context.fd == -1) { context.fd = 0; return false; } struct stat s {}; int r = fstat(context.fd, &s); if (r != 0) return false; mapl = s.st_size; context.mapl = mapl; void *vmap = mmap(nullptr, s.st_size, PROT_READ, MAP_PRIVATE, context.fd, 0); if (vmap == MAP_FAILED) // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) return false; context.vmap = vmap; #else context.file.setFileName(context.fileName); if (!context.file.open(QFile::ReadOnly)) return false; uchar *vmap = context.file.map(0, context.file.size()); mapl = context.file.size(); #endif if (!vmap) return false; std::string_view fileContent{reinterpret_cast(vmap), mapl}; // Check for UTF-8 Byte Order Mark (BOM). Skip if found. if (fileContent.size() >= 3 && fileContent[0] == char(0xef) && fileContent[1] == char(0xbb) && fileContent[2] == char(0xbf)) { fileContent = fileContent.substr(3); } context.fileContent = fileContent; CPlusPlus::Lexer lex(fileContent.data(), fileContent.data() + fileContent.size()); doScanCppFile(context, lex, scanForFileTags, scanForDependencies); return true; } span additionalFileTags(const CppScannerContext &context) { static const std::string_view thMocCpp[] = {"moc_cpp"}; static const std::string_view thMocHpp[] = {"moc_hpp"}; static const std::string_view thMocPluginHpp[] = {"moc_hpp_plugin"}; static const std::string_view thMocPluginCpp[] = {"moc_cpp_plugin"}; if (context.hasQObjectMacro) { switch (context.fileType) { case CppScannerContext::FT_CPP: case CppScannerContext::FT_OBJCPP: return {context.hasPluginMetaDataMacro ? thMocPluginCpp : thMocCpp, 1}; case CppScannerContext::FT_HPP: return {context.hasPluginMetaDataMacro ? thMocPluginHpp : thMocHpp, 1}; default: break; } } return {}; } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/cppscanner/Token.h0000644000175100001660000002171414776170045021016 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Copyright (c) 2008 Roberto Raggi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #ifndef CPLUSPLUS_TOKEN_H #define CPLUSPLUS_TOKEN_H #include "CPlusPlusForwardDeclarations.h" namespace CPlusPlus { enum Kind { T_EOF_SYMBOL = 0, T_ERROR, T_CPP_COMMENT, T_CPP_DOXY_COMMENT, T_COMMENT, T_DOXY_COMMENT, T_IDENTIFIER, T_FIRST_LITERAL, T_NUMERIC_LITERAL = T_FIRST_LITERAL, T_CHAR_LITERAL, T_WIDE_CHAR_LITERAL, T_STRING_LITERAL, T_WIDE_STRING_LITERAL, T_AT_STRING_LITERAL, T_ANGLE_STRING_LITERAL, T_LAST_LITERAL = T_ANGLE_STRING_LITERAL, T_FIRST_OPERATOR, T_AMPER = T_FIRST_OPERATOR, T_AMPER_AMPER, T_AMPER_EQUAL, T_ARROW, T_ARROW_STAR, T_CARET, T_CARET_EQUAL, T_COLON, T_COLON_COLON, T_COMMA, T_SLASH, T_SLASH_EQUAL, T_DOT, T_DOT_DOT_DOT, T_DOT_STAR, T_EQUAL, T_EQUAL_EQUAL, T_EXCLAIM, T_EXCLAIM_EQUAL, T_GREATER, T_GREATER_EQUAL, T_GREATER_GREATER, T_GREATER_GREATER_EQUAL, T_LBRACE, T_LBRACKET, T_LESS, T_LESS_EQUAL, T_LESS_LESS, T_LESS_LESS_EQUAL, T_LPAREN, T_MINUS, T_MINUS_EQUAL, T_MINUS_MINUS, T_PERCENT, T_PERCENT_EQUAL, T_PIPE, T_PIPE_EQUAL, T_PIPE_PIPE, T_PLUS, T_PLUS_EQUAL, T_PLUS_PLUS, T_POUND, T_POUND_POUND, T_QUESTION, T_RBRACE, T_RBRACKET, T_RPAREN, T_SEMICOLON, T_STAR, T_STAR_EQUAL, T_TILDE, T_TILDE_EQUAL, T_LAST_OPERATOR = T_TILDE_EQUAL, T_FIRST_KEYWORD, T_ASM = T_FIRST_KEYWORD, T_AUTO, T_BOOL, T_BREAK, T_CASE, T_CATCH, T_CHAR, T_CLASS, T_CONST, T_CONST_CAST, T_CONTINUE, T_DEFAULT, T_DELETE, T_DO, T_DOUBLE, T_DYNAMIC_CAST, T_ELSE, T_ENUM, T_EXPLICIT, T_EXPORT, T_EXTERN, T_FALSE, T_FLOAT, T_FOR, T_FRIEND, T_GOTO, T_IF, T_INLINE, T_INT, T_LONG, T_MUTABLE, T_NAMESPACE, T_NEW, T_OPERATOR, T_PRIVATE, T_PROTECTED, T_PUBLIC, T_REGISTER, T_REINTERPRET_CAST, T_RETURN, T_SHORT, T_SIGNED, T_SIZEOF, T_STATIC, T_STATIC_CAST, T_STRUCT, T_SWITCH, T_TEMPLATE, T_THIS, T_THROW, T_TRUE, T_TRY, T_TYPEDEF, T_TYPEID, T_TYPENAME, T_UNION, T_UNSIGNED, T_USING, T_VIRTUAL, T_VOID, T_VOLATILE, T_WCHAR_T, T_WHILE, T___ATTRIBUTE__, T___TYPEOF__, // obj c++ @ keywords T_FIRST_OBJC_AT_KEYWORD, T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD, T_AT_CLASS, T_AT_COMPATIBILITY_ALIAS, T_AT_DEFS, T_AT_DYNAMIC, T_AT_ENCODE, T_AT_END, T_AT_FINALLY, T_AT_IMPLEMENTATION, T_AT_INTERFACE, T_AT_NOT_KEYWORD, T_AT_OPTIONAL, T_AT_PACKAGE, T_AT_PRIVATE, T_AT_PROPERTY, T_AT_PROTECTED, T_AT_PROTOCOL, T_AT_PUBLIC, T_AT_REQUIRED, T_AT_SELECTOR, T_AT_SYNCHRONIZED, T_AT_SYNTHESIZE, T_AT_THROW, T_AT_TRY, T_LAST_OBJC_AT_KEYWORD = T_AT_TRY, T_FIRST_QT_KEYWORD, // Qt keywords T_SIGNAL = T_FIRST_QT_KEYWORD, T_SLOT, T_Q_SIGNAL, T_Q_SLOT, T_Q_SIGNALS, T_Q_SLOTS, T_Q_FOREACH, T_Q_D, T_Q_Q, T_Q_INVOKABLE, T_Q_PROPERTY, T_Q_INTERFACES, T_Q_ENUMS, T_Q_FLAGS, T_Q_PRIVATE_SLOT, T_Q_DECLARE_INTERFACE, T_Q_OBJECT, T_Q_GADGET, T_Q_NAMESPACE, T_LAST_KEYWORD = T_Q_NAMESPACE, // aliases T_OR = T_PIPE_PIPE, T_AND = T_AMPER_AMPER, T_NOT = T_EXCLAIM, T_XOR = T_CARET, T_BITOR = T_PIPE, T_COMPL = T_TILDE, T_OR_EQ = T_PIPE_EQUAL, T_AND_EQ = T_AMPER_EQUAL, T_BITAND = T_AMPER, T_NOT_EQ = T_EXCLAIM_EQUAL, T_XOR_EQ = T_CARET_EQUAL, T___ASM = T_ASM, T___ASM__ = T_ASM, T_TYPEOF = T___TYPEOF__, T___TYPEOF = T___TYPEOF__, T___INLINE = T_INLINE, T___INLINE__ = T_INLINE, T___CONST = T_CONST, T___CONST__ = T_CONST, T___VOLATILE = T_VOLATILE, T___VOLATILE__ = T_VOLATILE, T___ATTRIBUTE = T___ATTRIBUTE__ }; class CPLUSPLUS_EXPORT Token { public: inline bool is(unsigned k) const { return f.kind == k; } inline bool isNot(unsigned k) const { return f.kind != k; } #ifndef CPLUSPLUS_NO_PARSER const char *spell() const; #endif void reset(); inline unsigned kind() const { return f.kind; } inline bool newline() const { return f.newline; } inline bool whitespace() const { return f.whitespace; } inline bool joined() const { return f.joined; } inline bool expanded() const { return f.expanded; } inline bool generated() const { return f.generated; } inline unsigned length() const { return f.length; } inline unsigned begin() const { return offset; } inline unsigned end() const { return offset + f.length; } inline bool isLiteral() const { return f.kind >= T_FIRST_LITERAL && f.kind <= T_LAST_LITERAL; } inline bool isOperator() const { return f.kind >= T_FIRST_OPERATOR && f.kind <= T_LAST_OPERATOR; } inline bool isKeyword() const { return f.kind >= T_FIRST_KEYWORD && f.kind < T_FIRST_QT_KEYWORD; } inline bool isComment() const { return f.kind == T_COMMENT || f.kind == T_DOXY_COMMENT || f.kind == T_CPP_COMMENT || f.kind == T_CPP_DOXY_COMMENT; } inline bool isObjCAtKeyword() const { return f.kind >= T_FIRST_OBJC_AT_KEYWORD && f.kind <= T_LAST_OBJC_AT_KEYWORD; } static const char *name(int kind); public: struct Flags { unsigned kind : 8; unsigned newline : 1; unsigned whitespace : 1; unsigned joined : 1; unsigned expanded : 1; unsigned generated : 1; unsigned pad : 3; unsigned length : 16; }; Flags f{}; unsigned offset = 0; union { void *ptr = nullptr; #ifndef CPLUSPLUS_NO_PARSER const Literal *literal; const NumericLiteral *number; const StringLiteral *string; const Identifier *identifier; #endif unsigned close_brace; unsigned lineno; }; }; } // end of namespace CPlusPlus #endif // CPLUSPLUS_TOKEN_H qbs-src-2.6.1/src/lib/corelib/cppscanner/CPlusPlusForwardDeclarations.h0000644000175100001660000001130714776170045025503 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Copyright (c) 2008 Roberto Raggi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #ifndef CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H #define CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H #include #include #ifndef CPLUSPLUS_WITHOUT_QT # include //# if defined(CPLUSPLUS_BUILD_LIB) //# define CPLUSPLUS_EXPORT Q_DECL_EXPORT //# elif defined(CPLUSPLUS_BUILD_STATIC_LIB) //# define CPLUSPLUS_EXPORT //# else //# define CPLUSPLUS_EXPORT Q_DECL_IMPORT //# endif //#else # define CPLUSPLUS_EXPORT #endif namespace CPlusPlus { class TranslationUnit; class Control; class MemoryPool; class DiagnosticClient; class Identifier; class Literal; class StringLiteral; class NumericLiteral; class SymbolTable; // names class NameVisitor; class Name; class Identifier; class TemplateNameId; class DestructorNameId; class OperatorNameId; class ConversionNameId; class QualifiedNameId; class SelectorNameId; // types class TypeMatcher; class FullySpecifiedType; class TypeVisitor; class Type; class UndefinedType; class VoidType; class IntegerType; class FloatType; class PointerToMemberType; class PointerType; class ReferenceType; class ArrayType; class NamedType; // symbols class SymbolVisitor; class Symbol; class Scope; class UsingNamespaceDirective; class UsingDeclaration; class Declaration; class Argument; class TypenameArgument; class Function; class Namespace; class NamespaceAlias; class Template; class BaseClass; class Block; class Class; class Enum; class ForwardClassDeclaration; class Token; // Objective-C symbols class ObjCBaseClass; class ObjCBaseProtocol; class ObjCClass; class ObjCForwardClassDeclaration; class ObjCProtocol; class ObjCForwardProtocolDeclaration; class ObjCMethod; class ObjCPropertyDeclaration; } // end of namespace CPlusPlus #endif // CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H qbs-src-2.6.1/src/lib/corelib/cppscanner/cppscanner.h0000644000175100001660000000712214776170045022067 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #ifdef Q_OS_UNIX #include #include #include #include #include #else #include #endif namespace qbs::Internal { struct QBS_EXPORT ScanResult { std::string_view fileName; int flags = 0; }; struct QBS_EXPORT CppScannerContext { enum FileType { FT_UNKNOWN, FT_HPP, FT_CPP, FT_CPPM, FT_C, FT_OBJC, FT_OBJCPP, FT_RC }; CppScannerContext() = default; CppScannerContext(const CppScannerContext &other) = delete; CppScannerContext(CppScannerContext &&other) = delete; CppScannerContext &operator=(const CppScannerContext &other) = delete; CppScannerContext &operator=(CppScannerContext &&other) = delete; ~CppScannerContext() { #ifdef Q_OS_UNIX if (vmap) munmap(vmap, mapl); if (fd) close(fd); #endif } #ifdef Q_OS_WIN QFile file; #endif #ifdef Q_OS_UNIX int fd{0}; void *vmap{nullptr}; size_t mapl{0}; #endif QString fileName; std::string_view fileContent; FileType fileType{FT_UNKNOWN}; QList includedFiles; QByteArray providesModule; bool isInterface{false}; QList requiresModules; bool hasQObjectMacro{false}; bool hasPluginMetaDataMacro{false}; }; QBS_EXPORT bool scanCppFile( CppScannerContext &context, QStringView filePath, std::string_view fileTags, bool scanForFileTags, bool scanForDependencies); span additionalFileTags(const CppScannerContext &context); } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/logging/0000755000175100001660000000000014776170045017052 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/logging/logger.h0000644000175100001660000001154414776170045020507 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LOGGER_H #define QBS_LOGGER_H #include "ilogsink.h" #include #include #include #include #include QT_BEGIN_NAMESPACE class QVariant; QT_END_NAMESPACE namespace qbs { namespace Internal { template class Set; // Note that while these classes are not part of the API, we export some stuff for use by // our command line tools for the sake of a uniform logging approach. class QBS_EXPORT LogWriter { public: LogWriter(ILogSink *logSink, LoggerLevel level, bool force = false); // log writer has move semantics and the last instance of // a << chain prints the accumulated data LogWriter(const LogWriter &other); ~LogWriter(); const LogWriter &operator=(const LogWriter &other); // NOLINT void write(char c); void write(const char *str); void write(const QChar &c); void write(const QString &message); void setMessageTag(const QString &tag); private: ILogSink *m_logSink; LoggerLevel m_level; mutable QString m_message; QString m_tag; bool m_force; }; class QBS_EXPORT MessageTag { public: explicit MessageTag(QString tag) : m_tag(std::move(tag)) {} const QString &tag() const { return m_tag; } private: QString m_tag; }; QBS_EXPORT LogWriter operator<<(LogWriter w, const char *str); QBS_EXPORT LogWriter operator<<(LogWriter w, const QByteArray &byteArray); QBS_EXPORT LogWriter operator<<(LogWriter w, const QString &str); QBS_EXPORT LogWriter operator<<(LogWriter w, const QStringList &strList); QBS_EXPORT LogWriter operator<<(LogWriter w, const Internal::Set &strSet); QBS_EXPORT LogWriter operator<<(LogWriter w, const QVariant &variant); QBS_EXPORT LogWriter operator<<(LogWriter w, int n); QBS_EXPORT LogWriter operator<<(LogWriter w, qint64 n); QBS_EXPORT LogWriter operator<<(LogWriter w, bool b); QBS_EXPORT LogWriter operator<<(LogWriter w, const MessageTag &tag); class QBS_EXPORT Logger { public: Logger(ILogSink *logSink = 0); ILogSink *logSink() const { return m_logSink; } bool debugEnabled() const; bool traceEnabled() const; void printWarning(const ErrorInfo &warning); void printError(const ErrorInfo &error); QList warnings() const { return m_warnings; } QList errors() const { return m_errors; } void clearWarnings() { m_warnings.clear(); m_errors.clear(); } void storeWarnings() { m_storeWarnings = true; } LogWriter qbsLog(LoggerLevel level, bool force = false) const; LogWriter qbsWarning() const { return qbsLog(LoggerWarning); } LogWriter qbsInfo() const { return qbsLog(LoggerInfo); } LogWriter qbsDebug() const { return qbsLog(LoggerDebug); } LogWriter qbsTrace() const { return qbsLog(LoggerTrace); } private: ILogSink *m_logSink; QList m_warnings; QList m_errors; bool m_storeWarnings = false; }; } // namespace Internal } // namespace qbs #endif // QBS_LOGGER_H qbs-src-2.6.1/src/lib/corelib/logging/logger.cpp0000644000175100001660000001373114776170045021042 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #if defined(_MSC_VER) && _MSC_VER > 0 #define _CRT_SECURE_NO_WARNINGS #endif #include "logger.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { LogWriter::LogWriter(ILogSink *logSink, LoggerLevel level, bool force) : m_logSink(logSink), m_level(level), m_force(force) {} LogWriter::LogWriter(const LogWriter &other) : m_logSink(other.m_logSink) , m_level(other.m_level) , m_message(other.m_message) , m_tag(other.m_tag) , m_force(other.m_force) { other.m_message.clear(); } LogWriter::~LogWriter() { if (!m_message.isEmpty()) m_logSink->printMessage(m_level, m_message, m_tag, m_force); } const LogWriter &LogWriter::operator=(const LogWriter &other) { if (this == &other) // Self assignment guard. return *this; m_logSink = other.m_logSink; m_level = other.m_level; m_message = other.m_message; m_tag = other.m_tag; m_force = other.m_force; other.m_message.clear(); return *this; } void LogWriter::write(char c) { write(QLatin1Char(c)); } void LogWriter::write(const char *str) { write(QLatin1String(str)); } void LogWriter::write(const QChar &c) { if (m_force || m_logSink->logLevel() >= m_level) m_message.append(c); } void LogWriter::write(const QString &message) { if (m_force || m_logSink->logLevel() >= m_level) m_message += message; } void LogWriter::setMessageTag(const QString &tag) { m_tag = tag; } LogWriter operator<<(LogWriter w, const char *str) { w.write(str); return w; } LogWriter operator<<(LogWriter w, const QByteArray &byteArray) { w.write(byteArray.data()); return w; } LogWriter operator<<(LogWriter w, const QString &str) { w.write(str); return w; } LogWriter operator<<(LogWriter w, const QStringList &strList) { w.write('['); for (int i = 0; i < strList.size(); ++i) { w.write(strList.at(i)); if (i != strList.size() - 1) w.write(QStringLiteral(", ")); } w.write(']'); return w; } LogWriter operator<<(LogWriter w, const Internal::Set &strSet) { bool firstLoop = true; w.write('('); for (const QString &str : strSet) { if (firstLoop) firstLoop = false; else w.write(QStringLiteral(", ")); w.write(str); } w.write(')'); return w; } LogWriter operator<<(LogWriter w, const QVariant &variant) { QString str = QLatin1String(variant.typeName()) + QLatin1Char('('); if (variant.userType() == QMetaType::QVariantList) { bool firstLoop = true; const auto list = variant.toList(); for (const QVariant &item : list) { str += item.toString(); if (firstLoop) firstLoop = false; else str += QLatin1String(", "); } } else { str += variant.toString(); } str += QLatin1Char(')'); w.write(str); return w; } LogWriter operator<<(LogWriter w, int n) { w.write(QString::number(n)); return w; } LogWriter operator<<(LogWriter w, qint64 n) { w.write(QString::number(n)); return w; } LogWriter operator<<(LogWriter w, bool b) { w.write(QString::fromLatin1(b ? "true" : "false")); return w; } LogWriter operator<<(LogWriter w, const MessageTag &tag) { w.setMessageTag(tag.tag()); return w; } Logger::Logger(ILogSink *logger) : m_logSink(logger) { } bool Logger::debugEnabled() const { return m_logSink->willPrint(LoggerDebug); } bool Logger::traceEnabled() const { return m_logSink->willPrint(LoggerTrace); } void Logger::printWarning(const ErrorInfo &warning) { if (m_storeWarnings) m_warnings.push_back(warning); logSink()->printWarning(warning); } void Logger::printError(const ErrorInfo &error) { if (m_storeWarnings) m_errors.push_back(error); logSink()->printError(error); } LogWriter Logger::qbsLog(LoggerLevel level, bool force) const { return {m_logSink, level, force}; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/logging/categories.h0000644000175100001660000000462414776170045021356 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CATEGORIES_H #define CATEGORIES_H #include namespace qbs { namespace Internal { Q_DECLARE_LOGGING_CATEGORY(lcBuildGraph) Q_DECLARE_LOGGING_CATEGORY(lcDepScan) Q_DECLARE_LOGGING_CATEGORY(lcExec) Q_DECLARE_LOGGING_CATEGORY(lcMocScan) Q_DECLARE_LOGGING_CATEGORY(lcModuleLoader) Q_DECLARE_LOGGING_CATEGORY(lcPluginManager) Q_DECLARE_LOGGING_CATEGORY(lcProjectResolver) Q_DECLARE_LOGGING_CATEGORY(lcUpToDateCheck) Q_DECLARE_LOGGING_CATEGORY(lcLoaderScheduling) } // namespace Internal } // namespace qbs #endif // CATEGORIES_H qbs-src-2.6.1/src/lib/corelib/logging/categories.cpp0000644000175100001660000000505014776170045021703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "categories.h" namespace qbs { namespace Internal { Q_LOGGING_CATEGORY(lcBuildGraph, "qbs.buildgraph", QtCriticalMsg) Q_LOGGING_CATEGORY(lcDepScan, "qbs.depscan", QtCriticalMsg) Q_LOGGING_CATEGORY(lcExec, "qbs.exec", QtCriticalMsg) Q_LOGGING_CATEGORY(lcMocScan, "qbs.mocscan", QtCriticalMsg) Q_LOGGING_CATEGORY(lcModuleLoader, "qbs.moduleloader", QtCriticalMsg) Q_LOGGING_CATEGORY(lcPluginManager, "qbs.pluginmanager", QtCriticalMsg) Q_LOGGING_CATEGORY(lcProjectResolver, "qbs.projectresolver", QtCriticalMsg) Q_LOGGING_CATEGORY(lcUpToDateCheck, "qbs.uptodate", QtCriticalMsg) Q_LOGGING_CATEGORY(lcLoaderScheduling, "qbs.loader.scheduling", QtCriticalMsg) } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/logging/translator.h0000644000175100001660000000430514776170045021416 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TRANSLATOR_H #define QBS_TRANSLATOR_H #include #include namespace qbs { namespace Internal { class QBS_EXPORT Tr // Name intended to be short. Exported for use by command line tools. { Q_DECLARE_TR_FUNCTIONS(Qbs) }; } // namespace Internal } // namespace qbs #endif // QBS_TRANSLATOR_H qbs-src-2.6.1/src/lib/corelib/logging/ilogsink.cpp0000644000175100001660000000746014776170045021404 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "ilogsink.h" #include #include #include namespace qbs { QString logLevelTag(LoggerLevel level) { if (level == LoggerInfo) return {}; QString str = logLevelName(level).toUpper(); if (!str.isEmpty()) str.append(QLatin1String(": ")); return str; } QString logLevelName(LoggerLevel level) { switch (level) { case qbs::LoggerError: return QStringLiteral("error"); case qbs::LoggerWarning: return QStringLiteral("warning"); case qbs::LoggerInfo: return QStringLiteral("info"); case qbs::LoggerDebug: return QStringLiteral("debug"); case qbs::LoggerTrace: return QStringLiteral("trace"); default: break; } return {}; } class ILogSink::ILogSinkPrivate { public: LoggerLevel logLevel = defaultLogLevel(); std::mutex mutex; }; ILogSink::ILogSink() : d(std::make_unique()) { } ILogSink::~ILogSink() = default; void ILogSink::setLogLevel(LoggerLevel level) { d->logLevel = level; } LoggerLevel ILogSink::logLevel() const { return d->logLevel; } void ILogSink::printWarning(const ErrorInfo &warning) { if (willPrint(LoggerWarning)) { d->mutex.lock(); doPrintWarning(warning); d->mutex.unlock(); } } void ILogSink::printError(const ErrorInfo &error) { d->mutex.lock(); doPrintError(error); d->mutex.unlock(); } void ILogSink::printMessage(LoggerLevel level, const QString &message, const QString &tag, bool force) { if (force || willPrint(level)) { d->mutex.lock(); doPrintMessage(level, message, tag); d->mutex.unlock(); } } void ILogSink::doPrintWarning(const ErrorInfo &warning) { doPrintMessage(LoggerWarning, warning.toString(), QString()); } void ILogSink::doPrintError(const ErrorInfo &error) { doPrintMessage(LoggerError, error.toString(), QString()); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/logging/ilogsink.h0000644000175100001660000000630214776170045021043 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ILOGSINK_H #define QBS_ILOGSINK_H #include "../tools/qbs_export.h" #include #include namespace qbs { class ErrorInfo; enum LoggerLevel { LoggerMinLevel, LoggerError = LoggerMinLevel, LoggerWarning, LoggerInfo, LoggerDebug, LoggerTrace, LoggerMaxLevel = LoggerTrace }; inline LoggerLevel defaultLogLevel() { return LoggerInfo; } QBS_EXPORT QString logLevelTag(LoggerLevel level); QBS_EXPORT QString logLevelName(LoggerLevel level); class QBS_EXPORT ILogSink { Q_DISABLE_COPY(ILogSink) public: ILogSink(); virtual ~ILogSink(); void setLogLevel(LoggerLevel level); LoggerLevel logLevel() const; bool willPrint(LoggerLevel level) const { return level <= logLevel(); } void printWarning(const ErrorInfo &warning); void printError(const ErrorInfo &error); void printMessage(LoggerLevel level, const QString &message, const QString &tag = QString(), bool force = false); private: virtual void doPrintWarning(const ErrorInfo &warning); virtual void doPrintError(const ErrorInfo &error); virtual void doPrintMessage(LoggerLevel level, const QString &message, const QString &tag) = 0; class ILogSinkPrivate; const std::unique_ptr d; }; } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/api/0000755000175100001660000000000014776170045016175 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/api/runenvironment.cpp0000644000175100001660000004760014776170045022001 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "runenvironment.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { using namespace Internal; class RunEnvironment::RunEnvironmentPrivate { public: RunEnvironmentPrivate(ResolvedProductPtr product, TopLevelProjectConstPtr project, InstallOptions installOptions, const QProcessEnvironment &environment, QStringList setupRunEnvConfig, Settings *settings, Logger logger) : resolvedProduct(std::move(product)) , project(std::move(project)) , installOptions(std::move(installOptions)) , environment(environment) , setupRunEnvConfig(std::move(setupRunEnvConfig)) , settings(settings) , logger(std::move(logger)) , evalContext(this->logger) { } void checkProduct() { if (!resolvedProduct) throw ErrorInfo(Tr::tr("Cannot run: No such product.")); if (!resolvedProduct->enabled) { throw ErrorInfo(Tr::tr("Cannot run disabled product '%1'.") .arg(resolvedProduct->fullDisplayName())); } } const ResolvedProductPtr resolvedProduct; const TopLevelProjectConstPtr project; InstallOptions installOptions; const QProcessEnvironment environment; const QStringList setupRunEnvConfig; Settings * const settings; Logger logger; RulesEvaluationContext evalContext; }; RunEnvironment::RunEnvironment(const ResolvedProductPtr &product, const TopLevelProjectConstPtr &project, const InstallOptions &installOptions, const QProcessEnvironment &environment, const QStringList &setupRunEnvConfig, Settings *settings, const Logger &logger) : d(std::make_unique(product, project, installOptions, environment, setupRunEnvConfig, settings, logger)) { } RunEnvironment::~RunEnvironment() = default; 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, bool dryRun, ErrorInfo *error) { try { return doRunTarget(targetBin, arguments, dryRun); } 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 {}; } } const QProcessEnvironment RunEnvironment::buildEnvironment(ErrorInfo *error) const { try { return getBuildEnvironment(); } catch (const ErrorInfo &e) { if (error) *error = e; return {}; } } int RunEnvironment::doRunShell() { if (d->resolvedProduct) { EnvironmentScriptRunner(d->resolvedProduct.get(), &d->evalContext, d->project->environment).setupForBuild(); } const QString productId = d->resolvedProduct ? d->resolvedProduct->name : QString(); const QString configName = d->project->id(); if (productId.isEmpty()) { d->logger.qbsInfo() << Tr::tr("Starting shell for configuration '%1'.").arg(configName); } else { d->logger.qbsInfo() << Tr::tr("Starting shell for product '%1' in configuration '%2'.") .arg(productId, configName); } const QProcessEnvironment environment = d->resolvedProduct ? d->resolvedProduct->buildEnvironment : d->project->environment; #if defined(Q_OS_LINUX) || defined(__GLIBC__) clearenv(); #endif const auto keys = environment.keys(); for (const QString &key : keys) qputenv(key.toLocal8Bit().constData(), environment.value(key).toLocal8Bit()); QString command; if (HostOsInfo::isWindowsHost()) { command = environment.value(QStringLiteral("COMSPEC")); if (command.isEmpty()) command = QStringLiteral("cmd"); const QString prompt = environment.value(QStringLiteral("PROMPT")); command += QLatin1String(" /k prompt [qbs] ") + prompt; } else { const QVariantMap qbsProps = (d->resolvedProduct ? d->resolvedProduct->moduleProperties->value() : d->project->buildConfiguration()) .value(StringConstants::qbsModule()).toMap(); const QString profileName = qbsProps.value(StringConstants::profileProperty()).toString(); command = Preferences(d->settings, profileName).shell(); if (command.isEmpty()) command = environment.value(QStringLiteral("SHELL"), QStringLiteral("/bin/sh")); // Yes, we have to use this procedure. PS1 is not inherited from the environment. const QString prompt = QLatin1String("qbs ") + configName + (!productId.isEmpty() ? QLatin1Char(' ') + productId : QString()) + QLatin1String(" $ "); QTemporaryFile envFile; if (envFile.open()) { if (command.endsWith(QLatin1String("bash"))) command += QLatin1String(" --posix"); // Teach bash some manners. const QString promptLine = QLatin1String("PS1='") + prompt + QLatin1String("'\n"); envFile.write(promptLine.toLocal8Bit()); envFile.close(); qputenv("ENV", envFile.fileName().toLocal8Bit()); } else { d->logger.qbsWarning() << Tr::tr("Setting custom shell prompt failed."); } } // We cannot use QProcess, since it does not do stdin forwarding. return system(command.toLocal8Bit().constData()); } static QString findExecutable(const QStringList &fileNames) { const QStringList path = QString::fromLocal8Bit(qgetenv("PATH")) .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); for (const QString &fileName : fileNames) { const QString exeFileName = HostOsInfo::appendExecutableSuffix(fileName); for (const QString &ppath : path) { const QString fullPath = ppath + QLatin1Char('/') + exeFileName; QFileInfo fi(fullPath); if (fi.exists() && fi.isFile() && fi.isExecutable()) return QDir::cleanPath(fullPath); } } return {}; } static std::string readAaptBadgingAttribute(const std::string &line) { std::regex re("^[A-Za-z\\-]+:\\s+name='(.+?)'.*$"); std::smatch match; if (std::regex_match(line, match, re)) return match[1]; return {}; } static QString findMainIntent(const QString &aapt, const QString &apkFilePath) { QString packageId; QString activity; QProcess aaptProcess; aaptProcess.start(aapt, QStringList() << QStringLiteral("dump") << QStringLiteral("badging") << apkFilePath); if (aaptProcess.waitForFinished(-1)) { const auto lines = aaptProcess.readAllStandardOutput().split('\n'); for (const auto &line : lines) { if (line.startsWith(QByteArrayLiteral("package:"))) packageId = QString::fromStdString(readAaptBadgingAttribute(line.toStdString())); else if (line.startsWith(QByteArrayLiteral("launchable-activity:"))) activity = QString::fromStdString(readAaptBadgingAttribute(line.toStdString())); } } if (!packageId.isEmpty() && !activity.isEmpty()) return packageId + QStringLiteral("/") + activity; return {}; } void RunEnvironment::printStartInfo(const QProcess &proc, bool dryRun) { QString message = dryRun ? Tr::tr("Would start target.") : Tr::tr("Starting target."); message.append(QLatin1Char(' ')).append(Tr::tr("Full command line: %1") .arg(shellQuote(QStringList(QDir::toNativeSeparators(proc.program())) << proc.arguments()))); d->logger.qbsInfo() << message; } int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arguments, bool dryRun) { d->checkProduct(); const QStringList targetOS = d->resolvedProduct->moduleProperties->qbsPropertyValue( QStringLiteral("targetOS")).toStringList(); const QStringList toolchain = d->resolvedProduct->moduleProperties->qbsPropertyValue( QStringLiteral("toolchain")).toStringList(); QString targetExecutable = targetBin; QStringList targetArguments = arguments; const QString completeSuffix = QFileInfo(targetBin).completeSuffix(); if (targetOS.contains(QLatin1String("android"))) { const auto aapt = d->resolvedProduct->moduleProperties->moduleProperty( QStringLiteral("Android.sdk"), QStringLiteral("aaptFilePath")).toString(); const auto intent = findMainIntent(aapt, targetBin); const auto sdkDir = d->resolvedProduct->moduleProperties->moduleProperty( QStringLiteral("Android.sdk"), QStringLiteral("sdkDir")).toString(); targetExecutable = sdkDir + QStringLiteral("/platform-tools/adb"); if (!dryRun) { QProcess process; process.setProcessChannelMode(QProcess::ForwardedChannels); process.start(targetExecutable, QStringList() << StringConstants::androidInstallCommand() << QStringLiteral("-r") // replace existing application << QStringLiteral("-t") // allow test packages << QStringLiteral("-d") // allow version code downgrade << targetBin); if (!process.waitForFinished(-1)) { if (process.error() == QProcess::FailedToStart) { throw ErrorInfo(Tr::tr("The process '%1' could not be started: %2") .arg(targetExecutable, process.errorString())); } d->logger.qbsWarning() << "QProcess error: " << process.errorString(); return EXIT_FAILURE; } targetArguments << QStringList() << QStringLiteral("shell") << QStringLiteral("am") << QStringLiteral("start") << QStringLiteral("-W") // wait for launch to complete << QStringLiteral("-n") << intent; } } else if (targetOS.contains(QLatin1String("ios")) || targetOS.contains(QLatin1String("tvos"))) { const QString bundlePath = targetBin + StringConstants::slashDotDot(); if (targetOS.contains(QStringLiteral("ios-simulator")) || targetOS.contains(QStringLiteral("tvos-simulator"))) { const auto developerDir = d->resolvedProduct->moduleProperties->moduleProperty( StringConstants::xcode(), QStringLiteral("developerPath")).toString(); targetExecutable = developerDir + QStringLiteral("/usr/bin/simctl"); const auto simulatorId = QStringLiteral("booted"); // TODO: parameterize const auto bundleId = d->resolvedProduct->moduleProperties->moduleProperty( QStringLiteral("bundle"), QStringLiteral("identifier")).toString(); if (!dryRun) { QProcess process; process.setProcessChannelMode(QProcess::ForwardedChannels); process.start(targetExecutable, QStringList() << StringConstants::simctlInstallCommand() << simulatorId << QDir::cleanPath(bundlePath)); if (!process.waitForFinished(-1)) { if (process.error() == QProcess::FailedToStart) { throw ErrorInfo(Tr::tr("The process '%1' could not be started: %2") .arg(targetExecutable, process.errorString())); } return EXIT_FAILURE; } targetArguments << QStringList() << QStringLiteral("launch") << QStringLiteral("--console") << simulatorId << bundleId << arguments; } } else { if (targetExecutable = findExecutable(QStringList{QStringLiteral("iostool")}); QFileInfo(targetExecutable).isExecutable()) { targetArguments = QStringList() << QStringLiteral("-run") << QStringLiteral("-bundle") << QDir::cleanPath(bundlePath); if (!arguments.empty()) targetArguments << QStringLiteral("-extra-args") << arguments; } else if (targetExecutable = findExecutable(QStringList{QStringLiteral("ios-deploy")}); QFileInfo(targetExecutable).isExecutable()) { targetArguments = QStringList() << QStringLiteral("--no-wifi") << QStringLiteral("--noninteractive") << QStringLiteral("--bundle") << QDir::cleanPath(bundlePath); if (!arguments.empty()) targetArguments << QStringLiteral("--args") << arguments; } else { d->logger.qbsLog(LoggerError) << Tr::tr("No suitable deployment tools were found in the environment. " "Consider installing ios-deploy."); return EXIT_FAILURE; } } } else if (targetOS.contains(QLatin1String("windows"))) { if (completeSuffix == QLatin1String("msi")) { targetExecutable = QLatin1String("msiexec"); targetArguments.prepend(QDir::toNativeSeparators(targetBin)); targetArguments.prepend(QLatin1String("/package")); } // Run Windows executables through Wine when not on Windows if (!HostOsInfo::isWindowsHost()) { targetArguments.prepend(targetExecutable); targetExecutable = QStringLiteral("wine"); } } if (toolchain.contains(QLatin1String("mono"))) { targetArguments.prepend(targetExecutable); targetExecutable = QStringLiteral("mono"); } if (completeSuffix == QLatin1String("js")) { targetExecutable = d->resolvedProduct->moduleProperties->moduleProperty( QStringLiteral("nodejs"), QStringLiteral("interpreterFilePath")).toString(); if (targetExecutable.isEmpty()) // The Node.js binary is called nodejs on Debian/Ubuntu-family operating systems due to // conflict with another package containing a binary named node targetExecutable = findExecutable(QStringList() << QStringLiteral("nodejs") << QStringLiteral("node")); targetArguments.prepend(targetBin); } // Only check if the target is executable if we're not running it through another // known application such as msiexec or wine, as we can't check in this case anyways QFileInfo fi(targetExecutable); if (!dryRun && targetBin == targetExecutable && (!fi.isFile() || !fi.isExecutable())) { d->logger.qbsLog(LoggerError) << Tr::tr("File '%1' is not an executable.") .arg(QDir::toNativeSeparators(targetExecutable)); return EXIT_FAILURE; } QProcessEnvironment env = d->environment; env.insert(QStringLiteral("QBS_RUN_FILE_PATH"), targetBin); EnvironmentScriptRunner(d->resolvedProduct.get(), &d->evalContext, env) .setupForRun(d->setupRunEnvConfig); QProcess process; process.setProcessEnvironment(d->resolvedProduct->runEnvironment); process.setProcessChannelMode(QProcess::ForwardedChannels); process.setProgram(targetExecutable); process.setArguments(targetArguments); printStartInfo(process, dryRun); if (dryRun) return EXIT_SUCCESS; process.start(); if (!process.waitForFinished(-1)) { if (process.error() == QProcess::FailedToStart) { QString errorPrefixString; #ifdef Q_OS_UNIX if (QFileInfo(targetExecutable).isExecutable()) { const QString interpreter(shellInterpreter(targetExecutable)); if (!interpreter.isEmpty()) { errorPrefixString = Tr::tr("%1: bad interpreter: ").arg(interpreter); } } #endif throw ErrorInfo(Tr::tr("The process '%1' could not be started: %2") .arg(targetExecutable, errorPrefixString + process.errorString())); } d->logger.qbsWarning() << "QProcess error: " << process.errorString(); return EXIT_FAILURE; } return process.exitCode(); } const QProcessEnvironment RunEnvironment::getRunEnvironment() const { d->checkProduct(); EnvironmentScriptRunner(d->resolvedProduct.get(), &d->evalContext, d->environment) .setupForRun(d->setupRunEnvConfig); return d->resolvedProduct->runEnvironment; } const QProcessEnvironment RunEnvironment::getBuildEnvironment() const { if (!d->resolvedProduct) return d->environment; EnvironmentScriptRunner(d->resolvedProduct.get(), &d->evalContext, d->environment) .setupForBuild(); return d->resolvedProduct->buildEnvironment; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/projectdata.cpp0000644000175100001660000007545614776170045021222 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "projectdata.h" #include "projectdata_p.h" #include "propertymap_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { using namespace Internal; template static QJsonArray toJsonArray(const QList &list, const QStringList &moduleProperties) { // We can't use transformed from stlutils.h here as QJsonArray has not the reserve() method. QJsonArray jsonArray; transform(list, jsonArray, [&moduleProperties](const T &v) { return v.toJson(moduleProperties);}); return jsonArray; } static QVariant getModuleProperty(const PropertyMap &properties, const QString &fullPropertyName) { const int lastDotIndex = fullPropertyName.lastIndexOf(QLatin1Char('.')); if (lastDotIndex == -1) return {}; return properties.getModuleProperty(fullPropertyName.left(lastDotIndex), fullPropertyName.mid(lastDotIndex + 1)); } static void addModuleProperties(QJsonObject &obj, const PropertyMap &properties, const QStringList &propertyNames) { QJsonObject propertyValues; for (const QString &prop : propertyNames) { const QVariant v = getModuleProperty(properties, prop); if (v.isValid() && !v.isNull()) propertyValues.insert(prop, QJsonValue::fromVariant(v)); } if (!propertyValues.isEmpty()) obj.insert(StringConstants::modulePropertiesKey(), propertyValues); } /*! * \class GroupData * \brief The \c GroupData class corresponds to a Group item in a qbs source file that has its * \c files property set. */ GroupData::GroupData() : d(new GroupDataPrivate) { } GroupData::GroupData(const GroupData &other) = default; GroupData::GroupData(GroupData &&) Q_DECL_NOEXCEPT = default; GroupData &GroupData::operator=(const GroupData &other) = default; GroupData &GroupData::operator=(GroupData &&) Q_DECL_NOEXCEPT = default; GroupData::~GroupData() = default; /*! * \brief Returns true if and only if the Group holds data that was initialized by Qbs. */ bool GroupData::isValid() const { return d->isValid; } QJsonObject GroupData::toJson(const QStringList &moduleProperties) const { QJsonObject obj; if (isValid()) { obj.insert(StringConstants::locationKey(), location().toJson()); obj.insert(StringConstants::nameProperty(), name()); obj.insert(StringConstants::prefixProperty(), prefix()); obj.insert(StringConstants::isEnabledKey(), isEnabled()); obj.insert(QStringLiteral("source-artifacts"), toJsonArray(sourceArtifacts(), {})); obj.insert(QStringLiteral("source-artifacts-from-wildcards"), toJsonArray(sourceArtifactsFromWildcards(), {})); addModuleProperties(obj, properties(), moduleProperties); } return obj; } /*! * \brief The location at which the group is defined in the respective source file. */ CodeLocation GroupData::location() const { return d->location; } /*! * \brief The name of the group. */ QString GroupData::name() const { return d->name; } /*! * \brief The prefix of the group. */ QString GroupData::prefix() const { return d->prefix; } /*! * \brief The files listed in the group item's "files" binding. * \note These do not include expanded wildcards. * \sa GroupData::sourceArtifactsFromWildcards */ QList GroupData::sourceArtifacts() const { return d->sourceArtifacts; } /*! * \brief The list of files resulting from expanding all wildcard patterns in the group. */ QList GroupData::sourceArtifactsFromWildcards() const { return d->sourceArtifactsFromWildcards; } /*! * \brief All files in this group, regardless of how whether they were given explicitly * or via wildcards. * \sa GroupData::sourceArtifacts * \sa GroupData::sourceArtifactsFromWildcards */ QList GroupData::allSourceArtifacts() const { return sourceArtifacts() + sourceArtifactsFromWildcards(); } /*! * \brief The set of properties valid in this group. * Typically, most of them are inherited from the respective \c Product. */ PropertyMap GroupData::properties() const { return d->properties; } /*! * \brief Returns true if this group is enabled in Qbs * This method returns the "condition" property of the \c Group definition. If the group is enabled * then the files in this group will be processed, provided the product it belongs to is also * enabled. * * Note that a group can be enabled, even if the product it belongs to is not. In this case * the files in the group will not be processed. * \sa ProductData::isEnabled() */ bool GroupData::isEnabled() const { QBS_ASSERT(isValid(), return false); return d->isEnabled; } /*! * \brief The paths of all files in this group. * \sa GroupData::allSourceArtifacts */ QStringList GroupData::allFilePaths() const { const QList &artifacts = allSourceArtifacts(); return transformed(artifacts, [](const auto &sa) { return sa.filePath(); }); } bool operator!=(const GroupData &lhs, const GroupData &rhs) { return !(lhs == rhs); } bool operator==(const GroupData &lhs, const GroupData &rhs) { if (!lhs.isValid() && !rhs.isValid()) return true; return lhs.isValid() == rhs.isValid() && lhs.name() == rhs.name() && lhs.location() == rhs.location() && lhs.sourceArtifactsFromWildcards() == rhs.sourceArtifactsFromWildcards() && lhs.sourceArtifacts() == rhs.sourceArtifacts() && lhs.properties() == rhs.properties() && lhs.isEnabled() == rhs.isEnabled(); } bool operator<(const GroupData &lhs, const GroupData &rhs) { return lhs.name() < rhs.name(); } /*! * \class ArtifactData * The \c ArtifactData class describes a file in a product. It is either a source file * or it gets generated during the build process. */ ArtifactData::ArtifactData() : d(new ArtifactDataPrivate) { } ArtifactData::ArtifactData(const ArtifactData &other) = default; ArtifactData::ArtifactData(ArtifactData &&) Q_DECL_NOEXCEPT = default; ArtifactData &ArtifactData::operator=(const ArtifactData &other) = default; ArtifactData &ArtifactData::operator=(ArtifactData &&) Q_DECL_NOEXCEPT = default; ArtifactData::~ArtifactData() = default; /*! * \brief Returns true if and only if this object holds data that was initialized by Qbs. */ bool ArtifactData::isValid() const { return d->isValid; } QJsonObject ArtifactData::toJson(const QStringList &moduleProperties) const { QJsonObject obj; if (isValid()) { obj.insert(StringConstants::filePathKey(), filePath()); obj.insert(QStringLiteral("file-tags"), QJsonArray::fromStringList(fileTags())); obj.insert(QStringLiteral("is-generated"), isGenerated()); obj.insert(QStringLiteral("is-executable"), isExecutable()); obj.insert(QStringLiteral("is-target"), isTargetArtifact()); obj.insert(QStringLiteral("install-data"), installData().toJson()); addModuleProperties(obj, properties(), moduleProperties); } return obj; } /*! * \brief The full path of this file. */ QString ArtifactData::filePath() const { return d->filePath; } /*! * \brief The tags of this file. * Typically, this list will contain just one element. */ QStringList ArtifactData::fileTags() const { return d->fileTags; } bool ArtifactData::isGenerated() const { return d->isGenerated; } /*! * \brief True if and only if this file is executable, * either natively or through an interpreter or shell. */ bool ArtifactData::isExecutable() const { const bool isBundle = d->properties.getModuleProperty( QStringLiteral("bundle"), QStringLiteral("isBundle")).toBool(); const QString androidSdkPackageType = d->properties.getModuleProperty( QStringLiteral("Android.sdk"), QStringLiteral("packageType")).toString(); const bool isAndroidApk = androidSdkPackageType == QStringLiteral("apk"); return isRunnableArtifact(FileTags::fromStringList(d->fileTags), isBundle, isAndroidApk); } /*! * \brief True if and only if this artifact is a target artifact of its product. */ bool ArtifactData::isTargetArtifact() const { QBS_ASSERT(isValid(), return false); return d->isTargetArtifact; } /*! * \brief The properties of this file. */ PropertyMap ArtifactData::properties() const { return d->properties; } /*! \brief The installation-related data of this artifact. */ InstallData ArtifactData::installData() const { return d->installData; } bool operator==(const ArtifactData &ad1, const ArtifactData &ad2) { return ad1.filePath() == ad2.filePath() && ad1.fileTags() == ad2.fileTags() && ad1.isGenerated() == ad2.isGenerated() && ad1.properties() == ad2.properties(); } bool operator!=(const ArtifactData &ta1, const ArtifactData &ta2) { return !(ta1 == ta2); } bool operator<(const ArtifactData &ta1, const ArtifactData &ta2) { return ta1.filePath() < ta2.filePath(); } /*! * \class InstallData * \brief The \c InstallData class provides the installation-related data of an artifact. */ InstallData::InstallData() : d(new InstallDataPrivate) { } InstallData::InstallData(const InstallData &other) = default; InstallData::InstallData(InstallData &&) Q_DECL_NOEXCEPT = default; InstallData &InstallData::operator=(const InstallData &other) = default; InstallData &InstallData::operator=(InstallData &&) Q_DECL_NOEXCEPT = default; InstallData::~InstallData() = default; /*! * \brief Returns true if and only if this object holds data that was initialized by Qbs. */ bool InstallData::isValid() const { return d->isValid; } QJsonObject InstallData::toJson() const { QJsonObject obj; if (isValid()) { obj.insert(QStringLiteral("is-installable"), isInstallable()); if (isInstallable()) { obj.insert(QStringLiteral("install-file-path"), installFilePath()); obj.insert(QStringLiteral("install-root"), installRoot()); } } return obj; } /*! \brief Returns true if and only if \c{qbs.install} is \c true for the artifact. */ bool InstallData::isInstallable() const { QBS_ASSERT(isValid(), return false); return d->isInstallable; } /*! \brief Returns the directory into which the artifact will be installed. \note This is not necessarily the same as \c{qbs.installDir}, because \c{qbs.installSourceBase} might have been used. */ QString InstallData::installDir() const { QBS_ASSERT(isValid(), return {}); return FileInfo::path(installFilePath()); } /*! \brief Returns the installed file path of the artifact. */ QString InstallData::installFilePath() const { QBS_ASSERT(isValid(), return {}); return d->installFilePath; } /*! \brief Returns the value of \c{qbs.installRoot} for the artifact. */ QString InstallData::installRoot() const { QBS_ASSERT(isValid(), return {}); return d->installRoot; } /*! \brief Returns the local installation directory of the artifact, that is \c installDir() prepended by \c installRoot(). */ QString InstallData::localInstallDir() const { return QDir::cleanPath(installRoot() + QLatin1Char('/') + installDir()); } /*! \brief Returns the local installed file path of the artifact, that is \c installFilePath() prepended by \c installRoot(). */ QString InstallData::localInstallFilePath() const { return QDir::cleanPath(installRoot() + QLatin1Char('/') + installFilePath()); } /*! * \class ProductData * \brief The \c ProductData class corresponds to the Product item in a qbs source file. */ ProductData::ProductData() : d(new ProductDataPrivate) { } ProductData::ProductData(const ProductData &other) = default; ProductData::ProductData(ProductData &&) Q_DECL_NOEXCEPT = default; ProductData &ProductData::operator=(const ProductData &other) = default; ProductData &ProductData::operator=(ProductData &&) Q_DECL_NOEXCEPT = default; ProductData::~ProductData() = default; /*! * \brief Returns true if and only if the Product holds data that was initialized by Qbs. */ bool ProductData::isValid() const { return d->isValid; } QJsonObject ProductData::toJson(const QStringList &propertyNames) const { QJsonObject obj; if (!isValid()) return obj; obj.insert(StringConstants::typeProperty(), QJsonArray::fromStringList(type())); obj.insert(StringConstants::dependenciesProperty(), QJsonArray::fromStringList(dependencies())); obj.insert(StringConstants::nameProperty(), name()); obj.insert(StringConstants::fullDisplayNameKey(), fullDisplayName()); obj.insert(QStringLiteral("target-name"), targetName()); obj.insert(StringConstants::versionProperty(), version()); obj.insert(QStringLiteral("multiplex-configuration-id"), multiplexConfigurationId()); obj.insert(StringConstants::locationKey(), location().toJson()); obj.insert(StringConstants::buildDirectoryKey(), buildDirectory()); obj.insert(QStringLiteral("generated-artifacts"), toJsonArray(generatedArtifacts(), propertyNames)); obj.insert(QStringLiteral("target-executable"), targetExecutable()); QJsonArray groupArray; for (const GroupData &g : groups()) { const QStringList groupPropNames = g.properties() == moduleProperties() ? QStringList() : propertyNames; groupArray << g.toJson(groupPropNames); } obj.insert(QStringLiteral("groups"), groupArray); obj.insert(QStringLiteral("properties"), QJsonObject::fromVariantMap(properties())); obj.insert(StringConstants::isEnabledKey(), isEnabled()); obj.insert(QStringLiteral("is-runnable"), isRunnable()); obj.insert(QStringLiteral("is-multiplexed"), isMultiplexed()); addModuleProperties(obj, moduleProperties(), propertyNames); return obj; } /*! * \brief The product type, which is the list of file tags matching the product's target artifacts. */ const QStringList &ProductData::type() const { return d->type; } /*! * \brief The names of dependent products. */ const QStringList &ProductData::dependencies() const { return d->dependencies; } /*! * \brief The name of the product as given in the qbs source file. */ const QString &ProductData::name() const { return d->name; } /*! The name of the product as given in the qbs source file, plus information about which properties it was multiplexed on and the values of these properties. If the product was not multiplexed, the returned value is the same as \c name(). */ QString ProductData::fullDisplayName() const { return fullProductDisplayName(name(), multiplexConfigurationId()); } /*! * \brief The base name of the product's target file as given in the qbs source file. */ const QString &ProductData::targetName() const { return d->targetName; } /*! * \brief The version number of the product. */ const QString &ProductData::version() const { return d->version; } /*! * \brief The profile this product will be built for. */ QString ProductData::profile() const { return d->moduleProperties.getModuleProperty( StringConstants::qbsModule(), StringConstants::profileProperty()).toString(); } const QString &ProductData::multiplexConfigurationId() const { return d->multiplexConfigurationId; } /*! * \brief The location at which the product is defined in the source file. */ const CodeLocation &ProductData::location() const { return d->location; } /*! * \brief The directory under which the product's generated artifacts are located. */ const QString &ProductData::buildDirectory() const { return d->buildDirectory; } /*! * \brief All artifacts that are generated when building this product. */ const QList &ProductData::generatedArtifacts() const { return d->generatedArtifacts; } /*! \brief This product's target artifacts. This is a subset of \c generatedArtifacts() */ const QList ProductData::targetArtifacts() const { QList list; std::copy_if(d->generatedArtifacts.cbegin(), d->generatedArtifacts.cend(), std::back_inserter(list), [](const ArtifactData &a) { return a.isTargetArtifact(); }); return list; } /*! * \brief The list of artifacts in this product that are to be installed. */ const QList ProductData::installableArtifacts() const { QList artifacts; for (const GroupData &g : std::as_const(d->groups)) { const auto sourceArtifacts = g.allSourceArtifacts(); for (const ArtifactData &a : sourceArtifacts) { if (a.installData().isInstallable()) artifacts << a; } } for (const ArtifactData &a : std::as_const(d->generatedArtifacts)) { if (a.installData().isInstallable()) artifacts << a; } return artifacts; } /*! * \brief Returns the file path of the executable associated with this product. * If the product is not an application, an empty string is returned. */ QString ProductData::targetExecutable() const { QBS_ASSERT(isValid(), return {}); if (d->moduleProperties.getModuleProperty(QStringLiteral("bundle"), QStringLiteral("isBundle")).toBool()) { const auto artifacts = targetArtifacts(); for (const ArtifactData &ta : artifacts) { if (ta.fileTags().contains(QLatin1String("bundle.application-executable"))) { if (ta.installData().isInstallable()) return ta.installData().localInstallFilePath(); return ta.filePath(); } } } const auto artifacts = targetArtifacts(); for (const ArtifactData &ta : artifacts) { if (ta.isExecutable()) { if (ta.installData().isInstallable()) return ta.installData().localInstallFilePath(); return ta.filePath(); } } return {}; } /*! * \brief The list of \c GroupData in this product. */ const QList &ProductData::groups() const { return d->groups; } /*! * \brief The product properties. */ const QVariantMap &ProductData::properties() const { return d->properties; } /*! * \brief The set of properties inherited from dependent products and modules. */ const PropertyMap &ProductData::moduleProperties() const { return d->moduleProperties; } /*! * \brief Returns true if this Product is enabled in Qbs. * This method returns the \c condition property of the \c Product definition. If a product is * enabled, then it will be built in the current configuration. * \sa GroupData::isEnabled() */ bool ProductData::isEnabled() const { QBS_ASSERT(isValid(), return false); return d->isEnabled; } bool ProductData::isRunnable() const { QBS_ASSERT(isValid(), return false); return d->isRunnable; } bool ProductData::isMultiplexed() const { QBS_ASSERT(isValid(), return false); return d->isMultiplexed; } bool operator==(const ProductData &lhs, const ProductData &rhs) { if (!lhs.isValid() && !rhs.isValid()) return true; return lhs.isValid() == rhs.isValid() && lhs.name() == rhs.name() && lhs.targetName() == rhs.targetName() && lhs.type() == rhs.type() && lhs.version() == rhs.version() && lhs.dependencies() == rhs.dependencies() && lhs.profile() == rhs.profile() && lhs.multiplexConfigurationId() == rhs.multiplexConfigurationId() && lhs.location() == rhs.location() && lhs.groups() == rhs.groups() && lhs.generatedArtifacts() == rhs.generatedArtifacts() && qVariantMapsEqual(lhs.properties(), rhs.properties()) && lhs.moduleProperties() == rhs.moduleProperties() && lhs.isEnabled() == rhs.isEnabled() && lhs.isMultiplexed() == rhs.isMultiplexed(); } bool operator!=(const ProductData &lhs, const ProductData &rhs) { return !(lhs == rhs); } bool operator<(const ProductData &lhs, const ProductData &rhs) { const int nameCmp = lhs.name().compare(rhs.name()); if (nameCmp < 0) return true; if (nameCmp > 0) return false; return lhs.profile() < rhs.profile() && lhs.multiplexConfigurationId() < rhs.multiplexConfigurationId(); } /*! * \class ProjectData * \brief The \c ProjectData class corresponds to the \c Project item in a qbs source file. */ /*! * \fn QList ProjectData::products() const * \brief The products in this project. */ ProjectData::ProjectData() : d(new ProjectDataPrivate) { } ProjectData::ProjectData(const ProjectData &other) = default; ProjectData::ProjectData(ProjectData &&) Q_DECL_NOEXCEPT = default; ProjectData &ProjectData::operator =(const ProjectData &other) = default; ProjectData &ProjectData::operator=(ProjectData &&) Q_DECL_NOEXCEPT = default; ProjectData::~ProjectData() = default; /*! * \brief Returns true if and only if the Project holds data that was initialized by Qbs. */ bool ProjectData::isValid() const { return d->isValid; } QJsonObject ProjectData::toJson(const QStringList &moduleProperties) const { QJsonObject obj; if (!isValid()) return obj; obj.insert(StringConstants::nameProperty(), name()); obj.insert(StringConstants::locationKey(), location().toJson()); obj.insert(StringConstants::isEnabledKey(), isEnabled()); obj.insert(StringConstants::productsKey(), toJsonArray(products(), moduleProperties)); obj.insert(QStringLiteral("sub-projects"), toJsonArray(subProjects(), moduleProperties)); return obj; } /*! * \brief The name of this project. */ const QString &ProjectData::name() const { return d->name; } /*! * \brief The location at which the project is defined in a qbs source file. */ const CodeLocation &ProjectData::location() const { return d->location; } /*! * \brief Whether the project is enabled. * \note Disabled projects never have any products or sub-projects. */ bool ProjectData::isEnabled() const { QBS_ASSERT(isValid(), return false); return d->enabled; } /*! * \brief The base directory under which the build artifacts of this project will be created. * This is only valid for the top-level project. */ const QString &ProjectData::buildDirectory() const { return d->buildDir; } /*! * The products in this project. * \note This also includes disabled products. */ const QList &ProjectData::products() const { return d->products; } /*! * The sub-projects of this project. */ const QList &ProjectData::subProjects() const { return d->subProjects; } /*! * All products in this projects and its direct and indirect sub-projects. */ const QList ProjectData::allProducts() const { QList productList = products(); for (const ProjectData &pd : std::as_const(d->subProjects)) productList << pd.allProducts(); return productList; } /*! * The artifacts of all products in this project that are to be installed. */ const QList ProjectData::installableArtifacts() const { QList artifacts; const auto products = allProducts(); for (const ProductData &p : products) artifacts << p.installableArtifacts(); return artifacts; } bool operator==(const ProjectData &lhs, const ProjectData &rhs) { if (!lhs.isValid() && !rhs.isValid()) return true; return lhs.isValid() == rhs.isValid() && lhs.isEnabled() == rhs.isEnabled() && lhs.name() == rhs.name() && lhs.buildDirectory() == rhs.buildDirectory() && lhs.location() == rhs.location() && lhs.subProjects() == rhs.subProjects() && lhs.products() == rhs.products(); } bool operator!=(const ProjectData &lhs, const ProjectData &rhs) { return !(lhs == rhs); } bool operator<(const ProjectData &lhs, const ProjectData &rhs) { return lhs.name() < rhs.name(); } /*! * \class PropertyMap * \brief The \c PropertyMap class represents the properties of a group or a product. */ PropertyMap::PropertyMap() : d(std::make_unique()) { static PropertyMapPtr defaultInternalMap = PropertyMapInternal::create(); d->m_map = defaultInternalMap; } PropertyMap::PropertyMap(const PropertyMap &other) : d(std::make_unique(*other.d)) { } PropertyMap::PropertyMap(PropertyMap &&other) Q_DECL_NOEXCEPT = default; PropertyMap::~PropertyMap() = default; PropertyMap &PropertyMap::operator =(const PropertyMap &other) { if (this != &other) d = std::make_unique(*other.d); return *this; } PropertyMap &PropertyMap::operator =(PropertyMap &&other) Q_DECL_NOEXCEPT = default; /*! * \brief Returns the names of all properties. */ QStringList PropertyMap::allProperties() const { QStringList properties; for (QVariantMap::ConstIterator it = d->m_map->value().constBegin(); it != d->m_map->value().constEnd(); ++it) { if (!it.value().canConvert()) properties << it.key(); } return properties; } /*! * \brief Returns the names of all modules whose properties can be requested. */ QStringList PropertyMap::allModules() const { QStringList modules; for (auto it = d->m_map->value().constBegin(); it != d->m_map->value().constEnd(); ++it) { if (it.value().canConvert()) modules << it.key(); } return modules; } /*! * \brief Returns information about all properties of the given module. */ QList PropertyMap::allPropertiesForModule(const QString &module) const { const QVariantMap moduleProps = d->m_map->value().value(module).toMap(); QList properties; const auto builtinProps = transformed( BuiltinDeclarations::instance().declarationsForType(ItemType::Module).properties(), [](const PropertyDeclaration &decl) { return decl.name(); }); for (auto it = moduleProps.begin(); it != moduleProps.end(); ++it) { static const auto getType = [](const QVariant &v) -> QString { switch (qVariantType(v)) { case QMetaType::Bool: return PropertyDeclaration::typeString(PropertyDeclaration::Boolean); case QMetaType::Int: return PropertyDeclaration::typeString(PropertyDeclaration::Integer); case QMetaType::QVariantList: return PropertyDeclaration::typeString(PropertyDeclaration::VariantList); case QMetaType::QString: return PropertyDeclaration::typeString(PropertyDeclaration::String); case QMetaType::QStringList: return PropertyDeclaration::typeString(PropertyDeclaration::StringList); default: return PropertyDeclaration::typeString(PropertyDeclaration::Variant); } }; properties << PropertyInfo{ it.key(), getType(it.value()), it.value(), builtinProps.contains(it.key())}; } return properties; } /*! * \brief Returns the value of the given property of a product or group. */ QVariant PropertyMap::getProperty(const QString &name) const { return d->m_map->value().value(name); } /*! * \brief Convenience wrapper around \c PropertyMap::getModuleProperty for properties of list type. * */ QStringList PropertyMap::getModulePropertiesAsStringList(const QString &moduleName, const QString &propertyName) const { const QVariantList &vl = d->m_map->moduleProperty(moduleName, propertyName).toList(); QStringList sl; for (const QVariant &v : vl) { QBS_ASSERT(v.canConvert(), continue); sl << v.toString(); } return sl; } /*! * \brief Returns the value of the given module property. */ QVariant PropertyMap::getModuleProperty(const QString &moduleName, const QString &propertyName) const { return d->m_map->moduleProperty(moduleName, propertyName); } static QString mapToString(const QVariantMap &map, const QString &prefix) { QString stringRep; for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) { const QString &key = it.key(); const QVariant &val = it.value(); if (val.userType() == QMetaType::QVariantMap) { stringRep += mapToString(val.value(), prefix + key + QLatin1Char('.')); } else { stringRep += QStringLiteral("%1%2: %3\n") .arg(prefix, key, toJSLiteral(val)); } } return stringRep; } QString PropertyMap::toString() const { return mapToString(d->m_map->value(), QString()); } bool operator==(const PropertyMap &pm1, const PropertyMap &pm2) { return *pm1.d->m_map == *pm2.d->m_map; } bool operator!=(const PropertyMap &pm1, const PropertyMap &pm2) { return !(*pm1.d->m_map == *pm2.d->m_map); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/languageinfo.h0000644000175100001660000000426014776170045021007 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LANGUAGEINFO_H #define QBS_LANGUAGEINFO_H #include "../tools/qbs_export.h" #include namespace qbs { class Version; class QBS_EXPORT LanguageInfo { LanguageInfo() = delete; public: static std::string qmlTypeInfo(); static Version qbsVersion(); }; } // namespace qbs #endif // QBS_LANGUAGEINFO_H qbs-src-2.6.1/src/lib/corelib/api/internaljobs.h0000644000175100001660000001522614776170045021046 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_INTERNALJOBS_H #define QBS_INTERNALJOBS_H #include #include #include #include #include #include #include #include #include #include #include namespace qbs { class ProcessResult; class Settings; namespace Internal { class BuildGraphLoadResult; class BuildGraphLocker; class Executor; class JobObserver; class ScriptEngine; class InternalJob : public QObject { Q_OBJECT friend class JobObserver; public: ~InternalJob() override; void cancel(); virtual void start() {} ErrorInfo error() const { return m_error; } void setError(const ErrorInfo &error) { m_error = error; } Logger logger() const { return m_logger; } bool timed() const { return m_timed; } void shareObserverWith(InternalJob *otherJob); protected: explicit InternalJob(Logger logger, QObject *parent = nullptr); JobObserver *observer() const { return m_observer; } void setTimed(bool timed) { m_timed = timed; } void storeBuildGraph(const TopLevelProjectPtr &project); signals: void finished(Internal::InternalJob *job); void newTaskStarted(const QString &description, int totalEffort, Internal::InternalJob *job); void totalEffortChanged(int totalEffort, Internal::InternalJob *job); void taskProgress(int value, Internal::InternalJob *job); private: ErrorInfo m_error; JobObserver *m_observer; bool m_ownsObserver; Logger m_logger; bool m_timed; }; class InternalJobThreadWrapper : public InternalJob { Q_OBJECT public: InternalJobThreadWrapper(InternalJob *synchronousJob, QObject *parent = nullptr); ~InternalJobThreadWrapper() override; void start() override; InternalJob *synchronousJob() const { return m_job; } signals: void startRequested(); private: void handleFinished(); QThread m_thread; InternalJob *m_job; bool m_running; }; class InternalSetupProjectJob : public InternalJob { Q_OBJECT public: InternalSetupProjectJob(const Logger &logger); ~InternalSetupProjectJob() override; void init(const TopLevelProjectPtr &existingProject, const SetupProjectParameters ¶meters); void reportError(const ErrorInfo &error); TopLevelProjectPtr project() const; private: void start() override; void resolveProjectFromScratch(Internal::ScriptEngine *engine); void resolveBuildDataFromScratch(const RulesEvaluationContextPtr &evalContext); BuildGraphLoadResult restoreProject(const RulesEvaluationContextPtr &evalContext); void execute(); TopLevelProjectPtr m_existingProject; TopLevelProjectPtr m_newProject; SetupProjectParameters m_parameters; }; class BuildGraphTouchingJob : public InternalJob { Q_OBJECT public: const QVector &products() const { return m_products; } const TopLevelProjectPtr &project() const { return m_project; } signals: void reportCommandDescription(const QString &highlight, const QString &message); void reportProcessResult(const qbs::ProcessResult &result); protected: BuildGraphTouchingJob(const Logger &logger, QObject *parent = nullptr); ~BuildGraphTouchingJob() override; void setup(const TopLevelProjectPtr &project, const QVector &products, bool dryRun); void storeBuildGraph(); private: TopLevelProjectPtr m_project; QVector m_products; bool m_dryRun; }; class InternalBuildJob : public BuildGraphTouchingJob { Q_OBJECT public: InternalBuildJob(const Logger &logger, QObject *parent = nullptr); void build(const TopLevelProjectPtr &project, const QVector &products, const BuildOptions &buildOptions); private: void handleFinished(); void emitFinished(); Executor *m_executor; }; class InternalCleanJob : public BuildGraphTouchingJob { Q_OBJECT public: InternalCleanJob(const Logger &logger, QObject *parent = nullptr); void init(const TopLevelProjectPtr &project, const QVector &products, const CleanOptions &options); private: void start() override; CleanOptions m_options; }; class InternalInstallJob : public InternalJob { Q_OBJECT public: InternalInstallJob(const Logger &logger); ~InternalInstallJob() override; void init(const TopLevelProjectPtr &project, const QVector &products, const InstallOptions &options); private: void start() override; TopLevelProjectPtr m_project; QVector m_products; InstallOptions m_options; }; } // namespace Internal } // namespace qbs #endif // QBS_INTERNALJOBS_H qbs-src-2.6.1/src/lib/corelib/api/jobs.h0000644000175100001660000001246714776170045017315 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JOBS_H #define QBS_JOBS_H #include "project.h" #include "../language/forward_decls.h" #include "../tools/error.h" #include "../tools/qbs_export.h" #include #include #include namespace qbs { class BuildOptions; class CleanOptions; class InstallOptions; class ProcessResult; class SetupProjectParameters; namespace Internal { class InternalJob; class Logger; class ProjectPrivate; } // namespace Internal class Project; class QBS_EXPORT AbstractJob : public QObject { Q_OBJECT public: ~AbstractJob() override; enum State { StateRunning, StateCanceling, StateFinished }; State state() const { return m_state; } ErrorInfo error() const; public slots: void cancel(); protected: AbstractJob(Internal::InternalJob *internalJob, QObject *parent); Internal::InternalJob *internalJob() const { return m_internalJob; } bool lockProject(const Internal::TopLevelProjectPtr &project); void setError(const ErrorInfo &error) { m_error = error; } signals: void taskStarted(const QString &description, int maximumProgressValue, qbs::AbstractJob *job); void totalEffortChanged(int totalEffort, qbs::AbstractJob *job); void taskProgress(int newProgressValue, qbs::AbstractJob *job); void finished(bool success, qbs::AbstractJob *job); private: void handleTaskStarted(const QString &description, int maximumProgressValue); void handleTotalEffortChanged(int totalEffort); void handleTaskProgress(int newProgressValue); void handleFinished(); void unlockProject(); virtual void finish() { } Internal::InternalJob * const m_internalJob; Internal::TopLevelProjectPtr m_project; ErrorInfo m_error; State m_state; }; class QBS_EXPORT SetupProjectJob : public AbstractJob { Q_OBJECT friend class Project; public: Project project() const; private: SetupProjectJob(const Internal::Logger &logger, QObject *parent); void resolve(const Project &existingProject, const SetupProjectParameters ¶meters); void reportError(const ErrorInfo &error); void finish() override; Project m_existingProject; }; class QBS_EXPORT BuildJob : public AbstractJob { Q_OBJECT friend class Internal::ProjectPrivate; signals: void reportCommandDescription(const QString &highlight, const QString &message); void reportProcessResult(const qbs::ProcessResult &result); private: BuildJob(const Internal::Logger &logger, QObject *parent); void build(const Internal::TopLevelProjectPtr &project, const QVector &products, const BuildOptions &options); void handleLauncherError(const ErrorInfo &error); void finish() override; }; class QBS_EXPORT CleanJob : public AbstractJob { Q_OBJECT friend class Internal::ProjectPrivate; private: CleanJob(const Internal::Logger &logger, QObject *parent); void clean(const Internal::TopLevelProjectPtr &project, const QVector &products, const CleanOptions &options); }; class QBS_EXPORT InstallJob : public AbstractJob { Q_OBJECT friend class Internal::ProjectPrivate; private: InstallJob(const Internal::Logger &logger, QObject *parent); void install(const Internal::TopLevelProjectPtr &project, const QVector &products, const InstallOptions &options); }; } // namespace qbs #endif // QBS_JOBS_H qbs-src-2.6.1/src/lib/corelib/api/jobs.cpp0000644000175100001660000003272614776170045017650 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jobs.h" #include "internaljobs.h" #include "project_p.h" #include #include #include #include #include namespace qbs { using namespace Internal; /*! * \class AbstractJob * \brief The \c AbstractJob class represents an operation relating to a \c Project. * Concrete child classes of \c AbstractJob are created by factory functions in the \c Project * class. The respective objects represent an operation that is started automatically * and is considered "running" until the \c finished() signal has been emitted. Afterwards, * callers can find out whether the operation was successful by calling \c hasError(). While * the operation is going on, progress information is being provided via \c taskStarted() and * \c taskProgress. * Note that though a job is being started automatically by its factory function, you are guaranteed * to recevieve all signals it emits if you connect to it right after getting the object from the * creating function. * \sa Project */ /*! * \enum AbstractJob::State * This enum type specifies which states a job can be in. * \value StateRunning The respective operation is ongoing. * \value StateCanceling The job has been requested to cancel via \c AbstractJob::cancel(), * but the \c AbstractJob::finished() signal has not been emitted yet. * \value StateFinished The operation has finished and the \c AbstractJob::finished() signal * has been emitted. */ /*! * \fn AbstractJob::State AbstractJob::state() const * \brief Returns the current state of the operation. */ /*! * \fn bool AbstractJob::hasError() const * \brief Returns true if the operation has finished with an error, otherwise returns false. * This function should not be called before the \c finished() signal has been emitted. */ /*! * \fn void AbstractJob::taskStarted(const QString &description, int maximumProgressValue, qbs::AbstractJob *job) * \brief Indicates that a new task has been started. * The \a description parameter is a string intended for presentation to a user. * The \a maximumProgressValue parameter indicates the maximum value to which subsequent values of * \c taskProgress() will go. * This signal is typically emitted exactly once for a job that finishes successfully. However, * operations might emit it several times if they are made up of subtasks whose overall effort * cannot be determined in advance. * \sa AbstractJob::taskProgress() */ /*! * \fn void taskProgress(int newProgressValue, qbs::AbstractJob *job) * \brief Indicates progress in executing the operation. * The \a newProgressValue parameter represents the current progress. It is always greater than * zero, strictly increasing and goes up to the \c maximumProgressValue argument of the last * call to \c taskStarted(). * \sa AbstractJob::taskStarted() */ /*! * \fn void finished(bool success, qbs::AbstractJob *job) * \brief Indicates that the operation has finished. * Check the \a success parameter to find out whether everything went fine or an error occurred. */ AbstractJob::AbstractJob(InternalJob *internalJob, QObject *parent) : QObject(parent), m_internalJob(internalJob) { m_internalJob->setParent(this); connect(m_internalJob, &InternalJob::newTaskStarted, this, &AbstractJob::handleTaskStarted, Qt::QueuedConnection); connect(m_internalJob, &InternalJob::totalEffortChanged, this, &AbstractJob::handleTotalEffortChanged); connect(m_internalJob, &InternalJob::taskProgress, this, &AbstractJob::handleTaskProgress, Qt::QueuedConnection); connect(m_internalJob, &InternalJob::finished, this, &AbstractJob::handleFinished); m_state = StateRunning; } bool AbstractJob::lockProject(const TopLevelProjectPtr &project) { // The API is not thread-safe, so we don't need a mutex here, as the API requests come in // synchronously. if (project->locked) { internalJob()->setError(tr("Cannot start a job while another one is in progress.")); QTimer::singleShot(0, this, [this] { emit finished(false, this); }); return false; } project->locked = true; m_project = project; return true; } void AbstractJob::unlockProject() { if (!m_project) return; QBS_ASSERT(m_project->locked, return); m_project->locked = false; } /*! * \brief Destroys the object, canceling the operation if necessary. */ AbstractJob::~AbstractJob() { m_internalJob->disconnect(this); cancel(); } /*! * \brief Returns the error which caused this operation to fail, if it did fail. */ ErrorInfo AbstractJob::error() const { if (m_error.hasError()) return m_error; return internalJob()->error(); } /*! * \brief Cancels this job. * Note that the job might not finish immediately. If you need to make sure it has actually * finished, wait for the \c finished() signal. * \sa AbstractJob::finished(AbstractJob *); */ void AbstractJob::cancel() { if (m_state != StateRunning) return; m_state = StateCanceling; internalJob()->cancel(); } void AbstractJob::handleTaskStarted(const QString &description, int maximumProgressValue) { emit taskStarted(description, maximumProgressValue, this); } void AbstractJob::handleTotalEffortChanged(int totalEffort) { emit totalEffortChanged(totalEffort, this); } void AbstractJob::handleTaskProgress(int newProgressValue) { emit taskProgress(newProgressValue, this); } void AbstractJob::handleFinished() { QBS_ASSERT(m_state != StateFinished, return); finish(); m_state = StateFinished; unlockProject(); emit finished(!error().hasError(), this); } /*! * \class SetupProjectJob * \brief The \c SetupProjectJob class represents an operation that reads a qbs project file and * creates a \c Project object from it. * Note that this job can emit the \c taskStarted() signal more than once. * \sa AbstractJob::taskStarted() */ SetupProjectJob::SetupProjectJob(const Logger &logger, QObject *parent) : AbstractJob(new InternalJobThreadWrapper(new InternalSetupProjectJob(logger)), parent) { if (logger.logSink()->logLevel() == LoggerDebug || logger.logSink()->logLevel() == LoggerTrace) QLoggingCategory::setFilterRules(QStringLiteral("qbs.*.debug=true")); } /*! * \brief Returns the project resulting from this operation. * Note that the result is undefined if the job did not finish successfully. * \sa AbstractJob::hasError() */ Project SetupProjectJob::project() const { auto const wrapper = qobject_cast(internalJob()); auto const job = qobject_cast(wrapper->synchronousJob()); return {job->project(), job->logger()}; } void SetupProjectJob::resolve(const Project &existingProject, const SetupProjectParameters ¶meters) { m_existingProject = existingProject; const TopLevelProjectPtr &existingInternalProject = existingProject.d ? existingProject.d->internalProject : TopLevelProjectPtr(); if (existingInternalProject && !lockProject(existingInternalProject)) return; auto const wrapper = qobject_cast(internalJob()); auto const job = qobject_cast(wrapper->synchronousJob()); job->init(existingInternalProject, parameters); wrapper->start(); } void SetupProjectJob::reportError(const ErrorInfo &error) { auto const wrapper = qobject_cast(internalJob()); auto const job = qobject_cast(wrapper->synchronousJob()); job->reportError(error); } void SetupProjectJob::finish() { // If the new project was successfully created, invalidate the existing one. // The invariant is that there must always be at most one valid Project object // for the same build directory, so that exclusive ownership of the build graph lock // is ensured. // We also need to invalidate the project if an error has occurred after the build data was // already transferred. if (m_existingProject.isValid() && (!error().hasError() || !m_existingProject.d->internalProject->buildData)) { m_existingProject.d->internalProject.reset(); } } /*! * \class ProcessResult * \brief The \c ProcessResult class represents the result of one external program run by Qbs. * * The \c ProcessResult class represents all the information on one external program that was * run by Qbs. It includes the command line used to start the program, the working directory * as well as output and exit codes. */ /*! * \class BuildJob * \brief The \c BuildJob class represents a build operation. */ /*! * \fn void BuildJob::reportCommandDescription(const QString &highlight, const QString &message) * \brief Signals that a new command is being worked on. * The \a highlight parameter is used to decide on the colors and font styles to be used to * print the message. * The \a message parameter is the localized message to print. */ /*! * \fn void BuildJob::reportProcessResult(const qbs::ProcessResult &result) * \brief Signals that an external command has finished. * The \a result parameter contains all details on the process that was run by Qbs. */ BuildJob::BuildJob(const Logger &logger, QObject *parent) : AbstractJob(new InternalBuildJob(logger), parent) { connect(&LauncherInterface::instance(), &LauncherInterface::errorOccurred, this, &BuildJob::handleLauncherError); auto job = static_cast(internalJob()); connect(job, &BuildGraphTouchingJob::reportCommandDescription, this, &BuildJob::reportCommandDescription); connect(job, &BuildGraphTouchingJob::reportProcessResult, this, &BuildJob::reportProcessResult); } void BuildJob::build(const TopLevelProjectPtr &project, const QVector &products, const BuildOptions &options) { if (!lockProject(project)) return; LauncherInterface::startLauncher(); qobject_cast(internalJob())->build(project, products, options); } void BuildJob::handleLauncherError(const ErrorInfo &error) { setError(error); cancel(); } void BuildJob::finish() { LauncherInterface::stopLauncher(); } /*! * \class CleanJob * \brief The \c CleanJob class represents an operation removing build artifacts. */ CleanJob::CleanJob(const Logger &logger, QObject *parent) : AbstractJob(new InternalJobThreadWrapper(new InternalCleanJob(logger)), parent) { } void CleanJob::clean(const TopLevelProjectPtr &project, const QVector &products, const qbs::CleanOptions &options) { if (!lockProject(project)) return; auto wrapper = qobject_cast(internalJob()); qobject_cast(wrapper->synchronousJob())->init(project, products, options); wrapper->start(); } /*! * \class InstallJob * \brief The \c InstallJob class represents an operation installing files. */ InstallJob::InstallJob(const Logger &logger, QObject *parent) : AbstractJob(new InternalJobThreadWrapper(new InternalInstallJob(logger)), parent) { } void InstallJob::install(const TopLevelProjectPtr &project, const QVector &products, const InstallOptions &options) { if (!lockProject(project)) return; auto wrapper = qobject_cast(internalJob()); auto installJob = qobject_cast(wrapper->synchronousJob()); installJob->init(project, products, options); wrapper->start(); } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/projectfileupdater.h0000644000175100001660000001075314776170045022247 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECTFILEUPDATER_H #define QBS_PROJECTFILEUPDATER_H #include "projectdata.h" #include #include #include namespace QbsQmlJS { namespace AST { class UiProgram; } } namespace qbs { namespace Internal { class ProjectFileUpdater { public: virtual ~ProjectFileUpdater(); void apply(); CodeLocation itemPosition() const { return m_itemPosition; } int lineOffset() const { return m_lineOffset; } protected: ProjectFileUpdater(QString projectFile); QString projectFile() const { return m_projectFile; } void setLineOffset(int offset) { m_lineOffset = offset; } void setItemPosition(const CodeLocation &cl) { m_itemPosition = cl; } private: virtual void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) = 0; enum LineEndingType { UnknownLineEndings, UnixLineEndings, WindowsLineEndings, MixedLineEndings }; static LineEndingType guessLineEndingType(const QByteArray &text); static void convertToUnixLineEndings(QByteArray *text, LineEndingType oldLineEndings); static void convertFromUnixLineEndings(QByteArray *text, LineEndingType newLineEndings); const QString m_projectFile; CodeLocation m_itemPosition; int m_lineOffset = 0; }; class ProjectFileGroupInserter : public ProjectFileUpdater { public: ProjectFileGroupInserter(ProductData product, QString groupName); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; const ProductData m_product; const QString m_groupName; }; class ProjectFileFilesAdder : public ProjectFileUpdater { public: ProjectFileFilesAdder(ProductData product, GroupData group, QStringList files); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; const ProductData m_product; const GroupData m_group; const QStringList m_files; }; class ProjectFileFilesRemover : public ProjectFileUpdater { public: ProjectFileFilesRemover(ProductData product, GroupData group, QStringList files); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; const ProductData m_product; const GroupData m_group; const QStringList m_files; }; class ProjectFileGroupRemover : public ProjectFileUpdater { public: ProjectFileGroupRemover(ProductData product, GroupData group); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; const ProductData m_product; const GroupData m_group; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/transformerdata.h0000644000175100001660000000537314776170045021552 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TRANSFORMERDATA_H #define QBS_TRANSFORMERDATA_H #include "projectdata.h" #include "rulecommand.h" #include #include #include namespace qbs { namespace Internal { class ProjectPrivate; class TransformerDataPrivate; } class QBS_EXPORT TransformerData { friend class Internal::ProjectPrivate; public: TransformerData(); TransformerData(const TransformerData &other); ~TransformerData(); TransformerData &operator=(const TransformerData &other); QList inputs() const; QList outputs() const; RuleCommandList commands() const; private: QExplicitlySharedDataPointer d; }; using ProductTransformerData = QList; using ProjectTransformerData = QList>; } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/projectfileupdater.cpp0000644000175100001660000005336114776170045022604 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "projectfileupdater.h" #include "projectdata.h" #include "qmljsrewriter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace QbsQmlJS; using namespace AST; namespace qbs { namespace Internal { class ItemFinder : public Visitor { public: ItemFinder(CodeLocation cl) : m_cl(std::move(cl)), m_item(nullptr) { } UiObjectDefinition *item() const { return m_item; } private: bool visit(UiObjectDefinition *ast) override { if (toCodeLocation(m_cl.filePath(), ast->firstSourceLocation()) == m_cl) { m_item = ast; return false; } return true; } const CodeLocation m_cl; UiObjectDefinition *m_item; }; class FilesBindingFinder : public Visitor { public: FilesBindingFinder(const UiObjectDefinition *startItem) : m_startItem(startItem), m_binding(nullptr) { } UiScriptBinding *binding() const { return m_binding; } private: bool visit(UiObjectDefinition *ast) override { // We start with the direct parent of the binding, so do not descend into any // other item. return ast == m_startItem; } bool visit(UiScriptBinding *ast) override { if (ast->qualifiedId->name.toString() != StringConstants::filesProperty()) return true; m_binding = ast; return false; } const UiObjectDefinition * const m_startItem; UiScriptBinding *m_binding; }; ProjectFileUpdater::ProjectFileUpdater(QString projectFile) : m_projectFile(std::move(projectFile)) { } ProjectFileUpdater::~ProjectFileUpdater() = default; ProjectFileUpdater::LineEndingType ProjectFileUpdater::guessLineEndingType(const QByteArray &text) { char before = 0; int lfCount = 0; int crlfCount = 0; int i = text.indexOf('\n'); while (i != -1) { if (i > 0) before = text.at(i - 1); if (before == '\r') ++crlfCount; else ++lfCount; i = text.indexOf('\n', i + 1); } if (lfCount == 0 && crlfCount == 0) return UnknownLineEndings; if (crlfCount == 0) return UnixLineEndings; if (lfCount == 0) return WindowsLineEndings; return MixedLineEndings; } void ProjectFileUpdater::convertToUnixLineEndings(QByteArray *text, LineEndingType oldLineEndings) { if (oldLineEndings == UnixLineEndings) return; text->replace("\r\n", "\n"); } void ProjectFileUpdater::convertFromUnixLineEndings(QByteArray *text, LineEndingType newLineEndings) { if (newLineEndings == WindowsLineEndings || (newLineEndings != UnixLineEndings && HostOsInfo::isWindowsHost())) { text->replace('\n', "\r\n"); } } void ProjectFileUpdater::apply() { QFile file(m_projectFile); if (!file.open(QFile::ReadOnly)) { throw ErrorInfo(Tr::tr("File '%1' cannot be opened for reading: %2") .arg(m_projectFile, file.errorString())); } QByteArray rawContent = file.readAll(); const LineEndingType origLineEndingType = guessLineEndingType(rawContent); convertToUnixLineEndings(&rawContent, origLineEndingType); QString content = QString::fromUtf8(rawContent); file.close(); Engine engine; Lexer lexer(&engine); lexer.setCode(content, 1); Parser parser(&engine); if (!parser.parse()) { QList parserMessages = parser.diagnosticMessages(); if (!parserMessages.empty()) { ErrorInfo errorInfo; errorInfo.append(Tr::tr("Failure parsing project file.")); for (const DiagnosticMessage &msg : std::as_const(parserMessages)) errorInfo.append(msg.message, toCodeLocation(file.fileName(), msg.loc)); throw errorInfo; } } doApply(content, parser.ast()); if (!file.open(QFile::WriteOnly)) { throw ErrorInfo(Tr::tr("File '%1' cannot be opened for writing: %2") .arg(m_projectFile, file.errorString())); } file.resize(0); rawContent = content.toUtf8(); convertFromUnixLineEndings(&rawContent, origLineEndingType); file.write(rawContent); } ProjectFileGroupInserter::ProjectFileGroupInserter(ProductData product, QString groupName) : ProjectFileUpdater(product.location().filePath()) , m_product(std::move(product)) , m_groupName(std::move(groupName)) { } static int extractLine(const QString &fileContent, int pos) { return QStringView{fileContent}.left(pos).count(QLatin1Char('\n')); } void ProjectFileGroupInserter::doApply(QString &fileContent, UiProgram *ast) { ItemFinder itemFinder(m_product.location()); ast->accept(&itemFinder); if (!itemFinder.item()) { throw ErrorInfo(Tr::tr("The project file parser failed to find the product item."), CodeLocation(projectFile())); } ChangeSet changeSet; Rewriter rewriter(fileContent, &changeSet, QStringList()); QString groupItemString; const int productItemIndentation = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int groupItemIndentation = productItemIndentation + 4; const QString groupItemIndentationString = QString(groupItemIndentation, QLatin1Char(' ')); groupItemString += groupItemIndentationString + QLatin1String("Group {\n"); groupItemString += groupItemIndentationString + groupItemIndentationString + QLatin1String("name: \"") + m_groupName + QLatin1String("\"\n"); groupItemString += groupItemIndentationString + groupItemIndentationString + QLatin1String("files: []\n"); groupItemString += groupItemIndentationString + QLatin1Char('}'); rewriter.addObject(itemFinder.item()->initializer, groupItemString); int lineOffset = 3 + 1; // Our text + a leading newline that is always added by the rewriter. const QList &editOps = changeSet.operationList(); QBS_CHECK(editOps.size() == 1); const ChangeSet::EditOp &insertOp = editOps.front(); setLineOffset(lineOffset); int insertionLine = extractLine(fileContent, insertOp.pos1); for (int i = 0; i < insertOp.text.size() && insertOp.text.at(i) == QLatin1Char('\n'); ++i) ++insertionLine; // To account for newlines prepended by the rewriter. ++insertionLine; // To account for zero-based indexing. setItemPosition(CodeLocation(projectFile(), insertionLine, groupItemIndentation + 1)); changeSet.apply(&fileContent); } static QString getNodeRepresentation(const QString &fileContent, const QbsQmlJS::AST::Node *node) { const quint32 start = node->firstSourceLocation().offset; const quint32 end = node->lastSourceLocation().end(); return fileContent.mid(start, int(end - start)); } static const ChangeSet::EditOp &getEditOp(const ChangeSet &changeSet) { const QList &editOps = changeSet.operationList(); QBS_CHECK(editOps.size() == 1); return editOps.front(); } static int getLineOffsetForChangedBinding(const ChangeSet &changeSet, const QString &oldRhs) { return getEditOp(changeSet).text.count(QLatin1Char('\n')) - oldRhs.count(QLatin1Char('\n')); } static int getBindingLine(const ChangeSet &changeSet, const QString &fileContent) { return extractLine(fileContent, getEditOp(changeSet).pos1 + 1) + 1; } ProjectFileFilesAdder::ProjectFileFilesAdder(ProductData product, GroupData group, QStringList files) : ProjectFileUpdater(product.location().filePath()) , m_product(std::move(product)) , m_group(std::move(group)) , m_files(std::move(files)) { } static QString &addToFilesRepr(QString &filesRepr, const QString &fileRepr, int indentation) { filesRepr += QString(indentation, QLatin1Char(' ')); filesRepr += fileRepr; filesRepr += QLatin1String(",\n"); return filesRepr; } static QString &addToFilesRepr(QString &filesRepr, const QStringList &filePaths, int indentation) { for (const QString &f : filePaths) addToFilesRepr(filesRepr, toJSLiteral(f), indentation); return filesRepr; } static QString &completeFilesRepr(QString &filesRepr, int indentation) { return filesRepr.prepend(QLatin1String("[\n")).append(QString(indentation, QLatin1Char(' '))) .append(QLatin1Char(']')); } void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast) { if (m_files.empty()) return; QStringList sortedFiles = m_files; sortedFiles.sort(); // Find the item containing the "files" binding. ItemFinder itemFinder(m_group.isValid() ? m_group.location() : m_product.location()); ast->accept(&itemFinder); if (!itemFinder.item()) { throw ErrorInfo(Tr::tr("The project file parser failed to find the item."), CodeLocation(projectFile())); } const int itemIndentation = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int bindingIndentation = itemIndentation + 4; const int arrayElemIndentation = bindingIndentation + 4; // Now get the binding itself. FilesBindingFinder bindingFinder(itemFinder.item()); itemFinder.item()->accept(&bindingFinder); ChangeSet changeSet; Rewriter rewriter(fileContent, &changeSet, QStringList()); UiScriptBinding * const filesBinding = bindingFinder.binding(); if (filesBinding) { QString filesRepresentation; if (filesBinding->statement->kind != QbsQmlJS::AST::Node::Kind_ExpressionStatement) throw ErrorInfo(Tr::tr("JavaScript construct in source file is too complex.")); // TODO: rename, add new and concat. const auto exprStatement = static_cast(filesBinding->statement); switch (exprStatement->expression->kind) { case QbsQmlJS::AST::Node::Kind_ArrayLiteral: { auto elem = static_cast(exprStatement->expression)->elements; QStringList oldFileReprs; while (elem) { oldFileReprs << getNodeRepresentation(fileContent, elem->expression); elem = elem->next; } // Insert new files "sorted", but do not change the order of existing files. const QString firstNewFileRepr = toJSLiteral(sortedFiles.front()); while (!oldFileReprs.empty()) { if (oldFileReprs.front() > firstNewFileRepr) break; addToFilesRepr(filesRepresentation, oldFileReprs.takeFirst(), arrayElemIndentation); } addToFilesRepr(filesRepresentation, sortedFiles, arrayElemIndentation); while (!oldFileReprs.empty()) addToFilesRepr(filesRepresentation, oldFileReprs.takeFirst(), arrayElemIndentation); completeFilesRepr(filesRepresentation, bindingIndentation); break; } case QbsQmlJS::AST::Node::Kind_StringLiteral: { const auto existingElement = static_cast(exprStatement->expression)->value.toString(); sortedFiles << existingElement; sortedFiles.sort(); addToFilesRepr(filesRepresentation, sortedFiles, arrayElemIndentation); completeFilesRepr(filesRepresentation, bindingIndentation); break; } default: { // Note that we can often do better than simply concatenating: For instance, // in the case where the existing list is of the form ["a", "b"].concat(myProperty), // we could keep on parsing until we find the array literal and then merge it with // the new files, preventing cascading concat() calls. // But this is not essential and can be implemented when we have some downtime. const QString rhsRepr = getNodeRepresentation(fileContent, exprStatement->expression); addToFilesRepr(filesRepresentation, sortedFiles, arrayElemIndentation); completeFilesRepr(filesRepresentation, bindingIndentation); // It cannot be the other way around, since the existing right-hand side could // have string type. filesRepresentation += QStringLiteral(".concat(%1)").arg(rhsRepr); } } rewriter.changeBinding(itemFinder.item()->initializer, StringConstants::filesProperty(), filesRepresentation, Rewriter::ScriptBinding); } else { // Can happen for the product itself, for which the "files" binding is not mandatory. QString filesRepresentation; addToFilesRepr(filesRepresentation, sortedFiles, arrayElemIndentation); completeFilesRepr(filesRepresentation, bindingIndentation); const QString bindingString = QString(bindingIndentation, QLatin1Char(' ')) + StringConstants::filesProperty(); rewriter.addBinding(itemFinder.item()->initializer, bindingString, filesRepresentation, Rewriter::ScriptBinding); } setLineOffset(getLineOffsetForChangedBinding(changeSet, filesBinding ? getNodeRepresentation(fileContent, filesBinding->statement) : QString())); const int insertionLine = getBindingLine(changeSet, fileContent); const int insertionColumn = (filesBinding ? arrayElemIndentation : bindingIndentation) + 1; setItemPosition(CodeLocation(projectFile(), insertionLine, insertionColumn)); changeSet.apply(&fileContent); } ProjectFileFilesRemover::ProjectFileFilesRemover(ProductData product, GroupData group, QStringList files) : ProjectFileUpdater(product.location().filePath()) , m_product(std::move(product)) , m_group(std::move(group)) , m_files(std::move(files)) { } void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast) { if (m_files.empty()) return; // Find the item containing the "files" binding. ItemFinder itemFinder(m_group.isValid() ? m_group.location() : m_product.location()); ast->accept(&itemFinder); if (!itemFinder.item()) { throw ErrorInfo(Tr::tr("The project file parser failed to find the item."), CodeLocation(projectFile())); } // Now get the binding itself. FilesBindingFinder bindingFinder(itemFinder.item()); itemFinder.item()->accept(&bindingFinder); if (!bindingFinder.binding()) { throw ErrorInfo(Tr::tr("Could not find the 'files' binding in the project file."), m_product.location()); } if (bindingFinder.binding()->statement->kind != QbsQmlJS::AST::Node::Kind_ExpressionStatement) throw ErrorInfo(Tr::tr("JavaScript construct in source file is too complex.")); const CodeLocation bindingLocation = toCodeLocation(projectFile(), bindingFinder.binding()->firstSourceLocation()); ChangeSet changeSet; Rewriter rewriter(fileContent, &changeSet, QStringList()); const int itemIndentation = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int bindingIndentation = itemIndentation + 4; const int arrayElemIndentation = bindingIndentation + 4; const auto exprStatement = static_cast(bindingFinder.binding()->statement); switch (exprStatement->expression->kind) { case QbsQmlJS::AST::Node::Kind_ArrayLiteral: { QStringList filesToRemove = m_files; QStringList newFilesList; auto elem = static_cast(exprStatement->expression)->elements; while (elem) { if (elem->expression->kind != QbsQmlJS::AST::Node::Kind_StringLiteral) { throw ErrorInfo(Tr::tr("JavaScript construct in source file is too complex."), bindingLocation); } const auto existingFile = static_cast(elem->expression)->value.toString(); if (!filesToRemove.removeOne(existingFile)) newFilesList << existingFile; elem = elem->next; } if (!filesToRemove.empty()) { throw ErrorInfo(Tr::tr("The following files were not found in the 'files' list: %1") .arg(filesToRemove.join(QLatin1String(", "))), bindingLocation); } QString filesString; filesString += QLatin1String("[\n"); for (const QString &file : std::as_const(newFilesList)) { filesString += QString(arrayElemIndentation, QLatin1Char(' ')); filesString += QStringLiteral("\"%1\",\n").arg(file); } filesString += QString(bindingIndentation, QLatin1Char(' ')); filesString += QLatin1Char(']'); rewriter.changeBinding(itemFinder.item()->initializer, StringConstants::filesProperty(), filesString, Rewriter::ScriptBinding); break; } case QbsQmlJS::AST::Node::Kind_StringLiteral: { if (m_files.size() != 1) { throw ErrorInfo(Tr::tr("Was requested to remove %1 files, but there is only " "one in the list.").arg(m_files.size()), bindingLocation); } const auto existingFile = static_cast(exprStatement->expression)->value.toString(); if (existingFile != m_files.front()) { throw ErrorInfo(Tr::tr("File '%1' could not be found in the 'files' list.") .arg(m_files.front()), bindingLocation); } rewriter.changeBinding(itemFinder.item()->initializer, StringConstants::filesProperty(), StringConstants::emptyArrayValue(), Rewriter::ScriptBinding); break; } default: throw ErrorInfo(Tr::tr("JavaScript construct in source file is too complex."), bindingLocation); } setLineOffset(getLineOffsetForChangedBinding(changeSet, getNodeRepresentation(fileContent, exprStatement->expression))); const int bindingLine = getBindingLine(changeSet, fileContent); const int bindingColumn = (bindingFinder.binding() ? arrayElemIndentation : bindingIndentation) + 1; setItemPosition(CodeLocation(projectFile(), bindingLine, bindingColumn)); changeSet.apply(&fileContent); } ProjectFileGroupRemover::ProjectFileGroupRemover(ProductData product, GroupData group) : ProjectFileUpdater(product.location().filePath()) , m_product(std::move(product)) , m_group(std::move(group)) { } void ProjectFileGroupRemover::doApply(QString &fileContent, UiProgram *ast) { ItemFinder productFinder(m_product.location()); ast->accept(&productFinder); if (!productFinder.item()) { throw ErrorInfo(Tr::tr("The project file parser failed to find the product item."), CodeLocation(projectFile())); } ItemFinder groupFinder(m_group.location()); productFinder.item()->accept(&groupFinder); if (!groupFinder.item()) { throw ErrorInfo(Tr::tr("The project file parser failed to find the group item."), m_product.location()); } ChangeSet changeSet; Rewriter rewriter(fileContent, &changeSet, QStringList()); rewriter.removeObjectMember(groupFinder.item(), productFinder.item()); setItemPosition(m_group.location()); const QList &editOps = changeSet.operationList(); QBS_CHECK(editOps.size() == 1); const ChangeSet::EditOp &op = editOps.front(); const QString removedText = fileContent.mid(op.pos1, op.length1); setLineOffset(-removedText.count(QLatin1Char('\n'))); changeSet.apply(&fileContent); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/project_p.h0000644000175100001660000001313014776170045020331 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECT_P_H #define QBS_PROJECT_P_H #include "projectdata.h" #include "rulecommand.h" #include "transformerdata.h" #include #include #include #include namespace qbs { class BuildJob; class BuildOptions; class CleanJob; class CleanOptions; class InstallJob; class InstallOptions; namespace Internal { class ProjectPrivate : public QSharedData { public: ProjectPrivate(TopLevelProjectPtr internalProject, Logger logger) : internalProject(std::move(internalProject)), logger(std::move(logger)) { } ProjectData projectData(); BuildJob *buildProducts( const QVector &products, const BuildOptions &options, QObject *jobOwner); CleanJob *cleanProducts(const QVector &products, const CleanOptions &options, QObject *jobOwner); InstallJob *installProducts( const QVector &products, const InstallOptions &options, QObject *jobOwner); QVector internalProducts(const QList &products) const; QVector allEnabledInternalProducts(bool includingNonDefault) const; ResolvedProductPtr internalProduct(const ProductData &product) const; ProductData findProductData(const ProductData &product) const; QList findProductsByName(const QString &name) const; GroupData findGroupData(const ProductData &product, const QString &groupName) const; GroupData createGroupDataFromGroup(const GroupPtr &resolvedGroup, const ResolvedProductConstPtr &product); ArtifactData createApiSourceArtifact(const SourceArtifactConstPtr &sa); ArtifactData createArtifactData(const Artifact *artifact, const ResolvedProductConstPtr &product, const ArtifactSet &targetArtifacts); void setupInstallData(ArtifactData &artifact, const ResolvedProductConstPtr &product); struct GroupUpdateContext { QVector resolvedProducts; QList resolvedGroups; QList products; QList groups; }; struct FileListUpdateContext { GroupUpdateContext groupContext; QStringList absoluteFilePaths; QStringList relativeFilePaths; QStringList absoluteFilePathsFromWildcards; // Not included in the other two lists. }; GroupUpdateContext getGroupContext(const ProductData &product, const GroupData &group); FileListUpdateContext getFileListContext(const ProductData &product, const GroupData &group, const QStringList &filePaths, bool forAdding); void addGroup(const ProductData &product, const QString &groupName); void addFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths); void removeFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths); void removeGroup(const ProductData &product, const GroupData &group); void prepareChangeToProject(); RuleCommandList ruleCommandListForTransformer(const Transformer *transformer); RuleCommandList ruleCommands(const ProductData &product, const QString &inputFilePath, const QString &outputFileTag); ProjectTransformerData transformerData(); TopLevelProjectPtr internalProject; Logger logger; private: void retrieveProjectData(ProjectData &projectData, const ResolvedProjectConstPtr &internalProject); ProjectData m_projectData; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/api/qmljsrewriter.h0000644000175100001660000001251614776170045021265 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSREWRITER_H #define QMLJSREWRITER_H #include "changeset.h" #include #include namespace QbsQmlJS { class Rewriter { public: enum BindingType { ScriptBinding, ObjectBinding, ArrayBinding }; using Range = ChangeSet::Range; public: Rewriter(QString originalText, ChangeSet *changeSet, QStringList propertyOrder); Range addBinding(AST::UiObjectInitializer *ast, const QString &propertyName, const QString &propertyValue, BindingType bindingType); Range addBinding(AST::UiObjectInitializer *ast, const QString &propertyName, const QString &propertyValue, BindingType bindingType, AST::UiObjectMemberList *insertAfter); void changeBinding(AST::UiObjectInitializer *ast, const QString &propertyName, const QString &newValue, BindingType binding); void removeBindingByName(AST::UiObjectInitializer *ast, const QString &propertyName); void appendToArrayBinding(AST::UiArrayBinding *arrayBinding, const QString &content); Range addObject(AST::UiObjectInitializer *ast, const QString &content); Range addObject(AST::UiObjectInitializer *ast, const QString &content, AST::UiObjectMemberList *insertAfter); Range addObject(AST::UiArrayBinding *ast, const QString &content); Range addObject(AST::UiArrayBinding *ast, const QString &content, AST::UiArrayMemberList *insertAfter); void removeObjectMember(AST::UiObjectMember *member, AST::UiObjectMember *parent); static AST::UiObjectMemberList *searchMemberToInsertAfter(AST::UiObjectMemberList *members, const QStringList &propertyOrder); static AST::UiArrayMemberList *searchMemberToInsertAfter(AST::UiArrayMemberList *members, const QStringList &propertyOrder); static AST::UiObjectMemberList *searchMemberToInsertAfter(AST::UiObjectMemberList *members, const QString &propertyName, const QStringList &propertyOrder); static bool includeSurroundingWhitespace(const QString &source, int &start, int &end); static void includeLeadingEmptyLine(QStringView source, int &start); static void includeEmptyGroupedProperty(AST::UiObjectDefinition *groupedProperty, AST::UiObjectMember *memberToBeRemoved, int &start, int &end); private: void replaceMemberValue(AST::UiObjectMember *propertyMember, const QString &newValue, bool needsSemicolon); static bool isMatchingPropertyMember(const QString &propertyName, AST::UiObjectMember *member); static bool nextMemberOnSameLine(AST::UiObjectMemberList *members); void insertIntoArray(AST::UiArrayBinding* ast, const QString &newValue); void removeMember(AST::UiObjectMember *member); void removeGroupedProperty(AST::UiObjectDefinition *ast, const QString &propertyName); void extendToLeadingOrTrailingComma(AST::UiArrayBinding *parentArray, AST::UiObjectMember *member, int &start, int &end) const; private: QString m_originalText; ChangeSet *m_changeSet; const QStringList m_propertyOrder; }; } // namespace QbsQmlJS #endif // QMLJSREWRITER_H qbs-src-2.6.1/src/lib/corelib/api/languageinfo.cpp0000644000175100001660000001243114776170045021341 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "languageinfo.h" #include #include #include #include namespace qbs { std::string LanguageInfo::qmlTypeInfo() { const Internal::BuiltinDeclarations &builtins = Internal::BuiltinDeclarations::instance(); // Header: std::string result; result.append("import QtQuick.tooling 1.0\n\n"); result.append("// This file describes the plugin-supplied types contained in the library.\n"); result.append("// It is used for QML tooling purposes only.\n\n"); result.append("Module {\n"); // Individual Components: auto typeNames = builtins.allTypeNames(); typeNames.sort(); for (const QString &typeName : std::as_const(typeNames)) { const auto typeNameString = typeName.toStdString(); result.append(" Component {\n"); result.append(" name: \"" + typeNameString + "\"\n"); result.append(" exports: [ \"qbs/"); result.append(typeNameString); result.append(" "); const auto v = builtins.languageVersion(); result.append(QStringLiteral("%1.%2") .arg(v.majorVersion()).arg(v.minorVersion()).toUtf8().data()); result.append("\" ]\n"); result.append(" prototype: \"QQuickItem\"\n"); Internal::ItemDeclaration itemDecl = builtins.declarationsForType(builtins.typeForName(typeName)); const auto properties = Internal::sorted( itemDecl.properties(), [](const auto &lhs, const auto &rhs) { return lhs.name() < rhs.name(); }); for (const Internal::PropertyDeclaration &property : properties) { result.append(" Property { name: \""); result.append(property.name().toUtf8().data()); result.append("\"; "); switch (property.type()) { case qbs::Internal::PropertyDeclaration::UnknownType: result.append("type: \"unknown\""); break; case qbs::Internal::PropertyDeclaration::Boolean: result.append("type: \"bool\""); break; case qbs::Internal::PropertyDeclaration::Integer: result.append("type: \"int\""); break; case qbs::Internal::PropertyDeclaration::Path: result.append("type: \"string\""); break; case qbs::Internal::PropertyDeclaration::PathList: result.append("type: \"string\"; isList: true"); break; case qbs::Internal::PropertyDeclaration::String: result.append("type: \"string\""); break; case qbs::Internal::PropertyDeclaration::StringList: result.append("type: \"string\"; isList: true"); break; case qbs::Internal::PropertyDeclaration::Variant: result.append("type: \"QVariant\""); break; case qbs::Internal::PropertyDeclaration::VariantList: result.append("type: \"QVariantList\""); break; } result.append(" }\n"); // Property } result.append(" }\n"); // Component } // Footer: result.append("}\n"); // Module return result; } Version LanguageInfo::qbsVersion() { static const auto v = Version::fromString(QLatin1String(QBS_VERSION)); return v; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/propertymap_p.h0000644000175100001660000000415314776170045021252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROPERTYMAP_P_H #define QBS_PROPERTYMAP_P_H #include namespace qbs { namespace Internal { class PropertyMapPrivate { public: PropertyMapPtr m_map; }; } // namespace Internal } // namespace qbs #endif // QBS_PROPERTYMAP_P_H qbs-src-2.6.1/src/lib/corelib/api/projectdata_p.h0000644000175100001660000001012514776170045021164 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECTDATA_P_H #define QBS_PROJECTDATA_P_H #include "projectdata.h" #include #include namespace qbs { namespace Internal { class InstallDataPrivate : public QSharedData { public: QString installFilePath; QString installRoot; bool isValid = false; bool isInstallable = false; }; class ArtifactDataPrivate : public QSharedData { public: QString filePath; QStringList fileTags; PropertyMap properties; InstallData installData; bool isValid = false; bool isGenerated = false; bool isTargetArtifact = false; }; class GroupDataPrivate : public QSharedData { public: QString name; QString prefix; CodeLocation location; QList sourceArtifacts; QList sourceArtifactsFromWildcards; PropertyMap properties; bool isEnabled = false; bool isValid = false; }; class InstallableFilePrivate: public QSharedData { public: QString sourceFilePath; QString targetFilePath; QStringList fileTags; bool isValid = false; }; class ProductDataPrivate : public QSharedData { public: QStringList type; QStringList dependencies; QString name; QString targetName; QString version; QString multiplexConfigurationId; CodeLocation location; QString buildDirectory; QList groups; QVariantMap properties; PropertyMap moduleProperties; QList generatedArtifacts; bool isEnabled = false; bool isRunnable = false; bool isMultiplexed = false; bool isValid = false; }; class ProjectDataPrivate : public QSharedData { public: QString name; CodeLocation location; bool enabled = false; bool isValid = false; QList products; QList subProjects; QString buildDir; }; inline bool isRunnableArtifact(const FileTags &fileTags, bool isBundle, bool isAndroidApk) { return (fileTags.contains("application") && (!isBundle || fileTags.contains("bundle.content"))) || fileTags.contains("bundle.application-executable") || (fileTags.contains("android.package") && isAndroidApk) || fileTags.contains("msi"); } } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/project.cpp0000644000175100001660000013250514776170045020355 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "project.h" #include "project_p.h" #include "internaljobs.h" #include "jobs.h" #include "projectdata_p.h" #include "projectfileupdater.h" #include "propertymap_p.h" #include "rulecommand_p.h" #include "runenvironment.h" #include "transformerdata_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static bool pluginsLoaded = false; static std::mutex pluginsLoadedMutex; static void loadPlugins(const QStringList &_pluginPaths, const Logger &logger) { std::lock_guard locker(pluginsLoadedMutex); if (pluginsLoaded) return; std::vector pluginPaths; for (const QString &pluginPath : _pluginPaths) { if (!FileInfo::exists(pluginPath)) { #ifndef QBS_STATIC_LIB logger.qbsWarning() << Tr::tr("Plugin path '%1' does not exist.") .arg(QDir::toNativeSeparators(pluginPath)); #endif } else { pluginPaths.push_back(pluginPath.toStdString()); } } auto pluginManager = QbsPluginManager::instance(); pluginManager->loadStaticPlugins(); pluginManager->loadPlugins(pluginPaths, logger); qRegisterMetaType("qbs::ErrorInfo"); qRegisterMetaType("qbs::ProcessResult"); qRegisterMetaType("Internal::InternalJob *"); qRegisterMetaType("qbs::AbstractJob *"); pluginsLoaded = true; } ProjectData ProjectPrivate::projectData() { m_projectData = ProjectData(); retrieveProjectData(m_projectData, internalProject); m_projectData.d->buildDir = internalProject->buildDirectory; return m_projectData; } BuildJob *ProjectPrivate::buildProducts( const QVector &products, const BuildOptions &options, QObject *jobOwner) { const auto job = new BuildJob(logger, jobOwner); job->build(internalProject, products, options); QBS_ASSERT(job->state() == AbstractJob::StateRunning,); return job; } CleanJob *ProjectPrivate::cleanProducts(const QVector &products, const CleanOptions &options, QObject *jobOwner) { const auto job = new CleanJob(logger, jobOwner); job->clean(internalProject, products, options); QBS_ASSERT(job->state() == AbstractJob::StateRunning,); return job; } InstallJob *ProjectPrivate::installProducts( const QVector &products, const InstallOptions &options, QObject *jobOwner) { const auto job = new InstallJob(logger, jobOwner); job->install(internalProject, products, options); QBS_ASSERT(job->state() == AbstractJob::StateRunning,); return job; } QVector ProjectPrivate::internalProducts(const QList &products) const { QVector internalProducts; for (const ProductData &product : products) { if (product.isEnabled()) internalProducts.push_back(internalProduct(product)); } return internalProducts; } static QVector enabledInternalProducts(const ResolvedProjectConstPtr &project, bool includingNonDefault) { QVector products; for (const ResolvedProductPtr &p : project->products) { if (p->enabled && (includingNonDefault || p->builtByDefault())) products.push_back(p); } for (const auto &subProject : std::as_const(project->subProjects)) products << enabledInternalProducts(subProject, includingNonDefault); return products; } QVector ProjectPrivate::allEnabledInternalProducts( bool includingNonDefault) const { return enabledInternalProducts(internalProject, includingNonDefault); } static bool matches(const ProductData &product, const ResolvedProductConstPtr &rproduct) { return product.name() == rproduct->name && product.multiplexConfigurationId() == rproduct->multiplexConfigurationId; } static ResolvedProductPtr internalProductForProject(const ResolvedProjectConstPtr &project, const ProductData &product) { for (const ResolvedProductPtr &resolvedProduct : project->products) { if (matches(product, resolvedProduct)) return resolvedProduct; } for (const auto &subProject : std::as_const(project->subProjects)) { const ResolvedProductPtr &p = internalProductForProject(subProject, product); if (p) return p; } return {}; } ResolvedProductPtr ProjectPrivate::internalProduct(const ProductData &product) const { return internalProductForProject(internalProject, product); } ProductData ProjectPrivate::findProductData(const ProductData &product) const { for (const ProductData &p : m_projectData.allProducts()) { if (p.name() == product.name() && p.profile() == product.profile() && p.multiplexConfigurationId() == product.multiplexConfigurationId()) { return p; } } return {}; } QList ProjectPrivate::findProductsByName(const QString &name) const { QList list; for (const ProductData &p : m_projectData.allProducts()) { if (p.name() == name) list.push_back(p); } return list; } GroupData ProjectPrivate::findGroupData(const ProductData &product, const QString &groupName) const { for (const GroupData &g : product.groups()) { if (g.name() == groupName) return g; } return {}; } GroupData ProjectPrivate::createGroupDataFromGroup(const GroupPtr &resolvedGroup, const ResolvedProductConstPtr &product) { GroupData group; group.d->name = resolvedGroup->name; group.d->prefix = resolvedGroup->prefix; group.d->location = resolvedGroup->location; QBS_ASSERT(resolvedGroup->files, return group); for (const auto &sa : *resolvedGroup->files) { ArtifactData artifact = createApiSourceArtifact(sa); setupInstallData(artifact, product); if (sa->fromWildcard) group.d->sourceArtifactsFromWildcards.push_back(artifact); else group.d->sourceArtifacts.push_back(artifact); } std::sort(group.d->sourceArtifacts.begin(), group.d->sourceArtifacts.end()); std::sort(group.d->sourceArtifactsFromWildcards.begin(), group.d->sourceArtifactsFromWildcards.end()); group.d->properties.d->m_map = resolvedGroup->properties; group.d->isEnabled = resolvedGroup->enabled; group.d->isValid = true; return group; } ArtifactData ProjectPrivate::createApiSourceArtifact(const SourceArtifactConstPtr &sa) { ArtifactData saApi; saApi.d->isValid = true; saApi.d->filePath = sa->absoluteFilePath; saApi.d->fileTags = sa->fileTags.toStringList(); saApi.d->isGenerated = false; saApi.d->isTargetArtifact = false; saApi.d->properties.d->m_map = sa->properties; return saApi; } ArtifactData ProjectPrivate::createArtifactData(const Artifact *artifact, const ResolvedProductConstPtr &product, const ArtifactSet &targetArtifacts) { ArtifactData ta; ta.d->filePath = artifact->filePath(); ta.d->fileTags = artifact->fileTags().toStringList(); ta.d->properties.d->m_map = artifact->properties; ta.d->isGenerated = artifact->artifactType == Artifact::Generated; ta.d->isTargetArtifact = targetArtifacts.contains(const_cast(artifact)); ta.d->isValid = true; setupInstallData(ta, product); return ta; } void ProjectPrivate::setupInstallData(ArtifactData &artifact, const ResolvedProductConstPtr &product) { artifact.d->installData.d->isValid = true; artifact.d->installData.d->isInstallable = artifact.properties().getModuleProperty( StringConstants::qbsModule(), StringConstants::installProperty()).toBool(); if (!artifact.d->installData.d->isInstallable) return; const QString installRoot = artifact.properties().getModuleProperty( StringConstants::qbsModule(), StringConstants::installRootProperty()).toString(); InstallOptions options; options.setInstallRoot(installRoot); artifact.d->installData.d->installRoot = installRoot; try { QString installFilePath = ProductInstaller::targetFilePath(product->topLevelProject(), product->sourceDirectory, artifact.filePath(), artifact.properties().d->m_map, options); if (!installRoot.isEmpty()) installFilePath.remove(0, installRoot.size()); artifact.d->installData.d->installFilePath = installFilePath; } catch (const ErrorInfo &e) { logger.printWarning(e); } } void ProjectPrivate::addGroup(const ProductData &product, const QString &groupName) { if (groupName.isEmpty()) throw ErrorInfo(Tr::tr("Group has an empty name.")); if (!product.isValid()) throw ErrorInfo(Tr::tr("Product is invalid.")); QList products = findProductsByName(product.name()); if (products.empty()) throw ErrorInfo(Tr::tr("Product '%1' does not exist.").arg(product.name())); const auto resolvedProducts = internalProducts(products); QBS_CHECK(products.size() == resolvedProducts.size()); for (const GroupPtr &resolvedGroup : resolvedProducts.front()->groups) { if (resolvedGroup->name == groupName) { throw ErrorInfo(Tr::tr("Group '%1' already exists in product '%2'.") .arg(groupName, product.name()), resolvedGroup->location); } } ProjectFileGroupInserter groupInserter(products.front(), groupName); groupInserter.apply(); } ProjectPrivate::GroupUpdateContext ProjectPrivate::getGroupContext(const ProductData &product, const GroupData &group) { GroupUpdateContext context; if (!product.isValid()) throw ErrorInfo(Tr::tr("Product is invalid.")); context.products = findProductsByName(product.name()); if (context.products.empty()) throw ErrorInfo(Tr::tr("Product '%1' does not exist.").arg(product.name())); context.resolvedProducts = internalProducts(context.products); const QString groupName = group.isValid() ? group.name() : product.name(); for (const ResolvedProductPtr &p : std::as_const(context.resolvedProducts)) { for (const GroupPtr &g : p->groups) { if (g->name == groupName) { context.resolvedGroups << g; break; } } } if (context.resolvedGroups.empty()) throw ErrorInfo(Tr::tr("Group '%1' does not exist.").arg(groupName)); for (const ProductData &p : std::as_const(context.products)) { const GroupData &g = findGroupData(p, groupName); QBS_CHECK(p.isValid()); context.groups << g; } QBS_CHECK(context.resolvedProducts.size() == context.products.size()); QBS_CHECK(context.resolvedProducts.size() == context.resolvedGroups.size()); QBS_CHECK(context.products.size() == context.groups.size()); return context; } static bool matchesWildcard(const QString &filePath, const GroupConstPtr &group) { if (!group->wildcards) return false; for (const QString &pattern : std::as_const(group->wildcards->patterns)) { QString fullPattern; if (QFileInfo(group->prefix).isAbsolute()) { fullPattern = group->prefix; } else { fullPattern = QFileInfo(group->location.filePath()).absolutePath() + QLatin1Char('/') + group->prefix; } fullPattern.append(QLatin1Char('/')).append(pattern); fullPattern = QDir::cleanPath(fullPattern); if (QRegularExpression(QRegularExpression::wildcardToRegularExpression(fullPattern)).match(filePath).hasMatch()) return true; } return false; } ProjectPrivate::FileListUpdateContext ProjectPrivate::getFileListContext(const ProductData &product, const GroupData &group, const QStringList &filePaths, bool forAdding) { FileListUpdateContext filesContext; GroupUpdateContext &groupContext = filesContext.groupContext; groupContext = getGroupContext(product, group); if (filePaths.empty()) throw ErrorInfo(Tr::tr("No files supplied.")); QString prefix; for (int i = 0; i < groupContext.resolvedGroups.size(); ++i) { const GroupPtr &g = groupContext.resolvedGroups.at(i); if (!g->prefix.isEmpty() && !g->prefix.endsWith(QLatin1Char('/'))) throw ErrorInfo(Tr::tr("Group has non-directory prefix.")); if (i == 0) prefix = g->prefix; else if (prefix != g->prefix) throw ErrorInfo(Tr::tr("Cannot update: Group prefix depends on properties.")); } QString baseDirPath = QFileInfo(product.location().filePath()).dir().absolutePath() + QLatin1Char('/') + prefix; QDir baseDir(baseDirPath); for (const QString &filePath : filePaths) { const QString absPath = QDir::cleanPath(FileInfo::resolvePath(baseDirPath, filePath)); if (filesContext.absoluteFilePaths.contains(absPath)) throw ErrorInfo(Tr::tr("File '%1' appears more than once.").arg(absPath)); if (forAdding && !FileInfo(absPath).exists()) throw ErrorInfo(Tr::tr("File '%1' does not exist.").arg(absPath)); if (matchesWildcard(absPath, groupContext.resolvedGroups.front())) { filesContext.absoluteFilePathsFromWildcards << absPath; } else { filesContext.absoluteFilePaths << absPath; filesContext.relativeFilePaths << baseDir.relativeFilePath(absPath); } } return filesContext; } void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths) { FileListUpdateContext filesContext = getFileListContext(product, group, filePaths, true); GroupUpdateContext &groupContext = filesContext.groupContext; // We do not check for entries in other groups, because such doublettes might be legitimate // due to conditions. for (const GroupPtr &group : std::as_const(groupContext.resolvedGroups)) { for (const QString &filePath : std::as_const(filesContext.absoluteFilePaths)) { if (group->files) { for (const auto &sa : *group->files) { if (sa->absoluteFilePath == filePath) { throw ErrorInfo(Tr::tr("File '%1' already exists in group '%2'.") .arg(filePath, group->name)); } } } } } ProjectFileFilesAdder adder(groupContext.products.front(), group.isValid() ? groupContext.groups.front() : GroupData(), filesContext.relativeFilePaths); adder.apply(); } void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths) { FileListUpdateContext filesContext = getFileListContext(product, group, filePaths, false); GroupUpdateContext &groupContext = filesContext.groupContext; if (!filesContext.absoluteFilePathsFromWildcards.empty()) { throw ErrorInfo(Tr::tr("The following files cannot be removed from the project file, " "because they match wildcard patterns: %1") .arg(filesContext.absoluteFilePathsFromWildcards.join(QLatin1String(", ")))); } QStringList filesNotFound = filesContext.absoluteFilePaths; std::vector sourceArtifacts; QBS_ASSERT(groupContext.resolvedGroups.front()->files, return); for (const SourceArtifactPtr &sa : *groupContext.resolvedGroups.front()->files) { if (filesNotFound.removeOne(sa->absoluteFilePath)) sourceArtifacts << sa; } if (!filesNotFound.empty()) { throw ErrorInfo(Tr::tr("The following files are not known to qbs: %1") .arg(filesNotFound.join(QLatin1String(", ")))); } ProjectFileFilesRemover remover(groupContext.products.front(), group.isValid() ? groupContext.groups.front() : GroupData(), filesContext.relativeFilePaths); remover.apply(); } void ProjectPrivate::removeGroup(const ProductData &product, const GroupData &group) { GroupUpdateContext context = getGroupContext(product, group); ProjectFileGroupRemover remover(context.products.front(), context.groups.front()); remover.apply(); } void ProjectPrivate::prepareChangeToProject() { if (internalProject->locked) throw ErrorInfo(Tr::tr("A job is currently in progress.")); if (!m_projectData.isValid()) retrieveProjectData(m_projectData, internalProject); } RuleCommandList ProjectPrivate::ruleCommandListForTransformer(const Transformer *transformer) { RuleCommandList list; for (const AbstractCommandPtr &internalCommand : std::as_const(transformer->commands.commands())) { RuleCommand externalCommand; externalCommand.d->description = internalCommand->description(); externalCommand.d->extendedDescription = internalCommand->extendedDescription(); switch (internalCommand->type()) { case AbstractCommand::JavaScriptCommandType: { externalCommand.d->type = RuleCommand::JavaScriptCommandType; const JavaScriptCommandPtr &jsCmd = std::static_pointer_cast(internalCommand); externalCommand.d->sourceCode = jsCmd->sourceCode(); break; } case AbstractCommand::ProcessCommandType: { externalCommand.d->type = RuleCommand::ProcessCommandType; const ProcessCommandPtr &procCmd = std::static_pointer_cast(internalCommand); externalCommand.d->executable = procCmd->program(); externalCommand.d->arguments = procCmd->arguments(); externalCommand.d->workingDir = procCmd->workingDir(); externalCommand.d->environment = procCmd->environment(); break; } } list << externalCommand; } return list; } RuleCommandList ProjectPrivate::ruleCommands(const ProductData &product, const QString &inputFilePath, const QString &outputFileTag) { if (internalProject->locked) throw ErrorInfo(Tr::tr("A job is currently in progress.")); const ResolvedProductConstPtr resolvedProduct = internalProduct(product); if (!resolvedProduct) throw ErrorInfo(Tr::tr("No such product '%1'.").arg(product.name())); if (!resolvedProduct->enabled) throw ErrorInfo(Tr::tr("Product '%1' is disabled.").arg(product.name())); QBS_CHECK(resolvedProduct->buildData); const ArtifactSet &outputArtifacts = resolvedProduct->buildData->artifactsByFileTag() .value(FileTag(outputFileTag.toLocal8Bit())); for (const Artifact * const outputArtifact : std::as_const(outputArtifacts)) { const TransformerConstPtr transformer = outputArtifact->transformer; if (!transformer) continue; for (const Artifact * const inputArtifact : std::as_const(transformer->inputs)) { if (inputArtifact->filePath() == inputFilePath) return ruleCommandListForTransformer(transformer.get()); } } throw ErrorInfo(Tr::tr("No rule was found that produces an artifact tagged '%1' " "from input file '%2'.").arg(outputFileTag, inputFilePath)); } ProjectTransformerData ProjectPrivate::transformerData() { if (!m_projectData.isValid()) retrieveProjectData(m_projectData, internalProject); ProjectTransformerData projectTransformerData; for (const ProductData &productData : m_projectData.allProducts()) { if (!productData.isEnabled()) continue; const ResolvedProductConstPtr product = internalProduct(productData); QBS_ASSERT(!!product, continue); QBS_ASSERT(!!product->buildData, continue); const ArtifactSet targetArtifacts = product->targetArtifacts(); Set allTransformers; for (const Artifact * const a : TypeFilter(product->buildData->allNodes())) { if (a->artifactType == Artifact::Generated) allTransformers.insert(a->transformer.get()); } if (allTransformers.empty()) continue; ProductTransformerData productTransformerData; for (const Transformer * const t : allTransformers) { TransformerData tData; Set allInputs; for (Artifact * const a : t->outputs) { tData.d->outputs << createArtifactData(a, product, targetArtifacts); for (const Artifact * const child : filterByType(a->children)) allInputs << child; } for (const Artifact * const input : allInputs) tData.d->inputs << createArtifactData(input, product, targetArtifacts); tData.d->commands = ruleCommandListForTransformer(t); productTransformerData << tData; } projectTransformerData << qMakePair(productData, productTransformerData); } return projectTransformerData; } static bool productIsRunnable(const ResolvedProductConstPtr &product) { const bool isBundle = product->moduleProperties->moduleProperty( QStringLiteral("bundle"), QStringLiteral("isBundle")).toBool(); const QString androidSdkPackageType = product->moduleProperties->moduleProperty( QStringLiteral("Android.sdk"), QStringLiteral("packageType")).toString(); const bool isAndroidApk = androidSdkPackageType == QStringLiteral("apk"); return isRunnableArtifact(product->fileTags, isBundle, isAndroidApk); } static bool productIsMultiplexed(const ResolvedProductConstPtr &product) { return product->productProperties.value(StringConstants::multiplexedProperty()).toBool(); } void ProjectPrivate::retrieveProjectData(ProjectData &projectData, const ResolvedProjectConstPtr &internalProject) { projectData.d->name = internalProject->name; projectData.d->location = internalProject->location; projectData.d->enabled = internalProject->enabled; for (const auto &resolvedProduct : internalProject->products) { ProductData product; product.d->type = resolvedProduct->fileTags.toStringList(); product.d->name = resolvedProduct->name; product.d->targetName = resolvedProduct->targetName; product.d->version = resolvedProduct ->productProperties.value(StringConstants::versionProperty()).toString(); product.d->multiplexConfigurationId = resolvedProduct->multiplexConfigurationId; product.d->location = resolvedProduct->location; product.d->buildDirectory = resolvedProduct->buildDirectory(); product.d->isEnabled = resolvedProduct->enabled; product.d->isRunnable = productIsRunnable(resolvedProduct); product.d->isMultiplexed = productIsMultiplexed(resolvedProduct); product.d->properties = resolvedProduct->productProperties; product.d->moduleProperties.d->m_map = resolvedProduct->moduleProperties; for (const GroupPtr &resolvedGroup : resolvedProduct->groups) { if (resolvedGroup->targetOfModule.isEmpty() && resolvedGroup->files) { product.d->groups << createGroupDataFromGroup(resolvedGroup, resolvedProduct); } } if (resolvedProduct->enabled) { QBS_CHECK(resolvedProduct->buildData); const ArtifactSet targetArtifacts = resolvedProduct->targetArtifacts(); for (Artifact * const a : filterByType(resolvedProduct->buildData->allNodes())) { if (a->artifactType != Artifact::Generated) continue; product.d->generatedArtifacts << createArtifactData(a, resolvedProduct, targetArtifacts); } const AllRescuableArtifactData &rad = resolvedProduct->buildData->rescuableArtifactData(); for (auto it = rad.begin(); it != rad.end(); ++it) { ArtifactData ta; ta.d->filePath = it.key(); ta.d->fileTags = it.value().fileTags.toStringList(); ta.d->properties.d->m_map = it.value().properties; ta.d->isGenerated = true; ta.d->isTargetArtifact = resolvedProduct->fileTags.intersects(it.value().fileTags); ta.d->isValid = true; setupInstallData(ta, resolvedProduct); product.d->generatedArtifacts << ta; } } for (const ResolvedProductPtr &resolvedDependentProduct : std::as_const(resolvedProduct->dependencies)) { product.d->dependencies << resolvedDependentProduct->fullDisplayName(); } std::sort(product.d->type.begin(), product.d->type.end()); std::sort(product.d->groups.begin(), product.d->groups.end()); std::sort(product.d->generatedArtifacts.begin(), product.d->generatedArtifacts.end()); product.d->isValid = true; projectData.d->products << product; } for (const auto &internalSubProject : std::as_const(internalProject->subProjects)) { if (!internalSubProject->enabled) continue; ProjectData subProject; retrieveProjectData(subProject, internalSubProject); projectData.d->subProjects << subProject; } projectData.d->isValid = true; std::sort(projectData.d->products.begin(), projectData.d->products.end()); std::sort(projectData.d->subProjects.begin(), projectData.d->subProjects.end()); } } // namespace Internal using namespace Internal; /*! * \class Project * \brief The \c Project class provides services related to a qbs project. */ Project::Project(const TopLevelProjectPtr &internalProject, const Logger &logger) : d(new ProjectPrivate(internalProject, logger)) { } Project::Project(const Project &other) = default; Project::~Project() = default; /*! * \brief Returns true if and only if this object was retrieved from a successful \c SetupProjectJob. * \sa SetupProjectJob */ bool Project::isValid() const { return d && d->internalProject; } /*! * \brief The top-level profile for building this project. */ QString Project::profile() const { QBS_ASSERT(isValid(), return {}); return d->internalProject->profile(); } Project &Project::operator=(const Project &other) = default; /*! * \brief Sets up a \c Project from a source file, possibly re-using previously stored information. * The function will finish immediately, returning a \c SetupProjectJob which can be used to * track the results of the operation. * If the function is called on a valid \c Project object, the build graph will not be loaded * from a file, but will be taken from the existing project. In that case, if resolving * finishes successfully, the existing project will be invalidated. If resolving fails, qbs will * try to keep the existing project valid. However, under certain circumstances, resolving the new * project will fail at a time where existing project data has already been touched, in which case * the existing project has to be invalidated (this could be avoided, but it would hurt performance). * So after an unsuccessful re-resolve job, the existing project may or may not be valid anymore. * \note The qbs plugins will only be loaded once. As a result, the value of * \c parameters.pluginPaths will only have an effect the first time this function is called. * Similarly, the value of \c parameters.searchPaths will not have an effect if * a stored build graph is available. */ SetupProjectJob *Project::setupProject(const SetupProjectParameters ¶meters, ILogSink *logSink, QObject *jobOwner) { Logger logger(logSink); const auto job = new SetupProjectJob(logger, jobOwner); try { loadPlugins(parameters.pluginPaths(), logger); job->resolve(*this, parameters); QBS_ASSERT(job->state() == AbstractJob::StateRunning,); } catch (const ErrorInfo &error) { // Throwing from here would complicate the API, so let's report the error the same way // as all others, via AbstractJob::error(). job->reportError(error); } return job; } Project::Project() = default; /*! * \brief Retrieves information for this project. * Call this function if you need insight into the project structure, e.g. because you want to know * which products or files are in it. */ ProjectData Project::projectData() const { QBS_ASSERT(isValid(), return {}); return d->projectData(); } RunEnvironment Project::getRunEnvironment(const ProductData &product, const InstallOptions &installOptions, const QProcessEnvironment &environment, const QStringList &setupRunEnvConfig, Settings *settings) const { const ResolvedProductPtr resolvedProduct = d->internalProduct(product); return { resolvedProduct, d->internalProject, installOptions, environment, setupRunEnvConfig, settings, d->logger}; } /*! * \enum Project::ProductSelection * This enum type specifies which products to include if "all" products are to be built. * \value Project::ProdProductSelectionDefaultOnly Indicates that only those products should be * built whose \c builtByDefault property * is \c true. * \value Project::ProdProductSelectionWithNonDefault Indicates that products whose * \c builtByDefault property is \c false should * also be built. */ /*! * \brief Causes all products of this project to be built, if necessary. * If and only if \c producSelection is \c Project::ProductSelectionWithNonDefault, products with * the \c builtByDefault property set to \c false will be built too. * The function will finish immediately, returning a \c BuildJob identifiying the operation. */ BuildJob *Project::buildAllProducts(const BuildOptions &options, ProductSelection productSelection, QObject *jobOwner) const { QBS_ASSERT(isValid(), return nullptr); const bool includingNonDefault = productSelection == ProductSelectionWithNonDefault; return d->buildProducts(d->allEnabledInternalProducts(includingNonDefault), options, jobOwner); } /*! * \brief Causes the specified list of products to be built. * Use this function if you only want to build some products, not the whole project. If any of * the products in \a products depend on other products, those will also be built to the extent * that it is necessary. * The function will finish immediately, returning a \c BuildJob identifiying the operation. */ BuildJob *Project::buildSomeProducts(const QList &products, const BuildOptions &options, QObject *jobOwner) const { QBS_ASSERT(isValid(), return nullptr); return d->buildProducts(d->internalProducts(products), options, jobOwner); } /*! * \brief Convenience function for \c buildSomeProducts(). * \sa Project::buildSomeProducts(). */ BuildJob *Project::buildOneProduct(const ProductData &product, const BuildOptions &options, QObject *jobOwner) const { return buildSomeProducts(QList() << product, options, jobOwner); } /*! * \brief Removes the build artifacts of all products in the project. * The function will finish immediately, returning a \c CleanJob identifiying this operation. * \sa Project::cleanSomeProducts() */ CleanJob *Project::cleanAllProducts(const CleanOptions &options, QObject *jobOwner) const { QBS_ASSERT(isValid(), return nullptr); return d->cleanProducts(d->allEnabledInternalProducts(true), options, jobOwner); } /*! * \brief Removes the build artifacts of the given products. * The function will finish immediately, returning a \c CleanJob identifiying this operation. */ CleanJob *Project::cleanSomeProducts(const QList &products, const CleanOptions &options, QObject *jobOwner) const { QBS_ASSERT(isValid(), return nullptr); return d->cleanProducts(d->internalProducts(products), options, jobOwner); } /*! * \brief Convenience function for \c cleanSomeProducts(). * \sa Project::cleanSomeProducts(). */ CleanJob *Project::cleanOneProduct(const ProductData &product, const CleanOptions &options, QObject *jobOwner) const { return cleanSomeProducts(QList() << product, options, jobOwner); } /*! * \brief Installs the installable files of all products in the project. * If and only if \c producSelection is \c Project::ProductSelectionWithNonDefault, products with * the \c builtByDefault property set to \c false will be installed too. * The function will finish immediately, returning an \c InstallJob identifiying this operation. */ InstallJob *Project::installAllProducts(const InstallOptions &options, ProductSelection productSelection, QObject *jobOwner) const { QBS_ASSERT(isValid(), return nullptr); const bool includingNonDefault = productSelection == ProductSelectionWithNonDefault; return d->installProducts( d->allEnabledInternalProducts(includingNonDefault), options, jobOwner); } /*! * \brief Installs the installable files of the given products. * The function will finish immediately, returning an \c InstallJob identifiying this operation. */ InstallJob *Project::installSomeProducts(const QList &products, const InstallOptions &options, QObject *jobOwner) const { QBS_ASSERT(isValid(), return nullptr); return d->installProducts(d->internalProducts(products), options, jobOwner); } /*! * \brief Convenience function for \c installSomeProducts(). * \sa Project::installSomeProducts(). */ InstallJob *Project::installOneProduct(const ProductData &product, const InstallOptions &options, QObject *jobOwner) const { return installSomeProducts(QList() << product, options, jobOwner); } /*! * \brief Updates the timestamps of all build artifacts in the given products. * Afterwards, the build graph will have the same state as if a successful build had been done. */ void Project::updateTimestamps(const QList &products) { QBS_ASSERT(isValid(), return); TimestampsUpdater().updateTimestamps(d->internalProject, d->internalProducts(products), d->logger); } /*! * \brief Finds files generated from the given file in the given product. * If \a recursive is \c false, only files generated directly from \a file will be considered, * otherwise the generated files are collected recursively. * If \a tags is not empty, only generated files matching at least one of these tags will * be considered. */ QStringList Project::generatedFiles(const ProductData &product, const QString &file, bool recursive, const QStringList &tags) const { QBS_ASSERT(isValid(), return {}); const ResolvedProductConstPtr internalProduct = d->internalProduct(product); return internalProduct->generatedFiles(file, recursive, FileTags::fromStringList(tags)); } QVariantMap Project::projectConfiguration() const { QBS_ASSERT(isValid(), return {}); return d->internalProject->buildConfiguration(); } std::set Project::buildSystemFiles() const { QBS_ASSERT(isValid(), return {}); return rangeTo>(d->internalProject->buildSystemFiles); } CodeLinks Project::codeLinks() const { QBS_ASSERT(isValid(), return {}); return d->internalProject->codeLinks; } RuleCommandList Project::ruleCommands(const ProductData &product, const QString &inputFilePath, const QString &outputFileTag, ErrorInfo *error) const { QBS_ASSERT(isValid(), return {}); QBS_ASSERT(product.isValid(), return {}); try { return d->ruleCommands(product, inputFilePath, outputFileTag); } catch (const ErrorInfo &e) { if (error) *error = e; return {}; } } ProjectTransformerData Project::transformerData(ErrorInfo *error) const { QBS_ASSERT(isValid(), return {}); try { return d->transformerData(); } catch (const ErrorInfo &e) { if (error) *error = e; return {}; } } ErrorInfo Project::dumpNodesTree(QIODevice &outDevice, const QList &products) { try { NodeTreeDumper(outDevice).start(d->internalProducts(products)); } catch (const ErrorInfo &e) { return e; } return {}; } Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath, const QStringList &requestedProperties) { BuildGraphInfo info; try { const Internal::TopLevelProjectConstPtr project = BuildGraphLoader::loadProject(bgFilePath); info.bgFilePath = bgFilePath; info.overriddenProperties = project->overriddenValues; info.profileData = project->fullProfileConfigsTree(); std::vector> props; for (const QString &prop : requestedProperties) { QStringList components = prop.split(QLatin1Char('.')); const QString propName = components.takeLast(); props.emplace_back(components.join(QLatin1Char('.')), propName); } for (const auto &product : project->allProducts()) { if (props.empty()) break; if (product->profile() != project->profile()) continue; for (auto it = props.begin(); it != props.end();) { const QVariant value = product->moduleProperties->moduleProperty(it->first, it->second); if (value.isValid()) { info.requestedProperties.insert(it->first + QLatin1Char('.') + it->second, value); it = props.erase(it); } else { ++it; } } } } catch (const ErrorInfo &e) { info.error = e; } return info; } Project::BuildGraphInfo Project::getBuildGraphInfo() const { QBS_ASSERT(isValid(), return {}); BuildGraphInfo info; try { if (d->internalProject->locked) throw ErrorInfo(Tr::tr("A job is currently in progress.")); info.bgFilePath = d->internalProject->buildGraphFilePath(); info.overriddenProperties = d->internalProject->overriddenValues; info.profileData = d->internalProject->fullProfileConfigsTree(); } catch (const ErrorInfo &e) { info.error = e; } return info; } /*! * \brief Adds a new empty group to the given product. * Returns an \c ErrorInfo object for which \c hasError() is false in case of a success * and true otherwise. In the latter case, the object will have a sensible description. * After calling this function, it is recommended to re-fetch the project data, as other * items can be affected. * \sa qbs::Project::projectData() */ ErrorInfo Project::addGroup(const ProductData &product, const QString &groupName) { try { QBS_CHECK(isValid()); d->prepareChangeToProject(); d->addGroup(product, groupName); d->internalProject->store(d->logger); return {}; } catch (const ErrorInfo &exception) { auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure adding group '%1' to product '%2'.") .arg(groupName, product.name())); return errorInfo; } } /*! * \brief Adds the given files to the given product. * If \c group is a default-constructed object, the files will be added to the product's * "files" property, otherwise to the one of \c group. * The file paths can be absolute or relative to the location of \c product (including a possible * prefix in the group). The project file will always contain relative paths. * After calling this function, it is recommended to re-fetch the project data, as other * items can be affected. * \sa qbs::Project::projectData() */ ErrorInfo Project::addFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths) { try { QBS_CHECK(isValid()); d->prepareChangeToProject(); d->addFiles(product, group, filePaths); d->internalProject->store(d->logger); return {}; } catch (const ErrorInfo &exception) { auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure adding files to product.")); return errorInfo; } } /*! * \brief Removes the given files from the given product. * If \c group is a default-constructed object, the files will be removed from the product's * "files" property, otherwise from the one of \c group. * The file paths can be absolute or relative to the location of \c product (including a possible * prefix in the group). * After calling this function, it is recommended to re-fetch the project data, as other * items can be affected. * \sa qbs::Project::projectData() */ ErrorInfo Project::removeFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths) { try { QBS_CHECK(isValid()); d->prepareChangeToProject(); d->removeFiles(product, group, filePaths); d->internalProject->store(d->logger); return {}; } catch (const ErrorInfo &exception) { auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure removing files from product '%1'.").arg(product.name())); return errorInfo; } } /*! * \brief Removes the given group from the given product. * After calling this function, it is recommended to re-fetch the project data, as other * items can be affected. * \sa qbs::Project::projectData() */ ErrorInfo Project::removeGroup(const ProductData &product, const GroupData &group) { try { QBS_CHECK(isValid()); d->prepareChangeToProject(); d->removeGroup(product, group); d->internalProject->store(d->logger); return {}; } catch (const ErrorInfo &exception) { auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure removing group '%1' from product '%2'.") .arg(group.name(), product.name())); return errorInfo; } } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/rulecommand.h0000644000175100001660000000562114776170045020660 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RULECOMMAND_H #define QBS_RULECOMMAND_H #include #include #include #include QT_BEGIN_NAMESPACE class QProcessEnvironment; QT_END_NAMESPACE namespace qbs { namespace Internal { class ProjectPrivate; class RuleCommandPrivate; } class QBS_EXPORT RuleCommand { friend class Internal::ProjectPrivate; public: RuleCommand(); RuleCommand(const RuleCommand &other); ~RuleCommand(); RuleCommand &operator=(const RuleCommand &other); enum Type { ProcessCommandType, JavaScriptCommandType, InvalidType }; Type type() const; QString description() const; QString extendedDescription() const; QString sourceCode() const; QString executable() const; QStringList arguments() const; QString workingDirectory() const; QProcessEnvironment environment() const; private: QExplicitlySharedDataPointer d; }; using RuleCommandList = QList; } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/changeset.cpp0000644000175100001660000002342214776170045020645 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "changeset.h" namespace QbsQmlJS { ChangeSet::ChangeSet() : m_string(nullptr), m_error(false) { } ChangeSet::ChangeSet(QList operations) : m_string(nullptr), m_operationList(std::move(operations)), m_error(false) { } static bool overlaps(int posA, int lengthA, int posB, int lengthB) { if (lengthB > 0) { return // right edge of B contained in A (posA < posB + lengthB && posA + lengthA >= posB + lengthB) // left edge of B contained in A || (posA <= posB && posA + lengthA > posB) // A contained in B || (posB < posA && posB + lengthB > posA + lengthA); } return (posB > posA && posB < posA + lengthA); } bool ChangeSet::hasOverlap(int pos, int length) { for (const EditOp &cmd : m_operationList) { switch (cmd.type) { case EditOp::Replace: if (overlaps(pos, length, cmd.pos1, cmd.length1)) return true; break; case EditOp::Move: if (overlaps(pos, length, cmd.pos1, cmd.length1)) return true; if (cmd.pos2 > pos && cmd.pos2 < pos + length) return true; break; case EditOp::Insert: if (cmd.pos1 > pos && cmd.pos1 < pos + length) return true; break; case EditOp::Remove: if (overlaps(pos, length, cmd.pos1, cmd.length1)) return true; break; case EditOp::Flip: if (overlaps(pos, length, cmd.pos1, cmd.length1)) return true; if (overlaps(pos, length, cmd.pos2, cmd.length2)) return true; break; case EditOp::Copy: if (overlaps(pos, length, cmd.pos1, cmd.length1)) return true; if (cmd.pos2 > pos && cmd.pos2 < pos + length) return true; break; case EditOp::Unset: break; } } return false; } bool ChangeSet::empty() const { return m_operationList.empty(); } QList ChangeSet::operationList() const { return m_operationList; } void ChangeSet::clear() { m_string = nullptr; m_operationList.clear(); m_error = false; } bool ChangeSet::replace_helper(int pos, int length, const QString &replacement) { if (hasOverlap(pos, length)) m_error = true; EditOp cmd(EditOp::Replace); cmd.pos1 = pos; cmd.length1 = length; cmd.text = replacement; m_operationList.push_back(cmd); return !m_error; } bool ChangeSet::move_helper(int pos, int length, int to) { if (hasOverlap(pos, length) || hasOverlap(to, 0) || overlaps(pos, length, to, 0)) m_error = true; EditOp cmd(EditOp::Move); cmd.pos1 = pos; cmd.length1 = length; cmd.pos2 = to; m_operationList.push_back(cmd); return !m_error; } bool ChangeSet::insert(int pos, const QString &text) { Q_ASSERT(pos >= 0); if (hasOverlap(pos, 0)) m_error = true; EditOp cmd(EditOp::Insert); cmd.pos1 = pos; cmd.text = text; m_operationList.push_back(cmd); return !m_error; } bool ChangeSet::replace(const Range &range, const QString &replacement) { return replace(range.start, range.end, replacement); } bool ChangeSet::remove(const Range &range) { return remove(range.start, range.end); } bool ChangeSet::move(const Range &range, int to) { return move(range.start, range.end, to); } bool ChangeSet::flip(const Range &range1, const Range &range2) { return flip(range1.start, range1.end, range2.start, range2.end); } bool ChangeSet::copy(const Range &range, int to) { return copy(range.start, range.end, to); } bool ChangeSet::replace(int start, int end, const QString &replacement) { return replace_helper(start, end - start, replacement); } bool ChangeSet::remove(int start, int end) { return remove_helper(start, end - start); } bool ChangeSet::move(int start, int end, int to) { return move_helper(start, end - start, to); } bool ChangeSet::flip(int start1, int end1, int start2, int end2) { return flip_helper(start1, end1 - start1, start2, end2 - start2); } bool ChangeSet::copy(int start, int end, int to) { return copy_helper(start, end - start, to); } bool ChangeSet::remove_helper(int pos, int length) { if (hasOverlap(pos, length)) m_error = true; EditOp cmd(EditOp::Remove); cmd.pos1 = pos; cmd.length1 = length; m_operationList.push_back(cmd); return !m_error; } bool ChangeSet::flip_helper(int pos1, int length1, int pos2, int length2) { if (hasOverlap(pos1, length1) || hasOverlap(pos2, length2) || overlaps(pos1, length1, pos2, length2)) m_error = true; EditOp cmd(EditOp::Flip); cmd.pos1 = pos1; cmd.length1 = length1; cmd.pos2 = pos2; cmd.length2 = length2; m_operationList.push_back(cmd); return !m_error; } bool ChangeSet::copy_helper(int pos, int length, int to) { if (hasOverlap(pos, length) || hasOverlap(to, 0) || overlaps(pos, length, to, 0)) m_error = true; EditOp cmd(EditOp::Copy); cmd.pos1 = pos; cmd.length1 = length; cmd.pos2 = to; m_operationList.push_back(cmd); return !m_error; } void ChangeSet::doReplace(const EditOp &replace_helper, QList *replaceList) { Q_ASSERT(replace_helper.type == EditOp::Replace); { for (EditOp &c : *replaceList) { if (replace_helper.pos1 <= c.pos1) c.pos1 += replace_helper.text.size(); if (replace_helper.pos1 < c.pos1) c.pos1 -= replace_helper.length1; } } if (m_string) { m_string->replace(replace_helper.pos1, replace_helper.length1, replace_helper.text); } } void ChangeSet::convertToReplace(const EditOp &op, QList *replaceList) { EditOp replace1(EditOp::Replace); EditOp replace2(EditOp::Replace); switch (op.type) { case EditOp::Replace: replaceList->push_back(op); break; case EditOp::Move: replace1.pos1 = op.pos1; replace1.length1 = op.length1; replaceList->push_back(replace1); replace2.pos1 = op.pos2; replace2.text = textAt(op.pos1, op.length1); replaceList->push_back(replace2); break; case EditOp::Insert: replace1.pos1 = op.pos1; replace1.text = op.text; replaceList->push_back(replace1); break; case EditOp::Remove: replace1.pos1 = op.pos1; replace1.length1 = op.length1; replaceList->push_back(replace1); break; case EditOp::Flip: replace1.pos1 = op.pos1; replace1.length1 = op.length1; replace1.text = textAt(op.pos2, op.length2); replaceList->push_back(replace1); replace2.pos1 = op.pos2; replace2.length1 = op.length2; replace2.text = textAt(op.pos1, op.length1); replaceList->push_back(replace2); break; case EditOp::Copy: replace1.pos1 = op.pos2; replace1.text = textAt(op.pos1, op.length1); replaceList->push_back(replace1); break; case EditOp::Unset: break; } } bool ChangeSet::hadErrors() { return m_error; } void ChangeSet::apply(QString *s) { m_string = s; apply_helper(); m_string = nullptr; } QString ChangeSet::textAt(int pos, int length) { if (m_string) { return m_string->mid(pos, length); } return {}; } void ChangeSet::apply_helper() { // convert all ops to replace QList replaceList; { while (!m_operationList.empty()) { const EditOp cmd(m_operationList.front()); m_operationList.removeFirst(); convertToReplace(cmd, &replaceList); } } // execute replaces while (!replaceList.empty()) { const EditOp cmd(replaceList.front()); replaceList.removeFirst(); doReplace(cmd, &replaceList); } } } // namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/api/qmljsrewriter.cpp0000644000175100001660000006311114776170045021615 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmljsrewriter.h" #include namespace QbsQmlJS { using namespace AST; static QString toString(UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.')) { QString result; for (UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) { if (iter != qualifiedId) result += delimiter; result += iter->name; } return result; } Rewriter::Rewriter(QString originalText, ChangeSet *changeSet, QStringList propertyOrder) : m_originalText(std::move(originalText)) , m_changeSet(changeSet) , m_propertyOrder(std::move(propertyOrder)) { Q_ASSERT(changeSet); } Rewriter::Range Rewriter::addBinding(AST::UiObjectInitializer *ast, const QString &propertyName, const QString &propertyValue, BindingType bindingType) { UiObjectMemberList *insertAfter = searchMemberToInsertAfter(ast->members, propertyName, m_propertyOrder); return addBinding(ast, propertyName, propertyValue, bindingType, insertAfter); } Rewriter::Range Rewriter::addBinding(AST::UiObjectInitializer *ast, const QString &propertyName, const QString &propertyValue, BindingType bindingType, UiObjectMemberList *insertAfter) { SourceLocation endOfPreviousMember; SourceLocation startOfNextMember; if (insertAfter == nullptr || insertAfter->member == nullptr) { // insert as first member endOfPreviousMember = ast->lbraceToken; if (ast->members && ast->members->member) startOfNextMember = ast->members->member->firstSourceLocation(); else startOfNextMember = ast->rbraceToken; } else { endOfPreviousMember = insertAfter->member->lastSourceLocation(); if (insertAfter->next && insertAfter->next->member) startOfNextMember = insertAfter->next->member->firstSourceLocation(); else startOfNextMember = ast->rbraceToken; } const bool isOneLiner = endOfPreviousMember.startLine == startOfNextMember.startLine; bool needsPreceedingSemicolon = false; bool needsTrailingSemicolon = false; if (isOneLiner) { if (insertAfter == nullptr) { // we're inserting after an lbrace if (ast->members) { // we're inserting before a member (and not the rbrace) needsTrailingSemicolon = bindingType == ScriptBinding; } } else { // we're inserting after a member, not after the lbrace if (endOfPreviousMember.isValid()) { // there already is a semicolon after the previous member if (insertAfter->next && insertAfter->next->member) { // and the after us there is a member, not an rbrace, so: needsTrailingSemicolon = bindingType == ScriptBinding; } } else { // there is no semicolon after the previous member (probably because there is an rbrace after us/it, so: needsPreceedingSemicolon = true; } } } QString newPropertyTemplate; switch (bindingType) { case ArrayBinding: newPropertyTemplate = QStringLiteral("%1: [\n%2\n]"); break; case ObjectBinding: Q_FALLTHROUGH(); case ScriptBinding: newPropertyTemplate = QStringLiteral("%1: %2"); break; default: Q_ASSERT(!"unknown property type"); } if (isOneLiner) { if (needsPreceedingSemicolon) newPropertyTemplate.prepend(QLatin1Char(';')); newPropertyTemplate.prepend(QLatin1Char(' ')); if (needsTrailingSemicolon) newPropertyTemplate.append(QLatin1Char(';')); } else { newPropertyTemplate.prepend(QLatin1Char('\n')); } m_changeSet->insert(endOfPreviousMember.end(), newPropertyTemplate.arg(propertyName, propertyValue)); return {int(endOfPreviousMember.end()), int(endOfPreviousMember.end())}; } UiObjectMemberList *Rewriter::searchMemberToInsertAfter(UiObjectMemberList *members, const QStringList &propertyOrder) { const int objectDefinitionInsertionPoint = propertyOrder.indexOf(QString()); UiObjectMemberList *lastObjectDef = nullptr; UiObjectMemberList *lastNonObjectDef = nullptr; for (UiObjectMemberList *iter = members; iter; iter = iter->next) { UiObjectMember *member = iter->member; int idx = -1; if (cast(member)) lastObjectDef = iter; else if (auto arrayBinding = cast(member)) idx = propertyOrder.indexOf(toString(arrayBinding->qualifiedId)); else if (auto objectBinding = cast(member)) idx = propertyOrder.indexOf(toString(objectBinding->qualifiedId)); else if (auto scriptBinding = cast(member)) idx = propertyOrder.indexOf(toString(scriptBinding->qualifiedId)); else if (cast(member)) idx = propertyOrder.indexOf(QLatin1String("property")); if (idx < objectDefinitionInsertionPoint) lastNonObjectDef = iter; } if (lastObjectDef) return lastObjectDef; return lastNonObjectDef; } UiArrayMemberList *Rewriter::searchMemberToInsertAfter(UiArrayMemberList *members, const QStringList &propertyOrder) { const int objectDefinitionInsertionPoint = propertyOrder.indexOf(QString()); UiArrayMemberList *lastObjectDef = nullptr; UiArrayMemberList *lastNonObjectDef = nullptr; for (UiArrayMemberList *iter = members; iter; iter = iter->next) { UiObjectMember *member = iter->member; int idx = -1; if (cast(member)) lastObjectDef = iter; else if (auto arrayBinding = cast(member)) idx = propertyOrder.indexOf(toString(arrayBinding->qualifiedId)); else if (auto objectBinding = cast(member)) idx = propertyOrder.indexOf(toString(objectBinding->qualifiedId)); else if (auto scriptBinding = cast(member)) idx = propertyOrder.indexOf(toString(scriptBinding->qualifiedId)); else if (cast(member)) idx = propertyOrder.indexOf(QLatin1String("property")); if (idx < objectDefinitionInsertionPoint) lastNonObjectDef = iter; } if (lastObjectDef) return lastObjectDef; return lastNonObjectDef; } UiObjectMemberList *Rewriter::searchMemberToInsertAfter(UiObjectMemberList *members, const QString &propertyName, const QStringList &propertyOrder) { if (!members) return nullptr; // empty members QHash orderedMembers; for (UiObjectMemberList *iter = members; iter; iter = iter->next) { UiObjectMember *member = iter->member; if (auto arrayBinding = cast(member)) orderedMembers[toString(arrayBinding->qualifiedId)] = iter; else if (auto objectBinding = cast(member)) orderedMembers[toString(objectBinding->qualifiedId)] = iter; else if (cast(member)) orderedMembers[QString()] = iter; else if (auto scriptBinding = cast(member)) orderedMembers[toString(scriptBinding->qualifiedId)] = iter; else if (cast(member)) orderedMembers[QStringLiteral("property")] = iter; } int idx = propertyOrder.indexOf(propertyName); if (idx == -1) idx = propertyOrder.indexOf(QString()); if (idx == -1) idx = propertyOrder.size() - 1; for (; idx > 0; --idx) { const QString &prop = propertyOrder.at(idx - 1); UiObjectMemberList *candidate = orderedMembers.value(prop, 0); if (candidate != nullptr) return candidate; } return nullptr; } void Rewriter::changeBinding(UiObjectInitializer *ast, const QString &propertyName, const QString &newValue, BindingType binding) { QString prefix, suffix; int dotIdx = propertyName.indexOf(QLatin1Char('.')); if (dotIdx != -1) { prefix = propertyName.left(dotIdx); suffix = propertyName.mid(dotIdx + 1); } for (UiObjectMemberList *members = ast->members; members; members = members->next) { UiObjectMember *member = members->member; // for non-grouped properties: if (isMatchingPropertyMember(propertyName, member)) { switch (binding) { case ArrayBinding: insertIntoArray(cast(member), newValue); break; case ObjectBinding: replaceMemberValue(member, newValue, false); break; case ScriptBinding: replaceMemberValue(member, newValue, nextMemberOnSameLine(members)); break; default: Q_ASSERT(!"Unhandled QmlRefactoring::PropertyType"); } break; // for grouped properties: } if (!prefix.isEmpty()) { if (auto def = cast(member)) { if (toString(def->qualifiedTypeNameId) == prefix) changeBinding(def->initializer, suffix, newValue, binding); } } } } void Rewriter::replaceMemberValue(UiObjectMember *propertyMember, const QString &newValue, bool needsSemicolon) { QString replacement = newValue; int startOffset = -1; int endOffset = -1; if (auto objectBinding = AST::cast(propertyMember)) { startOffset = objectBinding->qualifiedTypeNameId->identifierToken.offset; endOffset = objectBinding->initializer->rbraceToken.end(); } else if (auto scriptBinding = AST::cast(propertyMember)) { startOffset = scriptBinding->statement->firstSourceLocation().offset; endOffset = scriptBinding->statement->lastSourceLocation().end(); } else if (auto arrayBinding = AST::cast(propertyMember)) { startOffset = arrayBinding->lbracketToken.offset; endOffset = arrayBinding->rbracketToken.end(); } else if (auto publicMember = AST::cast(propertyMember)) { if (publicMember->statement) { startOffset = publicMember->statement->firstSourceLocation().offset; if (publicMember->semicolonToken.isValid()) endOffset = publicMember->semicolonToken.end(); else endOffset = publicMember->statement->lastSourceLocation().offset; } else { startOffset = publicMember->lastSourceLocation().end(); endOffset = startOffset; if (publicMember->semicolonToken.isValid()) startOffset = publicMember->semicolonToken.offset; replacement.prepend(QStringLiteral(": ")); } } else { return; } if (needsSemicolon) replacement += QLatin1Char(';'); m_changeSet->replace(startOffset, endOffset, replacement); } bool Rewriter::isMatchingPropertyMember(const QString &propertyName, UiObjectMember *member) { if (auto publicMember = cast(member)) return publicMember->name == propertyName; if (auto objectBinding = cast(member)) return toString(objectBinding->qualifiedId) == propertyName; if (auto scriptBinding = cast(member)) return toString(scriptBinding->qualifiedId) == propertyName; if (auto arrayBinding = cast(member)) return toString(arrayBinding->qualifiedId) == propertyName; return false; } bool Rewriter::nextMemberOnSameLine(UiObjectMemberList *members) { if (members && members->next && members->next->member) return members->next->member->firstSourceLocation().startLine == members->member->lastSourceLocation().startLine; return false; } void Rewriter::insertIntoArray(UiArrayBinding *ast, const QString &newValue) { if (!ast) return; UiObjectMember *lastMember = nullptr; for (UiArrayMemberList *iter = ast->members; iter; iter = iter->next) { lastMember = iter->member; } if (!lastMember) return; const int insertionPoint = lastMember->lastSourceLocation().end(); m_changeSet->insert(insertionPoint, QLatin1String(",\n") + newValue); } void Rewriter::removeBindingByName(UiObjectInitializer *ast, const QString &propertyName) { QString prefix; int dotIdx = propertyName.indexOf(QLatin1Char('.')); if (dotIdx != -1) prefix = propertyName.left(dotIdx); for (UiObjectMemberList *it = ast->members; it; it = it->next) { UiObjectMember *member = it->member; // run full name match (for ungrouped properties): if (isMatchingPropertyMember(propertyName, member)) { removeMember(member); // check for grouped properties: } else if (!prefix.isEmpty()) { if (auto def = cast(member)) { if (toString(def->qualifiedTypeNameId) == prefix) removeGroupedProperty(def, propertyName); } } } } void Rewriter::removeGroupedProperty(UiObjectDefinition *ast, const QString &propertyName) { int dotIdx = propertyName.indexOf(QLatin1Char('.')); if (dotIdx == -1) return; const QString propName = propertyName.mid(dotIdx + 1); UiObjectMember *wanted = nullptr; unsigned memberCount = 0; for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) { ++memberCount; UiObjectMember *member = it->member; if (!wanted && isMatchingPropertyMember(propName, member)) wanted = member; } if (!wanted) return; if (memberCount == 1) removeMember(ast); else removeMember(wanted); } void Rewriter::removeMember(UiObjectMember *member) { int start = member->firstSourceLocation().offset; int end = member->lastSourceLocation().end(); includeSurroundingWhitespace(m_originalText, start, end); m_changeSet->remove(start, end); } bool Rewriter::includeSurroundingWhitespace(const QString &source, int &start, int &end) { bool includeStartingWhitespace = true; bool paragraphFound = false; bool paragraphSkipped = false; if (end >= 0) { QChar c = source.at(end); while (c.isSpace()) { ++end; if (c.unicode() == 10) { paragraphFound = true; paragraphSkipped = true; break; } if (end == source.length()) { break; } c = source.at(end); } includeStartingWhitespace = paragraphFound; } paragraphFound = false; if (includeStartingWhitespace) { while (start > 0) { const QChar c = source.at(start - 1); if (c.unicode() == 10) { paragraphFound = true; break; } if (!c.isSpace()) break; --start; } } if (!paragraphFound && paragraphSkipped) //keep the line ending --end; return paragraphFound; } void Rewriter::includeLeadingEmptyLine(QStringView source, int &start) { if (start == 0) return; const qsizetype lineEnd = source.lastIndexOf(QChar::LineFeed, start); if (lineEnd <= 0) return; const qsizetype lineStart = source.lastIndexOf(QChar::LineFeed, lineEnd - 1) + 1; const auto line = source.mid(lineStart, lineEnd - lineStart); if (!line.trimmed().isEmpty()) return; start = lineStart; } void Rewriter::includeEmptyGroupedProperty(UiObjectDefinition *groupedProperty, UiObjectMember *memberToBeRemoved, int &start, int &end) { if (groupedProperty->qualifiedTypeNameId && !groupedProperty->qualifiedTypeNameId->name.isEmpty() && groupedProperty->qualifiedTypeNameId->name.at(0).isLower()) { // grouped property UiObjectMemberList *memberIter = groupedProperty->initializer->members; while (memberIter) { if (memberIter->member != memberToBeRemoved) return; memberIter = memberIter->next; } start = groupedProperty->firstSourceLocation().begin(); end = groupedProperty->lastSourceLocation().end(); } } #if 0 UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter(UiObjectMemberList *members, const QStringList &propertyOrder) { const int objectDefinitionInsertionPoint = propertyOrder.indexOf(QString()); UiObjectMemberList *lastObjectDef = nullptr; UiObjectMemberList *lastNonObjectDef = nullptr; for (UiObjectMemberList *iter = members; iter; iter = iter->next) { UiObjectMember *member = iter->member; int idx = -1; if (cast(member)) lastObjectDef = iter; else if (UiArrayBinding *arrayBinding = cast(member)) idx = propertyOrder.indexOf(toString(arrayBinding->qualifiedId)); else if (UiObjectBinding *objectBinding = cast(member)) idx = propertyOrder.indexOf(toString(objectBinding->qualifiedId)); else if (UiScriptBinding *scriptBinding = cast(member)) idx = propertyOrder.indexOf(toString(scriptBinding->qualifiedId)); else if (cast(member)) idx = propertyOrder.indexOf(QLatin1String("property")); if (idx < objectDefinitionInsertionPoint) lastNonObjectDef = iter; } if (lastObjectDef) return lastObjectDef; else return lastNonObjectDef; } UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter(UiObjectMemberList *members, const QString &propertyName, const QStringList &propertyOrder) { if (!members) return nullptr; // empty members QHash orderedMembers; for (UiObjectMemberList *iter = members; iter; iter = iter->next) { UiObjectMember *member = iter->member; if (UiArrayBinding *arrayBinding = cast(member)) orderedMembers[toString(arrayBinding->qualifiedId)] = iter; else if (UiObjectBinding *objectBinding = cast(member)) orderedMembers[toString(objectBinding->qualifiedId)] = iter; else if (cast(member)) orderedMembers[QString()] = iter; else if (UiScriptBinding *scriptBinding = cast(member)) orderedMembers[toString(scriptBinding->qualifiedId)] = iter; else if (cast(member)) orderedMembers[QStringLiteral("property")] = iter; } int idx = propertyOrder.indexOf(propertyName); if (idx == -1) idx = propertyOrder.indexOf(QString()); if (idx == -1) idx = propertyOrder.size() - 1; for (; idx > 0; --idx) { const QString prop = propertyOrder.at(idx - 1); UiObjectMemberList *candidate = orderedMembers.value(prop, 0); if (candidate != 0) return candidate; } return nullptr; } #endif void Rewriter::appendToArrayBinding(UiArrayBinding *arrayBinding, const QString &content) { UiObjectMember *lastMember = nullptr; for (UiArrayMemberList *iter = arrayBinding->members; iter; iter = iter->next) if (iter->member) lastMember = iter->member; if (!lastMember) return; // an array binding cannot be empty, so there will (or should) always be a last member. const int insertionPoint = lastMember->lastSourceLocation().end(); m_changeSet->insert(insertionPoint, QLatin1String(",\n") + content); } Rewriter::Range Rewriter::addObject(UiObjectInitializer *ast, const QString &content) { UiObjectMemberList *insertAfter = searchMemberToInsertAfter(ast->members, m_propertyOrder); return addObject(ast, content, insertAfter); } Rewriter::Range Rewriter::addObject(UiObjectInitializer *ast, const QString &content, UiObjectMemberList *insertAfter) { int insertionPoint; QString textToInsert; if (insertAfter && insertAfter->member) { insertionPoint = insertAfter->member->lastSourceLocation().end(); textToInsert += QLatin1String("\n"); } else { insertionPoint = ast->lbraceToken.end(); } textToInsert += content; m_changeSet->insert(insertionPoint, QLatin1String("\n") + textToInsert); return {insertionPoint, insertionPoint}; } Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content) { UiArrayMemberList *insertAfter = searchMemberToInsertAfter(ast->members, m_propertyOrder); return addObject(ast, content, insertAfter); } Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content, UiArrayMemberList *insertAfter) { int insertionPoint; QString textToInsert; if (insertAfter && insertAfter->member) { insertionPoint = insertAfter->member->lastSourceLocation().end(); textToInsert = QLatin1String(",\n") + content; } else { insertionPoint = ast->lbracketToken.end(); textToInsert += QLatin1String("\n") + content + QLatin1Char(','); } m_changeSet->insert(insertionPoint, textToInsert); return {insertionPoint, insertionPoint}; } void Rewriter::removeObjectMember(UiObjectMember *member, UiObjectMember *parent) { int start = member->firstSourceLocation().offset; int end = member->lastSourceLocation().end(); if (auto parentArray = cast(parent)) { extendToLeadingOrTrailingComma(parentArray, member, start, end); } else { if (auto parentObjectDefinition = cast(parent)) includeEmptyGroupedProperty(parentObjectDefinition, member, start, end); includeSurroundingWhitespace(m_originalText, start, end); } includeLeadingEmptyLine(m_originalText, start); m_changeSet->remove(start, end); } void Rewriter::extendToLeadingOrTrailingComma(UiArrayBinding *parentArray, UiObjectMember *member, int &start, int &end) const { UiArrayMemberList *currentMember = nullptr; for (UiArrayMemberList *it = parentArray->members; it; it = it->next) { if (it->member == member) { currentMember = it; break; } } if (!currentMember) return; if (currentMember->commaToken.isValid()) { // leading comma start = currentMember->commaToken.offset; if (includeSurroundingWhitespace(m_originalText, start, end)) --end; } else if (currentMember->next && currentMember->next->commaToken.isValid()) { // trailing comma end = currentMember->next->commaToken.end(); includeSurroundingWhitespace(m_originalText, start, end); } else { // array with 1 element, so remove the complete binding start = parentArray->firstSourceLocation().offset; end = parentArray->lastSourceLocation().end(); includeSurroundingWhitespace(m_originalText, start, end); } } } // namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/api/internaljobs.cpp0000644000175100001660000003475114776170045021405 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "internaljobs.h" #include "jobs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class JobObserver : public ProgressObserver { public: JobObserver(InternalJob *job) : m_job(job) { } ~JobObserver() override { delete m_timedLogger; } void cancel() { std::lock_guard lock(m_cancelMutex); m_canceled = true; for (ScriptEngine * const engine : scriptEngines()) engine->cancel(); } private: void initialize(const QString &task, int maximum) override { QBS_ASSERT(!m_timedLogger, delete m_timedLogger); if (m_job->timed()) m_timedLogger = new TimedActivityLogger(m_job->logger(), task, true); m_value = 0; m_maximum = maximum; emit m_job->newTaskStarted(task, maximum, m_job); } void setMaximum(int maximum) override { m_maximum = maximum; emit m_job->totalEffortChanged(maximum, m_job); } void setProgressValue(int value) override { //QBS_ASSERT(value >= m_value, qDebug("old value = %d, new value = %d", m_value, value)); //QBS_ASSERT(value <= m_maximum, qDebug("value = %d, maximum = %d", value, m_maximum)); m_value = value; if (value == m_maximum) { delete m_timedLogger; m_timedLogger = nullptr; } emit m_job->taskProgress(value, m_job); } int progressValue() override { return m_value; } int maximum() const override { return m_maximum; } bool canceled() const override { std::lock_guard lock(m_cancelMutex); return m_canceled; } int m_value = 0; int m_maximum = 0; mutable std::mutex m_cancelMutex; bool m_canceled = false; InternalJob * const m_job; TimedActivityLogger *m_timedLogger = nullptr; }; InternalJob::InternalJob(Logger logger, QObject *parent) : QObject(parent) , m_observer(new JobObserver(this)) , m_ownsObserver(true) , m_logger(std::move(logger)) , m_timed(false) { } InternalJob::~InternalJob() { if (m_ownsObserver) delete m_observer; } void InternalJob::cancel() { m_observer->cancel(); } void InternalJob::shareObserverWith(InternalJob *otherJob) { if (m_ownsObserver) { delete m_observer; m_ownsObserver = false; } m_observer = otherJob->m_observer; } void InternalJob::storeBuildGraph(const TopLevelProjectPtr &project) { try { doSanityChecks(project, logger()); TimedActivityLogger storeTimer(m_logger, Tr::tr("Storing build graph"), timed()); project->store(logger()); } catch (const ErrorInfo &error) { ErrorInfo fullError = this->error(); const auto items = error.items(); for (const ErrorItem &item : items) fullError.append(item); setError(fullError); } } /** * Construct a new thread wrapper for a synchronous job. * This object takes over ownership of the synchronous job. */ InternalJobThreadWrapper::InternalJobThreadWrapper(InternalJob *synchronousJob, QObject *parent) : InternalJob(synchronousJob->logger(), parent) , m_job(synchronousJob) , m_running(false) { synchronousJob->shareObserverWith(this); m_job->moveToThread(&m_thread); connect(m_job, &InternalJob::finished, this, &InternalJobThreadWrapper::handleFinished); connect(m_job, &InternalJob::newTaskStarted, this, &InternalJob::newTaskStarted); connect(m_job, &InternalJob::taskProgress, this, &InternalJob::taskProgress); connect(m_job, &InternalJob::totalEffortChanged, this, &InternalJob::totalEffortChanged); connect(this, &InternalJobThreadWrapper::startRequested, m_job, &InternalJob::start); } InternalJobThreadWrapper::~InternalJobThreadWrapper() { if (m_running) { cancel(); while (m_running) QCoreApplication::processEvents(); } m_thread.quit(); m_thread.wait(); delete m_job; m_job = nullptr; } void InternalJobThreadWrapper::start() { setTimed(m_job->timed()); m_thread.start(); m_running = true; QTimer::singleShot(0, this, &InternalJobThreadWrapper::startRequested); } void InternalJobThreadWrapper::handleFinished() { m_running = false; setError(m_job->error()); emit finished(this); } InternalSetupProjectJob::InternalSetupProjectJob(const Logger &logger) : InternalJob(logger) { } InternalSetupProjectJob::~InternalSetupProjectJob() = default; void InternalSetupProjectJob::init(const TopLevelProjectPtr &existingProject, const SetupProjectParameters ¶meters) { m_existingProject = existingProject; m_parameters = parameters; setTimed(parameters.logElapsedTime()); } void InternalSetupProjectJob::reportError(const ErrorInfo &error) { setError(error); emit finished(this); } TopLevelProjectPtr InternalSetupProjectJob::project() const { return m_newProject; } void InternalSetupProjectJob::start() { BuildGraphLocker *bgLocker = m_existingProject ? m_existingProject->bgLocker : nullptr; bool deleteLocker = false; try { const ErrorInfo err = m_parameters.expandBuildConfiguration(); if (err.hasError()) throw err; const QString projectId = TopLevelProject::deriveId( m_parameters.finalBuildConfigurationTree()); const QString buildDir = TopLevelProject::deriveBuildDirectory(m_parameters.buildRoot(), projectId); if (m_existingProject && m_existingProject->buildDirectory != buildDir) m_existingProject.reset(); if (!m_existingProject) { bgLocker = new BuildGraphLocker(ProjectBuildData::deriveBuildGraphFilePath(buildDir, projectId), logger(), m_parameters.waitLockBuildGraph(), observer()); deleteLocker = true; } execute(); if (m_existingProject) { if (m_existingProject != m_newProject) m_existingProject->makeModuleProvidersNonTransient(); m_existingProject->bgLocker = nullptr; } m_newProject->bgLocker = bgLocker; deleteLocker = false; } catch (const ErrorInfo &error) { m_newProject.reset(); setError(error); // Delete the build graph locker if and only if we allocated it here. if (deleteLocker) delete bgLocker; } emit finished(this); } void InternalSetupProjectJob::execute() { RulesEvaluationContextPtr evalContext(new RulesEvaluationContext(logger())); evalContext->setObserver(observer()); switch (m_parameters.restoreBehavior()) { case SetupProjectParameters::ResolveOnly: resolveProjectFromScratch(evalContext->engine()); resolveBuildDataFromScratch(evalContext); break; case SetupProjectParameters::RestoreOnly: m_newProject = restoreProject(evalContext).loadedProject; break; case SetupProjectParameters::RestoreAndTrackChanges: case SetupProjectParameters::RestoreAndResolve: { const BuildGraphLoadResult loadResult = restoreProject(evalContext); m_newProject = loadResult.newlyResolvedProject; if (!m_newProject) m_newProject = loadResult.loadedProject; if (!m_newProject) { resolveProjectFromScratch(evalContext->engine()); resolveBuildDataFromScratch(evalContext); } else { QBS_CHECK(m_newProject->buildData); } break; } } if (!m_parameters.dryRun()) storeBuildGraph(m_newProject); // The evalutation context cannot be re-used for building, which runs in a different thread. m_newProject->buildData->evaluationContext.reset(); } void InternalSetupProjectJob::resolveProjectFromScratch(ScriptEngine *engine) { ProjectResolver resolver(m_parameters, engine, logger()); resolver.setProgressObserver(observer()); m_newProject = resolver.resolve(); QBS_CHECK(m_newProject); } void InternalSetupProjectJob::resolveBuildDataFromScratch(const RulesEvaluationContextPtr &evalContext) { BuildDataResolver(logger(), m_parameters).resolveBuildData(m_newProject, evalContext); } BuildGraphLoadResult InternalSetupProjectJob::restoreProject(const RulesEvaluationContextPtr &evalContext) { BuildGraphLoader bgLoader(logger()); BuildGraphLoadResult loadResult = bgLoader.load(m_existingProject, m_parameters, evalContext); return loadResult; } BuildGraphTouchingJob::BuildGraphTouchingJob(const Logger &logger, QObject *parent) : InternalJob(logger, parent), m_dryRun(false) { } BuildGraphTouchingJob::~BuildGraphTouchingJob() = default; void BuildGraphTouchingJob::setup(const TopLevelProjectPtr &project, const QVector &products, bool dryRun) { m_project = project; m_products = products; m_dryRun = dryRun; } void BuildGraphTouchingJob::storeBuildGraph() { if (!m_dryRun && !error().isInternalError()) InternalJob::storeBuildGraph(m_project); } InternalBuildJob::InternalBuildJob(const Logger &logger, QObject *parent) : BuildGraphTouchingJob(logger, parent), m_executor(nullptr) { } void InternalBuildJob::build(const TopLevelProjectPtr &project, const QVector &products, const BuildOptions &buildOptions) { setup(project, products, buildOptions.dryRun()); setTimed(buildOptions.logElapsedTime()); m_executor = new Executor(logger()); m_executor->setProject(project); m_executor->setProducts(products); m_executor->setBuildOptions(buildOptions); m_executor->setProgressObserver(observer()); const auto executorThread = new QThread(this); m_executor->moveToThread(executorThread); connect(m_executor, &Executor::reportCommandDescription, this, &BuildGraphTouchingJob::reportCommandDescription); connect(m_executor, &Executor::reportProcessResult, this, &BuildGraphTouchingJob::reportProcessResult); connect(executorThread, &QThread::started, m_executor, &Executor::build); connect(m_executor, &Executor::finished, this, &InternalBuildJob::handleFinished); connect(m_executor, &QObject::destroyed, executorThread, &QThread::quit); connect(executorThread, &QThread::finished, this, &InternalBuildJob::emitFinished); executorThread->start(); } void InternalBuildJob::handleFinished() { setError(m_executor->error()); project()->buildData->evaluationContext.reset(); storeBuildGraph(); m_executor->deleteLater(); } void InternalBuildJob::emitFinished() { emit finished(this); } InternalCleanJob::InternalCleanJob(const Logger &logger, QObject *parent) : BuildGraphTouchingJob(logger, parent) { } void InternalCleanJob::init(const TopLevelProjectPtr &project, const QVector &products, const CleanOptions &options) { setup(project, products, options.dryRun()); setTimed(options.logElapsedTime()); m_options = options; } void InternalCleanJob::start() { try { ArtifactCleaner cleaner(logger(), observer()); cleaner.cleanup(project(), products(), m_options); } catch (const ErrorInfo &error) { setError(error); } storeBuildGraph(); emit finished(this); } InternalInstallJob::InternalInstallJob(const Logger &logger) : InternalJob(logger) { } InternalInstallJob::~InternalInstallJob() = default; void InternalInstallJob::init(const TopLevelProjectPtr &project, const QVector &products, const InstallOptions &options) { m_project = project; m_products = products; m_options = options; setTimed(options.logElapsedTime()); } void InternalInstallJob::start() { try { ProductInstaller(m_project, m_products, m_options, observer(), logger()).install(); } catch (const ErrorInfo &error) { setError(error); } emit finished(this); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/transformerdata_p.h0000644000175100001660000000431214776170045022061 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TRANSFORMERDATA_P_H #define QBS_TRANSFORMERDATA_P_H #include "transformerdata.h" namespace qbs { namespace Internal { class TransformerDataPrivate : public QSharedData { public: QList inputs; QList outputs; RuleCommandList commands; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/transformerdata.cpp0000644000175100001660000000470514776170045022103 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "transformerdata_p.h" #include namespace qbs { TransformerData::TransformerData() : d(new Internal::TransformerDataPrivate) { } TransformerData::TransformerData(const TransformerData &other) = default; TransformerData::~TransformerData() = default; TransformerData& TransformerData::operator=(const TransformerData &other) = default; QList TransformerData::inputs() const { return d->inputs; } QList TransformerData::outputs() const { return d->outputs; } RuleCommandList TransformerData::commands() const { return d->commands; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/changeset.h0000644000175100001660000001011114776170045020301 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_CHANGESET_H #define QBS_CHANGESET_H #include #include namespace QbsQmlJS { class ChangeSet { public: struct EditOp { enum Type { Unset, Replace, Move, Insert, Remove, Flip, Copy }; EditOp(): type(Unset), pos1(0), pos2(0), length1(0), length2(0) {} EditOp(Type t): type(t), pos1(0), pos2(0), length1(0), length2(0) {} Type type; int pos1; int pos2; int length1; int length2; QString text; }; struct Range { Range() : start(0), end(0) {} Range(int start, int end) : start(start), end(end) {} int start; int end; }; public: ChangeSet(); ChangeSet(QList operations); bool empty() const; QList operationList() const; void clear(); bool replace(const Range &range, const QString &replacement); bool remove(const Range &range); bool move(const Range &range, int to); bool flip(const Range &range1, const Range &range2); bool copy(const Range &range, int to); bool replace(int start, int end, const QString &replacement); bool remove(int start, int end); bool move(int start, int end, int to); bool flip(int start1, int end1, int start2, int end2); bool copy(int start, int end, int to); bool insert(int pos, const QString &text); bool hadErrors(); void apply(QString *s); private: // length-based API. bool replace_helper(int pos, int length, const QString &replacement); bool move_helper(int pos, int length, int to); bool remove_helper(int pos, int length); bool flip_helper(int pos1, int length1, int pos2, int length2); bool copy_helper(int pos, int length, int to); bool hasOverlap(int pos, int length); QString textAt(int pos, int length); void doReplace(const EditOp &replace, QList *replaceList); void convertToReplace(const EditOp &op, QList *replaceList); void apply_helper(); private: QString *m_string; QList m_operationList; bool m_error; }; } // namespace QbsQmlJS #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/rulecommand_p.h0000644000175100001660000000466414776170045021205 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RULECOMMAND_P_H #define QBS_RULECOMMAND_P_H #include "rulecommand.h" #include #include namespace qbs { namespace Internal { class RuleCommandPrivate : public QSharedData { public: RuleCommandPrivate(): type(RuleCommand::InvalidType) {} RuleCommand::Type type; QString description; QString extendedDescription; QString sourceCode; QString executable; QStringList arguments; QString workingDir; QProcessEnvironment environment; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/api/rulecommand.cpp0000644000175100001660000001206314776170045021211 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rulecommand.h" #include "rulecommand_p.h" #include namespace qbs { /*! * \class RuleCommand * \brief The \c RuleCommand class corresponds to a \c ProcessCommand or \c JavaScriptCommand * in \QBS. */ /*! * \enum RuleCommand::Type * This enum type represents the different kinds of commands. * \value ProcessCommandType For the \QBS type \c ProcessCommand, which represents a command * whose execution involves calling an executable. * \value JavaScriptCommandType For the \QBS type \c JavaScriptCommand, which represents a command * whose execution involves running a piece of JavaScript code inside \QBS. * \value InvalidType Used to mark \c RuleCommand objects as invalid. */ RuleCommand::RuleCommand() : d(new Internal::RuleCommandPrivate) { } RuleCommand::RuleCommand(const RuleCommand &other) = default; RuleCommand::~RuleCommand() = default; RuleCommand& RuleCommand::operator=(const RuleCommand &other) = default; /*! * Returns the type of this object. If the value is \c InvalidType, the object is invalid. */ RuleCommand::Type RuleCommand::type() const { return d->type; } /*! * Returns the human-readable description of this command that \QBS will print when * the command executed. */ QString RuleCommand::description() const { return d->description; } /*! * Returns the detailed description of this command that \QBS will print when * the command is executed. */ QString RuleCommand::extendedDescription() const { return d->extendedDescription; } /*! * Returns the source of the command if \c type() is \c JavaScriptCommandType. * If \c type() is anything else, the behavior of this function is undefined. */ QString RuleCommand::sourceCode() const { QBS_ASSERT(type() == JavaScriptCommandType, return {}); return d->sourceCode; } /*! * Returns the executable that will be called when the corresponding \c ProcessCommand * is executed. * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. */ QString RuleCommand::executable() const { QBS_ASSERT(type() == ProcessCommandType, return {}); return d->executable; } /*! * Returns the command-line arguments of the executable that will be called when the * corresponding \c ProcessCommand is executed. * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. */ QStringList RuleCommand::arguments() const { QBS_ASSERT(type() == ProcessCommandType, return {}); return d->arguments; } /*! * Returns the working directory of the executable that will be called when the * corresponding \c ProcessCommand is executed. * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. */ QString RuleCommand::workingDirectory() const { QBS_ASSERT(type() == ProcessCommandType, return {}); return d->workingDir; } /*! * Returns the environment of the executable that will be called when the * corresponding \c ProcessCommand is executed. * If \c type() is not \c ProcessCommandType, the behavior of this function is undefined. */ QProcessEnvironment RuleCommand::environment() const { QBS_ASSERT(type() == ProcessCommandType, return {}); return d->environment; } } // namespace qbs qbs-src-2.6.1/src/lib/corelib/api/runenvironment.h0000644000175100001660000000714514776170045021446 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RUNENVIRONMENT_H #define QBS_RUNENVIRONMENT_H #include #include #include #include #include QT_BEGIN_NAMESPACE class QProcess; class QProcessEnvironment; QT_END_NAMESPACE class TestApi; namespace qbs { class ErrorInfo; class InstallOptions; class Settings; namespace Internal { class Logger; class ResolvedProduct; } // namespace Internal class QBS_EXPORT RunEnvironment { friend class CommandLineFrontend; friend class Project; friend class ::TestApi; public: ~RunEnvironment(); int runShell(ErrorInfo *error = nullptr); int runTarget(const QString &targetBin, const QStringList &arguments, bool dryRun, ErrorInfo *error = nullptr); const QProcessEnvironment runEnvironment(ErrorInfo *error = nullptr) const; const QProcessEnvironment buildEnvironment(ErrorInfo *error = nullptr) const; private: RunEnvironment(const Internal::ResolvedProductPtr &product, const Internal::TopLevelProjectConstPtr &project, const InstallOptions &installOptions, const QProcessEnvironment &environment, const QStringList &setupRunEnvConfig, Settings *settings, const Internal::Logger &logger); int doRunShell(); int doRunTarget(const QString &targetBin, const QStringList &arguments, bool dryRun); void printStartInfo(const QProcess &proc, bool dryRun); const QProcessEnvironment getRunEnvironment() const; const QProcessEnvironment getBuildEnvironment() const; class RunEnvironmentPrivate; const std::unique_ptr d; }; } // namespace qbs #endif // QBS_RUNENVIRONMENT_H qbs-src-2.6.1/src/lib/corelib/api/project.h0000644000175100001660000001613214776170045020017 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECT_H #define QBS_PROJECT_H #include "rulecommand.h" #include "transformerdata.h" #include "../language/forward_decls.h" #include "../tools/error.h" #include "../tools/porting.h" #include "../tools/qbs_export.h" #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QIODevice; class QObject; class QProcessEnvironment; QT_END_NAMESPACE namespace qbs { class BuildJob; class BuildOptions; class CleanJob; class CleanOptions; class GroupData; class ILogSink; class InstallJob; class InstallOptions; class ProductData; class ProjectData; class RunEnvironment; class Settings; class SetupProjectJob; class SetupProjectParameters; namespace Internal { class Logger; class ProjectPrivate; } // namespace Internal; class QBS_EXPORT Project { friend class SetupProjectJob; friend QHashValueType qHash(const Project &p); public: SetupProjectJob *setupProject(const SetupProjectParameters ¶meters, ILogSink *logSink, QObject *jobOwner); Project(); Project(const Project &other); Project &operator=(const Project &other); ~Project(); bool isValid() const; QString profile() const; ProjectData projectData() const; RunEnvironment getRunEnvironment(const ProductData &product, const InstallOptions &installOptions, const QProcessEnvironment &environment, const QStringList &setupRunEnvConfig, Settings *settings) const; enum ProductSelection { ProductSelectionDefaultOnly, ProductSelectionWithNonDefault }; BuildJob *buildAllProducts(const BuildOptions &options, ProductSelection productSelection = ProductSelectionDefaultOnly, QObject *jobOwner = nullptr) const; BuildJob *buildSomeProducts(const QList &products, const BuildOptions &options, QObject *jobOwner = nullptr) const; BuildJob *buildOneProduct(const ProductData &product, const BuildOptions &options, QObject *jobOwner = nullptr) const; CleanJob *cleanAllProducts(const CleanOptions &options, QObject *jobOwner = nullptr) const; CleanJob *cleanSomeProducts(const QList &products, const CleanOptions &options, QObject *jobOwner = nullptr) const; CleanJob *cleanOneProduct(const ProductData &product, const CleanOptions &options, QObject *jobOwner = nullptr) const; InstallJob *installAllProducts(const InstallOptions &options, ProductSelection productSelection = ProductSelectionDefaultOnly, QObject *jobOwner = nullptr) const; InstallJob *installSomeProducts(const QList &products, const InstallOptions &options, QObject *jobOwner = nullptr) const; InstallJob *installOneProduct(const ProductData &product, const InstallOptions &options, QObject *jobOwner = nullptr) const; void updateTimestamps(const QList &products); bool operator==(const Project &other) const { return d.data() == other.d.data(); } QStringList generatedFiles(const ProductData &product, const QString &file, bool recursive, const QStringList &tags = QStringList()) const; QVariantMap projectConfiguration() const; std::set buildSystemFiles() const; CodeLinks codeLinks() const; RuleCommandList ruleCommands(const ProductData &product, const QString &inputFilePath, const QString &outputFileTag, ErrorInfo *error = nullptr) const; ProjectTransformerData transformerData(ErrorInfo *error = nullptr) const; ErrorInfo dumpNodesTree(QIODevice &outDevice, const QList &products); class BuildGraphInfo { public: QString bgFilePath; QVariantMap overriddenProperties; QVariantMap profileData; QVariantMap requestedProperties; ErrorInfo error; }; static BuildGraphInfo getBuildGraphInfo(const QString &bgFilePath, const QStringList &requestedProperties); // Use with loaded project. Does not set requestedProperties. BuildGraphInfo getBuildGraphInfo() const; ErrorInfo addGroup(const ProductData &product, const QString &groupName); ErrorInfo addFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths); ErrorInfo removeFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths); ErrorInfo removeGroup(const ProductData &product, const GroupData &group); private: Project(const Internal::TopLevelProjectPtr &internalProject, const Internal::Logger &logger); QExplicitlySharedDataPointer d; }; inline bool operator!=(const Project &p1, const Project &p2) { return !(p1 == p2); } inline QHashValueType qHash(const Project &p) { return QT_PREPEND_NAMESPACE(qHash)(p.d.data()); } } // namespace qbs #endif // QBS_PROJECT_H qbs-src-2.6.1/src/lib/corelib/api/projectdata.h0000644000175100001660000002206514776170045020653 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECTDATA_H #define QBS_PROJECTDATA_H #include "../tools/codelocation.h" #include "../tools/qbs_export.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { class ArtifactDataPrivate; class GroupDataPrivate; class InstallDataPrivate; class ProductDataPrivate; class ProjectPrivate; class ProjectDataPrivate; class PropertyMapPrivate; } // namespace Internal class PropertyMap; QBS_EXPORT bool operator==(const PropertyMap &pm1, const PropertyMap &pm2); QBS_EXPORT bool operator!=(const PropertyMap &pm1, const PropertyMap &pm2); class QBS_EXPORT PropertyMap { friend class Internal::ProjectPrivate; friend QBS_EXPORT bool operator==(const PropertyMap &, const PropertyMap &); friend QBS_EXPORT bool operator!=(const PropertyMap &, const PropertyMap &); public: struct PropertyInfo { QString name; QString type; QVariant value; bool isBuiltin = false; }; PropertyMap(); PropertyMap(const PropertyMap &other); PropertyMap(PropertyMap &&other) Q_DECL_NOEXCEPT; ~PropertyMap(); PropertyMap &operator =(const PropertyMap &other); PropertyMap &operator =(PropertyMap &&other) Q_DECL_NOEXCEPT; QStringList allProperties() const; QStringList allModules() const; QList allPropertiesForModule(const QString &module) const; QVariant getProperty(const QString &name) const; QStringList getModulePropertiesAsStringList(const QString &moduleName, const QString &propertyName) const; QVariant getModuleProperty(const QString &moduleName, const QString &propertyName) const; // For debugging. QString toString() const; private: std::unique_ptr d; }; class InstallData; class QBS_EXPORT ArtifactData { friend class Internal::ProjectPrivate; public: ArtifactData(); ArtifactData(const ArtifactData &other); ArtifactData(ArtifactData &&) Q_DECL_NOEXCEPT; ArtifactData &operator=(const ArtifactData &other); ArtifactData &operator=(ArtifactData &&) Q_DECL_NOEXCEPT; ~ArtifactData(); bool isValid() const; QJsonObject toJson(const QStringList &moduleProperties = {}) const; QString filePath() const; QStringList fileTags() const; bool isGenerated() const; bool isExecutable() const; bool isTargetArtifact() const; PropertyMap properties() const; InstallData installData() const; private: QExplicitlySharedDataPointer d; }; class QBS_EXPORT InstallData { friend class Internal::ProjectPrivate; public: InstallData(); InstallData(const InstallData &other); InstallData(InstallData &&) Q_DECL_NOEXCEPT; InstallData &operator=(const InstallData &other); InstallData &operator=(InstallData &&) Q_DECL_NOEXCEPT; ~InstallData(); bool isValid() const; QJsonObject toJson() const; bool isInstallable() const; QString installDir() const; QString installFilePath() const; QString installRoot() const; QString localInstallDir() const; QString localInstallFilePath() const; private: QExplicitlySharedDataPointer d; }; QBS_EXPORT bool operator==(const ArtifactData &ta1, const ArtifactData &ta2); QBS_EXPORT bool operator!=(const ArtifactData &ta1, const ArtifactData &ta2); QBS_EXPORT bool operator<(const ArtifactData &ta1, const ArtifactData &ta2); class QBS_EXPORT GroupData { friend class Internal::ProjectPrivate; public: GroupData(); GroupData(const GroupData &other); GroupData(GroupData &&) Q_DECL_NOEXCEPT; GroupData &operator=(const GroupData &other); GroupData &operator=(GroupData &&) Q_DECL_NOEXCEPT; ~GroupData(); bool isValid() const; QJsonObject toJson(const QStringList &moduleProperties = {}) const; CodeLocation location() const; QString name() const; QString prefix() const; QList sourceArtifacts() const; QList sourceArtifactsFromWildcards() const; QList allSourceArtifacts() const; PropertyMap properties() const; bool isEnabled() const; QStringList allFilePaths() const; private: QExplicitlySharedDataPointer d; }; QBS_EXPORT bool operator==(const GroupData &lhs, const GroupData &rhs); QBS_EXPORT bool operator!=(const GroupData &lhs, const GroupData &rhs); QBS_EXPORT bool operator<(const GroupData &lhs, const GroupData &rhs); class QBS_EXPORT ProductData { friend class Internal::ProjectPrivate; public: ProductData(); ProductData(const ProductData &other); ProductData(ProductData &&) Q_DECL_NOEXCEPT; ProductData &operator=(const ProductData &other); ProductData &operator=(ProductData &&) Q_DECL_NOEXCEPT; ~ProductData(); bool isValid() const; QJsonObject toJson(const QStringList &propertyNames = {}) const; const QStringList &type() const; const QStringList &dependencies() const; const QString &name() const; QString fullDisplayName() const; const QString &targetName() const; const QString &version() const; QString profile() const; const QString &multiplexConfigurationId() const; const CodeLocation &location() const; const QString &buildDirectory() const; const QList &generatedArtifacts() const; const QList targetArtifacts() const; const QList installableArtifacts() const; QString targetExecutable() const; const QList &groups() const; const QVariantMap &properties() const; const PropertyMap &moduleProperties() const; bool isEnabled() const; bool isRunnable() const; bool isMultiplexed() const; private: QExplicitlySharedDataPointer d; }; QBS_EXPORT bool operator==(const ProductData &lhs, const ProductData &rhs); QBS_EXPORT bool operator!=(const ProductData &lhs, const ProductData &rhs); QBS_EXPORT bool operator<(const ProductData &lhs, const ProductData &rhs); class QBS_EXPORT ProjectData { friend class Internal::ProjectPrivate; public: ProjectData(); ProjectData(const ProjectData &other); ProjectData(ProjectData &&) Q_DECL_NOEXCEPT; ProjectData &operator=(const ProjectData &other); ProjectData &operator=(ProjectData &&) Q_DECL_NOEXCEPT; ~ProjectData(); bool isValid() const; QJsonObject toJson(const QStringList &moduleProperties = {}) const; const QString &name() const; const CodeLocation &location() const; bool isEnabled() const; const QString &buildDirectory() const; const QList &products() const; const QList &subProjects() const; const QList allProducts() const; const QList installableArtifacts() const; private: QExplicitlySharedDataPointer d; }; QBS_EXPORT bool operator==(const ProjectData &lhs, const ProjectData &rhs); QBS_EXPORT bool operator!=(const ProjectData &lhs, const ProjectData &rhs); QBS_EXPORT bool operator<(const ProjectData &lhs, const ProjectData &rhs); } // namespace qbs #endif // QBS_PROJECTDATA_H qbs-src-2.6.1/src/lib/corelib/jsextensions/0000755000175100001660000000000014776170045020160 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/jsextensions/propertylistutils.h0000644000175100001660000000513214776170045024173 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2014 Petroules Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QPROPERTYLISTUTILS_H #define QPROPERTYLISTUTILS_H #include #import #if !defined(__OBJC__) || !defined(__cplusplus) #error "This file must be included from Objective-C++" #endif class QPropertyListUtils { Q_DISABLE_COPY(QPropertyListUtils) public: static QVariant fromPropertyList(id plist); static id toPropertyList(const QVariant &map); private: QPropertyListUtils(); }; template QMap qHashToMap(const QHash &hash) { QMap map; for (auto i = hash.cbegin(), end = hash.cend(); i != end; ++i) map.insert(i.key(), i.value()); return map; } #endif // QPROPERTYLISTUTILS_H qbs-src-2.6.1/src/lib/corelib/jsextensions/propertylist_darwin.mm0000644000175100001660000003054614776170045024647 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include "propertylistutils.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { class PropertyList : public JsExtension { public: static const char *name() { return "PropertyList"; } static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int, JSValueConst *, int); PropertyList(JSContext *) {} static void setupMethods(JSContext *ctx, JSValue obj); DEFINE_JS_FORWARDER(jsIsEmpty, &PropertyList::isEmpty, "PropertyList.isEmpty"); DEFINE_JS_FORWARDER(jsClear, &PropertyList::clear, "PropertyList.clear"); DEFINE_JS_FORWARDER(jsReadFromObject, &PropertyList::readFromObject, "PropertyList.readFromObject"); DEFINE_JS_FORWARDER(jsReadFromString, &PropertyList::readFromString, "PropertyList.readFromString"); DEFINE_JS_FORWARDER(jsReadFromFile, &PropertyList::readFromFile, "PropertyList.readFromFile"); DEFINE_JS_FORWARDER(jsReadFromData, &PropertyList::readFromData, "PropertyList.readFromData"); DEFINE_JS_FORWARDER(jsWriteToFile, &PropertyList::writeToFile, "PropertyList.writeToFile"); DEFINE_JS_FORWARDER(jsFormat, &PropertyList::format, "PropertyList.format"); DEFINE_JS_FORWARDER(jsToObject, &PropertyList::toObject, "PropertyList.toObject"); DEFINE_JS_FORWARDER(jsToString, &PropertyList::toString, "PropertyList.toString"); DEFINE_JS_FORWARDER(jsToXmlString, &PropertyList::toXMLString, "PropertyList.toXMLString"); static JSValue jsToJson(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { QString style; if (argc > 0) style = fromArg(ctx, "Process.exec", 1, argv[0]); return toJsValue(ctx, fromJsObject(ctx, this_val)->toJSON(style)); } catch (const QString &error) { return throwError(ctx, error); } } private: bool isEmpty() const { return m_propertyListObject.isNull(); } void clear(); void readFromObject(const QVariant &value); void readFromString(const QString &input); void readFromFile(const QString &filePath); void readFromData(const QByteArray &data); void writeToFile(const QString &filePath, const QString &plistFormat); std::optional format() const; QVariant toObject() const { return m_propertyListObject.isNull() ? QVariantMap() : m_propertyListObject; } QString toString(const QString &plistFormat) const; QString toXMLString() const; QString toJSON(const QString &style = QString()) const; QByteArray writeToData(const QString &format) const; QVariant m_propertyListObject; int m_propertyListFormat = 0; }; // Same values as CoreFoundation and Foundation APIs enum { QPropertyListOpenStepFormat = 1, QPropertyListXMLFormat_v1_0 = 100, QPropertyListBinaryFormat_v1_0 = 200, QPropertyListJSONFormat = 1000 // If this conflicts someday, just change it :) }; JSValue PropertyList::ctor(JSContext *ctx, JSValueConst, JSValueConst, int, JSValueConst *, int) { try { JSValue obj = createObject(ctx); const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{ DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }; se->checkContext(QStringLiteral("qbs.PropertyList"), dubiousContexts); return obj; } catch (const QString &error) { return throwError(ctx, error); } } void PropertyList::setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "isEmpty", &jsIsEmpty, 0); setupMethod(ctx, obj, "clear", &jsClear, 0); setupMethod(ctx, obj, "readFromObject", &jsReadFromObject, 1); setupMethod(ctx, obj, "readFromString", &jsReadFromString, 1); setupMethod(ctx, obj, "readFromFile", &jsReadFromFile, 1); setupMethod(ctx, obj, "readFromData", &jsReadFromData, 1); setupMethod(ctx, obj, "writeToFile", &jsWriteToFile, 1); setupMethod(ctx, obj, "format", &jsFormat, 0); setupMethod(ctx, obj, "toObject", &jsToObject, 0); setupMethod(ctx, obj, "toString", &jsToString, 1); setupMethod(ctx, obj, "toXMLString", &jsToXmlString, 1); setupMethod(ctx, obj, "toJSON", &jsToJson, 1); } void PropertyList::clear() { m_propertyListObject = QVariant(); m_propertyListFormat = 0; } void PropertyList::readFromObject(const QVariant &value) { m_propertyListObject = value; m_propertyListFormat = 0; // wasn't deserialized from any external format } void PropertyList::readFromString(const QString &input) { readFromData(input.toUtf8()); } void PropertyList::readFromFile(const QString &filePath) { QFile file(filePath); if (file.open(QIODevice::ReadOnly)) { const QByteArray data = file.readAll(); if (file.error() == QFile::NoError) { readFromData(data); return; } } throw QStringLiteral("%1: %2").arg(filePath).arg(file.errorString()); } void PropertyList::readFromData(const QByteArray &data) { @autoreleasepool { NSPropertyListFormat format; int internalFormat = 0; NSString *errorString = nil; id plist = [NSPropertyListSerialization propertyListWithData:data.toNSData() options:0 format:&format error:nil]; if (plist) { internalFormat = format; } else { NSError *error = nil; plist = [NSJSONSerialization JSONObjectWithData:data.toNSData() options:0 error:&error]; if (Q_UNLIKELY(!plist)) { errorString = [error localizedDescription]; } else { internalFormat = QPropertyListJSONFormat; } } if (Q_UNLIKELY(!plist)) throw QString::fromNSString(errorString); QVariant obj = QPropertyListUtils::fromPropertyList(plist); if (!obj.isNull()) { m_propertyListObject = obj; m_propertyListFormat = internalFormat; } else { throw Tr::tr("error converting property list"); } } } void PropertyList::writeToFile(const QString &filePath, const QString &plistFormat) { QFile file(filePath); QByteArray data = writeToData(plistFormat); if (Q_LIKELY(!data.isEmpty())) { if (file.open(QIODevice::WriteOnly) && file.write(data) == data.size()) { return; } } throw QStringLiteral("%1: %2").arg(filePath).arg(file.errorString()); } std::optional PropertyList::format() const { switch (m_propertyListFormat) { case QPropertyListOpenStepFormat: return QStringLiteral("openstep"); case QPropertyListXMLFormat_v1_0: return QStringLiteral("xml1"); case QPropertyListBinaryFormat_v1_0: return QStringLiteral("binary1"); case QPropertyListJSONFormat: return QStringLiteral("json"); default: return {}; } } QString PropertyList::toString(const QString &plistFormat) const { if (plistFormat == QLatin1String("binary1")) { throw Tr::tr("Property list object cannot be converted to a " "string in the binary1 format; this format can only " "be written directly to a file"); } if (!isEmpty()) return QString::fromUtf8(writeToData(plistFormat)); return {}; } QString PropertyList::toXMLString() const { return toString(QStringLiteral("xml1")); } QString PropertyList::toJSON(const QString &style) const { QString format = QLatin1String("json"); if (!style.isEmpty()) format += QLatin1String("-") + style; return toString(format); } QByteArray PropertyList::writeToData(const QString &format) const { @autoreleasepool { NSError *error = nil; NSString *errorString = nil; NSData *data = nil; id obj = QPropertyListUtils::toPropertyList(m_propertyListObject); if (!obj) throw Tr::tr("error converting property list"); if (format == QLatin1String("json") || format == QLatin1String("json-pretty") || format == QLatin1String("json-compact")) { if ([NSJSONSerialization isValidJSONObject:obj]) { error = nil; errorString = nil; const NSJSONWritingOptions options = format == QLatin1String("json-pretty") ? NSJSONWritingPrettyPrinted : 0; data = [NSJSONSerialization dataWithJSONObject:obj options:options error:&error]; if (Q_UNLIKELY(!data)) { errorString = [error localizedDescription]; } } else { errorString = @"Property list object cannot be converted to JSON data"; } } else if (format == QLatin1String("xml1") || format == QLatin1String("binary1")) { const NSPropertyListFormat plistFormat = format == QLatin1String("xml1") ? NSPropertyListXMLFormat_v1_0 : NSPropertyListBinaryFormat_v1_0; error = nil; errorString = nil; data = [NSPropertyListSerialization dataWithPropertyList:obj format:plistFormat options:0 error:&error]; if (Q_UNLIKELY(!data)) { errorString = [error localizedDescription]; } } else { errorString = [NSString stringWithFormat:@"Property lists cannot be written in the '%s' " @"format", format.toUtf8().constData()]; } if (Q_UNLIKELY(!data)) throw QString::fromNSString(errorString); return QByteArray::fromNSData(data); } } } // namespace Internal } // namespace qbs void initializeJsExtensionPropertyList(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::PropertyList::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/domxml.cpp0000644000175100001660000005704414776170045022176 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 BogDan Vatra ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include namespace qbs { namespace Internal { template class XmlDomNode : public JsExtension> { public: static const char *name(); XmlDomNode(const C &value) : m_value(value) {} XmlDomNode(JSContext *, const QString &name); XmlDomNode(JSContext *) {} static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int); static void setupMethods(JSContext *ctx, JSValue obj); C value() const { return m_value; } private: #define XML_JS_FWD(name, func, text) DEFINE_JS_FORWARDER_QUAL(XmlDomNode, name, func, text) XML_JS_FWD(jsIsElement, &XmlDomNode::isElement, "DomNode.isElement"); XML_JS_FWD(jsIsCDATASection, &XmlDomNode::isCDATASection, "DomNode.isCDATASection"); XML_JS_FWD(jsIsText, &XmlDomNode::isText, "DomNode.isText"); XML_JS_FWD(jsHasAttribute, &XmlDomNode::hasAttribute, "DomNode.hasAttribute"); XML_JS_FWD(jsTagName, &XmlDomNode::tagName, "DomNode.tagName"); XML_JS_FWD(jsSetTagName, &XmlDomNode::setTagName, "DomNode.setTagName"); XML_JS_FWD(jsText, &XmlDomNode::text, "DomNode.text"); XML_JS_FWD(jsData, &XmlDomNode::data, "DomNode.data"); XML_JS_FWD(jsSetData, &XmlDomNode::setData, "DomNode.setData"); XML_JS_FWD(jsClear, &XmlDomNode::clear, "DomNode.clear"); XML_JS_FWD(jsHasAttributes, &XmlDomNode::hasAttributes, "DomNode.hasAttributes"); XML_JS_FWD(jsHasChildNodes, &XmlDomNode::hasChildNodes, "DomNode.hasChildNodes"); XML_JS_FWD(jsSetAttribute, &XmlDomNode::setAttribute, "DomNode.setAttribute"); XML_JS_FWD(jsAppendChild, &XmlDomNode::appendChild, "DomNode.appendChild"); XML_JS_FWD(jsInsertBefore, &XmlDomNode::insertBefore, "DomNode.insertBefore"); XML_JS_FWD(jsInsertAfter, &XmlDomNode::insertAfter, "DomNode.insertAfter"); XML_JS_FWD(jsReplaceChild, &XmlDomNode::replaceChild, "DomNode.replaceChild"); XML_JS_FWD(jsRemoveChild, &XmlDomNode::removeChild, "DomNode.removeChild"); static JSValue jsAttribute(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { const auto name = JsExtension::template getArgument (ctx, "DomNode.attribute", argc, argv); QString defaultValue; if (argc > 1) defaultValue = JsExtension::template fromArg (ctx, "DomNode.attribute", 2, argv[1]); return makeJsString(ctx, JsExtension::fromJsObject (ctx, this_val)->attribute(name, defaultValue)); } catch (const QString &error) { return throwError(ctx, error); } } static JSValue jsParentNode(JSContext *ctx, JSValueConst this_val, int, JSValueConst *) { return JsExtension>::createObjectDirect( ctx, JsExtension::fromJsObject(ctx, this_val)->parentNode()); } static JSValue jsFirstChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { QString tagName; if (argc > 0) tagName = JsExtension::template getArgument (ctx, "DomNode.firstChild", argc, argv); return JsExtension>::createObjectDirect (ctx, JsExtension::fromJsObject(ctx, this_val)->firstChild(tagName)); } catch (const QString &error) { return throwError(ctx, error); } } static JSValue jsLastChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { QString tagName; if (argc > 0) tagName = JsExtension::template getArgument (ctx, "DomNode.lastChild", argc, argv); return JsExtension>::createObjectDirect (ctx, JsExtension::fromJsObject(ctx, this_val)->lastChild(tagName)); } catch (const QString &error) { return throwError(ctx, error); } } static JSValue jsPreviousSibling(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { QString tagName; if (argc > 0) tagName = JsExtension::template getArgument (ctx, "DomNode.previousSibling", argc, argv); return JsExtension>::createObjectDirect(ctx, JsExtension::fromJsObject (ctx, this_val)->previousSibling(tagName)); } catch (const QString &error) { return throwError(ctx, error); } } static JSValue jsNextSibling(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { QString tagName; if (argc > 0) tagName = JsExtension::template getArgument (ctx, "Xml.DomElement.nextSibling", argc, argv); return JsExtension>::createObjectDirect (ctx, JsExtension::fromJsObject(ctx, this_val)->nextSibling(tagName)); } catch (const QString &error) { return throwError(ctx, error); } } // Implemented for QDomDocument only. static JSValue jsDocumentElement(JSContext *ctx, JSValueConst this_val, int, JSValueConst *); static JSValue jsCreateElement(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static JSValue jsCreateCDATASection(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static JSValue jsCreateTextNode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static JSValue jsSetContent(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static JSValue jsToString(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static JSValue jsSave(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static JSValue jsLoad(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); bool isElement() const { return m_value.isElement(); } bool isCDATASection() const { return m_value.isCDATASection(); } bool isText() const { return m_value.isText(); } QString attribute(const QString &name, const QString &defaultValue) { QDomElement el = m_value.toElement(); if (el.isNull()) throw QStringLiteral("Node '%1' is not an element node").arg(m_value.nodeName()); return el.attribute(name, defaultValue); } void setAttribute(const QString &name, const QString &value) { QDomElement el = m_value.toElement(); if (el.isNull()) throw QStringLiteral("Node '%1' is not an element node").arg(m_value.nodeName()); el.setAttribute(name, value); } bool hasAttribute(const QString &name) const { QDomElement el = m_value.toElement(); if (el.isNull()) throw QStringLiteral("Node '%1' is not an element node").arg(m_value.nodeName()); return el.hasAttribute(name); } QString tagName() const { QDomElement el = m_value.toElement(); if (el.isNull()) throw QStringLiteral("Node '%1' is not an element node").arg(m_value.nodeName()); return el.tagName(); } void setTagName(const QString &name) { QDomElement el = m_value.toElement(); if (el.isNull()) throw QStringLiteral("Node '%1' is not an element node").arg(m_value.nodeName()); el.setTagName(name); } QString text() const { QDomElement el = m_value.toElement(); if (el.isNull()) throw QStringLiteral("Node '%1' is not an element node").arg(m_value.nodeName()); return el.text(); } QString data() const { if (m_value.isText()) return m_value.toText().data(); if (m_value.isCDATASection()) return m_value.toCDATASection().data(); if (m_value.isCharacterData()) return m_value.toCharacterData().data(); throw QStringLiteral("Node '%1' is not a character data node").arg(m_value.nodeName()); } void setData(const QString &v) const { if (m_value.isText()) return m_value.toText().setData(v); if (m_value.isCDATASection()) return m_value.toCDATASection().setData(v); if (m_value.isCharacterData()) return m_value.toCharacterData().setData(v); throw QStringLiteral("Node '%1' is not a character data node").arg(m_value.nodeName()); } void clear() { m_value.clear(); } bool hasAttributes() const { return m_value.hasAttributes(); } bool hasChildNodes() const { return m_value.hasChildNodes(); } XmlDomNode *parentNode() const { return new XmlDomNode(m_value.parentNode()); } XmlDomNode *firstChild(const QString &tagName) { if (tagName.isEmpty()) return new XmlDomNode(m_value.firstChild()); return new XmlDomNode(m_value.firstChildElement(tagName)); } XmlDomNode *lastChild(const QString &tagName) const { if (tagName.isEmpty()) return new XmlDomNode(m_value.lastChild()); return new XmlDomNode(m_value.lastChildElement(tagName)); } XmlDomNode *previousSibling(const QString &tagName) const { if (tagName.isEmpty()) return new XmlDomNode(m_value.previousSibling()); return new XmlDomNode(m_value.previousSiblingElement(tagName)); } XmlDomNode *nextSibling(const QString &tagName) const { if (tagName.isEmpty()) return new XmlDomNode(m_value.nextSibling()); return new XmlDomNode(m_value.nextSiblingElement(tagName)); } void appendChild(const XmlDomNode *newChild) { m_value.appendChild(newChild->value()); } void insertBefore(const XmlDomNode *newChild, const XmlDomNode *refChild) { m_value.insertBefore(newChild->value(), refChild->value()); } void insertAfter(const XmlDomNode *newChild, const XmlDomNode *refChild) { m_value.insertAfter(newChild->value(), refChild->value()); } void replaceChild(const XmlDomNode *newChild, const XmlDomNode *oldChild) { m_value.replaceChild(newChild->value(), oldChild->value()); } void removeChild(const XmlDomNode *oldChild) { m_value.removeChild(oldChild->value()); } // Implemented for QDomDocument only. XmlDomNode *documentElement(); XmlDomNode *createElement(const QString &tagName); XmlDomNode *createCDATASection(const QString &value); XmlDomNode *createTextNode(const QString &value); bool setContent(const QString &content); QString toString(int indent = 1); void save(const QString &filePath, int indent = 1); void load(const QString &filePath); C m_value; }; template<> const char *XmlDomNode::name() { return "DomNode"; } template<> const char *XmlDomNode::name() { return "DomDocument"; } template<> JSValue XmlDomNode::ctor(JSContext *ctx, JSValue, JSValue, int , JSValue *, int) { const JSValue obj = createObject(ctx); const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{ DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }; se->checkContext(QStringLiteral("qbs.Xml.DomNode"), dubiousContexts); se->setUsesIo(); return obj; } template<> JSValue XmlDomNode::ctor(JSContext *ctx, JSValue, JSValue, int argc, JSValue *argv, int) { try { JSValue obj; if (argc == 0) { obj = createObject(ctx); } else { const auto name = getArgument(ctx, "XmlDomDocument constructor", argc, argv); obj = createObject(ctx, name); } const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{ DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }; se->checkContext(QStringLiteral("qbs.Xml.DomDocument"), dubiousContexts); se->setUsesIo(); return obj; } catch (const QString &error) { return throwError(ctx, error); } } template<> XmlDomNode *XmlDomNode::documentElement() { return new XmlDomNode(m_value.documentElement()); } template<> XmlDomNode *XmlDomNode::createElement(const QString &tagName) { return new XmlDomNode(m_value.createElement(tagName)); } template<> XmlDomNode *XmlDomNode::createCDATASection(const QString &value) { return new XmlDomNode(m_value.createCDATASection(value)); } template<> XmlDomNode *XmlDomNode::createTextNode(const QString &value) { return new XmlDomNode(m_value.createTextNode(value)); } template<> bool XmlDomNode::setContent(const QString &content) { return static_cast(m_value.setContent(content)); } template<> QString XmlDomNode::toString(int indent) { return m_value.toString(indent); } template<> JSValue XmlDomNode::jsDocumentElement(JSContext *ctx, JSValue this_val, int, JSValue *) { return XmlDomNode::createObjectDirect( ctx, fromJsObject(ctx, this_val)->documentElement()); } template<> JSValue XmlDomNode::jsCreateElement(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { const auto tagName = getArgument(ctx, "DomDocument.createElement", argc, argv); const JSValue obj = XmlDomNode::createObjectDirect( ctx, fromJsObject(ctx, this_val)->createElement(tagName)); return obj; } catch (const QString &error) { return throwError(ctx, error); } } template<> JSValue XmlDomNode::jsCreateCDATASection(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { const auto value = getArgument(ctx, "DomDocument.createCDATASection", argc, argv); return XmlDomNode::createObjectDirect( ctx, fromJsObject(ctx, this_val)->createCDATASection(value)); } catch (const QString &error) { return throwError(ctx, error); } } template<> JSValue XmlDomNode::jsCreateTextNode(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { const auto value = getArgument(ctx, "DomDocument.createTextNode", argc, argv); return XmlDomNode::createObjectDirect( ctx, fromJsObject(ctx, this_val)->createTextNode(value)); } catch (const QString &error) { return throwError(ctx, error); } } template<> JSValue XmlDomNode::jsSetContent(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { const auto content = getArgument(ctx, "DomDocument.setContent", argc, argv); return JS_NewBool(ctx, fromJsObject(ctx, this_val)->setContent(content)); } catch (const QString &error) { return throwError(ctx, error); } } template<> JSValue XmlDomNode::jsToString(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { qint32 indent = 1; if (argc > 0) indent = getArgument(ctx, "DomDocument.toString", argc, argv); return makeJsString(ctx, fromJsObject(ctx, this_val)->toString(indent)); } catch (const QString &error) { return throwError(ctx, error); } } template<> void XmlDomNode::save(const QString &filePath, int indent) { QFile f(filePath); if (!f.open(QIODevice::WriteOnly)) throw QStringLiteral("unable to open '%1'").arg(filePath); QByteArray buff(m_value.toByteArray(indent)); if (buff.size() != f.write(buff)) throw f.errorString(); f.close(); if (f.error() != QFile::NoError) throw f.errorString(); } template<> JSValue XmlDomNode::jsSave(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "DomDocument.save", argc, argv); qint32 indent = 1; if (argc > 1) indent = fromArg(ctx, "toString", 2, argv[1]); fromJsObject(ctx, this_val)->save(filePath, indent); return JS_UNDEFINED; } catch (const QString &error) { return throwError(ctx, error); } } template<> void XmlDomNode::load(const QString &filePath) { QFile f(filePath); if (!f.open(QIODevice::ReadOnly)) throw QStringLiteral("unable to open '%1'").arg(filePath); QString errorMsg; if (!m_value.setContent(&f, &errorMsg)) throw errorMsg; } template<> JSValue XmlDomNode::jsLoad(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "DomDocument.load", argc, argv); fromJsObject(ctx, this_val)->load(filePath); return JS_UNDEFINED; } catch (const QString &error) { return throwError(ctx, error); } } template<> XmlDomNode::XmlDomNode(JSContext *, const QString &name) : m_value(name) {} template void XmlDomNode::setupMethods(JSContext *ctx, JSValue obj) { JsExtension::setupMethod(ctx, obj, "appendChild", &jsAppendChild, 1); JsExtension::setupMethod(ctx, obj, "attribute", &jsAttribute, 2); JsExtension::setupMethod(ctx, obj, "clear", &jsClear, 0); JsExtension::setupMethod(ctx, obj, "data", &jsData, 0); JsExtension::setupMethod(ctx, obj, "firstChild", &jsFirstChild, 1); JsExtension::setupMethod(ctx, obj, "hasAttribute", &jsHasAttribute, 1); JsExtension::setupMethod(ctx, obj, "hasAttributes", &jsHasAttributes, 0); JsExtension::setupMethod(ctx, obj, "hasChildNodes", &jsHasChildNodes, 0); JsExtension::setupMethod(ctx, obj, "insertAfter", &jsInsertAfter, 2); JsExtension::setupMethod(ctx, obj, "insertBefore", &jsInsertBefore, 2); JsExtension::setupMethod(ctx, obj, "isCDATASection", &jsIsCDATASection, 0); JsExtension::setupMethod(ctx, obj, "isElement", &jsIsElement, 0); JsExtension::setupMethod(ctx, obj, "isText", &jsIsText, 0); JsExtension::setupMethod(ctx, obj, "lastChild", &jsLastChild, 1); JsExtension::setupMethod(ctx, obj, "nextSibling", &jsNextSibling, 1); JsExtension::setupMethod(ctx, obj, "parentNode", &jsParentNode, 0); JsExtension::setupMethod(ctx, obj, "previousSibling", &jsPreviousSibling, 1); JsExtension::setupMethod(ctx, obj, "removeChild", &jsRemoveChild, 1); JsExtension::setupMethod(ctx, obj, "replaceChild", &jsReplaceChild, 2); JsExtension::setupMethod(ctx, obj, "setAttribute", &jsSetAttribute, 2); JsExtension::setupMethod(ctx, obj, "setData", &jsSetData, 1); JsExtension::setupMethod(ctx, obj, "setTagName", &jsSetTagName, 1); JsExtension::setupMethod(ctx, obj, "tagName", &jsTagName, 0); JsExtension::setupMethod(ctx, obj, "text", &jsText, 0); if constexpr (std::is_same_v) { JsExtension::setupMethod(ctx, obj, "documentElement", &jsDocumentElement, 0); JsExtension::setupMethod(ctx, obj, "createElement", &jsCreateElement, 1); JsExtension::setupMethod(ctx, obj, "createCDATASection", &jsCreateCDATASection, 1); JsExtension::setupMethod(ctx, obj, "createTextNode", &jsCreateTextNode, 1); JsExtension::setupMethod(ctx, obj, "setContent", &jsSetContent, 1); JsExtension::setupMethod(ctx, obj, "toString", &jsToString, 1); JsExtension::setupMethod(ctx, obj, "save", &jsSave, 2); JsExtension::setupMethod(ctx, obj, "load", &jsLoad, 1); } } } // namespace Internal } // namespace qbs void initializeJsExtensionXml(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { using namespace qbs::Internal; JSValue contextObject = engine->newObject(); XmlDomNode::registerClass(engine, contextObject); XmlDomNode::registerClass(engine, contextObject); setJsProperty(engine->context(), extensionObject, std::string_view("Xml"), contextObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/utilitiesextension.cpp0000644000175100001660000010705414776170045024643 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include "jsextensions.h" #include #include #include #include #include #include #include #include #include #if defined(Q_OS_MACOS) #include #endif #ifdef __APPLE__ #include #include #include #include #ifndef FAT_MAGIC_64 #define FAT_MAGIC_64 0xcafebabf #define FAT_CIGAM_64 0xbfbafeca struct fat_arch_64 { cpu_type_t cputype; cpu_subtype_t cpusubtype; uint64_t offset; uint64_t size; uint32_t align; uint32_t reserved; }; #endif #endif #ifdef Q_OS_WIN #include #include #include #endif #include #include #include #include #include namespace qbs { namespace Internal { class DummyLogSink : public ILogSink { void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } }; class UtilitiesExtension : public JsExtension { public: static const char *name() { return "Utilities"; } static void setupStaticMethods(JSContext *ctx, JSValue classObj); static JSValue js_canonicalArchitecture(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_canonicalPlatform(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_canonicalTargetArchitecture(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_canonicalToolchain(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_cStringQuote(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_getHash(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_getNativeSetting(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_kernelVersion(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_nativeSettingGroups(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_rfc1034identifier(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_smimeMessageContent(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_certificateInfo(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_signingIdentities(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_msvcCompilerInfo(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_clangClCompilerInfo(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_installedMSVCs(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_installedClangCls(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_versionCompare(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_qmlTypeInfo(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_builtinExtensionNames(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue js_isSharedLibrary(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue js_getArchitecturesFromBinary(JSContext *ctx, JSValueConst, int, JSValueConst *); }; JSValue UtilitiesExtension::js_canonicalPlatform(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto platform = getArgument(ctx, "Utilities.canonicalPlatform", argc, argv); if (platform.isEmpty()) return makeJsStringList(ctx, {}); std::vector platforms = HostOsInfo::canonicalOSIdentifiers(platform); return makeJsStringList(ctx, QStringList(std::move_iterator(platforms.begin()), std::move_iterator(platforms.end()))); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_canonicalTargetArchitecture(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto arch = getArgument(ctx, "Utilities.canonicalTargetArchitecture", argc, argv); QString endianness, vendor, system, abi; if (argc > 1) endianness = fromArg(ctx, "Utilities.canonicalTargetArchitecture", 2, argv[1]); if (argc > 2) vendor = fromArg(ctx, "Utilities.canonicalTargetArchitecture", 3, argv[2]); if (argc > 3) system = fromArg(ctx, "Utilities.canonicalTargetArchitecture", 4, argv[3]); if (argc > 4) abi = fromArg(ctx, "Utilities.canonicalTargetArchitecture", 5, argv[4]); return makeJsString(ctx, canonicalTargetArchitecture(arch, endianness, vendor, system, abi)); } catch (const QString &error) { return throwError(ctx, error); } } void UtilitiesExtension::setupStaticMethods(JSContext *ctx, JSValue classObj) { setupMethod(ctx, classObj, "canonicalArchitecture", &UtilitiesExtension::js_canonicalArchitecture, 1); setupMethod(ctx, classObj, "canonicalPlatform", &UtilitiesExtension::js_canonicalPlatform, 1); setupMethod(ctx, classObj, "canonicalTargetArchitecture", &UtilitiesExtension::js_canonicalTargetArchitecture, 1); setupMethod(ctx, classObj, "canonicalToolchain", &UtilitiesExtension::js_canonicalToolchain, 1); setupMethod(ctx, classObj, "cStringQuote", &UtilitiesExtension::js_cStringQuote, 1); setupMethod(ctx, classObj, "getHash", &UtilitiesExtension::js_getHash, 1); setupMethod(ctx, classObj, "getNativeSetting", &UtilitiesExtension::js_getNativeSetting, 3); setupMethod(ctx, classObj, "kernelVersion", &UtilitiesExtension::js_kernelVersion, 0); setupMethod(ctx, classObj, "nativeSettingGroups", &UtilitiesExtension::js_nativeSettingGroups, 1); setupMethod(ctx, classObj, "rfc1034Identifier", &UtilitiesExtension::js_rfc1034identifier, 1); setupMethod(ctx, classObj, "smimeMessageContent", &UtilitiesExtension::js_smimeMessageContent, 1); setupMethod(ctx, classObj, "certificateInfo", &UtilitiesExtension::js_certificateInfo, 1); setupMethod(ctx, classObj, "signingIdentities", &UtilitiesExtension::js_signingIdentities, 1); setupMethod(ctx, classObj, "msvcCompilerInfo", &UtilitiesExtension::js_msvcCompilerInfo, 1); setupMethod(ctx, classObj, "clangClCompilerInfo", &UtilitiesExtension::js_clangClCompilerInfo, 1); setupMethod(ctx, classObj, "installedMSVCs", &UtilitiesExtension::js_installedMSVCs, 1); setupMethod(ctx, classObj, "installedClangCls", &UtilitiesExtension::js_installedClangCls, 1); setupMethod(ctx, classObj, "versionCompare", &UtilitiesExtension::js_versionCompare, 2); setupMethod(ctx, classObj, "qmlTypeInfo", &UtilitiesExtension::js_qmlTypeInfo, 0); setupMethod(ctx, classObj, "builtinExtensionNames", &UtilitiesExtension::js_builtinExtensionNames, 0); setupMethod(ctx, classObj, "isSharedLibrary", &UtilitiesExtension::js_isSharedLibrary, 1); setupMethod(ctx, classObj, "getArchitecturesFromBinary", &UtilitiesExtension::js_getArchitecturesFromBinary, 1); } JSValue UtilitiesExtension::js_canonicalArchitecture(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto arch = getArgument(ctx, "Utilities.canonicalArchitecture", argc, argv); if (arch.isEmpty()) return makeJsString(ctx, {}); return makeJsString(ctx, canonicalArchitecture(arch)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_canonicalToolchain(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { QStringList toolchain; for (int i = 0; i < argc; ++i) toolchain << fromArg(ctx, "Utilities.canonicalToolchain", i + 1, argv[i]); return makeJsStringList(ctx, canonicalToolchain(toolchain)); } catch (const QString &error) { return throwError(ctx, error); } } // copied from src/corelib/tools/qtools_p.h Q_DECL_CONSTEXPR inline uchar toHexUpper(uint value) Q_DECL_NOTHROW { return "0123456789ABCDEF"[value & 0xF]; } Q_DECL_CONSTEXPR inline int fromHex(uint c) Q_DECL_NOTHROW { return ((c >= '0') && (c <= '9')) ? int(c - '0') : ((c >= 'A') && (c <= 'F')) ? int(c - 'A' + 10) : ((c >= 'a') && (c <= 'f')) ? int(c - 'a' + 10) : /* otherwise */ -1; } // copied from src/corelib/io/qdebug.cpp static inline bool isPrintable(uchar c) { return c >= ' ' && c < 0x7f; } // modified template static inline QString escapedString(const Char *begin, int length, bool isUnicode = true) { QChar quote(QLatin1Char('"')); QString out = quote; bool lastWasHexEscape = false; const Char *end = begin + length; for (const Char *p = begin; p != end; ++p) { // check if we need to insert "" to break an hex escape sequence if (Q_UNLIKELY(lastWasHexEscape)) { if (fromHex(*p) != -1) { // yes, insert it out += QLatin1Char('"'); out += QLatin1Char('"'); } lastWasHexEscape = false; } if (sizeof(Char) == sizeof(QChar)) { // Surrogate characters are category Cs (Other_Surrogate), so isPrintable = false for them int runLength = 0; while (p + runLength != end && QChar::isPrint(p[runLength]) && p[runLength] != '\\' && p[runLength] != '"') ++runLength; if (runLength) { out += QString(reinterpret_cast(p), runLength); p += runLength - 1; continue; } } else if (isPrintable(*p) && *p != '\\' && *p != '"') { QChar c = QLatin1Char(*p); out += c; continue; } // print as an escape sequence (maybe, see below for surrogate pairs) int buflen = 2; ushort buf[sizeof "\\U12345678" - 1]; buf[0] = '\\'; switch (*p) { case '"': case '\\': buf[1] = *p; break; case '\b': buf[1] = 'b'; break; case '\f': buf[1] = 'f'; break; case '\n': buf[1] = 'n'; break; case '\r': buf[1] = 'r'; break; case '\t': buf[1] = 't'; break; default: if (!isUnicode) { // print as hex escape buf[1] = 'x'; buf[2] = toHexUpper(uchar(*p) >> 4); buf[3] = toHexUpper(uchar(*p)); buflen = 4; lastWasHexEscape = true; break; } if (QChar::isHighSurrogate(*p)) { if ((p + 1) != end && QChar::isLowSurrogate(p[1])) { // properly-paired surrogates uint ucs4 = QChar::surrogateToUcs4(*p, p[1]); if (QChar::isPrint(ucs4)) { buf[0] = *p; buf[1] = p[1]; buflen = 2; } else { buf[1] = 'U'; buf[2] = '0'; // toHexUpper(ucs4 >> 32); buf[3] = '0'; // toHexUpper(ucs4 >> 28); buf[4] = toHexUpper(ucs4 >> 20); buf[5] = toHexUpper(ucs4 >> 16); buf[6] = toHexUpper(ucs4 >> 12); buf[7] = toHexUpper(ucs4 >> 8); buf[8] = toHexUpper(ucs4 >> 4); buf[9] = toHexUpper(ucs4); buflen = 10; } ++p; break; } // improperly-paired surrogates, fall through } buf[1] = 'u'; buf[2] = toHexUpper(ushort(*p) >> 12); buf[3] = toHexUpper(ushort(*p) >> 8); buf[4] = toHexUpper(*p >> 4); buf[5] = toHexUpper(*p); buflen = 6; } out += QString(reinterpret_cast(buf), buflen); } out += quote; return out; } JSValue UtilitiesExtension::js_cStringQuote(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto str = getArgument(ctx, "Utilities.cStringQuote", argc, argv); return makeJsString(ctx, escapedString( reinterpret_cast(str.constData()), str.size())); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_getHash(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const QByteArray input = getArgument(ctx, "Utilities.getHash", argc, argv) .toLatin1(); const QByteArray hash = QCryptographicHash::hash(input, QCryptographicHash::Sha1) .toHex().left(16); return makeJsString(ctx, QString::fromLatin1(hash)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_getNativeSetting(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto path = getArgument(ctx, "Utilities.getNativeSetting", argc, argv); QString key; if (argc > 1) key = fromArg(ctx, "Utilities.getNativeSetting", 2, argv[1]); // QSettings will ignore the default value if an empty key is passed. if (key.isEmpty()) { key = HostOsInfo::isWindowsHost() ? StringConstants::dot() // default registry value : QLatin1String("__dummy"); } QVariant defaultValue; if (argc > 2) defaultValue = fromArg(ctx, "Utilities.getNativeSetting", 3, argv[2]); const QSettings settings(path, QSettings::NativeFormat); const QVariant v = settings.value(key, defaultValue); return v.isNull() ? JS_UNDEFINED : makeJsVariant(ctx, v); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_kernelVersion(JSContext *ctx, JSValueConst, int, JSValueConst *) { return makeJsString(ctx, QSysInfo::kernelVersion()); } JSValue UtilitiesExtension::js_nativeSettingGroups(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto path = getArgument(ctx, "Utilities.nativeSettingGroups", argc, argv); QSettings settings(path, QSettings::NativeFormat); return makeJsStringList(ctx, settings.childGroups()); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_rfc1034identifier(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto identifier = getArgument(ctx, "Utilities.rfc1034identifier", argc, argv); return makeJsString(ctx, HostOsInfo::rfc1034Identifier(identifier)); } catch (const QString &error) { return throwError(ctx, error); } } /** * Reads the contents of the S/MIME message located at \p filePath. * An equivalent command line would be: * \code security cms -D -i -o \endcode * or: * \code openssl smime -verify -noverify -inform DER -in -out \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. */ JSValue UtilitiesExtension::js_smimeMessageContent(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { #if !defined(Q_OS_MACOS) Q_UNUSED(argc) Q_UNUSED(argv) return throwError(ctx, QStringLiteral("smimeMessageContent is not available on this platform")); #else try { const QString filePath = getArgument(ctx, "Utilities.smimeMessageContent", argc, argv); QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) return JS_UNDEFINED; QByteArray content = smimeMessageContent(file.readAll()); if (content.isEmpty()) return JS_UNDEFINED; return toJsValue(ctx, content); } catch (const QString &error) { return throwError(ctx, error); } #endif } JSValue UtilitiesExtension::js_certificateInfo(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { #if !defined(Q_OS_MACOS) Q_UNUSED(argc) Q_UNUSED(argv) return throwError(ctx, QStringLiteral("certificateInfo is not available on this platform")); #else try { const QVariant arg = getArgument(ctx, "Utilities.certificateInfo", argc, argv); return toJsValue(ctx, certificateInfo(arg.toByteArray())); } catch (const QString &error) { return throwError(ctx, error); } #endif } // Rough command line equivalent: security find-identity -p codesigning -v JSValue UtilitiesExtension::js_signingIdentities(JSContext *ctx, JSValueConst, int, JSValueConst *) { #if !defined(Q_OS_MACOS) return throwError(ctx, QStringLiteral("signingIdentities is not available on this platform")); #else return makeJsVariantMap(ctx, identitiesProperties()); #endif } #ifdef Q_OS_WIN // Try to detect the cross-architecture from the compiler path; prepend the host architecture // if it is differ than the target architecture (e.g. something like x64_x86 and so forth). static QString detectArchitecture(const QString &compilerFilePath, const QString &targetArch) { const auto startIndex = compilerFilePath.lastIndexOf(QLatin1String("Host")); if (startIndex == -1) return targetArch; const auto endIndex = compilerFilePath.indexOf(QLatin1Char('/'), startIndex); if (endIndex == -1) return targetArch; const auto hostArch = compilerFilePath.mid(startIndex + 4, endIndex - startIndex - 4).toLower(); if (hostArch.isEmpty() || (hostArch == targetArch)) return targetArch; return hostArch + QLatin1Char('_') + targetArch; } static std::pair msvcCompilerInfoHelper( const QString &compilerFilePath, MSVC::CompilerLanguage language, const QString &vcvarsallPath, const QString &arch, const QString &sdkVersion) { QString detailedArch = detectArchitecture(compilerFilePath, arch); MSVC msvc(compilerFilePath, std::move(detailedArch), sdkVersion); VsEnvironmentDetector envdetector(vcvarsallPath); if (!envdetector.start(&msvc)) return { {}, QStringLiteral("Detecting the MSVC build environment failed: ") + envdetector.errorString() }; try { QVariantMap envMap; const auto keys = msvc.environment.keys(); for (const QString &key : keys) envMap.insert(key, msvc.environment.value(key)); return { QVariantMap { {QStringLiteral("buildEnvironment"), envMap}, {QStringLiteral("macros"), msvc.compilerDefines(compilerFilePath, language)}, }, {} }; } catch (const qbs::ErrorInfo &info) { return { {}, info.toString() }; } } #endif JSValue UtilitiesExtension::js_msvcCompilerInfo(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { #ifndef Q_OS_WIN Q_UNUSED(argc) Q_UNUSED(argv) return throwError(ctx, QStringLiteral("msvcCompilerInfo is not available on this platform")); #else try { const auto args = getArguments(ctx, "Utilities.msvcCompilerInfo", argc, argv); const QString compilerFilePath = std::get<0>(args); const QString compilerLanguage = std::get<1>(args); const QString sdkVersion = std::get<2>(args); MSVC::CompilerLanguage language; if (compilerLanguage == QStringLiteral("c")) language = MSVC::CLanguage; else if (compilerLanguage == StringConstants::cppLang()) language = MSVC::CPlusPlusLanguage; else throw Tr::tr("Utilities.msvcCompilerInfo expects \"c\" or \"cpp\" as its second argument"); const auto result = msvcCompilerInfoHelper( compilerFilePath, language, {}, MSVC::architectureFromClPath(compilerFilePath), sdkVersion); if (result.first.isEmpty()) throw result.second; return toJsValue(ctx, result.first); } catch (const QString &error) { return throwError(ctx, error); } #endif } JSValue UtilitiesExtension::js_clangClCompilerInfo(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { #ifndef Q_OS_WIN Q_UNUSED(argc) Q_UNUSED(argv) return throwError(ctx, QStringLiteral("clangClCompilerInfo is not available on this platform")); #else try { const auto args = getArguments(ctx, "Utilities.clangClCompilerInfo", argc, argv); const QString compilerFilePath = std::get<0>(args); // architecture cannot be empty as vcvarsall.bat requires at least 1 arg, so fallback // to host architecture if none is present QString arch = std::get<1>(args); if (arch.isEmpty()) arch = HostOsInfo::hostOSArchitecture(); const QString vcvarsallPath = std::get<2>(args); const QString compilerLanguage = std::get<3>(args); const QString sdkVersion = std::get<4>(args); MSVC::CompilerLanguage language; if (compilerLanguage == QStringLiteral("c")) language = MSVC::CLanguage; else if (compilerLanguage == StringConstants::cppLang()) language = MSVC::CPlusPlusLanguage; else throw Tr::tr("Utilities.clangClCompilerInfo expects \"c\" or \"cpp\" as its fourth argument"); const auto result = msvcCompilerInfoHelper( compilerFilePath, language, vcvarsallPath, arch, sdkVersion); if (result.first.isEmpty()) throw result.second; return toJsValue(ctx, result.first); } catch (const QString &error) { return throwError(ctx, error); } #endif } JSValue UtilitiesExtension::js_installedMSVCs(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { #ifndef Q_OS_WIN return throwError(ctx, QStringLiteral("Utilities.installedMSVCs is not available on this platform")); Q_UNUSED(argc) Q_UNUSED(argv) #else try { const QString hostArch = HostOsInfo::hostOSArchitecture(); QString preferredArch = getArgument(ctx, "Utilities.installedMSVCs", argc, argv); if (preferredArch.isEmpty()) preferredArch = hostArch; DummyLogSink dummySink; Logger dummyLogger(&dummySink); auto msvcs = MSVC::installedCompilers(dummyLogger); const auto predicate = [&preferredArch, &hostArch](const MSVC &msvc) { auto archPair = MSVC::getHostTargetArchPair(msvc.architecture); return archPair.first != hostArch || preferredArch != archPair.second; }; Internal::removeIf(msvcs, predicate); QVariantList result; for (const auto &msvc: msvcs) result.append(msvc.toVariantMap()); return makeJsVariantList(ctx, result); } catch (const QString &error) { return throwError(ctx, error); } #endif } JSValue UtilitiesExtension::js_installedClangCls(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { #ifndef Q_OS_WIN Q_UNUSED(argc) Q_UNUSED(argv) return throwError(ctx, QStringLiteral("Utilities.installedClangCls is not available on this platform")); #else try { const QString path = getArgument(ctx, "Utilities.installedClangCls", argc, argv); DummyLogSink dummySink; Logger dummyLogger(&dummySink); auto compilers = ClangClInfo::installedCompilers({path}, dummyLogger); QVariantList result; for (const auto &compiler: compilers) result.append(compiler.toVariantMap()); return makeJsVariantList(ctx, result); } catch (const QString &error) { return throwError(ctx, error); } #endif } JSValue UtilitiesExtension::js_versionCompare(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto args = getArguments(ctx, "Utilities.versionCompare", argc, argv); const auto a = Version::fromString(std::get<0>(args), true); const auto b = Version::fromString(std::get<1>(args), true); return JS_NewInt32(ctx, compare(a, b)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue UtilitiesExtension::js_qmlTypeInfo(JSContext *ctx, JSValueConst, int, JSValueConst *) { return makeJsString(ctx, QString::fromStdString(qbs::LanguageInfo::qmlTypeInfo())); } JSValue UtilitiesExtension::js_builtinExtensionNames(JSContext *ctx, JSValueConst, int, JSValueConst *) { return makeJsStringList(ctx, JsExtensions::extensionNames()); } JSValue UtilitiesExtension::js_isSharedLibrary(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto fileName = getArgument(ctx, "Utilities.isSharedLibrary", argc, argv); return JS_NewBool(ctx, QLibrary::isLibrary(fileName)); } catch (const QString &error) { return throwError(ctx, error); } } #ifdef __APPLE__ template T readInt(QIODevice *ioDevice, bool *ok, bool swap, bool peek = false) { const auto bytes = peek ? ioDevice->peek(sizeof(T)) : ioDevice->read(sizeof(T)); if (bytes.size() != sizeof(T)) { if (ok) *ok = false; return T(); } if (ok) *ok = true; T n = *reinterpret_cast(bytes.constData()); return swap ? qbswap(n) : n; } static QString archName(cpu_type_t cputype, cpu_subtype_t cpusubtype) { switch (cputype) { case CPU_TYPE_X86: switch (cpusubtype) { case CPU_SUBTYPE_X86_ALL: return QStringLiteral("i386"); default: return {}; } case CPU_TYPE_X86_64: switch (cpusubtype) { case CPU_SUBTYPE_X86_64_ALL: return QStringLiteral("x86_64"); case CPU_SUBTYPE_X86_64_H: return QStringLiteral("x86_64h"); default: return {}; } case CPU_TYPE_ARM: switch (cpusubtype) { case CPU_SUBTYPE_ARM_V7: return QStringLiteral("armv7a"); case CPU_SUBTYPE_ARM_V7S: return QStringLiteral("armv7s"); case CPU_SUBTYPE_ARM_V7K: return QStringLiteral("armv7k"); default: return {}; } case CPU_TYPE_ARM64: switch (cpusubtype) { case CPU_SUBTYPE_ARM64_ALL: return QStringLiteral("arm64"); default: return {}; } default: return {}; } } static QStringList detectMachOArchs(QIODevice *device) { bool ok; bool foundMachO = false; qint64 pos = device->pos(); char ar_header[SARMAG]; if (device->read(ar_header, SARMAG) == SARMAG) { if (strncmp(ar_header, ARMAG, SARMAG) == 0) { while (!device->atEnd()) { static_assert(sizeof(ar_hdr) == 60, "sizeof(ar_hdr) != 60"); ar_hdr header{}; if (device->read(reinterpret_cast(&header), sizeof(ar_hdr)) != sizeof(ar_hdr)) return {}; // If the file name is stored in the "extended format" manner, // the real filename is prepended to the data section, so skip that many bytes int filenameLength = 0; if (strncmp(header.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0) { char arName[sizeof(header.ar_name)] = { 0 }; memcpy(arName, header.ar_name + sizeof(AR_EFMT1) - 1, sizeof(header.ar_name) - (sizeof(AR_EFMT1) - 1) - 1); filenameLength = strtoul(arName, nullptr, 10); if (device->read(filenameLength).size() != filenameLength) return {}; } switch (readInt(device, nullptr, false, true)) { case MH_CIGAM: case MH_CIGAM_64: case MH_MAGIC: case MH_MAGIC_64: foundMachO = true; break; default: { // Skip the data and go to the next archive member... char szBuf[sizeof(header.ar_size) + 1] = { 0 }; memcpy(szBuf, header.ar_size, sizeof(header.ar_size)); int sz = static_cast(strtoul(szBuf, nullptr, 10)); if (sz % 2 != 0) ++sz; sz -= filenameLength; const auto data = device->read(sz); if (data.size() != sz) return {}; } } if (foundMachO) break; } } } // Wasn't an archive file, so try a fat file if (!foundMachO && !device->seek(pos)) return {}; pos = device->pos(); fat_header fatheader{}; fatheader.magic = readInt(device, nullptr, false); if (fatheader.magic == FAT_MAGIC || fatheader.magic == FAT_CIGAM || fatheader.magic == FAT_MAGIC_64 || fatheader.magic == FAT_CIGAM_64) { const bool swap = fatheader.magic == FAT_CIGAM || fatheader.magic == FAT_CIGAM_64; const bool is64bit = fatheader.magic == FAT_MAGIC_64 || fatheader.magic == FAT_CIGAM_64; fatheader.nfat_arch = readInt(device, &ok, swap); if (!ok) return {}; QStringList archs; for (uint32_t n = 0; n < fatheader.nfat_arch; ++n) { fat_arch_64 fatarch{}; static_assert(sizeof(fat_arch_64) == 32, "sizeof(fat_arch_64) != 32"); static_assert(sizeof(fat_arch) == 20, "sizeof(fat_arch) != 20"); const qint64 expectedBytes = is64bit ? sizeof(fat_arch_64) : sizeof(fat_arch); if (device->read(reinterpret_cast(&fatarch), expectedBytes) != expectedBytes) return {}; if (swap) { fatarch.cputype = qbswap(fatarch.cputype); fatarch.cpusubtype = qbswap(fatarch.cpusubtype); } const QString name = archName(fatarch.cputype, fatarch.cpusubtype); if (name.isEmpty()) { qWarning("Unknown cputype %d and cpusubtype %d", fatarch.cputype, fatarch.cpusubtype); return {}; } archs.push_back(name); } std::sort(archs.begin(), archs.end()); return archs; } // Wasn't a fat file, so we just read a thin Mach-O from the original offset if (!device->seek(pos)) return {}; bool swap = false; mach_header header{}; header.magic = readInt(device, nullptr, swap); switch (header.magic) { case MH_CIGAM: case MH_CIGAM_64: swap = true; break; case MH_MAGIC: case MH_MAGIC_64: break; default: return {}; } header.cputype = static_cast(readInt(device, &ok, swap)); if (!ok) return {}; header.cpusubtype = static_cast(readInt(device, &ok, swap)); if (!ok) return {}; const QString name = archName(header.cputype, header.cpusubtype); if (name.isEmpty()) { qWarning("Unknown cputype %d and cpusubtype %d", header.cputype, header.cpusubtype); return {}; } return {name}; } #endif JSValue UtilitiesExtension::js_getArchitecturesFromBinary(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto path = getArgument(ctx, "Utilities.getArchitecturesFromBinary", argc, argv); QStringList archs; #ifdef __APPLE__ QFile file(path); if (!file.open(QIODevice::ReadOnly)) { throw Tr::tr("In Utilities.getArchitecturesFromBinary: " "Failed to open file '%1': %2") .arg(file.fileName(), file.errorString()); } archs = detectMachOArchs(&file); #else Q_UNUSED(path) #endif // __APPLE__ return makeJsStringList(ctx, archs); } catch (const QString &error) { return throwError(ctx, error); } } } // namespace Internal } // namespace qbs void initializeJsExtensionUtilities(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::UtilitiesExtension::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/file.cpp0000644000175100001660000002663714776170045021621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include namespace qbs { namespace Internal { class File : public JsExtension { public: enum Filter { Dirs = 0x001, Files = 0x002, Drives = 0x004, NoSymLinks = 0x008, AllEntries = Dirs | Files | Drives, TypeMask = 0x00f, Readable = 0x010, Writable = 0x020, Executable = 0x040, PermissionMask = 0x070, Modified = 0x080, Hidden = 0x100, System = 0x200, AccessMask = 0x3F0, AllDirs = 0x400, CaseSensitive = 0x800, NoDot = 0x2000, NoDotDot = 0x4000, NoDotAndDotDot = NoDot | NoDotDot, NoFilter = -1 }; Q_DECLARE_FLAGS(Filters, Filter) static const char *name() { return "File"; } static void setupStaticMethods(JSContext *ctx, JSValue classObj); static void declareEnums(JSContext *ctx, JSValue classObj); static JSValue jsCopy(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsExists(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsDirectoryEntries(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsLastModified(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsMakePath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsMove(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsRemove(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsCanonicalFilePath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); }; void File::setupStaticMethods(JSContext *ctx, JSValue classObj) { setupMethod(ctx, classObj, "copy", &File::jsCopy, 2); setupMethod(ctx, classObj, "exists", &File::jsExists, 1); setupMethod(ctx, classObj, "directoryEntries", File::jsDirectoryEntries, 2); setupMethod(ctx, classObj, "lastModified", File::jsLastModified, 1); setupMethod(ctx, classObj, "makePath", &File::jsMakePath, 1); setupMethod(ctx, classObj, "move", &File::jsMove, 3); setupMethod(ctx, classObj, "remove", &File::jsRemove, 1); setupMethod(ctx, classObj, "canonicalFilePath", &File::jsCanonicalFilePath, 1); } void File::declareEnums(JSContext *ctx, JSValue classObj) { DECLARE_ENUM(ctx, classObj, Dirs); DECLARE_ENUM(ctx, classObj, Files); DECLARE_ENUM(ctx, classObj, Drives); DECLARE_ENUM(ctx, classObj, NoSymLinks); DECLARE_ENUM(ctx, classObj, AllEntries); DECLARE_ENUM(ctx, classObj, TypeMask); DECLARE_ENUM(ctx, classObj, Readable); DECLARE_ENUM(ctx, classObj, Writable); DECLARE_ENUM(ctx, classObj, Executable); DECLARE_ENUM(ctx, classObj, PermissionMask); DECLARE_ENUM(ctx, classObj, Modified); DECLARE_ENUM(ctx, classObj, Hidden); DECLARE_ENUM(ctx, classObj, System); DECLARE_ENUM(ctx, classObj, AccessMask); DECLARE_ENUM(ctx, classObj, AllDirs); DECLARE_ENUM(ctx, classObj, CaseSensitive); DECLARE_ENUM(ctx, classObj, NoDot); DECLARE_ENUM(ctx, classObj, NoDotDot); DECLARE_ENUM(ctx, classObj, NoDotAndDotDot); DECLARE_ENUM(ctx, classObj, NoFilter); } JSValue File::jsCopy(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts({ DubiousContext(EvalContext::PropertyEvaluation), DubiousContext(EvalContext::RuleExecution, DubiousContext::SuggestMoving) }); se->checkContext(QStringLiteral("File.copy()"), dubiousContexts); const auto args = getArguments(ctx, "File.copy", argc, argv); QString errorMessage; if (Q_UNLIKELY(!copyFileRecursion(std::get<0>(args), std::get<1>(args), true, true, &errorMessage))) { throw errorMessage; } return JS_TRUE; } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsExists(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "File.exists", argc, argv); const bool exists = FileInfo::exists(filePath); ScriptEngine::engineForContext(ctx)->addFileExistsResult(filePath, exists); return JS_NewBool(ctx, exists); } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsDirectoryEntries(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts({ DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }); se->checkContext(QStringLiteral("File.directoryEntries()"), dubiousContexts); const auto args = getArguments(ctx, "Environment.directoryEntries", argc, argv); const QString path = std::get<0>(args); const QDir dir(path); const auto filters = static_cast(std::get<1>(args)); const QStringList entries = dir.entryList(filters, QDir::Name); se->addDirectoryEntriesResult(path, filters, entries); return makeJsStringList(ctx, entries); } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsRemove(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{DubiousContext(EvalContext::PropertyEvaluation)}; se->checkContext(QStringLiteral("File.remove()"), dubiousContexts); const auto fileName = getArgument(ctx, "Environment.remove", argc, argv); QString errorMessage; if (Q_UNLIKELY(!removeFileRecursion(QFileInfo(fileName), &errorMessage))) throw errorMessage; return JS_TRUE; } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsLastModified(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "Environment.lastModified", argc, argv); const FileTime timestamp = FileInfo(filePath).lastModified(); const auto se = ScriptEngine::engineForContext(ctx); se->addFileLastModifiedResult(filePath, timestamp); return JS_NewFloat64(ctx, timestamp.asDouble()); } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsMakePath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{DubiousContext(EvalContext::PropertyEvaluation)}; se->checkContext(QStringLiteral("File.makePath()"), dubiousContexts); const auto path = getArgument(ctx, "File.makePath", argc, argv); return JS_NewBool(ctx, QDir::root().mkpath(path)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsMove(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{DubiousContext(EvalContext::PropertyEvaluation)}; se->checkContext(QStringLiteral("File.move()"), dubiousContexts); const auto args = getArguments(ctx, "File.move", argc, argv); const QString sourceFile = std::get<0>(args); const QString targetFile = std::get<1>(args); const auto overwrite = argc > 2 ? fromArg(ctx, "File.move", 3, argv[2]) : true; if (Q_UNLIKELY(QFileInfo(sourceFile).isDir())) { throw QStringLiteral("Could not move '%1' to '%2': " "Source file path is a directory.").arg(sourceFile, targetFile); } if (Q_UNLIKELY(QFileInfo(targetFile).isDir())) { throw QStringLiteral("Could not move '%1' to '%2': " "Destination file path is a directory.") .arg(sourceFile, targetFile); } QFile f(targetFile); if (overwrite && f.exists() && !f.remove()) { throw QStringLiteral("Could not move '%1' to '%2': %3") .arg(sourceFile, targetFile, f.errorString()); } if (QFile::exists(targetFile)) { throw QStringLiteral("Could not move '%1' to '%2': " "Destination file exists.").arg(sourceFile, targetFile); } QFile f2(sourceFile); if (Q_UNLIKELY(!f2.rename(targetFile))) { throw QStringLiteral("Could not move '%1' to '%2': %3") .arg(sourceFile, targetFile, f2.errorString()); } return JS_TRUE; } catch (const QString &error) { return throwError(ctx, error); } } JSValue File::jsCanonicalFilePath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto path = getArgument(ctx, "File.canonicalFilePath", argc, argv); return makeJsString(ctx, QFileInfo(path).canonicalFilePath()); } catch (const QString &error) { return throwError(ctx, error); } } } // namespace Internal } // namespace qbs void initializeJsExtensionFile(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::File::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/jsextension.h0000644000175100001660000003267614776170045022720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #pragma once #include #include #include #include #include namespace qbs::Internal { template struct PackHelper {}; template struct FromArgHelper; template struct FunctionTrait; #define DECLARE_ENUM(ctx, obj, enumVal) \ JS_SetPropertyStr((ctx), (obj), #enumVal, JS_NewInt32((ctx), (enumVal))) template class JsExtension { #define DEFINE_JS_FORWARDER(name, func, text) \ static JSValue name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) \ { \ return jsForward(func, text, ctx, this_val, argc, argv); \ } #define DEFINE_JS_FORWARDER_QUAL(klass, name, func, text) \ static JSValue name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) \ { \ return klass::jsForward(func, text, ctx, this_val, argc, argv); \ } public: virtual ~JsExtension() = default; template static JSValue createObject(JSContext *ctx, Args... args) { ScopedJsValue obj(ctx, JS_NewObjectClass(ctx, classId(ctx))); JS_SetOpaque(obj, new Derived(ctx, args...)); Derived::setupMethods(ctx, obj); return obj.release(); } static JSValue createObjectDirect(JSContext *ctx, void *obj) { JSValue jsObj = JS_NewObjectClass(ctx, classId(ctx)); attachPointerTo(jsObj, obj); Derived::setupMethods(ctx, jsObj); return jsObj; } static Derived *fromJsObject(JSContext *ctx, JSValue obj) { return attachedPointer(obj, classId(ctx)); } static void registerClass(ScriptEngine *engine, JSValue extensionObject) { if (const JSValue cachedValue = engine->getInternalExtension(Derived::name()); !JS_IsUndefined(cachedValue)) { JS_SetPropertyStr(engine->context(), extensionObject, Derived::name(), cachedValue); return; } engine->registerClass(Derived::name(), &Derived::ctor, &finalizer, extensionObject); const ScopedJsValue classObj( engine->context(), JS_GetPropertyStr(engine->context(), extensionObject, Derived::name())); Derived::setupStaticMethods(engine->context(), classObj); Derived::declareEnums(engine->context(), classObj); } // obj is either class (for "static" methods) or class instance template static void setupMethod(JSContext *ctx, JSValue obj, const char *name, Func func, int argc) { JS_DefinePropertyValueStr(ctx, obj, name, JS_NewCFunction(ctx, func, name, argc), 0); } template static void setupMethod(JSContext *ctx, JSValue obj, const QString &name, Func func, int argc) { setupMethod(ctx, obj, name.toUtf8().constData(), func, argc); } template static T fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { return FromArgHelper::fromArg(ctx, funcName, pos, v); } template static void assignToTuple(Tuple &tuple, std::index_sequence, JSContext *ctx, const char *funcName, JSValueConst *argv) { Q_UNUSED(ctx) Q_UNUSED(funcName) Q_UNUSED(argv) ((std::get(tuple) = fromArg>(ctx, funcName, I + 1, argv[I])), ...); } template static std::tuple getArguments(JSContext *ctx, const char *funcName, int argc, JSValueConst *argv) { constexpr int expectedArgc = sizeof ...(Args); if (argc < expectedArgc) { throw Tr::tr("%1 requires %d arguments.") .arg(QLatin1String(funcName)).arg(expectedArgc); } std::tuple>...> values; assignToTuple(values, std::make_index_sequence::value>(), ctx, funcName, argv); return values; } template static std::tuple getArgumentsHelper(PackHelper, JSContext *ctx, const char *funcName, int argc, JSValueConst *argv) { return getArguments(ctx, funcName, argc, argv); } template static T getArgument(JSContext *ctx, const char *funcName, int argc, JSValueConst *argv) { return std::get<0>(getArguments(ctx, funcName, argc, argv)); } template static void jsForwardHelperVoid(Derived *obj, Func func, const Tuple &tuple, std::index_sequence) { (obj->*func)(std::get(tuple)...); } template static Ret jsForwardHelperRet(Derived *obj, Func &func, Tuple const& tuple, std::index_sequence) { return (obj->*func)(std::get(tuple)...); } static JSValue toJsValue(JSContext *ctx, const QString &s) { return makeJsString(ctx, s); } static JSValue toJsValue(JSContext *ctx, bool v) { return JS_NewBool(ctx, v); } static JSValue toJsValue(JSContext *ctx, qint32 v) { return JS_NewInt32(ctx, v); } static JSValue toJsValue(JSContext *ctx, qint64 v) { return JS_NewInt64(ctx, v); } static JSValue toJsValue(JSContext *ctx, const QVariant &v) { return makeJsVariant(ctx, v); } static JSValue toJsValue(JSContext *ctx, const QByteArray &data) { const JSValue array = JS_NewArray(ctx); for (int i = 0; i < data.size(); ++i) { JS_SetPropertyUint32(ctx, array, i, JS_NewUint32(ctx, static_cast(data.at(i)))); } return array; } static JSValue toJsValue(JSContext *ctx, const QVariantMap &m) { return makeJsVariantMap(ctx, m); } template static JSValue toJsValue(JSContext *ctx, const std::optional &v) { if (!v) return JS_UNDEFINED; return makeJsString(ctx, *v); } template static JSValue jsForward(Func func, const char *name, JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { using Ret = typename FunctionTrait::Ret; using Args = typename FunctionTrait::Args; const auto args = getArgumentsHelper(Args(), ctx, name, argc, argv); const auto obj = fromJsObject(ctx, this_val); if constexpr (std::is_same_v) { jsForwardHelperVoid(obj, func, args, std::make_index_sequence::value>()); return JS_UNDEFINED; } else { return toJsValue(ctx, jsForwardHelperRet(obj, func, args, std::make_index_sequence>())); } } catch (const QString &error) { return throwError(ctx, error); } } static void setupMethods(JSContext *, JSValue) {} static void setupStaticMethods(JSContext *, JSValue) {} static void declareEnums(JSContext *, JSValue) {} private: static void finalizer(JSRuntime *rt, JSValue val) { delete attachedPointer(val, classId(rt)); } static JSClassID classId(JSContext *ctx) { return ScriptEngine::engineForContext(ctx)->getClassId(Derived::name()); } static JSClassID classId(JSRuntime *rt) { return ScriptEngine::engineForRuntime(rt)->getClassId(Derived::name()); } static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int, JSValueConst *, int) { return throwError(ctx, Tr::tr("'%1' cannot be instantiated.") .arg(QLatin1String(Derived::name()))); } }; template<> struct FromArgHelper { static bool fromArg(JSContext *ctx, const char *, int, JSValue v) { return JS_ToBool(ctx, v); } }; template<> struct FromArgHelper { static qint32 fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { int32_t val; if (JS_ToInt32(ctx, &val, v) < 0) { throw Tr::tr("%1 requires an integer as argument %2") .arg(QLatin1String(funcName)).arg(pos); } return val; } }; template<> struct FromArgHelper { static qint64 fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { int64_t val; if (JS_ToInt64(ctx, &val, v) < 0) { throw Tr::tr("%1 requires an integer as argument %2") .arg(QLatin1String(funcName)).arg(pos); } return val; } }; template<> struct FromArgHelper { static QByteArray fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { const auto throwError = [&] { throw Tr::tr("%1 requires an array of bytes as argument %2") .arg(QLatin1String(funcName)).arg(pos); }; if (!JS_IsArray(ctx, v)) throwError(); QByteArray data; data.resize(getJsIntProperty(ctx, v, QLatin1String("length"))); for (int i = 0; i < data.size(); ++i) { const JSValue jsNumber = JS_GetPropertyUint32(ctx, v, i); if (JS_VALUE_GET_TAG(jsNumber) != JS_TAG_INT) throwError(); uint32_t n; JS_ToUint32(ctx, &n, jsNumber); if (n > 0xff) throwError(); data[i] = n; } return data; } }; template<> struct FromArgHelper { static QString fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { if (JS_IsUndefined(v)) return {}; const ScopedJsValue stringified(ctx, JS_ToString(ctx, v)); if (!JS_IsString(stringified)) { throw Tr::tr("%1 requires a string as argument %2") .arg(QLatin1String(funcName)).arg(pos); } return getJsString(ctx, stringified); } }; template<> struct FromArgHelper { static QStringList fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { if (!JS_IsArray(ctx, v)) { throw Tr::tr("%1 requires an array of strings as argument %2") .arg(QLatin1String(funcName)).arg(pos); } return getJsStringList(ctx, v); } }; template<> struct FromArgHelper { static QVariant fromArg(JSContext *ctx, const char *, int, JSValue v) { return getJsVariant(ctx, v); } }; template struct FromArgHelper { static C *fromArg(JSContext *ctx, const char *funcName, int pos, JSValue v) { C * const obj = JsExtension::fromJsObject(ctx, v); if (!obj) { throw Tr::tr("Argument %2 has wrong type in call to %1") .arg(QLatin1String(funcName)).arg(pos); } return obj; } }; template struct FunctionTrait { using Ret = R; using Args = PackHelper...>; }; template struct FunctionTrait { using Ret = R; using Args = PackHelper...>; }; } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/jsextensions/jsextensions.cpp0000644000175100001660000000723514776170045023427 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextensions.h" #include #include #include #include using InitializerMap = QMap; static InitializerMap setupMap() { #define INITIALIZER_NAME(name) initializeJsExtension##name #define ADD_JS_EXTENSION(name) \ void INITIALIZER_NAME(name)(qbs::Internal::ScriptEngine *, JSValue); \ map.insert(QStringLiteral(#name), &INITIALIZER_NAME(name)) InitializerMap map; ADD_JS_EXTENSION(BinaryFile); ADD_JS_EXTENSION(Environment); ADD_JS_EXTENSION(File); ADD_JS_EXTENSION(FileInfo); ADD_JS_EXTENSION(Host); ADD_JS_EXTENSION(PkgConfig); ADD_JS_EXTENSION(Process); ADD_JS_EXTENSION(PropertyList); ADD_JS_EXTENSION(TemporaryDir); ADD_JS_EXTENSION(TextFile); ADD_JS_EXTENSION(Utilities); ADD_JS_EXTENSION(Xml); return map; } namespace qbs { namespace Internal { static InitializerMap &initializers() { static InitializerMap theMap = setupMap(); return theMap; } void JsExtensions::setupExtensions(ScriptEngine *engine, const QStringList &names, const JSValue &scope) { for (const QString &name : names) initializers().value(name)(engine, scope); } JSValue JsExtensions::loadExtension(ScriptEngine *engine, const QString &name) { if (!hasExtension(name)) return {}; ScopedJsValue extensionObj(engine->context(), engine->newObject()); initializers().value(name)(engine, extensionObj); return getJsProperty(engine->context(), extensionObj, name); } bool JsExtensions::hasExtension(const QString &name) { return initializers().contains(name); } QStringList JsExtensions::extensionNames() { return initializers().keys(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/jsextensions/jsextensions.h0000644000175100001660000000463714776170045023077 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JSEXTENSIONS_H #define QBS_JSEXTENSIONS_H #include #include namespace qbs { namespace Internal { class ScriptEngine; class JsExtensions { public: static void setupExtensions(ScriptEngine *engine, const QStringList &names, const JSValue &scope); static JSValue loadExtension(ScriptEngine *engine, const QString &name); static bool hasExtension(const QString &name); static QStringList extensionNames(); }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/jsextensions/process.cpp0000644000175100001660000003145614776170045022353 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include #include #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #else #include #endif namespace qbs { namespace Internal { class Process : public JsExtension { friend class JsExtension; public: static const char *name() { return "Process"; } static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int, JSValueConst *, int); static void setupStaticMethods(JSContext *ctx, JSValue classObj); static void setupMethods(JSContext *ctx, JSValue obj); Process(JSContext *context); DEFINE_JS_FORWARDER(jsGetEnv, &Process::getEnv, "Process.getEnv") DEFINE_JS_FORWARDER(jsSetEnv, &Process::setEnv, "Process.setEnv") DEFINE_JS_FORWARDER(jsSetCodec, &Process::setCodec, "Process.setCodec") DEFINE_JS_FORWARDER(jsWorkingDir, &Process::workingDirectory, "Process.workingDirectory") DEFINE_JS_FORWARDER(jsSetWorkingDir, &Process::setWorkingDirectory, "Process.setWorkingDirectory") DEFINE_JS_FORWARDER(jsStart, &Process::start, "Process.start") DEFINE_JS_FORWARDER(jsClose, &Process::close, "Process.close") DEFINE_JS_FORWARDER(jsTerminate, &Process::terminate, "Process.terminate") DEFINE_JS_FORWARDER(jsKill, &Process::kill, "Process.kill") DEFINE_JS_FORWARDER(jsReadLine, &Process::readLine, "Process.readLine") DEFINE_JS_FORWARDER(jsAtEnd, &Process::atEnd, "Process.atEnd") DEFINE_JS_FORWARDER(jsReadStdOut, &Process::readStdOut, "Process.readStdOut") DEFINE_JS_FORWARDER(jsReadStdErr, &Process::readStdErr, "Process.readStdErr") DEFINE_JS_FORWARDER(jsCloseWriteChannel, &Process::closeWriteChannel, "Process.closeWriteChannel") DEFINE_JS_FORWARDER(jsWrite, &Process::write, "Process.write") DEFINE_JS_FORWARDER(jsWriteLine, &Process::writeLine, "Process.writeLine") DEFINE_JS_FORWARDER(jsExitCode, &Process::exitCode, "Process.exitCode") static JSValue jsExec(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { const auto args = getArguments(ctx, "Process.exec", argc, argv); bool throwOnError = false; if (argc > 2) throwOnError = fromArg(ctx, "Process.exec", 3, argv[2]); return JS_NewInt32(ctx, fromJsObject(ctx, this_val) ->exec(std::get<0>(args), std::get<1>(args), throwOnError)); } catch (const QString &error) { return throwError(ctx, error); } } static JSValue jsWaitForFinished(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { try { int msecs = 30000; if (argc > 0) msecs = getArgument(ctx, "Process.waitForFinished", argc, argv); return JS_NewBool(ctx, fromJsObject(ctx, this_val)->waitForFinished(msecs)); } catch (const QString &error) { return throwError(ctx, error); } } QString getEnv(const QString &name) const { return m_environment.value(name); } void setEnv(const QString &name, const QString &value) { m_environment.insert(name, value); } void setCodec(const QString &codec); QString workingDirectory() const { return m_workingDirectory; } void setWorkingDirectory(const QString &dir) { m_workingDirectory = dir; } bool start(const QString &program, const QStringList &arguments); int exec(const QString &program, const QStringList &arguments, bool throwOnError); void close(); bool waitForFinished(int msecs); void terminate() { m_qProcess->terminate(); } void kill() { m_qProcess->kill(); } QString readLine(); bool atEnd() const { return m_qProcess->atEnd(); } QString readStdOut() { return m_codec->toUnicode(m_qProcess->readAllStandardOutput()); } QString readStdErr() { return m_codec->toUnicode(m_qProcess->readAllStandardError()); } void closeWriteChannel() { m_qProcess->closeWriteChannel(); } void write(const QString &str) { m_qProcess->write(m_codec->fromUnicode(str)); } void writeLine(const QString &str); int exitCode() const { return m_qProcess->exitCode(); } static JSValue jsShellQuote(JSContext *ctx, JSValue, int argc, JSValue *argv); private: QString findExecutable(const QString &filePath) const; std::unique_ptr m_qProcess; QProcessEnvironment m_environment; QString m_workingDirectory; QTextCodec *m_codec = nullptr; }; JSValue Process::ctor(JSContext *ctx, JSValueConst, JSValueConst, int, JSValueConst *, int) { try { JSValue obj = createObject(ctx); Process * const process = fromJsObject(ctx, obj); const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{ DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }; se->checkContext(QStringLiteral("qbs.Process"), dubiousContexts); // Get environment QVariant v = se->property(StringConstants::qbsProcEnvVarInternal()); if (v.isNull()) { // The build environment is not initialized yet. // This can happen if one uses Process on the RHS of a binding like Group.name. process->m_environment = se->environment(); } else { process->m_environment = QProcessEnvironment(*reinterpret_cast(v.value())); } se->setUsesIo(); return obj; } catch (const QString &error) { return throwError(ctx, error); } } void Process::setupStaticMethods(JSContext *ctx, JSValue classObj) { setupMethod(ctx, classObj, "shellQuote", &Process::jsShellQuote, 3); } void Process::setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "getEnv", &jsGetEnv, 1); setupMethod(ctx, obj, "setEnv", &jsSetEnv, 2); setupMethod(ctx, obj, "setCodec", &jsSetCodec, 1); setupMethod(ctx, obj, "workingDirectory", &jsWorkingDir, 0); setupMethod(ctx, obj, "setWorkingDirectory", &jsSetWorkingDir, 1); setupMethod(ctx, obj, "start", &jsStart, 2); setupMethod(ctx, obj, "exec", &jsExec, 3); setupMethod(ctx, obj, "close", &jsClose, 0); setupMethod(ctx, obj, "waitForFinished", &jsWaitForFinished, 1); setupMethod(ctx, obj, "terminate", &jsTerminate, 0); setupMethod(ctx, obj, "kill", &jsKill, 0); setupMethod(ctx, obj, "readLine", &jsReadLine, 0); setupMethod(ctx, obj, "atEnd", &jsAtEnd, 0); setupMethod(ctx, obj, "readStdOut", &jsReadStdOut, 0); setupMethod(ctx, obj, "readStdErr", &jsReadStdErr, 0); setupMethod(ctx, obj, "closeWriteChannel", &jsCloseWriteChannel, 0); setupMethod(ctx, obj, "write", &jsWrite, 1); setupMethod(ctx, obj, "writeLine", &jsWriteLine, 1); setupMethod(ctx, obj, "exitCode", &jsExitCode, 0); } Process::Process(JSContext *) { m_qProcess = std::make_unique(); m_codec = QTextCodec::codecForName("UTF-8"); } bool Process::start(const QString &program, const QStringList &arguments) { if (!m_workingDirectory.isEmpty()) m_qProcess->setWorkingDirectory(m_workingDirectory); m_qProcess->setProcessEnvironment(m_environment); m_qProcess->start(findExecutable(program), arguments, QIODevice::ReadWrite | QIODevice::Text); return m_qProcess->waitForStarted(); } int Process::exec(const QString &program, const QStringList &arguments, bool throwOnError) { if (!start(findExecutable(program), arguments)) { if (throwOnError) throw Tr::tr("Error running '%1': %2").arg(program, m_qProcess->errorString()); return -1; } m_qProcess->closeWriteChannel(); m_qProcess->waitForFinished(-1); if (throwOnError) { if (m_qProcess->error() != QProcess::UnknownError && m_qProcess->error() != QProcess::Crashed) { throw Tr::tr("Error running '%1': %2").arg(program, m_qProcess->errorString()); } else if (m_qProcess->exitStatus() == QProcess::CrashExit || m_qProcess->exitCode() != 0) { QString errorMessage = m_qProcess->error() == QProcess::Crashed ? Tr::tr("Error running '%1': %2").arg(program, m_qProcess->errorString()) : Tr::tr("Process '%1 %2' finished with exit code %3.") .arg(program, arguments.join(QStringLiteral(" "))) .arg(m_qProcess->exitCode()); const QString stdOut = readStdOut(); if (!stdOut.isEmpty()) errorMessage.append(Tr::tr(" The standard output was:\n")).append(stdOut); const QString stdErr = readStdErr(); if (!stdErr.isEmpty()) errorMessage.append(Tr::tr(" The standard error output was:\n")).append(stdErr); throw errorMessage; } } if (m_qProcess->error() != QProcess::UnknownError) return -1; return m_qProcess->exitCode(); } void Process::close() { if (!m_qProcess) return; m_qProcess.reset(); } bool Process::waitForFinished(int msecs) { if (m_qProcess->state() == QProcess::NotRunning) return true; return m_qProcess->waitForFinished(msecs); } void Process::setCodec(const QString &codec) { const auto newCodec = QTextCodec::codecForName(qPrintable(codec)); if (newCodec) m_codec = newCodec; } QString Process::readLine() { auto result = m_codec->toUnicode(m_qProcess->readLine()); if (!result.isEmpty() && result.back() == QLatin1Char('\n')) result.chop(1); return result; } QString Process::findExecutable(const QString &filePath) const { ExecutableFinder exeFinder(ResolvedProductPtr(), m_environment); return exeFinder.findExecutable(filePath, m_workingDirectory); } void Process::writeLine(const QString &str) { m_qProcess->write(m_codec->fromUnicode(str)); m_qProcess->putChar('\n'); } JSValue Process::jsShellQuote(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto args = getArguments(ctx, "Process.shellQuote", argc, argv); HostOsInfo::HostOs hostOs = HostOsInfo::hostOs(); if (argc > 2) { const auto osList = fromArg(ctx, "Process.shellQuote", 3, argv[2]); hostOs = osList.contains(QLatin1String("windows")) ? HostOsInfo::HostOsWindows : HostOsInfo::HostOsOtherUnix; } return makeJsString(ctx, shellQuote(std::get<0>(args), std::get<1>(args), hostOs)); } catch (const QString &error) { return throwError(ctx, error); } } } // namespace Internal } // namespace qbs void initializeJsExtensionProcess(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::Process::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/propertylist.cpp0000644000175100001660000000434714776170045023454 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Petroules Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include void initializeJsExtensionPropertyList(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { JSValue obj = engine->newObject(); // provide a fake object qbs::Internal::setJsProperty(engine->context(), extensionObject, QStringLiteral("PropertyList"), obj); } qbs-src-2.6.1/src/lib/corelib/jsextensions/moduleproperties.cpp0000644000175100001660000003441114776170045024271 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "moduleproperties.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { JSValue createDataForModuleScriptValue(ScriptEngine *engine, const Artifact *artifact) { JSValue data = JS_NewObjectClass(engine->context(), engine->dataWithPtrClass()); attachPointerTo(data, artifact); return data; } static JSValue getModuleProperty(const ResolvedProduct *product, const Artifact *artifact, ScriptEngine *engine, const QString &moduleName, const QString &propertyName, bool *isPresent = nullptr) { const PropertyMapConstPtr &properties = artifact ? artifact->properties : product->moduleProperties; QVariant value; if (engine->isPropertyCacheEnabled()) value = engine->retrieveFromPropertyCache(moduleName, propertyName, properties); if (!value.isValid()) { value = properties->moduleProperty(moduleName, propertyName, isPresent); // Cache the variant value. We must not cache the script value here, because it's a // reference and the user might change the actual object. if (engine->isPropertyCacheEnabled()) engine->addToPropertyCache(moduleName, propertyName, properties, value); } else if (isPresent) { *isPresent = true; } const Property p(product->uniqueName(), moduleName, propertyName, value, Property::PropertyInModule); if (artifact) engine->addPropertyRequestedFromArtifact(artifact, p); else engine->addPropertyRequestedInScript(p); return engine->toScriptValue(value); } struct ModuleData { JSValue dependencyParameters = JS_UNDEFINED; const Artifact *artifact = nullptr; }; ModuleData getModuleData(JSContext *ctx, JSValue obj) { const ScopedJsValue jsData(ctx, getJsProperty(ctx, obj, StringConstants::dataPropertyInternal())); ModuleData data; data.dependencyParameters = JS_GetPropertyUint32(ctx, jsData, DependencyParametersKey); data.artifact = attachedPointer( jsData, ScriptEngine::engineForContext(ctx)->dataWithPtrClass()); return data; } static int getModulePropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj) { const auto engine = ScriptEngine::engineForContext(ctx); const ModuleData data = getModuleData(ctx, obj); const auto module = attachedPointer(obj, engine->modulePropertyScriptClass()); QBS_ASSERT(module, return -1); const PropertyMapInternal *propertyMap; QStringList additionalProperties; if (data.artifact) { propertyMap = data.artifact->properties.get(); } else { propertyMap = module->product->moduleProperties.get(); if (JS_IsObject(data.dependencyParameters)) additionalProperties.push_back(StringConstants::parametersProperty()); } JS_FreeValue(ctx, data.dependencyParameters); getPropertyNames(ctx, ptab, plen, propertyMap->value().value(module->name).toMap(), additionalProperties, engine->baseModuleScriptValue(module)); return 0; } static int getModuleProperty(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop) { if (desc) { desc->getter = desc->setter = desc->value = JS_UNDEFINED; desc->flags = JS_PROP_ENUMERABLE; } const auto engine = ScriptEngine::engineForContext(ctx); const QString name = getJsString(ctx, prop); const ModuleData data = getModuleData(ctx, obj); const auto module = attachedPointer(obj, engine->modulePropertyScriptClass()); QBS_ASSERT(module, return -1); ScopedJsValue parametersMgr(ctx, data.dependencyParameters); if (name == StringConstants::parametersProperty()) { if (desc) desc->value = parametersMgr.release(); return 1; } bool isPresent; JSValue value = getModuleProperty( module->product, data.artifact, ScriptEngine::engineForContext(ctx), module->name, name, &isPresent); if (isPresent) { if (desc) desc->value = value; return 1; } ScopedJsValue v(ctx, JS_GetProperty(ctx, engine->baseModuleScriptValue(module), prop)); const int ret = JS_IsUndefined(v) ? 0 : 1; if (desc) desc->value = v.release(); return ret; } static JSValue js_moduleDependencies(JSContext *ctx, JSValueConst this_val, int , JSValueConst *) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto module = attachedPointer(this_val, engine->dataWithPtrClass()); JSValue result = JS_NewArray(engine->context()); quint32 idx = 0; for (const QString &depName : std::as_const(module->moduleDependencies)) { for (const auto &dep : module->product->modules) { if (dep->name != depName) continue; JSValue obj = JS_NewObjectClass(ctx, engine->modulePropertyScriptClass()); attachPointerTo(obj, dep.get()); JSValue data = createDataForModuleScriptValue(engine, nullptr); const QVariantMap ¶ms = module->product->moduleParameters.value(dep); JS_SetPropertyUint32(ctx, data, DependencyParametersKey, dependencyParametersValue(module->product->uniqueName(), dep->name, params, engine)); defineJsProperty(ctx, obj, StringConstants::dataPropertyInternal(), data); JS_SetPropertyUint32(ctx, result, idx++, obj); break; } } QBS_ASSERT(idx == quint32(module->moduleDependencies.size()),;); return result; } template static JSValue moduleProperty(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { if (Q_UNLIKELY(argc < 2)) return throwError(ctx, Tr::tr("Function moduleProperty() expects 2 arguments")); ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const ResolvedProduct *product = nullptr; const Artifact *artifact = nullptr; if constexpr (std::is_same_v) { product = attachedPointer(this_val, engine->productPropertyScriptClass()); } else { artifact = attachedPointer(this_val, engine->dataWithPtrClass()); product = artifact->product; } const QString moduleName = getJsString(ctx, argv[0]); const QString propertyName = getJsString(ctx, argv[1]); return getModuleProperty(product, artifact, engine, moduleName, propertyName); } template static JSValue js_moduleProperty(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { try { return moduleProperty(ctx, this_val, argc, argv); } catch (const ErrorInfo &e) { return throwError(ctx, e.toString()); } } template static void initModuleProperties(ScriptEngine *engine, JSValue objectWithProperties) { JSContext * const ctx = engine->context(); JSValue func = JS_NewCFunction(ctx, js_moduleProperty, "moduleProperty", 2); setJsProperty(ctx, objectWithProperties, std::string_view("moduleProperty"), func); } static JSValue setupBaseModuleScriptValue(ScriptEngine *engine, const ResolvedModule *module) { JSValue &moduleScriptValue = engine->baseModuleScriptValue(module); if (JS_IsObject(moduleScriptValue)) return moduleScriptValue; const ScopedJsValue proto(engine->context(), JS_NewObject(engine->context())); moduleScriptValue = JS_NewObjectProtoClass(engine->context(), proto, engine->dataWithPtrClass()); attachPointerTo(moduleScriptValue, module); QByteArray name = StringConstants::dependenciesProperty().toUtf8(); const ScopedJsValue depfunc( engine->context(), JS_NewCFunction(engine->context(), js_moduleDependencies, name.constData(), 0)); const ScopedJsAtom depAtom(engine->context(), name); JS_DefineProperty(engine->context(), moduleScriptValue, depAtom, JS_UNDEFINED, depfunc, JS_UNDEFINED, JS_PROP_HAS_GET | JS_PROP_ENUMERABLE); name = StringConstants::artifactsProperty().toUtf8(); const ScopedJsValue artifactsFunc( engine->context(), JS_NewCFunction(engine->context(), &artifactsScriptValueForModule, name.constData(), 0)); const ScopedJsAtom artifactsAtom(engine->context(), name); JS_DefineProperty(engine->context(), moduleScriptValue, artifactsAtom, JS_UNDEFINED, artifactsFunc, JS_UNDEFINED, JS_PROP_HAS_GET | JS_PROP_ENUMERABLE); return moduleScriptValue; } void ModuleProperties::init(ScriptEngine *engine, JSValue productObject, const ResolvedProduct *product) { initModuleProperties(engine, productObject); setupModules(engine, productObject, product, nullptr); } void ModuleProperties::init(ScriptEngine *engine, JSValue artifactObject, const Artifact *artifact) { initModuleProperties(engine, artifactObject); const auto product = artifact->product; const QVariantMap productProperties { {StringConstants::buildDirectoryProperty(), product->buildDirectory()}, {StringConstants::destinationDirProperty(), product->destinationDirectory}, {StringConstants::nameProperty(), product->name}, {StringConstants::sourceDirectoryProperty(), product->sourceDirectory}, {StringConstants::targetNameProperty(), product->targetName}, {StringConstants::typeProperty(), sorted(product->fileTags.toStringList())} }; setJsProperty(engine->context(), artifactObject, StringConstants::productVar(), engine->toScriptValue(productProperties)); setupModules(engine, artifactObject, artifact->product.get(), artifact); } void ModuleProperties::setModuleScriptValue(ScriptEngine *engine, JSValue targetObject, const JSValue &moduleObject, const QString &moduleName) { const QualifiedId name = QualifiedId::fromString(moduleName); JSValue obj = targetObject; for (int i = 0; i < name.size() - 1; ++i) { JSValue tmp = getJsProperty(engine->context(), obj, name.at(i)); if (!JS_IsObject(tmp)) { tmp = engine->newObject(); setJsProperty(engine->context(), obj, name.at(i), tmp); } else { JS_FreeValue(engine->context(), tmp); } obj = tmp; } setJsProperty(engine->context(), obj, name.last(), moduleObject); if (name.size() > 1) { setJsProperty(engine->context(), targetObject, moduleName, JS_DupValue(engine->context(), moduleObject)); } } void ModuleProperties::setupModules(ScriptEngine *engine, JSValue &object, const ResolvedProduct *product, const Artifact *artifact) { JSClassID modulePropertyScriptClass = engine->modulePropertyScriptClass(); if (modulePropertyScriptClass == 0) { modulePropertyScriptClass = engine->registerClass("ModulePropertyScriptClass", nullptr, nullptr, JS_UNDEFINED, &getModulePropertyNames, &getModuleProperty); engine->setModulePropertyScriptClass(modulePropertyScriptClass); } for (const auto &module : product->modules) { setupBaseModuleScriptValue(engine, module.get()); JSValue moduleObject = JS_NewObjectClass(engine->context(), modulePropertyScriptClass); attachPointerTo(moduleObject, module.get()); defineJsProperty(engine->context(), moduleObject, StringConstants::dataPropertyInternal(), createDataForModuleScriptValue(engine, artifact)); setModuleScriptValue(engine, object, moduleObject, module->name); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/jsextensions/moduleproperties.h0000644000175100001660000000566614776170045023750 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_MODULEPROPERTIES_H #define QBS_MODULEPROPERTIES_H #include #include #include namespace qbs { namespace Internal { class ScriptEngine; enum ModulePropertiesScriptValueCommonPropertyKeys : quint32 { ModuleNameKey, DependencyParametersKey, }; JSValue createDataForModuleScriptValue(ScriptEngine *engine, const Artifact *artifact); class ModuleProperties { public: static void init(ScriptEngine *engine, JSValue productObject, const ResolvedProduct *product); static void init(ScriptEngine *engine, JSValue artifactObject, const Artifact *artifact); static void setModuleScriptValue(ScriptEngine *engine, JSValue targetObject, const JSValue &moduleObject, const QString &moduleName); private: static void setupModules(ScriptEngine *engine, JSValue &object, const ResolvedProduct *product, const Artifact *artifact); }; } // namespace Internal } // namespace qbs #endif // QBS_MODULEPROPERTIES_H qbs-src-2.6.1/src/lib/corelib/jsextensions/environmentextension.cpp0000644000175100001660000001420214776170045025164 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include namespace qbs { namespace Internal { class EnvironmentExtension : public JsExtension { public: static const char *name() { return "Environment"; } static void setupStaticMethods(JSContext *ctx, JSValue classObj); static JSValue jsGetEnv(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsPutEnv(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsUnsetEnv(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsCurrentEnv(JSContext *ctx, JSValueConst, int, JSValueConst *); }; void EnvironmentExtension::setupStaticMethods(JSContext *ctx, JSValue classObj) { setupMethod(ctx, classObj, "getEnv", &EnvironmentExtension::jsGetEnv, 1); setupMethod(ctx, classObj, "putEnv", &EnvironmentExtension::jsPutEnv, 2); setupMethod(ctx, classObj, "unsetEnv", &EnvironmentExtension::jsUnsetEnv, 1); setupMethod(ctx, classObj, "currentEnv", &EnvironmentExtension::jsCurrentEnv, 0); } static QProcessEnvironment *getProcessEnvironment(ScriptEngine *engine, const QString &func, bool doThrow = true) { QVariant v = engine->property(StringConstants::qbsProcEnvVarInternal()); auto procenv = reinterpret_cast(v.value()); if (!procenv && doThrow) { throw QStringLiteral("%1 can only be called from " "Module.setupBuildEnvironment and " "Module.setupRunEnvironment").arg(func); } return procenv; } JSValue EnvironmentExtension::jsGetEnv(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv) { try { const auto name = getArgument(ctx, "Environment.getEnv", argc, argv); ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const QProcessEnvironment env = engine->environment(); const QProcessEnvironment *procenv = getProcessEnvironment(engine, QStringLiteral("getEnv"), false); if (!procenv) procenv = &env; const QString value = procenv->value(name); return value.isNull() ? engine->undefinedValue() : makeJsString(ctx, value); } catch (const QString &error) { return throwError(ctx, error); } } JSValue EnvironmentExtension::jsPutEnv(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto args = getArguments(ctx, "Environment.putEnv", argc, argv); getProcessEnvironment(ScriptEngine::engineForContext(ctx), QStringLiteral("putEnv")) ->insert(std::get<0>(args), std::get<1>(args)); return JS_UNDEFINED; } catch (const QString &error) { return throwError(ctx, error); } } JSValue EnvironmentExtension::jsUnsetEnv(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto name = getArgument(ctx, "Environment.unsetEnv", argc, argv); getProcessEnvironment(ScriptEngine::engineForContext(ctx), QStringLiteral("unsetEnv")) ->remove(name); return JS_UNDEFINED; } catch (const QString &error) { return throwError(ctx, error); } } JSValue EnvironmentExtension::jsCurrentEnv(JSContext *ctx, JSValue, int, JSValue *) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const QProcessEnvironment env = engine->environment(); const QProcessEnvironment *procenv = getProcessEnvironment(engine, QStringLiteral("currentEnv"), false); if (!procenv) procenv = &env; JSValue envObject = engine->newObject(); const auto keys = procenv->keys(); for (const QString &key : keys) { const QString keyName = HostOsInfo::isWindowsHost() ? key.toUpper() : key; setJsProperty(ctx, envObject, keyName, procenv->value(key)); } return envObject; } } // namespace Internal } // namespace qbs void initializeJsExtensionEnvironment(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::EnvironmentExtension::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/temporarydir.cpp0000644000175100001660000000747214776170045023417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Jake Petroules. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include namespace qbs { namespace Internal { static bool tempDirIsCanonical() { #if QT_VERSION >= 0x050c00 return true; #endif return false; } class TemporaryDir : public JsExtension { friend class JsExtension; public: static const char *name() { return "TemporaryDir"; } static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int, JSValueConst *, int) { const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts{DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving)}; se->checkContext(QStringLiteral("qbs.TemporaryDir"), dubiousContexts); return createObject(ctx); } static void setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "isValid", &jsIsValid, 0); setupMethod(ctx, obj, "path", &jsPath, 0); setupMethod(ctx, obj, "remove", &jsRemove, 0); } private: TemporaryDir(JSContext *) { m_dir.setAutoRemove(false); } DEFINE_JS_FORWARDER(jsIsValid, &TemporaryDir::isValid, "TemporaryDir.isValid") DEFINE_JS_FORWARDER(jsPath, &TemporaryDir::path, "TemporaryDir.path") DEFINE_JS_FORWARDER(jsRemove, &TemporaryDir::remove, "TemporaryDir.remove") bool isValid() const { return m_dir.isValid(); } QString path() const { return tempDirIsCanonical() ? m_dir.path() : QFileInfo(m_dir.path()).canonicalFilePath(); } bool remove() { return m_dir.remove(); } QTemporaryDir m_dir; }; } // namespace Internal } // namespace qbs void initializeJsExtensionTemporaryDir(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::TemporaryDir::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/host.cpp0000644000175100001660000001411314776170045021641 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Raphaël Cotty ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include namespace qbs { namespace Internal { class Host : public JsExtension { public: static const char *name() { return "Host"; } static void setupStaticMethods(JSContext *ctx, JSValue classObj); static JSValue jsArchitecture(JSContext *ctx, JSValueConst, int, JSValueConst *) { return makeJsString(ctx, HostOsInfo::hostOSArchitecture()); } static JSValue jsOs(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsPlatform(JSContext *ctx, JSValueConst, int, JSValueConst *) { return makeJsString(ctx, HostOsInfo::hostOSIdentifier()); } static JSValue jsOsVersion(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsOsBuildVersion(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsOsVersionParts(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsOsVersionMajor(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsOsVersionMinor(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsOsVersionPatch(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsNullDevice(JSContext *ctx, JSValueConst, int, JSValueConst *); }; static QStringList osList() { QStringList list; for (const auto &s : HostOsInfo::canonicalOSIdentifiers(HostOsInfo::hostOSIdentifier())) list.push_back(s); return list; } void Host::setupStaticMethods(JSContext *ctx, JSValue classObj) { setupMethod(ctx, classObj, "architecture", &Host::jsArchitecture, 0); setupMethod(ctx, classObj, "os", &Host::jsOs, 0); setupMethod(ctx, classObj, "platform", &Host::jsPlatform, 0); setupMethod(ctx, classObj, "osVersion", &Host::jsOsVersion, 0); setupMethod(ctx, classObj, "osBuildVersion", &Host::jsOsBuildVersion, 0); setupMethod(ctx, classObj, "osVersionParts", &Host::jsOsVersionParts, 0); setupMethod(ctx, classObj, "osVersionMajor", &Host::jsOsVersionMajor, 0); setupMethod(ctx, classObj, "osVersionMinor", &Host::jsOsVersionMinor, 0); setupMethod(ctx, classObj, "osVersionPatch", &Host::jsOsVersionPatch, 0); setupMethod(ctx, classObj, "nullDevice", &Host::jsNullDevice, 0); } JSValue Host::jsOs(JSContext *ctx, JSValue, int, JSValue *) { static QStringList host = osList(); return makeJsStringList(ctx, host); } JSValue Host::jsOsVersion(JSContext *ctx, JSValue, int, JSValue *) { static QString osVersion = HostOsInfo::hostOsVersion().toString(); return osVersion.isNull() ? JS_UNDEFINED : makeJsString(ctx, osVersion); } JSValue Host::jsOsBuildVersion(JSContext *ctx, JSValue, int, JSValue *) { static QString osBuildVersion = HostOsInfo::hostOsBuildVersion(); return osBuildVersion.isNull() ? JS_UNDEFINED : makeJsString(ctx, osBuildVersion); } JSValue Host::jsOsVersionParts(JSContext *ctx, JSValue, int, JSValue *) { static QStringList osVersionParts = HostOsInfo::hostOsVersion().toString().split( QStringLiteral(".")); return makeJsStringList(ctx, osVersionParts); } JSValue Host::jsOsVersionMajor(JSContext *ctx, JSValue, int, JSValue *) { static int osVersionMajor = HostOsInfo::hostOsVersion().majorVersion(); return JS_NewInt32(ctx, osVersionMajor); } JSValue Host::jsOsVersionMinor(JSContext *ctx, JSValue, int, JSValue *) { static int osVersionMinor = HostOsInfo::hostOsVersion().minorVersion(); return JS_NewInt32(ctx, osVersionMinor); } JSValue Host::jsOsVersionPatch(JSContext *ctx, JSValue, int, JSValue *) { static int osVersionPatch = HostOsInfo::hostOsVersion().patchLevel(); return JS_NewInt32(ctx, osVersionPatch); } JSValue Host::jsNullDevice(JSContext *ctx, JSValue, int, JSValue *) { static QString nullDevice = HostOsInfo::isWindowsHost() ? QStringLiteral("NUL") : QStringLiteral("/dev/null"); return makeJsString(ctx, nullDevice); } } // namespace Internal } // namespace qbs void initializeJsExtensionHost(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::Host::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/textfile.cpp0000644000175100001660000001750114776170045022514 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #else #include #endif namespace qbs { namespace Internal { class TextFile : public JsExtension { friend class JsExtension; public: enum OpenMode { ReadOnly = 1, WriteOnly = 2, ReadWrite = ReadOnly | WriteOnly, Append = 4 }; static const char *name() { return "TextFile"; } static void declareEnums(JSContext *ctx, JSValue classObj); static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int); static void setupMethods(JSContext *ctx, JSValue obj); private: DEFINE_JS_FORWARDER(jsClose, &TextFile::close, "TextFile.close") DEFINE_JS_FORWARDER(jsFilePath, &TextFile::filePath, "TextFile.filePath") DEFINE_JS_FORWARDER(jsSetCodec, &TextFile::setCodec, "TextFile.setCodec") DEFINE_JS_FORWARDER(jsReadLine, &TextFile::readLine, "TextFile.readLine") DEFINE_JS_FORWARDER(jsReadAll, &TextFile::readAll, "TextFile.readAll") DEFINE_JS_FORWARDER(jsAtEof, &TextFile::atEof, "TextFile.atEof") DEFINE_JS_FORWARDER(jsTruncate, &TextFile::truncate, "TextFile.truncate") DEFINE_JS_FORWARDER(jsWrite, &TextFile::write, "TextFile.write") DEFINE_JS_FORWARDER(jsWriteLine, &TextFile::writeLine, "TextFile.writeLine") void close(); QString filePath(); void setCodec(const QString &codec); QString readLine(); QString readAll(); bool atEof() const; void truncate(); void write(const QString &str); void writeLine(const QString &str); TextFile(JSContext *, const QString &filePath, OpenMode mode, const QString &codec); void checkForClosed() const; std::unique_ptr m_file; QTextCodec *m_codec = nullptr; }; void TextFile::declareEnums(JSContext *ctx, JSValue classObj) { DECLARE_ENUM(ctx, classObj, ReadOnly); DECLARE_ENUM(ctx, classObj, WriteOnly); DECLARE_ENUM(ctx, classObj, ReadWrite); DECLARE_ENUM(ctx, classObj, Append); } JSValue TextFile::ctor(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int) { try { const auto filePath = getArgument(ctx, "TextFile constructor", argc, argv); OpenMode mode = ReadOnly; QString codec = QLatin1String("UTF-8"); if (argc > 1) { mode = static_cast (fromArg(ctx, "TextFile constructor", 2, argv[1])); } if (argc > 2) { codec = fromArg(ctx, "TextFile constructor", 3, argv[2]); } ScopedJsValue obj(ctx, createObject(ctx, filePath, mode, codec)); const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts { DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }; se->checkContext(QStringLiteral("qbs.TextFile"), dubiousContexts); se->setUsesIo(); return obj.release(); } catch (const QString &error) { return throwError(ctx, error); } } void TextFile::setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "close", &jsClose, 0); setupMethod(ctx, obj, "filePath", &jsFilePath, 0); setupMethod(ctx, obj, "atEof", &jsAtEof, 0); setupMethod(ctx, obj, "setCodec", &jsSetCodec, 1); setupMethod(ctx, obj, "readLine", &jsReadLine, 0); setupMethod(ctx, obj, "readAll", &jsReadAll, 0); setupMethod(ctx, obj, "truncate", &jsTruncate, 0); setupMethod(ctx, obj, "write", &jsWrite, 1); setupMethod(ctx, obj, "writeLine", &jsWriteLine, 1); } TextFile::TextFile(JSContext *, const QString &filePath, OpenMode mode, const QString &codec) { auto file = std::make_unique(filePath); const auto newCodec = QTextCodec::codecForName(qPrintable(codec)); m_codec = newCodec ? newCodec : QTextCodec::codecForName("UTF-8"); QIODevice::OpenMode m = QIODevice::NotOpen; if (mode & ReadOnly) m |= QIODevice::ReadOnly; if (mode & WriteOnly) m |= QIODevice::WriteOnly; if (mode & Append) m |= QIODevice::Append; m |= QIODevice::Text; if (Q_UNLIKELY(!file->open(m))) throw Tr::tr("Unable to open file '%1': %2").arg(filePath, file->errorString()); m_file = std::move(file); } void TextFile::close() { checkForClosed(); m_file->close(); m_file.reset(); } QString TextFile::filePath() { checkForClosed(); return QFileInfo(*m_file).absoluteFilePath(); } void TextFile::setCodec(const QString &codec) { checkForClosed(); const auto newCodec = QTextCodec::codecForName(qPrintable(codec)); if (newCodec) m_codec = newCodec; } QString TextFile::readLine() { checkForClosed(); auto result = m_codec->toUnicode(m_file->readLine()); if (!result.isEmpty() && result.back() == QLatin1Char('\n')) result.chop(1); return result; } QString TextFile::readAll() { checkForClosed(); return m_codec->toUnicode(m_file->readAll()); } bool TextFile::atEof() const { checkForClosed(); return m_file->atEnd(); } void TextFile::truncate() { checkForClosed(); m_file->resize(0); } void TextFile::write(const QString &str) { checkForClosed(); m_file->write(m_codec->fromUnicode(str)); } void TextFile::writeLine(const QString &str) { checkForClosed(); m_file->write(m_codec->fromUnicode(str)); m_file->putChar('\n'); } void TextFile::checkForClosed() const { if (!m_file) throw Tr::tr("Access to TextFile object that was already closed."); } } // namespace Internal } // namespace qbs void initializeJsExtensionTextFile(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::TextFile::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/pkgconfigjs.cpp0000644000175100001660000002441514776170045023176 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "pkgconfigjs.h" #include #include #include #include namespace qbs { namespace Internal { namespace { template QVariantList convert(const C &c, F &&f) { QVariantList result; result.reserve(int(c.size())); std::transform(c.begin(), c.end(), std::back_inserter(result), f); return result; } QVariantMap variablesMapToMap(const PcPackage::VariablesMap &variables) { QVariantMap result; for (const auto &item: variables) result.insert(QString::fromStdString(item.first), QString::fromStdString(item.second)); return result; } QVariantMap packageToMap(const PcPackage &package) { QVariantMap result; result[QStringLiteral("isBroken")] = false; result[QStringLiteral("filePath")] = QString::fromStdString(package.filePath); result[QStringLiteral("baseFileName")] = QString::fromStdString(package.baseFileName); result[QStringLiteral("name")] = QString::fromStdString(package.name); result[QStringLiteral("version")] = QString::fromStdString(package.version); result[QStringLiteral("description")] = QString::fromStdString(package.description); result[QStringLiteral("url")] = QString::fromStdString(package.url); const auto flagToMap = [](const PcPackage::Flag &flag) { QVariantMap result; const auto value = QString::fromStdString(flag.value); result[QStringLiteral("type")] = QVariant::fromValue(qint32(flag.type)); result[QStringLiteral("value")] = value; return result; }; const auto requiredVersionToMap = [](const PcPackage::RequiredVersion &version) { using Type = PcPackage::RequiredVersion::ComparisonType; QVariantMap result; result[QStringLiteral("name")] = QString::fromStdString(version.name); const auto versionString = QString::fromStdString(version.version); const auto qbsVersion = Version::fromString(QString::fromStdString(version.version)); const auto nextQbsVersion = Version( qbsVersion.majorVersion(), qbsVersion.minorVersion(), qbsVersion.patchLevel() + 1); switch (version.comparison) { case Type::LessThan: result[QStringLiteral("versionBelow")] = versionString; break; case Type::GreaterThan: result[QStringLiteral("versionAtLeast")] = nextQbsVersion.toString(); break; case Type::LessThanEqual: result[QStringLiteral("versionBelow")] = nextQbsVersion.toString(); break; case Type::GreaterThanEqual: result[QStringLiteral("versionAtLeast")] = versionString; break; case Type::Equal: result[QStringLiteral("version")] = versionString; break; case Type::NotEqual: result[QStringLiteral("versionBelow")] = versionString; result[QStringLiteral("versionAtLeast")] = nextQbsVersion.toString(); break; case Type::AlwaysMatch: break; } return result; }; result[QStringLiteral("libs")] = convert(package.libs, flagToMap); result[QStringLiteral("libsPrivate")] = convert(package.libsPrivate, flagToMap); result[QStringLiteral("cflags")] = convert(package.cflags, flagToMap); result[QStringLiteral("requires")] = convert(package.requiresPublic, requiredVersionToMap); result[QStringLiteral("requiresPrivate")] = convert(package.requiresPrivate, requiredVersionToMap); result[QStringLiteral("conflicts")] = convert(package.conflicts, requiredVersionToMap); result[QStringLiteral("variables")] = variablesMapToMap(package.variables); return result; }; QVariantMap brokenPackageToMap(const PcBrokenPackage &package) { QVariantMap result; result[QStringLiteral("isBroken")] = true; result[QStringLiteral("filePath")] = QString::fromStdString(package.filePath); result[QStringLiteral("baseFileName")] = QString::fromStdString(package.baseFileName); result[QStringLiteral("errorText")] = QString::fromStdString(package.errorText); return result; } QVariantMap packageVariantToMap(const PcPackageVariant &package) { return package.visit([](const auto &value) { using T = std::decay_t; if constexpr (std::is_same_v) return packageToMap(value); else return brokenPackageToMap(value); }); } PcPackage::VariablesMap envToVariablesMap(const QProcessEnvironment &env) { PcPackage::VariablesMap result; const auto keys = env.keys(); for (const auto &key : keys) result[key.toStdString()] = env.value(key).toStdString(); return result; } PcPackage::VariablesMap variablesFromQVariantMap(const QVariantMap &map) { PcPackage::VariablesMap result; for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) result[it.key().toStdString()] = it.value().toString().toStdString(); return result; } std::vector stringListToStdVector(const QStringList &list) { return transformed>(list, [](const auto &s) { return s.toStdString(); }); } } // namespace void PkgConfigJs::declareEnums(JSContext *ctx, JSValue classObj) { DECLARE_ENUM(ctx, classObj, LibraryName); DECLARE_ENUM(ctx, classObj, LibraryPath); DECLARE_ENUM(ctx, classObj, StaticLibraryName); DECLARE_ENUM(ctx, classObj, Framework); DECLARE_ENUM(ctx, classObj, FrameworkPath); DECLARE_ENUM(ctx, classObj, LinkerFlag); DECLARE_ENUM(ctx, classObj, IncludePath); DECLARE_ENUM(ctx, classObj, SystemIncludePath); DECLARE_ENUM(ctx, classObj, Define); DECLARE_ENUM(ctx, classObj, CompilerFlag); } JSValue PkgConfigJs::ctor(JSContext *ctx, JSValue, JSValue, int argc, JSValue *argv, int) { try { QVariantMap options; if (argc > 0) options = fromArg(ctx, "PkgConfig constructor", 1, argv[0]).toMap(); JSValue obj = createObject(ctx, options); return obj; } catch (const PcException &e) { return throwError(ctx, QString::fromUtf8(e.what())); } catch (const QString &error) { return throwError(ctx, error); } } PkgConfigJs::PkgConfigJs(JSContext *ctx, const QVariantMap &options) : m_pkgConfig(std::make_unique( convertOptions(ScriptEngine::engineForContext(ctx)->environment(), options))) { for (const auto &package : m_pkgConfig->packages()) { m_packages.insert( QString::fromStdString(package.getBaseFileName()), packageVariantToMap(package)); } } PkgConfig::Options PkgConfigJs::convertOptions(const QProcessEnvironment &env, const QVariantMap &map) { PkgConfig::Options result; result.libDirs = stringListToStdVector(map.value(QStringLiteral("libDirs")).toStringList()); result.extraPaths = stringListToStdVector(map.value(QStringLiteral("extraPaths")).toStringList()); result.sysroot = map.value(QStringLiteral("sysroot")).toString().toStdString(); result.topBuildDir = map.value(QStringLiteral("topBuildDir")).toString().toStdString(); result.allowSystemLibraryPaths = map.value(QStringLiteral("allowSystemLibraryPaths"), false).toBool(); const auto systemLibraryPaths = map.value(QStringLiteral("systemLibraryPaths")).toStringList(); result.systemLibraryPaths.reserve(systemLibraryPaths.size()); std::transform( systemLibraryPaths.begin(), systemLibraryPaths.end(), std::back_inserter(result.systemLibraryPaths), [](const QString &str){ return str.toStdString(); }); result.disableUninstalled = map.value(QStringLiteral("disableUninstalled"), true).toBool(); result.staticMode = map.value(QStringLiteral("staticMode"), false).toBool(); result.definePrefix = map.value(QStringLiteral("definePrefix"), false).toBool(); result.globalVariables = variablesFromQVariantMap(map.value(QStringLiteral("globalVariables")).toMap()); result.systemVariables = envToVariablesMap(env); return result; } void PkgConfigJs::setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "packages", &PkgConfigJs::jsPackages, 0); } } // namespace Internal } // namespace qbs void initializeJsExtensionPkgConfig(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::PkgConfigJs::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/binaryfile.cpp0000644000175100001660000001742714776170045023023 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 Sergey Belyashov ** Copyright (C) 2017 Denis Shienkov ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include #include namespace qbs { namespace Internal { class BinaryFile : public JsExtension { friend class JsExtension; public: enum OpenMode { ReadOnly = 1, WriteOnly = 2, ReadWrite = ReadOnly | WriteOnly }; static const char *name() { return "BinaryFile"; } static void declareEnums(JSContext *ctx, JSValue classObj); static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int); private: static void setupMethods(JSContext *ctx, JSValue obj); DEFINE_JS_FORWARDER(jsClose, &BinaryFile::close, "BinaryFile.close") DEFINE_JS_FORWARDER(jsFilePath, &BinaryFile::filePath, "BinaryFile.filePath") DEFINE_JS_FORWARDER(jsAtEof, &BinaryFile::atEof, "BinaryFile.atEof") DEFINE_JS_FORWARDER(jsSize, &BinaryFile::size, "BinaryFile.size") DEFINE_JS_FORWARDER(jsResize, &BinaryFile::resize, "BinaryFile.resize") DEFINE_JS_FORWARDER(jsPos, &BinaryFile::pos, "BinaryFile.pos") DEFINE_JS_FORWARDER(jsSeek, &BinaryFile::seek, "BinaryFile.seek") DEFINE_JS_FORWARDER(jsRead, &BinaryFile::read, "BinaryFile.read") DEFINE_JS_FORWARDER(jsWrite, &BinaryFile::write, "BinaryFile.write") void close(); QString filePath(); bool atEof() const; qint64 size() const; void resize(qint64 size); qint64 pos() const; void seek(qint64 pos); QByteArray read(qint64 size); void write(const QByteArray &data); explicit BinaryFile(JSContext *, const QString &filePath, OpenMode mode); void checkForClosed() const; std::unique_ptr m_file; }; void BinaryFile::declareEnums(JSContext *ctx, JSValue classObj) { DECLARE_ENUM(ctx, classObj, ReadOnly); DECLARE_ENUM(ctx, classObj, WriteOnly); DECLARE_ENUM(ctx, classObj, ReadWrite); } void BinaryFile::setupMethods(JSContext *ctx, JSValue obj) { setupMethod(ctx, obj, "close", &jsClose, 0); setupMethod(ctx, obj, "filePath", &jsFilePath, 0); setupMethod(ctx, obj, "atEof", &jsAtEof, 0); setupMethod(ctx, obj, "size", &jsSize, 0); setupMethod(ctx, obj, "resize", &jsResize, 0); setupMethod(ctx, obj, "pos", &jsPos, 0); setupMethod(ctx, obj, "seek", &jsSeek, 0); setupMethod(ctx, obj, "read", &jsRead, 0); setupMethod(ctx, obj, "write", &jsWrite, 0); } JSValue BinaryFile::ctor(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int) { try { const auto filePath = getArgument(ctx, "BinaryFile constructor", argc, argv); OpenMode mode = ReadOnly; if (argc > 1) { mode = static_cast (fromArg(ctx, "BinaryFile constructor", 2, argv[1])); } const JSValue obj = createObject(ctx, filePath, mode); const auto se = ScriptEngine::engineForContext(ctx); const DubiousContextList dubiousContexts { DubiousContext(EvalContext::PropertyEvaluation, DubiousContext::SuggestMoving) }; se->checkContext(QStringLiteral("qbs.BinaryFile"), dubiousContexts); se->setUsesIo(); return obj; } catch (const QString &error) { return throwError(ctx, error); } } BinaryFile::BinaryFile(JSContext *, const QString &filePath, OpenMode mode) { QIODevice::OpenMode m = QIODevice::NotOpen; switch (mode) { case ReadWrite: m = QIODevice::ReadWrite; break; case ReadOnly: m = QIODevice::ReadOnly; break; case WriteOnly: m = QIODevice::WriteOnly; break; default: throw Tr::tr("Unable to open file '%1': Undefined mode '%2'").arg(filePath).arg(mode); } auto file = std::make_unique(filePath); if (Q_UNLIKELY(!file->open(m))) throw Tr::tr("Unable to open file '%1': %2").arg(filePath, file->errorString()); m_file = std::move(file); } void BinaryFile::close() { checkForClosed(); m_file->close(); m_file.reset(); } QString BinaryFile::filePath() { checkForClosed(); return QFileInfo(*m_file).absoluteFilePath(); } bool BinaryFile::atEof() const { checkForClosed(); return m_file->atEnd(); } qint64 BinaryFile::size() const { checkForClosed(); return m_file->size(); } void BinaryFile::resize(qint64 size) { checkForClosed(); if (Q_UNLIKELY(!m_file->resize(size))) throw Tr::tr("Could not resize '%1': %2").arg(m_file->fileName(), m_file->errorString()); } qint64 BinaryFile::pos() const { checkForClosed(); return m_file->pos(); } void BinaryFile::seek(qint64 pos) { checkForClosed(); if (Q_UNLIKELY(!m_file->seek(pos))) throw Tr::tr("Could not seek '%1': %2").arg(m_file->fileName(), m_file->errorString()); } QByteArray BinaryFile::read(qint64 size) { checkForClosed(); QByteArray bytes = m_file->read(size); if (Q_UNLIKELY(bytes.size() == 0 && m_file->error() != QFile::NoError)) { throw (Tr::tr("Could not read from '%1': %2") .arg(m_file->fileName(), m_file->errorString())); } return bytes; } void BinaryFile::write(const QByteArray &data) { checkForClosed(); const qint64 size = m_file->write(data); if (Q_UNLIKELY(size == -1)) { throw Tr::tr("Could not write to '%1': %2") .arg(m_file->fileName(), m_file->errorString()); } } void BinaryFile::checkForClosed() const { if (!m_file) throw Tr::tr("Access to BinaryFile object that was already closed."); } } // namespace Internal } // namespace qbs void initializeJsExtensionBinaryFile(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::BinaryFile::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/jsextensions/propertylistutils.mm0000644000175100001660000001645514776170045024367 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import #include "propertylistutils.h" #include #include #include #include static QVariant fromObject(id obj); static QVariantMap fromDictionary(NSDictionary *dict); static QVariantList fromArray(NSArray *array); static QVariant fromObject(id obj) { QVariant value; if (!obj) { return value; } else if ([obj isKindOfClass:[NSDictionary class]]) { value = fromDictionary(obj); } else if ([obj isKindOfClass:[NSArray class]]) { value = fromArray(obj); } else if ([obj isKindOfClass:[NSString class]]) { value = QString::fromNSString(obj); } else if ([obj isKindOfClass:[NSData class]]) { value = QByteArray::fromNSData(obj); } else if ([obj isKindOfClass:[NSDate class]]) { value = QDateTime::fromNSDate(obj); } else if ([obj isKindOfClass:[NSNumber class]]) { if (strcmp([(NSNumber *)obj objCType], @encode(BOOL)) == 0) { value = static_cast([obj boolValue]); } else if (strcmp([(NSNumber *)obj objCType], @encode(signed char)) == 0) { value = [obj charValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(unsigned char)) == 0) { value = [obj unsignedCharValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(signed short)) == 0) { value = [obj shortValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(unsigned short)) == 0) { value = [obj unsignedShortValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(signed int)) == 0) { value = [obj intValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(unsigned int)) == 0) { value = [obj unsignedIntValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(signed long long)) == 0) { value = [obj longLongValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(unsigned long long)) == 0) { value = [obj unsignedLongLongValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(float)) == 0) { value = [obj floatValue]; } else if (strcmp([(NSNumber *)obj objCType], @encode(double)) == 0) { value = [obj doubleValue]; } else { // NSDecimal or unknown value = [obj doubleValue]; } } else if ([obj isKindOfClass:[NSNull class]]) { // A null variant, close enough... } else { // unknown } return value; } static QVariantMap fromDictionary(NSDictionary *dict) { QVariantMap map; for (NSString *key in dict) map[QString::fromNSString(key)] = fromObject([dict objectForKey:key]); return map; } static QVariantList fromArray(NSArray *array) { QVariantList list; for (id obj in array) list.push_back(fromObject(obj)); return list; } QVariant QPropertyListUtils::fromPropertyList(id plist) { return fromObject(plist); } static id toObject(const QVariant &variant); static NSDictionary *toDictionary(const QVariantMap &map); static NSArray *toArray(const QVariantList &list); static id toObject(const QVariant &variant) { if (variant.userType() == QMetaType::QVariantHash) { return toDictionary(qHashToMap(variant.toHash())); } else if (variant.userType() == QMetaType::QVariantMap) { return toDictionary(variant.toMap()); } else if (variant.userType() == QMetaType::QVariantList) { return toArray(variant.toList()); } else if (variant.userType() == QMetaType::QString) { return variant.toString().toNSString(); } else if (variant.userType() == QMetaType::QByteArray) { return variant.toByteArray().toNSData(); } else if (variant.userType() == QMetaType::QDate || variant.userType() == QMetaType::QDateTime) { return variant.toDateTime().toNSDate(); } else if (variant.userType() == QMetaType::Bool) { return variant.toBool() ? [NSNumber numberWithBool:YES] : [NSNumber numberWithBool:NO]; } else if (variant.userType() == QMetaType::Char || variant.userType() == QMetaType::Int) { return [NSNumber numberWithInt:variant.toInt()]; } else if (variant.userType() == QMetaType::UInt) { return [NSNumber numberWithUnsignedInt:variant.toUInt()]; } else if (variant.userType() == QMetaType::LongLong) { return [NSNumber numberWithLongLong:variant.toLongLong()]; } else if (variant.userType() == QMetaType::ULongLong) { return [NSNumber numberWithUnsignedLongLong:variant.toULongLong()]; } else if (variant.userType() == QMetaType::Double) { return [NSNumber numberWithDouble:variant.toDouble()]; } else { return [NSNull null]; } } static NSDictionary *toDictionary(const QVariantMap &map) { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) [dict setObject:toObject(i.value()) forKey:i.key().toNSString()]; return [NSDictionary dictionaryWithDictionary:dict]; } static NSArray *toArray(const QVariantList &list) { NSMutableArray *array = [NSMutableArray array]; for (const QVariant &variant : list) [array addObject:toObject(variant)]; return [NSArray arrayWithArray:array]; } id QPropertyListUtils::toPropertyList(const QVariant &variant) { return toObject(variant); } qbs-src-2.6.1/src/lib/corelib/jsextensions/pkgconfigjs.h0000644000175100001660000000753514776170045022647 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include "tools/qbs_export.h" #include #include #include #include class QProcessEnvironment; namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT PkgConfigJs : public JsExtension { public: enum FlagType { LibraryName = toUnderlying(PcPackage::Flag::Type::LibraryName), LibraryPath = toUnderlying(PcPackage::Flag::Type::LibraryPath), StaticLibraryName = toUnderlying(PcPackage::Flag::Type::StaticLibraryName), Framework = toUnderlying(PcPackage::Flag::Type::Framework), FrameworkPath = toUnderlying(PcPackage::Flag::Type::FrameworkPath), LinkerFlag = toUnderlying(PcPackage::Flag::Type::LinkerFlag), IncludePath = toUnderlying(PcPackage::Flag::Type::IncludePath), SystemIncludePath = toUnderlying(PcPackage::Flag::Type::SystemIncludePath), Define = toUnderlying(PcPackage::Flag::Type::Define), CompilerFlag = toUnderlying(PcPackage::Flag::Type::CompilerFlag), }; enum class ComparisonType { LessThan, GreaterThan, LessThanEqual, GreaterThanEqual, Equal, NotEqual, AlwaysMatch }; static const char *name() { return "PkgConfig"; } static void declareEnums(JSContext *ctx, JSValue classObj); static JSValue ctor(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int); explicit PkgConfigJs(JSContext *ctx, const QVariantMap &options = {}); DEFINE_JS_FORWARDER(jsPackages, &PkgConfigJs::packages, "PkgConfig.packages") QVariantMap packages() const { return m_packages; } // also used in tests static PkgConfig::Options convertOptions(const QProcessEnvironment &env, const QVariantMap &map); static void setupMethods(JSContext *ctx, JSValue obj); private: std::unique_ptr m_pkgConfig; QVariantMap m_packages; }; } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/jsextensions/fileinfoextension.cpp0000644000175100001660000003454414776170045024426 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jsextension.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { // removes duplicate separators from the path static QString uniqueSeparators(QString path) { const auto it = std::unique(path.begin(), path.end(), [](QChar c1, QChar c2) { return c1 == c2 && c1 == QLatin1Char('/'); }); path.resize(int(it - path.begin())); return path; } class FileInfoExtension : public JsExtension { public: static const char *name() { return "FileInfo"; } static void setupStaticMethods(JSContext *ctx, JSValue classObj); static JSValue jsPath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsFileName(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsBaseName(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsSuffix(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsCompleteSuffix(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsCanonicalPath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsCleanPath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsCompleteBaseName(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsRelativePath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsResolvePath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsIsAbsolutePath(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsToWindowsSeparators(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsFromWindowsSeparators(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsToNativeSeparators(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsFromNativeSeparators(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsJoinPaths(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv); static JSValue jsPathListSeparator(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsPathSeparator(JSContext *ctx, JSValueConst, int, JSValueConst *); static JSValue jsExecutableSuffix(JSContext *ctx, JSValueConst, int, JSValueConst *); }; void FileInfoExtension::setupStaticMethods(JSContext *ctx, JSValue classObj) { setupMethod(ctx, classObj, StringConstants::fileInfoPath(), &FileInfoExtension::jsPath, 1); setupMethod(ctx, classObj, StringConstants::fileInfoFileName(), &FileInfoExtension::jsFileName, 1); setupMethod(ctx, classObj, StringConstants::baseNameProperty(), &FileInfoExtension::jsBaseName, 1); setupMethod(ctx, classObj, "suffix", &FileInfoExtension::jsSuffix, 1); setupMethod(ctx, classObj, "completeSuffix", &FileInfoExtension::jsCompleteSuffix, 1); setupMethod(ctx, classObj, "canonicalPath", &FileInfoExtension::jsCanonicalPath, 1); setupMethod(ctx, classObj, "cleanPath", &FileInfoExtension::jsCleanPath, 1); setupMethod(ctx, classObj, StringConstants::completeBaseNameProperty(), &FileInfoExtension::jsCompleteBaseName, 1); setupMethod(ctx, classObj, "relativePath", &FileInfoExtension::jsRelativePath, 1); setupMethod(ctx, classObj, "resolvePath", &FileInfoExtension::jsResolvePath, 1); setupMethod(ctx, classObj, "isAbsolutePath", &FileInfoExtension::jsIsAbsolutePath, 1); setupMethod(ctx, classObj, "toWindowsSeparators", &FileInfoExtension::jsToWindowsSeparators, 1); setupMethod(ctx, classObj, "fromWindowsSeparators", &FileInfoExtension::jsFromWindowsSeparators, 1); setupMethod(ctx, classObj, "toNativeSeparators", &FileInfoExtension::jsToNativeSeparators, 1); setupMethod(ctx, classObj, "fromNativeSeparators", &FileInfoExtension::jsFromNativeSeparators, 1); setupMethod(ctx, classObj, "joinPaths", &FileInfoExtension::jsJoinPaths, 0); setupMethod(ctx, classObj, "pathListSeparator", &FileInfoExtension::jsPathListSeparator, 0); setupMethod(ctx, classObj, "pathSeparator", &FileInfoExtension::jsPathSeparator, 0); setupMethod(ctx, classObj, "executableSuffix", &FileInfoExtension::jsExecutableSuffix, 0); } JSValue FileInfoExtension::jsPath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.path", argc, argv); HostOsInfo::HostOs hostOs = HostOsInfo::hostOs(); if (argc > 1) { const auto osList = fromArg(ctx, "FileInfo.path", 2, argv[1]); hostOs = osList.contains(QLatin1String("windows")) ? HostOsInfo::HostOsWindows : HostOsInfo::HostOsOtherUnix; } return makeJsString(ctx, FileInfo::path(filePath, hostOs)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsFileName(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.fileName", argc, argv); return makeJsString(ctx, FileInfo::fileName(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsBaseName(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.baseName", argc, argv); return makeJsString(ctx, FileInfo::baseName(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsSuffix(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.suffix", argc, argv); return makeJsString(ctx, FileInfo::suffix(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsCompleteSuffix(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.completeSuffix", argc, argv); return makeJsString(ctx, FileInfo::completeSuffix(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsCanonicalPath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.canonicalPath", argc, argv); return makeJsString(ctx, QFileInfo(filePath).canonicalFilePath()); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsCleanPath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.cleanPath", argc, argv); return makeJsString(ctx, QDir::cleanPath(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsCompleteBaseName(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.completeBaseName", argc, argv); return makeJsString(ctx, FileInfo::completeBaseName(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsRelativePath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto args = getArguments(ctx, "File.relativePath", argc, argv); const QString baseDir = std::get<0>(args); const QString filePath = std::get<1>(args); if (!FileInfo::isAbsolute(baseDir)) { throw Tr::tr("FileInfo.relativePath() expects an absolute path as " "its first argument, but it is '%1'.").arg(baseDir); } if (!FileInfo::isAbsolute(filePath)) { throw Tr::tr("FileInfo.relativePath() expects an absolute path as " "its second argument, but it is '%1'.").arg(filePath); } return makeJsString(ctx, QDir(baseDir).relativeFilePath(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsResolvePath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto args = getArguments(ctx, "File.resolvePath", argc, argv); const QString base = std::get<0>(args); const QString rel = std::get<1>(args); return makeJsString(ctx, FileInfo::resolvePath(base, rel)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsIsAbsolutePath(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.isAbsolutePath", argc, argv); HostOsInfo::HostOs hostOs = HostOsInfo::hostOs(); if (argc > 1) { const auto osList = fromArg(ctx, "FileInfo.isAbsolutePath", 2, argv[1]); hostOs = osList.contains(QLatin1String("windows")) ? HostOsInfo::HostOsWindows : HostOsInfo::HostOsOtherUnix; } return JS_NewBool(ctx, FileInfo::isAbsolute(filePath, hostOs)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsToWindowsSeparators(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { auto filePath = getArgument(ctx, "FileInfo.toWindowsSeparators", argc, argv); return makeJsString(ctx, filePath.replace(QLatin1Char('/'), QLatin1Char('\\'))); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsFromWindowsSeparators(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { auto filePath = getArgument(ctx, "FileInfo.fromWindowsSeparators", argc, argv); return makeJsString(ctx, filePath.replace(QLatin1Char('\\'), QLatin1Char('/'))); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsToNativeSeparators(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.toWindowsSeparators", argc, argv); return makeJsString(ctx, QDir::toNativeSeparators(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsFromNativeSeparators(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { const auto filePath = getArgument(ctx, "FileInfo.fromWindowsSeparators", argc, argv); return makeJsString(ctx, QDir::fromNativeSeparators(filePath)); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsJoinPaths(JSContext *ctx, JSValue, int argc, JSValue *argv) { try { QStringList paths; for (int i = 0; i < argc; ++i) { const auto value = fromArg(ctx, "FileInfo.joinPaths", i + 1, argv[i]); if (!value.isEmpty()) paths.push_back(value); } return makeJsString(ctx, uniqueSeparators(paths.join(QLatin1Char('/')))); } catch (const QString &error) { return throwError(ctx, error); } } JSValue FileInfoExtension::jsPathListSeparator(JSContext *ctx, JSValue, int, JSValue *) { return makeJsString(ctx, QString(HostOsInfo::pathListSeparator())); } JSValue FileInfoExtension::jsPathSeparator(JSContext *ctx, JSValue, int, JSValue *) { return makeJsString(ctx, QString(HostOsInfo::pathSeparator())); } JSValue FileInfoExtension::jsExecutableSuffix(JSContext *ctx, JSValue, int, JSValue *) { static QString executableSuffix = HostOsInfo::isWindowsHost() ? QLatin1String(QBS_HOST_EXE_SUFFIX) : QString(); return makeJsString(ctx, executableSuffix); } } // namespace Internal } // namespace qbs void initializeJsExtensionFileInfo(qbs::Internal::ScriptEngine *engine, JSValue extensionObject) { qbs::Internal::FileInfoExtension::registerClass(engine, extensionObject); } qbs-src-2.6.1/src/lib/corelib/CMakeLists.txt0000644000175100001660000002672714776170045020202 0ustar runnerdockerset(QBS_HEADERS qbs.h) set(FILE_UPDATE_SOURCES changeset.cpp changeset.h projectfileupdater.cpp projectfileupdater.h qmljsrewriter.cpp qmljsrewriter.h ) list_transform_prepend(FILE_UPDATE_SOURCES api/) set(API_SOURCES internaljobs.cpp internaljobs.h jobs.cpp languageinfo.cpp project.cpp project_p.h projectdata.cpp projectdata_p.h propertymap_p.h rulecommand.cpp rulecommand_p.h runenvironment.cpp transformerdata.cpp transformerdata_p.h ) list_transform_prepend(API_SOURCES api/) set(API_HEADERS jobs.h languageinfo.h project.h projectdata.h rulecommand.h runenvironment.h transformerdata.h ) list_transform_prepend(API_HEADERS api/) set(BUILD_GRAPH_SOURCES abstractcommandexecutor.cpp abstractcommandexecutor.h artifact.cpp artifact.h artifactcleaner.cpp artifactcleaner.h artifactsscriptvalue.cpp artifactsscriptvalue.h artifactvisitor.cpp artifactvisitor.h buildgraph.cpp buildgraph.h buildgraphnode.cpp buildgraphnode.h buildgraphloader.cpp buildgraphloader.h buildgraphvisitor.h cppmodulesscanner.cpp cppmodulesscanner.h cycledetector.cpp cycledetector.h dependencyparametersscriptvalue.cpp dependencyparametersscriptvalue.h depscanner.cpp depscanner.h emptydirectoriesremover.cpp emptydirectoriesremover.h environmentscriptrunner.cpp environmentscriptrunner.h executor.cpp executor.h executorjob.cpp executorjob.h filedependency.cpp filedependency.h inputartifactscanner.cpp inputartifactscanner.h jscommandexecutor.cpp jscommandexecutor.h nodeset.cpp nodeset.h nodetreedumper.cpp nodetreedumper.h processcommandexecutor.cpp processcommandexecutor.h productbuilddata.cpp productbuilddata.h productinstaller.cpp productinstaller.h projectbuilddata.cpp projectbuilddata.h qtmocscanner.cpp qtmocscanner.h rawscanneddependency.cpp rawscanneddependency.h rawscanresults.cpp rawscanresults.h requestedartifacts.cpp requestedartifacts.h requesteddependencies.cpp requesteddependencies.h rescuableartifactdata.h rulecommands.cpp rulecommands.h rulegraph.cpp rulegraph.h rulenode.cpp rulenode.h rulesapplicator.cpp rulesapplicator.h rulesevaluationcontext.cpp rulesevaluationcontext.h timestampsupdater.cpp timestampsupdater.h transformer.cpp transformer.h transformerchangetracking.cpp transformerchangetracking.h ) list_transform_prepend(BUILD_GRAPH_SOURCES buildgraph/) set(BUILD_GRAPH_HEADERS buildgraph/forward_decls.h) set(GENERATORS_SOURCES generatableprojectiterator.cpp generatableprojectiterator.h generator.cpp generatordata.cpp generatorutils.cpp generatorutils.h generatorversioninfo.cpp generatorversioninfo.h igeneratableprojectvisitor.h ixmlnodevisitor.h xmlproject.cpp xmlproject.h xmlprojectwriter.cpp xmlprojectwriter.h xmlproperty.cpp xmlproperty.h xmlpropertygroup.cpp xmlpropertygroup.h xmlworkspace.cpp xmlworkspace.h xmlworkspacewriter.cpp xmlworkspacewriter.h ) list_transform_prepend(GENERATORS_SOURCES generators/) set(GENERATORS_HEADERS generators/generator.h generators/generatordata.h) set(JS_EXTENSIONS_SOURCES environmentextension.cpp file.cpp fileinfoextension.cpp host.cpp jsextensions.cpp jsextensions.h moduleproperties.cpp moduleproperties.h pkgconfigjs.cpp pkgconfigjs.h process.cpp temporarydir.cpp textfile.cpp binaryfile.cpp utilitiesextension.cpp domxml.cpp ) list_transform_prepend(JS_EXTENSIONS_SOURCES jsextensions/) if(APPLE) set(JS_EXTENSIONS_MACOS_SOURCES propertylist_darwin.mm propertylistutils.h propertylistutils.mm ) else() set(JS_EXTENSIONS_MACOS_SOURCES propertylist.cpp) endif() list_transform_prepend(JS_EXTENSIONS_MACOS_SOURCES jsextensions/) set(LANGUAGE_SOURCES artifactproperties.cpp artifactproperties.h asttools.cpp asttools.h builtindeclarations.cpp builtindeclarations.h deprecationinfo.h evaluator.cpp evaluator.h filecontext.cpp filecontext.h filecontextbase.cpp filecontextbase.h filetags.cpp filetags.h identifiersearch.cpp identifiersearch.h item.cpp item.h itemdeclaration.cpp itemdeclaration.h itemobserver.h itempool.cpp itempool.h itemtype.h jsimports.h language.cpp language.h moduleproviderinfo.h preparescriptobserver.cpp preparescriptobserver.h property.cpp property.h propertydeclaration.cpp propertydeclaration.h propertymapinternal.cpp propertymapinternal.h qualifiedid.cpp qualifiedid.h resolvedfilecontext.cpp resolvedfilecontext.h scriptengine.cpp scriptengine.h scriptimporter.cpp scriptimporter.h scriptpropertyobserver.cpp scriptpropertyobserver.h value.cpp value.h ) list_transform_prepend(LANGUAGE_SOURCES language/) set(LANGUAGE_HEADERS language/forward_decls.h) set(LOADER_SOURCES astimportshandler.cpp astimportshandler.h astpropertiesitemhandler.cpp astpropertiesitemhandler.h dependenciesresolver.cpp dependenciesresolver.h groupshandler.cpp groupshandler.h itemreader.cpp itemreader.h itemreaderastvisitor.cpp itemreaderastvisitor.h itemreadervisitorstate.cpp itemreadervisitorstate.h loaderutils.cpp loaderutils.h localprofiles.cpp localprofiles.h moduleinstantiator.cpp moduleinstantiator.h moduleloader.cpp moduleloader.h modulepropertymerger.cpp modulepropertymerger.h moduleproviderloader.cpp moduleproviderloader.h probesresolver.cpp probesresolver.h productitemmultiplexer.cpp productitemmultiplexer.h productresolver.cpp productresolver.h productscollector.cpp productscollector.h productsresolver.cpp productsresolver.h projectresolver.cpp projectresolver.h ) list_transform_prepend(LOADER_SOURCES loader/) set(LOGGING_SOURCES categories.cpp categories.h ilogsink.cpp logger.cpp logger.h translator.h ) list_transform_prepend(LOGGING_SOURCES logging/) set(LOGGING_HEADERS logging/ilogsink.h) set(PARSER_SOURCES qmlerror.cpp qmlerror.h qmljsast.cpp qmljsast_p.h qmljsastfwd_p.h qmljsastvisitor.cpp qmljsastvisitor_p.h qmljsengine_p.cpp qmljsengine_p.h qmljsglobal_p.h qmljsgrammar.cpp qmljsgrammar_p.h qmljskeywords_p.h qmljslexer.cpp qmljslexer_p.h qmljsmemorypool_p.h qmljsparser.cpp qmljsparser_p.h ) list_transform_prepend(PARSER_SOURCES parser/) set(TOOLS_SOURCES architectures.cpp buildgraphlocker.cpp buildgraphlocker.h buildoptions.cpp clangclinfo.cpp clangclinfo.h cleanoptions.cpp codelocation.cpp commandechomode.cpp deprecationwarningmode.cpp dynamictypecheck.h error.cpp executablefinder.cpp executablefinder.h fileinfo.cpp fileinfo.h filesaver.cpp filesaver.h filetime.cpp filetime.h generateoptions.cpp hostosinfo.h id.cpp id.h iosutils.h joblimits.cpp jsliterals.cpp jsliterals.h jsonhelper.h installoptions.cpp launcherinterface.cpp launcherinterface.h launcherpackets.cpp launcherpackets.h launchersocket.cpp launchersocket.h msvcinfo.cpp msvcinfo.h pathutils.h pimpl.h persistence.cpp persistence.h porting.h preferences.cpp processresult.cpp processresult_p.h processutils.cpp processutils.h profile.cpp profiling.cpp profiling.h progressobserver.cpp progressobserver.h projectgeneratormanager.cpp propagate_const.h qbsassert.cpp qbsassert.h qbspluginmanager.cpp qbspluginmanager.h qbsprocess.cpp qbsprocess.h qttools.cpp qttools.h scannerpluginmanager.cpp scannerpluginmanager.h scripttools.cpp scripttools.h set.h settings.cpp settingscreator.cpp settingscreator.h settingsmodel.cpp settingsrepresentation.cpp setupprojectparameters.cpp shellutils.cpp shellutils.h stlutils.h stringconstants.h stringutils.h toolchains.cpp version.cpp visualstudioversioninfo.cpp visualstudioversioninfo.h vsenvironmentdetector.cpp vsenvironmentdetector.h weakpointer.h ) list_transform_prepend(TOOLS_SOURCES tools/) set(TOOLS_HEADERS architectures.h buildoptions.h cleanoptions.h codelocation.h commandechomode.h deprecationwarningmode.h error.h generateoptions.h installoptions.h joblimits.h mutexdata.h preferences.h processresult.h profile.h projectgeneratormanager.h qbs_export.h settings.h settingsmodel.h settingsrepresentation.h setupprojectparameters.h toolchains.h version.h ) list_transform_prepend(TOOLS_HEADERS tools/) set(CPPSCANNER_SOURCES Lexer.cpp Token.cpp cppscanner.cpp ) list_transform_prepend(CPPSCANNER_SOURCES cppscanner/) set(CPPSCANNER_HEADERS Lexer.h Token.h cppscanner.h ) list_transform_prepend(CPPSCANNER_HEADERS cppscanner/) set(EXTERNAL_DEPENDS "") if(APPLE) set(TOOLS_MACOS_SOURCES applecodesignutils.cpp applecodesignutils.h ) list_transform_prepend(TOOLS_MACOS_SOURCES tools/) set(EXTERNAL_DEPENDS "-framework Foundation" "-framework Security") endif() if(WIN32) set(EXTERNAL_DEPENDS "psapi" "shell32") endif() add_qbs_library(qbscore DEFINES "QBS_VERSION=\"${QBS_VERSION}\"" "QBS_RELATIVE_LIBEXEC_PATH=\"${QBS_RELATIVE_LIBEXEC_PATH}\"" "QBS_LIBRARY" "CPLUSPLUS_NO_PARSER" ${QBS_UNIT_TESTS_DEFINES} DEPENDS Qt${QT_VERSION_MAJOR}::CorePrivate Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Xml Qt6Core5Compat qbspkgconfig qbsquickjs PUBLIC_DEPENDS Qt${QT_VERSION_MAJOR}::Core span ${EXTERNAL_DEPENDS} INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/../.." SOURCES ${QBS_HEADERS} ${FILE_UPDATE_SOURCES} ${API_SOURCES} ${API_HEADERS} ${BUILD_GRAPH_SOURCES} ${BUILD_GRAPH_HEADERS} ${GENERATORS_SOURCES} ${GENERATORS_HEADERS} ${JS_EXTENSIONS_SOURCES} ${JS_EXTENSIONS_MACOS_SOURCES} ${LANGUAGE_SOURCES} ${LANGUAGE_HEADERS} ${LOADER_SOURCES} ${LOGGING_SOURCES} ${LOGGING_HEADERS} ${PARSER_SOURCES} ${TOOLS_SOURCES} ${TOOLS_HEADERS} ${CPPSCANNER_SOURCES} ${CPPSCANNER_HEADERS} ${TOOLS_MACOS_SOURCES} ) # not sure if there's a better way to do this if(INSTALL_PUBLIC_HEADERS) install(FILES ${QBS_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}) install(FILES ${API_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}/api) install(FILES ${BUILD_GRAPH_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}/buildgraph) install(FILES ${GENERATORS_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}/generators) install(FILES ${LOGGING_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}/logging) install(FILES ${LANGUAGE_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}/language) install(FILES ${TOOLS_HEADERS} DESTINATION ${QBS_HEADERS_INSTALL_DIR}/tools) endif() qbs-src-2.6.1/src/lib/corelib/buildgraph/0000755000175100001660000000000014776170045017545 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraph.cpp0000644000175100001660000012134314776170045022376 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "buildgraph.h" #include "artifact.h" #include "artifactsscriptvalue.h" #include "cycledetector.h" #include "dependencyparametersscriptvalue.h" #include "projectbuilddata.h" #include "productbuilddata.h" #include "rulenode.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static QString childItemsProperty() { return QStringLiteral("childItems"); } static QString exportsProperty() { return QStringLiteral("exports"); } // TODO: Introduce productscriptvalue.{h,cpp}. static JSValue getDataObject(JSContext *ctx, JSValue obj) { return getJsProperty(ctx, obj, StringConstants::dataPropertyInternal()); } static JSValue getValueFromData(JSContext *ctx, JSValue data, ModulePropertiesScriptValueCommonPropertyKeys key) { return JS_GetPropertyUint32(ctx, data, key); } static JSValue getValueFromObject(JSContext *ctx, JSValue obj, ModulePropertiesScriptValueCommonPropertyKeys key) { const ScopedJsValue data(ctx, getDataObject(ctx, obj)); return getValueFromData(ctx, data, key); } void getPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, const QVariantMap &properties, const QStringList &extraPropertyNames, JSValue extraObject) { JSPropertyEnum *basePTab = nullptr; uint32_t basePlen = 0; JS_GetOwnPropertyNames(ctx, &basePTab, &basePlen, extraObject, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY); *plen = uint32_t(extraPropertyNames.size() + properties.size() + basePlen); *ptab = reinterpret_cast(js_malloc(ctx, *plen * sizeof **ptab)); JSPropertyEnum *entry = *ptab; for (auto it = properties.begin(); it != properties.end(); ++it, ++entry) { entry->atom = JS_NewAtom(ctx, it.key().toUtf8().constData()); entry->is_enumerable = 1; } for (const QString &prop : extraPropertyNames) { entry->atom = JS_NewAtom(ctx, prop.toUtf8().constData()); entry->is_enumerable = 1; ++entry; } for (uint32_t i = 0; i < basePlen; ++i, ++entry) { entry->atom = basePTab[i].atom; entry->is_enumerable = 1; } js_free(ctx, basePTab); } static int getProductPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const ScopedJsValue data(ctx, getDataObject(engine->context(), obj)); const auto product = attachedPointer( obj, engine->productPropertyScriptClass()); QBS_ASSERT(product, return -1); // The "moduleName" convenience property is only available for the "main product" in a rule, // and the "parameters" property exists only for elements of the "dependencies" array for // which dependency parameters are present. const auto hasModuleName = [&] { const ScopedJsValue v(ctx, getValueFromData(ctx, data, ModuleNameKey)); return JS_IsString(v); }; const auto hasDependencyParams = [&] { const ScopedJsValue v(ctx, getValueFromData(ctx, data, DependencyParametersKey)); return JS_IsObject(v); }; QStringList additionalProperties; if (hasModuleName()) additionalProperties.push_back(StringConstants::moduleNameProperty()); else if (hasDependencyParams()) additionalProperties.push_back(StringConstants::parametersProperty()); getPropertyNames(ctx, ptab, plen, product->productProperties, additionalProperties, engine->baseProductScriptValue(product)); return 0; } static int getProductProperty(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop) { if (desc) { desc->getter = desc->setter = desc->value = JS_UNDEFINED; desc->flags = JS_PROP_ENUMERABLE; } const QString name = getJsString(ctx, prop); if (name == StringConstants::parametersProperty()) { if (desc) desc->value = getValueFromObject(ctx, obj, DependencyParametersKey); return 1; } if (name == StringConstants::moduleNameProperty()) { if (desc) desc->value = getValueFromObject(ctx, obj, ModuleNameKey); return 1; } ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto product = attachedPointer( obj, engine->productPropertyScriptClass()); QBS_ASSERT(product, return -1); const JSValue baseProductValue = engine->baseProductScriptValue(product); if (name == exportsProperty()) { if (desc) desc->value = getJsProperty(ctx, baseProductValue, name); engine->addRequestedExport(product); return 1; } const auto it = product->productProperties.constFind(name); if (it == product->productProperties.cend()) { ScopedJsValue v(ctx, JS_GetProperty(ctx, baseProductValue, prop)); const int ret = JS_IsUndefined(v) ? 0 : 1; if (desc) desc->value = v.release(); return ret; } engine->addPropertyRequestedInScript(Property(product->uniqueName(), QString(), name, it.value(), Property::PropertyInProduct)); if (desc) desc->value = engine->toScriptValue(it.value()); return 1; } static JSValue setupProjectScriptValue(ScriptEngine *engine, const ResolvedProjectConstPtr &project) { JSValue &obj = engine->projectScriptValue(project.get()); if (JS_IsObject(obj)) return JS_DupValue(engine->context(), obj); obj = engine->newObject(); setJsProperty(engine->context(), obj, StringConstants::filePathProperty(), project->location.filePath()); setJsProperty(engine->context(), obj, StringConstants::pathProperty(), FileInfo::path(project->location.filePath())); const QVariantMap &projectProperties = project->projectProperties(); for (QVariantMap::const_iterator it = projectProperties.begin(); it != projectProperties.end(); ++it) { const ScopedJsValue val(engine->context(), engine->toScriptValue(it.value())); engine->setObservedProperty(obj, it.key(), val); } engine->observer()->addProjectObjectId(jsObjectId(obj), project->name); return JS_DupValue(engine->context(), obj); } static void setupBaseProductScriptValue(ScriptEngine *engine, const ResolvedProduct *product); class DependenciesFunction { public: DependenciesFunction(ScriptEngine *engine) : m_engine(engine) { } void init(JSValue &productScriptValue, JSValue exportsScriptValue) { const QByteArray name = StringConstants::dependenciesProperty().toUtf8(); const ScopedJsValue depfunc( m_engine->context(), JS_NewCFunction(m_engine->context(), &js_internalProductDependencies, name.constData(), 0)); const ScopedJsAtom depAtom(m_engine->context(), name); JS_DefineProperty(m_engine->context(), productScriptValue, depAtom, JS_UNDEFINED, depfunc, JS_UNDEFINED, JS_PROP_HAS_GET | JS_PROP_ENUMERABLE); const ScopedJsValue exportedDepfunc( m_engine->context(), JS_NewCFunction(m_engine->context(), &js_exportedProductDependencies, name.constData(), 0)); JS_DefineProperty(m_engine->context(), exportsScriptValue, depAtom, JS_UNDEFINED, exportedDepfunc, JS_UNDEFINED, JS_PROP_HAS_GET | JS_PROP_ENUMERABLE); } private: enum class DependencyType { Internal, Exported }; static JSValue js_productDependencies(const ResolvedProduct *product, JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, DependencyType depType) { Q_UNUSED(this_val) Q_UNUSED(argc) Q_UNUSED(argv) ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); JSValue result = JS_NewArray(ctx); quint32 idx = 0; const bool exportCase = depType == DependencyType::Exported; std::vector productDeps; if (exportCase) { if (!product->exportedModule.productDependencies.empty()) { const auto allProducts = product->topLevelProject()->allProducts(); const auto getProductForName = [&allProducts](const QString &name) { const auto cmp = [name](const ResolvedProductConstPtr &p) { return p->uniqueName() == name; }; const auto it = std::find_if(allProducts.cbegin(), allProducts.cend(), cmp); QBS_ASSERT(it != allProducts.cend(), return ResolvedProductPtr()); return *it; }; std::transform(product->exportedModule.productDependencies.cbegin(), product->exportedModule.productDependencies.cend(), std::back_inserter(productDeps), getProductForName); } } else { productDeps = product->dependencies; } for (const ResolvedProductPtr &dependency : std::as_const(productDeps)) { setupBaseProductScriptValue(engine, dependency.get()); JSValue obj = JS_NewObjectClass(engine->context(), engine->productPropertyScriptClass()); attachPointerTo(obj, dependency.get()); const QVariantMap ¶ms = (exportCase ? product->exportedModule.dependencyParameters.value(dependency) : product->dependencyParameters.value(dependency)); JSValue data = JS_NewObjectClass(engine->context(), engine->dataWithPtrClass()); JS_SetPropertyUint32(ctx, data, DependencyParametersKey, dependencyParametersValue( product->uniqueName(), dependency->name, params, engine)); defineJsProperty(ctx, obj, StringConstants::dataPropertyInternal(), data); JS_SetPropertyUint32(ctx, result, idx++, obj); } if (exportCase) { for (const ExportedModuleDependency &m : product->exportedModule.moduleDependencies) { JSValue obj = engine->newObject(); setJsProperty(ctx, obj, StringConstants::nameProperty(), m.name); JSValue exportsValue = engine->newObject(); setJsProperty(ctx, obj, exportsProperty(), exportsValue); setJsProperty(ctx, exportsValue, StringConstants::dependenciesProperty(), JS_NewArray(ctx)); for (auto modIt = m.moduleProperties.begin(); modIt != m.moduleProperties.end(); ++modIt) { const QVariantMap entries = modIt.value().toMap(); if (entries.empty()) continue; JSValue moduleObj = engine->newObject(); ModuleProperties::setModuleScriptValue(engine, exportsValue, moduleObj, modIt.key()); for (auto valIt = entries.begin(); valIt != entries.end(); ++valIt) { setJsProperty(ctx, moduleObj, valIt.key(), engine->toScriptValue(valIt.value())); } } JS_SetPropertyUint32(ctx, result, idx++, obj); } return result; } for (const auto &dependency : product->modules) { if (dependency->isProduct) continue; JSValue obj = JS_NewObjectClass(ctx, engine->modulePropertyScriptClass()); attachPointerTo(obj, dependency.get()); const QVariantMap ¶ms = product->moduleParameters.value(dependency); JSValue data = createDataForModuleScriptValue(engine, nullptr); JS_SetPropertyUint32(ctx, data, DependencyParametersKey, dependencyParametersValue( product->uniqueName(), dependency->name, params, engine)); defineJsProperty(ctx, obj, StringConstants::dataPropertyInternal(), data); JS_SetPropertyUint32(ctx, result, idx++, obj); } return result; } static JSValue js_internalProductDependencies(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto product = attachedPointer(this_val, engine->dataWithPtrClass()); engine->addDependenciesArrayRequested(product); return js_productDependencies(product, ctx, this_val, argc, argv, DependencyType::Internal); } static JSValue js_exportedProductDependencies(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { const auto product = attachedPointer( this_val, ScriptEngine::engineForContext(ctx)->dataWithPtrClass()); return js_productDependencies(product, ctx, this_val, argc, argv, DependencyType::Exported); } ScriptEngine *m_engine; }; static JSValue setupExportedPropertyScriptValue(const ExportedProperty &property, ScriptEngine *engine) { JSValue propertyScriptValue = engine->newObject(); setJsProperty(engine->context(), propertyScriptValue, StringConstants::nameProperty(), property.fullName); setJsProperty(engine->context(), propertyScriptValue, StringConstants::typeProperty(), PropertyDeclaration::typeString(property.type)); setJsProperty(engine->context(), propertyScriptValue, StringConstants::sourceCodeProperty(), property.sourceCode); JS_SetPropertyStr(engine->context(), propertyScriptValue, "isBuiltin", JS_NewBool(engine->context(), property.isBuiltin)); return propertyScriptValue; } static void setupExportedPropertiesScriptValue(JSValue &parentObject, const std::vector &properties, ScriptEngine *engine) { JSValue propertiesScriptValue = JS_NewArray(engine->context()); quint32 arrayIndex = 0; for (const ExportedProperty &p : properties) { JS_SetPropertyUint32(engine->context(), propertiesScriptValue, arrayIndex++, setupExportedPropertyScriptValue(p, engine)); } JS_SetPropertyStr(engine->context(), parentObject, "properties", propertiesScriptValue); } static JSValue setupExportedItemScriptValue(const ExportedItem *item, ScriptEngine *engine) { JSValue itemScriptValue = engine->newObject(); setJsProperty(engine->context(), itemScriptValue, StringConstants::nameProperty(), item->name); setupExportedPropertiesScriptValue(itemScriptValue, item->properties, engine); JSValue childrenScriptValue = JS_NewArray(engine->context()); quint32 arrayIndex = 0; for (const auto &childItem : item->children) { JS_SetPropertyUint32(engine->context(), childrenScriptValue, arrayIndex++, setupExportedItemScriptValue(childItem.get(), engine)); } setJsProperty(engine->context(), itemScriptValue, childItemsProperty(), childrenScriptValue); return itemScriptValue; } static JSValue setupExportsScriptValue(const ResolvedProduct *product, ScriptEngine *engine) { const ExportedModule &module = product->exportedModule; JSValue exportsScriptValue = JS_NewObjectClass(engine->context(), engine->dataWithPtrClass()); attachPointerTo(exportsScriptValue, product); for (auto it = module.propertyValues.cbegin(); it != module.propertyValues.cend(); ++it) { setJsProperty(engine->context(), exportsScriptValue, it.key(), engine->toScriptValue(it.value())); } setupExportedPropertiesScriptValue(exportsScriptValue, module.m_properties, engine); JSValue childrenScriptValue = JS_NewArray(engine->context()); quint32 arrayIndex = 0; for (const auto &exportedItem : module.children) { JS_SetPropertyUint32(engine->context(), childrenScriptValue, arrayIndex++, setupExportedItemScriptValue(exportedItem.get(), engine)); } setJsProperty(engine->context(), exportsScriptValue, childItemsProperty(), childrenScriptValue); JSValue importsScriptValue = JS_NewArray(engine->context()); arrayIndex = 0; for (const QString &importStatement : module.importStatements) { JS_SetPropertyUint32(engine->context(), importsScriptValue, arrayIndex++, makeJsString(engine->context(), importStatement)); } setJsProperty(engine->context(), exportsScriptValue, StringConstants::importsProperty(), importsScriptValue); for (auto it = module.modulePropertyValues.cbegin(); it != module.modulePropertyValues.cend(); ++it) { const QVariantMap entries = it.value().toMap(); if (entries.empty()) continue; JSValue moduleObject = engine->newObject(); ModuleProperties::setModuleScriptValue(engine, exportsScriptValue, moduleObject, it.key()); for (auto valIt = entries.begin(); valIt != entries.end(); ++valIt) { setJsProperty(engine->context(), moduleObject, valIt.key(), engine->toScriptValue(valIt.value())); } } return exportsScriptValue; } static void setupBaseProductScriptValue(ScriptEngine *engine, const ResolvedProduct *product) { JSValue &productScriptValue = engine->baseProductScriptValue(product); if (JS_IsObject(productScriptValue)) return; const ScopedJsValue proto(engine->context(), JS_NewObject(engine->context())); productScriptValue = JS_NewObjectProtoClass(engine->context(), proto, engine->dataWithPtrClass()); attachPointerTo(productScriptValue, product); ModuleProperties::init(engine, productScriptValue, product); const QByteArray funcName = StringConstants::artifactsProperty().toUtf8(); const ScopedJsValue artifactsFunc( engine->context(), JS_NewCFunction(engine->context(), &artifactsScriptValueForProduct, funcName.constData(), 0)); const ScopedJsAtom artifactsAtom(engine->context(), funcName); JS_DefineProperty(engine->context(), productScriptValue, artifactsAtom, JS_UNDEFINED, artifactsFunc, JS_UNDEFINED, JS_PROP_HAS_GET | JS_PROP_ENUMERABLE); // FIXME: Proper un-observe rather than ref count decrease here. ScopedJsValue exportsScriptValue(engine->context(), setupExportsScriptValue(product, engine)); DependenciesFunction(engine).init(productScriptValue, exportsScriptValue); // TODO: Why are these necessary? We catch accesses to product.exports in getProductProperty(). // But the exportsQbs() and exportsPkgConfig() tests fail without them. engine->setObservedProperty(productScriptValue, exportsProperty(), exportsScriptValue); engine->observer()->addExportsObjectId(jsObjectId(exportsScriptValue), product); } void setupScriptEngineForFile(ScriptEngine *engine, const FileContextBaseConstPtr &fileContext, JSValue targetObject, const ObserveMode &observeMode) { engine->import(fileContext, targetObject, observeMode); JsExtensions::setupExtensions(engine, fileContext->jsExtensions(), targetObject); } void setupScriptEngineForProduct(ScriptEngine *engine, ResolvedProduct *product, const ResolvedModule *module, JSValue targetObject, bool setBuildEnvironment) { JSValue projectScriptValue = setupProjectScriptValue(engine, product->project.lock()); setJsProperty(engine->context(), targetObject, StringConstants::projectVar(), projectScriptValue); if (setBuildEnvironment) { QVariant v; v.setValue(&product->buildEnvironment); engine->setProperty(StringConstants::qbsProcEnvVarInternal(), v); } JSClassID scriptClass = engine->productPropertyScriptClass(); if (scriptClass == 0) { engine->setProductPropertyScriptClass(engine->registerClass("ProductProperties", nullptr, nullptr, JS_UNDEFINED, &getProductPropertyNames, &getProductProperty)); scriptClass = engine->productPropertyScriptClass(); } setupBaseProductScriptValue(engine, product); JSValue productScriptValue = JS_NewObjectClass(engine->context(), scriptClass); attachPointerTo(productScriptValue, product); setJsProperty(engine->context(), targetObject, StringConstants::productVar(), productScriptValue); JSValue data = JS_NewObjectClass(engine->context(), engine->dataWithPtrClass()); // If the Rule is in a Module, set up the 'moduleName' property if (!module->name.isEmpty()) { JS_SetPropertyUint32(engine->context(), data, ModuleNameKey, makeJsString(engine->context(), module->name)); } defineJsProperty(engine->context(), productScriptValue, StringConstants::dataPropertyInternal(), data); } bool findPath(BuildGraphNode *u, BuildGraphNode *v, QList &path) { if (u == v) { path.push_back(v); return true; } for (BuildGraphNode * const childNode : std::as_const(u->children)) { if (findPath(childNode, v, path)) { path.prepend(u); return true; } } return false; } /* * Creates the build graph edge p -> c, which represents the dependency "c must be built before p". */ void connect(BuildGraphNode *p, BuildGraphNode *c) { qCDebug(lcBuildGraph).noquote() << "connect" << p->toString() << "->" << c->toString(); QBS_CHECK(p != c); if (c->type() == BuildGraphNode::ArtifactNodeType) { auto const ac = static_cast(c); for (const Artifact *child : filterByType(p->children)) { if (child == ac) return; const bool filePathsMustBeDifferent = child->artifactType == Artifact::Generated || child->product == ac->product || child->artifactType != ac->artifactType; if (filePathsMustBeDifferent && child->filePath() == ac->filePath()) { throw ErrorInfo(QStringLiteral("%1 already has a child artifact %2 as " "different object.").arg(p->toString(), ac->filePath()), CodeLocation(), true); } } } p->children.insert(c); c->parents.insert(p); p->product->topLevelProject()->buildData->setDirty(); } static bool existsPath_impl(BuildGraphNode *u, BuildGraphNode *v, NodeSet *seen) { if (u == v) return true; if (!seen->insert(u).second) return false; return Internal::any_of(u->children, [v, seen](const auto &child) { return existsPath_impl(child, v, seen); }); } static bool existsPath(BuildGraphNode *u, BuildGraphNode *v) { NodeSet seen; return existsPath_impl(u, v, &seen); } static QStringList toStringList(const QList &path) { QStringList lst; for (BuildGraphNode *node : path) lst << node->toString(); return lst; } bool safeConnect(Artifact *u, Artifact *v) { QBS_CHECK(u != v); qCDebug(lcBuildGraph) << "safeConnect:" << relativeArtifactFileName(u) << "->" << relativeArtifactFileName(v); if (existsPath(v, u)) { QList circle; findPath(v, u, circle); qCDebug(lcBuildGraph) << "safeConnect: circle detected " << toStringList(circle); return false; } connect(u, v); return true; } void disconnect(BuildGraphNode *u, BuildGraphNode *v) { qCDebug(lcBuildGraph).noquote() << "disconnect:" << u->toString() << v->toString(); u->children.remove(v); v->parents.remove(u); u->onChildDisconnected(v); } void removeGeneratedArtifactFromDisk(Artifact *artifact, const Logger &logger) { if (artifact->artifactType != Artifact::Generated) return; removeGeneratedArtifactFromDisk(artifact->filePath(), logger); } void removeGeneratedArtifactFromDisk(const QString &filePath, const Logger &logger) { QFile file(filePath); if (!file.exists()) return; logger.qbsDebug() << "removing " << filePath; if (!file.remove()) logger.qbsWarning() << QStringLiteral("Cannot remove '%1'.").arg(filePath); } QString relativeArtifactFileName(const Artifact *artifact) { const QString &buildDir = artifact->product->topLevelProject()->buildDirectory; QString str = artifact->filePath(); if (str.startsWith(buildDir)) str.remove(0, buildDir.size()); if (str.startsWith(QLatin1Char('/'))) str.remove(0, 1); return str; } Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const ProjectBuildData *projectBuildData, const QString &dirPath, const QString &fileName, bool compareByName) { for (const auto &fileResource : projectBuildData->lookupFiles(dirPath, fileName)) { if (fileResource->fileType() != FileResourceBase::FileTypeArtifact) continue; const auto artifact = static_cast(fileResource); if (compareByName ? artifact->product->uniqueName() == product->uniqueName() : artifact->product == product) { return artifact; } } return nullptr; } Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const QString &dirPath, const QString &fileName, bool compareByName) { return lookupArtifact(product, product->topLevelProject()->buildData.get(), dirPath, fileName, compareByName); } Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const QString &filePath, bool compareByName) { QString dirPath, fileName; FileInfo::splitIntoDirectoryAndFileName(filePath, &dirPath, &fileName); return lookupArtifact(product, dirPath, fileName, compareByName); } Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const ProjectBuildData *buildData, const QString &filePath, bool compareByName) { QString dirPath, fileName; FileInfo::splitIntoDirectoryAndFileName(filePath, &dirPath, &fileName); return lookupArtifact(product, buildData, dirPath, fileName, compareByName); } Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const Artifact *artifact, bool compareByName) { return lookupArtifact(product, artifact->dirPath(), artifact->fileName(), compareByName); } Artifact *createArtifact(const ResolvedProductPtr &product, const SourceArtifactConstPtr &sourceArtifact) { const auto artifact = new Artifact; artifact->artifactType = Artifact::SourceFile; setArtifactData(artifact, sourceArtifact); insertArtifact(product, artifact); return artifact; } void setArtifactData(Artifact *artifact, const SourceArtifactConstPtr &sourceArtifact) { artifact->targetOfModule = sourceArtifact->targetOfModule; artifact->setFilePath(sourceArtifact->absoluteFilePath); artifact->setFileTags(sourceArtifact->fileTags); artifact->properties = sourceArtifact->properties; } void updateArtifactFromSourceArtifact(const ResolvedProductPtr &product, const SourceArtifactConstPtr &sourceArtifact) { Artifact * const artifact = lookupArtifact(product, sourceArtifact->absoluteFilePath, false); QBS_CHECK(artifact); const FileTags oldFileTags = artifact->fileTags(); const QVariantMap oldModuleProperties = artifact->properties->value(); setArtifactData(artifact, sourceArtifact); if (oldFileTags != artifact->fileTags() || !qVariantMapsEqual(oldModuleProperties, artifact->properties->value())) { invalidateArtifactAsRuleInputIfNecessary(artifact); } } void insertArtifact(const ResolvedProductPtr &product, Artifact *artifact) { qCDebug(lcBuildGraph) << "insert artifact" << artifact->filePath(); QBS_CHECK(!artifact->product); QBS_CHECK(!artifact->filePath().isEmpty()); artifact->product = product; product->topLevelProject()->buildData->insertIntoLookupTable(artifact); product->buildData->addArtifact(artifact); } void provideFullFileTagsAndProperties(Artifact *artifact) { artifact->properties = artifact->product->moduleProperties; FileTags allTags = artifact->pureFileTags.empty() ? artifact->product->fileTagsForFileName(artifact->fileName()) : artifact->pureFileTags; for (const auto &props : artifact->product->artifactProperties) { if (allTags.intersects(props->fileTagsFilter())) { artifact->properties = props->propertyMap(); allTags += props->extraFileTags(); break; } } artifact->setFileTags(allTags); // Let a positive value of qbs.install imply the file tag "installable". if (artifact->properties->qbsPropertyValue(StringConstants::installProperty()).toBool()) artifact->addFileTag("installable"); } void applyPerArtifactProperties(Artifact *artifact) { if (artifact->pureProperties.empty()) return; QVariantMap props = artifact->properties->value(); for (const auto &property : artifact->pureProperties) setConfigProperty(props, property.first, property.second); artifact->properties = artifact->properties->clone(); artifact->properties->setValue(props); } void updateGeneratedArtifacts(ResolvedProduct *product) { if (!product->buildData) return; for (Artifact * const artifact : filterByType(product->buildData->allNodes())) { if (artifact->artifactType == Artifact::Generated) { const FileTags oldFileTags = artifact->fileTags(); const QVariantMap oldModuleProperties = artifact->properties->value(); provideFullFileTagsAndProperties(artifact); applyPerArtifactProperties(artifact); if (oldFileTags != artifact->fileTags() || !qVariantMapsEqual(oldModuleProperties, artifact->properties->value())) { invalidateArtifactAsRuleInputIfNecessary(artifact); } } } } // This is needed for artifacts which are inputs to rules whose outputArtifacts script // returned an empty array for this input. Since there is no transformer, our usual change // tracking procedure will not notice if the artifact's file tags or module properties have // changed, so we need to force a re-run of the outputArtifacts script. void invalidateArtifactAsRuleInputIfNecessary(Artifact *artifact) { for (RuleNode * const parentRuleNode : filterByType(artifact->parents)) { if (!parentRuleNode->rule()->isDynamic()) continue; bool artifactNeedsExplicitInvalidation = true; for (Artifact * const output : filterByType(parentRuleNode->parents)) { if (output->children.contains(artifact) && !output->childrenAddedByScanner.contains(artifact)) { artifactNeedsExplicitInvalidation = false; break; } } if (artifactNeedsExplicitInvalidation) parentRuleNode->removeOldInputArtifact(artifact); } } static void doSanityChecksForProduct(const ResolvedProductConstPtr &product, const Set &allProducts, const Logger &logger) { qCDebug(lcBuildGraph) << "Sanity checking product" << product->uniqueName(); CycleDetector cycleDetector(logger); cycleDetector.visitProduct(product); const ProductBuildData * const buildData = product->buildData.get(); for (const auto &m : product->modules) QBS_CHECK(m->product == product.get()); qCDebug(lcBuildGraph) << "enabled:" << product->enabled << "build data:" << buildData; if (product->enabled) QBS_CHECK(buildData); if (!product->buildData) return; for (BuildGraphNode * const node : std::as_const(buildData->rootNodes())) { qCDebug(lcBuildGraph).noquote() << "Checking root node" << node->toString(); QBS_CHECK(buildData->allNodes().contains(node)); } Set filePaths; for (BuildGraphNode * const node : std::as_const(buildData->allNodes())) { qCDebug(lcBuildGraph).noquote() << "Sanity checking node" << node->toString(); QBS_CHECK(node->product == product); for (const BuildGraphNode * const parent : std::as_const(node->parents)) QBS_CHECK(parent->children.contains(node)); for (BuildGraphNode * const child : std::as_const(node->children)) { QBS_CHECK(child->parents.contains(node)); QBS_CHECK(!child->product.expired()); QBS_CHECK(child->product->buildData); QBS_CHECK(child->product->buildData->allNodes().contains(child)); QBS_CHECK(allProducts.contains(child->product.lock())); } Artifact * const artifact = node->type() == BuildGraphNode::ArtifactNodeType ? static_cast(node) : nullptr; if (!artifact) { QBS_CHECK(node->type() == BuildGraphNode::RuleNodeType); auto const ruleNode = static_cast(node); QBS_CHECK(ruleNode->rule()); QBS_CHECK(ruleNode->rule()->product); QBS_CHECK(ruleNode->rule()->product == ruleNode->product.get()); QBS_CHECK(ruleNode->rule()->product == product.get()); QBS_CHECK(contains(product->rules, std::const_pointer_cast(ruleNode->rule()))); continue; } QBS_CHECK(product->topLevelProject()->buildData->fileDependencies.contains( artifact->fileDependencies)); QBS_CHECK(artifact->artifactType == Artifact::SourceFile || !filePaths.contains(artifact->filePath())); filePaths << artifact->filePath(); for (Artifact * const child : std::as_const(artifact->childrenAddedByScanner)) QBS_CHECK(artifact->children.contains(child)); const TransformerConstPtr transformer = artifact->transformer; if (artifact->artifactType == Artifact::SourceFile) continue; const auto parentRuleNodes = filterByType(artifact->children); QBS_CHECK(std::distance(parentRuleNodes.begin(), parentRuleNodes.end()) == 1); QBS_CHECK(transformer); QBS_CHECK(transformer->rule); QBS_CHECK(transformer->rule->product); QBS_CHECK(transformer->rule->product == artifact->product.get()); QBS_CHECK(transformer->rule->product == product.get()); QBS_CHECK(transformer->outputs.contains(artifact)); QBS_CHECK(contains(product->rules, std::const_pointer_cast(transformer->rule))); qCDebug(lcBuildGraph) << "The transformer has" << transformer->outputs.size() << "outputs."; ArtifactSet transformerOutputChildren; for (const Artifact * const output : std::as_const(transformer->outputs)) { QBS_CHECK(output->transformer == transformer); transformerOutputChildren.unite(ArtifactSet::filtered(output->children)); for (const Artifact *a : filterByType(output->children)) { for (const Artifact *other : filterByType(output->children)) { if (other != a && other->filePath() == a->filePath() && (other->artifactType != Artifact::SourceFile || a->artifactType != Artifact::SourceFile || other->product == a->product)) { throw ErrorInfo(QStringLiteral("There is more than one artifact for " "file '%1' in the child list for output '%2'.") .arg(a->filePath(), output->filePath()), CodeLocation(), true); } } } } if (lcBuildGraph().isDebugEnabled()) { qCDebug(lcBuildGraph) << "The transformer output children are:"; for (const Artifact * const a : std::as_const(transformerOutputChildren)) qCDebug(lcBuildGraph) << "\t" << a->fileName(); qCDebug(lcBuildGraph) << "The transformer inputs are:"; for (const Artifact * const a : std::as_const(transformer->inputs)) qCDebug(lcBuildGraph) << "\t" << a->fileName(); } QBS_CHECK(transformer->inputs.size() <= transformerOutputChildren.size()); for (Artifact * const transformerInput : std::as_const(transformer->inputs)) QBS_CHECK(transformerOutputChildren.contains(transformerInput)); transformer->artifactsMapRequestedInPrepareScript.doSanityChecks(); transformer->artifactsMapRequestedInCommands.doSanityChecks(); } } static void doSanityChecks(const ResolvedProjectPtr &project, const Set &allProducts, Set &productNames, const Logger &logger) { logger.qbsDebug() << "Sanity checking project '" << project->name << "'"; for (const ResolvedProjectPtr &subProject : std::as_const(project->subProjects)) doSanityChecks(subProject, allProducts, productNames, logger); for (const auto &product : project->products) { QBS_CHECK(product->project == project); QBS_CHECK(product->topLevelProject() == project->topLevelProject()); doSanityChecksForProduct(product, allProducts, logger); QBS_CHECK(!productNames.contains(product->uniqueName())); productNames << product->uniqueName(); } } void doSanityChecks(const ResolvedProjectPtr &project, const Logger &logger) { if (qEnvironmentVariableIsEmpty("QBS_SANITY_CHECKS")) return; Set productNames; const auto allProducts = rangeTo>(project->allProducts()); doSanityChecks(project, allProducts, productNames, logger); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/nodeset.cpp0000644000175100001660000000516414776170045021720 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "nodeset.h" #include "artifact.h" #include "rulenode.h" #include #include namespace qbs { namespace Internal { BuildGraphNode *loadBuildGraphNode(PersistentPool &pool) { const auto t = pool.load(); BuildGraphNode *node = nullptr; switch (static_cast(t)) { case BuildGraphNode::ArtifactNodeType: node = pool.load(); break; case BuildGraphNode::RuleNodeType: node = pool.load(); break; } QBS_CHECK(node); return node; } void storeBuildGraphNode(PersistentPool &pool, const BuildGraphNode *node) { pool.store(static_cast(node->type())); pool.store(node); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/artifactcleaner.h0000644000175100001660000000520414776170045023046 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ARTIFACTCLEANER_H #define QBS_ARTIFACTCLEANER_H #include #include #include namespace qbs { class CleanOptions; namespace Internal { class ProgressObserver; class ArtifactCleaner { public: ArtifactCleaner(Logger logger, ProgressObserver *observer); void cleanup(const TopLevelProjectPtr &project, const QVector &products, const CleanOptions &options); private: void removeEmptyDirectories(const QString &rootDir, const CleanOptions &options, bool *isEmpty = nullptr); Logger m_logger; bool m_hasError = false; ProgressObserver *m_observer = nullptr; }; } // namespace Internal } // namespace qbs #endif // QBS_ARTIFACTCLEANER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/requesteddependencies.cpp0000644000175100001660000000653714776170045024634 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "requesteddependencies.h" #include #include #include namespace qbs { namespace Internal { static Set depNamesForProduct(const ResolvedProduct *p) { Set names; for (const auto &dep : p->dependencies) names.insert(dep->uniqueName()); for (const auto &m : p->modules) { if (!m->isProduct) names.insert(m->name); } return names; } void RequestedDependencies::set(const Set &products) { m_depsPerProduct.clear(); add(products); } void RequestedDependencies::add(const Set &products) { for (const ResolvedProduct * const p : products) m_depsPerProduct[p->uniqueName()] = depNamesForProduct(p); } bool RequestedDependencies::isUpToDate(const TopLevelProject *project) const { if (m_depsPerProduct.empty()) return true; for (const auto &product : project->allProducts()) { const auto it = m_depsPerProduct.find(product->uniqueName()); if (it == m_depsPerProduct.cend()) continue; const Set newDepNames = depNamesForProduct(product.get()); if (newDepNames != it->second) { qCDebug(lcBuildGraph) << "dependencies list was accessed for product" << product->fullDisplayName() << "and dependencies have changed."; return false; } } return true; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/transformerchangetracking.h0000644000175100001660000000406114776170045025152 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TRANSFORMERCHANGETRACKING_H #define QBS_TRANSFORMERCHANGETRACKING_H #include "forward_decls.h" #include #include namespace qbs { namespace Internal { bool prepareScriptNeedsRerun( Transformer *transformer, const ResolvedProduct *product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName); bool commandsNeedRerun(Transformer *transformer, const ResolvedProduct *product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName); } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/filedependency.cpp0000644000175100001660000000555614776170045023242 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "filedependency.h" #include namespace qbs { namespace Internal { FileResourceBase::FileResourceBase() = default; FileResourceBase::~FileResourceBase() = default; void FileResourceBase::setTimestamp(const FileTime &t) { m_timestamp = t; } const FileTime &FileResourceBase::timestamp() const { return m_timestamp; } void FileResourceBase::setFilePath(const QString &filePath) { m_filePath = filePath; FileInfo::splitIntoDirectoryAndFileName(m_filePath, &m_dirPath, &m_fileName); } const QString &FileResourceBase::filePath() const { return m_filePath; } void FileResourceBase::load(PersistentPool &pool) { serializationOp(pool); FileInfo::splitIntoDirectoryAndFileName(m_filePath, &m_dirPath, &m_fileName); } void FileResourceBase::store(PersistentPool &pool) { serializationOp(pool); } FileDependency::FileDependency() = default; FileDependency::~FileDependency() = default; } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/executor.cpp0000644000175100001660000014560314776170045022120 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "executor.h" #include "buildgraph.h" #include "emptydirectoriesremover.h" #include "environmentscriptrunner.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "cycledetector.h" #include "executorjob.h" #include "inputartifactscanner.h" #include "productinstaller.h" #include "rescuableartifactdata.h" #include "rulecommands.h" #include "rulenode.h" #include "rulesevaluationcontext.h" #include "transformerchangetracking.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { bool Executor::ComparePriority::operator() (const BuildGraphNode *x, const BuildGraphNode *y) const { return x->product->buildData->buildPriority() < y->product->buildData->buildPriority(); } Executor::Executor(Logger logger, QObject *parent) : QObject(parent) , m_productInstaller(nullptr) , m_logger(std::move(logger)) , m_progressObserver(nullptr) , m_state(ExecutorIdle) , m_cancelationTimer(new QTimer(this)) { m_inputArtifactScanContext = new InputArtifactScannerContext; m_cancelationTimer->setSingleShot(false); m_cancelationTimer->setInterval(1000); connect(m_cancelationTimer, &QTimer::timeout, this, &Executor::checkForCancellation); } Executor::~Executor() { // jobs must be destroyed before deleting the m_inputArtifactScanContext m_allJobs.clear(); delete m_inputArtifactScanContext; delete m_productInstaller; } FileTime Executor::recursiveFileTime(const QString &filePath) const { FileTime newest; FileInfo fileInfo(filePath); if (!fileInfo.exists()) { const QString nativeFilePath = QDir::toNativeSeparators(filePath); m_logger.qbsWarning() << Tr::tr("File '%1' not found.").arg(nativeFilePath); return newest; } newest = std::max(fileInfo.lastModified(), fileInfo.lastStatusChange()); if (!fileInfo.isDir()) return newest; const QStringList dirContents = QDir(filePath) .entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); for (const QString &curFileName : dirContents) { const FileTime ft = recursiveFileTime(filePath + QLatin1Char('/') + curFileName); if (ft > newest) newest = ft; } return newest; } void Executor::retrieveSourceFileTimestamp(Artifact *artifact) const { QBS_CHECK(artifact->artifactType == Artifact::SourceFile); if (m_buildOptions.changedFiles().contains(artifact->filePath())) artifact->setTimestamp(FileTime::currentTime()); else if (m_buildOptions.changedFiles().empty() || !artifact->timestamp().isValid()) artifact->setTimestamp(recursiveFileTime(artifact->filePath())); artifact->timestampRetrieved = true; if (!artifact->timestamp().isValid()) throw ErrorInfo(Tr::tr("Source file '%1' has disappeared.").arg(artifact->filePath())); } void Executor::build() { try { m_partialBuild = size_t(m_primaryProducts.size()) != m_allProducts.size(); doBuild(); } catch (const ErrorInfo &e) { handleError(e); } } void Executor::setProject(const TopLevelProjectPtr &project) { m_project = project; m_allProducts = project->allProducts(); m_projectsByName.clear(); m_projectsByName.insert(std::make_pair(project->name, project.get())); for (const ResolvedProjectPtr &p : project->allSubProjects()) m_projectsByName.insert(std::make_pair(p->name, p.get())); } void Executor::setProducts(const QVector &productsToBuild) { m_primaryProducts = productsToBuild; setupAuxiliaryProducts(); m_productsByName.clear(); for (const ResolvedProductPtr &p : m_buildableProducts) m_productsByName.insert(std::make_pair(p->uniqueName(), p.get())); } void Executor::setupAuxiliaryProducts() { m_buildableProducts = m_primaryProducts; if (int(m_primaryProducts.size()) == int(m_allProducts.size())) return; for (int i = 0; i < m_buildableProducts.size(); ++i) { const ResolvedProductPtr product = m_buildableProducts.at(i); for (const ResolvedProductPtr &dependency : std::as_const(product->dependencies)) { if (!contains(m_buildableProducts, dependency)) m_buildableProducts.push_back(dependency); } } } class ProductPrioritySetter { const std::vector &m_allProducts; unsigned int m_priority = 0; Set m_seenProducts; public: ProductPrioritySetter(const std::vector &allProducts) // TODO: Use only products to build? : m_allProducts(allProducts) { } void apply() { Set allDependencies; for (const ResolvedProductPtr &product : m_allProducts) { for (const ResolvedProductPtr &dep : product->dependencies) allDependencies += dep; } const Set rootProducts = rangeTo>(m_allProducts) - allDependencies; m_priority = UINT_MAX; m_seenProducts.clear(); for (const ResolvedProductPtr &rootProduct : rootProducts) traverse(rootProduct); } private: void traverse(const ResolvedProductPtr &product) { if (!m_seenProducts.insert(product).second) return; for (const ResolvedProductPtr &dependency : std::as_const(product->dependencies)) traverse(dependency); if (!product->buildData) return; product->buildData->setBuildPriority(m_priority--); } }; void Executor::doBuild() { if (m_buildOptions.maxJobCount() <= 0) { m_buildOptions.setMaxJobCount(BuildOptions::defaultMaxJobCount()); qCDebug(lcExec) << "max job count not explicitly set, using value of" << m_buildOptions.maxJobCount(); } QBS_CHECK(m_state == ExecutorIdle); m_leaves = Leaves(); m_error.clear(); m_explicitlyCanceled = false; m_activeFileTags = FileTags::fromStringList(m_buildOptions.activeFileTags()); m_tagsOfFilesToConsider.clear(); m_tagsNeededForFilesToConsider.clear(); m_productsOfFilesToConsider.clear(); m_artifactsRemovedFromDisk.clear(); m_jobCountPerPool.clear(); setupJobLimits(); // TODO: The "filesToConsider" thing is badly designed; we should know exactly which artifact // it is. Remove this from the BuildOptions class and introduce Project::buildSomeFiles() // instead. const QStringList &filesToConsider = m_buildOptions.filesToConsider(); if (!filesToConsider.empty()) { for (const QString &fileToConsider : filesToConsider) { const auto &files = m_project->buildData->lookupFiles(fileToConsider); for (const FileResourceBase * const file : files) { if (file->fileType() != FileResourceBase::FileTypeArtifact) continue; auto const artifact = static_cast(file); if (contains(m_buildableProducts, artifact->product.lock())) { m_tagsOfFilesToConsider.unite(artifact->fileTags()); m_productsOfFilesToConsider << artifact->product.lock(); } } } } setState(ExecutorRunning); if (m_primaryProducts.empty()) { qCDebug(lcExec) << "No products to build, finishing."; QTimer::singleShot(0, this, &Executor::finish); // Don't call back on the caller. return; } doSanityChecks(); QBS_CHECK(!m_project->buildData->evaluationContext); m_project->buildData->evaluationContext = std::make_shared(m_logger); m_evalContext = m_project->buildData->evaluationContext; m_progressObserver->addScriptEngine(m_evalContext->engine()); m_elapsedTimeRules = m_elapsedTimeScanners = m_elapsedTimeInstalling = 0; m_evalContext->engine()->enableProfiling(m_buildOptions.logElapsedTime()); InstallOptions installOptions; installOptions.setDryRun(m_buildOptions.dryRun()); installOptions.setInstallRoot( m_buildableProducts.front() ->moduleProperties->qbsPropertyValue(StringConstants::installRootProperty()) .toString()); installOptions.setKeepGoing(m_buildOptions.keepGoing()); m_productInstaller = new ProductInstaller( m_project, m_buildableProducts, installOptions, m_progressObserver, m_logger); if (m_buildOptions.removeExistingInstallation()) m_productInstaller->removeInstallRoot(); addExecutorJobs(); syncFileDependencies(); prepareAllNodes(); prepareProducts(); setupRootNodes(); prepareReachableNodes(); setupProgressObserver(); initLeaves(); if (!scheduleJobs()) { qCDebug(lcExec) << "Nothing to do at all, finishing."; QTimer::singleShot(0, this, &Executor::finish); // Don't call back on the caller. } if (m_progressObserver) m_cancelationTimer->start(); } void Executor::setBuildOptions(const BuildOptions &buildOptions) { m_buildOptions = buildOptions; } void Executor::initLeaves() { updateLeaves(m_roots); } void Executor::updateLeaves(const NodeSet &nodes) { NodeSet seenNodes; for (BuildGraphNode * const node : nodes) updateLeaves(node, seenNodes); } void Executor::updateLeaves(BuildGraphNode *node, NodeSet &seenNodes) { if (!seenNodes.insert(node).second) return; // Artifacts that appear in the build graph after // prepareBuildGraph() has been called, must be initialized. if (node->buildState == BuildGraphNode::Untouched) { node->buildState = BuildGraphNode::Buildable; if (node->type() == BuildGraphNode::ArtifactNodeType) { auto const artifact = static_cast(node); if (artifact->artifactType == Artifact::SourceFile) retrieveSourceFileTimestamp(artifact); } } bool isLeaf = true; for (BuildGraphNode *child : std::as_const(node->children)) { if (child->buildState != BuildGraphNode::Built) { isLeaf = false; updateLeaves(child, seenNodes); } } if (isLeaf) { qCDebug(lcExec).noquote() << "adding leaf" << node->toString(); m_leaves.push(node); } } // Returns true if some artifacts are still waiting to be built or currently building. bool Executor::scheduleJobs() { QBS_CHECK(m_state == ExecutorRunning); std::vector delayedLeaves; while (!m_leaves.empty() && !m_availableJobs.empty()) { BuildGraphNode * const nodeToBuild = m_leaves.top(); m_leaves.pop(); switch (nodeToBuild->buildState) { case BuildGraphNode::Untouched: QBS_ASSERT(!"untouched node in leaves list", qDebug("%s", qPrintable(nodeToBuild->toString()))); break; case BuildGraphNode::Buildable: // This is the only state in which we want to build a node. // TODO: It's a bit annoying that we have to check this here already, when we // don't know whether the transformer needs to run at all. Investigate // moving the whole job allocation logic to runTransformer(). if (schedulingBlockedByJobLimit(nodeToBuild)) { qCDebug(lcExec).noquote() << "node delayed due to occupied job pool:" << nodeToBuild->toString(); delayedLeaves.push_back(nodeToBuild); } else { nodeToBuild->accept(this); } break; case BuildGraphNode::Building: qCDebug(lcExec).noquote() << nodeToBuild->toString(); qCDebug(lcExec) << "node is currently being built. Skipping."; break; case BuildGraphNode::Built: qCDebug(lcExec).noquote() << nodeToBuild->toString(); qCDebug(lcExec) << "node already built. Skipping."; break; } } for (BuildGraphNode * const delayedLeaf : delayedLeaves) m_leaves.push(delayedLeaf); return !m_leaves.empty() || !m_processingJobs.empty(); } bool Executor::schedulingBlockedByJobLimit(const BuildGraphNode *node) { if (node->type() != BuildGraphNode::ArtifactNodeType) return false; const auto artifact = static_cast(node); if (artifact->artifactType == Artifact::SourceFile) return false; const Transformer * const transformer = artifact->transformer.get(); for (const QString &jobPool : transformer->jobPools()) { const int currentJobCount = m_jobCountPerPool[jobPool]; if (currentJobCount == 0) continue; const auto jobLimitIsExceeded = [currentJobCount, jobPool, this](const Transformer *t) { const auto it = m_jobLimitsPerProduct.find(t->product().get()); if (it == m_jobLimitsPerProduct.cend()) return false; // See checkNodeProduct() for why this is possible const int maxJobCount = it->second.getLimit(jobPool); return maxJobCount > 0 && currentJobCount >= maxJobCount; }; // Different products can set different limits. The effective limit is the minimum of what // is set in this transformer's product and in the products of all currently // running transformers. if (jobLimitIsExceeded(transformer)) return true; const auto runningJobs = m_processingJobs.keys(); for (const ExecutorJob * const runningJob : runningJobs) { if (!runningJob->jobPools().contains(jobPool)) continue; const Transformer * const runningTransformer = runningJob->transformer(); if (!runningTransformer) continue; // This can happen if the ExecutorJob has already finished. if (runningTransformer->product() == transformer->product()) continue; // We have already checked this product's job limit. if (jobLimitIsExceeded(runningTransformer)) return true; } } return false; } bool Executor::isUpToDate(Artifact *artifact) const { QBS_CHECK(artifact->artifactType == Artifact::Generated); qCDebug(lcUpToDateCheck) << "check" << artifact->filePath() << artifact->timestamp().toString(); if (m_buildOptions.forceTimestampCheck()) { artifact->setTimestamp(FileInfo(artifact->filePath()).lastModified()); qCDebug(lcUpToDateCheck) << "timestamp retrieved from filesystem:" << artifact->timestamp().toString(); } if (!artifact->timestamp().isValid()) { qCDebug(lcUpToDateCheck) << "invalid timestamp. Out of date."; return false; } for (Artifact *childArtifact : filterByType(artifact->children)) { QBS_CHECK(!childArtifact->alwaysUpdated || childArtifact->timestamp().isValid()); qCDebug(lcUpToDateCheck) << "child timestamp" << childArtifact->timestamp().toString() << childArtifact->filePath(); if (artifact->timestamp() < childArtifact->timestamp()) return false; } for (FileDependency *fileDependency : std::as_const(artifact->fileDependencies)) { if (!fileDependency->timestamp().isValid()) { qCDebug(lcUpToDateCheck) << "file dependency doesn't exist" << fileDependency->filePath(); return false; } qCDebug(lcUpToDateCheck) << "file dependency timestamp" << fileDependency->timestamp().toString() << fileDependency->filePath(); if (artifact->timestamp() < fileDependency->timestamp()) return false; } return true; } bool Executor::mustExecuteTransformer(const TransformerPtr &transformer) const { if (transformer->alwaysRun) return true; if (transformer->markedForRerun) { qCDebug(lcUpToDateCheck) << "explicitly marked for re-run."; return true; } bool hasAlwaysUpdatedArtifacts = false; bool hasUpToDateNotAlwaysUpdatedArtifacts = false; for (Artifact *artifact : std::as_const(transformer->outputs)) { if (isUpToDate(artifact)) { if (artifact->alwaysUpdated) hasAlwaysUpdatedArtifacts = true; else hasUpToDateNotAlwaysUpdatedArtifacts = true; } else if (artifact->alwaysUpdated || m_buildOptions.forceTimestampCheck()) { return true; } } if (commandsNeedRerun(transformer.get(), transformer->product().get(), m_productsByName, m_projectsByName)) { return true; } // If all artifacts in a transformer have "alwaysUpdated" set to false, that transformer is // run if and only if *all* of them are out of date. return !hasAlwaysUpdatedArtifacts && !hasUpToDateNotAlwaysUpdatedArtifacts; } void Executor::buildArtifact(Artifact *artifact) { qCDebug(lcExec) << relativeArtifactFileName(artifact); QBS_CHECK(artifact->buildState == BuildGraphNode::Buildable); if (artifact->artifactType != Artifact::SourceFile && !checkNodeProduct(artifact)) return; // skip artifacts without transformer if (artifact->artifactType != Artifact::Generated) { // For source artifacts, that were not reachable when initializing the build, we must // retrieve timestamps. This can happen, if a dependency that's added during the build // makes the source artifact reachable. if (artifact->artifactType == Artifact::SourceFile && !artifact->timestampRetrieved) retrieveSourceFileTimestamp(artifact); qCDebug(lcExec) << "artifact type" << toString(artifact->artifactType) << "Skipping."; finishArtifact(artifact); return; } // Every generated artifact must have a transformer. QBS_CHECK(artifact->transformer); potentiallyRunTransformer(artifact->transformer); } void Executor::executeRuleNode(RuleNode *ruleNode) { AccumulatingTimer rulesTimer(m_buildOptions.logElapsedTime() ? &m_elapsedTimeRules : nullptr); if (!checkNodeProduct(ruleNode)) return; QBS_CHECK(!m_evalContext->engine()->isActive()); const RuleNode::ApplicationResult result = ruleNode->apply( m_logger, m_productsByName, m_projectsByName); updateLeaves(result.createdArtifacts); updateLeaves(result.invalidatedArtifacts); m_artifactsRemovedFromDisk << result.removedArtifacts; if (m_progressObserver) { const int transformerCount = ruleNode->transformerCount(); if (transformerCount == 0) { m_progressObserver->incrementProgressValue(); } else { m_pendingTransformersPerRule.insert(std::make_pair(ruleNode->rule().get(), transformerCount)); } } finishNode(ruleNode); } void Executor::finishJob(ExecutorJob *job, bool success) { QBS_CHECK(job); QBS_CHECK(m_state != ExecutorIdle); const JobMap::Iterator it = m_processingJobs.find(job); QBS_CHECK(it != m_processingJobs.end()); const TransformerPtr transformer = it.value(); m_processingJobs.erase(it); m_availableJobs.push_back(job); updateJobCounts(transformer.get(), -1); if (success) { m_project->buildData->setDirty(); for (Artifact * const artifact : std::as_const(transformer->outputs)) { if (artifact->alwaysUpdated) { artifact->setTimestamp(FileTime::currentTime()); for (Artifact * const parent : artifact->parentArtifacts()) parent->transformer->markedForRerun = true; if (m_buildOptions.forceOutputCheck() && !m_buildOptions.dryRun() && !FileInfo(artifact->filePath()).exists()) { if (transformer->rule) { if (!transformer->rule->name.isEmpty()) { throw ErrorInfo(tr("Rule '%1' declares artifact '%2', " "but the artifact was not produced.") .arg(transformer->rule->name, artifact->filePath())); } throw ErrorInfo(tr("Rule declares artifact '%1', " "but the artifact was not produced.") .arg(artifact->filePath())); } throw ErrorInfo(tr("Transformer declares artifact '%1', " "but the artifact was not produced.") .arg(artifact->filePath())); } } else { artifact->setTimestamp(FileInfo(artifact->filePath()).lastModified()); } } finishTransformer(transformer); } if (!success && !m_buildOptions.keepGoing()) cancelJobs(); if (m_state == ExecutorRunning && m_progressObserver && m_progressObserver->canceled()) { qCDebug(lcExec) << "Received cancel request; canceling build."; m_explicitlyCanceled = true; cancelJobs(); } if (m_state == ExecutorCanceling) { if (m_processingJobs.empty()) { qCDebug(lcExec) << "All pending jobs are done, finishing."; finish(); } return; } if (!scheduleJobs()) { qCDebug(lcExec) << "Nothing left to build; finishing."; finish(); } } static bool allChildrenBuilt(BuildGraphNode *node) { return Internal::all_of(node->children, std::mem_fn(&BuildGraphNode::isBuilt)); } void Executor::finishNode(BuildGraphNode *leaf) { leaf->buildState = BuildGraphNode::Built; for (BuildGraphNode * const parent : std::as_const(leaf->parents)) { if (parent->buildState != BuildGraphNode::Buildable) { qCDebug(lcExec).noquote() << "parent" << parent->toString() << "build state:" << toString(parent->buildState); continue; } if (allChildrenBuilt(parent)) { m_leaves.push(parent); qCDebug(lcExec).noquote() << "finishNode adds leaf" << parent->toString() << toString(parent->buildState); } else { qCDebug(lcExec).noquote() << "parent" << parent->toString() << "build state:" << toString(parent->buildState); } } } void Executor::finishArtifact(Artifact *leaf) { QBS_CHECK(leaf); qCDebug(lcExec) << "finishArtifact" << relativeArtifactFileName(leaf); finishNode(leaf); } QString Executor::configString() const { return tr(" for configuration %1").arg(m_project->id()); } bool Executor::transformerHasMatchingOutputTags(const TransformerConstPtr &transformer) const { if (m_activeFileTags.empty()) return true; // No filtering requested. return Internal::any_of(transformer->outputs, [this](const Artifact *a) { return artifactHasMatchingOutputTags(a); }); } bool Executor::artifactHasMatchingOutputTags(const Artifact *artifact) const { return m_activeFileTags.intersects(artifact->fileTags()) || m_tagsNeededForFilesToConsider.intersects(artifact->fileTags()); } bool Executor::transformerHasMatchingInputFiles(const TransformerConstPtr &transformer) const { if (m_buildOptions.filesToConsider().empty()) return true; // No filtering requested. if (!m_productsOfFilesToConsider.contains(transformer->product())) return false; if (transformer->inputs.empty()) return true; for (const Artifact * const input : std::as_const(transformer->inputs)) { const auto files = m_buildOptions.filesToConsider(); for (const QString &filePath : files) { if (input->filePath() == filePath || input->fileTags().intersects(m_tagsNeededForFilesToConsider)) { return true; } } } return false; } void Executor::setupJobLimits() { Settings settings(m_buildOptions.settingsDirectory()); for (const auto &p : std::as_const(m_buildableProducts)) { const Preferences prefs(&settings, p->profile()); const JobLimits &jobLimitsFromSettings = prefs.jobLimits(); JobLimits effectiveJobLimits; if (m_buildOptions.projectJobLimitsTakePrecedence()) { effectiveJobLimits.update(jobLimitsFromSettings).update(m_buildOptions.jobLimits()) .update(p->jobLimits); } else { effectiveJobLimits.update(p->jobLimits).update(jobLimitsFromSettings) .update(m_buildOptions.jobLimits()); } m_jobLimitsPerProduct.insert(std::make_pair(p.get(), effectiveJobLimits)); } } void Executor::updateJobCounts(const Transformer *transformer, int diff) { for (const QString &jobPool : transformer->jobPools()) m_jobCountPerPool[jobPool] += diff; } void Executor::cancelJobs() { if (m_state == ExecutorCanceling) return; qCDebug(lcExec) << "Canceling all jobs."; setState(ExecutorCanceling); const auto jobs = m_processingJobs.keys(); for (ExecutorJob *job : jobs) job->cancel(); } void Executor::setupProgressObserver() { if (!m_progressObserver) return; int totalEffort = 1; // For the effort after the last rule application; for (const auto &product : std::as_const(m_buildableProducts)) { QBS_CHECK(product->buildData); const auto filtered = filterByType(product->buildData->allNodes()); totalEffort += std::distance(filtered.begin(), filtered.end()); } m_progressObserver->initialize(tr("Building%1").arg(configString()), totalEffort); } void Executor::doSanityChecks() { QBS_CHECK(m_project); QBS_CHECK(!m_primaryProducts.empty()); QBS_CHECK(m_buildableProducts.size() >= m_primaryProducts.size()); for (const auto &product : std::as_const(m_buildableProducts)) { QBS_CHECK(product->buildData); QBS_CHECK(product->topLevelProject() == m_project.get()); } } void Executor::handleError(const ErrorInfo &error) { const auto items = error.items(); for (const ErrorItem &ei : items) m_error.append(ei); if (m_processingJobs.empty()) finish(); else cancelJobs(); } void Executor::addExecutorJobs() { const int count = m_buildOptions.maxJobCount(); qCDebug(lcExec) << "preparing executor for" << count << "jobs in parallel"; m_allJobs.reserve(count); m_availableJobs.reserve(count); for (int i = 1; i <= count; i++) { m_allJobs.push_back(std::make_unique(m_logger)); const auto job = m_allJobs.back().get(); job->setMainThreadScriptEngine(m_evalContext->engine()); job->setObjectName(QStringLiteral("J%1").arg(i)); job->setDryRun(m_buildOptions.dryRun()); job->setEchoMode(m_buildOptions.echoMode()); m_availableJobs.push_back(job); connect(job, &ExecutorJob::reportCommandDescription, this, &Executor::reportCommandDescription); connect(job, &ExecutorJob::reportProcessResult, this, &Executor::reportProcessResult); connect(job, &ExecutorJob::finished, this, &Executor::onJobFinished, Qt::QueuedConnection); } } void Executor::rescueOldBuildData(Artifact *artifact, bool *childrenAdded = nullptr) { if (childrenAdded) *childrenAdded = false; if (!artifact->oldDataPossiblyPresent) return; artifact->oldDataPossiblyPresent = false; if (artifact->artifactType != Artifact::Generated) return; ResolvedProduct * const product = artifact->product.get(); const RescuableArtifactData rad = product->buildData->removeFromRescuableArtifactData(artifact->filePath()); if (!rad.isValid()) return; qCDebug(lcBuildGraph) << "Attempting to rescue data of artifact" << artifact->fileName(); std::vector childrenToConnect; bool canRescue = artifact->transformer->commands == rad.commands; if (canRescue) { ResolvedProductPtr pseudoProduct = ResolvedProduct::create(); for (const RescuableArtifactData::ChildData &cd : rad.children) { pseudoProduct->name = cd.productName; pseudoProduct->multiplexConfigurationId = cd.productMultiplexId; Artifact * const child = lookupArtifact(pseudoProduct, m_project->buildData.get(), cd.childFilePath, true); if (artifact->children.contains(child)) continue; if (!child) { // If a child has disappeared, we must re-build even if the commands // are the same. Example: Header file included in cpp file does not exist anymore. canRescue = false; qCDebug(lcBuildGraph) << "Former child artifact" << cd.childFilePath << "does not exist anymore."; const RescuableArtifactData childRad = product->buildData->removeFromRescuableArtifactData(cd.childFilePath); if (childRad.isValid()) { m_artifactsRemovedFromDisk << artifact->filePath(); removeGeneratedArtifactFromDisk(cd.childFilePath, m_logger); } } if (!cd.addedByScanner) { // If an artifact has disappeared from the list of children, the commands // might need to run again. canRescue = false; qCDebug(lcBuildGraph) << "Former child artifact" << cd.childFilePath << "is no longer in the list of children"; } if (canRescue) childrenToConnect.push_back(child); } for (const QString &depPath : rad.fileDependencies) { const auto &depList = m_project->buildData->lookupFiles(depPath); if (depList.empty()) { canRescue = false; qCDebug(lcBuildGraph) << "File dependency" << depPath << "not in the project's list of dependencies anymore."; break; } const auto depFinder = [](const FileResourceBase *f) { return f->fileType() == FileResourceBase::FileTypeDependency; }; const auto depIt = std::find_if(depList.cbegin(), depList.cend(), depFinder); if (depIt == depList.cend()) { canRescue = false; qCDebug(lcBuildGraph) << "File dependency" << depPath << "not in the project's list of dependencies anymore."; break; } artifact->fileDependencies.insert(static_cast(*depIt)); } if (canRescue) { const TypeFilter childArtifacts(artifact->children); const size_t newChildCount = childrenToConnect.size() + std::distance(childArtifacts.begin(), childArtifacts.end()); QBS_CHECK(newChildCount >= rad.children.size()); if (newChildCount > rad.children.size()) { canRescue = false; qCDebug(lcBuildGraph) << "Artifact has children not present in rescue data."; } } } else { qCDebug(lcBuildGraph) << "Transformer commands changed."; } if (canRescue) { artifact->transformer->propertiesRequestedInPrepareScript = rad.propertiesRequestedInPrepareScript; artifact->transformer->propertiesRequestedInCommands = rad.propertiesRequestedInCommands; artifact->transformer->propertiesRequestedFromArtifactInPrepareScript = rad.propertiesRequestedFromArtifactInPrepareScript; artifact->transformer->propertiesRequestedFromArtifactInCommands = rad.propertiesRequestedFromArtifactInCommands; artifact->transformer->importedFilesUsedInPrepareScript = rad.importedFilesUsedInPrepareScript; artifact->transformer->importedFilesUsedInCommands = rad.importedFilesUsedInCommands; artifact->transformer->depsRequestedInPrepareScript = rad.depsRequestedInPrepareScript; artifact->transformer->depsRequestedInCommands = rad.depsRequestedInCommands; artifact->transformer->artifactsMapRequestedInPrepareScript = rad.artifactsMapRequestedInPrepareScript; artifact->transformer->artifactsMapRequestedInCommands = rad.artifactsMapRequestedInCommands; artifact->transformer->exportedModulesAccessedInPrepareScript = rad.exportedModulesAccessedInPrepareScript; artifact->transformer->exportedModulesAccessedInCommands = rad.exportedModulesAccessedInCommands; artifact->transformer->lastCommandExecutionTime = rad.lastCommandExecutionTime; artifact->transformer->lastPrepareScriptExecutionTime = rad.lastPrepareScriptExecutionTime; artifact->transformer->commandsNeedChangeTracking = true; artifact->setTimestamp(rad.timeStamp); artifact->transformer->markedForRerun = artifact->transformer->markedForRerun || rad.knownOutOfDate; if (childrenAdded && !childrenToConnect.empty()) *childrenAdded = true; for (Artifact * const child : childrenToConnect) { if (safeConnect(artifact, child)) artifact->childrenAddedByScanner << child; } qCDebug(lcBuildGraph) << "Data was rescued."; } else { removeGeneratedArtifactFromDisk(artifact, m_logger); m_artifactsRemovedFromDisk << artifact->filePath(); qCDebug(lcBuildGraph) << "Data not rescued."; } } bool Executor::checkForUnbuiltDependencies(Artifact *artifact) { bool buildingDependenciesFound = false; NodeSet unbuiltDependencies; for (BuildGraphNode * const dependency : std::as_const(artifact->children)) { switch (dependency->buildState) { case BuildGraphNode::Untouched: case BuildGraphNode::Buildable: qCDebug(lcExec).noquote() << "unbuilt dependency:" << dependency->toString(); unbuiltDependencies += dependency; break; case BuildGraphNode::Building: { qCDebug(lcExec).noquote() << "dependency in state 'Building':" << dependency->toString(); buildingDependenciesFound = true; break; } case BuildGraphNode::Built: // do nothing break; } } if (!unbuiltDependencies.empty()) { artifact->inputsScanned = false; updateLeaves(unbuiltDependencies); return true; } if (buildingDependenciesFound) { artifact->inputsScanned = false; return true; } return false; } void Executor::potentiallyRunTransformer(const TransformerPtr &transformer) { for (Artifact * const output : std::as_const(transformer->outputs)) { // Rescuing build data can introduce new dependencies, potentially delaying execution of // this transformer. bool childrenAddedDueToRescue; rescueOldBuildData(output, &childrenAddedDueToRescue); if (childrenAddedDueToRescue && checkForUnbuiltDependencies(output)) return; } if (!transformerHasMatchingOutputTags(transformer)) { qCDebug(lcExec) << "file tags do not match. Skipping."; finishTransformer(transformer); return; } if (!transformerHasMatchingInputFiles(transformer)) { qCDebug(lcExec) << "input files do not match. Skipping."; finishTransformer(transformer); return; } const bool mustExecute = mustExecuteTransformer(transformer); if (mustExecute || m_buildOptions.forceTimestampCheck()) { for (Artifact * const output : std::as_const(transformer->outputs)) { // Scan all input artifacts. If new dependencies were found during scanning, delay // execution of this transformer. InputArtifactScanner scanner(output, m_inputArtifactScanContext, m_logger); AccumulatingTimer scanTimer(m_buildOptions.logElapsedTime() ? &m_elapsedTimeScanners : nullptr); scanner.scan(); scanTimer.stop(); if (scanner.newDependencyAdded() && checkForUnbuiltDependencies(output)) return; } } if (!mustExecute) { qCDebug(lcExec) << "Up to date. Skipping."; finishTransformer(transformer); return; } if (m_buildOptions.executeRulesOnly()) finishTransformer(transformer); else runTransformer(transformer); } void Executor::runTransformer(const TransformerPtr &transformer) { QBS_CHECK(transformer); // create the output directories if (!m_buildOptions.dryRun()) { for (Artifact * const output : std::as_const(transformer->outputs)) { QDir outDir = QFileInfo(output->filePath()).absoluteDir(); if (!outDir.exists() && !outDir.mkpath(StringConstants::dot())) { throw ErrorInfo(tr("Failed to create directory '%1'.") .arg(QDir::toNativeSeparators(outDir.absolutePath()))); } } } QBS_CHECK(!m_availableJobs.empty()); ExecutorJob *job = m_availableJobs.takeFirst(); for (Artifact * const artifact : std::as_const(transformer->outputs)) artifact->buildState = BuildGraphNode::Building; m_processingJobs.insert(job, transformer); updateJobCounts(transformer.get(), 1); job->run(transformer.get()); } void Executor::finishTransformer(const TransformerPtr &transformer) { transformer->markedForRerun = false; for (Artifact * const artifact : std::as_const(transformer->outputs)) { possiblyInstallArtifact(artifact); finishArtifact(artifact); } if (m_progressObserver) { const auto it = m_pendingTransformersPerRule.find(transformer->rule.get()); QBS_CHECK(it != m_pendingTransformersPerRule.cend()); if (--it->second == 0) { m_progressObserver->incrementProgressValue(); m_pendingTransformersPerRule.erase(it); } } } void Executor::possiblyInstallArtifact(const Artifact *artifact) { AccumulatingTimer installTimer(m_buildOptions.logElapsedTime() ? &m_elapsedTimeInstalling : nullptr); if (m_buildOptions.install() && !m_buildOptions.executeRulesOnly() && (m_activeFileTags.empty() || artifactHasMatchingOutputTags(artifact)) && artifact->properties->qbsPropertyValue(StringConstants::installProperty()) .toBool()) { m_productInstaller->copyFile(artifact); } } void Executor::onJobFinished(const qbs::ErrorInfo &err) { try { auto const job = qobject_cast(sender()); QBS_CHECK(job); if (m_evalContext->engine()->isActive()) { qCDebug(lcExec) << "Executor job finished while rule execution is pausing. " "Delaying slot execution."; QTimer::singleShot(0, job, [job, err] { emit job->finished(err); }); return; } if (err.hasError()) { if (m_buildOptions.keepGoing()) { ErrorInfo fullWarning(err); fullWarning.prepend(Tr::tr("Ignoring the following errors on user request:")); m_logger.printError(fullWarning); } else { if (!m_error.hasError()) m_error = err; // All but the first one could be due to canceling. } } finishJob(job, !err.hasError()); } catch (const ErrorInfo &error) { handleError(error); } } void Executor::checkForUnbuiltProducts() { if (m_buildOptions.executeRulesOnly()) return; std::vector unbuiltProducts; for (const ResolvedProductPtr &product : std::as_const(m_primaryProducts)) { bool productBuilt = true; for (BuildGraphNode *rootNode : std::as_const(product->buildData->rootNodes())) { if (rootNode->buildState != BuildGraphNode::Built) { productBuilt = false; unbuiltProducts.push_back(product); break; } } if (productBuilt) { // Any element still left after a successful build has not been re-created // by any rule and therefore does not exist anymore as an artifact. const AllRescuableArtifactData rad = product->buildData->rescuableArtifactData(); for (auto it = rad.cbegin(); it != rad.cend(); ++it) { removeGeneratedArtifactFromDisk(it.key(), m_logger); product->buildData->removeFromRescuableArtifactData(it.key()); m_artifactsRemovedFromDisk << it.key(); } } } if (unbuiltProducts.empty()) { m_logger.qbsInfo() << Tr::tr("Build done%1.").arg(configString()); } else { m_error.append(Tr::tr("The following products could not be built%1:").arg(configString())); auto productNames = transformed(unbuiltProducts, [](const auto &p) { return p->fullDisplayName(); }); std::sort(productNames.begin(), productNames.end()); m_error.append(productNames.join(QLatin1String(", "))); } } bool Executor::checkNodeProduct(BuildGraphNode *node) { if (!m_partialBuild || contains(m_buildableProducts, node->product.lock())) return true; // TODO: Turn this into a warning once we have a reliable C++ scanner. qCDebug(lcExec).noquote() << "Ignoring node " << node->toString() << ", which belongs to a " "product that is not part of the list of products to build. " "Possible reasons are an erroneous project design or a false " "positive from a dependency scanner."; finishNode(node); return false; } void Executor::finish() { QBS_ASSERT(m_state != ExecutorIdle, /* ignore */); QBS_ASSERT(!m_evalContext || !m_evalContext->engine()->isActive(), /* ignore */); checkForUnbuiltProducts(); if (m_explicitlyCanceled) { QString message = Tr::tr(m_buildOptions.executeRulesOnly() ? "Rule execution canceled" : "Build canceled"); m_error.append(Tr::tr("%1%2.").arg(message, configString())); } setState(ExecutorIdle); if (m_progressObserver) { m_progressObserver->setFinished(); m_cancelationTimer->stop(); } EmptyDirectoriesRemover(m_project.get(), m_logger) .removeEmptyParentDirectories(m_artifactsRemovedFromDisk); if (m_buildOptions.logElapsedTime()) { m_logger.qbsLog(LoggerInfo, true) << "\t" << Tr::tr("Rule execution took %1.") .arg(elapsedTimeString(m_elapsedTimeRules)); m_logger.qbsLog(LoggerInfo, true) << "\t" << Tr::tr("Artifact scanning took %1.") .arg(elapsedTimeString(m_elapsedTimeScanners)); m_logger.qbsLog(LoggerInfo, true) << "\t" << Tr::tr("Installing artifacts took %1.") .arg(elapsedTimeString(m_elapsedTimeInstalling)); } emit finished(); } void Executor::checkForCancellation() { QBS_ASSERT(m_progressObserver, return); if (m_state == ExecutorRunning && m_progressObserver->canceled()) { cancelJobs(); if (m_evalContext->engine()->isActive()) m_evalContext->engine()->cancel(); } } bool Executor::visit(Artifact *artifact) { QBS_CHECK(artifact->buildState != BuildGraphNode::Untouched); buildArtifact(artifact); return false; } bool Executor::visit(RuleNode *ruleNode) { QBS_CHECK(ruleNode->buildState != BuildGraphNode::Untouched); executeRuleNode(ruleNode); return false; } /** * Sets the state of all artifacts in the graph to "untouched". * This must be done before doing a build. * * Retrieves the timestamps of source artifacts. * * This function also fills the list of changed source files. */ void Executor::prepareAllNodes() { for (const ResolvedProductPtr &product : m_allProducts) { if (product->enabled) { QBS_CHECK(product->buildData); for (BuildGraphNode * const node : std::as_const(product->buildData->allNodes())) node->buildState = BuildGraphNode::Untouched; } } for (const ResolvedProductPtr &product : std::as_const(m_buildableProducts)) { QBS_CHECK(product->buildData); for (Artifact * const artifact : filterByType(product->buildData->allNodes())) prepareArtifact(artifact); } } void Executor::syncFileDependencies() { Set &globalFileDepList = m_project->buildData->fileDependencies; for (auto it = globalFileDepList.begin(); it != globalFileDepList.end(); ) { FileDependency * const dep = *it; FileInfo fi(dep->filePath()); if (fi.exists()) { dep->setTimestamp(fi.lastModified()); ++it; continue; } qCDebug(lcBuildGraph()) << "file dependency" << dep->filePath() << "no longer exists; " "removing from lookup table"; m_project->buildData->removeFromLookupTable(dep); bool isReferencedByArtifact = false; for (const auto &product : m_allProducts) { if (!product->buildData) continue; const auto artifactList = filterByType(product->buildData->allNodes()); isReferencedByArtifact = Internal::any_of(artifactList, [dep](const Artifact *a) { return a->fileDependencies.contains(dep); }); // TODO: Would it be safe to mark the artifact as "not up to date" here and clear // its list of file dependencies, rather than doing the check again in // isUpToDate()? if (isReferencedByArtifact) break; } if (!isReferencedByArtifact) { qCDebug(lcBuildGraph()) << "dependency is not referenced by any artifact, deleting"; it = globalFileDepList.erase(it); delete dep; } else { dep->clearTimestamp(); ++it; } } } void Executor::prepareArtifact(Artifact *artifact) { artifact->inputsScanned = false; artifact->timestampRetrieved = false; if (artifact->artifactType == Artifact::SourceFile) { retrieveSourceFileTimestamp(artifact); possiblyInstallArtifact(artifact); } } void Executor::setupForBuildingSelectedFiles(const BuildGraphNode *node) { if (node->type() != BuildGraphNode::RuleNodeType) return; if (m_buildOptions.filesToConsider().empty()) return; if (!m_productsOfFilesToConsider.contains(node->product.lock())) return; const auto ruleNode = static_cast(node); const Rule * const rule = ruleNode->rule().get(); if (rule->inputs.intersects(m_tagsOfFilesToConsider)) { FileTags otherInputs = rule->auxiliaryInputs; otherInputs.unite(rule->explicitlyDependsOn).subtract(rule->excludedInputs); m_tagsNeededForFilesToConsider.unite(otherInputs); } else if (rule->collectedOutputFileTags().intersects(m_tagsNeededForFilesToConsider)) { FileTags allInputs = rule->inputs; allInputs.unite(rule->auxiliaryInputs).unite(rule->explicitlyDependsOn) .subtract(rule->excludedInputs); m_tagsNeededForFilesToConsider.unite(allInputs); } } /** * Walk the build graph top-down from the roots and for each reachable node N * - mark N as buildable. */ void Executor::prepareReachableNodes() { for (BuildGraphNode * const root : std::as_const(m_roots)) prepareReachableNodes_impl(root); } void Executor::prepareReachableNodes_impl(BuildGraphNode *node) { setupForBuildingSelectedFiles(node); if (node->buildState != BuildGraphNode::Untouched) return; node->buildState = BuildGraphNode::Buildable; for (BuildGraphNode *child : std::as_const(node->children)) prepareReachableNodes_impl(child); } void Executor::prepareProducts() { ProductPrioritySetter prioritySetter(m_allProducts); prioritySetter.apply(); for (const ResolvedProductPtr &product : std::as_const(m_buildableProducts)) { EnvironmentScriptRunner(product.get(), m_evalContext.get(), m_project->environment) .setupForBuild(); } } void Executor::setupRootNodes() { m_roots.clear(); for (const ResolvedProductPtr &product : std::as_const(m_primaryProducts)) m_roots += product->buildData->rootNodes(); } void Executor::setState(ExecutorState s) { if (m_state == s) return; m_state = s; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/artifactvisitor.h0000644000175100001660000000504414776170045023136 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ARTIFACTVISITOR_H #define QBS_ARTIFACTVISITOR_H #include "forward_decls.h" #include "buildgraphvisitor.h" #include #include namespace qbs { namespace Internal { class ArtifactVisitor : public BuildGraphVisitor { public: ArtifactVisitor(int artifactType); void visitProduct(const ResolvedProductConstPtr &product); void visitProject(const ResolvedProjectConstPtr &project); bool visit(RuleNode *ruleNode) override; bool visit(Artifact *artifact) override; private: virtual void doVisit(Artifact *artifact) = 0; const int m_artifactType; }; } // namespace Internal } // namespace qbs #endif // QBS_ARTIFACTVISITOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraphloader.cpp0000644000175100001660000013062514776170045023570 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "buildgraphloader.h" #include "buildgraph.h" #include "emptydirectoriesremover.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "rulenode.h" #include "rulecommands.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { BuildGraphLoader::BuildGraphLoader(Logger logger) : m_logger(std::move(logger)) { } BuildGraphLoader::~BuildGraphLoader() { qDeleteAll(m_objectsToDelete); } static void restoreBackPointers(const ResolvedProjectPtr &project) { for (const ResolvedProductPtr &product : project->products) { product->project = project; if (!product->buildData) continue; for (BuildGraphNode * const n : std::as_const(product->buildData->allNodes())) { if (n->type() == BuildGraphNode::ArtifactNodeType) { project->topLevelProject()->buildData ->insertIntoLookupTable(static_cast(n)); } } } for (const ResolvedProjectPtr &subProject : std::as_const(project->subProjects)) { subProject->parentProject = project; restoreBackPointers(subProject); } } BuildGraphLoadResult BuildGraphLoader::load(const TopLevelProjectPtr &existingProject, const SetupProjectParameters ¶meters, const RulesEvaluationContextPtr &evalContext) { m_parameters = parameters; m_result = BuildGraphLoadResult(); m_evalContext = evalContext; if (existingProject) { QBS_CHECK(existingProject->buildData); existingProject->buildData->evaluationContext = evalContext; if (!checkBuildGraphCompatibility(existingProject)) return m_result; m_result.loadedProject = existingProject; } else { loadBuildGraphFromDisk(); } if (!m_result.loadedProject) return m_result; if (parameters.restoreBehavior() == SetupProjectParameters::RestoreOnly) { for (const ErrorInfo &e : std::as_const(m_result.loadedProject->errorsEncountered)) m_logger.printError(e); for (const ErrorInfo &e : std::as_const(m_result.loadedProject->warningsEncountered)) m_logger.printWarning(e); return m_result; } QBS_CHECK( parameters.restoreBehavior() == SetupProjectParameters::RestoreAndTrackChanges || parameters.restoreBehavior() == SetupProjectParameters::RestoreAndResolve); if (m_parameters.logElapsedTime()) { m_wildcardExpansionEffort = 0; m_propertyComparisonEffort = 0; } trackProjectChanges(); if (m_parameters.logElapsedTime()) { m_logger.qbsLog(LoggerInfo, true) << "\t" << Tr::tr("Wildcard expansion took %1.") .arg(elapsedTimeString(m_wildcardExpansionEffort)); m_logger.qbsLog(LoggerInfo, true) << "\t" << Tr::tr("Comparing property values took %1.") .arg(elapsedTimeString(m_propertyComparisonEffort)); } return m_result; } TopLevelProjectConstPtr BuildGraphLoader::loadProject(const QString &bgFilePath) { class LogSink : public ILogSink { void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } } dummySink; Logger dummyLogger(&dummySink); BuildGraphLocker bgLocker(bgFilePath, dummyLogger, false, nullptr); PersistentPool pool(dummyLogger); pool.load(bgFilePath); const TopLevelProjectPtr project = TopLevelProject::create(); project->load(pool); project->setBuildConfiguration(pool.headData().projectConfig); return project; } void BuildGraphLoader::loadBuildGraphFromDisk() { const QString projectId = TopLevelProject::deriveId(m_parameters.finalBuildConfigurationTree()); const QString buildDir = TopLevelProject::deriveBuildDirectory(m_parameters.buildRoot(), projectId); const QString buildGraphFilePath = ProjectBuildData::deriveBuildGraphFilePath(buildDir, projectId); PersistentPool pool(m_logger); qCDebug(lcBuildGraph) << "trying to load:" << buildGraphFilePath; try { pool.load(buildGraphFilePath); } catch (const NoBuildGraphError &) { if (m_parameters.restoreBehavior() == SetupProjectParameters::RestoreOnly) throw; m_logger.qbsInfo() << Tr::tr("Build graph does not yet exist for configuration '%1'. " "Starting from scratch.").arg(m_parameters.configurationName()); return; } catch (const ErrorInfo &loadError) { if (!m_parameters.overrideBuildGraphData()) { ErrorInfo fullError = loadError; fullError.append(Tr::tr("Use the 'resolve' command to set up a new build graph.")); throw fullError; } m_logger.qbsWarning() << loadError.toString(); return; } const TopLevelProjectPtr project = TopLevelProject::create(); // TODO: Store some meta data that will enable us to show actual progress (e.g. number of products). m_evalContext->initializeObserver(Tr::tr("Restoring build graph from disk"), 1); project->load(pool); project->buildData->evaluationContext = m_evalContext; project->setBuildConfiguration(pool.headData().projectConfig); project->buildDirectory = buildDir; if (!checkBuildGraphCompatibility(project)) return; restoreBackPointers(project); project->buildData->setClean(); project->location = CodeLocation(m_parameters.projectFilePath(), project->location.line(), project->location.column()); m_result.loadedProject = project; m_evalContext->incrementProgressValue(); doSanityChecks(project, m_logger); } bool BuildGraphLoader::checkBuildGraphCompatibility(const TopLevelProjectConstPtr &project) { if (m_parameters.projectFilePath().isEmpty()) m_parameters.setProjectFilePath(project->location.filePath()); else m_parameters.finalizeProjectFilePath(); if (QFileInfo(project->location.filePath()) == QFileInfo(m_parameters.projectFilePath())) return true; QString message = Tr::tr("Stored build graph at '%1' is for project file '%2', but " "input file is '%3'.") .arg(QDir::toNativeSeparators(project->buildGraphFilePath()), QDir::toNativeSeparators(project->location.filePath()), QDir::toNativeSeparators(m_parameters.projectFilePath())); if (m_parameters.overrideBuildGraphData()) { m_logger.qbsInfo() << message; return false; } message.append(QLatin1Char('\n')).append(Tr::tr("Use the 'resolve' command to enforce " "using a different project file.")); throw ErrorInfo(message); } static bool checkProductForChangedDependency(std::vector &changedProducts, Set &seenProducts, const ResolvedProductPtr &product) { if (seenProducts.contains(product)) return false; if (contains(changedProducts, product)) return true; for (const ResolvedProductPtr &dep : std::as_const(product->dependencies)) { if (checkProductForChangedDependency(changedProducts, seenProducts, dep)) { changedProducts << product; return true; } } seenProducts << product; return false; } // All products depending on changed products also become changed. Otherwise the output // artifacts of the rules taking the artifacts from the dependency as inputs will be // rebuilt due to their rule getting re-applied (as the rescued input artifacts will show // up as newly added) and no rescue data being available. static void makeChangedProductsListComplete(std::vector &changedProducts, const std::vector &allRestoredProducts) { Set seenProducts; for (const ResolvedProductPtr &p : allRestoredProducts) checkProductForChangedDependency(changedProducts, seenProducts, p); } static void updateProductAndRulePointers(const ResolvedProductPtr &newProduct) { std::unordered_map ruleMap; for (BuildGraphNode *node : std::as_const(newProduct->buildData->allNodes())) { node->product = newProduct; const auto findNewRule = [&ruleMap, &newProduct] (const RuleConstPtr &oldRule) -> RuleConstPtr { const auto it = ruleMap.find(oldRule); if (it != ruleMap.cend()) return it->second; for (const auto &r : std::as_const(newProduct->rules)) { if (*r == *oldRule) { ruleMap.insert(std::make_pair(oldRule, r)); return r; } } QBS_CHECK(false); return {}; }; if (node->type() == BuildGraphNode::RuleNodeType) { const auto ruleNode = static_cast(node); ruleNode->setRule(findNewRule(ruleNode->rule())); } else { QBS_CHECK(node->type() == BuildGraphNode::ArtifactNodeType); const auto artifact = static_cast(node); if (artifact->artifactType == Artifact::Generated) { QBS_CHECK(artifact->transformer); artifact->transformer->rule = findNewRule(artifact->transformer->rule); } } } } void BuildGraphLoader::trackProjectChanges() { TimedActivityLogger trackingTimer(m_logger, Tr::tr("Change tracking"), m_parameters.logElapsedTime()); const TopLevelProjectPtr &restoredProject = m_result.loadedProject; Set buildSystemFiles = restoredProject->buildSystemFiles; std::vector allRestoredProducts = restoredProject->allProducts(); std::vector changedProducts; bool reResolvingNecessary = false; if (!checkConfigCompatibility()) { m_logger.qbsInfo() << Tr::tr("One or more properties have changed."); reResolvingNecessary = true; } if (hasProductFileChanged(allRestoredProducts, restoredProject->lastStartResolveTime, buildSystemFiles, changedProducts)) { reResolvingNecessary = true; } // "External" changes, e.g. in the environment or in a JavaScript file, // can make the list of source files in a product change without the respective file // having been touched. In such a case, the build data for that product will have to be set up // anew. if (probeExecutionForced(restoredProject, allRestoredProducts) || hasBuildSystemFileChanged(buildSystemFiles, restoredProject.get()) || hasEnvironmentChanged(restoredProject) || hasCanonicalFilePathResultChanged(restoredProject) || hasFileExistsResultChanged(restoredProject) || hasDirectoryEntriesResultChanged(restoredProject) || hasFileLastModifiedResultChanged(restoredProject)) { reResolvingNecessary = true; } if (!reResolvingNecessary && m_parameters.restoreBehavior() == SetupProjectParameters::RestoreAndResolve) { m_logger.qbsInfo() << Tr::tr("No changes detected, but re-resolve was forced."); reResolvingNecessary = true; } if (!reResolvingNecessary) { for (const ErrorInfo &e : std::as_const(restoredProject->errorsEncountered)) m_logger.printError(e); for (const ErrorInfo &e : std::as_const(restoredProject->warningsEncountered)) m_logger.printWarning(e); return; } for (const QString &file : m_changedProjectFiles) { m_logger.qbsInfo() << Tr::tr("Project file '%1' has changed.") .arg(QDir::toNativeSeparators(file)); } for (const QString &file : m_removedProjectFiles) { m_logger.qbsInfo() << Tr::tr("Project file '%1' was removed.") .arg(QDir::toNativeSeparators(file)); } restoredProject->buildData->setDirty(); markTransformersForChangeTracking(allRestoredProducts); if (!m_parameters.overrideBuildGraphData()) m_parameters.setEnvironment(restoredProject->environment); ProjectResolver resolver(m_parameters, m_evalContext->engine(), m_logger); resolver.setProgressObserver(m_evalContext->observer()); resolver.setOldProjectProbes(restoredProject->probes); if (!m_parameters.forceProbeExecution()) resolver.setStoredModuleProviderInfo(restoredProject->moduleProviderInfo); resolver.setLastResolveTime(restoredProject->lastStartResolveTime); QHash> restoredProbes; for (const auto &restoredProduct : std::as_const(allRestoredProducts)) restoredProbes.insert(restoredProduct->uniqueName(), restoredProduct->probes); resolver.setOldProductProbes(restoredProbes); if (!m_parameters.overrideBuildGraphData()) resolver.setStoredProfiles(restoredProject->profileConfigs); m_result.newlyResolvedProject = resolver.resolve(); std::vector allNewlyResolvedProducts = m_result.newlyResolvedProject->allProducts(); for (const ResolvedProductPtr &cp : std::as_const(allNewlyResolvedProducts)) m_freshProductsByName.insert(cp->uniqueName(), cp); checkAllProductsForChanges(allRestoredProducts, changedProducts); std::shared_ptr oldBuildData; ChildListHash childLists; if (!changedProducts.empty()) { oldBuildData = std::make_shared(restoredProject->buildData.get()); for (const auto &product : std::as_const(allRestoredProducts)) { if (!product->buildData) continue; // If the product gets temporarily removed, its artifacts will get disconnected // and this structural information will no longer be directly available from them. for (const Artifact *a : filterByType(product->buildData->allNodes())) { childLists.insert(a, ChildrenInfo(ArtifactSet::filtered(a->children), a->childrenAddedByScanner)); } } } makeChangedProductsListComplete(changedProducts, allRestoredProducts); // Set up build data from scratch for all changed products. This does not necessarily // mean that artifacts will have to get rebuilt; whether this is necesessary will be decided // an a per-artifact basis by the Executor on the next build. QHash rescuableArtifactData; for (const ResolvedProductPtr &product : std::as_const(changedProducts)) { const QString name = product->uniqueName(); m_changedSourcesByProduct.erase(name); m_productsWhoseArtifactsNeedUpdate.remove(name); ResolvedProductPtr freshProduct = m_freshProductsByName.value(name); if (!freshProduct) continue; onProductRemoved(product, product->topLevelProject()->buildData.get(), false); if (product->buildData) { rescuableArtifactData.insert(product->uniqueName(), product->buildData->rescuableArtifactData()); } removeOne(allRestoredProducts, product); } // Move over restored build data to newly resolved project. m_result.newlyResolvedProject->buildData.swap(restoredProject->buildData); QBS_CHECK(m_result.newlyResolvedProject->buildData); m_result.newlyResolvedProject->buildData->setDirty(); for (auto it = allNewlyResolvedProducts.begin(); it != allNewlyResolvedProducts.end();) { const ResolvedProductPtr &newlyResolvedProduct = *it; auto k = std::find_if(allRestoredProducts.begin(), allRestoredProducts.end(), [&newlyResolvedProduct](const ResolvedProductPtr &restoredProduct) { return newlyResolvedProduct->uniqueName() == restoredProduct->uniqueName(); }); if (k == allRestoredProducts.end()) { ++it; } else { const ResolvedProductPtr &restoredProduct = *k; if (newlyResolvedProduct->enabled) newlyResolvedProduct->buildData.swap(restoredProduct->buildData); if (newlyResolvedProduct->buildData) updateProductAndRulePointers(newlyResolvedProduct); // Keep in list if build data still needs to be resolved. if (!newlyResolvedProduct->enabled || newlyResolvedProduct->buildData) it = allNewlyResolvedProducts.erase(it); allRestoredProducts.erase(k); } } // Products still left in the list do not exist anymore. for (const ResolvedProductPtr &removedProduct : std::as_const(allRestoredProducts)) { removeOne(changedProducts, removedProduct); onProductRemoved(removedProduct, m_result.newlyResolvedProject->buildData.get()); } // Products still left in the list need resolving, either because they are new // or because they are newly enabled. if (!allNewlyResolvedProducts.empty()) { BuildDataResolver bpr(m_logger, m_parameters); bpr.resolveProductBuildDataForExistingProject(m_result.newlyResolvedProject, allNewlyResolvedProducts); } for (const auto &kv : m_changedSourcesByProduct) { const ResolvedProductPtr product = m_freshProductsByName.value(kv.first); QBS_CHECK(!!product); for (const SourceArtifactConstPtr &sa : kv.second) updateArtifactFromSourceArtifact(product, sa); } for (const QString &productName : m_productsWhoseArtifactsNeedUpdate) { const ResolvedProductPtr product = m_freshProductsByName.value(productName); QBS_CHECK(!!product); updateGeneratedArtifacts(product.get()); } for (const auto &changedProduct : std::as_const(changedProducts)) { rescueOldBuildData(changedProduct, m_freshProductsByName.value(changedProduct->uniqueName()), childLists, rescuableArtifactData.value(changedProduct->uniqueName())); } EmptyDirectoriesRemover(m_result.newlyResolvedProject.get(), m_logger) .removeEmptyParentDirectories(m_artifactsRemovedFromDisk); for (FileResourceBase * const f : std::as_const(m_objectsToDelete)) { if (f->fileType() == FileResourceBase::FileTypeArtifact) static_cast(f)->product.reset(); // To help with the sanity checks. } doSanityChecks(m_result.newlyResolvedProject, m_logger); } bool BuildGraphLoader::probeExecutionForced( const TopLevelProjectConstPtr &restoredProject, const std::vector &restoredProducts) const { if (!m_parameters.forceProbeExecution()) return false; if (!restoredProject->probes.empty()) return true; return Internal::any_of(restoredProducts, [](const auto &p) { return !p->probes.empty(); }); } bool BuildGraphLoader::hasEnvironmentChanged(const TopLevelProjectConstPtr &restoredProject) const { if (!m_parameters.overrideBuildGraphData()) return false; QProcessEnvironment oldEnv = restoredProject->environment; QProcessEnvironment newEnv = m_parameters.adjustedEnvironment(); static const QString ldPreloadEnvVar = QStringLiteral("LD_PRELOAD"); // HACK. Valgrind screws up our null-build benchmarker otherwise. // TODO: Think about a (module-provided) whitelist. oldEnv.remove(ldPreloadEnvVar); newEnv.remove(ldPreloadEnvVar); if (oldEnv != newEnv) { m_logger.qbsInfo() << Tr::tr("Environment changed."); m_logger.qbsDebug() << Tr::tr("old: %1").arg( restoredProject->environment.toStringList().join(QLatin1Char('\n'))); m_logger.qbsDebug() << Tr::tr("new: %2").arg( m_parameters.adjustedEnvironment().toStringList().join(QLatin1Char('\n'))); return true; } return false; } bool BuildGraphLoader::hasCanonicalFilePathResultChanged(const TopLevelProjectConstPtr &restoredProject) const { for (auto it = restoredProject->canonicalFilePathResults.constBegin(); it != restoredProject->canonicalFilePathResults.constEnd(); ++it) { if (QFileInfo(it.key()).canonicalFilePath() != it.value()) { m_logger.qbsInfo() << Tr::tr("Canonical file path for file '%1' changed.") .arg(QDir::toNativeSeparators(it.key())); return true; } } return false; } bool BuildGraphLoader::hasFileExistsResultChanged(const TopLevelProjectConstPtr &restoredProject) const { for (QHash::ConstIterator it = restoredProject->fileExistsResults.constBegin(); it != restoredProject->fileExistsResults.constEnd(); ++it) { if (FileInfo(it.key()).exists() != it.value()) { m_logger.qbsInfo() << Tr::tr("Existence check for file '%1' changed.") .arg(QDir::toNativeSeparators(it.key())); return true; } } return false; } bool BuildGraphLoader::hasDirectoryEntriesResultChanged(const TopLevelProjectConstPtr &restoredProject) const { for (auto it = restoredProject->directoryEntriesResults.constBegin(); it != restoredProject->directoryEntriesResults.constEnd(); ++it) { if (QDir(it.key().first).entryList(static_cast(it.key().second), QDir::Name) != it.value()) { m_logger.qbsInfo() << Tr::tr("Entry list for directory '%1' changed.") .arg(QDir::toNativeSeparators(it.key().first)); return true; } } return false; } bool BuildGraphLoader::hasFileLastModifiedResultChanged(const TopLevelProjectConstPtr &restoredProject) const { for (QHash::ConstIterator it = restoredProject->fileLastModifiedResults.constBegin(); it != restoredProject->fileLastModifiedResults.constEnd(); ++it) { if (FileInfo(it.key()).lastModified() != it.value()) { m_logger.qbsInfo() << Tr::tr("Timestamp for file '%1' has changed.") .arg(QDir::toNativeSeparators(it.key())); return true; } } return false; } bool BuildGraphLoader::hasProductFileChanged(const std::vector &restoredProducts, const FileTime &referenceTime, Set &remainingBuildSystemFiles, std::vector &changedProducts) { bool hasChanged = false; for (const ResolvedProductPtr &product : restoredProducts) { const QString filePath = product->location.filePath(); const FileInfo pfi(filePath); remainingBuildSystemFiles.remove(filePath); if (!pfi.exists()) { m_removedProjectFiles << filePath; hasChanged = true; } else if (referenceTime < pfi.lastModified()) { m_changedProjectFiles << filePath; hasChanged = true; } else if (!contains(changedProducts, product)) { bool foundMissingSourceFile = false; for (const QString &file : std::as_const(product->missingSourceFiles)) { if (FileInfo(file).exists()) { m_logger.qbsInfo() << Tr::tr("Formerly missing file '%1' in product '%2' exists now.") .arg(QDir::toNativeSeparators(filePath), product->fullDisplayName()); foundMissingSourceFile = true; break; } } if (foundMissingSourceFile) { hasChanged = true; changedProducts.push_back(product); continue; } AccumulatingTimer wildcardTimer(m_parameters.logElapsedTime() ? &m_wildcardExpansionEffort : nullptr); for (const GroupPtr &group : product->groups) { if (group->wildcards && group->wildcards->hasChangedSinceExpansion()) { m_logger.qbsInfo() << Tr::tr("Must re-expand wildcards for group '%1' in product '%2'.") .arg(group->name, product->fullDisplayName()); hasChanged = true; changedProducts.push_back(product); break; } } } } return hasChanged; } bool BuildGraphLoader::hasBuildSystemFileChanged(const Set &buildSystemFiles, const TopLevelProject *restoredProject) { for (const QString &file : buildSystemFiles) { const FileInfo fi(file); if (!fi.exists()) { m_removedProjectFiles << file; return true; } const auto generatedChecker = [&file, restoredProject](const auto &item) { const ModuleProviderInfo &mpi = item.second; return file.startsWith(mpi.outputDirPath(restoredProject->buildDirectory)); }; const bool fileWasCreatedByModuleProvider = any_of(restoredProject->moduleProviderInfo.providers, generatedChecker); const FileTime referenceTime = fileWasCreatedByModuleProvider ? restoredProject->lastEndResolveTime : restoredProject->lastStartResolveTime; if (referenceTime < fi.lastModified()) { m_changedProjectFiles << file; return true; } } return false; } void BuildGraphLoader::markTransformersForChangeTracking( const std::vector &restoredProducts) { for (const ResolvedProductPtr &product : restoredProducts) { if (!product->buildData) continue; for (Artifact * const artifact : filterByType(product->buildData->allNodes())) { if (artifact->transformer) { artifact->transformer->prepareScriptNeedsChangeTracking = true; artifact->transformer->commandsNeedChangeTracking = true; } } } } void BuildGraphLoader::checkAllProductsForChanges( const std::vector &restoredProducts, std::vector &changedProducts) { for (const ResolvedProductPtr &restoredProduct : restoredProducts) { const ResolvedProductPtr newlyResolvedProduct = m_freshProductsByName.value(restoredProduct->uniqueName()); if (!newlyResolvedProduct) continue; if (newlyResolvedProduct->enabled != restoredProduct->enabled) { qCDebug(lcBuildGraph) << "Condition of product" << restoredProduct->uniqueName() << "was changed, must set up build data from scratch"; if (!contains(changedProducts, restoredProduct)) changedProducts << restoredProduct; continue; } if (checkProductForChanges(restoredProduct, newlyResolvedProduct)) { qCDebug(lcBuildGraph) << "Product" << restoredProduct->uniqueName() << "was changed, must set up build data from scratch"; if (!contains(changedProducts, restoredProduct)) changedProducts << restoredProduct; continue; } if (checkProductForChangesInSourceFiles(restoredProduct, newlyResolvedProduct)) { qCDebug(lcBuildGraph) << "File list of product" << restoredProduct->uniqueName() << "was changed."; if (!contains(changedProducts, restoredProduct)) changedProducts << restoredProduct; } } } bool BuildGraphLoader::checkProductForChangesInSourceFiles( const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct) { std::vector oldFiles = restoredProduct->allEnabledFiles(); std::vector newFiles = newlyResolvedProduct->allEnabledFiles(); // TODO: Also handle added and removed files in a fine-grained manner. if (oldFiles.size() != newFiles.size()) return true; static const auto cmp = [](const SourceArtifactConstPtr &a1, const SourceArtifactConstPtr &a2) { return a1->absoluteFilePath < a2->absoluteFilePath; }; std::sort(oldFiles.begin(), oldFiles.end(), cmp); std::sort(newFiles.begin(), newFiles.end(), cmp); std::vector changedFiles; for (int i = 0; i < int(oldFiles.size()); ++i) { const SourceArtifactConstPtr &oldFile = oldFiles.at(i); const SourceArtifactConstPtr &newFile = newFiles.at(i); if (oldFile->absoluteFilePath != newFile->absoluteFilePath) return true; if (*oldFile != *newFile) { qCDebug(lcBuildGraph) << "source artifact" << oldFile->absoluteFilePath << "changed"; changedFiles.push_back(newFile); } } if (!changedFiles.empty()) { m_changedSourcesByProduct.insert(std::make_pair(restoredProduct->uniqueName(), changedFiles)); } return false; } static bool dependenciesAreEqual(const ResolvedProductConstPtr &p1, const ResolvedProductConstPtr &p2) { if (p1->dependencies.size() != p2->dependencies.size()) return false; Set names1; Set names2; for (const auto &dep : std::as_const(p1->dependencies)) names1 << dep->uniqueName(); for (const auto &dep : std::as_const(p2->dependencies)) names2 << dep->uniqueName(); return names1 == names2; } bool BuildGraphLoader::checkProductForChanges(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct) { // This check must come first, as it can prevent build data rescuing as a side effect. // TODO: Similar special checks must be done for Environment.getEnv() and File.exists() in // commands (or possibly it could be reasonable to just forbid such "dynamic" constructs // within commands). if (checkForPropertyChanges(restoredProduct, newlyResolvedProduct)) return true; if (!ruleListsAreEqual(restoredProduct->rules, newlyResolvedProduct->rules)) return true; if (!dependenciesAreEqual(restoredProduct, newlyResolvedProduct)) return true; return false; } bool BuildGraphLoader::checkProductForInstallInfoChanges(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct) { // These are not requested from rules at build time, but we still need to take // them into account. const QStringList specialProperties = QStringList() << StringConstants::installProperty() << StringConstants::installDirProperty() << StringConstants::installPrefixProperty() << StringConstants::installRootProperty(); for (const QString &key : specialProperties) { if (!qVariantsEqual( restoredProduct->moduleProperties->qbsPropertyValue(key), newlyResolvedProduct->moduleProperties->qbsPropertyValue(key))) { qCDebug(lcBuildGraph).noquote().nospace() << "Product property 'qbs." << key << "' changed."; return true; } } return false; } bool BuildGraphLoader::checkForPropertyChanges(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct) { AccumulatingTimer propertyComparisonTimer(m_parameters.logElapsedTime() ? &m_propertyComparisonEffort: nullptr); qCDebug(lcBuildGraph) << "Checking for changes in properties requested in prepare scripts for " "product" << restoredProduct->uniqueName(); if (!restoredProduct->buildData) return false; if (restoredProduct->fileTags != newlyResolvedProduct->fileTags) { qCDebug(lcBuildGraph) << "Product type changed from" << restoredProduct->fileTags << "to" << newlyResolvedProduct->fileTags; return true; } if (checkProductForInstallInfoChanges(restoredProduct, newlyResolvedProduct)) return true; if (!artifactPropertyListsAreEqual(restoredProduct->artifactProperties, newlyResolvedProduct->artifactProperties)) { qCDebug(lcBuildGraph) << "a fileTagFilter group changed for product" << restoredProduct->uniqueName(); m_productsWhoseArtifactsNeedUpdate << restoredProduct->uniqueName(); } if (*restoredProduct->moduleProperties != *newlyResolvedProduct->moduleProperties) { qCDebug(lcBuildGraph) << "module properties changed for product" << restoredProduct->uniqueName(); m_productsWhoseArtifactsNeedUpdate << restoredProduct->uniqueName(); } return false; } void BuildGraphLoader::onProductRemoved(const ResolvedProductPtr &product, ProjectBuildData *projectBuildData, bool removeArtifactsFromDisk) { qCDebug(lcBuildGraph) << "product" << product->uniqueName() << "removed."; removeOne(product->project->products, product); if (product->buildData) { for (BuildGraphNode * const node : std::as_const(product->buildData->allNodes())) { if (node->type() == BuildGraphNode::ArtifactNodeType) { const auto artifact = static_cast(node); projectBuildData->removeArtifact(artifact, m_logger, removeArtifactsFromDisk, false); if (removeArtifactsFromDisk && artifact->artifactType == Artifact::Generated) m_artifactsRemovedFromDisk << artifact->filePath(); } else { for (BuildGraphNode * const parent : std::as_const(node->parents)) parent->children.remove(node); node->parents.clear(); for (BuildGraphNode * const child : std::as_const(node->children)) child->parents.remove(node); node->children.clear(); } } } } void BuildGraphLoader::replaceFileDependencyWithArtifact(const ResolvedProductPtr &fileDepProduct, FileDependency *filedep, Artifact *artifact) { qCDebug(lcBuildGraph) << "replace file dependency" << filedep->filePath() << "with artifact of type" << toString(artifact->artifactType); for (const ResolvedProductPtr &product : fileDepProduct->topLevelProject()->allProducts()) { if (!product->buildData) continue; for (Artifact *artifactInProduct : filterByType(product->buildData->allNodes())) { if (artifactInProduct->fileDependencies.remove(filedep)) connect(artifactInProduct, artifact); } } fileDepProduct->topLevelProject()->buildData->fileDependencies.remove(filedep); fileDepProduct->topLevelProject()->buildData->removeFromLookupTable(filedep); m_objectsToDelete << filedep; } bool BuildGraphLoader::checkConfigCompatibility() { const TopLevelProjectConstPtr restoredProject = m_result.loadedProject; if (m_parameters.topLevelProfile().isEmpty()) { m_parameters.setTopLevelProfile(restoredProject->profile()); m_parameters.expandBuildConfiguration(); } if (!m_parameters.overrideBuildGraphData()) { if (!m_parameters.overriddenValues().empty() && !qVariantMapsEqual( m_parameters.overriddenValues(), restoredProject->overriddenValues)) { const auto toUserOutput = [](const QVariantMap &propMap) { QString o; for (auto it = propMap.begin(); it != propMap.end(); ++it) { if (!o.isEmpty()) o += QLatin1Char(' '); o.append(it.key()).append(QLatin1Char(':')).append(toJSLiteral(it.value())); } return o; }; throw ErrorInfo(Tr::tr("Property values set on the command line differ from the " "ones used for the previous build.\n" "Old property values: %1\n" "New property values: %2\n" "Use the 'resolve' command if " "you really want to rebuild with the new properties.") .arg(toUserOutput(restoredProject->overriddenValues), toUserOutput(m_parameters.overriddenValues()))); } m_parameters.setOverriddenValues(restoredProject->overriddenValues); if (m_parameters.topLevelProfile() != restoredProject->profile()) { throw ErrorInfo(Tr::tr("The current profile is '%1', but profile '%2' was used " "when last building for configuration '%3'. Use the " "'resolve' command if you really want to rebuild with a " "different profile.") .arg(m_parameters.topLevelProfile(), restoredProject->profile(), m_parameters.configurationName())); } m_parameters.setTopLevelProfile(restoredProject->profile()); m_parameters.expandBuildConfiguration(); } if (!m_parameters.overrideBuildGraphData()) return true; if (!qVariantMapsEqual( m_parameters.finalBuildConfigurationTree(), restoredProject->buildConfiguration())) return false; Settings settings(m_parameters.settingsDirectory()); const QVariantMap profileConfigsTree = restoredProject->fullProfileConfigsTree(); for (auto it = profileConfigsTree.begin(); it != profileConfigsTree.end(); ++it) { const Profile profile(it.key(), &settings); const QVariantMap buildConfig = SetupProjectParameters::expandedBuildConfiguration( profile, m_parameters.configurationName()); const QVariantMap newConfig = SetupProjectParameters::finalBuildConfigurationTree( buildConfig, m_parameters.overriddenValues()); if (newConfig != it.value()) return false; } return true; } void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct, const ChildListHash &childLists, const AllRescuableArtifactData &existingRad) { QBS_CHECK(newlyResolvedProduct); if (!restoredProduct->buildData) return; if (!newlyResolvedProduct->buildData) newlyResolvedProduct->buildData = std::make_unique(); qCDebug(lcBuildGraph) << "rescue data of product" << restoredProduct->uniqueName(); QBS_CHECK(newlyResolvedProduct->buildData); QBS_CHECK(newlyResolvedProduct->buildData->rescuableArtifactData().empty()); newlyResolvedProduct->buildData->setRescuableArtifactData(existingRad); // This is needed for artifacts created by rules, which happens later in the executor. for (Artifact * const oldArtifact : filterByType(restoredProduct->buildData->allNodes())) { if (!oldArtifact->transformer) continue; Artifact * const newArtifact = lookupArtifact(newlyResolvedProduct, oldArtifact, false); if (!newArtifact) { RescuableArtifactData rad; rad.timeStamp = oldArtifact->timestamp(); rad.knownOutOfDate = oldArtifact->transformer->markedForRerun; rad.fileTags = oldArtifact->fileTags(); rad.properties = oldArtifact->properties; rad.commands = oldArtifact->transformer->commands; rad.propertiesRequestedInPrepareScript = oldArtifact->transformer->propertiesRequestedInPrepareScript; rad.propertiesRequestedInCommands = oldArtifact->transformer->propertiesRequestedInCommands; rad.propertiesRequestedFromArtifactInPrepareScript = oldArtifact->transformer->propertiesRequestedFromArtifactInPrepareScript; rad.propertiesRequestedFromArtifactInCommands = oldArtifact->transformer->propertiesRequestedFromArtifactInCommands; rad.importedFilesUsedInPrepareScript = oldArtifact->transformer->importedFilesUsedInPrepareScript; rad.importedFilesUsedInCommands = oldArtifact->transformer->importedFilesUsedInCommands; rad.depsRequestedInPrepareScript = oldArtifact->transformer->depsRequestedInPrepareScript; rad.depsRequestedInCommands = oldArtifact->transformer->depsRequestedInCommands; rad.artifactsMapRequestedInPrepareScript = oldArtifact->transformer->artifactsMapRequestedInPrepareScript; rad.artifactsMapRequestedInCommands = oldArtifact->transformer->artifactsMapRequestedInCommands; rad.exportedModulesAccessedInPrepareScript = oldArtifact->transformer->exportedModulesAccessedInPrepareScript; rad.exportedModulesAccessedInCommands = oldArtifact->transformer->exportedModulesAccessedInCommands; rad.lastCommandExecutionTime = oldArtifact->transformer->lastCommandExecutionTime; rad.lastPrepareScriptExecutionTime = oldArtifact->transformer->lastPrepareScriptExecutionTime; const ChildrenInfo &childrenInfo = childLists.value(oldArtifact); for (Artifact * const child : std::as_const(childrenInfo.children)) { rad.children.emplace_back(child->product->name, child->product->multiplexConfigurationId, child->filePath(), childrenInfo.childrenAddedByScanner.contains(child)); transform(oldArtifact->fileDependencies, rad.fileDependencies, std::mem_fn(&FileDependency::filePath)); } newlyResolvedProduct->buildData->addRescuableArtifactData(oldArtifact->filePath(), rad); } } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraphloader.h0000644000175100001660000001601614776170045023232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPHLOADER_H #define QBS_BUILDGRAPHLOADER_H #include "forward_decls.h" #include "artifact.h" #include "rescuableartifactdata.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { class FileDependency; class FileResourceBase; class FileTime; class Property; class BuildGraphLoadResult { public: TopLevelProjectPtr newlyResolvedProject; TopLevelProjectPtr loadedProject; }; class BuildGraphLoader { public: BuildGraphLoader(Logger logger); ~BuildGraphLoader(); BuildGraphLoadResult load(const TopLevelProjectPtr &existingProject, const SetupProjectParameters ¶meters, const RulesEvaluationContextPtr &evalContext); static TopLevelProjectConstPtr loadProject(const QString &bgFilePath); private: void loadBuildGraphFromDisk(); bool checkBuildGraphCompatibility(const TopLevelProjectConstPtr &project); void trackProjectChanges(); bool probeExecutionForced(const TopLevelProjectConstPtr &restoredProject, const std::vector &restoredProducts) const; bool hasEnvironmentChanged(const TopLevelProjectConstPtr &restoredProject) const; bool hasCanonicalFilePathResultChanged(const TopLevelProjectConstPtr &restoredProject) const; bool hasFileExistsResultChanged(const TopLevelProjectConstPtr &restoredProject) const; bool hasDirectoryEntriesResultChanged(const TopLevelProjectConstPtr &restoredProject) const; bool hasFileLastModifiedResultChanged(const TopLevelProjectConstPtr &restoredProject) const; bool hasProductFileChanged(const std::vector &restoredProducts, const FileTime &referenceTime, Set &remainingBuildSystemFiles, std::vector &productsWithChangedFiles); bool hasBuildSystemFileChanged(const Set &buildSystemFiles, const TopLevelProject *restoredProject); void markTransformersForChangeTracking(const std::vector &restoredProducts); void checkAllProductsForChanges(const std::vector &restoredProducts, std::vector &changedProducts); bool checkProductForChanges(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct); bool checkProductForChangesInSourceFiles(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct); bool checkProductForInstallInfoChanges(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct); bool checkForPropertyChanges(const ResolvedProductPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct); QVariantMap propertyMapByKind(const ResolvedProductConstPtr &product, const Property &property); void onProductRemoved(const ResolvedProductPtr &product, ProjectBuildData *projectBuildData, bool removeArtifactsFromDisk = true); bool checkForPropertyChanges(const TransformerPtr &restoredTrafo, const ResolvedProductPtr &freshProduct); bool checkForPropertyChange(const Property &restoredProperty, const QVariantMap &newProperties); void replaceFileDependencyWithArtifact(const ResolvedProductPtr &fileDepProduct, FileDependency *filedep, Artifact *artifact); bool checkConfigCompatibility(); struct ChildrenInfo { ChildrenInfo() = default; ChildrenInfo(ArtifactSet c1, ArtifactSet c2) : children(std::move(c1)), childrenAddedByScanner(std::move(c2)) {} ArtifactSet children; ArtifactSet childrenAddedByScanner; }; using ChildListHash = QHash; void rescueOldBuildData(const ResolvedProductConstPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct, const ChildListHash &childLists, const AllRescuableArtifactData &existingRad); QMap m_freshProductsByName; RulesEvaluationContextPtr m_evalContext; SetupProjectParameters m_parameters; BuildGraphLoadResult m_result; Logger m_logger; QStringList m_artifactsRemovedFromDisk; std::unordered_map> m_changedSourcesByProduct; Set m_changedProjectFiles; Set m_removedProjectFiles; Set m_productsWhoseArtifactsNeedUpdate; qint64 m_wildcardExpansionEffort = 0; qint64 m_propertyComparisonEffort = 0; // These must only be deleted at the end so we can still peek into the old look-up table. QList m_objectsToDelete; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/buildgraph/artifact.cpp0000644000175100001660000001352514776170045022054 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "artifact.h" #include "transformer.h" #include "buildgraphvisitor.h" #include "productbuilddata.h" #include "rulenode.h" #include #include #include #include namespace qbs { namespace Internal { Artifact::Artifact() : artifactType(ArtifactType::Unknown), inputsScanned(false), timestampRetrieved(false), alwaysUpdated(false), oldDataPossiblyPresent(true) { } Artifact::~Artifact() { for (Artifact *p : parentArtifacts()) p->childrenAddedByScanner.remove(this); if (m_deregister) m_deregister(this); } void Artifact::accept(BuildGraphVisitor *visitor) { if (visitor->visit(this)) acceptChildren(visitor); visitor->endVisit(this); } QString Artifact::toString() const { return QLatin1String("ARTIFACT ") + filePath() + QLatin1String(" [") + (!product.expired() ? product->name : QLatin1String("")) + QLatin1Char(']'); } void Artifact::addFileTag(const FileTag &t) { m_fileTags += t; if (!product.expired() && product->buildData) { product->buildData->addFileTagToArtifact(this, t); if (product->fileTags.contains(t)) product->buildData->addRootNode(this); } } void Artifact::removeFileTag(const FileTag &t) { m_fileTags -= t; if (!product.expired() && product->buildData) { product->buildData->removeArtifactFromSetByFileTag(this, t); if (product->fileTags.contains(t) && !product->fileTags.intersects(m_fileTags)) product->buildData->removeFromRootNodes(this); } } void Artifact::setFileTags(const FileTags &newFileTags) { if (product.expired() || !product->buildData) { m_fileTags = newFileTags; return; } if (m_fileTags == newFileTags) return; const Set addedTags = newFileTags - m_fileTags; for (const FileTag &t : addedTags) addFileTag(t); const Set removedTags = m_fileTags - newFileTags; for (const FileTag &t : removedTags) removeFileTag(t); } RuleNode *Artifact::producer() const { if (artifactType == SourceFile) return nullptr; const auto ruleNodes = filterByType(children); QBS_CHECK(ruleNodes.begin() != ruleNodes.end()); return *ruleNodes.begin(); } const TypeFilter Artifact::parentArtifacts() const { return TypeFilter(parents); } const TypeFilter Artifact::childArtifacts() const { return TypeFilter(children); } void Artifact::onChildDisconnected(BuildGraphNode *child) { if (child->type() != BuildGraphNode::ArtifactNodeType) return; childrenAddedByScanner.remove(static_cast(child)); } void Artifact::load(PersistentPool &pool) { FileResourceBase::load(pool); BuildGraphNode::load(pool); children.load(pool); // restore parents of the loaded children for (auto it = children.constBegin(); it != children.constEnd(); ++it) (*it)->parents.insert(this); pool.load(childrenAddedByScanner); pool.load(fileDependencies); pool.load(properties); pool.load(targetOfModule); pool.load(transformer); pool.load(m_fileTags); pool.load(pureFileTags); pool.load(pureProperties); artifactType = static_cast(pool.load()); alwaysUpdated = pool.load(); oldDataPossiblyPresent = pool.load(); } void Artifact::store(PersistentPool &pool) { FileResourceBase::store(pool); BuildGraphNode::store(pool); // Do not store parents to avoid recursion. children.store(pool); pool.store(childrenAddedByScanner); pool.store(fileDependencies); pool.store(properties); pool.store(targetOfModule); pool.store(transformer); pool.store(m_fileTags); pool.store(pureFileTags); pool.store(pureProperties); pool.store(static_cast(artifactType)); pool.store(alwaysUpdated); pool.store(oldDataPossiblyPresent); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/productbuilddata.h0000644000175100001660000001126014776170045023250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PRODUCTBUILDDATA_H #define QBS_PRODUCTBUILDDATA_H #include "artifact.h" #include "nodeset.h" #include "rescuableartifactdata.h" #include #include #include #include #include namespace qbs { namespace Internal { class Logger; using ArtifactSetByFileTag = QHash; class QBS_AUTOTEST_EXPORT ProductBuildData { public: ~ProductBuildData(); const TypeFilter rootArtifacts() const; const NodeSet &allNodes() const { return m_nodes; } const NodeSet &rootNodes() const { return m_roots; } void addNode(BuildGraphNode *node) { m_nodes.insert(node); } void addRootNode(BuildGraphNode *node) { m_roots.insert(node); } void removeFromRootNodes(BuildGraphNode *node) { m_roots.remove(node); } void addArtifact(Artifact *artifact); void addArtifactToSet(Artifact *artifact); void removeArtifact(Artifact *artifact); void removeArtifactFromSetByFileTag(Artifact *artifact, const FileTag &fileTag); void addFileTagToArtifact(Artifact *artifact, const FileTag &tag); ArtifactSetByFileTag artifactsByFileTag() const; AllRescuableArtifactData rescuableArtifactData() const { return m_rescuableArtifactData; } void setRescuableArtifactData(const AllRescuableArtifactData &rad); RescuableArtifactData removeFromRescuableArtifactData(const QString &filePath); void addRescuableArtifactData(const QString &filePath, const RescuableArtifactData &rad); unsigned int buildPriority() const { return m_buildPriority; } void setBuildPriority(unsigned int prio) { m_buildPriority = prio; } bool checkAndSetJsArtifactsMapUpToDateFlag(); std::unique_lock getArtifactsMapLock() { return std::unique_lock(m_artifactsMapMutex); } template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_nodes, m_roots, m_rescuableArtifactData, m_artifactsByFileTag); } private: void removeArtifactFromSet(Artifact *artifact); NodeSet m_nodes; NodeSet m_roots; // After change tracking, this is the relevant data of artifacts that were in the build data // of the restored product, and will potentially be re-created by our rules. // If and when that happens, the relevant data will be copied over to the newly created // artifact. AllRescuableArtifactData m_rescuableArtifactData; // Do not store, initialized in executor. Higher prioritized artifacts are built first. unsigned int m_buildPriority = 0; ArtifactSetByFileTag m_artifactsByFileTag; mutable std::mutex m_artifactsMapMutex; bool m_jsArtifactsMapUpToDate = true; }; } // namespace Internal } // namespace qbs #endif // QBS_PRODUCTBUILDDATA_H qbs-src-2.6.1/src/lib/corelib/buildgraph/timestampsupdater.cpp0000644000175100001660000000670714776170045024036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "timestampsupdater.h" #include "artifact.h" #include "artifactvisitor.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include #include #include #include #include namespace qbs { namespace Internal { class TimestampsUpdateVisitor : public ArtifactVisitor { public: TimestampsUpdateVisitor() : ArtifactVisitor(Artifact::Generated), m_now(FileTime::currentTime()) {} void visitProduct(const ResolvedProductConstPtr &product) { QBS_CHECK(product->buildData); ArtifactVisitor::visitProduct(product); // For target artifacts, we have to update the on-disk timestamp, because // the executor will look at it. for (Artifact * const targetArtifact : product->targetArtifacts()) { if (FileInfo(targetArtifact->filePath()).exists()) QFile(targetArtifact->filePath()).open(QIODevice::WriteOnly | QIODevice::Append); } } private: void doVisit(Artifact *artifact) override { if (FileInfo(artifact->filePath()).exists()) artifact->setTimestamp(m_now); } FileTime m_now; }; void TimestampsUpdater::updateTimestamps(const TopLevelProjectPtr &project, const QVector &products, const Logger &logger) { TimestampsUpdateVisitor v; for (const ResolvedProductPtr &product : products) v.visitProduct(product); if (!products.empty()) project->buildData->setDirty(); project->store(logger); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraph.h0000644000175100001660000001200714776170045022037 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPH_H #define QBS_BUILDGRAPH_H #include "forward_decls.h" #include #include #include #include #include namespace qbs { namespace Internal { class BuildGraphNode; class Logger; class ScriptEngine; class PrepareScriptObserver; Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const ProjectBuildData *projectBuildData, const QString &dirPath, const QString &fileName, bool compareByName = false); Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const QString &dirPath, const QString &fileName, bool compareByName = false); Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const ProjectBuildData *buildData, const QString &filePath, bool compareByName = false); Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const QString &filePath, bool compareByName = false); Artifact *lookupArtifact(const ResolvedProductConstPtr &product, const Artifact *artifact, bool compareByName); Artifact *createArtifact(const ResolvedProductPtr &product, const SourceArtifactConstPtr &sourceArtifact); void setArtifactData(Artifact *artifact, const SourceArtifactConstPtr &sourceArtifact); void updateArtifactFromSourceArtifact(const ResolvedProductPtr &product, const SourceArtifactConstPtr &sourceArtifact); void insertArtifact(const ResolvedProductPtr &product, Artifact *artifact); void dumpProductBuildData(const ResolvedProductConstPtr &product); void provideFullFileTagsAndProperties(Artifact *artifact); void applyPerArtifactProperties(Artifact *artifact); void updateGeneratedArtifacts(ResolvedProduct *product); void invalidateArtifactAsRuleInputIfNecessary(Artifact *artifact); bool findPath(BuildGraphNode *u, BuildGraphNode *v, QList &path); void QBS_AUTOTEST_EXPORT connect(BuildGraphNode *p, BuildGraphNode *c); bool safeConnect(Artifact *u, Artifact *v); void removeGeneratedArtifactFromDisk(Artifact *artifact, const Logger &logger); void removeGeneratedArtifactFromDisk(const QString &filePath, const Logger &logger); void disconnect(BuildGraphNode *u, BuildGraphNode *v); void setupScriptEngineForFile(ScriptEngine *engine, const FileContextBaseConstPtr &fileContext, JSValue targetObject, const ObserveMode &observeMode); void setupScriptEngineForProduct(ScriptEngine *engine, ResolvedProduct *product, const ResolvedModule *module, JSValue targetObject, bool setBuildEnvironment); QString relativeArtifactFileName(const Artifact *artifact); // Debugging helpers void doSanityChecks(const ResolvedProjectPtr &project, const Logger &logger); void getPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, const QVariantMap &properties, const QStringList &extraPropertyNames, JSValueConst extraObject); } // namespace Internal } // namespace qbs #endif // QBS_BUILDGRAPH_H qbs-src-2.6.1/src/lib/corelib/buildgraph/artifactsscriptvalue.h0000644000175100001660000000445014776170045024163 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ARTIFACTSSCRIPTVALUE_H #define QBS_ARTIFACTSSCRIPTVALUE_H #include #include namespace qbs { namespace Internal { class ScriptEngine; JSValue artifactsScriptValueForProduct(JSContext *ctx, JSValueConst this_val, int, JSValueConst *); JSValue artifactsScriptValueForModule(JSContext *ctx, JSValueConst this_val, int, JSValueConst *); } // namespace Internal } // namespace qbs #endif // include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/artifactvisitor.cpp0000644000175100001660000000551314776170045023472 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "artifactvisitor.h" #include "artifact.h" #include "productbuilddata.h" #include #include #include namespace qbs { namespace Internal { ArtifactVisitor::ArtifactVisitor(int artifactType) : m_artifactType(artifactType) { } void ArtifactVisitor::visitProduct(const ResolvedProductConstPtr &product) { if (!product->buildData) return; for (BuildGraphNode *node : std::as_const(product->buildData->allNodes())) node->accept(this); } void ArtifactVisitor::visitProject(const ResolvedProjectConstPtr &project) { for (const auto &product : project->allProducts()) visitProduct(product); } bool ArtifactVisitor::visit(RuleNode *ruleNode) { Q_UNUSED(ruleNode); return false; } bool ArtifactVisitor::visit(Artifact *artifact) { QBS_CHECK(artifact); if (m_artifactType & artifact->artifactType) doVisit(artifact); return false; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/rulenode.cpp0000644000175100001660000002765714776170045022107 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rulenode.h" #include "buildgraph.h" #include "buildgraphvisitor.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "rulesapplicator.h" #include "transformer.h" #include "transformerchangetracking.h" #include #include #include #include #include namespace qbs { namespace Internal { RuleNode::RuleNode() = default; RuleNode::~RuleNode() = default; void RuleNode::accept(BuildGraphVisitor *visitor) { if (visitor->visit(this)) acceptChildren(visitor); visitor->endVisit(this); } QString RuleNode::toString() const { return QLatin1String("RULE ") + m_rule->toString() + QLatin1String(" [") + (!product.expired() ? product->name : QLatin1String("")) + QLatin1Char(']') + QLatin1String(" located at ") + m_rule->prepareScript.location().toString(); } RuleNode::ApplicationResult RuleNode::apply( const Logger &logger, const std::unordered_map &productsByName, const std::unordered_map &projectsByName) { ApplicationResult result; ArtifactSet allCompatibleInputs = currentInputArtifacts(); const ArtifactSet explicitlyDependsOn = RulesApplicator::collectExplicitlyDependsOn( m_rule.get(), product.get()); const ArtifactSet addedInputs = allCompatibleInputs - m_oldInputArtifacts; const ArtifactSet removedInputs = m_oldInputArtifacts - allCompatibleInputs; const ArtifactSet changedInputs = changedInputArtifacts( allCompatibleInputs, explicitlyDependsOn); bool upToDate = changedInputs.empty() && addedInputs.empty() && removedInputs.empty(); qCDebug(lcBuildGraph).noquote().nospace() << "consider " << (m_rule->isDynamic() ? "dynamic " : "") << (m_rule->multiplex ? "multiplex " : "") << "rule node " << m_rule->toString() << "\n\tchanged: " << changedInputs.toString() << "\n\tcompatible: " << allCompatibleInputs.toString() << "\n\tadded: " << addedInputs.toString() << "\n\tremoved: " << removedInputs.toString(); ArtifactSet inputs = changedInputs; if (m_rule->multiplex) inputs = allCompatibleInputs; else inputs += addedInputs; for (Artifact * const input : allCompatibleInputs) { for (const Artifact * const output : input->parentArtifacts()) { if (output->transformer->rule != m_rule) continue; if (prepareScriptNeedsRerun(output->transformer.get(), output->transformer->product().get(), productsByName, projectsByName)) { upToDate = false; inputs += input; } break; } if (m_rule->multiplex) break; } // Handle rules without inputs: We want to run such a rule if and only if it has not run yet // or its transformer is not up to date regarding the prepare script. if (upToDate && (!m_rule->declaresInputs() || !m_rule->requiresInputs) && inputs.empty()) { bool hasOutputs = false; for (const Artifact * const output : filterByType(parents)) { if (output->transformer->rule != m_rule) continue; hasOutputs = true; if (prepareScriptNeedsRerun(output->transformer.get(), output->transformer->product().get(), productsByName, projectsByName)) { upToDate = false; break; } if (m_rule->multiplex) break; } if (!hasOutputs) upToDate = false; } if (upToDate) { qCDebug(lcExec) << "rule is up to date. Skipping."; return result; } const bool mustApplyRule = !inputs.empty() || !m_rule->declaresInputs() || !m_rule->requiresInputs; // For a non-multiplex rule, the removal of an input always implies that the // corresponding outputs disappear. // For a multiplex rule, the outputs disappear only if *all* inputs are gone *and* // the rule requires inputs. This is exactly the opposite condition of whether to // re-apply the rule. const bool removedInputForcesOutputRemoval = !m_rule->multiplex || !mustApplyRule; ArtifactSet outputArtifactsToRemove; std::vector> connectionsToBreak; for (Artifact * const artifact : removedInputs) { if (!artifact) // dummy artifact continue; for (Artifact *parent : filterByType(artifact->parents)) { if (parent->transformer->rule != m_rule) { // parent was not created by our rule. continue; } // parent must always have a transformer, because it's generated. QBS_CHECK(parent->transformer); // Artifact is a former input of m_rule and parent was created by m_rule. // The inputs of the transformer must contain artifact, or it is a scanned dependency, // in which case it is not relevant here. if (!parent->transformer->inputs.contains(artifact)) { QBS_CHECK(parent->childrenAddedByScanner.contains(artifact)); continue; } if (removedInputForcesOutputRemoval) outputArtifactsToRemove += parent; else connectionsToBreak.emplace_back(parent, artifact); } disconnect(this, artifact); } for (const auto &connection : connectionsToBreak) disconnect(connection.first, connection.second); if (!outputArtifactsToRemove.empty()) { RulesApplicator::handleRemovedRuleOutputs( inputs, outputArtifactsToRemove, result.removedArtifacts, logger); } if (mustApplyRule) { RulesApplicator applicator(product.lock(), productsByName, projectsByName, logger); applicator.applyRule(this, inputs, explicitlyDependsOn); result.createdArtifacts = applicator.createdArtifacts(); result.invalidatedArtifacts = applicator.invalidatedArtifacts(); m_lastApplicationTime = FileTime::currentTime(); if (applicator.ruleUsesIo()) m_needsToConsiderChangedInputs = true; } else { qCDebug(lcExec).noquote() << "prepare script does not need to run"; } m_oldInputArtifacts = allCompatibleInputs; m_oldExplicitlyDependsOn = explicitlyDependsOn; product->topLevelProject()->buildData->setDirty(); return result; } void RuleNode::load(PersistentPool &pool) { BuildGraphNode::load(pool); serializationOp(pool); } void RuleNode::store(PersistentPool &pool) { BuildGraphNode::store(pool); serializationOp(pool); } int RuleNode::transformerCount() const { Set transformers; for (const Artifact * const output : filterByType(parents)) transformers.insert(output->transformer.get()); return int(transformers.size()); } ArtifactSet RuleNode::currentInputArtifacts() const { ArtifactSet s; for (const FileTag &t : std::as_const(m_rule->inputs)) { for (Artifact *artifact : product->lookupArtifactsByFileTag(t)) { if (artifact->isTargetOfModule()) continue; if (artifact->transformer && artifact->transformer->rule == m_rule) { // Do not add compatible artifacts as inputs that were created by this rule. // This can e.g. happen for the ["cpp", "hpp"] -> ["hpp", "cpp", "unmocable"] rule. continue; } if (artifact->fileTags().intersects(m_rule->excludedInputs)) continue; s += artifact; } } if (m_rule->inputsFromDependencies.empty()) return s; for (const FileTag &t : std::as_const(m_rule->inputsFromDependencies)) { for (Artifact *artifact : product->lookupArtifactsByFileTag(t)) { if (!artifact->isTargetOfModule()) continue; if (artifact->transformer && artifact->transformer->rule == m_rule) continue; if (artifact->fileTags().intersects(m_rule->excludedInputs)) continue; s += artifact; } } for (const auto &dep : std::as_const(product->dependencies)) { if (!dep->buildData) continue; for (Artifact * const a : filterByType(dep->buildData->allNodes())) { if (a->fileTags().intersects(m_rule->inputsFromDependencies) && !a->fileTags().intersects(m_rule->excludedInputs)) s += a; } } return s; } ArtifactSet RuleNode::changedInputArtifacts( const ArtifactSet &allCompatibleInputs, const ArtifactSet &explicitlyDependsOn) const { ArtifactSet changedInputArtifacts; if (explicitlyDependsOn != m_oldExplicitlyDependsOn) return allCompatibleInputs; if (!m_needsToConsiderChangedInputs) return changedInputArtifacts; for (Artifact * const artifact : explicitlyDependsOn) { if (artifact->timestamp() > m_lastApplicationTime) return allCompatibleInputs; } for (Artifact * const artifact : allCompatibleInputs) { if (artifact->timestamp() > m_lastApplicationTime) changedInputArtifacts.insert(artifact); } return changedInputArtifacts; } void RuleNode::removeOldInputArtifact(Artifact *artifact) { if (m_oldInputArtifacts.remove(artifact)) { qCDebug(lcBuildGraph) << "remove old input" << artifact->filePath() << "from rule" << rule()->toString(); m_oldInputArtifacts.insert(nullptr); } if (m_oldExplicitlyDependsOn.remove(artifact)) { qCDebug(lcBuildGraph) << "remove old explicitlyDependsOn" << artifact->filePath() << "from rule" << rule()->toString(); m_oldExplicitlyDependsOn.insert(nullptr); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/inputartifactscanner.h0000644000175100001660000001141314776170045024145 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_INPUTARTIFACTSCANNER_H #define QBS_INPUTARTIFACTSCANNER_H #include #include #include #include #include #include #include class ScannerPlugin; namespace qbs { namespace Internal { class Artifact; class FileResourceBase; class RawScanResult; class RawScanResults; class PropertyMapInternal; class DependencyScanner; using DependencyScannerPtr = std::shared_ptr; class ResolvedDependency { public: bool isValid() const { return !filePath.isNull(); } QString filePath; FileResourceBase *file = nullptr; }; class InputArtifactScannerContext { using ResolvedDependencyCacheItem = std::optional; using ResolvedDependenciesCache = QHash>; struct ScannerKeyCacheData { QStringList searchPaths; ResolvedDependenciesCache resolvedDependenciesCache; }; using ScannerKeyCacheItem = std::optional; using ScannerKeyCache = QHash; QHash cachePerProperties; QHash cachePerFile; using DependencyScannerCacheItem = std::optional>; QHash> scannersCache; friend class InputArtifactScanner; }; class InputArtifactScanner { public: InputArtifactScanner(Artifact *artifact, InputArtifactScannerContext *ctx, Logger logger); void scan(); bool newDependencyAdded() const { return m_newDependencyAdded; } private: void scanForFileDependencies(Artifact *inputArtifact); Set scannersForArtifact(const Artifact *artifact) const; void scanForScannerFileDependencies( DependencyScanner *scanner, Artifact *inputArtifact, FileResourceBase *fileToBeScanned, QList *filesToScan, InputArtifactScannerContext::ScannerKeyCacheItem &cache); void resolveScanResultDependencies( const Artifact *inputArtifact, const RawScanResult &scanResult, QList *artifactsToScan, InputArtifactScannerContext::ScannerKeyCacheData &cache); void handleDependency(ResolvedDependency &dependency); void scanWithScannerPlugin(DependencyScanner *scanner, Artifact *inputArtifact, FileResourceBase *fileToBeScanned, RawScanResult *scanResult); Artifact * const m_artifact; RawScanResults &m_rawScanResults; InputArtifactScannerContext *const m_context; QByteArray m_fileTagsForScanner; bool m_newDependencyAdded; Logger m_logger; }; } // namespace Internal } // namespace qbs #endif // QBS_INPUTARTIFACTSCANNER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/projectbuilddata.h0000644000175100001660000001175614776170045023250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROJECTBUILDDATA_H #define QBS_PROJECTBUILDDATA_H #include "forward_decls.h" #include "rawscanresults.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { class BuildGraphNode; class FileDependency; class FileResourceBase; class ScriptEngine; class QBS_AUTOTEST_EXPORT ProjectBuildData { public: ProjectBuildData(const ProjectBuildData *other = nullptr); ~ProjectBuildData(); static QString deriveBuildGraphFilePath(const QString &buildDir, const QString &projectId); void insertIntoLookupTable(FileResourceBase *fileres); void removeFromLookupTable(FileResourceBase *fileres); const std::vector &lookupFiles(const QString &filePath) const; const std::vector &lookupFiles(const QString &dirPath, const QString &fileName) const; const std::vector &lookupFiles(const Artifact *artifact) const; void insertFileDependency(FileDependency *dependency); void removeArtifactAndExclusiveDependents(Artifact *artifact, const Logger &logger, bool removeFromProduct = true, ArtifactSet *removedArtifacts = nullptr); void removeArtifact(Artifact *artifact, const Logger &logger, bool removeFromDisk = true, bool removeFromProduct = true); void setDirty(); void setClean(); bool isDirty() const { return m_isDirty; } Set fileDependencies; RawScanResults rawScanResults; // do not serialize: RulesEvaluationContextPtr evaluationContext; void load(PersistentPool &pool); void store(PersistentPool &pool); private: template void serializationOp(PersistentPool &pool) { pool.serializationOp(fileDependencies, rawScanResults); } using ArtifactKey = std::pair; using ArtifactLookupTable = std::unordered_map>; ArtifactLookupTable m_artifactLookupTable; bool m_doCleanupInDestructor = true; bool m_isDirty = true; }; class BuildDataResolver { public: BuildDataResolver(Logger logger, const SetupProjectParameters ¶meters); void resolveBuildData(const TopLevelProjectPtr &resolvedProject, const RulesEvaluationContextPtr &evalContext); void resolveProductBuildDataForExistingProject(const TopLevelProjectPtr &project, const std::vector &freshProducts); private: void resolveProductBuildData(const ResolvedProductPtr &product); void connectRulesToDependencies(const ResolvedProductPtr &product, const std::vector &dependencies); RulesEvaluationContextPtr evalContext() const; ScriptEngine *engine() const; JSValue scope() const; TopLevelProjectPtr m_project; Logger m_logger; const SetupProjectParameters &m_parameters; }; } // namespace Internal } // namespace qbs #endif // QBS_PROJECTBUILDDATA_H qbs-src-2.6.1/src/lib/corelib/buildgraph/abstractcommandexecutor.h0000644000175100001660000000733614776170045024650 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ABSTRACTCOMMANDEXECUTOR_H #define QBS_ABSTRACTCOMMANDEXECUTOR_H #include #include #include #include #include namespace qbs { class ErrorInfo; namespace Internal { class AbstractCommand; class ScriptEngine; class Transformer; class AbstractCommandExecutor : public QObject { Q_OBJECT public: explicit AbstractCommandExecutor(Internal::Logger logger, QObject *parent = nullptr); void setMainThreadScriptEngine(ScriptEngine *engine) { m_mainThreadScriptEngine = engine; } void setDryRunEnabled(bool enabled) { m_dryRun = enabled; } void setEchoMode(CommandEchoMode echoMode) { m_echoMode = echoMode; } virtual void cancel(const qbs::ErrorInfo &reason = {}) = 0; void start(Transformer *transformer, AbstractCommand *cmd); signals: void reportCommandDescription(const QString &highlight, const QString &message); void finished(const qbs::ErrorInfo &err = ErrorInfo()); // !hasError() <=> command successful protected: virtual void doReportCommandDescription(const QString &productName); AbstractCommand *command() const { return m_command; } Transformer *transformer() const { return m_transformer; } ScriptEngine *scriptEngine() const { return m_mainThreadScriptEngine; } bool dryRun() const { return m_dryRun; } Internal::Logger logger() const { return m_logger; } CommandEchoMode m_echoMode; private: virtual void doSetup() { }; virtual bool doStart() = 0; void startTimeout(); private: AbstractCommand *m_command; Transformer *m_transformer; ScriptEngine *m_mainThreadScriptEngine; bool m_dryRun; Internal::Logger m_logger; QTimer m_watchdog; }; } // namespace Internal } // namespace qbs #endif // QBS_ABSTRACTCOMMANDEXECUTOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rulesapplicator.h0000644000175100001660000001300714776170045023130 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RULESAPPLICATOR_H #define QBS_RULESAPPLICATOR_H #include "artifact.h" #include "forward_decls.h" #include "nodeset.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class CppModulesScanner; class BuildGraphNode; class QtMocScanner; class ScriptEngine; class RulesApplicator { public: RulesApplicator(ResolvedProductPtr product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName, Logger logger); ~RulesApplicator(); const NodeSet &createdArtifacts() const { return m_createdArtifacts; } const NodeSet &invalidatedArtifacts() const { return m_invalidatedArtifacts; } QStringList removedArtifacts() const { return m_removedArtifacts; } bool ruleUsesIo() const { return m_ruleUsesIo; } void applyRule(RuleNode *ruleNode, const ArtifactSet &inputArtifacts, const ArtifactSet &explicitlyDependsOn); static void handleRemovedRuleOutputs( const ArtifactSet &inputArtifacts, const ArtifactSet &artifactsToRemove, QStringList &removedArtifacts, const Logger &logger); static ArtifactSet collectExplicitlyDependsOn(const Rule *rule, const ResolvedProduct *product); private: enum InputsSources { CurrentProduct, Dependencies }; void doApply(const ArtifactSet &inputArtifacts, JSValue prepareScriptContext); ArtifactSet collectOldOutputArtifacts(const ArtifactSet &inputArtifacts) const; struct OutputArtifactInfo { Artifact *artifact = nullptr; bool newlyCreated = false; FileTags oldFileTags; QVariantMap oldProperties; }; OutputArtifactInfo createOutputArtifactFromRuleArtifact( const RuleArtifactConstPtr &ruleArtifact, const ArtifactSet &inputArtifacts, Set *outputFilePaths); OutputArtifactInfo createOutputArtifact(const QString &filePath, const FileTags &fileTags, bool alwaysUpdated, const ArtifactSet &inputArtifacts); QList runOutputArtifactsScript(const ArtifactSet &inputArtifacts, const JSValueList &args); Artifact *createOutputArtifactFromScriptValue(const JSValue &obj, const ArtifactSet &inputArtifacts); QString resolveOutPath(const QString &path) const; const RulesEvaluationContextPtr &evalContext() const; ScriptEngine *engine() const; JSContext *jsContext() const; JSValue scope() const; static ArtifactSet collectAdditionalInputs(const FileTags &tags, const Rule *rule, const ResolvedProduct *product, InputsSources inputsSources); const ResolvedProductPtr m_product; const std::unordered_map &m_productsByName; const std::unordered_map &m_projectsByName; ArtifactSet m_explicitlyDependsOn; NodeSet m_createdArtifacts; NodeSet m_invalidatedArtifacts; QStringList m_removedArtifacts; RuleNode *m_ruleNode = nullptr; RuleConstPtr m_rule; ArtifactSet m_completeInputSet; TransformerPtr m_transformer; TransformerConstPtr m_oldTransformer; QtMocScanner *m_mocScanner = nullptr; CppModulesScanner *m_cxxModulesScanner = nullptr; Logger m_logger; bool m_ruleUsesIo = false; }; } // namespace Internal } // namespace qbs #endif // QBS_RULESAPPLICATOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/inputartifactscanner.cpp0000644000175100001660000004177714776170045024520 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "inputartifactscanner.h" #include "artifact.h" #include "buildgraph.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "transformer.h" #include "depscanner.h" #include "rulesevaluationcontext.h" #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static void resolveDepencency(const RawScannedDependency &dependency, const ResolvedProduct *product, ResolvedDependency *result, const QString &baseDir = QString()) { QString absDirPath = baseDir.isEmpty() ? dependency.dirPath() : dependency.dirPath().isEmpty() ? baseDir : FileInfo::resolvePath(baseDir, dependency.dirPath()); if (!dependency.isClean()) absDirPath = QDir::cleanPath(absDirPath); ResolvedProject *project = product->project.get(); FileDependency *fileDependencyArtifact = nullptr; Artifact *dependencyInProduct = nullptr; Artifact *dependencyInOtherProduct = nullptr; bool productOfDependencyIsDependency = false; const auto files = project->topLevelProject() ->buildData->lookupFiles(absDirPath, dependency.fileName()); for (FileResourceBase *lookupResult : files) { switch (lookupResult->fileType()) { case FileResourceBase::FileTypeDependency: fileDependencyArtifact = static_cast(lookupResult); break; case FileResourceBase::FileTypeArtifact: { auto const foundArtifact = static_cast(lookupResult); if (foundArtifact->product == product) { dependencyInProduct = foundArtifact; } else if (!productOfDependencyIsDependency) { dependencyInOtherProduct = foundArtifact; productOfDependencyIsDependency = contains(product->dependencies, dependencyInOtherProduct->product.lock()); } break; } } if (dependencyInProduct) break; } // prioritize found artifacts if (dependencyInProduct) result->file = dependencyInProduct; else if (dependencyInOtherProduct) result->file = dependencyInOtherProduct; else result->file = fileDependencyArtifact; if (result->file) { result->filePath = result->file->filePath(); if (result->file == dependencyInOtherProduct && !productOfDependencyIsDependency) { qCDebug(lcDepScan) << "product" << dependencyInOtherProduct->product->fullDisplayName() << "of scanned dependency" << result->filePath << "is not a dependency of product" << product->fullDisplayName() << ". The file dependency might get lost during change tracking."; } return; } const QString &absFilePath = baseDir.isEmpty() ? dependency.filePath() : absDirPath + QLatin1Char('/') + dependency.fileName(); // TODO: We probably need a flag that tells us whether directories are allowed. const FileInfo fi(absFilePath); if (fi.exists(absFilePath) && !fi.isDir()) result->filePath = absFilePath; } InputArtifactScanner::InputArtifactScanner(Artifact *artifact, InputArtifactScannerContext *ctx, Logger logger) : m_artifact(artifact), m_rawScanResults(artifact->product->topLevelProject()->buildData->rawScanResults), m_context(ctx), m_newDependencyAdded(false), m_logger(std::move(logger)) { } void InputArtifactScanner::scan() { if (m_artifact->inputsScanned) return; qCDebug(lcDepScan) << "scan inputs for" << m_artifact->filePath() << m_artifact->fileTags() << "in product" << m_artifact->product->name; m_artifact->inputsScanned = true; // clear file dependencies; they will be regenerated m_artifact->fileDependencies.clear(); // Remove all connections to children that were added by the dependency scanner. // They will be regenerated. const Set childrenAddedByScanner = m_artifact->childrenAddedByScanner; m_artifact->childrenAddedByScanner.clear(); for (Artifact * const dependency : childrenAddedByScanner) disconnect(m_artifact, dependency); for (Artifact * const inputArtifact : std::as_const(m_artifact->transformer->inputs)) scanForFileDependencies(inputArtifact); } void InputArtifactScanner::scanForFileDependencies(Artifact *inputArtifact) { qCDebug(lcDepScan) << "input artifact" << inputArtifact->filePath() << inputArtifact->fileTags(); Set visitedFilePaths; QList filesToScan; filesToScan.push_back(inputArtifact); const Set scanners = scannersForArtifact(inputArtifact); if (scanners.empty()) return; m_fileTagsForScanner = inputArtifact->fileTags().toStringList().join(QLatin1Char(',')).toLatin1(); InputArtifactScannerContext::ScannerKeyCache *lastPerFileCacheItem = nullptr; InputArtifactScannerContext::ScannerKeyCache *lastPerPropsCacheItem = nullptr; while (!filesToScan.empty()) { FileResourceBase *fileToBeScanned = filesToScan.takeFirst(); const QString &filePathToBeScanned = fileToBeScanned->filePath(); if (!visitedFilePaths.insert(filePathToBeScanned).second) continue; for (DependencyScanner * const scanner : scanners) { InputArtifactScannerContext::ScannerKeyCache *cacheItem; if (scanner->cacheIsPerFile()) { if (!lastPerFileCacheItem) lastPerFileCacheItem = &m_context->cachePerFile[inputArtifact]; cacheItem = lastPerFileCacheItem; } else { if (!lastPerPropsCacheItem) { lastPerPropsCacheItem = &m_context->cachePerProperties [inputArtifact->properties]; } cacheItem = lastPerPropsCacheItem; } scanForScannerFileDependencies(scanner, inputArtifact, fileToBeScanned, scanner->recursive() ? &filesToScan : nullptr, (*cacheItem)[scanner->key()]); } } } Set InputArtifactScanner::scannersForArtifact(const Artifact *artifact) const { Set scanners; ResolvedProduct *product = artifact->product.get(); ScriptEngine *engine = product->topLevelProject()->buildData->evaluationContext->engine(); QHash &scannerCache = m_context->scannersCache[product]; for (const FileTag &fileTag : artifact->fileTags()) { InputArtifactScannerContext::DependencyScannerCacheItem &cache = scannerCache[fileTag]; if (!cache) { QList cacheScanners; const auto scanners = ScannerPluginManager::scannersForFileTag(fileTag); transform(scanners, cacheScanners, [](const auto &scanner) { return std::make_shared(scanner); }); for (const ResolvedScannerConstPtr &scanner : product->scanners) { if (scanner->inputs.contains(fileTag)) { cacheScanners.push_back( std::make_shared(scanner, engine)); break; } } cache = std::move(cacheScanners); } for (const DependencyScannerPtr &scanner : std::as_const(*cache)) scanners += scanner.get(); } return scanners; } void InputArtifactScanner::scanForScannerFileDependencies( DependencyScanner *scanner, Artifact *inputArtifact, FileResourceBase *fileToBeScanned, QList *filesToScan, InputArtifactScannerContext::ScannerKeyCacheItem &cache) { qCDebug(lcDepScan) << "file" << fileToBeScanned->filePath(); const bool cacheHit = !!cache; if (!cacheHit) { cache.emplace(); cache->searchPaths = scanner->collectSearchPaths(inputArtifact); } qCDebug(lcDepScan) << "include paths (cache" << (cacheHit ? "hit)" : "miss)"); for (const QString &s : std::as_const(cache->searchPaths)) qCDebug(lcDepScan) << " " << s; const QString &filePathToBeScanned = fileToBeScanned->filePath(); RawScanResults::ScanData &scanData = m_rawScanResults.findScanData(fileToBeScanned, scanner, m_artifact->properties); if (scanData.lastScanTime < fileToBeScanned->timestamp()) { qCDebug(lcDepScan) << "scanning" << FileInfo::fileName(filePathToBeScanned); scanWithScannerPlugin(scanner, inputArtifact, fileToBeScanned, &scanData.rawScanResult); scanData.lastScanTime = FileTime::currentTime(); } resolveScanResultDependencies(inputArtifact, scanData.rawScanResult, filesToScan, *cache); } void InputArtifactScanner::resolveScanResultDependencies( const Artifact *inputArtifact, const RawScanResult &scanResult, QList *artifactsToScan, InputArtifactScannerContext::ScannerKeyCacheData &cache) { auto getResolvedDependency = [inputArtifact, &cache](const RawScannedDependency &dependency) -> ResolvedDependency* { const QString &dependencyFilePath = dependency.filePath(); InputArtifactScannerContext::ResolvedDependencyCacheItem &cachedResolvedDependencyItem = cache.resolvedDependenciesCache[dependency.dirPath()][dependency.fileName()]; if (cachedResolvedDependencyItem) { ResolvedDependency &resolvedDependency = *cachedResolvedDependencyItem; if (resolvedDependency.filePath.isEmpty()) return nullptr; return &resolvedDependency; } ResolvedDependency &resolvedDependency = cachedResolvedDependencyItem.emplace(); if (FileInfo::isAbsolute(dependencyFilePath)) { resolveDepencency(dependency, inputArtifact->product.get(), &resolvedDependency); if (resolvedDependency.filePath.isEmpty()) return nullptr; return &resolvedDependency; } // try include paths for (const QString &includePath : std::as_const(cache.searchPaths)) { resolveDepencency(dependency, inputArtifact->product.get(), &resolvedDependency, includePath); if (resolvedDependency.isValid()) return &resolvedDependency; } return nullptr; }; for (const RawScannedDependency &dependency : scanResult.deps) { const auto maybeResolvedDependency = getResolvedDependency(dependency); if (!maybeResolvedDependency) { qCWarning(lcDepScan) << "unresolved dependency " << dependency.filePath(); continue; } auto &resolvedDependency = *maybeResolvedDependency; handleDependency(resolvedDependency); if (artifactsToScan && resolvedDependency.file) { if (resolvedDependency.file->fileType() == FileResourceBase::FileTypeArtifact) { // Do not scan an artifact that is not built yet: Its contents might still change. auto const artifactDependency = static_cast(resolvedDependency.file); if (artifactDependency->artifactType == Artifact::SourceFile || artifactDependency->buildState == BuildGraphNode::Built) { artifactsToScan->push_back(artifactDependency); } } else { // Add file dependency to the next round of scanning. artifactsToScan->push_back(resolvedDependency.file); } } } } void InputArtifactScanner::handleDependency(ResolvedDependency &dependency) { const ResolvedProductPtr product = m_artifact->product.lock(); QBS_CHECK(m_artifact->artifactType == Artifact::Generated); QBS_CHECK(product); Artifact *artifactDependency = nullptr; FileDependency *fileDependency = nullptr; if (dependency.file) { switch (dependency.file->fileType()) { case FileResourceBase::FileTypeArtifact: artifactDependency = static_cast(dependency.file); break; case FileResourceBase::FileTypeDependency: fileDependency = static_cast(dependency.file); break; } } QBS_CHECK(!dependency.file || artifactDependency || fileDependency); if (!dependency.file) { // The dependency is an existing file but does not exist in the build graph. qCDebug(lcDepScan) << "add new file dependency" << dependency.filePath; fileDependency = new FileDependency(); dependency.file = fileDependency; fileDependency->setFilePath(dependency.filePath); product->topLevelProject()->buildData->insertFileDependency(fileDependency); } else if (fileDependency) { // The dependency exists in the project's list of file dependencies. qCDebug(lcDepScan) << "add existing file dependency" << dependency.filePath; } else if (artifactDependency->product == product) { // The dependency is in our product. qCDebug(lcDepScan) << "add artifact dependency" << dependency.filePath << "(from this product)"; } else { // The dependency is in some other product. ResolvedProduct * const otherProduct = artifactDependency->product; qCDebug(lcDepScan) << "add artifact dependency" << dependency.filePath << " (from product" << otherProduct->uniqueName() << ')'; } if (m_artifact == dependency.file) return; if (artifactDependency && artifactDependency->transformer == m_artifact->transformer) return; if (fileDependency) { m_artifact->fileDependencies << fileDependency; if (!fileDependency->timestamp().isValid()) fileDependency->setTimestamp(FileInfo(fileDependency->filePath()).lastModified()); } else { if (m_artifact->children.contains(artifactDependency)) return; if (safeConnect(m_artifact, artifactDependency)) m_artifact->childrenAddedByScanner += artifactDependency; m_newDependencyAdded = true; } } void InputArtifactScanner::scanWithScannerPlugin(DependencyScanner *scanner, Artifact *inputArtifact, FileResourceBase *fileToBeScanned, RawScanResult *scanResult) { scanResult->deps.clear(); const QStringList &dependencies = scanner->collectDependencies( inputArtifact, fileToBeScanned, m_fileTagsForScanner.constData()); for (const QString &s : dependencies) scanResult->deps.emplace_back(s); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/emptydirectoriesremover.h0000644000175100001660000000520214776170045024710 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_EMPTYDIRECTORIESREMOVER_H #define QBS_EMPTYDIRECTORIESREMOVER_H #include "forward_decls.h" #include #include #include namespace qbs { namespace Internal { class TopLevelProject; class EmptyDirectoriesRemover { public: EmptyDirectoriesRemover(const TopLevelProject *project, Logger logger); void removeEmptyParentDirectories(const QStringList &artifactFilePaths); void removeEmptyParentDirectories(const ArtifactSet &artifacts); private: void insertSorted(const QString &dirPath); void removeDirIfEmpty(); const TopLevelProject * const m_project; Logger m_logger; QStringList m_dirsToRemove; Set m_handledDirs; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/depscanner.cpp0000644000175100001660000002547414776170045022407 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "depscanner.h" #include "artifact.h" #include "projectbuilddata.h" #include "buildgraph.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { QString DependencyScanner::id() const { if (m_id.isEmpty()) m_id = createId(); return m_id; } static QStringList collectCppIncludePaths(const QVariantMap &modules) { QStringList result; const QVariantMap cpp = modules.value(StringConstants::cppModule()).toMap(); if (cpp.empty()) return result; result << cpp.value(QStringLiteral("includePaths")).toStringList(); const bool useSystemHeaders = cpp.value(QStringLiteral("treatSystemHeadersAsDependencies")).toBool(); if (useSystemHeaders) { result << cpp.value(QStringLiteral("systemIncludePaths")).toStringList() << cpp.value(QStringLiteral("distributionIncludePaths")).toStringList() << cpp.value(QStringLiteral("compilerIncludePaths")).toStringList(); } result.removeDuplicates(); return result; } static bool modulesEnabled(const QVariantMap &properties) { const QVariantMap cpp = properties.value(StringConstants::cppModule()).toMap(); if (cpp.empty()) return false; return cpp.value(QStringLiteral("forceUseCxxModules")).toBool(); } static QString getCompiledModuleSuffix(const QVariantMap &modules) { const QVariantMap cpp = modules.value(StringConstants::cppModule()).toMap(); if (cpp.empty()) return {}; return cpp.value(QStringLiteral("compiledModuleSuffix")).toString(); } PluginDependencyScanner::PluginDependencyScanner(ScannerPlugin *plugin) : m_plugin(plugin) { } QStringList PluginDependencyScanner::collectModulesPaths(const ResolvedProduct *product) { QStringList result; if (!product) return result; const auto getModulesPath = [](const ResolvedProduct *product) -> QString { return product->buildDirectory() + QStringLiteral("/cxx-modules"); }; result << getModulesPath(product); // a module can also be in the dependent product for (const auto &dep : product->dependencies) { const auto depProduct = dep.get(); if (depProduct) result << getModulesPath(depProduct); } return result; } QStringList PluginDependencyScanner::collectSearchPaths(Artifact *artifact) { if (m_plugin->flags & ScannerUsesCppIncludePaths) { auto result = collectCppIncludePaths(artifact->properties->value()); if (modulesEnabled(artifact->properties->value()) && artifact->product) { result << collectModulesPaths(artifact->product.get()); } return result; } return {}; } QStringList PluginDependencyScanner::collectDependencies(Artifact *artifact, FileResourceBase *file, const char *fileTags) { Q_UNUSED(artifact); Set result; QString baseDirOfInFilePath = file->dirPath(); const QString &filepath = file->filePath(); void *scannerHandle = m_plugin->open(filepath.utf16(), fileTags, ScanForDependenciesFlag); if (!scannerHandle) return {}; for (;;) { int flags = 0; int length = 0; const char *szOutFilePath = m_plugin->next(scannerHandle, &length, &flags); if (szOutFilePath == nullptr) break; QString outFilePath = QString::fromLocal8Bit(szOutFilePath, length); if (outFilePath.isEmpty()) continue; if (flags & SC_LOCAL_INCLUDE_FLAG) { QString localFilePath = FileInfo::resolvePath(baseDirOfInFilePath, outFilePath); if (FileInfo::exists(localFilePath)) outFilePath = localFilePath; } if (flags & SC_MODULE_FLAG) { outFilePath = outFilePath.replace(QLatin1Char(':'), QLatin1Char('-')) + getCompiledModuleSuffix(artifact->properties->value()); } result += outFilePath; } m_plugin->close(scannerHandle); return rangeTo(result); } bool PluginDependencyScanner::recursive() const { return m_plugin->flags & ScannerRecursiveDependencies; } const void *PluginDependencyScanner::key() const { return m_plugin; } QString PluginDependencyScanner::createId() const { return QString::fromLatin1(m_plugin->name); } bool PluginDependencyScanner::areModulePropertiesCompatible(const PropertyMapConstPtr &m1, const PropertyMapConstPtr &m2) const { // This changes when our C++ scanner starts taking defines into account. Q_UNUSED(m1); Q_UNUSED(m2); return true; } UserDependencyScanner::UserDependencyScanner(ResolvedScannerConstPtr scanner, ScriptEngine *engine) : m_scanner(std::move(scanner)), m_engine(engine), m_global(engine->context(), JS_NewObjectProto(engine->context(), m_engine->globalObject())), m_product(nullptr) { setupScriptEngineForFile(m_engine, m_scanner->scanScript.fileContext(), m_global, ObserveMode::Disabled); // TODO: QBS-1092 } QStringList UserDependencyScanner::collectSearchPaths(Artifact *artifact) { return evaluate(artifact, nullptr, m_scanner->searchPathsScript); } QStringList UserDependencyScanner::collectDependencies(Artifact *artifact, FileResourceBase *file, const char *fileTags) { Q_UNUSED(fileTags); return evaluate(artifact, file, m_scanner->scanScript); } bool UserDependencyScanner::recursive() const { return m_scanner->recursive; } const void *UserDependencyScanner::key() const { return m_scanner.get(); } QString UserDependencyScanner::createId() const { return m_scanner->scanScript.sourceCode(); } bool UserDependencyScanner::areModulePropertiesCompatible(const PropertyMapConstPtr &m1, const PropertyMapConstPtr &m2) const { // TODO: This should probably be made more fine-grained. Perhaps the Scanner item // could declare the relevant properties, or we could figure them out automatically // somehow. return m1 == m2 || *m1 == *m2; } class ScriptEngineActiveFlagGuard { ScriptEngine *m_engine; public: ScriptEngineActiveFlagGuard(ScriptEngine *engine) : m_engine(engine) { m_engine->setActive(true); } ~ScriptEngineActiveFlagGuard() { m_engine->setActive(false); } }; QStringList UserDependencyScanner::evaluate(Artifact *artifact, const FileResourceBase *fileToScan, const PrivateScriptFunction &script) { ScriptEngineActiveFlagGuard guard(m_engine); if (artifact->product.get() != m_product) { m_product = artifact->product.get(); setupScriptEngineForProduct(m_engine, artifact->product.get(), m_scanner->module.get(), m_global, true); } JSValueList args; args.reserve(fileToScan ? 4 : 3); args.push_back(getJsProperty(m_engine->context(), m_global, StringConstants::projectVar())); args.push_back(getJsProperty(m_engine->context(), m_global, StringConstants::productVar())); args.push_back(Transformer::translateFileConfig(m_engine, artifact, m_scanner->module->name)); if (fileToScan) args.push_back(makeJsString(m_engine->context(), fileToScan->filePath())); const ScopedJsValueList argsMgr(m_engine->context(), args); const TemporaryGlobalObjectSetter gos(m_engine, m_global); const JSValue function = script.getFunction(m_engine, Tr::tr("Invalid scan script.")); const ScopedJsValue result( m_engine->context(), JS_Call(m_engine->context(), function, m_engine->globalObject(), int(args.size()), args.data())); m_engine->clearRequestedProperties(); if (JsException ex = m_engine->checkAndClearException(script.location())) { ErrorInfo err = ex.toErrorInfo(); err.prepend(Tr::tr("Error evaluating scan script")); throw err; } QStringList list; if (JS_IsArray(m_engine->context(), result)) { const int count = getJsIntProperty(m_engine->context(), result, StringConstants::lengthProperty()); list.reserve(count); for (qint32 i = 0; i < count; ++i) { JSValue item = JS_GetPropertyUint32(m_engine->context(), result, i); if (!JS_IsUninitialized(item) && !JS_IsUndefined(item)) list.push_back(getJsString(m_engine->context(), item)); JS_FreeValue(m_engine->context(), item); } } return list; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraphnode.cpp0000644000175100001660000000556714776170045023255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "buildgraphnode.h" #include "buildgraphvisitor.h" #include "projectbuilddata.h" #include #include #include #include #include namespace qbs { namespace Internal { BuildGraphNode::BuildGraphNode() : buildState(Untouched) { } BuildGraphNode::~BuildGraphNode() { for (BuildGraphNode *p : std::as_const(parents)) p->children.remove(this); for (BuildGraphNode *c : std::as_const(children)) c->parents.remove(this); } void BuildGraphNode::onChildDisconnected(BuildGraphNode *child) { Q_UNUSED(child); } void BuildGraphNode::acceptChildren(BuildGraphVisitor *visitor) { for (BuildGraphNode *child : std::as_const(children)) child->accept(visitor); } void BuildGraphNode::load(PersistentPool &pool) { serializationOp(pool); } void BuildGraphNode::store(PersistentPool &pool) { serializationOp(pool); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/jscommandexecutor.cpp0000644000175100001660000002433514776170045024012 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "jscommandexecutor.h" #include "buildgraph.h" #include "rulecommands.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { struct JavaScriptCommandResult { bool success = false; QString errorMessage; CodeLocation errorLocation; }; class JsCommandExecutorThreadObject : public QObject { Q_OBJECT public: JsCommandExecutorThreadObject(Logger logger) : m_logger(std::move(logger)) , m_scriptEngine(nullptr) { } const JavaScriptCommandResult &result() const { return m_result; } void cancel(const qbs::ErrorInfo &reason) { QMutexLocker locker(&m_resultMutex); m_result.success = !reason.hasError(); m_result.errorMessage = reason.toString(); if (m_scriptEngine) m_scriptEngine->cancel(); m_cancelled = true; } signals: void finished(); public: void start(const JavaScriptCommand *cmd, Transformer *transformer) { if (m_cancelled) { emit finished(); return; } m_running = true; try { doStart(cmd, transformer); } catch (const qbs::ErrorInfo &error) { setError(error.toString(), cmd->codeLocation()); } m_running = false; emit finished(); } private: void doStart(const JavaScriptCommand *cmd, Transformer *transformer) { m_result.success = true; m_result.errorMessage.clear(); ScriptEngine * const scriptEngine = provideScriptEngine(); JSContext * const ctx = scriptEngine->context(); const ScopedJsValue scope(ctx, JS_NewObject(scriptEngine->context())); setupScriptEngineForFile(scriptEngine, transformer->rule->prepareScript.fileContext(), scope, ObserveMode::Enabled); ScopedJsValue importScopeForSourceCode(ctx, JS_UNDEFINED); if (!cmd->scopeName().isEmpty()) importScopeForSourceCode.setValue(getJsProperty(ctx, scope, cmd->scopeName())); setupScriptEngineForProduct(scriptEngine, transformer->product().get(), transformer->rule->module.get(), scope, true); transformer->setupInputs(scriptEngine, scope); transformer->setupOutputs(scriptEngine, scope); transformer->setupExplicitlyDependsOn(scriptEngine, scope); for (auto it = cmd->properties().constBegin(); it != cmd->properties().constEnd(); ++it) setJsProperty(ctx, scope, it.key(), scriptEngine->toScriptValue(it.value())); const TemporaryGlobalObjectSetter gos(scriptEngine, scope); JSValueList scopeChain; if (JS_IsObject(importScopeForSourceCode)) scopeChain << importScopeForSourceCode; const ScopedJsValue res(ctx, scriptEngine->evaluate(JsValueOwner::Caller, cmd->sourceCode(), {}, 1, scopeChain)); transformer->propertiesRequestedInCommands += scriptEngine->propertiesRequestedInScript(); unite(transformer->propertiesRequestedFromArtifactInCommands, scriptEngine->propertiesRequestedFromArtifact()); const std::vector &importFilesUsedInCommand = scriptEngine->importedFilesUsedInScript(); transformer->importedFilesUsedInCommands.insert( transformer->importedFilesUsedInCommands.cend(), importFilesUsedInCommand.cbegin(), importFilesUsedInCommand.cend()); transformer->depsRequestedInCommands.add(scriptEngine->productsWithRequestedDependencies()); transformer->artifactsMapRequestedInCommands.unite(scriptEngine->requestedArtifacts()); for (const ResolvedProduct * const p : scriptEngine->requestedExports()) { transformer->exportedModulesAccessedInCommands.insert( std::make_pair(p->uniqueName(), p->exportedModule)); } scriptEngine->clearRequestedProperties(); if (const JsException exception = scriptEngine->checkAndClearException(cmd->codeLocation())) { // ### We don't know the line number of the command's sourceCode property assignment. setError(exception.message(), cmd->codeLocation()); } } void setError(const QString &errorMessage, const CodeLocation &codeLocation) { QMutexLocker locker(&m_resultMutex); if (m_cancelled) return; m_result.success = false; m_result.errorMessage = errorMessage; m_result.errorLocation = codeLocation; } ScriptEngine *provideScriptEngine() { if (!m_scriptEngine) m_scriptEngine = ScriptEngine::create(m_logger, EvalContext::JsCommand); else m_scriptEngine->reset(); return m_scriptEngine.get(); } Logger m_logger; std::unique_ptr m_scriptEngine; JavaScriptCommandResult m_result; QMutex m_resultMutex; bool m_running = false; bool m_cancelled = false; }; JsCommandExecutor::JsCommandExecutor(const Logger &logger, QObject *parent) : AbstractCommandExecutor(logger, parent) , m_thread(new QThread(this)) , m_objectInThread(new JsCommandExecutorThreadObject(logger)) , m_running(false) { qRegisterMetaType("Transformer *"); qRegisterMetaType("const JavaScriptCommand *"); m_objectInThread->moveToThread(m_thread); connect(m_objectInThread, &JsCommandExecutorThreadObject::finished, this, &JsCommandExecutor::onJavaScriptCommandFinished); connect(this, &JsCommandExecutor::startRequested, m_objectInThread, &JsCommandExecutorThreadObject::start); } JsCommandExecutor::~JsCommandExecutor() { waitForFinished(); m_thread->quit(); m_thread->wait(); delete m_objectInThread; } void JsCommandExecutor::doReportCommandDescription(const QString &productName) { if ((m_echoMode == CommandEchoModeCommandLine || m_echoMode == CommandEchoModeCommandLineWithEnvironment) && !command()->extendedDescription().isEmpty()) { emit reportCommandDescription(command()->highlight(), command()->extendedDescription()); return; } AbstractCommandExecutor::doReportCommandDescription(productName); } void JsCommandExecutor::waitForFinished() { if (!m_running) return; QEventLoop loop; connect(this, &AbstractCommandExecutor::finished, &loop, &QEventLoop::quit); loop.exec(); } bool JsCommandExecutor::doStart() { QBS_ASSERT(!m_running, return false); if (dryRun() && !command()->ignoreDryRun()) { QTimer::singleShot(0, this, [this] { emit finished(); }); // Don't call back on the caller. return false; } m_thread->start(); m_running = true; emit startRequested(jsCommand(), transformer()); return true; } void JsCommandExecutor::cancel(const qbs::ErrorInfo &reason) { if (m_running && (!dryRun() || command()->ignoreDryRun()) && m_objectInThread) m_objectInThread->cancel(reason); } void JsCommandExecutor::onJavaScriptCommandFinished() { m_running = false; const JavaScriptCommandResult &result = m_objectInThread->result(); ErrorInfo err; if (!result.success) { logger().qbsDebug() << "JS context:\n" << jsCommand()->properties(); logger().qbsDebug() << "JS code:\n" << jsCommand()->sourceCode(); 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); } const JavaScriptCommand *JsCommandExecutor::jsCommand() const { return static_cast(command()); } } // namespace Internal } // namespace qbs #include "jscommandexecutor.moc" qbs-src-2.6.1/src/lib/corelib/buildgraph/executor.h0000644000175100001660000001653614776170045021567 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPHEXECUTOR_H #define QBS_BUILDGRAPHEXECUTOR_H #include "forward_decls.h" #include "buildgraphvisitor.h" #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE namespace qbs { class ProcessResult; namespace Internal { class ExecutorJob; class FileTime; class InputArtifactScannerContext; class ProductInstaller; class ProgressObserver; class RuleNode; class Executor : public QObject, private BuildGraphVisitor { Q_OBJECT public: void build(); Executor(Logger logger, QObject *parent = nullptr); ~Executor() override; void setProject(const TopLevelProjectPtr &project); void setProducts(const QVector &productsToBuild); void setBuildOptions(const BuildOptions &buildOptions); void setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; } ErrorInfo error() const { return m_error; } signals: void reportCommandDescription(const QString &highlight, const QString &message); void reportProcessResult(const qbs::ProcessResult &result); void finished(); private: void setupAuxiliaryProducts(); void onJobFinished(const qbs::ErrorInfo &err); void finish(); void checkForCancellation(); // BuildGraphVisitor implementation bool visit(Artifact *artifact) override; bool visit(RuleNode *ruleNode) override; enum ExecutorState { ExecutorIdle, ExecutorRunning, ExecutorCanceling }; struct ComparePriority { bool operator() (const BuildGraphNode *x, const BuildGraphNode *y) const; }; using Leaves = std::priority_queue, ComparePriority>; void doBuild(); void prepareAllNodes(); void syncFileDependencies(); void prepareArtifact(Artifact *artifact); void setupForBuildingSelectedFiles(const BuildGraphNode *node); void prepareReachableNodes(); void prepareReachableNodes_impl(BuildGraphNode *node); void prepareProducts(); void setupRootNodes(); void initLeaves(); void updateLeaves(const NodeSet &nodes); void updateLeaves(BuildGraphNode *node, NodeSet &seenNodes); bool scheduleJobs(); void buildArtifact(Artifact *artifact); void executeRuleNode(RuleNode *ruleNode); void finishJob(ExecutorJob *job, bool success); void finishNode(BuildGraphNode *leaf); void finishArtifact(Artifact *artifact); void setState(ExecutorState); void addExecutorJobs(); void cancelJobs(); void setupProgressObserver(); void doSanityChecks(); void handleError(const ErrorInfo &error); void rescueOldBuildData(Artifact *artifact, bool *childrenAdded); bool checkForUnbuiltDependencies(Artifact *artifact); void potentiallyRunTransformer(const TransformerPtr &transformer); void runTransformer(const TransformerPtr &transformer); void finishTransformer(const TransformerPtr &transformer); void possiblyInstallArtifact(const Artifact *artifact); void checkForUnbuiltProducts(); bool checkNodeProduct(BuildGraphNode *node); bool mustExecuteTransformer(const TransformerPtr &transformer) const; bool isUpToDate(Artifact *artifact) const; void retrieveSourceFileTimestamp(Artifact *artifact) const; FileTime recursiveFileTime(const QString &filePath) const; QString configString() const; bool transformerHasMatchingOutputTags(const TransformerConstPtr &transformer) const; bool artifactHasMatchingOutputTags(const Artifact *artifact) const; bool transformerHasMatchingInputFiles(const TransformerConstPtr &transformer) const; void setupJobLimits(); void updateJobCounts(const Transformer *transformer, int diff); bool schedulingBlockedByJobLimit(const BuildGraphNode *node); using JobMap = QHash; JobMap m_processingJobs; ProductInstaller *m_productInstaller; RulesEvaluationContextPtr m_evalContext; BuildOptions m_buildOptions; Logger m_logger; ProgressObserver *m_progressObserver; std::vector> m_allJobs; QList m_availableJobs; ExecutorState m_state; TopLevelProjectPtr m_project; QVector m_primaryProducts; QVector m_buildableProducts; std::vector m_allProducts; std::unordered_map m_productsByName; std::unordered_map m_projectsByName; std::unordered_map m_jobCountPerPool; std::unordered_map m_jobLimitsPerProduct; std::unordered_map m_pendingTransformersPerRule; NodeSet m_roots; Leaves m_leaves; InputArtifactScannerContext *m_inputArtifactScanContext; ErrorInfo m_error; bool m_explicitlyCanceled = false; FileTags m_activeFileTags; FileTags m_tagsOfFilesToConsider; FileTags m_tagsNeededForFilesToConsider; QList m_productsOfFilesToConsider; QTimer * const m_cancelationTimer; QStringList m_artifactsRemovedFromDisk; bool m_partialBuild = false; qint64 m_elapsedTimeRules = 0; qint64 m_elapsedTimeScanners = 0; qint64 m_elapsedTimeInstalling = 0; }; } // namespace Internal } // namespace qbs #endif // QBS_BUILDGRAPHEXECUTOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rulegraph.cpp0000644000175100001660000001261714776170045022251 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rulegraph.h" #include #include #include #include namespace qbs { namespace Internal { RuleGraph::RuleGraph() = default; void RuleGraph::build(const std::vector &rules, const FileTags &productFileTags) { QMap > inputFileTagToRule; m_rules.reserve(rules.size()); for (const RulePtr &rule : rules) { for (const FileTag &fileTag : rule->collectedOutputFileTags()) m_outputFileTagToRule[fileTag].push_back(rule.get()); insert(rule); } m_parents.resize(rules.size()); m_children.resize(rules.size()); for (const auto &rule : std::as_const(m_rules)) { FileTags inFileTags = rule->inputs; inFileTags += rule->auxiliaryInputs; inFileTags += rule->explicitlyDependsOn; for (const FileTag &fileTag : std::as_const(inFileTags)) { inputFileTagToRule[fileTag].push_back(rule.get()); for (const Rule * const producingRule : m_outputFileTagToRule.value(fileTag)) { if (!producingRule->collectedOutputFileTags().intersects( rule->excludedInputs)) { connect(rule.get(), producingRule); } } } } QList productRules; for (const FileTag &productFileTag : productFileTags) { QList rules = m_outputFileTagToRule.value(productFileTag); productRules << rules; //### check: the rule graph must be a in valid shape! } for (const Rule *r : std::as_const(productRules)) m_rootRules += r->ruleGraphId; } void RuleGraph::accept(RuleGraphVisitor *visitor) const { const RuleConstPtr nullParent; for (int rootIndex : std::as_const(m_rootRules)) traverse(visitor, nullParent, m_rules.at(rootIndex)); } void RuleGraph::dump() const { QByteArray indent; std::printf("---rule graph dump:\n"); Set rootRules; for (const auto &rule : std::as_const(m_rules)) if (m_parents[rule->ruleGraphId].empty()) rootRules += rule->ruleGraphId; for (int idx : std::as_const(rootRules)) dump_impl(indent, idx); } void RuleGraph::dump_impl(QByteArray &indent, int rootIndex) const { const RuleConstPtr r = m_rules[rootIndex]; std::printf("%s", indent.constData()); std::printf("%s", qPrintable(r->toString())); std::printf("\n"); indent.append(" "); for (int childIndex : std::as_const(m_children[rootIndex])) dump_impl(indent, childIndex); indent.chop(2); } int RuleGraph::insert(const RulePtr &rule) { rule->ruleGraphId = int(m_rules.size()); m_rules.push_back(rule); return rule->ruleGraphId; } void RuleGraph::connect(const Rule *creatingRule, const Rule *consumingRule) { int maxIndex = std::max(creatingRule->ruleGraphId, consumingRule->ruleGraphId); if (static_cast(m_parents.size()) <= maxIndex) { const int c = maxIndex + 1; m_parents.resize(c); m_children.resize(c); } m_parents[consumingRule->ruleGraphId].push_back(creatingRule->ruleGraphId); m_children[creatingRule->ruleGraphId].push_back(consumingRule->ruleGraphId); } void RuleGraph::traverse(RuleGraphVisitor *visitor, const RuleConstPtr &parentRule, const RuleConstPtr &rule) const { visitor->visit(parentRule, rule); for (int childIndex : m_children.at(rule->ruleGraphId)) traverse(visitor, rule, m_rules.at(childIndex)); visitor->endVisit(rule); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/projectbuilddata.cpp0000644000175100001660000004307014776170045023575 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "projectbuilddata.h" #include "artifact.h" #include "buildgraph.h" #include "buildgraphvisitor.h" #include "productbuilddata.h" #include "rulecommands.h" #include "rulegraph.h" #include "rulenode.h" #include "rulesevaluationcontext.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static Set findDependentProducts(const ResolvedProductPtr &product) { Set result; for (const ResolvedProductPtr &parent : product->topLevelProject()->allProducts()) { if (contains(parent->dependencies, product)) result += parent; } return result; } ProjectBuildData::ProjectBuildData(const ProjectBuildData *other) { // This is needed for temporary duplication of build data when doing change tracking. if (other) { *this = *other; m_doCleanupInDestructor = false; } } ProjectBuildData::~ProjectBuildData() { if (!m_doCleanupInDestructor) return; qDeleteAll(fileDependencies); } QString ProjectBuildData::deriveBuildGraphFilePath(const QString &buildDir, const QString &projectId) { return buildDir + QLatin1Char('/') + projectId + QStringLiteral(".bg"); } void ProjectBuildData::insertIntoLookupTable(FileResourceBase *fileres) { auto &lst = m_artifactLookupTable[{fileres->fileName(), fileres->dirPath()}]; const auto * const artifact = fileres->fileType() == FileResourceBase::FileTypeArtifact ? static_cast(fileres) : nullptr; if (artifact && artifact->artifactType == Artifact::Generated) { for (const auto *file : lst) { if (file->fileType() != FileResourceBase::FileTypeArtifact) continue; const auto * const otherArtifact = static_cast(file); ErrorInfo error; error.append(Tr::tr("Conflicting artifacts for file path '%1'.") .arg(artifact->filePath())); error.append(Tr::tr("The first artifact comes from product '%1'.") .arg(otherArtifact->product->fullDisplayName()), otherArtifact->product->location); error.append(Tr::tr("The second artifact comes from product '%1'.") .arg(artifact->product->fullDisplayName()), artifact->product->location); throw error; } } QBS_CHECK(!contains(lst, fileres)); lst.push_back(fileres); m_isDirty = true; } void ProjectBuildData::removeFromLookupTable(FileResourceBase *fileres) { removeOne(m_artifactLookupTable[{fileres->fileName(), fileres->dirPath()}], fileres); } const std::vector &ProjectBuildData::lookupFiles(const QString &filePath) const { QString dirPath, fileName; FileInfo::splitIntoDirectoryAndFileName(filePath, &dirPath, &fileName); return lookupFiles(dirPath, fileName); } const std::vector &ProjectBuildData::lookupFiles(const QString &dirPath, const QString &fileName) const { static const std::vector emptyResult; const auto it = m_artifactLookupTable.find({fileName, dirPath}); return it != m_artifactLookupTable.end() ? it->second : emptyResult; } const std::vector &ProjectBuildData::lookupFiles(const Artifact *artifact) const { return lookupFiles(artifact->dirPath(), artifact->fileName()); } void ProjectBuildData::insertFileDependency(FileDependency *dependency) { fileDependencies += dependency; insertIntoLookupTable(dependency); } static void disconnectArtifactChildren(Artifact *artifact) { qCDebug(lcBuildGraph) << "disconnect children of" << relativeArtifactFileName(artifact); for (BuildGraphNode * const child : std::as_const(artifact->children)) child->parents.remove(artifact); artifact->children.clear(); artifact->childrenAddedByScanner.clear(); } static void disconnectArtifactParents(Artifact *artifact) { qCDebug(lcBuildGraph) << "disconnect parents of" << relativeArtifactFileName(artifact); for (BuildGraphNode * const parent : std::as_const(artifact->parents)) { parent->children.remove(artifact); if (parent->type() != BuildGraphNode::ArtifactNodeType) continue; auto const parentArtifact = static_cast(parent); QBS_CHECK(parentArtifact->transformer); parentArtifact->childrenAddedByScanner.remove(artifact); parentArtifact->transformer->inputs.remove(artifact); parentArtifact->transformer->explicitlyDependsOn.remove(artifact); } artifact->parents.clear(); } static void disconnectArtifact(Artifact *artifact) { disconnectArtifactChildren(artifact); disconnectArtifactParents(artifact); } /*! * Removes the artifact and all the artifacts that depend exclusively on it. * Example: if you remove a cpp artifact then the obj artifact is removed but * not the resulting application (if there's more then one cpp artifact). */ void ProjectBuildData::removeArtifactAndExclusiveDependents(Artifact *artifact, const Logger &logger, bool removeFromProduct, ArtifactSet *removedArtifacts) { if (removedArtifacts) removedArtifacts->insert(artifact); // Iterate over a copy of the artifact's parents, because we'll change // artifact->parents with the disconnect call. const NodeSet parentsCopy = artifact->parents; for (Artifact *parent : filterByType(parentsCopy)) { bool removeParent = false; disconnect(parent, artifact); if (parent->children.empty()) { removeParent = true; } else if (parent->transformer) { parent->transformer->inputs.remove(artifact); removeParent = parent->transformer->inputs.empty(); } if (removeParent) { removeArtifactAndExclusiveDependents(parent, logger, removeFromProduct, removedArtifacts); } else { parent->clearTimestamp(); } } const bool removeFromDisk = artifact->artifactType == Artifact::Generated; removeArtifact(artifact, logger, removeFromDisk, removeFromProduct); } static void removeFromRuleNodes(Artifact *artifact) { for (RuleNode * const ruleNode : filterByType(artifact->parents)) ruleNode->removeOldInputArtifact(artifact); } void ProjectBuildData::removeArtifact(Artifact *artifact, const Logger &logger, bool removeFromDisk, bool removeFromProduct) { qCDebug(lcBuildGraph) << "remove artifact" << relativeArtifactFileName(artifact); if (removeFromDisk) removeGeneratedArtifactFromDisk(artifact, logger); removeFromLookupTable(artifact); removeFromRuleNodes(artifact); disconnectArtifact(artifact); if (artifact->transformer) artifact->transformer->outputs.remove(artifact); if (removeFromProduct) artifact->product->buildData->removeArtifact(artifact); } void ProjectBuildData::setDirty() { qCDebug(lcBuildGraph) << "Marking build graph as dirty"; m_isDirty = true; } void ProjectBuildData::setClean() { qCDebug(lcBuildGraph) << "Marking build graph as clean"; m_isDirty = false; } void ProjectBuildData::load(PersistentPool &pool) { serializationOp(pool); for (FileDependency * const dep : std::as_const(fileDependencies)) insertIntoLookupTable(dep); m_isDirty = false; } void ProjectBuildData::store(PersistentPool &pool) { serializationOp(pool); } BuildDataResolver::BuildDataResolver(Logger logger, const SetupProjectParameters ¶meters) : m_logger(std::move(logger)) , m_parameters(parameters) { } void BuildDataResolver::resolveBuildData(const TopLevelProjectPtr &resolvedProject, const RulesEvaluationContextPtr &evalContext) { QBS_CHECK(!resolvedProject->buildData); m_project = resolvedProject; resolvedProject->buildData = std::make_unique(); resolvedProject->buildData->evaluationContext = evalContext; const std::vector &allProducts = resolvedProject->allProducts(); evalContext->initializeObserver(Tr::tr("Setting up build graph for configuration %1") .arg(resolvedProject->id()), int(allProducts.size()) + 1); for (const auto &rProduct : allProducts) { if (rProduct->enabled) resolveProductBuildData(rProduct); evalContext->incrementProgressValue(); } evalContext->incrementProgressValue(); doSanityChecks(resolvedProject, m_logger); } void BuildDataResolver::resolveProductBuildDataForExistingProject(const TopLevelProjectPtr &project, const std::vector &freshProducts) { m_project = project; for (const ResolvedProductPtr &product : freshProducts) { if (product->enabled) resolveProductBuildData(product); } QHash> dependencyMap; for (const ResolvedProductPtr &product : freshProducts) { if (!product->enabled) continue; QBS_CHECK(product->buildData); const Set dependents = findDependentProducts(product); for (const ResolvedProductPtr &dependentProduct : dependents) { if (!dependentProduct->enabled) continue; if (!contains(dependencyMap[dependentProduct], product)) dependencyMap[dependentProduct].push_back(product); } } for (auto it = dependencyMap.cbegin(); it != dependencyMap.cend(); ++it) { if (!contains(freshProducts, it.key())) connectRulesToDependencies(it.key(), it.value()); } } class CreateRuleNodes : public RuleGraphVisitor { public: CreateRuleNodes(const ResolvedProductPtr &product) : m_product(product) { } private: const ResolvedProductPtr &m_product; QHash m_nodePerRule; Set m_rulesOnPath; QList m_rulePath; void visit(const RuleConstPtr &parentRule, const RuleConstPtr &rule) override { if (!m_rulesOnPath.insert(rule.get()).second) { QString pathstr; for (const Rule *r : std::as_const(m_rulePath)) { pathstr += QLatin1Char('\n') + r->toString() + QLatin1Char('\t') + r->prepareScript.location().toString(); } throw ErrorInfo(Tr::tr("Cycle detected in rule dependencies: %1").arg(pathstr)); } m_rulePath.push_back(rule.get()); RuleNode *node = m_nodePerRule.value(rule); if (!node) { node = new RuleNode; m_nodePerRule.insert(rule, node); node->product = m_product; node->setRule(rule); m_product->buildData->addNode(node); qCDebug(lcBuildGraph).noquote() << "create" << node->toString() << "for product" << m_product->uniqueName(); } if (parentRule) { RuleNode *parent = m_nodePerRule.value(parentRule); QBS_CHECK(parent); connect(parent, node); } else { m_product->buildData->addRootNode(node); } } void endVisit(const RuleConstPtr &rule) override { m_rulesOnPath.remove(rule.get()); m_rulePath.removeLast(); } }; static bool areRulesCompatible(const RuleNode *ruleNode, const RuleNode *dependencyRule) { const FileTags outTags = dependencyRule->rule()->collectedOutputFileTags(); if (ruleNode->rule()->excludedInputs.intersects(outTags)) return false; if (ruleNode->rule()->inputsFromDependencies.intersects(outTags)) return true; if (ruleNode->rule()->explicitlyDependsOnFromDependencies.intersects(outTags)) return true; return ruleNode->rule()->auxiliaryInputsFromDependencies.intersects(outTags); } void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &product) { if (product->buildData) return; evalContext()->checkForCancelation(); product->buildData = std::make_unique(); ArtifactSetByFileTag artifactsPerFileTag; for (const auto &dependency : std::as_const(product->dependencies)) { if (!dependency->enabled) { QBS_CHECK(m_parameters.productErrorMode() == ErrorHandlingMode::Relaxed); continue; } resolveProductBuildData(dependency); } //add qbsFile artifact Artifact *qbsFileArtifact = lookupArtifact(product, product->location.filePath()); if (!qbsFileArtifact) { qbsFileArtifact = new Artifact; qbsFileArtifact->artifactType = Artifact::SourceFile; qbsFileArtifact->setFilePath(product->location.filePath()); qbsFileArtifact->properties = product->moduleProperties; insertArtifact(product, qbsFileArtifact); } qbsFileArtifact->addFileTag("qbs"); artifactsPerFileTag["qbs"].insert(qbsFileArtifact); // read sources for (const auto &sourceArtifact : product->allEnabledFiles()) { QString filePath = sourceArtifact->absoluteFilePath; if (lookupArtifact(product, filePath)) continue; // ignore duplicate artifacts Artifact *artifact = createArtifact(product, sourceArtifact); for (const FileTag &fileTag : artifact->fileTags()) artifactsPerFileTag[fileTag].insert(artifact); } RuleGraph ruleGraph; ruleGraph.build(product->rules, product->fileTags); CreateRuleNodes crn(product); ruleGraph.accept(&crn); connectRulesToDependencies(product, product->dependencies); } static bool isRootRuleNode(RuleNode *ruleNode) { return ruleNode->product->buildData->rootNodes().contains(ruleNode); } void BuildDataResolver::connectRulesToDependencies(const ResolvedProductPtr &product, const std::vector &dependencies) { // Connect the rules of this product to the compatible rules of all product dependencies. // Rules that take "installable" artifacts are connected to all root rules of product // dependencies. std::vector ruleNodes; for (RuleNode *ruleNode : filterByType(product->buildData->allNodes())) ruleNodes.push_back(ruleNode); for (const auto &dep : dependencies) { if (!dep->buildData) continue; for (RuleNode *depRuleNode : filterByType(dep->buildData->allNodes())) { for (RuleNode *ruleNode : ruleNodes) { static const FileTag installableTag("installable"); if (areRulesCompatible(ruleNode, depRuleNode) || ((ruleNode->rule()->inputsFromDependencies.contains(installableTag) || ruleNode->rule()->auxiliaryInputsFromDependencies.contains( installableTag) || ruleNode->rule()->explicitlyDependsOnFromDependencies.contains( installableTag)) && isRootRuleNode(depRuleNode))) { connect(ruleNode, depRuleNode); } } } } } RulesEvaluationContextPtr BuildDataResolver::evalContext() const { return m_project->buildData->evaluationContext; } ScriptEngine *BuildDataResolver::engine() const { return evalContext()->engine(); } JSValue BuildDataResolver::scope() const { return evalContext()->scope(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/requestedartifacts.cpp0000644000175100001660000001701214776170045024154 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "requestedartifacts.h" #include "productbuilddata.h" #include #include #include #include #include #include namespace qbs { namespace Internal { bool RequestedArtifacts::isUpToDate(const TopLevelProject *project) const { if (m_requestedArtifactsPerProduct.empty()) return true; const std::vector &allProducts = project->allProducts(); for (const auto &kv : m_requestedArtifactsPerProduct) { const QString &productName = kv.first; const auto findProduct = [productName](const ResolvedProductConstPtr &p) { return p->uniqueName() == productName; }; const auto productIt = std::find_if(allProducts.begin(), allProducts.end(), findProduct); if (productIt == allProducts.end()) { qCDebug(lcBuildGraph) << "artifacts map not up to date: product" << productName << "does not exist anymore"; return false; } if (!kv.second.isUpToDate(productIt->get())) return false; } return true; } void RequestedArtifacts::setAllArtifactTags(const ResolvedProduct *product, bool forceUpdate) { RequestedArtifactsPerProduct &ra = m_requestedArtifactsPerProduct[product->uniqueName()]; if (!ra.allTags.empty() && !forceUpdate) return; ra.allTags.clear(); const ArtifactSetByFileTag artifactsMap = product->buildData->artifactsByFileTag(); for (auto it = artifactsMap.begin(); it != artifactsMap.end(); ++it) ra.allTags.insert(it.key().toString()); } void RequestedArtifacts::setArtifactsForTag(const ResolvedProduct *product, const FileTag &tag) { RequestedArtifactsPerProduct &ra = m_requestedArtifactsPerProduct[product->uniqueName()]; QBS_ASSERT(!ra.allTags.empty(), ;); Set &filePaths = ra.requestedTags[tag.toString()]; for (const Artifact * const a : product->buildData->artifactsByFileTag().value(tag)) filePaths.insert(a->filePath()); } void RequestedArtifacts::setNonExistingTagRequested(const ResolvedProduct *product, const QString &tag) { RequestedArtifactsPerProduct &ra = m_requestedArtifactsPerProduct[product->uniqueName()]; QBS_ASSERT(!ra.allTags.empty(), ;); Set &filePaths = ra.requestedTags[tag]; QBS_CHECK(filePaths.empty()); } void RequestedArtifacts::setArtifactsEnumerated(const ResolvedProduct *product) { m_requestedArtifactsPerProduct[product->uniqueName()].artifactsEnumerated = true; } void RequestedArtifacts::unite(const RequestedArtifacts &other) { for (const auto &kv : other.m_requestedArtifactsPerProduct) m_requestedArtifactsPerProduct[kv.first].unite(kv.second); } void RequestedArtifacts::doSanityChecks() const { for (const auto &kv : m_requestedArtifactsPerProduct) kv.second.doSanityChecks(); } void RequestedArtifacts::load(PersistentPool &pool) { serializationOp(pool); } void RequestedArtifacts::store(PersistentPool &pool) { serializationOp(pool); } bool RequestedArtifacts::RequestedArtifactsPerProduct::isUpToDate( const ResolvedProduct *product) const { if (!product->buildData) { qCDebug(lcBuildGraph) << "artifacts map not up to date: product" << product->uniqueName() << "is now disabled"; return false; } if (!artifactsEnumerated && requestedTags.empty()) return true; const ArtifactSetByFileTag currentArtifacts = product->buildData->artifactsByFileTag(); for (const auto &kv : requestedTags) { const FileTag tag = FileTag(kv.first.toUtf8()); const auto currentIt = currentArtifacts.constFind(tag); Set currentFilePathsForTag; if (currentIt != currentArtifacts.constEnd()) { for (const Artifact * const a : currentIt.value()) currentFilePathsForTag.insert(a->filePath()); } if (currentFilePathsForTag != kv.second) { qCDebug(lcBuildGraph) << "artifacts map not up to date: requested artifact set for " "file tag" << kv.first << "in product" << product->uniqueName() << "differs from the current one"; return false; } } if (!artifactsEnumerated) return true; Set currentTags; for (auto it = currentArtifacts.begin(); it != currentArtifacts.end(); ++it) currentTags.insert(it.key().toString()); if (currentTags != allTags) { qCDebug(lcBuildGraph) << "artifacts map not up to date: overall file tags differ for " << "product" << product->uniqueName(); return false; } return true; } void RequestedArtifacts::RequestedArtifactsPerProduct::unite( const RequestedArtifactsPerProduct &other) { if (allTags.empty()) { *this = other; return; } allTags = other.allTags; for (const auto &kv : other.requestedTags) requestedTags[kv.first] = kv.second; } void RequestedArtifacts::RequestedArtifactsPerProduct::doSanityChecks() const { for (const auto &kv : requestedTags) QBS_CHECK(allTags.contains(kv.first) || kv.second.empty()); } void RequestedArtifacts::RequestedArtifactsPerProduct::load(PersistentPool &pool) { serializationOp(pool); } void RequestedArtifacts::RequestedArtifactsPerProduct::store(PersistentPool &pool) { serializationOp(pool); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/nodeset.h0000644000175100001660000000776214776170045021373 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_NODESET_H #define QBS_NODESET_H #include #include namespace qbs { namespace Internal { class BuildGraphNode; BuildGraphNode *loadBuildGraphNode(PersistentPool &pool); void storeBuildGraphNode(PersistentPool &pool, const BuildGraphNode *node); using NodeSet = Set; template<> inline BuildGraphNode *NodeSet::loadElem(PersistentPool &pool) { return loadBuildGraphNode(pool); } template<> inline void NodeSet::storeElem(PersistentPool &pool, BuildGraphNode * const &node) const { storeBuildGraphNode(pool, node); } template class TypeFilter { const NodeSet &m_nodes; public: TypeFilter(const NodeSet &nodes) : m_nodes(nodes) { } class const_iterator { const NodeSet &m_nodes; NodeSet::const_iterator m_it; public: using value_type = T*; using difference_type = ptrdiff_t; using pointer = value_type*; using reference = value_type&; using iterator_category = std::forward_iterator_tag; const_iterator(const NodeSet &nodes, const NodeSet::const_iterator &it) : m_nodes(nodes), m_it(it) { while (m_it != m_nodes.constEnd() && !hasDynamicType(*m_it)) ++m_it; } bool operator==(const const_iterator &rhs) const { return m_it == rhs.m_it; } bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } const_iterator &operator++() { for (;;) { ++m_it; if (m_it == m_nodes.constEnd() || hasDynamicType(*m_it)) return *this; } } T *operator*() const { return static_cast(*m_it); } }; const_iterator begin() const { return const_iterator(m_nodes, m_nodes.constBegin()); } const_iterator end() const { return const_iterator(m_nodes, m_nodes.constEnd()); } }; template const TypeFilter filterByType(const NodeSet &nodes) { return TypeFilter(nodes); } } // namespace Internal } // namespace qbs #endif // QBS_NODESET_H qbs-src-2.6.1/src/lib/corelib/buildgraph/dependencyparametersscriptvalue.h0000644000175100001660000000445014776170045026405 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_DEPENDENCYPARAMETERSSCRIPTVALUE_H #define QBS_DEPENDENCYPARAMETERSSCRIPTVALUE_H #include #include namespace qbs { namespace Internal { class ScriptEngine; JSValue dependencyParametersValue(const QString &productName, const QString &dependencyName, const QVariantMap ¶metersMap, ScriptEngine *engine); } // namespace Internal } // namespace qbs #endif // include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/rulesapplicator.cpp0000644000175100001660000007614314776170045023475 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rulesapplicator.h" #include "buildgraph.h" #include "cppmodulesscanner.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "qtmocscanner.h" #include "rulecommands.h" #include "rulenode.h" #include "rulesevaluationcontext.h" #include "transformer.h" #include "transformerchangetracking.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { RulesApplicator::RulesApplicator( ResolvedProductPtr product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName, Logger logger) : m_product(std::move(product)) // m_productsByName and m_projectsByName are references, cannot move-construct , m_productsByName(productsByName) , m_projectsByName(projectsByName) , m_logger(std::move(logger)) {} RulesApplicator::~RulesApplicator() { delete m_mocScanner; delete m_cxxModulesScanner; } void RulesApplicator::applyRule(RuleNode *ruleNode, const ArtifactSet &inputArtifacts, const ArtifactSet &explicitlyDependsOn) { m_ruleNode = ruleNode; m_rule = ruleNode->rule(); QBS_CHECK(!inputArtifacts.empty() || !m_rule->declaresInputs() || !m_rule->requiresInputs); m_product->topLevelProject()->buildData->setDirty(); m_createdArtifacts.clear(); m_invalidatedArtifacts.clear(); m_removedArtifacts.clear(); m_explicitlyDependsOn = explicitlyDependsOn; RulesEvaluationContext::Scope s(evalContext().get()); m_completeInputSet = inputArtifacts; if (m_rule->name.startsWith(QLatin1String("QtCoreMocRule"))) { delete m_mocScanner; m_mocScanner = new QtMocScanner(m_product, engine(), scope()); } if (m_rule->name.startsWith(QLatin1String("cpp_compiler"))) { delete m_cxxModulesScanner; m_cxxModulesScanner = new CppModulesScanner(engine(), scope()); } ScopedJsValue prepareScriptContext(jsContext(), engine()->newObject()); JS_SetPrototype(jsContext(), prepareScriptContext, engine()->globalObject()); setupScriptEngineForFile(engine(), m_rule->prepareScript.fileContext(), scope(), ObserveMode::Enabled); setupScriptEngineForProduct(engine(), m_product.get(), m_rule->module.get(), prepareScriptContext, true); engine()->clearUsesIo(); if (m_rule->multiplex) { // apply the rule once for a set of inputs doApply(inputArtifacts, prepareScriptContext); } else { // apply the rule once for each input for (Artifact * const inputArtifact : inputArtifacts) { ArtifactSet lst; lst += inputArtifact; doApply(lst, prepareScriptContext); } } if (engine()->usesIo()) m_ruleUsesIo = true; engine()->releaseInputArtifactScriptValues(ruleNode); } void RulesApplicator::handleRemovedRuleOutputs(const ArtifactSet &inputArtifacts, const ArtifactSet &outputArtifactsToRemove, QStringList &removedArtifacts, const Logger &logger) { ArtifactSet artifactsToRemove; const TopLevelProject *project = nullptr; for (Artifact * const removedArtifact : outputArtifactsToRemove) { qCDebug(lcBuildGraph).noquote() << "dynamic rule removed output artifact" << removedArtifact->toString(); if (!project) project = removedArtifact->product->topLevelProject(); project->buildData->removeArtifactAndExclusiveDependents(removedArtifact, logger, true, &artifactsToRemove); } for (Artifact * const artifact : std::as_const(artifactsToRemove)) { QBS_CHECK(!inputArtifacts.contains(artifact)); removedArtifacts << artifact->filePath(); delete artifact; } } static void copyProperty(JSContext *ctx, const QString &name, const JSValue &src, JSValue dst) { setJsProperty(ctx, dst, name, getJsProperty(ctx, src, name)); } static QStringList toStringList(const ArtifactSet &artifacts) { QStringList lst; for (const Artifact * const artifact : artifacts) { const QString str = artifact->filePath() + QLatin1String(" [") + artifact->fileTags().toStringList().join(QLatin1String(", ")) + QLatin1Char(']'); lst << str; } return lst; } void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, JSValue prepareScriptContext) { evalContext()->checkForCancelation(); for (const Artifact *inputArtifact : inputArtifacts) QBS_CHECK(!inputArtifact->fileTags().intersects(m_rule->excludedInputs)); qCDebug(lcBuildGraph) << "apply rule" << m_rule->toString() << toStringList(inputArtifacts).join(QLatin1String(",\n ")); std::vector> ruleArtifactArtifactMap; QList outputArtifacts; m_transformer = Transformer::create(); m_transformer->rule = m_rule; m_transformer->inputs = inputArtifacts; m_transformer->explicitlyDependsOn = m_explicitlyDependsOn; m_transformer->alwaysRun = m_rule->alwaysRun; m_oldTransformer.reset(); engine()->clearRequestedProperties(); // create the output artifacts from the set of input artifacts m_transformer->setupInputs(engine(), prepareScriptContext); m_transformer->setupExplicitlyDependsOn(engine(), prepareScriptContext); copyProperty(jsContext(), StringConstants::inputsVar(), prepareScriptContext, scope()); copyProperty(jsContext(), StringConstants::inputVar(), prepareScriptContext, scope()); copyProperty(jsContext(), StringConstants::explicitlyDependsOnVar(), prepareScriptContext, scope()); copyProperty(jsContext(), StringConstants::productVar(), prepareScriptContext, scope()); copyProperty(jsContext(), StringConstants::projectVar(), prepareScriptContext, scope()); if (m_rule->isDynamic()) { const ScopedJsValueList argList = engine()->argumentList(Rule::argumentNamesForOutputArtifacts(), scope()); outputArtifacts = runOutputArtifactsScript(inputArtifacts, argList); } else { Set outputFilePaths; for (const auto &ruleArtifact : m_rule->artifacts) { const OutputArtifactInfo &outputInfo = createOutputArtifactFromRuleArtifact( ruleArtifact, inputArtifacts, &outputFilePaths); if (!outputInfo.artifact) continue; outputArtifacts.push_back(outputInfo.artifact); ruleArtifactArtifactMap.emplace_back(ruleArtifact.get(), outputInfo); } if (m_rule->artifacts.empty()) { outputArtifacts.push_back(createOutputArtifactFromRuleArtifact( nullptr, inputArtifacts, &outputFilePaths).artifact); } } const auto newOutputs = rangeTo(outputArtifacts); const ArtifactSet oldOutputs = collectOldOutputArtifacts(inputArtifacts); handleRemovedRuleOutputs(m_completeInputSet, oldOutputs - newOutputs, m_removedArtifacts, m_logger); // The inputs become children of the rule node. Generated artifacts in the same product // already are children, because output artifacts become children of the producing // rule node's parent rule node. for (Artifact * const input : inputArtifacts) { if (input->artifactType == Artifact::SourceFile || input->product != m_ruleNode->product || input->producer()->rule()->collectedOutputFileTags().intersects( m_ruleNode->rule()->excludedInputs)) { connect(m_ruleNode, input); } else { QBS_CHECK(m_ruleNode->children.contains(input)); } } if (outputArtifacts.empty()) return; for (Artifact * const outputArtifact : std::as_const(outputArtifacts)) { for (Artifact * const dependency : std::as_const(m_transformer->explicitlyDependsOn)) connect(outputArtifact, dependency); } if (inputArtifacts != m_transformer->inputs) m_transformer->setupInputs(engine(), prepareScriptContext); // change the transformer outputs according to the bindings in Artifact if (!ruleArtifactArtifactMap.empty()) { const TemporaryGlobalObjectSetter gos(engine(), prepareScriptContext); for (auto it = ruleArtifactArtifactMap.crbegin(), end = ruleArtifactArtifactMap.crend(); it != end; ++it) { const RuleArtifact *ra = it->first; if (ra->bindings.empty()) continue; // expose attributes of this artifact const OutputArtifactInfo &outputInfo = it->second; Artifact *outputArtifact = outputInfo.artifact; outputArtifact->properties = outputArtifact->properties->clone(); setJsProperty(jsContext(), scope(), StringConstants::fileNameProperty(), engine()->toScriptValue(outputArtifact->filePath())); setJsProperty(jsContext(), scope(), StringConstants::fileTagsProperty(), makeJsStringList(engine()->context(), outputArtifact->fileTags().toStringList())); QVariantMap artifactModulesCfg = outputArtifact->properties->value(); for (const auto &binding : ra->bindings) { const ScopedJsValue scriptValue(jsContext(), engine()->evaluate( JsValueOwner::Caller, binding.code, binding.location.filePath(), binding.location.line())); if (JsException ex = engine()->checkAndClearException(binding.location)) { ErrorInfo err = ex.toErrorInfo(); err.prepend(QStringLiteral("evaluating rule binding '%1'") .arg(binding.name.join(QLatin1Char('.')))); throw err; } const QVariant value = getJsVariant(jsContext(), scriptValue); setConfigProperty(artifactModulesCfg, binding.name, value); outputArtifact->pureProperties.emplace_back(binding.name, value); } outputArtifact->properties->setValue(artifactModulesCfg); if (!outputInfo.newlyCreated && (outputArtifact->fileTags() != outputInfo.oldFileTags || !qVariantMapsEqual( outputArtifact->properties->value(), outputInfo.oldProperties))) { invalidateArtifactAsRuleInputIfNecessary(outputArtifact); } } } m_transformer->setupOutputs(engine(), prepareScriptContext); const ScopedJsValueList argList = engine()->argumentList(Rule::argumentNamesForPrepare(), prepareScriptContext); m_transformer->createCommands(engine(), m_rule->prepareScript, argList); if (Q_UNLIKELY(m_transformer->commands.empty())) throw ErrorInfo(Tr::tr("There is a rule without commands: %1.") .arg(m_rule->toString()), m_rule->prepareScript.location()); if (!m_oldTransformer || m_oldTransformer->outputs != m_transformer->outputs || m_oldTransformer->inputs != m_transformer->inputs || m_oldTransformer->explicitlyDependsOn != m_transformer->explicitlyDependsOn || m_oldTransformer->commands != m_transformer->commands || commandsNeedRerun(m_transformer.get(), m_product.get(), m_productsByName, m_projectsByName)) { for (Artifact * const output : std::as_const(outputArtifacts)) { output->clearTimestamp(); m_invalidatedArtifacts += output; } } m_transformer->commandsNeedChangeTracking = false; } ArtifactSet RulesApplicator::collectOldOutputArtifacts(const ArtifactSet &inputArtifacts) const { ArtifactSet result; for (Artifact * const a : inputArtifacts) { for (Artifact *p : a->parentArtifacts()) { QBS_CHECK(p->transformer); if (p->transformer->rule == m_rule && p->transformer->inputs.contains(a)) result += p; } } return result; } ArtifactSet RulesApplicator::collectAdditionalInputs(const FileTags &tags, const Rule *rule, const ResolvedProduct *product, InputsSources inputsSources) { ArtifactSet artifacts; for (const FileTag &fileTag : tags) { for (Artifact *dependency : product->lookupArtifactsByFileTag(fileTag)) { // Skip excluded inputs. if (dependency->fileTags().intersects(rule->excludedInputs)) continue; // Two cases are considered: // 1) An artifact is considered a dependency when it's part of the current product. // 2) An artifact marked with filesAreTargets: true inside a Group inside of a // Module also ends up in the results returned by product->lookupArtifactsByFileTag, // so it should be considered conceptually as a "dependent product artifact". if ((inputsSources == CurrentProduct && !dependency->isTargetOfModule()) || (inputsSources == Dependencies && dependency->isTargetOfModule())) { artifacts << dependency; } } if (inputsSources == Dependencies) { for (const auto &depProduct : product->dependencies) { for (Artifact * const ta : filterByType(depProduct->buildData->allNodes())) { if (ta->fileTags().contains(fileTag) && !ta->fileTags().intersects(rule->excludedInputs)) { artifacts << ta; } } } } } return artifacts; } ArtifactSet RulesApplicator::collectExplicitlyDependsOn(const Rule *rule, const ResolvedProduct *product) { ArtifactSet first = collectAdditionalInputs( rule->explicitlyDependsOn, rule, product, CurrentProduct); ArtifactSet second = collectAdditionalInputs( rule->explicitlyDependsOnFromDependencies, rule, product, Dependencies); return first.unite(second); } RulesApplicator::OutputArtifactInfo RulesApplicator::createOutputArtifactFromRuleArtifact( const RuleArtifactConstPtr &ruleArtifact, const ArtifactSet &inputArtifacts, Set *outputFilePaths) { QString outputPath; FileTags fileTags; bool alwaysUpdated; if (ruleArtifact) { const ScopedJsValue scriptValue( jsContext(), engine()->evaluate(JsValueOwner::Caller, ruleArtifact->filePath, ruleArtifact->filePathLocation.filePath(), ruleArtifact->filePathLocation.line())); if (JsException ex = engine()->checkAndClearException(ruleArtifact->filePathLocation)) throw ex.toErrorInfo(); outputPath = getJsString(jsContext(), scriptValue); fileTags = ruleArtifact->fileTags; alwaysUpdated = ruleArtifact->alwaysUpdated; } else { outputPath = QStringLiteral("__dummyoutput__"); QByteArray hashInput = m_rule->toString().toLatin1(); for (const Artifact * const input : inputArtifacts) hashInput += input->filePath().toLatin1(); outputPath += QLatin1String(QCryptographicHash::hash(hashInput, QCryptographicHash::Sha1) .toHex().left(16)); fileTags = m_rule->outputFileTags; alwaysUpdated = false; } outputPath = FileInfo::resolvePath(m_product->buildDirectory(), outputPath); if (Q_UNLIKELY(!outputFilePaths->insert(outputPath).second)) { throw ErrorInfo(Tr::tr("Rule %1 already created '%2'.") .arg(m_rule->toString(), outputPath)); } return createOutputArtifact(outputPath, fileTags, alwaysUpdated, inputArtifacts); } RulesApplicator::OutputArtifactInfo RulesApplicator::createOutputArtifact(const QString &filePath, const FileTags &fileTags, bool alwaysUpdated, const ArtifactSet &inputArtifacts) { const QString outputPath = resolveOutPath(filePath); if (m_rule->isDynamic()) { const Set undeclaredTags = fileTags - m_rule->collectedOutputFileTags(); if (!undeclaredTags.empty()) { throw ErrorInfo(Tr::tr("Artifact '%1' has undeclared file tags [\"%2\"].") .arg(outputPath, undeclaredTags.toStringList() .join(QLatin1String("\",\""))), m_rule->prepareScript.location()); } } OutputArtifactInfo outputInfo; Artifact *& outputArtifact = outputInfo.artifact; outputArtifact = lookupArtifact(m_product, outputPath); outputInfo.newlyCreated = !outputArtifact; if (outputArtifact) { const Transformer * const transformer = outputArtifact->transformer.get(); if (transformer && transformer->rule != m_rule) { QString e = Tr::tr("Conflicting rules for producing %1 %2 \n") .arg(outputArtifact->filePath(), QLatin1Char('[') + outputArtifact->fileTags().toStringList().join(QLatin1String(", ")) + QLatin1Char(']')); QString str = QLatin1Char('[') + m_rule->inputs.toStringList().join(QLatin1String(", ")) + QLatin1String("] -> [") + outputArtifact->fileTags().toStringList() .join(QLatin1String(", ")) + QLatin1Char(']'); e += QStringLiteral(" while trying to apply: %1:%2:%3 %4\n") .arg(m_rule->prepareScript.location().filePath()) .arg(m_rule->prepareScript.location().line()) .arg(m_rule->prepareScript.location().column()) .arg(str); e += QStringLiteral(" was already defined in: %1:%2:%3 %4\n") .arg(transformer->rule->prepareScript.location().filePath()) .arg(transformer->rule->prepareScript.location().line()) .arg(transformer->rule->prepareScript.location().column()) .arg(str); throw ErrorInfo(e); } if (transformer && !m_rule->multiplex && transformer->inputs != inputArtifacts) { QBS_CHECK(inputArtifacts.size() == 1); QBS_CHECK(transformer->inputs.size() == 1); ErrorInfo error(Tr::tr("Conflicting instances of rule '%1':").arg(m_rule->toString()), m_rule->prepareScript.location()); error.append(Tr::tr("Output artifact '%1' is to be produced from input " "artifacts '%2' and '%3', but the rule is not a multiplex rule.") .arg(outputArtifact->filePath(), (*transformer->inputs.cbegin())->filePath(), (*inputArtifacts.cbegin())->filePath())); throw error; } m_transformer->rescueChangeTrackingData(outputArtifact->transformer); m_oldTransformer = outputArtifact->transformer; outputInfo.oldFileTags = outputArtifact->fileTags(); outputInfo.oldProperties = outputArtifact->properties->value(); } else { std::unique_ptr newArtifact(new Artifact); newArtifact->artifactType = Artifact::Generated; newArtifact->setFilePath(outputPath); insertArtifact(m_product, newArtifact.get()); m_createdArtifacts += newArtifact.get(); outputArtifact = newArtifact.release(); qCDebug(lcExec).noquote() << "rule created" << outputArtifact->toString(); connect(outputArtifact, m_ruleNode); } outputArtifact->alwaysUpdated = alwaysUpdated; outputArtifact->pureFileTags = fileTags; provideFullFileTagsAndProperties(outputArtifact); if (outputInfo.newlyCreated || outputInfo.oldFileTags != outputArtifact->fileTags()) { for (RuleNode * const parentRule : filterByType(m_ruleNode->parents)) connect(parentRule, outputArtifact); } for (Artifact * const inputArtifact : inputArtifacts) { QBS_CHECK(outputArtifact != inputArtifact); connect(outputArtifact, inputArtifact); } outputArtifact->transformer = m_transformer; m_transformer->outputs.insert(outputArtifact); QBS_CHECK(m_rule->multiplex || m_transformer->inputs.size() == 1); return outputInfo; } class RuleOutputArtifactsException : public ErrorInfo { public: using ErrorInfo::ErrorInfo; }; QList RulesApplicator::runOutputArtifactsScript(const ArtifactSet &inputArtifacts, const JSValueList &args) { QList lst; const ScopedJsValue fun(jsContext(), engine()->evaluate(JsValueOwner::Caller, m_rule->outputArtifactsScript.sourceCode(), m_rule->outputArtifactsScript.location().filePath(), m_rule->outputArtifactsScript.location().line())); if (!JS_IsFunction(jsContext(), fun)) throw ErrorInfo(QStringLiteral("Function expected."), m_rule->outputArtifactsScript.location()); JSValueList argv(args.begin(), args.end()); const ScopedJsValue res( jsContext(), JS_Call(jsContext(), fun, engine()->globalObject(), int(args.size()), argv.data())); if (JsException ex = engine()->checkAndClearException(m_rule->outputArtifactsScript.location())) throw ex.toErrorInfo(); if (!JS_IsArray(jsContext(), res)) throw ErrorInfo(Tr::tr("Rule.outputArtifacts must return an array of objects."), m_rule->outputArtifactsScript.location()); const quint32 c = getJsIntProperty(jsContext(), res, StringConstants::lengthProperty()); for (quint32 i = 0; i < c; ++i) { try { ScopedJsValue val(engine()->context(), JS_GetPropertyUint32(jsContext(), res, i)); lst.push_back(createOutputArtifactFromScriptValue(val, inputArtifacts)); } catch (const RuleOutputArtifactsException &roae) { ErrorInfo ei = roae; ei.prepend(Tr::tr("Error in Rule.outputArtifacts[%1]").arg(i), m_rule->outputArtifactsScript.location()); throw ei; } } return lst; } class ArtifactBindingsExtractor { struct Entry { Entry(QString module, QString name, QVariant value) : module(std::move(module)), name(std::move(name)), value(std::move(value)) {} QString module; QString name; QVariant value; }; ScriptEngine *m_engine = nullptr; JSContext *m_ctx = nullptr; std::vector m_propertyValues; static Set getArtifactItemPropertyNames() { Set s; const auto properties = BuiltinDeclarations::instance().declarationsForType( ItemType::Artifact).properties(); for (const PropertyDeclaration &pd : properties) { s.insert(pd.name()); } s.insert(StringConstants::explicitlyDependsOnProperty()); return s; } void extractPropertyValues(const JSValue &obj, const QString &moduleName = QString()) { handleJsProperties(m_ctx, obj, [&](const JSAtom &prop, const JSPropertyDescriptor &desc) { const QString name = getJsString(m_ctx, prop); if (moduleName.isEmpty()) { // Ignore property names that are part of the Artifact item. static const Set artifactItemPropertyNames = getArtifactItemPropertyNames(); if (artifactItemPropertyNames.contains(name)) return; } const JSValue value = desc.value; if (JS_IsObject(value) && !JS_IsArray(m_ctx, value) && !JS_IsError(m_ctx, value) && !JS_IsRegExp(m_ctx, value)) { QString newModuleName; if (!moduleName.isEmpty()) newModuleName.append(moduleName + QLatin1Char('.')); newModuleName.append(name); extractPropertyValues(value, newModuleName); } else { m_propertyValues.emplace_back(moduleName, name, getJsVariant(m_ctx, value)); } }); } public: void apply(ScriptEngine *engine, Artifact *outputArtifact, const JSValue &obj) { m_engine = engine; m_ctx = m_engine->context(); extractPropertyValues(obj); if (m_propertyValues.empty()) return; outputArtifact->properties = outputArtifact->properties->clone(); QVariantMap artifactCfg = outputArtifact->properties->value(); for (const auto &e : m_propertyValues) { const QStringList key{e.module, e.name}; setConfigProperty(artifactCfg, key, e.value); outputArtifact->pureProperties.emplace_back(key, e.value); } outputArtifact->properties->setValue(artifactCfg); } }; Artifact *RulesApplicator::createOutputArtifactFromScriptValue(const JSValue &obj, const ArtifactSet &inputArtifacts) { if (!JS_IsObject(obj)) { throw ErrorInfo(Tr::tr("Elements of the Rule.outputArtifacts array must be " "of Object type."), m_rule->outputArtifactsScript.location()); } QString unresolvedFilePath; const ScopedJsValue jsFilePath(jsContext(), getJsProperty(jsContext(), obj, StringConstants::filePathProperty())); if (JS_IsString(jsFilePath)) unresolvedFilePath = getJsString(jsContext(), jsFilePath); if (unresolvedFilePath.isEmpty()) { throw RuleOutputArtifactsException( Tr::tr("Property filePath must be a non-empty string.")); } const QString filePath = FileInfo::resolvePath(m_product->buildDirectory(), unresolvedFilePath); const FileTags fileTags = FileTags::fromStringList( getJsStringListProperty(jsContext(), obj, StringConstants::fileTagsProperty())); const QVariant alwaysUpdatedVar = getJsVariantProperty(jsContext(), obj, StringConstants::alwaysUpdatedProperty()); const bool alwaysUpdated = alwaysUpdatedVar.isValid() ? alwaysUpdatedVar.toBool() : true; OutputArtifactInfo outputInfo = createOutputArtifact(filePath, fileTags, alwaysUpdated, inputArtifacts); if (outputInfo.artifact->fileTags().empty()) { // Check the file tags after file taggers were run. throw RuleOutputArtifactsException( Tr::tr("Property fileTags for artifact '%1' must be a non-empty string list. " "Alternatively, a FileTagger can be provided.") .arg(unresolvedFilePath)); } const FileTags explicitlyDependsOn = FileTags::fromStringList(getJsStringListProperty( jsContext(), obj, StringConstants::explicitlyDependsOnProperty())); for (const FileTag &tag : explicitlyDependsOn) { for (Artifact * const dependency : m_product->lookupArtifactsByFileTag(tag)) connect(outputInfo.artifact, dependency); } ArtifactBindingsExtractor().apply(engine(), outputInfo.artifact, obj); if (!outputInfo.newlyCreated && (outputInfo.artifact->fileTags() != outputInfo.oldFileTags || !qVariantMapsEqual( outputInfo.artifact->properties->value(), outputInfo.oldProperties))) { invalidateArtifactAsRuleInputIfNecessary(outputInfo.artifact); } return outputInfo.artifact; } QString RulesApplicator::resolveOutPath(const QString &path) const { const QString buildDir = m_product->topLevelProject()->buildDirectory; QString result = QDir::cleanPath(FileInfo::resolvePath(buildDir, path)); if (!result.startsWith(buildDir + QLatin1Char('/'))) { throw ErrorInfo( Tr::tr("Refusing to create artifact '%1' outside of build directory '%2'.") .arg(QDir::toNativeSeparators(result), QDir::toNativeSeparators(buildDir)), m_rule->prepareScript.location()); } return result; } const RulesEvaluationContextPtr &RulesApplicator::evalContext() const { return m_product->topLevelProject()->buildData->evaluationContext; } ScriptEngine *RulesApplicator::engine() const { return evalContext()->engine(); } JSContext *RulesApplicator::jsContext() const { return engine()->context(); } JSValue RulesApplicator::scope() const { return evalContext()->scope(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/transformerchangetracking.cpp0000644000175100001660000003603414776170045025512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "transformerchangetracking.h" #include "projectbuilddata.h" #include "requesteddependencies.h" #include "rulecommands.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class TrafoChangeTracker { public: TrafoChangeTracker(const Transformer *transformer, const ResolvedProduct *product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName) : m_transformer(transformer), m_product(product), m_productsByName(productsByName), m_projectsByName(projectsByName) { } bool prepareScriptNeedsRerun() const; bool commandsNeedRerun() const; private: QVariantMap propertyMapByKind(const Property &property) const; bool checkForPropertyChange(const Property &restoredProperty, const QVariantMap &newProperties) const; bool checkForImportFileChange(const std::vector &importedFiles, const FileTime &referenceTime, const char *context) const; bool isExportedModuleUpToDate(const QString &productName, const ExportedModule &module) const; bool areExportedModulesUpToDate( const std::unordered_map &exportedModules) const; const Artifact *getArtifact(const QString &filePath, const QString &productName) const; const ResolvedProduct *getProduct(const QString &name) const; const Transformer * const m_transformer; const ResolvedProduct * const m_product; const std::unordered_map &m_productsByName; const std::unordered_map &m_projectsByName; mutable const ResolvedProduct * m_lastProduct = nullptr; mutable const Artifact *m_lastArtifact = nullptr; }; template static QVariantMap getParameterValue( const QHash ¶meters, const QString &depName) { for (auto it = parameters.cbegin(); it != parameters.cend(); ++it) { if (it.key()->name == depName) return it.value(); } return {}; } QVariantMap TrafoChangeTracker::propertyMapByKind(const Property &property) const { switch (property.kind) { case Property::PropertyInModule: { const ResolvedProduct * const p = getProduct(property.productName); return p ? p->moduleProperties->value() : QVariantMap(); } case Property::PropertyInProduct: { const ResolvedProduct * const p = getProduct(property.productName); return p ? p->productProperties : QVariantMap(); } case Property::PropertyInProject: { if (property.productName == m_product->project->name) return m_product->project->projectProperties(); const auto it = m_projectsByName.find(property.productName); if (it != m_projectsByName.cend()) return it->second->projectProperties(); return {}; } case Property::PropertyInParameters: { const int sepIndex = property.moduleName.indexOf(QLatin1Char(':')); const QString depName = property.moduleName.left(sepIndex); const ResolvedProduct * const p = getProduct(property.productName); if (!p) return {}; QVariantMap v = getParameterValue(p->dependencyParameters, depName); if (!v.empty()) return v; return getParameterValue(p->moduleParameters, depName); } case Property::PropertyInArtifact: default: QBS_CHECK(false); } return {}; } bool TrafoChangeTracker::checkForPropertyChange(const Property &restoredProperty, const QVariantMap &newProperties) const { QVariant v; switch (restoredProperty.kind) { case Property::PropertyInProduct: case Property::PropertyInProject: v = newProperties.value(restoredProperty.propertyName); break; case Property::PropertyInModule: v = moduleProperty(newProperties, restoredProperty.moduleName, restoredProperty.propertyName); break; case Property::PropertyInParameters: { const int sepIndex = restoredProperty.moduleName.indexOf(QLatin1Char(':')); QualifiedId moduleName = QualifiedId::fromString(restoredProperty.moduleName.mid(sepIndex + 1)); QVariantMap map = newProperties; while (!moduleName.empty()) map = map.value(moduleName.takeFirst()).toMap(); v = map.value(restoredProperty.propertyName); break; } case Property::PropertyInArtifact: QBS_CHECK(false); } if (!qVariantsEqual(restoredProperty.value, v)) { qCDebug(lcBuildGraph).noquote().nospace() << "Value for property '" << restoredProperty.moduleName << "." << restoredProperty.propertyName << "' has changed.\n" << "Old value was '" << restoredProperty.value << "'.\n" << "New value is '" << v << "'."; return true; } return false; } bool TrafoChangeTracker::checkForImportFileChange(const std::vector &importedFiles, const FileTime &referenceTime, const char *context) const { for (const QString &importedFile : importedFiles) { const FileInfo fi(importedFile); if (!fi.exists()) { qCDebug(lcBuildGraph) << context << "imported file" << importedFile << "is gone, need to re-run"; return true; } if (fi.lastModified() > referenceTime) { qCDebug(lcBuildGraph) << context << "imported file" << importedFile << "has been updated, need to re-run" << fi.lastModified() << referenceTime; return true; } } return false; } bool TrafoChangeTracker::isExportedModuleUpToDate(const QString &productName, const ExportedModule &module) const { const ResolvedProduct * const product = getProduct(productName); if (!product) { qCDebug(lcBuildGraph) << "product" << productName << "does not exist anymore, need to re-run"; return false; } if (product->exportedModule != module) { qCDebug(lcBuildGraph) << "exported module has changed for product" << productName << ", need to re-run"; return false; } return true; } bool TrafoChangeTracker::areExportedModulesUpToDate( const std::unordered_map &exportedModules) const { return Internal::all_of(exportedModules, [this](const auto &kv) { return isExportedModuleUpToDate(kv.first, kv.second); }); } const Artifact *TrafoChangeTracker::getArtifact(const QString &filePath, const QString &productName) const { if (m_lastArtifact && m_lastArtifact->filePath() == filePath && m_lastArtifact->product.get()->uniqueName() == productName) { return m_lastArtifact; } const ResolvedProduct * const product = getProduct(productName); if (!product) return nullptr; const auto &candidates = product->topLevelProject()->buildData->lookupFiles(filePath); const Artifact *artifact = nullptr; for (const FileResourceBase * const candidate : candidates) { if (candidate->fileType() == FileResourceBase::FileTypeArtifact) { auto const a = static_cast(candidate); if (a->product.get() == product) { m_lastArtifact = artifact = a; break; } } } return artifact; } const ResolvedProduct *TrafoChangeTracker::getProduct(const QString &name) const { if (m_lastProduct && name == m_lastProduct->uniqueName()) return m_lastProduct; if (name == m_product->uniqueName()) { m_lastProduct = m_product; return m_product; } const auto it = m_productsByName.find(name); if (it != m_productsByName.cend()) { m_lastProduct = it->second; return it->second; } return nullptr; } bool TrafoChangeTracker::prepareScriptNeedsRerun() const { for (const Property &property : std::as_const(m_transformer->propertiesRequestedInPrepareScript)) { if (checkForPropertyChange(property, propertyMapByKind(property))) return true; } if (checkForImportFileChange(m_transformer->importedFilesUsedInPrepareScript, m_transformer->lastPrepareScriptExecutionTime, "prepare script")) { return true; } for (auto it = m_transformer->propertiesRequestedFromArtifactInPrepareScript.constBegin(); it != m_transformer->propertiesRequestedFromArtifactInPrepareScript.constEnd(); ++it) { for (const Property &property : std::as_const(it.value())) { const Artifact * const artifact = getArtifact(it.key(), property.productName); if (!artifact) return true; if (property.kind == Property::PropertyInArtifact) { if (sorted(artifact->fileTags().toStringList()) != property.value.toStringList()) return true; continue; } if (checkForPropertyChange(property, artifact->properties->value())) return true; } } if (!m_transformer->depsRequestedInPrepareScript.isUpToDate(m_product->topLevelProject())) return true; if (!m_transformer->artifactsMapRequestedInPrepareScript.isUpToDate( m_product->topLevelProject())) { return true; } if (!areExportedModulesUpToDate(m_transformer->exportedModulesAccessedInPrepareScript)) return true; return false; } bool TrafoChangeTracker::commandsNeedRerun() const { for (const Property &property : std::as_const(m_transformer->propertiesRequestedInCommands)) { if (checkForPropertyChange(property, propertyMapByKind(property))) return true; } for (auto it = m_transformer->propertiesRequestedFromArtifactInCommands.cbegin(); it != m_transformer->propertiesRequestedFromArtifactInCommands.cend(); ++it) { for (const Property &property : std::as_const(it.value())) { const Artifact * const artifact = getArtifact(it.key(), property.productName); if (!artifact) return true; if (property.kind == Property::PropertyInArtifact) { if (sorted(artifact->fileTags().toStringList()) != property.value.toStringList()) return true; continue; } if (checkForPropertyChange(property, artifact->properties->value())) return true; } } if (checkForImportFileChange(m_transformer->importedFilesUsedInCommands, m_transformer->lastCommandExecutionTime, "command")) { return true; } if (!m_transformer->depsRequestedInCommands.isUpToDate(m_product->topLevelProject())) return true; if (!m_transformer->artifactsMapRequestedInCommands.isUpToDate(m_product->topLevelProject())) return true; if (!areExportedModulesUpToDate(m_transformer->exportedModulesAccessedInCommands)) return true; // TODO: Also track env access in JS commands and prepare scripts for (const AbstractCommandPtr &c : std::as_const(m_transformer->commands.commands())) { if (c->type() != AbstractCommand::ProcessCommandType) continue; const ProcessCommandPtr &processCmd = std::static_pointer_cast(c); const auto envVars = processCmd->relevantEnvVars(); for (const QString &var : envVars) { const QString &oldValue = processCmd->relevantEnvValue(var); const QString &newValue = m_product->buildEnvironment.value(var); if (oldValue != newValue) { qCDebug(lcBuildGraph) << "need to re-run command: value of environment variable" << var << "changed from" << oldValue << "to" << newValue << "for command" << processCmd->program() << "in rule" << m_transformer->rule->toString(); return true; } } } return false; } bool prepareScriptNeedsRerun( Transformer *transformer, const ResolvedProduct *product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName) { if (!transformer->prepareScriptNeedsChangeTracking) return false; transformer->prepareScriptNeedsChangeTracking = false; return TrafoChangeTracker(transformer, product, productsByName, projectsByName) .prepareScriptNeedsRerun(); } bool commandsNeedRerun(Transformer *transformer, const ResolvedProduct *product, const std::unordered_map &productsByName, const std::unordered_map &projectsByName) { if (!transformer->commandsNeedChangeTracking) return false; transformer->commandsNeedChangeTracking = false; return TrafoChangeTracker(transformer, product, productsByName, projectsByName) .commandsNeedRerun(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/qtmocscanner.cpp0000644000175100001660000002364114776170045022754 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtmocscanner.h" #include "artifact.h" #include "depscanner.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "rawscanresults.h" #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { struct CommonFileTags { const FileTag cpp = "cpp"; const FileTag cppCombine = "cpp.combine"; const FileTag hpp = "hpp"; const FileTag moc_cpp = "moc_cpp"; const FileTag moc_cpp_plugin = "moc_cpp_plugin"; const FileTag moc_hpp_plugin = "moc_hpp_plugin"; const FileTag moc_hpp = "moc_hpp"; const FileTag objcpp = "objcpp"; const FileTag objcppCombine = "objcpp.combine"; }; Q_GLOBAL_STATIC(CommonFileTags, commonFileTags) static QString qtMocScannerJsName() { return QStringLiteral("QtMocScanner"); } QtMocScanner::QtMocScanner(const ResolvedProductPtr &product, ScriptEngine *engine, JSValue targetScriptValue) : m_engine(engine) , m_tags(*commonFileTags()) , m_product(product) , m_targetScriptValue(JS_DupValue(engine->context(), targetScriptValue)) { JSValue scannerObj = JS_NewObjectClass(engine->context(), engine->dataWithPtrClass()); attachPointerTo(scannerObj, this); setJsProperty(engine->context(), targetScriptValue, qtMocScannerJsName(), scannerObj); JSValue applyFunction = JS_NewCFunction(engine->context(), &js_apply, "QtMocScanner", 1); setJsProperty(engine->context(), scannerObj, std::string_view("apply"), applyFunction); } QtMocScanner::~QtMocScanner() { setJsProperty(m_engine->context(), m_targetScriptValue, qtMocScannerJsName(), JS_UNDEFINED); JS_FreeValue(m_engine->context(), m_targetScriptValue); } static RawScanResult runScannerForArtifact(const Artifact *artifact) { const QString &filepath = artifact->filePath(); RawScanResults &rawScanResults = artifact->product->topLevelProject()->buildData->rawScanResults; auto predicate = [](const PropertyMapConstPtr &, const PropertyMapConstPtr &) { return true; }; RawScanResults::ScanData &scanData = rawScanResults.findScanData( artifact, qtMocScannerJsName(), artifact->properties, predicate); if (scanData.lastScanTime < artifact->timestamp()) { FileTags tags = artifact->fileTags(); if (tags.contains(commonFileTags->cppCombine)) { tags.remove(commonFileTags->cppCombine); tags.insert(commonFileTags->cpp); } if (tags.contains(commonFileTags->objcppCombine)) { tags.remove(commonFileTags->objcppCombine); tags.insert(commonFileTags->objcpp); } const QByteArray tagsForScanner = tags.toStringList().join(QLatin1Char(',')).toLatin1(); CppScannerContext context; const bool ok = scanCppFile( context, filepath, {tagsForScanner.data(), size_t(tagsForScanner.size())}, true, true); if (!ok) return scanData.rawScanResult; scanData.rawScanResult.additionalFileTags.clear(); scanData.rawScanResult.deps.clear(); for (const auto tag : additionalFileTags(context)) scanData.rawScanResult.additionalFileTags += FileTag(tag.data()); QString baseDirOfInFilePath = artifact->dirPath(); for (const auto &scanResult : context.includedFiles) { int flags = scanResult.flags; QString includedFilePath = QString::fromLocal8Bit( scanResult.fileName.data(), scanResult.fileName.size()); if (includedFilePath.isEmpty()) continue; bool isLocalInclude = (flags & SC_LOCAL_INCLUDE_FLAG); if (isLocalInclude) { QString localFilePath = FileInfo::resolvePath(baseDirOfInFilePath, includedFilePath); if (FileInfo::exists(localFilePath)) includedFilePath = localFilePath; } scanData.rawScanResult.deps.emplace_back(includedFilePath); } scanData.lastScanTime = FileTime::currentTime(); } return scanData.rawScanResult; } void QtMocScanner::findIncludedMocCppFiles() { if (!m_includedMocCppFiles.empty()) return; qCDebug(lcMocScan) << "looking for included moc_XXX.cpp files"; static const FileTags mocCppTags = {m_tags.cpp, m_tags.objcpp}; for (Artifact *artifact : m_product->lookupArtifactsByFileTags(mocCppTags)) { const RawScanResult scanResult = runScannerForArtifact(artifact); for (const RawScannedDependency &dependency : scanResult.deps) { QString includedFileName = dependency.fileName(); if (includedFileName.startsWith(QLatin1String("moc_")) && includedFileName.endsWith(QLatin1String(".cpp"))) { qCDebug(lcMocScan) << artifact->fileName() << "includes" << includedFileName; includedFileName.remove(0, 4); includedFileName.chop(4); m_includedMocCppFiles.insert(includedFileName, artifact->fileName()); } } } } JSValue QtMocScanner::js_apply(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { if (argc < 1) return throwError(ctx, Tr::tr("QtMocScanner.apply() requires an argument.")); ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto scanner = attachedPointer(this_val, engine->dataWithPtrClass()); return scanner->apply(engine, attachedPointer(argv[0], engine->dataWithPtrClass())); } JSValue QtMocScanner::apply(ScriptEngine *engine, const Artifact *artifact) { qCDebug(lcMocScan).noquote() << "scanning" << artifact->toString(); bool hasQObjectMacro = false; bool mustCompile = false; bool hasPluginMetaDataMacro = false; const bool isHeaderFile = artifact->fileTags().contains(m_tags.hpp); RawScanResult scanResult = runScannerForArtifact(artifact); if (scanResult.additionalFileTags.empty() && artifact->fileTags().contains("mocable")) { if (isHeaderFile) { scanResult.additionalFileTags.insert(m_tags.moc_hpp); } else if (artifact->fileTags().contains(m_tags.cpp) || artifact->fileTags().contains(m_tags.cppCombine) || artifact->fileTags().contains(m_tags.objcpp) || artifact->fileTags().contains(m_tags.objcppCombine)) { scanResult.additionalFileTags.insert(m_tags.moc_cpp); } } if (!scanResult.additionalFileTags.empty()) { if (isHeaderFile) { if (scanResult.additionalFileTags.contains(m_tags.moc_hpp)) hasQObjectMacro = true; if (scanResult.additionalFileTags.contains(m_tags.moc_hpp_plugin)) { hasQObjectMacro = true; hasPluginMetaDataMacro = true; } findIncludedMocCppFiles(); if (!m_includedMocCppFiles.contains(FileInfo::completeBaseName(artifact->fileName()))) mustCompile = true; } else { if (scanResult.additionalFileTags.contains(m_tags.moc_cpp)) hasQObjectMacro = true; if (scanResult.additionalFileTags.contains(m_tags.moc_cpp_plugin)) { hasQObjectMacro = true; hasPluginMetaDataMacro = true; } } } qCDebug(lcMocScan) << "hasQObjectMacro:" << hasQObjectMacro << "mustCompile:" << mustCompile << "hasPluginMetaDataMacro:" << hasPluginMetaDataMacro; JSValue obj = engine->newObject(); JSContext * const ctx = m_engine->context(); setJsProperty(ctx, obj, std::string_view("hasQObjectMacro"), JS_NewBool(ctx, hasQObjectMacro)); setJsProperty(ctx, obj, std::string_view("mustCompile"), JS_NewBool(ctx, mustCompile)); setJsProperty( ctx, obj, std::string_view("hasPluginMetaDataMacro"), JS_NewBool(ctx, hasPluginMetaDataMacro)); engine->setUsesIo(); return obj; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/depscanner.h0000644000175100001660000001130314776170045022036 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_DEPENDENCY_SCANNER_H #define QBS_DEPENDENCY_SCANNER_H #include #include #include #include #include #include class ScannerPlugin; namespace qbs { namespace Internal { class Artifact; class FileResourceBase; class Logger; class ScriptEngine; class DependencyScanner { public: virtual ~DependencyScanner() = default; QString id() const; virtual QStringList collectSearchPaths(Artifact *artifact) = 0; virtual QStringList collectDependencies(Artifact *artifact, FileResourceBase *file, const char *fileTags) = 0; virtual bool recursive() const = 0; virtual const void *key() const = 0; virtual bool areModulePropertiesCompatible(const PropertyMapConstPtr &m1, const PropertyMapConstPtr &m2) const = 0; virtual bool cacheIsPerFile() const = 0; private: virtual QString createId() const = 0; mutable QString m_id; }; class PluginDependencyScanner : public DependencyScanner { public: PluginDependencyScanner(ScannerPlugin *plugin); private: QStringList collectModulesPaths(const ResolvedProduct *product); QStringList collectSearchPaths(Artifact *artifact) override; QStringList collectDependencies(Artifact *artifact, FileResourceBase *file, const char *fileTags) override; bool recursive() const override; const void *key() const override; QString createId() const override; bool areModulePropertiesCompatible(const PropertyMapConstPtr &m1, const PropertyMapConstPtr &m2) const override; bool cacheIsPerFile() const override { return false; } ScannerPlugin* m_plugin; }; class UserDependencyScanner : public DependencyScanner { public: UserDependencyScanner(ResolvedScannerConstPtr scanner, ScriptEngine *engine); private: QStringList collectSearchPaths(Artifact *artifact) override; QStringList collectDependencies(Artifact *artifact, FileResourceBase *file, const char *fileTags) override; bool recursive() const override; const void *key() const override; QString createId() const override; bool areModulePropertiesCompatible(const PropertyMapConstPtr &m1, const PropertyMapConstPtr &m2) const override; bool cacheIsPerFile() const override { return true; } QStringList evaluate(Artifact *artifact, const FileResourceBase *fileToScan, const PrivateScriptFunction &script); ResolvedScannerConstPtr m_scanner; ScriptEngine *m_engine; ScopedJsValue m_global; ResolvedProduct *m_product; }; } // namespace Internal } // namespace qbs #endif // QBS_DEPENDENCY_SCANNER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rawscanneddependency.cpp0000644000175100001660000000560514776170045024443 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rawscanneddependency.h" #include namespace qbs { namespace Internal { RawScannedDependency::RawScannedDependency() : m_isClean(true) {} RawScannedDependency::RawScannedDependency(const QString &filePath) { FileInfo::splitIntoDirectoryAndFileName(filePath, &m_dirPath, &m_fileName); setClean(); } QString RawScannedDependency::filePath() const { return m_dirPath.isEmpty() ? m_fileName : m_dirPath + QLatin1Char('/') + m_fileName; } void RawScannedDependency::setClean() { m_isClean = !m_dirPath.contains(QLatin1Char('.')) && !m_dirPath.contains(QStringLiteral("//")); } void RawScannedDependency::load(PersistentPool &pool) { serializationOp(pool); setClean(); } void RawScannedDependency::store(PersistentPool &pool) { serializationOp(pool); } bool operator==(const RawScannedDependency &d1, const RawScannedDependency &d2) { return d1.dirPath() == d2.dirPath() && d1.fileName() == d2.fileName(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/artifactsscriptvalue.cpp0000644000175100001660000002164514776170045024523 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "artifactsscriptvalue.h" #include "artifact.h" #include "productbuilddata.h" #include "transformer.h" #include #include #include #include namespace qbs { namespace Internal { template static bool isRelevantArtifact(const ProductOrModule *productOrModule, const Artifact *artifact) { if constexpr (std::is_same_v) { Q_UNUSED(productOrModule) return !artifact->isTargetOfModule(); } else { return artifact->targetOfModule == productOrModule->name; } } template static ArtifactSetByFileTag artifactsMap(const ProductOrModule *productOrModule) { if constexpr (std::is_same_v) return productOrModule->buildData->artifactsByFileTag(); else return artifactsMap(productOrModule->product); } template static int scriptClassIndex() { if constexpr (std::is_same_v) return 0; return 1; } template std::unique_lock getArtifactsMapLock(ProductOrModule *productOrModule) { if constexpr (std::is_same_v) return productOrModule->buildData->getArtifactsMapLock(); else return getArtifactsMapLock(productOrModule->product); } template static bool checkAndSetArtifactsMapUpToDateFlag(const ProductOrModule *productOrModule) { if constexpr (std::is_same_v) return productOrModule->buildData->checkAndSetJsArtifactsMapUpToDateFlag(); else return checkAndSetArtifactsMapUpToDateFlag(productOrModule->product); } // Must be called with artifacts map lock held! template void registerArtifactsMapAccess(ScriptEngine *engine, ProductOrModule *productOrModule) { if constexpr (std::is_same_v) { if (!checkAndSetArtifactsMapUpToDateFlag(productOrModule)) engine->setArtifactsMapRequested(productOrModule, true); else engine->setArtifactsMapRequested(productOrModule, false); } else { registerArtifactsMapAccess(engine, productOrModule->product); } } template static int getArtifactsPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto productOrModule = attachedPointer( obj, engine->artifactsScriptClass(scriptClassIndex())); const std::unique_lock lock = getArtifactsMapLock(productOrModule); registerArtifactsMapAccess(engine, productOrModule); if constexpr (std::is_same_v) engine->setArtifactsEnumerated(productOrModule); const auto &map = artifactsMap(productOrModule); const auto filter = [productOrModule](const Artifact *a) { return isRelevantArtifact(productOrModule, a); }; QStringList tags; for (auto it = map.cbegin(); it != map.cend(); ++it) { if (any_of(it.value(), filter)) { tags << it.key().toString(); } } *plen = tags.size(); if (!tags.isEmpty()) { *ptab = reinterpret_cast(js_malloc(ctx, *plen * sizeof **ptab)); JSPropertyEnum *entry = *ptab; for (const QString &tag : std::as_const(tags)) { entry->atom = JS_NewAtom(ctx, tag.toUtf8().constData()); entry->is_enumerable = 1; ++entry; } } else { *ptab = nullptr; } return 0; } template static int getArtifactsProperty(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop) { if (!desc) return 1; desc->flags = JS_PROP_ENUMERABLE; desc->value = desc->getter = desc->setter = JS_UNDEFINED; ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto productOrModule = attachedPointer( obj, engine->artifactsScriptClass(scriptClassIndex())); const std::unique_lock lock = getArtifactsMapLock(productOrModule); registerArtifactsMapAccess(engine, productOrModule); const QString tagString = getJsString(ctx, prop); const FileTag fileTag(tagString.toUtf8()); const auto &map = artifactsMap(productOrModule); const auto it = map.constFind(fileTag); if (it == map.constEnd()) { if constexpr (std::is_same_v) engine->setNonExistingArtifactSetRequested(productOrModule, tagString); return 1; } if constexpr (std::is_same_v) engine->setArtifactSetRequestedForTag(productOrModule, fileTag); ArtifactSet artifacts = it.value(); removeIf(artifacts, [productOrModule](const Artifact *a) { return !isRelevantArtifact(productOrModule, a); }); if (!artifacts.empty()) { desc->value = JS_NewArray(ctx); // TODO: Also cache this list? int k = 0; for (Artifact * const artifact : artifacts) { JS_SetPropertyUint32(ctx, desc->value, k++, Transformer::translateFileConfig(engine, artifact, QString())); } } return 1; } template static JSValue js_artifacts(JSContext *ctx, JSValue jsProductOrModule) { ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto productOrModule = attachedPointer(jsProductOrModule, engine->dataWithPtrClass()); JSValue artifactsObj = engine->artifactsMapScriptValue(productOrModule); if (!JS_IsUndefined(artifactsObj)) return artifactsObj; const int classIndex = scriptClassIndex(); JSClassID scriptClass = engine->artifactsScriptClass(classIndex); if (scriptClass == 0) { const QByteArray className = "ArtifactsScriptClass" + QByteArray::number(classIndex); scriptClass = engine->registerClass(className.constData(), nullptr, nullptr, JS_UNDEFINED, &getArtifactsPropertyNames, &getArtifactsProperty); engine->setArtifactsScriptClass(classIndex, scriptClass); } artifactsObj = JS_NewObjectClass(engine->context(), scriptClass); attachPointerTo(artifactsObj, productOrModule); return artifactsObj; } JSValue artifactsScriptValueForProduct(JSContext *ctx, JSValue this_val, int, JSValue *) { return js_artifacts(ctx, this_val); } JSValue artifactsScriptValueForModule(JSContext *ctx, JSValueConst this_val, int, JSValueConst *) { return js_artifacts(ctx, this_val); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/timestampsupdater.h0000644000175100001660000000443014776170045023472 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef TIMESTAMPSUPDATER_H #define TIMESTAMPSUPDATER_H #include #include namespace qbs { namespace Internal { class Logger; class TimestampsUpdater { public: void updateTimestamps(const TopLevelProjectPtr &project, const QVector &products, const Logger &logger); }; } // namespace Internal } // namespace qbs #endif // TIMESTAMPSUPDATER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/transformer.h0000644000175100001660000001416114776170045022263 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_TRANSFORMER_H #define QBS_TRANSFORMER_H #include "artifact.h" #include "forward_decls.h" #include "requestedartifacts.h" #include "requesteddependencies.h" #include "rulecommands.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class Artifact; class AbstractCommand; class Rule; class Transformer { public: static TransformerPtr create() { return TransformerPtr(new Transformer); } ~Transformer(); ArtifactSet inputs; // Subset of "children of all outputs". ArtifactSet outputs; ArtifactSet explicitlyDependsOn; RuleConstPtr rule; CommandList commands; PropertySet propertiesRequestedInPrepareScript; PropertySet propertiesRequestedInCommands; QHash propertiesRequestedFromArtifactInPrepareScript; QHash propertiesRequestedFromArtifactInCommands; std::vector importedFilesUsedInPrepareScript; std::vector importedFilesUsedInCommands; RequestedDependencies depsRequestedInPrepareScript; RequestedDependencies depsRequestedInCommands; RequestedArtifacts artifactsMapRequestedInPrepareScript; RequestedArtifacts artifactsMapRequestedInCommands; FileTime lastPrepareScriptExecutionTime; FileTime lastCommandExecutionTime; std::unordered_map exportedModulesAccessedInPrepareScript; std::unordered_map exportedModulesAccessedInCommands; bool alwaysRun; bool prepareScriptNeedsChangeTracking = false; bool commandsNeedChangeTracking = false; bool markedForRerun = false; static JSValue translateFileConfig(ScriptEngine *engine, Artifact *artifact, const QString &defaultModuleName); ResolvedProductPtr product() const; void setupInputs(ScriptEngine *engine, const JSValue &targetScriptValue); void setupOutputs(ScriptEngine *engine, JSValue targetScriptValue); void setupExplicitlyDependsOn(ScriptEngine *engine, JSValue targetScriptValue); void createCommands(ScriptEngine *engine, const PrivateScriptFunction &script, const JSValueList &args); void rescueChangeTrackingData(const TransformerConstPtr &other); Set jobPools() const; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(rule, inputs, outputs, explicitlyDependsOn, propertiesRequestedInPrepareScript, propertiesRequestedInCommands, propertiesRequestedFromArtifactInPrepareScript, propertiesRequestedFromArtifactInCommands, importedFilesUsedInPrepareScript, importedFilesUsedInCommands, depsRequestedInPrepareScript, depsRequestedInCommands, commands, artifactsMapRequestedInPrepareScript, artifactsMapRequestedInCommands, lastPrepareScriptExecutionTime, lastCommandExecutionTime, exportedModulesAccessedInPrepareScript, exportedModulesAccessedInCommands, alwaysRun, prepareScriptNeedsChangeTracking, commandsNeedChangeTracking, markedForRerun); } private: Transformer(); AbstractCommandPtr createCommandFromScriptValue(ScriptEngine *engine, const JSValue &scriptValue, const CodeLocation &codeLocation); static void setupInputs(ScriptEngine *engine, JSValue targetScriptValue, const ArtifactSet &inputs, const QString &defaultModuleName); static JSValue translateInOutputs(ScriptEngine *engine, const ArtifactSet &artifacts, const QString &defaultModuleName); }; } // namespace Internal } // namespace qbs #endif // QBS_TRANSFORMER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/nodetreedumper.cpp0000644000175100001660000000714714776170045023304 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "nodetreedumper.h" #include "artifact.h" #include "productbuilddata.h" #include "rulenode.h" #include #include #include namespace qbs { namespace Internal { static int indentWidth() { return 4; } NodeTreeDumper::NodeTreeDumper(QIODevice &outDevice) : m_outDevice(outDevice) { } void NodeTreeDumper::start(const QVector &products) { m_indentation = 0; for (const ResolvedProductPtr &p : products) { if (!p->buildData) continue; m_currentProduct = p; for (Artifact * const root : p->buildData->rootArtifacts()) root->accept(this); m_visited.clear(); QBS_CHECK(m_indentation == 0); } } bool NodeTreeDumper::visit(Artifact *artifact) { return doVisit(artifact, artifact->fileName()); } void NodeTreeDumper::endVisit(Artifact *artifact) { Q_UNUSED(artifact); doEndVisit(); } bool NodeTreeDumper::visit(RuleNode *rule) { return doVisit(rule, rule->toString()); } void NodeTreeDumper::endVisit(RuleNode *rule) { Q_UNUSED(rule); doEndVisit(); } void NodeTreeDumper::doEndVisit() { unindent(); } void NodeTreeDumper::indent() { m_outDevice.write("\n"); m_indentation += indentWidth(); } void NodeTreeDumper::unindent() { m_indentation -= indentWidth(); } bool NodeTreeDumper::doVisit(BuildGraphNode *node, const QString &nodeRepr) { m_outDevice.write(indentation()); m_outDevice.write(nodeRepr.toLocal8Bit()); indent(); const bool wasVisited = !m_visited.insert(node).second; return !wasVisited && node->product == m_currentProduct; } QByteArray NodeTreeDumper::indentation() const { return {m_indentation, ' '}; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/qtmocscanner.h0000644000175100001660000000551314776170045022417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_QTMOCSCANNER_H #define QBS_QTMOCSCANNER_H #include #include #include #include QT_BEGIN_NAMESPACE class QScriptContext; QT_END_NAMESPACE class ScannerPlugin; namespace qbs { namespace Internal { class ScriptEngine; class Artifact; struct CommonFileTags; class QtMocScanner { public: explicit QtMocScanner(const ResolvedProductPtr &product, ScriptEngine *engine, JSValue targetScriptValue); ~QtMocScanner(); private: void findIncludedMocCppFiles(); static JSValue js_apply(JSContext *ctx, JSValue this_val, int argc, JSValue *argv); JSValue apply(ScriptEngine *engine, const Artifact *artifact); ScriptEngine * const m_engine; const CommonFileTags &m_tags; const ResolvedProductPtr &m_product; JSValue m_targetScriptValue; QHash m_includedMocCppFiles; }; } // namespace Internal } // namespace qbs #endif // QBS_QTMOCSCANNER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/artifact.h0000644000175100001660000001340114776170045021512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ARTIFACT_H #define QBS_ARTIFACT_H #include "filedependency.h" #include "buildgraphnode.h" #include "forward_decls.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class Logger; class Artifact; using ArtifactSet = Set; /** * The Artifact class * * Let artifact P be the parent of artifact C. Thus C is child of P. * C produces P using the transformer P.transformer. * * */ class QBS_AUTOTEST_EXPORT Artifact : public FileResourceBase, public BuildGraphNode { public: Artifact(); ~Artifact() override; Type type() const override { return ArtifactNodeType; } FileType fileType() const override { return FileTypeArtifact; } void accept(BuildGraphVisitor *visitor) override; QString toString() const override; void addFileTag(const FileTag &t); void removeFileTag(const FileTag &t); void setFileTags(const FileTags &newFileTags); const FileTags &fileTags() const { return m_fileTags; } RuleNode *producer() const; ArtifactSet childrenAddedByScanner; Set fileDependencies; TransformerPtr transformer; PropertyMapPtr properties; QString targetOfModule; // The tags set directly via an Artifact item or an outputArtifacts script, // not the result of file taggers or fileTagsFilter groups, nor the ones inherited from // the product. FileTags pureFileTags; // The properties attached directly to an artifact in an Artifact item or outputArtifacts // script. std::vector> pureProperties; enum ArtifactType { Unknown = 1, SourceFile = 2, Generated = 4 }; ArtifactType artifactType; bool inputsScanned : 1; // Do not serialize. Will be refreshed for every build. bool timestampRetrieved : 1; // Do not serialize. Will be refreshed for every build. bool alwaysUpdated : 1; bool oldDataPossiblyPresent : 1; const TypeFilter parentArtifacts() const; const TypeFilter childArtifacts() const; void onChildDisconnected(BuildGraphNode *child) override; bool isTargetOfModule() const { return !targetOfModule.isEmpty(); } void load(PersistentPool &pool) override; void store(PersistentPool &pool) override; using Deregister = std::function; void setDeregister(const Deregister &deregister) { m_deregister = deregister; } private: FileTags m_fileTags; Deregister m_deregister; }; template<> inline QString Set::toString(Artifact * const &artifact) const { return artifact ? artifact->filePath() : QStringLiteral(""); } template<> inline const void *uniqueAddress(const Artifact *a) { return static_cast(a); } template<> inline bool hasDynamicType(const BuildGraphNode *n) { return n->type() == BuildGraphNode::ArtifactNodeType; } // debugging helper inline QString toString(Artifact::ArtifactType t) { switch (t) { case Artifact::SourceFile: return QStringLiteral("SourceFile"); case Artifact::Generated: return QStringLiteral("Generated"); case Artifact::Unknown: default: return QStringLiteral("Unknown"); } } // debugging helper inline QString toString(BuildGraphNode::BuildState s) { switch (s) { case BuildGraphNode::Untouched: return QStringLiteral("Untouched"); case BuildGraphNode::Buildable: return QStringLiteral("Buildable"); case BuildGraphNode::Building: return QStringLiteral("Building"); case BuildGraphNode::Built: return QStringLiteral("Built"); default: return QStringLiteral("Unknown"); } } } // namespace Internal } // namespace qbs #endif // QBS_ARTIFACT_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rulegraph.h0000644000175100001660000000620714776170045021714 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RULEGRAPH_H #define QBS_RULEGRAPH_H #include #include #include #include #include #include #include namespace qbs { namespace Internal { class RuleGraphVisitor { public: virtual ~RuleGraphVisitor() = default; virtual void visit(const RuleConstPtr &parentRule, const RuleConstPtr &rule) = 0; virtual void endVisit(const RuleConstPtr &rule) { Q_UNUSED(rule); } }; class RuleGraph { public: RuleGraph(); void build(const std::vector &rules, const FileTags &productFileTag); void accept(RuleGraphVisitor *visitor) const; void dump() const; private: void dump_impl(QByteArray &indent, int rootIndex) const; int insert(const RulePtr &rule); void connect(const Rule *creatingRule, const Rule *consumingRule); void traverse(RuleGraphVisitor *visitor, const RuleConstPtr &parentRule, const RuleConstPtr &rule) const; private: QMap > m_outputFileTagToRule; std::vector m_rules; std::vector< std::vector > m_parents; std::vector< std::vector > m_children; Set m_rootRules; }; } // namespace Internal } // namespace qbs #endif // QBS_RULEGRAPH_H qbs-src-2.6.1/src/lib/corelib/buildgraph/forward_decls.h0000644000175100001660000000535614776170045022545 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BG_FORWARD_DECLS_H #define QBS_BG_FORWARD_DECLS_H #include namespace qbs { namespace Internal { class Artifact; class BuildGraphNode; class ProjectBuildData; class ProductBuildData; class RuleNode; class Transformer; using TransformerPtr = std::shared_ptr; using TransformerConstPtr = std::shared_ptr; class RulesEvaluationContext; using RulesEvaluationContextPtr = std::shared_ptr; class AbstractCommand; using AbstractCommandPtr = std::shared_ptr; class ProcessCommand; using ProcessCommandPtr = std::shared_ptr; class JavaScriptCommand; using JavaScriptCommandPtr = std::shared_ptr; template class Set; using ArtifactSet = Set; using NodeSet = Set; } // namespace Internal } // namespace qbs #endif // QBS_BG_FORWARD_DECLS_H qbs-src-2.6.1/src/lib/corelib/buildgraph/cppmodulesscanner.h0000644000175100001660000000434214776170045023446 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Janet Black. ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef QBS_CXXMODULESSCANNER_H #define QBS_CXXMODULESSCANNER_H #include #include #include #include class ScannerPlugin; namespace qbs::Internal { class Artifact; struct CommonFileTags; class CppModulesScanner { public: explicit CppModulesScanner(ScriptEngine *engine, JSValue targetScriptValue); ~CppModulesScanner(); private: static JSValue js_apply(JSContext *ctx, JSValue this_val, int argc, JSValue *argv); JSValue apply(ScriptEngine *engine, const Artifact *artifact); ScriptEngine * const m_engine; const JSValue m_targetScriptValue; }; } // namespace qbs::Internal #endif // QBS_CXXMODULESSCANNER_H qbs-src-2.6.1/src/lib/corelib/buildgraph/cycledetector.cpp0000644000175100001660000000671214776170045023110 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "cycledetector.h" #include "artifact.h" #include "buildgraph.h" #include "projectbuilddata.h" #include "rulenode.h" #include #include #include #include namespace qbs { namespace Internal { CycleDetector::CycleDetector(Logger logger) : m_parent(nullptr), m_logger(std::move(logger)) { } void CycleDetector::visitProject(const TopLevelProjectConstPtr &project) { project->accept(this); } void CycleDetector::visitProduct(const ResolvedProductConstPtr &product) { product->accept(this); } bool CycleDetector::visit(Artifact *artifact) { return visitNode(artifact); } bool CycleDetector::visit(RuleNode *ruleNode) { return visitNode(ruleNode); } bool CycleDetector::visitNode(BuildGraphNode *node) { if (Q_UNLIKELY(m_nodesInCurrentPath.contains(node))) { ErrorInfo error(Tr::tr("Cycle in build graph detected.")); const auto nodes = cycle(node); for (const BuildGraphNode * const n : nodes) error.append(n->toString()); throw error; } if (m_allNodes.contains(node)) return false; m_nodesInCurrentPath += node; m_parent = node; for (BuildGraphNode * const child : std::as_const(node->children)) child->accept(this); m_nodesInCurrentPath -= node; m_allNodes += node; return false; } QList CycleDetector::cycle(BuildGraphNode *doubleEntry) { QList path; findPath(doubleEntry, m_parent, path); path.push_back(doubleEntry); return path; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/environmentscriptrunner.h0000644000175100001660000000547414776170045024753 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_ENVIRONMENTSCRIPTRUNNER_H #define QBS_ENVIRONMENTSCRIPTRUNNER_H #include #include #include namespace qbs { namespace Internal { class RulesEvaluationContext; class ScriptEngine; class EnvironmentScriptRunner { public: EnvironmentScriptRunner(ResolvedProduct *product, RulesEvaluationContext *evalContext, const QProcessEnvironment &env); void setupForBuild(); void setupForRun(const QStringList &config); private: void setupEnvironment(); ScriptEngine *engine() const; const PrivateScriptFunction &getScript(const ResolvedModule *module) const; ResolvedProduct * const m_product; RulesEvaluationContext * const m_evalContext; const QProcessEnvironment m_env; QStringList m_runEnvConfig; enum EnvType { BuildEnv, RunEnv } m_envType = EnvType::BuildEnv; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/buildgraph/nodetreedumper.h0000644000175100001660000000546014776170045022745 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_NODETREEDUMPER_H #define QBS_NODETREEDUMPER_H #include "artifact.h" #include "buildgraphvisitor.h" #include #include QT_BEGIN_NAMESPACE class QIODevice; QT_END_NAMESPACE namespace qbs { namespace Internal { class NodeTreeDumper : public BuildGraphVisitor { public: NodeTreeDumper(QIODevice &outDevice); void start(const QVector &products); private: bool visit(Artifact *artifact) override; void endVisit(Artifact *artifact) override; bool visit(RuleNode *rule) override; void endVisit(RuleNode *rule) override; void doEndVisit(); void indent(); void unindent(); bool doVisit(BuildGraphNode *node, const QString &nodeRepr); QByteArray indentation() const; QIODevice &m_outDevice; ResolvedProductPtr m_currentProduct; NodeSet m_visited; int m_indentation = 0; }; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/buildgraph/dependencyparametersscriptvalue.cpp0000644000175100001660000000727614776170045026751 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "dependencyparametersscriptvalue.h" #include #include #include #include namespace qbs { namespace Internal { static JSValue toScriptValue(ScriptEngine *engine, const QString &productName, const QVariantMap &v, const QString &depName, const QualifiedId &moduleName) { JSValue obj = engine->newObject(); bool objIdAddedToObserver = false; for (auto it = v.begin(); it != v.end(); ++it) { if (it.value().userType() == QMetaType::QVariantMap) { setJsProperty(engine->context(), obj, it.key(), toScriptValue(engine, productName, it.value().toMap(), depName, QualifiedId(moduleName) << it.key())); } else { if (!objIdAddedToObserver) { objIdAddedToObserver = true; engine->observer()->addParameterObjectId(jsObjectId(obj), productName, depName, moduleName); } const ScopedJsValue val(engine->context(), engine->toScriptValue(it.value())); engine->setObservedProperty(obj, it.key(), val); } } return obj; } static JSValue toScriptValue(ScriptEngine *scriptEngine, const QString &productName, const QVariantMap &v, const QString &depName) { return toScriptValue(scriptEngine, productName, v, depName, {}); } JSValue dependencyParametersValue(const QString &productName, const QString &dependencyName, const QVariantMap ¶metersMap, ScriptEngine *engine) { return toScriptValue(engine, productName, parametersMap, dependencyName); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/environmentscriptrunner.cpp0000644000175100001660000002213014776170045025272 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "environmentscriptrunner.h" #include "buildgraph.h" #include "rulesevaluationcontext.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class EnvProvider { public: EnvProvider(ScriptEngine *engine, const QProcessEnvironment &originalEnv) : m_engine(engine), m_env(originalEnv) { QVariant v; v.setValue(&m_env); m_engine->setProperty(StringConstants::qbsProcEnvVarInternal(), v); } ~EnvProvider() { m_engine->setProperty(StringConstants::qbsProcEnvVarInternal(), QVariant()); } QProcessEnvironment alteredEnvironment() const { return m_env; } private: ScriptEngine * const m_engine; QProcessEnvironment m_env; }; static QList topSortModules(const QHash > &moduleChildren, const QList &modules, Set &seenModuleNames) { QList result; for (const ResolvedModule * const m : modules) { if (m->name.isNull()) continue; result << topSortModules(moduleChildren, moduleChildren.value(m), seenModuleNames); if (seenModuleNames.insert(m->name).second) result.push_back(m); } return result; } EnvironmentScriptRunner::EnvironmentScriptRunner(ResolvedProduct *product, RulesEvaluationContext *evalContext, const QProcessEnvironment &env) : m_product(product), m_evalContext(evalContext), m_env(env) { } void EnvironmentScriptRunner::setupForBuild() { // TODO: Won't this fail to take changed properties into account? We probably need // change tracking here as well. if (!m_product->buildEnvironment.isEmpty()) return; m_envType = BuildEnv; setupEnvironment(); } void EnvironmentScriptRunner::setupForRun(const QStringList &config) { m_envType = RunEnv; m_runEnvConfig = config; setupEnvironment(); } void EnvironmentScriptRunner::setupEnvironment() { const auto hasScript = [this](const ResolvedModuleConstPtr &m) { return !getScript(m.get()).sourceCode().isEmpty(); }; const bool hasAnyScripts = Internal::any_of(m_product->modules, hasScript); if (!hasAnyScripts) return; QMap moduleMap; for (const auto &module : m_product->modules) moduleMap.insert(module->name, module.get()); QHash > moduleParents; QHash > moduleChildren; for (const auto &module : m_product->modules) { for (const QString &moduleName : std::as_const(module->moduleDependencies)) { const ResolvedModule * const depmod = moduleMap.value(moduleName); QBS_ASSERT(depmod, return); moduleParents[depmod].push_back(module.get()); moduleChildren[module.get()].push_back(depmod); } } QList rootModules; for (const auto &module : m_product->modules) { if (moduleParents.value(module.get()).isEmpty()) { QBS_ASSERT(module, return); rootModules.push_back(module.get()); } } EnvProvider envProvider(engine(), m_env); Set seenModuleNames; const QList &topSortedModules = topSortModules(moduleChildren, rootModules, seenModuleNames); const QStringList scriptFunctionArgs = m_envType == BuildEnv ? ResolvedModule::argumentNamesForSetupBuildEnv() : ResolvedModule::argumentNamesForSetupRunEnv(); for (const ResolvedModule * const module : topSortedModules) { const PrivateScriptFunction &setupScript = getScript(module); if (setupScript.sourceCode().isEmpty()) continue; RulesEvaluationContext::Scope s(m_evalContext); JSContext * const ctx = engine()->context(); ScopedJsValue envScriptContext(ctx, JS_NewObjectProto(ctx, engine()->globalObject())); setupScriptEngineForProduct(engine(), m_product, module, envScriptContext, false); const QString &productKey = StringConstants::productVar(); const QString &projectKey = StringConstants::projectVar(); setJsProperty(ctx, m_evalContext->scope(), productKey, getJsProperty(ctx, envScriptContext, productKey)); setJsProperty(ctx, m_evalContext->scope(), projectKey, getJsProperty(ctx, envScriptContext, projectKey)); if (m_envType == RunEnv) { JSValue configArray = JS_NewArray(ctx); for (int i = 0; i < m_runEnvConfig.size(); ++i) JS_SetPropertyUint32(ctx, configArray, i, makeJsString(ctx, m_runEnvConfig.at(i))); JS_SetPropertyStr(ctx, m_evalContext->scope(), "config", configArray); } setupScriptEngineForFile(engine(), setupScript.fileContext(), m_evalContext->scope(), ObserveMode::Disabled); // TODO: Cache evaluate result ScopedJsValue fun(ctx, engine()->evaluate(JsValueOwner::Caller, setupScript.sourceCode(), setupScript.location().filePath(), setupScript.location().line())); QBS_CHECK(JS_IsFunction(ctx, fun)); const ScopedJsValueList svArgs = engine()->argumentList(scriptFunctionArgs, m_evalContext->scope()); JSValueList argsForFun = svArgs; JS_Call(ctx, fun, engine()->globalObject(), int(argsForFun.size()), argsForFun.data()); if (const JsException ex = engine()->checkAndClearException(setupScript.location())) { const QString scriptName = m_envType == BuildEnv ? StringConstants::setupBuildEnvironmentProperty() : StringConstants::setupRunEnvironmentProperty(); ErrorInfo err = ex.toErrorInfo(); err.prepend(Tr::tr("Error running %1 script for product '%2'") .arg(scriptName, m_product->fullDisplayName())); throw err; } } const QProcessEnvironment &newEnv = envProvider.alteredEnvironment(); if (m_envType == BuildEnv) m_product->buildEnvironment = newEnv; else m_product->runEnvironment = newEnv; } ScriptEngine *EnvironmentScriptRunner::engine() const { return m_evalContext->engine(); } const PrivateScriptFunction &EnvironmentScriptRunner::getScript(const ResolvedModule *module) const { return m_envType == BuildEnv ? module->setupBuildEnvironmentScript : module->setupRunEnvironmentScript; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/cycledetector.h0000644000175100001660000000530614776170045022553 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_CYCLEDETECTOR_H #define QBS_CYCLEDETECTOR_H #include "buildgraphvisitor.h" #include "nodeset.h" #include #include namespace qbs { namespace Internal { class BuildGraphNode; class QBS_AUTOTEST_EXPORT CycleDetector : private BuildGraphVisitor { public: CycleDetector(Logger logger); void visitProject(const TopLevelProjectConstPtr &project); void visitProduct(const ResolvedProductConstPtr &product); private: bool visit(Artifact *artifact) override; bool visit(RuleNode *ruleNode) override; bool visitNode(BuildGraphNode *node); QList cycle(BuildGraphNode *doubleEntry); NodeSet m_allNodes; NodeSet m_nodesInCurrentPath; BuildGraphNode *m_parent; Logger m_logger; }; } // namespace Internal } // namespace qbs #endif // QBS_CYCLEDETECTOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/requesteddependencies.h0000644000175100001660000000561714776170045024277 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_REQUESTEDDEPENDENCIES_H #define QBS_REQUESTEDDEPENDENCIES_H #include #include #include #include #include namespace qbs { namespace Internal { class RequestedDependencies { public: RequestedDependencies() = default; RequestedDependencies(const Set &products) { set(products); } void set(const Set &products); void add(const Set &products); void clear() { m_depsPerProduct.clear(); } bool isUpToDate(const TopLevelProject *project) const; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_depsPerProduct); } private: struct QStringHash { std::size_t operator()(const QString &s) const { return qHash(s); } }; std::unordered_map, QStringHash> m_depsPerProduct; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/cppmodulesscanner.cpp0000644000175100001660000001314314776170045024000 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Janet Black. ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "cppmodulesscanner.h" #include "artifact.h" #include "depscanner.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "rawscanresults.h" #include #include #include #include #include #include #include namespace qbs::Internal { static QString cppModulesScannerJsName() { return QStringLiteral("CppModulesScanner"); } CppModulesScanner::CppModulesScanner(ScriptEngine *engine, JSValue targetScriptValue) : m_engine(engine) , m_targetScriptValue(JS_DupValue(engine->context(), targetScriptValue)) { JSValue scannerObj = JS_NewObjectClass(engine->context(), engine->dataWithPtrClass()); attachPointerTo(scannerObj, this); setJsProperty(engine->context(), targetScriptValue, cppModulesScannerJsName(), scannerObj); JSValue applyFunction = JS_NewCFunction( engine->context(), &js_apply, qPrintable(cppModulesScannerJsName()), 1); setJsProperty(engine->context(), scannerObj, QStringLiteral("apply"), applyFunction); } CppModulesScanner::~CppModulesScanner() { setJsProperty( m_engine->context(), m_targetScriptValue, cppModulesScannerJsName(), JS_UNDEFINED); JS_FreeValue(m_engine->context(), m_targetScriptValue); } static RawScanResult runScannerForArtifact(const Artifact *artifact) { const QString &filepath = artifact->filePath(); RawScanResults &rawScanResults = artifact->product->topLevelProject()->buildData->rawScanResults; // TODO: use the same id for all c++ scanners? auto predicate = [](const PropertyMapConstPtr &, const PropertyMapConstPtr &) { return true; }; RawScanResults::ScanData &scanData = rawScanResults.findScanData( artifact, cppModulesScannerJsName(), artifact->properties, predicate); if (scanData.lastScanTime < artifact->timestamp()) { FileTags tags = artifact->fileTags(); if (tags.contains("cpp.combine")) { tags.remove("cpp.combine"); tags.insert("cpp"); } const QByteArray tagsForScanner = tags.toStringList().join(QLatin1Char(',')).toLatin1(); CppScannerContext context; const bool ok = scanCppFile( context, filepath, {tagsForScanner.data(), size_t(tagsForScanner.size())}, true, true); if (!ok) return scanData.rawScanResult; scanData.rawScanResult.providesModule = QString::fromUtf8(context.providesModule); scanData.rawScanResult.isInterfaceModule = context.isInterface; scanData.rawScanResult.requiresModules.clear(); for (const auto &module : context.requiresModules) scanData.rawScanResult.requiresModules += QString::fromUtf8(module); scanData.lastScanTime = FileTime::currentTime(); } return scanData.rawScanResult; } JSValue CppModulesScanner::js_apply(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { if (argc < 1) return throwError(ctx, Tr::tr("CppModulesScanner.apply() requires an argument.")); ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const auto scanner = attachedPointer(this_val, engine->dataWithPtrClass()); return scanner->apply(engine, attachedPointer(argv[0], engine->dataWithPtrClass())); } JSValue CppModulesScanner::apply(ScriptEngine *engine, const Artifact *artifact) { JSContext * const ctx = m_engine->context(); if (!artifact) return JSValue{}; RawScanResult scanResult = runScannerForArtifact(artifact); JSValue obj = engine->newObject(); setJsProperty( ctx, obj, QStringLiteral("providesModule"), makeJsString(ctx, scanResult.providesModule)); setJsProperty( ctx, obj, QStringLiteral("isInterfaceModule"), JS_NewBool(ctx, scanResult.isInterfaceModule)); setJsProperty( ctx, obj, QStringLiteral("requiresModules"), makeJsStringList(ctx, scanResult.requiresModules)); engine->setUsesIo(); return obj; } } // namespace qbs::Internal qbs-src-2.6.1/src/lib/corelib/buildgraph/rulenode.h0000644000175100001660000001035614776170045021540 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RULENODE_H #define QBS_RULENODE_H #include "artifact.h" #include "buildgraphnode.h" #include "forward_decls.h" #include #include #include #include namespace qbs { namespace Internal { class Logger; class RuleNode : public BuildGraphNode { public: RuleNode(); ~RuleNode() override; void setRule(const RuleConstPtr &rule) { m_rule = rule; } const RuleConstPtr &rule() const { return m_rule; } Type type() const override { return RuleNodeType; } void accept(BuildGraphVisitor *visitor) override; QString toString() const override; struct ApplicationResult { NodeSet createdArtifacts; NodeSet invalidatedArtifacts; QStringList removedArtifacts; }; ApplicationResult apply( const Logger &logger, const std::unordered_map &productsByName, const std::unordered_map &projectsByName); void removeOldInputArtifact(Artifact *artifact); void load(PersistentPool &pool) override; void store(PersistentPool &pool) override; int transformerCount() const; private: template void serializationOp(PersistentPool &pool) { pool.serializationOp( m_rule, m_oldInputArtifacts, m_oldExplicitlyDependsOn, m_lastApplicationTime, m_needsToConsiderChangedInputs); } ArtifactSet currentInputArtifacts() const; ArtifactSet changedInputArtifacts( const ArtifactSet &allCompatibleInputs, const ArtifactSet &explicitlyDependsOn) const; RuleConstPtr m_rule; // These two can contain null pointers, which represent a "dummy artifact" encoding // the information that an artifact that used to be in here has ceased to exist. // This is okay, because no code outside this class has access to these sets, so // we cannot break any assumptions about non-nullness. ArtifactSet m_oldInputArtifacts; ArtifactSet m_oldExplicitlyDependsOn; FileTime m_lastApplicationTime; bool m_needsToConsiderChangedInputs = false; }; template<> inline bool hasDynamicType(const BuildGraphNode *n) { return n->type() == BuildGraphNode::RuleNodeType; } } // namespace Internal } // namespace qbs #endif // QBS_RULENODE_H qbs-src-2.6.1/src/lib/corelib/buildgraph/productinstaller.h0000644000175100001660000000615214776170045023320 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PRODUCT_INSTALLER_H #define QBS_PRODUCT_INSTALLER_H #include "forward_decls.h" #include #include #include #include #include namespace qbs { namespace Internal { class ProgressObserver; class ProductInstaller { public: ProductInstaller(TopLevelProjectPtr project, QVector products, InstallOptions options, ProgressObserver *observer, Logger logger); void install(); static QString targetFilePath(const TopLevelProject *project, const QString &productSourceDir, const QString &sourceFilePath, const PropertyMapConstPtr &properties, InstallOptions &options); static void initInstallRoot(const TopLevelProject *project, InstallOptions &options); void removeInstallRoot(); void copyFile(const Artifact *artifact); private: void handleError(const QString &message); const TopLevelProjectConstPtr m_project; const QVector m_products; InstallOptions m_options; ProgressObserver * const m_observer; Logger m_logger; QHash m_targetFilePathsMap; }; } // namespace Internal } // namespace qbs #endif // Header guard qbs-src-2.6.1/src/lib/corelib/buildgraph/processcommandexecutor.h0000644000175100001660000000667414776170045024527 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PROCESSCOMMANDEXECUTOR_H #define QBS_PROCESSCOMMANDEXECUTOR_H #include "abstractcommandexecutor.h" #include #include namespace qbs { class ProcessResult; namespace Internal { class ProcessCommand; class ProcessCommandExecutor : public AbstractCommandExecutor { Q_OBJECT public: explicit ProcessCommandExecutor(const Internal::Logger &logger, QObject *parent = nullptr); void setProcessEnvironment(const QProcessEnvironment &processEnvironment) { m_buildEnvironment = processEnvironment; } signals: void reportProcessResult(const qbs::ProcessResult &result); private: void onProcessError(); void onProcessFinished(); void doSetup() override; void doReportCommandDescription(const QString &productName) override; bool doStart() override; void cancel(const qbs::ErrorInfo &reason) override; void startProcessCommand(); QString filterProcessOutput(const QByteArray &output, const QString &filterFunctionSource); void getProcessOutput(bool stdOut, ProcessResult &result); void sendProcessOutput(); void removeResponseFile(); ProcessCommand *processCommand() const; private: QString m_program; QStringList m_arguments; QString m_shellInvocation; QbsProcess m_process; QProcessEnvironment m_buildEnvironment; QProcessEnvironment m_commandEnvironment; QString m_responseFileName; qbs::ErrorInfo m_cancelReason; }; } // namespace Internal } // namespace qbs #endif // QBS_PROCESSCOMMANDEXECUTOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/transformer.cpp0000644000175100001660000003575314776170045022630 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "transformer.h" #include "artifact.h" #include "productbuilddata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { Transformer::Transformer() : alwaysRun(false) { } Transformer::~Transformer() = default; static JSValue js_baseName(JSContext *ctx, JSValueConst this_val, int, JSValueConst *) { return ScriptEngine::engineForContext(ctx)->getArtifactProperty(this_val, [ctx](const Artifact *a) { return makeJsString(ctx, FileInfo::baseName(a->filePath())); }); } static JSValue js_completeBaseName(JSContext *ctx, JSValueConst this_val, int, JSValueConst *) { return ScriptEngine::engineForContext(ctx)->getArtifactProperty(this_val, [ctx](const Artifact *a) { return makeJsString(ctx, FileInfo::completeBaseName(a->filePath())); }); } static JSValue js_baseDir(JSContext *ctx, JSValueConst this_val, int, JSValueConst *) { return ScriptEngine::engineForContext(ctx)->getArtifactProperty(this_val, [ctx](const Artifact *artifact) { QString basedir; if (artifact->artifactType == Artifact::SourceFile) { QDir sourceDir(artifact->product->sourceDirectory); basedir = FileInfo::path(sourceDir.relativeFilePath(artifact->filePath())); } else { QDir buildDir(artifact->product->buildDirectory()); basedir = FileInfo::path(buildDir.relativeFilePath(artifact->filePath())); } return makeJsString(ctx, basedir); }); } static JSValue js_children(JSContext *ctx, JSValueConst this_val, int, JSValueConst *) { return ScriptEngine::engineForContext(ctx)->getArtifactProperty(this_val, [ctx](const Artifact *artifact) { JSValue sv = JS_NewArray(ctx); uint idx = 0; // FIXME: childArtifacts() is not guarded by any mutex ... for (Artifact *child : artifact->childArtifacts()) { JS_SetPropertyUint32(ctx, sv, idx++, Transformer::translateFileConfig( ScriptEngine::engineForContext(ctx), child, QString())); } return sv; }); } static void setArtifactProperty(JSContext *ctx, JSValue &obj, const QString &name, JSCFunction *func) { const QByteArray nameBa = name.toUtf8(); const JSValue jsFunc = JS_NewCFunction(ctx, func, nameBa.constData(), 0); const ScopedJsAtom nameAtom(ctx, nameBa); JS_DefinePropertyGetSet(ctx, obj, nameAtom, jsFunc, JS_UNDEFINED, JS_PROP_HAS_GET); } JSValue Transformer::translateFileConfig(ScriptEngine *engine, Artifact *artifact, const QString &defaultModuleName) { return engine->getArtifactScriptValue(artifact, defaultModuleName, [&](JSValue obj) { ModuleProperties::init(engine, obj, artifact); JSContext * const ctx = engine->context(); setJsProperty(ctx, obj, StringConstants::fileNameProperty(), artifact->fileName()); setJsProperty(ctx, obj, StringConstants::filePathProperty(), artifact->filePath()); setArtifactProperty(ctx, obj, StringConstants::baseNameProperty(), js_baseName); setArtifactProperty(ctx, obj, StringConstants::completeBaseNameProperty(), js_completeBaseName); setArtifactProperty(ctx, obj, QStringLiteral("baseDir"), js_baseDir); setArtifactProperty(ctx, obj, QStringLiteral("children"), js_children); const QStringList fileTags = sorted(artifact->fileTags().toStringList()); const ScopedJsValue jsFileTags(ctx, engine->toScriptValue(fileTags)); engine->setObservedProperty(obj, StringConstants::fileTagsProperty(), jsFileTags); engine->observer()->addArtifactId(jsObjectId(obj)); if (!defaultModuleName.isEmpty()) setJsProperty(ctx, obj, StringConstants::moduleNameProperty(), defaultModuleName); }); } static bool compareByFilePath(const Artifact *a1, const Artifact *a2) { return a1->filePath() < a2->filePath(); } JSValue Transformer::translateInOutputs(ScriptEngine *engine, const ArtifactSet &artifacts, const QString &defaultModuleName) { using TagArtifactsMap = QMap>; TagArtifactsMap tagArtifactsMap; for (Artifact *artifact : artifacts) for (const FileTag &fileTag : artifact->fileTags()) tagArtifactsMap[fileTag.toString()].push_back(artifact); for (TagArtifactsMap::Iterator it = tagArtifactsMap.begin(); it != tagArtifactsMap.end(); ++it) std::sort(it.value().begin(), it.value().end(), compareByFilePath); JSValue jsTagFiles = engine->newObject(); for (auto tag = tagArtifactsMap.constBegin(); tag != tagArtifactsMap.constEnd(); ++tag) { const QList &artifacts = tag.value(); JSValue jsFileConfig = JS_NewArray(engine->context()); int i = 0; for (Artifact * const artifact : artifacts) { JS_SetPropertyUint32(engine->context(), jsFileConfig, i++, translateFileConfig(engine, artifact, defaultModuleName)); } setJsProperty(engine->context(), jsTagFiles, tag.key(), jsFileConfig); } return jsTagFiles; } ResolvedProductPtr Transformer::product() const { if (outputs.empty()) return {}; return (*outputs.cbegin())->product.lock(); } void Transformer::setupInputs(ScriptEngine *engine, JSValue targetScriptValue, const ArtifactSet &inputs, const QString &defaultModuleName) { JSValue scriptValue = translateInOutputs(engine, inputs, defaultModuleName); setJsProperty(engine->context(), targetScriptValue, StringConstants::inputsVar(), scriptValue); JSValue inputScriptValue = JS_UNDEFINED; if (inputs.size() == 1) { Artifact *input = *inputs.cbegin(); const FileTags &fileTags = input->fileTags(); QBS_ASSERT(!fileTags.empty(), return); const ScopedJsValue inputsForFileTag( engine->context(), getJsProperty(engine->context(), scriptValue, fileTags.cbegin()->toString())); inputScriptValue = JS_GetPropertyUint32(engine->context(), inputsForFileTag, 0); } setJsProperty(engine->context(), targetScriptValue, StringConstants::inputVar(), inputScriptValue); } void Transformer::setupInputs(ScriptEngine *engine, const JSValue &targetScriptValue) { setupInputs(engine, targetScriptValue, inputs, rule->module->name); } void Transformer::setupOutputs(ScriptEngine *engine, JSValue targetScriptValue) { const QString &defaultModuleName = rule->module->name; JSValue scriptValue = translateInOutputs(engine, outputs, defaultModuleName); setJsProperty(engine->context(), targetScriptValue, StringConstants::outputsVar(), scriptValue); JSValue outputScriptValue = JS_UNDEFINED; if (outputs.size() == 1) { Artifact *output = *outputs.cbegin(); const FileTags &fileTags = output->fileTags(); QBS_ASSERT(!fileTags.empty(), return); const ScopedJsValue outputsForFileTag( engine->context(), getJsProperty(engine->context(), scriptValue, fileTags.cbegin()->toString())); outputScriptValue = JS_GetPropertyUint32(engine->context(), outputsForFileTag, 0); } setJsProperty(engine->context(), targetScriptValue, StringConstants::outputVar(), outputScriptValue); } void Transformer::setupExplicitlyDependsOn(ScriptEngine *engine, JSValue targetScriptValue) { JSValue scriptValue = translateInOutputs(engine, explicitlyDependsOn, rule->module->name); setJsProperty(engine->context(), targetScriptValue, StringConstants::explicitlyDependsOnVar(), scriptValue); } AbstractCommandPtr Transformer::createCommandFromScriptValue( ScriptEngine *engine, const JSValue &scriptValue, const CodeLocation &codeLocation) { AbstractCommandPtr cmdBase; if (JS_IsUndefined(scriptValue) || JS_IsUninitialized(scriptValue)) return cmdBase; QString className = getJsStringProperty(engine->context(), scriptValue, StringConstants::classNameProperty()); if (className == StringConstants::commandType()) cmdBase = ProcessCommand::create(); else if (className == StringConstants::javaScriptCommandType()) cmdBase = JavaScriptCommand::create(); if (cmdBase) cmdBase->fillFromScriptValue(engine->context(), &scriptValue, codeLocation); if (className == StringConstants::commandType()) { auto procCmd = static_cast(cmdBase.get()); procCmd->clearRelevantEnvValues(); const auto envVars = procCmd->relevantEnvVars(); for (const QString &key : envVars) procCmd->addRelevantEnvValue(key, product()->buildEnvironment.value(key)); } return cmdBase; } void Transformer::createCommands(ScriptEngine *engine, const PrivateScriptFunction &script, const JSValueList &args) { JSValueList argv(args.cbegin(), args.cend()); const JSValue function = script.getFunction(engine, Tr::tr("Invalid prepare script.")); const ScopedJsValue scriptValue( engine->context(), JS_Call(engine->context(), function, engine->globalObject(), int(argv.size()), argv.data())); propertiesRequestedInPrepareScript = engine->propertiesRequestedInScript(); propertiesRequestedFromArtifactInPrepareScript = engine->propertiesRequestedFromArtifact(); importedFilesUsedInPrepareScript = engine->importedFilesUsedInScript(); depsRequestedInPrepareScript = engine->requestedDependencies(); artifactsMapRequestedInPrepareScript = engine->requestedArtifacts(); lastPrepareScriptExecutionTime = FileTime::currentTime(); for (const ResolvedProduct * const p : engine->requestedExports()) { exportedModulesAccessedInPrepareScript.insert(std::make_pair(p->uniqueName(), p->exportedModule)); } engine->clearRequestedProperties(); if (JsException ex = engine->checkAndClearException(script.location())) throw ex.toErrorInfo(); commands.clear(); if (JS_IsArray(engine->context(), scriptValue)) { const int count = JS_VALUE_GET_INT(getJsProperty(engine->context(), scriptValue, StringConstants::lengthProperty())); for (qint32 i = 0; i < count; ++i) { ScopedJsValue item(engine->context(), JS_GetPropertyUint32(engine->context(), scriptValue, i)); if (!JS_IsUninitialized(item) && !JS_IsUndefined(item)) { const AbstractCommandPtr cmd = createCommandFromScriptValue(engine, item, script.location()); if (cmd) commands.addCommand(cmd); } } } else { const AbstractCommandPtr cmd = createCommandFromScriptValue(engine, scriptValue, script.location()); if (cmd) commands.addCommand(cmd); } } void Transformer::rescueChangeTrackingData(const TransformerConstPtr &other) { if (!other) return; propertiesRequestedInPrepareScript = other->propertiesRequestedInPrepareScript; propertiesRequestedInCommands = other->propertiesRequestedInCommands; propertiesRequestedFromArtifactInPrepareScript = other->propertiesRequestedFromArtifactInPrepareScript; propertiesRequestedFromArtifactInCommands = other->propertiesRequestedFromArtifactInCommands; importedFilesUsedInPrepareScript = other->importedFilesUsedInPrepareScript; importedFilesUsedInCommands = other->importedFilesUsedInCommands; depsRequestedInPrepareScript = other->depsRequestedInPrepareScript; depsRequestedInCommands = other->depsRequestedInCommands; artifactsMapRequestedInPrepareScript = other->artifactsMapRequestedInPrepareScript; artifactsMapRequestedInCommands = other->artifactsMapRequestedInCommands; lastCommandExecutionTime = other->lastCommandExecutionTime; lastPrepareScriptExecutionTime = other->lastPrepareScriptExecutionTime; prepareScriptNeedsChangeTracking = other->prepareScriptNeedsChangeTracking; commandsNeedChangeTracking = other->commandsNeedChangeTracking; markedForRerun = other->markedForRerun; exportedModulesAccessedInPrepareScript = other->exportedModulesAccessedInPrepareScript; exportedModulesAccessedInCommands = other->exportedModulesAccessedInCommands; } Set Transformer::jobPools() const { Set pools; for (const AbstractCommandPtr &c : commands.commands()) { if (!c->jobPool().isEmpty()) pools.insert(c->jobPool()); } return pools; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/artifactcleaner.cpp0000644000175100001660000002003214776170045023375 0ustar runnerdocker#include /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "artifactcleaner.h" #include "artifact.h" #include "artifactvisitor.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static void printRemovalMessage(const QString &path, bool dryRun, const Logger &logger) { if (dryRun) logger.qbsInfo() << Tr::tr("Would remove '%1'.").arg(path); else logger.qbsDebug() << "Removing '" << path << "'."; } static void invalidateArtifactTimestamp(Artifact *artifact) { if (artifact->timestamp().isValid()) { artifact->clearTimestamp(); artifact->product->topLevelProject()->buildData->setDirty(); } } static void removeArtifactFromDisk(Artifact *artifact, bool dryRun, const Logger &logger) { QFileInfo fileInfo(artifact->filePath()); if (!FileInfo::fileExists(fileInfo)) { if (!dryRun) invalidateArtifactTimestamp(artifact); return; } printRemovalMessage(fileInfo.filePath(), dryRun, logger); if (dryRun) return; invalidateArtifactTimestamp(artifact); QString errorMessage; if (!removeFileRecursion(fileInfo, &errorMessage)) throw ErrorInfo(errorMessage); } class CleanupVisitor : public ArtifactVisitor { public: CleanupVisitor(CleanOptions options, const ProgressObserver *observer, Logger logger) : ArtifactVisitor(Artifact::Generated) , m_options(std::move(options)) , m_observer(observer) , m_logger(std::move(logger)) , m_hasError(false) { } void visitProduct(const ResolvedProductPtr &product) { m_product = product; ArtifactVisitor::visitProduct(product); const AllRescuableArtifactData rescuableArtifactData = product->buildData->rescuableArtifactData(); for (auto it = rescuableArtifactData.begin(); it != rescuableArtifactData.end(); ++it) { Artifact tmp; tmp.product = product; tmp.setFilePath(it.key()); tmp.setTimestamp(it.value().timeStamp); removeArtifactFromDisk(&tmp, m_options.dryRun(), m_logger); product->buildData->removeFromRescuableArtifactData(it.key()); } } const Set &directories() const { return m_directories; } bool hasError() const { return m_hasError; } private: void doVisit(Artifact *artifact) override { if (m_observer->canceled()) throw ErrorInfo(Tr::tr("Cleaning up was canceled.")); if (artifact->product != m_product) return; try { removeArtifactFromDisk(artifact, m_options.dryRun(), m_logger); } catch (const ErrorInfo &error) { if (!m_options.keepGoing()) throw; m_logger.printError(error); m_hasError = true; } m_directories << artifact->dirPath(); } const CleanOptions m_options; const ProgressObserver * const m_observer; Logger m_logger; bool m_hasError; ResolvedProductConstPtr m_product; Set m_directories; }; ArtifactCleaner::ArtifactCleaner(Logger logger, ProgressObserver *observer) : m_logger(std::move(logger)), m_observer(observer) { } void ArtifactCleaner::cleanup(const TopLevelProjectPtr &project, const QVector &products, const CleanOptions &options) { m_hasError = false; const QString configString = Tr::tr(" for configuration %1").arg(project->id()); m_observer->initialize(Tr::tr("Cleaning up%1").arg(configString), products.size() + 1); Set directories; for (const ResolvedProductPtr &product : products) { CleanupVisitor visitor(options, m_observer, m_logger); visitor.visitProduct(product); directories.unite(visitor.directories()); if (visitor.hasError()) m_hasError = true; m_observer->incrementProgressValue(); } // Directories created during the build are not artifacts (TODO: should they be?), // so we have to clean them up manually. auto dirList = rangeTo(directories); for (int i = 0; i < dirList.size(); ++i) { const QString &dir = dirList.at(i); if (!dir.startsWith(project->buildDirectory)) continue; if (FileInfo(dir).exists()) removeEmptyDirectories(dir, options); if (dir != project->buildDirectory) { const QString parentDir = QDir::cleanPath(dir + StringConstants::slashDotDot()); if (parentDir != project->buildDirectory && !dirList.contains(parentDir)) dirList.push_back(parentDir); } } m_observer->incrementProgressValue(); if (m_hasError) throw ErrorInfo(Tr::tr("Failed to remove some files.")); m_observer->setFinished(); } void ArtifactCleaner::removeEmptyDirectories(const QString &rootDir, const CleanOptions &options, bool *isEmpty) { bool subTreeIsEmpty = true; QDirIterator it(rootDir, QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot); while (it.hasNext()) { it.next(); if (!it.fileInfo().isSymLink() && it.fileInfo().isDir()) removeEmptyDirectories(it.filePath(), options, &subTreeIsEmpty); else subTreeIsEmpty = false; } if (subTreeIsEmpty) { printRemovalMessage(rootDir, options.dryRun(), m_logger); if (!QDir::root().rmdir(rootDir)) { ErrorInfo error(Tr::tr("Failure to remove empty directory '%1'.").arg(rootDir)); if (!options.keepGoing()) throw error; m_logger.printError(error); m_hasError = true; subTreeIsEmpty = false; } } if (!subTreeIsEmpty && isEmpty) *isEmpty = false; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/rulecommands.h0000644000175100001660000002254014776170045022412 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPH_COMMAND_H #define QBS_BUILDGRAPH_COMMAND_H #include "forward_decls.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { class ScriptEngine; class AbstractCommand { public: virtual ~AbstractCommand(); enum CommandType { ProcessCommandType, JavaScriptCommandType }; static QString defaultDescription() { return {}; } static QString defaultExtendedDescription() { return {}; } static QString defaultHighLight() { return {}; } static bool defaultIgnoreDryRun() { return false; } static bool defaultIsSilent() { return false; } static int defaultTimeout() { return -1; } virtual CommandType type() const = 0; virtual bool equals(const AbstractCommand *other) const; virtual void fillFromScriptValue(JSContext *ctx, const JSValue *scriptValue, const CodeLocation &codeLocation); virtual QString descriptionForCancelMessage(const QString &productName) const; QString fullDescription(const QString &productName) const; const QString description() const { return m_description; } const QString extendedDescription() const { return m_extendedDescription; } const QString highlight() const { return m_highlight; } bool ignoreDryRun() const { return m_ignoreDryRun; } bool isSilent() const { return m_silent; } QString jobPool() const { return m_jobPool; } CodeLocation codeLocation() const { return m_codeLocation; } int timeout() const { return m_timeout; } const QVariantMap &properties() const { return m_properties; } virtual void load(PersistentPool &pool); virtual void store(PersistentPool &pool); protected: AbstractCommand(); void applyCommandProperties(JSContext *ctx, const JSValue *scriptValue); Set m_predefinedProperties; private: template void serializationOp(PersistentPool &pool) { pool.serializationOp(m_description, m_extendedDescription, m_highlight, m_ignoreDryRun, m_silent, m_codeLocation, m_jobPool, m_timeout, m_properties); } QString m_description; QString m_extendedDescription; QString m_highlight; bool m_ignoreDryRun; bool m_silent; CodeLocation m_codeLocation; QString m_jobPool; int m_timeout; QVariantMap m_properties; }; class ProcessCommand : public AbstractCommand { public: static ProcessCommandPtr create() { return ProcessCommandPtr(new ProcessCommand); } static void setupForJavaScript(ScriptEngine *engine, JSValue targetObject); CommandType type() const override { return ProcessCommandType; } bool equals(const AbstractCommand *otherAbstractCommand) const override; void fillFromScriptValue(JSContext *ctx, const JSValue *scriptValue, const CodeLocation &codeLocation) override; QString descriptionForCancelMessage(const QString &productName) const override; const QString program() const { return m_program; } const QStringList arguments() const { return m_arguments; } const QString workingDir() const { return m_workingDir; } int maxExitCode() const { return m_maxExitCode; } QString stdoutFilterFunction() const { return m_stdoutFilterFunction; } QString stderrFilterFunction() const { return m_stderrFilterFunction; } int responseFileThreshold() const { return m_responseFileThreshold; } int responseFileArgumentIndex() const { return m_responseFileArgumentIndex; } QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; } QString responseFileSeparator() const { return m_responseFileSeparator; } QProcessEnvironment environment() const { return m_environment; } QStringList relevantEnvVars() const; void clearRelevantEnvValues() { m_relevantEnvValues.clear(); } void addRelevantEnvValue(const QString &key, const QString &value); QString relevantEnvValue(const QString &key) const { return m_relevantEnvValues.value(key); } QString stdoutFilePath() const { return m_stdoutFilePath; } QString stderrFilePath() const { return m_stderrFilePath; } void load(PersistentPool &pool) override; void store(PersistentPool &pool) override; private: ProcessCommand(); int defaultResponseFileThreshold() const; void getEnvironmentFromList(const QStringList &envList); template void serializationOp(PersistentPool &pool) { pool.serializationOp(m_program, m_arguments, m_environment, m_workingDir, m_stdoutFilterFunction, m_stderrFilterFunction, m_responseFileUsagePrefix, m_responseFileSeparator, m_maxExitCode, m_responseFileThreshold, m_responseFileArgumentIndex, m_relevantEnvVars, m_relevantEnvValues, m_stdoutFilePath, m_stderrFilePath); } QString m_program; QStringList m_arguments; QString m_workingDir; int m_maxExitCode; QString m_stdoutFilterFunction; QString m_stderrFilterFunction; int m_responseFileThreshold; // When to use response files? In bytes of (program name + arguments). int m_responseFileArgumentIndex; QString m_responseFileUsagePrefix; QString m_responseFileSeparator; QProcessEnvironment m_environment; QStringList m_relevantEnvVars; QProcessEnvironment m_relevantEnvValues; QString m_stdoutFilePath; QString m_stderrFilePath; }; class JavaScriptCommand : public AbstractCommand { public: static JavaScriptCommandPtr create() { return JavaScriptCommandPtr(new JavaScriptCommand); } static void setupForJavaScript(ScriptEngine *engine, JSValue targetObject); CommandType type() const override { return JavaScriptCommandType; } bool equals(const AbstractCommand *otherAbstractCommand) const override; void fillFromScriptValue(JSContext *ctx, const JSValue *scriptValue, const CodeLocation &codeLocation) override; const QString &scopeName() const { return m_scopeName; } const QString &sourceCode() const { return m_sourceCode; } void load(PersistentPool &pool) override; void store(PersistentPool &pool) override; private: JavaScriptCommand(); template void serializationOp(PersistentPool &pool) { pool.serializationOp(m_scopeName, m_sourceCode); } QString m_scopeName; QString m_sourceCode; }; class CommandList { public: bool empty() const { return m_commands.empty(); } int size() const { return m_commands.size(); } AbstractCommandPtr commandAt(int i) const { return m_commands.at(i); } const QList &commands() const { return m_commands; } void clear() { m_commands.clear(); } void addCommand(const AbstractCommandPtr &cmd) { m_commands.push_back(cmd); } void load(PersistentPool &pool); void store(PersistentPool &pool) const; private: QList m_commands; }; bool operator==(const CommandList &cl1, const CommandList &cl2); inline bool operator!=(const CommandList &cl1, const CommandList &cl2) { return !(cl1 == cl2); } } // namespace Internal } // namespace qbs #endif // QBS_BUILDGRAPH_COMMAND_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rawscanresults.cpp0000644000175100001660000000622714776170045023340 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rawscanresults.h" #include "filedependency.h" #include "depscanner.h" #include namespace qbs { namespace Internal { RawScanResults::ScanData &RawScanResults::findScanData( const FileResourceBase *file, const QString &scannerId, const PropertyMapConstPtr &moduleProperties, const FilterFunction &filter) { std::vector &scanDataForFile = m_rawScanData[file->filePath()]; for (auto &scanData : scanDataForFile) { if (scannerId != scanData.scannerId) continue; if (!filter(moduleProperties, scanData.moduleProperties)) continue; return scanData; } ScanData newScanData; newScanData.scannerId = scannerId; newScanData.moduleProperties = moduleProperties; scanDataForFile.push_back(std::move(newScanData)); return scanDataForFile.back(); } RawScanResults::ScanData &RawScanResults::findScanData( const FileResourceBase *file, const DependencyScanner *scanner, const PropertyMapConstPtr &moduleProperties) { auto predicate = [scanner](const PropertyMapConstPtr &lhs, const PropertyMapConstPtr &rhs) { return scanner->areModulePropertiesCompatible(lhs, rhs); }; return findScanData(file, scanner->id(), moduleProperties, predicate); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/jscommandexecutor.h0000644000175100001660000000561714776170045023461 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_JSCOMMANDEXECUTOR_H #define QBS_JSCOMMANDEXECUTOR_H #include "abstractcommandexecutor.h" #include namespace qbs { class CodeLocation; namespace Internal { class JavaScriptCommand; class JsCommandExecutorThreadObject; class JsCommandExecutor : public AbstractCommandExecutor { Q_OBJECT public: explicit JsCommandExecutor(const Logger &logger, QObject *parent = nullptr); ~JsCommandExecutor() override; signals: void startRequested(const JavaScriptCommand *cmd, Transformer *transformer); private: void onJavaScriptCommandFinished(); void doReportCommandDescription(const QString &productName) override; bool doStart() override; void cancel(const qbs::ErrorInfo &reason) override; void waitForFinished(); const JavaScriptCommand *jsCommand() const; QThread *m_thread; JsCommandExecutorThreadObject *m_objectInThread; bool m_running; }; } // namespace Internal } // namespace qbs #endif // QBS_JSCOMMANDEXECUTOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/productbuilddata.cpp0000644000175100001660000001065514776170045023612 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "productbuilddata.h" #include "artifact.h" #include "projectbuilddata.h" #include "rulecommands.h" #include #include #include #include namespace qbs { namespace Internal { ProductBuildData::~ProductBuildData() { qDeleteAll(m_nodes); } const TypeFilter ProductBuildData::rootArtifacts() const { return TypeFilter(m_roots); } void ProductBuildData::addArtifact(Artifact *artifact) { QBS_CHECK(m_nodes.insert(artifact).second); addArtifactToSet(artifact); } void ProductBuildData::addArtifactToSet(Artifact *artifact) { std::lock_guard l(m_artifactsMapMutex); for (const FileTag &tag : artifact->fileTags()) { m_artifactsByFileTag[tag] += artifact; m_jsArtifactsMapUpToDate = false; } } void ProductBuildData::removeArtifact(Artifact *artifact) { m_roots.remove(artifact); m_nodes.remove(artifact); removeArtifactFromSet(artifact); } void ProductBuildData::removeArtifactFromSetByFileTag(Artifact *artifact, const FileTag &fileTag) { std::lock_guard l(m_artifactsMapMutex); const auto it = m_artifactsByFileTag.find(fileTag); if (it == m_artifactsByFileTag.end()) return; it->remove(artifact); if (it->empty()) m_artifactsByFileTag.erase(it); m_jsArtifactsMapUpToDate = false; } void ProductBuildData::addFileTagToArtifact(Artifact *artifact, const FileTag &tag) { std::lock_guard l(m_artifactsMapMutex); m_artifactsByFileTag[tag] += artifact; m_jsArtifactsMapUpToDate = false; } ArtifactSetByFileTag ProductBuildData::artifactsByFileTag() const { return m_artifactsByFileTag; } void ProductBuildData::setRescuableArtifactData(const AllRescuableArtifactData &rad) { m_rescuableArtifactData = rad; } RescuableArtifactData ProductBuildData::removeFromRescuableArtifactData(const QString &filePath) { return m_rescuableArtifactData.take(filePath); } void ProductBuildData::addRescuableArtifactData(const QString &filePath, const RescuableArtifactData &rad) { m_rescuableArtifactData.insert(filePath, rad); } bool ProductBuildData::checkAndSetJsArtifactsMapUpToDateFlag() { if (!m_jsArtifactsMapUpToDate) { m_jsArtifactsMapUpToDate = true; return false; } return true; } void ProductBuildData::removeArtifactFromSet(Artifact *artifact) { for (const FileTag &t : artifact->fileTags()) removeArtifactFromSetByFileTag(artifact, t); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/filedependency.h0000644000175100001660000000623514776170045022702 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_FILEDEPENDENCY_H #define QBS_FILEDEPENDENCY_H #include #include namespace qbs { namespace Internal { class FileResourceBase { protected: FileResourceBase(); public: virtual ~FileResourceBase(); enum FileType { FileTypeDependency, FileTypeArtifact }; virtual FileType fileType() const = 0; void setTimestamp(const FileTime &t); const FileTime ×tamp() const; void clearTimestamp() { m_timestamp.clear(); } void setFilePath(const QString &filePath); const QString &filePath() const; QString dirPath() const { return m_dirPath.toString(); } QString fileName() const { return m_fileName.toString(); } virtual void load(PersistentPool &pool); virtual void store(PersistentPool &pool); private: template void serializationOp(PersistentPool &pool) { pool.serializationOp(m_filePath, m_timestamp); } FileTime m_timestamp; QString m_filePath; QStringView m_dirPath; QStringView m_fileName; }; class FileDependency : public FileResourceBase { public: FileDependency(); ~FileDependency() override; FileType fileType() const override { return FileTypeDependency; } }; } // namespace Internal } // namespace qbs #endif // QBS_FILEDEPENDENCY_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rulesevaluationcontext.h0000644000175100001660000000624014776170045024547 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RULESEVALUATIONCONTEXT_H #define QBS_RULESEVALUATIONCONTEXT_H #include #include #include #include #include namespace qbs { namespace Internal { class ProgressObserver; class ScriptEngine; class RulesEvaluationContext { public: RulesEvaluationContext(Logger logger); ~RulesEvaluationContext(); class Scope { public: Scope(RulesEvaluationContext *evalContext); ~Scope(); private: RulesEvaluationContext * const m_evalContext; }; ScriptEngine *engine() const { return m_engine.get(); } JSValue scope() const { return m_scope; } void setObserver(ProgressObserver *observer) { m_observer = observer; } ProgressObserver *observer() const { return m_observer; } void initializeObserver(const QString &description, int maximumProgress); void incrementProgressValue(); void checkForCancelation(); private: void initScope(); void cleanupScope(); Logger m_logger; const std::unique_ptr m_engine; ProgressObserver *m_observer; unsigned int m_initScopeCalls; JSValue m_scope = JS_UNDEFINED; const JSValue m_prepareScriptScope; }; } // namespace Internal } // namespace qbs #endif // QBS_RULESEVALUATIONCONTEXT_H qbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraphvisitor.h0000644000175100001660000000475214776170045023467 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPHVISITOR_H #define QBS_BUILDGRAPHVISITOR_H namespace qbs { namespace Internal { class Artifact; class RuleNode; /*! * \brief The BuildGraphVisitor class * * The return value of a visit method indicates whether the children of the current node * are to be visited next. */ class BuildGraphVisitor { public: virtual ~BuildGraphVisitor() = default; virtual bool visit(Artifact *) { return true; } virtual void endVisit(Artifact *) { } virtual bool visit(RuleNode *) { return true; } virtual void endVisit(RuleNode *) { } }; } // namespace Internal } // namespace qbs #endif // QBS_BUILDGRAPHVISITOR_H qbs-src-2.6.1/src/lib/corelib/buildgraph/rulecommands.cpp0000644000175100001660000005155414776170045022754 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rulecommands.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { static QString argumentsProperty() { return QStringLiteral("arguments"); } static QString environmentProperty() { return QStringLiteral("environment"); } static QString extendedDescriptionProperty() { return QStringLiteral("extendedDescription"); } static QString highlightProperty() { return QStringLiteral("highlight"); } static QString ignoreDryRunProperty() { return QStringLiteral("ignoreDryRun"); } static QString maxExitCodeProperty() { return QStringLiteral("maxExitCode"); } static QString programProperty() { return QStringLiteral("program"); } static QString responseFileArgumentIndexProperty() { return QStringLiteral("responseFileArgumentIndex"); } static QString responseFileThresholdProperty() { return QStringLiteral("responseFileThreshold"); } static QString responseFileUsagePrefixProperty() { return QStringLiteral("responseFileUsagePrefix"); } static QString responseFileSeparatorProperty() { return QStringLiteral("responseFileSeparator"); } static QString silentProperty() { return QStringLiteral("silent"); } static QString stderrFilePathProperty() { return QStringLiteral("stderrFilePath"); } static QString stderrFilterFunctionProperty() { return QStringLiteral("stderrFilterFunction"); } static QString stdoutFilePathProperty() { return QStringLiteral("stdoutFilePath"); } static QString stdoutFilterFunctionProperty() { return QStringLiteral("stdoutFilterFunction"); } static QString timeoutProperty() { return QStringLiteral("timeout"); } static QString workingDirProperty() { return QStringLiteral("workingDirectory"); } static QString invokedSourceCode(JSContext *ctx, const JSValue &codeOrFunction) { const QString &code = getJsString(ctx, codeOrFunction); return JS_IsFunction(ctx, codeOrFunction) ? QStringLiteral("(") + code + QStringLiteral(")()") : code; } AbstractCommand::AbstractCommand() : m_description(defaultDescription()), m_extendedDescription(defaultExtendedDescription()), m_highlight(defaultHighLight()), m_ignoreDryRun(defaultIgnoreDryRun()), m_silent(defaultIsSilent()), m_timeout(defaultTimeout()) { } AbstractCommand::~AbstractCommand() = default; bool AbstractCommand::equals(const AbstractCommand *other) const { return type() == other->type() && m_description == other->m_description && m_extendedDescription == other->m_extendedDescription && m_highlight == other->m_highlight && m_ignoreDryRun == other->m_ignoreDryRun && m_silent == other->m_silent && m_jobPool == other->m_jobPool && m_timeout == other->m_timeout && qVariantMapsEqual(m_properties, other->m_properties); } void AbstractCommand::fillFromScriptValue(JSContext *ctx, const JSValue *scriptValue, const CodeLocation &codeLocation) { m_description = getJsStringProperty(ctx, *scriptValue, StringConstants::descriptionProperty()); m_extendedDescription = getJsStringProperty(ctx, *scriptValue, extendedDescriptionProperty()); m_highlight = getJsStringProperty(ctx, *scriptValue, highlightProperty()); m_ignoreDryRun = getJsBoolProperty(ctx, *scriptValue, ignoreDryRunProperty()); m_silent = getJsBoolProperty(ctx, *scriptValue, silentProperty()); m_jobPool = getJsStringProperty(ctx, *scriptValue, StringConstants::jobPoolProperty()); const auto timeoutScriptValue = getJsProperty(ctx, *scriptValue, timeoutProperty()); if (!JS_IsUndefined(timeoutScriptValue) && !JS_IsNull(timeoutScriptValue)) m_timeout = JS_VALUE_GET_INT(timeoutScriptValue); m_codeLocation = codeLocation; m_predefinedProperties << StringConstants::descriptionProperty() << extendedDescriptionProperty() << highlightProperty() << ignoreDryRunProperty() << StringConstants::jobPoolProperty() << silentProperty() << timeoutProperty(); } QString AbstractCommand::fullDescription(const QString &productName) const { return QLatin1Char('[') + productName + QLatin1String("] ") + description(); } QString AbstractCommand::descriptionForCancelMessage(const QString &productName) const { return fullDescription(productName); } void AbstractCommand::load(PersistentPool &pool) { serializationOp(pool); } void AbstractCommand::store(PersistentPool &pool) { serializationOp(pool); } void AbstractCommand::applyCommandProperties(JSContext *ctx, const JSValue *scriptValue) { handleJsProperties(ctx, *scriptValue, [this, ctx](const JSAtom &prop, const JSPropertyDescriptor &desc) { const QString name = getJsString(ctx, prop); if (m_predefinedProperties.contains(name)) return; // TODO: Use script class for command objects, don't allow setting random properties if (!isSimpleValue(desc.value)) { throw ErrorInfo(Tr::tr("Property '%1' has a type unsuitable for storing in a command " "object.").arg(name), m_codeLocation); } m_properties.insert(name, getJsVariant(ctx, desc.value)); }); } static JSValue js_CommandBase(JSContext *ctx) { const JSValue cmd = JS_NewObject(ctx); setJsProperty(ctx, cmd, StringConstants::descriptionProperty(), makeJsString(ctx, AbstractCommand::defaultDescription())); setJsProperty(ctx, cmd, extendedDescriptionProperty(), makeJsString(ctx, AbstractCommand::defaultExtendedDescription())); setJsProperty(ctx, cmd, highlightProperty(), makeJsString(ctx, AbstractCommand::defaultHighLight())); setJsProperty(ctx, cmd, ignoreDryRunProperty(), JS_NewBool(ctx, AbstractCommand::defaultIgnoreDryRun())); setJsProperty(ctx, cmd, silentProperty(), JS_NewBool(ctx, AbstractCommand::defaultIsSilent())); setJsProperty(ctx, cmd, timeoutProperty(), JS_NewInt32(ctx, AbstractCommand::defaultTimeout())); return cmd; } static JSValue js_Command(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *argv, int) { static ProcessCommandPtr commandPrototype = ProcessCommand::create(); JSValue program = JS_UNDEFINED; if (argc > 0) program = JS_DupValue(ctx, argv[0]); if (JS_IsUndefined(program)) program = makeJsString(ctx, commandPrototype->program()); JSValue arguments = JS_UNDEFINED; if (argc > 1) arguments = JS_DupValue(ctx, argv[1]); if (JS_IsUndefined(arguments)) arguments = makeJsStringList(ctx, commandPrototype->arguments()); if (JS_IsString(arguments)) { JSValue args = JS_NewArray(ctx); JS_SetPropertyUint32(ctx, args, 0, arguments); arguments = args; } JSValue cmd = js_CommandBase(ctx); setJsProperty(ctx, cmd, StringConstants::classNameProperty(), makeJsString(ctx, StringConstants::commandType())); setJsProperty(ctx, cmd, programProperty(), program); setJsProperty(ctx, cmd, argumentsProperty(), arguments); setJsProperty(ctx, cmd, workingDirProperty(), makeJsString(ctx, commandPrototype->workingDir())); setJsProperty(ctx, cmd, maxExitCodeProperty(), JS_NewInt32(ctx, commandPrototype->maxExitCode())); setJsProperty(ctx, cmd, stdoutFilterFunctionProperty(), makeJsString(ctx, commandPrototype->stdoutFilterFunction())); setJsProperty(ctx, cmd, stderrFilterFunctionProperty(), makeJsString(ctx, commandPrototype->stderrFilterFunction())); setJsProperty(ctx, cmd, responseFileThresholdProperty(), JS_NewInt32(ctx, commandPrototype->responseFileThreshold())); setJsProperty(ctx, cmd, responseFileArgumentIndexProperty(), JS_NewInt32(ctx, commandPrototype->responseFileArgumentIndex())); setJsProperty(ctx, cmd, responseFileUsagePrefixProperty(), makeJsString(ctx, commandPrototype->responseFileUsagePrefix())); setJsProperty(ctx, cmd, responseFileSeparatorProperty(), makeJsString(ctx, commandPrototype->responseFileSeparator())); setJsProperty(ctx, cmd, stdoutFilePathProperty(), makeJsString(ctx, commandPrototype->stdoutFilePath())); setJsProperty(ctx, cmd, stderrFilePathProperty(), makeJsString(ctx, commandPrototype->stderrFilePath())); setJsProperty(ctx, cmd, environmentProperty(), makeJsStringList(ctx, commandPrototype->environment().toStringList())); setJsProperty(ctx, cmd, ignoreDryRunProperty(), JS_NewBool(ctx, commandPrototype->ignoreDryRun())); return cmd; } void ProcessCommand::setupForJavaScript(ScriptEngine *engine, JSValue targetObject) { engine->registerClass(StringConstants::commandType().toUtf8().constData(), js_Command, nullptr, targetObject); } ProcessCommand::ProcessCommand() : m_maxExitCode(0) , m_responseFileThreshold(defaultResponseFileThreshold()) , m_responseFileArgumentIndex(0) , m_responseFileSeparator(QStringLiteral("\n")) { } int ProcessCommand::defaultResponseFileThreshold() const { // TODO: Non-Windows platforms likely have their own limits. Investigate. return HostOsInfo::isWindowsHost() ? 31000 // 32000 minus "safety offset" : -1; } void ProcessCommand::getEnvironmentFromList(const QStringList &envList) { m_environment.clear(); for (const QString &env : envList) { const int equalsIndex = env.indexOf(QLatin1Char('=')); if (equalsIndex <= 0 || equalsIndex == env.size() - 1) continue; const QString &var = env.left(equalsIndex); const QString &value = env.mid(equalsIndex + 1); m_environment.insert(var, value); } } bool ProcessCommand::equals(const AbstractCommand *otherAbstractCommand) const { if (!AbstractCommand::equals(otherAbstractCommand)) return false; const auto other = static_cast(otherAbstractCommand); return m_program == other->m_program && m_arguments == other->m_arguments && m_workingDir == other->m_workingDir && m_maxExitCode == other->m_maxExitCode && m_stdoutFilterFunction == other->m_stdoutFilterFunction && m_stderrFilterFunction == other->m_stderrFilterFunction && m_responseFileThreshold == other->m_responseFileThreshold && m_responseFileArgumentIndex == other->m_responseFileArgumentIndex && m_responseFileUsagePrefix == other->m_responseFileUsagePrefix && m_responseFileSeparator == other->m_responseFileSeparator && m_stdoutFilePath == other->m_stdoutFilePath && m_stderrFilePath == other->m_stderrFilePath && m_relevantEnvVars == other->m_relevantEnvVars && m_relevantEnvValues == other->m_relevantEnvValues && m_environment == other->m_environment; } void ProcessCommand::fillFromScriptValue(JSContext *ctx, const JSValue *scriptValue, const CodeLocation &codeLocation) { AbstractCommand::fillFromScriptValue(ctx, scriptValue, codeLocation); m_program = getJsStringProperty(ctx, *scriptValue, programProperty()); m_arguments = getJsStringListProperty(ctx, *scriptValue, argumentsProperty()); m_workingDir = getJsStringProperty(ctx, *scriptValue, workingDirProperty()); m_maxExitCode = getJsIntProperty(ctx, *scriptValue, maxExitCodeProperty()); const ScopedJsValue stdoutFilterFunction(ctx, getJsProperty(ctx, *scriptValue, stdoutFilterFunctionProperty())); if (JS_IsFunction(ctx, stdoutFilterFunction)) m_stdoutFilterFunction = QLatin1Char('(') + getJsString(ctx, stdoutFilterFunction) + QLatin1Char(')'); const ScopedJsValue stderrFilterFunction(ctx, getJsProperty(ctx, *scriptValue, stderrFilterFunctionProperty())); if (JS_IsFunction(ctx, stderrFilterFunction)) m_stderrFilterFunction = QLatin1Char('(') + getJsString(ctx, stderrFilterFunction) + QLatin1Char(')'); m_relevantEnvVars = getJsStringListProperty(ctx, *scriptValue, QStringLiteral("relevantEnvironmentVariables")); m_responseFileThreshold = getJsIntProperty(ctx, *scriptValue, responseFileThresholdProperty()); m_responseFileArgumentIndex = getJsIntProperty(ctx, *scriptValue, responseFileArgumentIndexProperty()); m_responseFileUsagePrefix = getJsStringProperty(ctx, *scriptValue, responseFileUsagePrefixProperty()); m_responseFileSeparator = getJsStringProperty(ctx, *scriptValue, responseFileSeparatorProperty()); QStringList envList = getJsStringListProperty(ctx, *scriptValue, environmentProperty()); getEnvironmentFromList(envList); m_stdoutFilePath = getJsStringProperty(ctx, *scriptValue, stdoutFilePathProperty()); m_stderrFilePath = getJsStringProperty(ctx, *scriptValue, stderrFilePathProperty()); m_predefinedProperties << programProperty() << argumentsProperty() << workingDirProperty() << maxExitCodeProperty() << stdoutFilterFunctionProperty() << stderrFilterFunctionProperty() << responseFileThresholdProperty() << responseFileArgumentIndexProperty() << responseFileUsagePrefixProperty() << environmentProperty() << stdoutFilePathProperty() << stderrFilePathProperty(); applyCommandProperties(ctx, scriptValue); } QString ProcessCommand::descriptionForCancelMessage(const QString &productName) const { return description() + QLatin1String(" (") + QDir::toNativeSeparators(m_program) + QLatin1String(") [") + productName + QLatin1Char(']'); } QStringList ProcessCommand::relevantEnvVars() const { QStringList vars = m_relevantEnvVars; if (!FileInfo::isAbsolute(program())) vars << StringConstants::pathEnvVar(); return vars; } void ProcessCommand::addRelevantEnvValue(const QString &key, const QString &value) { m_relevantEnvValues.insert(key, value); } void ProcessCommand::load(PersistentPool &pool) { AbstractCommand::load(pool); serializationOp(pool); } void ProcessCommand::store(PersistentPool &pool) { AbstractCommand::store(pool); serializationOp(pool); } static QString currentImportScopeName(JSContext *ctx) { const ScriptEngine * const engine = ScriptEngine::engineForContext(ctx); const JSValueList &contextStack = engine->contextStack(); for (auto it = contextStack.rbegin(); it != contextStack.rend(); ++it) { if (!JS_IsObject(*it)) continue; const ScopedJsValue v(ctx, getJsProperty(ctx, *it, StringConstants::importScopeNamePropertyInternal())); if (JS_IsString(v)) return getJsString(ctx, v); } return {}; } static JSValue js_JavaScriptCommand(JSContext *ctx, JSValueConst, JSValueConst, int argc, JSValueConst *, int) { if (argc > 0) return throwError(ctx, Tr::tr("JavaScriptCommand c'tor doesn't take arguments.")); static JavaScriptCommandPtr commandPrototype = JavaScriptCommand::create(); JSValue cmd = js_CommandBase(ctx); setJsProperty(ctx, cmd, StringConstants::classNameProperty(), makeJsString(ctx, StringConstants::javaScriptCommandType())); setJsProperty(ctx, cmd, StringConstants::sourceCodeProperty(), makeJsString(ctx, commandPrototype->sourceCode())); setJsProperty(ctx, cmd, StringConstants::importScopeNamePropertyInternal(), makeJsString(ctx, currentImportScopeName(ctx))); return cmd; } void JavaScriptCommand::setupForJavaScript(ScriptEngine *engine, JSValue targetObject) { engine->registerClass(StringConstants::javaScriptCommandType().toUtf8().constData(), js_JavaScriptCommand, nullptr, targetObject); } JavaScriptCommand::JavaScriptCommand() = default; bool JavaScriptCommand::equals(const AbstractCommand *otherAbstractCommand) const { if (!AbstractCommand::equals(otherAbstractCommand)) return false; auto const other = static_cast(otherAbstractCommand); return m_sourceCode == other->m_sourceCode; } void JavaScriptCommand::fillFromScriptValue(JSContext *ctx, const JSValue *scriptValue, const CodeLocation &codeLocation) { AbstractCommand::fillFromScriptValue(ctx, scriptValue, codeLocation); const ScopedJsValue importScope(ctx, getJsProperty(ctx, *scriptValue, StringConstants::importScopeNamePropertyInternal())); if (JS_IsString(importScope)) m_scopeName = getJsString(ctx, importScope); const ScopedJsValue sourceCode(ctx, getJsProperty(ctx, *scriptValue, StringConstants::sourceCodeProperty())); m_sourceCode = invokedSourceCode(ctx, sourceCode); m_predefinedProperties << StringConstants::classNameProperty() << StringConstants::sourceCodeProperty() << StringConstants::importScopeNamePropertyInternal(); applyCommandProperties(ctx, scriptValue); } void JavaScriptCommand::load(PersistentPool &pool) { AbstractCommand::load(pool); serializationOp(pool); } void JavaScriptCommand::store(PersistentPool &pool) { AbstractCommand::store(pool); serializationOp(pool); } void CommandList::load(PersistentPool &pool) { m_commands.clear(); int count = pool.load(); m_commands.reserve(count); while (--count >= 0) { const auto cmdType = pool.load(); AbstractCommandPtr cmd; switch (cmdType) { case AbstractCommand::JavaScriptCommandType: cmd = pool.load(); break; case AbstractCommand::ProcessCommandType: cmd = pool.load(); break; default: QBS_CHECK(false); } addCommand(cmd); } } void CommandList::store(PersistentPool &pool) const { pool.store(int(m_commands.size())); for (const AbstractCommandPtr &cmd : m_commands) { pool.store(static_cast(cmd->type())); pool.store(cmd); } } bool operator==(const CommandList &l1, const CommandList &l2) { if (l1.size() != l2.size()) return false; for (int i = 0; i < l1.size(); ++i) if (!l1.commandAt(i)->equals(l2.commandAt(i).get())) return false; return true; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/rescuableartifactdata.h0000644000175100001660000001301614776170045024234 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RESCUABLEARTIFACTDATA_H #define QBS_RESCUABLEARTIFACTDATA_H #include "forward_decls.h" #include "requestedartifacts.h" #include "requesteddependencies.h" #include "rulecommands.h" #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class QBS_AUTOTEST_EXPORT RescuableArtifactData { public: template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(timeStamp, children, fileDependencies, knownOutOfDate, propertiesRequestedInPrepareScript, propertiesRequestedInCommands, propertiesRequestedFromArtifactInPrepareScript, propertiesRequestedFromArtifactInCommands, importedFilesUsedInPrepareScript, importedFilesUsedInCommands, depsRequestedInPrepareScript, depsRequestedInCommands, commands, artifactsMapRequestedInPrepareScript, artifactsMapRequestedInCommands, exportedModulesAccessedInPrepareScript, exportedModulesAccessedInCommands, lastPrepareScriptExecutionTime, lastCommandExecutionTime, fileTags, properties); } bool isValid() const { return !!properties; } struct ChildData { ChildData(QString n = QString(), QString m = QString(), QString c = QString(), bool byScanner = false) : productName(std::move(n)) , productMultiplexId(std::move(m)) , childFilePath(std::move(c)) , addedByScanner(byScanner) {} template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(productName, productMultiplexId, childFilePath, addedByScanner); } QString productName; QString productMultiplexId; QString childFilePath; bool addedByScanner; }; FileTime timeStamp; std::vector children; std::vector fileDependencies; // Per-Transformer data CommandList commands; PropertySet propertiesRequestedInPrepareScript; PropertySet propertiesRequestedInCommands; PropertyHash propertiesRequestedFromArtifactInPrepareScript; PropertyHash propertiesRequestedFromArtifactInCommands; std::vector importedFilesUsedInPrepareScript; std::vector importedFilesUsedInCommands; RequestedDependencies depsRequestedInPrepareScript; RequestedDependencies depsRequestedInCommands; RequestedArtifacts artifactsMapRequestedInPrepareScript; RequestedArtifacts artifactsMapRequestedInCommands; FileTime lastPrepareScriptExecutionTime; FileTime lastCommandExecutionTime; std::unordered_map exportedModulesAccessedInPrepareScript; std::unordered_map exportedModulesAccessedInCommands; bool knownOutOfDate = false; // Only needed for API purposes FileTags fileTags; PropertyMapPtr properties; }; using AllRescuableArtifactData = QHash; } // namespace Internal } // namespace qbs #endif // Include guard. qbs-src-2.6.1/src/lib/corelib/buildgraph/productinstaller.cpp0000644000175100001660000002601714776170045023655 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "productinstaller.h" #include "artifact.h" #include "productbuilddata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { ProductInstaller::ProductInstaller(TopLevelProjectPtr project, QVector products, InstallOptions options, ProgressObserver *observer, Logger logger) : m_project(std::move(project)), m_products(std::move(products)), m_options(std::move(options)), m_observer(observer), m_logger(std::move(logger)) { if (!m_options.installRoot().isEmpty()) { QFileInfo installRootFileInfo(m_options.installRoot()); QBS_ASSERT(installRootFileInfo.isAbsolute(), /* just complain */); if (m_options.removeExistingInstallation()) { const QString cfp = installRootFileInfo.canonicalFilePath(); if (cfp == QFileInfo(QDir::rootPath()).canonicalFilePath()) throw ErrorInfo(Tr::tr("Refusing to remove root directory.")); if (cfp == QFileInfo(QDir::homePath()).canonicalFilePath()) throw ErrorInfo(Tr::tr("Refusing to remove home directory.")); } return; } if (m_options.installIntoSysroot()) { if (m_options.removeExistingInstallation()) throw ErrorInfo(Tr::tr("Refusing to remove sysroot.")); } initInstallRoot(m_project.get(), m_options); } void ProductInstaller::install() { m_targetFilePathsMap.clear(); if (m_options.removeExistingInstallation()) removeInstallRoot(); QList artifactsToInstall; for (const auto &product : std::as_const(m_products)) { QBS_CHECK(product->buildData); for (const Artifact *artifact : filterByType(product->buildData->allNodes())) { if (artifact->properties->qbsPropertyValue(StringConstants::installProperty()).toBool()) artifactsToInstall.push_back(artifact); } } m_observer->initialize(Tr::tr("Installing"), artifactsToInstall.size()); for (const Artifact * const a : std::as_const(artifactsToInstall)) { copyFile(a); m_observer->incrementProgressValue(); } } QString ProductInstaller::targetFilePath(const TopLevelProject *project, const QString &productSourceDir, const QString &sourceFilePath, const PropertyMapConstPtr &properties, InstallOptions &options) { if (!properties->qbsPropertyValue(StringConstants::installProperty()).toBool()) return {}; const QString relativeInstallDir = properties->qbsPropertyValue(StringConstants::installDirProperty()).toString(); const QString installPrefix = properties->qbsPropertyValue(StringConstants::installPrefixProperty()).toString(); const QString installSourceBase = properties->qbsPropertyValue(StringConstants::installSourceBaseProperty()).toString(); initInstallRoot(project, options); QString targetDir = options.installRoot(); if (targetDir.isEmpty()) targetDir = properties->qbsPropertyValue(StringConstants::installRootProperty()).toString(); targetDir.append(QLatin1Char('/')).append(installPrefix) .append(QLatin1Char('/')).append(relativeInstallDir); targetDir = QDir::cleanPath(targetDir); QString targetFilePath; if (installSourceBase.isEmpty()) { if (!targetDir.startsWith(options.installRoot())) { throw ErrorInfo(Tr::tr("Cannot install '%1', because target directory '%2' " "is outside of install root '%3'") .arg(sourceFilePath, targetDir, options.installRoot())); } // This has the same effect as if installSourceBase would equal the directory of the file. targetFilePath = FileInfo::fileName(sourceFilePath); } else { const QString localAbsBasePath = FileInfo::resolvePath(QDir::cleanPath(productSourceDir), QDir::cleanPath(installSourceBase)); targetFilePath = sourceFilePath; if (!targetFilePath.startsWith(localAbsBasePath)) { throw ErrorInfo(Tr::tr("Cannot install '%1', because it doesn't start with the" " value of qbs.installSourceBase '%2'.").arg(sourceFilePath, localAbsBasePath)); } // Since there is a difference between X: and X:\\ on Windows, absolute paths can sometimes // end with a slash, so only remove an extra character if there is no ending slash targetFilePath.remove(0, localAbsBasePath.length() + (localAbsBasePath.endsWith(QLatin1Char('/')) ? 0 : 1)); } targetFilePath.prepend(targetDir + QLatin1Char('/')); return QDir::cleanPath(targetFilePath); } void ProductInstaller::initInstallRoot(const TopLevelProject *project, InstallOptions &options) { if (!options.installRoot().isEmpty()) return; options.setInstallRoot(effectiveInstallRoot(options, project)); } void ProductInstaller::removeInstallRoot() { const QString nativeInstallRoot = QDir::toNativeSeparators(m_options.installRoot()); if (m_options.dryRun()) { m_logger.qbsInfo() << Tr::tr("Would remove install root '%1'.").arg(nativeInstallRoot); return; } m_logger.qbsDebug() << QStringLiteral("Removing install root '%1'.") .arg(nativeInstallRoot); QString errorMessage; if (!removeDirectoryWithContents(m_options.installRoot(), &errorMessage)) { const QString fullErrorMessage = Tr::tr("Cannot remove install root '%1': %2") .arg(QDir::toNativeSeparators(m_options.installRoot()), errorMessage); handleError(fullErrorMessage); } } void ProductInstaller::copyFile(const Artifact *artifact) { if (m_observer->canceled()) { throw ErrorInfo(Tr::tr("Installation canceled for configuration '%1'.") .arg(m_products.front()->project->topLevelProject()->id())); } const QString targetFilePath = this->targetFilePath(m_project.get(), artifact->product->sourceDirectory, artifact->filePath(), artifact->properties, m_options); const QString targetDir = FileInfo::path(targetFilePath); const QString nativeFilePath = QDir::toNativeSeparators(artifact->filePath()); const QString nativeTargetDir = QDir::toNativeSeparators(targetDir); if (m_options.dryRun()) { m_logger.qbsDebug() << Tr::tr("Would copy file '%1' into target directory '%2'.") .arg(nativeFilePath, nativeTargetDir); return; } m_logger.qbsDebug() << QStringLiteral("Copying file '%1' into target directory '%2'.") .arg(nativeFilePath, nativeTargetDir); if (!QDir::root().mkpath(targetDir)) { handleError(Tr::tr("Directory '%1' could not be created.").arg(nativeTargetDir)); return; } QFileInfo fi(artifact->filePath()); if (fi.isDir() && !(HostOsInfo::isAnyUnixHost() && fi.isSymLink())) { m_logger.qbsWarning() << Tr::tr("Not recursively copying directory '%1' into target " "directory '%2'. Install the individual file artifacts " "instead.") .arg(nativeFilePath, nativeTargetDir); } if (m_targetFilePathsMap.contains(targetFilePath)) { // We only want this error message when installing artifacts pointing to different file // paths, to the same location. We do NOT want it when installing different artifacts // pointing to the same file, to the same location. This reduces unnecessary noise: for // example, when installing headers from a multiplexed product, the user does not need to // do extra work to ensure the files are installed by only one of the instances. if (artifact->filePath() != m_targetFilePathsMap[targetFilePath]) { handleError(Tr::tr("Cannot install files '%1' and '%2' to the same location '%3'. " "If you are attempting to install a directory hierarchy, consider " "using the qbs.installSourceBase property.") .arg(artifact->filePath(), m_targetFilePathsMap[targetFilePath], targetFilePath)); } } m_targetFilePathsMap.insert(targetFilePath, artifact->filePath()); QString errorMessage; if (!copyFileRecursion(artifact->filePath(), targetFilePath, true, false, &errorMessage)) handleError(Tr::tr("Installation error: %1").arg(errorMessage)); } void ProductInstaller::handleError(const QString &message) { if (!m_options.keepGoing()) throw ErrorInfo(message); m_logger.qbsWarning() << message; } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp0000644000175100001660000001030714776170045025101 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "rulesevaluationcontext.h" #include "rulecommands.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { RulesEvaluationContext::RulesEvaluationContext(Logger logger) : m_logger(std::move(logger)), m_engine(ScriptEngine::create(m_logger, EvalContext::RuleExecution)), m_observer(nullptr), m_initScopeCalls(0), m_prepareScriptScope(m_engine->newObject()) { JS_SetPrototype(m_engine->context(), m_prepareScriptScope, m_engine->globalObject()); ProcessCommand::setupForJavaScript(m_engine.get(), m_prepareScriptScope); JavaScriptCommand::setupForJavaScript(m_engine.get(), m_prepareScriptScope); } RulesEvaluationContext::~RulesEvaluationContext() { JS_FreeValue(m_engine->context(), m_prepareScriptScope); } void RulesEvaluationContext::initializeObserver(const QString &description, int maximumProgress) { if (m_observer) m_observer->initialize(description, maximumProgress); } void RulesEvaluationContext::incrementProgressValue() { if (m_observer) m_observer->incrementProgressValue(); } void RulesEvaluationContext::checkForCancelation() { if (Q_UNLIKELY(m_observer && m_observer->canceled())) throw ErrorInfo(Tr::tr("Build canceled.")); } void RulesEvaluationContext::initScope() { if (m_initScopeCalls++ > 0) return; m_engine->setActive(true); m_scope = m_engine->newObject(); JS_SetPrototype(m_engine->context(), m_scope, m_prepareScriptScope); m_engine->setGlobalObject(m_scope); } void RulesEvaluationContext::cleanupScope() { QBS_CHECK(m_initScopeCalls > 0); if (--m_initScopeCalls > 0) return; JS_FreeValue(m_engine->context(), m_scope); m_scope = JS_UNDEFINED; const ScopedJsValue proto(engine()->context(), JS_GetPrototype(m_engine->context(), m_prepareScriptScope)); m_engine->setGlobalObject(proto); m_engine->setActive(false); } RulesEvaluationContext::Scope::Scope(RulesEvaluationContext *evalContext) : m_evalContext(evalContext) { evalContext->initScope(); } RulesEvaluationContext::Scope::~Scope() { m_evalContext->cleanupScope(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/buildgraphnode.h0000644000175100001660000000643514776170045022715 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_BUILDGRAPHNODE_H #define QBS_BUILDGRAPHNODE_H #include "nodeset.h" #include #include #include namespace qbs { namespace Internal { class BuildGraphVisitor; class BuildGraphNode { friend NodeSet; public: virtual ~BuildGraphNode(); NodeSet parents; NodeSet children; WeakPointer product; enum BuildState { Untouched = 0, Buildable, Building, Built }; BuildState buildState; // Do not serialize. Will be refreshed for every build. enum Type { ArtifactNodeType, RuleNodeType }; virtual Type type() const = 0; virtual void accept(BuildGraphVisitor *visitor) = 0; virtual QString toString() const = 0; virtual void onChildDisconnected(BuildGraphNode *child); bool isBuilt() const { return buildState == Built; } virtual void load(PersistentPool &pool); virtual void store(PersistentPool &pool); protected: explicit BuildGraphNode(); void acceptChildren(BuildGraphVisitor *visitor); // Do not store parents to avoid recursion. // Parents must be updated after loading all nodes. template void serializationOp(PersistentPool &pool) { pool.serializationOp(children); } }; } // namespace Internal } // namespace qbs #endif // QBS_BUILDGRAPHNODE_H qbs-src-2.6.1/src/lib/corelib/buildgraph/processcommandexecutor.cpp0000644000175100001660000004211714776170045025052 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "processcommandexecutor.h" #include "artifact.h" #include "rulecommands.h" #include "transformer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { ProcessCommandExecutor::ProcessCommandExecutor(const Logger &logger, QObject *parent) : AbstractCommandExecutor(logger, parent) { connect(&m_process, &QbsProcess::errorOccurred, this, &ProcessCommandExecutor::onProcessError); connect(&m_process, static_cast(&QbsProcess::finished), this, &ProcessCommandExecutor::onProcessFinished); } static QProcessEnvironment mergeEnvironments(const QProcessEnvironment &baseEnv, const QProcessEnvironment &additionalEnv) { QProcessEnvironment env = baseEnv; static const QStringList pathListVariables{ StringConstants::pathEnvVar(), QStringLiteral("LD_LIBRARY_PATH"), QStringLiteral("DYLD_LIBRARY_PATH"), QStringLiteral("DYLD_FRAMEWORK_PATH"), }; const auto keys = additionalEnv.keys(); for (const QString &key : keys) { QString newValue = additionalEnv.value(key); if (pathListVariables.contains(key, HostOsInfo::fileNameCaseSensitivity())) { const QString &oldValue = baseEnv.value(key); if (!oldValue.isEmpty()) newValue.append(HostOsInfo::pathListSeparator()).append(oldValue); } env.insert(key, newValue); } return env; } void ProcessCommandExecutor::doSetup() { ProcessCommand * const cmd = processCommand(); const QString program = ExecutableFinder(transformer()->product(), transformer()->product()->buildEnvironment) .findExecutable(cmd->program(), cmd->workingDir()); cmd->clearRelevantEnvValues(); const auto keys = cmd->relevantEnvVars(); for (const QString &key : keys) cmd->addRelevantEnvValue(key, transformer()->product()->buildEnvironment.value(key)); m_commandEnvironment = mergeEnvironments(m_buildEnvironment, cmd->environment()); m_program = program; m_arguments = cmd->arguments(); m_shellInvocation = shellQuote(QDir::toNativeSeparators(m_program), m_arguments); } bool ProcessCommandExecutor::doStart() { QBS_ASSERT(m_process.state() == QProcess::NotRunning, return false); const ProcessCommand * const cmd = processCommand(); m_process.setProcessEnvironment(m_commandEnvironment); QStringList arguments = m_arguments; if (dryRun() && !cmd->ignoreDryRun()) { QTimer::singleShot(0, this, [this] { emit finished(); }); // Don't call back on the caller. return false; } const QString workingDir = QDir::fromNativeSeparators(cmd->workingDir()); if (!workingDir.isEmpty()) { FileInfo fi(workingDir); if (!fi.exists() || !fi.isDir()) { emit finished(ErrorInfo(Tr::tr("The working directory '%1' for process '%2' " "is invalid.").arg(QDir::toNativeSeparators(workingDir), QDir::toNativeSeparators(m_program)), cmd->codeLocation())); return false; } } // Automatically use response files, if the command line gets to long. if (!cmd->responseFileUsagePrefix().isEmpty()) { const int commandLineLength = m_shellInvocation.length(); if (cmd->responseFileThreshold() >= 0 && commandLineLength > cmd->responseFileThreshold()) { qCDebug(lcExec) << QString::fromUtf8("Using response file. " "Threshold is %1. Command line length %2.") .arg(cmd->responseFileThreshold()).arg(commandLineLength); // The QTemporaryFile keeps a handle on the file, even if closed. // On Windows, some commands (e.g. msvc link.exe) won't accept that. // We need to delete the file manually, later. QTemporaryFile responseFile; responseFile.setAutoRemove(false); responseFile.setFileTemplate(QDir::tempPath() + QLatin1String("/qbsresp")); if (!responseFile.open()) { emit finished(ErrorInfo(Tr::tr("Cannot create response file '%1'.") .arg(responseFile.fileName()))); return false; } const auto separator = cmd->responseFileSeparator().toUtf8(); for (int i = cmd->responseFileArgumentIndex(); i < cmd->arguments().size(); ++i) { const QString arg = cmd->arguments().at(i); if (arg.startsWith(cmd->responseFileUsagePrefix())) { QFile f(arg.mid(cmd->responseFileUsagePrefix().size())); if (!f.open(QIODevice::ReadOnly)) { emit finished(ErrorInfo(Tr::tr("Cannot open command file '%1'.") .arg(QDir::toNativeSeparators(f.fileName())))); return false; } responseFile.write(f.readAll()); } else { responseFile.write(qbs::Internal::shellQuote(arg).toLocal8Bit()); } responseFile.write(separator); } responseFile.close(); m_responseFileName = responseFile.fileName(); arguments = arguments.mid(0, std::min(cmd->responseFileArgumentIndex(), arguments.size())); arguments += QDir::toNativeSeparators(cmd->responseFileUsagePrefix() + responseFile.fileName()); } } qCDebug(lcExec) << "Running external process; full command line is:" << m_shellInvocation; const QProcessEnvironment &additionalVariables = cmd->environment(); qCDebug(lcExec) << "Additional environment:" << additionalVariables.toStringList(); m_process.setWorkingDirectory(workingDir); m_process.start(m_program, arguments); return true; } void ProcessCommandExecutor::cancel(const qbs::ErrorInfo &reason) { // We don't want this command to be reported as failing, since we explicitly terminated it. disconnect(this, &ProcessCommandExecutor::reportProcessResult, nullptr, nullptr); m_cancelReason = reason; m_process.cancel(); } QString ProcessCommandExecutor::filterProcessOutput(const QByteArray &_output, const QString &filterFunctionSource) { QString output = !_output.isNull() ? QString::fromLocal8Bit(_output) : QStringLiteral(""); if (filterFunctionSource.isEmpty()) return output; JSContext * const ctx = scriptEngine()->context(); const ScopedJsValue scope(ctx, JS_NewObjectProto(ctx, scriptEngine()->globalObject())); for (auto it = command()->properties().constBegin(); it != command()->properties().constEnd(); ++it) { setJsProperty(ctx, scope, it.key(), scriptEngine()->toScriptValue(it.value())); } TemporaryGlobalObjectSetter tgos(scriptEngine(), scope); const ScopedJsValue filterFunction( ctx, scriptEngine()->evaluate(JsValueOwner::Caller, QLatin1String("var f = ") + filterFunctionSource + QLatin1String("; f"))); if (!JS_IsFunction(scriptEngine()->context(), filterFunction)) { logger().printError(ErrorInfo( Tr::tr("Error in filter function: %1.\n%2") .arg( filterFunctionSource, getJsString(scriptEngine()->context(), filterFunction)))); return output; } const ScopedJsValue outputArg(ctx, scriptEngine()->toScriptValue(output)); JSValue outputArgForCall = outputArg; const ScopedJsValue filteredOutput( ctx, JS_Call(ctx, filterFunction, JS_UNDEFINED, 1, &outputArgForCall)); if (const JsException ex = scriptEngine()->checkAndClearException({})) { ErrorInfo err = ex.toErrorInfo(); err.prepend(Tr::tr("Error when calling output filter function")); logger().printError(err); return output; } return getJsString(ctx, filteredOutput); } static QProcess::ProcessError saveToFile(const QString &filePath, const QByteArray &content) { QBS_ASSERT(!filePath.isEmpty(), return QProcess::WriteError); QFile f(filePath); if (!f.open(QIODevice::WriteOnly)) return QProcess::WriteError; if (f.write(content) != content.size()) return QProcess::WriteError; f.close(); return f.error() == QFileDevice::NoError ? QProcess::UnknownError : QProcess::WriteError; } void ProcessCommandExecutor::getProcessOutput(bool stdOut, ProcessResult &result) { QByteArray content; QString filterFunction; QString redirectPath; QStringList *target; if (stdOut) { content = m_process.readAllStandardOutput(); filterFunction = processCommand()->stdoutFilterFunction(); redirectPath = processCommand()->stdoutFilePath(); target = &result.d->stdOut; } else { content = m_process.readAllStandardError(); filterFunction = processCommand()->stderrFilterFunction(); redirectPath = processCommand()->stderrFilePath(); target = &result.d->stdErr; } QString contentString = filterProcessOutput(content, filterFunction); if (!redirectPath.isEmpty()) { const QByteArray dataToWrite = filterFunction.isEmpty() ? content : contentString.toLocal8Bit(); const QProcess::ProcessError error = saveToFile(redirectPath, dataToWrite); if (result.error() == QProcess::UnknownError && error != QProcess::UnknownError) result.d->error = error; } else { if (!contentString.isEmpty() && contentString.endsWith(QLatin1Char('\n'))) contentString.chop(1); *target = contentString.split(QLatin1Char('\n'), Qt::SkipEmptyParts); } } void ProcessCommandExecutor::sendProcessOutput() { ProcessResult result; result.d->executableFilePath = m_program; result.d->arguments = m_arguments; result.d->workingDirectory = m_process.workingDirectory(); if (result.workingDirectory().isEmpty()) result.d->workingDirectory = QDir::currentPath(); result.d->exitCode = m_process.exitCode(); result.d->error = m_process.error(); QString errorString = m_process.errorString(); getProcessOutput(true, result); getProcessOutput(false, result); const bool processError = result.error() != QProcess::UnknownError; const bool failureExit = quint32(m_process.exitCode()) > quint32(processCommand()->maxExitCode()); const bool cancelledWithError = m_cancelReason.hasError(); result.d->success = !processError && !failureExit && !cancelledWithError; emit reportProcessResult(result); if (Q_UNLIKELY(cancelledWithError)) { emit finished(m_cancelReason); } else if (Q_UNLIKELY(processError)) { emit finished(ErrorInfo(errorString)); } else if (Q_UNLIKELY(failureExit)) { emit finished(ErrorInfo(Tr::tr("Process failed with exit code %1.") .arg(m_process.exitCode()))); } else { emit finished(); } } void ProcessCommandExecutor::onProcessError() { if (scriptEngine()->isActive()) { qCDebug(lcExec) << "Command error while rule execution is pausing. " "Delaying slot execution."; QTimer::singleShot(0, this, &ProcessCommandExecutor::onProcessError); return; } if (m_cancelReason.hasError()) return; // Ignore. Cancel reasons will be handled by on ProcessFinished(). switch (m_process.error()) { case QProcess::FailedToStart: { removeResponseFile(); const QString binary = QDir::toNativeSeparators(processCommand()->program()); QString errorPrefixString; #ifdef Q_OS_UNIX if (QFileInfo(binary).isExecutable()) { const QString interpreter(shellInterpreter(binary)); if (!interpreter.isEmpty()) { errorPrefixString = Tr::tr("%1: bad interpreter: ").arg(interpreter); } } #endif emit finished(ErrorInfo(Tr::tr("The process '%1' could not be started: %2. " "The full command line invocation was: %3") .arg(binary, errorPrefixString + m_process.errorString(), m_shellInvocation))); break; } case QProcess::Crashed: break; // Ignore. Will be handled by onProcessFinished(). default: logger().qbsWarning() << "QProcess error: " << m_process.errorString(); } } void ProcessCommandExecutor::onProcessFinished() { if (scriptEngine()->isActive()) { qCDebug(lcExec) << "Command finished while rule execution is pausing. " "Delaying slot execution."; QTimer::singleShot(0, this, &ProcessCommandExecutor::onProcessFinished); return; } removeResponseFile(); sendProcessOutput(); } static QString environmentVariableString(const QString &key, const QString &value) { QString str; if (HostOsInfo::isWindowsHost()) str += QStringLiteral("set "); str += shellQuote(key + QLatin1Char('=') + value); if (HostOsInfo::isWindowsHost()) str += QLatin1Char('\n'); else str += QLatin1Char(' '); return str; } void ProcessCommandExecutor::doReportCommandDescription(const QString &productName) { if (m_echoMode == CommandEchoModeCommandLine || m_echoMode == CommandEchoModeCommandLineWithEnvironment) { QString fullInvocation; if (m_echoMode == CommandEchoModeCommandLineWithEnvironment) { QStringList keys = m_commandEnvironment.keys(); keys.sort(); for (const QString &key : std::as_const(keys)) fullInvocation += environmentVariableString(key, m_commandEnvironment.value(key)); } fullInvocation += m_shellInvocation; emit reportCommandDescription(command()->highlight(), !command()->extendedDescription().isEmpty() ? command()->extendedDescription() : fullInvocation); return; } AbstractCommandExecutor::doReportCommandDescription(productName); } void ProcessCommandExecutor::removeResponseFile() { if (m_responseFileName.isEmpty()) return; QFile::remove(m_responseFileName); m_responseFileName.clear(); } ProcessCommand *ProcessCommandExecutor::processCommand() const { return static_cast(command()); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/executorjob.cpp0000644000175100001660000001361514776170045022610 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "executorjob.h" #include "artifact.h" #include "jscommandexecutor.h" #include "processcommandexecutor.h" #include "rulecommands.h" #include "transformer.h" #include #include #include #include namespace qbs { namespace Internal { ExecutorJob::ExecutorJob(const Logger &logger, QObject *parent) : QObject(parent) , m_processCommandExecutor(new ProcessCommandExecutor(logger, this)) , m_jsCommandExecutor(new JsCommandExecutor(logger, this)) { connect(m_processCommandExecutor, &AbstractCommandExecutor::reportCommandDescription, this, &ExecutorJob::reportCommandDescription); connect(m_processCommandExecutor, &ProcessCommandExecutor::reportProcessResult, this, &ExecutorJob::reportProcessResult); connect(m_processCommandExecutor, &AbstractCommandExecutor::finished, this, &ExecutorJob::onCommandFinished); connect(m_jsCommandExecutor, &AbstractCommandExecutor::reportCommandDescription, this, &ExecutorJob::reportCommandDescription); connect(m_jsCommandExecutor, &AbstractCommandExecutor::finished, this, &ExecutorJob::onCommandFinished); reset(); } ExecutorJob::~ExecutorJob() = default; void ExecutorJob::setMainThreadScriptEngine(ScriptEngine *engine) { m_processCommandExecutor->setMainThreadScriptEngine(engine); m_jsCommandExecutor->setMainThreadScriptEngine(engine); } void ExecutorJob::setDryRun(bool enabled) { m_processCommandExecutor->setDryRunEnabled(enabled); m_jsCommandExecutor->setDryRunEnabled(enabled); } void ExecutorJob::setEchoMode(CommandEchoMode echoMode) { m_processCommandExecutor->setEchoMode(echoMode); m_jsCommandExecutor->setEchoMode(echoMode); } void ExecutorJob::run(Transformer *t) { QBS_ASSERT(m_currentCommandIdx == -1, return); if (t->commands.empty()) { setFinished(); return; } t->propertiesRequestedInCommands.clear(); t->propertiesRequestedFromArtifactInCommands.clear(); t->importedFilesUsedInCommands.clear(); t->depsRequestedInCommands.clear(); t->artifactsMapRequestedInCommands.clear(); t->exportedModulesAccessedInCommands.clear(); t->lastCommandExecutionTime = FileTime::currentTime(); QBS_CHECK(!t->outputs.empty()); m_processCommandExecutor->setProcessEnvironment( (*t->outputs.cbegin())->product->buildEnvironment); m_transformer = t; m_jobPools = t->jobPools(); runNextCommand(); } void ExecutorJob::cancel() { if (!m_currentCommandExecutor) return; m_error = ErrorInfo(tr("Transformer execution canceled.")); m_currentCommandExecutor->cancel(); } void ExecutorJob::runNextCommand() { QBS_ASSERT(m_currentCommandIdx <= m_transformer->commands.size(), return); ++m_currentCommandIdx; if (m_currentCommandIdx >= m_transformer->commands.size()) { setFinished(); return; } const AbstractCommandPtr &command = m_transformer->commands.commandAt(m_currentCommandIdx); switch (command->type()) { case AbstractCommand::ProcessCommandType: m_currentCommandExecutor = m_processCommandExecutor; break; case AbstractCommand::JavaScriptCommandType: m_currentCommandExecutor = m_jsCommandExecutor; break; default: qFatal("Missing implementation for command type %d", command->type()); } m_currentCommandExecutor->start(m_transformer, command.get()); } void ExecutorJob::onCommandFinished(const ErrorInfo &err) { QBS_ASSERT(m_transformer, return); if (m_error.hasError()) { // Canceled? setFinished(); } else if (err.hasError()) { m_error = err; setFinished(); } else { runNextCommand(); } } void ExecutorJob::setFinished() { const ErrorInfo err = m_error; reset(); emit finished(err); } void ExecutorJob::reset() { m_transformer = nullptr; m_jobPools.clear(); m_currentCommandExecutor = nullptr; m_currentCommandIdx = -1; m_error.clear(); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/executorjob.h0000644000175100001660000000704514776170045022255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_EXECUTORJOB_H #define QBS_EXECUTORJOB_H #include #include #include #include #include #include namespace qbs { class CodeLocation; class ProcessResult; namespace Internal { class AbstractCommandExecutor; class ProductBuildData; class JsCommandExecutor; class Logger; class ProcessCommandExecutor; class ScriptEngine; class Transformer; class ExecutorJob : public QObject { Q_OBJECT public: explicit ExecutorJob(const Logger &logger, QObject *parent = nullptr); ~ExecutorJob() override; void setMainThreadScriptEngine(ScriptEngine *engine); void setDryRun(bool enabled); void setEchoMode(CommandEchoMode echoMode); void run(Transformer *t); void cancel(); const Transformer *transformer() const { return m_transformer; } Set jobPools() const { return m_jobPools; } signals: void reportCommandDescription(const QString &highlight, const QString &message); void reportProcessResult(const qbs::ProcessResult &result); void finished(const qbs::ErrorInfo &error = ErrorInfo()); // !hasError() <=> command successful private: void runNextCommand(); void onCommandFinished(const qbs::ErrorInfo &err); void setFinished(); void reset(); AbstractCommandExecutor *m_currentCommandExecutor = nullptr; ProcessCommandExecutor *m_processCommandExecutor = nullptr; JsCommandExecutor *m_jsCommandExecutor = nullptr; Transformer *m_transformer = nullptr; Set m_jobPools; int m_currentCommandIdx = 0; ErrorInfo m_error; }; } // namespace Internal } // namespace qbs #endif // QBS_EXECUTORJOB_H qbs-src-2.6.1/src/lib/corelib/buildgraph/emptydirectoriesremover.cpp0000644000175100001660000001014414776170045025244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "emptydirectoriesremover.h" #include "artifact.h" #include #include #include namespace qbs { namespace Internal { EmptyDirectoriesRemover::EmptyDirectoriesRemover(const TopLevelProject *project, Logger logger) : m_project(project), m_logger(std::move(logger)) { } void EmptyDirectoriesRemover::removeEmptyParentDirectories(const QStringList &artifactFilePaths) { m_dirsToRemove.clear(); m_handledDirs.clear(); for (const QString &filePath : artifactFilePaths) insertSorted(QFileInfo(filePath).absolutePath()); while (!m_dirsToRemove.empty()) removeDirIfEmpty(); } void EmptyDirectoriesRemover::removeEmptyParentDirectories(const ArtifactSet &artifacts) { QStringList filePaths; for (const Artifact * const a : artifacts) { if (a->artifactType == Artifact::Generated) filePaths << a->filePath(); } removeEmptyParentDirectories(filePaths); } // List is sorted so that "deeper" directories come first. void EmptyDirectoriesRemover::insertSorted(const QString &dirPath) { int i; for (i = 0; i < m_dirsToRemove.size(); ++i) { const QString &cur = m_dirsToRemove.at(i); if (dirPath == cur) return; if (dirPath.count(QLatin1Char('/')) > cur.count(QLatin1Char('/'))) break; } m_dirsToRemove.insert(i, dirPath); } void EmptyDirectoriesRemover::removeDirIfEmpty() { const QString dirPath = m_dirsToRemove.takeFirst(); m_handledDirs.insert(dirPath); QFileInfo fi(dirPath); if (fi.isSymLink() || !fi.exists() || !dirPath.startsWith(m_project->buildDirectory) || fi.filePath() == m_project->buildDirectory) { return; } QDir dir(dirPath); dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); if (dir.count() != 0) return; dir.cdUp(); if (!dir.rmdir(fi.fileName())) { m_logger.qbsWarning() << QStringLiteral("Cannot remove empty directory '%1'.") .arg(dirPath); return; } const QString parentDir = dir.path(); if (!m_handledDirs.contains(parentDir)) insertSorted(parentDir); } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/rawscanresults.h0000644000175100001660000000762614776170045023011 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RAWSCANRESULTS_H #define QBS_RAWSCANRESULTS_H #include "rawscanneddependency.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class DependencyScanner; class FileResourceBase; class RawScanResult { public: std::vector deps; FileTags additionalFileTags; // TODO: does this belong here? QString providesModule; bool isInterfaceModule{false}; QStringList requiresModules; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp( deps, additionalFileTags, providesModule, isInterfaceModule, requiresModules); } }; class RawScanResults { public: struct ScanData { QString scannerId; PropertyMapConstPtr moduleProperties; FileTime lastScanTime; RawScanResult rawScanResult; template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(scannerId, moduleProperties, lastScanTime, rawScanResult); } }; using FilterFunction = std::function; ScanData &findScanData( const FileResourceBase *file, const QString &scannerId, const PropertyMapConstPtr &moduleProperties, const FilterFunction &filter); ScanData &findScanData( const FileResourceBase *file, const DependencyScanner *scanner, const PropertyMapConstPtr &moduleProperties); template void completeSerializationOp(PersistentPool &pool) { pool.serializationOp(m_rawScanData); } private: QHash> m_rawScanData; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/rawscanneddependency.h0000644000175100001660000000576214776170045024114 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_RAWSCANNEDDEPENDENCY_H #define QBS_RAWSCANNEDDEPENDENCY_H #include #include namespace qbs { namespace Internal { class PersistentPool; class RawScannedDependency { public: RawScannedDependency(); RawScannedDependency(const QString &filePath); QString filePath() const; const QString &dirPath() const { return m_dirPath; } const QString &fileName() const { return m_fileName; } bool isClean() const { return m_isClean; } bool isValid() const { return !m_fileName.isEmpty(); } void load(PersistentPool &pool); void store(PersistentPool &pool); private: void setClean(); template void serializationOp(PersistentPool &pool) { pool.serializationOp(m_dirPath, m_fileName); } QString m_dirPath; QString m_fileName; bool m_isClean = 0; }; bool operator==(const RawScannedDependency &d1, const RawScannedDependency &d2); inline bool operator!=(const RawScannedDependency &d1, const RawScannedDependency &d2) { return !(d1 == d2); } } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/buildgraph/abstractcommandexecutor.cpp0000644000175100001660000000766214776170045025205 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 Jochen Ulrich ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "abstractcommandexecutor.h" #include "rulecommands.h" #include "transformer.h" #include #include #include namespace qbs { namespace Internal { AbstractCommandExecutor::AbstractCommandExecutor(Logger logger, QObject *parent) : QObject(parent) , m_echoMode(defaultCommandEchoMode()) , m_command(nullptr) , m_transformer(nullptr) , m_mainThreadScriptEngine(nullptr) , m_dryRun(false) , m_logger(std::move(logger)) { m_watchdog.setSingleShot(true); connect(&m_watchdog, &QTimer::timeout, this, [this]() { cancel(ErrorInfo{Tr::tr("Command cancelled because it exceeded the timeout: %1") .arg(m_command->descriptionForCancelMessage( m_transformer->product()->fullDisplayName()))}); }); connect(this, &AbstractCommandExecutor::finished, &m_watchdog, &QTimer::stop); } void AbstractCommandExecutor::start(Transformer *transformer, AbstractCommand *cmd) { m_transformer = transformer; m_command = cmd; doSetup(); doReportCommandDescription(transformer->product()->fullDisplayName()); if (doStart()) startTimeout(); } void AbstractCommandExecutor::doReportCommandDescription(const QString &productName) { if (m_command->isSilent() || m_echoMode == CommandEchoModeSilent) return; if (m_command->description().isEmpty()) { m_logger.printWarning( ErrorInfo(Tr::tr("Command is not marked silent, but has no description."), m_command->codeLocation())); } else { emit reportCommandDescription(m_command->highlight(), m_command->fullDescription(productName)); } } void AbstractCommandExecutor::startTimeout() { if (!m_dryRun || m_command->ignoreDryRun()) { const auto timeout = m_command->timeout(); if (timeout > 0) m_watchdog.start(timeout * 1000); } } } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/corelib/buildgraph/requestedartifacts.h0000644000175100001660000000731414776170045023625 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_REQUESTEDARTIFACTS_H #define QBS_REQUESTEDARTIFACTS_H #include #include #include #include #include namespace qbs { namespace Internal { class FileTag; class PersistentPool; class RequestedArtifacts { public: bool isUpToDate(const TopLevelProject *project) const; void clear() { m_requestedArtifactsPerProduct.clear(); } void setAllArtifactTags(const ResolvedProduct *product, bool forceUpdate); void setArtifactsForTag(const ResolvedProduct *product, const FileTag &tag); void setNonExistingTagRequested(const ResolvedProduct *product, const QString &tag); void setArtifactsEnumerated(const ResolvedProduct *product); void unite(const RequestedArtifacts &other); void doSanityChecks() const; void load(PersistentPool &pool); void store(PersistentPool &pool); template void serializationOp(PersistentPool &pool) { pool.serializationOp(m_requestedArtifactsPerProduct); } private: struct RequestedArtifactsPerProduct { Set allTags; std::unordered_map> requestedTags; bool artifactsEnumerated = false; bool isUpToDate(const ResolvedProduct *product) const; void unite(const RequestedArtifactsPerProduct &other); void doSanityChecks() const; template void serializationOp(PersistentPool &pool) { pool.serializationOp(allTags, requestedTags, artifactsEnumerated); } void load(PersistentPool &pool); void store(PersistentPool &pool); }; std::unordered_map m_requestedArtifactsPerProduct; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/lib/corelib/parser/0000755000175100001660000000000014776170045016720 5ustar runnerdockerqbs-src-2.6.1/src/lib/corelib/parser/qmljsastfwd_p.h0000644000175100001660000001164414776170045021755 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSAST_FWD_P_H #define QMLJSAST_FWD_P_H #include "qmljsglobal_p.h" #include // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // namespace QbsQmlJS { namespace AST { class SourceLocation { public: SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0) : offset(offset), length(length), startLine(line), startColumn(column) { } bool isValid() const { return length != 0; } quint32 begin() const { return offset; } quint32 end() const { return offset + length; } // attributes // ### encode quint32 offset; quint32 length; quint32 startLine; quint32 startColumn; }; class Visitor; class Node; class ExpressionNode; class Statement; class ThisExpression; class IdentifierExpression; class NullExpression; class TrueLiteral; class FalseLiteral; class NumericLiteral; class StringLiteral; class RegExpLiteral; class ArrayLiteral; class ObjectLiteral; class ElementList; class Elision; class PropertyNameAndValueList; class PropertyName; class IdentifierPropertyName; class StringLiteralPropertyName; class NumericLiteralPropertyName; class ArrayMemberExpression; class FieldMemberExpression; class NewMemberExpression; class NewExpression; class CallExpression; class ArgumentList; class PostIncrementExpression; class PostDecrementExpression; class DeleteExpression; class VoidExpression; class TypeOfExpression; class PreIncrementExpression; class PreDecrementExpression; class UnaryPlusExpression; class UnaryMinusExpression; class TildeExpression; class NotExpression; class BinaryExpression; class ConditionalExpression; class Expression; // ### rename class Block; class StatementList; class VariableStatement; class VariableDeclarationList; class VariableDeclaration; class EmptyStatement; class ExpressionStatement; class IfStatement; class DoWhileStatement; class WhileStatement; class ForStatement; class LocalForStatement; class ForEachStatement; class LocalForEachStatement; class ContinueStatement; class BreakStatement; class ReturnStatement; class WithStatement; class SwitchStatement; class CaseBlock; class CaseClauses; class CaseClause; class DefaultClause; class LabelledStatement; class ThrowStatement; class TryStatement; class Catch; class Finally; class FunctionDeclaration; class FunctionExpression; class FormalParameterList; class FunctionBody; class Program; class SourceElements; class SourceElement; class FunctionSourceElement; class StatementSourceElement; class DebuggerStatement; class NestedExpression; // ui elements class UiProgram; class UiImportList; class UiImport; class UiPublicMember; class UiObjectDefinition; class UiObjectInitializer; class UiObjectBinding; class UiScriptBinding; class UiSourceElement; class UiArrayBinding; class UiObjectMember; class UiObjectMemberList; class UiArrayMemberList; class UiQualifiedId; } // namespace AST } // namespace QbsQmlJS #endif qbs-src-2.6.1/src/lib/corelib/parser/qmlerror.cpp0000644000175100001660000001642714776170045021301 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmlerror.h" #include #include #include #include #include namespace QbsQmlJS { /*! \class QmlError \since 5.0 \inmodule QtQml \brief The QmlError class encapsulates a QML error. QmlError includes a textual description of the error, as well as location information (the file, line, and column). The toString() method creates a single-line, human-readable string containing all of this information, for example: \code file:///home/user/test.qml:7:8: Invalid property assignment: double expected \endcode You can use qDebug() or qWarning() to output errors to the console. This method will attempt to open the file indicated by the error and include additional contextual information. \code file:///home/user/test.qml:7:8: Invalid property assignment: double expected y: "hello" ^ \endcode Note that the QtQuick 1 version is named QDeclarativeError \sa QQuickView::errors(), QmlComponent::errors() */ class QmlErrorPrivate { public: QmlErrorPrivate(); QUrl url; QString description; int line; int column; }; QmlErrorPrivate::QmlErrorPrivate() : line(-1), column(-1) { } /*! Creates an empty error object. */ QmlError::QmlError() = default; /*! Creates a copy of \a other. */ QmlError::QmlError(const QmlError &other) { *this = other; } /*! Assigns \a other to this error object. */ QmlError &QmlError::operator=(const QmlError &other) { if (this == &other) // Self assignment guard. return *this; if (!other.d) { d = nullptr; } else { if (!d) d = qbs::Internal::makePimpl(); d->url = other.d->url; d->description = other.d->description; d->line = other.d->line; d->column = other.d->column; } return *this; } /*! \internal */ QmlError::~QmlError() = default; /*! Returns true if this error is valid, otherwise false. */ bool QmlError::isValid() const { return d != nullptr; } /*! Returns the url for the file that caused this error. */ QUrl QmlError::url() const { if (d) return d->url; return {}; } /*! Sets the \a url for the file that caused this error. */ void QmlError::setUrl(const QUrl &url) { if (!d) d = qbs::Internal::makePimpl(); d->url = url; } /*! Returns the error description. */ QString QmlError::description() const { if (d) return d->description; return {}; } /*! Sets the error \a description. */ void QmlError::setDescription(const QString &description) { if (!d) d = qbs::Internal::makePimpl(); d->description = description; } /*! Returns the error line number. */ int QmlError::line() const { if (d) return d->line; return -1; } /*! Sets the error \a line number. */ void QmlError::setLine(int line) { if (!d) qbs::Internal::makePimpl(); d->line = line; } /*! Returns the error column number. */ int QmlError::column() const { if (d) return d->column; return -1; } /*! Sets the error \a column number. */ void QmlError::setColumn(int column) { if (!d) qbs::Internal::makePimpl(); d->column = column; } /*! Returns the error as a human readable string. */ QString QmlError::toString() const { QString rv; if (url().isEmpty()) { rv = QStringLiteral(""); } else if (line() != -1) { rv = url().toString() + QLatin1Char(':') + QString::number(line()); if (column() != -1) rv += QLatin1Char(':') + QString::number(column()); } else { rv = url().toString(); } rv += QLatin1String(": ") + description(); return rv; } } // namespace QbsQmlJS QT_BEGIN_NAMESPACE using namespace QbsQmlJS; /*! \relates QmlError \fn QDebug operator<<(QDebug debug, const QmlError &error) Outputs a human readable version of \a error to \a debug. */ QDebug operator<<(QDebug debug, const QmlError &error) { debug << qPrintable(error.toString()); QUrl url = error.url(); if (error.line() > 0 && url.scheme() == QLatin1String("file")) { QString file = url.toLocalFile(); QFile f(file); if (f.open(QIODevice::ReadOnly)) { QByteArray data = f.readAll(); QTextStream stream(data, QIODevice::ReadOnly); qbs::setupDefaultCodec(stream); const QString code = stream.readAll(); const QStringList lines = code.split(QLatin1Char('\n')); if (lines.size() >= error.line()) { const QString &line = lines.at(error.line() - 1); debug << "\n " << qPrintable(line); if (error.column() > 0) { int column = std::max(0, error.column() - 1); column = std::min(column, line.length()); QByteArray ind; ind.reserve(column); for (int i = 0; i < column; ++i) { const QChar ch = line.at(i); if (ch.isSpace()) ind.append(ch.unicode()); else ind.append(' '); } ind.append('^'); debug << "\n " << ind.constData(); } } } } return debug; } QT_END_NAMESPACE qbs-src-2.6.1/src/lib/corelib/parser/qmljsgrammar_p.h0000644000175100001660000001355014776170045022111 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists for the convenience // of other Qt classes. This header file may change from version to // version without notice, or even be removed. // // We mean it. // // This file was generated by qlalr - DO NOT EDIT! #ifndef QMLJSGRAMMAR_P_H #define QMLJSGRAMMAR_P_H #include namespace QbsQmlJS { class QmlJSGrammar { public: enum VariousConstants { EOF_SYMBOL = 0, REDUCE_HERE = 101, SHIFT_THERE = 100, T_AND = 1, T_AND_AND = 2, T_AND_EQ = 3, T_AS = 91, T_AUTOMATIC_SEMICOLON = 62, T_BREAK = 4, T_CASE = 5, T_CATCH = 6, T_COLON = 7, T_COMMA = 8, T_COMMENT = 88, T_CONST = 84, T_CONTINUE = 9, T_DEBUGGER = 85, T_DEFAULT = 10, T_DELETE = 11, T_DIVIDE_ = 12, T_DIVIDE_EQ = 13, T_DO = 14, T_DOT = 15, T_ELSE = 16, T_EQ = 17, T_EQ_EQ = 18, T_EQ_EQ_EQ = 19, T_ERROR = 93, T_FALSE = 83, T_FEED_JS_EXPRESSION = 97, T_FEED_JS_PROGRAM = 99, T_FEED_JS_SOURCE_ELEMENT = 98, T_FEED_JS_STATEMENT = 96, T_FEED_UI_OBJECT_MEMBER = 95, T_FEED_UI_PROGRAM = 94, T_FINALLY = 20, T_FOR = 21, T_FUNCTION = 22, T_GE = 23, T_GT = 24, T_GT_GT = 25, T_GT_GT_EQ = 26, T_GT_GT_GT = 27, T_GT_GT_GT_EQ = 28, T_IDENTIFIER = 29, T_IF = 30, T_IMPORT = 90, T_IN = 31, T_INSTANCEOF = 32, T_LBRACE = 33, T_LBRACKET = 34, T_LE = 35, T_LPAREN = 36, T_LT = 37, T_LT_LT = 38, T_LT_LT_EQ = 39, T_MINUS = 40, T_MINUS_EQ = 41, T_MINUS_MINUS = 42, T_MULTILINE_STRING_LITERAL = 87, T_NEW = 43, T_NOT = 44, T_NOT_EQ = 45, T_NOT_EQ_EQ = 46, T_NULL = 81, T_NUMERIC_LITERAL = 47, T_ON = 92, T_OR = 48, T_OR_EQ = 49, T_OR_OR = 50, T_PLUS = 51, T_PLUS_EQ = 52, T_PLUS_PLUS = 53, T_PROPERTY = 66, T_PUBLIC = 89, T_QUESTION = 54, T_RBRACE = 55, T_RBRACKET = 56, T_READONLY = 68, T_REMAINDER = 57, T_REMAINDER_EQ = 58, T_RESERVED_WORD = 86, T_RETURN = 59, T_RPAREN = 60, T_SEMICOLON = 61, T_SIGNAL = 67, T_STAR = 63, T_STAR_EQ = 64, T_STRING_LITERAL = 65, T_SWITCH = 69, T_THIS = 70, T_THROW = 71, T_TILDE = 72, T_TRUE = 82, T_TRY = 73, T_TYPEOF = 74, T_VAR = 75, T_VOID = 76, T_WHILE = 77, T_WITH = 78, T_XOR = 79, T_XOR_EQ = 80, ACCEPT_STATE = 644, RULE_COUNT = 349, STATE_COUNT = 645, TERMINAL_COUNT = 102, NON_TERMINAL_COUNT = 107, GOTO_INDEX_OFFSET = 645, GOTO_INFO_OFFSET = 2789, GOTO_CHECK_OFFSET = 2789 }; static const char *const spell[]; static const short lhs[]; static const short rhs[]; static const short goto_default[]; static const short action_default[]; static const short action_index[]; static const short action_info[]; static const short action_check[]; static inline int nt_action (int state, int nt) { const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) return goto_default [nt]; return action_info [GOTO_INFO_OFFSET + yyn]; } static inline int t_action (int state, int token) { const int yyn = action_index [state] + token; if (yyn < 0 || action_check [yyn] != token) return - action_default [state]; return action_info [yyn]; } }; } // namespace QbsQmlJS #endif // QMLJSGRAMMAR_P_H qbs-src-2.6.1/src/lib/corelib/parser/qmljsgrammar.cpp0000644000175100001660000013031114776170045022120 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // This file was generated by qlalr - DO NOT EDIT! #include "qmljsgrammar_p.h" namespace QbsQmlJS { const char *const QmlJSGrammar::spell [] = { "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ",", "continue", "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===", "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier", "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=", "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=", "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return", ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch", "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^", "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public", "import", "as", "on", 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const short QmlJSGrammar::lhs [] = { 102, 102, 102, 102, 102, 102, 103, 109, 109, 112, 112, 114, 113, 113, 113, 113, 113, 113, 113, 113, 116, 111, 110, 119, 119, 120, 120, 121, 121, 118, 107, 107, 107, 107, 123, 123, 123, 123, 123, 123, 123, 107, 131, 131, 131, 132, 132, 133, 133, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 117, 117, 117, 117, 117, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 122, 138, 138, 138, 138, 137, 137, 140, 140, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 144, 144, 115, 115, 115, 115, 115, 147, 147, 148, 148, 148, 148, 146, 146, 149, 149, 150, 150, 151, 151, 151, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 155, 155, 155, 155, 156, 156, 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 159, 159, 159, 159, 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, 171, 141, 141, 172, 172, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 105, 105, 174, 174, 175, 175, 176, 176, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 124, 185, 185, 184, 184, 135, 135, 186, 186, 187, 187, 189, 189, 188, 190, 193, 191, 191, 194, 192, 192, 125, 126, 126, 127, 127, 177, 177, 177, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179, 180, 180, 128, 129, 195, 195, 198, 198, 196, 196, 199, 197, 181, 181, 181, 182, 182, 130, 130, 130, 200, 201, 183, 183, 134, 145, 205, 205, 202, 202, 203, 203, 206, 108, 108, 207, 207, 106, 106, 204, 204, 139, 139, 208 }; const short QmlJSGrammar::rhs [] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 3, 3, 5, 5, 4, 4, 2, 0, 1, 1, 2, 1, 3, 2, 3, 2, 1, 5, 4, 4, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 1, 2, 4, 6, 6, 3, 3, 7, 7, 4, 4, 5, 5, 5, 6, 6, 10, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 5, 3, 4, 3, 1, 1, 2, 3, 4, 1, 2, 3, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 3, 5, 1, 2, 4, 4, 4, 3, 0, 1, 1, 3, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 3, 3, 1, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 1, 3, 3, 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 5, 1, 5, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 1, 1, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 0, 1, 3, 3, 1, 1, 1, 3, 1, 3, 2, 2, 2, 0, 1, 2, 0, 1, 1, 2, 2, 7, 5, 7, 7, 5, 9, 10, 7, 8, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 5, 5, 3, 5, 1, 2, 0, 1, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, 8, 8, 1, 3, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 1, 2 }; const short QmlJSGrammar::action_default [] = { 0, 0, 22, 0, 0, 0, 22, 0, 175, 242, 206, 214, 210, 154, 226, 202, 3, 139, 73, 155, 218, 222, 143, 172, 153, 158, 138, 192, 179, 0, 80, 81, 76, 345, 67, 347, 0, 0, 0, 0, 78, 0, 0, 74, 77, 71, 0, 0, 68, 70, 69, 79, 72, 0, 75, 0, 0, 168, 0, 0, 155, 174, 157, 156, 0, 0, 0, 170, 171, 169, 173, 0, 203, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 177, 178, 176, 181, 185, 184, 182, 180, 195, 194, 196, 0, 211, 0, 207, 0, 0, 149, 136, 148, 137, 105, 106, 107, 132, 108, 133, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 134, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 135, 0, 0, 147, 243, 150, 0, 151, 0, 152, 146, 0, 239, 232, 230, 237, 238, 236, 235, 241, 234, 233, 231, 240, 227, 0, 215, 0, 0, 219, 0, 0, 223, 0, 0, 149, 141, 0, 140, 0, 145, 159, 0, 346, 334, 335, 0, 332, 0, 333, 0, 336, 250, 257, 256, 264, 252, 0, 253, 337, 0, 344, 254, 255, 260, 258, 341, 338, 343, 261, 0, 272, 0, 0, 0, 0, 345, 67, 0, 347, 68, 244, 286, 69, 0, 0, 0, 273, 0, 0, 262, 263, 0, 251, 259, 287, 288, 331, 342, 0, 302, 303, 304, 305, 0, 298, 299, 300, 301, 328, 329, 0, 0, 0, 0, 0, 291, 292, 248, 246, 208, 216, 212, 228, 204, 249, 0, 155, 220, 224, 197, 186, 0, 0, 205, 0, 0, 0, 0, 198, 0, 0, 0, 0, 0, 190, 188, 191, 189, 187, 200, 199, 201, 0, 213, 0, 209, 0, 247, 155, 0, 229, 244, 245, 0, 244, 0, 0, 294, 0, 0, 0, 296, 0, 217, 0, 0, 221, 0, 0, 225, 284, 0, 276, 285, 279, 0, 283, 0, 244, 277, 0, 244, 0, 0, 295, 0, 0, 0, 297, 346, 334, 0, 0, 336, 0, 330, 0, 320, 0, 0, 0, 290, 0, 289, 0, 348, 0, 104, 266, 269, 0, 105, 272, 108, 133, 110, 111, 76, 115, 116, 67, 117, 120, 74, 77, 68, 244, 69, 79, 123, 72, 125, 75, 127, 128, 273, 130, 131, 135, 0, 97, 0, 0, 99, 103, 101, 88, 100, 102, 0, 98, 87, 267, 265, 143, 144, 149, 0, 142, 0, 319, 0, 306, 307, 0, 318, 0, 0, 0, 309, 314, 312, 315, 0, 0, 313, 314, 0, 310, 0, 311, 268, 317, 0, 268, 316, 0, 321, 322, 0, 268, 323, 324, 0, 0, 325, 0, 0, 0, 326, 327, 161, 160, 0, 0, 0, 293, 0, 0, 0, 308, 281, 274, 0, 282, 278, 0, 280, 270, 0, 271, 275, 91, 0, 0, 95, 82, 0, 84, 93, 0, 85, 94, 96, 86, 92, 83, 0, 89, 165, 163, 167, 164, 162, 166, 339, 6, 340, 4, 2, 65, 90, 0, 0, 68, 70, 69, 31, 5, 0, 66, 0, 45, 44, 43, 0, 0, 58, 0, 59, 35, 36, 37, 38, 40, 41, 62, 39, 0, 45, 0, 0, 0, 0, 0, 54, 0, 55, 0, 0, 26, 0, 0, 63, 27, 0, 30, 28, 24, 0, 29, 25, 0, 56, 0, 57, 143, 0, 60, 64, 0, 0, 0, 0, 61, 0, 52, 46, 53, 47, 0, 0, 0, 0, 49, 0, 50, 51, 48, 0, 0, 143, 268, 0, 0, 42, 105, 272, 108, 133, 110, 111, 76, 115, 116, 67, 117, 120, 74, 77, 68, 244, 69, 79, 123, 72, 125, 75, 127, 128, 273, 130, 131, 135, 0, 32, 33, 0, 34, 8, 0, 10, 0, 9, 0, 1, 21, 12, 0, 13, 0, 14, 0, 19, 20, 0, 15, 16, 0, 17, 18, 11, 23, 7, 349 }; const short QmlJSGrammar::goto_default [] = { 7, 625, 207, 196, 205, 508, 496, 624, 643, 495, 623, 621, 626, 22, 622, 18, 507, 549, 539, 546, 541, 526, 191, 195, 197, 201, 233, 208, 230, 530, 570, 569, 200, 232, 26, 474, 473, 356, 355, 9, 354, 357, 107, 17, 145, 24, 13, 144, 19, 25, 57, 23, 8, 28, 27, 269, 15, 263, 10, 259, 12, 261, 11, 260, 20, 267, 21, 268, 14, 262, 258, 299, 411, 264, 265, 202, 193, 192, 204, 203, 229, 194, 360, 359, 231, 463, 462, 321, 322, 465, 324, 464, 323, 419, 423, 426, 422, 421, 441, 442, 185, 199, 181, 184, 198, 206, 0 }; const short QmlJSGrammar::action_index [] = { 360, 1257, 2491, 2491, 2393, 982, 78, 84, 145, -102, 81, 64, 68, 210, -102, 306, 54, -102, -102, 620, 59, 128, 268, 244, -102, -102, -102, 521, 205, 1257, -102, -102, -102, 442, -102, 2197, 1819, 1257, 1257, 1257, -102, 682, 1257, -102, -102, -102, 1257, 1257, -102, -102, -102, -102, -102, 1257, -102, 1257, 1257, -102, 1257, 1257, 95, 188, -102, -102, 1257, 1257, 1257, -102, -102, -102, 191, 1257, 313, 1257, 1257, 1257, 1257, 521, 1257, 1257, 1257, 1257, 1257, 1257, 196, 1257, 1257, 1257, 151, 146, 116, 167, 174, 182, 186, 189, 521, 429, 521, 1257, 45, 1257, 41, 2099, 1257, 1257, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 125, 1257, -102, -102, 58, 46, -102, 1257, -102, -102, 1257, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 1257, 17, 1257, 1257, 75, 71, 1257, -102, 2099, 1257, 1257, -102, 154, -102, 51, -102, -102, 55, -102, 288, 72, 57, -102, 297, -102, 62, 2491, -102, -102, -102, -102, -102, 232, -102, -102, 60, -102, -102, -102, -102, -102, -102, 2491, -102, -102, 458, -102, 470, 89, 2393, 49, 442, 69, 47, 2687, 65, 1257, -102, 61, 43, 1257, 40, -102, 39, 82, -102, -102, 442, -102, -102, -102, -102, -102, -102, 102, -102, -102, -102, -102, 98, -102, -102, -102, -102, -102, -102, 76, 63, 1257, 92, 93, -102, -102, 1348, -102, 88, 66, 48, -102, 304, 80, 77, 560, 187, 86, 400, 271, 442, 1257, 302, 1257, 1257, 1257, 1257, 407, 1257, 1257, 1257, 1257, 1257, 253, 257, 272, 281, 278, 362, 358, 337, 1257, 48, 1257, 73, 1257, -102, 620, 1257, -102, 1257, 56, 44, 1257, 42, 2393, -102, 1257, 117, 2393, -102, 1257, 38, 1257, 1257, 187, 74, 1257, -102, 70, 118, 22, -102, -102, 1257, -102, 442, 1257, -102, 67, 1257, 79, 2393, -102, 1257, 112, 2393, -102, -25, 442, -48, -20, 2491, -41, -102, 2393, -102, 1257, 113, 2393, 2, 2393, -102, 3, 11, -34, -102, -102, 2393, -30, 504, 19, 450, 114, 1257, 2393, 20, -16, 414, -1, -31, 772, -3, -4, -102, 1443, -102, 87, -35, -5, 1257, 0, 30, 1257, 33, 1257, 14, 15, 1257, -102, 2295, 1, -102, -102, -102, -102, -102, -102, 1257, -102, -102, -102, -102, 226, -102, 1257, -6, -102, 2393, -102, 96, -102, -102, 2393, -102, 1257, 101, 36, -102, 53, -102, 29, 91, 1257, -102, 24, 23, -102, -24, -102, 2393, -102, 100, 2393, -102, 250, -102, -102, 90, 2393, 16, -102, 10, 12, -102, 442, -12, 4, -102, -102, -102, -102, 1257, 111, 2393, -102, 1257, 105, 2393, -102, 6, -102, 214, -102, -102, 1257, -102, -102, 354, -102, -102, -102, 85, 1537, -102, -102, 1631, -102, -102, 1725, -102, -102, -102, -102, -102, -102, 135, -102, -102, -102, -102, -102, -102, -102, -102, -102, 2491, -102, -102, -102, 159, -10, 890, 202, -11, 18, -102, -102, 222, -102, 199, -102, -102, -102, 359, 211, -102, 1910, -102, -102, -102, -102, -102, -102, -102, -102, -102, 183, -13, 349, 175, -2, 344, 282, -102, -17, -102, 800, 124, -102, -18, 890, -102, -102, 1074, -102, -102, -102, 1166, -102, -102, 208, -102, 1910, -102, 369, -18, -102, -102, 204, 341, 9, 1910, -102, 203, -102, 177, -102, -8, -51, 309, 206, 442, -102, 83, -102, -102, -102, 2001, 800, 369, 2589, 1819, 34, -102, 436, 25, 493, 108, 1257, 2393, 26, 7, 409, 28, 8, 598, 32, 31, -102, 1443, -102, 87, 5, 21, 1257, 52, 37, 1257, 50, 1257, 35, 13, 134, -102, -102, 27, -102, -102, 710, -102, 266, -38, 890, -102, -102, 115, 300, -102, 176, -102, 122, -102, -102, 442, -102, -102, 126, -102, -102, -102, -102, -102, -102, -107, -3, -98, 4, 7, 280, 3, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -35, -107, -107, -107, -107, -107, -107, -107, -107, -107, 78, -107, -107, -107, 20, -107, -107, -22, 15, 86, 72, -107, 193, 175, -107, -107, -107, 174, 170, -107, -107, -107, -107, -107, 118, -107, 144, 145, -107, 127, 156, -107, -107, -107, -107, 162, 165, 166, -107, -107, -107, -107, 149, -107, 137, 136, 135, 134, -107, 181, 180, 179, 173, 53, 117, -107, 81, 95, 90, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 103, -107, 101, -107, 194, 92, 58, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 32, -107, -107, -107, -107, -107, 16, -107, -107, 49, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 70, -107, 109, 34, -107, -107, 45, -107, 216, 60, 100, -107, -107, -107, -107, -107, -107, -107, -107, 44, -107, -107, -107, 47, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 48, -107, -107, 35, -107, 39, -107, 56, -107, 79, -107, -107, 83, -107, 76, -107, -107, -107, 89, 69, -107, -107, -107, -107, -107, -2, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 19, -107, -107, -107, -107, 105, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -13, 195, -107, 218, 212, 215, 228, -107, 114, 87, 121, 124, 107, -107, -107, -107, -107, -107, -107, -107, -107, 198, -107, 221, -107, 236, -107, -107, 237, -107, 128, -107, -107, 184, -107, 36, -107, 24, -107, 102, -107, 192, -107, 234, 238, -107, -107, 224, -107, -107, -107, -107, -107, -107, 191, -107, 93, 99, -107, -107, 108, -107, 88, -107, 84, -107, 91, -107, -107, 141, -107, -107, -23, -107, -107, 59, -107, 57, -107, 55, -107, 54, -107, -107, -107, -107, -107, -107, 46, -107, 31, -107, 30, -107, 169, 37, -107, -107, 68, -107, -107, 85, -107, -107, -107, 73, -107, -107, -107, -107, 66, -107, 52, 98, -107, 104, -107, -107, 43, -107, 40, -107, -107, -107, -107, -107, -107, -107, 42, -107, -107, -107, -107, -107, -107, 106, -107, -107, 62, -107, -107, -107, -107, 63, -107, 65, -107, -107, -107, -107, -107, -30, -107, 67, -107, -19, -107, -107, -107, -107, 94, -107, -107, 97, -107, -107, -107, -107, -107, 75, -50, -107, -107, 25, -107, 28, -107, 29, -107, -107, -107, -107, 41, -107, 64, -107, 38, -107, 51, -107, -107, -107, -107, -107, -107, 33, -107, -107, 122, -107, -107, -107, -107, 61, -107, -107, 163, -107, -107, 50, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 82, -107, -107, -107, -107, -107, -12, -107, -107, -107, -107, -107, -107, -107, -15, -107, -107, -107, -5, -107, -107, 297, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -9, -26, -107, -11, -107, -107, -107, -107, 183, -107, -107, -107, 288, -107, -107, 283, -107, -107, -107, 390, -107, -107, -107, -107, 321, -107, -107, -8, -107, -107, 11, 18, -107, 305, -107, -107, -107, 1, -107, -107, -107, 14, -4, 0, -107, -107, -107, -107, -107, 337, 217, -107, 22, 279, 9, -107, 8, -107, 6, -107, 153, 17, -107, -107, 5, -107, -107, 96, -107, -107, -107, 13, -107, -107, -107, -107, 23, -107, 10, 77, -107, 71, -107, -107, -107, -107, -107, 12, -107, -107, 21, -107, -107, 26, 148, -107, -107, -107, 27, -107, -107, -107, -107, -107, -107, -10, -107, -107, -107, -107, -107, -107, -107, -107, -107 }; const short QmlJSGrammar::action_info [] = { 572, 416, -124, -103, -121, 348, 346, -126, 399, 575, 389, 340, 342, 343, 345, 545, 563, 538, 352, 391, 257, 401, 533, 466, 531, 403, -132, -113, -124, 424, 431, 430, -132, -113, 424, 346, 444, 440, -103, -121, -129, 416, 71, 257, 348, 440, 446, 565, 448, 457, 453, 457, 620, 335, 408, 560, 511, -129, 424, -126, 545, 164, 141, 440, 141, 99, 147, 545, 414, 420, 440, 453, 409, 440, 272, 453, 346, 164, 170, 416, 187, 318, 71, 348, 644, 257, 292, 325, 296, 272, 0, 183, 0, 477, -102, 190, 443, 0, 0, 252, 141, 427, 306, 0, 0, 304, 149, 434, 141, 141, 444, 179, 99, 141, 292, 236, 0, 189, 457, 141, 141, 141, 0, 0, 101, 141, 327, 294, 331, 0, 172, 0, 542, 141, 0, 0, 314, 62, 301, 333, 315, 478, 542, 141, 577, 576, 428, 101, 63, 173, 249, 248, 254, 251, 256, 255, 58, 413, 412, 247, 246, 418, 141, 242, 241, 459, 0, 59, 620, 249, 248, 455, 337, 350, 172, 249, 248, 310, 166, 328, 543, 142, 167, 634, 633, 58, 58, 640, 639, 312, 615, 58, 85, 173, 86, 488, 59, 59, 172, 85, 64, 86, 59, 64, 512, 87, 512, 85, 0, 86, 177, 85, 87, 86, 85, 554, 86, 173, 518, 406, 87, 85, 469, 86, 87, 103, 0, 87, 512, 579, 85, 529, 86, 512, 87, 512, 0, 637, 636, 567, 141, 172, 0, 87, 104, 65, 105, 0, 65, 0, 514, 66, 514, 0, 66, 545, 64, 0, 141, 0, 173, 513, 406, 513, 568, 566, 0, 635, 0, 555, 553, 0, 519, 517, 514, 470, 468, 514, 85, 514, 86, 514, 85, 172, 86, 513, 0, 0, 513, 536, 513, 87, 513, 235, 234, 87, 85, 85, 86, 86, 0, 65, 173, 85, 174, 86, 85, 66, 86, 87, 87, 438, 437, 630, 580, 0, 87, 34, 0, 87, 274, 275, 274, 275, 73, 74, 34, 631, 629, 34, 0, 73, 74, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 537, 535, 0, 0, 276, 277, 276, 277, 75, 76, 0, 48, 50, 49, 628, 75, 76, 279, 280, 0, 48, 50, 49, 48, 50, 49, 281, 34, 0, 282, 34, 283, 48, 50, 49, 34, 0, 45, 279, 280, 34, 172, 279, 280, 0, 34, 45, 281, 0, 45, 282, 281, 283, 0, 282, 0, 283, 0, 45, -90, 173, 0, 174, 0, 48, 50, 49, 48, 50, 49, 0, 0, 48, 50, 49, 0, 0, 48, 50, 49, 279, 280, 48, 50, 49, 0, 0, 279, 280, 281, 45, 0, 282, 45, 283, 34, 281, 0, 45, 282, 34, 283, -345, 45, 0, 0, 0, -345, 45, 78, 79, 6, 5, 4, 1, 3, 2, 80, 81, 0, 0, 82, 34, 83, 0, 0, 0, 0, 34, 0, 0, 0, 48, 50, 49, 0, 34, 48, 50, 49, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 239, 34, 0, 45, 48, 50, 49, 0, 45, 0, 48, 50, 49, 245, 244, 0, 0, 0, 48, 50, 49, 240, 239, 0, 34, 0, 48, 50, 49, 0, 45, 0, 0, 245, 244, 34, 45, 0, 48, 50, 49, 0, 0, 0, 45, 0, 78, 79, 0, 0, 0, 0, 45, 0, 80, 81, 245, 244, 82, 0, 83, 48, 50, 49, 45, 151, 0, 240, 239, 0, 0, 0, 48, 50, 49, 152, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 45, 154, 0, 155, 0, 0, 308, 0, 0, 0, 0, 45, 0, 0, 156, 0, 157, 62, 0, 0, 0, 0, 0, 0, 158, 30, 31, 159, 63, 0, 0, 0, 0, 160, 0, 33, 0, 0, 151, 161, 0, 0, 34, 0, 0, 0, 35, 36, 152, 37, 0, 0, 153, 0, 0, 162, 41, 0, 0, 0, 44, 154, 0, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 0, 157, 62, 51, 48, 50, 49, 0, 52, 158, 0, 0, 159, 63, 0, 0, 0, 0, 160, 43, 54, 32, 0, 0, 161, 40, 0, 0, 0, 0, 45, 0, 0, 0, 30, 31, 0, 0, 0, 0, 162, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 30, 31, 0, 41, 0, 0, 0, 44, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 51, 48, 50, 49, 0, 52, 503, 0, 0, 0, 44, 0, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 51, 48, 50, 49, 0, 52, 0, 0, 0, 30, 31, 0, 0, 0, 0, 0, 43, 54, 32, 33, 0, 0, 40, 0, 0, 0, 34, 45, 0, 0, 35, 36, 0, 37, 0, 0, 0, 30, 31, 0, 41, 0, 0, 0, 44, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 51, 48, 50, 49, 0, 52, 503, 0, 0, 0, 44, 0, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 51, 48, 50, 49, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 0, 0, 0, 503, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 502, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 0, 0, 0, 503, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 504, 506, 505, 0, 52, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 43, 54, 32, 210, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 502, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 0, 0, 0, 503, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 504, 506, 505, 0, 52, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 43, 54, 32, 210, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 502, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 0, 0, 0, 503, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 504, 506, 505, 0, 52, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 43, 54, 32, 210, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 271, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 483, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 486, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 475, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 483, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 475, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 217, 0, 0, 218, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 51, 48, 50, 49, 223, 52, 0, 53, 225, 55, 0, 56, 0, 228, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 217, 0, 0, 582, 583, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 51, 48, 50, 49, 223, 52, 0, 53, 225, 55, 0, 56, 0, 228, 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 110, 111, 0, 0, 113, 115, 116, 0, 0, 117, 0, 118, 0, 0, 0, 120, 121, 122, 0, 0, 0, 0, 0, 0, 34, 123, 124, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, 0, 0, 0, 0, 48, 50, 49, 130, 131, 132, 0, 134, 135, 136, 137, 138, 139, 0, 0, 127, 133, 119, 112, 114, 128, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 110, 111, 0, 0, 113, 115, 116, 0, 0, 117, 0, 118, 0, 0, 0, 120, 121, 122, 0, 0, 0, 0, 0, 0, 393, 123, 124, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, 0, 0, 0, 398, 395, 397, 0, 130, 131, 132, 0, 134, 135, 136, 137, 138, 139, 0, 0, 127, 133, 119, 112, 114, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 110, 111, 0, 0, 113, 115, 116, 0, 0, 117, 0, 118, 0, 0, 0, 120, 121, 122, 0, 0, 0, 0, 0, 0, 393, 123, 124, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, 396, 0, 0, 0, 129, 0, 0, 0, 0, 0, 398, 395, 397, 0, 130, 131, 132, 0, 134, 135, 136, 137, 138, 139, 0, 0, 127, 133, 119, 112, 114, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 211, 0, 29, 30, 31, 213, 0, 0, 0, 0, 0, 0, 214, 33, 0, 0, 0, 0, 0, 0, 216, 217, 0, 0, 218, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 220, 0, 221, 0, 0, 0, 51, 219, 222, 49, 223, 52, 224, 53, 225, 55, 226, 56, 227, 228, 0, 0, 43, 54, 32, 210, 212, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 211, 0, 29, 30, 31, 213, 0, 0, 0, 0, 0, 0, 214, 215, 0, 0, 0, 0, 0, 0, 216, 217, 0, 0, 218, 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 220, 0, 221, 0, 0, 0, 51, 219, 222, 49, 223, 52, 224, 53, 225, 55, 226, 56, 227, 228, 0, 0, 43, 54, 32, 210, 212, 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 586, 110, 111, 0, 0, 588, 115, 590, 30, 31, 591, 0, 118, 0, 0, 0, 120, 593, 594, 0, 0, 0, 0, 0, 0, 595, 596, 124, 125, 218, 36, 0, 37, 0, 0, 0, 38, 0, 39, 597, 42, 0, 0, 599, 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, 601, 0, 221, 0, 0, 0, 603, 600, 602, 49, 604, 605, 606, 53, 608, 609, 610, 611, 612, 613, 0, 0, 598, 607, 592, 587, 589, 128, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 361, 110, 111, 0, 0, 363, 115, 365, 30, 31, 366, 0, 118, 0, 0, 0, 120, 368, 369, 0, 0, 0, 0, 0, 0, 370, 371, 124, 125, 218, 36, 0, 37, 0, 0, 0, 38, 0, 39, 372, 42, 0, 0, 374, 0, 0, 0, 46, 0, 47, 0, -268, 0, 0, 0, 376, 0, 221, 0, 0, 0, 378, 375, 377, 49, 379, 380, 381, 53, 383, 384, 385, 386, 387, 388, 0, 0, 373, 382, 367, 362, 364, 128, 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 528, 320, 532, 534, 638, 552, 497, 498, 499, 516, 559, 619, 461, 515, 574, 302, 472, 487, 250, 182, 243, 253, 238, 358, 573, 436, 309, 616, 578, 571, 618, 439, 562, 627, 182, 150, 641, 307, 250, 561, 458, 632, 447, 454, 243, 238, 450, 402, 445, 238, 449, 237, 460, 243, 148, 353, 351, 250, 186, 349, 347, 188, 176, 410, 415, 456, 425, 417, 436, 433, 143, 467, 169, 439, 429, 302, 358, 344, 302, 392, 400, 390, 182, 171, 358, 237, 336, 163, 482, 334, 439, 436, 338, 339, 140, 358, 146, 404, 358, 485, 60, 302, 0, 311, 0, 94, 0, 320, 404, 0, 302, 0, 0, 0, 0, 0, 0, 60, 60, 60, 452, 490, 0, 0, 60, 60, 451, 180, 60, 405, 302, 165, 88, 60, 60, 489, 461, 60, 146, 285, 405, 90, 60, 178, 146, 60, 89, 451, 60, 407, 60, 60, 266, 452, 60, 186, 60, 270, 102, 288, 501, 60, 100, 642, 60, 60, 284, 494, 60, 95, 330, 60, 168, 286, 60, 432, 287, 61, 435, 332, 329, 60, 60, 60, 60, 0, 302, 98, 97, 96, 77, 60, 60, 451, 452, 501, 60, 480, 540, 303, 60, 479, 180, 60, 72, 404, 70, 471, 106, 60, 0, 67, 60, 60, 68, 69, 60, 60, 180, 493, 60, 60, 60, 492, 491, 93, 60, 60, 60, 501, 106, 92, 91, 84, 108, 0, 617, 405, 298, 60, 341, 0, 60, 270, 270, 60, 0, 270, 0, 0, 270, 273, 0, 0, 313, 305, 108, 175, 293, 60, 326, 0, 60, 0, 270, 60, 289, 270, 60, 290, 270, 298, 278, 270, 0, 60, 270, 0, 0, 295, 270, 60, 291, 298, 298, 298, 270, 548, 270, 270, 270, 556, 501, 319, 540, 501, 614, 0, 316, 509, 501, 0, 509, 544, 0, 297, 300, 317, 0, 0, 0, 500, 510, 0, 500, 510, 0, 472, 520, 521, 522, 523, 527, 524, 525, 564, 520, 521, 522, 523, 527, 524, 525, 556, 0, 0, 0, 0, 0, 0, 557, 558, 520, 521, 522, 523, 527, 524, 525, 581, 0, 0, 0, 0, 0, 0, 584, 585, 520, 521, 522, 523, 527, 524, 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const short QmlJSGrammar::action_check [] = { 8, 36, 7, 7, 7, 36, 7, 7, 7, 60, 7, 36, 60, 33, 55, 33, 7, 34, 16, 8, 36, 55, 24, 17, 37, 55, 7, 7, 7, 5, 7, 55, 7, 7, 5, 7, 20, 33, 7, 7, 7, 36, 1, 36, 36, 33, 36, 29, 60, 36, 36, 36, 90, 31, 60, 66, 66, 7, 5, 7, 33, 2, 8, 33, 8, 48, 8, 33, 7, 33, 33, 36, 7, 33, 1, 36, 7, 2, 7, 36, 8, 7, 1, 36, 0, 36, 48, 17, 8, 1, -1, 36, -1, 8, 7, 33, 6, -1, -1, 36, 8, 10, 60, -1, -1, 61, 60, 7, 8, 8, 20, 60, 48, 8, 48, 55, -1, 60, 36, 8, 8, 8, -1, -1, 79, 8, 8, 79, 61, -1, 15, -1, 8, 8, -1, -1, 50, 42, 61, 60, 54, 56, 8, 8, 61, 62, 55, 79, 53, 34, 61, 62, 60, 77, 61, 62, 40, 61, 62, 61, 62, 60, 8, 61, 62, 60, -1, 51, 90, 61, 62, 60, 60, 60, 15, 61, 62, 60, 50, 61, 56, 56, 54, 61, 62, 40, 40, 61, 62, 2, 56, 40, 25, 34, 27, 60, 51, 51, 15, 25, 12, 27, 51, 12, 29, 38, 29, 25, -1, 27, 56, 25, 38, 27, 25, 7, 27, 34, 7, 36, 38, 25, 8, 27, 38, 15, -1, 38, 29, 7, 25, 29, 27, 29, 38, 29, -1, 61, 62, 36, 8, 15, -1, 38, 34, 57, 36, -1, 57, -1, 75, 63, 75, -1, 63, 33, 12, -1, 8, -1, 34, 86, 36, 86, 61, 62, -1, 91, -1, 61, 62, -1, 61, 62, 75, 61, 62, 75, 25, 75, 27, 75, 25, 15, 27, 86, -1, -1, 86, 7, 86, 38, 86, 61, 62, 38, 25, 25, 27, 27, -1, 57, 34, 25, 36, 27, 25, 63, 27, 38, 38, 61, 62, 47, 92, -1, 38, 29, -1, 38, 18, 19, 18, 19, 18, 19, 29, 61, 62, 29, -1, 18, 19, -1, -1, -1, -1, -1, 29, -1, -1, -1, -1, 61, 62, -1, -1, 45, 46, 45, 46, 45, 46, -1, 66, 67, 68, 91, 45, 46, 23, 24, -1, 66, 67, 68, 66, 67, 68, 32, 29, -1, 35, 29, 37, 66, 67, 68, 29, -1, 92, 23, 24, 29, 15, 23, 24, -1, 29, 92, 32, -1, 92, 35, 32, 37, -1, 35, -1, 37, -1, 92, 33, 34, -1, 36, -1, 66, 67, 68, 66, 67, 68, -1, -1, 66, 67, 68, -1, -1, 66, 67, 68, 23, 24, 66, 67, 68, -1, -1, 23, 24, 32, 92, -1, 35, 92, 37, 29, 32, -1, 92, 35, 29, 37, 36, 92, -1, -1, -1, 36, 92, 23, 24, 94, 95, 96, 97, 98, 99, 31, 32, -1, -1, 35, 29, 37, -1, -1, -1, -1, 29, -1, -1, -1, 66, 67, 68, -1, 29, 66, 67, 68, -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, 29, -1, 92, 66, 67, 68, -1, 92, -1, 66, 67, 68, 61, 62, -1, -1, -1, 66, 67, 68, 61, 62, -1, 29, -1, 66, 67, 68, -1, 92, -1, -1, 61, 62, 29, 92, -1, 66, 67, 68, -1, -1, -1, 92, -1, 23, 24, -1, -1, -1, -1, 92, -1, 31, 32, 61, 62, 35, -1, 37, 66, 67, 68, 92, 3, -1, 61, 62, -1, -1, -1, 66, 67, 68, 13, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, 92, 26, -1, 28, -1, -1, 31, -1, -1, -1, -1, 92, -1, -1, 39, -1, 41, 42, -1, -1, -1, -1, -1, -1, 49, 12, 13, 52, 53, -1, -1, -1, -1, 58, -1, 22, -1, -1, 3, 64, -1, -1, 29, -1, -1, -1, 33, 34, 13, 36, -1, -1, 17, -1, -1, 80, 43, -1, -1, -1, 47, 26, -1, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 41, 42, 65, 66, 67, 68, -1, 70, 49, -1, -1, 52, 53, -1, -1, -1, -1, 58, 81, 82, 83, -1, -1, 64, 87, -1, -1, -1, -1, 92, -1, -1, -1, 12, 13, -1, -1, -1, -1, 80, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 12, 13, -1, 43, -1, -1, -1, 47, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, 65, 66, 67, 68, -1, 70, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, 65, 66, 67, 68, -1, 70, -1, -1, -1, 12, 13, -1, -1, -1, -1, -1, 81, 82, 83, 22, -1, -1, 87, -1, -1, -1, 29, 92, -1, -1, 33, 34, -1, 36, -1, -1, -1, 12, 13, -1, 43, -1, -1, -1, 47, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, 65, 66, 67, 68, -1, 70, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, 75, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, -1, 76, -1, 78, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, -1, 76, -1, 78, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, 9, -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, 9, -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, 55, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 13, 15, 29, 15, 15, 15, 105, 4, 2, 15, 19, 9, 15, 29, 15, 3, 39, 3, 2, 15, 15, 3, 15, 2, 29, 3, 3, 19, 15, 29, 19, 22, 15, 13, 15, 71, 11, 2, 2, 29, 3, 15, 15, 3, 15, 15, 22, 2, 99, 15, 22, 4, 2, 15, 39, 2, 2, 2, 15, 3, 2, 15, 3, 2, 2, 2, 97, 3, 3, 3, 39, 39, 39, 22, 94, 3, 2, 101, 3, 40, 39, 39, 15, 39, 2, 4, 3, 39, 39, 2, 22, 3, 2, 15, 3, 2, 39, 13, 2, 39, 48, 3, -1, 2, -1, 53, -1, 15, 13, -1, 3, -1, -1, -1, -1, -1, -1, 48, 48, 48, 50, 50, -1, -1, 48, 48, 50, 50, 48, 45, 3, 62, 52, 48, 48, 50, 15, 48, 39, 53, 45, 52, 48, 44, 39, 48, 52, 50, 48, 44, 48, 48, 48, 50, 48, 15, 48, 53, 58, 53, 13, 48, 60, 16, 48, 48, 53, 50, 48, 53, 72, 48, 64, 53, 48, 82, 53, 51, 82, 72, 88, 48, 48, 48, 48, -1, 3, 54, 54, 54, 54, 48, 48, 50, 50, 13, 48, 35, 16, 72, 48, 39, 50, 48, 56, 13, 51, 86, 15, 48, -1, 50, 48, 48, 50, 50, 48, 48, 50, 50, 48, 48, 48, 50, 50, 53, 48, 48, 48, 13, 15, 53, 53, 53, 41, -1, 20, 45, 48, 48, 100, -1, 48, 53, 53, 48, -1, 53, -1, -1, 53, 57, -1, -1, 63, 72, 41, 42, 61, 48, 70, -1, 48, -1, 53, 48, 55, 53, 48, 55, 53, 48, 55, 53, -1, 48, 53, -1, -1, 59, 53, 48, 55, 48, 48, 48, 53, 5, 53, 53, 53, 13, 13, 70, 16, 13, 18, -1, 65, 20, 13, -1, 20, 16, -1, 70, 70, 70, -1, -1, -1, 32, 33, -1, 32, 33, -1, 39, 22, 23, 24, 25, 26, 27, 28, 21, 22, 23, 24, 25, 26, 27, 28, 13, -1, -1, -1, -1, -1, -1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 13, -1, -1, -1, -1, -1, -1, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; } // end of namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/parser/qmljsastvisitor_p.h0000644000175100001660000002742114776170045022674 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSASTVISITOR_P_H #define QMLJSASTVISITOR_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qmljsastfwd_p.h" #include "qmljsglobal_p.h" #include namespace QbsQmlJS { namespace AST { class QML_PARSER_EXPORT Visitor { public: Visitor(); virtual ~Visitor(); virtual bool preVisit(Node *) { return true; } virtual void postVisit(Node *) {} // Ui virtual bool visit(UiProgram *) { return true; } virtual bool visit(UiImportList *) { return true; } virtual bool visit(UiImport *) { return true; } virtual bool visit(UiPublicMember *) { return true; } virtual bool visit(UiSourceElement *) { return true; } virtual bool visit(UiObjectDefinition *) { return true; } virtual bool visit(UiObjectInitializer *) { return true; } virtual bool visit(UiObjectBinding *) { return true; } virtual bool visit(UiScriptBinding *) { return true; } virtual bool visit(UiArrayBinding *) { return true; } virtual bool visit(UiObjectMemberList *) { return true; } virtual bool visit(UiArrayMemberList *) { return true; } virtual bool visit(UiQualifiedId *) { return true; } virtual void endVisit(UiProgram *) {} virtual void endVisit(UiImportList *) {} virtual void endVisit(UiImport *) {} virtual void endVisit(UiPublicMember *) {} virtual void endVisit(UiSourceElement *) {} virtual void endVisit(UiObjectDefinition *) {} virtual void endVisit(UiObjectInitializer *) {} virtual void endVisit(UiObjectBinding *) {} virtual void endVisit(UiScriptBinding *) {} virtual void endVisit(UiArrayBinding *) {} virtual void endVisit(UiObjectMemberList *) {} virtual void endVisit(UiArrayMemberList *) {} virtual void endVisit(UiQualifiedId *) {} // QbsQmlJS virtual bool visit(ThisExpression *) { return true; } virtual void endVisit(ThisExpression *) {} virtual bool visit(IdentifierExpression *) { return true; } virtual void endVisit(IdentifierExpression *) {} virtual bool visit(NullExpression *) { return true; } virtual void endVisit(NullExpression *) {} virtual bool visit(TrueLiteral *) { return true; } virtual void endVisit(TrueLiteral *) {} virtual bool visit(FalseLiteral *) { return true; } virtual void endVisit(FalseLiteral *) {} virtual bool visit(StringLiteral *) { return true; } virtual void endVisit(StringLiteral *) {} virtual bool visit(NumericLiteral *) { return true; } virtual void endVisit(NumericLiteral *) {} virtual bool visit(RegExpLiteral *) { return true; } virtual void endVisit(RegExpLiteral *) {} virtual bool visit(ArrayLiteral *) { return true; } virtual void endVisit(ArrayLiteral *) {} virtual bool visit(ObjectLiteral *) { return true; } virtual void endVisit(ObjectLiteral *) {} virtual bool visit(ElementList *) { return true; } virtual void endVisit(ElementList *) {} virtual bool visit(Elision *) { return true; } virtual void endVisit(Elision *) {} virtual bool visit(PropertyNameAndValueList *) { return true; } virtual void endVisit(PropertyNameAndValueList *) {} virtual bool visit(NestedExpression *) { return true; } virtual void endVisit(NestedExpression *) {} virtual bool visit(IdentifierPropertyName *) { return true; } virtual void endVisit(IdentifierPropertyName *) {} virtual bool visit(StringLiteralPropertyName *) { return true; } virtual void endVisit(StringLiteralPropertyName *) {} virtual bool visit(NumericLiteralPropertyName *) { return true; } virtual void endVisit(NumericLiteralPropertyName *) {} virtual bool visit(ArrayMemberExpression *) { return true; } virtual void endVisit(ArrayMemberExpression *) {} virtual bool visit(FieldMemberExpression *) { return true; } virtual void endVisit(FieldMemberExpression *) {} virtual bool visit(NewMemberExpression *) { return true; } virtual void endVisit(NewMemberExpression *) {} virtual bool visit(NewExpression *) { return true; } virtual void endVisit(NewExpression *) {} virtual bool visit(CallExpression *) { return true; } virtual void endVisit(CallExpression *) {} virtual bool visit(ArgumentList *) { return true; } virtual void endVisit(ArgumentList *) {} virtual bool visit(PostIncrementExpression *) { return true; } virtual void endVisit(PostIncrementExpression *) {} virtual bool visit(PostDecrementExpression *) { return true; } virtual void endVisit(PostDecrementExpression *) {} virtual bool visit(DeleteExpression *) { return true; } virtual void endVisit(DeleteExpression *) {} virtual bool visit(VoidExpression *) { return true; } virtual void endVisit(VoidExpression *) {} virtual bool visit(TypeOfExpression *) { return true; } virtual void endVisit(TypeOfExpression *) {} virtual bool visit(PreIncrementExpression *) { return true; } virtual void endVisit(PreIncrementExpression *) {} virtual bool visit(PreDecrementExpression *) { return true; } virtual void endVisit(PreDecrementExpression *) {} virtual bool visit(UnaryPlusExpression *) { return true; } virtual void endVisit(UnaryPlusExpression *) {} virtual bool visit(UnaryMinusExpression *) { return true; } virtual void endVisit(UnaryMinusExpression *) {} virtual bool visit(TildeExpression *) { return true; } virtual void endVisit(TildeExpression *) {} virtual bool visit(NotExpression *) { return true; } virtual void endVisit(NotExpression *) {} virtual bool visit(BinaryExpression *) { return true; } virtual void endVisit(BinaryExpression *) {} virtual bool visit(ConditionalExpression *) { return true; } virtual void endVisit(ConditionalExpression *) {} virtual bool visit(Expression *) { return true; } virtual void endVisit(Expression *) {} virtual bool visit(Block *) { return true; } virtual void endVisit(Block *) {} virtual bool visit(StatementList *) { return true; } virtual void endVisit(StatementList *) {} virtual bool visit(VariableStatement *) { return true; } virtual void endVisit(VariableStatement *) {} virtual bool visit(VariableDeclarationList *) { return true; } virtual void endVisit(VariableDeclarationList *) {} virtual bool visit(VariableDeclaration *) { return true; } virtual void endVisit(VariableDeclaration *) {} virtual bool visit(EmptyStatement *) { return true; } virtual void endVisit(EmptyStatement *) {} virtual bool visit(ExpressionStatement *) { return true; } virtual void endVisit(ExpressionStatement *) {} virtual bool visit(IfStatement *) { return true; } virtual void endVisit(IfStatement *) {} virtual bool visit(DoWhileStatement *) { return true; } virtual void endVisit(DoWhileStatement *) {} virtual bool visit(WhileStatement *) { return true; } virtual void endVisit(WhileStatement *) {} virtual bool visit(ForStatement *) { return true; } virtual void endVisit(ForStatement *) {} virtual bool visit(LocalForStatement *) { return true; } virtual void endVisit(LocalForStatement *) {} virtual bool visit(ForEachStatement *) { return true; } virtual void endVisit(ForEachStatement *) {} virtual bool visit(LocalForEachStatement *) { return true; } virtual void endVisit(LocalForEachStatement *) {} virtual bool visit(ContinueStatement *) { return true; } virtual void endVisit(ContinueStatement *) {} virtual bool visit(BreakStatement *) { return true; } virtual void endVisit(BreakStatement *) {} virtual bool visit(ReturnStatement *) { return true; } virtual void endVisit(ReturnStatement *) {} virtual bool visit(WithStatement *) { return true; } virtual void endVisit(WithStatement *) {} virtual bool visit(SwitchStatement *) { return true; } virtual void endVisit(SwitchStatement *) {} virtual bool visit(CaseBlock *) { return true; } virtual void endVisit(CaseBlock *) {} virtual bool visit(CaseClauses *) { return true; } virtual void endVisit(CaseClauses *) {} virtual bool visit(CaseClause *) { return true; } virtual void endVisit(CaseClause *) {} virtual bool visit(DefaultClause *) { return true; } virtual void endVisit(DefaultClause *) {} virtual bool visit(LabelledStatement *) { return true; } virtual void endVisit(LabelledStatement *) {} virtual bool visit(ThrowStatement *) { return true; } virtual void endVisit(ThrowStatement *) {} virtual bool visit(TryStatement *) { return true; } virtual void endVisit(TryStatement *) {} virtual bool visit(Catch *) { return true; } virtual void endVisit(Catch *) {} virtual bool visit(Finally *) { return true; } virtual void endVisit(Finally *) {} virtual bool visit(FunctionDeclaration *) { return true; } virtual void endVisit(FunctionDeclaration *) {} virtual bool visit(FunctionExpression *) { return true; } virtual void endVisit(FunctionExpression *) {} virtual bool visit(FormalParameterList *) { return true; } virtual void endVisit(FormalParameterList *) {} virtual bool visit(FunctionBody *) { return true; } virtual void endVisit(FunctionBody *) {} virtual bool visit(Program *) { return true; } virtual void endVisit(Program *) {} virtual bool visit(SourceElements *) { return true; } virtual void endVisit(SourceElements *) {} virtual bool visit(FunctionSourceElement *) { return true; } virtual void endVisit(FunctionSourceElement *) {} virtual bool visit(StatementSourceElement *) { return true; } virtual void endVisit(StatementSourceElement *) {} virtual bool visit(DebuggerStatement *) { return true; } virtual void endVisit(DebuggerStatement *) {} }; } // namespace AST } // namespace QbsQmlJS #endif // QMLJSASTVISITOR_P_H qbs-src-2.6.1/src/lib/corelib/parser/qmljsparser.cpp0000644000175100001660000014031014776170045021766 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include "qmljsengine_p.h" #include "qmljslexer_p.h" #include "qmljsast_p.h" #include "qmljsmemorypool_p.h" #include "qmljsparser_p.h" #include // // This file is automatically generated from qmljs.g. // Changes will be lost. // namespace QbsQmlJS { void Parser::reallocateStack() { if (! stack_size) stack_size = 128; else stack_size <<= 1; sym_stack = reinterpret_cast (realloc(sym_stack, stack_size * sizeof(Value))); state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int))); location_stack = reinterpret_cast (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); string_stack = reinterpret_cast (realloc( static_cast(string_stack), stack_size * sizeof(QStringRef))); } Parser::Parser(Engine *engine): driver(engine), pool(engine->pool()), tos(0), stack_size(0), sym_stack(nullptr), state_stack(nullptr), location_stack(nullptr), string_stack(nullptr), program(nullptr), first_token(nullptr), last_token(nullptr) { } Parser::~Parser() { if (stack_size) { free(sym_stack); free(state_stack); free(location_stack); free(string_stack); } } static inline AST::SourceLocation location(Lexer *lexer) { AST::SourceLocation loc; loc.offset = lexer->tokenOffset(); loc.length = lexer->tokenLength(); loc.startLine = lexer->tokenStartLine(); loc.startColumn = lexer->tokenStartColumn(); return loc; } AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) { QVarLengthArray nameIds; QVarLengthArray locations; AST::ExpressionNode *it = expr; while (const auto m = AST::cast(it)) { nameIds.append(m->name); locations.append(m->identifierToken); it = m->base; } if (const auto idExpr = AST::cast(it)) { const auto q = new (pool) AST::UiQualifiedId(idExpr->name); q->identifierToken = idExpr->identifierToken; AST::UiQualifiedId *currentId = q; for (int i = nameIds.size() - 1; i != -1; --i) { currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]); currentId->identifierToken = locations[i]; } return currentId->finish(); } return nullptr; } bool Parser::parse(int startToken) { Lexer *lexer = driver->lexer(); bool hadErrors = false; int yytoken = -1; int action = 0; token_buffer[0].token = startToken; first_token = &token_buffer[0]; if (startToken == T_FEED_JS_PROGRAM) { Directives ignoreDirectives; Directives *directives = driver->directives(); if (!directives) directives = &ignoreDirectives; lexer->scanDirectives(directives); token_buffer[1].token = lexer->tokenKind(); token_buffer[1].dval = lexer->tokenValue(); token_buffer[1].loc = location(lexer); token_buffer[1].spell = lexer->tokenSpell(); last_token = &token_buffer[2]; } else { last_token = &token_buffer[1]; } tos = -1; program = nullptr; do { if (++tos == stack_size) reallocateStack(); state_stack[tos] = action; _Lcheck_token: if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) { yyprevlloc = yylloc; if (first_token == last_token) { yytoken = lexer->lex(); yylval = lexer->tokenValue(); yytokenspell = lexer->tokenSpell(); yylloc = location(lexer); } else { yytoken = first_token->token; yylval = first_token->dval; yytokenspell = first_token->spell; yylloc = first_token->loc; ++first_token; } } action = t_action(action, yytoken); if (action > 0) { if (action != ACCEPT_STATE) { yytoken = -1; sym(1).dval = yylval; stringRef(1) = yytokenspell; loc(1) = yylloc; } else { --tos; return ! hadErrors; } } else if (action < 0) { const int r = -action - 1; tos -= rhs[r]; switch (r) { case 0: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; case 1: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; case 2: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; case 3: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; case 4: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; case 5: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; case 6: { sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList, sym(2).UiObjectMemberList->finish()); } break; case 8: { sym(1).Node = sym(1).UiImportList->finish(); } break; case 9: { sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport); } break; case 10: { sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport); } break; case 13: { sym(1).UiImport->semicolonToken = loc(2); } break; case 15: { sym(1).UiImport->versionToken = loc(2); sym(1).UiImport->semicolonToken = loc(3); } break; case 17: { sym(1).UiImport->versionToken = loc(2); sym(1).UiImport->asToken = loc(3); sym(1).UiImport->importIdToken = loc(4); sym(1).UiImport->importId = stringRef(4); sym(1).UiImport->semicolonToken = loc(5); } break; case 19: { sym(1).UiImport->asToken = loc(2); sym(1).UiImport->importIdToken = loc(3); sym(1).UiImport->importId = stringRef(3); sym(1).UiImport->semicolonToken = loc(4); } break; case 20: { AST::UiImport *node = nullptr; if (const auto importIdLiteral = AST::cast(sym(2).Expression)) { node = new (pool) AST::UiImport(importIdLiteral->value); node->fileNameToken = loc(2); } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { node = new (pool) AST::UiImport(qualifiedId); node->fileNameToken = loc(2); } sym(1).Node = node; if (node) { node->importToken = loc(1); } else { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), QStringLiteral("Expected a qualified name id or a string literal"))); return false; // ### remove me } } break; case 21: { sym(1).Node = nullptr; } break; case 22: { sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); } break; case 23: { sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); } break; case 24: { const auto node = new (pool) AST:: UiObjectMemberList( sym(1).UiObjectMemberList, sym(2).UiObjectMember); sym(1).Node = node; } break; case 25: { sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember); } break; case 26: { const auto node = new (pool) AST::UiArrayMemberList( sym(1).UiArrayMemberList, sym(3).UiObjectMember); node->commaToken = loc(2); sym(1).Node = node; } break; case 27: { const auto node = new (pool) AST::UiObjectInitializer(nullptr); node->lbraceToken = loc(1); node->rbraceToken = loc(2); sym(1).Node = node; } break; case 28: { const auto node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish()); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; case 29: { const auto node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId, sym(2).UiObjectInitializer); sym(1).Node = node; } break; case 31: { const auto node = new (pool) AST::UiArrayBinding( sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish()); node->colonToken = loc(2); node->lbracketToken = loc(3); node->rbracketToken = loc(5); sym(1).Node = node; } break; case 32: { const auto node = new (pool) AST::UiObjectBinding( sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); node->colonToken = loc(2); sym(1).Node = node; } break; case 33: { const auto node = new (pool) AST::UiObjectBinding( sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer); node->colonToken = loc(2); node->hasOnToken = true; sym(1).Node = node; } break; case 41: { const auto node = new (pool) AST::UiScriptBinding( sym(1).UiQualifiedId, sym(3).Statement); node->colonToken = loc(2); sym(1).Node = node; } break; case 45: { sym(1).Node = nullptr; } break; case 46: { sym(1).Node = sym(1).UiParameterList->finish (); } break; case 47: { const auto node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2)); node->propertyTypeToken = loc(1); node->identifierToken = loc(2); sym(1).Node = node; } break; case 48: { const auto node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4)); node->commaToken = loc(2); node->identifierToken = loc(4); sym(1).Node = node; } break; case 50: { const auto node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(2); node->parameters = sym(4).UiParameterList; node->semicolonToken = loc(6); sym(1).Node = node; } break; case 52: { const auto node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(2); node->semicolonToken = loc(3); sym(1).Node = node; } break; case 54: { const auto node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); node->typeModifier = stringRef(2); node->propertyToken = loc(1); node->typeModifierToken = loc(2); node->typeToken = loc(4); node->identifierToken = loc(6); node->semicolonToken = loc(7); sym(1).Node = node; } break; case 56: { const auto node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(3); node->semicolonToken = loc(4); sym(1).Node = node; } break; case 58: { const auto node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4)); node->isDefaultMember = true; node->defaultToken = loc(1); node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->semicolonToken = loc(5); sym(1).Node = node; } break; case 59: { const auto node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3), sym(5).Statement); node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(3); node->colonToken = loc(4); sym(1).Node = node; } break; case 60: { const auto node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), sym(6).Statement); node->isReadonlyMember = true; node->readonlyToken = loc(1); node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->colonToken = loc(5); sym(1).Node = node; } break; case 61: { const auto node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), sym(6).Statement); node->isDefaultMember = true; node->defaultToken = loc(1); node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->colonToken = loc(5); sym(1).Node = node; } break; case 62: { const auto node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); node->typeModifier = stringRef(2); node->propertyToken = loc(1); node->typeModifierToken = loc(2); node->typeToken = loc(4); node->identifierToken = loc(6); node->semicolonToken = loc(7); // insert a fake ';' before ':' const auto propertyName = new (pool) AST::UiQualifiedId(stringRef(6)); propertyName->identifierToken = loc(6); propertyName->next = nullptr; const auto binding = new (pool) AST::UiArrayBinding( propertyName, sym(9).UiArrayMemberList->finish()); binding->colonToken = loc(7); binding->lbracketToken = loc(8); binding->rbracketToken = loc(10); node->binding = binding; sym(1).Node = node; } break; case 63: { const auto node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(3); node->semicolonToken = loc(4); // insert a fake ';' before ':' const auto propertyName = new (pool) AST::UiQualifiedId(stringRef(3)); propertyName->identifierToken = loc(3); propertyName->next = nullptr; const auto binding = new (pool) AST::UiObjectBinding( propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer); binding->colonToken = loc(4); node->binding = binding; sym(1).Node = node; } break; case 64: { sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); } break; case 65: { sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); } break; case 71: { const auto node = new (pool) AST::ThisExpression(); node->thisToken = loc(1); sym(1).Node = node; } break; case 72: { const auto node = new (pool) AST::IdentifierExpression(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; case 73: { const auto node = new (pool) AST::NullExpression(); node->nullToken = loc(1); sym(1).Node = node; } break; case 74: { const auto node = new (pool) AST::TrueLiteral(); node->trueToken = loc(1); sym(1).Node = node; } break; case 75: { const auto node = new (pool) AST::FalseLiteral(); node->falseToken = loc(1); sym(1).Node = node; } break; case 76: { const auto node = new (pool) AST::NumericLiteral(sym(1).dval); node->literalToken = loc(1); sym(1).Node = node; } break; case 77: case 78: { const auto node = new (pool) AST::StringLiteral(stringRef(1)); node->literalToken = loc(1); sym(1).Node = node; } break; case 79: { bool rx = lexer->scanRegExp(Lexer::NoPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); return false; // ### remove me } loc(1).length = lexer->tokenLength(); yylloc = loc(1); // adjust the location of the current token const auto node = new (pool) AST::RegExpLiteral( driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); node->literalToken = loc(1); sym(1).Node = node; } break; case 80: { bool rx = lexer->scanRegExp(Lexer::EqualPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); return false; } loc(1).length = lexer->tokenLength(); yylloc = loc(1); // adjust the location of the current token const auto node = new (pool) AST::RegExpLiteral( driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); node->literalToken = loc(1); sym(1).Node = node; } break; case 81: { const auto node = new (pool) AST::ArrayLiteral(static_cast(nullptr)); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; } break; case 82: { const auto node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; case 83: { const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; case 84: { const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), nullptr); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(4); sym(1).Node = node; } break; case 85: { const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), sym(4).Elision->finish()); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(5); sym(1).Node = node; } break; case 86: { AST::ObjectLiteral *node = nullptr; if (sym(2).Node) node = new (pool) AST::ObjectLiteral( sym(2).PropertyNameAndValueList->finish ()); else node = new (pool) AST::ObjectLiteral(); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; case 87: { const auto node = new (pool) AST::ObjectLiteral( sym(2).PropertyNameAndValueList->finish ()); node->lbraceToken = loc(1); node->rbraceToken = loc(4); sym(1).Node = node; } break; case 88: { const auto node = new (pool) AST::NestedExpression(sym(2).Expression); node->lparenToken = loc(1); node->rparenToken = loc(3); sym(1).Node = node; } break; case 89: { if (const auto *mem = AST::cast(sym(1).Expression)) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, QStringLiteral("Ignored annotation"))); sym(1).Expression = mem->base; } if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { sym(1).UiQualifiedId = qualifiedId; } else { sym(1).UiQualifiedId = nullptr; diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), QStringLiteral("Expected a qualified name id"))); return false; // ### recover } } break; case 90: { sym(1).Node = new (pool) AST::ElementList(nullptr, sym(1).Expression); } break; case 91: { sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression); } break; case 92: { const auto node = new (pool) AST::ElementList(sym(1).ElementList, nullptr, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; case 93: { const auto node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(), sym(4).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; case 94: { const auto node = new (pool) AST::Elision(); node->commaToken = loc(1); sym(1).Node = node; } break; case 95: { const auto node = new (pool) AST::Elision(sym(1).Elision); node->commaToken = loc(2); sym(1).Node = node; } break; case 96: { const auto node = new (pool) AST::PropertyNameAndValueList( sym(1).PropertyName, sym(3).Expression); node->colonToken = loc(2); sym(1).Node = node; } break; case 97: { const auto node = new (pool) AST::PropertyNameAndValueList( sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); node->commaToken = loc(2); node->colonToken = loc(4); sym(1).Node = node; } break; case 98: { const auto node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 99: case 100: { const auto node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 101: { const auto node = new (pool) AST::StringLiteralPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 102: { const auto node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 103: { const auto node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 139: { const auto node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; case 140: { const auto node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; case 141: { const auto node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); node->rparenToken = loc(5); sym(1).Node = node; } break; case 143: { const auto node = new (pool) AST::NewExpression(sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; case 144: { const auto node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; case 145: { const auto node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; case 146: { const auto node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; case 147: { const auto node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; case 148: { sym(1).Node = nullptr; } break; case 149: { sym(1).Node = sym(1).ArgumentList->finish(); } break; case 150: { sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression); } break; case 151: { const auto node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; case 155: { const auto node = new (pool) AST::PostIncrementExpression(sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; case 156: { const auto node = new (pool) AST::PostDecrementExpression(sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; case 158: { const auto node = new (pool) AST::DeleteExpression(sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; case 159: { const auto node = new (pool) AST::VoidExpression(sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; case 160: { const auto node = new (pool) AST::TypeOfExpression(sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; case 161: { const auto node = new (pool) AST::PreIncrementExpression(sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; case 162: { const auto node = new (pool) AST::PreDecrementExpression(sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; case 163: { const auto node = new (pool) AST::UnaryPlusExpression(sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; case 164: { const auto node = new (pool) AST::UnaryMinusExpression(sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; case 165: { const auto node = new (pool) AST::TildeExpression(sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; case 166: { const auto node = new (pool) AST::NotExpression(sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; case 168: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 169: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 170: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 172: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 173: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 175: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 176: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 177: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 179: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 180: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 181: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 182: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 183: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 184: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 186: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 187: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 188: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 189: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 190: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 192: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 193: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 194: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 195: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 197: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 198: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 199: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 200: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 202: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 204: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 206: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 208: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 210: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 212: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 214: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 216: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 218: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 220: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 222: { const auto node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); node->colonToken = loc(4); sym(1).Node = node; } break; case 224: { const auto node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); node->colonToken = loc(4); sym(1).Node = node; } break; case 226: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 228: { const auto node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 229: { sym(1).ival = QSOperator::Assign; } break; case 230: { sym(1).ival = QSOperator::InplaceMul; } break; case 231: { sym(1).ival = QSOperator::InplaceDiv; } break; case 232: { sym(1).ival = QSOperator::InplaceMod; } break; case 233: { sym(1).ival = QSOperator::InplaceAdd; } break; case 234: { sym(1).ival = QSOperator::InplaceSub; } break; case 235: { sym(1).ival = QSOperator::InplaceLeftShift; } break; case 236: { sym(1).ival = QSOperator::InplaceRightShift; } break; case 237: { sym(1).ival = QSOperator::InplaceURightShift; } break; case 238: { sym(1).ival = QSOperator::InplaceAnd; } break; case 239: { sym(1).ival = QSOperator::InplaceXor; } break; case 240: { sym(1).ival = QSOperator::InplaceOr; } break; case 242: { const auto node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; case 243: { sym(1).Node = nullptr; } break; case 246: { const auto node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; case 247: { sym(1).Node = nullptr; } break; case 264: { const auto node = new (pool) AST::Block(sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; case 265: { sym(1).Node = new (pool) AST::StatementList(sym(1).Statement); } break; case 266: { sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement); } break; case 267: { sym(1).Node = nullptr; } break; case 268: { sym(1).Node = sym(1).StatementList->finish (); } break; case 270: { const auto node = new (pool) AST::VariableStatement( sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); node->declarationKindToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; case 271: { sym(1).ival = T_CONST; } break; case 272: { sym(1).ival = T_VAR; } break; case 273: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; case 274: { const auto node = new (pool) AST::VariableDeclarationList( sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; case 275: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; case 276: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; case 277: { const auto node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; case 278: { const auto node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; case 279: { // ### TODO: AST for initializer sym(1) = sym(2); } break; case 280: { sym(1).Node = nullptr; } break; case 282: { // ### TODO: AST for initializer sym(1) = sym(2); } break; case 283: { sym(1).Node = nullptr; } break; case 285: { const auto node = new (pool) AST::EmptyStatement(); node->semicolonToken = loc(1); sym(1).Node = node; } break; case 287: { const auto node = new (pool) AST::ExpressionStatement(sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; case 288: { const auto node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); node->elseToken = loc(6); sym(1).Node = node; } break; case 289: { const auto node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; case 291: { const auto node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); node->lparenToken = loc(4); node->rparenToken = loc(6); node->semicolonToken = loc(7); sym(1).Node = node; } break; case 292: { const auto node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; case 293: { const auto node = new (pool) AST::ForStatement(sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->firstSemicolonToken = loc(4); node->secondSemicolonToken = loc(6); node->rparenToken = loc(8); sym(1).Node = node; } break; case 294: { const auto node = new (pool) AST::LocalForStatement( sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->varToken = loc(3); node->firstSemicolonToken = loc(5); node->secondSemicolonToken = loc(7); node->rparenToken = loc(9); sym(1).Node = node; } break; case 295: { const auto node = new (pool) AST::ForEachStatement(sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->inToken = loc(4); node->rparenToken = loc(6); sym(1).Node = node; } break; case 296: { const auto node = new (pool) AST::LocalForEachStatement( sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->varToken = loc(3); node->inToken = loc(5); node->rparenToken = loc(7); sym(1).Node = node; } break; case 298: { const auto node = new (pool) AST::ContinueStatement(); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; case 300: { const auto node = new (pool) AST::ContinueStatement(stringRef(2)); node->continueToken = loc(1); node->identifierToken = loc(2); node->semicolonToken = loc(3); sym(1).Node = node; } break; case 302: { const auto node = new (pool) AST::BreakStatement(QStringRef()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; case 304: { const auto node = new (pool) AST::BreakStatement(stringRef(2)); node->breakToken = loc(1); node->identifierToken = loc(2); node->semicolonToken = loc(3); sym(1).Node = node; } break; case 306: { const auto node = new (pool) AST::ReturnStatement(sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; case 307: { const auto node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; case 308: { const auto node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; case 309: { const auto node = new (pool) AST::CaseBlock(sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; case 310: { const auto node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; case 311: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause); } break; case 312: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause); } break; case 313: { sym(1).Node = nullptr; } break; case 314: { sym(1).Node = sym(1).CaseClauses->finish (); } break; case 315: { const auto node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; case 316: { const auto node = new (pool) AST::DefaultClause(sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; case 317: case 318: { const auto node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; case 319: { const auto node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; case 321: { const auto node = new (pool) AST::ThrowStatement(sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; case 322: { const auto node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; case 323: { const auto node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; case 324: { const auto node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; case 325: { const auto node = new (pool) AST::Catch(stringRef(3), sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); node->identifierToken = loc(3); node->rparenToken = loc(4); sym(1).Node = node; } break; case 326: { const auto node = new (pool) AST::Finally(sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; case 328: { const auto node = new (pool) AST::DebuggerStatement(); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; case 329: { const auto node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); node->lparenToken = loc(3); node->rparenToken = loc(5); node->lbraceToken = loc(6); node->rbraceToken = loc(8); sym(1).Node = node; } break; case 330: { const auto node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (! stringRef(2).isNull()) node->identifierToken = loc(2); node->lparenToken = loc(3); node->rparenToken = loc(5); node->lbraceToken = loc(6); node->rbraceToken = loc(8); sym(1).Node = node; } break; case 331: { const auto node = new (pool) AST::FormalParameterList(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; case 332: { const auto node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3)); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; case 333: { sym(1).Node = nullptr; } break; case 334: { sym(1).Node = sym(1).FormalParameterList->finish (); } break; case 335: { sym(1).Node = nullptr; } break; case 337: { sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ()); } break; case 339: { sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ()); } break; case 340: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement); } break; case 341: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement); } break; case 342: { sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement); } break; case 343: { sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration); } break; case 344: { stringRef(1) = QStringRef(); } break; case 346: { sym(1).Node = nullptr; } break; } // switch action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); } // if } while (action != 0); if (first_token == last_token) { const int errorState = state_stack[tos]; // automatic insertion of `;' if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) { SavedToken &tk = token_buffer[0]; tk.token = yytoken; tk.dval = yylval; tk.spell = yytokenspell; tk.loc = yylloc; yylloc = yyprevlloc; yylloc.offset += yylloc.length; yylloc.startColumn += yylloc.length; yylloc.length = 0; //const QString msg = qApp->translate("QmlParser", "Missing `;'"); //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); first_token = &token_buffer[0]; last_token = &token_buffer[1]; yytoken = T_SEMICOLON; yylval = 0; action = errorState; goto _Lcheck_token; } hadErrors = true; token_buffer[0].token = yytoken; token_buffer[0].dval = yylval; token_buffer[0].spell = yytokenspell; token_buffer[0].loc = yylloc; token_buffer[1].token = yytoken = lexer->lex(); token_buffer[1].dval = yylval = lexer->tokenValue(); token_buffer[1].spell = yytokenspell = lexer->tokenSpell(); token_buffer[1].loc = yylloc = location(lexer); if (t_action(errorState, yytoken)) { QString msg; int token = token_buffer[0].token; if (token < 0 || token >= TERMINAL_COUNT) msg = qApp->translate("QmlParser", "Syntax error"); else msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); action = errorState; goto _Lcheck_token; } static int tokens[] = { T_PLUS, T_EQ, T_COMMA, T_COLON, T_SEMICOLON, T_RPAREN, T_RBRACKET, T_RBRACE, T_NUMERIC_LITERAL, T_IDENTIFIER, T_LPAREN, T_LBRACKET, T_LBRACE, EOF_SYMBOL }; for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) { int a = t_action(errorState, *tk); if (a > 0 && t_action(a, yytoken)) { const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); yytoken = *tk; yylval = 0; yylloc = token_buffer[0].loc; yylloc.length = 0; first_token = &token_buffer[0]; last_token = &token_buffer[2]; action = errorState; goto _Lcheck_token; } } for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION || tk == T_FEED_JS_SOURCE_ELEMENT) continue; int a = t_action(errorState, tk); if (a > 0 && t_action(a, yytoken)) { const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); yytoken = tk; yylval = 0; yylloc = token_buffer[0].loc; yylloc.length = 0; action = errorState; goto _Lcheck_token; } } const QString msg = qApp->translate("QmlParser", "Syntax error"); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); } return false; } } // namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/parser/qmljsengine_p.h0000644000175100001660000000751114776170045021730 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSENGINE_P_H #define QMLJSENGINE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qmljsglobal_p.h" #include "qmljsastfwd_p.h" #include "qmljsmemorypool_p.h" #include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #endif #include #include namespace QbsQmlJS { class Lexer; class Directives; class MemoryPool; class QML_PARSER_EXPORT DiagnosticMessage { public: enum Kind { Warning, Error }; DiagnosticMessage() : kind(Error) {} DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, QString message) : kind(kind), loc(loc), message(std::move(message)) {} bool isWarning() const { return kind == Warning; } bool isError() const { return kind == Error; } Kind kind; AST::SourceLocation loc; QString message; }; class QML_PARSER_EXPORT Engine { Lexer *_lexer{nullptr}; Directives *_directives{nullptr}; MemoryPool _pool; QList _comments; QString _extraCode; QString _code; public: Engine(); ~Engine(); void setCode(const QString &code); void addComment(int pos, int len, int line, int col); QList comments() const; Lexer *lexer() const; void setLexer(Lexer *lexer); void setDirectives(Directives *directives); Directives *directives() const; MemoryPool *pool(); inline QStringRef midRef(int position, int size) { return QStringRef(&_code).mid(position, size); } QStringRef newStringRef(const QString &s); QStringRef newStringRef(const QChar *chars, int size); }; double integerFromString(const char *buf, int size, int radix); } // end of namespace QbsQmlJS #endif // QMLJSENGINE_P_H qbs-src-2.6.1/src/lib/corelib/parser/qmljs.g0000644000175100001660000024423514776170045020230 0ustar runnerdocker----------------------------------------------------------------------------- -- -- Copyright (C) 2016 The Qt Company Ltd. -- Contact: https://www.qt.io/licensing/ -- -- This file is part of Qbs. -- -- $QT_BEGIN_LICENSE:LGPL$ -- 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 https://www.qt.io/terms-conditions. For further -- information use the contact form at https://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 3 as published by the Free Software -- Foundation and appearing in the file LICENSE.LGPL3 included in the -- packaging of this file. Please review the following information to -- ensure the GNU Lesser General Public License version 3 requirements -- will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -- -- GNU General Public License Usage -- Alternatively, this file may be used under the terms of the GNU -- General Public License version 2.0 or (at your option) the GNU General -- Public license version 3 or any later version approved by the KDE Free -- Qt Foundation. The licenses are as published by the Free Software -- Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -- included in the packaging of this file. Please review the following -- information to ensure the GNU General Public License requirements will -- be met: https://www.gnu.org/licenses/gpl-2.0.html and -- https://www.gnu.org/licenses/gpl-3.0.html. -- -- $QT_END_LICENSE$ -- ----------------------------------------------------------------------------- %parser QmlJSGrammar %decl qmljsparser_p.h %impl qdeclarativejsparser.cpp %expect 2 %expect-rr 2 %token T_AND "&" T_AND_AND "&&" T_AND_EQ "&=" %token T_BREAK "break" T_CASE "case" T_CATCH "catch" %token T_COLON ":" T_COMMA "," T_CONTINUE "continue" %token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/" %token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "." %token T_ELSE "else" T_EQ "=" T_EQ_EQ "==" %token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for" %token T_FUNCTION "function" T_GE ">=" T_GT ">" %token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>" %token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if" %token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{" %token T_LBRACKET "[" T_LE "<=" T_LPAREN "(" %token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<=" %token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--" %token T_NEW "new" T_NOT "!" T_NOT_EQ "!=" %token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|" %token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+" %token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?" %token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%" %token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")" %token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*" %token T_STAR_EQ "*=" T_STRING_LITERAL "string literal" %token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly" %token T_SWITCH "switch" T_THIS "this" T_THROW "throw" %token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof" %token T_VAR "var" T_VOID "void" T_WHILE "while" %token T_WITH "with" T_XOR "^" T_XOR_EQ "^=" %token T_NULL "null" T_TRUE "true" T_FALSE "false" %token T_CONST "const" %token T_DEBUGGER "debugger" %token T_RESERVED_WORD "reserved word" %token T_MULTILINE_STRING_LITERAL "multiline string literal" %token T_COMMENT "comment" --- context keywords. %token T_PUBLIC "public" %token T_IMPORT "import" %token T_AS "as" %token T_ON "on" %token T_ERROR --- feed tokens %token T_FEED_UI_PROGRAM %token T_FEED_UI_OBJECT_MEMBER %token T_FEED_JS_STATEMENT %token T_FEED_JS_EXPRESSION %token T_FEED_JS_SOURCE_ELEMENT %token T_FEED_JS_PROGRAM %nonassoc SHIFT_THERE %nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY %nonassoc REDUCE_HERE %start TopLevel /./**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include "qmljsengine_p.h" #include "qmljslexer_p.h" #include "qmljsast_p.h" #include "qmljsmemorypool_p.h" ./ /:/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // // // This file is automatically generated from qmljs.g. // Changes will be lost. // #ifndef QMLJSPARSER_P_H #define QMLJSPARSER_P_H #include "qmljsglobal_p.h" #include "qmljsgrammar_p.h" #include "qmljsast_p.h" #include "qmljsengine_p.h" #include #include #include namespace QbsQmlJS { class Engine; class QBS_AUTOTEST_EXPORT Parser: protected $table { public: union Value { int ival; double dval; AST::ArgumentList *ArgumentList; AST::CaseBlock *CaseBlock; AST::CaseClause *CaseClause; AST::CaseClauses *CaseClauses; AST::Catch *Catch; AST::DefaultClause *DefaultClause; AST::ElementList *ElementList; AST::Elision *Elision; AST::ExpressionNode *Expression; AST::Finally *Finally; AST::FormalParameterList *FormalParameterList; AST::FunctionBody *FunctionBody; AST::FunctionDeclaration *FunctionDeclaration; AST::Node *Node; AST::PropertyName *PropertyName; AST::PropertyNameAndValueList *PropertyNameAndValueList; AST::SourceElement *SourceElement; AST::SourceElements *SourceElements; AST::Statement *Statement; AST::StatementList *StatementList; AST::Block *Block; AST::VariableDeclaration *VariableDeclaration; AST::VariableDeclarationList *VariableDeclarationList; AST::UiProgram *UiProgram; AST::UiImportList *UiImportList; AST::UiImport *UiImport; AST::UiParameterList *UiParameterList; AST::UiPublicMember *UiPublicMember; AST::UiObjectDefinition *UiObjectDefinition; AST::UiObjectInitializer *UiObjectInitializer; AST::UiObjectBinding *UiObjectBinding; AST::UiScriptBinding *UiScriptBinding; AST::UiArrayBinding *UiArrayBinding; AST::UiObjectMember *UiObjectMember; AST::UiObjectMemberList *UiObjectMemberList; AST::UiArrayMemberList *UiArrayMemberList; AST::UiQualifiedId *UiQualifiedId; }; public: Parser(Engine *engine); ~Parser(); // parse a UI program bool parse() { return parse(T_FEED_UI_PROGRAM); } bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); } bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } bool parseProgram() { return parse(T_FEED_JS_PROGRAM); } AST::UiProgram *ast() const { return AST::cast(program); } AST::Statement *statement() const { if (! program) return nullptr; return program->statementCast(); } AST::ExpressionNode *expression() const { if (! program) return nullptr; return program->expressionCast(); } AST::UiObjectMember *uiObjectMember() const { if (! program) return nullptr; return program->uiObjectMemberCast(); } AST::Node *rootNode() const { return program; } QList diagnosticMessages() const { return diagnostic_messages; } inline DiagnosticMessage diagnosticMessage() const { foreach (const DiagnosticMessage &d, diagnostic_messages) { if (d.kind != DiagnosticMessage::Warning) return d; } return DiagnosticMessage(); } inline QString errorMessage() const { return diagnosticMessage().message; } inline int errorLineNumber() const { return diagnosticMessage().loc.startLine; } inline int errorColumnNumber() const { return diagnosticMessage().loc.startColumn; } protected: bool parse(int startToken); void reallocateStack(); inline Value &sym(int index) { return sym_stack [tos + index - 1]; } inline QStringRef &stringRef(int index) { return string_stack [tos + index - 1]; } inline AST::SourceLocation &loc(int index) { return location_stack [tos + index - 1]; } AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); protected: Engine *driver; MemoryPool *pool; int tos; int stack_size; Value *sym_stack; int *state_stack; AST::SourceLocation *location_stack; QStringRef *string_stack; AST::Node *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; struct SavedToken { int token = 0; double dval = 0.0; AST::SourceLocation loc; QStringRef spell; }; double yylval = 0.0; QStringRef yytokenspell; AST::SourceLocation yylloc; AST::SourceLocation yyprevlloc; SavedToken token_buffer[TOKEN_BUFFER_SIZE]; SavedToken *first_token; SavedToken *last_token; QList diagnostic_messages; }; } // end of namespace QbsQmlJS :/ /. #include "qmljsparser_p.h" #include // // This file is automatically generated from qmljs.g. // Changes will be lost. // using namespace QmlJS; QT_QML_BEGIN_NAMESPACE void Parser::reallocateStack() { if (! stack_size) stack_size = 128; else stack_size <<= 1; sym_stack = reinterpret_cast (realloc(sym_stack, stack_size * sizeof(Value))); state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int))); location_stack = reinterpret_cast (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); string_stack = reinterpret_cast (realloc(string_stack, stack_size * sizeof(QStringRef))); } Parser::Parser(Engine *engine): driver(engine), pool(engine->pool()), tos(0), stack_size(0), sym_stack(0), state_stack(0), location_stack(0), string_stack(0), first_token(0), last_token(0) { } Parser::~Parser() { if (stack_size) { free(sym_stack); free(state_stack); free(location_stack); free(string_stack); } } static inline AST::SourceLocation location(Lexer *lexer) { AST::SourceLocation loc; loc.offset = lexer->tokenOffset(); loc.length = lexer->tokenLength(); loc.startLine = lexer->tokenStartLine(); loc.startColumn = lexer->tokenStartColumn(); return loc; } AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) { QVarLengthArray nameIds; QVarLengthArray locations; AST::ExpressionNode *it = expr; while (AST::FieldMemberExpression *m = AST::cast(it)) { nameIds.append(m->name); locations.append(m->identifierToken); it = m->base; } if (AST::IdentifierExpression *idExpr = AST::cast(it)) { AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name); q->identifierToken = idExpr->identifierToken; AST::UiQualifiedId *currentId = q; for (int i = nameIds.size() - 1; i != -1; --i) { currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]); currentId->identifierToken = locations[i]; } return currentId->finish(); } return nullptr; } bool Parser::parse(int startToken) { Lexer *lexer = driver->lexer(); bool hadErrors = false; int yytoken = -1; int action = 0; token_buffer[0].token = startToken; first_token = &token_buffer[0]; last_token = &token_buffer[1]; tos = -1; program = 0; do { if (++tos == stack_size) reallocateStack(); state_stack[tos] = action; _Lcheck_token: if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) { yyprevlloc = yylloc; if (first_token == last_token) { yytoken = lexer->lex(); yylval = lexer->tokenValue(); yytokenspell = lexer->tokenSpell(); yylloc = location(lexer); } else { yytoken = first_token->token; yylval = first_token->dval; yytokenspell = first_token->spell; yylloc = first_token->loc; ++first_token; } } action = t_action(action, yytoken); if (action > 0) { if (action != ACCEPT_STATE) { yytoken = -1; sym(1).dval = yylval; stringRef(1) = yytokenspell; loc(1) = yylloc; } else { --tos; return ! hadErrors; } } else if (action < 0) { const int r = -action - 1; tos -= rhs[r]; switch (r) { ./ -------------------------------------------------------------------------------------------------------- -- Declarative UI -------------------------------------------------------------------------------------------------------- TopLevel: T_FEED_UI_PROGRAM UiProgram ; /. case $rule_number: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; ./ TopLevel: T_FEED_JS_STATEMENT Statement ; /. case $rule_number: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; ./ TopLevel: T_FEED_JS_EXPRESSION Expression ; /. case $rule_number: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; ./ TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ; /. case $rule_number: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; ./ TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ; /. case $rule_number: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; ./ TopLevel: T_FEED_JS_PROGRAM Program ; /. case $rule_number: { sym(1).Node = sym(2).Node; program = sym(1).Node; } break; ./ UiProgram: UiImportListOpt UiRootMember ; /. case $rule_number: { sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList, sym(2).UiObjectMemberList->finish()); } break; ./ UiImportListOpt: Empty ; UiImportListOpt: UiImportList ; /. case $rule_number: { sym(1).Node = sym(1).UiImportList->finish(); } break; ./ UiImportList: UiImport ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport); } break; ./ UiImportList: UiImportList UiImport ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport); } break; ./ ImportId: MemberExpression ; UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ; UiImport: UiImportHead T_SEMICOLON ; /. case $rule_number: { sym(1).UiImport->semicolonToken = loc(2); } break; ./ UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ; UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ; /. case $rule_number: { sym(1).UiImport->versionToken = loc(2); sym(1).UiImport->semicolonToken = loc(3); } break; ./ UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ; UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ; /. case $rule_number: { sym(1).UiImport->versionToken = loc(2); sym(1).UiImport->asToken = loc(3); sym(1).UiImport->importIdToken = loc(4); sym(1).UiImport->importId = stringRef(4); sym(1).UiImport->semicolonToken = loc(5); } break; ./ UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ; UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ; /. case $rule_number: { sym(1).UiImport->asToken = loc(2); sym(1).UiImport->importIdToken = loc(3); sym(1).UiImport->importId = stringRef(3); sym(1).UiImport->semicolonToken = loc(4); } break; ./ UiImportHead: T_IMPORT ImportId ; /. case $rule_number: { AST::UiImport *node = 0; if (AST::StringLiteral *importIdLiteral = AST::cast(sym(2).Expression)) { node = new (pool) AST::UiImport(importIdLiteral->value); node->fileNameToken = loc(2); } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { node = new (pool) AST::UiImport(qualifiedId); node->fileNameToken = loc(2); } sym(1).Node = node; if (node) { node->importToken = loc(1); } else { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), QLatin1String("Expected a qualified name id or a string literal"))); return false; // ### remove me } } break; ./ Empty: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ UiRootMember: UiObjectDefinition ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); } break; ./ UiObjectMemberList: UiObjectMember ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); } break; ./ UiObjectMemberList: UiObjectMemberList UiObjectMember ; /. case $rule_number: { AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList( sym(1).UiObjectMemberList, sym(2).UiObjectMember); sym(1).Node = node; } break; ./ UiArrayMemberList: UiObjectDefinition ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember); } break; ./ UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ; /. case $rule_number: { AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList( sym(1).UiArrayMemberList, sym(3).UiObjectMember); node->commaToken = loc(2); sym(1).Node = node; } break; ./ UiObjectInitializer: T_LBRACE T_RBRACE ; /. case $rule_number: { AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0); node->lbraceToken = loc(1); node->rbraceToken = loc(2); sym(1).Node = node; } break; ./ UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ; /. case $rule_number: { AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish()); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; ./ UiObjectDefinition: UiQualifiedId UiObjectInitializer ; /. case $rule_number: { AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId, sym(2).UiObjectInitializer); sym(1).Node = node; } break; ./ UiObjectMember: UiObjectDefinition ; UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; /. case $rule_number: { AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding( sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish()); node->colonToken = loc(2); node->lbracketToken = loc(3); node->rbracketToken = loc(5); sym(1).Node = node; } break; ./ UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; /. case $rule_number: { AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding( sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); node->colonToken = loc(2); sym(1).Node = node; } break; ./ UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ; /. case $rule_number: { AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding( sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer); node->colonToken = loc(2); node->hasOnToken = true; sym(1).Node = node; } break; ./ UiScriptStatement: Block ; UiScriptStatement: EmptyStatement ; UiScriptStatement: ExpressionStatement ; UiScriptStatement: IfStatement ; UiScriptStatement: WithStatement ; UiScriptStatement: SwitchStatement ; UiScriptStatement: TryStatement ; UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ; /. case $rule_number: { AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding( sym(1).UiQualifiedId, sym(3).Statement); node->colonToken = loc(2); sym(1).Node = node; } break; ./ UiPropertyType: T_VAR ; UiPropertyType: T_RESERVED_WORD ; UiPropertyType: T_IDENTIFIER ; UiParameterListOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ UiParameterListOpt: UiParameterList ; /. case $rule_number: { sym(1).Node = sym(1).UiParameterList->finish (); } break; ./ UiParameterList: UiPropertyType JsIdentifier ; /. case $rule_number: { AST::UiParameterList *node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2)); node->propertyTypeToken = loc(1); node->identifierToken = loc(2); sym(1).Node = node; } break; ./ UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ; /. case $rule_number: { AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4)); node->commaToken = loc(2); node->identifierToken = loc(4); sym(1).Node = node; } break; ./ UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ; UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(2); node->parameters = sym(4).UiParameterList; node->semicolonToken = loc(6); sym(1).Node = node; } break; ./ UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2)); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(2); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ; UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); node->typeModifier = stringRef(2); node->propertyToken = loc(1); node->typeModifierToken = loc(2); node->typeToken = loc(4); node->identifierToken = loc(6); node->semicolonToken = loc(7); sym(1).Node = node; } break; ./ UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ; UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(3); node->semicolonToken = loc(4); sym(1).Node = node; } break; ./ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ; UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4)); node->isDefaultMember = true; node->defaultToken = loc(1); node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->semicolonToken = loc(5); sym(1).Node = node; } break; ./ UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3), sym(5).Statement); node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(3); node->colonToken = loc(4); sym(1).Node = node; } break; ./ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), sym(6).Statement); node->isReadonlyMember = true; node->readonlyToken = loc(1); node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->colonToken = loc(5); sym(1).Node = node; } break; ./ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4), sym(6).Statement); node->isDefaultMember = true; node->defaultToken = loc(1); node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->colonToken = loc(5); sym(1).Node = node; } break; ./ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6)); node->typeModifier = stringRef(2); node->propertyToken = loc(1); node->typeModifierToken = loc(2); node->typeToken = loc(4); node->identifierToken = loc(6); node->semicolonToken = loc(7); // insert a fake ';' before ':' AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6)); propertyName->identifierToken = loc(6); propertyName->next = 0; AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding( propertyName, sym(9).UiArrayMemberList->finish()); binding->colonToken = loc(7); binding->lbracketToken = loc(8); binding->rbracketToken = loc(10); node->binding = binding; sym(1).Node = node; } break; ./ UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3)); node->propertyToken = loc(1); node->typeToken = loc(2); node->identifierToken = loc(3); node->semicolonToken = loc(4); // insert a fake ';' before ':' AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3)); propertyName->identifierToken = loc(3); propertyName->next = 0; AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding( propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer); binding->colonToken = loc(4); node->binding = binding; sym(1).Node = node; } break; ./ UiObjectMember: FunctionDeclaration ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); } break; ./ UiObjectMember: VariableStatement ; /. case $rule_number: { sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); } break; ./ JsIdentifier: T_IDENTIFIER; JsIdentifier: T_PROPERTY ; JsIdentifier: T_SIGNAL ; JsIdentifier: T_READONLY ; JsIdentifier: T_ON ; -------------------------------------------------------------------------------------------------------- -- Expressions -------------------------------------------------------------------------------------------------------- PrimaryExpression: T_THIS ; /. case $rule_number: { AST::ThisExpression *node = new (pool) AST::ThisExpression(); node->thisToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: JsIdentifier ; /. case $rule_number: { AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_NULL ; /. case $rule_number: { AST::NullExpression *node = new (pool) AST::NullExpression(); node->nullToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_TRUE ; /. case $rule_number: { AST::TrueLiteral *node = new (pool) AST::TrueLiteral(); node->trueToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_FALSE ; /. case $rule_number: { AST::FalseLiteral *node = new (pool) AST::FalseLiteral(); node->falseToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_NUMERIC_LITERAL ; /. case $rule_number: { AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval); node->literalToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_MULTILINE_STRING_LITERAL ; /.case $rule_number:./ PrimaryExpression: T_STRING_LITERAL ; /. case $rule_number: { AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1)); node->literalToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_DIVIDE_ ; /: #define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number :/ /. case $rule_number: { bool rx = lexer->scanRegExp(Lexer::NoPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); return false; // ### remove me } loc(1).length = lexer->tokenLength(); yylloc = loc(1); // adjust the location of the current token AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral( driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); node->literalToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_DIVIDE_EQ ; /: #define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number :/ /. case $rule_number: { bool rx = lexer->scanRegExp(Lexer::EqualPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); return false; } loc(1).length = lexer->tokenLength(); yylloc = loc(1); // adjust the location of the current token AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral( driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags()); node->literalToken = loc(1); sym(1).Node = node; } break; ./ PrimaryExpression: T_LBRACKET T_RBRACKET ; /. case $rule_number: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; } break; ./ PrimaryExpression: T_LBRACKET Elision T_RBRACKET ; /. case $rule_number: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; ./ PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ; /. case $rule_number: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; ./ PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ; /. case $rule_number: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), (AST::Elision *) 0); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(4); sym(1).Node = node; } break; ./ PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ; /. case $rule_number: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), sym(4).Elision->finish()); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(5); sym(1).Node = node; } break; ./ -- PrimaryExpression: T_LBRACE T_RBRACE ; -- /. -- case $rule_number: { -- sym(1).Node = new (pool) AST::ObjectLiteral(); -- } break; -- ./ PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ; /. case $rule_number: { AST::ObjectLiteral *node = 0; if (sym(2).Node) node = new (pool) AST::ObjectLiteral( sym(2).PropertyNameAndValueList->finish ()); else node = new (pool) AST::ObjectLiteral(); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; ./ PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ; /. case $rule_number: { AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral( sym(2).PropertyNameAndValueList->finish ()); node->lbraceToken = loc(1); node->rbraceToken = loc(4); sym(1).Node = node; } break; ./ PrimaryExpression: T_LPAREN Expression T_RPAREN ; /. case $rule_number: { AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression); node->lparenToken = loc(1); node->rparenToken = loc(3); sym(1).Node = node; } break; ./ UiQualifiedId: MemberExpression ; /. case $rule_number: { if (AST::ArrayMemberExpression *mem = AST::cast(sym(1).Expression)) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, QLatin1String("Ignored annotation"))); sym(1).Expression = mem->base; } if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { sym(1).UiQualifiedId = qualifiedId; } else { sym(1).UiQualifiedId = 0; diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), QLatin1String("Expected a qualified name id"))); return false; // ### recover } } break; ./ ElementList: AssignmentExpression ; /. case $rule_number: { sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression); } break; ./ ElementList: Elision AssignmentExpression ; /. case $rule_number: { sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression); } break; ./ ElementList: ElementList T_COMMA AssignmentExpression ; /. case $rule_number: { AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, (AST::Elision *) 0, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; ./ ElementList: ElementList T_COMMA Elision AssignmentExpression ; /. case $rule_number: { AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(), sym(4).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; ./ Elision: T_COMMA ; /. case $rule_number: { AST::Elision *node = new (pool) AST::Elision(); node->commaToken = loc(1); sym(1).Node = node; } break; ./ Elision: Elision T_COMMA ; /. case $rule_number: { AST::Elision *node = new (pool) AST::Elision(sym(1).Elision); node->commaToken = loc(2); sym(1).Node = node; } break; ./ PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ; /. case $rule_number: { AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList( sym(1).PropertyName, sym(3).Expression); node->colonToken = loc(2); sym(1).Node = node; } break; ./ PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ; /. case $rule_number: { AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList( sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); node->commaToken = loc(2); node->colonToken = loc(4); sym(1).Node = node; } break; ./ PropertyName: T_IDENTIFIER %prec SHIFT_THERE ; /. case $rule_number: { AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; ./ PropertyName: T_SIGNAL ; /.case $rule_number:./ PropertyName: T_PROPERTY ; /. case $rule_number: { AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; ./ PropertyName: T_STRING_LITERAL ; /. case $rule_number: { AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; ./ PropertyName: T_NUMERIC_LITERAL ; /. case $rule_number: { AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; ./ PropertyName: ReservedIdentifier ; /. case $rule_number: { AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; ./ ReservedIdentifier: T_BREAK ; ReservedIdentifier: T_CASE ; ReservedIdentifier: T_CATCH ; ReservedIdentifier: T_CONTINUE ; ReservedIdentifier: T_DEFAULT ; ReservedIdentifier: T_DELETE ; ReservedIdentifier: T_DO ; ReservedIdentifier: T_ELSE ; ReservedIdentifier: T_FALSE ; ReservedIdentifier: T_FINALLY ; ReservedIdentifier: T_FOR ; ReservedIdentifier: T_FUNCTION ; ReservedIdentifier: T_IF ; ReservedIdentifier: T_IN ; ReservedIdentifier: T_INSTANCEOF ; ReservedIdentifier: T_NEW ; ReservedIdentifier: T_NULL ; ReservedIdentifier: T_RETURN ; ReservedIdentifier: T_SWITCH ; ReservedIdentifier: T_THIS ; ReservedIdentifier: T_THROW ; ReservedIdentifier: T_TRUE ; ReservedIdentifier: T_TRY ; ReservedIdentifier: T_TYPEOF ; ReservedIdentifier: T_VAR ; ReservedIdentifier: T_VOID ; ReservedIdentifier: T_WHILE ; ReservedIdentifier: T_CONST ; ReservedIdentifier: T_DEBUGGER ; ReservedIdentifier: T_RESERVED_WORD ; ReservedIdentifier: T_WITH ; PropertyIdentifier: JsIdentifier ; PropertyIdentifier: ReservedIdentifier ; MemberExpression: PrimaryExpression ; MemberExpression: FunctionExpression ; MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ; /. case $rule_number: { AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; ./ MemberExpression: MemberExpression T_DOT PropertyIdentifier ; /. case $rule_number: { AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; ./ MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; /. case $rule_number: { AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); node->rparenToken = loc(5); sym(1).Node = node; } break; ./ NewExpression: MemberExpression ; NewExpression: T_NEW NewExpression ; /. case $rule_number: { AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; ./ CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; /. case $rule_number: { AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ; /. case $rule_number: { AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ; /. case $rule_number: { AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; ./ CallExpression: CallExpression T_DOT PropertyIdentifier ; /. case $rule_number: { AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; ./ ArgumentListOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ ArgumentListOpt: ArgumentList ; /. case $rule_number: { sym(1).Node = sym(1).ArgumentList->finish(); } break; ./ ArgumentList: AssignmentExpression ; /. case $rule_number: { sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression); } break; ./ ArgumentList: ArgumentList T_COMMA AssignmentExpression ; /. case $rule_number: { AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; ./ LeftHandSideExpression: NewExpression ; LeftHandSideExpression: CallExpression ; PostfixExpression: LeftHandSideExpression ; PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ; /. case $rule_number: { AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; ./ PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ; /. case $rule_number: { AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; ./ UnaryExpression: PostfixExpression ; UnaryExpression: T_DELETE UnaryExpression ; /. case $rule_number: { AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_VOID UnaryExpression ; /. case $rule_number: { AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_TYPEOF UnaryExpression ; /. case $rule_number: { AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_PLUS_PLUS UnaryExpression ; /. case $rule_number: { AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_MINUS_MINUS UnaryExpression ; /. case $rule_number: { AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_PLUS UnaryExpression ; /. case $rule_number: { AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_MINUS UnaryExpression ; /. case $rule_number: { AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_TILDE UnaryExpression ; /. case $rule_number: { AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; ./ UnaryExpression: T_NOT UnaryExpression ; /. case $rule_number: { AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; ./ MultiplicativeExpression: UnaryExpression ; MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ AdditiveExpression: MultiplicativeExpression ; AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ ShiftExpression: AdditiveExpression ; ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpression: ShiftExpression ; RelationalExpression: RelationalExpression T_LT ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpression: RelationalExpression T_GT ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpression: RelationalExpression T_LE ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpression: RelationalExpression T_GE ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpression: RelationalExpression T_IN ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpressionNotIn: ShiftExpression ; RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpression: RelationalExpression ; EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpressionNotIn: RelationalExpressionNotIn ; EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ BitwiseANDExpression: EqualityExpression ; BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ BitwiseANDExpressionNotIn: EqualityExpressionNotIn ; BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ BitwiseXORExpression: BitwiseANDExpression ; BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ; BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ BitwiseORExpression: BitwiseXORExpression ; BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ; BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ LogicalANDExpression: BitwiseORExpression ; LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ; LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ LogicalORExpression: LogicalANDExpression ; LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ LogicalORExpressionNotIn: LogicalANDExpressionNotIn ; LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ ConditionalExpression: LogicalORExpression ; ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ; /. case $rule_number: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); node->colonToken = loc(4); sym(1).Node = node; } break; ./ ConditionalExpressionNotIn: LogicalORExpressionNotIn ; ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ; /. case $rule_number: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); node->colonToken = loc(4); sym(1).Node = node; } break; ./ AssignmentExpression: ConditionalExpression ; AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ AssignmentExpressionNotIn: ConditionalExpressionNotIn ; AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ; /. case $rule_number: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; ./ AssignmentOperator: T_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::Assign; } break; ./ AssignmentOperator: T_STAR_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceMul; } break; ./ AssignmentOperator: T_DIVIDE_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceDiv; } break; ./ AssignmentOperator: T_REMAINDER_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceMod; } break; ./ AssignmentOperator: T_PLUS_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceAdd; } break; ./ AssignmentOperator: T_MINUS_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceSub; } break; ./ AssignmentOperator: T_LT_LT_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceLeftShift; } break; ./ AssignmentOperator: T_GT_GT_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceRightShift; } break; ./ AssignmentOperator: T_GT_GT_GT_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceURightShift; } break; ./ AssignmentOperator: T_AND_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceAnd; } break; ./ AssignmentOperator: T_XOR_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceXor; } break; ./ AssignmentOperator: T_OR_EQ ; /. case $rule_number: { sym(1).ival = QSOperator::InplaceOr; } break; ./ Expression: AssignmentExpression ; Expression: Expression T_COMMA AssignmentExpression ; /. case $rule_number: { AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; ./ ExpressionOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ ExpressionOpt: Expression ; ExpressionNotIn: AssignmentExpressionNotIn ; ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ; /. case $rule_number: { AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; ./ ExpressionNotInOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ ExpressionNotInOpt: ExpressionNotIn ; Statement: Block ; Statement: VariableStatement ; Statement: EmptyStatement ; Statement: ExpressionStatement ; Statement: IfStatement ; Statement: IterationStatement ; Statement: ContinueStatement ; Statement: BreakStatement ; Statement: ReturnStatement ; Statement: WithStatement ; Statement: LabelledStatement ; Statement: SwitchStatement ; Statement: ThrowStatement ; Statement: TryStatement ; Statement: DebuggerStatement ; Block: T_LBRACE StatementListOpt T_RBRACE ; /. case $rule_number: { AST::Block *node = new (pool) AST::Block(sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; ./ StatementList: Statement ; /. case $rule_number: { sym(1).Node = new (pool) AST::StatementList(sym(1).Statement); } break; ./ StatementList: StatementList Statement ; /. case $rule_number: { sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement); } break; ./ StatementListOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ StatementListOpt: StatementList ; /. case $rule_number: { sym(1).Node = sym(1).StatementList->finish (); } break; ./ VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ; /. case $rule_number: { AST::VariableStatement *node = new (pool) AST::VariableStatement( sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); node->declarationKindToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ VariableDeclarationKind: T_CONST ; /. case $rule_number: { sym(1).ival = T_CONST; } break; ./ VariableDeclarationKind: T_VAR ; /. case $rule_number: { sym(1).ival = T_VAR; } break; ./ VariableDeclarationList: VariableDeclaration ; /. case $rule_number: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; ./ VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ; /. case $rule_number: { AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList( sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; ./ VariableDeclarationListNotIn: VariableDeclarationNotIn ; /. case $rule_number: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; ./ VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ; /. case $rule_number: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; ./ VariableDeclaration: JsIdentifier InitialiserOpt ; /. case $rule_number: { AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; ./ VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ; /. case $rule_number: { AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; ./ Initialiser: T_EQ AssignmentExpression ; /. case $rule_number: { // ### TODO: AST for initializer sym(1) = sym(2); } break; ./ InitialiserOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ InitialiserOpt: Initialiser ; InitialiserNotIn: T_EQ AssignmentExpressionNotIn ; /. case $rule_number: { // ### TODO: AST for initializer sym(1) = sym(2); } break; ./ InitialiserNotInOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ InitialiserNotInOpt: InitialiserNotIn ; EmptyStatement: T_SEMICOLON ; /. case $rule_number: { AST::EmptyStatement *node = new (pool) AST::EmptyStatement(); node->semicolonToken = loc(1); sym(1).Node = node; } break; ./ ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon ExpressionStatement: Expression T_SEMICOLON ; /. case $rule_number: { AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; ./ IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ; /. case $rule_number: { AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); node->elseToken = loc(6); sym(1).Node = node; } break; ./ IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ; /. case $rule_number: { AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ; /. case $rule_number: { AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); node->lparenToken = loc(4); node->rparenToken = loc(6); node->semicolonToken = loc(7); sym(1).Node = node; } break; ./ IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ; /. case $rule_number: { AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; /. case $rule_number: { AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->firstSemicolonToken = loc(4); node->secondSemicolonToken = loc(6); node->rparenToken = loc(8); sym(1).Node = node; } break; ./ IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; /. case $rule_number: { AST::LocalForStatement *node = new (pool) AST::LocalForStatement( sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->varToken = loc(3); node->firstSemicolonToken = loc(5); node->secondSemicolonToken = loc(7); node->rparenToken = loc(9); sym(1).Node = node; } break; ./ IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ; /. case $rule_number: { AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->inToken = loc(4); node->rparenToken = loc(6); sym(1).Node = node; } break; ./ IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ; /. case $rule_number: { AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement( sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); node->lparenToken = loc(2); node->varToken = loc(3); node->inToken = loc(5); node->rparenToken = loc(7); sym(1).Node = node; } break; ./ ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon ContinueStatement: T_CONTINUE T_SEMICOLON ; /. case $rule_number: { AST::ContinueStatement *node = new (pool) AST::ContinueStatement(); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; ./ ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ; /. case $rule_number: { AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2)); node->continueToken = loc(1); node->identifierToken = loc(2); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon BreakStatement: T_BREAK T_SEMICOLON ; /. case $rule_number: { AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; ./ BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ; /. case $rule_number: { AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2)); node->breakToken = loc(1); node->identifierToken = loc(2); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ; /. case $rule_number: { AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ; /. case $rule_number: { AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ; /. case $rule_number: { AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ; /. case $rule_number: { AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; ./ CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ; /. case $rule_number: { AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; ./ CaseClauses: CaseClause ; /. case $rule_number: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause); } break; ./ CaseClauses: CaseClauses CaseClause ; /. case $rule_number: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause); } break; ./ CaseClausesOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ CaseClausesOpt: CaseClauses ; /. case $rule_number: { sym(1).Node = sym(1).CaseClauses->finish (); } break; ./ CaseClause: T_CASE Expression T_COLON StatementListOpt ; /. case $rule_number: { AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; ./ DefaultClause: T_DEFAULT T_COLON StatementListOpt ; /. case $rule_number: { AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; ./ LabelledStatement: T_SIGNAL T_COLON Statement ; /.case $rule_number:./ LabelledStatement: T_PROPERTY T_COLON Statement ; /. case $rule_number: { AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; ./ LabelledStatement: T_IDENTIFIER T_COLON Statement ; /. case $rule_number: { AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; ./ ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon ThrowStatement: T_THROW Expression T_SEMICOLON ; /. case $rule_number: { AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ TryStatement: T_TRY Block Catch ; /. case $rule_number: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; ./ TryStatement: T_TRY Block Finally ; /. case $rule_number: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; ./ TryStatement: T_TRY Block Catch Finally ; /. case $rule_number: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; ./ Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ; /. case $rule_number: { AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); node->identifierToken = loc(3); node->rparenToken = loc(4); sym(1).Node = node; } break; ./ Finally: T_FINALLY Block ; /. case $rule_number: { AST::Finally *node = new (pool) AST::Finally(sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; ./ DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon DebuggerStatement: T_DEBUGGER T_SEMICOLON ; /. case $rule_number: { AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement(); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; ./ FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; /. case $rule_number: { AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); node->lparenToken = loc(3); node->rparenToken = loc(5); node->lbraceToken = loc(6); node->rbraceToken = loc(8); sym(1).Node = node; } break; ./ FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; /. case $rule_number: { AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (! stringRef(2).isNull()) node->identifierToken = loc(2); node->lparenToken = loc(3); node->rparenToken = loc(5); node->lbraceToken = loc(6); node->rbraceToken = loc(8); sym(1).Node = node; } break; ./ FormalParameterList: JsIdentifier ; /. case $rule_number: { AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; ./ FormalParameterList: FormalParameterList T_COMMA JsIdentifier ; /. case $rule_number: { AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3)); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; ./ FormalParameterListOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ FormalParameterListOpt: FormalParameterList ; /. case $rule_number: { sym(1).Node = sym(1).FormalParameterList->finish (); } break; ./ FunctionBodyOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ FunctionBodyOpt: FunctionBody ; FunctionBody: SourceElements ; /. case $rule_number: { sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ()); } break; ./ Program: Empty ; Program: SourceElements ; /. case $rule_number: { sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ()); } break; ./ SourceElements: SourceElement ; /. case $rule_number: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement); } break; ./ SourceElements: SourceElements SourceElement ; /. case $rule_number: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement); } break; ./ SourceElement: Statement ; /. case $rule_number: { sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement); } break; ./ SourceElement: FunctionDeclaration ; /. case $rule_number: { sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration); } break; ./ IdentifierOpt: ; /. case $rule_number: { stringRef(1) = QStringRef(); } break; ./ IdentifierOpt: JsIdentifier ; PropertyNameAndValueListOpt: ; /. case $rule_number: { sym(1).Node = 0; } break; ./ PropertyNameAndValueListOpt: PropertyNameAndValueList ; /. } // switch action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); } // if } while (action != 0); if (first_token == last_token) { const int errorState = state_stack[tos]; // automatic insertion of `;' if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) { SavedToken &tk = token_buffer[0]; tk.token = yytoken; tk.dval = yylval; tk.spell = yytokenspell; tk.loc = yylloc; yylloc = yyprevlloc; yylloc.offset += yylloc.length; yylloc.startColumn += yylloc.length; yylloc.length = 0; //const QString msg = qApp->translate("QmlParser", "Missing `;'"); //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); first_token = &token_buffer[0]; last_token = &token_buffer[1]; yytoken = T_SEMICOLON; yylval = 0; action = errorState; goto _Lcheck_token; } hadErrors = true; token_buffer[0].token = yytoken; token_buffer[0].dval = yylval; token_buffer[0].spell = yytokenspell; token_buffer[0].loc = yylloc; token_buffer[1].token = yytoken = lexer->lex(); token_buffer[1].dval = yylval = lexer->tokenValue(); token_buffer[1].spell = yytokenspell = lexer->tokenSpell(); token_buffer[1].loc = yylloc = location(lexer); if (t_action(errorState, yytoken)) { QString msg; int token = token_buffer[0].token; if (token < 0 || token >= TERMINAL_COUNT) msg = qApp->translate("QmlParser", "Syntax error"); else msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); action = errorState; goto _Lcheck_token; } static int tokens[] = { T_PLUS, T_EQ, T_COMMA, T_COLON, T_SEMICOLON, T_RPAREN, T_RBRACKET, T_RBRACE, T_NUMERIC_LITERAL, T_IDENTIFIER, T_LPAREN, T_LBRACKET, T_LBRACE, EOF_SYMBOL }; for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) { int a = t_action(errorState, *tk); if (a > 0 && t_action(a, yytoken)) { const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); yytoken = *tk; yylval = 0; yylloc = token_buffer[0].loc; yylloc.length = 0; first_token = &token_buffer[0]; last_token = &token_buffer[2]; action = errorState; goto _Lcheck_token; } } for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION || tk == T_FEED_JS_SOURCE_ELEMENT) continue; int a = t_action(errorState, tk); if (a > 0 && t_action(a, yytoken)) { const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); yytoken = tk; yylval = 0; yylloc = token_buffer[0].loc; yylloc.length = 0; action = errorState; goto _Lcheck_token; } } const QString msg = qApp->translate("QmlParser", "Syntax error"); diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); } return false; } QT_QML_END_NAMESPACE ./ /: #endif // QMLJSPARSER_P_H :/ qbs-src-2.6.1/src/lib/corelib/parser/qmljslexer.cpp0000644000175100001660000010073614776170045021621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmljslexer_p.h" #include "qmljsengine_p.h" #include "qmljsmemorypool_p.h" #include #include #include QT_BEGIN_NAMESPACE #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) Q_CORE_EXPORT double qstrntod(const char *s00, int len, char const **se, bool *ok); #else Q_CORE_EXPORT double qstrntod(const char *s00, qsizetype len, char const **se, bool *ok); #endif QT_END_NAMESPACE namespace QbsQmlJS { static int regExpFlagFromChar(const QChar &ch) { switch (ch.unicode()) { case 'g': return Lexer::RegExp_Global; case 'i': return Lexer::RegExp_IgnoreCase; case 'm': return Lexer::RegExp_Multiline; } return 0; } static unsigned char convertHex(ushort c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); return (c - 'A' + 10); } static QChar convertHex(QChar c1, QChar c2) { return QChar{(convertHex(c1.unicode()) << 4) + convertHex(c2.unicode())}; } static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4) { return QChar{uchar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode())), uchar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()))}; } Lexer::Lexer(Engine *engine) : _engine(engine) , _codePtr(nullptr) , _lastLinePtr(nullptr) , _tokenLinePtr(nullptr) , _tokenStartPtr(nullptr) , _char(QLatin1Char('\n')) , _errorCode(NoError) , _currentLineNumber(0) , _tokenValue(0) , _parenthesesState(IgnoreParentheses) , _parenthesesCount(0) , _stackToken(-1) , _patternFlags(0) , _tokenKind(0) , _tokenLength(0) , _tokenLine(0) , _validTokenText(false) , _prohibitAutomaticSemicolon(false) , _restrictedKeyword(false) , _terminator(false) , _followsClosingBrace(false) , _delimited(true) , _qmlMode(true) { if (engine) engine->setLexer(this); } bool Lexer::qmlMode() const { return _qmlMode; } QString Lexer::code() const { return _code; } void Lexer::setCode(const QString &code, int lineno, bool qmlMode) { if (_engine) _engine->setCode(code); _qmlMode = qmlMode; _code = code; _tokenText.clear(); _tokenText.reserve(1024); _errorMessage.clear(); _tokenSpell = QStringRef(); _codePtr = code.unicode(); _lastLinePtr = _codePtr; _tokenLinePtr = _codePtr; _tokenStartPtr = _codePtr; _char = QLatin1Char('\n'); _errorCode = NoError; _currentLineNumber = lineno; _tokenValue = 0; // parentheses state _parenthesesState = IgnoreParentheses; _parenthesesCount = 0; _stackToken = -1; _patternFlags = 0; _tokenLength = 0; _tokenLine = lineno; _validTokenText = false; _prohibitAutomaticSemicolon = false; _restrictedKeyword = false; _terminator = false; _followsClosingBrace = false; _delimited = true; } void Lexer::scanChar() { _char = *_codePtr++; if (_char == QLatin1Char('\n')) { _lastLinePtr = _codePtr; // points to the first character after the newline ++_currentLineNumber; } } int Lexer::lex() { const int previousTokenKind = _tokenKind; _tokenSpell = QStringRef(); _tokenKind = scanToken(); _tokenLength = int(_codePtr - _tokenStartPtr - 1); _delimited = false; _restrictedKeyword = false; _followsClosingBrace = (previousTokenKind == T_RBRACE); // update the flags switch (_tokenKind) { case T_LBRACE: case T_SEMICOLON: case T_COLON: _delimited = true; break; case T_IF: case T_FOR: case T_WHILE: case T_WITH: _parenthesesState = CountParentheses; _parenthesesCount = 0; break; case T_DO: _parenthesesState = BalancedParentheses; break; case T_CONTINUE: case T_BREAK: case T_RETURN: case T_THROW: _restrictedKeyword = true; break; } // switch // update the parentheses state switch (_parenthesesState) { case IgnoreParentheses: break; case CountParentheses: if (_tokenKind == T_RPAREN) { --_parenthesesCount; if (_parenthesesCount == 0) _parenthesesState = BalancedParentheses; } else if (_tokenKind == T_LPAREN) { ++_parenthesesCount; } break; case BalancedParentheses: _parenthesesState = IgnoreParentheses; break; } // switch return _tokenKind; } bool Lexer::isUnicodeEscapeSequence(const QChar *chars) { return isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3]); } QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok) { if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) { scanChar(); // skip u const QChar c1 = _char; scanChar(); const QChar c2 = _char; scanChar(); const QChar c3 = _char; scanChar(); const QChar c4 = _char; scanChar(); if (ok) *ok = true; return convertUnicode(c1, c2, c3, c4); } *ok = false; return {}; } int Lexer::scanToken() { if (_stackToken != -1) { int tk = _stackToken; _stackToken = -1; return tk; } _terminator = false; again: _validTokenText = false; _tokenLinePtr = _lastLinePtr; while (_char.isSpace()) { if (_char == QLatin1Char('\n')) { _tokenLinePtr = _codePtr; if (_restrictedKeyword) { // automatic semicolon insertion _tokenLine = _currentLineNumber; _tokenStartPtr = _codePtr - 1; // ### TODO: insert it before the optional \r sequence. return T_SEMICOLON; } _terminator = true; syncProhibitAutomaticSemicolon(); } scanChar(); } _tokenStartPtr = _codePtr - 1; _tokenLine = _currentLineNumber; if (_char.isNull()) return EOF_SYMBOL; const QChar ch = _char; scanChar(); switch (ch.unicode()) { case '~': return T_TILDE; case '}': return T_RBRACE; case '|': if (_char == QLatin1Char('|')) { scanChar(); return T_OR_OR; } else if (_char == QLatin1Char('=')) { scanChar(); return T_OR_EQ; } return T_OR; case '{': return T_LBRACE; case '^': if (_char == QLatin1Char('=')) { scanChar(); return T_XOR_EQ; } return T_XOR; case ']': return T_RBRACKET; case '[': return T_LBRACKET; case '?': return T_QUESTION; case '>': if (_char == QLatin1Char('>')) { scanChar(); if (_char == QLatin1Char('>')) { scanChar(); if (_char == QLatin1Char('=')) { scanChar(); return T_GT_GT_GT_EQ; } return T_GT_GT_GT; } if (_char == QLatin1Char('=')) { scanChar(); return T_GT_GT_EQ; } return T_GT_GT; } else if (_char == QLatin1Char('=')) { scanChar(); return T_GE; } return T_GT; case '=': if (_char == QLatin1Char('=')) { scanChar(); if (_char == QLatin1Char('=')) { scanChar(); return T_EQ_EQ_EQ; } return T_EQ_EQ; } return T_EQ; case '<': if (_char == QLatin1Char('=')) { scanChar(); return T_LE; } else if (_char == QLatin1Char('<')) { scanChar(); if (_char == QLatin1Char('=')) { scanChar(); return T_LT_LT_EQ; } return T_LT_LT; } return T_LT; case ';': return T_SEMICOLON; case ':': return T_COLON; case '/': if (_char == QLatin1Char('*')) { scanChar(); while (!_char.isNull()) { if (_char == QLatin1Char('*')) { scanChar(); if (_char == QLatin1Char('/')) { scanChar(); if (_engine) { _engine->addComment(tokenOffset() + 2, int(_codePtr - _tokenStartPtr - 1 - 4), tokenStartLine(), tokenStartColumn() + 2); } goto again; } } else { scanChar(); } } } else if (_char == QLatin1Char('/')) { while (!_char.isNull() && _char != QLatin1Char('\n')) { scanChar(); } if (_engine) { _engine->addComment(tokenOffset() + 2, int(_codePtr - _tokenStartPtr - 1 - 2), tokenStartLine(), tokenStartColumn() + 2); } goto again; } if (_char == QLatin1Char('=')) { scanChar(); return T_DIVIDE_EQ; } return T_DIVIDE_; case '.': if (_char.isDigit()) { QVarLengthArray chars; chars.append(ch.unicode()); // append the `.' while (_char.isDigit()) { chars.append(_char.unicode()); scanChar(); } if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && _codePtr[1].isDigit())) { chars.append(_char.unicode()); scanChar(); // consume `e' if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { chars.append(_char.unicode()); scanChar(); // consume the sign } while (_char.isDigit()) { chars.append(_char.unicode()); scanChar(); } } } const char *begin = chars.constData(); const char *end = nullptr; bool ok = false; _tokenValue = qstrntod(begin, chars.size(), &end, &ok); if (end - begin != chars.size()) { _errorCode = IllegalExponentIndicator; _errorMessage = QCoreApplication::translate("QmlParser", "Illegal syntax for exponential number"); return T_ERROR; } return T_NUMERIC_LITERAL; } return T_DOT; case '-': if (_char == QLatin1Char('=')) { scanChar(); return T_MINUS_EQ; } else if (_char == QLatin1Char('-')) { scanChar(); if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) { _stackToken = T_MINUS_MINUS; return T_SEMICOLON; } return T_MINUS_MINUS; } return T_MINUS; case ',': return T_COMMA; case '+': if (_char == QLatin1Char('=')) { scanChar(); return T_PLUS_EQ; } else if (_char == QLatin1Char('+')) { scanChar(); if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) { _stackToken = T_PLUS_PLUS; return T_SEMICOLON; } return T_PLUS_PLUS; } return T_PLUS; case '*': if (_char == QLatin1Char('=')) { scanChar(); return T_STAR_EQ; } return T_STAR; case ')': return T_RPAREN; case '(': return T_LPAREN; case '&': if (_char == QLatin1Char('=')) { scanChar(); return T_AND_EQ; } else if (_char == QLatin1Char('&')) { scanChar(); return T_AND_AND; } return T_AND; case '%': if (_char == QLatin1Char('=')) { scanChar(); return T_REMAINDER_EQ; } return T_REMAINDER; case '!': if (_char == QLatin1Char('=')) { scanChar(); if (_char == QLatin1Char('=')) { scanChar(); return T_NOT_EQ_EQ; } return T_NOT_EQ; } return T_NOT; case '\'': case '"': { const QChar quote = ch; bool multilineStringLiteral = false; const QChar *startCode = _codePtr; if (_engine) { while (!_char.isNull()) { if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) { break; } if (_char == quote) { _tokenSpell = _engine->midRef( int(startCode - _code.unicode() - 1), int(_codePtr - startCode)); scanChar(); return T_STRING_LITERAL; } scanChar(); } } _validTokenText = true; _tokenText.resize(0); startCode--; while (startCode != _codePtr - 1) _tokenText += *startCode++; while (! _char.isNull()) { if (_char == QLatin1Char('\n')) { multilineStringLiteral = true; _tokenText += _char; scanChar(); } else if (_char == quote) { scanChar(); if (_engine) _tokenSpell = _engine->newStringRef(_tokenText); return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL; } else if (_char == QLatin1Char('\\')) { scanChar(); QChar u; bool ok = false; switch (_char.unicode()) { // unicode escape sequence case 'u': u = decodeUnicodeEscapeCharacter(&ok); if (! ok) u = _char; break; // hex escape sequence case 'x': case 'X': if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) { scanChar(); const QChar c1 = _char; scanChar(); const QChar c2 = _char; scanChar(); u = convertHex(c1, c2); } else { u = _char; } break; // single character escape sequence case '\\': u = QLatin1Char('\\'); scanChar(); break; case '\'': u = QLatin1Char('\''); scanChar(); break; case '\"': u = QLatin1Char('\"'); scanChar(); break; case 'b': u = QLatin1Char('\b'); scanChar(); break; case 'f': u = QLatin1Char('\f'); scanChar(); break; case 'n': u = QLatin1Char('\n'); scanChar(); break; case 'r': u = QLatin1Char('\r'); scanChar(); break; case 't': u = QLatin1Char('\t'); scanChar(); break; case 'v': u = QLatin1Char('\v'); scanChar(); break; case '0': if (! _codePtr[1].isDigit()) { scanChar(); u = QLatin1Char('\0'); } else { // ### parse deprecated octal escape sequence ? u = _char; } break; case '\r': while (_char == QLatin1Char('\r')) scanChar(); if (_char == QLatin1Char('\n')) { u = _char; scanChar(); } else { u = QLatin1Char('\n'); } break; case '\n': u = _char; scanChar(); break; default: // non escape character u = _char; scanChar(); } _tokenText += u; } else { _tokenText += _char; scanChar(); } } _errorCode = UnclosedStringLiteral; _errorMessage = QCoreApplication::translate("QmlParser", "Unclosed string at end of line"); return T_ERROR; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return scanNumber(ch); default: if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) { bool identifierWithEscapeChars = false; if (ch == QLatin1Char('\\')) { identifierWithEscapeChars = true; _tokenText.resize(0); bool ok = false; _tokenText += decodeUnicodeEscapeCharacter(&ok); _validTokenText = true; if (! ok) { _errorCode = IllegalUnicodeEscapeSequence; _errorMessage = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence"); return T_ERROR; } } while (true) { if (_char.isLetterOrNumber() || _char == QLatin1Char('$') || _char == QLatin1Char('_')) { if (identifierWithEscapeChars) _tokenText += _char; scanChar(); } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) { if (! identifierWithEscapeChars) { identifierWithEscapeChars = true; _tokenText.resize(0); _tokenText.insert(0, _tokenStartPtr, int(_codePtr - _tokenStartPtr - 1)); _validTokenText = true; } scanChar(); // skip '\\' bool ok = false; _tokenText += decodeUnicodeEscapeCharacter(&ok); if (! ok) { _errorCode = IllegalUnicodeEscapeSequence; _errorMessage = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence"); return T_ERROR; } } else { _tokenLength = int(_codePtr - _tokenStartPtr - 1); int kind = T_IDENTIFIER; if (! identifierWithEscapeChars) kind = classify(_tokenStartPtr, _tokenLength, _qmlMode); if (_engine) { if (kind == T_IDENTIFIER && identifierWithEscapeChars) { _tokenSpell = _engine->newStringRef(_tokenText); } else { _tokenSpell = _engine->midRef( int(_tokenStartPtr - _code.unicode()), _tokenLength); } } return kind; } } } break; } return T_ERROR; } int Lexer::scanNumber(QChar ch) { if (ch != QLatin1Char('0')) { double integer = ch.unicode() - '0'; QChar n = _char; const QChar *code = _codePtr; while (n.isDigit()) { integer = integer * 10 + (n.unicode() - '0'); n = *code++; } if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) { if (code != _codePtr) { _codePtr = code - 1; scanChar(); } _tokenValue = integer; return T_NUMERIC_LITERAL; } } QVarLengthArray chars; chars.append(ch.unicode()); if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) { // parse hex integer literal chars.append(_char.unicode()); scanChar(); // consume `x' while (isHexDigit(_char)) { chars.append(_char.unicode()); scanChar(); } _tokenValue = integerFromString(chars.constData(), chars.size(), 16); return T_NUMERIC_LITERAL; } // decimal integer literal while (_char.isDigit()) { chars.append(_char.unicode()); scanChar(); // consume the digit } if (_char == QLatin1Char('.')) { chars.append(_char.unicode()); scanChar(); // consume `.' while (_char.isDigit()) { chars.append(_char.unicode()); scanChar(); } if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && _codePtr[1].isDigit())) { chars.append(_char.unicode()); scanChar(); // consume `e' if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { chars.append(_char.unicode()); scanChar(); // consume the sign } while (_char.isDigit()) { chars.append(_char.unicode()); scanChar(); } } } } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && _codePtr[1].isDigit())) { chars.append(_char.unicode()); scanChar(); // consume `e' if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { chars.append(_char.unicode()); scanChar(); // consume the sign } while (_char.isDigit()) { chars.append(_char.unicode()); scanChar(); } } } if (chars.size() == 1) { // if we ended up with a single digit, then it was a '0' _tokenValue = 0; return T_NUMERIC_LITERAL; } const char *begin = chars.constData(); const char *end = nullptr; bool ok = false; _tokenValue = qstrntod(begin, chars.size(), &end, &ok); if (end - begin != chars.size()) { _errorCode = IllegalExponentIndicator; _errorMessage = QCoreApplication::translate("QmlParser", "Illegal syntax for exponential number"); return T_ERROR; } return T_NUMERIC_LITERAL; } bool Lexer::scanRegExp(RegExpBodyPrefix prefix) { _tokenText.resize(0); _validTokenText = true; _patternFlags = 0; if (prefix == EqualPrefix) _tokenText += QLatin1Char('='); while (true) { switch (_char.unicode()) { case 0: // eof case '\n': case '\r': // line terminator _errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression literal"); return false; case '/': scanChar(); // scan the flags _patternFlags = 0; while (isIdentLetter(_char)) { int flag = regExpFlagFromChar(_char); if (flag == 0) { _errorMessage = QCoreApplication::translate("QmlParser", "Invalid regular expression flag '%0'") .arg(QChar(_char)); return false; } _patternFlags |= flag; scanChar(); } _tokenLength = int(_codePtr - _tokenStartPtr - 1); return true; case '\\': // regular expression backslash sequence _tokenText += _char; scanChar(); if (_char.isNull() || isLineTerminator()) { _errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence"); return false; } _tokenText += _char; scanChar(); break; case '[': // regular expression class _tokenText += _char; scanChar(); while (! _char.isNull() && ! isLineTerminator()) { if (_char == QLatin1Char(']')) break; if (_char == QLatin1Char('\\')) { // regular expression backslash sequence _tokenText += _char; scanChar(); if (_char.isNull() || isLineTerminator()) { _errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence"); return false; } _tokenText += _char; scanChar(); } else { _tokenText += _char; scanChar(); } } if (_char != QLatin1Char(']')) { _errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression class"); return false; } _tokenText += _char; scanChar(); // skip ] break; default: _tokenText += _char; scanChar(); } // switch } // while return false; } bool Lexer::isLineTerminator() const { return (_char == QLatin1Char('\n') || _char == QLatin1Char('\r')); } bool Lexer::isIdentLetter(QChar ch) { // ASCII-biased, since all reserved words are ASCII, aand hence the // bulk of content to be parsed. if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z')) || ch == QLatin1Char('$') || ch == QLatin1Char('_')) return true; if (ch.unicode() < 128) return false; return ch.isLetterOrNumber(); } bool Lexer::isDecimalDigit(ushort c) { return (c >= '0' && c <= '9'); } bool Lexer::isHexDigit(QChar c) { return ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) || (c >= QLatin1Char('a') && c <= QLatin1Char('f')) || (c >= QLatin1Char('A') && c <= QLatin1Char('F'))); } bool Lexer::isOctalDigit(ushort c) { return (c >= '0' && c <= '7'); } int Lexer::tokenEndLine() const { return _currentLineNumber; } int Lexer::tokenEndColumn() const { return int(_codePtr - _lastLinePtr); } QString Lexer::tokenText() const { if (_validTokenText) return _tokenText; if (_tokenKind == T_STRING_LITERAL) return QString(_tokenStartPtr + 1, _tokenLength - 2); return QString(_tokenStartPtr, _tokenLength); } Lexer::Error Lexer::errorCode() const { return _errorCode; } QString Lexer::errorMessage() const { return _errorMessage; } void Lexer::syncProhibitAutomaticSemicolon() { if (_parenthesesState == BalancedParentheses) { // we have seen something like "if (foo)", which means we should // never insert an automatic semicolon at this point, since it would // then be expanded into an empty statement (ECMA-262 7.9.1) _prohibitAutomaticSemicolon = true; _parenthesesState = IgnoreParentheses; } else { _prohibitAutomaticSemicolon = false; } } bool Lexer::prevTerminator() const { return _terminator; } bool Lexer::followsClosingBrace() const { return _followsClosingBrace; } bool Lexer::canInsertAutomaticSemicolon(int token) const { return token == T_RBRACE || token == EOF_SYMBOL || _terminator || _followsClosingBrace; } bool Lexer::scanDirectives(Directives *directives) { if (_qmlMode) { // the directives are a Javascript-only extension. return false; } lex(); // fetch the first token if (_tokenKind != T_DOT) return true; do { lex(); // skip T_DOT const int lineNumber = tokenStartLine(); if (_tokenKind != T_IDENTIFIER && _tokenKind != T_RESERVED_WORD) return false; // expected a valid QML/JS directive const QString directiveName = tokenText(); if (! (directiveName == QLatin1String("pragma") || directiveName == QLatin1String("import"))) return false; // not a valid directive name // it must be a pragma or an import directive. if (directiveName == QLatin1String("pragma")) { // .pragma library if (lex() != T_IDENTIFIER || tokenText() != QLatin1String("library")) return false; // expected `library // we found a .pragma library directive directives->pragmaLibrary(); } else { Q_ASSERT(directiveName == QLatin1String("import")); lex(); // skip .import QString pathOrUri; QString version; bool fileImport = false; // file or uri import if (_tokenKind == T_STRING_LITERAL) { // .import T_STRING_LITERAL as T_IDENTIFIER fileImport = true; pathOrUri = tokenText(); } else if (_tokenKind == T_IDENTIFIER) { // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER pathOrUri = tokenText(); lex(); // skip the first T_IDENTIFIER for (; _tokenKind == T_DOT; lex()) { if (lex() != T_IDENTIFIER) return false; pathOrUri += QLatin1Char('.'); pathOrUri += tokenText(); } if (_tokenKind != T_NUMERIC_LITERAL) return false; // expected the module version number version = tokenText(); } // // recognize the mandatory `as' followed by the module name // if (lex() != T_RESERVED_WORD || tokenText() != QLatin1String("as")) return false; // expected `as' if (lex() != T_IDENTIFIER) return false; // expected module name const QString module = tokenText(); if (fileImport) directives->importFile(pathOrUri, module); else directives->importModule(pathOrUri, version, module); } if (tokenStartLine() != lineNumber) return false; // the directives cannot span over multiple lines // fetch the first token after the .pragma/.import directive lex(); } while (_tokenKind == T_DOT); return true; } } // namespace QbsQmlJS #include "qmljskeywords_p.h" qbs-src-2.6.1/src/lib/corelib/parser/qmljskeywords_p.h0000644000175100001660000005357114776170045022341 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSKEYWORDS_P_H #define QMLJSKEYWORDS_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // namespace QbsQmlJS { static inline int classify2(const QChar *s, bool qmlMode) { if (s[0].unicode() == 'a') { if (s[1].unicode() == 's') { return qmlMode ? Lexer::T_AS : Lexer::T_RESERVED_WORD; } } else if (s[0].unicode() == 'd') { if (s[1].unicode() == 'o') { return Lexer::T_DO; } } else if (s[0].unicode() == 'i') { if (s[1].unicode() == 'f') { return Lexer::T_IF; } else if (s[1].unicode() == 'n') { return Lexer::T_IN; } } else if (qmlMode && s[0].unicode() == 'o') { if (s[1].unicode() == 'n') { return Lexer::T_ON; } } return Lexer::T_IDENTIFIER; } static inline int classify3(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 'f') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 'r') { return Lexer::T_FOR; } } } else if (s[0].unicode() == 'i') { if (s[1].unicode() == 'n') { if (s[2].unicode() == 't') { return Lexer::T_INT; } } } else if (s[0].unicode() == 'n') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 'w') { return Lexer::T_NEW; } } } else if (s[0].unicode() == 't') { if (s[1].unicode() == 'r') { if (s[2].unicode() == 'y') { return Lexer::T_TRY; } } } else if (s[0].unicode() == 'v') { if (s[1].unicode() == 'a') { if (s[2].unicode() == 'r') { return Lexer::T_VAR; } } } return Lexer::T_IDENTIFIER; } static inline int classify4(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 'b') { if (s[1].unicode() == 'y') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'e') { return Lexer::T_BYTE; } } } } else if (s[0].unicode() == 'c') { if (s[1].unicode() == 'a') { if (s[2].unicode() == 's') { if (s[3].unicode() == 'e') { return Lexer::T_CASE; } } } else if (s[1].unicode() == 'h') { if (s[2].unicode() == 'a') { if (s[3].unicode() == 'r') { return Lexer::T_CHAR; } } } } else if (s[0].unicode() == 'e') { if (s[1].unicode() == 'l') { if (s[2].unicode() == 's') { if (s[3].unicode() == 'e') { return Lexer::T_ELSE; } } } else if (s[1].unicode() == 'n') { if (s[2].unicode() == 'u') { if (s[3].unicode() == 'm') { return Lexer::T_ENUM; } } } } else if (s[0].unicode() == 'g') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'o') { return Lexer::T_GOTO; } } } } else if (s[0].unicode() == 'l') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 'g') { return Lexer::T_LONG; } } } } else if (s[0].unicode() == 'n') { if (s[1].unicode() == 'u') { if (s[2].unicode() == 'l') { if (s[3].unicode() == 'l') { return Lexer::T_NULL; } } } } else if (s[0].unicode() == 't') { if (s[1].unicode() == 'h') { if (s[2].unicode() == 'i') { if (s[3].unicode() == 's') { return Lexer::T_THIS; } } } else if (s[1].unicode() == 'r') { if (s[2].unicode() == 'u') { if (s[3].unicode() == 'e') { return Lexer::T_TRUE; } } } } else if (s[0].unicode() == 'v') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 'i') { if (s[3].unicode() == 'd') { return Lexer::T_VOID; } } } } else if (s[0].unicode() == 'w') { if (s[1].unicode() == 'i') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'h') { return Lexer::T_WITH; } } } } return Lexer::T_IDENTIFIER; } static inline int classify5(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 'b') { if (s[1].unicode() == 'r') { if (s[2].unicode() == 'e') { if (s[3].unicode() == 'a') { if (s[4].unicode() == 'k') { return Lexer::T_BREAK; } } } } } else if (s[0].unicode() == 'c') { if (s[1].unicode() == 'a') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'c') { if (s[4].unicode() == 'h') { return Lexer::T_CATCH; } } } } else if (s[1].unicode() == 'l') { if (s[2].unicode() == 'a') { if (s[3].unicode() == 's') { if (s[4].unicode() == 's') { return Lexer::T_CLASS; } } } } else if (s[1].unicode() == 'o') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 's') { if (s[4].unicode() == 't') { return Lexer::T_CONST; } } } } } else if (s[0].unicode() == 'f') { if (s[1].unicode() == 'a') { if (s[2].unicode() == 'l') { if (s[3].unicode() == 's') { if (s[4].unicode() == 'e') { return Lexer::T_FALSE; } } } } else if (s[1].unicode() == 'i') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 'a') { if (s[4].unicode() == 'l') { return Lexer::T_FINAL; } } } } else if (s[1].unicode() == 'l') { if (s[2].unicode() == 'o') { if (s[3].unicode() == 'a') { if (s[4].unicode() == 't') { return Lexer::T_FLOAT; } } } } } else if (s[0].unicode() == 's') { if (s[1].unicode() == 'h') { if (s[2].unicode() == 'o') { if (s[3].unicode() == 'r') { if (s[4].unicode() == 't') { return Lexer::T_SHORT; } } } } else if (s[1].unicode() == 'u') { if (s[2].unicode() == 'p') { if (s[3].unicode() == 'e') { if (s[4].unicode() == 'r') { return Lexer::T_SUPER; } } } } } else if (s[0].unicode() == 't') { if (s[1].unicode() == 'h') { if (s[2].unicode() == 'r') { if (s[3].unicode() == 'o') { if (s[4].unicode() == 'w') { return Lexer::T_THROW; } } } } } else if (s[0].unicode() == 'w') { if (s[1].unicode() == 'h') { if (s[2].unicode() == 'i') { if (s[3].unicode() == 'l') { if (s[4].unicode() == 'e') { return Lexer::T_WHILE; } } } } } return Lexer::T_IDENTIFIER; } static inline int classify6(const QChar *s, bool qmlMode) { if (s[0].unicode() == 'd') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 'l') { if (s[3].unicode() == 'e') { if (s[4].unicode() == 't') { if (s[5].unicode() == 'e') { return Lexer::T_DELETE; } } } } } else if (s[1].unicode() == 'o') { if (s[2].unicode() == 'u') { if (s[3].unicode() == 'b') { if (s[4].unicode() == 'l') { if (s[5].unicode() == 'e') { return Lexer::T_DOUBLE; } } } } } } else if (s[0].unicode() == 'e') { if (s[1].unicode() == 'x') { if (s[2].unicode() == 'p') { if (s[3].unicode() == 'o') { if (s[4].unicode() == 'r') { if (s[5].unicode() == 't') { return Lexer::T_EXPORT; } } } } } } else if (s[0].unicode() == 'i') { if (s[1].unicode() == 'm') { if (s[2].unicode() == 'p') { if (s[3].unicode() == 'o') { if (s[4].unicode() == 'r') { if (s[5].unicode() == 't') { return qmlMode ? Lexer::T_IMPORT : Lexer::T_RESERVED_WORD; } } } } } } else if (s[0].unicode() == 'n') { if (s[1].unicode() == 'a') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'i') { if (s[4].unicode() == 'v') { if (s[5].unicode() == 'e') { return Lexer::T_NATIVE; } } } } } } else if (s[0].unicode() == 'p') { if (s[1].unicode() == 'u') { if (s[2].unicode() == 'b') { if (s[3].unicode() == 'l') { if (s[4].unicode() == 'i') { if (s[5].unicode() == 'c') { return qmlMode ? Lexer::T_PUBLIC : Lexer::T_RESERVED_WORD; } } } } } } else if (s[0].unicode() == 'r') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'u') { if (s[4].unicode() == 'r') { if (s[5].unicode() == 'n') { return Lexer::T_RETURN; } } } } } } else if (s[0].unicode() == 's') { if (qmlMode && s[1].unicode() == 'i') { if (s[2].unicode() == 'g') { if (s[3].unicode() == 'n') { if (s[4].unicode() == 'a') { if (s[5].unicode() == 'l') { return Lexer::T_SIGNAL; } } } } } else if (s[1].unicode() == 't') { if (s[2].unicode() == 'a') { if (s[3].unicode() == 't') { if (s[4].unicode() == 'i') { if (s[5].unicode() == 'c') { return Lexer::T_STATIC; } } } } } else if (s[1].unicode() == 'w') { if (s[2].unicode() == 'i') { if (s[3].unicode() == 't') { if (s[4].unicode() == 'c') { if (s[5].unicode() == 'h') { return Lexer::T_SWITCH; } } } } } } else if (s[0].unicode() == 't') { if (s[1].unicode() == 'h') { if (s[2].unicode() == 'r') { if (s[3].unicode() == 'o') { if (s[4].unicode() == 'w') { if (s[5].unicode() == 's') { return Lexer::T_THROWS; } } } } } else if (s[1].unicode() == 'y') { if (s[2].unicode() == 'p') { if (s[3].unicode() == 'e') { if (s[4].unicode() == 'o') { if (s[5].unicode() == 'f') { return Lexer::T_TYPEOF; } } } } } } return Lexer::T_IDENTIFIER; } static inline int classify7(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 'b') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 'o') { if (s[3].unicode() == 'l') { if (s[4].unicode() == 'e') { if (s[5].unicode() == 'a') { if (s[6].unicode() == 'n') { return Lexer::T_BOOLEAN; } } } } } } } else if (s[0].unicode() == 'd') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 'f') { if (s[3].unicode() == 'a') { if (s[4].unicode() == 'u') { if (s[5].unicode() == 'l') { if (s[6].unicode() == 't') { return Lexer::T_DEFAULT; } } } } } } } else if (s[0].unicode() == 'e') { if (s[1].unicode() == 'x') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'e') { if (s[4].unicode() == 'n') { if (s[5].unicode() == 'd') { if (s[6].unicode() == 's') { return Lexer::T_EXTENDS; } } } } } } } else if (s[0].unicode() == 'f') { if (s[1].unicode() == 'i') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 'a') { if (s[4].unicode() == 'l') { if (s[5].unicode() == 'l') { if (s[6].unicode() == 'y') { return Lexer::T_FINALLY; } } } } } } } else if (s[0].unicode() == 'p') { if (s[1].unicode() == 'a') { if (s[2].unicode() == 'c') { if (s[3].unicode() == 'k') { if (s[4].unicode() == 'a') { if (s[5].unicode() == 'g') { if (s[6].unicode() == 'e') { return Lexer::T_PACKAGE; } } } } } } else if (s[1].unicode() == 'r') { if (s[2].unicode() == 'i') { if (s[3].unicode() == 'v') { if (s[4].unicode() == 'a') { if (s[5].unicode() == 't') { if (s[6].unicode() == 'e') { return Lexer::T_PRIVATE; } } } } } } } return Lexer::T_IDENTIFIER; } static inline int classify8(const QChar *s, bool qmlMode) { if (s[0].unicode() == 'a') { if (s[1].unicode() == 'b') { if (s[2].unicode() == 's') { if (s[3].unicode() == 't') { if (s[4].unicode() == 'r') { if (s[5].unicode() == 'a') { if (s[6].unicode() == 'c') { if (s[7].unicode() == 't') { return Lexer::T_ABSTRACT; } } } } } } } } else if (s[0].unicode() == 'c') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 't') { if (s[4].unicode() == 'i') { if (s[5].unicode() == 'n') { if (s[6].unicode() == 'u') { if (s[7].unicode() == 'e') { return Lexer::T_CONTINUE; } } } } } } } } else if (s[0].unicode() == 'd') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 'b') { if (s[3].unicode() == 'u') { if (s[4].unicode() == 'g') { if (s[5].unicode() == 'g') { if (s[6].unicode() == 'e') { if (s[7].unicode() == 'r') { return Lexer::T_DEBUGGER; } } } } } } } } else if (s[0].unicode() == 'f') { if (s[1].unicode() == 'u') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 'c') { if (s[4].unicode() == 't') { if (s[5].unicode() == 'i') { if (s[6].unicode() == 'o') { if (s[7].unicode() == 'n') { return Lexer::T_FUNCTION; } } } } } } } } else if (qmlMode && s[0].unicode() == 'p') { if (s[1].unicode() == 'r') { if (s[2].unicode() == 'o') { if (s[3].unicode() == 'p') { if (s[4].unicode() == 'e') { if (s[5].unicode() == 'r') { if (s[6].unicode() == 't') { if (s[7].unicode() == 'y') { return Lexer::T_PROPERTY; } } } } } } } } else if (qmlMode && s[0].unicode() == 'r') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 'a') { if (s[3].unicode() == 'd') { if (s[4].unicode() == 'o') { if (s[5].unicode() == 'n') { if (s[6].unicode() == 'l') { if (s[7].unicode() == 'y') { return Lexer::T_READONLY; } } } } } } } } else if (s[0].unicode() == 'v') { if (s[1].unicode() == 'o') { if (s[2].unicode() == 'l') { if (s[3].unicode() == 'a') { if (s[4].unicode() == 't') { if (s[5].unicode() == 'i') { if (s[6].unicode() == 'l') { if (s[7].unicode() == 'e') { return Lexer::T_VOLATILE; } } } } } } } } return Lexer::T_IDENTIFIER; } static inline int classify9(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 'i') { if (s[1].unicode() == 'n') { if (s[2].unicode() == 't') { if (s[3].unicode() == 'e') { if (s[4].unicode() == 'r') { if (s[5].unicode() == 'f') { if (s[6].unicode() == 'a') { if (s[7].unicode() == 'c') { if (s[8].unicode() == 'e') { return Lexer::T_INTERFACE; } } } } } } } } } else if (s[0].unicode() == 'p') { if (s[1].unicode() == 'r') { if (s[2].unicode() == 'o') { if (s[3].unicode() == 't') { if (s[4].unicode() == 'e') { if (s[5].unicode() == 'c') { if (s[6].unicode() == 't') { if (s[7].unicode() == 'e') { if (s[8].unicode() == 'd') { return Lexer::T_PROTECTED; } } } } } } } } } else if (s[0].unicode() == 't') { if (s[1].unicode() == 'r') { if (s[2].unicode() == 'a') { if (s[3].unicode() == 'n') { if (s[4].unicode() == 's') { if (s[5].unicode() == 'i') { if (s[6].unicode() == 'e') { if (s[7].unicode() == 'n') { if (s[8].unicode() == 't') { return Lexer::T_TRANSIENT; } } } } } } } } } return Lexer::T_IDENTIFIER; } static inline int classify10(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 'i') { if (s[1].unicode() == 'm') { if (s[2].unicode() == 'p') { if (s[3].unicode() == 'l') { if (s[4].unicode() == 'e') { if (s[5].unicode() == 'm') { if (s[6].unicode() == 'e') { if (s[7].unicode() == 'n') { if (s[8].unicode() == 't') { if (s[9].unicode() == 's') { return Lexer::T_IMPLEMENTS; } } } } } } } } } else if (s[1].unicode() == 'n') { if (s[2].unicode() == 's') { if (s[3].unicode() == 't') { if (s[4].unicode() == 'a') { if (s[5].unicode() == 'n') { if (s[6].unicode() == 'c') { if (s[7].unicode() == 'e') { if (s[8].unicode() == 'o') { if (s[9].unicode() == 'f') { return Lexer::T_INSTANCEOF; } } } } } } } } } } return Lexer::T_IDENTIFIER; } static inline int classify12(const QChar *s, bool /*qmlMode*/) { if (s[0].unicode() == 's') { if (s[1].unicode() == 'y') { if (s[2].unicode() == 'n') { if (s[3].unicode() == 'c') { if (s[4].unicode() == 'h') { if (s[5].unicode() == 'r') { if (s[6].unicode() == 'o') { if (s[7].unicode() == 'n') { if (s[8].unicode() == 'i') { if (s[9].unicode() == 'z') { if (s[10].unicode() == 'e') { if (s[11].unicode() == 'd') { return Lexer::T_SYNCHRONIZED; } } } } } } } } } } } } return Lexer::T_IDENTIFIER; } int Lexer::classify(const QChar *s, int n, bool qmlMode) { switch (n) { case 2: return classify2(s, qmlMode); case 3: return classify3(s, qmlMode); case 4: return classify4(s, qmlMode); case 5: return classify5(s, qmlMode); case 6: return classify6(s, qmlMode); case 7: return classify7(s, qmlMode); case 8: return classify8(s, qmlMode); case 9: return classify9(s, qmlMode); case 10: return classify10(s, qmlMode); case 12: return classify12(s, qmlMode); default: return Lexer::T_IDENTIFIER; } // switch } } // namespace QbsQmlJS #endif // QMLJSKEYWORDS_P_H qbs-src-2.6.1/src/lib/corelib/parser/qmljsglobal_p.h0000644000175100001660000000422714776170045021724 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSGLOBAL_P_H #define QMLJSGLOBAL_P_H #include #ifdef QBS_STATIC_LIB #define QML_PARSER_EXPORT #else #ifdef QBS_LIBRARY #define QML_PARSER_EXPORT Q_DECL_EXPORT #else #define QML_PARSER_EXPORT Q_DECL_IMPORT #endif // QBS_LIBRARY #endif // QBS_STATIC_LIB #endif // QMLJSGLOBAL_P_H qbs-src-2.6.1/src/lib/corelib/parser/qmljsengine_p.cpp0000644000175100001660000001100714776170045022256 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmljsengine_p.h" #include "qmljsglobal_p.h" #include #include #include namespace QbsQmlJS { static int toDigit(char c) { if ((c >= '0') && (c <= '9')) return c - '0'; if ((c >= 'a') && (c <= 'z')) return 10 + c - 'a'; if ((c >= 'A') && (c <= 'Z')) return 10 + c - 'A'; return -1; } double integerFromString(const char *buf, int size, int radix) { if (size == 0) return qSNaN(); double sign = 1.0; int i = 0; if (buf[0] == '+') { ++i; } else if (buf[0] == '-') { sign = -1.0; ++i; } if (((size-i) >= 2) && (buf[i] == '0')) { if (((buf[i+1] == 'x') || (buf[i+1] == 'X')) && (radix < 34)) { if ((radix != 0) && (radix != 16)) return 0; radix = 16; i += 2; } else { if (radix == 0) { radix = 8; ++i; } } } else if (radix == 0) { radix = 10; } int j = i; for ( ; i < size; ++i) { int d = toDigit(buf[i]); if ((d == -1) || (d >= radix)) break; } double result; if (j == i) { if (!qstrcmp(buf, "Infinity")) result = qInf(); else result = qSNaN(); } else { result = 0; double multiplier = 1; for (--i ; i >= j; --i, multiplier *= radix) result += toDigit(buf[i]) * multiplier; } result *= sign; return result; } double integerFromString(const QString &str, int radix) { QByteArray ba = str.trimmed().toLatin1(); return integerFromString(ba.constData(), ba.size(), radix); } Engine::Engine() = default; Engine::~Engine() = default; void Engine::setCode(const QString &code) { _code = code; } void Engine::addComment(int pos, int len, int line, int col) { if (len > 0) _comments.append(QbsQmlJS::AST::SourceLocation(pos, len, line, col)); } QList Engine::comments() const { return _comments; } Lexer *Engine::lexer() const { return _lexer; } void Engine::setLexer(Lexer *lexer) { _lexer = lexer; } void Engine::setDirectives(Directives *directives) { _directives = directives; } Directives *Engine::directives() const { return _directives; } MemoryPool *Engine::pool() { return &_pool; } QStringRef Engine::newStringRef(const QString &text) { const int pos = _extraCode.length(); _extraCode += text; return QStringRef(&_extraCode).mid(pos, text.length()); } QStringRef Engine::newStringRef(const QChar *chars, int size) { return newStringRef(QString(chars, size)); } } // end of namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/parser/qmlerror.h0000644000175100001660000000534014776170045020736 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QQMLERROR_H #define QQMLERROR_H #include #include #include QT_BEGIN_NAMESPACE class QDebug; QT_END_NAMESPACE namespace QbsQmlJS { class QmlErrorPrivate; class QmlError { public: QmlError(); QmlError(const QmlError &); QmlError &operator=(const QmlError &); ~QmlError(); bool isValid() const; QUrl url() const; void setUrl(const QUrl &); QString description() const; void setDescription(const QString &); int line() const; void setLine(int); int column() const; void setColumn(int); QString toString() const; private: qbs::Internal::Pimpl d; }; } // namespace QbsQmlJS QT_BEGIN_NAMESPACE QDebug operator<<(QDebug debug, const QbsQmlJS::QmlError &error); Q_DECLARE_TYPEINFO(QbsQmlJS::QmlError, Q_MOVABLE_TYPE); QT_END_NAMESPACE #endif // QQMLERROR_H qbs-src-2.6.1/src/lib/corelib/parser/qmljsast_p.h0000644000175100001660000020116414776170045021252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSAST_P_H #define QMLJSAST_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qmljsastvisitor_p.h" #include "qmljsglobal_p.h" #include "qmljsmemorypool_p.h" #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #endif namespace QbsQmlJS { #define QMLJS_DECLARE_AST_NODE(name) \ enum { K = Kind_##name }; namespace QSOperator // ### rename { enum Op { Add, And, InplaceAnd, Assign, BitAnd, BitOr, BitXor, InplaceSub, Div, InplaceDiv, Equal, Ge, Gt, In, InplaceAdd, InstanceOf, Le, LShift, InplaceLeftShift, Lt, Mod, InplaceMod, Mul, InplaceMul, NotEqual, Or, InplaceOr, RShift, InplaceRightShift, StrictEqual, StrictNotEqual, Sub, URShift, InplaceURightShift, InplaceXor }; } // namespace QSOperator namespace AST { template _T1 cast(_T2 *ast) { if (ast && ast->kind == static_cast<_T1>(nullptr)->K) return static_cast<_T1>(ast); return nullptr; } class QML_PARSER_EXPORT Node: public Managed { public: enum Kind { Kind_Undefined, Kind_ArgumentList, Kind_ArrayLiteral, Kind_ArrayMemberExpression, Kind_BinaryExpression, Kind_Block, Kind_BreakStatement, Kind_CallExpression, Kind_CaseBlock, Kind_CaseClause, Kind_CaseClauses, Kind_Catch, Kind_ConditionalExpression, Kind_ContinueStatement, Kind_DebuggerStatement, Kind_DefaultClause, Kind_DeleteExpression, Kind_DoWhileStatement, Kind_ElementList, Kind_Elision, Kind_EmptyStatement, Kind_Expression, Kind_ExpressionStatement, Kind_FalseLiteral, Kind_FieldMemberExpression, Kind_Finally, Kind_ForEachStatement, Kind_ForStatement, Kind_FormalParameterList, Kind_FunctionBody, Kind_FunctionDeclaration, Kind_FunctionExpression, Kind_FunctionSourceElement, Kind_IdentifierExpression, Kind_IdentifierPropertyName, Kind_IfStatement, Kind_LabelledStatement, Kind_LocalForEachStatement, Kind_LocalForStatement, Kind_NewExpression, Kind_NewMemberExpression, Kind_NotExpression, Kind_NullExpression, Kind_NumericLiteral, Kind_NumericLiteralPropertyName, Kind_ObjectLiteral, Kind_PostDecrementExpression, Kind_PostIncrementExpression, Kind_PreDecrementExpression, Kind_PreIncrementExpression, Kind_Program, Kind_PropertyName, Kind_PropertyNameAndValueList, Kind_RegExpLiteral, Kind_ReturnStatement, Kind_SourceElement, Kind_SourceElements, Kind_StatementList, Kind_StatementSourceElement, Kind_StringLiteral, Kind_StringLiteralPropertyName, Kind_SwitchStatement, Kind_ThisExpression, Kind_ThrowStatement, Kind_TildeExpression, Kind_TrueLiteral, Kind_TryStatement, Kind_TypeOfExpression, Kind_UnaryMinusExpression, Kind_UnaryPlusExpression, Kind_VariableDeclaration, Kind_VariableDeclarationList, Kind_VariableStatement, Kind_VoidExpression, Kind_WhileStatement, Kind_WithStatement, Kind_NestedExpression, Kind_UiArrayBinding, Kind_UiImport, Kind_UiImportList, Kind_UiObjectBinding, Kind_UiObjectDefinition, Kind_UiObjectInitializer, Kind_UiObjectMemberList, Kind_UiArrayMemberList, Kind_UiProgram, Kind_UiParameterList, Kind_UiPublicMember, Kind_UiQualifiedId, Kind_UiScriptBinding, Kind_UiSourceElement }; inline Node() : kind(Kind_Undefined) {} // NOTE: node destructors are never called, // instead we block free the memory // (see the NodePool class) virtual ~Node() = default; virtual ExpressionNode *expressionCast(); virtual BinaryExpression *binaryExpressionCast(); virtual Statement *statementCast(); virtual UiObjectMember *uiObjectMemberCast(); void accept(Visitor *visitor); static void accept(Node *node, Visitor *visitor); inline static void acceptChild(Node *node, Visitor *visitor) { return accept(node, visitor); } // ### remove virtual void accept0(Visitor *visitor) = 0; virtual SourceLocation firstSourceLocation() const = 0; virtual SourceLocation lastSourceLocation() const = 0; // attributes int kind; }; class QML_PARSER_EXPORT ExpressionNode: public Node { public: ExpressionNode() = default; ExpressionNode *expressionCast() override; }; class QML_PARSER_EXPORT Statement: public Node { public: Statement() = default; Statement *statementCast() override; }; class QML_PARSER_EXPORT NestedExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(NestedExpression) NestedExpression(ExpressionNode *expression) : expression(expression) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return lparenToken; } SourceLocation lastSourceLocation() const override { return rparenToken; } // attributes ExpressionNode *expression; SourceLocation lparenToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT ThisExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(ThisExpression) ThisExpression() { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return thisToken; } SourceLocation lastSourceLocation() const override { return thisToken; } // attributes SourceLocation thisToken; }; class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(IdentifierExpression) IdentifierExpression(const QStringRef &n): name (n) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } SourceLocation lastSourceLocation() const override { return identifierToken; } // attributes QStringRef name; SourceLocation identifierToken; }; class QML_PARSER_EXPORT NullExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(NullExpression) NullExpression() { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return nullToken; } SourceLocation lastSourceLocation() const override { return nullToken; } // attributes SourceLocation nullToken; }; class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(TrueLiteral) TrueLiteral() { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return trueToken; } SourceLocation lastSourceLocation() const override { return trueToken; } // attributes SourceLocation trueToken; }; class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(FalseLiteral) FalseLiteral() { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return falseToken; } SourceLocation lastSourceLocation() const override { return falseToken; } // attributes SourceLocation falseToken; }; class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(NumericLiteral) NumericLiteral(double v): value(v) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return literalToken; } SourceLocation lastSourceLocation() const override { return literalToken; } // attributes: double value; SourceLocation literalToken; }; class QML_PARSER_EXPORT StringLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(StringLiteral) StringLiteral(const QStringRef &v): value (v) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return literalToken; } SourceLocation lastSourceLocation() const override { return literalToken; } // attributes: QStringRef value; SourceLocation literalToken; }; class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(RegExpLiteral) RegExpLiteral(const QStringRef &p, int f): pattern (p), flags (f) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return literalToken; } SourceLocation lastSourceLocation() const override { return literalToken; } // attributes: QStringRef pattern; int flags; SourceLocation literalToken; }; class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(ArrayLiteral) ArrayLiteral(Elision *e): elements (nullptr), elision (e) { kind = K; } ArrayLiteral(ElementList *elts): elements (elts), elision (nullptr) { kind = K; } ArrayLiteral(ElementList *elts, Elision *e): elements (elts), elision (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbracketToken; } SourceLocation lastSourceLocation() const override { return rbracketToken; } // attributes ElementList *elements; Elision *elision; SourceLocation lbracketToken; SourceLocation commaToken; SourceLocation rbracketToken; }; class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(ObjectLiteral) ObjectLiteral(): properties (nullptr) { kind = K; } ObjectLiteral(PropertyNameAndValueList *plist): properties (plist) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } SourceLocation lastSourceLocation() const override { return rbraceToken; } // attributes PropertyNameAndValueList *properties; SourceLocation lbraceToken; SourceLocation rbraceToken; }; class QML_PARSER_EXPORT Elision: public Node { public: QMLJS_DECLARE_AST_NODE(Elision) Elision(): next (this) { kind = K; } Elision(Elision *previous) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return commaToken; } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : commaToken; } inline Elision *finish () { Elision *front = next; next = nullptr; return front; } // attributes Elision *next; SourceLocation commaToken; }; class QML_PARSER_EXPORT ElementList: public Node { public: QMLJS_DECLARE_AST_NODE(ElementList) ElementList(Elision *e, ExpressionNode *expr): elision (e), expression (expr), next (this) { kind = K; } ElementList(ElementList *previous, Elision *e, ExpressionNode *expr): elision (e), expression (expr) { kind = K; next = previous->next; previous->next = this; } inline ElementList *finish () { ElementList *front = next; next = nullptr; return front; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { if (elision) return elision->firstSourceLocation(); return expression->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { if (next) return next->lastSourceLocation(); return expression->lastSourceLocation(); } // attributes Elision *elision; ExpressionNode *expression; ElementList *next; SourceLocation commaToken; }; class QML_PARSER_EXPORT PropertyName: public Node { public: QMLJS_DECLARE_AST_NODE(PropertyName) PropertyName() { kind = K; } SourceLocation firstSourceLocation() const override { return propertyNameToken; } SourceLocation lastSourceLocation() const override { return propertyNameToken; } // attributes SourceLocation propertyNameToken; }; class QML_PARSER_EXPORT PropertyNameAndValueList: public Node { public: QMLJS_DECLARE_AST_NODE(PropertyNameAndValueList) PropertyNameAndValueList(PropertyName *n, ExpressionNode *v): name (n), value (v), next (this) { kind = K; } PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v): name (n), value (v) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return name->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { if (next) return next->lastSourceLocation(); return value->lastSourceLocation(); } inline PropertyNameAndValueList *finish () { PropertyNameAndValueList *front = next; next = nullptr; return front; } // attributes PropertyName *name; ExpressionNode *value; PropertyNameAndValueList *next; SourceLocation colonToken; SourceLocation commaToken; }; class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName { public: QMLJS_DECLARE_AST_NODE(IdentifierPropertyName) IdentifierPropertyName(const QStringRef &n): id (n) { kind = K; } void accept0(Visitor *visitor) override; // attributes QStringRef id; }; class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName { public: QMLJS_DECLARE_AST_NODE(StringLiteralPropertyName) StringLiteralPropertyName(const QStringRef &n): id (n) { kind = K; } void accept0(Visitor *visitor) override; // attributes QStringRef id; }; class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName { public: QMLJS_DECLARE_AST_NODE(NumericLiteralPropertyName) NumericLiteralPropertyName(double n): id (n) { kind = K; } void accept0(Visitor *visitor) override; // attributes double id; }; class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(ArrayMemberExpression) ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e): base (b), expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return rbracketToken; } // attributes ExpressionNode *base; ExpressionNode *expression; SourceLocation lbracketToken; SourceLocation rbracketToken; }; class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(FieldMemberExpression) FieldMemberExpression(ExpressionNode *b, const QStringRef &n): base (b), name (n) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return identifierToken; } // attributes ExpressionNode *base; QStringRef name; SourceLocation dotToken; SourceLocation identifierToken; }; class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(NewMemberExpression) NewMemberExpression(ExpressionNode *b, ArgumentList *a): base (b), arguments (a) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return newToken; } SourceLocation lastSourceLocation() const override { return rparenToken; } // attributes ExpressionNode *base; ArgumentList *arguments; SourceLocation newToken; SourceLocation lparenToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT NewExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(NewExpression) NewExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return newToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation newToken; }; class QML_PARSER_EXPORT CallExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(CallExpression) CallExpression(ExpressionNode *b, ArgumentList *a): base (b), arguments (a) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return rparenToken; } // attributes ExpressionNode *base; ArgumentList *arguments; SourceLocation lparenToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT ArgumentList: public Node { public: QMLJS_DECLARE_AST_NODE(ArgumentList) ArgumentList(ExpressionNode *e): expression (e), next (this) { kind = K; } ArgumentList(ArgumentList *previous, ExpressionNode *e): expression (e) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return expression->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { if (next) return next->lastSourceLocation(); return expression->lastSourceLocation(); } inline ArgumentList *finish () { ArgumentList *front = next; next = nullptr; return front; } // attributes ExpressionNode *expression; ArgumentList *next; SourceLocation commaToken; }; class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(PostIncrementExpression) PostIncrementExpression(ExpressionNode *b): base (b) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return incrementToken; } // attributes ExpressionNode *base; SourceLocation incrementToken; }; class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(PostDecrementExpression) PostDecrementExpression(ExpressionNode *b): base (b) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return decrementToken; } // attributes ExpressionNode *base; SourceLocation decrementToken; }; class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(DeleteExpression) DeleteExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return deleteToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation deleteToken; }; class QML_PARSER_EXPORT VoidExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(VoidExpression) VoidExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return voidToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation voidToken; }; class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(TypeOfExpression) TypeOfExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return typeofToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation typeofToken; }; class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(PreIncrementExpression) PreIncrementExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return incrementToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation incrementToken; }; class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(PreDecrementExpression) PreDecrementExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return decrementToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation decrementToken; }; class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(UnaryPlusExpression) UnaryPlusExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return plusToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation plusToken; }; class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(UnaryMinusExpression) UnaryMinusExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return minusToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation minusToken; }; class QML_PARSER_EXPORT TildeExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(TildeExpression) TildeExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return tildeToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation tildeToken; }; class QML_PARSER_EXPORT NotExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(NotExpression) NotExpression(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return notToken; } SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); } // attributes ExpressionNode *expression; SourceLocation notToken; }; class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(BinaryExpression) BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r): left (l), op (o), right (r) { kind = K; } BinaryExpression *binaryExpressionCast() override; void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return left->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return right->lastSourceLocation(); } // attributes ExpressionNode *left; int op; ExpressionNode *right; SourceLocation operatorToken; }; class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(ConditionalExpression) ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f): expression (e), ok (t), ko (f) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return expression->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return ko->lastSourceLocation(); } // attributes ExpressionNode *expression; ExpressionNode *ok; ExpressionNode *ko; SourceLocation questionToken; SourceLocation colonToken; }; class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename { public: QMLJS_DECLARE_AST_NODE(Expression) Expression(ExpressionNode *l, ExpressionNode *r): left (l), right (r) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return left->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return right->lastSourceLocation(); } // attributes ExpressionNode *left; ExpressionNode *right; SourceLocation commaToken; }; class QML_PARSER_EXPORT Block: public Statement { public: QMLJS_DECLARE_AST_NODE(Block) Block(StatementList *slist): statements (slist) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } SourceLocation lastSourceLocation() const override { return rbraceToken; } // attributes StatementList *statements; SourceLocation lbraceToken; SourceLocation rbraceToken; }; class QML_PARSER_EXPORT StatementList: public Node { public: QMLJS_DECLARE_AST_NODE(StatementList) StatementList(Statement *stmt): statement (stmt), next (this) { kind = K; } StatementList(StatementList *previous, Statement *stmt): statement (stmt) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return statement->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : statement->lastSourceLocation(); } inline StatementList *finish () { StatementList *front = next; next = nullptr; return front; } // attributes Statement *statement; StatementList *next; }; class QML_PARSER_EXPORT VariableStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(VariableStatement) VariableStatement(VariableDeclarationList *vlist): declarations (vlist) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return declarationKindToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes VariableDeclarationList *declarations; SourceLocation declarationKindToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT VariableDeclaration: public Node { public: QMLJS_DECLARE_AST_NODE(VariableDeclaration) VariableDeclaration(const QStringRef &n, ExpressionNode *e): name (n), expression (e), readOnly(false) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } SourceLocation lastSourceLocation() const override { return expression ? expression->lastSourceLocation() : identifierToken; } // attributes QStringRef name; ExpressionNode *expression; bool readOnly; SourceLocation identifierToken; }; class QML_PARSER_EXPORT VariableDeclarationList: public Node { public: QMLJS_DECLARE_AST_NODE(VariableDeclarationList) VariableDeclarationList(VariableDeclaration *decl): declaration (decl), next (this) { kind = K; } VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl): declaration (decl) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return declaration->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { if (next) return next->lastSourceLocation(); return declaration->lastSourceLocation(); } inline VariableDeclarationList *finish (bool readOnly) { VariableDeclarationList *front = next; next = nullptr; if (readOnly) { VariableDeclarationList *vdl; for (vdl = front; vdl != nullptr; vdl = vdl->next) vdl->declaration->readOnly = true; } return front; } // attributes VariableDeclaration *declaration; VariableDeclarationList *next; SourceLocation commaToken; }; class QML_PARSER_EXPORT EmptyStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(EmptyStatement) EmptyStatement() { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return semicolonToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes SourceLocation semicolonToken; }; class QML_PARSER_EXPORT ExpressionStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(ExpressionStatement) ExpressionStatement(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return expression->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes ExpressionNode *expression; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT IfStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(IfStatement) IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0): expression (e), ok (t), ko (f) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return ifToken; } SourceLocation lastSourceLocation() const override { if (ko) return ko->lastSourceLocation(); return ok->lastSourceLocation(); } // attributes ExpressionNode *expression; Statement *ok; Statement *ko; SourceLocation ifToken; SourceLocation lparenToken; SourceLocation rparenToken; SourceLocation elseToken; }; class QML_PARSER_EXPORT DoWhileStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(DoWhileStatement) DoWhileStatement(Statement *stmt, ExpressionNode *e): statement (stmt), expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return doToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes Statement *statement; ExpressionNode *expression; SourceLocation doToken; SourceLocation whileToken; SourceLocation lparenToken; SourceLocation rparenToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT WhileStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(WhileStatement) WhileStatement(ExpressionNode *e, Statement *stmt): expression (e), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return whileToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes ExpressionNode *expression; Statement *statement; SourceLocation whileToken; SourceLocation lparenToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT ForStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(ForStatement) ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt): initialiser (i), condition (c), expression (e), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return forToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes ExpressionNode *initialiser; ExpressionNode *condition; ExpressionNode *expression; Statement *statement; SourceLocation forToken; SourceLocation lparenToken; SourceLocation firstSemicolonToken; SourceLocation secondSemicolonToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT LocalForStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(LocalForStatement) LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt): declarations (vlist), condition (c), expression (e), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return forToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes VariableDeclarationList *declarations; ExpressionNode *condition; ExpressionNode *expression; Statement *statement; SourceLocation forToken; SourceLocation lparenToken; SourceLocation varToken; SourceLocation firstSemicolonToken; SourceLocation secondSemicolonToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT ForEachStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(ForEachStatement) ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt): initialiser (i), expression (e), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return forToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes ExpressionNode *initialiser; ExpressionNode *expression; Statement *statement; SourceLocation forToken; SourceLocation lparenToken; SourceLocation inToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT LocalForEachStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(LocalForEachStatement) LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt): declaration (v), expression (e), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return forToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes VariableDeclaration *declaration; ExpressionNode *expression; Statement *statement; SourceLocation forToken; SourceLocation lparenToken; SourceLocation varToken; SourceLocation inToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT ContinueStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(ContinueStatement) ContinueStatement(const QStringRef &l = QStringRef()): label (l) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return continueToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes QStringRef label; SourceLocation continueToken; SourceLocation identifierToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT BreakStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(BreakStatement) BreakStatement(const QStringRef &l): label (l) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return breakToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes QStringRef label; SourceLocation breakToken; SourceLocation identifierToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT ReturnStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(ReturnStatement) ReturnStatement(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return returnToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes ExpressionNode *expression; SourceLocation returnToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT WithStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(WithStatement) WithStatement(ExpressionNode *e, Statement *stmt): expression (e), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return withToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes ExpressionNode *expression; Statement *statement; SourceLocation withToken; SourceLocation lparenToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT CaseBlock: public Node { public: QMLJS_DECLARE_AST_NODE(CaseBlock) CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0): clauses (c), defaultClause (d), moreClauses (r) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } SourceLocation lastSourceLocation() const override { return rbraceToken; } // attributes CaseClauses *clauses; DefaultClause *defaultClause; CaseClauses *moreClauses; SourceLocation lbraceToken; SourceLocation rbraceToken; }; class QML_PARSER_EXPORT SwitchStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(SwitchStatement) SwitchStatement(ExpressionNode *e, CaseBlock *b): expression (e), block (b) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return switchToken; } SourceLocation lastSourceLocation() const override { return block->rbraceToken; } // attributes ExpressionNode *expression; CaseBlock *block; SourceLocation switchToken; SourceLocation lparenToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT CaseClause: public Node { public: QMLJS_DECLARE_AST_NODE(CaseClause) CaseClause(ExpressionNode *e, StatementList *slist): expression (e), statements (slist) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return caseToken; } SourceLocation lastSourceLocation() const override { return statements ? statements->lastSourceLocation() : colonToken; } // attributes ExpressionNode *expression; StatementList *statements; SourceLocation caseToken; SourceLocation colonToken; }; class QML_PARSER_EXPORT CaseClauses: public Node { public: QMLJS_DECLARE_AST_NODE(CaseClauses) CaseClauses(CaseClause *c): clause (c), next (this) { kind = K; } CaseClauses(CaseClauses *previous, CaseClause *c): clause (c) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return clause->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : clause->lastSourceLocation(); } inline CaseClauses *finish () { CaseClauses *front = next; next = nullptr; return front; } //attributes CaseClause *clause; CaseClauses *next; }; class QML_PARSER_EXPORT DefaultClause: public Node { public: QMLJS_DECLARE_AST_NODE(DefaultClause) DefaultClause(StatementList *slist): statements (slist) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return defaultToken; } SourceLocation lastSourceLocation() const override { return statements ? statements->lastSourceLocation() : colonToken; } // attributes StatementList *statements; SourceLocation defaultToken; SourceLocation colonToken; }; class QML_PARSER_EXPORT LabelledStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(LabelledStatement) LabelledStatement(const QStringRef &l, Statement *stmt): label (l), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes QStringRef label; Statement *statement; SourceLocation identifierToken; SourceLocation colonToken; }; class QML_PARSER_EXPORT ThrowStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(ThrowStatement) ThrowStatement(ExpressionNode *e): expression (e) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return throwToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes ExpressionNode *expression; SourceLocation throwToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT Catch: public Node { public: QMLJS_DECLARE_AST_NODE(Catch) Catch(const QStringRef &n, Block *stmt): name (n), statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return catchToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes QStringRef name; Block *statement; SourceLocation catchToken; SourceLocation lparenToken; SourceLocation identifierToken; SourceLocation rparenToken; }; class QML_PARSER_EXPORT Finally: public Node { public: QMLJS_DECLARE_AST_NODE(Finally) Finally(Block *stmt): statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return finallyToken; } SourceLocation lastSourceLocation() const override { return statement ? statement->lastSourceLocation() : finallyToken; } // attributes Block *statement; SourceLocation finallyToken; }; class QML_PARSER_EXPORT TryStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(TryStatement) TryStatement(Statement *stmt, Catch *c, Finally *f): statement (stmt), catchExpression (c), finallyExpression (f) { kind = K; } TryStatement(Statement *stmt, Finally *f): statement (stmt), catchExpression (nullptr), finallyExpression (f) { kind = K; } TryStatement(Statement *stmt, Catch *c): statement (stmt), catchExpression (c), finallyExpression (nullptr) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return tryToken; } SourceLocation lastSourceLocation() const override { if (finallyExpression) return finallyExpression->statement->rbraceToken; else if (catchExpression) return catchExpression->statement->rbraceToken; return statement->lastSourceLocation(); } // attributes Statement *statement; Catch *catchExpression; Finally *finallyExpression; SourceLocation tryToken; }; class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode { public: QMLJS_DECLARE_AST_NODE(FunctionExpression) FunctionExpression(const QStringRef &n, FormalParameterList *f, FunctionBody *b): name (n), formals (f), body (b) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return functionToken; } SourceLocation lastSourceLocation() const override { return rbraceToken; } // attributes QStringRef name; FormalParameterList *formals; FunctionBody *body; SourceLocation functionToken; SourceLocation identifierToken; SourceLocation lparenToken; SourceLocation rparenToken; SourceLocation lbraceToken; SourceLocation rbraceToken; }; class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression { public: QMLJS_DECLARE_AST_NODE(FunctionDeclaration) FunctionDeclaration(const QStringRef &n, FormalParameterList *f, FunctionBody *b): FunctionExpression(n, f, b) { kind = K; } void accept0(Visitor *visitor) override; }; class QML_PARSER_EXPORT FormalParameterList: public Node { public: QMLJS_DECLARE_AST_NODE(FormalParameterList) FormalParameterList(const QStringRef &n): name (n), next (this) { kind = K; } FormalParameterList(FormalParameterList *previous, const QStringRef &n): name (n) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : identifierToken; } inline FormalParameterList *finish () { FormalParameterList *front = next; next = nullptr; return front; } // attributes QStringRef name; FormalParameterList *next; SourceLocation commaToken; SourceLocation identifierToken; }; class QML_PARSER_EXPORT SourceElement: public Node { public: QMLJS_DECLARE_AST_NODE(SourceElement) inline SourceElement() { kind = K; } }; class QML_PARSER_EXPORT SourceElements: public Node { public: QMLJS_DECLARE_AST_NODE(SourceElements) SourceElements(SourceElement *elt): element (elt), next (this) { kind = K; } SourceElements(SourceElements *previous, SourceElement *elt): element (elt) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return element->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : element->lastSourceLocation(); } inline SourceElements *finish () { SourceElements *front = next; next = nullptr; return front; } // attributes SourceElement *element; SourceElements *next; }; class QML_PARSER_EXPORT FunctionBody: public Node { public: QMLJS_DECLARE_AST_NODE(FunctionBody) FunctionBody(SourceElements *elts): elements (elts) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return elements ? elements->firstSourceLocation() : SourceLocation(); } SourceLocation lastSourceLocation() const override { return elements ? elements->lastSourceLocation() : SourceLocation(); } // attributes SourceElements *elements; }; class QML_PARSER_EXPORT Program: public Node { public: QMLJS_DECLARE_AST_NODE(Program) Program(SourceElements *elts): elements (elts) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return elements ? elements->firstSourceLocation() : SourceLocation(); } SourceLocation lastSourceLocation() const override { return elements ? elements->lastSourceLocation() : SourceLocation(); } // attributes SourceElements *elements; }; class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement { public: QMLJS_DECLARE_AST_NODE(FunctionSourceElement) FunctionSourceElement(FunctionDeclaration *f): declaration (f) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return declaration->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return declaration->lastSourceLocation(); } // attributes FunctionDeclaration *declaration; }; class QML_PARSER_EXPORT StatementSourceElement: public SourceElement { public: QMLJS_DECLARE_AST_NODE(StatementSourceElement) StatementSourceElement(Statement *stmt): statement (stmt) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return statement->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } // attributes Statement *statement; }; class QML_PARSER_EXPORT DebuggerStatement: public Statement { public: QMLJS_DECLARE_AST_NODE(DebuggerStatement) DebuggerStatement() { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return debuggerToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes SourceLocation debuggerToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT UiQualifiedId: public Node { public: QMLJS_DECLARE_AST_NODE(UiQualifiedId) UiQualifiedId(const QStringRef &name) : next(this), name(name) { kind = K; } UiQualifiedId(UiQualifiedId *previous, const QStringRef &name) : name(name) { kind = K; next = previous->next; previous->next = this; } UiQualifiedId *finish() { UiQualifiedId *head = next; next = nullptr; return head; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : identifierToken; } // attributes UiQualifiedId *next; QStringRef name; SourceLocation identifierToken; }; class QML_PARSER_EXPORT UiImport: public Node { public: QMLJS_DECLARE_AST_NODE(UiImport) UiImport(const QStringRef &fileName) : fileName(fileName), importUri(nullptr) { kind = K; } UiImport(UiQualifiedId *uri) : importUri(uri) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return importToken; } SourceLocation lastSourceLocation() const override { return semicolonToken; } // attributes QStringRef fileName; UiQualifiedId *importUri; QStringRef importId; SourceLocation importToken; SourceLocation fileNameToken; SourceLocation versionToken; SourceLocation asToken; SourceLocation importIdToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT UiImportList: public Node { public: QMLJS_DECLARE_AST_NODE(UiImportList) UiImportList(UiImport *import) : import(import), next(this) { kind = K; } UiImportList(UiImportList *previous, UiImport *import) : import(import) { kind = K; next = previous->next; previous->next = this; } UiImportList *finish() { UiImportList *head = next; next = nullptr; return head; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return import->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : import->lastSourceLocation(); } // attributes UiImport *import; UiImportList *next; }; class QML_PARSER_EXPORT UiObjectMember: public Node { public: SourceLocation firstSourceLocation() const override = 0; SourceLocation lastSourceLocation() const override = 0; UiObjectMember *uiObjectMemberCast() override; }; class QML_PARSER_EXPORT UiObjectMemberList: public Node { public: QMLJS_DECLARE_AST_NODE(UiObjectMemberList) UiObjectMemberList(UiObjectMember *member) : next(this), member(member) { kind = K; } UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member) : member(member) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return member->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : member->lastSourceLocation(); } UiObjectMemberList *finish() { UiObjectMemberList *head = next; next = nullptr; return head; } // attributes UiObjectMemberList *next; UiObjectMember *member; }; class QML_PARSER_EXPORT UiProgram: public Node { public: QMLJS_DECLARE_AST_NODE(UiProgram) UiProgram(UiImportList *imports, UiObjectMemberList *members) : imports(imports), members(members) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { if (imports) return imports->firstSourceLocation(); else if (members) return members->firstSourceLocation(); return {}; } SourceLocation lastSourceLocation() const override { if (members) return members->lastSourceLocation(); else if (imports) return imports->lastSourceLocation(); return {}; } // attributes UiImportList *imports; UiObjectMemberList *members; }; class QML_PARSER_EXPORT UiArrayMemberList: public Node { public: QMLJS_DECLARE_AST_NODE(UiArrayMemberList) UiArrayMemberList(UiObjectMember *member) : next(this), member(member) { kind = K; } UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member) : member(member) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return member->firstSourceLocation(); } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : member->lastSourceLocation(); } UiArrayMemberList *finish() { UiArrayMemberList *head = next; next = nullptr; return head; } // attributes UiArrayMemberList *next; UiObjectMember *member; SourceLocation commaToken; }; class QML_PARSER_EXPORT UiObjectInitializer: public Node { public: QMLJS_DECLARE_AST_NODE(UiObjectInitializer) UiObjectInitializer(UiObjectMemberList *members) : members(members) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } SourceLocation lastSourceLocation() const override { return rbraceToken; } // attributes SourceLocation lbraceToken; UiObjectMemberList *members; SourceLocation rbraceToken; }; class QML_PARSER_EXPORT UiParameterList: public Node { public: QMLJS_DECLARE_AST_NODE(UiParameterList) UiParameterList(const QStringRef &t, const QStringRef &n): type (t), name (n), next (this) { kind = K; } UiParameterList(UiParameterList *previous, const QStringRef &t, const QStringRef &n): type (t), name (n) { kind = K; next = previous->next; previous->next = this; } void accept0(Visitor *) override {} SourceLocation firstSourceLocation() const override { return propertyTypeToken; } SourceLocation lastSourceLocation() const override { return next ? next->lastSourceLocation() : identifierToken; } inline UiParameterList *finish () { UiParameterList *front = next; next = nullptr; return front; } // attributes QStringRef type; QStringRef name; UiParameterList *next; SourceLocation commaToken; SourceLocation propertyTypeToken; SourceLocation identifierToken; }; class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember { public: QMLJS_DECLARE_AST_NODE(UiPublicMember) UiPublicMember(const QStringRef &memberType, const QStringRef &name) : type(Property), memberType(memberType), name(name), statement(nullptr), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr) { kind = K; } UiPublicMember(const QStringRef &memberType, const QStringRef &name, Statement *statement) : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { if (defaultToken.isValid()) return defaultToken; else if (readonlyToken.isValid()) return readonlyToken; return propertyToken; } SourceLocation lastSourceLocation() const override { if (binding) return binding->lastSourceLocation(); if (statement) return statement->lastSourceLocation(); return semicolonToken; } // attributes enum { Signal, Property } type; QStringRef typeModifier; QStringRef memberType; QStringRef name; Statement *statement; // initialized with a JS expression UiObjectMember *binding; // initialized with a QML object or array. bool isDefaultMember; bool isReadonlyMember; UiParameterList *parameters; SourceLocation defaultToken; SourceLocation readonlyToken; SourceLocation propertyToken; SourceLocation typeModifierToken; SourceLocation typeToken; SourceLocation identifierToken; SourceLocation colonToken; SourceLocation semicolonToken; }; class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember { public: QMLJS_DECLARE_AST_NODE(UiObjectDefinition) UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId, UiObjectInitializer *initializer) : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) { kind = K; } void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override { return qualifiedTypeNameId->identifierToken; } SourceLocation lastSourceLocation() const override { return initializer->rbraceToken; } // attributes UiQualifiedId *qualifiedTypeNameId; UiObjectInitializer *initializer; }; class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember { public: QMLJS_DECLARE_AST_NODE(UiSourceElement) UiSourceElement(Node *sourceElement) : sourceElement(sourceElement) { kind = K; } SourceLocation firstSourceLocation() const override { if (const auto funDecl = cast(sourceElement)) return funDecl->firstSourceLocation(); else if (const auto varStmt = cast(sourceElement)) return varStmt->firstSourceLocation(); return {}; } SourceLocation lastSourceLocation() const override { if (const auto funDecl = cast(sourceElement)) return funDecl->lastSourceLocation(); else if (const auto varStmt = cast(sourceElement)) return varStmt->lastSourceLocation(); return {}; } void accept0(Visitor *visitor) override; // attributes Node *sourceElement; }; class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember { public: QMLJS_DECLARE_AST_NODE(UiObjectBinding) UiObjectBinding(UiQualifiedId *qualifiedId, UiQualifiedId *qualifiedTypeNameId, UiObjectInitializer *initializer) : qualifiedId(qualifiedId), qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer), hasOnToken(false) { kind = K; } SourceLocation firstSourceLocation() const override { if (hasOnToken && qualifiedTypeNameId) return qualifiedTypeNameId->identifierToken; return qualifiedId->identifierToken; } SourceLocation lastSourceLocation() const override { return initializer->rbraceToken; } void accept0(Visitor *visitor) override; // attributes UiQualifiedId *qualifiedId; UiQualifiedId *qualifiedTypeNameId; UiObjectInitializer *initializer; SourceLocation colonToken; bool hasOnToken; }; class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember { public: QMLJS_DECLARE_AST_NODE(UiScriptBinding) UiScriptBinding(UiQualifiedId *qualifiedId, Statement *statement) : qualifiedId(qualifiedId), statement(statement) { kind = K; } SourceLocation firstSourceLocation() const override { return qualifiedId->identifierToken; } SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } void accept0(Visitor *visitor) override; // attributes UiQualifiedId *qualifiedId; Statement *statement; SourceLocation colonToken; }; class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember { public: QMLJS_DECLARE_AST_NODE(UiArrayBinding) UiArrayBinding(UiQualifiedId *qualifiedId, UiArrayMemberList *members) : qualifiedId(qualifiedId), members(members) { kind = K; } SourceLocation firstSourceLocation() const override { return qualifiedId->identifierToken; } SourceLocation lastSourceLocation() const override { return rbracketToken; } void accept0(Visitor *visitor) override; // attributes UiQualifiedId *qualifiedId; UiArrayMemberList *members; SourceLocation colonToken; SourceLocation lbracketToken; SourceLocation rbracketToken; }; } // namespace AST } // namespace QbsQmlJS #endif qbs-src-2.6.1/src/lib/corelib/parser/qmljsmemorypool_p.h0000644000175100001660000001074614776170045022671 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSMEMORYPOOL_P_H #define QMLJSMEMORYPOOL_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qmljsglobal_p.h" #include #include #include #include namespace QbsQmlJS { class QML_PARSER_EXPORT MemoryPool : public QSharedData { MemoryPool(const MemoryPool &other); void operator =(const MemoryPool &other); public: MemoryPool() : _blocks(nullptr), _allocatedBlocks(0), _blockCount(-1), _ptr(nullptr), _end(nullptr) { } ~MemoryPool() { if (_blocks) { for (int i = 0; i < _allocatedBlocks; ++i) { if (char *b = _blocks[i]) free(b); } free(_blocks); } } inline void *allocate(size_t size) { size = (size + 7) & ~7; if (_ptr && (_ptr + size < _end)) { void *addr = _ptr; _ptr += size; return addr; } return allocate_helper(size); } void reset() { _blockCount = -1; _ptr = _end = nullptr; } private: void *allocate_helper(size_t size) { Q_ASSERT(size < BLOCK_SIZE); if (++_blockCount == _allocatedBlocks) { if (! _allocatedBlocks) _allocatedBlocks = DEFAULT_BLOCK_COUNT; else _allocatedBlocks *= 2; _blocks = (char **) realloc(_blocks, sizeof(char *) * _allocatedBlocks); for (int index = _blockCount; index < _allocatedBlocks; ++index) _blocks[index] = nullptr; } char *&block = _blocks[_blockCount]; if (! block) block = (char *) malloc(BLOCK_SIZE); _ptr = block; _end = _ptr + BLOCK_SIZE; void *addr = _ptr; _ptr += size; return addr; } private: char **_blocks; int _allocatedBlocks; int _blockCount; char *_ptr; char *_end; enum { BLOCK_SIZE = 8 * 1024, DEFAULT_BLOCK_COUNT = 8 }; }; class QML_PARSER_EXPORT Managed { Managed(const Managed &other); void operator = (const Managed &other); public: Managed() = default; ~Managed() = default; void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); } void operator delete(void *) {} void operator delete(void *, MemoryPool *) {} }; } // namespace QbsQmlJS #endif qbs-src-2.6.1/src/lib/corelib/parser/qmljsastvisitor.cpp0000644000175100001660000000402114776170045022677 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmljsastvisitor_p.h" namespace QbsQmlJS { namespace AST { Visitor::Visitor() = default; Visitor::~Visitor() = default; } // namespace AST } // namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/parser/qmljslexer_p.h0000644000175100001660000001551214776170045021602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJSLEXER_P_H #define QMLJSLEXER_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qmljsglobal_p.h" #include "qmljsgrammar_p.h" #include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #endif namespace QbsQmlJS { class Engine; class QML_PARSER_EXPORT Directives { public: virtual ~Directives() = default; virtual void pragmaLibrary() { } virtual void importFile(const QString &jsfile, const QString &module) { Q_UNUSED(jsfile); Q_UNUSED(module); } virtual void importModule(const QString &uri, const QString &version, const QString &module) { Q_UNUSED(uri); Q_UNUSED(version); Q_UNUSED(module); } }; class QML_PARSER_EXPORT Lexer : public QmlJSGrammar { public: enum { T_ABSTRACT = T_RESERVED_WORD, T_BOOLEAN = T_RESERVED_WORD, T_BYTE = T_RESERVED_WORD, T_CHAR = T_RESERVED_WORD, T_CLASS = T_RESERVED_WORD, T_DOUBLE = T_RESERVED_WORD, T_ENUM = T_RESERVED_WORD, T_EXPORT = T_RESERVED_WORD, T_EXTENDS = T_RESERVED_WORD, T_FINAL = T_RESERVED_WORD, T_FLOAT = T_RESERVED_WORD, T_GOTO = T_RESERVED_WORD, T_IMPLEMENTS = T_RESERVED_WORD, T_INT = T_RESERVED_WORD, T_INTERFACE = T_RESERVED_WORD, T_LET = T_RESERVED_WORD, T_LONG = T_RESERVED_WORD, T_NATIVE = T_RESERVED_WORD, T_PACKAGE = T_RESERVED_WORD, T_PRIVATE = T_RESERVED_WORD, T_PROTECTED = T_RESERVED_WORD, T_SHORT = T_RESERVED_WORD, T_STATIC = T_RESERVED_WORD, T_SUPER = T_RESERVED_WORD, T_SYNCHRONIZED = T_RESERVED_WORD, T_THROWS = T_RESERVED_WORD, T_TRANSIENT = T_RESERVED_WORD, T_VOLATILE = T_RESERVED_WORD, T_YIELD = T_RESERVED_WORD }; enum Error { NoError, IllegalCharacter, UnclosedStringLiteral, IllegalEscapeSequence, IllegalUnicodeEscapeSequence, UnclosedComment, IllegalExponentIndicator, IllegalIdentifier }; enum RegExpBodyPrefix { NoPrefix, EqualPrefix }; enum RegExpFlag { RegExp_Global = 0x01, RegExp_IgnoreCase = 0x02, RegExp_Multiline = 0x04 }; public: Lexer(Engine *engine); bool qmlMode() const; QString code() const; void setCode(const QString &code, int lineno, bool qmlMode = true); int lex(); bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); bool scanDirectives(Directives *directives); int regExpFlags() const { return _patternFlags; } QString regExpPattern() const { return _tokenText; } int tokenKind() const { return _tokenKind; } int tokenOffset() const { return _tokenStartPtr - _code.unicode(); } int tokenLength() const { return _tokenLength; } int tokenStartLine() const { return _tokenLine; } int tokenStartColumn() const { return _tokenStartPtr - _tokenLinePtr + 1; } int tokenEndLine() const; int tokenEndColumn() const; inline QStringRef tokenSpell() const { return _tokenSpell; } double tokenValue() const { return _tokenValue; } QString tokenText() const; Error errorCode() const; QString errorMessage() const; bool prevTerminator() const; bool followsClosingBrace() const; bool canInsertAutomaticSemicolon(int token) const; enum ParenthesesState { IgnoreParentheses, CountParentheses, BalancedParentheses }; protected: int classify(const QChar *s, int n, bool qmlMode); private: inline void scanChar(); int scanToken(); int scanNumber(QChar ch); bool isLineTerminator() const; static bool isIdentLetter(QChar c); static bool isDecimalDigit(ushort c); static bool isHexDigit(QChar c); static bool isOctalDigit(ushort c); static bool isUnicodeEscapeSequence(const QChar *chars); void syncProhibitAutomaticSemicolon(); QChar decodeUnicodeEscapeCharacter(bool *ok); private: Engine *_engine; QString _code; QString _tokenText; QString _errorMessage; QStringRef _tokenSpell; const QChar *_codePtr; const QChar *_lastLinePtr; const QChar *_tokenLinePtr; const QChar *_tokenStartPtr; QChar _char; Error _errorCode; int _currentLineNumber; double _tokenValue; // parentheses state ParenthesesState _parenthesesState; int _parenthesesCount; int _stackToken; int _patternFlags; int _tokenKind; int _tokenLength; int _tokenLine; bool _validTokenText; bool _prohibitAutomaticSemicolon; bool _restrictedKeyword; bool _terminator; bool _followsClosingBrace; bool _delimited; bool _qmlMode; }; } // namespace QbsQmlJS #endif // LEXER_H qbs-src-2.6.1/src/lib/corelib/parser/qmljsast.cpp0000644000175100001660000004317714776170045021276 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmljsast_p.h" #include "qmljsastvisitor_p.h" namespace QbsQmlJS { namespace AST { void Node::accept(Visitor *visitor) { if (visitor->preVisit(this)) { accept0(visitor); } visitor->postVisit(this); } void Node::accept(Node *node, Visitor *visitor) { if (node) node->accept(visitor); } ExpressionNode *Node::expressionCast() { return nullptr; } BinaryExpression *Node::binaryExpressionCast() { return nullptr; } Statement *Node::statementCast() { return nullptr; } UiObjectMember *Node::uiObjectMemberCast() { return nullptr; } ExpressionNode *ExpressionNode::expressionCast() { return this; } BinaryExpression *BinaryExpression::binaryExpressionCast() { return this; } Statement *Statement::statementCast() { return this; } UiObjectMember *UiObjectMember::uiObjectMemberCast() { return this; } void NestedExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void ThisExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void IdentifierExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void NullExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void TrueLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void FalseLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void StringLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void NumericLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void RegExpLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void ArrayLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(elements, visitor); accept(elision, visitor); } visitor->endVisit(this); } void ObjectLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(properties, visitor); } visitor->endVisit(this); } void ElementList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (ElementList *it = this; it; it = it->next) { accept(it->elision, visitor); accept(it->expression, visitor); } } visitor->endVisit(this); } void Elision::accept0(Visitor *visitor) { if (visitor->visit(this)) { // ### } visitor->endVisit(this); } void PropertyNameAndValueList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (PropertyNameAndValueList *it = this; it; it = it->next) { accept(it->name, visitor); accept(it->value, visitor); } } visitor->endVisit(this); } void IdentifierPropertyName::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void StringLiteralPropertyName::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void NumericLiteralPropertyName::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void ArrayMemberExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); accept(expression, visitor); } visitor->endVisit(this); } void FieldMemberExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); } visitor->endVisit(this); } void NewMemberExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); accept(arguments, visitor); } visitor->endVisit(this); } void NewExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void CallExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); accept(arguments, visitor); } visitor->endVisit(this); } void ArgumentList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (ArgumentList *it = this; it; it = it->next) { accept(it->expression, visitor); } } visitor->endVisit(this); } void PostIncrementExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); } visitor->endVisit(this); } void PostDecrementExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); } visitor->endVisit(this); } void DeleteExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void VoidExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void TypeOfExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void PreIncrementExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void PreDecrementExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void UnaryPlusExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void UnaryMinusExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void TildeExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void NotExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void BinaryExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(left, visitor); accept(right, visitor); } visitor->endVisit(this); } void ConditionalExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); accept(ok, visitor); accept(ko, visitor); } visitor->endVisit(this); } void Expression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(left, visitor); accept(right, visitor); } visitor->endVisit(this); } void Block::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statements, visitor); } visitor->endVisit(this); } void StatementList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (StatementList *it = this; it; it = it->next) { accept(it->statement, visitor); } } visitor->endVisit(this); } void VariableStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(declarations, visitor); } visitor->endVisit(this); } void VariableDeclarationList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (VariableDeclarationList *it = this; it; it = it->next) { accept(it->declaration, visitor); } } visitor->endVisit(this); } void VariableDeclaration::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void EmptyStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void ExpressionStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void IfStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); accept(ok, visitor); accept(ko, visitor); } visitor->endVisit(this); } void DoWhileStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); accept(expression, visitor); } visitor->endVisit(this); } void WhileStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); accept(statement, visitor); } visitor->endVisit(this); } void ForStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(initialiser, visitor); accept(condition, visitor); accept(expression, visitor); accept(statement, visitor); } visitor->endVisit(this); } void LocalForStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(declarations, visitor); accept(condition, visitor); accept(expression, visitor); accept(statement, visitor); } visitor->endVisit(this); } void ForEachStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(initialiser, visitor); accept(expression, visitor); accept(statement, visitor); } visitor->endVisit(this); } void LocalForEachStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(declaration, visitor); accept(expression, visitor); accept(statement, visitor); } visitor->endVisit(this); } void ContinueStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void BreakStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void ReturnStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void WithStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); accept(statement, visitor); } visitor->endVisit(this); } void SwitchStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); accept(block, visitor); } visitor->endVisit(this); } void CaseBlock::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(clauses, visitor); accept(defaultClause, visitor); accept(moreClauses, visitor); } visitor->endVisit(this); } void CaseClauses::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (CaseClauses *it = this; it; it = it->next) { accept(it->clause, visitor); } } visitor->endVisit(this); } void CaseClause::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); accept(statements, visitor); } visitor->endVisit(this); } void DefaultClause::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statements, visitor); } visitor->endVisit(this); } void LabelledStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); } visitor->endVisit(this); } void ThrowStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); } visitor->endVisit(this); } void TryStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); accept(catchExpression, visitor); accept(finallyExpression, visitor); } visitor->endVisit(this); } void Catch::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); } visitor->endVisit(this); } void Finally::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); } visitor->endVisit(this); } void FunctionDeclaration::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(formals, visitor); accept(body, visitor); } visitor->endVisit(this); } void FunctionExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(formals, visitor); accept(body, visitor); } visitor->endVisit(this); } void FormalParameterList::accept0(Visitor *visitor) { if (visitor->visit(this)) { // ### } visitor->endVisit(this); } void FunctionBody::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(elements, visitor); } visitor->endVisit(this); } void Program::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(elements, visitor); } visitor->endVisit(this); } void SourceElements::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (SourceElements *it = this; it; it = it->next) { accept(it->element, visitor); } } visitor->endVisit(this); } void FunctionSourceElement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(declaration, visitor); } visitor->endVisit(this); } void StatementSourceElement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); } visitor->endVisit(this); } void DebuggerStatement::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void UiProgram::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(imports, visitor); accept(members, visitor); } visitor->endVisit(this); } void UiPublicMember::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); accept(binding, visitor); } visitor->endVisit(this); } void UiObjectDefinition::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(qualifiedTypeNameId, visitor); accept(initializer, visitor); } visitor->endVisit(this); } void UiObjectInitializer::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(members, visitor); } visitor->endVisit(this); } void UiObjectBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(qualifiedId, visitor); accept(qualifiedTypeNameId, visitor); accept(initializer, visitor); } visitor->endVisit(this); } void UiScriptBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(qualifiedId, visitor); accept(statement, visitor); } visitor->endVisit(this); } void UiArrayBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(qualifiedId, visitor); accept(members, visitor); } visitor->endVisit(this); } void UiObjectMemberList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (UiObjectMemberList *it = this; it; it = it->next) accept(it->member, visitor); } visitor->endVisit(this); } void UiArrayMemberList::accept0(Visitor *visitor) { if (visitor->visit(this)) { for (UiArrayMemberList *it = this; it; it = it->next) accept(it->member, visitor); } visitor->endVisit(this); } void UiQualifiedId::accept0(Visitor *visitor) { if (visitor->visit(this)) { } visitor->endVisit(this); } void UiImport::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(importUri, visitor); } visitor->endVisit(this); } void UiImportList::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(import, visitor); accept(next, visitor); } visitor->endVisit(this); } void UiSourceElement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(sourceElement, visitor); } visitor->endVisit(this); } } // namespace AST } // namespace QbsQmlJS qbs-src-2.6.1/src/lib/corelib/parser/qmljsparser_p.h0000644000175100001660000001570514776170045021763 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // // // This file is automatically generated from qmljs.g. // Changes will be lost. // #ifndef QMLJSPARSER_P_H #define QMLJSPARSER_P_H #include "qmljsglobal_p.h" #include "qmljsgrammar_p.h" #include "qmljsast_p.h" #include "qmljsengine_p.h" #include #include #include namespace QbsQmlJS { class Engine; class QML_PARSER_EXPORT Parser : protected QmlJSGrammar { public: union Value { int ival; double dval; AST::ArgumentList *ArgumentList; AST::CaseBlock *CaseBlock; AST::CaseClause *CaseClause; AST::CaseClauses *CaseClauses; AST::Catch *Catch; AST::DefaultClause *DefaultClause; AST::ElementList *ElementList; AST::Elision *Elision; AST::ExpressionNode *Expression; AST::Finally *Finally; AST::FormalParameterList *FormalParameterList; AST::FunctionBody *FunctionBody; AST::FunctionDeclaration *FunctionDeclaration; AST::Node *Node; AST::PropertyName *PropertyName; AST::PropertyNameAndValueList *PropertyNameAndValueList; AST::SourceElement *SourceElement; AST::SourceElements *SourceElements; AST::Statement *Statement; AST::StatementList *StatementList; AST::Block *Block; AST::VariableDeclaration *VariableDeclaration; AST::VariableDeclarationList *VariableDeclarationList; AST::UiProgram *UiProgram; AST::UiImportList *UiImportList; AST::UiImport *UiImport; AST::UiParameterList *UiParameterList; AST::UiPublicMember *UiPublicMember; AST::UiObjectDefinition *UiObjectDefinition; AST::UiObjectInitializer *UiObjectInitializer; AST::UiObjectBinding *UiObjectBinding; AST::UiScriptBinding *UiScriptBinding; AST::UiArrayBinding *UiArrayBinding; AST::UiObjectMember *UiObjectMember; AST::UiObjectMemberList *UiObjectMemberList; AST::UiArrayMemberList *UiArrayMemberList; AST::UiQualifiedId *UiQualifiedId; }; public: Parser(Engine *engine); ~Parser(); // parse a UI program bool parse() { return parse(T_FEED_UI_PROGRAM); } bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); } bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } bool parseProgram() { return parse(T_FEED_JS_PROGRAM); } AST::UiProgram *ast() const { return AST::cast(program); } AST::Statement *statement() const { if (! program) return nullptr; return program->statementCast(); } AST::ExpressionNode *expression() const { if (! program) return nullptr; return program->expressionCast(); } AST::UiObjectMember *uiObjectMember() const { if (! program) return nullptr; return program->uiObjectMemberCast(); } AST::Node *rootNode() const { return program; } QList diagnosticMessages() const { return diagnostic_messages; } inline DiagnosticMessage diagnosticMessage() const { foreach (const DiagnosticMessage &d, diagnostic_messages) { if (d.kind != DiagnosticMessage::Warning) return d; } return DiagnosticMessage(); } inline QString errorMessage() const { return diagnosticMessage().message; } inline int errorLineNumber() const { return diagnosticMessage().loc.startLine; } inline int errorColumnNumber() const { return diagnosticMessage().loc.startColumn; } protected: bool parse(int startToken); void reallocateStack(); inline Value &sym(int index) { return sym_stack [tos + index - 1]; } inline QStringRef &stringRef(int index) { return string_stack [tos + index - 1]; } inline AST::SourceLocation &loc(int index) { return location_stack [tos + index - 1]; } AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); protected: Engine *driver; MemoryPool *pool; int tos; int stack_size; Value *sym_stack; int *state_stack; AST::SourceLocation *location_stack; QStringRef *string_stack; AST::Node *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; struct SavedToken { int token = 0; double dval = 0.0; AST::SourceLocation loc; QStringRef spell; }; double yylval = 0.0; QStringRef yytokenspell; AST::SourceLocation yylloc; AST::SourceLocation yyprevlloc; SavedToken token_buffer[TOKEN_BUFFER_SIZE]; SavedToken *first_token; SavedToken *last_token; QList diagnostic_messages; }; } // end of namespace QbsQmlJS #define J_SCRIPT_REGEXPLITERAL_RULE1 79 #define J_SCRIPT_REGEXPLITERAL_RULE2 80 #endif // QMLJSPARSER_P_H qbs-src-2.6.1/src/lib/corelib/qbs.h0000644000175100001660000000524514776170045016370 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_H #define QBS_H #include "api/jobs.h" #include "api/languageinfo.h" #include "api/project.h" #include "api/projectdata.h" #include "api/rulecommand.h" #include "api/runenvironment.h" #include "logging/ilogsink.h" #include "tools/architectures.h" #include "tools/buildoptions.h" #include "tools/cleanoptions.h" #include "tools/codelocation.h" #include "tools/commandechomode.h" #include "tools/error.h" #include "tools/generateoptions.h" #include "tools/installoptions.h" #include "tools/preferences.h" #include "tools/processresult.h" #include "tools/profile.h" #include "tools/projectgeneratormanager.h" #include "tools/settings.h" #include "tools/settingsmodel.h" #include "tools/settingsrepresentation.h" #include "tools/setupprojectparameters.h" #include "tools/toolchains.h" #include "tools/version.h" #endif // QBS_H qbs-src-2.6.1/src/lib/CMakeLists.txt0000644000175100001660000000012014776170045016536 0ustar runnerdockeradd_subdirectory(pkgconfig) add_subdirectory(corelib) add_subdirectory(msbuild) qbs-src-2.6.1/src/lib/libs.qbs0000644000175100001660000000020514776170045015442 0ustar runnerdockerProject { references: [ "corelib/corelib.qbs", "msbuild/msbuild.qbs", "pkgconfig/pkgconfig.qbs", ] } qbs-src-2.6.1/src/lib/pkgconfig/0000755000175100001660000000000014776170045015754 5ustar runnerdockerqbs-src-2.6.1/src/lib/pkgconfig/pkgconfig.cpp0000644000175100001660000002341014776170045020427 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "pkgconfig.h" #include "pcparser.h" #include #include #include namespace qbs { namespace { std::string varToEnvVar(std::string_view pkg, std::string_view var) { auto result = std::string("PKG_CONFIG_"); result += pkg; result += '_'; result += var; for (char &p : result) { int c = std::toupper(p); if (!std::isalnum(c)) c = '_'; p = char(c); } return result; } std::vector split(std::string_view str, const char delim) { std::vector result; size_t prev = 0; size_t pos = 0; do { pos = str.find(delim, prev); if (pos == std::string::npos) pos = str.length(); std::string token(str.substr(prev, pos - prev)); if (!token.empty()) result.push_back(token); prev = pos + 1; } while (pos < str.length() && prev < str.length()); return result; } constexpr inline char listSeparator() noexcept { #if defined(WIN32) return ';'; #else return ':'; #endif } [[noreturn]] void raizeUnknownPackageException(std::string_view package) { std::string message; message += "Can't find package '"; message += package; message += "'"; throw PcException(message); } template C &operator<<(C &container, const C &other) { container.insert(container.end(), other.cbegin(), other.cend()); return container; } } // namespace PkgConfig::PkgConfig() : PkgConfig(Options()) { } PkgConfig::PkgConfig(Options options) : m_options(std::move(options)) { if (m_options.libDirs.empty()) m_options.libDirs = split(PKG_CONFIG_PC_PATH, listSeparator()); if (m_options.topBuildDir.empty()) m_options.topBuildDir = "$(top_builddir)"; // pkg-config sets this for automake =) if (m_options.systemLibraryPaths.empty()) m_options.systemLibraryPaths = split(PKG_CONFIG_SYSTEM_LIBRARY_PATH, ':'); // this is weird on Windows, but that's what pkg-config does if (m_options.sysroot.empty()) m_options.globalVariables["pc_sysrootdir"] = "/"; else m_options.globalVariables["pc_sysrootdir"] = m_options.sysroot; m_options.globalVariables["pc_top_builddir"] = m_options.topBuildDir; m_packages = findPackages(); } const PcPackageVariant &PkgConfig::getPackage(std::string_view baseFileName) const { // heterogeneous comparator so we can search the package using string_view const auto lessThan = [](const PcPackageVariant &package, const std::string_view &name) { return package.visit([name](auto &&value) noexcept { return value.baseFileName < name; }); }; const auto testPackage = [baseFileName](const PcPackageVariant &package) { return package.visit([baseFileName](auto &&value) noexcept { return baseFileName != value.baseFileName; }); }; const auto it = std::lower_bound(m_packages.begin(), m_packages.end(), baseFileName, lessThan); if (it == m_packages.end() || testPackage(*it)) raizeUnknownPackageException(baseFileName); return *it; } std::optional PkgConfig::packageGetVariable( const PcPackage &pkg, std::string_view var) const { std::optional result; if (var.empty()) return result; const auto &globals = m_options.globalVariables; if (auto it = globals.find(var); it != globals.end()) result = it->second; // Allow overriding specific variables using an environment variable of the // form PKG_CONFIG_$PACKAGENAME_$VARIABLE if (!pkg.baseFileName.empty()) { const std::string envVariable = varToEnvVar(pkg.baseFileName, var); const auto it = m_options.systemVariables.find(envVariable); if (it != m_options.systemVariables.end()) result = it->second; } if (!result) { if (const auto it = pkg.variables.find(var); it != pkg.variables.end()) result = it->second; } return result; } std::vector getPcFilePaths(const std::vector &searchPaths) { std::vector paths; for (const auto &searchPath : searchPaths) { if (!std::filesystem::exists(std::filesystem::directory_entry(searchPath).status())) continue; const auto dir = std::filesystem::directory_iterator(searchPath); std::copy_if( std::filesystem::begin(dir), std::filesystem::end(dir), std::back_inserter(paths), [](const auto &entry) { return entry.path().extension() == ".pc"; } ); } std::vector result; std::transform( std::begin(paths), std::end(paths), std::back_inserter(result), [](const auto &path) { return path.generic_string(); } ); return result; } PcBrokenPackage makeMissingDependency( const PcPackage &package, const PcPackage::RequiredVersion &depVersion) { std::string message; message += "Package "; message += package.name; message += " requires package "; message += depVersion.name; message += " but it is not found"; return PcBrokenPackage{ package.filePath, package.baseFileName, std::move(message)}; } PcBrokenPackage makeBrokenDependency( const PcPackage &package, const PcPackage::RequiredVersion &depVersion) { std::string message; message += "Package "; message += package.name; message += " requires package "; message += depVersion.name; message += " but it is broken"; return PcBrokenPackage{ package.filePath, package.baseFileName, std::move(message)}; } PcBrokenPackage makeVersionMismatchDependency( const PcPackage &package, const PcPackage &depPackage, const PcPackage::RequiredVersion &depVersion) { std::string message; message += "Package "; message += package.name; message += " requires version "; message += PcPackage::RequiredVersion::comparisonToString( depVersion.comparison); message += depVersion.version; message += " but "; message += depPackage.version; message += " is present"; return PcBrokenPackage{ package.filePath, package.baseFileName, std::move(message)}; } PkgConfig::Packages PkgConfig::findPackages() const { Packages result; PcParser parser(*this); const auto systemLibraryPaths = !m_options.allowSystemLibraryPaths ? std::unordered_set( m_options.systemLibraryPaths.begin(), m_options.systemLibraryPaths.end()) : std::unordered_set(); auto allSearchPaths = m_options.extraPaths; allSearchPaths.insert( allSearchPaths.end(), m_options.libDirs.begin(), m_options.libDirs.end()); const auto pcFilePaths = getPcFilePaths(allSearchPaths); for (const auto &pcFilePath : pcFilePaths) { if (m_options.disableUninstalled) { if (pcFilePath.find("-uninstalled.pc") != std::string::npos) continue; } auto pkg = parser.parsePackageFile(pcFilePath); pkg.visit([&](auto &value) { using T = std::decay_t; if constexpr (std::is_same_v) { // NOLINT value = std::move(value) // Weird, but pkg-config removes libs first and only then appends // sysroot. Looks like sysroot has to be used with // allowSystemLibraryPaths: true .removeSystemLibraryPaths(systemLibraryPaths) .prependSysroot(m_options.sysroot); } }); result.emplace_back(std::move(pkg)); } const auto lessThanPackage = [](const PcPackageVariant &lhs, const PcPackageVariant &rhs) { return lhs.getBaseFileName() < rhs.getBaseFileName(); }; std::sort(result.begin(), result.end(), lessThanPackage); return result; } } // namespace qbs qbs-src-2.6.1/src/lib/pkgconfig/pcpackage.cpp0000644000175100001660000001767314776170045020414 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "pcpackage.h" #include namespace qbs { using Internal::startsWith; using ComparisonType = PcPackage::RequiredVersion::ComparisonType; std::string_view PcPackage::Flag::typeToString(Type t) { switch (t) { case Type::LibraryName: return "LibraryName"; case Type::StaticLibraryName: return "StaticLibraryName"; case Type::LibraryPath: return "LibraryPath"; case Type::Framework: return "Framework"; case Type::FrameworkPath: return "FrameworkPath"; case Type::LinkerFlag: return "LinkerFlag"; case Type::IncludePath: return "IncludePath"; case Type::SystemIncludePath: return "SystemIncludePath"; case Type::DirAfterIncludePath: return "DirAfterIncludePath"; case Type::Define: return "Define"; case Type::CompilerFlag: return "CompilerFlag"; } return {}; } std::optional PcPackage::Flag::typeFromString(std::string_view s) { if (s == "LibraryName") return Type::LibraryName; if (s == "StaticLibraryName") return Type::StaticLibraryName; if (s == "LibraryPath") return Type::LibraryPath; if (s == "Framework") return Type::Framework; if (s == "FrameworkPath") return Type::FrameworkPath; if (s == "LinkerFlag") return Type::LinkerFlag; if (s == "IncludePath") return Type::IncludePath; if (s == "SystemIncludePath") return Type::SystemIncludePath; if (s == "DirAfterIncludePath") return Type::DirAfterIncludePath; if (s == "Define") return Type::Define; if (s == "CompilerFlag") return Type::CompilerFlag; return std::nullopt; } std::string_view PcPackage::RequiredVersion::comparisonToString(ComparisonType t) { switch (t) { case ComparisonType::LessThan: return "LessThan"; case ComparisonType::GreaterThan: return "GreaterThan"; case ComparisonType::LessThanEqual: return "LessThanEqual"; case ComparisonType::GreaterThanEqual: return "GreaterThanEqual"; case ComparisonType::Equal: return "Equal"; case ComparisonType::NotEqual: return "NotEqual"; case ComparisonType::AlwaysMatch: return "AlwaysMatch"; } return {}; } std::optional PcPackage::RequiredVersion::comparisonFromString(std::string_view s) { if (s == "LessThan") return ComparisonType::LessThan; if (s == "GreaterThan") return ComparisonType::GreaterThan; if (s == "LessThanEqual") return ComparisonType::LessThanEqual; if (s == "GreaterThanEqual") return ComparisonType::GreaterThanEqual; if (s == "Equal") return ComparisonType::Equal; if (s == "NotEqual") return ComparisonType::NotEqual; if (s == "AlwaysMatch") return ComparisonType::AlwaysMatch; return std::nullopt; } // see https://github.com/pkgconf/pkgconf/blob/pkgconf-2.1.0/libpkgconf/tuple.c#L194 bool PcPackage::shouldRewriteSysroot(std::string_view sysroot, std::string_view value) { if (sysroot.empty() || value.empty()) return false; if (value.front() != '/') return false; if (sysroot == "/") return false; if (startsWith(value, sysroot)) return false; return true; } // TODO: pkg-config only prepends sysroot to flags; while pkgconf does this as a part of the // variable substitution and thus this affects all variables, not only flags PcPackage PcPackage::prependSysroot(std::string_view sysroot) && { PcPackage package(std::move(*this)); const auto doAppend = [](std::vector flags, std::string_view sysroot) { if (sysroot.empty()) return flags; for (auto &flag : flags) { if (!shouldRewriteSysroot(sysroot, flag.value)) continue; if (flag.type == Flag::Type::IncludePath || flag.type == Flag::Type::SystemIncludePath || flag.type == Flag::Type::DirAfterIncludePath || flag.type == Flag::Type::LibraryPath) { flag.value = std::string(sysroot) + std::move(flag.value); } } return flags; }; package.libs = doAppend(std::move(package.libs), sysroot); package.libsPrivate = doAppend(std::move(package.libsPrivate), sysroot); package.cflags = doAppend(std::move(package.cflags), sysroot); return package; } PcPackage PcPackage::removeSystemLibraryPaths( const std::unordered_set &libraryPaths) && { PcPackage package(std::move(*this)); if (libraryPaths.empty()) return package; const auto doRemove = [&libraryPaths](std::vector flags) { const auto predicate = [&libraryPaths](const Flag &flag) { return flag.type == Flag::Type::LibraryPath && libraryPaths.count(flag.value); }; flags.erase(std::remove_if(flags.begin(), flags.end(), predicate), flags.end()); return flags; }; package.libs = doRemove(package.libs); package.libsPrivate = doRemove(package.libsPrivate); return package; } namespace Internal { std::string_view fileName(std::string_view filePath) { const auto pos = filePath.rfind('/'); if (pos == std::string_view::npos) { #if defined(WIN32) if (filePath.size() >= 2 && filePath[1] == ':') return filePath.substr(2); #endif return filePath; } return filePath.substr(pos + 1); } std::string_view completeBaseName(std::string_view filePath) { filePath = fileName(filePath); const auto pos = filePath.rfind('.'); return pos == std::string_view::npos ? filePath : filePath.substr(0, pos); } std::string_view parentPath(std::string_view path) { if (path.empty()) return {}; auto pos = path.rfind('/'); if (pos == std::string_view::npos) { #if defined(WIN32) if (path.size() >= 2 && path[1] == ':') return path.substr(0, 2); #endif return "."; } if (pos == 0) return "/"; #if defined(WIN32) if (pos == 2 && path[1] == ':') return path.substr(0, pos + 1); #endif return path.substr(0, pos); }; } // namespace Internal } // namespace qbs qbs-src-2.6.1/src/lib/pkgconfig/pcparser.h0000644000175100001660000000627314776170045017754 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PC_PARSER_H #define PC_PARSER_H #include "pcpackage.h" namespace qbs { class PkgConfig; class PcParser { public: explicit PcParser(const PkgConfig &pkgConfig); PcPackageVariant parsePackageFile(const std::string &path); private: std::string trimAndSubstitute(const PcPackage &pkg, std::string_view str) const; std::string evaluateVariable(PcPackage &pkg, std::string_view tag, std::string_view str) const; void parseStringField( PcPackage &pkg, std::string &field, std::string_view fieldName, std::string_view str); void parseLibs( PcPackage &pkg, std::vector &libs, std::string_view fieldName, std::string_view str); std::vector doParseLibs(const std::vector &argv); void parseCFlags(PcPackage &pkg, std::string_view str); std::vector parseModuleList(PcPackage &pkg, std::string_view str); void parseVersionsField( PcPackage &pkg, std::vector &modules, std::string_view fieldName, std::string_view str); void parseLine(PcPackage &pkg, std::string_view str); private: const PkgConfig &m_pkgConfig; }; } // namespace qbs #endif // PC_PARSER_H qbs-src-2.6.1/src/lib/pkgconfig/pkgconfig.h0000644000175100001660000000647114776170045020104 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PKGCONFIG_H #define PKGCONFIG_H #include "pcpackage.h" namespace qbs { class PkgConfig { public: struct Options { using VariablesMap = PcPackage::VariablesMap; std::vector libDirs; // PKG_CONFIG_LIBDIR std::vector extraPaths; // PKG_CONFIG_PATH std::string sysroot; // PKG_CONFIG_SYSROOT_DIR std::string topBuildDir; // PKG_CONFIG_TOP_BUILD_DIR bool allowSystemLibraryPaths{false}; // PKG_CONFIG_ALLOW_SYSTEM_LIBS std::vector systemLibraryPaths; // PKG_CONFIG_SYSTEM_LIBRARY_PATH bool disableUninstalled{true}; // PKG_CONFIG_DISABLE_UNINSTALLED bool staticMode{false}; bool definePrefix{false}; VariablesMap globalVariables; VariablesMap systemVariables; }; using Packages = std::vector; explicit PkgConfig(); explicit PkgConfig(Options options); const Options &options() const { return m_options; } const Packages &packages() const { return m_packages; } const PcPackageVariant &getPackage(std::string_view baseFileName) const; std::optional packageGetVariable( const PcPackage &pkg, std::string_view var) const; private: Packages findPackages() const; private: Options m_options; Packages m_packages; }; } // namespace qbs #endif // PKGCONFIG_H qbs-src-2.6.1/src/lib/pkgconfig/pkgconfig.qbs0000644000175100001660000000332614776170045020436 0ustar runnerdockerimport qbs.FileInfo import qbs.Utilities QbsProduct { type: "staticlibrary" Depends { name: "cpp" } Depends { name: "qbsbuildconfig" } property stringList pcPaths: { var result = []; result.push(FileInfo.joinPaths(qbs.installPrefix, qbsbuildconfig.libDirName, "pkgconfig")); result.push(FileInfo.joinPaths(qbs.installPrefix, "share", "pkgconfig")); if (qbs.hostOS.contains("unix")) { result.push("/usr/lib/pkgconfig/") result.push("/usr/share/pkgconfig/") } return result } readonly property stringList pcPathsString: pcPaths.join(qbs.pathListSeparator) property bool withQtSupport: true readonly property stringList publicDefines: { var result = []; if (withQtSupport) result.push("QBS_PC_WITH_QT_SUPPORT=1") else result.push("QBS_PC_WITH_QT_SUPPORT=0") return result; } name: "qbspkgconfig" files: [ "pcpackage.cpp", "pcpackage.h", "pcparser.cpp", "pcparser.h", "pkgconfig.cpp", "pkgconfig.h", ] cpp.defines: { var result = [ "PKG_CONFIG_PC_PATH=\"" + pcPathsString + "\"", "PKG_CONFIG_SYSTEM_LIBRARY_PATH=\"/usr/" + qbsbuildconfig.libDirName + "\"", ] result = result.concat(publicDefines); return result } Export { Depends { name: "cpp" } cpp.defines: exportingProduct.publicDefines cpp.includePaths: [exportingProduct.sourceDirectory] cpp.staticLibraries: { if (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor < 9) return ["stdc++fs"]; return []; } } } qbs-src-2.6.1/src/lib/pkgconfig/pcpackage.h0000644000175100001660000001520114776170045020042 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef PC_PACKAGE_H #define PC_PACKAGE_H #include #include #include #include #include #include #include #include #include namespace qbs { class PcPackage { public: struct Flag { enum class Type { LibraryName = (1 << 0), StaticLibraryName = (1 << 1), LibraryPath = (1 << 2), Framework = (1 << 3), FrameworkPath = (1 << 4), LinkerFlag = (1 << 5), // this is a lie, this is DriverLinkerFlags IncludePath = (1 << 6), SystemIncludePath = (1 << 7), DirAfterIncludePath = (1 << 8), Define = (1 << 9), CompilerFlag = (1 << 10), }; Type type{Type::CompilerFlag}; std::string value; static std::string_view typeToString(Type t); static std::optional typeFromString(std::string_view s); }; struct RequiredVersion { enum class ComparisonType { LessThan, GreaterThan, LessThanEqual, GreaterThanEqual, Equal, NotEqual, AlwaysMatch }; std::string name; ComparisonType comparison{ComparisonType::GreaterThanEqual}; std::string version; static std::string_view comparisonToString(ComparisonType t); static std::optional comparisonFromString(std::string_view s); }; std::string filePath; std::string baseFileName; std::string name; std::string version; std::string description; std::string url; std::vector libs; std::vector libsPrivate; std::vector cflags; std::vector requiresPublic; std::vector requiresPrivate; std::vector conflicts; std::optional oldPrefix; using VariablesMap = std::map>; VariablesMap variables; bool uninstalled{false}; static bool shouldRewriteSysroot(std::string_view sysroot, std::string_view value); PcPackage prependSysroot(std::string_view sysroot) &&; PcPackage removeSystemLibraryPaths(const std::unordered_set &libraryPaths) &&; }; class PcBrokenPackage { public: std::string filePath; std::string baseFileName; std::string errorText; }; class PcPackageVariant : public std::variant { public: using Base = std::variant; using Base::Base; bool isValid() const noexcept { return index() == 0; } bool isBroken() const noexcept { return index() == 1; } const PcPackage &asPackage() const { return std::get(*this); } PcPackage &asPackage() { return std::get(*this); } const PcBrokenPackage &asBrokenPackage() const { return std::get(*this); } PcBrokenPackage &asBrokenPackage() { return std::get(*this); } template decltype(auto) visit(F &&f) const { return std::visit(std::forward(f), static_cast(*this)); } template decltype(auto) visit(F &&f) { return std::visit(std::forward(f), static_cast(*this)); } const std::string &getBaseFileName() const { return visit([](auto &&value) noexcept -> const std::string & { return value.baseFileName; }); } }; class PcException: public std::runtime_error { public: explicit PcException(const std::string &message) : std::runtime_error(message) {} }; inline bool operator==(const PcPackage::Flag &lhs, const PcPackage::Flag &rhs) { return lhs.type == rhs.type && lhs.value == rhs.value; } inline bool operator!=(const PcPackage::Flag &lhs, const PcPackage::Flag &rhs) { return !(lhs == rhs); } namespace Internal { // fast versions (no allocations) of the QFileInfo methods std::string_view fileName(std::string_view filePath); std::string_view completeBaseName(std::string_view filePath); std::string_view parentPath(std::string_view path); inline bool startsWith(std::string_view haystack, std::string_view needle) { return haystack.size() >= needle.size() && haystack.compare(0, needle.size(), needle) == 0; } inline bool endsWith(std::string_view haystack, std::string_view needle) { return haystack.size() >= needle.size() && haystack.compare(haystack.size() - needle.size(), needle.size(), needle) == 0; } } // Internal } // namespace qbs namespace std { template<> struct hash { size_t operator()(const qbs::PcPackage::Flag &v) const noexcept { return hash()(v.value) + size_t(v.type); } }; } // namespace std #endif // PC_PACKAGE_H qbs-src-2.6.1/src/lib/pkgconfig/CMakeLists.txt0000644000175100001660000000142114776170045020512 0ustar runnerdockerset(SOURCES pcpackage.cpp pcpackage.h pcparser.cpp pcparser.h pkgconfig.cpp pkgconfig.h ) list_transform_prepend(SOLUTION_SOURCES solution/) set(QBS_PKGCONFIG_PUBLIC_DEPENDS "") if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) set(QBS_PKGCONFIG_PUBLIC_DEPENDS "stdc++fs") endif() add_qbs_library(qbspkgconfig STATIC DEFINES "PKG_CONFIG_PC_PATH=\"${CMAKE_INSTALL_PREFIX}/${QBS_LIBDIR_NAME}/pkgconfig:${CMAKE_INSTALL_PREFIX}/share/pkgconfig:/usr/${QBS_LIBDIR_NAME}/pkgconfig/:/usr/share/pkgconfig/\"" "PKG_CONFIG_SYSTEM_LIBRARY_PATH=\"/usr/${QBS_LIBDIR_NAME}\"" PUBLIC_DEFINES "QBS_PC_WITH_QT_SUPPORT=1" PUBLIC_DEPENDS ${QBS_PKGCONFIG_PUBLIC_DEPENDS} SOURCES ${SOURCES} ) qbs-src-2.6.1/src/lib/pkgconfig/pcparser.cpp0000644000175100001660000005452414776170045020311 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "pcparser.h" #include "pkgconfig.h" #include #include #include #include #include namespace qbs { using Internal::completeBaseName; using Internal::parentPath; using Internal::startsWith; using Internal::endsWith; namespace { // workaround for a missing ctor before c++20 template std::string_view makeStringView(It begin, It end) { if (begin == end) return {}; return std::string_view(&*begin, std::distance(begin, end)); } bool readOneLine(std::ifstream &file, std::string &line) { bool quoted = false; bool comment = false; int n_read = 0; line = {}; while (true) { char c; file.get(c); const bool ok = file.good(); if (!ok) { if (quoted) line += '\\'; return n_read > 0; } n_read++; if (c == '\r') { n_read--; continue; } if (quoted) { quoted = false; switch (c) { case '#': line += '#'; break; case '\n': break; default: line += '\\'; line += c; break; } } else { switch (c) { case '#': comment = true; break; case '\\': if (!comment) quoted = true; break; case '\n': return n_read > 0; default: if (!comment) line += c; break; } } } return n_read > 0; } std::string_view trimmed(std::string_view str) { const auto predicate = [](int c){ return std::isspace(c); }; const auto left = std::find_if_not(str.begin(), str.end(), predicate); const auto right = std::find_if_not(str.rbegin(), str.rend(), predicate).base(); if (right <= left) return {}; return makeStringView(left, right); } // based on https://opensource.apple.com/source/distcc/distcc-31.0.81/popt/poptparse.c.auto.html std::optional> splitCommand(std::string_view s) { std::vector result; std::string arg; char quote = '\0'; for (auto it = s.begin(), end = s.end(); it != end; ++it) { if (quote == *it) { quote = '\0'; } else if (quote != '\0') { if (*it == '\\') { ++it; if (it == s.end()) return std::nullopt; if (*it != quote) arg += '\\'; } arg += *it; } else if (isspace(*it)) { if (!arg.empty()) { result.push_back(arg); arg.clear(); } } else { switch (*it) { case '"': case '\'': quote = *it; break; case '\\': ++it; if (it == s.end()) return std::nullopt; [[fallthrough]]; default: arg += *it; break; } } } if (!arg.empty()) result.push_back(arg); return result; } [[noreturn]] void raizeUnknownComparisonException(const PcPackage &pkg, std::string_view verName, std::string_view comp) { std::string message; message += "Unknown version comparison operator '"; message += comp; message += "' after package name '"; message += verName; message += "' in file '"; message += pkg.filePath; message += "'"; throw PcException(message); } [[noreturn]] void raiseDuplicateFieldException(std::string_view fieldName, std::string_view path) { std::string message; message += fieldName; message += " field occurs twice in '"; message += path; message += "'"; throw PcException(message); } [[noreturn]] void raizeEmptyPackageNameException(const PcPackage &pkg) { std::string message; message += "Empty package name in Requires or Conflicts in file '"; message += pkg.filePath; message += "'"; throw PcException(message); } [[noreturn]] void raizeNoVersionException(const PcPackage &pkg, std::string_view verName) { std::string message; message += "Comparison operator but no version after package name '"; message += verName; message += "' in file '"; message += pkg.filePath; message += "'"; throw PcException(message); } [[noreturn]] void raizeDuplicateVariableException(const PcPackage &pkg, std::string_view variable) { std::string message; message += "Duplicate definition of variable '"; message += variable; message += "' in '"; message += pkg.filePath; throw PcException(message); } [[noreturn]] void raizeUndefinedVariableException(const PcPackage &pkg, std::string_view variable) { std::string message; message += "Variable '"; message += variable; message += "' not defined in '"; message += pkg.filePath; throw PcException(message); } bool isModuleSeparator(char c) { return c == ',' || std::isspace(c); } bool isModuleOperator(char c) { return c == '<' || c == '>' || c == '!' || c == '='; } // A module list is a list of modules with optional version specification, // separated by commas and/or spaces. Commas are treated just like whitespace, // in order to allow stuff like: Requires: @FRIBIDI_PC@, glib, gmodule // where @FRIBIDI_PC@ gets substituted to nothing or to 'fribidi' std::vector splitModuleList(std::string_view str) { enum class State { // put numbers to help interpret lame debug spew ;-) OutsideModule = 0, InModuleName = 1, BeforeOperator = 2, InOperator = 3, AfterOperator = 4, InModuleVersion = 5 }; std::vector result; State state = State::OutsideModule; State last_state = State::OutsideModule; auto start = str.begin(); const auto end = str.end(); auto p = start; while (p != end) { switch (state) { case State::OutsideModule: if (!isModuleSeparator(*p)) state = State::InModuleName; break; case State::InModuleName: if (std::isspace(*p)) { // Need to look ahead to determine next state auto s = p; while (s != end && std::isspace (*s)) ++s; state = State::OutsideModule; if (s != end && isModuleOperator(*s)) state = State::BeforeOperator; } else if (isModuleSeparator(*p)) state = State::OutsideModule; // comma precludes any operators break; case State::BeforeOperator: // We know an operator is coming up here due to lookahead from // IN_MODULE_NAME if (std::isspace(*p)) ; // no change else if (isModuleOperator(*p)) state = State::InOperator; break; case State::InOperator: if (!isModuleOperator(*p)) state = State::AfterOperator; break; case State::AfterOperator: if (!std::isspace(*p)) state = State::InModuleVersion; break; case State::InModuleVersion: if (isModuleSeparator(*p)) state = State::OutsideModule; break; default: break; } if (state == State::OutsideModule && last_state != State::OutsideModule) { // We left a module while (start != end && isModuleSeparator(*start)) ++start; std::string module(&*start, p - start); result.push_back(module); // reset start start = p; } last_state = state; ++p; } if (p != start) { // get the last module while (start != end && isModuleSeparator(*start)) ++start; std::string module(&*start, p - start); result.push_back(module); } return result; } PcPackage::RequiredVersion::ComparisonType comparisonFromString( const PcPackage &pkg, std::string_view verName, std::string_view comp) { using ComparisonType = PcPackage::RequiredVersion::ComparisonType; if (comp.empty()) return ComparisonType::AlwaysMatch; if (comp == "=") return ComparisonType::Equal; if (comp == ">=") return ComparisonType::GreaterThanEqual; if (comp == "<=") return ComparisonType::LessThanEqual; if (comp == ">") return ComparisonType::GreaterThan; if (comp == "<") return ComparisonType::LessThan; if (comp == "!=") return ComparisonType::NotEqual; raizeUnknownComparisonException(pkg, verName, comp); } } // namespace PcParser::PcParser(const PkgConfig &pkgConfig) : m_pkgConfig(pkgConfig) { } PcPackageVariant PcParser::parsePackageFile(const std::string &path) try { PcPackage package; if (path.empty()) return package; std::ifstream file(path); if (!file.is_open()) throw PcException(std::string("Can't open file ") + path); package.baseFileName = std::string{completeBaseName(path)}; const auto fsPath = std::filesystem::path(path); package.filePath = fsPath.generic_string(); package.variables["pcfiledir"] = fsPath.parent_path().generic_string(); std::string line; while (readOneLine(file, line)) parseLine(package, line); return package; } catch(const PcException &ex) { return PcBrokenPackage{path, std::string{completeBaseName(path)}, ex.what()}; } std::string PcParser::trimAndSubstitute(const PcPackage &pkg, std::string_view str) const { str = trimmed(str); std::string result; while (!str.empty()) { if (startsWith(str, "$$")) { // escaped $ result += '$'; str.remove_prefix(2); // cut "$$" } else if (startsWith(str, "${")) { // variable str.remove_prefix(2); // cut "${" const auto it = std::find(str.begin(), str.end(), '}'); // funny, original pkg-config simply reads all available memory here if (it == str.end()) throw PcException("Missing closing '}'"); const std::string_view varname = str.substr(0, std::distance(str.begin(), it)); // past brace str.remove_prefix(varname.size()); str.remove_prefix(1); const auto varval = m_pkgConfig.packageGetVariable(pkg, varname); if (!varval) raizeUndefinedVariableException(pkg, varname); result += *varval; } else { result += str.front(); str.remove_prefix(1); } } return result; } std::string PcParser::evaluateVariable( PcPackage &pkg, std::string_view tag, std::string_view str) const { static constexpr std::string_view prefixVariable = "prefix"; if (m_pkgConfig.options().definePrefix) { if (tag == prefixVariable) { std::string_view prefix = pkg.filePath; prefix = parentPath(prefix); if (completeBaseName(prefix) == "pkgconfig") { prefix = parentPath(prefix); prefix = parentPath(prefix); } pkg.oldPrefix = std::string(str); if (!prefix.empty()) str = prefix; return std::string(str); } else if (pkg.oldPrefix && str.size() > pkg.oldPrefix->size() && str.substr(0, pkg.oldPrefix->size()) == *pkg.oldPrefix && str[pkg.oldPrefix->size()] == '/') { auto result = pkg.variables["prefix"]; result += str.substr(pkg.oldPrefix->size()); return trimAndSubstitute(pkg, result); } } return trimAndSubstitute(pkg, str); } void PcParser::parseStringField( PcPackage &pkg, std::string &field, std::string_view fieldName, std::string_view str) { if (!field.empty()) raiseDuplicateFieldException(fieldName, pkg.filePath); field = trimAndSubstitute(pkg, str); } void PcParser::parseLibs( PcPackage &pkg, std::vector &libs, std::string_view fieldName, std::string_view str) { // Strip out -l and -L flags, put them in a separate list. if (!libs.empty()) raiseDuplicateFieldException(fieldName, pkg.filePath); const auto trimmed = trimAndSubstitute(pkg, str); if (trimmed.empty()) return; const auto argv = splitCommand(trimmed); if (!argv) throw PcException("Couldn't parse Libs field into an argument vector"); libs = doParseLibs(*argv); } std::vector PcParser::doParseLibs(const std::vector &argv) { std::vector libs; libs.reserve(argv.size()); for (auto it = argv.begin(), end = argv.end(); it != end; ++it) { PcPackage::Flag flag; const auto escapedArgument = trimmed(*it); std::string_view arg(escapedArgument); // -lib: is used by the C# compiler for libs; it's not an -l flag. if (startsWith(arg, "-l") && !startsWith(arg, "-lib:")) { arg.remove_prefix(2); arg = trimmed(arg); flag.type = PcPackage::Flag::Type::LibraryName; flag.value += arg; } else if (startsWith(arg, "-L")) { arg.remove_prefix(2); arg = trimmed(arg); flag.type = PcPackage::Flag::Type::LibraryPath; flag.value += arg; } else if ((arg == "-framework" /*|| arg == "-Wl,-framework"*/) && it + 1 != end) { // macOS has a -framework Foo which is really one option, // so we join those to avoid having -framework Foo // -framework Bar being changed into -framework Foo Bar // later const auto framework = trimmed(*(it + 1)); flag.type = PcPackage::Flag::Type::Framework; flag.value += framework; ++it; } else if (startsWith(arg, "-F")) { arg.remove_prefix(2); arg = trimmed(arg); flag.type = PcPackage::Flag::Type::FrameworkPath; flag.value += arg; } else if (!startsWith(arg, "-") && (endsWith(arg, ".a") || endsWith(arg, ".lib"))) { flag.type = PcPackage::Flag::Type::StaticLibraryName; flag.value += arg; } else if (!arg.empty()) { flag.type = PcPackage::Flag::Type::LinkerFlag; flag.value += arg; } else { continue; } libs.push_back(flag); } return libs; } void PcParser::parseCFlags(PcPackage &pkg, std::string_view str) { // Strip out -I, -D, -isystem and idirafter flags, put them in a separate lists. if (!pkg.cflags.empty()) raiseDuplicateFieldException("Cflags", pkg.filePath); const auto command = trimAndSubstitute(pkg, str); if (command.empty()) return; const auto argv = splitCommand(command); if (!argv) throw PcException("Couldn't parse Cflags field into an argument vector"); std::vector cflags; cflags.reserve(argv->size()); for (auto it = argv->begin(), end = argv->end(); it != end; ++it) { PcPackage::Flag flag; const auto escapedArgument = trimmed(*it); std::string_view arg(escapedArgument); if (startsWith(arg, "-I")) { arg.remove_prefix(2); arg = trimmed(arg); flag.type = PcPackage::Flag::Type::IncludePath; flag.value += arg; } else if (startsWith(arg, "-D")) { arg.remove_prefix(2); arg = trimmed(arg); flag.type = PcPackage::Flag::Type::Define; flag.value += arg; } else if (arg == "-isystem" && it + 1 != end) { flag.type = PcPackage::Flag::Type::SystemIncludePath; flag.value = trimmed(*(it + 1)); ++it; } else if (arg == "-idirafter" && it + 1 != end) { flag.type = PcPackage::Flag::Type::DirAfterIncludePath; flag.value = trimmed(*(it + 1)); ++it; } else if (!arg.empty()) { flag.type = PcPackage::Flag::Type::CompilerFlag; flag.value += arg; } else { continue; } cflags.push_back(flag); } pkg.cflags = std::move(cflags); } std::vector PcParser::parseModuleList(PcPackage &pkg, std::string_view str) { using ComparisonType = PcPackage::RequiredVersion::ComparisonType; std::vector result; auto split = splitModuleList(str); for (auto &module: split) { PcPackage::RequiredVersion ver; auto p = module.begin(); const auto end = module.end(); ver.comparison = ComparisonType::AlwaysMatch; auto start = p; while (p != end && !std::isspace(*p)) ++p; const auto name = makeStringView(start, p); if (name.empty()) raizeEmptyPackageNameException(pkg); ver.name = std::string(name); while (p != end && std::isspace(*p)) ++p; start = p; while (p != end && !std::isspace(*p)) ++p; const auto comp = makeStringView(start, p); ver.comparison = comparisonFromString(pkg, ver.name, comp); while (p != end && std::isspace(*p)) ++p; start = p; while (p != end && !std::isspace(*p)) ++p; const auto version = makeStringView(start, p); while (p != end && std::isspace(*p)) ++p; if (ver.comparison != ComparisonType::AlwaysMatch && version.empty()) raizeNoVersionException(pkg, ver.name); ver.version = std::string(version); result.push_back(ver); } return result; } void PcParser::parseVersionsField( PcPackage &pkg, std::vector &modules, std::string_view fieldName, std::string_view str) { if (!modules.empty()) raiseDuplicateFieldException(fieldName, pkg.filePath); const auto trimmed = trimAndSubstitute(pkg, str); modules = parseModuleList(pkg, trimmed.c_str()); } void PcParser::parseLine(PcPackage &pkg, std::string_view str) { str = trimmed(str); if (str.empty()) return; auto getFirstWord = [](std::string_view s) { size_t pos = 0; for (; pos < s.size(); ++pos) { auto p = s.data() + pos; if ((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && *p != '_' && *p != '.') { break; } } return s.substr(0, pos); }; const auto tag = getFirstWord(str); str.remove_prefix(tag.size()); // cut tag str = trimmed(str); if (str.empty()) return; if (str.front() == ':') { // keyword str.remove_prefix(1); // cut ':' str = trimmed(str); if (tag == "Name") parseStringField(pkg, pkg.name, tag, str); else if (tag == "Description") parseStringField(pkg, pkg.description, tag, str); else if (tag == "Version") parseStringField(pkg, pkg.version, tag, str); else if (tag == "Requires.private") parseVersionsField(pkg, pkg.requiresPrivate, tag, str); else if (tag == "Requires") parseVersionsField(pkg, pkg.requiresPublic, tag, str); else if (tag == "Libs.private") parseLibs(pkg, pkg.libsPrivate, "Libs.private", str); else if (tag == "Libs") parseLibs(pkg, pkg.libs, "Libs", str); else if (tag == "Cflags" || tag == "CFlags") parseCFlags(pkg, str); else if (tag == "Conflicts") parseVersionsField(pkg, pkg.conflicts, tag, str); else if (tag == "URL") parseStringField(pkg, pkg.url, tag, str); else { // we don't error out on unknown keywords because they may // represent additions to the .pc file format from future // versions of pkg-config. return; } } else if (str.front() == '=') { // variable str.remove_prefix(1); // cut '=' str = trimmed(str); const auto value = evaluateVariable(pkg, tag, str); if (!pkg.variables.insert({std::string(tag), value}).second) raizeDuplicateVariableException(pkg, tag); } } } // namespace qbs qbs-src-2.6.1/src/src.qbs0000644000175100001660000000050114776170045014531 0ustar runnerdockerProject { references: [ "app/apps.qbs", "lib/libs.qbs", "libexec/libexec.qbs", "packages/packages.qbs", "plugins/plugins.qbs", "shared/bundledqt/bundledqt.qbs", "shared/lsp/lsp.qbs", "shared/quickjs/quickjs.qbs", "shared/span/span.qbs", ] } qbs-src-2.6.1/src/shared/0000755000175100001660000000000014776170045014505 5ustar runnerdockerqbs-src-2.6.1/src/shared/span/0000755000175100001660000000000014776170045015446 5ustar runnerdockerqbs-src-2.6.1/src/shared/span/README.md0000644000175100001660000010654514776170045016740 0ustar runnerdocker # span lite: A single-file header-only version of a C++20-like span for C++98, C++11 and later [![Language](https://img.shields.io/badge/C%2B%2B-98/11/14/17/20-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) [![Build Status](https://github.com/martinmoene/span-lite/actions/workflows/ci.yml/badge.svg)](https://github.com/martinmoene/span-lite/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/1ha3wnxtam547m8p?svg=true)](https://ci.appveyor.com/project/martinmoene/span-lite) [![Version](https://badge.fury.io/gh/martinmoene%2Fspan-lite.svg)](https://github.com/martinmoene/span-lite/releases) [![download](https://img.shields.io/badge/latest-download-blue.svg)](https://github.com/martinmoene/span-lite/blob/master/include/nonstd/span.hpp) [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://conan.io/center/span-lite) [![Try it on wandbox](https://img.shields.io/badge/on-wandbox-blue.svg)](https://wandbox.org/permlink/venR3Ko2Q4tlvcVk) [![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](https://godbolt.org/z/htwpnb) **Contents** - [Example usage](#example-usage) - [In a nutshell](#in-a-nutshell) - [License](#license) - [Dependencies](#dependencies) - [Installation and use](#installation-and-use) - [Synopsis](#synopsis) - [Reported to work with](#reported-to-work-with) - [Building the tests](#building-the-tests) - [Other implementations of span](#other-implementations-of-span) - [Notes and references](#notes-and-references) - [Appendix](#appendix) ## Example usage ```cpp #include "nonstd/span.hpp" #include #include #include std::ptrdiff_t size( nonstd::span spn ) { return spn.size(); } int main() { int arr[] = { 1, }; std::cout << "C-array:" << size( arr ) << " array:" << size( std::array { 1, 2, } ) << " vector:" << size( std::vector{ 1, 2, 3, } ); } ``` ### Compile and run ```bash prompt> g++ -std=c++11 -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe C-array:1 array:2 vector:3 ``` ## In a nutshell **span lite** is a single-file header-only library to provide a bounds-safe view for sequences of objects. The library provides a [C++20-like span](http://en.cppreference.com/w/cpp/container/span) for use with C++98 and later. If available, `std::span` is used, unless [configured otherwise](#configuration). *span-lite* can detect the presence of [*byte-lite*](https://github.com/martinmoene/byte-lite) and if present, it provides `as_bytes()` and `as_writable_bytes()` also for C++14 and earlier. **Features and properties of span lite** are ease of installation (single header), freedom of dependencies other than the standard library. To compensate for the class template argument deduction that is missing from pre-C++17 compilers, `nonstd::span` can provide `make_span` functions. See [configuration](#configuration). ## License *span lite* is distributed under the [Boost Software License](https://github.com/martinmoene/span-lite/blob/master/LICENSE.txt). ## Dependencies *span lite* has no other dependencies than the [C++ standard library](http://en.cppreference.com/w/cpp/header). ## Installation and use *span lite* is a single-file header-only library. Put `span.hpp` in the [include](include) folder directly into the project source tree or somewhere reachable from your project. ## Synopsis **Contents** [Documentation of `std::span`](#documentation-of-stdspan) [Later additions](#later-additions) [Non-standard extensions](#non-standard-extensions) [Configuration](#configuration) ## Documentation of `std::span` Depending on the compiler and C++-standard used, `nonstd::span` behaves less or more like `std::span`. To get an idea of the capabilities of `nonstd::span` with your configuration, look at the output of the [tests](test/span.t.cpp), issuing `span-main.t --pass @`. For `std::span`, see its [documentation at cppreference](http://en.cppreference.com/w/cpp/container/span). ## Later additions ### `back()` and `front()` *span lite* can provide `back()` and `front()` member functions for element access. See the table below and section [configuration](#configuration). ## Non-standard extensions ### Construct from std::initializer_list (p2447) *span lite* can provide construction from a std::initializer_list<> as a constant set of values as proposed in [p2447](https://wg21.link/p2447). See the table below and section [configuration](#configuration). ### Construct from container To construct a span from a container with compilers that cannot constrain such a single-parameter constructor to containers, *span lite* provides a constructor that takes an additional parameter of type `with_container_t`. Use `with_container` as value for this parameter. See the table below and section [configuration](#configuration). ### Construct from `std::array` with const data *span lite* can provide construction of a span from a `std::array` with const data. See the table below and section [configuration](#configuration). ### `operator()` *span lite* can provide member function call `operator()` for element access. It is equivalent to `operator[]` and has been marked `[[deprecated]]`. Its main purpose is to provide a migration path. ### `at()` *span lite* can provide member function `at()` for element access. Unless exceptions have been disabled, `at()` throws std::out_of_range if the index falls outside the span. With exceptions disabled, `at(index_t)` delegates bounds checking to `operator[](index_t)`. See the table below and sections [configuration](#configuration) and [disable exceptions](#disable-exceptions). ### `swap()` *span lite* can provide a `swap()`member function. See the table below and section [configuration](#configuration). ### `operator==()` and other comparison functions *span lite* can provide functions to compare the content of two spans. However, C++20's span will not provide comparison and _span lite_ will omit comparison at default in the near future. See the table below and section [configuration](#configuration). See also [Revisiting Regular Types](#regtyp). ### `same()` *span lite* can provide function `same()` to determine if two spans refer as identical spans to the same data via the same type. If `same()` is enabled, `operator==()` incorporates it in its comparison. See the table below and section [configuration](#configuration). ### `first()`, `last()` and `subspan()` *span lite* can provide functions `first()`, `last()` and `subspan()` to avoid having to use the *dot template* syntax when the span is a dependent type. See the table below and section [configuration](#configuration). ### `make_span()` *span lite* can provide `make_span()` creator functions to compensate for the class template argument deduction that is missing from pre-C++17 compilers. See the table below and section [configuration](#configuration). ### `byte_span()` *span lite* can provide `byte_span()` creator functions to represent an object as a span of bytes. This requires the C++17 type `std::byte` to be available. See the table below and section [configuration](#configuration). | Kind | std | Function or method | |--------------------|------|--------------------| | **Macro** | | macro **`span_FEATURE_WITH_INITIALIZER_LIST_P2447`** | | **Constructor**
  | | constexpr explicit **span**( std::initializer_list<value_type> il ) noexcept
explicit for non-dynamic extent | |   | |   | | **Macro**
 | | macro **`span_FEATURE_WITH_CONTAINER`**
macro **`span_FEATURE_WITH_CONTAINER_TO_STD`** | | **Types** | | **with_container_t** type to disambiguate below constructors | | **Objects** | | **with_container** value to disambiguate below constructors | | **Constructors** | | macro **`span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE`**| |   | | template<class Container>
constexpr **span**(with_container_t, Container & cont) | |   | | template<class Container>
constexpr **span**(with_container_t, Container const & cont) | |   | |   | | **Methods** | | macro **`span_FEATURE_MEMBER_CALL_OPERATOR`** | |   | | constexpr reference **operator()**(index_t idx) const
Equivalent to **operator[]**(), marked `[[deprecated]]` | |   | |   | | **Methods** | | macro **`span_FEATURE_MEMBER_AT`** | |   | | constexpr reference **at**(index_t idx) const
May throw std::out_of_range exception | |   | |   | | **Methods** | | macro **`span_FEATURE_MEMBER_BACK_FRONT`** (on since v0.5.0) | |   | | constexpr reference **back()** const noexcept | |   | | constexpr reference **front()** const noexcept | |   | |   | | **Method** | | macro **`span_FEATURE_MEMBER_SWAP`** | |   | | constexpr void **swap**(span & other) noexcept | |   | |   | | **Free functions** | | macro **`span_FEATURE_COMPARISON`** | |

== != < > <= >= | | template<class T1, index_t E1, class T2, index_t E2>
constexpr bool
**operator==**( span const & l, span const & r) noexcept | |   | |   | | **Free function** | | macro **`span_FEATURE_SAME`** | |   | | template<class T1, index_t E1, class T2, index_t E2>
constexpr bool
**same**( span const & l, span const & r) noexcept | |   | |   | | **Free functions**
 
  | | macros **`span_FEATURE_NON_MEMBER_FIRST_LAST_SUB`**,
**`span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN`**,
**`span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER`** | |   | |   | | **Free functions** | | macro **`span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN`** | |   |   | template<extent_t Count, class T, extent_t Extent>
constexpr span<T,Count>
**first**(span<T,Extent> spn) | |   |   | template<class T, extent_t Extent >
constexpr span<T>
**first**(span<T,Extent> spn, size_t count) | |   |   | template<extent_t Count, class T, extent_t Extent>
constexpr span<T,Count>
**last**(span<T,Extent> spn) | |   |   | template<class T, extent_t Extent >
constexpr span<T>
**last**(span<T,Extent> spn, size_t count) | |   |   | template<size_t Offset, extent_t Count, class T, extent_t Extent>
constexpr span<T, Count>
**subspan**(span<T, Extent> spn) | |   |   | template<class T, extent_t Extent>
constexpr span<T>
**subspan**( span<T, Extent> spn, size_t offset, extent_t count = dynamic_extent) | |   | |   | | **Free functions** | | macro **`span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER`** | |   | >= C++11 | template<extent_t Count, class T>
constexpr auto
**first**(T & t) ->... | |   | >= C++11 | template<class T>
constexpr auto
**first**(T & t, index_t count) ->... | |   | >= C++11 | template<extent_t Count, class T>
constexpr auto
**last**(T & t) ->... | |   | >= C++11 | template<class T>
constexpr auto
**last**(T & t, extent_t count) ->... | |   | >= C++11 | template<index_t Offset, extent_t Count = dynamic_extent, class T>
constexpr auto
**subspan**(T & t) ->... | |   | >= C++11 | template<class T>
constexpr auto
**subspan**(T & t, index_t offset, extent_t count = dynamic_extent) ->... | |   |   |   | | **Free functions**
  | | macro **`span_FEATURE_MAKE_SPAN`**
macro **`span_FEATURE_MAKE_SPAN_TO_STD`** | |   |   | template<class T>
constexpr span<T>
**make_span**(T \* first, T \* last) noexcept | |   |   | template<class T>
constexpr span<T>
**make_span**(T \* ptr, index_t count) noexcept | |   |   | template<class T, size_t N>
constexpr span<T,N>
**make_span**(T (&arr)[N]) noexcept | |   | >= C++11 | template<class T, size_t N>
constexpr span<T,N>
**make_span**(std::array<T,N> & arr) noexcept | |   | >= C++11 | template<class T, size_t N>
constexpr span<const T,N>
**make_span**(std::array<T,N > const & arr) noexcept | |   | >= C++11 | template<class T>
constexpr span<T>
**make_span**(std::initializer_list<T> il) noexcept | |   | >= C++11 | template<class Container>
constexpr auto
**make_span**(Container & cont) ->
 span<typename Container::value_type> noexcept | |   | >= C++11 | template<class Container>
constexpr auto
**make_span**(Container const & cont) ->
 span<const typename Container::value_type> noexcept | |   |   | template<class Container>
span<typename Container::value_type>
**make_span**( with_container_t, Container & cont ) | |   |   | template<class Container>
span<const typename Container::value_type>
**make_span**( with_container_t, Container const & cont ) | |   | < C++11 | template<class T, Allocator>
span<T>
**make_span**(std::vector<T, Allocator> & cont) | |   | < C++11 | template<class T, Allocator>
span<const T>
**make_span**(std::vector<T, Allocator> const & cont) | |   |   |   | | **Free functions** | | macro **`span_FEATURE_BYTE_SPAN`** | |   | >= C++11 | template<class T>
span<T, sizeof(T)>
**byte_span**(T & t) | |   | >= C++11 | template<class T>
span<const T, sizeof(T)>
**byte_span**(T const & t) | ## Configuration ### Tweak header If the compiler supports [`__has_include()`](https://en.cppreference.com/w/cpp/preprocessor/include), *span lite* supports the [tweak header](https://vector-of-bool.github.io/2020/10/04/lib-configuration.html) mechanism. Provide your *tweak header* as `nonstd/span.tweak.hpp` in a folder in the include-search-path. In the tweak header, provide definitions as documented below, like `#define span_CONFIG_NO_EXCEPTIONS 1`. ### Standard selection macro \-Dspan\_CPLUSPLUS=199711L Define this macro to override the auto-detection of the supported C++ standard, if your compiler does not set the `__cplusplus` macro correctly. ### Select `std::span` or `nonstd::span` At default, *span lite* uses `std::span` if it is available and lets you use it via namespace `nonstd`. You can however override this default and explicitly request to use `std::span` or span lite's `nonstd::span` as `nonstd::span` via the following macros. -Dspan\_CONFIG\_SELECT\_SPAN=span_SPAN_DEFAULT Define this to `span_SPAN_STD` to select `std::span` as `nonstd::span`. Define this to `span_SPAN_NONSTD` to select `nonstd::span` as `nonstd::span`. Default is undefined, which has the same effect as defining to `span_SPAN_DEFAULT`. ### Select extent type -Dspan_CONFIG_EXTENT_TYPE=std::size_t Define this to `std::ptrdiff_t` to use the signed type. The default is `std::size_t`, as in C++20 (since v0.7.0). ### Select size type -Dspan_CONFIG_SIZE_TYPE=std::size_t Define this to `std::ptrdiff_t` to use the signed type. The default is `std::size_t`, as in C++20 (since v0.7.0). Note `span_CONFIG_SIZE_TYPE` replaces `span_CONFIG_INDEX_TYPE` which is deprecated. ### Disable exceptions -Dspan_CONFIG_NO_EXCEPTIONS=0 Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via `-fno-exceptions`). Disabling exceptions will force contract violation to use termination, see [contract violation macros](#contract-violation-response-macros). Default is undefined. ### Provide construction from std::initializer_list (p2447) -Dspan_FEATURE_WITH_INITIALIZER_LIST_P2447=0 Define this to 1 to enable constructing a span from a std::initializer_list<> as a constant set of values. See proposal [p2447](https://wg21.link/p2447). Default is undefined. ### Provide construction using `with_container_t` -Dspan_FEATURE_WITH_CONTAINER=0 Define this to 1 to enable constructing a span using `with_container_t`. Note that `span_FEATURE_WITH_CONTAINER` takes precedence over `span_FEATURE_WITH_CONTAINER_TO_STD`. Default is undefined. -Dspan_FEATURE_WITH_CONTAINER_TO_STD=*n* Define this to the highest C++ language version for which to enable constructing a span using `with_container_t`, like 98, 03, 11, 14, 17, 20. You can use 99 for inclusion with any standard, but prefer to use `span_FEATURE_WITH_CONTAINER` for this. Note that `span_FEATURE_WITH_CONTAINER` takes precedence over `span_FEATURE_WITH_CONTAINER_TO_STD`. Default is undefined. ### Provide construction from `std::array` with const data -Dspan_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE=0 Define this to 1 to enable constructing a span from a std::array with const data. Default is undefined. ### Provide `operator()` member function -Dspan_FEATURE_MEMBER_CALL_OPERATOR=0 Define this to 1 to provide member function `operator()`for element access. It is equivalent to `operator[]` and has been marked `[[deprecated]]`. Its main purpose is to provide a migration path. Default is undefined. ### Provide `at()` member function -Dspan_FEATURE_MEMBER_AT=0 Define this to 1 to provide member function `at()`. Define this to 2 to include index and size in message of std::out_of_range exception. Default is undefined. ### Provide `back()` and `front()` member functions -Dspan_FEATURE_MEMBER_BACK_FRONT=1 _(on since v0.5.0)_ Define this to 0 to omit member functions `back()` and `front()`. Default is undefined. ### Provide `swap()` member function -Dspan_FEATURE_MEMBER_SWAP=0 Define this to 1 to provide member function `swap()`. Default is undefined. ### Provide `operator==()` and other comparison functions -Dspan_FEATURE_COMPARISON=0 Define this to 1 to include the comparison functions to compare the content of two spans. C++20's span does not provide comparison and _span lite_ omits comparison from v0.7.0. Default is undefined. ### Provide `same()` function -Dspan_FEATURE_SAME=0 Define this to 1 to provide function `same()` to test if two spans refer as identical spans to the same data via the same type. If `same()` is enabled, `operator==()` incorporates it in its comparison. Default is undefined. ### Provide `first()`, `last()` and `subspan()` functions -Dspan_FEATURE_NON_MEMBER_FIRST_LAST_SUB=0 Define this to 1 to enable both `span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN` and `span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER`. Default is undefined. -Dspan_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN=0 Define this to 1 to provide functions `first()`, `last()` and `subspan()` that take a `span<>` (work with C++98). This implies `span_FEATURE_MAKE_SPAN` to provide functions `make_span()` that are required for this feature. Default is undefined. -Dspan_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER=0 Define this to 1 to provide functions `first()`, `last()` and `subspan()` that take a compatible container (requires C++11). This implies `span_FEATURE_MAKE_SPAN` to provide functions `make_span()` that are required for this feature. Default is undefined. ### Provide `make_span()` functions -Dspan_FEATURE_MAKE_SPAN=0 Define this to 1 to provide creator functions `nonstd::make_span()`. This feature is implied by using `span_FEATURE_NON_MEMBER_FIRST_LAST_SUB=1`. Note that `span_FEATURE_MAKE_SPAN` takes precedence over `span_FEATURE_MAKE_SPAN_TO_STD`. Default is undefined. -Dspan_FEATURE_MAKE_SPAN_TO_STD=*n* Define this to the highest C++ language version for which to provide creator functions `nonstd::make_span()`, like 98, 03, 11, 14, 17, 20. You can use 99 for inclusion with any standard, but prefer to use `span_FEATURE_MAKE_SPAN` for this. Note that `span_FEATURE_MAKE_SPAN` takes precedence over `span_FEATURE_MAKE_SPAN_TO_STD`. Default is undefined. ### Provide `byte_span()` functions -Dspan_FEATURE_BYTE_SPAN=0 Define this to 1 to provide creator functions `nonstd::byte_span()`. Default is undefined. ### Contract violation response macros *span-lite* provides contract violation response control as suggested in proposal [N4415](http://wg21.link/n4415). \-Dspan\_CONFIG\_CONTRACT\_LEVEL\_ON (*default*) Define this macro to include both `span_EXPECTS` and `span_ENSURES` in the code. This is the default case. \-Dspan\_CONFIG\_CONTRACT\_LEVEL\_OFF Define this macro to exclude both `span_EXPECTS` and `span_ENSURES` from the code. \-Dspan\_CONFIG_CONTRACT\_LEVEL\_EXPECTS\_ONLY Define this macro to include `span_EXPECTS` in the code and exclude `span_ENSURES` from the code. \-Dspan\_CONFIG\_CONTRACT\_LEVEL\_ENSURES\_ONLY Define this macro to exclude `span_EXPECTS` from the code and include `span_ENSURES` in the code. \-Dspan\_CONFIG\_CONTRACT\_VIOLATION\_TERMINATES (*default*) Define this macro to call `std::terminate()` on a contract violation in `span_EXPECTS`, `span_ENSURES`. This is the default case. \-Dspan\_CONFIG\_CONTRACT\_VIOLATION\_THROWS Define this macro to throw an exception of implementation-defined type that is derived from `std::runtime_exception` instead of calling `std::terminate()` on a contract violation in `span_EXPECTS` and `span_ENSURES`. See also [disable exceptions](#disable-exceptions). Reported to work with -------------------- The table below mentions the compiler versions *span lite* is reported to work with. OS | Compiler | Where | Versions | ------------:|:-----------|:--------|:---------| **GNU/Linux**| Clang/LLVM | Travis | 3.5.0, 3.6.2, 3.7.1, 3.8.0, 3.9.1, 4.0.1 |   | GCC | Travis | 5.5.0, 6.4.0, 7.3.0 | **OS X** | ? | Local | ? | **Windows** | Clang/LLVM | Local | 6.0.0 |   | GCC | Local | 7.2.0 |   | Visual C++
(Visual Studio)| Local | 8 (2005), 10 (2010), 11 (2012),
12 (2013), 14 (2015), 15 (2017) |   | Visual C++
(Visual Studio)| AppVeyor | 10 (2010), 11 (2012),
12 (2013), 14 (2015), 15 (2017) | ## Building the tests To build the tests you need: - [CMake](http://cmake.org), version 3.0 or later to be installed and in your PATH. - A [suitable compiler](#reported-to-work-with). The [*lest* test framework](https://github.com/martinmoene/lest) is included in the [test folder](test). The following steps assume that the [*span lite* source code](https://github.com/martinmoene/span-lite) has been cloned into a directory named `./span-lite`. 1. Create a directory for the build outputs. cd ./span-lite md build && cd build 2. Configure CMake to use the compiler of your choice (run `cmake --help` for a list). cmake -G "Unix Makefiles" -DSPAN_LITE_OPT_BUILD_TESTS=ON .. 3. Optional. You can control above configuration through the following options: `-DSPAN_LITE_OPT_BUILD_TESTS=ON`: build the tests for span, default off `-DSPAN_LITE_OPT_BUILD_EXAMPLES=OFF`: build the examples, default off 4. Build the test suite. cmake --build . 5. Run the test suite. ctest -V All tests should pass, indicating your platform is supported and you are ready to use *span lite*. ## Other implementations of span - *gsl-lite* [span](https://github.com/martinmoene/gsl-lite/blob/73c4f16f2b35fc174fc2f09d44d5ab13e5c638c3/include/gsl/gsl-lite.hpp#L1221). - Microsoft GSL [span](https://github.com/Microsoft/GSL/blob/master/include/gsl/span). - Google Abseil [span](https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h). - Marshall Clow's [libc++ span snippet](https://github.com/mclow/snippets/blob/master/span.cpp). - Tristan Brindle's [Implementation of C++20's std::span for older compilers](https://github.com/tcbrindle/span). - [Search _span c++_ on GitHub](https://github.com/search?l=C%2B%2B&q=span+c%2B%2B&type=Repositories&utf8=%E2%9C%93). ## Notes and references *Interface and specification* - [span on cppreference](https://en.cppreference.com/w/cpp/container/span). - [p0122 - C++20 Proposal](http://wg21.link/p0122). - [span in C++20 Working Draft](http://eel.is/c++draft/views). *Presentations* - TBD *Proposals* - [p0122 - span: bounds-safe views for sequences of objects](http://wg21.link/p0122). - [p1024 - Usability Enhancements for std::span](http://wg21.link/p1024). - [p1419 - A SFINAE-friendly trait to determine the extent of statically sized containers](http://wg21.link/p1419). - [p0805 - Comparing Containers](http://wg21.link/p0805). - [p1085 - Should Span be Regular?](http://wg21.link/p0805). - [p0091 - Template argument deduction for class templates](http://wg21.link/p0091). - [p0856 - Restrict Access Property for mdspan and span](http://wg21.link/p0856). - [p1428 - Subscripts and sizes should be signed](http://wg21.link/p1428). - [p1089 - Sizes Should Only span Unsigned](http://wg21.link/p1089). - [p1227 - Signed size() functions](http://wg21.link/p1227). - [p1872 - span should have size_type, not index_type](http://wg21.link/p1872). - [p2447 - std::span and the missing constructor](https://wg21.link/p2447). - [lwg 3101 - span's Container constructors need another constraint](https://cplusplus.github.io/LWG/issue3101). - [Reddit - 2018-06 Rapperswil ISO C++ Committee Trip Report](https://www.reddit.com/r/cpp/comments/8prqzm/2018_rapperswil_iso_c_committee_trip_report/) - [Reddit - 2018-11 San Diego ISO C++ Committee Trip Report](https://www.reddit.com/r/cpp/comments/9vwvbz/2018_san_diego_iso_c_committee_trip_report_ranges/). - [Reddit - 2019-02 Kona ISO C++ Committee Trip Report](https://www.reddit.com/r/cpp/comments/au0c4x/201902_kona_iso_c_committee_trip_report_c20/). - [Reddit - 2019-07 Cologne ISO C++ Committee Trip Report](https://www.reddit.com/r/cpp/comments/cfk9de/201907_cologne_iso_c_committee_trip_report_the/) - [Reddit - 2019-11 Belfast ISO C++ Committee Trip Report](https://www.reddit.com/r/cpp/comments/dtuov8/201911_belfast_iso_c_committee_trip_report/) - Titus Winters. [Revisiting Regular Types](https://abseil.io/blog/20180531-regular-types). Abseil Blog. 31 May 2018. ## Appendix ### A.1 Compile-time information The version of *span lite* is available via tag `[.version]`. The following tags are available for information on the compiler and on the C++ standard library used: `[.compiler]`, `[.stdc++]`, `[.stdlanguage]` and `[.stdlibrary]`. ### A.2 Span lite test specification
click to expand

```Text span<>: Terminates construction from a nullptr and a non-zero size (C++11) span<>: Terminates construction from two pointers in the wrong order span<>: Terminates construction from a null pointer and a non-zero size span<>: Terminates creation of a sub span of the first n elements for n exceeding the span span<>: Terminates creation of a sub span of the last n elements for n exceeding the span span<>: Terminates creation of a sub span outside the span span<>: Terminates access outside the span span<>: Throws on access outside the span via at(): std::out_of_range [span_FEATURE_MEMBER_AT>0][span_CONFIG_NO_EXCEPTIONS=0] span<>: Termination throws std::logic_error-derived exception [span_CONFIG_CONTRACT_VIOLATION_THROWS=1] span<>: Allows to default-construct span<>: Allows to construct from a nullptr and a zero size (C++11) span<>: Allows to construct from two pointers span<>: Allows to construct from two iterators span<>: Allows to construct from two iterators - empty range span<>: Allows to construct from two iterators - move-only element span<>: Allows to construct from an iterator and a size span<>: Allows to construct from an iterator and a size - empty range span<>: Allows to construct from an iterator and a size - move-only element span<>: Allows to construct from two pointers to const span<>: Allows to construct from a non-null pointer and a size span<>: Allows to construct from a non-null pointer to const and a size span<>: Allows to construct from a temporary pointer and a size span<>: Allows to construct from a temporary pointer to const and a size span<>: Allows to construct from any pointer and a zero size (C++98) span<>: Allows to construct from a pointer and a size via a deduction guide (C++17) span<>: Allows to construct from an iterator and a size via a deduction guide (C++17) span<>: Allows to construct from two iterators via a deduction guide (C++17) span<>: Allows to construct from a C-array span<>: Allows to construct from a C-array via a deduction guide (C++17) span<>: Allows to construct from a const C-array span<>: Allows to construct from a C-array with size via decay to pointer (potentially dangerous) span<>: Allows to construct from a const C-array with size via decay to pointer (potentially dangerous) span<>: Allows to construct from a std::initializer_list<> (C++11) span<>: Allows to construct from a std::initializer_list<> as a constant set of values (C++11, p2447) span<>: Allows to construct from a std::array<> (C++11) span<>: Allows to construct from a std::array via a deduction guide (C++17) span<>: Allows to construct from a std::array<> with const data (C++11, span_FEATURE_CONSTR..._ELEMENT_TYPE=1) span<>: Allows to construct from an empty std::array<> (C++11) span<>: Allows to construct from a container (std::vector<>) span<>: Allows to construct from a container via a deduction guide (std::vector<>, C++17) span<>: Allows to tag-construct from a container (std::vector<>) span<>: Allows to tag-construct from a const container (std::vector<>) span<>: Allows to copy-construct from another span of the same type span<>: Allows to copy-construct from another span of a compatible type span<>: Allows to copy-construct from a temporary span of the same type (C++11) span<>: Allows to copy-assign from another span of the same type span<>: Allows to copy-assign from a temporary span of the same type (C++11) span<>: Allows to create a sub span of the first n elements span<>: Allows to create a sub span of the last n elements span<>: Allows to create a sub span starting at a given offset span<>: Allows to create a sub span starting at a given offset with a given length span<>: Allows to observe an element via array indexing span<>: Allows to observe an element via call indexing span<>: Allows to observe an element via at() [span_FEATURE_MEMBER_AT>0] span<>: Allows to observe an element via data() span<>: Allows to observe the first element via front() [span_FEATURE_MEMBER_BACK_FRONT=1] span<>: Allows to observe the last element via back() [span_FEATURE_MEMBER_BACK_FRONT=1] span<>: Allows to change an element via array indexing span<>: Allows to change an element via call indexing span<>: Allows to change an element via at() [span_FEATURE_MEMBER_AT>0] span<>: Allows to change an element via data() span<>: Allows to change the first element via front() [span_FEATURE_MEMBER_BACK_FRONT=1] span<>: Allows to change the last element via back() [span_FEATURE_MEMBER_BACK_FRONT=1] span<>: Allows to swap with another span [span_FEATURE_MEMBER_SWAP=1] span<>: Allows forward iteration span<>: Allows const forward iteration span<>: Allows reverse iteration span<>: Allows const reverse iteration span<>: Allows to identify if a span is the same as another span [span_FEATURE_SAME=1] span<>: Allows to compare equal to another span of the same type [span_FEATURE_COMPARISON=1] span<>: Allows to compare unequal to another span of the same type [span_FEATURE_COMPARISON=1] span<>: Allows to compare less than another span of the same type [span_FEATURE_COMPARISON=1] span<>: Allows to compare less than or equal to another span of the same type [span_FEATURE_COMPARISON=1] span<>: Allows to compare greater than another span of the same type [span_FEATURE_COMPARISON=1] span<>: Allows to compare greater than or equal to another span of the same type [span_FEATURE_COMPARISON=1] span<>: Allows to compare to another span of the same type and different cv-ness [span_FEATURE_SAME=0] span<>: Allows to compare empty spans as equal [span_FEATURE_COMPARISON=1] span<>: Allows to test for empty span via empty(), empty case span<>: Allows to test for empty span via empty(), non-empty case span<>: Allows to obtain the number of elements via size() span<>: Allows to obtain the number of elements via ssize() span<>: Allows to obtain the number of bytes via size_bytes() span<>: Allows to view the elements as read-only bytes span<>: Allows to view and change the elements as writable bytes make_span() [span_FEATURE_MAKE_SPAN_TO_STD=99] make_span(): Allows building from two pointers make_span(): Allows building from two const pointers make_span(): Allows building from a non-null pointer and a size make_span(): Allows building from a non-null const pointer and a size make_span(): Allows building from a C-array make_span(): Allows building from a const C-array make_span(): Allows building from a std::initializer_list<> (C++11) make_span(): Allows building from a std::initializer_list<> as a constant set of values (C++11) make_span(): Allows building from a std::array<> (C++11) make_span(): Allows building from a const std::array<> (C++11) make_span(): Allows building from a container (std::vector<>) make_span(): Allows building from a const container (std::vector<>) make_span(): Allows building from a container (with_container_t, std::vector<>) make_span(): Allows building from a const container (with_container_t, std::vector<>) byte_span() [span_FEATURE_BYTE_SPAN=1] byte_span(): Allows building a span of std::byte from a single object (C++17, byte-lite) byte_span(): Allows building a span of const std::byte from a single const object (C++17, byte-lite) first(), last(), subspan() [span_FEATURE_NON_MEMBER_FIRST_LAST_SUB=1] first(): Allows to create a sub span of the first n elements (span, template parameter) first(): Allows to create a sub span of the first n elements (span, function parameter) first(): Allows to create a sub span of the first n elements (compatible container, template parameter) first(): Allows to create a sub span of the first n elements (compatible container, function parameter) last(): Allows to create a sub span of the last n elements (span, template parameter) last(): Allows to create a sub span of the last n elements (span, function parameter) last(): Allows to create a sub span of the last n elements (compatible container, template parameter) last(): Allows to create a sub span of the last n elements (compatible container, function parameter) subspan(): Allows to create a sub span starting at a given offset (span, template parameter) subspan(): Allows to create a sub span starting at a given offset (span, function parameter) subspan(): Allows to create a sub span starting at a given offset (compatible container, template parameter) subspan(): Allows to create a sub span starting at a given offset (compatible container, function parameter) size(): Allows to obtain the number of elements via size() ssize(): Allows to obtain the number of elements via ssize() tuple_size<>: Allows to obtain the number of elements via std::tuple_size<> (C++11) tuple_element<>: Allows to obtain an element via std::tuple_element<> (C++11) tuple_element<>: Allows to obtain an element via std::tuple_element_t<> (C++11) get(spn): Allows to access an element via std::get<>() tweak header: reads tweak header if supported [tweak] ```

qbs-src-2.6.1/src/shared/span/.clang-format0000644000175100001660000000005014776170045020014 0ustar runnerdockerDisableFormat: true SortIncludes: Never qbs-src-2.6.1/src/shared/span/span.qbs0000644000175100001660000000034214776170045017115 0ustar runnerdockerProduct { name: "span" files: [ "LICENSE_1_0.txt", "README.md", "span.hpp", ] Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.sourceDirectory } } qbs-src-2.6.1/src/shared/span/span.hpp0000644000175100001660000015331314776170045017126 0ustar runnerdocker// // span for C++98 and later. // Based on http://wg21.link/p0122r7 // For more information see https://github.com/martinmoene/span-lite // // Copyright 2018-2021 Martin Moene // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef NONSTD_SPAN_HPP_INCLUDED #define NONSTD_SPAN_HPP_INCLUDED #define span_lite_MAJOR 0 #define span_lite_MINOR 11 #define span_lite_PATCH 0 #define span_lite_VERSION span_STRINGIFY(span_lite_MAJOR) "." span_STRINGIFY(span_lite_MINOR) "." span_STRINGIFY(span_lite_PATCH) #define span_STRINGIFY( x ) span_STRINGIFY_( x ) #define span_STRINGIFY_( x ) #x // span configuration: #define span_SPAN_DEFAULT 0 #define span_SPAN_NONSTD 1 #define span_SPAN_STD 2 // tweak header support: #ifdef __has_include # if __has_include() # include # endif #define span_HAVE_TWEAK_HEADER 1 #else #define span_HAVE_TWEAK_HEADER 0 //# pragma message("span.hpp: Note: Tweak header not supported.") #endif // span selection and configuration: #define span_HAVE( feature ) ( span_HAVE_##feature ) #ifndef span_CONFIG_SELECT_SPAN # define span_CONFIG_SELECT_SPAN ( span_HAVE_STD_SPAN ? span_SPAN_STD : span_SPAN_NONSTD ) #endif #ifndef span_CONFIG_EXTENT_TYPE # define span_CONFIG_EXTENT_TYPE std::size_t #endif #ifndef span_CONFIG_SIZE_TYPE # define span_CONFIG_SIZE_TYPE std::size_t #endif #ifdef span_CONFIG_INDEX_TYPE # error `span_CONFIG_INDEX_TYPE` is deprecated since v0.7.0; it is replaced by `span_CONFIG_SIZE_TYPE`. #endif // span configuration (features): #ifndef span_FEATURE_WITH_INITIALIZER_LIST_P2447 # define span_FEATURE_WITH_INITIALIZER_LIST_P2447 0 #endif #ifndef span_FEATURE_WITH_CONTAINER #ifdef span_FEATURE_WITH_CONTAINER_TO_STD # define span_FEATURE_WITH_CONTAINER span_IN_STD( span_FEATURE_WITH_CONTAINER_TO_STD ) #else # define span_FEATURE_WITH_CONTAINER 0 # define span_FEATURE_WITH_CONTAINER_TO_STD 0 #endif #endif #ifndef span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE # define span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE 0 #endif #ifndef span_FEATURE_MEMBER_AT # define span_FEATURE_MEMBER_AT 0 #endif #ifndef span_FEATURE_MEMBER_BACK_FRONT # define span_FEATURE_MEMBER_BACK_FRONT 1 #endif #ifndef span_FEATURE_MEMBER_CALL_OPERATOR # define span_FEATURE_MEMBER_CALL_OPERATOR 0 #endif #ifndef span_FEATURE_MEMBER_SWAP # define span_FEATURE_MEMBER_SWAP 0 #endif #ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB # define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB 0 #elif span_FEATURE_NON_MEMBER_FIRST_LAST_SUB # define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN 1 # define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER 1 #endif #ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN # define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN 0 #endif #ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER # define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER 0 #endif #ifndef span_FEATURE_COMPARISON # define span_FEATURE_COMPARISON 0 // Note: C++20 does not provide comparison #endif #ifndef span_FEATURE_SAME # define span_FEATURE_SAME 0 #endif #if span_FEATURE_SAME && !span_FEATURE_COMPARISON # error `span_FEATURE_SAME` requires `span_FEATURE_COMPARISON` #endif #ifndef span_FEATURE_MAKE_SPAN #ifdef span_FEATURE_MAKE_SPAN_TO_STD # define span_FEATURE_MAKE_SPAN span_IN_STD( span_FEATURE_MAKE_SPAN_TO_STD ) #else # define span_FEATURE_MAKE_SPAN 0 # define span_FEATURE_MAKE_SPAN_TO_STD 0 #endif #endif #ifndef span_FEATURE_BYTE_SPAN # define span_FEATURE_BYTE_SPAN 0 #endif // Control presence of exception handling (try and auto discover): #ifndef span_CONFIG_NO_EXCEPTIONS # if defined(_MSC_VER) # include // for _HAS_EXCEPTIONS # endif # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) # define span_CONFIG_NO_EXCEPTIONS 0 # else # define span_CONFIG_NO_EXCEPTIONS 1 # undef span_CONFIG_CONTRACT_VIOLATION_THROWS # undef span_CONFIG_CONTRACT_VIOLATION_TERMINATES # define span_CONFIG_CONTRACT_VIOLATION_THROWS 0 # define span_CONFIG_CONTRACT_VIOLATION_TERMINATES 1 # endif #endif // Control pre- and postcondition violation behaviour: #if defined( span_CONFIG_CONTRACT_LEVEL_ON ) # define span_CONFIG_CONTRACT_LEVEL_MASK 0x11 #elif defined( span_CONFIG_CONTRACT_LEVEL_OFF ) # define span_CONFIG_CONTRACT_LEVEL_MASK 0x00 #elif defined( span_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) # define span_CONFIG_CONTRACT_LEVEL_MASK 0x01 #elif defined( span_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) # define span_CONFIG_CONTRACT_LEVEL_MASK 0x10 #else # define span_CONFIG_CONTRACT_LEVEL_MASK 0x11 #endif #if defined( span_CONFIG_CONTRACT_VIOLATION_THROWS ) # define span_CONFIG_CONTRACT_VIOLATION_THROWS_V span_CONFIG_CONTRACT_VIOLATION_THROWS #else # define span_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 #endif #if defined( span_CONFIG_CONTRACT_VIOLATION_THROWS ) && span_CONFIG_CONTRACT_VIOLATION_THROWS && \ defined( span_CONFIG_CONTRACT_VIOLATION_TERMINATES ) && span_CONFIG_CONTRACT_VIOLATION_TERMINATES # error Please define none or one of span_CONFIG_CONTRACT_VIOLATION_THROWS and span_CONFIG_CONTRACT_VIOLATION_TERMINATES to 1, but not both. #endif // C++ language version detection (C++23 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. #ifndef span_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) # define span_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) # else # define span_CPLUSPLUS __cplusplus # endif #endif #define span_CPP98_OR_GREATER ( span_CPLUSPLUS >= 199711L ) #define span_CPP11_OR_GREATER ( span_CPLUSPLUS >= 201103L ) #define span_CPP14_OR_GREATER ( span_CPLUSPLUS >= 201402L ) #define span_CPP17_OR_GREATER ( span_CPLUSPLUS >= 201703L ) #define span_CPP20_OR_GREATER ( span_CPLUSPLUS >= 202002L ) #define span_CPP23_OR_GREATER ( span_CPLUSPLUS >= 202300L ) // C++ language version (represent 98 as 3): #define span_CPLUSPLUS_V ( span_CPLUSPLUS / 100 - (span_CPLUSPLUS > 200000 ? 2000 : 1994) ) #define span_IN_STD( v ) ( ((v) == 98 ? 3 : (v)) >= span_CPLUSPLUS_V ) #define span_CONFIG( feature ) ( span_CONFIG_##feature ) #define span_FEATURE( feature ) ( span_FEATURE_##feature ) #define span_FEATURE_TO_STD( feature ) ( span_IN_STD( span_FEATURE( feature##_TO_STD ) ) ) // Use C++20 std::span if available and requested: #if span_CPP20_OR_GREATER && defined(__has_include ) # if __has_include( ) # define span_HAVE_STD_SPAN 1 # else # define span_HAVE_STD_SPAN 0 # endif #else # define span_HAVE_STD_SPAN 0 #endif #define span_USES_STD_SPAN ( (span_CONFIG_SELECT_SPAN == span_SPAN_STD) || ((span_CONFIG_SELECT_SPAN == span_SPAN_DEFAULT) && span_HAVE_STD_SPAN) ) // // Use C++20 std::span: // #if span_USES_STD_SPAN #include namespace nonstd { using std::span; using std::dynamic_extent; // Note: C++20 does not provide comparison // using std::operator==; // using std::operator!=; // using std::operator<; // using std::operator<=; // using std::operator>; // using std::operator>=; } // namespace nonstd #else // span_USES_STD_SPAN #include // Compiler versions: // // MSVC++ 6.0 _MSC_VER == 1200 span_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) // MSVC++ 7.0 _MSC_VER == 1300 span_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) // MSVC++ 7.1 _MSC_VER == 1310 span_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) // MSVC++ 8.0 _MSC_VER == 1400 span_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) // MSVC++ 9.0 _MSC_VER == 1500 span_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) // MSVC++ 10.0 _MSC_VER == 1600 span_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) // MSVC++ 11.0 _MSC_VER == 1700 span_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) // MSVC++ 12.0 _MSC_VER == 1800 span_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) // MSVC++ 14.0 _MSC_VER == 1900 span_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 span_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) // MSVC++ 14.2 _MSC_VER >= 1920 span_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) #if defined(_MSC_VER ) && !defined(__clang__) # define span_COMPILER_MSVC_VER (_MSC_VER ) # define span_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) #else # define span_COMPILER_MSVC_VER 0 # define span_COMPILER_MSVC_VERSION 0 #endif #define span_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) #if defined(__clang__) # define span_COMPILER_CLANG_VERSION span_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else # define span_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) # define span_COMPILER_GNUC_VERSION span_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else # define span_COMPILER_GNUC_VERSION 0 #endif // half-open range [lo..hi): #define span_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Compiler warning suppression: #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wundef" # pragma clang diagnostic ignored "-Wmismatched-tags" # define span_RESTORE_WARNINGS() _Pragma( "clang diagnostic pop" ) #elif defined __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wundef" # define span_RESTORE_WARNINGS() _Pragma( "GCC diagnostic pop" ) #elif span_COMPILER_MSVC_VER >= 1900 # define span_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) # define span_RESTORE_WARNINGS() __pragma(warning(pop )) // Suppress the following MSVC GSL warnings: // - C26439, gsl::f.6 : special function 'function' can be declared 'noexcept' // - C26440, gsl::f.6 : function 'function' can be declared 'noexcept' // - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions; // use brace initialization, gsl::narrow_cast or gsl::narrow // - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same // - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead // - C26490: gsl::t.1 : don't use reinterpret_cast span_DISABLE_MSVC_WARNINGS( 26439 26440 26472 26473 26481 26490 ) #else # define span_RESTORE_WARNINGS() /*empty*/ #endif // Presence of language and library features: #ifdef _HAS_CPP0X # define span_HAS_CPP0X _HAS_CPP0X #else # define span_HAS_CPP0X 0 #endif #define span_CPP11_80 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1400) #define span_CPP11_90 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1500) #define span_CPP11_100 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1600) #define span_CPP11_110 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1700) #define span_CPP11_120 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1800) #define span_CPP11_140 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1900) #define span_CPP14_000 (span_CPP14_OR_GREATER) #define span_CPP14_120 (span_CPP14_OR_GREATER || span_COMPILER_MSVC_VER >= 1800) #define span_CPP14_140 (span_CPP14_OR_GREATER || span_COMPILER_MSVC_VER >= 1900) #define span_CPP17_000 (span_CPP17_OR_GREATER) // Presence of C++11 language features: #define span_HAVE_ALIAS_TEMPLATE span_CPP11_140 #define span_HAVE_AUTO span_CPP11_100 #define span_HAVE_CONSTEXPR_11 span_CPP11_140 #define span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG span_CPP11_120 #define span_HAVE_EXPLICIT_CONVERSION span_CPP11_140 #define span_HAVE_INITIALIZER_LIST span_CPP11_120 #define span_HAVE_IS_DEFAULT span_CPP11_140 #define span_HAVE_IS_DELETE span_CPP11_140 #define span_HAVE_NOEXCEPT span_CPP11_140 #define span_HAVE_NORETURN ( span_CPP11_140 && ! span_BETWEEN( span_COMPILER_GNUC_VERSION, 1, 480 ) ) #define span_HAVE_NULLPTR span_CPP11_100 #define span_HAVE_STATIC_ASSERT span_CPP11_100 // Presence of C++14 language features: #define span_HAVE_CONSTEXPR_14 span_CPP14_000 // Presence of C++17 language features: #define span_HAVE_DEPRECATED span_CPP17_000 #define span_HAVE_NODISCARD span_CPP17_000 // MSVC: template parameter deduction guides since Visual Studio 2017 v15.7 #if defined(__cpp_deduction_guides) # define span_HAVE_DEDUCTION_GUIDES 1 #else # define span_HAVE_DEDUCTION_GUIDES (span_CPP17_OR_GREATER && ! span_BETWEEN( span_COMPILER_MSVC_VER, 1, 1913 )) #endif // Presence of C++ library features: #define span_HAVE_ADDRESSOF span_CPP17_000 #define span_HAVE_ARRAY span_CPP11_110 #define span_HAVE_BYTE span_CPP17_000 #define span_HAVE_CONDITIONAL span_CPP11_120 #define span_HAVE_CONTAINER_DATA_METHOD (span_CPP11_140 || ( span_COMPILER_MSVC_VER >= 1500 && span_HAS_CPP0X )) #define span_HAVE_DATA span_CPP17_000 #define span_HAVE_LONGLONG span_CPP11_80 #define span_HAVE_REMOVE_CONST span_CPP11_110 #define span_HAVE_SNPRINTF span_CPP11_140 #define span_HAVE_STRUCT_BINDING span_CPP11_120 #define span_HAVE_TYPE_TRAITS span_CPP11_90 // Presence of byte-lite: #ifdef NONSTD_BYTE_LITE_HPP # define span_HAVE_NONSTD_BYTE 1 #else # define span_HAVE_NONSTD_BYTE 0 #endif // C++ feature usage: #if span_HAVE_ADDRESSOF # define span_ADDRESSOF(x) std::addressof(x) #else # define span_ADDRESSOF(x) (&x) #endif #if span_HAVE_CONSTEXPR_11 # define span_constexpr constexpr #else # define span_constexpr /*span_constexpr*/ #endif #if span_HAVE_CONSTEXPR_14 # define span_constexpr14 constexpr #else # define span_constexpr14 /*span_constexpr*/ #endif #if span_HAVE_EXPLICIT_CONVERSION # define span_explicit explicit #else # define span_explicit /*explicit*/ #endif #if span_HAVE_IS_DELETE # define span_is_delete = delete #else # define span_is_delete #endif #if span_HAVE_IS_DELETE # define span_is_delete_access public #else # define span_is_delete_access private #endif #if span_HAVE_NOEXCEPT && ! span_CONFIG_CONTRACT_VIOLATION_THROWS_V # define span_noexcept noexcept #else # define span_noexcept /*noexcept*/ #endif #if span_HAVE_NULLPTR # define span_nullptr nullptr #else # define span_nullptr NULL #endif #if span_HAVE_DEPRECATED # define span_deprecated(msg) [[deprecated(msg)]] #else # define span_deprecated(msg) /*[[deprecated]]*/ #endif #if span_HAVE_NODISCARD # define span_nodiscard [[nodiscard]] #else # define span_nodiscard /*[[nodiscard]]*/ #endif #if span_HAVE_NORETURN # define span_noreturn [[noreturn]] #else # define span_noreturn /*[[noreturn]]*/ #endif // Other features: #define span_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG #define span_HAVE_ITERATOR_CTOR span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG // Additional includes: #if span_HAVE( ADDRESSOF ) # include #endif #if span_HAVE( ARRAY ) # include #endif #if span_HAVE( BYTE ) # include #endif #if span_HAVE( DATA ) # include // for std::data(), std::size() #endif #if span_HAVE( TYPE_TRAITS ) # include #endif #if ! span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) # include #endif #if span_FEATURE( MEMBER_AT ) > 1 # include #endif #if ! span_CONFIG( NO_EXCEPTIONS ) # include #endif // Contract violation #define span_ELIDE_CONTRACT_EXPECTS ( 0 == ( span_CONFIG_CONTRACT_LEVEL_MASK & 0x01 ) ) #define span_ELIDE_CONTRACT_ENSURES ( 0 == ( span_CONFIG_CONTRACT_LEVEL_MASK & 0x10 ) ) #if span_ELIDE_CONTRACT_EXPECTS # define span_constexpr_exp span_constexpr # define span_EXPECTS( cond ) /* Expect elided */ #else # define span_constexpr_exp span_constexpr14 # define span_EXPECTS( cond ) span_CONTRACT_CHECK( "Precondition", cond ) #endif #if span_ELIDE_CONTRACT_ENSURES # define span_constexpr_ens span_constexpr # define span_ENSURES( cond ) /* Ensures elided */ #else # define span_constexpr_ens span_constexpr14 # define span_ENSURES( cond ) span_CONTRACT_CHECK( "Postcondition", cond ) #endif #define span_CONTRACT_CHECK( type, cond ) \ cond ? static_cast< void >( 0 ) \ : nonstd::span_lite::detail::report_contract_violation( span_LOCATION( __FILE__, __LINE__ ) ": " type " violation." ) #ifdef __GNUG__ # define span_LOCATION( file, line ) file ":" span_STRINGIFY( line ) #else # define span_LOCATION( file, line ) file "(" span_STRINGIFY( line ) ")" #endif // Method enabling #if span_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) #define span_REQUIRES_0(VA) \ template< bool B = (VA), typename std::enable_if::type = 0 > # if span_BETWEEN( span_COMPILER_MSVC_VERSION, 1, 140 ) // VS 2013 and earlier seem to have trouble with SFINAE for default non-type arguments # define span_REQUIRES_T(VA) \ , typename = typename std::enable_if< ( VA ), nonstd::span_lite::detail::enabler >::type # else # define span_REQUIRES_T(VA) \ , typename std::enable_if< (VA), int >::type = 0 # endif #define span_REQUIRES_R(R, VA) \ typename std::enable_if< (VA), R>::type #define span_REQUIRES_A(VA) \ , typename std::enable_if< (VA), void*>::type = nullptr #else # define span_REQUIRES_0(VA) /*empty*/ # define span_REQUIRES_T(VA) /*empty*/ # define span_REQUIRES_R(R, VA) R # define span_REQUIRES_A(VA) /*empty*/ #endif namespace nonstd { namespace span_lite { // [views.constants], constants typedef span_CONFIG_EXTENT_TYPE extent_t; typedef span_CONFIG_SIZE_TYPE size_t; span_constexpr const extent_t dynamic_extent = static_cast( -1 ); template< class T, extent_t Extent = dynamic_extent > class span; // Tag to select span constructor taking a container (prevent ms-gsl warning C26426): struct with_container_t { span_constexpr with_container_t() span_noexcept {} }; const span_constexpr with_container_t with_container; // C++11 emulation: namespace std11 { #if span_HAVE( REMOVE_CONST ) using std::remove_cv; using std::remove_const; using std::remove_volatile; #else template< class T > struct remove_const { typedef T type; }; template< class T > struct remove_const< T const > { typedef T type; }; template< class T > struct remove_volatile { typedef T type; }; template< class T > struct remove_volatile< T volatile > { typedef T type; }; template< class T > struct remove_cv { typedef typename std11::remove_volatile< typename std11::remove_const< T >::type >::type type; }; #endif // span_HAVE( REMOVE_CONST ) #if span_HAVE( TYPE_TRAITS ) using std::is_same; using std::is_signed; using std::integral_constant; using std::true_type; using std::false_type; using std::remove_reference; #else template< class T, T v > struct integral_constant { enum { value = v }; }; typedef integral_constant< bool, true > true_type; typedef integral_constant< bool, false > false_type; template< class T, class U > struct is_same : false_type{}; template< class T > struct is_same : true_type{}; template< typename T > struct is_signed : false_type {}; template<> struct is_signed : true_type {}; template<> struct is_signed : true_type {}; template<> struct is_signed : true_type {}; #endif } // namespace std11 // C++17 emulation: namespace std17 { template< bool v > struct bool_constant : std11::integral_constant{}; #if span_CPP11_120 template< class...> using void_t = void; #endif #if span_HAVE( DATA ) using std::data; using std::size; #elif span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) template< typename T, std::size_t N > inline span_constexpr auto size( const T(&)[N] ) span_noexcept -> size_t { return N; } template< typename C > inline span_constexpr auto size( C const & cont ) -> decltype( cont.size() ) { return cont.size(); } template< typename T, std::size_t N > inline span_constexpr auto data( T(&arr)[N] ) span_noexcept -> T* { return &arr[0]; } template< typename C > inline span_constexpr auto data( C & cont ) -> decltype( cont.data() ) { return cont.data(); } template< typename C > inline span_constexpr auto data( C const & cont ) -> decltype( cont.data() ) { return cont.data(); } template< typename E > inline span_constexpr auto data( std::initializer_list il ) span_noexcept -> E const * { return il.begin(); } #endif // span_HAVE( DATA ) #if span_HAVE( BYTE ) using std::byte; #elif span_HAVE( NONSTD_BYTE ) using nonstd::byte; #endif } // namespace std17 // C++20 emulation: namespace std20 { #if span_HAVE( DEDUCTION_GUIDES ) template< class T > using iter_reference_t = decltype( *std::declval() ); #endif } // namespace std20 // Implementation details: namespace detail { /*enum*/ struct enabler{}; template< typename T > span_constexpr bool is_positive( T x ) { return std11::is_signed::value ? x >= 0 : true; } #if span_HAVE( TYPE_TRAITS ) template< class Q > struct is_span_oracle : std::false_type{}; template< class T, span_CONFIG_EXTENT_TYPE Extent > struct is_span_oracle< span > : std::true_type{}; template< class Q > struct is_span : is_span_oracle< typename std::remove_cv::type >{}; template< class Q > struct is_std_array_oracle : std::false_type{}; #if span_HAVE( ARRAY ) template< class T, std::size_t Extent > struct is_std_array_oracle< std::array > : std::true_type{}; #endif template< class Q > struct is_std_array : is_std_array_oracle< typename std::remove_cv::type >{}; template< class Q > struct is_array : std::false_type {}; template< class T > struct is_array : std::true_type {}; template< class T, std::size_t N > struct is_array : std::true_type {}; #if span_CPP11_140 && ! span_BETWEEN( span_COMPILER_GNUC_VERSION, 1, 500 ) template< class, class = void > struct has_size_and_data : std::false_type{}; template< class C > struct has_size_and_data < C, std17::void_t< decltype( std17::size(std::declval()) ), decltype( std17::data(std::declval()) ) > > : std::true_type{}; template< class, class, class = void > struct is_compatible_element : std::false_type {}; template< class C, class E > struct is_compatible_element < C, E, std17::void_t< decltype( std17::data(std::declval()) ) > > : std::is_convertible< typename std::remove_pointer() ) )>::type(*)[], E(*)[] >{}; template< class C > struct is_container : std17::bool_constant < ! is_span< C >::value && ! is_array< C >::value && ! is_std_array< C >::value && has_size_and_data< C >::value >{}; template< class C, class E > struct is_compatible_container : std17::bool_constant < is_container::value && is_compatible_element::value >{}; #else // span_CPP11_140 template< class C, class E span_REQUIRES_T(( ! is_span< C >::value && ! is_array< C >::value && ! is_std_array< C >::value && ( std::is_convertible< typename std::remove_pointer() ) )>::type(*)[], E(*)[] >::value) // && has_size_and_data< C >::value )) , class = decltype( std17::size(std::declval()) ) , class = decltype( std17::data(std::declval()) ) > struct is_compatible_container : std::true_type{}; #endif // span_CPP11_140 #endif // span_HAVE( TYPE_TRAITS ) #if ! span_CONFIG( NO_EXCEPTIONS ) #if span_FEATURE( MEMBER_AT ) > 1 // format index and size: #if defined(__clang__) # pragma clang diagnostic ignored "-Wlong-long" #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wformat=ll" # pragma GCC diagnostic ignored "-Wlong-long" #endif span_noreturn inline void throw_out_of_range( size_t idx, size_t size ) { const char fmt[] = "span::at(): index '%lli' is out of range [0..%lli)"; char buffer[ 2 * 20 + sizeof fmt ]; sprintf( buffer, fmt, static_cast(idx), static_cast(size) ); throw std::out_of_range( buffer ); } #else // MEMBER_AT span_noreturn inline void throw_out_of_range( size_t /*idx*/, size_t /*size*/ ) { throw std::out_of_range( "span::at(): index outside span" ); } #endif // MEMBER_AT #endif // NO_EXCEPTIONS #if span_CONFIG( CONTRACT_VIOLATION_THROWS_V ) struct contract_violation : std::logic_error { explicit contract_violation( char const * const message ) : std::logic_error( message ) {} }; inline void report_contract_violation( char const * msg ) { throw contract_violation( msg ); } #else // span_CONFIG( CONTRACT_VIOLATION_THROWS_V ) span_noreturn inline void report_contract_violation( char const * /*msg*/ ) span_noexcept { std::terminate(); } #endif // span_CONFIG( CONTRACT_VIOLATION_THROWS_V ) } // namespace detail // Prevent signed-unsigned mismatch: #define span_sizeof(T) static_cast( sizeof(T) ) template< class T > inline span_constexpr size_t to_size( T size ) { return static_cast( size ); } // // [views.span] - A view over a contiguous, single-dimension sequence of objects // template< class T, extent_t Extent /*= dynamic_extent*/ > class span { public: // constants and types typedef T element_type; typedef typename std11::remove_cv< T >::type value_type; typedef T & reference; typedef T * pointer; typedef T const * const_pointer; typedef T const & const_reference; typedef size_t size_type; typedef extent_t extent_type; typedef pointer iterator; typedef const_pointer const_iterator; typedef std::ptrdiff_t difference_type; typedef std::reverse_iterator< iterator > reverse_iterator; typedef std::reverse_iterator< const_iterator > const_reverse_iterator; // static constexpr extent_type extent = Extent; enum { extent = Extent }; // 26.7.3.2 Constructors, copy, and assignment [span.cons] span_REQUIRES_0( ( Extent == 0 ) || ( Extent == dynamic_extent ) ) span_constexpr span() span_noexcept : data_( span_nullptr ) , size_( 0 ) { // span_EXPECTS( data() == span_nullptr ); // span_EXPECTS( size() == 0 ); } #if span_HAVE( ITERATOR_CTOR ) // Didn't yet succeed in combining the next two constructors: span_constexpr_exp span( std::nullptr_t, size_type count ) : data_( span_nullptr ) , size_( count ) { span_EXPECTS( data_ == span_nullptr && count == 0 ); } template< typename It span_REQUIRES_T(( std::is_convertible()), element_type &>::value )) > span_constexpr_exp span( It first, size_type count ) : data_( to_address( first ) ) , size_( count ) { span_EXPECTS( ( data_ == span_nullptr && count == 0 ) || ( data_ != span_nullptr && detail::is_positive( count ) ) ); } #else span_constexpr_exp span( pointer ptr, size_type count ) : data_( ptr ) , size_( count ) { span_EXPECTS( ( ptr == span_nullptr && count == 0 ) || ( ptr != span_nullptr && detail::is_positive( count ) ) ); } #endif #if span_HAVE( ITERATOR_CTOR ) template< typename It, typename End span_REQUIRES_T(( std::is_convertible()), element_type *>::value && ! std::is_convertible::value )) > span_constexpr_exp span( It first, End last ) : data_( to_address( first ) ) , size_( to_size( last - first ) ) { span_EXPECTS( last - first >= 0 ); } #else span_constexpr_exp span( pointer first, pointer last ) : data_( first ) , size_( to_size( last - first ) ) { span_EXPECTS( last - first >= 0 ); } #endif template< std::size_t N span_REQUIRES_T(( (Extent == dynamic_extent || Extent == static_cast(N)) && std::is_convertible< value_type(*)[], element_type(*)[] >::value )) > span_constexpr span( element_type ( &arr )[ N ] ) span_noexcept : data_( span_ADDRESSOF( arr[0] ) ) , size_( N ) {} #if span_HAVE( ARRAY ) template< std::size_t N span_REQUIRES_T(( (Extent == dynamic_extent || Extent == static_cast(N)) && std::is_convertible< value_type(*)[], element_type(*)[] >::value )) > # if span_FEATURE( CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE ) span_constexpr span( std::array< element_type, N > & arr ) span_noexcept # else span_constexpr span( std::array< value_type, N > & arr ) span_noexcept # endif : data_( arr.data() ) , size_( to_size( arr.size() ) ) {} template< std::size_t N # if span_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) span_REQUIRES_T(( (Extent == dynamic_extent || Extent == static_cast(N)) && std::is_convertible< value_type(*)[], element_type(*)[] >::value )) # endif > span_constexpr span( std::array< value_type, N> const & arr ) span_noexcept : data_( arr.data() ) , size_( to_size( arr.size() ) ) {} #endif // span_HAVE( ARRAY ) #if span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) template< class Container span_REQUIRES_T(( detail::is_compatible_container< Container, element_type >::value )) > span_constexpr span( Container & cont ) : data_( std17::data( cont ) ) , size_( to_size( std17::size( cont ) ) ) {} template< class Container span_REQUIRES_T(( std::is_const< element_type >::value && detail::is_compatible_container< Container, element_type >::value )) > span_constexpr span( Container const & cont ) : data_( std17::data( cont ) ) , size_( to_size( std17::size( cont ) ) ) {} #endif // span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) #if span_FEATURE( WITH_CONTAINER ) template< class Container > span_constexpr span( with_container_t, Container & cont ) : data_( cont.size() == 0 ? span_nullptr : span_ADDRESSOF( cont[0] ) ) , size_( to_size( cont.size() ) ) {} template< class Container > span_constexpr span( with_container_t, Container const & cont ) : data_( cont.size() == 0 ? span_nullptr : const_cast( span_ADDRESSOF( cont[0] ) ) ) , size_( to_size( cont.size() ) ) {} #endif #if span_FEATURE( WITH_INITIALIZER_LIST_P2447 ) && span_HAVE( INITIALIZER_LIST ) // constexpr explicit(extent != dynamic_extent) span(std::initializer_list il) noexcept; #if !span_BETWEEN( span_COMPILER_MSVC_VERSION, 120, 130 ) template< extent_t U = Extent span_REQUIRES_T(( U != dynamic_extent )) > #if span_COMPILER_GNUC_VERSION >= 900 // prevent GCC's "-Winit-list-lifetime" span_constexpr14 explicit span( std::initializer_list il ) span_noexcept { data_ = il.begin(); size_ = il.size(); } #else span_constexpr explicit span( std::initializer_list il ) span_noexcept : data_( il.begin() ) , size_( il.size() ) {} #endif #endif // MSVC 120 (VS2013) template< extent_t U = Extent span_REQUIRES_T(( U == dynamic_extent )) > #if span_COMPILER_GNUC_VERSION >= 900 // prevent GCC's "-Winit-list-lifetime" span_constexpr14 /*explicit*/ span( std::initializer_list il ) span_noexcept { data_ = il.begin(); size_ = il.size(); } #else span_constexpr /*explicit*/ span( std::initializer_list il ) span_noexcept : data_( il.begin() ) , size_( il.size() ) {} #endif #endif // P2447 #if span_HAVE( IS_DEFAULT ) span_constexpr span( span const & other ) span_noexcept = default; ~span() span_noexcept = default; span_constexpr14 span & operator=( span const & other ) span_noexcept = default; #else span_constexpr span( span const & other ) span_noexcept : data_( other.data_ ) , size_( other.size_ ) {} ~span() span_noexcept {} span_constexpr14 span & operator=( span const & other ) span_noexcept { data_ = other.data_; size_ = other.size_; return *this; } #endif template< class OtherElementType, extent_type OtherExtent span_REQUIRES_T(( (Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent) && std::is_convertible::value )) > span_constexpr_exp span( span const & other ) span_noexcept : data_( other.data() ) , size_( other.size() ) { span_EXPECTS( OtherExtent == dynamic_extent || other.size() == to_size(OtherExtent) ); } // 26.7.3.3 Subviews [span.sub] template< extent_type Count > span_constexpr_exp span< element_type, Count > first() const { span_EXPECTS( detail::is_positive( Count ) && Count <= size() ); return span< element_type, Count >( data(), Count ); } template< extent_type Count > span_constexpr_exp span< element_type, Count > last() const { span_EXPECTS( detail::is_positive( Count ) && Count <= size() ); return span< element_type, Count >( data() + (size() - Count), Count ); } #if span_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) template< size_type Offset, extent_type Count = dynamic_extent > #else template< size_type Offset, extent_type Count /*= dynamic_extent*/ > #endif span_constexpr_exp span< element_type, Count > subspan() const { span_EXPECTS( ( detail::is_positive( Offset ) && Offset <= size() ) && ( Count == dynamic_extent || (detail::is_positive( Count ) && Count + Offset <= size()) ) ); return span< element_type, Count >( data() + Offset, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : size() - Offset) ); } span_constexpr_exp span< element_type, dynamic_extent > first( size_type count ) const { span_EXPECTS( detail::is_positive( count ) && count <= size() ); return span< element_type, dynamic_extent >( data(), count ); } span_constexpr_exp span< element_type, dynamic_extent > last( size_type count ) const { span_EXPECTS( detail::is_positive( count ) && count <= size() ); return span< element_type, dynamic_extent >( data() + ( size() - count ), count ); } span_constexpr_exp span< element_type, dynamic_extent > subspan( size_type offset, size_type count = static_cast(dynamic_extent) ) const { span_EXPECTS( ( ( detail::is_positive( offset ) && offset <= size() ) ) && ( count == static_cast(dynamic_extent) || ( detail::is_positive( count ) && offset + count <= size() ) ) ); return span< element_type, dynamic_extent >( data() + offset, count == static_cast(dynamic_extent) ? size() - offset : count ); } // 26.7.3.4 Observers [span.obs] span_constexpr size_type size() const span_noexcept { return size_; } span_constexpr std::ptrdiff_t ssize() const span_noexcept { return static_cast( size_ ); } span_constexpr size_type size_bytes() const span_noexcept { return size() * to_size( sizeof( element_type ) ); } span_nodiscard span_constexpr bool empty() const span_noexcept { return size() == 0; } // 26.7.3.5 Element access [span.elem] span_constexpr_exp reference operator[]( size_type idx ) const { span_EXPECTS( detail::is_positive( idx ) && idx < size() ); return *( data() + idx ); } #if span_FEATURE( MEMBER_CALL_OPERATOR ) span_deprecated("replace operator() with operator[]") span_constexpr_exp reference operator()( size_type idx ) const { span_EXPECTS( detail::is_positive( idx ) && idx < size() ); return *( data() + idx ); } #endif #if span_FEATURE( MEMBER_AT ) span_constexpr14 reference at( size_type idx ) const { #if span_CONFIG( NO_EXCEPTIONS ) return this->operator[]( idx ); #else if ( !detail::is_positive( idx ) || size() <= idx ) { detail::throw_out_of_range( idx, size() ); } return *( data() + idx ); #endif } #endif span_constexpr pointer data() const span_noexcept { return data_; } #if span_FEATURE( MEMBER_BACK_FRONT ) span_constexpr_exp reference front() const span_noexcept { span_EXPECTS( ! empty() ); return *data(); } span_constexpr_exp reference back() const span_noexcept { span_EXPECTS( ! empty() ); return *( data() + size() - 1 ); } #endif // xx.x.x.x Modifiers [span.modifiers] #if span_FEATURE( MEMBER_SWAP ) span_constexpr14 void swap( span & other ) span_noexcept { using std::swap; swap( data_, other.data_ ); swap( size_, other.size_ ); } #endif // 26.7.3.6 Iterator support [span.iterators] span_constexpr iterator begin() const span_noexcept { #if span_CPP11_OR_GREATER return { data() }; #else return iterator( data() ); #endif } span_constexpr iterator end() const span_noexcept { #if span_CPP11_OR_GREATER return { data() + size() }; #else return iterator( data() + size() ); #endif } span_constexpr const_iterator cbegin() const span_noexcept { #if span_CPP11_OR_GREATER return { data() }; #else return const_iterator( data() ); #endif } span_constexpr const_iterator cend() const span_noexcept { #if span_CPP11_OR_GREATER return { data() + size() }; #else return const_iterator( data() + size() ); #endif } span_constexpr reverse_iterator rbegin() const span_noexcept { return reverse_iterator( end() ); } span_constexpr reverse_iterator rend() const span_noexcept { return reverse_iterator( begin() ); } span_constexpr const_reverse_iterator crbegin() const span_noexcept { return const_reverse_iterator ( cend() ); } span_constexpr const_reverse_iterator crend() const span_noexcept { return const_reverse_iterator( cbegin() ); } private: // Note: C++20 has std::pointer_traits::to_address( it ); #if span_HAVE( ITERATOR_CTOR ) static inline span_constexpr pointer to_address( std::nullptr_t ) span_noexcept { return nullptr; } template< typename U > static inline span_constexpr U * to_address( U * p ) span_noexcept { return p; } template< typename Ptr span_REQUIRES_T(( ! std::is_pointer::value )) > static inline span_constexpr pointer to_address( Ptr const & it ) span_noexcept { return to_address( it.operator->() ); } #endif // span_HAVE( ITERATOR_CTOR ) private: pointer data_; size_type size_; }; // class template argument deduction guides: #if span_HAVE( DEDUCTION_GUIDES ) template< class T, size_t N > span( T (&)[N] ) -> span(N)>; template< class T, size_t N > span( std::array & ) -> span(N)>; template< class T, size_t N > span( std::array const & ) -> span(N)>; #if span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) template< class Container > span( Container& ) -> span; template< class Container > span( Container const & ) -> span; #endif // iterator: constraints: It satisfies contiguous_­iterator. template< class It, class EndOrSize > span( It, EndOrSize ) -> span< typename std11::remove_reference< typename std20::iter_reference_t >::type >; #endif // span_HAVE( DEDUCTION_GUIDES ) // 26.7.3.7 Comparison operators [span.comparison] #if span_FEATURE( COMPARISON ) #if span_FEATURE( SAME ) template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool same( span const & l, span const & r ) span_noexcept { return std11::is_same::value && l.size() == r.size() && static_cast( l.data() ) == r.data(); } #endif template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool operator==( span const & l, span const & r ) { return #if span_FEATURE( SAME ) same( l, r ) || #endif ( l.size() == r.size() && std::equal( l.begin(), l.end(), r.begin() ) ); } template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool operator<( span const & l, span const & r ) { return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); } template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool operator!=( span const & l, span const & r ) { return !( l == r ); } template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool operator<=( span const & l, span const & r ) { return !( r < l ); } template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool operator>( span const & l, span const & r ) { return ( r < l ); } template< class T1, extent_t E1, class T2, extent_t E2 > inline span_constexpr bool operator>=( span const & l, span const & r ) { return !( l < r ); } #endif // span_FEATURE( COMPARISON ) // 26.7.2.6 views of object representation [span.objectrep] #if span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) // Avoid MSVC 14.1 (1910), VS 2017: warning C4307: '*': integral constant overflow: template< typename T, extent_t Extent > struct BytesExtent { #if span_CPP11_OR_GREATER enum ET : extent_t { value = span_sizeof(T) * Extent }; #else enum ET { value = span_sizeof(T) * Extent }; #endif }; template< typename T > struct BytesExtent< T, dynamic_extent > { #if span_CPP11_OR_GREATER enum ET : extent_t { value = dynamic_extent }; #else enum ET { value = dynamic_extent }; #endif }; template< class T, extent_t Extent > inline span_constexpr span< const std17::byte, BytesExtent::value > as_bytes( span spn ) span_noexcept { #if 0 return { reinterpret_cast< std17::byte const * >( spn.data() ), spn.size_bytes() }; #else return span< const std17::byte, BytesExtent::value >( reinterpret_cast< std17::byte const * >( spn.data() ), spn.size_bytes() ); // NOLINT #endif } template< class T, extent_t Extent > inline span_constexpr span< std17::byte, BytesExtent::value > as_writable_bytes( span spn ) span_noexcept { #if 0 return { reinterpret_cast< std17::byte * >( spn.data() ), spn.size_bytes() }; #else return span< std17::byte, BytesExtent::value >( reinterpret_cast< std17::byte * >( spn.data() ), spn.size_bytes() ); // NOLINT #endif } #endif // span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) // 27.8 Container and view access [iterator.container] template< class T, extent_t Extent /*= dynamic_extent*/ > span_constexpr std::size_t size( span const & spn ) { return static_cast( spn.size() ); } template< class T, extent_t Extent /*= dynamic_extent*/ > span_constexpr std::ptrdiff_t ssize( span const & spn ) { return static_cast( spn.size() ); } } // namespace span_lite } // namespace nonstd // make available in nonstd: namespace nonstd { using span_lite::dynamic_extent; using span_lite::span; using span_lite::with_container; #if span_FEATURE( COMPARISON ) #if span_FEATURE( SAME ) using span_lite::same; #endif using span_lite::operator==; using span_lite::operator!=; using span_lite::operator<; using span_lite::operator<=; using span_lite::operator>; using span_lite::operator>=; #endif #if span_HAVE( BYTE ) using span_lite::as_bytes; using span_lite::as_writable_bytes; #endif using span_lite::size; using span_lite::ssize; } // namespace nonstd #endif // span_USES_STD_SPAN // make_span() [span-lite extension]: #if span_FEATURE( MAKE_SPAN ) || span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_SPAN ) || span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_CONTAINER ) #if span_USES_STD_SPAN # define span_constexpr constexpr # define span_noexcept noexcept # define span_nullptr nullptr # ifndef span_CONFIG_EXTENT_TYPE # define span_CONFIG_EXTENT_TYPE std::size_t # endif using extent_t = span_CONFIG_EXTENT_TYPE; #endif // span_USES_STD_SPAN namespace nonstd { namespace span_lite { template< class T > inline span_constexpr span make_span( T * ptr, size_t count ) span_noexcept { return span( ptr, count ); } template< class T > inline span_constexpr span make_span( T * first, T * last ) span_noexcept { return span( first, last ); } template< class T, std::size_t N > inline span_constexpr span(N)> make_span( T ( &arr )[ N ] ) span_noexcept { return span(N)>( &arr[ 0 ], N ); } #if span_USES_STD_SPAN || span_HAVE( ARRAY ) template< class T, std::size_t N > inline span_constexpr span(N)> make_span( std::array< T, N > & arr ) span_noexcept { return span(N)>( arr ); } template< class T, std::size_t N > inline span_constexpr span< const T, static_cast(N) > make_span( std::array< T, N > const & arr ) span_noexcept { return span(N)>( arr ); } #endif // span_HAVE( ARRAY ) #if span_USES_STD_SPAN || span_HAVE( INITIALIZER_LIST ) template< class T > inline span_constexpr span< const T > make_span( std::initializer_list il ) span_noexcept { return span( il.begin(), il.size() ); } #endif // span_HAVE( INITIALIZER_LIST ) #if span_USES_STD_SPAN template< class Container, class EP = decltype( std::data(std::declval())) > inline span_constexpr auto make_span( Container & cont ) span_noexcept -> span< typename std::remove_pointer::type > { return span< typename std::remove_pointer::type >( cont ); } template< class Container, class EP = decltype( std::data(std::declval())) > inline span_constexpr auto make_span( Container const & cont ) span_noexcept -> span< const typename std::remove_pointer::type > { return span< const typename std::remove_pointer::type >( cont ); } #elif span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && span_HAVE( AUTO ) template< class Container, class EP = decltype( std17::data(std::declval())) > inline span_constexpr auto make_span( Container & cont ) span_noexcept -> span< typename std::remove_pointer::type > { return span< typename std::remove_pointer::type >( cont ); } template< class Container, class EP = decltype( std17::data(std::declval())) > inline span_constexpr auto make_span( Container const & cont ) span_noexcept -> span< const typename std::remove_pointer::type > { return span< const typename std::remove_pointer::type >( cont ); } #else template< class T > inline span_constexpr span make_span( span spn ) span_noexcept { return spn; } template< class T, class Allocator > inline span_constexpr span make_span( std::vector & cont ) span_noexcept { return span( with_container, cont ); } template< class T, class Allocator > inline span_constexpr span make_span( std::vector const & cont ) span_noexcept { return span( with_container, cont ); } #endif // span_USES_STD_SPAN || ( ... ) #if ! span_USES_STD_SPAN && span_FEATURE( WITH_CONTAINER ) template< class Container > inline span_constexpr span make_span( with_container_t, Container & cont ) span_noexcept { return span< typename Container::value_type >( with_container, cont ); } template< class Container > inline span_constexpr span make_span( with_container_t, Container const & cont ) span_noexcept { return span< const typename Container::value_type >( with_container, cont ); } #endif // ! span_USES_STD_SPAN && span_FEATURE( WITH_CONTAINER ) // extensions: non-member views: // this feature implies the presence of make_span() #if span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_SPAN ) template< extent_t Count, class T, extent_t Extent > span_constexpr span first( span spn ) { return spn.template first(); } template< class T, extent_t Extent > span_constexpr span first( span spn, size_t count ) { return spn.first( count ); } template< extent_t Count, class T, extent_t Extent > span_constexpr span last( span spn ) { return spn.template last(); } template< class T, extent_t Extent > span_constexpr span last( span spn, size_t count ) { return spn.last( count ); } template< size_t Offset, extent_t Count, class T, extent_t Extent > span_constexpr span subspan( span spn ) { return spn.template subspan(); } template< class T, extent_t Extent > span_constexpr span subspan( span spn, size_t offset, extent_t count = dynamic_extent ) { return spn.subspan( offset, count ); } #endif // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_SPAN ) #if span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_CONTAINER ) && span_CPP11_120 template< extent_t Count, class T > span_constexpr auto first( T & t ) -> decltype( make_span(t).template first() ) { return make_span( t ).template first(); } template< class T > span_constexpr auto first( T & t, size_t count ) -> decltype( make_span(t).first(count) ) { return make_span( t ).first( count ); } template< extent_t Count, class T > span_constexpr auto last( T & t ) -> decltype( make_span(t).template last() ) { return make_span(t).template last(); } template< class T > span_constexpr auto last( T & t, extent_t count ) -> decltype( make_span(t).last(count) ) { return make_span( t ).last( count ); } template< size_t Offset, extent_t Count = dynamic_extent, class T > span_constexpr auto subspan( T & t ) -> decltype( make_span(t).template subspan() ) { return make_span( t ).template subspan(); } template< class T > span_constexpr auto subspan( T & t, size_t offset, extent_t count = dynamic_extent ) -> decltype( make_span(t).subspan(offset, count) ) { return make_span( t ).subspan( offset, count ); } #endif // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_CONTAINER ) } // namespace span_lite } // namespace nonstd // make available in nonstd: namespace nonstd { using span_lite::make_span; #if span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_SPAN ) || ( span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_CONTAINER ) && span_CPP11_120 ) using span_lite::first; using span_lite::last; using span_lite::subspan; #endif // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_[SPAN|CONTAINER] ) } // namespace nonstd #endif // #if span_FEATURE_TO_STD( MAKE_SPAN ) #if span_CPP11_OR_GREATER && span_FEATURE( BYTE_SPAN ) && ( span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) ) namespace nonstd { namespace span_lite { template< class T > inline span_constexpr auto byte_span( T & t ) span_noexcept -> span< std17::byte, span_sizeof(T) > { return span< std17::byte, span_sizeof(t) >( reinterpret_cast< std17::byte * >( &t ), span_sizeof(T) ); } template< class T > inline span_constexpr auto byte_span( T const & t ) span_noexcept -> span< const std17::byte, span_sizeof(T) > { return span< const std17::byte, span_sizeof(t) >( reinterpret_cast< std17::byte const * >( &t ), span_sizeof(T) ); } } // namespace span_lite } // namespace nonstd // make available in nonstd: namespace nonstd { using span_lite::byte_span; } // namespace nonstd #endif // span_FEATURE( BYTE_SPAN ) #if !span_USES_STD_SPAN && span_HAVE( STRUCT_BINDING ) #if span_CPP14_OR_GREATER # include #elif span_CPP11_OR_GREATER # include namespace std { template< std::size_t I, typename T > using tuple_element_t = typename tuple_element::type; } #else namespace std { template< typename T > class tuple_size; /*undefined*/ template< std::size_t I, typename T > class tuple_element; /* undefined */ } #endif // span_CPP14_OR_GREATER namespace std { // 26.7.X Tuple interface // std::tuple_size<>: template< typename ElementType, nonstd::span_lite::extent_t Extent > class tuple_size< nonstd::span > : public integral_constant(Extent)> {}; // std::tuple_size<>: Leave undefined for dynamic extent: template< typename ElementType > class tuple_size< nonstd::span >; // std::tuple_element<>: template< size_t I, typename ElementType, nonstd::span_lite::extent_t Extent > class tuple_element< I, nonstd::span > { public: #if span_HAVE( STATIC_ASSERT ) static_assert( Extent != nonstd::dynamic_extent && I < Extent, "tuple_element: dynamic extent or index out of range" ); #endif using type = ElementType; }; // std::get<>(), 2 variants: template< size_t I, typename ElementType, nonstd::span_lite::extent_t Extent > span_constexpr ElementType & get( nonstd::span & spn ) span_noexcept { #if span_HAVE( STATIC_ASSERT ) static_assert( Extent != nonstd::dynamic_extent && I < Extent, "get<>(span): dynamic extent or index out of range" ); #endif return spn[I]; } template< size_t I, typename ElementType, nonstd::span_lite::extent_t Extent > span_constexpr ElementType const & get( nonstd::span const & spn ) span_noexcept { #if span_HAVE( STATIC_ASSERT ) static_assert( Extent != nonstd::dynamic_extent && I < Extent, "get<>(span): dynamic extent or index out of range" ); #endif return spn[I]; } } // end namespace std #endif // !span_USES_STD_SPAN && span_HAVE( STRUCT_BINDING ) #if ! span_USES_STD_SPAN span_RESTORE_WARNINGS() #endif // span_USES_STD_SPAN #endif // NONSTD_SPAN_HPP_INCLUDED qbs-src-2.6.1/src/shared/span/CMakeLists.txt0000644000175100001660000000017714776170045020213 0ustar runnerdockeradd_library(span INTERFACE) target_include_directories( span INTERFACE $) qbs-src-2.6.1/src/shared/span/LICENSE_1_0.txt0000644000175100001660000000247214776170045017735 0ustar runnerdockerBoost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. qbs-src-2.6.1/src/shared/bundledqt/0000755000175100001660000000000014776170045016467 5ustar runnerdockerqbs-src-2.6.1/src/shared/bundledqt/qt.conf0000644000175100001660000000002414776170045017756 0ustar runnerdocker[Paths] Prefix = .. qbs-src-2.6.1/src/shared/bundledqt/bundledqt.qbs0000644000175100001660000001521514776170045021164 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.Utilities Product { Depends { name: "qbsbuildconfig" } Depends { name: "Qt"; submodules: ["core", "gui", "network", "printsupport", "widgets", "xml"] } Depends { name: "Qt.test"; condition: project.withTests === true } Depends { name: "Qt.core5compat"; condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 } Depends { name: "Qt"; submodules: [ "dbus", "xcb_qpa_lib-private" ]; required: false } condition: { if (!qbsbuildconfig.enableBundledQt) return false; if (Qt.core.staticBuild) throw("Cannot bundle static Qt libraries"); return true; } readonly property string qtDebugLibrarySuffix: { if (Qt.core.qtBuildVariant !== "debug") return ""; if (qbs.targetOS.contains("windows")) return "d"; if (qbs.targetOS.contains("darwin")) return "_debug"; return ""; } Group { name: "qt.conf" files: ["qt.conf"] qbs.install: true qbs.installDir: qbsbuildconfig.appInstallDir } Group { name: "Qt libraries" files: { function getLibsForQtModule(mod) { if (mod === "script" && !Qt[mod].present) return []; if ((mod !== "core") && !Qt[mod].hasLibrary) return []; if (Qt[mod].isStaticLibrary) return []; var list = []; if (qbs.targetOS.contains("windows")) { var basename = FileInfo.baseName(Qt[mod].libNameForLinker); var dir = Qt.core.binPath; list.push(dir + "/" + basename + ".dll"); } else if (qbs.targetOS.contains("linux")) { var fp = Qt[mod].libFilePath; var basename = FileInfo.baseName(fp); var dir = FileInfo.path(fp); list.push(dir + "/" + basename + ".so"); list.push(dir + "/" + basename + ".so." + Qt.core.versionMajor); if (Utilities.versionCompare(Qt.core.version, "6") < 0) { list.push(dir + "/" + basename + ".so." + Qt.core.versionMajor + "." + Qt.core.versionMinor); } list.push(dir + "/" + basename + ".so." + Qt.core.versionMajor + "." + Qt.core.versionMinor + "." + Qt.core.versionPatch); } else if (Qt.core.frameworkBuild) { var fp = Qt[mod].libFilePathRelease; var fpd = fp + "_debug"; if (qtDebugLibrarySuffix) list.push(fpd); var suffix = ".framework/"; var frameworkPath = fp.substr(0, fp.lastIndexOf(suffix) + suffix.length - 1); var versionsPath = frameworkPath + "/Versions"; var versionName = Utilities.versionCompare(Qt.core.version, "6") >= 0 ? "A" : Qt.core.versionMajor; var versionPath = versionsPath + "/" + versionName; list.push(frameworkPath + "/Resources"); list.push(versionPath + "/Resources/Info.plist"); list.push(versionPath + "/" + FileInfo.fileName(fp)); if (qtDebugLibrarySuffix) list.push(versionPath + "/" + FileInfo.fileName(fpd)); if (qbsbuildconfig.installApiHeaders) { list.push(frameworkPath + "/Headers"); list.push(versionPath + "/Headers/**"); } } return list; } var qtModules = Object.getOwnPropertyNames(Qt); var libraries = Array.prototype.concat.apply([], qtModules.map(getLibsForQtModule)); // Qt might be bundled with additional libraries if (qbs.targetOS.contains("linux")) { var dir = FileInfo.path(Qt.core.libFilePathRelease); var addons = [ "libicui18n", "libicuuc", "libicudata" ]; addons.forEach(function(lib) { var fp = dir + "/" + lib + ".so"; if (File.exists(fp)) libraries.push(fp + "*"); }); } return libraries; } fileTags: [] qbs.install: true qbs.installDir: qbsbuildconfig.libInstallDir qbs.installSourceBase: qbs.targetOS.contains("windows") ? Qt.core.binPath : Qt.core.libPath } Group { name: "Windows Plugins" condition: qbs.targetOS.contains("windows") prefix: Qt.core.pluginPath + "/" files: [ "platforms/qwindows" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix, "styles/qwindowsvistastyle" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix ] qbs.install: true qbs.installDir: "plugins" qbs.installSourceBase: prefix } Group { name: "macOS Plugins" condition: qbs.targetOS.contains("darwin") prefix: Qt.core.pluginPath + "/" files: [ "platforms/libqcocoa" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix, "styles/libqmacstyle" + qtDebugLibrarySuffix + cpp.dynamicLibrarySuffix ] qbs.install: true qbs.installDir: "plugins" qbs.installSourceBase: prefix } Group { name: "Linux Plugins" condition: qbs.targetOS.contains("linux") prefix: Qt.core.pluginPath + "/" files: [ "platforms/libqxcb" + cpp.dynamicLibrarySuffix, "platformthemes/libqgtk3" + cpp.dynamicLibrarySuffix ] qbs.install: true qbs.installDir: "plugins" qbs.installSourceBase: prefix } Group { name: "MinGW Runtime DLLs" condition: qbs.targetOS.contains("windows") && qbs.toolchain.contains("mingw") files: { var libFileGlobs = [ "*libgcc_s*.dll", "*libstdc++-6.dll", "*libwinpthread-1.dll" ]; var searchPaths = cpp.compilerLibraryPaths; return Array.prototype.concat.apply([], searchPaths.map(function(path) { return libFileGlobs.map(function(glob) { return path + "/" + glob; }); })); } qbs.install: true qbs.installDir: "bin" } } qbs-src-2.6.1/src/shared/quickjs/0000755000175100001660000000000014776170045016156 5ustar runnerdockerqbs-src-2.6.1/src/shared/quickjs/quickjs.qbs0000644000175100001660000000153014776170045020335 0ustar runnerdockerStaticLibrary { name: "quickjs" Depends { name: "qbsbuildconfig" } Depends { name: "cpp" } cpp.cLanguageVersion: qbs.toolchain.contains("msvc") ? "c99" : "gnu99" cpp.defines: ['CONFIG_VERSION="2021-03-27"'].concat(qbsbuildconfig.dumpJsLeaks ? "DUMP_LEAKS" : []) cpp.warningLevel: "none" files: [ "cutils.c", "cutils.h", "libbf.c", "libbf.h", "libregexp-opcode.h", "libregexp.c", "libregexp.h", "libunicode-table.h", "libunicode.c", "libunicode.h", "list.h", "quickjs-atom.h", "quickjs-opcode.h", "quickjs.c", "quickjs.h", ] Export { Depends { name: "cpp" } cpp.systemIncludePaths: [exportingProduct.sourceDirectory] } } qbs-src-2.6.1/src/shared/quickjs/LICENSE0000644000175100001660000000215214776170045017163 0ustar runnerdockerQuickJS Javascript Engine Copyright (c) 2017-2021 Fabrice Bellard Copyright (c) 2017-2021 Charlie Gordon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. qbs-src-2.6.1/src/shared/quickjs/libregexp-opcode.h0000644000175100001660000000431214776170045021557 0ustar runnerdocker/* * Regular Expression Engine * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef DEF DEF(invalid, 1) /* never used */ DEF(char, 3) DEF(char32, 5) DEF(dot, 1) DEF(any, 1) /* same as dot but match any character including line terminator */ DEF(line_start, 1) DEF(line_end, 1) DEF(goto, 5) DEF(split_goto_first, 5) DEF(split_next_first, 5) DEF(match, 1) DEF(save_start, 2) /* save start position */ DEF(save_end, 2) /* save end position, must come after saved_start */ DEF(save_reset, 3) /* reset save positions */ DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ DEF(push_i32, 5) /* push integer on the stack */ DEF(drop, 1) DEF(word_boundary, 1) DEF(not_word_boundary, 1) DEF(back_reference, 2) DEF(backward_back_reference, 2) /* must come after back_reference */ DEF(range, 3) /* variable length */ DEF(range32, 3) /* variable length */ DEF(lookahead, 5) DEF(negative_lookahead, 5) DEF(push_char_pos, 1) /* push the character position on the stack */ DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */ DEF(prev, 1) /* go to the previous char */ DEF(simple_greedy_quant, 17) #endif /* DEF */ qbs-src-2.6.1/src/shared/quickjs/quickjs.c0000644000175100001660000676646314776170045020027 0ustar runnerdocker/* * QuickJS Javascript Engine * * Copyright (c) 2017-2021 Fabrice Bellard * Copyright (c) 2017-2021 Charlie Gordon * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #ifndef _MSC_VER #include #endif #include #include #include #if defined(__APPLE__) #include #elif defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif #ifdef _MSC_VER #include #include #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__APPLE__) #include #else #include #endif #include "cutils.h" #include "list.h" #include "quickjs.h" #include "libregexp.h" #include "libunicode.h" #include "libbf.h" #define OPTIMIZE 0 #define SHORT_OPCODES 1 #if defined(EMSCRIPTEN) || defined(_MSC_VER) #define DIRECT_DISPATCH 0 #else #define DIRECT_DISPATCH 1 #endif #if defined(__APPLE__) #define MALLOC_OVERHEAD 0 #else #define MALLOC_OVERHEAD 8 #endif #if !defined(_WIN32) /* define it if printf uses the RNDN rounding mode instead of RNDNA */ #define CONFIG_PRINTF_RNDN #endif /* define to include Atomics.* operations which depend on the OS threads */ #if !defined(EMSCRIPTEN) && !defined(_MSC_VER) #define CONFIG_ATOMICS #endif #if !defined(EMSCRIPTEN) /* enable stack limitation */ #define CONFIG_STACK_CHECK #endif /* dump object free */ //#define DUMP_FREE //#define DUMP_CLOSURE /* dump the bytecode of the compiled functions: combination of bits 1: dump pass 3 final byte code 2: dump pass 2 code 4: dump pass 1 code 8: dump stdlib functions 16: dump bytecode in hex 32: dump line number table 64: dump compute_stack_size */ //#define DUMP_BYTECODE (1) /* dump the occurence of the automatic GC */ //#define DUMP_GC /* dump objects freed by the garbage collector */ //#define DUMP_GC_FREE /* dump objects leaking when freeing the runtime */ //#define DUMP_LEAKS 1 /* dump memory usage before running the garbage collector */ //#define DUMP_MEM //#define DUMP_OBJECTS /* dump objects in JS_FreeContext */ //#define DUMP_ATOMS /* dump atoms in JS_FreeContext */ //#define DUMP_SHAPES /* dump shapes in JS_FreeContext */ //#define DUMP_MODULE_RESOLVE //#define DUMP_PROMISE //#define DUMP_READ_OBJECT /* test the GC by forcing it before each object allocation */ //#define FORCE_GC_AT_MALLOC #ifdef CONFIG_ATOMICS #include #include #include #endif static double safe_strtod(const char *restrict nptr, char **restrict endptr) { #if defined(_MSC_VER) || defined(__MINGW32__) _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); setlocale(LC_NUMERIC, "C"); #else const locale_t tempLoc = newlocale(LC_NUMERIC_MASK, "C", 0); uselocale(tempLoc); #endif double d = strtod(nptr, endptr); #if defined(_MSC_VER) || defined(__MINGW32__) _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); #else uselocale(LC_GLOBAL_LOCALE); freelocale(tempLoc); #endif return d; } enum { /* classid tag */ /* union usage | properties */ JS_CLASS_OBJECT = 1, /* must be first */ JS_CLASS_ARRAY, /* u.array | length */ JS_CLASS_ERROR, JS_CLASS_NUMBER, /* u.object_data */ JS_CLASS_STRING, /* u.object_data */ JS_CLASS_BOOLEAN, /* u.object_data */ JS_CLASS_SYMBOL, /* u.object_data */ JS_CLASS_ARGUMENTS, /* u.array | length */ JS_CLASS_MAPPED_ARGUMENTS, /* | length */ JS_CLASS_DATE, /* u.object_data */ JS_CLASS_MODULE_NS, JS_CLASS_C_FUNCTION, /* u.cfunc */ JS_CLASS_BYTECODE_FUNCTION, /* u.func */ JS_CLASS_BOUND_FUNCTION, /* u.bound_function */ JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */ JS_CLASS_GENERATOR_FUNCTION, /* u.func */ JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */ JS_CLASS_REGEXP, /* u.regexp */ JS_CLASS_ARRAY_BUFFER, /* u.array_buffer */ JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */ JS_CLASS_UINT8C_ARRAY, /* u.array (typed_array) */ JS_CLASS_INT8_ARRAY, /* u.array (typed_array) */ JS_CLASS_UINT8_ARRAY, /* u.array (typed_array) */ JS_CLASS_INT16_ARRAY, /* u.array (typed_array) */ JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */ JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_DATAVIEW, /* u.typed_array */ JS_CLASS_BIG_INT, /* u.object_data */ #ifdef CONFIG_BIGNUM JS_CLASS_BIG_FLOAT, /* u.object_data */ JS_CLASS_FLOAT_ENV, /* u.float_env */ JS_CLASS_BIG_DECIMAL, /* u.object_data */ JS_CLASS_OPERATOR_SET, /* u.operator_set */ #endif JS_CLASS_MAP, /* u.map_state */ JS_CLASS_SET, /* u.map_state */ JS_CLASS_WEAKMAP, /* u.map_state */ JS_CLASS_WEAKSET, /* u.map_state */ JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */ JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */ JS_CLASS_GENERATOR, /* u.generator_data */ JS_CLASS_PROXY, /* u.proxy_data */ JS_CLASS_PROMISE, /* u.promise_data */ JS_CLASS_PROMISE_RESOLVE_FUNCTION, /* u.promise_function_data */ JS_CLASS_PROMISE_REJECT_FUNCTION, /* u.promise_function_data */ JS_CLASS_ASYNC_FUNCTION, /* u.func */ JS_CLASS_ASYNC_FUNCTION_RESOLVE, /* u.async_function_data */ JS_CLASS_ASYNC_FUNCTION_REJECT, /* u.async_function_data */ JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */ JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */ JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */ JS_CLASS_INIT_COUNT, /* last entry for predefined classes */ }; /* number of typed array types */ #define JS_TYPED_ARRAY_COUNT (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1) static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT]; #define typed_array_size_log2(classid) (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY]) typedef enum JSErrorEnum { JS_EVAL_ERROR, JS_RANGE_ERROR, JS_REFERENCE_ERROR, JS_SYNTAX_ERROR, JS_TYPE_ERROR, JS_URI_ERROR, JS_INTERNAL_ERROR, JS_AGGREGATE_ERROR, JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ } JSErrorEnum; #define JS_MAX_LOCAL_VARS 65535 #define JS_STACK_SIZE_MAX 65534 #define JS_STRING_LEN_MAX ((1 << 30) - 1) #ifdef __GNUC__ #define __exception __attribute__((warn_unused_result)) #else #define __exception #endif typedef struct JSShape JSShape; typedef struct JSString JSString; typedef struct JSString JSAtomStruct; typedef enum { JS_GC_PHASE_NONE, JS_GC_PHASE_DECREF, JS_GC_PHASE_REMOVE_CYCLES, } JSGCPhaseEnum; typedef enum OPCodeEnum OPCodeEnum; /* function pointers are used for numeric operations so that it is possible to remove some numeric types */ typedef struct { JSValue (*to_string)(JSContext *ctx, JSValueConst val); JSValue (*from_string)(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent); int (*unary_arith)(JSContext *ctx, JSValue *pres, OPCodeEnum op, JSValue op1); int (*binary_arith)(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2); int (*compare)(JSContext *ctx, OPCodeEnum op, JSValue op1, JSValue op2); /* only for bigfloat: */ JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a, int64_t exponent); int (*mul_pow10)(JSContext *ctx, JSValue *sp); } JSNumericOperations; struct JSRuntime { JSMallocFunctions mf; JSMallocState malloc_state; const char *rt_info; int atom_hash_size; /* power of two */ int atom_count; int atom_size; int atom_count_resize; /* resize hash table at this count */ uint32_t *atom_hash; JSAtomStruct **atom_array; int atom_free_index; /* 0 = none */ int class_count; /* size of class_array */ JSClass *class_array; struct list_head context_list; /* list of JSContext.link */ /* list of JSGCObjectHeader.link. List of allocated GC objects (used by the garbage collector) */ struct list_head gc_obj_list; /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */ struct list_head gc_zero_ref_count_list; struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; #ifdef DUMP_LEAKS struct list_head string_list; /* list of JSString.link */ #endif /* stack limitation */ uintptr_t stack_size; /* in bytes, 0 if no limit */ uintptr_t stack_top; uintptr_t stack_limit; /* lower stack limit */ JSValue current_exception; /* true if inside an out of memory error, to avoid recursing */ BOOL in_out_of_memory : 8; struct JSStackFrame *current_stack_frame; JSInterruptHandler *interrupt_handler; void *interrupt_opaque; JSHostPromiseRejectionTracker *host_promise_rejection_tracker; void *host_promise_rejection_tracker_opaque; struct list_head job_list; /* list of JSJobEntry.link */ JSModuleNormalizeFunc *module_normalize_func; JSModuleLoaderFunc *module_loader_func; void *module_loader_opaque; /* timestamp for internal use in module evaluation */ int64_t module_async_evaluation_next_timestamp; BOOL can_block : 8; /* TRUE if Atomics.wait can block */ /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; /* Shape hash table */ int shape_hash_bits; int shape_hash_size; int shape_hash_count; /* number of hashed shapes */ JSShape **shape_hash; bf_context_t bf_ctx; JSNumericOperations bigint_ops; #ifdef CONFIG_BIGNUM JSNumericOperations bigfloat_ops; JSNumericOperations bigdecimal_ops; uint32_t operator_count; #endif void *user_opaque; }; struct JSClass { uint32_t class_id; /* 0 means free entry */ JSAtom class_name; JSClassFinalizer *finalizer; JSClassGCMark *gc_mark; JSClassCall *call; /* pointers for exotic behavior, can be NULL if none are present */ const JSClassExoticMethods *exotic; }; #define JS_MODE_STRICT (1 << 0) #define JS_MODE_STRIP (1 << 1) #define JS_MODE_MATH (1 << 2) #define JS_MODE_ASYNC (1 << 3) /* async function */ typedef struct JSStackFrame { struct JSStackFrame *prev_frame; /* NULL if first stack frame */ JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */ JSValue *arg_buf; /* arguments */ JSValue *var_buf; /* variables */ struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */ const uint8_t *cur_pc; /* only used in bytecode functions : PC of the instruction after the call */ int arg_count; int js_mode; /* for C functions, only JS_MODE_MATH may be set */ /* only used in generators. Current stack pointer value. NULL if the function is running. */ JSValue *cur_sp; } JSStackFrame; typedef enum { JS_GC_OBJ_TYPE_JS_OBJECT, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE, JS_GC_OBJ_TYPE_SHAPE, JS_GC_OBJ_TYPE_VAR_REF, JS_GC_OBJ_TYPE_ASYNC_FUNCTION, JS_GC_OBJ_TYPE_JS_CONTEXT, } JSGCObjectTypeEnum; /* header for GC objects. GC objects are C data structures with a reference count that can reference other GC objects. JS Objects are a particular type of GC object. */ struct JSGCObjectHeader { int ref_count; /* must come first, 32-bit */ JSGCObjectTypeEnum gc_obj_type : 4; uint8_t mark : 4; /* used by the GC */ uint8_t dummy1; /* not used by the GC */ uint16_t dummy2; /* not used by the GC */ struct list_head link; }; typedef struct JSVarRef { union { JSGCObjectHeader header; /* must come first */ struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ uint8_t is_detached : 1; uint8_t is_arg : 1; uint16_t var_idx; /* index of the corresponding function variable on the stack */ }; }; JSValue *pvalue; /* pointer to the value, either on the stack or to 'value' */ union { JSValue value; /* used when is_detached = TRUE */ struct { struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */ struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */ }; /* used when is_detached = FALSE */ }; } JSVarRef; /* the same structure is used for big integers and big floats. Big integers are never infinite or NaNs */ typedef struct JSBigFloat { JSRefCountHeader header; /* must come first, 32-bit */ bf_t num; } JSBigFloat; #ifdef CONFIG_BIGNUM typedef struct JSFloatEnv { limb_t prec; bf_flags_t flags; unsigned int status; } JSFloatEnv; typedef struct JSBigDecimal { JSRefCountHeader header; /* must come first, 32-bit */ bfdec_t num; } JSBigDecimal; #endif typedef enum { JS_AUTOINIT_ID_PROTOTYPE, JS_AUTOINIT_ID_MODULE_NS, JS_AUTOINIT_ID_PROP, } JSAutoInitIDEnum; /* must be large enough to have a negligible runtime cost and small enough to call the interrupt callback often. */ #define JS_INTERRUPT_COUNTER_INIT 10000 struct JSContext { JSGCObjectHeader header; /* must come first */ JSRuntime *rt; struct list_head link; uint16_t binary_object_count; int binary_object_size; JSShape *array_shape; /* initial shape for Array objects */ JSValue *class_proto; JSValue function_proto; JSValue function_ctor; JSValue array_ctor; JSValue regexp_ctor; JSValue promise_ctor; JSValue native_error_proto[JS_NATIVE_ERROR_COUNT]; JSValue iterator_proto; JSValue async_iterator_proto; JSValue array_proto_values; JSValue throw_type_error; JSValue eval_obj; JSValue global_obj; /* global object */ JSValue global_var_obj; /* contains the global let/const definitions */ uint64_t random_state; bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */ #ifdef CONFIG_BIGNUM JSFloatEnv fp_env; /* global FP environment */ BOOL bignum_ext : 8; /* enable math mode */ BOOL allow_operator_overloading : 8; #endif /* when the counter reaches zero, JSRutime.interrupt_handler is called */ int interrupt_counter; struct list_head loaded_modules; /* list of JSModuleDef.link */ /* if NULL, RegExp compilation is not supported */ JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern, JSValueConst flags); /* if NULL, eval is not supported */ JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, const char *filename, int line, int flags, int scope_idx); void *user_opaque; ScopeLookup *scopeLookup; FoundUndefinedHandler *handleUndefined; FunctionEnteredHandler *handleFunctionEntered; FunctionExitedHandler *handleFunctionExited; }; typedef union JSFloat64Union { double d; uint64_t u64; uint32_t u32[2]; } JSFloat64Union; enum { JS_ATOM_TYPE_STRING = 1, JS_ATOM_TYPE_GLOBAL_SYMBOL, JS_ATOM_TYPE_SYMBOL, JS_ATOM_TYPE_PRIVATE, }; enum { JS_ATOM_HASH_SYMBOL, JS_ATOM_HASH_PRIVATE, }; typedef enum { JS_ATOM_KIND_STRING, JS_ATOM_KIND_SYMBOL, JS_ATOM_KIND_PRIVATE, } JSAtomKindEnum; #define JS_ATOM_HASH_MASK ((1 << 30) - 1) struct JSString { JSRefCountHeader header; /* must come first, 32-bit */ uint32_t len : 31; uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */ /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3, for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3 XXX: could change encoding to have one more bit in hash */ uint32_t hash : 30; uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */ uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */ #ifdef DUMP_LEAKS struct list_head link; /* string list */ #endif union { uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */ uint16_t str16[0]; } u; }; typedef struct JSClosureVar { uint8_t is_local : 1; uint8_t is_arg : 1; uint8_t is_const : 1; uint8_t is_lexical : 1; uint8_t var_kind : 4; /* see JSVarKindEnum */ /* 8 bits available */ uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the parent function. otherwise: index to a closure variable of the parent function */ JSAtom var_name; } JSClosureVar; #define ARG_SCOPE_INDEX 1 #define ARG_SCOPE_END (-2) typedef struct JSVarScope { int parent; /* index into fd->scopes of the enclosing scope */ int first; /* index into fd->vars of the last variable in this scope */ } JSVarScope; typedef enum { /* XXX: add more variable kinds here instead of using bit fields */ JS_VAR_NORMAL, JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */ JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator function declaration */ JS_VAR_CATCH, JS_VAR_FUNCTION_NAME, /* function expression name */ JS_VAR_PRIVATE_FIELD, JS_VAR_PRIVATE_METHOD, JS_VAR_PRIVATE_GETTER, JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */ JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */ } JSVarKindEnum; /* XXX: could use a different structure in bytecode functions to save memory */ typedef struct JSVarDef { JSAtom var_name; /* index into fd->scopes of this variable lexical scope */ int scope_level; /* during compilation: - if scope_level = 0: scope in which the variable is defined - if scope_level != 0: index into fd->vars of the next variable in the same or enclosing lexical scope in a bytecode function: index into fd->vars of the next variable in the same or enclosing lexical scope */ int scope_next; uint8_t is_const : 1; uint8_t is_lexical : 1; uint8_t is_captured : 1; uint8_t is_static_private : 1; /* only used during private class field parsing */ uint8_t var_kind : 4; /* see JSVarKindEnum */ /* only used during compilation: function pool index for lexical variables with var_kind = JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of the definition of the 'var' variables (they have scope_level = 0) */ int func_pool_idx : 24; /* only used during compilation : index in the constant pool for hoisted function definition */ } JSVarDef; /* for the encoding of the pc2line table */ #define PC2LINE_BASE (-1) #define PC2LINE_RANGE 5 #define PC2LINE_OP_FIRST 1 #define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) typedef enum JSFunctionKindEnum { JS_FUNC_NORMAL = 0, JS_FUNC_GENERATOR = (1 << 0), JS_FUNC_ASYNC = (1 << 1), JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), } JSFunctionKindEnum; typedef struct JSFunctionBytecode { JSGCObjectHeader header; /* must come first */ uint8_t js_mode; uint8_t has_prototype : 1; /* true if a prototype field is necessary */ uint8_t has_simple_parameter_list : 1; uint8_t is_derived_class_constructor : 1; /* true if home_object needs to be initialized */ uint8_t need_home_object : 1; uint8_t func_kind : 2; uint8_t new_target_allowed : 1; uint8_t super_call_allowed : 1; uint8_t super_allowed : 1; uint8_t arguments_allowed : 1; uint8_t has_debug : 1; uint8_t backtrace_barrier : 1; /* stop backtrace on this function */ uint8_t read_only_bytecode : 1; uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */ /* XXX: 10 bits available */ uint8_t *byte_code_buf; /* (self pointer) */ int byte_code_len; JSAtom func_name; JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */ JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */ uint16_t arg_count; uint16_t var_count; uint16_t defined_arg_count; /* for length function property */ uint16_t stack_size; /* maximum stack size */ JSContext *realm; /* function realm */ JSValue *cpool; /* constant pool (self pointer) */ int cpool_count; int closure_var_count; struct { /* debug info, move to separate structure to save memory? */ JSAtom filename; int line_num; int source_len; int pc2line_len; uint8_t *pc2line_buf; char *source; } debug; } JSFunctionBytecode; typedef struct JSBoundFunction { JSValue func_obj; JSValue this_val; int argc; JSValue argv[0]; } JSBoundFunction; typedef enum JSIteratorKindEnum { JS_ITERATOR_KIND_KEY, JS_ITERATOR_KIND_VALUE, JS_ITERATOR_KIND_KEY_AND_VALUE, } JSIteratorKindEnum; typedef struct JSForInIterator { JSValue obj; uint32_t idx; uint32_t atom_count; uint8_t in_prototype_chain; uint8_t is_array; JSPropertyEnum *tab_atom; /* is_array = FALSE */ } JSForInIterator; typedef struct JSRegExp { JSString *pattern; JSString *bytecode; /* also contains the flags */ } JSRegExp; typedef struct JSProxyData { JSValue target; JSValue handler; uint8_t is_func; uint8_t is_revoked; } JSProxyData; typedef struct JSArrayBuffer { int byte_length; /* 0 if detached */ uint8_t detached; uint8_t shared; /* if shared, the array buffer cannot be detached */ uint8_t *data; /* NULL if detached */ struct list_head array_list; void *opaque; JSFreeArrayBufferDataFunc *free_func; } JSArrayBuffer; typedef struct JSTypedArray { struct list_head link; /* link to arraybuffer */ JSObject *obj; /* back pointer to the TypedArray/DataView object */ JSObject *buffer; /* based array buffer */ uint32_t offset; /* offset in the array buffer */ uint32_t length; /* length in the array buffer */ } JSTypedArray; typedef struct JSAsyncFunctionState { JSGCObjectHeader header; JSValue this_val; /* 'this' argument */ int argc; /* number of function arguments */ BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */ BOOL is_completed; /* TRUE if the function has returned. The stack frame is no longer valid */ JSValue resolving_funcs[2]; /* only used in JS async functions */ JSStackFrame frame; } JSAsyncFunctionState; typedef enum { /* binary operators */ JS_OVOP_ADD, JS_OVOP_SUB, JS_OVOP_MUL, JS_OVOP_DIV, JS_OVOP_MOD, JS_OVOP_POW, JS_OVOP_OR, JS_OVOP_AND, JS_OVOP_XOR, JS_OVOP_SHL, JS_OVOP_SAR, JS_OVOP_SHR, JS_OVOP_EQ, JS_OVOP_LESS, JS_OVOP_BINARY_COUNT, /* unary operators */ JS_OVOP_POS = JS_OVOP_BINARY_COUNT, JS_OVOP_NEG, JS_OVOP_INC, JS_OVOP_DEC, JS_OVOP_NOT, JS_OVOP_COUNT, } JSOverloadableOperatorEnum; typedef struct { uint32_t operator_index; JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */ } JSBinaryOperatorDefEntry; typedef struct { int count; JSBinaryOperatorDefEntry *tab; } JSBinaryOperatorDef; typedef struct { uint32_t operator_counter; BOOL is_primitive; /* OperatorSet for a primitive type */ /* NULL if no operator is defined */ JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */ JSBinaryOperatorDef left; JSBinaryOperatorDef right; } JSOperatorSetData; typedef struct JSReqModuleEntry { JSAtom module_name; JSModuleDef *module; /* used using resolution */ } JSReqModuleEntry; typedef enum JSExportTypeEnum { JS_EXPORT_TYPE_LOCAL, JS_EXPORT_TYPE_INDIRECT, } JSExportTypeEnum; typedef struct JSExportEntry { union { struct { int var_idx; /* closure variable index */ JSVarRef *var_ref; /* if != NULL, reference to the variable */ } local; /* for local export */ int req_module_idx; /* module for indirect export */ } u; JSExportTypeEnum export_type; JSAtom local_name; /* '*' if export ns from. not used for local export after compilation */ JSAtom export_name; /* exported variable name */ } JSExportEntry; typedef struct JSStarExportEntry { int req_module_idx; /* in req_module_entries */ } JSStarExportEntry; typedef struct JSImportEntry { int var_idx; /* closure variable index */ JSAtom import_name; int req_module_idx; /* in req_module_entries */ } JSImportEntry; typedef enum { JS_MODULE_STATUS_UNLINKED, JS_MODULE_STATUS_LINKING, JS_MODULE_STATUS_LINKED, JS_MODULE_STATUS_EVALUATING, JS_MODULE_STATUS_EVALUATING_ASYNC, JS_MODULE_STATUS_EVALUATED, } JSModuleStatus; struct JSModuleDef { JSRefCountHeader header; /* must come first, 32-bit */ JSAtom module_name; struct list_head link; JSReqModuleEntry *req_module_entries; int req_module_entries_count; int req_module_entries_size; JSExportEntry *export_entries; int export_entries_count; int export_entries_size; JSStarExportEntry *star_export_entries; int star_export_entries_count; int star_export_entries_size; JSImportEntry *import_entries; int import_entries_count; int import_entries_size; JSValue module_ns; JSValue func_obj; /* only used for JS modules */ JSModuleInitFunc *init_func; /* only used for C modules */ BOOL has_tla : 8; /* true if func_obj contains await */ BOOL resolved : 8; BOOL func_created : 8; JSModuleStatus status : 8; /* temp use during js_module_link() & js_module_evaluate() */ int dfs_index, dfs_ancestor_index; JSModuleDef *stack_prev; /* temp use during js_module_evaluate() */ JSModuleDef **async_parent_modules; int async_parent_modules_count; int async_parent_modules_size; int pending_async_dependencies; BOOL async_evaluation; int64_t async_evaluation_timestamp; JSModuleDef *cycle_root; JSValue promise; /* corresponds to spec field: capability */ JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ /* true if evaluation yielded an exception. It is saved in eval_exception */ BOOL eval_has_exception : 8; JSValue eval_exception; JSValue meta_obj; /* for import.meta */ }; typedef struct JSJobEntry { struct list_head link; JSContext *ctx; JSJobFunc *job_func; int argc; JSValue argv[0]; } JSJobEntry; typedef struct JSProperty { union { JSValue value; /* JS_PROP_NORMAL */ struct { /* JS_PROP_GETSET */ JSObject *getter; /* NULL if undefined */ JSObject *setter; /* NULL if undefined */ } getset; JSVarRef *var_ref; /* JS_PROP_VARREF */ struct { /* JS_PROP_AUTOINIT */ /* in order to use only 2 pointers, we compress the realm and the init function pointer */ uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x) in the 2 low bits */ void *opaque; } init; } u; } JSProperty; #define JS_PROP_INITIAL_SIZE 2 #define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */ #define JS_ARRAY_INITIAL_SIZE 2 typedef struct JSShapeProperty { uint32_t hash_next : 26; /* 0 if last in list */ uint32_t flags : 6; /* JS_PROP_XXX */ JSAtom atom; /* JS_ATOM_NULL = free property entry */ } JSShapeProperty; struct JSShape { /* hash table of size hash_mask + 1 before the start of the structure (see prop_hash_end()). */ JSGCObjectHeader header; /* true if the shape is inserted in the shape hash table. If not, JSShape.hash is not valid */ uint8_t is_hashed; /* If true, the shape may have small array index properties 'n' with 0 <= n <= 2^31-1. If false, the shape is guaranteed not to have small array index properties */ uint8_t has_small_array_index; uint32_t hash; /* current hash value */ uint32_t prop_hash_mask; int prop_size; /* allocated properties */ int prop_count; /* include deleted properties */ int deleted_prop_count; JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ JSObject *proto; JSShapeProperty prop[0]; /* prop_size elements */ }; struct JSObject { union { JSGCObjectHeader header; struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ uint8_t extensible : 1; uint8_t free_mark : 1; /* only used when freeing objects with cycles */ uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */ uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */ uint8_t is_constructor : 1; /* TRUE if object is a constructor function */ uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */ uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */ uint16_t class_id; /* see JS_CLASS_x */ }; }; /* byte offsets: 16/24 */ JSShape *shape; /* prototype and property names + flag */ JSProperty *prop; /* array of properties */ /* byte offsets: 24/40 */ struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */ /* byte offsets: 28/48 */ union { void *opaque; struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */ struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */ struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */ struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */ struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */ #ifdef CONFIG_BIGNUM struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */ struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */ #endif struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */ struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */ struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */ struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */ struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */ struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */ struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */ struct JSFunctionBytecode *function_bytecode; JSVarRef **var_refs; JSObject *home_object; /* for 'super' access */ } func; struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */ JSContext *realm; JSCFunctionType c_function; uint8_t length; uint8_t cproto; int16_t magic; } cfunc; /* array part for fast arrays and typed arrays */ struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ union { uint32_t size; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ } u1; union { JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ void *ptr; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ int8_t *int8_ptr; /* JS_CLASS_INT8_ARRAY */ uint8_t *uint8_ptr; /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */ int16_t *int16_ptr; /* JS_CLASS_INT16_ARRAY */ uint16_t *uint16_ptr; /* JS_CLASS_UINT16_ARRAY */ int32_t *int32_ptr; /* JS_CLASS_INT32_ARRAY */ uint32_t *uint32_ptr; /* JS_CLASS_UINT32_ARRAY */ int64_t *int64_ptr; /* JS_CLASS_INT64_ARRAY */ uint64_t *uint64_ptr; /* JS_CLASS_UINT64_ARRAY */ float *float_ptr; /* JS_CLASS_FLOAT32_ARRAY */ double *double_ptr; /* JS_CLASS_FLOAT64_ARRAY */ } u; uint32_t count; /* <= 2^31-1. 0 for a detached typed array */ } array; /* 12/20 bytes */ JSRegExp regexp; /* JS_CLASS_REGEXP: 8/16 bytes */ JSValue object_data; /* for JS_SetObjectData(): 8/16/16 bytes */ } u; /* byte sizes: 40/48/72 */ }; enum { __JS_ATOM_NULL = JS_ATOM_NULL, #define DEF(name, str) JS_ATOM_ ## name, #include "quickjs-atom.h" #undef DEF JS_ATOM_END, }; #define JS_ATOM_LAST_KEYWORD JS_ATOM_super #define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield static const char js_atom_init[] = #define DEF(name, str) str "\0" #include "quickjs-atom.h" #undef DEF ; typedef enum OPCodeFormat { #define FMT(f) OP_FMT_ ## f, #define DEF(id, size, n_pop, n_push, f) #include "quickjs-opcode.h" #undef DEF #undef FMT } OPCodeFormat; enum OPCodeEnum { #define FMT(f) #define DEF(id, size, n_pop, n_push, f) OP_ ## id, #define def(id, size, n_pop, n_push, f) #include "quickjs-opcode.h" #undef def #undef DEF #undef FMT OP_COUNT, /* excluding temporary opcodes */ /* temporary opcodes : overlap with the short opcodes */ OP_TEMP_START = OP_nop + 1, OP___dummy = OP_TEMP_START - 1, #define FMT(f) #define DEF(id, size, n_pop, n_push, f) #define def(id, size, n_pop, n_push, f) OP_ ## id, #include "quickjs-opcode.h" #undef def #undef DEF #undef FMT OP_TEMP_END, }; static int JS_InitAtoms(JSRuntime *rt); static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, int atom_type); static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p); static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b); static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags); static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags); static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, JSValueConst new_target, int argc, JSValue *argv, int flags); static JSValue JS_CallConstructorInternal(JSContext *ctx, JSValueConst func_obj, JSValueConst new_target, int argc, JSValue *argv, int flags); static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, int argc, JSValueConst *argv); static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, int argc, JSValueConst *argv); static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, JSValue val, BOOL is_array_ctor); static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, JSValueConst val, int flags, int scope_idx); static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p); static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt); static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p); static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p); static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val); static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val); static __maybe_unused void JS_PrintValue(JSContext *ctx, const char *str, JSValueConst val); static __maybe_unused void JS_DumpShapes(JSRuntime *rt); static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); static void js_array_finalizer(JSRuntime *rt, JSValue val); static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_object_data_finalizer(JSRuntime *rt, JSValue val); static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_c_function_finalizer(JSRuntime *rt, JSValue val); static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val); static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_bound_function_finalizer(JSRuntime *rt, JSValue val); static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_regexp_finalizer(JSRuntime *rt, JSValue val); static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val); static void js_typed_array_finalizer(JSRuntime *rt, JSValue val); static void js_typed_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_proxy_finalizer(JSRuntime *rt, JSValue val); static void js_proxy_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_map_finalizer(JSRuntime *rt, JSValue val); static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_generator_finalizer(JSRuntime *rt, JSValue obj); static void js_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_promise_finalizer(JSRuntime *rt, JSValue val); static void js_promise_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val); static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); #ifdef CONFIG_BIGNUM static void js_operator_set_finalizer(JSRuntime *rt, JSValue val); static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); #endif #define HINT_STRING 0 #define HINT_NUMBER 1 #define HINT_NONE 2 #define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint); static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); static int JS_ToBoolFree(JSContext *ctx, JSValue val); static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val); static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val); static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val); static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, JSValueConst flags); static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, JSValue pattern, JSValue bc); static void gc_decref(JSRuntime *rt); static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def, JSAtom name); typedef enum JSStrictEqModeEnum { JS_EQ_STRICT, JS_EQ_SAME_VALUE, JS_EQ_SAME_VALUE_ZERO, } JSStrictEqModeEnum; static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode); static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2); static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2); static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2); static JSValue JS_ToObject(JSContext *ctx, JSValueConst val); static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val); static JSProperty *add_property(JSContext *ctx, JSObject *p, JSAtom prop, int prop_flags); static JSValue JS_NewBigInt(JSContext *ctx); static inline bf_t *JS_GetBigInt(JSValueConst val) { JSBigFloat *p = JS_VALUE_GET_PTR(val); return &p->num; } static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, BOOL convert_to_safe_integer); static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); #ifdef CONFIG_BIGNUM static void js_float_env_finalizer(JSRuntime *rt, JSValue val); static JSValue JS_NewBigFloat(JSContext *ctx); static inline bf_t *JS_GetBigFloat(JSValueConst val) { JSBigFloat *p = JS_VALUE_GET_PTR(val); return &p->num; } static JSValue JS_NewBigDecimal(JSContext *ctx); static inline bfdec_t *JS_GetBigDecimal(JSValueConst val) { JSBigDecimal *p = JS_VALUE_GET_PTR(val); return &p->num; } static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val); static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, BOOL allow_null_or_undefined); static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val); #endif static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx); static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj); static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, JSValueConst proto_val, BOOL throw_flag); static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception); static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj); static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj); static int JS_CreateProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags); static int js_string_memcmp(const JSString *p1, const JSString *p2, int len); static void reset_weak_ref(JSRuntime *rt, JSObject *p); static JSValue js_array_buffer_constructor3(JSContext *ctx, JSValueConst new_target, uint64_t len, JSClassID class_id, uint8_t *buf, JSFreeArrayBufferDataFunc *free_func, void *opaque, BOOL alloc_flag); static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj); static JSValue js_typed_array_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int classid); static JSValue js_typed_array_constructor_ta(JSContext *ctx, JSValueConst new_target, JSValueConst src_obj, int classid); static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p); static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg); static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags); static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val); static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, const char *filename, int line, int flags, int scope_idx); static void js_free_module_def(JSContext *ctx, JSModuleDef *m); static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkFunc *mark_func); static JSValue js_import_meta(JSContext *ctx); static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier); static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref); static JSValue js_new_promise_capability(JSContext *ctx, JSValue *resolving_funcs, JSValueConst ctor); static __exception int perform_promise_then(JSContext *ctx, JSValueConst promise, JSValueConst *resolve_reject, JSValueConst *cap_resolving_funcs); static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); static int js_string_compare(JSContext *ctx, const JSString *p1, const JSString *p2); static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags); static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val); static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val); static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val); static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSObject *p, JSAtom prop); static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc); static void JS_AddIntrinsicBasicObjects(JSContext *ctx); static void js_free_shape(JSRuntime *rt, JSShape *sh); static void js_free_shape_null(JSRuntime *rt, JSShape *sh); static int js_shape_prepare_update(JSContext *ctx, JSObject *p, JSShapeProperty **pprs); static int init_shape_hash(JSRuntime *rt); static __exception int js_get_length32(JSContext *ctx, uint32_t *pres, JSValueConst obj); static __exception int js_get_length64(JSContext *ctx, int64_t *pres, JSValueConst obj); static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len); static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, JSValueConst array_arg); static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, JSValue **arrpp, uint32_t *countp); static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, JSValueConst sync_iter); static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val); static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_val, int argc, JSValueConst *argv, int flags); static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val); static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type); static void remove_gc_object(JSGCObjectHeader *h); static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int is_map); static const JSClassExoticMethods js_arguments_exotic_methods; static const JSClassExoticMethods js_string_exotic_methods; static const JSClassExoticMethods js_proxy_exotic_methods; static const JSClassExoticMethods js_module_ns_exotic_methods; static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; static void js_trigger_gc(JSRuntime *rt, size_t size) { BOOL force_gc; #ifdef FORCE_GC_AT_MALLOC force_gc = TRUE; #else force_gc = ((rt->malloc_state.malloc_size + size) > rt->malloc_gc_threshold); #endif if (force_gc) { #ifdef DUMP_GC printf("GC: size=%" PRIu64 "\n", (uint64_t)rt->malloc_state.malloc_size); #endif JS_RunGC(rt); rt->malloc_gc_threshold = rt->malloc_state.malloc_size + (rt->malloc_state.malloc_size >> 1); } } static size_t js_malloc_usable_size_unknown(const void *ptr) { return 0; } void *js_malloc_rt(JSRuntime *rt, size_t size) { return rt->mf.js_malloc(&rt->malloc_state, size); } void js_free_rt(JSRuntime *rt, void *ptr) { rt->mf.js_free(&rt->malloc_state, ptr); } void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size) { return rt->mf.js_realloc(&rt->malloc_state, ptr, size); } size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr) { return rt->mf.js_malloc_usable_size(ptr); } void *js_mallocz_rt(JSRuntime *rt, size_t size) { void *ptr; ptr = js_malloc_rt(rt, size); if (!ptr) return NULL; return memset(ptr, 0, size); } /* called by libbf */ static void *js_bf_realloc(void *opaque, void *ptr, size_t size) { JSRuntime *rt = opaque; return js_realloc_rt(rt, ptr, size); } /* Throw out of memory in case of error */ void *js_malloc(JSContext *ctx, size_t size) { void *ptr; ptr = js_malloc_rt(ctx->rt, size); if (unlikely(!ptr)) { JS_ThrowOutOfMemory(ctx); return NULL; } return ptr; } /* Throw out of memory in case of error */ void *js_mallocz(JSContext *ctx, size_t size) { void *ptr; ptr = js_mallocz_rt(ctx->rt, size); if (unlikely(!ptr)) { JS_ThrowOutOfMemory(ctx); return NULL; } return ptr; } void js_free(JSContext *ctx, void *ptr) { js_free_rt(ctx->rt, ptr); } /* Throw out of memory in case of error */ void *js_realloc(JSContext *ctx, void *ptr, size_t size) { void *ret; ret = js_realloc_rt(ctx->rt, ptr, size); if (unlikely(!ret && size != 0)) { JS_ThrowOutOfMemory(ctx); return NULL; } return ret; } /* store extra allocated size in *pslack if successful */ void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack) { void *ret; ret = js_realloc_rt(ctx->rt, ptr, size); if (unlikely(!ret && size != 0)) { JS_ThrowOutOfMemory(ctx); return NULL; } if (pslack) { size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret); *pslack = (new_size > size) ? new_size - size : 0; } return ret; } size_t js_malloc_usable_size(JSContext *ctx, const void *ptr) { return js_malloc_usable_size_rt(ctx->rt, ptr); } /* Throw out of memory exception in case of error */ char *js_strndup(JSContext *ctx, const char *s, size_t n) { char *ptr; ptr = js_malloc(ctx, n + 1); if (ptr) { memcpy(ptr, s, n); ptr[n] = '\0'; } return ptr; } char *js_strdup(JSContext *ctx, const char *str) { return js_strndup(ctx, str, strlen(str)); } static no_inline int js_realloc_array(JSContext *ctx, void **parray, int elem_size, int *psize, int req_size) { int new_size; size_t slack; void *new_array; /* XXX: potential arithmetic overflow */ new_size = max_int(req_size, *psize * 3 / 2); new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack); if (!new_array) return -1; new_size += slack / elem_size; *psize = new_size; *parray = new_array; return 0; } /* resize the array and update its size if req_size > *psize */ static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size, int *psize, int req_size) { if (unlikely(req_size > *psize)) return js_realloc_array(ctx, parray, elem_size, psize, req_size); else return 0; } static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) { dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt); } static inline int is_digit(int c) { return c >= '0' && c <= '9'; } static inline int string_get(const JSString *p, int idx) { return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx]; } typedef struct JSClassShortDef { JSAtom class_name; JSClassFinalizer *finalizer; JSClassGCMark *gc_mark; } JSClassShortDef; static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */ { JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */ { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */ { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */ { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */ { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */ { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */ { JS_ATOM_Arguments, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARGUMENTS */ { JS_ATOM_Arguments, NULL, NULL }, /* JS_CLASS_MAPPED_ARGUMENTS */ { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */ { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_MODULE_NS */ { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */ { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */ { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */ { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */ { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_GENERATOR_FUNCTION */ { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */ { JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */ { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_ARRAY_BUFFER */ { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_SHARED_ARRAY_BUFFER */ { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */ { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT8_ARRAY */ { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8_ARRAY */ { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT16_ARRAY */ { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */ { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */ { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */ { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */ { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */ { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */ { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */ { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */ { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ #ifdef CONFIG_BIGNUM { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */ { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */ { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */ { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark }, /* JS_CLASS_OPERATOR_SET */ #endif { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */ { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */ { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKMAP */ { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */ { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */ { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */ { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */ { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */ }; static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, int start, int count) { JSClassDef cm_s, *cm = &cm_s; int i, class_id; for(i = 0; i < count; i++) { class_id = i + start; memset(cm, 0, sizeof(*cm)); cm->finalizer = tab[i].finalizer; cm->gc_mark = tab[i].gc_mark; if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0) return -1; } return 0; } static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx) { return JS_ThrowTypeError(ctx, "unsupported operation"); } static JSValue invalid_to_string(JSContext *ctx, JSValueConst val) { return JS_ThrowUnsupportedOperation(ctx); } static JSValue invalid_from_string(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { return JS_NAN; } static int invalid_unary_arith(JSContext *ctx, JSValue *pres, OPCodeEnum op, JSValue op1) { JS_FreeValue(ctx, op1); JS_ThrowUnsupportedOperation(ctx); return -1; } static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); JS_ThrowUnsupportedOperation(ctx); return -1; } static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, int64_t exponent) { return JS_ThrowUnsupportedOperation(ctx); } static int invalid_mul_pow10(JSContext *ctx, JSValue *sp) { JS_ThrowUnsupportedOperation(ctx); return -1; } static void set_dummy_numeric_ops(JSNumericOperations *ops) { ops->to_string = invalid_to_string; ops->from_string = invalid_from_string; ops->unary_arith = invalid_unary_arith; ops->binary_arith = invalid_binary_arith; ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64; ops->mul_pow10 = invalid_mul_pow10; } #if !defined(CONFIG_STACK_CHECK) /* no stack limitation */ static inline uintptr_t js_get_stack_pointer(void) { return 0; } static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { return FALSE; } #else // Uses code from LLVM project. static inline uintptr_t js_get_stack_pointer(void) { #ifdef _MSC_VER return (uintptr_t) _AddressOfReturnAddress(); #elif defined __has_builtin #if __has_builtin(__builtin_frame_address) return (uintptr_t) __builtin_frame_address(0); #endif #elif defined __GNUC__ return (uintptr_t) __builtin_frame_address(0); #else char CharOnStack = 0; // The volatile store here is intended to escape the local variable, to // prevent the compiler from optimizing CharOnStack into anything other // than a char on the stack. // // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. char *volatile Ptr = &CharOnStack; return (uintptr_t) Ptr; #endif } static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { uintptr_t sp; sp = js_get_stack_pointer() - alloca_size; return unlikely(sp < rt->stack_limit); } #endif JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) { JSRuntime *rt; JSMallocState ms; memset(&ms, 0, sizeof(ms)); ms.opaque = opaque; ms.malloc_limit = -1; rt = mf->js_malloc(&ms, sizeof(JSRuntime)); if (!rt) return NULL; memset(rt, 0, sizeof(*rt)); rt->mf = *mf; if (!rt->mf.js_malloc_usable_size) { /* use dummy function if none provided */ rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown; } rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); set_dummy_numeric_ops(&rt->bigint_ops); #ifdef CONFIG_BIGNUM set_dummy_numeric_ops(&rt->bigfloat_ops); set_dummy_numeric_ops(&rt->bigdecimal_ops); #endif init_list_head(&rt->context_list); init_list_head(&rt->gc_obj_list); init_list_head(&rt->gc_zero_ref_count_list); rt->gc_phase = JS_GC_PHASE_NONE; #ifdef DUMP_LEAKS init_list_head(&rt->string_list); #endif init_list_head(&rt->job_list); if (JS_InitAtoms(rt)) goto fail; /* create the object, array and function classes */ if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT, countof(js_std_class_def)) < 0) goto fail; rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods; rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods; rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods; rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function; rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call; rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function; rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call; if (init_shape_hash(rt)) goto fail; rt->stack_size = JS_DEFAULT_STACK_SIZE; JS_UpdateStackTop(rt); rt->current_exception = JS_NULL; return rt; fail: JS_FreeRuntime(rt); return NULL; } void *JS_GetRuntimeOpaque(JSRuntime *rt) { return rt->user_opaque; } void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) { rt->user_opaque = opaque; } /* default memory allocation functions with memory limitation */ static size_t js_def_malloc_usable_size(const void *ptr) { #if defined(__APPLE__) return malloc_size(ptr); #elif defined(_WIN32) return _msize((void *)ptr); #elif defined(EMSCRIPTEN) return 0; #elif defined(__linux__) return malloc_usable_size((void *)ptr); #else /* change this to `return 0;` if compilation fails */ return malloc_usable_size((void *)ptr); #endif } static void *js_def_malloc(JSMallocState *s, size_t size) { void *ptr; /* Do not allocate zero bytes: behavior is platform dependent */ assert(size != 0); if (unlikely(s->malloc_size + size > s->malloc_limit)) return NULL; ptr = malloc(size); if (!ptr) return NULL; s->malloc_count++; s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD; return ptr; } static void js_def_free(JSMallocState *s, void *ptr) { if (!ptr) return; s->malloc_count--; s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD; free(ptr); } static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size) { size_t old_size; if (!ptr) { if (size == 0) return NULL; return js_def_malloc(s, size); } old_size = js_def_malloc_usable_size(ptr); if (size == 0) { s->malloc_count--; s->malloc_size -= old_size + MALLOC_OVERHEAD; free(ptr); return NULL; } if (s->malloc_size + size - old_size > s->malloc_limit) return NULL; ptr = realloc(ptr, size); if (!ptr) return NULL; s->malloc_size += js_def_malloc_usable_size(ptr) - old_size; return ptr; } static const JSMallocFunctions def_malloc_funcs = { js_def_malloc, js_def_free, js_def_realloc, js_def_malloc_usable_size, }; JSRuntime *JS_NewRuntime(void) { return JS_NewRuntime2(&def_malloc_funcs, NULL); } void JS_SetMemoryLimit(JSRuntime *rt, size_t limit) { rt->malloc_state.malloc_limit = limit; } /* use -1 to disable automatic GC */ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) { rt->malloc_gc_threshold = gc_threshold; } #define malloc(s) malloc_is_forbidden(s) #define free(p) free_is_forbidden(p) #define realloc(p,s) realloc_is_forbidden(p,s) void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque) { rt->interrupt_handler = cb; rt->interrupt_opaque = opaque; } void JS_SetCanBlock(JSRuntime *rt, BOOL can_block) { rt->can_block = can_block; } void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf) { rt->sab_funcs = *sf; } /* return 0 if OK, < 0 if exception */ int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv) { JSRuntime *rt = ctx->rt; JSJobEntry *e; int i; e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue)); if (!e) return -1; e->ctx = ctx; e->job_func = job_func; e->argc = argc; for(i = 0; i < argc; i++) { e->argv[i] = JS_DupValue(ctx, argv[i]); } list_add_tail(&e->link, &rt->job_list); return 0; } BOOL JS_IsJobPending(JSRuntime *rt) { return !list_empty(&rt->job_list); } /* return < 0 if exception, 0 if no job pending, 1 if a job was executed successfully. the context of the job is stored in '*pctx' */ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) { JSContext *ctx; JSJobEntry *e; JSValue res; int i, ret; if (list_empty(&rt->job_list)) { *pctx = NULL; return 0; } /* get the first pending job and execute it */ e = list_entry(rt->job_list.next, JSJobEntry, link); list_del(&e->link); ctx = e->ctx; res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv); for(i = 0; i < e->argc; i++) JS_FreeValue(ctx, e->argv[i]); if (JS_IsException(res)) ret = -1; else ret = 1; JS_FreeValue(ctx, res); js_free(ctx, e); *pctx = ctx; return ret; } static inline uint32_t atom_get_free(const JSAtomStruct *p) { return (uintptr_t)p >> 1; } static inline BOOL atom_is_free(const JSAtomStruct *p) { return (uintptr_t)p & 1; } static inline JSAtomStruct *atom_set_free(uint32_t v) { return (JSAtomStruct *)(((uintptr_t)v << 1) | 1); } /* Note: the string contents are uninitialized */ static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char) { JSString *str; str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char); if (unlikely(!str)) return NULL; str->header.ref_count = 1; str->is_wide_char = is_wide_char; str->len = max_len; str->atom_type = 0; str->hash = 0; /* optional but costless */ str->hash_next = 0; /* optional */ #ifdef DUMP_LEAKS list_add_tail(&str->link, &rt->string_list); #endif return str; } static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char) { JSString *p; p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char); if (unlikely(!p)) { JS_ThrowOutOfMemory(ctx); return NULL; } return p; } /* same as JS_FreeValueRT() but faster */ static inline void js_free_string(JSRuntime *rt, JSString *str) { if (--str->header.ref_count <= 0) { if (str->atom_type) { JS_FreeAtomStruct(rt, str); } else { #ifdef DUMP_LEAKS list_del(&str->link); #endif js_free_rt(rt, str); } } } void JS_SetRuntimeInfo(JSRuntime *rt, const char *s) { if (rt) rt->rt_info = s; } void JS_FreeRuntime(JSRuntime *rt) { struct list_head *el, *el1; int i; JS_FreeValueRT(rt, rt->current_exception); list_for_each_safe(el, el1, &rt->job_list) { JSJobEntry *e = list_entry(el, JSJobEntry, link); for(i = 0; i < e->argc; i++) JS_FreeValueRT(rt, e->argv[i]); js_free_rt(rt, e); } init_list_head(&rt->job_list); JS_RunGC(rt); #ifdef DUMP_LEAKS /* leaking objects */ { BOOL header_done; JSGCObjectHeader *p; int count; /* remove the internal refcounts to display only the object referenced externally */ list_for_each(el, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); p->mark = 0; } gc_decref(rt); header_done = FALSE; list_for_each(el, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); if (p->ref_count != 0) { if (!header_done) { printf("Object leaks:\n"); JS_DumpObjectHeader(rt); header_done = TRUE; } JS_DumpGCObject(rt, p); } } count = 0; list_for_each(el, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); if (p->ref_count == 0) { count++; } } if (count != 0) printf("Secondary object leaks: %d\n", count); } #endif fflush(stdout); assert(list_empty(&rt->gc_obj_list)); /* free the classes */ for(i = 0; i < rt->class_count; i++) { JSClass *cl = &rt->class_array[i]; if (cl->class_id != 0) { JS_FreeAtomRT(rt, cl->class_name); } } js_free_rt(rt, rt->class_array); bf_context_end(&rt->bf_ctx); #ifdef DUMP_LEAKS /* only the atoms defined in JS_InitAtoms() should be left */ { BOOL header_done = FALSE; for(i = 0; i < rt->atom_size; i++) { JSAtomStruct *p = rt->atom_array[i]; if (!atom_is_free(p) /* && p->str*/) { if (i >= JS_ATOM_END || p->header.ref_count != 1) { if (!header_done) { header_done = TRUE; if (rt->rt_info) { printf("%s:1: atom leakage:", rt->rt_info); } else { printf("Atom leaks:\n" " %6s %6s %s\n", "ID", "REFCNT", "NAME"); } } if (rt->rt_info) { printf(" "); } else { printf(" %6u %6u ", i, p->header.ref_count); } switch (p->atom_type) { case JS_ATOM_TYPE_STRING: JS_DumpString(rt, p); break; case JS_ATOM_TYPE_GLOBAL_SYMBOL: printf("Symbol.for("); JS_DumpString(rt, p); printf(")"); break; case JS_ATOM_TYPE_SYMBOL: if (p->hash == JS_ATOM_HASH_SYMBOL) { printf("Symbol("); JS_DumpString(rt, p); printf(")"); } else { printf("Private("); JS_DumpString(rt, p); printf(")"); } break; } if (rt->rt_info) { printf(":%u", p->header.ref_count); } else { printf("\n"); } } } } if (rt->rt_info && header_done) printf("\n"); } #endif /* free the atoms */ for(i = 0; i < rt->atom_size; i++) { JSAtomStruct *p = rt->atom_array[i]; if (!atom_is_free(p)) { #ifdef DUMP_LEAKS list_del(&p->link); #endif js_free_rt(rt, p); } } js_free_rt(rt, rt->atom_array); js_free_rt(rt, rt->atom_hash); js_free_rt(rt, rt->shape_hash); #ifdef DUMP_LEAKS if (!list_empty(&rt->string_list)) { if (rt->rt_info) { printf("%s:1: string leakage:", rt->rt_info); } else { printf("String leaks:\n" " %6s %s\n", "REFCNT", "VALUE"); } list_for_each_safe(el, el1, &rt->string_list) { JSString *str = list_entry(el, JSString, link); if (rt->rt_info) { printf(" "); } else { printf(" %6u ", str->header.ref_count); } JS_DumpString(rt, str); if (rt->rt_info) { printf(":%u", str->header.ref_count); } else { printf("\n"); } list_del(&str->link); js_free_rt(rt, str); } if (rt->rt_info) printf("\n"); } { JSMallocState *s = &rt->malloc_state; if (s->malloc_count > 1) { if (rt->rt_info) printf("%s:1: ", rt->rt_info); printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n", (uint64_t)(s->malloc_size - sizeof(JSRuntime)), (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]); } } #endif { JSMallocState ms = rt->malloc_state; rt->mf.js_free(&ms, rt); } } JSContext *JS_NewContextRaw(JSRuntime *rt) { JSContext *ctx; int i; ctx = js_mallocz_rt(rt, sizeof(JSContext)); if (!ctx) return NULL; ctx->header.ref_count = 1; add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT); ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) * rt->class_count); if (!ctx->class_proto) { js_free_rt(rt, ctx); return NULL; } ctx->rt = rt; list_add_tail(&ctx->link, &rt->context_list); ctx->bf_ctx = &rt->bf_ctx; #ifdef CONFIG_BIGNUM ctx->fp_env.prec = 113; ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL; #endif for(i = 0; i < rt->class_count; i++) ctx->class_proto[i] = JS_NULL; ctx->array_ctor = JS_NULL; ctx->regexp_ctor = JS_NULL; ctx->promise_ctor = JS_NULL; init_list_head(&ctx->loaded_modules); JS_AddIntrinsicBasicObjects(ctx); return ctx; } JSContext *JS_NewContext(JSRuntime *rt) { JSContext *ctx; ctx = JS_NewContextRaw(rt); if (!ctx) return NULL; JS_AddIntrinsicBaseObjects(ctx); JS_AddIntrinsicDate(ctx); JS_AddIntrinsicEval(ctx); JS_AddIntrinsicStringNormalize(ctx); JS_AddIntrinsicRegExp(ctx); JS_AddIntrinsicJSON(ctx); JS_AddIntrinsicProxy(ctx); JS_AddIntrinsicMapSet(ctx); JS_AddIntrinsicTypedArrays(ctx); JS_AddIntrinsicPromise(ctx); JS_AddIntrinsicBigInt(ctx); return ctx; } void *JS_GetContextOpaque(JSContext *ctx) { return ctx->user_opaque; } void JS_SetContextOpaque(JSContext *ctx, void *opaque) { ctx->user_opaque = opaque; } /* set the new value and free the old value after (freeing the value can reallocate the object data) */ static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val) { JSValue old_val; old_val = *pval; *pval = new_val; JS_FreeValue(ctx, old_val); } void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj) { JSRuntime *rt = ctx->rt; assert(class_id < rt->class_count); set_value(ctx, &ctx->class_proto[class_id], obj); } JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) { JSRuntime *rt = ctx->rt; assert(class_id < rt->class_count); return JS_DupValue(ctx, ctx->class_proto[class_id]); } typedef enum JSFreeModuleEnum { JS_FREE_MODULE_ALL, JS_FREE_MODULE_NOT_RESOLVED, } JSFreeModuleEnum; /* XXX: would be more efficient with separate module lists */ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) { struct list_head *el, *el1; list_for_each_safe(el, el1, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el, JSModuleDef, link); if (flag == JS_FREE_MODULE_ALL || (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { js_free_module_def(ctx, m); } } } JSContext *JS_DupContext(JSContext *ctx) { ctx->header.ref_count++; return ctx; } /* used by the GC */ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, JS_MarkFunc *mark_func) { int i; struct list_head *el; /* modules are not seen by the GC, so we directly mark the objects referenced by each module */ list_for_each(el, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el, JSModuleDef, link); js_mark_module_def(rt, m, mark_func); } JS_MarkValue(rt, ctx->global_obj, mark_func); JS_MarkValue(rt, ctx->global_var_obj, mark_func); JS_MarkValue(rt, ctx->throw_type_error, mark_func); JS_MarkValue(rt, ctx->eval_obj, mark_func); JS_MarkValue(rt, ctx->array_proto_values, mark_func); for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { JS_MarkValue(rt, ctx->native_error_proto[i], mark_func); } for(i = 0; i < rt->class_count; i++) { JS_MarkValue(rt, ctx->class_proto[i], mark_func); } JS_MarkValue(rt, ctx->iterator_proto, mark_func); JS_MarkValue(rt, ctx->async_iterator_proto, mark_func); JS_MarkValue(rt, ctx->promise_ctor, mark_func); JS_MarkValue(rt, ctx->array_ctor, mark_func); JS_MarkValue(rt, ctx->regexp_ctor, mark_func); JS_MarkValue(rt, ctx->function_ctor, mark_func); JS_MarkValue(rt, ctx->function_proto, mark_func); if (ctx->array_shape) mark_func(rt, &ctx->array_shape->header); } void JS_FreeContext(JSContext *ctx) { JSRuntime *rt = ctx->rt; int i; if (--ctx->header.ref_count > 0) return; assert(ctx->header.ref_count == 0); #ifdef DUMP_ATOMS JS_DumpAtoms(ctx->rt); #endif #ifdef DUMP_SHAPES JS_DumpShapes(ctx->rt); #endif #ifdef DUMP_OBJECTS { struct list_head *el; JSGCObjectHeader *p; printf("JSObjects: {\n"); JS_DumpObjectHeader(ctx->rt); list_for_each(el, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); JS_DumpGCObject(rt, p); } printf("}\n"); } #endif #ifdef DUMP_MEM { JSMemoryUsage stats; JS_ComputeMemoryUsage(rt, &stats); JS_DumpMemoryUsage(stdout, &stats, rt); } #endif js_free_modules(ctx, JS_FREE_MODULE_ALL); JS_FreeValue(ctx, ctx->global_obj); JS_FreeValue(ctx, ctx->global_var_obj); JS_FreeValue(ctx, ctx->throw_type_error); JS_FreeValue(ctx, ctx->eval_obj); JS_FreeValue(ctx, ctx->array_proto_values); for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { JS_FreeValue(ctx, ctx->native_error_proto[i]); } for(i = 0; i < rt->class_count; i++) { JS_FreeValue(ctx, ctx->class_proto[i]); } js_free_rt(rt, ctx->class_proto); JS_FreeValue(ctx, ctx->iterator_proto); JS_FreeValue(ctx, ctx->async_iterator_proto); JS_FreeValue(ctx, ctx->promise_ctor); JS_FreeValue(ctx, ctx->array_ctor); JS_FreeValue(ctx, ctx->regexp_ctor); JS_FreeValue(ctx, ctx->function_ctor); JS_FreeValue(ctx, ctx->function_proto); js_free_shape_null(ctx->rt, ctx->array_shape); list_del(&ctx->link); remove_gc_object(&ctx->header); js_free_rt(ctx->rt, ctx); } JSRuntime *JS_GetRuntime(JSContext *ctx) { return ctx->rt; } static void update_stack_limit(JSRuntime *rt) { if (rt->stack_size == 0) { rt->stack_limit = 0; /* no limit */ } else { rt->stack_limit = rt->stack_top - rt->stack_size; } } void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size) { rt->stack_size = stack_size; update_stack_limit(rt); } void JS_UpdateStackTop(JSRuntime *rt) { rt->stack_top = js_get_stack_pointer(); update_stack_limit(rt); } static inline BOOL is_strict_mode(JSContext *ctx) { JSStackFrame *sf = ctx->rt->current_stack_frame; return (sf && (sf->js_mode & JS_MODE_STRICT)); } #ifdef CONFIG_BIGNUM static inline BOOL is_math_mode(JSContext *ctx) { JSStackFrame *sf = ctx->rt->current_stack_frame; return (sf && (sf->js_mode & JS_MODE_MATH)); } #else static inline BOOL is_math_mode(JSContext *ctx) { return FALSE; } #endif /* JSAtom support */ #define JS_ATOM_TAG_INT (1U << 31) #define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1) #define JS_ATOM_MAX ((1U << 30) - 1) /* return the max count from the hash size */ #define JS_ATOM_COUNT_RESIZE(n) ((n) * 2) static inline BOOL __JS_AtomIsConst(JSAtom v) { #if defined(DUMP_LEAKS) && DUMP_LEAKS > 1 return (int32_t)v <= 0; #else return (int32_t)v < JS_ATOM_END; #endif } static inline BOOL __JS_AtomIsTaggedInt(JSAtom v) { return (v & JS_ATOM_TAG_INT) != 0; } static inline JSAtom __JS_AtomFromUInt32(uint32_t v) { return v | JS_ATOM_TAG_INT; } static inline uint32_t __JS_AtomToUInt32(JSAtom atom) { return atom & ~JS_ATOM_TAG_INT; } static inline int is_num(int c) { return c >= '0' && c <= '9'; } /* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */ static inline BOOL is_num_string(uint32_t *pval, const JSString *p) { uint32_t n; uint64_t n64; int c, i, len; len = p->len; if (len == 0 || len > 10) return FALSE; c = string_get(p, 0); if (is_num(c)) { if (c == '0') { if (len != 1) return FALSE; n = 0; } else { n = c - '0'; for(i = 1; i < len; i++) { c = string_get(p, i); if (!is_num(c)) return FALSE; n64 = (uint64_t)n * 10 + (c - '0'); if ((n64 >> 32) != 0) return FALSE; n = n64; } } *pval = n; return TRUE; } else { return FALSE; } } /* XXX: could use faster version ? */ static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h) { size_t i; for(i = 0; i < len; i++) h = h * 263 + str[i]; return h; } static inline uint32_t hash_string16(const uint16_t *str, size_t len, uint32_t h) { size_t i; for(i = 0; i < len; i++) h = h * 263 + str[i]; return h; } static uint32_t hash_string(const JSString *str, uint32_t h) { if (str->is_wide_char) h = hash_string16(str->u.str16, str->len, h); else h = hash_string8(str->u.str8, str->len, h); return h; } static __maybe_unused void JS_DumpChar(JSRuntime *rt, int c, int sep) { if (c == sep || c == '\\') { putchar('\\'); putchar(c); } else if (c >= ' ' && c <= 126) { putchar(c); } else if (c == '\n') { putchar('\\'); putchar('n'); } else { printf("\\u%04x", c); } } static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p) { int i, sep; if (p == NULL) { printf(""); return; } printf("%d", p->header.ref_count); sep = (p->header.ref_count == 1) ? '\"' : '\''; putchar(sep); for(i = 0; i < p->len; i++) { JS_DumpChar(rt, string_get(p, i), sep); } putchar(sep); } static __maybe_unused void JS_DumpAtoms(JSRuntime *rt) { JSAtomStruct *p; int h, i; /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */ printf("JSAtom count=%d size=%d hash_size=%d:\n", rt->atom_count, rt->atom_size, rt->atom_hash_size); printf("JSAtom hash table: {\n"); for(i = 0; i < rt->atom_hash_size; i++) { h = rt->atom_hash[i]; if (h) { printf(" %d:", i); while (h) { p = rt->atom_array[h]; printf(" "); JS_DumpString(rt, p); h = p->hash_next; } printf("\n"); } } printf("}\n"); printf("JSAtom table: {\n"); for(i = 0; i < rt->atom_size; i++) { p = rt->atom_array[i]; if (!atom_is_free(p)) { printf(" %d: { %d %08x ", i, p->atom_type, p->hash); if (!(p->len == 0 && p->is_wide_char != 0)) JS_DumpString(rt, p); printf(" %d }\n", p->hash_next); } } printf("}\n"); } static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size) { JSAtomStruct *p; uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash; assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */ new_hash_mask = new_hash_size - 1; new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size); if (!new_hash) return -1; for(i = 0; i < rt->atom_hash_size; i++) { h = rt->atom_hash[i]; while (h != 0) { p = rt->atom_array[h]; hash_next1 = p->hash_next; /* add in new hash table */ j = p->hash & new_hash_mask; p->hash_next = new_hash[j]; new_hash[j] = h; h = hash_next1; } } js_free_rt(rt, rt->atom_hash); rt->atom_hash = new_hash; rt->atom_hash_size = new_hash_size; rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size); // JS_DumpAtoms(rt); return 0; } static int JS_InitAtoms(JSRuntime *rt) { int i, len, atom_type; const char *p; rt->atom_hash_size = 0; rt->atom_hash = NULL; rt->atom_count = 0; rt->atom_size = 0; rt->atom_free_index = 0; if (JS_ResizeAtomHash(rt, 256)) /* there are at least 195 predefined atoms */ return -1; p = js_atom_init; for(i = 1; i < JS_ATOM_END; i++) { if (i == JS_ATOM_Private_brand) atom_type = JS_ATOM_TYPE_PRIVATE; else if (i >= JS_ATOM_Symbol_toPrimitive) atom_type = JS_ATOM_TYPE_SYMBOL; else atom_type = JS_ATOM_TYPE_STRING; len = strlen(p); if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL) return -1; p = p + len + 1; } return 0; } static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v) { JSAtomStruct *p; if (!__JS_AtomIsConst(v)) { p = rt->atom_array[v]; p->header.ref_count++; } return v; } JSAtom JS_DupAtom(JSContext *ctx, JSAtom v) { JSRuntime *rt; JSAtomStruct *p; if (!__JS_AtomIsConst(v)) { rt = ctx->rt; p = rt->atom_array[v]; p->header.ref_count++; } return v; } static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v) { JSRuntime *rt; JSAtomStruct *p; rt = ctx->rt; if (__JS_AtomIsTaggedInt(v)) return JS_ATOM_KIND_STRING; p = rt->atom_array[v]; switch(p->atom_type) { case JS_ATOM_TYPE_STRING: return JS_ATOM_KIND_STRING; case JS_ATOM_TYPE_GLOBAL_SYMBOL: return JS_ATOM_KIND_SYMBOL; case JS_ATOM_TYPE_SYMBOL: switch(p->hash) { case JS_ATOM_HASH_SYMBOL: return JS_ATOM_KIND_SYMBOL; case JS_ATOM_HASH_PRIVATE: return JS_ATOM_KIND_PRIVATE; default: abort(); } default: abort(); } } static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v) { return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING; } static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p) { uint32_t i = p->hash_next; /* atom_index */ if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { JSAtomStruct *p1; i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)]; p1 = rt->atom_array[i]; while (p1 != p) { assert(i != 0); i = p1->hash_next; p1 = rt->atom_array[i]; } } return i; } /* string case (internal). Return JS_ATOM_NULL if error. 'str' is freed. */ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) { uint32_t h, h1, i; JSAtomStruct *p; int len; #if 0 printf("__JS_NewAtom: "); JS_DumpString(rt, str); printf("\n"); #endif if (atom_type < JS_ATOM_TYPE_SYMBOL) { /* str is not NULL */ if (str->atom_type == atom_type) { /* str is the atom, return its index */ i = js_get_atom_index(rt, str); /* reduce string refcount and increase atom's unless constant */ if (__JS_AtomIsConst(i)) str->header.ref_count--; return i; } /* try and locate an already registered atom */ len = str->len; h = hash_string(str, atom_type); h &= JS_ATOM_HASH_MASK; h1 = h & (rt->atom_hash_size - 1); i = rt->atom_hash[h1]; while (i != 0) { p = rt->atom_array[i]; if (p->hash == h && p->atom_type == atom_type && p->len == len && js_string_memcmp(p, str, len) == 0) { if (!__JS_AtomIsConst(i)) p->header.ref_count++; goto done; } i = p->hash_next; } } else { h1 = 0; /* avoid warning */ if (atom_type == JS_ATOM_TYPE_SYMBOL) { h = JS_ATOM_HASH_SYMBOL; } else { h = JS_ATOM_HASH_PRIVATE; atom_type = JS_ATOM_TYPE_SYMBOL; } } if (rt->atom_free_index == 0) { /* allow new atom entries */ uint32_t new_size, start; JSAtomStruct **new_array; /* alloc new with size progression 3/2: 4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092 preallocating space for predefined atoms (at least 195). */ new_size = max_int(211, rt->atom_size * 3 / 2); if (new_size > JS_ATOM_MAX) goto fail; /* XXX: should use realloc2 to use slack space */ new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size); if (!new_array) goto fail; /* Note: the atom 0 is not used */ start = rt->atom_size; if (start == 0) { /* JS_ATOM_NULL entry */ p = js_mallocz_rt(rt, sizeof(JSAtomStruct)); if (!p) { js_free_rt(rt, new_array); goto fail; } p->header.ref_count = 1; /* not refcounted */ p->atom_type = JS_ATOM_TYPE_SYMBOL; #ifdef DUMP_LEAKS list_add_tail(&p->link, &rt->string_list); #endif new_array[0] = p; rt->atom_count++; start = 1; } rt->atom_size = new_size; rt->atom_array = new_array; rt->atom_free_index = start; for(i = start; i < new_size; i++) { uint32_t next; if (i == (new_size - 1)) next = 0; else next = i + 1; rt->atom_array[i] = atom_set_free(next); } } if (str) { if (str->atom_type == 0) { p = str; p->atom_type = atom_type; } else { p = js_malloc_rt(rt, sizeof(JSString) + (str->len << str->is_wide_char) + 1 - str->is_wide_char); if (unlikely(!p)) goto fail; p->header.ref_count = 1; p->is_wide_char = str->is_wide_char; p->len = str->len; #ifdef DUMP_LEAKS list_add_tail(&p->link, &rt->string_list); #endif memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) + 1 - str->is_wide_char); js_free_string(rt, str); } } else { p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */ if (!p) return JS_ATOM_NULL; p->header.ref_count = 1; p->is_wide_char = 1; /* Hack to represent NULL as a JSString */ p->len = 0; #ifdef DUMP_LEAKS list_add_tail(&p->link, &rt->string_list); #endif } /* use an already free entry */ i = rt->atom_free_index; rt->atom_free_index = atom_get_free(rt->atom_array[i]); rt->atom_array[i] = p; p->hash = h; p->hash_next = i; /* atom_index */ p->atom_type = atom_type; rt->atom_count++; if (atom_type != JS_ATOM_TYPE_SYMBOL) { p->hash_next = rt->atom_hash[h1]; rt->atom_hash[h1] = i; if (unlikely(rt->atom_count >= rt->atom_count_resize)) JS_ResizeAtomHash(rt, rt->atom_hash_size * 2); } // JS_DumpAtoms(rt); return i; fail: i = JS_ATOM_NULL; done: if (str) js_free_string(rt, str); return i; } /* only works with zero terminated 8 bit strings */ static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, int atom_type) { JSString *p; p = js_alloc_string_rt(rt, len, 0); if (!p) return JS_ATOM_NULL; memcpy(p->u.str8, str, len); p->u.str8[len] = '\0'; return __JS_NewAtom(rt, p, atom_type); } /* Warning: str must be ASCII only */ static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len, int atom_type) { uint32_t h, h1, i; JSAtomStruct *p; h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING); h &= JS_ATOM_HASH_MASK; h1 = h & (rt->atom_hash_size - 1); i = rt->atom_hash[h1]; while (i != 0) { p = rt->atom_array[i]; if (p->hash == h && p->atom_type == JS_ATOM_TYPE_STRING && p->len == len && p->is_wide_char == 0 && memcmp(p->u.str8, str, len) == 0) { if (!__JS_AtomIsConst(i)) p->header.ref_count++; return i; } i = p->hash_next; } return JS_ATOM_NULL; } static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p) { #if 0 /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */ if (unlikely(i == JS_ATOM_NULL)) { p->header.ref_count = INT32_MAX / 2; return; } #endif uint32_t i = p->hash_next; /* atom_index */ if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { JSAtomStruct *p0, *p1; uint32_t h0; h0 = p->hash & (rt->atom_hash_size - 1); i = rt->atom_hash[h0]; p1 = rt->atom_array[i]; if (p1 == p) { rt->atom_hash[h0] = p1->hash_next; } else { for(;;) { assert(i != 0); p0 = p1; i = p1->hash_next; p1 = rt->atom_array[i]; if (p1 == p) { p0->hash_next = p1->hash_next; break; } } } } /* insert in free atom list */ rt->atom_array[i] = atom_set_free(rt->atom_free_index); rt->atom_free_index = i; /* free the string structure */ #ifdef DUMP_LEAKS list_del(&p->link); #endif js_free_rt(rt, p); rt->atom_count--; assert(rt->atom_count >= 0); } static void __JS_FreeAtom(JSRuntime *rt, uint32_t i) { JSAtomStruct *p; p = rt->atom_array[i]; if (--p->header.ref_count > 0) return; JS_FreeAtomStruct(rt, p); } /* Warning: 'p' is freed */ static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p) { JSRuntime *rt = ctx->rt; uint32_t n; if (is_num_string(&n, p)) { if (n <= JS_ATOM_MAX_INT) { js_free_string(rt, p); return __JS_AtomFromUInt32(n); } } /* XXX: should generate an exception */ return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING); } /* str is UTF-8 encoded */ JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len) { JSValue val; if (len == 0 || !is_digit(*str)) { // XXX: this will not work if UTF-8 encoded str contains non ASCII bytes JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING); if (atom) return atom; } val = JS_NewStringLen(ctx, str, len); if (JS_IsException(val)) return JS_ATOM_NULL; return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val)); } JSAtom JS_NewAtom(JSContext *ctx, const char *str) { return JS_NewAtomLen(ctx, str, strlen(str)); } JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n) { if (n <= JS_ATOM_MAX_INT) { return __JS_AtomFromUInt32(n); } else { char buf[11]; JSValue val; snprintf(buf, sizeof(buf), "%u", n); val = JS_NewString(ctx, buf); if (JS_IsException(val)) return JS_ATOM_NULL; return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), JS_ATOM_TYPE_STRING); } } static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n) { if ((uint64_t)n <= JS_ATOM_MAX_INT) { return __JS_AtomFromUInt32((uint32_t)n); } else { char buf[24]; JSValue val; snprintf(buf, sizeof(buf), "%" PRId64 , n); val = JS_NewString(ctx, buf); if (JS_IsException(val)) return JS_ATOM_NULL; return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), JS_ATOM_TYPE_STRING); } } /* 'p' is freed */ static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type) { JSRuntime *rt = ctx->rt; JSAtom atom; atom = __JS_NewAtom(rt, p, atom_type); if (atom == JS_ATOM_NULL) return JS_ThrowOutOfMemory(ctx); return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]); } /* descr must be a non-numeric string atom */ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr, int atom_type) { JSRuntime *rt = ctx->rt; JSString *p; assert(!__JS_AtomIsTaggedInt(descr)); assert(descr < rt->atom_size); p = rt->atom_array[descr]; JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); return JS_NewSymbol(ctx, p, atom_type); } #define ATOM_GET_STR_BUF_SIZE 64 /* Should only be used for debug. */ static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, JSAtom atom) { if (__JS_AtomIsTaggedInt(atom)) { snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom)); } else { JSAtomStruct *p; assert(atom < rt->atom_size); if (atom == JS_ATOM_NULL) { snprintf(buf, buf_size, ""); } else { int i, c; char *q; JSString *str; q = buf; p = rt->atom_array[atom]; assert(!atom_is_free(p)); str = p; if (str) { if (!str->is_wide_char) { /* special case ASCII strings */ c = 0; for(i = 0; i < str->len; i++) { c |= str->u.str8[i]; } if (c < 0x80) return (const char *)str->u.str8; } for(i = 0; i < str->len; i++) { c = string_get(str, i); if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX) break; if (c < 128) { *q++ = c; } else { q += unicode_to_utf8((uint8_t *)q, c); } } } *q = '\0'; } } return buf; } static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom) { return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom); } static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string) { char buf[ATOM_GET_STR_BUF_SIZE]; if (__JS_AtomIsTaggedInt(atom)) { snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom)); return JS_NewString(ctx, buf); } else { JSRuntime *rt = ctx->rt; JSAtomStruct *p; assert(atom < rt->atom_size); p = rt->atom_array[atom]; if (p->atom_type == JS_ATOM_TYPE_STRING) { goto ret_string; } else if (force_string) { if (p->len == 0 && p->is_wide_char != 0) { /* no description string */ p = rt->atom_array[JS_ATOM_empty_string]; } ret_string: return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); } else { return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p)); } } } JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom) { return __JS_AtomToValue(ctx, atom, FALSE); } JSValue JS_AtomToString(JSContext *ctx, JSAtom atom) { return __JS_AtomToValue(ctx, atom, TRUE); } /* return TRUE if the atom is an array index (i.e. 0 <= index <= 2^32-2 and return its value */ static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) { if (__JS_AtomIsTaggedInt(atom)) { *pval = __JS_AtomToUInt32(atom); return TRUE; } else { JSRuntime *rt = ctx->rt; JSAtomStruct *p; uint32_t val; assert(atom < rt->atom_size); p = rt->atom_array[atom]; if (p->atom_type == JS_ATOM_TYPE_STRING && is_num_string(&val, p) && val != -1) { *pval = val; return TRUE; } else { *pval = 0; return FALSE; } } } /* This test must be fast if atom is not a numeric index (e.g. a method name). Return JS_UNDEFINED if not a numeric index. JS_EXCEPTION can also be returned. */ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) { JSRuntime *rt = ctx->rt; JSAtomStruct *p1; JSString *p; int c, len, ret; JSValue num, str; if (__JS_AtomIsTaggedInt(atom)) return JS_NewInt32(ctx, __JS_AtomToUInt32(atom)); assert(atom < rt->atom_size); p1 = rt->atom_array[atom]; if (p1->atom_type != JS_ATOM_TYPE_STRING) return JS_UNDEFINED; p = p1; len = p->len; if (p->is_wide_char) { const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len; if (r >= r_end) return JS_UNDEFINED; c = *r; if (c == '-') { if (r >= r_end) return JS_UNDEFINED; r++; c = *r; /* -0 case is specific */ if (c == '0' && len == 2) goto minus_zero; } /* XXX: should test NaN, but the tests do not check it */ if (!is_num(c)) { /* XXX: String should be normalized, therefore 8-bit only */ const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' }; if (!(c =='I' && (r_end - r) == 8 && !memcmp(r + 1, nfinity16, sizeof(nfinity16)))) return JS_UNDEFINED; } } else { const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len; if (r >= r_end) return JS_UNDEFINED; c = *r; if (c == '-') { if (r >= r_end) return JS_UNDEFINED; r++; c = *r; /* -0 case is specific */ if (c == '0' && len == 2) { minus_zero: return __JS_NewFloat64(ctx, -0.0); } } if (!is_num(c)) { if (!(c =='I' && (r_end - r) == 8 && !memcmp(r + 1, "nfinity", 7))) return JS_UNDEFINED; } } /* XXX: bignum: would be better to only accept integer to avoid relying on current floating point precision */ /* this is ECMA CanonicalNumericIndexString primitive */ num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p)); if (JS_IsException(num)) return num; str = JS_ToString(ctx, num); if (JS_IsException(str)) { JS_FreeValue(ctx, num); return str; } ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str)); JS_FreeValue(ctx, str); if (ret == 0) { return num; } else { JS_FreeValue(ctx, num); return JS_UNDEFINED; } } /* return -1 if exception or TRUE/FALSE */ static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom) { JSValue num; num = JS_AtomIsNumericIndex1(ctx, atom); if (likely(JS_IsUndefined(num))) return FALSE; if (JS_IsException(num)) return -1; JS_FreeValue(ctx, num); return TRUE; } void JS_FreeAtom(JSContext *ctx, JSAtom v) { if (!__JS_AtomIsConst(v)) __JS_FreeAtom(ctx->rt, v); } void JS_FreeAtomRT(JSRuntime *rt, JSAtom v) { if (!__JS_AtomIsConst(v)) __JS_FreeAtom(rt, v); } /* return TRUE if 'v' is a symbol with a string description */ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v) { JSRuntime *rt; JSAtomStruct *p; rt = ctx->rt; if (__JS_AtomIsTaggedInt(v)) return FALSE; p = rt->atom_array[v]; return (((p->atom_type == JS_ATOM_TYPE_SYMBOL && p->hash == JS_ATOM_HASH_SYMBOL) || p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) && !(p->len == 0 && p->is_wide_char != 0)); } static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom) { char buf[ATOM_GET_STR_BUF_SIZE]; const char *p; int i; /* XXX: should handle embedded null characters */ /* XXX: should move encoding code to JS_AtomGetStr */ p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom); for (i = 0; p[i]; i++) { int c = (unsigned char)p[i]; if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0))) break; } if (i > 0 && p[i] == '\0') { printf("%s", p); } else { putchar('"'); printf("%.*s", i, p); for (; p[i]; i++) { int c = (unsigned char)p[i]; if (c == '\"' || c == '\\') { putchar('\\'); putchar(c); } else if (c >= ' ' && c <= 126) { putchar(c); } else if (c == '\n') { putchar('\\'); putchar('n'); } else { printf("\\u%04x", c); } } putchar('\"'); } } /* free with JS_FreeCString() */ const char *JS_AtomToCString(JSContext *ctx, JSAtom atom) { JSValue str; const char *cstr; str = JS_AtomToString(ctx, atom); if (JS_IsException(str)) return NULL; cstr = JS_ToCString(ctx, str); JS_FreeValue(ctx, str); return cstr; } /* return a string atom containing name concatenated with str1 */ static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) { JSValue str; JSAtom atom; const char *cstr; char *cstr2; size_t len, len1; str = JS_AtomToString(ctx, name); if (JS_IsException(str)) return JS_ATOM_NULL; cstr = JS_ToCStringLen(ctx, &len, str); if (!cstr) goto fail; len1 = strlen(str1); cstr2 = js_malloc(ctx, len + len1 + 1); if (!cstr2) goto fail; memcpy(cstr2, cstr, len); memcpy(cstr2 + len, str1, len1); cstr2[len + len1] = '\0'; atom = JS_NewAtomLen(ctx, cstr2, len + len1); js_free(ctx, cstr2); JS_FreeCString(ctx, cstr); JS_FreeValue(ctx, str); return atom; fail: JS_FreeCString(ctx, cstr); JS_FreeValue(ctx, str); return JS_ATOM_NULL; } static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n) { char buf[16]; snprintf(buf, sizeof(buf), "%u", n); return js_atom_concat_str(ctx, name, buf); } static inline BOOL JS_IsEmptyString(JSValueConst v) { return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0; } /* JSClass support */ #ifdef CONFIG_ATOMICS static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /* a new class ID is allocated if *pclass_id != 0 */ JSClassID JS_NewClassID(JSClassID *pclass_id) { JSClassID class_id; #ifdef CONFIG_ATOMICS pthread_mutex_lock(&js_class_id_mutex); #endif class_id = *pclass_id; if (class_id == 0) { class_id = js_class_id_alloc++; *pclass_id = class_id; } #ifdef CONFIG_ATOMICS pthread_mutex_unlock(&js_class_id_mutex); #endif return class_id; } JSClassID JS_GetClassID(JSValue v) { JSObject *p; if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) return JS_INVALID_CLASS_ID; p = JS_VALUE_GET_OBJ(v); return p->class_id; } BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id) { return (class_id < rt->class_count && rt->class_array[class_id].class_id != 0); } /* create a new object internal class. Return -1 if error, 0 if OK. The finalizer can be NULL if none is needed. */ static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def, JSAtom name) { int new_size, i; JSClass *cl, *new_class_array; struct list_head *el; if (class_id >= (1 << 16)) return -1; if (class_id < rt->class_count && rt->class_array[class_id].class_id != 0) return -1; if (class_id >= rt->class_count) { new_size = max_int(JS_CLASS_INIT_COUNT, max_int(class_id + 1, rt->class_count * 3 / 2)); /* reallocate the context class prototype array, if any */ list_for_each(el, &rt->context_list) { JSContext *ctx = list_entry(el, JSContext, link); JSValue *new_tab; new_tab = js_realloc_rt(rt, ctx->class_proto, sizeof(ctx->class_proto[0]) * new_size); if (!new_tab) return -1; for(i = rt->class_count; i < new_size; i++) new_tab[i] = JS_NULL; ctx->class_proto = new_tab; } /* reallocate the class array */ new_class_array = js_realloc_rt(rt, rt->class_array, sizeof(JSClass) * new_size); if (!new_class_array) return -1; memset(new_class_array + rt->class_count, 0, (new_size - rt->class_count) * sizeof(JSClass)); rt->class_array = new_class_array; rt->class_count = new_size; } cl = &rt->class_array[class_id]; cl->class_id = class_id; cl->class_name = JS_DupAtomRT(rt, name); cl->finalizer = class_def->finalizer; cl->gc_mark = class_def->gc_mark; cl->call = class_def->call; cl->exotic = class_def->exotic; return 0; } int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def) { int ret, len; JSAtom name; len = strlen(class_def->class_name); name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); if (name == JS_ATOM_NULL) { name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); if (name == JS_ATOM_NULL) return -1; } ret = JS_NewClass1(rt, class_id, class_def, name); JS_FreeAtomRT(rt, name); return ret; } static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len) { JSString *str; if (len <= 0) { return JS_AtomToString(ctx, JS_ATOM_empty_string); } str = js_alloc_string(ctx, len, 0); if (!str) return JS_EXCEPTION; memcpy(str->u.str8, buf, len); str->u.str8[len] = '\0'; return JS_MKPTR(JS_TAG_STRING, str); } static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len) { JSString *str; str = js_alloc_string(ctx, len, 1); if (!str) return JS_EXCEPTION; memcpy(str->u.str16, buf, len * 2); return JS_MKPTR(JS_TAG_STRING, str); } static JSValue js_new_string_char(JSContext *ctx, uint16_t c) { if (c < 0x100) { uint8_t ch8 = c; return js_new_string8(ctx, &ch8, 1); } else { uint16_t ch16 = c; return js_new_string16(ctx, &ch16, 1); } } static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end) { int len = end - start; if (start == 0 && end == p->len) { return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); } if (p->is_wide_char && len > 0) { JSString *str; int i; uint16_t c = 0; for (i = start; i < end; i++) { c |= p->u.str16[i]; } if (c > 0xFF) return js_new_string16(ctx, p->u.str16 + start, len); str = js_alloc_string(ctx, len, 0); if (!str) return JS_EXCEPTION; for (i = 0; i < len; i++) { str->u.str8[i] = p->u.str16[start + i]; } str->u.str8[len] = '\0'; return JS_MKPTR(JS_TAG_STRING, str); } else { return js_new_string8(ctx, p->u.str8 + start, len); } } typedef struct StringBuffer { JSContext *ctx; JSString *str; int len; int size; int is_wide_char; int error_status; } StringBuffer; /* It is valid to call string_buffer_end() and all string_buffer functions even if string_buffer_init() or another string_buffer function returns an error. If the error_status is set, string_buffer_end() returns JS_EXCEPTION. */ static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size, int is_wide) { s->ctx = ctx; s->size = size; s->len = 0; s->is_wide_char = is_wide; s->error_status = 0; s->str = js_alloc_string(ctx, size, is_wide); if (unlikely(!s->str)) { s->size = 0; return s->error_status = -1; } #ifdef DUMP_LEAKS /* the StringBuffer may reallocate the JSString, only link it at the end */ list_del(&s->str->link); #endif return 0; } static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size) { return string_buffer_init2(ctx, s, size, 0); } static void string_buffer_free(StringBuffer *s) { js_free(s->ctx, s->str); s->str = NULL; } static int string_buffer_set_error(StringBuffer *s) { js_free(s->ctx, s->str); s->str = NULL; s->size = 0; s->len = 0; return s->error_status = -1; } static no_inline int string_buffer_widen(StringBuffer *s, int size) { JSString *str; size_t slack; int i; if (s->error_status) return -1; str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack); if (!str) return string_buffer_set_error(s); size += slack >> 1; for(i = s->len; i-- > 0;) { str->u.str16[i] = str->u.str8[i]; } s->is_wide_char = 1; s->size = size; s->str = str; return 0; } static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c) { JSString *new_str; int new_size; size_t new_size_bytes, slack; if (s->error_status) return -1; if (new_len > JS_STRING_LEN_MAX) { JS_ThrowInternalError(s->ctx, "string too long"); return string_buffer_set_error(s); } new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX); if (!s->is_wide_char && c >= 0x100) { return string_buffer_widen(s, new_size); } new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char; new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack); if (!new_str) return string_buffer_set_error(s); new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX); s->size = new_size; s->str = new_str; return 0; } static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c) { if (unlikely(s->len >= s->size)) { if (string_buffer_realloc(s, s->len + 1, c)) return -1; } if (s->is_wide_char) { s->str->u.str16[s->len++] = c; } else if (c < 0x100) { s->str->u.str8[s->len++] = c; } else { if (string_buffer_widen(s, s->size)) return -1; s->str->u.str16[s->len++] = c; } return 0; } /* 0 <= c <= 0xff */ static int string_buffer_putc8(StringBuffer *s, uint32_t c) { if (unlikely(s->len >= s->size)) { if (string_buffer_realloc(s, s->len + 1, c)) return -1; } if (s->is_wide_char) { s->str->u.str16[s->len++] = c; } else { s->str->u.str8[s->len++] = c; } return 0; } /* 0 <= c <= 0xffff */ static int string_buffer_putc16(StringBuffer *s, uint32_t c) { if (likely(s->len < s->size)) { if (s->is_wide_char) { s->str->u.str16[s->len++] = c; return 0; } else if (c < 0x100) { s->str->u.str8[s->len++] = c; return 0; } } return string_buffer_putc_slow(s, c); } /* 0 <= c <= 0x10ffff */ static int string_buffer_putc(StringBuffer *s, uint32_t c) { if (unlikely(c >= 0x10000)) { /* surrogate pair */ if (string_buffer_putc16(s, get_hi_surrogate(c))) return -1; c = get_lo_surrogate(c); } return string_buffer_putc16(s, c); } static int string_getc(const JSString *p, int *pidx) { int idx, c, c1; idx = *pidx; if (p->is_wide_char) { c = p->u.str16[idx++]; if (is_hi_surrogate(c) && idx < p->len) { c1 = p->u.str16[idx]; if (is_lo_surrogate(c1)) { c = from_surrogate(c, c1); idx++; } } } else { c = p->u.str8[idx++]; } *pidx = idx; return c; } static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len) { int i; if (s->len + len > s->size) { if (string_buffer_realloc(s, s->len + len, 0)) return -1; } if (s->is_wide_char) { for (i = 0; i < len; i++) { s->str->u.str16[s->len + i] = p[i]; } s->len += len; } else { memcpy(&s->str->u.str8[s->len], p, len); s->len += len; } return 0; } static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len) { int c = 0, i; for (i = 0; i < len; i++) { c |= p[i]; } if (s->len + len > s->size) { if (string_buffer_realloc(s, s->len + len, c)) return -1; } else if (!s->is_wide_char && c >= 0x100) { if (string_buffer_widen(s, s->size)) return -1; } if (s->is_wide_char) { memcpy(&s->str->u.str16[s->len], p, len << 1); s->len += len; } else { for (i = 0; i < len; i++) { s->str->u.str8[s->len + i] = p[i]; } s->len += len; } return 0; } /* appending an ASCII string */ static int string_buffer_puts8(StringBuffer *s, const char *str) { return string_buffer_write8(s, (const uint8_t *)str, strlen(str)); } static int string_buffer_concat(StringBuffer *s, const JSString *p, uint32_t from, uint32_t to) { if (to <= from) return 0; if (p->is_wide_char) return string_buffer_write16(s, p->u.str16 + from, to - from); else return string_buffer_write8(s, p->u.str8 + from, to - from); } static int string_buffer_concat_value(StringBuffer *s, JSValueConst v) { JSString *p; JSValue v1; int res; if (s->error_status) { /* prevent exception overload */ return -1; } if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { v1 = JS_ToString(s->ctx, v); if (JS_IsException(v1)) return string_buffer_set_error(s); p = JS_VALUE_GET_STRING(v1); res = string_buffer_concat(s, p, 0, p->len); JS_FreeValue(s->ctx, v1); return res; } p = JS_VALUE_GET_STRING(v); return string_buffer_concat(s, p, 0, p->len); } static int string_buffer_concat_value_free(StringBuffer *s, JSValue v) { JSString *p; int res; if (s->error_status) { /* prevent exception overload */ JS_FreeValue(s->ctx, v); return -1; } if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { v = JS_ToStringFree(s->ctx, v); if (JS_IsException(v)) return string_buffer_set_error(s); } p = JS_VALUE_GET_STRING(v); res = string_buffer_concat(s, p, 0, p->len); JS_FreeValue(s->ctx, v); return res; } static int string_buffer_fill(StringBuffer *s, int c, int count) { /* XXX: optimize */ if (s->len + count > s->size) { if (string_buffer_realloc(s, s->len + count, c)) return -1; } while (count-- > 0) { if (string_buffer_putc16(s, c)) return -1; } return 0; } static JSValue string_buffer_end(StringBuffer *s) { JSString *str; str = s->str; if (s->error_status) return JS_EXCEPTION; if (s->len == 0) { js_free(s->ctx, str); s->str = NULL; return JS_AtomToString(s->ctx, JS_ATOM_empty_string); } if (s->len < s->size) { /* smaller size so js_realloc should not fail, but OK if it does */ /* XXX: should add some slack to avoid unnecessary calls */ /* XXX: might need to use malloc+free to ensure smaller size */ str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) + (s->len << s->is_wide_char) + 1 - s->is_wide_char); if (str == NULL) str = s->str; s->str = str; } if (!s->is_wide_char) str->u.str8[s->len] = 0; #ifdef DUMP_LEAKS list_add_tail(&str->link, &s->ctx->rt->string_list); #endif str->is_wide_char = s->is_wide_char; str->len = s->len; s->str = NULL; return JS_MKPTR(JS_TAG_STRING, str); } /* create a string from a UTF-8 buffer */ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) { const uint8_t *p, *p_end, *p_start, *p_next; uint32_t c; StringBuffer b_s, *b = &b_s; size_t len1; p_start = (const uint8_t *)buf; p_end = p_start + buf_len; p = p_start; while (p < p_end && *p < 128) p++; len1 = p - p_start; if (len1 > JS_STRING_LEN_MAX) return JS_ThrowInternalError(ctx, "string too long"); if (p == p_end) { /* ASCII string */ return js_new_string8(ctx, (const uint8_t *)buf, buf_len); } else { if (string_buffer_init(ctx, b, buf_len)) goto fail; string_buffer_write8(b, p_start, len1); while (p < p_end) { if (*p < 128) { string_buffer_putc8(b, *p++); } else { /* parse utf-8 sequence, return 0xFFFFFFFF for error */ c = unicode_from_utf8(p, p_end - p, &p_next); if (c < 0x10000) { p = p_next; } else if (c <= 0x10FFFF) { p = p_next; /* surrogate pair */ string_buffer_putc16(b, get_hi_surrogate(c)); c = get_lo_surrogate(c); } else { /* invalid char */ c = 0xfffd; /* skip the invalid chars */ /* XXX: seems incorrect. Why not just use c = *p++; ? */ while (p < p_end && (*p >= 0x80 && *p < 0xc0)) p++; if (p < p_end) { p++; while (p < p_end && (*p >= 0x80 && *p < 0xc0)) p++; } } string_buffer_putc16(b, c); } } } return string_buffer_end(b); fail: string_buffer_free(b); return JS_EXCEPTION; } static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, JSValue str2, const char *str3) { StringBuffer b_s, *b = &b_s; int len1, len3; JSString *p; if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) { str2 = JS_ToStringFree(ctx, str2); if (JS_IsException(str2)) goto fail; } p = JS_VALUE_GET_STRING(str2); len1 = strlen(str1); len3 = strlen(str3); if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char)) goto fail; string_buffer_write8(b, (const uint8_t *)str1, len1); string_buffer_concat(b, p, 0, p->len); string_buffer_write8(b, (const uint8_t *)str3, len3); JS_FreeValue(ctx, str2); return string_buffer_end(b); fail: JS_FreeValue(ctx, str2); return JS_EXCEPTION; } JSValue JS_NewString(JSContext *ctx, const char *str) { return JS_NewStringLen(ctx, str, strlen(str)); } JSValue JS_NewAtomString(JSContext *ctx, const char *str) { JSAtom atom = JS_NewAtom(ctx, str); if (atom == JS_ATOM_NULL) return JS_EXCEPTION; JSValue val = JS_AtomToString(ctx, atom); JS_FreeAtom(ctx, atom); return val; } /* return (NULL, 0) if exception. */ /* return pointer into a JSString with a live ref_count */ /* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */ const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8) { JSValue val; JSString *str, *str_new; int pos, len, c, c1; uint8_t *q; if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) { val = JS_ToString(ctx, val1); if (JS_IsException(val)) goto fail; } else { val = JS_DupValue(ctx, val1); } str = JS_VALUE_GET_STRING(val); len = str->len; if (!str->is_wide_char) { const uint8_t *src = str->u.str8; int count; /* count the number of non-ASCII characters */ /* Scanning the whole string is required for ASCII strings, and computing the number of non-ASCII bytes is less expensive than testing each byte, hence this method is faster for ASCII strings, which is the most common case. */ count = 0; for (pos = 0; pos < len; pos++) { count += src[pos] >> 7; } if (count == 0) { if (plen) *plen = len; return (const char *)src; } str_new = js_alloc_string(ctx, len + count, 0); if (!str_new) goto fail; q = str_new->u.str8; for (pos = 0; pos < len; pos++) { c = src[pos]; if (c < 0x80) { *q++ = c; } else { *q++ = (c >> 6) | 0xc0; *q++ = (c & 0x3f) | 0x80; } } } else { const uint16_t *src = str->u.str16; /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may produce 4 bytes but use 2 code points. */ str_new = js_alloc_string(ctx, len * 3, 0); if (!str_new) goto fail; q = str_new->u.str8; pos = 0; while (pos < len) { c = src[pos++]; if (c < 0x80) { *q++ = c; } else { if (is_hi_surrogate(c)) { if (pos < len && !cesu8) { c1 = src[pos]; if (is_lo_surrogate(c1)) { pos++; c = from_surrogate(c, c1); } else { /* Keep unmatched surrogate code points */ /* c = 0xfffd; */ /* error */ } } else { /* Keep unmatched surrogate code points */ /* c = 0xfffd; */ /* error */ } } q += unicode_to_utf8(q, c); } } } *q = '\0'; str_new->len = q - str_new->u.str8; JS_FreeValue(ctx, val); if (plen) *plen = str_new->len; return (const char *)str_new->u.str8; fail: if (plen) *plen = 0; return NULL; } void JS_FreeCString(JSContext *ctx, const char *ptr) { JSString *p; if (!ptr) return; /* purposely removing constness */ p = container_of(ptr, JSString, u); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); } static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len) { int c, i; for(i = 0; i < len; i++) { c = src1[i] - src2[i]; if (c != 0) return c; } return 0; } static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len) { int c, i; for(i = 0; i < len; i++) { c = src1[i] - src2[i]; if (c != 0) return c; } return 0; } static int js_string_memcmp(const JSString *p1, const JSString *p2, int len) { int res; if (likely(!p1->is_wide_char)) { if (likely(!p2->is_wide_char)) res = memcmp(p1->u.str8, p2->u.str8, len); else res = -memcmp16_8(p2->u.str16, p1->u.str8, len); } else { if (!p2->is_wide_char) res = memcmp16_8(p1->u.str16, p2->u.str8, len); else res = memcmp16(p1->u.str16, p2->u.str16, len); } return res; } /* return < 0, 0 or > 0 */ static int js_string_compare(JSContext *ctx, const JSString *p1, const JSString *p2) { int res, len; len = min_int(p1->len, p2->len); res = js_string_memcmp(p1, p2, len); if (res == 0) { if (p1->len == p2->len) res = 0; else if (p1->len < p2->len) res = -1; else res = 1; } return res; } static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len) { if (p->is_wide_char) { memcpy(dst, p->u.str16 + offset, len * 2); } else { const uint8_t *src1 = p->u.str8 + offset; int i; for(i = 0; i < len; i++) dst[i] = src1[i]; } } static JSValue JS_ConcatString1(JSContext *ctx, const JSString *p1, const JSString *p2) { JSString *p; uint32_t len; int is_wide_char; len = p1->len + p2->len; if (len > JS_STRING_LEN_MAX) return JS_ThrowInternalError(ctx, "string too long"); is_wide_char = p1->is_wide_char | p2->is_wide_char; p = js_alloc_string(ctx, len, is_wide_char); if (!p) return JS_EXCEPTION; if (!is_wide_char) { memcpy(p->u.str8, p1->u.str8, p1->len); memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len); p->u.str8[len] = '\0'; } else { copy_str16(p->u.str16, p1, 0, p1->len); copy_str16(p->u.str16 + p1->len, p2, 0, p2->len); } return JS_MKPTR(JS_TAG_STRING, p); } static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) { if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { JSString *p2 = JS_VALUE_GET_STRING(op2); size_t size1; if (p2->len == 0) return TRUE; if (p1->header.ref_count != 1) return FALSE; size1 = js_malloc_usable_size(ctx, p1); if (p1->is_wide_char) { if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) { if (p2->is_wide_char) { memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1); p1->len += p2->len; return TRUE; } else { size_t i; for (i = 0; i < p2->len; i++) { p1->u.str16[p1->len++] = p2->u.str8[i]; } return TRUE; } } } else if (!p2->is_wide_char) { if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) { memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len); p1->len += p2->len; p1->u.str8[p1->len] = '\0'; return TRUE; } } } return FALSE; } /* op1 and op2 are converted to strings. For convenience, op1 or op2 = JS_EXCEPTION are accepted and return JS_EXCEPTION. */ static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2) { JSValue ret; JSString *p1, *p2; if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) { op1 = JS_ToStringFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); return JS_EXCEPTION; } } if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) { op2 = JS_ToStringFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); return JS_EXCEPTION; } } p1 = JS_VALUE_GET_STRING(op1); if (JS_ConcatStringInPlace(ctx, p1, op2)) { JS_FreeValue(ctx, op2); return op1; } p2 = JS_VALUE_GET_STRING(op2); ret = JS_ConcatString1(ctx, p1, p2); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return ret; } /* Shape support */ static inline size_t get_shape_size(size_t hash_size, size_t prop_size) { return hash_size * sizeof(uint32_t) + sizeof(JSShape) + prop_size * sizeof(JSShapeProperty); } static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size) { return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size); } static inline uint32_t *prop_hash_end(JSShape *sh) { return (uint32_t *)sh; } static inline void *get_alloc_from_shape(JSShape *sh) { return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1); } static inline JSShapeProperty *get_shape_prop(JSShape *sh) { return sh->prop; } static int init_shape_hash(JSRuntime *rt) { rt->shape_hash_bits = 4; /* 16 shapes */ rt->shape_hash_size = 1 << rt->shape_hash_bits; rt->shape_hash_count = 0; rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * rt->shape_hash_size); if (!rt->shape_hash) return -1; return 0; } /* same magic hash multiplier as the Linux kernel */ static uint32_t shape_hash(uint32_t h, uint32_t val) { return (h + val) * 0x9e370001; } /* truncate the shape hash to 'hash_bits' bits */ static uint32_t get_shape_hash(uint32_t h, int hash_bits) { return h >> (32 - hash_bits); } static uint32_t shape_initial_hash(JSObject *proto) { uint32_t h; h = shape_hash(1, (uintptr_t)proto); if (sizeof(proto) > 4) h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32); return h; } static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits) { int new_shape_hash_size, i; uint32_t h; JSShape **new_shape_hash, *sh, *sh_next; new_shape_hash_size = 1 << new_shape_hash_bits; new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * new_shape_hash_size); if (!new_shape_hash) return -1; for(i = 0; i < rt->shape_hash_size; i++) { for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) { sh_next = sh->shape_hash_next; h = get_shape_hash(sh->hash, new_shape_hash_bits); sh->shape_hash_next = new_shape_hash[h]; new_shape_hash[h] = sh; } } js_free_rt(rt, rt->shape_hash); rt->shape_hash_bits = new_shape_hash_bits; rt->shape_hash_size = new_shape_hash_size; rt->shape_hash = new_shape_hash; return 0; } static void js_shape_hash_link(JSRuntime *rt, JSShape *sh) { uint32_t h; h = get_shape_hash(sh->hash, rt->shape_hash_bits); sh->shape_hash_next = rt->shape_hash[h]; rt->shape_hash[h] = sh; rt->shape_hash_count++; } static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh) { uint32_t h; JSShape **psh; h = get_shape_hash(sh->hash, rt->shape_hash_bits); psh = &rt->shape_hash[h]; while (*psh != sh) psh = &(*psh)->shape_hash_next; *psh = sh->shape_hash_next; rt->shape_hash_count--; } /* create a new empty shape with prototype 'proto' */ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, int hash_size, int prop_size) { JSRuntime *rt = ctx->rt; void *sh_alloc; JSShape *sh; /* resize the shape hash table if necessary */ if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) { resize_shape_hash(rt, rt->shape_hash_bits + 1); } sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size)); if (!sh_alloc) return NULL; sh = get_shape_from_alloc(sh_alloc, hash_size); sh->header.ref_count = 1; add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); if (proto) JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto)); sh->proto = proto; memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) * hash_size); sh->prop_hash_mask = hash_size - 1; sh->prop_size = prop_size; sh->prop_count = 0; sh->deleted_prop_count = 0; /* insert in the hash table */ sh->hash = shape_initial_hash(proto); sh->is_hashed = TRUE; sh->has_small_array_index = FALSE; js_shape_hash_link(ctx->rt, sh); return sh; } static JSShape *js_new_shape(JSContext *ctx, JSObject *proto) { return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE, JS_PROP_INITIAL_SIZE); } /* The shape is cloned. The new shape is not inserted in the shape hash table */ static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1) { JSShape *sh; void *sh_alloc, *sh_alloc1; size_t size; JSShapeProperty *pr; uint32_t i, hash_size; hash_size = sh1->prop_hash_mask + 1; size = get_shape_size(hash_size, sh1->prop_size); sh_alloc = js_malloc(ctx, size); if (!sh_alloc) return NULL; sh_alloc1 = get_alloc_from_shape(sh1); memcpy(sh_alloc, sh_alloc1, size); sh = get_shape_from_alloc(sh_alloc, hash_size); sh->header.ref_count = 1; add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); sh->is_hashed = FALSE; if (sh->proto) { JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); } for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { JS_DupAtom(ctx, pr->atom); } return sh; } static JSShape *js_dup_shape(JSShape *sh) { sh->header.ref_count++; return sh; } static void js_free_shape0(JSRuntime *rt, JSShape *sh) { uint32_t i; JSShapeProperty *pr; assert(sh->header.ref_count == 0); if (sh->is_hashed) js_shape_hash_unlink(rt, sh); if (sh->proto != NULL) { JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); } pr = get_shape_prop(sh); for(i = 0; i < sh->prop_count; i++) { JS_FreeAtomRT(rt, pr->atom); pr++; } remove_gc_object(&sh->header); js_free_rt(rt, get_alloc_from_shape(sh)); } static void js_free_shape(JSRuntime *rt, JSShape *sh) { if (unlikely(--sh->header.ref_count <= 0)) { js_free_shape0(rt, sh); } } static void js_free_shape_null(JSRuntime *rt, JSShape *sh) { if (sh) js_free_shape(rt, sh); } /* make space to hold at least 'count' properties */ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, JSObject *p, uint32_t count) { JSShape *sh; uint32_t new_size, new_hash_size, new_hash_mask, i; JSShapeProperty *pr; void *sh_alloc; intptr_t h; JSShape *old_sh; sh = *psh; new_size = max_int(count, sh->prop_size * 3 / 2); /* Reallocate prop array first to avoid crash or size inconsistency in case of memory allocation failure */ if (p) { JSProperty *new_prop; new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); if (unlikely(!new_prop)) return -1; p->prop = new_prop; } new_hash_size = sh->prop_hash_mask + 1; while (new_hash_size < new_size) new_hash_size = 2 * new_hash_size; /* resize the property shapes. Using js_realloc() is not possible in case the GC runs during the allocation */ old_sh = sh; sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); if (!sh_alloc) return -1; sh = get_shape_from_alloc(sh_alloc, new_hash_size); list_del(&old_sh->header.link); /* copy all the shape properties */ memcpy(sh, old_sh, sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); if (new_hash_size != (sh->prop_hash_mask + 1)) { /* resize the hash table and the properties */ new_hash_mask = new_hash_size - 1; sh->prop_hash_mask = new_hash_mask; memset(prop_hash_end(sh) - new_hash_size, 0, sizeof(prop_hash_end(sh)[0]) * new_hash_size); for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) { if (pr->atom != JS_ATOM_NULL) { h = ((uintptr_t)pr->atom & new_hash_mask); pr->hash_next = prop_hash_end(sh)[-h - 1]; prop_hash_end(sh)[-h - 1] = i + 1; } } } else { /* just copy the previous hash table */ memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size, sizeof(prop_hash_end(sh)[0]) * new_hash_size); } js_free(ctx, get_alloc_from_shape(old_sh)); *psh = sh; sh->prop_size = new_size; return 0; } /* remove the deleted properties. */ static int compact_properties(JSContext *ctx, JSObject *p) { JSShape *sh, *old_sh; void *sh_alloc; intptr_t h; uint32_t new_hash_size, i, j, new_hash_mask, new_size; JSShapeProperty *old_pr, *pr; JSProperty *prop, *new_prop; sh = p->shape; assert(!sh->is_hashed); new_size = max_int(JS_PROP_INITIAL_SIZE, sh->prop_count - sh->deleted_prop_count); assert(new_size <= sh->prop_size); new_hash_size = sh->prop_hash_mask + 1; while ((new_hash_size / 2) >= new_size) new_hash_size = new_hash_size / 2; new_hash_mask = new_hash_size - 1; /* resize the hash table and the properties */ old_sh = sh; sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); if (!sh_alloc) return -1; sh = get_shape_from_alloc(sh_alloc, new_hash_size); list_del(&old_sh->header.link); memcpy(sh, old_sh, sizeof(JSShape)); list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); memset(prop_hash_end(sh) - new_hash_size, 0, sizeof(prop_hash_end(sh)[0]) * new_hash_size); j = 0; old_pr = old_sh->prop; pr = sh->prop; prop = p->prop; for(i = 0; i < sh->prop_count; i++) { if (old_pr->atom != JS_ATOM_NULL) { pr->atom = old_pr->atom; pr->flags = old_pr->flags; h = ((uintptr_t)old_pr->atom & new_hash_mask); pr->hash_next = prop_hash_end(sh)[-h - 1]; prop_hash_end(sh)[-h - 1] = j + 1; prop[j] = prop[i]; j++; pr++; } old_pr++; } assert(j == (sh->prop_count - sh->deleted_prop_count)); sh->prop_hash_mask = new_hash_mask; sh->prop_size = new_size; sh->deleted_prop_count = 0; sh->prop_count = j; p->shape = sh; js_free(ctx, get_alloc_from_shape(old_sh)); /* reduce the size of the object properties */ new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); if (new_prop) p->prop = new_prop; return 0; } static int add_shape_property(JSContext *ctx, JSShape **psh, JSObject *p, JSAtom atom, int prop_flags) { JSRuntime *rt = ctx->rt; JSShape *sh = *psh; JSShapeProperty *pr, *prop; uint32_t hash_mask, new_shape_hash = 0; intptr_t h; /* update the shape hash */ if (sh->is_hashed) { js_shape_hash_unlink(rt, sh); new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags); } if (unlikely(sh->prop_count >= sh->prop_size)) { if (resize_properties(ctx, psh, p, sh->prop_count + 1)) { /* in case of error, reinsert in the hash table. sh is still valid if resize_properties() failed */ if (sh->is_hashed) js_shape_hash_link(rt, sh); return -1; } sh = *psh; } if (sh->is_hashed) { sh->hash = new_shape_hash; js_shape_hash_link(rt, sh); } /* Initialize the new shape property. The object property at p->prop[sh->prop_count] is uninitialized */ prop = get_shape_prop(sh); pr = &prop[sh->prop_count++]; pr->atom = JS_DupAtom(ctx, atom); pr->flags = prop_flags; sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom); /* add in hash table */ hash_mask = sh->prop_hash_mask; h = atom & hash_mask; pr->hash_next = prop_hash_end(sh)[-h - 1]; prop_hash_end(sh)[-h - 1] = sh->prop_count; return 0; } /* find a hashed empty shape matching the prototype. Return NULL if not found */ static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto) { JSShape *sh1; uint32_t h, h1; h = shape_initial_hash(proto); h1 = get_shape_hash(h, rt->shape_hash_bits); for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) { if (sh1->hash == h && sh1->proto == proto && sh1->prop_count == 0) { return sh1; } } return NULL; } /* find a hashed shape matching sh + (prop, prop_flags). Return NULL if not found */ static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh, JSAtom atom, int prop_flags) { JSShape *sh1; uint32_t h, h1, i, n; h = sh->hash; h = shape_hash(h, atom); h = shape_hash(h, prop_flags); h1 = get_shape_hash(h, rt->shape_hash_bits); for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) { /* we test the hash first so that the rest is done only if the shapes really match */ if (sh1->hash == h && sh1->proto == sh->proto && sh1->prop_count == ((n = sh->prop_count) + 1)) { for(i = 0; i < n; i++) { if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) || unlikely(sh1->prop[i].flags != sh->prop[i].flags)) goto next; } if (unlikely(sh1->prop[n].atom != atom) || unlikely(sh1->prop[n].flags != prop_flags)) goto next; return sh1; } next: ; } return NULL; } static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh) { char atom_buf[ATOM_GET_STR_BUF_SIZE]; int j; /* XXX: should output readable class prototype */ printf("%5d %3d%c %14p %5d %5d", i, sh->header.ref_count, " *"[sh->is_hashed], (void *)sh->proto, sh->prop_size, sh->prop_count); for(j = 0; j < sh->prop_count; j++) { printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), sh->prop[j].atom)); } printf("\n"); } static __maybe_unused void JS_DumpShapes(JSRuntime *rt) { int i; JSShape *sh; struct list_head *el; JSObject *p; JSGCObjectHeader *gp; printf("JSShapes: {\n"); printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS"); for(i = 0; i < rt->shape_hash_size; i++) { for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) { JS_DumpShape(rt, i, sh); assert(sh->is_hashed); } } /* dump non-hashed shapes */ list_for_each(el, &rt->gc_obj_list) { gp = list_entry(el, JSGCObjectHeader, link); if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { p = (JSObject *)gp; if (!p->shape->is_hashed) { JS_DumpShape(rt, -1, p->shape); } } } printf("}\n"); } static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id) { JSObject *p; js_trigger_gc(ctx->rt, sizeof(JSObject)); p = js_malloc(ctx, sizeof(JSObject)); if (unlikely(!p)) goto fail; p->class_id = class_id; p->extensible = TRUE; p->free_mark = 0; p->is_exotic = 0; p->fast_array = 0; p->is_constructor = 0; p->is_uncatchable_error = 0; p->tmp_mark = 0; p->is_HTMLDDA = 0; p->first_weak_ref = NULL; p->u.opaque = NULL; p->shape = sh; p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size); if (unlikely(!p->prop)) { js_free(ctx, p); fail: js_free_shape(ctx->rt, sh); return JS_EXCEPTION; } switch(class_id) { case JS_CLASS_OBJECT: break; case JS_CLASS_ARRAY: { JSProperty *pr; p->is_exotic = 1; p->fast_array = 1; p->u.array.u.values = NULL; p->u.array.count = 0; p->u.array.u1.size = 0; /* the length property is always the first one */ if (likely(sh == ctx->array_shape)) { pr = &p->prop[0]; } else { /* only used for the first array */ /* cannot fail */ pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH); } pr->u.value = JS_NewInt32(ctx, 0); } break; case JS_CLASS_C_FUNCTION: p->prop[0].u.value = JS_UNDEFINED; break; case JS_CLASS_ARGUMENTS: case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_INT8_ARRAY: case JS_CLASS_UINT8_ARRAY: case JS_CLASS_INT16_ARRAY: case JS_CLASS_UINT16_ARRAY: case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: p->is_exotic = 1; p->fast_array = 1; p->u.array.u.ptr = NULL; p->u.array.count = 0; break; case JS_CLASS_DATAVIEW: p->u.array.u.ptr = NULL; p->u.array.count = 0; break; case JS_CLASS_NUMBER: case JS_CLASS_STRING: case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: case JS_CLASS_BIG_INT: #ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif p->u.object_data = JS_UNDEFINED; goto set_exotic; case JS_CLASS_REGEXP: p->u.regexp.pattern = NULL; p->u.regexp.bytecode = NULL; goto set_exotic; default: set_exotic: if (ctx->rt->class_array[class_id].exotic) { p->is_exotic = 1; } break; } p->header.ref_count = 1; add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT); return JS_MKPTR(JS_TAG_OBJECT, p); } static JSObject *get_proto_obj(JSValueConst proto_val) { if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) return NULL; else return JS_VALUE_GET_OBJ(proto_val); } /* WARNING: proto must be an object or JS_NULL */ JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val, JSClassID class_id) { JSShape *sh; JSObject *proto; proto = get_proto_obj(proto_val); sh = find_hashed_shape_proto(ctx->rt, proto); if (likely(sh)) { sh = js_dup_shape(sh); } else { sh = js_new_shape(ctx, proto); if (!sh) return JS_EXCEPTION; } return JS_NewObjectFromShape(ctx, sh, class_id); } #if 0 static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = JS_VALUE_GET_OBJ(obj); switch(p->class_id) { case JS_CLASS_NUMBER: case JS_CLASS_STRING: case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: case JS_CLASS_BIG_INT: #ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif return JS_DupValue(ctx, p->u.object_data); } } return JS_UNDEFINED; } #endif static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) { JSObject *p; if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = JS_VALUE_GET_OBJ(obj); switch(p->class_id) { case JS_CLASS_NUMBER: case JS_CLASS_STRING: case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: case JS_CLASS_BIG_INT: #ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif JS_FreeValue(ctx, p->u.object_data); p->u.object_data = val; return 0; } } JS_FreeValue(ctx, val); if (!JS_IsException(obj)) JS_ThrowTypeError(ctx, "invalid object type"); return -1; } JSValue JS_NewObjectClass(JSContext *ctx, int class_id) { return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id); } JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto) { return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT); } JSValue JS_NewArray(JSContext *ctx) { return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape), JS_CLASS_ARRAY); } JSValue JS_NewObject(JSContext *ctx) { /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */ return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT); } static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj, JSAtom name, int len) { /* ES6 feature non compatible with ES5.1: length is configurable */ JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len), JS_PROP_CONFIGURABLE); JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE); } static BOOL js_class_has_bytecode(JSClassID class_id) { return (class_id == JS_CLASS_BYTECODE_FUNCTION || class_id == JS_CLASS_GENERATOR_FUNCTION || class_id == JS_CLASS_ASYNC_FUNCTION || class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION); } /* return NULL without exception if not a function or no bytecode */ static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return NULL; p = JS_VALUE_GET_OBJ(val); if (!js_class_has_bytecode(p->class_id)) return NULL; return p->u.func.function_bytecode; } static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj, JSValueConst home_obj) { JSObject *p, *p1; JSFunctionBytecode *b; if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) return; p = JS_VALUE_GET_OBJ(func_obj); if (!js_class_has_bytecode(p->class_id)) return; b = p->u.func.function_bytecode; if (b->need_home_object) { p1 = p->u.func.home_object; if (p1) { JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); } if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT) p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj)); else p1 = NULL; p->u.func.home_object = p1; } } static JSValue js_get_function_name(JSContext *ctx, JSAtom name) { JSValue name_str; name_str = JS_AtomToString(ctx, name); if (JS_AtomSymbolHasDescription(ctx, name)) { name_str = JS_ConcatString3(ctx, "[", name_str, "]"); } return name_str; } /* Modify the name of a method according to the atom and 'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and JS_PROP_HAS_SET. Also set the home object of the method. Return < 0 if exception. */ static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj, JSAtom name, int flags, JSValueConst home_obj) { JSValue name_str; name_str = js_get_function_name(ctx, name); if (flags & JS_PROP_HAS_GET) { name_str = JS_ConcatString3(ctx, "get ", name_str, ""); } else if (flags & JS_PROP_HAS_SET) { name_str = JS_ConcatString3(ctx, "set ", name_str, ""); } if (JS_IsException(name_str)) return -1; if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str, JS_PROP_CONFIGURABLE) < 0) return -1; js_method_set_home_object(ctx, func_obj, home_obj); return 0; } /* Note: at least 'length' arguments will be readable in 'argv' */ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, const char *name, int length, JSCFunctionEnum cproto, int magic, JSValueConst proto_val) { JSValue func_obj; JSObject *p; JSAtom name_atom; func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION); if (JS_IsException(func_obj)) return func_obj; p = JS_VALUE_GET_OBJ(func_obj); p->u.cfunc.realm = JS_DupContext(ctx); p->u.cfunc.c_function.generic = func; p->u.cfunc.length = length; p->u.cfunc.cproto = cproto; p->u.cfunc.magic = magic; p->is_constructor = (cproto == JS_CFUNC_constructor || cproto == JS_CFUNC_constructor_magic || cproto == JS_CFUNC_constructor_or_func || cproto == JS_CFUNC_constructor_or_func_magic); if (!name) name = ""; name_atom = JS_NewAtom(ctx, name); js_function_set_properties(ctx, func_obj, name_atom, length); JS_FreeAtom(ctx, name_atom); return func_obj; } /* Note: at least 'length' arguments will be readable in 'argv' */ JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, const char *name, int length, JSCFunctionEnum cproto, int magic) { return JS_NewCFunction3(ctx, func, name, length, cproto, magic, ctx->function_proto); } typedef struct JSCFunctionDataRecord { JSCFunctionData *func; uint8_t length; uint8_t data_len; uint16_t magic; JSValue data[0]; } JSCFunctionDataRecord; static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val) { JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); int i; if (s) { for(i = 0; i < s->data_len; i++) { JS_FreeValueRT(rt, s->data[i]); } js_free_rt(rt, s); } } static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); int i; if (s) { for(i = 0; i < s->data_len; i++) { JS_MarkValue(rt, s->data[i], mark_func); } } } static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_val, int argc, JSValueConst *argv, int flags) { JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA); JSValueConst *arg_buf; int i; /* XXX: could add the function on the stack for debug */ if (unlikely(argc < s->length)) { arg_buf = alloca(sizeof(arg_buf[0]) * s->length); for(i = 0; i < argc; i++) arg_buf[i] = argv[i]; for(i = argc; i < s->length; i++) arg_buf[i] = JS_UNDEFINED; } else { arg_buf = argv; } return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data); } JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, int length, int magic, int data_len, JSValueConst *data) { JSCFunctionDataRecord *s; JSValue func_obj; int i; func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, JS_CLASS_C_FUNCTION_DATA); if (JS_IsException(func_obj)) return func_obj; s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue)); if (!s) { JS_FreeValue(ctx, func_obj); return JS_EXCEPTION; } s->func = func; s->length = length; s->data_len = data_len; s->magic = magic; for(i = 0; i < data_len; i++) s->data[i] = JS_DupValue(ctx, data[i]); JS_SetOpaque(func_obj, s); js_function_set_properties(ctx, func_obj, JS_ATOM_empty_string, length); return func_obj; } static JSContext *js_autoinit_get_realm(JSProperty *pr) { return (JSContext *)(pr->u.init.realm_and_id & ~3); } static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr) { return pr->u.init.realm_and_id & 3; } static void js_autoinit_free(JSRuntime *rt, JSProperty *pr) { JS_FreeContext(js_autoinit_get_realm(pr)); } static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr, JS_MarkFunc *mark_func) { mark_func(rt, &js_autoinit_get_realm(pr)->header); } static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags) { if (unlikely(prop_flags & JS_PROP_TMASK)) { if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) { if (pr->u.getset.getter) JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); if (pr->u.getset.setter) JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) { free_var_ref(rt, pr->u.var_ref); } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { js_autoinit_free(rt, pr); } } else { JS_FreeValueRT(rt, pr->u.value); } } static force_inline JSShapeProperty *find_own_property1(JSObject *p, JSAtom atom) { JSShape *sh; JSShapeProperty *pr, *prop; intptr_t h; sh = p->shape; h = (uintptr_t)atom & sh->prop_hash_mask; h = prop_hash_end(sh)[-h - 1]; prop = get_shape_prop(sh); while (h) { pr = &prop[h - 1]; if (likely(pr->atom == atom)) { return pr; } h = pr->hash_next; } return NULL; } static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, JSObject *p, JSAtom atom) { JSShape *sh; JSShapeProperty *pr, *prop; intptr_t h; sh = p->shape; h = (uintptr_t)atom & sh->prop_hash_mask; h = prop_hash_end(sh)[-h - 1]; prop = get_shape_prop(sh); while (h) { pr = &prop[h - 1]; if (likely(pr->atom == atom)) { *ppr = &p->prop[h - 1]; /* the compiler should be able to assume that pr != NULL here */ return pr; } h = pr->hash_next; } *ppr = NULL; return NULL; } /* indicate that the object may be part of a function prototype cycle */ static void set_cycle_flag(JSContext *ctx, JSValueConst obj) { } static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref) { if (var_ref) { assert(var_ref->header.ref_count > 0); if (--var_ref->header.ref_count == 0) { if (var_ref->is_detached) { JS_FreeValueRT(rt, var_ref->value); } else { list_del(&var_ref->var_ref_link); /* still on the stack */ if (var_ref->async_func) async_func_free(rt, var_ref->async_func); } remove_gc_object(&var_ref->header); js_free_rt(rt, var_ref); } } } static void js_array_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); int i; for(i = 0; i < p->u.array.count; i++) { JS_FreeValueRT(rt, p->u.array.u.values[i]); } js_free_rt(rt, p->u.array.u.values); } static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); int i; for(i = 0; i < p->u.array.count; i++) { JS_MarkValue(rt, p->u.array.u.values[i], mark_func); } } static void js_object_data_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JS_FreeValueRT(rt, p->u.object_data); p->u.object_data = JS_UNDEFINED; } static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JS_MarkValue(rt, p->u.object_data, mark_func); } static void js_c_function_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); if (p->u.cfunc.realm) JS_FreeContext(p->u.cfunc.realm); } static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); if (p->u.cfunc.realm) mark_func(rt, &p->u.cfunc.realm->header); } static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val) { JSObject *p1, *p = JS_VALUE_GET_OBJ(val); JSFunctionBytecode *b; JSVarRef **var_refs; int i; p1 = p->u.func.home_object; if (p1) { JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1)); } b = p->u.func.function_bytecode; if (b) { var_refs = p->u.func.var_refs; if (var_refs) { for(i = 0; i < b->closure_var_count; i++) free_var_ref(rt, var_refs[i]); js_free_rt(rt, var_refs); } JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b)); } } static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSVarRef **var_refs = p->u.func.var_refs; JSFunctionBytecode *b = p->u.func.function_bytecode; int i; if (p->u.func.home_object) { JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object), mark_func); } if (b) { if (var_refs) { for(i = 0; i < b->closure_var_count; i++) { JSVarRef *var_ref = var_refs[i]; if (var_ref) { mark_func(rt, &var_ref->header); } } } /* must mark the function bytecode because template objects may be part of a cycle */ JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func); } } static void js_bound_function_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSBoundFunction *bf = p->u.bound_function; int i; JS_FreeValueRT(rt, bf->func_obj); JS_FreeValueRT(rt, bf->this_val); for(i = 0; i < bf->argc; i++) { JS_FreeValueRT(rt, bf->argv[i]); } js_free_rt(rt, bf); } static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSBoundFunction *bf = p->u.bound_function; int i; JS_MarkValue(rt, bf->func_obj, mark_func); JS_MarkValue(rt, bf->this_val, mark_func); for(i = 0; i < bf->argc; i++) JS_MarkValue(rt, bf->argv[i], mark_func); } static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSForInIterator *it = p->u.for_in_iterator; int i; JS_FreeValueRT(rt, it->obj); if (!it->is_array) { for(i = 0; i < it->atom_count; i++) { JS_FreeAtomRT(rt, it->tab_atom[i].atom); } js_free_rt(rt, it->tab_atom); } js_free_rt(rt, it); } static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSForInIterator *it = p->u.for_in_iterator; JS_MarkValue(rt, it->obj, mark_func); } static void free_object(JSRuntime *rt, JSObject *p) { int i; JSClassFinalizer *finalizer; JSShape *sh; JSShapeProperty *pr; p->free_mark = 1; /* used to tell the object is invalid when freeing cycles */ /* free all the fields */ sh = p->shape; pr = get_shape_prop(sh); for(i = 0; i < sh->prop_count; i++) { free_property(rt, &p->prop[i], pr->flags); pr++; } js_free_rt(rt, p->prop); /* as an optimization we destroy the shape immediately without putting it in gc_zero_ref_count_list */ js_free_shape(rt, sh); /* fail safe */ p->shape = NULL; p->prop = NULL; if (unlikely(p->first_weak_ref)) { reset_weak_ref(rt, p); } finalizer = rt->class_array[p->class_id].finalizer; if (finalizer) (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p)); /* fail safe */ p->class_id = 0; p->u.opaque = NULL; p->u.func.var_refs = NULL; p->u.func.home_object = NULL; remove_gc_object(&p->header); if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) { list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list); } else { js_free_rt(rt, p); } } static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) { switch(gp->gc_obj_type) { case JS_GC_OBJ_TYPE_JS_OBJECT: free_object(rt, (JSObject *)gp); break; case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: free_function_bytecode(rt, (JSFunctionBytecode *)gp); break; case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: __async_func_free(rt, (JSAsyncFunctionState *)gp); break; default: abort(); } } static void free_zero_refcount(JSRuntime *rt) { struct list_head *el; JSGCObjectHeader *p; rt->gc_phase = JS_GC_PHASE_DECREF; for(;;) { el = rt->gc_zero_ref_count_list.next; if (el == &rt->gc_zero_ref_count_list) break; p = list_entry(el, JSGCObjectHeader, link); assert(p->ref_count == 0); free_gc_object(rt, p); } rt->gc_phase = JS_GC_PHASE_NONE; } /* called with the ref_count of 'v' reaches zero. */ static void __JS_FreeValueRT(JSRuntime *rt, JSValue v) { uint32_t tag = JS_VALUE_GET_TAG(v); #ifdef DUMP_FREE { printf("Freeing "); if (tag == JS_TAG_OBJECT) { JS_DumpObject(rt, JS_VALUE_GET_OBJ(v)); } else { JS_DumpValueShort(rt, v); printf("\n"); } } #endif switch(tag) { case JS_TAG_STRING: { JSString *p = JS_VALUE_GET_STRING(v); if (p->atom_type) { JS_FreeAtomStruct(rt, p); } else { #ifdef DUMP_LEAKS list_del(&p->link); #endif js_free_rt(rt, p); } } break; case JS_TAG_OBJECT: case JS_TAG_FUNCTION_BYTECODE: { JSGCObjectHeader *p = JS_VALUE_GET_PTR(v); if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { list_del(&p->link); list_add(&p->link, &rt->gc_zero_ref_count_list); if (rt->gc_phase == JS_GC_PHASE_NONE) { free_zero_refcount(rt); } } } break; case JS_TAG_MODULE: abort(); /* never freed here */ break; case JS_TAG_BIG_INT: #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: #endif { JSBigFloat *bf = JS_VALUE_GET_PTR(v); bf_delete(&bf->num); js_free_rt(rt, bf); } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: { JSBigDecimal *bf = JS_VALUE_GET_PTR(v); bfdec_delete(&bf->num); js_free_rt(rt, bf); } break; #endif case JS_TAG_SYMBOL: { JSAtomStruct *p = JS_VALUE_GET_PTR(v); JS_FreeAtomStruct(rt, p); } break; default: printf("__JS_FreeValue: unknown tag=%d\n", tag); abort(); } } static void __JS_FreeValue(JSContext *ctx, JSValue v) { __JS_FreeValueRT(ctx->rt, v); } /* garbage collection */ static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type) { h->mark = 0; h->gc_obj_type = type; list_add_tail(&h->link, &rt->gc_obj_list); } static void remove_gc_object(JSGCObjectHeader *h) { list_del(&h->link); } void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { if (JS_VALUE_HAS_REF_COUNT(val)) { switch(JS_VALUE_GET_TAG(val)) { case JS_TAG_OBJECT: case JS_TAG_FUNCTION_BYTECODE: mark_func(rt, JS_VALUE_GET_PTR(val)); break; default: break; } } } static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, JS_MarkFunc *mark_func) { switch(gp->gc_obj_type) { case JS_GC_OBJ_TYPE_JS_OBJECT: { JSObject *p = (JSObject *)gp; JSShapeProperty *prs; JSShape *sh; int i; sh = p->shape; mark_func(rt, &sh->header); /* mark all the fields */ prs = get_shape_prop(sh); for(i = 0; i < sh->prop_count; i++) { JSProperty *pr = &p->prop[i]; if (prs->atom != JS_ATOM_NULL) { if (prs->flags & JS_PROP_TMASK) { if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { if (pr->u.getset.getter) mark_func(rt, &pr->u.getset.getter->header); if (pr->u.getset.setter) mark_func(rt, &pr->u.getset.setter->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { /* Note: the tag does not matter provided it is a GC object */ mark_func(rt, &pr->u.var_ref->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { js_autoinit_mark(rt, pr, mark_func); } } else { JS_MarkValue(rt, pr->u.value, mark_func); } } prs++; } if (p->class_id != JS_CLASS_OBJECT) { JSClassGCMark *gc_mark; gc_mark = rt->class_array[p->class_id].gc_mark; if (gc_mark) gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func); } } break; case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: /* the template objects can be part of a cycle */ { JSFunctionBytecode *b = (JSFunctionBytecode *)gp; int i; for(i = 0; i < b->cpool_count; i++) { JS_MarkValue(rt, b->cpool[i], mark_func); } if (b->realm) mark_func(rt, &b->realm->header); } break; case JS_GC_OBJ_TYPE_VAR_REF: { JSVarRef *var_ref = (JSVarRef *)gp; if (var_ref->is_detached) { JS_MarkValue(rt, *var_ref->pvalue, mark_func); } else if (var_ref->async_func) { mark_func(rt, &var_ref->async_func->header); } } break; case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: { JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp; JSStackFrame *sf = &s->frame; JSValue *sp; if (!s->is_completed) { JS_MarkValue(rt, sf->cur_func, mark_func); JS_MarkValue(rt, s->this_val, mark_func); /* sf->cur_sp = NULL if the function is running */ if (sf->cur_sp) { /* if the function is running, cur_sp is not known so we cannot mark the stack. Marking the variables is not needed because a running function cannot be part of a removable cycle */ for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) JS_MarkValue(rt, *sp, mark_func); } } JS_MarkValue(rt, s->resolving_funcs[0], mark_func); JS_MarkValue(rt, s->resolving_funcs[1], mark_func); } break; case JS_GC_OBJ_TYPE_SHAPE: { JSShape *sh = (JSShape *)gp; if (sh->proto != NULL) { mark_func(rt, &sh->proto->header); } } break; case JS_GC_OBJ_TYPE_JS_CONTEXT: { JSContext *ctx = (JSContext *)gp; JS_MarkContext(rt, ctx, mark_func); } break; default: abort(); } } static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p) { assert(p->ref_count > 0); p->ref_count--; if (p->ref_count == 0 && p->mark == 1) { list_del(&p->link); list_add_tail(&p->link, &rt->tmp_obj_list); } } static void gc_decref(JSRuntime *rt) { struct list_head *el, *el1; JSGCObjectHeader *p; init_list_head(&rt->tmp_obj_list); /* decrement the refcount of all the children of all the GC objects and move the GC objects with zero refcount to tmp_obj_list */ list_for_each_safe(el, el1, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->mark == 0); mark_children(rt, p, gc_decref_child); p->mark = 1; if (p->ref_count == 0) { list_del(&p->link); list_add_tail(&p->link, &rt->tmp_obj_list); } } } static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p) { p->ref_count++; if (p->ref_count == 1) { /* ref_count was 0: remove from tmp_obj_list and add at the end of gc_obj_list */ list_del(&p->link); list_add_tail(&p->link, &rt->gc_obj_list); p->mark = 0; /* reset the mark for the next GC call */ } } static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p) { p->ref_count++; } static void gc_scan(JSRuntime *rt) { struct list_head *el; JSGCObjectHeader *p; /* keep the objects with a refcount > 0 and their children. */ list_for_each(el, &rt->gc_obj_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->ref_count > 0); p->mark = 0; /* reset the mark for the next GC call */ mark_children(rt, p, gc_scan_incref_child); } /* restore the refcount of the objects to be deleted. */ list_for_each(el, &rt->tmp_obj_list) { p = list_entry(el, JSGCObjectHeader, link); mark_children(rt, p, gc_scan_incref_child2); } } static void gc_free_cycles(JSRuntime *rt) { struct list_head *el, *el1; JSGCObjectHeader *p; #ifdef DUMP_GC_FREE BOOL header_done = FALSE; #endif rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES; for(;;) { el = rt->tmp_obj_list.next; if (el == &rt->tmp_obj_list) break; p = list_entry(el, JSGCObjectHeader, link); /* Only need to free the GC object associated with JS values or async functions. The rest will be automatically removed because they must be referenced by them. */ switch(p->gc_obj_type) { case JS_GC_OBJ_TYPE_JS_OBJECT: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: #ifdef DUMP_GC_FREE if (!header_done) { printf("Freeing cycles:\n"); JS_DumpObjectHeader(rt); header_done = TRUE; } JS_DumpGCObject(rt, p); #endif free_gc_object(rt, p); break; default: list_del(&p->link); list_add_tail(&p->link, &rt->gc_zero_ref_count_list); break; } } rt->gc_phase = JS_GC_PHASE_NONE; list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE || p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION); js_free_rt(rt, p); } init_list_head(&rt->gc_zero_ref_count_list); } void JS_RunGC(JSRuntime *rt) { /* decrement the reference of the children of each object. mark = 1 after this pass. */ gc_decref(rt); /* keep the GC objects with a non zero refcount and their childs */ gc_scan(rt); /* free the GC objects in a cycle */ gc_free_cycles(rt); } /* Return false if not an object or if the object has already been freed (zombie objects are visible in finalizers when freeing cycles). */ BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj) { JSObject *p; if (!JS_IsObject(obj)) return FALSE; p = JS_VALUE_GET_OBJ(obj); return !p->free_mark; } /* Compute memory used by various object types */ /* XXX: poor man's approach to handling multiply referenced objects */ typedef struct JSMemoryUsage_helper { double memory_used_count; double str_count; double str_size; int64_t js_func_count; double js_func_size; int64_t js_func_code_size; int64_t js_func_pc2line_count; int64_t js_func_pc2line_size; } JSMemoryUsage_helper; static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp); static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp) { if (!str->atom_type) { /* atoms are handled separately */ double s_ref_count = str->header.ref_count; hp->str_count += 1 / s_ref_count; hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) + 1 - str->is_wide_char) / s_ref_count); } } static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp) { int memory_used_count, js_func_size, i; memory_used_count = 0; js_func_size = offsetof(JSFunctionBytecode, debug); if (b->vardefs) { js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs); } if (b->cpool) { js_func_size += b->cpool_count * sizeof(*b->cpool); for (i = 0; i < b->cpool_count; i++) { JSValueConst val = b->cpool[i]; compute_value_size(val, hp); } } if (b->closure_var) { js_func_size += b->closure_var_count * sizeof(*b->closure_var); } if (!b->read_only_bytecode && b->byte_code_buf) { hp->js_func_code_size += b->byte_code_len; } if (b->has_debug) { js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug); if (b->debug.source) { memory_used_count++; js_func_size += b->debug.source_len + 1; } if (b->debug.pc2line_len) { memory_used_count++; hp->js_func_pc2line_count += 1; hp->js_func_pc2line_size += b->debug.pc2line_len; } } hp->js_func_size += js_func_size; hp->js_func_count += 1; hp->memory_used_count += memory_used_count; } static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp) { switch(JS_VALUE_GET_TAG(val)) { case JS_TAG_STRING: compute_jsstring_size(JS_VALUE_GET_STRING(val), hp); break; case JS_TAG_BIG_INT: #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: case JS_TAG_BIG_DECIMAL: #endif /* should track JSBigFloat usage */ break; } } void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) { struct list_head *el, *el1; int i; JSMemoryUsage_helper mem = { 0 }, *hp = &mem; memset(s, 0, sizeof(*s)); s->malloc_count = rt->malloc_state.malloc_count; s->malloc_size = rt->malloc_state.malloc_size; s->malloc_limit = rt->malloc_state.malloc_limit; s->memory_used_count = 2; /* rt + rt->class_array */ s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count; list_for_each(el, &rt->context_list) { JSContext *ctx = list_entry(el, JSContext, link); JSShape *sh = ctx->array_shape; s->memory_used_count += 2; /* ctx + ctx->class_proto */ s->memory_used_size += sizeof(JSContext) + sizeof(JSValue) * rt->class_count; s->binary_object_count += ctx->binary_object_count; s->binary_object_size += ctx->binary_object_size; /* the hashed shapes are counted separately */ if (sh && !sh->is_hashed) { int hash_size = sh->prop_hash_mask + 1; s->shape_count++; s->shape_size += get_shape_size(hash_size, sh->prop_size); } list_for_each(el1, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el1, JSModuleDef, link); s->memory_used_count += 1; s->memory_used_size += sizeof(*m); if (m->req_module_entries) { s->memory_used_count += 1; s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries); } if (m->export_entries) { s->memory_used_count += 1; s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries); for (i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) { /* potential multiple count */ s->memory_used_count += 1; compute_value_size(me->u.local.var_ref->value, hp); } } } if (m->star_export_entries) { s->memory_used_count += 1; s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries); } if (m->import_entries) { s->memory_used_count += 1; s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries); } compute_value_size(m->module_ns, hp); compute_value_size(m->func_obj, hp); } } list_for_each(el, &rt->gc_obj_list) { JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link); JSObject *p; JSShape *sh; JSShapeProperty *prs; /* XXX: could count the other GC object types too */ if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) { compute_bytecode_size((JSFunctionBytecode *)gp, hp); continue; } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) { continue; } p = (JSObject *)gp; sh = p->shape; s->obj_count++; if (p->prop) { s->memory_used_count++; s->prop_size += sh->prop_size * sizeof(*p->prop); s->prop_count += sh->prop_count; prs = get_shape_prop(sh); for(i = 0; i < sh->prop_count; i++) { JSProperty *pr = &p->prop[i]; if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) { compute_value_size(pr->u.value, hp); } prs++; } } /* the hashed shapes are counted separately */ if (!sh->is_hashed) { int hash_size = sh->prop_hash_mask + 1; s->shape_count++; s->shape_size += get_shape_size(hash_size, sh->prop_size); } switch(p->class_id) { case JS_CLASS_ARRAY: /* u.array | length */ case JS_CLASS_ARGUMENTS: /* u.array | length */ s->array_count++; if (p->fast_array) { s->fast_array_count++; if (p->u.array.u.values) { s->memory_used_count++; s->memory_used_size += p->u.array.count * sizeof(*p->u.array.u.values); s->fast_array_elements += p->u.array.count; for (i = 0; i < p->u.array.count; i++) { compute_value_size(p->u.array.u.values[i], hp); } } } break; case JS_CLASS_NUMBER: /* u.object_data */ case JS_CLASS_STRING: /* u.object_data */ case JS_CLASS_BOOLEAN: /* u.object_data */ case JS_CLASS_SYMBOL: /* u.object_data */ case JS_CLASS_DATE: /* u.object_data */ case JS_CLASS_BIG_INT: /* u.object_data */ #ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: /* u.object_data */ case JS_CLASS_BIG_DECIMAL: /* u.object_data */ #endif compute_value_size(p->u.object_data, hp); break; case JS_CLASS_C_FUNCTION: /* u.cfunc */ s->c_func_count++; break; case JS_CLASS_BYTECODE_FUNCTION: /* u.func */ { JSFunctionBytecode *b = p->u.func.function_bytecode; JSVarRef **var_refs = p->u.func.var_refs; /* home_object: object will be accounted for in list scan */ if (var_refs) { s->memory_used_count++; s->js_func_size += b->closure_var_count * sizeof(*var_refs); for (i = 0; i < b->closure_var_count; i++) { if (var_refs[i]) { double ref_count = var_refs[i]->header.ref_count; s->memory_used_count += 1 / ref_count; s->js_func_size += sizeof(*var_refs[i]) / ref_count; /* handle non object closed values */ if (var_refs[i]->pvalue == &var_refs[i]->value) { /* potential multiple count */ compute_value_size(var_refs[i]->value, hp); } } } } } break; case JS_CLASS_BOUND_FUNCTION: /* u.bound_function */ { JSBoundFunction *bf = p->u.bound_function; /* func_obj and this_val are objects */ for (i = 0; i < bf->argc; i++) { compute_value_size(bf->argv[i], hp); } s->memory_used_count += 1; s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv); } break; case JS_CLASS_C_FUNCTION_DATA: /* u.c_function_data_record */ { JSCFunctionDataRecord *fd = p->u.c_function_data_record; if (fd) { for (i = 0; i < fd->data_len; i++) { compute_value_size(fd->data[i], hp); } s->memory_used_count += 1; s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data); } } break; case JS_CLASS_REGEXP: /* u.regexp */ compute_jsstring_size(p->u.regexp.pattern, hp); compute_jsstring_size(p->u.regexp.bytecode, hp); break; case JS_CLASS_FOR_IN_ITERATOR: /* u.for_in_iterator */ { JSForInIterator *it = p->u.for_in_iterator; if (it) { compute_value_size(it->obj, hp); s->memory_used_count += 1; s->memory_used_size += sizeof(*it); } } break; case JS_CLASS_ARRAY_BUFFER: /* u.array_buffer */ case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */ { JSArrayBuffer *abuf = p->u.array_buffer; if (abuf) { s->memory_used_count += 1; s->memory_used_size += sizeof(*abuf); if (abuf->data) { s->memory_used_count += 1; s->memory_used_size += abuf->byte_length; } } } break; case JS_CLASS_GENERATOR: /* u.generator_data */ case JS_CLASS_UINT8C_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_INT8_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_UINT8_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_INT16_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_DATAVIEW: /* u.typed_array */ #ifdef CONFIG_BIGNUM case JS_CLASS_FLOAT_ENV: /* u.float_env */ #endif case JS_CLASS_MAP: /* u.map_state */ case JS_CLASS_SET: /* u.map_state */ case JS_CLASS_WEAKMAP: /* u.map_state */ case JS_CLASS_WEAKSET: /* u.map_state */ case JS_CLASS_MAP_ITERATOR: /* u.map_iterator_data */ case JS_CLASS_SET_ITERATOR: /* u.map_iterator_data */ case JS_CLASS_ARRAY_ITERATOR: /* u.array_iterator_data */ case JS_CLASS_STRING_ITERATOR: /* u.array_iterator_data */ case JS_CLASS_PROXY: /* u.proxy_data */ case JS_CLASS_PROMISE: /* u.promise_data */ case JS_CLASS_PROMISE_RESOLVE_FUNCTION: /* u.promise_function_data */ case JS_CLASS_PROMISE_REJECT_FUNCTION: /* u.promise_function_data */ case JS_CLASS_ASYNC_FUNCTION_RESOLVE: /* u.async_function_data */ case JS_CLASS_ASYNC_FUNCTION_REJECT: /* u.async_function_data */ case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR: /* u.async_from_sync_iterator_data */ case JS_CLASS_ASYNC_GENERATOR: /* u.async_generator_data */ /* TODO */ default: /* XXX: class definition should have an opaque block size */ if (p->u.opaque) { s->memory_used_count += 1; } break; } } s->obj_size += s->obj_count * sizeof(JSObject); /* hashed shapes */ s->memory_used_count++; /* rt->shape_hash */ s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size; for(i = 0; i < rt->shape_hash_size; i++) { JSShape *sh; for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) { int hash_size = sh->prop_hash_mask + 1; s->shape_count++; s->shape_size += get_shape_size(hash_size, sh->prop_size); } } /* atoms */ s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */ s->atom_count = rt->atom_count; s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size + sizeof(rt->atom_hash[0]) * rt->atom_hash_size; for(i = 0; i < rt->atom_size; i++) { JSAtomStruct *p = rt->atom_array[i]; if (!atom_is_free(p)) { s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) + 1 - p->is_wide_char); } } s->str_count = round(mem.str_count); s->str_size = round(mem.str_size); s->js_func_count = mem.js_func_count; s->js_func_size = round(mem.js_func_size); s->js_func_code_size = mem.js_func_code_size; s->js_func_pc2line_count = mem.js_func_pc2line_count; s->js_func_pc2line_size = mem.js_func_pc2line_size; s->memory_used_count += round(mem.memory_used_count) + s->atom_count + s->str_count + s->obj_count + s->shape_count + s->js_func_count + s->js_func_pc2line_count; s->memory_used_size += s->atom_size + s->str_size + s->obj_size + s->prop_size + s->shape_size + s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size; } void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) { fprintf(fp, "QuickJS memory usage -- " #ifdef CONFIG_BIGNUM "BigNum " #endif CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n", (int)sizeof(void *) * 8, s->malloc_limit); #if 1 if (rt) { static const struct { const char *name; size_t size; } object_types[] = { { "JSRuntime", sizeof(JSRuntime) }, { "JSContext", sizeof(JSContext) }, { "JSObject", sizeof(JSObject) }, { "JSString", sizeof(JSString) }, { "JSFunctionBytecode", sizeof(JSFunctionBytecode) }, }; int i, usage_size_ok = 0; for(i = 0; i < countof(object_types); i++) { unsigned int size = object_types[i].size; void *p = js_malloc_rt(rt, size); if (p) { unsigned int size1 = js_malloc_usable_size_rt(rt, p); if (size1 >= size) { usage_size_ok = 1; fprintf(fp, " %3u + %-2u %s\n", size, size1 - size, object_types[i].name); } js_free_rt(rt, p); } } if (!usage_size_ok) { fprintf(fp, " malloc_usable_size unavailable\n"); } { int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 }; int class_id; struct list_head *el; list_for_each(el, &rt->gc_obj_list) { JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link); JSObject *p; if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { p = (JSObject *)gp; obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++; } } fprintf(fp, "\n" "JSObject classes\n"); if (obj_classes[0]) fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { if (obj_classes[class_id] && class_id < rt->class_count) { char buf[ATOM_GET_STR_BUF_SIZE]; fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); } } if (obj_classes[JS_CLASS_INIT_COUNT]) fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other"); } fprintf(fp, "\n"); } #endif fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); if (s->malloc_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n", "memory allocated", s->malloc_count, s->malloc_size, (double)s->malloc_size / s->malloc_count); fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n", "memory used", s->memory_used_count, s->memory_used_size, MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) / s->memory_used_count)); } if (s->atom_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n", "atoms", s->atom_count, s->atom_size, (double)s->atom_size / s->atom_count); } if (s->str_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n", "strings", s->str_count, s->str_size, (double)s->str_size / s->str_count); } if (s->obj_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", "objects", s->obj_count, s->obj_size, (double)s->obj_size / s->obj_count); fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", " properties", s->prop_count, s->prop_size, (double)s->prop_count / s->obj_count); fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n", " shapes", s->shape_count, s->shape_size, (double)s->shape_size / s->shape_count); } if (s->js_func_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", "bytecode functions", s->js_func_count, s->js_func_size); fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", " bytecode", s->js_func_count, s->js_func_code_size, (double)s->js_func_code_size / s->js_func_count); if (s->js_func_pc2line_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", " pc2line", s->js_func_pc2line_count, s->js_func_pc2line_size, (double)s->js_func_pc2line_size / s->js_func_pc2line_count); } } if (s->c_func_count) { fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count); } if (s->array_count) { fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count); if (s->fast_array_count) { fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count); fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n", " elements", s->fast_array_elements, s->fast_array_elements * (int)sizeof(JSValue), (double)s->fast_array_elements / s->fast_array_count); } } if (s->binary_object_count) { fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", "binary objects", s->binary_object_count, s->binary_object_size); } } JSValue JS_GetGlobalObject(JSContext *ctx) { return JS_DupValue(ctx, ctx->global_obj); } /* WARNING: obj is freed */ JSValue JS_Throw(JSContext *ctx, JSValue obj) { JSRuntime *rt = ctx->rt; JS_FreeValue(ctx, rt->current_exception); rt->current_exception = obj; return JS_EXCEPTION; } /* return the pending exception (cannot be called twice). */ JSValue JS_GetException(JSContext *ctx) { JSValue val; JSRuntime *rt = ctx->rt; val = rt->current_exception; rt->current_exception = JS_NULL; return val; } JS_BOOL JS_HasException(JSContext *ctx) { return !JS_IsNull(ctx->rt->current_exception); } static void dbuf_put_leb128(DynBuf *s, uint32_t v) { uint32_t a; for(;;) { a = v & 0x7f; v >>= 7; if (v != 0) { dbuf_putc(s, a | 0x80); } else { dbuf_putc(s, a); break; } } } static void dbuf_put_sleb128(DynBuf *s, int32_t v1) { uint32_t v = v1; dbuf_put_leb128(s, (2 * v) ^ -(v >> 31)); } static int get_leb128(uint32_t *pval, const uint8_t *buf, const uint8_t *buf_end) { const uint8_t *ptr = buf; uint32_t v, a, i; v = 0; for(i = 0; i < 5; i++) { if (unlikely(ptr >= buf_end)) break; a = *ptr++; v |= (a & 0x7f) << (i * 7); if (!(a & 0x80)) { *pval = v; return ptr - buf; } } *pval = 0; return -1; } static int get_sleb128(int32_t *pval, const uint8_t *buf, const uint8_t *buf_end) { int ret; uint32_t val; ret = get_leb128(&val, buf, buf_end); if (ret < 0) { *pval = 0; return -1; } *pval = (val >> 1) ^ -(val & 1); return ret; } static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, uint32_t pc_value) { const uint8_t *p_end, *p; int new_line_num, line_num, pc, v, ret; unsigned int op; if (!b->has_debug || !b->debug.pc2line_buf) { /* function was stripped */ return -1; } p = b->debug.pc2line_buf; p_end = p + b->debug.pc2line_len; pc = 0; line_num = b->debug.line_num; while (p < p_end) { op = *p++; if (op == 0) { uint32_t val; ret = get_leb128(&val, p, p_end); if (ret < 0) goto fail; pc += val; p += ret; ret = get_sleb128(&v, p, p_end); if (ret < 0) { fail: /* should never happen */ return b->debug.line_num; } p += ret; new_line_num = line_num + v; } else { op -= PC2LINE_OP_FIRST; pc += (op / PC2LINE_RANGE); new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE; } if (pc_value < pc) return line_num; line_num = new_line_num; } return line_num; } /* in order to avoid executing arbitrary code during the stack trace generation, we only look at simple 'name' properties containing a string. */ static const char *get_func_name(JSContext *ctx, JSValueConst func) { JSProperty *pr; JSShapeProperty *prs; JSValueConst val; if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) return NULL; prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name); if (!prs) return NULL; if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) return NULL; val = pr->u.value; if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) return NULL; return JS_ToCString(ctx, val); } #define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0) /* only taken into account if filename is provided */ #define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1) /* if filename != NULL, an additional level is added with the filename and line number information (used for parse error). */ void build_backtrace(JSContext *ctx, JSValueConst error_obj, const char *filename, int line_num, int backtrace_flags) { JSStackFrame *sf; JSValue str; DynBuf dbuf; const char *func_name_str; const char *str1; JSObject *p; BOOL backtrace_barrier; js_dbuf_init(ctx, &dbuf); if (filename) { dbuf_printf(&dbuf, " at %s", filename); if (line_num != -1) dbuf_printf(&dbuf, ":%d", line_num); dbuf_putc(&dbuf, '\n'); str = JS_NewString(ctx, filename); JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL) goto done; } for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) { backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL; continue; } func_name_str = get_func_name(ctx, sf->cur_func); if (!func_name_str || func_name_str[0] == '\0') str1 = ""; else str1 = func_name_str; dbuf_printf(&dbuf, " at %s", str1); JS_FreeCString(ctx, func_name_str); p = JS_VALUE_GET_OBJ(sf->cur_func); backtrace_barrier = FALSE; if (js_class_has_bytecode(p->class_id)) { JSFunctionBytecode *b; const char *atom_str; int line_num1; b = p->u.func.function_bytecode; backtrace_barrier = b->backtrace_barrier; if (b->has_debug) { line_num1 = find_line_num(ctx, b, sf->cur_pc - b->byte_code_buf - 1); atom_str = JS_AtomToCString(ctx, b->debug.filename); dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : ""); JS_FreeCString(ctx, atom_str); if (line_num1 != -1) dbuf_printf(&dbuf, ":%d", line_num1); dbuf_putc(&dbuf, ')'); } } else { dbuf_printf(&dbuf, " (native)"); } dbuf_putc(&dbuf, '\n'); /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */ if (backtrace_barrier) break; } done: dbuf_putc(&dbuf, '\0'); if (dbuf_error(&dbuf)) str = JS_NULL; else str = JS_NewString(ctx, (char *)dbuf.buf); dbuf_free(&dbuf); JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } /* Note: it is important that no exception is returned by this function */ static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(obj); if (p->class_id != JS_CLASS_ERROR) return FALSE; if (find_own_property1(p, JS_ATOM_stack)) return FALSE; return TRUE; } JSValue JS_NewError(JSContext *ctx) { return JS_NewObjectClass(ctx, JS_CLASS_ERROR); } static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap, BOOL add_backtrace) { char buf[8192]; JSValue obj, ret; vsnprintf(buf, sizeof(buf), fmt, ap); obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], JS_CLASS_ERROR); if (unlikely(JS_IsException(obj))) { /* out of memory: throw JS_NULL to avoid recursing */ obj = JS_NULL; } else { JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, JS_NewString(ctx, buf), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } if (add_backtrace) { build_backtrace(ctx, obj, NULL, 0, 0); } ret = JS_Throw(ctx, obj); return ret; } static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap) { JSRuntime *rt = ctx->rt; JSStackFrame *sf; BOOL add_backtrace; /* the backtrace is added later if called from a bytecode function */ sf = rt->current_stack_frame; add_backtrace = !rt->in_out_of_memory && (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL)); return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace); } JSValue FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; va_start(ap, fmt); val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap); va_end(ap); return val; } JSValue FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; va_start(ap, fmt); val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap); va_end(ap); return val; } static int FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...) { va_list ap; if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { va_start(ap, fmt); JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap); va_end(ap); return -1; } else { return FALSE; } } /* never use it directly */ static JSValue FORMAT_ATTR(3, 4) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowTypeError(ctx, fmt, JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); } /* never use it directly */ static JSValue FORMAT_ATTR(3, 4) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowSyntaxError(ctx, fmt, JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); } /* %s is replaced by 'atom'. The macro is used so that gcc can check the format string. */ #define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "") #define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "") static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom) { if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom); return -1; } else { return FALSE; } } JSValue FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; va_start(ap, fmt); val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap); va_end(ap); return val; } JSValue FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; va_start(ap, fmt); val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap); va_end(ap); return val; } JSValue FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; va_start(ap, fmt); val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap); va_end(ap); return val; } JSValue JS_ThrowOutOfMemory(JSContext *ctx) { JSRuntime *rt = ctx->rt; if (!rt->in_out_of_memory) { rt->in_out_of_memory = TRUE; JS_ThrowInternalError(ctx, "out of memory"); rt->in_out_of_memory = FALSE; } return JS_EXCEPTION; } static JSValue JS_ThrowStackOverflow(JSContext *ctx) { return JS_ThrowInternalError(ctx, "stack overflow"); } static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx) { return JS_ThrowTypeError(ctx, "not an object"); } static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) { return JS_ThrowTypeError(ctx, "not a symbol"); } static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowReferenceError(ctx, "'%s' is not defined", JS_AtomGetStr(ctx, buf, sizeof(buf), name)); } static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowReferenceError(ctx, "%s is not initialized", name == JS_ATOM_NULL ? "lexical variable" : JS_AtomGetStr(ctx, buf, sizeof(buf), name)); } static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx, JSFunctionBytecode *b, int idx, BOOL is_ref) { JSAtom atom = JS_ATOM_NULL; if (is_ref) { atom = b->closure_var[idx].var_name; } else { /* not present if the function is stripped and contains no eval() */ if (b->vardefs) atom = b->vardefs[b->arg_count + idx].var_name; } return JS_ThrowReferenceErrorUninitialized(ctx, atom); } static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id) { JSRuntime *rt = ctx->rt; JSAtom name; name = rt->class_array[class_id].class_name; return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name); } static no_inline __exception int __js_poll_interrupts(JSContext *ctx) { JSRuntime *rt = ctx->rt; ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT; if (rt->interrupt_handler) { if (rt->interrupt_handler(rt, rt->interrupt_opaque)) { /* XXX: should set a specific flag to avoid catching */ JS_ThrowInternalError(ctx, "interrupted"); JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE); return -1; } } return 0; } static inline __exception int js_poll_interrupts(JSContext *ctx) { if (unlikely(--ctx->interrupt_counter <= 0)) { return __js_poll_interrupts(ctx); } else { return 0; } } /* return -1 (exception) or TRUE/FALSE */ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, JSValueConst proto_val, BOOL throw_flag) { JSObject *proto, *p, *p1; JSShape *sh; if (throw_flag) { if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL || JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED) goto not_obj; } else { if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) goto not_obj; } p = JS_VALUE_GET_OBJ(obj); if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) { if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) { not_obj: JS_ThrowTypeErrorNotAnObject(ctx); return -1; } proto = NULL; } else { proto = JS_VALUE_GET_OBJ(proto_val); } if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return TRUE; if (unlikely(p->class_id == JS_CLASS_PROXY)) return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag); sh = p->shape; if (sh->proto == proto) return TRUE; if (!p->extensible) { if (throw_flag) { JS_ThrowTypeError(ctx, "object is not extensible"); return -1; } else { return FALSE; } } if (proto) { /* check if there is a cycle */ p1 = proto; do { if (p1 == p) { if (throw_flag) { JS_ThrowTypeError(ctx, "circular prototype chain"); return -1; } else { return FALSE; } } /* Note: for Proxy objects, proto is NULL */ p1 = p1->shape->proto; } while (p1 != NULL); JS_DupValue(ctx, proto_val); } if (js_shape_prepare_update(ctx, p, NULL)) return -1; sh = p->shape; if (sh->proto) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); sh->proto = proto; return TRUE; } /* return -1 (exception) or TRUE/FALSE */ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) { return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE); } /* Only works for primitive types, otherwise return JS_NULL. */ static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) { switch(JS_VALUE_GET_NORM_TAG(val)) { case JS_TAG_BIG_INT: val = ctx->class_proto[JS_CLASS_BIG_INT]; break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: val = ctx->class_proto[JS_CLASS_BIG_FLOAT]; break; case JS_TAG_BIG_DECIMAL: val = ctx->class_proto[JS_CLASS_BIG_DECIMAL]; break; #endif case JS_TAG_INT: case JS_TAG_FLOAT64: val = ctx->class_proto[JS_CLASS_NUMBER]; break; case JS_TAG_BOOL: val = ctx->class_proto[JS_CLASS_BOOLEAN]; break; case JS_TAG_STRING: val = ctx->class_proto[JS_CLASS_STRING]; break; case JS_TAG_SYMBOL: val = ctx->class_proto[JS_CLASS_SYMBOL]; break; case JS_TAG_OBJECT: case JS_TAG_NULL: case JS_TAG_UNDEFINED: default: val = JS_NULL; break; } return val; } /* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) { JSValue val; if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { JSObject *p; p = JS_VALUE_GET_OBJ(obj); if (unlikely(p->class_id == JS_CLASS_PROXY)) { val = js_proxy_getPrototypeOf(ctx, obj); } else { p = p->shape->proto; if (!p) val = JS_NULL; else val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); } } else { val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj)); } return val; } static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj) { JSValue obj1; obj1 = JS_GetPrototype(ctx, obj); JS_FreeValue(ctx, obj); return obj1; } /* return TRUE, FALSE or (-1) in case of exception */ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) { JSValue obj_proto; JSObject *proto; const JSObject *p, *proto1; BOOL ret; if (!JS_IsFunction(ctx, obj)) return FALSE; p = JS_VALUE_GET_OBJ(obj); if (p->class_id == JS_CLASS_BOUND_FUNCTION) { JSBoundFunction *s = p->u.bound_function; return JS_IsInstanceOf(ctx, val, s->func_obj); } /* Only explicitly boxed values are instances of constructors */ if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return FALSE; obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype); if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) { if (!JS_IsException(obj_proto)) JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object"); ret = -1; goto done; } proto = JS_VALUE_GET_OBJ(obj_proto); p = JS_VALUE_GET_OBJ(val); for(;;) { proto1 = p->shape->proto; if (!proto1) { /* slow case if proxy in the prototype chain */ if (unlikely(p->class_id == JS_CLASS_PROXY)) { JSValue obj1; obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); for(;;) { obj1 = JS_GetPrototypeFree(ctx, obj1); if (JS_IsException(obj1)) { ret = -1; break; } if (JS_IsNull(obj1)) { ret = FALSE; break; } if (proto == JS_VALUE_GET_OBJ(obj1)) { JS_FreeValue(ctx, obj1); ret = TRUE; break; } /* must check for timeout to avoid infinite loop */ if (js_poll_interrupts(ctx)) { JS_FreeValue(ctx, obj1); ret = -1; break; } } } else { ret = FALSE; } break; } p = proto1; if (proto == p) { ret = TRUE; break; } } done: JS_FreeValue(ctx, obj_proto); return ret; } /* return TRUE, FALSE or (-1) in case of exception */ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) { JSValue method; if (!JS_IsObject(obj)) goto fail; method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance); if (JS_IsException(method)) return -1; if (!JS_IsNull(method) && !JS_IsUndefined(method)) { JSValue ret; ret = JS_CallFree(ctx, method, obj, 1, &val); return JS_ToBoolFree(ctx, ret); } /* legacy case */ if (!JS_IsFunction(ctx, obj)) { fail: JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand"); return -1; } return JS_OrdinaryIsInstanceOf(ctx, val, obj); } /* return the value associated to the autoinit property or an exception */ typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSAutoInitFunc *js_autoinit_func_table[] = { js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */ JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */ }; /* warning: 'prs' is reallocated after it */ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSProperty *pr, JSShapeProperty *prs) { JSValue val; JSContext *realm; JSAutoInitFunc *func; if (js_shape_prepare_update(ctx, p, &prs)) return -1; realm = js_autoinit_get_realm(pr); func = js_autoinit_func_table[js_autoinit_get_id(pr)]; /* 'func' shall not modify the object properties 'pr' */ val = func(realm, p, prop, pr->u.init.opaque); js_autoinit_free(ctx->rt, pr); prs->flags &= ~JS_PROP_TMASK; pr->u.value = JS_UNDEFINED; if (JS_IsException(val)) return -1; pr->u.value = val; return 0; } JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, BOOL throw_ref_error) { JSObject *p; JSProperty *pr; JSShapeProperty *prs; uint32_t tag; tag = JS_VALUE_GET_TAG(obj); if (unlikely(tag != JS_TAG_OBJECT)) { switch(tag) { case JS_TAG_NULL: return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop); case JS_TAG_UNDEFINED: return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop); case JS_TAG_EXCEPTION: return JS_EXCEPTION; case JS_TAG_STRING: { JSString *p1 = JS_VALUE_GET_STRING(obj); if (__JS_AtomIsTaggedInt(prop)) { uint32_t idx, ch; idx = __JS_AtomToUInt32(prop); if (idx < p1->len) { if (p1->is_wide_char) ch = p1->u.str16[idx]; else ch = p1->u.str8[idx]; return js_new_string_char(ctx, ch); } } else if (prop == JS_ATOM_length) { return JS_NewInt32(ctx, p1->len); } } break; default: break; } /* cannot raise an exception */ p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); if (!p) return JS_UNDEFINED; } else { p = JS_VALUE_GET_OBJ(obj); } for(;;) { prs = find_own_property(&pr, p, prop); if (prs) { /* found */ if (unlikely(prs->flags & JS_PROP_TMASK)) { if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { if (unlikely(!pr->u.getset.getter)) { return JS_UNDEFINED; } else { JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter); /* Note: the field could be removed in the getter */ func = JS_DupValue(ctx, func); return JS_CallFree(ctx, func, this_obj, 0, NULL); } } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { JSValue val = *pr->u.var_ref->pvalue; if (unlikely(JS_IsUninitialized(val))) return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return JS_DupValue(ctx, val); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) return JS_EXCEPTION; continue; } } else { if (JS_IsUndefined(pr->u.value) && ctx->handleUndefined) ctx->handleUndefined(ctx); return JS_DupValue(ctx, pr->u.value); } } if (unlikely(p->is_exotic)) { /* exotic behaviors */ if (p->fast_array) { if (__JS_AtomIsTaggedInt(prop)) { uint32_t idx = __JS_AtomToUInt32(prop); if (idx < p->u.array.count) { /* we avoid duplicating the code */ return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { return JS_UNDEFINED; } } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { int ret; ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { if (ret < 0) return JS_EXCEPTION; return JS_UNDEFINED; } } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em) { if (em->get_property) { JSValue obj1, retval; /* XXX: should pass throw_ref_error */ /* Note: if 'p' is a prototype, it can be freed in the called function */ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); retval = em->get_property(ctx, obj1, prop, this_obj); JS_FreeValue(ctx, obj1); return retval; } if (em->get_own_property) { JSPropertyDescriptor desc; int ret; JSValue obj1; /* Note: if 'p' is a prototype, it can be freed in the called function */ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = em->get_own_property(ctx, &desc, obj1, prop); JS_FreeValue(ctx, obj1); if (ret < 0) return JS_EXCEPTION; if (ret) { if (desc.flags & JS_PROP_GETSET) { JS_FreeValue(ctx, desc.setter); return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL); } else { return desc.value; } } } } } } p = p->shape->proto; if (!p) break; } if (unlikely(throw_ref_error)) { return JS_ThrowReferenceErrorNotDefined(ctx, prop); } else { return JS_UNDEFINED; } } static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) { return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", atom); } /* Private fields can be added even on non extensible objects or Proxies */ static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, JSValueConst name, JSValue val) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; JSAtom prop; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); goto fail; } /* safety check */ if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) { JS_ThrowTypeErrorNotASymbol(ctx); goto fail; } prop = js_symbol_to_atom(ctx, name); p = JS_VALUE_GET_OBJ(obj); prs = find_own_property(&pr, p, prop); if (prs) { JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists", prop); goto fail; } pr = add_property(ctx, p, prop, JS_PROP_C_W_E); if (unlikely(!pr)) { fail: JS_FreeValue(ctx, val); return -1; } pr->u.value = val; return 0; } static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj, JSValueConst name) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; JSAtom prop; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) return JS_ThrowTypeErrorNotAnObject(ctx); /* safety check */ if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) return JS_ThrowTypeErrorNotASymbol(ctx); prop = js_symbol_to_atom(ctx, name); p = JS_VALUE_GET_OBJ(obj); prs = find_own_property(&pr, p, prop); if (!prs) { JS_ThrowTypeErrorPrivateNotFound(ctx, prop); return JS_EXCEPTION; } return JS_DupValue(ctx, pr->u.value); } static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, JSValueConst name, JSValue val) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; JSAtom prop; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); goto fail; } /* safety check */ if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) { JS_ThrowTypeErrorNotASymbol(ctx); goto fail; } prop = js_symbol_to_atom(ctx, name); p = JS_VALUE_GET_OBJ(obj); prs = find_own_property(&pr, p, prop); if (!prs) { JS_ThrowTypeErrorPrivateNotFound(ctx, prop); fail: JS_FreeValue(ctx, val); return -1; } set_value(ctx, &pr->u.value, val); return 0; } /* add a private brand field to 'home_obj' if not already present and if obj is != null add a private brand to it */ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) { JSObject *p, *p1; JSShapeProperty *prs; JSProperty *pr; JSValue brand; JSAtom brand_atom; if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; } p = JS_VALUE_GET_OBJ(home_obj); prs = find_own_property(&pr, p, JS_ATOM_Private_brand); if (!prs) { /* if the brand is not present, add it */ brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE); if (JS_IsException(brand)) return -1; pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E); if (!pr) { JS_FreeValue(ctx, brand); return -1; } pr->u.value = JS_DupValue(ctx, brand); } else { brand = JS_DupValue(ctx, pr->u.value); } brand_atom = js_symbol_to_atom(ctx, brand); if (JS_IsObject(obj)) { p1 = JS_VALUE_GET_OBJ(obj); prs = find_own_property(&pr, p1, brand_atom); if (unlikely(prs)) { JS_FreeAtom(ctx, brand_atom); JS_ThrowTypeError(ctx, "private method is already present"); return -1; } pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); JS_FreeAtom(ctx, brand_atom); if (!pr) return -1; pr->u.value = JS_UNDEFINED; } else { JS_FreeAtom(ctx, brand_atom); } return 0; } /* return a boolean telling if the brand of the home object of 'func' is present on 'obj' or -1 in case of exception */ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) { JSObject *p, *p1, *home_obj; JSShapeProperty *prs; JSProperty *pr; JSValueConst brand; /* get the home object of 'func' */ if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) goto not_obj; p1 = JS_VALUE_GET_OBJ(func); if (!js_class_has_bytecode(p1->class_id)) goto not_obj; home_obj = p1->u.func.home_object; if (!home_obj) goto not_obj; prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand); if (!prs) { JS_ThrowTypeError(ctx, "expecting private field"); return -1; } brand = pr->u.value; /* safety check */ if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL)) goto not_obj; /* get the brand array of 'obj' */ if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { not_obj: JS_ThrowTypeErrorNotAnObject(ctx); return -1; } p = JS_VALUE_GET_OBJ(obj); prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand)); return (prs != NULL); } static uint32_t js_string_obj_get_length(JSContext *ctx, JSValueConst obj) { JSObject *p; JSString *p1; uint32_t len = 0; /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ p = JS_VALUE_GET_OBJ(obj); if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { p1 = JS_VALUE_GET_STRING(p->u.object_data); len = p1->len; } return len; } static int num_keys_cmp(const void *p1, const void *p2, void *opaque) { JSContext *ctx = opaque; JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom; JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom; uint32_t v1, v2; BOOL atom1_is_integer, atom2_is_integer; atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1); atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2); assert(atom1_is_integer && atom2_is_integer); if (v1 < v2) return -1; else if (v1 == v2) return 0; else return 1; } static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) { uint32_t i; if (tab) { for(i = 0; i < len; i++) JS_FreeAtom(ctx, tab[i].atom); js_free(ctx, tab); } } /* return < 0 in case if exception, 0 if OK. ptab and its atoms must be freed by the user. */ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSObject *p, int flags) { int i, j; JSShape *sh; JSShapeProperty *prs; JSPropertyEnum *tab_atom, *tab_exotic; JSAtom atom; uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count; uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count; BOOL is_enumerable, num_sorted; uint32_t num_key; JSAtomKindEnum kind; /* clear pointer for consistency in case of failure */ *ptab = NULL; *plen = 0; /* compute the number of returned properties */ num_keys_count = 0; str_keys_count = 0; sym_keys_count = 0; exotic_keys_count = 0; exotic_count = 0; tab_exotic = NULL; sh = p->shape; for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { atom = prs->atom; if (atom != JS_ATOM_NULL) { is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); kind = JS_AtomGetKind(ctx, atom); if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) { /* need to raise an exception in case of the module name space (implicit GetOwnProperty) */ if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) && (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) { JSVarRef *var_ref = p->prop[i].u.var_ref; if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) { JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return -1; } } if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { num_keys_count++; } else if (kind == JS_ATOM_KIND_STRING) { str_keys_count++; } else { sym_keys_count++; } } } } if (p->is_exotic) { if (p->fast_array) { if (flags & JS_GPN_STRING_MASK) { num_keys_count += p->u.array.count; } } else if (p->class_id == JS_CLASS_STRING) { if (flags & JS_GPN_STRING_MASK) { num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->get_own_property_names) { if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count, JS_MKPTR(JS_TAG_OBJECT, p))) return -1; for(i = 0; i < exotic_count; i++) { atom = tab_exotic[i].atom; kind = JS_AtomGetKind(ctx, atom); if (((flags >> kind) & 1) != 0) { is_enumerable = FALSE; if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) { JSPropertyDescriptor desc; int res; /* set the "is_enumerable" field if necessary */ res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); if (res < 0) { js_free_prop_enum(ctx, tab_exotic, exotic_count); return -1; } if (res) { is_enumerable = ((desc.flags & JS_PROP_ENUMERABLE) != 0); js_free_desc(ctx, &desc); } tab_exotic[i].is_enumerable = is_enumerable; } if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) { exotic_keys_count++; } } } } } } /* fill them */ atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count; /* avoid allocating 0 bytes */ tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1)); if (!tab_atom) { js_free_prop_enum(ctx, tab_exotic, exotic_count); return -1; } num_index = 0; str_index = num_keys_count; sym_index = str_index + str_keys_count; num_sorted = TRUE; sh = p->shape; for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { atom = prs->atom; if (atom != JS_ATOM_NULL) { is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); kind = JS_AtomGetKind(ctx, atom); if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) { if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { j = num_index++; num_sorted = FALSE; } else if (kind == JS_ATOM_KIND_STRING) { j = str_index++; } else { j = sym_index++; } tab_atom[j].atom = JS_DupAtom(ctx, atom); tab_atom[j].is_enumerable = is_enumerable; } } } if (p->is_exotic) { int len; if (p->fast_array) { if (flags & JS_GPN_STRING_MASK) { len = p->u.array.count; goto add_array_keys; } } else if (p->class_id == JS_CLASS_STRING) { if (flags & JS_GPN_STRING_MASK) { len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); add_array_keys: for(i = 0; i < len; i++) { tab_atom[num_index].atom = __JS_AtomFromUInt32(i); if (tab_atom[num_index].atom == JS_ATOM_NULL) { js_free_prop_enum(ctx, tab_atom, num_index); return -1; } tab_atom[num_index].is_enumerable = TRUE; num_index++; } } } else { /* Note: exotic keys are not reordered and comes after the object own properties. */ for(i = 0; i < exotic_count; i++) { atom = tab_exotic[i].atom; is_enumerable = tab_exotic[i].is_enumerable; kind = JS_AtomGetKind(ctx, atom); if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) { tab_atom[sym_index].atom = atom; tab_atom[sym_index].is_enumerable = is_enumerable; sym_index++; } else { JS_FreeAtom(ctx, atom); } } js_free(ctx, tab_exotic); } } assert(num_index == num_keys_count); assert(str_index == num_keys_count + str_keys_count); assert(sym_index == atom_count); if (num_keys_count != 0 && !num_sorted) { rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp, ctx); } *ptab = tab_atom; *plen = atom_count; return 0; } int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen, JSValueConst obj, int flags) { if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; } return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen, JS_VALUE_GET_OBJ(obj), flags); } /* Return -1 if exception, FALSE if the property does not exist, TRUE if it exists. If TRUE is returned, the property descriptor 'desc' is filled present. */ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSObject *p, JSAtom prop) { JSShapeProperty *prs; JSProperty *pr; retry: prs = find_own_property(&pr, p, prop); if (prs) { if (desc) { desc->flags = prs->flags & JS_PROP_C_W_E; desc->getter = JS_UNDEFINED; desc->setter = JS_UNDEFINED; desc->value = JS_UNDEFINED; if (unlikely(prs->flags & JS_PROP_TMASK)) { if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { desc->flags |= JS_PROP_GETSET; if (pr->u.getset.getter) desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); if (pr->u.getset.setter) desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { JSValue val = *pr->u.var_ref->pvalue; if (unlikely(JS_IsUninitialized(val))) { JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return -1; } desc->value = JS_DupValue(ctx, val); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) return -1; goto retry; } } else { desc->value = JS_DupValue(ctx, pr->u.value); } } else { /* for consistency, send the exception even if desc is NULL */ if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) { if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) { JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return -1; } } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* nothing to do: delay instantiation until actual value and/or attributes are read */ } } return TRUE; } if (p->is_exotic) { if (p->fast_array) { /* specific case for fast arrays */ if (__JS_AtomIsTaggedInt(prop)) { uint32_t idx; idx = __JS_AtomToUInt32(prop); if (idx < p->u.array.count) { if (desc) { desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE; desc->getter = JS_UNDEFINED; desc->setter = JS_UNDEFINED; desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); } return TRUE; } } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->get_own_property) { return em->get_own_property(ctx, desc, JS_MKPTR(JS_TAG_OBJECT, p), prop); } } } return FALSE; } int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop) { if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; } return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop); } /* return -1 if exception (Proxy object only) or TRUE/FALSE */ int JS_IsExtensible(JSContext *ctx, JSValueConst obj) { JSObject *p; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) return FALSE; p = JS_VALUE_GET_OBJ(obj); if (unlikely(p->class_id == JS_CLASS_PROXY)) return js_proxy_isExtensible(ctx, obj); else return p->extensible; } /* return -1 if exception (Proxy object only) or TRUE/FALSE */ int JS_PreventExtensions(JSContext *ctx, JSValueConst obj) { JSObject *p; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) return FALSE; p = JS_VALUE_GET_OBJ(obj); if (unlikely(p->class_id == JS_CLASS_PROXY)) return js_proxy_preventExtensions(ctx, obj); p->extensible = FALSE; return TRUE; } /* return -1 if exception otherwise TRUE or FALSE */ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) { JSObject *p; int ret; JSValue obj1; if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) return FALSE; p = JS_VALUE_GET_OBJ(obj); for(;;) { if (p->is_exotic) { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->has_property) { /* has_property can free the prototype */ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = em->has_property(ctx, obj1, prop); JS_FreeValue(ctx, obj1); return ret; } } /* JS_GetOwnPropertyInternal can free the prototype */ JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ret != 0) return ret; if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { if (ret < 0) return -1; return FALSE; } } p = p->shape->proto; if (!p) break; } return FALSE; } /* val must be a symbol */ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val) { JSAtomStruct *p = JS_VALUE_GET_PTR(val); return js_get_atom_index(ctx->rt, p); } /* return JS_ATOM_NULL in case of exception */ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val) { JSAtom atom; uint32_t tag; tag = JS_VALUE_GET_TAG(val); if (tag == JS_TAG_INT && (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) { /* fast path for integer values */ atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val)); } else if (tag == JS_TAG_SYMBOL) { JSAtomStruct *p = JS_VALUE_GET_PTR(val); atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p)); } else { JSValue str; str = JS_ToPropertyKey(ctx, val); if (JS_IsException(str)) return JS_ATOM_NULL; if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) { atom = js_symbol_to_atom(ctx, str); } else { atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str)); } } return atom; } static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, JSValue prop) { JSAtom atom; JSValue ret; if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { JSObject *p; uint32_t idx; /* fast path for array access */ p = JS_VALUE_GET_OBJ(this_obj); idx = JS_VALUE_GET_INT(prop); switch(p->class_id) { case JS_CLASS_ARRAY: case JS_CLASS_ARGUMENTS: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_DupValue(ctx, p->u.array.u.values[idx]); case JS_CLASS_INT8_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]); case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_UINT8_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]); case JS_CLASS_INT16_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]); case JS_CLASS_UINT16_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]); case JS_CLASS_INT32_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]); case JS_CLASS_UINT32_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]); case JS_CLASS_BIG_INT64_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); case JS_CLASS_BIG_UINT64_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); case JS_CLASS_FLOAT32_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]); case JS_CLASS_FLOAT64_ARRAY: if (unlikely(idx >= p->u.array.count)) goto slow_path; return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]); default: goto slow_path; } } else { slow_path: atom = JS_ValueToAtom(ctx, prop); JS_FreeValue(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; ret = JS_GetProperty(ctx, this_obj, atom); JS_FreeAtom(ctx, atom); return ret; } } JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx) { return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx)); } /* Check if an object has a generalized numeric property. Return value: -1 for exception, TRUE if property exists, stored into *pval, FALSE if proprty does not exist. */ static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval) { JSValue val = JS_UNDEFINED; JSAtom prop; int present; if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) { /* fast path */ present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx)); if (present > 0) { val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx)); if (unlikely(JS_IsException(val))) present = -1; } } else { prop = JS_NewAtomInt64(ctx, idx); present = -1; if (likely(prop != JS_ATOM_NULL)) { present = JS_HasProperty(ctx, obj, prop); if (present > 0) { val = JS_GetProperty(ctx, obj, prop); if (unlikely(JS_IsException(val))) present = -1; } JS_FreeAtom(ctx, prop); } } *pval = val; return present; } static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx) { JSAtom prop; JSValue val; if ((uint64_t)idx <= INT32_MAX) { /* fast path for fast arrays */ return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx)); } prop = JS_NewAtomInt64(ctx, idx); if (prop == JS_ATOM_NULL) return JS_EXCEPTION; val = JS_GetProperty(ctx, obj, prop); JS_FreeAtom(ctx, prop); return val; } JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, const char *prop) { JSAtom atom; JSValue ret; atom = JS_NewAtom(ctx, prop); ret = JS_GetProperty(ctx, this_obj, atom); JS_FreeAtom(ctx, atom); return ret; } /* Note: the property value is not initialized. Return NULL if memory error. */ static JSProperty *add_property(JSContext *ctx, JSObject *p, JSAtom prop, int prop_flags) { JSShape *sh, *new_sh; sh = p->shape; if (sh->is_hashed) { /* try to find an existing shape */ new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags); if (new_sh) { /* matching shape found: use it */ /* the property array may need to be resized */ if (new_sh->prop_size != sh->prop_size) { JSProperty *new_prop; new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) * new_sh->prop_size); if (!new_prop) return NULL; p->prop = new_prop; } p->shape = js_dup_shape(new_sh); js_free_shape(ctx->rt, sh); return &p->prop[new_sh->prop_count - 1]; } else if (sh->header.ref_count != 1) { /* if the shape is shared, clone it */ new_sh = js_clone_shape(ctx, sh); if (!new_sh) return NULL; /* hash the cloned shape */ new_sh->is_hashed = TRUE; js_shape_hash_link(ctx->rt, new_sh); js_free_shape(ctx->rt, p->shape); p->shape = new_sh; } } assert(p->shape->header.ref_count == 1); if (add_shape_property(ctx, &p->shape, p, prop, prop_flags)) return NULL; return &p->prop[p->shape->prop_count - 1]; } /* can be called on Array or Arguments objects. return < 0 if memory alloc error. */ static no_inline __exception int convert_fast_array_to_array(JSContext *ctx, JSObject *p) { JSProperty *pr; JSShape *sh; JSValue *tab; uint32_t i, len, new_count; if (js_shape_prepare_update(ctx, p, NULL)) return -1; len = p->u.array.count; /* resize the properties once to simplify the error handling */ sh = p->shape; new_count = sh->prop_count + len; if (new_count > sh->prop_size) { if (resize_properties(ctx, &p->shape, p, new_count)) return -1; } tab = p->u.array.u.values; for(i = 0; i < len; i++) { /* add_property cannot fail here but __JS_AtomFromUInt32(i) fails for i > INT32_MAX */ pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E); pr->u.value = *tab++; } js_free(ctx, p->u.array.u.values); p->u.array.count = 0; p->u.array.u.values = NULL; /* fail safe */ p->u.array.u1.size = 0; p->fast_array = 0; return 0; } static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) { JSShape *sh; JSShapeProperty *pr, *lpr, *prop; JSProperty *pr1; uint32_t lpr_idx; intptr_t h, h1; redo: sh = p->shape; h1 = atom & sh->prop_hash_mask; h = prop_hash_end(sh)[-h1 - 1]; prop = get_shape_prop(sh); lpr = NULL; lpr_idx = 0; /* prevent warning */ while (h != 0) { pr = &prop[h - 1]; if (likely(pr->atom == atom)) { /* found ! */ if (!(pr->flags & JS_PROP_CONFIGURABLE)) return FALSE; /* realloc the shape if needed */ if (lpr) lpr_idx = lpr - get_shape_prop(sh); if (js_shape_prepare_update(ctx, p, &pr)) return -1; sh = p->shape; /* remove property */ if (lpr) { lpr = get_shape_prop(sh) + lpr_idx; lpr->hash_next = pr->hash_next; } else { prop_hash_end(sh)[-h1 - 1] = pr->hash_next; } sh->deleted_prop_count++; /* free the entry */ pr1 = &p->prop[h - 1]; free_property(ctx->rt, pr1, pr->flags); JS_FreeAtom(ctx, pr->atom); /* put default values */ pr->flags = 0; pr->atom = JS_ATOM_NULL; pr1->u.value = JS_UNDEFINED; /* compact the properties if too many deleted properties */ if (sh->deleted_prop_count >= 8 && sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { compact_properties(ctx, p); } return TRUE; } lpr = pr; h = pr->hash_next; } if (p->is_exotic) { if (p->fast_array) { uint32_t idx; if (JS_AtomIsArrayIndex(ctx, &idx, atom) && idx < p->u.array.count) { if (p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) { /* Special case deleting the last element of a fast Array */ if (idx == p->u.array.count - 1) { JS_FreeValue(ctx, p->u.array.u.values[idx]); p->u.array.count = idx; return TRUE; } if (convert_fast_array_to_array(ctx, p)) return -1; goto redo; } else { return FALSE; } } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->delete_property) { return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom); } } } /* not found */ return TRUE; } static int call_setter(JSContext *ctx, JSObject *setter, JSValueConst this_obj, JSValue val, int flags) { JSValue ret, func; if (likely(setter)) { func = JS_MKPTR(JS_TAG_OBJECT, setter); /* Note: the field could be removed in the setter */ func = JS_DupValue(ctx, func); ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val); JS_FreeValue(ctx, val); if (JS_IsException(ret)) return -1; JS_FreeValue(ctx, ret); return TRUE; } else { JS_FreeValue(ctx, val); if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { JS_ThrowTypeError(ctx, "no setter for property"); return -1; } return FALSE; } } /* set the array length and remove the array elements if necessary. */ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags) { uint32_t len, idx, cur_len; int i, ret; /* Note: this call can reallocate the properties of 'p' */ ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE); if (ret) return -1; /* JS_ToArrayLengthFree() must be done before the read-only test */ if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE))) return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); if (likely(p->fast_array)) { uint32_t old_len = p->u.array.count; if (len < old_len) { for(i = len; i < old_len; i++) { JS_FreeValue(ctx, p->u.array.u.values[i]); } p->u.array.count = len; } p->prop[0].u.value = JS_NewUint32(ctx, len); } else { /* Note: length is always a uint32 because the object is an array */ JS_ToUint32(ctx, &cur_len, p->prop[0].u.value); if (len < cur_len) { uint32_t d; JSShape *sh; JSShapeProperty *pr; d = cur_len - len; sh = p->shape; if (d <= sh->prop_count) { JSAtom atom; /* faster to iterate */ while (cur_len > len) { atom = JS_NewAtomUInt32(ctx, cur_len - 1); ret = delete_property(ctx, p, atom); JS_FreeAtom(ctx, atom); if (unlikely(!ret)) { /* unlikely case: property is not configurable */ break; } cur_len--; } } else { /* faster to iterate thru all the properties. Need two passes in case one of the property is not configurable */ cur_len = len; for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { if (pr->atom != JS_ATOM_NULL && JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { if (idx >= cur_len && !(pr->flags & JS_PROP_CONFIGURABLE)) { cur_len = idx + 1; } } } for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { if (pr->atom != JS_ATOM_NULL && JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { if (idx >= cur_len) { /* remove the property */ delete_property(ctx, p, pr->atom); /* WARNING: the shape may have been modified */ sh = p->shape; pr = get_shape_prop(sh) + i; } } } } } else { cur_len = len; } set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len)); if (unlikely(cur_len > len)) { return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable"); } } return TRUE; } /* return -1 if exception */ static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) { uint32_t new_size; size_t slack; JSValue *new_array_prop; /* XXX: potential arithmetic overflow */ new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); if (!new_array_prop) return -1; new_size += slack / sizeof(*new_array_prop); p->u.array.u.values = new_array_prop; p->u.array.u1.size = new_size; return 0; } /* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array = TRUE and p->extensible = TRUE */ static int add_fast_array_element(JSContext *ctx, JSObject *p, JSValue val, int flags) { uint32_t new_len, array_len; /* extend the array by one */ /* XXX: convert to slow array if new_len > 2^31-1 elements */ new_len = p->u.array.count + 1; /* update the length if necessary. We assume that if the length is not an integer, then if it >= 2^31. */ if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) { array_len = JS_VALUE_GET_INT(p->prop[0].u.value); if (new_len > array_len) { if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) { JS_FreeValue(ctx, val); return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); } p->prop[0].u.value = JS_NewInt32(ctx, new_len); } } if (unlikely(new_len > p->u.array.u1.size)) { if (expand_fast_array(ctx, p, new_len)) { JS_FreeValue(ctx, val); return -1; } } p->u.array.u.values[new_len - 1] = val; p->u.array.count = new_len; return TRUE; } /* Allocate a new fast array. Its 'length' property is set to zero. It maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit integer. WARNING: the content of the array is not initialized. */ static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len) { JSValue arr; JSObject *p; if (len > INT32_MAX) return JS_ThrowRangeError(ctx, "invalid array length"); arr = JS_NewArray(ctx); if (JS_IsException(arr)) return arr; if (len > 0) { p = JS_VALUE_GET_OBJ(arr); if (expand_fast_array(ctx, p, len) < 0) { JS_FreeValue(ctx, arr); return JS_EXCEPTION; } p->u.array.count = len; } return arr; } static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) { JS_FreeValue(ctx, desc->getter); JS_FreeValue(ctx, desc->setter); JS_FreeValue(ctx, desc->value); } /* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, the new property is not added and an error is raised. 'this_obj' is the receiver. If obj != this_obj, then obj must be an object (Reflect.set case). */ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValue val, JSValueConst this_obj, int flags) { JSObject *p, *p1; JSShapeProperty *prs; JSProperty *pr; uint32_t tag; JSPropertyDescriptor desc; int ret; #if 0 printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n"); #endif tag = JS_VALUE_GET_TAG(this_obj); if (unlikely(tag != JS_TAG_OBJECT)) { if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = NULL; p1 = JS_VALUE_GET_OBJ(obj); goto prototype_lookup; } else { switch(tag) { case JS_TAG_NULL: JS_FreeValue(ctx, val); JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); return -1; case JS_TAG_UNDEFINED: JS_FreeValue(ctx, val); JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); return -1; default: /* even on a primitive type we can have setters on the prototype */ p = NULL; p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); goto prototype_lookup; } } } else { p = JS_VALUE_GET_OBJ(this_obj); p1 = JS_VALUE_GET_OBJ(obj); if (unlikely(p != p1)) goto retry2; } /* fast path if obj == this_obj */ retry: prs = find_own_property(&pr, p1, prop); if (prs) { if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { /* fast case */ set_value(ctx, &pr->u.value, val); return TRUE; } else if (prs->flags & JS_PROP_LENGTH) { assert(p->class_id == JS_CLASS_ARRAY); assert(prop == JS_ATOM_length); return set_array_length(ctx, p, val, flags); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { /* JS_PROP_WRITABLE is always true for variable references, but they are write protected in module name spaces. */ if (p->class_id == JS_CLASS_MODULE_NS) goto read_only_prop; set_value(ctx, pr->u.var_ref->pvalue, val); return TRUE; } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry (potentially useless) */ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) { JS_FreeValue(ctx, val); return -1; } goto retry; } else { goto read_only_prop; } } for(;;) { if (p1->is_exotic) { if (p1->fast_array) { if (__JS_AtomIsTaggedInt(prop)) { uint32_t idx = __JS_AtomToUInt32(prop); if (idx < p1->u.array.count) { if (unlikely(p == p1)) return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags); else break; } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && p1->class_id <= JS_CLASS_FLOAT64_ARRAY) { goto typed_array_oob; } } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && p1->class_id <= JS_CLASS_FLOAT64_ARRAY) { ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { if (ret < 0) { JS_FreeValue(ctx, val); return -1; } typed_array_oob: /* must convert the argument even if out of bound access */ if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY || p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) { int64_t v; if (JS_ToBigInt64Free(ctx, &v, val)) return -1; } else { val = JS_ToNumberFree(ctx, val); JS_FreeValue(ctx, val); if (JS_IsException(val)) return -1; } return TRUE; } } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic; if (em) { JSValue obj1; if (em->set_property) { /* set_property can free the prototype */ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); ret = em->set_property(ctx, obj1, prop, val, this_obj, flags); JS_FreeValue(ctx, obj1); JS_FreeValue(ctx, val); return ret; } if (em->get_own_property) { /* get_own_property can free the prototype */ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); ret = em->get_own_property(ctx, &desc, obj1, prop); JS_FreeValue(ctx, obj1); if (ret < 0) { JS_FreeValue(ctx, val); return ret; } if (ret) { if (desc.flags & JS_PROP_GETSET) { JSObject *setter; if (JS_IsUndefined(desc.setter)) setter = NULL; else setter = JS_VALUE_GET_OBJ(desc.setter); ret = call_setter(ctx, setter, this_obj, val, flags); JS_FreeValue(ctx, desc.getter); JS_FreeValue(ctx, desc.setter); return ret; } else { JS_FreeValue(ctx, desc.value); if (!(desc.flags & JS_PROP_WRITABLE)) goto read_only_prop; if (likely(p == p1)) { ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, JS_PROP_HAS_VALUE); JS_FreeValue(ctx, val); return ret; } else { break; } } } } } } } p1 = p1->shape->proto; prototype_lookup: if (!p1) break; retry2: prs = find_own_property(&pr, p1, prop); if (prs) { if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry (potentially useless) */ if (JS_AutoInitProperty(ctx, p1, prop, pr, prs)) return -1; goto retry2; } else if (!(prs->flags & JS_PROP_WRITABLE)) { goto read_only_prop; } } } if (unlikely(flags & JS_PROP_NO_ADD)) { JS_FreeValue(ctx, val); JS_ThrowReferenceErrorNotDefined(ctx, prop); return -1; } if (unlikely(!p)) { JS_FreeValue(ctx, val); return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object"); } if (unlikely(!p->extensible)) { JS_FreeValue(ctx, val); return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); } if (likely(p == JS_VALUE_GET_OBJ(obj))) { if (p->is_exotic) { if (p->class_id == JS_CLASS_ARRAY && p->fast_array && __JS_AtomIsTaggedInt(prop)) { uint32_t idx = __JS_AtomToUInt32(prop); if (idx == p->u.array.count) { /* fast case */ return add_fast_array_element(ctx, p, val, flags); } else { goto generic_create_prop; } } else { goto generic_create_prop; } } else { pr = add_property(ctx, p, prop, JS_PROP_C_W_E); if (unlikely(!pr)) { JS_FreeValue(ctx, val); return -1; } pr->u.value = val; return TRUE; } } else { /* generic case: modify the property in this_obj if it already exists */ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); if (ret < 0) { JS_FreeValue(ctx, val); return ret; } if (ret) { if (desc.flags & JS_PROP_GETSET) { JS_FreeValue(ctx, desc.getter); JS_FreeValue(ctx, desc.setter); JS_FreeValue(ctx, val); return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); } else { JS_FreeValue(ctx, desc.value); if (!(desc.flags & JS_PROP_WRITABLE) || p->class_id == JS_CLASS_MODULE_NS) { read_only_prop: JS_FreeValue(ctx, val); return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); } } ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, JS_PROP_HAS_VALUE); JS_FreeValue(ctx, val); return ret; } else { generic_create_prop: ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_ENUMERABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_C_W_E); JS_FreeValue(ctx, val); return ret; } } } /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags) { if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { JSObject *p; uint32_t idx; double d; int32_t v; /* fast path for array access */ p = JS_VALUE_GET_OBJ(this_obj); idx = JS_VALUE_GET_INT(prop); switch(p->class_id) { case JS_CLASS_ARRAY: if (unlikely(idx >= (uint32_t)p->u.array.count)) { JSObject *p1; JSShape *sh1; /* fast path to add an element to the array */ if (idx != (uint32_t)p->u.array.count || !p->fast_array || !p->extensible) goto slow_path; /* check if prototype chain has a numeric property */ p1 = p->shape->proto; while (p1 != NULL) { sh1 = p1->shape; if (p1->class_id == JS_CLASS_ARRAY) { if (unlikely(!p1->fast_array)) goto slow_path; } else if (p1->class_id == JS_CLASS_OBJECT) { if (unlikely(sh1->has_small_array_index)) goto slow_path; } else { goto slow_path; } p1 = sh1->proto; } /* add element */ return add_fast_array_element(ctx, p, val, flags); } set_value(ctx, &p->u.array.u.values[idx], val); break; case JS_CLASS_ARGUMENTS: if (unlikely(idx >= (uint32_t)p->u.array.count)) goto slow_path; set_value(ctx, &p->u.array.u.values[idx], val); break; case JS_CLASS_UINT8C_ARRAY: if (JS_ToUint8ClampFree(ctx, &v, val)) return -1; /* Note: the conversion can detach the typed array, so the array bound check must be done after */ if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint8_ptr[idx] = v; break; case JS_CLASS_INT8_ARRAY: case JS_CLASS_UINT8_ARRAY: if (JS_ToInt32Free(ctx, &v, val)) return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint8_ptr[idx] = v; break; case JS_CLASS_INT16_ARRAY: case JS_CLASS_UINT16_ARRAY: if (JS_ToInt32Free(ctx, &v, val)) return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint16_ptr[idx] = v; break; case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: if (JS_ToInt32Free(ctx, &v, val)) return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint32_ptr[idx] = v; break; case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: /* XXX: need specific conversion function */ { int64_t v; if (JS_ToBigInt64Free(ctx, &v, val)) return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.uint64_ptr[idx] = v; } break; case JS_CLASS_FLOAT32_ARRAY: if (JS_ToFloat64Free(ctx, &d, val)) return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) goto ta_out_of_bound; p->u.array.u.float_ptr[idx] = d; break; case JS_CLASS_FLOAT64_ARRAY: if (JS_ToFloat64Free(ctx, &d, val)) return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) { ta_out_of_bound: return TRUE; } p->u.array.u.double_ptr[idx] = d; break; default: goto slow_path; } return TRUE; } else { JSAtom atom; int ret; slow_path: atom = JS_ValueToAtom(ctx, prop); JS_FreeValue(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) { JS_FreeValue(ctx, val); return -1; } ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags); JS_FreeAtom(ctx, atom); return ret; } } int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx, JSValue val) { return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val, JS_PROP_THROW); } int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, int64_t idx, JSValue val) { JSAtom prop; int res; if ((uint64_t)idx <= INT32_MAX) { /* fast path for fast arrays */ return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, JS_PROP_THROW); } prop = JS_NewAtomInt64(ctx, idx); if (prop == JS_ATOM_NULL) { JS_FreeValue(ctx, val); return -1; } res = JS_SetProperty(ctx, this_obj, prop, val); JS_FreeAtom(ctx, prop); return res; } int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, const char *prop, JSValue val) { JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW); JS_FreeAtom(ctx, atom); return ret; } /* compute the property flags. For each flag: (JS_PROP_HAS_x forces it, otherwise def_flags is used) Note: makes assumption about the bit pattern of the flags */ static int get_prop_flags(int flags, int def_flags) { int mask; mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E; return (flags & mask) | (def_flags & ~mask); } static int JS_CreateProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags) { JSProperty *pr; int ret, prop_flags; /* add a new property or modify an existing exotic one */ if (p->is_exotic) { if (p->class_id == JS_CLASS_ARRAY) { uint32_t idx, len; if (p->fast_array) { if (__JS_AtomIsTaggedInt(prop)) { idx = __JS_AtomToUInt32(prop); if (idx == p->u.array.count) { if (!p->extensible) goto not_extensible; if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) goto convert_to_array; prop_flags = get_prop_flags(flags, 0); if (prop_flags != JS_PROP_C_W_E) goto convert_to_array; return add_fast_array_element(ctx, p, JS_DupValue(ctx, val), flags); } else { goto convert_to_array; } } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) { /* convert the fast array to normal array */ convert_to_array: if (convert_fast_array_to_array(ctx, p)) return -1; goto generic_array; } } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) { JSProperty *plen; JSShapeProperty *pslen; generic_array: /* update the length field */ plen = &p->prop[0]; JS_ToUint32(ctx, &len, plen->u.value); if ((idx + 1) > len) { pslen = get_shape_prop(p->shape); if (unlikely(!(pslen->flags & JS_PROP_WRITABLE))) return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); /* XXX: should update the length after defining the property */ len = idx + 1; set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len)); } } } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { ret = JS_AtomIsNumericIndex(ctx, prop); if (ret != 0) { if (ret < 0) return -1; return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array"); } } else if (!(flags & JS_PROP_NO_EXOTIC)) { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em) { if (em->define_own_property) { return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop, val, getter, setter, flags); } ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ret < 0) return -1; if (!ret) goto not_extensible; } } } if (!p->extensible) { not_extensible: return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); } if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | JS_PROP_GETSET; } else { prop_flags = flags & JS_PROP_C_W_E; } pr = add_property(ctx, p, prop, prop_flags); if (unlikely(!pr)) return -1; if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { pr->u.getset.getter = NULL; if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) { pr->u.getset.getter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter)); } pr->u.getset.setter = NULL; if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) { pr->u.getset.setter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter)); } } else { if (flags & JS_PROP_HAS_VALUE) { pr->u.value = JS_DupValue(ctx, val); } else { pr->u.value = JS_UNDEFINED; } } return TRUE; } /* return FALSE if not OK */ static BOOL check_define_prop_flags(int prop_flags, int flags) { BOOL has_accessor, is_getset; if (!(prop_flags & JS_PROP_CONFIGURABLE)) { if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) == (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) { return FALSE; } if ((flags & JS_PROP_HAS_ENUMERABLE) && (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE)) return FALSE; } if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { if (!(prop_flags & JS_PROP_CONFIGURABLE)) { has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0); is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET); if (has_accessor != is_getset) return FALSE; if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) { /* not writable: cannot set the writable bit */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) return FALSE; } } } return TRUE; } /* ensure that the shape can be safely modified */ static int js_shape_prepare_update(JSContext *ctx, JSObject *p, JSShapeProperty **pprs) { JSShape *sh; uint32_t idx = 0; /* prevent warning */ sh = p->shape; if (sh->is_hashed) { if (sh->header.ref_count != 1) { if (pprs) idx = *pprs - get_shape_prop(sh); /* clone the shape (the resulting one is no longer hashed) */ sh = js_clone_shape(ctx, sh); if (!sh) return -1; js_free_shape(ctx->rt, p->shape); p->shape = sh; if (pprs) *pprs = get_shape_prop(sh) + idx; } else { js_shape_hash_unlink(ctx->rt, sh); sh->is_hashed = FALSE; } } return 0; } static int js_update_property_flags(JSContext *ctx, JSObject *p, JSShapeProperty **pprs, int flags) { if (flags != (*pprs)->flags) { if (js_shape_prepare_update(ctx, p, pprs)) return -1; (*pprs)->flags = flags; } return 0; } /* allowed flags: JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE, JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE, JS_PROP_THROW, JS_PROP_NO_EXOTIC. If JS_PROP_THROW is set, return an exception instead of FALSE. if JS_PROP_NO_EXOTIC is set, do not call the exotic define_own_property callback. return -1 (exception), FALSE or TRUE. */ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; int mask, res; if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; } p = JS_VALUE_GET_OBJ(this_obj); redo_prop_update: prs = find_own_property(&pr, p, prop); if (prs) { /* the range of the Array length property is always tested before */ if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) { uint32_t array_length; if (JS_ToArrayLengthFree(ctx, &array_length, JS_DupValue(ctx, val), FALSE)) { return -1; } /* this code relies on the fact that Uint32 are never allocated */ val = JS_NewUint32(ctx, array_length); /* prs may have been modified */ prs = find_own_property(&pr, p, prop); assert(prs != NULL); } /* property already exists */ if (!check_define_prop_flags(prs->flags, flags)) { not_configurable: return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); } if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) return -1; goto redo_prop_update; } if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { JSObject *new_getter, *new_setter; if (JS_IsFunction(ctx, getter)) { new_getter = JS_VALUE_GET_OBJ(getter); } else { new_getter = NULL; } if (JS_IsFunction(ctx, setter)) { new_setter = JS_VALUE_GET_OBJ(setter); } else { new_setter = NULL; } if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) { if (js_shape_prepare_update(ctx, p, &prs)) return -1; /* convert to getset */ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { free_var_ref(ctx->rt, pr->u.var_ref); } else { JS_FreeValue(ctx, pr->u.value); } prs->flags = (prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | JS_PROP_GETSET; pr->u.getset.getter = NULL; pr->u.getset.setter = NULL; } else { if (!(prs->flags & JS_PROP_CONFIGURABLE)) { if ((flags & JS_PROP_HAS_GET) && new_getter != pr->u.getset.getter) { goto not_configurable; } if ((flags & JS_PROP_HAS_SET) && new_setter != pr->u.getset.setter) { goto not_configurable; } } } if (flags & JS_PROP_HAS_GET) { if (pr->u.getset.getter) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); if (new_getter) JS_DupValue(ctx, getter); pr->u.getset.getter = new_getter; } if (flags & JS_PROP_HAS_SET) { if (pr->u.getset.setter) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); if (new_setter) JS_DupValue(ctx, setter); pr->u.getset.setter = new_setter; } } else { if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { /* convert to data descriptor */ if (js_shape_prepare_update(ctx, p, &prs)) return -1; if (pr->u.getset.getter) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); if (pr->u.getset.setter) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); pr->u.value = JS_UNDEFINED; } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { /* Note: JS_PROP_VARREF is always writable */ } else { if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && (flags & JS_PROP_HAS_VALUE)) { if (!js_same_value(ctx, val, pr->u.value)) { goto not_configurable; } else { return TRUE; } } } if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { if (flags & JS_PROP_HAS_VALUE) { if (p->class_id == JS_CLASS_MODULE_NS) { /* JS_PROP_WRITABLE is always true for variable references, but they are write protected in module name spaces. */ if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) goto not_configurable; } else { /* update the reference */ set_value(ctx, pr->u.var_ref->pvalue, JS_DupValue(ctx, val)); } } /* if writable is set to false, no longer a reference (for mapped arguments) */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { JSValue val1; if (p->class_id == JS_CLASS_MODULE_NS) { return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false"); } if (js_shape_prepare_update(ctx, p, &prs)) return -1; val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue); free_var_ref(ctx->rt, pr->u.var_ref); pr->u.value = val1; prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); } } else if (prs->flags & JS_PROP_LENGTH) { if (flags & JS_PROP_HAS_VALUE) { /* Note: no JS code is executable because 'val' is guaranted to be a Uint32 */ res = set_array_length(ctx, p, JS_DupValue(ctx, val), flags); } else { res = TRUE; } /* still need to reset the writable flag if needed. The JS_PROP_LENGTH is kept because the Uint32 test is still done if the length property is read-only. */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { prs = get_shape_prop(p->shape); if (js_update_property_flags(ctx, p, &prs, prs->flags & ~JS_PROP_WRITABLE)) return -1; } return res; } else { if (flags & JS_PROP_HAS_VALUE) { JS_FreeValue(ctx, pr->u.value); pr->u.value = JS_DupValue(ctx, val); } if (flags & JS_PROP_HAS_WRITABLE) { if (js_update_property_flags(ctx, p, &prs, (prs->flags & ~JS_PROP_WRITABLE) | (flags & JS_PROP_WRITABLE))) return -1; } } } } mask = 0; if (flags & JS_PROP_HAS_CONFIGURABLE) mask |= JS_PROP_CONFIGURABLE; if (flags & JS_PROP_HAS_ENUMERABLE) mask |= JS_PROP_ENUMERABLE; if (js_update_property_flags(ctx, p, &prs, (prs->flags & ~mask) | (flags & mask))) return -1; return TRUE; } /* handle modification of fast array elements */ if (p->fast_array) { uint32_t idx; uint32_t prop_flags; if (p->class_id == JS_CLASS_ARRAY) { if (__JS_AtomIsTaggedInt(prop)) { idx = __JS_AtomToUInt32(prop); if (idx < p->u.array.count) { prop_flags = get_prop_flags(flags, JS_PROP_C_W_E); if (prop_flags != JS_PROP_C_W_E) goto convert_to_slow_array; if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { convert_to_slow_array: if (convert_fast_array_to_array(ctx, p)) return -1; else goto redo_prop_update; } if (flags & JS_PROP_HAS_VALUE) { set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val)); } return TRUE; } } } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { JSValue num; int ret; if (!__JS_AtomIsTaggedInt(prop)) { /* slow path with to handle all numeric indexes */ num = JS_AtomIsNumericIndex1(ctx, prop); if (JS_IsUndefined(num)) goto typed_array_done; if (JS_IsException(num)) return -1; ret = JS_NumberIsInteger(ctx, num); if (ret < 0) { JS_FreeValue(ctx, num); return -1; } if (!ret) { JS_FreeValue(ctx, num); return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array"); } ret = JS_NumberIsNegativeOrMinusZero(ctx, num); JS_FreeValue(ctx, num); if (ret) { return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array"); } if (!__JS_AtomIsTaggedInt(prop)) goto typed_array_oob; } idx = __JS_AtomToUInt32(prop); /* if the typed array is detached, p->u.array.count = 0 */ if (idx >= p->u.array.count) { typed_array_oob: return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); } prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) || prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) { return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags"); } if (flags & JS_PROP_HAS_VALUE) { return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags); } return TRUE; typed_array_done: ; } } return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags); } static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSAutoInitIDEnum id, void *opaque, int flags) { JSObject *p; JSProperty *pr; if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(this_obj); if (find_own_property(&pr, p, prop)) { /* property already exists */ abort(); return FALSE; } /* Specialized CreateProperty */ pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT); if (unlikely(!pr)) return -1; pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx); assert((pr->u.init.realm_and_id & 3) == 0); assert(id <= 3); pr->u.init.realm_and_id |= id; pr->u.init.opaque = opaque; return TRUE; } /* shortcut to add or redefine a new property value */ int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags) { int ret; ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); JS_FreeValue(ctx, val); return ret; } int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags) { JSAtom atom; int ret; atom = JS_ValueToAtom(ctx, prop); JS_FreeValue(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) { JS_FreeValue(ctx, val); return -1; } ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags); JS_FreeAtom(ctx, atom); return ret; } int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx, JSValue val, int flags) { return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx), val, flags); } int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj, int64_t idx, JSValue val, int flags) { return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), val, flags); } int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, const char *prop, JSValue val, int flags) { JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags); JS_FreeAtom(ctx, atom); return ret; } /* shortcut to add getter & setter */ int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue getter, JSValue setter, int flags) { int ret; ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter, flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE); JS_FreeValue(ctx, getter); JS_FreeValue(ctx, setter); return ret; } static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj, int64_t idx, JSValue val, int flags) { return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), val, flags | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); } /* return TRUE if 'obj' has a non empty 'name' string */ static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj) { JSProperty *pr; JSShapeProperty *prs; JSValueConst val; JSString *p; prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name); if (!prs) return FALSE; if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) return TRUE; val = pr->u.value; if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) return TRUE; p = JS_VALUE_GET_STRING(val); return (p->len != 0); } static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj, JSAtom name, int flags) { if (name != JS_ATOM_NULL && JS_IsObject(obj) && !js_object_has_name(ctx, obj) && JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) { return -1; } return 0; } static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj, JSValueConst str, int flags) { if (JS_IsObject(obj) && !js_object_has_name(ctx, obj)) { JSAtom prop; JSValue name_str; prop = JS_ValueToAtom(ctx, str); if (prop == JS_ATOM_NULL) return -1; name_str = js_get_function_name(ctx, prop); JS_FreeAtom(ctx, prop); if (JS_IsException(name_str)) return -1; if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0) return -1; } return 0; } #define DEFINE_GLOBAL_LEX_VAR (1 << 7) #define DEFINE_GLOBAL_FUNC_VAR (1 << 6) static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop) { return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop); } /* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */ /* XXX: could support exotic global object. */ static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) { JSObject *p; JSShapeProperty *prs; p = JS_VALUE_GET_OBJ(ctx->global_obj); prs = find_own_property1(p, prop); /* XXX: should handle JS_PROP_AUTOINIT */ if (flags & DEFINE_GLOBAL_LEX_VAR) { if (prs && !(prs->flags & JS_PROP_CONFIGURABLE)) goto fail_redeclaration; } else { if (!prs && !p->extensible) goto define_error; if (flags & DEFINE_GLOBAL_FUNC_VAR) { if (prs) { if (!(prs->flags & JS_PROP_CONFIGURABLE) && ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET || ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) != (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) { define_error: JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", prop); return -1; } } } } /* check if there already is a lexical declaration */ p = JS_VALUE_GET_OBJ(ctx->global_var_obj); prs = find_own_property1(p, prop); if (prs) { fail_redeclaration: JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop); return -1; } return 0; } /* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */ /* XXX: could support exotic global object. */ static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; JSValue val; int flags; if (def_flags & DEFINE_GLOBAL_LEX_VAR) { p = JS_VALUE_GET_OBJ(ctx->global_var_obj); flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) | JS_PROP_CONFIGURABLE; val = JS_UNINITIALIZED; } else { p = JS_VALUE_GET_OBJ(ctx->global_obj); flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | (def_flags & JS_PROP_CONFIGURABLE); val = JS_UNDEFINED; } prs = find_own_property1(p, prop); if (prs) return 0; if (!p->extensible) return 0; pr = add_property(ctx, p, prop, flags); if (unlikely(!pr)) return -1; pr->u.value = val; return 0; } /* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */ /* XXX: could support exotic global object. */ static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop, JSValueConst func, int def_flags) { JSObject *p; JSShapeProperty *prs; int flags; p = JS_VALUE_GET_OBJ(ctx->global_obj); prs = find_own_property1(p, prop); flags = JS_PROP_HAS_VALUE | JS_PROP_THROW; if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) { flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE; } if (JS_DefineProperty(ctx, ctx->global_obj, prop, func, JS_UNDEFINED, JS_UNDEFINED, flags) < 0) return -1; return 0; } static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, BOOL throw_ref_error) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; /* no exotic behavior is possible in global_var_obj */ p = JS_VALUE_GET_OBJ(ctx->global_var_obj); prs = find_own_property(&pr, p, prop); if (prs) { /* XXX: should handle JS_PROP_TMASK properties */ if (unlikely(JS_IsUninitialized(pr->u.value))) return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return JS_DupValue(ctx, pr->u.value); } if (ctx->scopeLookup) { struct LookupResult result = ctx->scopeLookup(ctx, prop); if (result.useResult) return result.value; } return JS_GetPropertyInternal(ctx, ctx->global_obj, prop, ctx->global_obj, throw_ref_error); } /* construct a reference to a global variable */ static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; /* no exotic behavior is possible in global_var_obj */ p = JS_VALUE_GET_OBJ(ctx->global_var_obj); prs = find_own_property(&pr, p, prop); if (prs) { /* XXX: should handle JS_PROP_AUTOINIT properties? */ /* XXX: conformance: do these tests in OP_put_var_ref/OP_get_var_ref ? */ if (unlikely(JS_IsUninitialized(pr->u.value))) { JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return -1; } if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); } sp[0] = JS_DupValue(ctx, ctx->global_var_obj); } else { int ret; ret = JS_HasProperty(ctx, ctx->global_obj, prop); if (ret < 0) return -1; if (ret) { sp[0] = JS_DupValue(ctx, ctx->global_obj); } else { sp[0] = JS_UNDEFINED; } } sp[1] = JS_AtomToValue(ctx, prop); return 0; } /* use for strict variable access: test if the variable exists */ static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop) { JSObject *p; JSShapeProperty *prs; int ret; /* no exotic behavior is possible in global_var_obj */ p = JS_VALUE_GET_OBJ(ctx->global_var_obj); prs = find_own_property1(p, prop); if (prs) { ret = TRUE; } else { ret = JS_HasProperty(ctx, ctx->global_obj, prop); if (ret < 0) return -1; } return ret; } /* flag = 0: normal variable write flag = 1: initialize lexical variable flag = 2: normal variable write, strict check was done before */ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, int flag) { JSObject *p; JSShapeProperty *prs; JSProperty *pr; int flags; /* no exotic behavior is possible in global_var_obj */ p = JS_VALUE_GET_OBJ(ctx->global_var_obj); prs = find_own_property(&pr, p, prop); if (prs) { /* XXX: should handle JS_PROP_AUTOINIT properties? */ if (flag != 1) { if (unlikely(JS_IsUninitialized(pr->u.value))) { JS_FreeValue(ctx, val); JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); return -1; } if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { JS_FreeValue(ctx, val); return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); } } set_value(ctx, &pr->u.value, val); return 0; } flags = JS_PROP_THROW_STRICT; if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; if (ctx->scopeLookup) { struct LookupResult result = ctx->scopeLookup(ctx, prop); if (result.useResult) { JS_FreeValue(ctx, result.value); return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, result.scope, flags); } } return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags); } /* return -1, FALSE or TRUE. return FALSE if not configurable or invalid object. return -1 in case of exception. flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) { JSValue obj1; JSObject *p; int res; obj1 = JS_ToObject(ctx, obj); if (JS_IsException(obj1)) return -1; p = JS_VALUE_GET_OBJ(obj1); res = delete_property(ctx, p, prop); JS_FreeValue(ctx, obj1); if (res != FALSE) return res; if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { JS_ThrowTypeError(ctx, "could not delete property"); return -1; } return FALSE; } int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags) { JSAtom prop; int res; if ((uint64_t)idx <= JS_ATOM_MAX_INT) { /* fast path for fast arrays */ return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags); } prop = JS_NewAtomInt64(ctx, idx); if (prop == JS_ATOM_NULL) return -1; res = JS_DeleteProperty(ctx, obj, prop, flags); JS_FreeAtom(ctx, prop); return res; } BOOL JS_IsFunction(JSContext *ctx, JSValueConst val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(val); switch(p->class_id) { case JS_CLASS_BYTECODE_FUNCTION: return TRUE; case JS_CLASS_PROXY: return p->u.proxy_data->is_func; default: return (ctx->rt->class_array[p->class_id].call != NULL); } } BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(val); if (p->class_id == JS_CLASS_C_FUNCTION) return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic); else return FALSE; } BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(val); return p->is_constructor; } BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val) { JSObject *p; if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(func_obj); p->is_constructor = val; return TRUE; } JS_BOOL JS_IsArrayBuffer(JSValueConst v) { if (!JS_IsObject(v)) return FALSE; JSObject *p = JS_VALUE_GET_OBJ(v); return p->class_id == JS_CLASS_ARRAY_BUFFER || p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER; } BOOL JS_IsError(JSContext *ctx, JSValueConst val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(val); return (p->class_id == JS_CLASS_ERROR); } /* used to avoid catching interrupt exceptions */ BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(val); return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error; } void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag) { JSObject *p; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return; p = JS_VALUE_GET_OBJ(val); if (p->class_id == JS_CLASS_ERROR) p->is_uncatchable_error = flag; } void JS_ResetUncatchableError(JSContext *ctx) { JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE); } void JS_SetOpaque(JSValue obj, void *opaque) { JSObject *p; if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = JS_VALUE_GET_OBJ(obj); p->u.opaque = opaque; } } /* return NULL if not an object of class class_id */ void *JS_GetOpaque(JSValueConst obj, JSClassID class_id) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return NULL; p = JS_VALUE_GET_OBJ(obj); if (p->class_id != class_id) return NULL; return p->u.opaque; } void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) { void *p = JS_GetOpaque(obj, class_id); if (unlikely(!p)) { JS_ThrowTypeErrorInvalidClass(ctx, class_id); } return p; } static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) { int i; BOOL force_ordinary; JSAtom method_name; JSValue method, ret; if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) return val; force_ordinary = hint & HINT_FORCE_ORDINARY; hint &= ~HINT_FORCE_ORDINARY; if (!force_ordinary) { method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive); if (JS_IsException(method)) goto exception; /* ECMA says *If exoticToPrim is not undefined* but tests in test262 use null as a non callable converter */ if (!JS_IsUndefined(method) && !JS_IsNull(method)) { JSAtom atom; JSValue arg; switch(hint) { case HINT_STRING: atom = JS_ATOM_string; break; case HINT_NUMBER: atom = JS_ATOM_number; break; default: case HINT_NONE: atom = JS_ATOM_default; break; } arg = JS_AtomToString(ctx, atom); ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg); JS_FreeValue(ctx, arg); if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, val); if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) return ret; JS_FreeValue(ctx, ret); return JS_ThrowTypeError(ctx, "toPrimitive"); } } if (hint != HINT_STRING) hint = HINT_NUMBER; for(i = 0; i < 2; i++) { if ((i ^ hint) == 0) { method_name = JS_ATOM_toString; } else { method_name = JS_ATOM_valueOf; } method = JS_GetProperty(ctx, val, method_name); if (JS_IsException(method)) goto exception; if (JS_IsFunction(ctx, method)) { ret = JS_CallFree(ctx, method, val, 0, NULL); if (JS_IsException(ret)) goto exception; if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) { JS_FreeValue(ctx, val); return ret; } JS_FreeValue(ctx, ret); } else { JS_FreeValue(ctx, method); } } JS_ThrowTypeError(ctx, "toPrimitive"); exception: JS_FreeValue(ctx, val); return JS_EXCEPTION; } static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint) { return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint); } void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return; p = JS_VALUE_GET_OBJ(obj); p->is_HTMLDDA = TRUE; } static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) { JSObject *p; if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return FALSE; p = JS_VALUE_GET_OBJ(obj); return p->is_HTMLDDA; } static int JS_ToBoolFree(JSContext *ctx, JSValue val) { uint32_t tag = JS_VALUE_GET_TAG(val); switch(tag) { case JS_TAG_INT: return JS_VALUE_GET_INT(val) != 0; case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: return JS_VALUE_GET_INT(val); case JS_TAG_EXCEPTION: return -1; case JS_TAG_STRING: { BOOL ret = JS_VALUE_GET_STRING(val)->len != 0; JS_FreeValue(ctx, val); return ret; } case JS_TAG_BIG_INT: #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: #endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); BOOL ret; ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN; JS_FreeValue(ctx, val); return ret; } #ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: { JSBigDecimal *p = JS_VALUE_GET_PTR(val); BOOL ret; ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN; JS_FreeValue(ctx, val); return ret; } #endif case JS_TAG_OBJECT: { JSObject *p = JS_VALUE_GET_OBJ(val); BOOL ret; ret = !p->is_HTMLDDA; JS_FreeValue(ctx, val); return ret; } break; default: if (JS_TAG_IS_FLOAT64(tag)) { double d = JS_VALUE_GET_FLOAT64(val); return !isnan(d) && d != 0; } else { JS_FreeValue(ctx, val); return TRUE; } } } int JS_ToBool(JSContext *ctx, JSValueConst val) { return JS_ToBoolFree(ctx, JS_DupValue(ctx, val)); } static int skip_spaces(const char *pc) { const uint8_t *p, *p_next, *p_start; uint32_t c; p = p_start = (const uint8_t *)pc; for (;;) { c = *p; if (c < 128) { if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20))) break; p++; } else { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); if (!lre_is_space(c)) break; p = p_next; } } return p - p_start; } static inline int to_digit(int c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'A' && c <= 'Z') return c - 'A' + 10; else if (c >= 'a' && c <= 'z') return c - 'a' + 10; else return 36; } /* XXX: remove */ static double js_strtod(const char *str, int radix, BOOL is_float) { double d; int c; if (!is_float || radix != 10) { const char *p = str; uint64_t n_max, n; int int_exp, is_neg; is_neg = 0; if (*p == '-') { is_neg = 1; p++; } /* skip leading zeros */ while (*p == '0') p++; n = 0; if (radix == 10) n_max = ((uint64_t)-1 - 9) / 10; /* most common case */ else n_max = ((uint64_t)-1 - (radix - 1)) / radix; /* XXX: could be more precise */ int_exp = 0; while (*p != '\0') { c = to_digit((uint8_t)*p); if (c >= radix) break; if (n <= n_max) { n = n * radix + c; } else { if (radix == 10) goto strtod_case; int_exp++; } p++; } d = n; if (int_exp != 0) { d *= pow(radix, int_exp); } if (is_neg) d = -d; } else { strtod_case: d = safe_strtod(str, NULL); } return d; } #define ATOD_INT_ONLY (1 << 0) /* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */ #define ATOD_ACCEPT_BIN_OCT (1 << 2) /* accept O prefix as octal if radix == 0 and properly formed (Annex B) */ #define ATOD_ACCEPT_LEGACY_OCTAL (1 << 4) /* accept _ between digits as a digit separator */ #define ATOD_ACCEPT_UNDERSCORES (1 << 5) /* allow a suffix to override the type */ #define ATOD_ACCEPT_SUFFIX (1 << 6) /* default type */ #define ATOD_TYPE_MASK (3 << 7) #define ATOD_TYPE_FLOAT64 (0 << 7) #define ATOD_TYPE_BIG_INT (1 << 7) #ifdef CONFIG_BIGNUM #define ATOD_TYPE_BIG_FLOAT (2 << 7) #define ATOD_TYPE_BIG_DECIMAL (3 << 7) /* assume bigint mode: floats are parsed as integers if no decimal point nor exponent */ #define ATOD_MODE_BIGINT (1 << 9) #endif /* accept -0x1 */ #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { bf_t a_s, *a = &a_s; int ret; JSValue val; val = JS_NewBigInt(ctx); if (JS_IsException(val)) return val; a = JS_GetBigInt(val); ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ); if (ret & BF_ST_MEM_ERROR) { JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } #ifdef CONFIG_BIGNUM val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0); #else val = JS_CompactBigInt1(ctx, val, FALSE); #endif return val; } #ifdef CONFIG_BIGNUM static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { bf_t *a; int ret; JSValue val; val = JS_NewBigFloat(ctx); if (JS_IsException(val)) return val; a = JS_GetBigFloat(val); if (flags & ATOD_ACCEPT_SUFFIX) { /* return the exponent to get infinite precision */ ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF, BF_RNDZ | BF_ATOF_EXPONENT); } else { ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec, ctx->fp_env.flags); } if (ret & BF_ST_MEM_ERROR) { JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } return val; } static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { bfdec_t *a; int ret; JSValue val; val = JS_NewBigDecimal(ctx); if (JS_IsException(val)) return val; a = JS_GetBigDecimal(val); ret = bfdec_atof(a, buf, NULL, BF_PREC_INF, BF_RNDZ | BF_ATOF_NO_NAN_INF); if (ret & BF_ST_MEM_ERROR) { JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } return val; } #endif /* return an exception in case of memory error. Return JS_NAN if invalid syntax */ #ifdef CONFIG_BIGNUM static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp, int radix, int flags, slimb_t *pexponent) #else static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, int radix, int flags) #endif { const char *p, *p_start; int sep, is_neg; BOOL is_float, has_legacy_octal; int atod_type = flags & ATOD_TYPE_MASK; char buf1[64], *buf; int i, j, len; BOOL buf_allocated = FALSE; JSValue val; /* optional separator between digits */ sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; has_legacy_octal = FALSE; p = str; p_start = p; is_neg = 0; if (p[0] == '+') { p++; p_start++; if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) goto no_radix_prefix; } else if (p[0] == '-') { p++; p_start++; is_neg = 1; if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) goto no_radix_prefix; } if (p[0] == '0') { if ((p[1] == 'x' || p[1] == 'X') && (radix == 0 || radix == 16)) { p += 2; radix = 16; } else if ((p[1] == 'o' || p[1] == 'O') && radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { p += 2; radix = 8; } else if ((p[1] == 'b' || p[1] == 'B') && radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { p += 2; radix = 2; } else if ((p[1] >= '0' && p[1] <= '9') && radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) { int i; has_legacy_octal = TRUE; sep = 256; for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) continue; if (p[i] == '8' || p[i] == '9') goto no_prefix; p += 1; radix = 8; } else { goto no_prefix; } /* there must be a digit after the prefix */ if (to_digit((uint8_t)*p) >= radix) goto fail; no_prefix: ; } else { no_radix_prefix: if (!(flags & ATOD_INT_ONLY) && (atod_type == ATOD_TYPE_FLOAT64 #ifdef CONFIG_BIGNUM || atod_type == ATOD_TYPE_BIG_FLOAT #endif ) && strstart(p, "Infinity", &p)) { #ifdef CONFIG_BIGNUM if (atod_type == ATOD_TYPE_BIG_FLOAT) { bf_t *a; val = JS_NewBigFloat(ctx); if (JS_IsException(val)) goto done; a = JS_GetBigFloat(val); bf_set_inf(a, is_neg); } else #endif { double d = INFINITY; if (is_neg) d = -d; val = JS_NewFloat64(ctx, d); } goto done; } } if (radix == 0) radix = 10; is_float = FALSE; p_start = p; while (to_digit((uint8_t)*p) < radix || (*p == sep && (radix != 10 || p != p_start + 1 || p[-1] != '0') && to_digit((uint8_t)p[1]) < radix)) { p++; } if (!(flags & ATOD_INT_ONLY)) { if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) { is_float = TRUE; p++; if (*p == sep) goto fail; while (to_digit((uint8_t)*p) < radix || (*p == sep && to_digit((uint8_t)p[1]) < radix)) p++; } if (p > p_start && (((*p == 'e' || *p == 'E') && radix == 10) || ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) { const char *p1 = p + 1; is_float = TRUE; if (*p1 == '+') { p1++; } else if (*p1 == '-') { p1++; } if (is_digit((uint8_t)*p1)) { p = p1 + 1; while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1]))) p++; } } } if (p == p_start) goto fail; buf = buf1; buf_allocated = FALSE; len = p - p_start; if (unlikely((len + 2) > sizeof(buf1))) { buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */ if (!buf) goto mem_error; buf_allocated = TRUE; } /* remove the separators and the radix prefixes */ j = 0; if (is_neg) buf[j++] = '-'; for (i = 0; i < len; i++) { if (p_start[i] != '_') buf[j++] = p_start[i]; } buf[j] = '\0'; if (flags & ATOD_ACCEPT_SUFFIX) { if (*p == 'n') { p++; atod_type = ATOD_TYPE_BIG_INT; } else #ifdef CONFIG_BIGNUM if (*p == 'l') { p++; atod_type = ATOD_TYPE_BIG_FLOAT; } else if (*p == 'm') { p++; atod_type = ATOD_TYPE_BIG_DECIMAL; } else if (flags & ATOD_MODE_BIGINT) { if (!is_float) atod_type = ATOD_TYPE_BIG_INT; if (has_legacy_octal) goto fail; } else #endif { if (is_float && radix != 10) goto fail; } } else { if (atod_type == ATOD_TYPE_FLOAT64) { #ifdef CONFIG_BIGNUM if (flags & ATOD_MODE_BIGINT) { if (!is_float) atod_type = ATOD_TYPE_BIG_INT; if (has_legacy_octal) goto fail; } else #endif { if (is_float && radix != 10) goto fail; } } } switch(atod_type) { case ATOD_TYPE_FLOAT64: { double d; d = js_strtod(buf, radix, is_float); /* return int or float64 */ val = JS_NewFloat64(ctx, d); } break; case ATOD_TYPE_BIG_INT: if (has_legacy_octal || is_float) goto fail; val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL); break; #ifdef CONFIG_BIGNUM case ATOD_TYPE_BIG_FLOAT: if (has_legacy_octal) goto fail; val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags, pexponent); break; case ATOD_TYPE_BIG_DECIMAL: if (radix != 10) goto fail; val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL); break; #endif default: abort(); } done: if (buf_allocated) js_free_rt(ctx->rt, buf); if (pp) *pp = p; return val; fail: val = JS_NAN; goto done; mem_error: val = JS_ThrowOutOfMemory(ctx); goto done; } #ifdef CONFIG_BIGNUM static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, int radix, int flags) { return js_atof2(ctx, str, pp, radix, flags, NULL); } #endif typedef enum JSToNumberHintEnum { TON_FLAG_NUMBER, TON_FLAG_NUMERIC, } JSToNumberHintEnum; static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, JSToNumberHintEnum flag) { uint32_t tag; JSValue ret; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_BIG_INT: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); } ret = val; break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number"); } ret = val; break; case JS_TAG_BIG_FLOAT: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number"); } ret = val; break; #endif case JS_TAG_FLOAT64: case JS_TAG_INT: case JS_TAG_EXCEPTION: ret = val; break; case JS_TAG_BOOL: case JS_TAG_NULL: ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); break; case JS_TAG_UNDEFINED: ret = JS_NAN; break; case JS_TAG_OBJECT: val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); if (JS_IsException(val)) return JS_EXCEPTION; goto redo; case JS_TAG_STRING: { const char *str; const char *p; size_t len; str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) return JS_EXCEPTION; p = str; p += skip_spaces(p); if ((p - str) == len) { ret = JS_NewInt32(ctx, 0); } else { int flags = ATOD_ACCEPT_BIN_OCT; ret = js_atof(ctx, p, &p, 0, flags); if (!JS_IsException(ret)) { p += skip_spaces(p); if ((p - str) != len) { JS_FreeValue(ctx, ret); ret = JS_NAN; } } } JS_FreeCString(ctx, str); } break; case JS_TAG_SYMBOL: JS_FreeValue(ctx, val); return JS_ThrowTypeError(ctx, "cannot convert symbol to number"); default: JS_FreeValue(ctx, val); ret = JS_NAN; break; } return ret; } static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) { return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER); } static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val) { return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC); } static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) { return JS_ToNumericFree(ctx, JS_DupValue(ctx, val)); } static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val) { double d; uint32_t tag; val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { *pres = JS_FLOAT64_NAN; return -1; } tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: d = JS_VALUE_GET_INT(val); break; case JS_TAG_FLOAT64: d = JS_VALUE_GET_FLOAT64(val); break; case JS_TAG_BIG_INT: #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: #endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); /* XXX: there can be a double rounding issue with some primitives (such as JS_ToUint8ClampFree()), but it is not critical to fix it. */ bf_get_float64(&p->num, &d, BF_RNDN); JS_FreeValue(ctx, val); } break; default: abort(); } *pres = d; return 0; } static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val) { uint32_t tag; tag = JS_VALUE_GET_TAG(val); if (tag <= JS_TAG_NULL) { *pres = JS_VALUE_GET_INT(val); return 0; } else if (JS_TAG_IS_FLOAT64(tag)) { *pres = JS_VALUE_GET_FLOAT64(val); return 0; } else { return __JS_ToFloat64Free(ctx, pres, val); } } int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val) { return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val)); } static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val) { return JS_ToNumberFree(ctx, JS_DupValue(ctx, val)); } /* same as JS_ToNumber() but return 0 in case of NaN/Undefined */ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) { uint32_t tag; JSValue ret; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); break; case JS_TAG_FLOAT64: { double d = JS_VALUE_GET_FLOAT64(val); if (isnan(d)) { ret = JS_NewInt32(ctx, 0); } else { /* convert -0 to +0 */ d = trunc(d) + 0.0; ret = JS_NewFloat64(ctx, d); } } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { bf_t a_s, *a, r_s, *r = &r_s; BOOL is_nan; a = JS_ToBigFloat(ctx, &a_s, val); if (!a) { JS_FreeValue(ctx, val); return JS_EXCEPTION; } if (!bf_is_finite(a)) { is_nan = bf_is_nan(a); if (is_nan) ret = JS_NewInt32(ctx, 0); else ret = JS_DupValue(ctx, val); } else { ret = JS_NewBigInt(ctx); if (!JS_IsException(ret)) { r = JS_GetBigInt(ret); bf_set(r, a); bf_rint(r, BF_RNDZ); ret = JS_CompactBigInt(ctx, ret); } } if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, val); } break; #endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) return val; goto redo; } return ret; } /* Note: the integer value is satured to 32 bits */ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) { uint32_t tag; int ret; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: ret = JS_VALUE_GET_INT(val); break; case JS_TAG_EXCEPTION: *pres = 0; return -1; case JS_TAG_FLOAT64: { double d = JS_VALUE_GET_FLOAT64(val); if (isnan(d)) { ret = 0; } else { if (d < INT32_MIN) ret = INT32_MIN; else if (d > INT32_MAX) ret = INT32_MAX; else ret = (int)d; } } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_get_int32(&ret, &p->num, 0); JS_FreeValue(ctx, val); } break; #endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { *pres = 0; return -1; } goto redo; } *pres = ret; return 0; } int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val) { return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val)); } int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val, int min, int max, int min_offset) { int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val)); if (res == 0) { if (*pres < min) { *pres += min_offset; if (*pres < min) *pres = min; } else { if (*pres > max) *pres = max; } } return res; } static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) { uint32_t tag; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: *pres = JS_VALUE_GET_INT(val); return 0; case JS_TAG_EXCEPTION: *pres = 0; return -1; case JS_TAG_FLOAT64: { double d = JS_VALUE_GET_FLOAT64(val); if (isnan(d)) { *pres = 0; } else { if (d < INT64_MIN) *pres = INT64_MIN; else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */ *pres = INT64_MAX; else *pres = (int64_t)d; } } return 0; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_get_int64(pres, &p->num, 0); JS_FreeValue(ctx, val); } return 0; #endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { *pres = 0; return -1; } goto redo; } } int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val) { return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val)); } int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val, int64_t min, int64_t max, int64_t neg_offset) { int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val)); if (res == 0) { if (*pres < 0) *pres += neg_offset; if (*pres < min) *pres = min; else if (*pres > max) *pres = max; } return res; } /* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0) in case of exception */ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) { uint32_t tag; int64_t ret; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: ret = JS_VALUE_GET_INT(val); break; case JS_TAG_FLOAT64: { JSFloat64Union u; double d; int e; d = JS_VALUE_GET_FLOAT64(val); u.d = d; /* we avoid doing fmod(x, 2^64) */ e = (u.u64 >> 52) & 0x7ff; if (likely(e <= (1023 + 62))) { /* fast case */ ret = (int64_t)d; } else if (e <= (1023 + 62 + 53)) { uint64_t v; /* remainder modulo 2^64 */ v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52); ret = v << ((e - 1023) - 52); /* take the sign into account */ if (u.u64 >> 63) ret = -ret; } else { ret = 0; /* also handles NaN and +inf */ } } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_get_int64(&ret, &p->num, BF_GET_INT_MOD); JS_FreeValue(ctx, val); } break; #endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { *pres = 0; return -1; } goto redo; } *pres = ret; return 0; } int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val) { return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val)); } int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val) { if (JS_IsBigInt(ctx, val)) return JS_ToBigInt64(ctx, pres, val); else return JS_ToInt64(ctx, pres, val); } /* return (<0, 0) in case of exception */ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) { uint32_t tag; int32_t ret; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: ret = JS_VALUE_GET_INT(val); break; case JS_TAG_FLOAT64: { JSFloat64Union u; double d; int e; d = JS_VALUE_GET_FLOAT64(val); u.d = d; /* we avoid doing fmod(x, 2^32) */ e = (u.u64 >> 52) & 0x7ff; if (likely(e <= (1023 + 30))) { /* fast case */ ret = (int32_t)d; } else if (e <= (1023 + 30 + 53)) { uint64_t v; /* remainder modulo 2^32 */ v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52); v = v << ((e - 1023) - 52 + 32); ret = v >> 32; /* take the sign into account */ if (u.u64 >> 63) ret = -ret; } else { ret = 0; /* also handles NaN and +inf */ } } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_get_int32(&ret, &p->num, BF_GET_INT_MOD); JS_FreeValue(ctx, val); } break; #endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { *pres = 0; return -1; } goto redo; } *pres = ret; return 0; } int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val) { return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val)); } static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val) { return JS_ToInt32Free(ctx, (int32_t *)pres, val); } static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) { uint32_t tag; int res; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: case JS_TAG_UNDEFINED: res = JS_VALUE_GET_INT(val); #ifdef CONFIG_BIGNUM int_clamp: #endif res = max_int(0, min_int(255, res)); break; case JS_TAG_FLOAT64: { double d = JS_VALUE_GET_FLOAT64(val); if (isnan(d)) { res = 0; } else { if (d < 0) res = 0; else if (d > 255) res = 255; else res = lrint(d); } } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_t r_s, *r = &r_s; bf_init(ctx->bf_ctx, r); bf_set(r, &p->num); bf_rint(r, BF_RNDN); bf_get_int32(&res, r, 0); bf_delete(r); JS_FreeValue(ctx, val); } goto int_clamp; #endif default: val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) { *pres = 0; return -1; } goto redo; } *pres = res; return 0; } static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, JSValue val, BOOL is_array_ctor) { uint32_t tag, len; tag = JS_VALUE_GET_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: { int v; v = JS_VALUE_GET_INT(val); if (v < 0) goto fail; len = v; } break; case JS_TAG_BIG_INT: #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: #endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_t a; BOOL res; bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD); bf_init(ctx->bf_ctx, &a); bf_set_ui(&a, len); res = bf_cmp_eq(&a, &p->num); bf_delete(&a); JS_FreeValue(ctx, val); if (!res) goto fail; } break; default: if (JS_TAG_IS_FLOAT64(tag)) { double d; d = JS_VALUE_GET_FLOAT64(val); if (!(d >= 0 && d <= UINT32_MAX)) goto fail; len = (uint32_t)d; if (len != d) goto fail; } else { uint32_t len1; if (is_array_ctor) { val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) return -1; /* cannot recurse because val is a number */ if (JS_ToArrayLengthFree(ctx, &len, val, TRUE)) return -1; } else { /* legacy behavior: must do the conversion twice and compare */ if (JS_ToUint32(ctx, &len, val)) { JS_FreeValue(ctx, val); return -1; } val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) return -1; /* cannot recurse because val is a number */ if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE)) return -1; if (len1 != len) { fail: JS_ThrowRangeError(ctx, "invalid array length"); return -1; } } } break; } *plen = len; return 0; } #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1) static BOOL is_safe_integer(double d) { return isfinite(d) && floor(d) == d && fabs(d) <= (double)MAX_SAFE_INTEGER; } int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val) { int64_t v; if (JS_ToInt64Sat(ctx, &v, val)) return -1; if (v < 0 || v > MAX_SAFE_INTEGER) { JS_ThrowRangeError(ctx, "invalid array index"); *plen = 0; return -1; } *plen = v; return 0; } /* convert a value to a length between 0 and MAX_SAFE_INTEGER. return -1 for exception */ static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen, JSValue val) { int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0); JS_FreeValue(ctx, val); return res; } /* Note: can return an exception */ static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val) { double d; if (!JS_IsNumber(val)) return FALSE; if (unlikely(JS_ToFloat64(ctx, &d, val))) return -1; return isfinite(d) && floor(d) == d; } static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) { uint32_t tag; tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: { int v; v = JS_VALUE_GET_INT(val); return (v < 0); } case JS_TAG_FLOAT64: { JSFloat64Union u; u.d = JS_VALUE_GET_FLOAT64(val); return (u.u64 >> 63); } case JS_TAG_BIG_INT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); /* Note: integer zeros are not necessarily positive */ return p->num.sign && !bf_is_zero(&p->num); } #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); return p->num.sign; } break; case JS_TAG_BIG_DECIMAL: { JSBigDecimal *p = JS_VALUE_GET_PTR(val); return p->num.sign; } break; #endif default: return FALSE; } } static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) { JSValue ret; bf_t a_s, *a; char *str; int saved_sign; a = JS_ToBigInt(ctx, &a_s, val); if (!a) return JS_EXCEPTION; saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC | BF_FTOA_JS_QUIRKS); a->sign = saved_sign; JS_FreeBigInt(ctx, a, &a_s); if (!str) return JS_ThrowOutOfMemory(ctx); ret = JS_NewString(ctx, str); bf_free(ctx->bf_ctx, str); return ret; } static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) { return js_bigint_to_string1(ctx, val, 10); } #ifdef CONFIG_BIGNUM static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix, limb_t prec, bf_flags_t flags) { JSValue val, ret; bf_t a_s, *a; char *str; int saved_sign; val = JS_ToNumeric(ctx, val1); if (JS_IsException(val)) return val; a = JS_ToBigFloat(ctx, &a_s, val); if (!a) { JS_FreeValue(ctx, val); return JS_EXCEPTION; } saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; flags |= BF_FTOA_JS_QUIRKS; if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) { /* Note: for floating point numbers with a radix which is not a power of two, the current precision is used to compute the number of digits. */ if ((radix & (radix - 1)) != 0) { bf_t r_s, *r = &r_s; int prec, flags1; /* must round first */ if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) { prec = ctx->fp_env.prec; flags1 = ctx->fp_env.flags & (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)); } else { prec = 53; flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL; } bf_init(ctx->bf_ctx, r); bf_set(r, a); bf_round(r, prec, flags1 | BF_RNDN); str = bf_ftoa(NULL, r, radix, prec, flags1 | flags); bf_delete(r); } else { str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags); } } else { str = bf_ftoa(NULL, a, radix, prec, flags); } a->sign = saved_sign; if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, val); if (!str) return JS_ThrowOutOfMemory(ctx); ret = JS_NewString(ctx, str); bf_free(ctx->bf_ctx, str); return ret; } static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val) { return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN); } static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val, limb_t prec, int flags) { JSValue ret; bfdec_t *a; char *str; int saved_sign; a = JS_ToBigDecimal(ctx, val); if (!a) return JS_EXCEPTION; saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS); a->sign = saved_sign; if (!str) return JS_ThrowOutOfMemory(ctx); ret = JS_NewString(ctx, str); bf_free(ctx->bf_ctx, str); return ret; } static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) { return js_bigdecimal_to_string1(ctx, val, 0, BF_RNDZ | BF_FTOA_FORMAT_FREE); } #endif /* CONFIG_BIGNUM */ /* 2 <= base <= 36 */ static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; static char *i64toa(char *buf_end, int64_t n, unsigned int base) { char *q = buf_end; int digit, is_neg; is_neg = 0; if (n < 0) { is_neg = 1; n = -n; } *--q = '\0'; if (base == 10) { /* division by known base uses multiplication */ do { digit = (uint64_t)n % 10; n = (uint64_t)n / 10; *--q = '0' + digit; } while (n != 0); } else { do { digit = (uint64_t)n % base; n = (uint64_t)n / base; *--q = digits[digit]; } while (n != 0); } if (is_neg) *--q = '-'; return q; } /* buf1 contains the printf result */ static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf, int rounding_mode, char *buf1, int buf1_size) { if (rounding_mode != FE_TONEAREST) fesetround(rounding_mode); snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d); if (rounding_mode != FE_TONEAREST) fesetround(FE_TONEAREST); *sign = (buf1[0] == '-'); /* mantissa */ buf[0] = buf1[1]; if (n_digits > 1) memcpy(buf + 1, buf1 + 3, n_digits - 1); buf[n_digits] = '\0'; /* exponent */ *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1; } /* maximum buffer size for js_dtoa */ #define JS_DTOA_BUF_SIZE 128 /* needed because ecvt usually limits the number of digits to 17. Return the number of digits. */ static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf, BOOL is_fixed) { int rounding_mode; char buf_tmp[JS_DTOA_BUF_SIZE]; if (!is_fixed) { unsigned int n_digits_min, n_digits_max; /* find the minimum amount of digits (XXX: inefficient but simple) */ n_digits_min = 1; n_digits_max = 17; while (n_digits_min < n_digits_max) { n_digits = (n_digits_min + n_digits_max) / 2; js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST, buf_tmp, sizeof(buf_tmp)); if (safe_strtod(buf_tmp, NULL) == d) { /* no need to keep the trailing zeros */ while (n_digits >= 2 && buf[n_digits - 1] == '0') n_digits--; n_digits_max = n_digits; } else { n_digits_min = n_digits + 1; } } n_digits = n_digits_max; rounding_mode = FE_TONEAREST; } else { rounding_mode = FE_TONEAREST; #ifdef CONFIG_PRINTF_RNDN { char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE]; int decpt1, sign1, decpt2, sign2; /* The JS rounding is specified as round to nearest ties away from zero (RNDNA), but in printf the "ties" case is not specified (for example it is RNDN for glibc, RNDNA for Windows), so we must round manually. */ js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST, buf_tmp, sizeof(buf_tmp)); /* XXX: could use 2 digits to reduce the average running time */ if (buf1[n_digits] == '5') { js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD, buf_tmp, sizeof(buf_tmp)); js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD, buf_tmp, sizeof(buf_tmp)); if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) { /* exact result: round away from zero */ if (sign1) rounding_mode = FE_DOWNWARD; else rounding_mode = FE_UPWARD; } } } #endif /* CONFIG_PRINTF_RNDN */ } js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode, buf_tmp, sizeof(buf_tmp)); return n_digits; } static int js_fcvt1(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits, int rounding_mode) { int n; if (rounding_mode != FE_TONEAREST) fesetround(rounding_mode); n = snprintf(*buf, sizeof(*buf), "%.*f", n_digits, d); if (rounding_mode != FE_TONEAREST) fesetround(FE_TONEAREST); assert(n < sizeof(*buf)); return n; } static void js_fcvt(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits) { int rounding_mode; rounding_mode = FE_TONEAREST; #ifdef CONFIG_PRINTF_RNDN { int n1, n2; char buf1[JS_DTOA_BUF_SIZE]; char buf2[JS_DTOA_BUF_SIZE]; /* The JS rounding is specified as round to nearest ties away from zero (RNDNA), but in printf the "ties" case is not specified (for example it is RNDN for glibc, RNDNA for Windows), so we must round manually. */ n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_TONEAREST); rounding_mode = FE_TONEAREST; /* XXX: could use 2 digits to reduce the average running time */ if (buf1[n1 - 1] == '5') { n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_DOWNWARD); n2 = js_fcvt1(&buf2, d, n_digits + 1, FE_UPWARD); if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) { /* exact result: round away from zero */ if (buf1[0] == '-') rounding_mode = FE_DOWNWARD; else rounding_mode = FE_UPWARD; } } } #endif /* CONFIG_PRINTF_RNDN */ js_fcvt1(buf, d, n_digits, rounding_mode); } /* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */ /* use as many digits as necessary */ #define JS_DTOA_VAR_FORMAT (0 << 0) /* use n_digits significant digits (1 <= n_digits <= 101) */ #define JS_DTOA_FIXED_FORMAT (1 << 0) /* force fractional format: [-]dd.dd with n_digits fractional digits */ #define JS_DTOA_FRAC_FORMAT (2 << 0) /* force exponential notation either in fixed or variable format */ #define JS_DTOA_FORCE_EXP (1 << 2) /* XXX: slow and maybe not fully correct. Use libbf when it is fast enough. XXX: radix != 10 is only supported for small integers */ static void js_dtoa1(char (*buf)[JS_DTOA_BUF_SIZE], double d, int radix, int n_digits, int flags) { char *q; if (!isfinite(d)) { if (isnan(d)) { pstrcpy(*buf, sizeof(*buf), "NaN"); } else if (d < 0) { pstrcpy(*buf, sizeof(*buf), "-Infinity"); } else { pstrcpy(*buf, sizeof(*buf), "Infinity"); } } else if (flags == JS_DTOA_VAR_FORMAT) { int64_t i64; char buf1[70], *ptr; if (d > (double)MAX_SAFE_INTEGER || d < (double)-MAX_SAFE_INTEGER) goto generic_conv; i64 = (int64_t)d; if (d != i64) goto generic_conv; /* fast path for integers */ ptr = i64toa(buf1 + sizeof(buf1), i64, radix); pstrcpy(*buf, sizeof(*buf), ptr); } else { if (d == 0.0) d = 0.0; /* convert -0 to 0 */ if (flags == JS_DTOA_FRAC_FORMAT) { js_fcvt(buf, d, n_digits); } else { char buf1[JS_DTOA_BUF_SIZE]; int sign, decpt, k, n, i, p, n_max; BOOL is_fixed; generic_conv: is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT); if (is_fixed) { n_max = n_digits; } else { n_max = 21; } /* the number has k digits (k >= 1) */ k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed); n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */ q = *buf; if (sign) *q++ = '-'; if (flags & JS_DTOA_FORCE_EXP) goto force_exp; if (n >= 1 && n <= n_max) { if (k <= n) { memcpy(q, buf1, k); q += k; for(i = 0; i < (n - k); i++) *q++ = '0'; *q = '\0'; } else { /* k > n */ memcpy(q, buf1, n); q += n; *q++ = '.'; for(i = 0; i < (k - n); i++) *q++ = buf1[n + i]; *q = '\0'; } } else if (n >= -5 && n <= 0) { *q++ = '0'; *q++ = '.'; for(i = 0; i < -n; i++) *q++ = '0'; memcpy(q, buf1, k); q += k; *q = '\0'; } else { force_exp: /* exponential notation */ *q++ = buf1[0]; if (k > 1) { *q++ = '.'; for(i = 1; i < k; i++) *q++ = buf1[i]; } *q++ = 'e'; p = n - 1; if (p >= 0) *q++ = '+'; snprintf(q, *buf + sizeof(*buf) - q, "%d", p); } } } } static JSValue js_dtoa(JSContext *ctx, double d, int radix, int n_digits, int flags) { char buf[JS_DTOA_BUF_SIZE]; js_dtoa1(&buf, d, radix, n_digits, flags); return JS_NewString(ctx, buf); } static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix) { char buf[2200], *ptr, *ptr2; /* d is finite */ int sign = d < 0; int digit; double frac, d0; int64_t n0 = 0; d = fabs(d); d0 = trunc(d); frac = d - d0; ptr = buf + 1100; *ptr = '\0'; if (d0 <= MAX_SAFE_INTEGER) { int64_t n = n0 = (int64_t)d0; while (n >= radix) { digit = n % radix; n = n / radix; *--ptr = digits[digit]; } *--ptr = digits[(int)n]; } else { /* no decimals */ while (d0 >= radix) { digit = fmod(d0, radix); d0 = trunc(d0 / radix); if (d0 >= MAX_SAFE_INTEGER) digit = 0; *--ptr = digits[digit]; } *--ptr = digits[(int)d0]; goto done; } if (frac != 0) { double log2_radix = log2(radix); double prec = 1023 + 51; // handle subnormals ptr2 = buf + 1100; *ptr2++ = '.'; while (frac != 0 && n0 <= MAX_SAFE_INTEGER/2 && prec > 0) { frac *= radix; digit = trunc(frac); frac -= digit; *ptr2++ = digits[digit]; n0 = n0 * radix + digit; prec -= log2_radix; } *ptr2 = '\0'; if (frac * radix >= radix / 2) { char nine = digits[radix - 1]; // round to closest while (ptr2[-1] == nine) *--ptr2 = '\0'; if (ptr2[-1] == '.') { *--ptr2 = '\0'; while (ptr2[-1] == nine) *--ptr2 = '0'; } if (ptr2 - 1 == ptr) *--ptr = '1'; else ptr2[-1] += 1; } else { while (ptr2[-1] == '0') *--ptr2 = '\0'; if (ptr2[-1] == '.') *--ptr2 = '\0'; } } done: ptr[-1] = '-'; ptr -= sign; return JS_NewString(ctx, ptr); } JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey) { uint32_t tag; const char *str; char buf[32]; tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_STRING: return JS_DupValue(ctx, val); case JS_TAG_INT: snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val)); str = buf; goto new_string; case JS_TAG_BOOL: return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? JS_ATOM_true : JS_ATOM_false); case JS_TAG_NULL: return JS_AtomToString(ctx, JS_ATOM_null); case JS_TAG_UNDEFINED: return JS_AtomToString(ctx, JS_ATOM_undefined); case JS_TAG_EXCEPTION: return JS_EXCEPTION; case JS_TAG_OBJECT: { JSValue val1, ret; val1 = JS_ToPrimitive(ctx, val, HINT_STRING); if (JS_IsException(val1)) return val1; ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey); JS_FreeValue(ctx, val1); return ret; } break; case JS_TAG_FUNCTION_BYTECODE: str = "[function bytecode]"; goto new_string; case JS_TAG_SYMBOL: if (is_ToPropertyKey) { return JS_DupValue(ctx, val); } else { return JS_ThrowTypeError(ctx, "cannot convert symbol to string"); } case JS_TAG_FLOAT64: return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, JS_DTOA_VAR_FORMAT); case JS_TAG_BIG_INT: return ctx->rt->bigint_ops.to_string(ctx, val); #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: return ctx->rt->bigfloat_ops.to_string(ctx, val); case JS_TAG_BIG_DECIMAL: return ctx->rt->bigdecimal_ops.to_string(ctx, val); #endif default: str = "[unsupported type]"; new_string: return JS_NewString(ctx, str); } } JSValue JS_ToString(JSContext *ctx, JSValueConst val) { return JS_ToStringInternal(ctx, val, FALSE); } static JSValue JS_ToStringFree(JSContext *ctx, JSValue val) { JSValue ret; ret = JS_ToString(ctx, val); JS_FreeValue(ctx, val); return ret; } static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val) { if (JS_IsUndefined(val) || JS_IsNull(val)) return JS_ToStringFree(ctx, val); return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL); } JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val) { return JS_ToStringInternal(ctx, val, TRUE); } static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val) { uint32_t tag = JS_VALUE_GET_TAG(val); if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) return JS_ThrowTypeError(ctx, "null or undefined are forbidden"); return JS_ToString(ctx, val); } static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1) { JSValue val; JSString *p; int i; uint32_t c; StringBuffer b_s, *b = &b_s; char buf[16]; val = JS_ToStringCheckObject(ctx, val1); if (JS_IsException(val)) return val; p = JS_VALUE_GET_STRING(val); if (string_buffer_init(ctx, b, p->len + 2)) goto fail; if (string_buffer_putc8(b, '\"')) goto fail; for(i = 0; i < p->len; ) { c = string_getc(p, &i); switch(c) { case '\t': c = 't'; goto quote; case '\r': c = 'r'; goto quote; case '\n': c = 'n'; goto quote; case '\b': c = 'b'; goto quote; case '\f': c = 'f'; goto quote; case '\"': case '\\': quote: if (string_buffer_putc8(b, '\\')) goto fail; if (string_buffer_putc8(b, c)) goto fail; break; default: if (c < 32 || is_surrogate(c)) { snprintf(buf, sizeof(buf), "\\u%04x", c); if (string_buffer_puts8(b, buf)) goto fail; } else { if (string_buffer_putc(b, c)) goto fail; } break; } } if (string_buffer_putc8(b, '\"')) goto fail; JS_FreeValue(ctx, val); return string_buffer_end(b); fail: JS_FreeValue(ctx, val); string_buffer_free(b); return JS_EXCEPTION; } static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt) { printf("%14s %4s %4s %14s %10s %s\n", "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS"); } /* for debug only: dump an object without side effect */ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) { uint32_t i; char atom_buf[ATOM_GET_STR_BUF_SIZE]; JSShape *sh; JSShapeProperty *prs; JSProperty *pr; BOOL is_first = TRUE; /* XXX: should encode atoms with special characters */ sh = p->shape; /* the shape can be NULL while freeing an object */ printf("%14p %4d ", (void *)p, p->header.ref_count); if (sh) { printf("%3d%c %14p ", sh->header.ref_count, " *"[sh->is_hashed], (void *)sh->proto); } else { printf("%3s %14s ", "-", "-"); } printf("%10s ", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name)); if (p->is_exotic && p->fast_array) { printf("[ "); for(i = 0; i < p->u.array.count; i++) { if (i != 0) printf(", "); switch (p->class_id) { case JS_CLASS_ARRAY: case JS_CLASS_ARGUMENTS: JS_DumpValueShort(rt, p->u.array.u.values[i]); break; case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_INT8_ARRAY: case JS_CLASS_UINT8_ARRAY: case JS_CLASS_INT16_ARRAY: case JS_CLASS_UINT16_ARRAY: case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: { int size = 1 << typed_array_size_log2(p->class_id); const uint8_t *b = p->u.array.u.uint8_ptr + i * size; while (size-- > 0) printf("%02X", *b++); } break; } } printf(" ] "); } if (sh) { printf("{ "); for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { if (prs->atom != JS_ATOM_NULL) { pr = &p->prop[i]; if (!is_first) printf(", "); printf("%s: ", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom)); if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { printf("[getset %p %p]", (void *)pr->u.getset.getter, (void *)pr->u.getset.setter); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { printf("[varref %p]", (void *)pr->u.var_ref); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { printf("[autoinit %p %d %p]", (void *)js_autoinit_get_realm(pr), js_autoinit_get_id(pr), (void *)pr->u.init.opaque); } else { JS_DumpValueShort(rt, pr->u.value); } is_first = FALSE; } } printf(" }"); } if (js_class_has_bytecode(p->class_id)) { JSFunctionBytecode *b = p->u.func.function_bytecode; JSVarRef **var_refs; if (b->closure_var_count) { var_refs = p->u.func.var_refs; printf(" Closure:"); for(i = 0; i < b->closure_var_count; i++) { printf(" "); JS_DumpValueShort(rt, var_refs[i]->value); } if (p->u.func.home_object) { printf(" HomeObject: "); JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object)); } } } printf("\n"); } static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p) { if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { JS_DumpObject(rt, (JSObject *)p); } else { printf("%14p %4d ", (void *)p, p->ref_count); switch(p->gc_obj_type) { case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: printf("[function bytecode]"); break; case JS_GC_OBJ_TYPE_SHAPE: printf("[shape]"); break; case JS_GC_OBJ_TYPE_VAR_REF: printf("[var_ref]"); break; case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: printf("[async_function]"); break; case JS_GC_OBJ_TYPE_JS_CONTEXT: printf("[js_context]"); break; default: printf("[unknown %d]", p->gc_obj_type); break; } printf("\n"); } } static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val) { uint32_t tag = JS_VALUE_GET_NORM_TAG(val); const char *str; switch(tag) { case JS_TAG_INT: printf("%d", JS_VALUE_GET_INT(val)); break; case JS_TAG_BOOL: if (JS_VALUE_GET_BOOL(val)) str = "true"; else str = "false"; goto print_str; case JS_TAG_NULL: str = "null"; goto print_str; case JS_TAG_EXCEPTION: str = "exception"; goto print_str; case JS_TAG_UNINITIALIZED: str = "uninitialized"; goto print_str; case JS_TAG_UNDEFINED: str = "undefined"; print_str: printf("%s", str); break; case JS_TAG_FLOAT64: printf("%.14g", JS_VALUE_GET_FLOAT64(val)); break; case JS_TAG_BIG_INT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); char *str; str = bf_ftoa(NULL, &p->num, 10, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC); printf("%sn", str); bf_realloc(&rt->bf_ctx, str, 0); } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); char *str; str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF, BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX); printf("%sl", str); bf_free(&rt->bf_ctx, str); } break; case JS_TAG_BIG_DECIMAL: { JSBigDecimal *p = JS_VALUE_GET_PTR(val); char *str; str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF, BF_RNDZ | BF_FTOA_FORMAT_FREE); printf("%sm", str); bf_free(&rt->bf_ctx, str); } break; #endif case JS_TAG_STRING: { JSString *p; p = JS_VALUE_GET_STRING(val); JS_DumpString(rt, p); } break; case JS_TAG_FUNCTION_BYTECODE: { JSFunctionBytecode *b = JS_VALUE_GET_PTR(val); char buf[ATOM_GET_STR_BUF_SIZE]; printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); } break; case JS_TAG_OBJECT: { JSObject *p = JS_VALUE_GET_OBJ(val); JSAtom atom = rt->class_array[p->class_id].class_name; char atom_buf[ATOM_GET_STR_BUF_SIZE]; printf("[%s %p]", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p); } break; case JS_TAG_SYMBOL: { JSAtomStruct *p = JS_VALUE_GET_PTR(val); char atom_buf[ATOM_GET_STR_BUF_SIZE]; printf("Symbol(%s)", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p))); } break; case JS_TAG_MODULE: printf("[module]"); break; default: printf("[unknown tag %d]", tag); break; } } static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val) { JS_DumpValueShort(ctx->rt, val); } static __maybe_unused void JS_PrintValue(JSContext *ctx, const char *str, JSValueConst val) { printf("%s=", str); JS_DumpValueShort(ctx->rt, val); printf("\n"); } /* return -1 if exception (proxy case) or TRUE/FALSE */ // TODO: should take flags to make proxy resolution and exceptions optional int JS_IsArray(JSContext *ctx, JSValueConst val) { if (js_resolve_proxy(ctx, &val, TRUE)) return -1; if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(val); return p->class_id == JS_CLASS_ARRAY; } else { return FALSE; } } static double js_pow(double a, double b) { if (unlikely(!isfinite(b)) && fabs(a) == 1) { /* not compatible with IEEE 754 */ return JS_FLOAT64_NAN; } else { return pow(a, b); } } JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v) { JSValue val; bf_t *a; val = JS_NewBigInt(ctx); if (JS_IsException(val)) return val; a = JS_GetBigInt(val); if (bf_set_si(a, v)) { JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } return val; } JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) { if (is_math_mode(ctx) && v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { return JS_NewInt64(ctx, v); } else { return JS_NewBigInt64_1(ctx, v); } } JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) { JSValue val; if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) { val = JS_NewInt64(ctx, v); } else { bf_t *a; val = JS_NewBigInt(ctx); if (JS_IsException(val)) return val; a = JS_GetBigInt(val); if (bf_set_ui(a, v)) { JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } } return val; } /* return NaN if bad bigint literal */ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) { const char *str, *p; size_t len; int flags; str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) return JS_EXCEPTION; p = str; p += skip_spaces(p); if ((p - str) == len) { val = JS_NewBigInt64(ctx, 0); } else { flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT; #ifdef CONFIG_BIGNUM if (is_math_mode(ctx)) flags |= ATOD_MODE_BIGINT; #endif val = js_atof(ctx, p, &p, 0, flags); p += skip_spaces(p); if (!JS_IsException(val)) { if ((p - str) != len) { JS_FreeValue(ctx, val); val = JS_NAN; } } } JS_FreeCString(ctx, str); return val; } static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val) { val = JS_StringToBigInt(ctx, val); if (JS_VALUE_IS_NAN(val)) return JS_ThrowSyntaxError(ctx, "invalid bigint literal"); return val; } /* if the returned bigfloat is allocated it is equal to 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) { uint32_t tag; bf_t *r; JSBigFloat *p; redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_NULL: case JS_TAG_UNDEFINED: if (!is_math_mode(ctx)) goto fail; /* fall tru */ case JS_TAG_BOOL: r = buf; bf_init(ctx->bf_ctx, r); bf_set_si(r, JS_VALUE_GET_INT(val)); break; case JS_TAG_FLOAT64: { double d = JS_VALUE_GET_FLOAT64(val); if (!is_math_mode(ctx)) goto fail; if (!isfinite(d)) goto fail; r = buf; bf_init(ctx->bf_ctx, r); d = trunc(d); bf_set_float64(r, d); } break; case JS_TAG_BIG_INT: p = JS_VALUE_GET_PTR(val); r = &p->num; break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: if (!is_math_mode(ctx)) goto fail; p = JS_VALUE_GET_PTR(val); if (!bf_is_finite(&p->num)) goto fail; r = buf; bf_init(ctx->bf_ctx, r); bf_set(r, &p->num); bf_rint(r, BF_RNDZ); JS_FreeValue(ctx, val); break; #endif case JS_TAG_STRING: val = JS_StringToBigIntErr(ctx, val); if (JS_IsException(val)) return NULL; goto redo; case JS_TAG_OBJECT: val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); if (JS_IsException(val)) return NULL; goto redo; default: fail: JS_FreeValue(ctx, val); JS_ThrowTypeError(ctx, "cannot convert to bigint"); return NULL; } return r; } static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val) { return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val)); } static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val) { if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) { return val; } else { bf_t a_s, *a, *r; int ret; JSValue res; res = JS_NewBigInt(ctx); if (JS_IsException(res)) return JS_EXCEPTION; a = JS_ToBigIntFree(ctx, &a_s, val); if (!a) { JS_FreeValue(ctx, res); return JS_EXCEPTION; } r = JS_GetBigInt(res); ret = bf_set(r, a); JS_FreeBigInt(ctx, a, &a_s); if (ret) { JS_FreeValue(ctx, res); return JS_ThrowOutOfMemory(ctx); } return JS_CompactBigInt(ctx, res); } } /* free the bf_t allocated by JS_ToBigInt */ static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf) { if (a == buf) { bf_delete(a); } else { JSBigFloat *p = (JSBigFloat *)((uint8_t *)a - offsetof(JSBigFloat, num)); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p)); } } /* XXX: merge with JS_ToInt64Free with a specific flag */ static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val) { bf_t a_s, *a; a = JS_ToBigIntFree(ctx, &a_s, val); if (!a) { *pres = 0; return -1; } bf_get_int64(pres, a, BF_GET_INT_MOD); JS_FreeBigInt(ctx, a, &a_s); return 0; } int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) { return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val)); } static JSBigFloat *js_new_bf(JSContext *ctx) { JSBigFloat *p; p = js_malloc(ctx, sizeof(*p)); if (!p) return NULL; p->header.ref_count = 1; bf_init(ctx->bf_ctx, &p->num); return p; } static JSValue JS_NewBigInt(JSContext *ctx) { JSBigFloat *p; p = js_malloc(ctx, sizeof(*p)); if (!p) return JS_EXCEPTION; p->header.ref_count = 1; bf_init(ctx->bf_ctx, &p->num); return JS_MKPTR(JS_TAG_BIG_INT, p); } static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, BOOL convert_to_safe_integer) { int64_t v; bf_t *a; if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) return val; /* fail safe */ a = JS_GetBigInt(val); if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 && v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { JS_FreeValue(ctx, val); return JS_NewInt64(ctx, v); } else if (a->expn == BF_EXP_ZERO && a->sign) { JSBigFloat *p = JS_VALUE_GET_PTR(val); assert(p->header.ref_count == 1); a->sign = 0; } return val; } /* Convert the big int to a safe integer if in math mode. normalize the zero representation. Could also be used to convert the bigint to a short bigint value. The reference count of the value must be 1. Cannot fail */ static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) { return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); } static JSValue throw_bf_exception(JSContext *ctx, int status) { const char *str; if (status & BF_ST_MEM_ERROR) return JS_ThrowOutOfMemory(ctx); if (status & BF_ST_DIVIDE_ZERO) { str = "division by zero"; } else if (status & BF_ST_INVALID_OP) { str = "invalid operation"; } else { str = "integer overflow"; } return JS_ThrowRangeError(ctx, "%s", str); } /* if the returned bigfloat is allocated it is equal to 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return NULL in case of error. */ static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val) { uint32_t tag; bf_t *r; JSBigFloat *p; tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_INT: case JS_TAG_BOOL: case JS_TAG_NULL: r = buf; bf_init(ctx->bf_ctx, r); if (bf_set_si(r, JS_VALUE_GET_INT(val))) goto fail; break; case JS_TAG_FLOAT64: r = buf; bf_init(ctx->bf_ctx, r); if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { fail: bf_delete(r); return NULL; } break; case JS_TAG_BIG_INT: #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: #endif p = JS_VALUE_GET_PTR(val); r = &p->num; break; case JS_TAG_UNDEFINED: default: r = buf; bf_init(ctx->bf_ctx, r); bf_set_nan(r); break; } return r; } #ifdef CONFIG_BIGNUM /* return NULL if invalid type */ static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) { uint32_t tag; JSBigDecimal *p; bfdec_t *r; tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_BIG_DECIMAL: p = JS_VALUE_GET_PTR(val); r = &p->num; break; default: JS_ThrowTypeError(ctx, "bigdecimal expected"); r = NULL; break; } return r; } static JSValue JS_NewBigFloat(JSContext *ctx) { JSBigFloat *p; p = js_malloc(ctx, sizeof(*p)); if (!p) return JS_EXCEPTION; p->header.ref_count = 1; bf_init(ctx->bf_ctx, &p->num); return JS_MKPTR(JS_TAG_BIG_FLOAT, p); } static JSValue JS_NewBigDecimal(JSContext *ctx) { JSBigDecimal *p; p = js_malloc(ctx, sizeof(*p)); if (!p) return JS_EXCEPTION; p->header.ref_count = 1; bfdec_init(ctx->bf_ctx, &p->num); return JS_MKPTR(JS_TAG_BIG_DECIMAL, p); } /* must be kept in sync with JSOverloadableOperatorEnum */ /* XXX: use atoms ? */ static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = { "+", "-", "*", "/", "%", "**", "|", "&", "^", "<<", ">>", ">>>", "==", "<", "pos", "neg", "++", "--", "~", }; static int get_ovop_from_opcode(OPCodeEnum op) { switch(op) { case OP_add: return JS_OVOP_ADD; case OP_sub: return JS_OVOP_SUB; case OP_mul: return JS_OVOP_MUL; case OP_div: return JS_OVOP_DIV; case OP_mod: case OP_math_mod: return JS_OVOP_MOD; case OP_pow: return JS_OVOP_POW; case OP_or: return JS_OVOP_OR; case OP_and: return JS_OVOP_AND; case OP_xor: return JS_OVOP_XOR; case OP_shl: return JS_OVOP_SHL; case OP_sar: return JS_OVOP_SAR; case OP_shr: return JS_OVOP_SHR; case OP_eq: case OP_neq: return JS_OVOP_EQ; case OP_lt: case OP_lte: case OP_gt: case OP_gte: return JS_OVOP_LESS; case OP_plus: return JS_OVOP_POS; case OP_neg: return JS_OVOP_NEG; case OP_inc: return JS_OVOP_INC; case OP_dec: return JS_OVOP_DEC; default: abort(); } } /* return NULL if not present */ static JSObject *find_binary_op(JSBinaryOperatorDef *def, uint32_t operator_index, JSOverloadableOperatorEnum op) { JSBinaryOperatorDefEntry *ent; int i; for(i = 0; i < def->count; i++) { ent = &def->tab[i]; if (ent->operator_index == operator_index) return ent->ops[op]; } return NULL; } /* return -1 if exception, 0 if no operator overloading, 1 if overloaded operator called */ static __exception int js_call_binary_op_fallback(JSContext *ctx, JSValue *pret, JSValueConst op1, JSValueConst op2, OPCodeEnum op, BOOL is_numeric, int hint) { JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2; JSOperatorSetData *opset1, *opset2; JSOverloadableOperatorEnum ovop; JSObject *p; JSValueConst args[2]; if (!ctx->allow_operator_overloading) return 0; opset2_obj = JS_UNDEFINED; opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) goto exception; if (JS_IsUndefined(opset1_obj)) return 0; opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET); if (!opset1) goto exception; opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset2_obj)) goto exception; if (JS_IsUndefined(opset2_obj)) { JS_FreeValue(ctx, opset1_obj); return 0; } opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET); if (!opset2) goto exception; if (opset1->is_primitive && opset2->is_primitive) { JS_FreeValue(ctx, opset1_obj); JS_FreeValue(ctx, opset2_obj); return 0; } ovop = get_ovop_from_opcode(op); if (opset1->operator_counter == opset2->operator_counter) { p = opset1->self_ops[ovop]; } else if (opset1->operator_counter > opset2->operator_counter) { p = find_binary_op(&opset1->left, opset2->operator_counter, ovop); } else { p = find_binary_op(&opset2->right, opset1->operator_counter, ovop); } if (!p) { JS_ThrowTypeError(ctx, "operator %s: no function defined", js_overloadable_operator_names[ovop]); goto exception; } if (opset1->is_primitive) { if (is_numeric) { new_op1 = JS_ToNumeric(ctx, op1); } else { new_op1 = JS_ToPrimitive(ctx, op1, hint); } if (JS_IsException(new_op1)) goto exception; } else { new_op1 = JS_DupValue(ctx, op1); } if (opset2->is_primitive) { if (is_numeric) { new_op2 = JS_ToNumeric(ctx, op2); } else { new_op2 = JS_ToPrimitive(ctx, op2, hint); } if (JS_IsException(new_op2)) { JS_FreeValue(ctx, new_op1); goto exception; } } else { new_op2 = JS_DupValue(ctx, op2); } /* XXX: could apply JS_ToPrimitive() if primitive type so that the operator function does not get a value object */ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) { args[0] = new_op2; args[1] = new_op1; } else { args[0] = new_op1; args[1] = new_op2; } ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args); JS_FreeValue(ctx, new_op1); JS_FreeValue(ctx, new_op2); if (JS_IsException(ret)) goto exception; if (ovop == JS_OVOP_EQ) { BOOL res = JS_ToBoolFree(ctx, ret); if (op == OP_neq) res ^= 1; ret = JS_NewBool(ctx, res); } else if (ovop == JS_OVOP_LESS) { if (JS_IsUndefined(ret)) { ret = JS_FALSE; } else { BOOL res = JS_ToBoolFree(ctx, ret); if (op == OP_lte || op == OP_gte) res ^= 1; ret = JS_NewBool(ctx, res); } } JS_FreeValue(ctx, opset1_obj); JS_FreeValue(ctx, opset2_obj); *pret = ret; return 1; exception: JS_FreeValue(ctx, opset1_obj); JS_FreeValue(ctx, opset2_obj); *pret = JS_UNDEFINED; return -1; } /* try to call the operation on the operatorSet field of 'obj'. Only used for "/" and "**" on the BigInt prototype in math mode */ static __exception int js_call_binary_op_simple(JSContext *ctx, JSValue *pret, JSValueConst obj, JSValueConst op1, JSValueConst op2, OPCodeEnum op) { JSValue opset1_obj, method, ret, new_op1, new_op2; JSOperatorSetData *opset1; JSOverloadableOperatorEnum ovop; JSObject *p; JSValueConst args[2]; opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) goto exception; if (JS_IsUndefined(opset1_obj)) return 0; opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET); if (!opset1) goto exception; ovop = get_ovop_from_opcode(op); p = opset1->self_ops[ovop]; if (!p) { JS_FreeValue(ctx, opset1_obj); return 0; } new_op1 = JS_ToNumeric(ctx, op1); if (JS_IsException(new_op1)) goto exception; new_op2 = JS_ToNumeric(ctx, op2); if (JS_IsException(new_op2)) { JS_FreeValue(ctx, new_op1); goto exception; } method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); args[0] = new_op1; args[1] = new_op2; ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args); JS_FreeValue(ctx, new_op1); JS_FreeValue(ctx, new_op2); if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, opset1_obj); *pret = ret; return 1; exception: JS_FreeValue(ctx, opset1_obj); *pret = JS_UNDEFINED; return -1; } /* return -1 if exception, 0 if no operator overloading, 1 if overloaded operator called */ static __exception int js_call_unary_op_fallback(JSContext *ctx, JSValue *pret, JSValueConst op1, OPCodeEnum op) { JSValue opset1_obj, method, ret; JSOperatorSetData *opset1; JSOverloadableOperatorEnum ovop; JSObject *p; if (!ctx->allow_operator_overloading) return 0; opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) goto exception; if (JS_IsUndefined(opset1_obj)) return 0; opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET); if (!opset1) goto exception; if (opset1->is_primitive) { JS_FreeValue(ctx, opset1_obj); return 0; } ovop = get_ovop_from_opcode(op); p = opset1->self_ops[ovop]; if (!p) { JS_ThrowTypeError(ctx, "no overloaded operator %s", js_overloadable_operator_names[ovop]); goto exception; } method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1); if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, opset1_obj); *pret = ret; return 1; exception: JS_FreeValue(ctx, opset1_obj); *pret = JS_UNDEFINED; return -1; } static int js_unary_arith_bigfloat(JSContext *ctx, JSValue *pres, OPCodeEnum op, JSValue op1) { bf_t a_s, *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); JS_FreeValue(ctx, op1); return -1; } res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } r = JS_GetBigFloat(res); a = JS_ToBigFloat(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, res); JS_FreeValue(ctx, op1); return -1; } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_plus: ret = bf_set(r, a); break; case OP_neg: ret = bf_set(r, a); bf_neg(r); break; default: abort(); } if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, op1); if (unlikely(ret & BF_ST_MEM_ERROR)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } *pres = res; return 0; } static int js_unary_arith_bigdecimal(JSContext *ctx, JSValue *pres, OPCodeEnum op, JSValue op1) { bfdec_t *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); JS_FreeValue(ctx, op1); return -1; } res = JS_NewBigDecimal(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } r = JS_GetBigDecimal(res); a = JS_ToBigDecimal(ctx, op1); if (!a) { JS_FreeValue(ctx, res); JS_FreeValue(ctx, op1); return -1; } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); break; case OP_plus: ret = bfdec_set(r, a); break; case OP_neg: ret = bfdec_set(r, a); bfdec_neg(r); break; default: abort(); } JS_FreeValue(ctx, op1); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } *pres = res; return 0; } #endif /* CONFIG_BIGNUM */ static int js_unary_arith_bigint(JSContext *ctx, JSValue *pres, OPCodeEnum op, JSValue op1) { bf_t a_s, *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigint argument with unary +"); JS_FreeValue(ctx, op1); return -1; } res = JS_NewBigInt(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } r = JS_GetBigInt(res); a = JS_ToBigInt(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, res); JS_FreeValue(ctx, op1); return -1; } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); break; case OP_plus: ret = bf_set(r, a); break; case OP_neg: ret = bf_set(r, a); bf_neg(r); break; case OP_not: ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ); bf_neg(r); break; default: abort(); } JS_FreeBigInt(ctx, a, &a_s); JS_FreeValue(ctx, op1); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } res = JS_CompactBigInt(ctx, res); *pres = res; return 0; } static no_inline __exception int js_unary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { JSValue op1; int v; uint32_t tag; op1 = sp[-1]; /* fast path for float64 */ if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) goto handle_float64; #ifdef CONFIG_BIGNUM if (JS_IsObject(op1)) { JSValue val; int ret = js_call_unary_op_fallback(ctx, &val, op1, op); if (ret < 0) return -1; if (ret) { JS_FreeValue(ctx, op1); sp[-1] = val; return 0; } } #endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; tag = JS_VALUE_GET_TAG(op1); switch(tag) { case JS_TAG_INT: { int64_t v64; v64 = JS_VALUE_GET_INT(op1); switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; v64 += v; break; case OP_plus: break; case OP_neg: if (v64 == 0) { sp[-1] = JS_NewFloat64(ctx, -0.0); return 0; } else { v64 = -v64; } break; default: abort(); } sp[-1] = JS_NewInt64(ctx, v64); } break; case JS_TAG_BIG_INT: handle_bigint: if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; case JS_TAG_BIG_DECIMAL: if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; #endif default: handle_float64: { double d; if (is_math_mode(ctx)) goto handle_bigint; d = JS_VALUE_GET_FLOAT64(op1); switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; d += v; break; case OP_plus: break; case OP_neg: d = -d; break; default: abort(); } sp[-1] = JS_NewFloat64(ctx, d); } break; } return 0; exception: sp[-1] = JS_UNDEFINED; return -1; } static __exception int js_post_inc_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { JSValue op1; /* XXX: allow custom operators */ op1 = sp[-1]; op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { sp[-1] = JS_UNDEFINED; return -1; } sp[-1] = op1; sp[0] = JS_DupValue(ctx, op1); return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec); } static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) { JSValue op1; op1 = sp[-1]; #ifdef CONFIG_BIGNUM if (JS_IsObject(op1)) { JSValue val; int ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); if (ret < 0) return -1; if (ret) { JS_FreeValue(ctx, op1); sp[-1] = val; return 0; } } #endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) { if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1)) goto exception; } else { int32_t v1; if (unlikely(JS_ToInt32Free(ctx, &v1, op1))) goto exception; sp[-1] = JS_NewInt32(ctx, ~v1); } return 0; exception: sp[-1] = JS_UNDEFINED; return -1; } static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2) { bf_t a_s, b_s, *r, *a, *b; int ret; JSValue res; res = JS_NewBigInt(ctx); if (JS_IsException(res)) goto fail; a = JS_ToBigInt(ctx, &a_s, op1); if (!a) goto fail; b = JS_ToBigInt(ctx, &b_s, op2); if (!b) { JS_FreeBigInt(ctx, a, &a_s); goto fail; } r = JS_GetBigInt(res); ret = 0; switch(op) { case OP_add: ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_sub: ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_mul: ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_div: if (!is_math_mode(ctx)) { bf_t rem_s, *rem = &rem_s; bf_init(ctx->bf_ctx, rem); ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ); bf_delete(rem); } else { goto math_mode_div_pow; } break; #ifdef CONFIG_BIGNUM case OP_math_mod: /* Euclidian remainder */ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP; break; #endif case OP_mod: ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ) & BF_ST_INVALID_OP; break; case OP_pow: if (b->sign) { if (!is_math_mode(ctx)) { ret = BF_ST_INVALID_OP; } else { math_mode_div_pow: #ifdef CONFIG_BIGNUM JS_FreeValue(ctx, res); ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op); if (ret != 0) { JS_FreeBigInt(ctx, a, &a_s); JS_FreeBigInt(ctx, b, &b_s); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (ret < 0) { return -1; } else { *pres = res; return 0; } } /* if no BigInt power operator defined, return a bigfloat */ res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { JS_FreeBigInt(ctx, a, &a_s); JS_FreeBigInt(ctx, b, &b_s); goto fail; } r = JS_GetBigFloat(res); if (op == OP_div) { ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR; } else { ret = bf_pow(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR; } JS_FreeBigInt(ctx, a, &a_s); JS_FreeBigInt(ctx, b, &b_s); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } *pres = res; return 0; #else abort(); #endif } } else { ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS); } break; /* logical operations */ case OP_shl: case OP_sar: { slimb_t v2; #if LIMB_BITS == 32 bf_get_int32(&v2, b, 0); if (v2 == INT32_MIN) v2 = INT32_MIN + 1; #else bf_get_int64(&v2, b, 0); if (v2 == INT64_MIN) v2 = INT64_MIN + 1; #endif if (op == OP_sar) v2 = -v2; ret = bf_set(r, a); ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ); if (v2 < 0) { ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR); } } break; case OP_and: ret = bf_logic_and(r, a, b); break; case OP_or: ret = bf_logic_or(r, a, b); break; case OP_xor: ret = bf_logic_xor(r, a, b); break; default: abort(); } JS_FreeBigInt(ctx, a, &a_s); JS_FreeBigInt(ctx, b, &b_s); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } *pres = JS_CompactBigInt(ctx, res); return 0; fail: JS_FreeValue(ctx, res); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return -1; } #ifdef CONFIG_BIGNUM static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2) { bf_t a_s, b_s, *r, *a, *b; int ret; JSValue res; res = JS_NewBigFloat(ctx); if (JS_IsException(res)) goto fail; r = JS_GetBigFloat(res); a = JS_ToBigFloat(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, res); goto fail; } b = JS_ToBigFloat(ctx, &b_s, op2); if (!b) { if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, res); goto fail; } bf_init(ctx->bf_ctx, r); switch(op) { case OP_add: ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_sub: ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_mul: ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_div: ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_math_mod: /* Euclidian remainder */ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, BF_DIVREM_EUCLIDIAN); break; case OP_mod: ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, BF_RNDZ); break; case OP_pow: ret = bf_pow(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags | BF_POW_JS_QUIRKS); break; default: abort(); } if (a == &a_s) bf_delete(a); if (b == &b_s) bf_delete(b); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (unlikely(ret & BF_ST_MEM_ERROR)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } *pres = res; return 0; fail: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return -1; } /* b must be a positive integer */ static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b) { bfdec_t b1; int32_t b2; int ret; bfdec_init(b->ctx, &b1); ret = bfdec_set(&b1, b); if (ret) { bfdec_delete(&b1); return ret; } ret = bfdec_rint(&b1, BF_RNDZ); if (ret) { bfdec_delete(&b1); return BF_ST_INVALID_OP; /* must be an integer */ } ret = bfdec_get_int32(&b2, &b1); bfdec_delete(&b1); if (ret) return ret; /* overflow */ if (b2 < 0) return BF_ST_INVALID_OP; /* must be positive */ return bfdec_pow_ui(r, a, b2); } static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2) { bfdec_t *r, *a, *b; int ret; JSValue res; res = JS_NewBigDecimal(ctx); if (JS_IsException(res)) goto fail; r = JS_GetBigDecimal(res); a = JS_ToBigDecimal(ctx, op1); if (!a) goto fail; b = JS_ToBigDecimal(ctx, op2); if (!b) goto fail; switch(op) { case OP_add: ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_sub: ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_mul: ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_div: ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ); break; case OP_math_mod: /* Euclidian remainder */ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN); break; case OP_mod: ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ); break; case OP_pow: ret = js_bfdec_pow(r, a, b); break; default: abort(); } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } *pres = res; return 0; fail: JS_FreeValue(ctx, res); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return -1; } #endif /* CONFIG_BIGNUM */ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { JSValue op1, op2; uint32_t tag1, tag2; double d1, d2; op1 = sp[-2]; op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); /* fast path for float operations */ if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) { d1 = JS_VALUE_GET_FLOAT64(op1); d2 = JS_VALUE_GET_FLOAT64(op2); goto handle_float64; } #ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { JSValue res; int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (ret < 0) { goto exception; } else { sp[-2] = res; return 0; } } } #endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToNumericFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { int32_t v1, v2; int64_t v; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); switch(op) { case OP_sub: v = (int64_t)v1 - (int64_t)v2; break; case OP_mul: v = (int64_t)v1 * (int64_t)v2; if (is_math_mode(ctx) && (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER)) goto handle_bigint; if (v == 0 && (v1 | v2) < 0) { sp[-2] = JS_NewFloat64(ctx, -0.0); return 0; } break; case OP_div: if (is_math_mode(ctx)) goto handle_bigint; sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2); return 0; #ifdef CONFIG_BIGNUM case OP_math_mod: if (unlikely(v2 == 0)) { throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO); goto exception; } v = (int64_t)v1 % (int64_t)v2; if (v < 0) { if (v2 < 0) v -= v2; else v += v2; } break; #endif case OP_mod: if (v1 < 0 || v2 <= 0) { sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2)); return 0; } else { v = (int64_t)v1 % (int64_t)v2; } break; case OP_pow: if (!is_math_mode(ctx)) { sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2)); return 0; } else { goto handle_bigint; } break; default: abort(); } sp[-2] = JS_NewInt64(ctx, v); } else #ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; } else #endif if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { handle_bigint: if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; } else { double dr; /* float64 result */ if (JS_ToFloat64Free(ctx, &d1, op1)) { JS_FreeValue(ctx, op2); goto exception; } if (JS_ToFloat64Free(ctx, &d2, op2)) goto exception; handle_float64: if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2)) goto handle_bigint; switch(op) { case OP_sub: dr = d1 - d2; break; case OP_mul: dr = d1 * d2; break; case OP_div: dr = d1 / d2; break; case OP_mod: dr = fmod(d1, d2); break; #ifdef CONFIG_BIGNUM case OP_math_mod: d2 = fabs(d2); dr = fmod(d1, d2); /* XXX: loss of accuracy if dr < 0 */ if (dr < 0) dr += d2; break; #endif case OP_pow: dr = js_pow(d1, d2); break; default: abort(); } sp[-2] = JS_NewFloat64(ctx, dr); } return 0; exception: sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) { JSValue op1, op2; uint32_t tag1, tag2; op1 = sp[-2]; op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); /* fast path for float64 */ if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) { double d1, d2; d1 = JS_VALUE_GET_FLOAT64(op1); d2 = JS_VALUE_GET_FLOAT64(op2); sp[-2] = JS_NewFloat64(ctx, d1 + d2); return 0; } if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) { #ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED && tag2 != JS_TAG_STRING)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED && tag1 != JS_TAG_STRING))) { JSValue res; int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add, FALSE, HINT_NONE); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (ret < 0) { goto exception; } else { sp[-2] = res; return 0; } } } #endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); } if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) { sp[-2] = JS_ConcatString(ctx, op1, op2); if (JS_IsException(sp[-2])) goto exception; return 0; } op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToNumericFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { int32_t v1, v2; int64_t v; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); v = (int64_t)v1 + (int64_t)v2; sp[-2] = JS_NewInt64(ctx, v); } else #ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; } else #endif if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { handle_bigint: if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; } else { double d1, d2; /* float64 result */ if (JS_ToFloat64Free(ctx, &d1, op1)) { JS_FreeValue(ctx, op2); goto exception; } if (JS_ToFloat64Free(ctx, &d2, op2)) goto exception; if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2)) goto handle_bigint; sp[-2] = JS_NewFloat64(ctx, d1 + d2); } return 0; exception: sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } static no_inline __exception int js_binary_logic_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { JSValue op1, op2; uint32_t tag1, tag2; uint32_t v1, v2, r; op1 = sp[-2]; op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); #ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { JSValue res; int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (ret < 0) { goto exception; } else { sp[-2] = res; return 0; } } } #endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToNumericFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } if (is_math_mode(ctx)) goto bigint_op; tag1 = JS_VALUE_GET_TAG(op1); tag2 = JS_VALUE_GET_TAG(op2); if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { if (tag1 != tag2) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); JS_ThrowTypeError(ctx, "both operands must be bigint"); goto exception; } else { bigint_op: if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; } } else { if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) { JS_FreeValue(ctx, op2); goto exception; } if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2))) goto exception; switch(op) { case OP_shl: r = v1 << (v2 & 0x1f); break; case OP_sar: r = (int)v1 >> (v2 & 0x1f); break; case OP_and: r = v1 & v2; break; case OP_or: r = v1 | v2; break; case OP_xor: r = v1 ^ v2; break; default: abort(); } sp[-2] = JS_NewInt32(ctx, r); } return 0; exception: sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } /* Note: also used for bigint */ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, JSValue op1, JSValue op2) { bf_t a_s, b_s, *a, *b; int res; a = JS_ToBigFloat(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, op2); return -1; } b = JS_ToBigFloat(ctx, &b_s, op2); if (!b) { if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, op1); return -1; } switch(op) { case OP_lt: res = bf_cmp_lt(a, b); /* if NaN return false */ break; case OP_lte: res = bf_cmp_le(a, b); /* if NaN return false */ break; case OP_gt: res = bf_cmp_lt(b, a); /* if NaN return false */ break; case OP_gte: res = bf_cmp_le(b, a); /* if NaN return false */ break; case OP_eq: res = bf_cmp_eq(a, b); /* if NaN return false */ break; default: abort(); } if (a == &a_s) bf_delete(a); if (b == &b_s) bf_delete(b); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return res; } #ifdef CONFIG_BIGNUM static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JSValue op1, JSValue op2) { bfdec_t *a, *b; int res; /* Note: binary floats are converted to bigdecimal with toString(). It is not mathematically correct but is consistent with the BigDecimal() constructor behavior */ op1 = JS_ToBigDecimalFree(ctx, op1, TRUE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); return -1; } op2 = JS_ToBigDecimalFree(ctx, op2, TRUE); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); return -1; } a = JS_ToBigDecimal(ctx, op1); /* cannot fail */ b = JS_ToBigDecimal(ctx, op2); /* cannot fail */ switch(op) { case OP_lt: res = bfdec_cmp_lt(a, b); /* if NaN return false */ break; case OP_lte: res = bfdec_cmp_le(a, b); /* if NaN return false */ break; case OP_gt: res = bfdec_cmp_lt(b, a); /* if NaN return false */ break; case OP_gte: res = bfdec_cmp_le(b, a); /* if NaN return false */ break; case OP_eq: res = bfdec_cmp_eq(a, b); /* if NaN return false */ break; default: abort(); } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return res; } #endif /* !CONFIG_BIGNUM */ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { JSValue op1, op2; int res; uint32_t tag1, tag2; op1 = sp[-2]; op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); #ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { JSValue ret; res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op, FALSE, HINT_NUMBER); if (res != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (res < 0) { goto exception; } else { sp[-2] = ret; return 0; } } } #endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) { JSString *p1, *p2; p1 = JS_VALUE_GET_STRING(op1); p2 = JS_VALUE_GET_STRING(op2); res = js_string_compare(ctx, p1, p2); switch(op) { case OP_lt: res = (res < 0); break; case OP_lte: res = (res <= 0); break; case OP_gt: res = (res > 0); break; default: case OP_gte: res = (res >= 0); break; } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) && (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) { /* fast path for float64/int */ goto float64_compare; } else { if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) || (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) && !is_math_mode(ctx)) { if (tag1 == JS_TAG_STRING) { op1 = JS_StringToBigInt(ctx, op1); if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT) goto invalid_bigint_string; } if (tag2 == JS_TAG_STRING) { op2 = JS_StringToBigInt(ctx, op2); if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) { invalid_bigint_string: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); res = FALSE; goto done; } } } else { op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToNumericFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } } tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); #ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; } else #endif if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; } else { double d1, d2; float64_compare: /* can use floating point comparison */ if (tag1 == JS_TAG_FLOAT64) { d1 = JS_VALUE_GET_FLOAT64(op1); } else { d1 = JS_VALUE_GET_INT(op1); } if (tag2 == JS_TAG_FLOAT64) { d2 = JS_VALUE_GET_FLOAT64(op2); } else { d2 = JS_VALUE_GET_INT(op2); } switch(op) { case OP_lt: res = (d1 < d2); /* if NaN return false */ break; case OP_lte: res = (d1 <= d2); /* if NaN return false */ break; case OP_gt: res = (d1 > d2); /* if NaN return false */ break; default: case OP_gte: res = (d1 >= d2); /* if NaN return false */ break; } } } done: sp[-2] = JS_NewBool(ctx, res); return 0; exception: sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } static BOOL tag_is_number(uint32_t tag) { return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT || tag == JS_TAG_FLOAT64 #ifdef CONFIG_BIGNUM || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL #endif ); } static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq) { JSValue op1, op2; #ifdef CONFIG_BIGNUM JSValue ret; #endif int res; uint32_t tag1, tag2; op1 = sp[-2]; op2 = sp[-1]; redo: tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); if (tag_is_number(tag1) && tag_is_number(tag2)) { if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); } else if ((tag1 == JS_TAG_FLOAT64 && (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) || (tag2 == JS_TAG_FLOAT64 && (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) { double d1, d2; if (tag1 == JS_TAG_FLOAT64) { d1 = JS_VALUE_GET_FLOAT64(op1); } else { d1 = JS_VALUE_GET_INT(op1); } if (tag2 == JS_TAG_FLOAT64) { d2 = JS_VALUE_GET_FLOAT64(op2); } else { d2 = JS_VALUE_GET_INT(op2); } res = (d1 == d2); } else #ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; } else #endif { res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; } } else if (tag1 == tag2) { #ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_OBJECT) { /* try the fallback operator */ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, is_neq ? OP_neq : OP_eq, FALSE, HINT_NONE); if (res != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (res < 0) { goto exception; } else { sp[-2] = ret; return 0; } } } #endif res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { res = TRUE; } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) || (tag2 == JS_TAG_STRING && tag_is_number(tag1))) { if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) && !is_math_mode(ctx)) { if (tag1 == JS_TAG_STRING) { op1 = JS_StringToBigInt(ctx, op1); if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT) goto invalid_bigint_string; } if (tag2 == JS_TAG_STRING) { op2 = JS_StringToBigInt(ctx, op2); if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) { invalid_bigint_string: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); res = FALSE; goto done; } } } else { op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToNumericFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } } res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } else if (tag1 == JS_TAG_BOOL) { op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1)); goto redo; } else if (tag2 == JS_TAG_BOOL) { op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2)); goto redo; } else if ((tag1 == JS_TAG_OBJECT && (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) || (tag2 == JS_TAG_OBJECT && (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) { #ifdef CONFIG_BIGNUM /* try the fallback operator */ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, is_neq ? OP_neq : OP_eq, FALSE, HINT_NONE); if (res != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); if (res < 0) { goto exception; } else { sp[-2] = ret; return 0; } } #endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } goto redo; } else { /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ if ((JS_IsHTMLDDA(ctx, op1) && (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || (JS_IsHTMLDDA(ctx, op2) && (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { res = TRUE; } else { res = FALSE; } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); } done: sp[-2] = JS_NewBool(ctx, res ^ is_neq); return 0; exception: sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) { JSValue op1, op2; uint32_t v1, v2, r; op1 = sp[-2]; op2 = sp[-1]; op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); goto exception; } op2 = JS_ToNumericFree(ctx, op2); if (JS_IsException(op2)) { JS_FreeValue(ctx, op1); goto exception; } /* XXX: could forbid >>> in bignum mode */ if (!is_math_mode(ctx) && (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT || JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) { JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>"); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); goto exception; } /* cannot give an exception */ JS_ToUint32Free(ctx, &v1, op1); JS_ToUint32Free(ctx, &v2, op2); r = v1 >> (v2 & 0x1f); sp[-2] = JS_NewUint32(ctx, r); return 0; exception: sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } #ifdef CONFIG_BIGNUM static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, int64_t exponent) { bf_t r_s, *r = &r_s; double d; int ret; /* always convert to Float64 */ bf_init(ctx->bf_ctx, r); ret = bf_mul_pow_radix(r, a, 10, exponent, 53, bf_set_exp_bits(11) | BF_RNDN | BF_FLAG_SUBNORMAL); bf_get_float64(r, &d, BF_RNDN); bf_delete(r); if (ret & BF_ST_MEM_ERROR) return JS_ThrowOutOfMemory(ctx); else return JS_NewFloat64(ctx, d); } static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) { bf_t a_s, *a, *r; JSValue op1, op2, res; int64_t e; int ret; res = JS_NewBigFloat(ctx); if (JS_IsException(res)) return -1; r = JS_GetBigFloat(res); op1 = sp[-2]; op2 = sp[-1]; a = JS_ToBigFloat(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, res); return -1; } if (JS_IsBigInt(ctx, op2)) { ret = JS_ToBigInt64(ctx, &e, op2); } else { ret = JS_ToInt64(ctx, &e, op2); } if (ret) { if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, res); return -1; } bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags); if (a == &a_s) bf_delete(a); JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); sp[-2] = res; return 0; } #endif /* XXX: Should take JSValueConst arguments */ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode) { BOOL res; int tag1, tag2; double d1, d2; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); switch(tag1) { case JS_TAG_BOOL: if (tag1 != tag2) { res = FALSE; } else { res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); goto done_no_free; } break; case JS_TAG_NULL: case JS_TAG_UNDEFINED: res = (tag1 == tag2); break; case JS_TAG_STRING: { JSString *p1, *p2; if (tag1 != tag2) { res = FALSE; } else { p1 = JS_VALUE_GET_STRING(op1); p2 = JS_VALUE_GET_STRING(op2); res = (js_string_compare(ctx, p1, p2) == 0); } } break; case JS_TAG_SYMBOL: { JSAtomStruct *p1, *p2; if (tag1 != tag2) { res = FALSE; } else { p1 = JS_VALUE_GET_PTR(op1); p2 = JS_VALUE_GET_PTR(op2); res = (p1 == p2); } } break; case JS_TAG_OBJECT: if (tag1 != tag2) res = FALSE; else res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2); break; case JS_TAG_INT: d1 = JS_VALUE_GET_INT(op1); if (tag2 == JS_TAG_INT) { d2 = JS_VALUE_GET_INT(op2); goto number_test; } else if (tag2 == JS_TAG_FLOAT64) { d2 = JS_VALUE_GET_FLOAT64(op2); goto number_test; } else { res = FALSE; } break; case JS_TAG_FLOAT64: d1 = JS_VALUE_GET_FLOAT64(op1); if (tag2 == JS_TAG_FLOAT64) { d2 = JS_VALUE_GET_FLOAT64(op2); } else if (tag2 == JS_TAG_INT) { d2 = JS_VALUE_GET_INT(op2); } else { res = FALSE; break; } number_test: if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) { JSFloat64Union u1, u2; /* NaN is not always normalized, so this test is necessary */ if (isnan(d1) || isnan(d2)) { res = isnan(d1) == isnan(d2); } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) { res = (d1 == d2); /* +0 == -0 */ } else { u1.d = d1; u2.d = d2; res = (u1.u64 == u2.u64); /* +0 != -0 */ } } else { res = (d1 == d2); /* if NaN return false and +0 == -0 */ } goto done_no_free; case JS_TAG_BIG_INT: { bf_t a_s, *a, b_s, *b; if (tag1 != tag2) { res = FALSE; break; } a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */ b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */ res = bf_cmp_eq(a, b); if (a == &a_s) bf_delete(a); if (b == &b_s) bf_delete(b); } break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p1, *p2; const bf_t *a, *b; if (tag1 != tag2) { res = FALSE; break; } p1 = JS_VALUE_GET_PTR(op1); p2 = JS_VALUE_GET_PTR(op2); a = &p1->num; b = &p2->num; if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) { if (eq_mode == JS_EQ_SAME_VALUE_ZERO && a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) { res = TRUE; } else { res = (bf_cmp_full(a, b) == 0); } } else { res = bf_cmp_eq(a, b); } } break; case JS_TAG_BIG_DECIMAL: { JSBigDecimal *p1, *p2; const bfdec_t *a, *b; if (tag1 != tag2) { res = FALSE; break; } p1 = JS_VALUE_GET_PTR(op1); p2 = JS_VALUE_GET_PTR(op2); a = &p1->num; b = &p2->num; res = bfdec_cmp_eq(a, b); } break; #endif default: res = FALSE; break; } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); done_no_free: return res; } static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_strict_eq2(ctx, JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), JS_EQ_STRICT); } BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_strict_eq(ctx, op1, op2); } static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_strict_eq2(ctx, JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), JS_EQ_SAME_VALUE); } BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_same_value(ctx, op1, op2); } static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_strict_eq2(ctx, JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), JS_EQ_SAME_VALUE_ZERO); } BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2) { return js_same_value_zero(ctx, op1, op2); } static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq) { BOOL res; res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT); sp[-2] = JS_NewBool(ctx, res ^ is_neq); return 0; } static __exception int js_operator_in(JSContext *ctx, JSValue *sp) { JSValue op1, op2; JSAtom atom; int ret; op1 = sp[-2]; op2 = sp[-1]; if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) { JS_ThrowTypeError(ctx, "invalid 'in' operand"); return -1; } atom = JS_ValueToAtom(ctx, op1); if (unlikely(atom == JS_ATOM_NULL)) return -1; ret = JS_HasProperty(ctx, op2, atom); JS_FreeAtom(ctx, atom); if (ret < 0) return -1; JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); sp[-2] = JS_NewBool(ctx, ret); return 0; } static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) { JSValue op1, op2; int ret; op1 = sp[-2]; /* object */ op2 = sp[-1]; /* field name or method function */ if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) { JS_ThrowTypeError(ctx, "invalid 'in' operand"); return -1; } if (JS_IsObject(op2)) { /* method: use the brand */ ret = JS_CheckBrand(ctx, op1, op2); if (ret < 0) return -1; } else { JSAtom atom; JSObject *p; JSShapeProperty *prs; JSProperty *pr; /* field */ atom = JS_ValueToAtom(ctx, op2); if (unlikely(atom == JS_ATOM_NULL)) return -1; p = JS_VALUE_GET_OBJ(op1); prs = find_own_property(&pr, p, atom); JS_FreeAtom(ctx, atom); ret = (prs != NULL); } JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); sp[-2] = JS_NewBool(ctx, ret); return 0; } static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj, JSAtom atom) { JSValue arr, val; int ret; arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables); if (JS_IsException(arr)) return -1; ret = 0; if (JS_IsObject(arr)) { val = JS_GetProperty(ctx, arr, atom); ret = JS_ToBoolFree(ctx, val); } JS_FreeValue(ctx, arr); return ret; } static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) { JSValue op1, op2; BOOL ret; op1 = sp[-2]; op2 = sp[-1]; ret = JS_IsInstanceOf(ctx, op1, op2); if (ret < 0) return ret; JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); sp[-2] = JS_NewBool(ctx, ret); return 0; } static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) { JSAtom atom; uint32_t tag; tag = JS_VALUE_GET_NORM_TAG(op1); switch(tag) { case JS_TAG_BIG_INT: atom = JS_ATOM_bigint; break; #ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: atom = JS_ATOM_bigfloat; break; case JS_TAG_BIG_DECIMAL: atom = JS_ATOM_bigdecimal; break; #endif case JS_TAG_INT: case JS_TAG_FLOAT64: atom = JS_ATOM_number; break; case JS_TAG_UNDEFINED: atom = JS_ATOM_undefined; break; case JS_TAG_BOOL: atom = JS_ATOM_boolean; break; case JS_TAG_STRING: atom = JS_ATOM_string; break; case JS_TAG_OBJECT: { JSObject *p; p = JS_VALUE_GET_OBJ(op1); if (unlikely(p->is_HTMLDDA)) atom = JS_ATOM_undefined; else if (JS_IsFunction(ctx, op1)) atom = JS_ATOM_function; else goto obj_type; } break; case JS_TAG_NULL: obj_type: atom = JS_ATOM_object; break; case JS_TAG_SYMBOL: atom = JS_ATOM_symbol; break; default: atom = JS_ATOM_unknown; break; } return atom; } static __exception int js_operator_delete(JSContext *ctx, JSValue *sp) { JSValue op1, op2; JSAtom atom; int ret; op1 = sp[-2]; op2 = sp[-1]; atom = JS_ValueToAtom(ctx, op2); if (unlikely(atom == JS_ATOM_NULL)) return -1; ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT); JS_FreeAtom(ctx, atom); if (unlikely(ret < 0)) return -1; JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); sp[-2] = JS_NewBool(ctx, ret); return 0; } static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { return JS_ThrowTypeError(ctx, "invalid property access"); } /* XXX: not 100% compatible, but mozilla seems to use a similar implementation to ensure that caller in non strict mode does not throw (ES5 compatibility) */ static JSValue js_function_proto_caller(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) { return js_throw_type_error(ctx, this_val, 0, NULL); } return JS_UNDEFINED; } static JSValue js_function_proto_fileName(JSContext *ctx, JSValueConst this_val) { JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); if (b && b->has_debug) { return JS_AtomToString(ctx, b->debug.filename); } return JS_UNDEFINED; } static JSValue js_function_proto_lineNumber(JSContext *ctx, JSValueConst this_val) { JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); if (b && b->has_debug) { return JS_NewInt32(ctx, b->debug.line_num); } return JS_UNDEFINED; } static int js_arguments_define_own_property(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags) { JSObject *p; uint32_t idx; p = JS_VALUE_GET_OBJ(this_obj); /* convert to normal array when redefining an existing numeric field */ if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) && idx < p->u.array.count) { if (convert_fast_array_to_array(ctx, p)) return -1; } /* run the default define own property */ return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, flags | JS_PROP_NO_EXOTIC); } static const JSClassExoticMethods js_arguments_exotic_methods = { .define_own_property = js_arguments_define_own_property, }; static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) { JSValue val, *tab; JSProperty *pr; JSObject *p; int i; val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_ARGUMENTS); if (JS_IsException(val)) return val; p = JS_VALUE_GET_OBJ(val); /* add the length field (cannot fail) */ pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); pr->u.value = JS_NewInt32(ctx, argc); /* initialize the fast array part */ tab = NULL; if (argc > 0) { tab = js_malloc(ctx, sizeof(tab[0]) * argc); if (!tab) { JS_FreeValue(ctx, val); return JS_EXCEPTION; } for(i = 0; i < argc; i++) { tab[i] = JS_DupValue(ctx, argv[i]); } } p->u.array.u.values = tab; p->u.array.count = argc; JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, JS_DupValue(ctx, ctx->array_proto_values), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); /* add callee property to throw a TypeError in strict mode */ JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED, ctx->throw_type_error, ctx->throw_type_error, JS_PROP_HAS_GET | JS_PROP_HAS_SET); return val; } #define GLOBAL_VAR_OFFSET 0x40000000 #define ARGUMENT_VAR_OFFSET 0x20000000 /* legacy arguments object: add references to the function arguments */ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, JSValueConst *argv, JSStackFrame *sf, int arg_count) { JSValue val; JSProperty *pr; JSObject *p; int i; val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_MAPPED_ARGUMENTS); if (JS_IsException(val)) return val; p = JS_VALUE_GET_OBJ(val); /* add the length field (cannot fail) */ pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); pr->u.value = JS_NewInt32(ctx, argc); for(i = 0; i < arg_count; i++) { JSVarRef *var_ref; var_ref = get_var_ref(ctx, sf, i, TRUE); if (!var_ref) goto fail; pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF); if (!pr) { free_var_ref(ctx->rt, var_ref); goto fail; } pr->u.var_ref = var_ref; } /* the arguments not mapped to the arguments of the function can be normal properties */ for(i = arg_count; i < argc; i++) { if (JS_DefinePropertyValueUint32(ctx, val, i, JS_DupValue(ctx, argv[i]), JS_PROP_C_W_E) < 0) goto fail; } JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, JS_DupValue(ctx, ctx->array_proto_values), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); /* callee returns this function in non strict mode */ JS_DefinePropertyValue(ctx, val, JS_ATOM_callee, JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); return val; fail: JS_FreeValue(ctx, val); return JS_EXCEPTION; } static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv) { JSValue val; int i, ret; val = JS_NewArray(ctx); if (JS_IsException(val)) return val; for (i = first; i < argc; i++) { ret = JS_DefinePropertyValueUint32(ctx, val, i - first, JS_DupValue(ctx, argv[i]), JS_PROP_C_W_E); if (ret < 0) { JS_FreeValue(ctx, val); return JS_EXCEPTION; } } return val; } static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) { JSObject *p, *p1; JSPropertyEnum *tab_atom; int i; JSValue enum_obj; JSForInIterator *it; uint32_t tag, tab_atom_count; tag = JS_VALUE_GET_TAG(obj); if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) { obj = JS_ToObjectFree(ctx, obj); } it = js_malloc(ctx, sizeof(*it)); if (!it) { JS_FreeValue(ctx, obj); return JS_EXCEPTION; } enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR); if (JS_IsException(enum_obj)) { js_free(ctx, it); JS_FreeValue(ctx, obj); return JS_EXCEPTION; } it->is_array = FALSE; it->obj = obj; it->idx = 0; it->tab_atom = NULL; it->atom_count = 0; it->in_prototype_chain = FALSE; p1 = JS_VALUE_GET_OBJ(enum_obj); p1->u.for_in_iterator = it; if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) return enum_obj; p = JS_VALUE_GET_OBJ(obj); if (p->fast_array) { JSShape *sh; JSShapeProperty *prs; /* check that there are no enumerable normal fields */ sh = p->shape; for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { if (prs->flags & JS_PROP_ENUMERABLE) goto normal_case; } /* for fast arrays, we only store the number of elements */ it->is_array = TRUE; it->atom_count = p->u.array.count; } else { normal_case: if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { JS_FreeValue(ctx, enum_obj); return JS_EXCEPTION; } it->tab_atom = tab_atom; it->atom_count = tab_atom_count; } return enum_obj; } /* obj -> enum_obj */ static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) { sp[-1] = build_for_in_iterator(ctx, sp[-1]); if (JS_IsException(sp[-1])) return -1; return 0; } /* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */ static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx, JSValueConst enum_obj) { JSObject *p; JSForInIterator *it; JSPropertyEnum *tab_atom; uint32_t tab_atom_count, i; JSValue obj1; p = JS_VALUE_GET_OBJ(enum_obj); it = p->u.for_in_iterator; /* check if there are enumerable properties in the prototype chain (fast path) */ obj1 = JS_DupValue(ctx, it->obj); for(;;) { obj1 = JS_GetPrototypeFree(ctx, obj1); if (JS_IsNull(obj1)) break; if (JS_IsException(obj1)) goto fail; if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, JS_VALUE_GET_OBJ(obj1), JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { JS_FreeValue(ctx, obj1); goto fail; } js_free_prop_enum(ctx, tab_atom, tab_atom_count); if (tab_atom_count != 0) { JS_FreeValue(ctx, obj1); goto slow_path; } /* must check for timeout to avoid infinite loop */ if (js_poll_interrupts(ctx)) { JS_FreeValue(ctx, obj1); goto fail; } } JS_FreeValue(ctx, obj1); return 1; slow_path: /* add the visited properties, even if they are not enumerable */ if (it->is_array) { if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, JS_VALUE_GET_OBJ(it->obj), JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { goto fail; } it->is_array = FALSE; it->tab_atom = tab_atom; it->atom_count = tab_atom_count; } for(i = 0; i < it->atom_count; i++) { if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0) goto fail; } return 0; fail: return -1; } /* enum_obj -> enum_obj value done */ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) { JSValueConst enum_obj; JSObject *p; JSAtom prop; JSForInIterator *it; JSPropertyEnum *tab_atom; uint32_t tab_atom_count; int ret; enum_obj = sp[-1]; /* fail safe */ if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT) goto done; p = JS_VALUE_GET_OBJ(enum_obj); if (p->class_id != JS_CLASS_FOR_IN_ITERATOR) goto done; it = p->u.for_in_iterator; for(;;) { if (it->idx >= it->atom_count) { if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj)) goto done; /* not an object */ /* no more property in the current object: look in the prototype */ if (!it->in_prototype_chain) { ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj); if (ret < 0) return -1; if (ret) goto done; it->in_prototype_chain = TRUE; } it->obj = JS_GetPrototypeFree(ctx, it->obj); if (JS_IsException(it->obj)) return -1; if (JS_IsNull(it->obj)) goto done; /* no more prototype */ /* must check for timeout to avoid infinite loop */ if (js_poll_interrupts(ctx)) return -1; if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, JS_VALUE_GET_OBJ(it->obj), JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { return -1; } js_free_prop_enum(ctx, it->tab_atom, it->atom_count); it->tab_atom = tab_atom; it->atom_count = tab_atom_count; it->idx = 0; } else { if (it->is_array) { prop = __JS_AtomFromUInt32(it->idx); it->idx++; } else { BOOL is_enumerable; prop = it->tab_atom[it->idx].atom; is_enumerable = it->tab_atom[it->idx].is_enumerable; it->idx++; if (it->in_prototype_chain) { /* slow case: we are in the prototype chain */ ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop); if (ret < 0) return ret; if (ret) continue; /* already visited */ /* add to the visited property list */ if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL, JS_PROP_ENUMERABLE) < 0) return -1; } if (!is_enumerable) continue; } /* check if the property was deleted */ ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop); if (ret < 0) return ret; if (ret) break; } } /* return the property */ sp[0] = JS_AtomToValue(ctx, prop); sp[1] = JS_FALSE; return 0; done: /* return the end */ sp[0] = JS_UNDEFINED; sp[1] = JS_TRUE; return 0; } static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj, JSValueConst method) { JSValue enum_obj; enum_obj = JS_Call(ctx, method, obj, 0, NULL); if (JS_IsException(enum_obj)) return enum_obj; if (!JS_IsObject(enum_obj)) { JS_FreeValue(ctx, enum_obj); return JS_ThrowTypeErrorNotAnObject(ctx); } return enum_obj; } static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async) { JSValue method, ret, sync_iter; if (is_async) { method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator); if (JS_IsException(method)) return method; if (JS_IsUndefined(method) || JS_IsNull(method)) { method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); if (JS_IsException(method)) return method; sync_iter = JS_GetIterator2(ctx, obj, method); JS_FreeValue(ctx, method); if (JS_IsException(sync_iter)) return sync_iter; ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter); JS_FreeValue(ctx, sync_iter); return ret; } } else { method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); if (JS_IsException(method)) return method; } if (!JS_IsFunction(ctx, method)) { JS_FreeValue(ctx, method); return JS_ThrowTypeError(ctx, "value is not iterable"); } ret = JS_GetIterator2(ctx, obj, method); JS_FreeValue(ctx, method); return ret; } /* return *pdone = 2 if the iterator object is not parsed */ static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, JSValueConst method, int argc, JSValueConst *argv, int *pdone) { JSValue obj; /* fast path for the built-in iterators (avoid creating the intermediate result object) */ if (JS_IsObject(method)) { JSObject *p = JS_VALUE_GET_OBJ(method); if (p->class_id == JS_CLASS_C_FUNCTION && p->u.cfunc.cproto == JS_CFUNC_iterator_next) { JSCFunctionType func; JSValueConst args[1]; /* in case the function expects one argument */ if (argc == 0) { args[0] = JS_UNDEFINED; argv = args; } func = p->u.cfunc.c_function; return func.iterator_next(ctx, enum_obj, argc, argv, pdone, p->u.cfunc.magic); } } obj = JS_Call(ctx, method, enum_obj, argc, argv); if (JS_IsException(obj)) goto fail; if (!JS_IsObject(obj)) { JS_FreeValue(ctx, obj); JS_ThrowTypeError(ctx, "iterator must return an object"); goto fail; } *pdone = 2; return obj; fail: *pdone = FALSE; return JS_EXCEPTION; } static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj, JSValueConst method, int argc, JSValueConst *argv, BOOL *pdone) { JSValue obj, value, done_val; int done; obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done); if (JS_IsException(obj)) goto fail; if (done != 2) { *pdone = done; return obj; } else { done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); if (JS_IsException(done_val)) goto fail; *pdone = JS_ToBoolFree(ctx, done_val); value = JS_UNDEFINED; if (!*pdone) { value = JS_GetProperty(ctx, obj, JS_ATOM_value); } JS_FreeValue(ctx, obj); return value; } fail: JS_FreeValue(ctx, obj); *pdone = FALSE; return JS_EXCEPTION; } /* return < 0 in case of exception */ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, BOOL is_exception_pending) { JSValue method, ret, ex_obj; int res; if (is_exception_pending) { ex_obj = ctx->rt->current_exception; ctx->rt->current_exception = JS_NULL; res = -1; } else { ex_obj = JS_UNDEFINED; res = 0; } method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return); if (JS_IsException(method)) { res = -1; goto done; } if (JS_IsUndefined(method) || JS_IsNull(method)) { goto done; } ret = JS_CallFree(ctx, method, enum_obj, 0, NULL); if (!is_exception_pending) { if (JS_IsException(ret)) { res = -1; } else if (!JS_IsObject(ret)) { JS_ThrowTypeErrorNotAnObject(ctx); res = -1; } } JS_FreeValue(ctx, ret); done: if (is_exception_pending) { JS_Throw(ctx, ex_obj); } return res; } /* obj -> enum_rec (3 slots) */ static __exception int js_for_of_start(JSContext *ctx, JSValue *sp, BOOL is_async) { JSValue op1, obj, method; op1 = sp[-1]; obj = JS_GetIterator(ctx, op1, is_async); if (JS_IsException(obj)) return -1; JS_FreeValue(ctx, op1); sp[-1] = obj; method = JS_GetProperty(ctx, obj, JS_ATOM_next); if (JS_IsException(method)) return -1; sp[0] = method; return 0; } /* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset' objs. If 'done' is true or in case of exception, 'enum_rec' is set to undefined. If 'done' is true, 'value' is always set to undefined. */ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) { JSValue value = JS_UNDEFINED; int done = 1; if (likely(!JS_IsUndefined(sp[offset]))) { value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done); if (JS_IsException(value)) done = -1; if (done) { /* value is JS_UNDEFINED or JS_EXCEPTION */ /* replace the iteration object with undefined */ JS_FreeValue(ctx, sp[offset]); sp[offset] = JS_UNDEFINED; if (done < 0) { return -1; } else { JS_FreeValue(ctx, value); value = JS_UNDEFINED; } } } sp[0] = value; sp[1] = JS_NewBool(ctx, done); return 0; } static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj, BOOL *pdone) { JSValue done_val, value; BOOL done; done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); if (JS_IsException(done_val)) goto fail; done = JS_ToBoolFree(ctx, done_val); value = JS_GetProperty(ctx, obj, JS_ATOM_value); if (JS_IsException(value)) goto fail; *pdone = done; return value; fail: *pdone = FALSE; return JS_EXCEPTION; } static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp) { JSValue obj, value; BOOL done; obj = sp[-1]; if (!JS_IsObject(obj)) { JS_ThrowTypeError(ctx, "iterator must return an object"); return -1; } value = JS_IteratorGetCompleteValue(ctx, obj, &done); if (JS_IsException(value)) return -1; JS_FreeValue(ctx, obj); sp[-1] = value; sp[0] = JS_NewBool(ctx, done); return 0; } static JSValue js_create_iterator_result(JSContext *ctx, JSValue val, BOOL done) { JSValue obj; obj = JS_NewObject(ctx); if (JS_IsException(obj)) { JS_FreeValue(ctx, val); return obj; } if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, val, JS_PROP_C_W_E) < 0) { goto fail; } if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) { fail: JS_FreeValue(ctx, obj); return JS_EXCEPTION; } return obj; } static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, BOOL *pdone, int magic); static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj) { /* Try and handle fast arrays explicitly */ if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(obj); if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { return TRUE; } } return FALSE; } /* Access an Array's internal JSValue array if available */ static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, JSValue **arrpp, uint32_t *countp) { /* Try and handle fast arrays explicitly */ if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(obj); if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { *countp = p->u.array.count; *arrpp = p->u.array.u.values; return TRUE; } } return FALSE; } static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) { JSValue iterator, enumobj, method, value; int is_array_iterator; JSValue *arrp; uint32_t i, count32, pos; if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { JS_ThrowInternalError(ctx, "invalid index for append"); return -1; } pos = JS_VALUE_GET_INT(sp[-2]); /* XXX: further optimisations: - use ctx->array_proto_values? - check if array_iterator_prototype next method is built-in and avoid constructing actual iterator object? - build this into js_for_of_start and use in all `for (x of o)` loops */ iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator); if (JS_IsException(iterator)) return -1; is_array_iterator = JS_IsCFunction(ctx, iterator, (JSCFunction *)js_create_array_iterator, JS_ITERATOR_KIND_VALUE); JS_FreeValue(ctx, iterator); enumobj = JS_GetIterator(ctx, sp[-1], FALSE); if (JS_IsException(enumobj)) return -1; method = JS_GetProperty(ctx, enumobj, JS_ATOM_next); if (JS_IsException(method)) { JS_FreeValue(ctx, enumobj); return -1; } if (is_array_iterator && JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0) && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { uint32_t len; if (js_get_length32(ctx, &len, sp[-1])) goto exception; /* if len > count32, the elements >= count32 might be read in the prototypes and might have side effects */ if (len != count32) goto general_case; /* Handle fast arrays explicitly */ for (i = 0; i < count32; i++) { if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0) goto exception; } } else { general_case: for (;;) { BOOL done; value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); if (JS_IsException(value)) goto exception; if (done) { /* value is JS_UNDEFINED */ break; } if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0) goto exception; } } /* Note: could raise an error if too many elements */ sp[-2] = JS_NewInt32(ctx, pos); JS_FreeValue(ctx, enumobj); JS_FreeValue(ctx, method); return 0; exception: JS_IteratorClose(ctx, enumobj, TRUE); JS_FreeValue(ctx, enumobj); JS_FreeValue(ctx, method); return -1; } static __exception int JS_CopyDataProperties(JSContext *ctx, JSValueConst target, JSValueConst source, JSValueConst excluded, BOOL setprop) { JSPropertyEnum *tab_atom; JSValue val; uint32_t i, tab_atom_count; JSObject *p; JSObject *pexcl = NULL; int ret, gpn_flags; JSPropertyDescriptor desc; BOOL is_enumerable; if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) return 0; if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT) pexcl = JS_VALUE_GET_OBJ(excluded); p = JS_VALUE_GET_OBJ(source); gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY; if (p->is_exotic) { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it introduces a visible change */ if (em && em->get_own_property_names) { gpn_flags &= ~JS_GPN_ENUM_ONLY; } } if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, gpn_flags)) return -1; for (i = 0; i < tab_atom_count; i++) { if (pexcl) { ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom); if (ret) { if (ret < 0) goto exception; continue; } } if (!(gpn_flags & JS_GPN_ENUM_ONLY)) { /* test if the property is enumerable */ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom); if (ret < 0) goto exception; if (!ret) continue; is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0; js_free_desc(ctx, &desc); if (!is_enumerable) continue; } val = JS_GetProperty(ctx, source, tab_atom[i].atom); if (JS_IsException(val)) goto exception; if (setprop) ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val); else ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, JS_PROP_C_W_E); if (ret < 0) goto exception; } js_free_prop_enum(ctx, tab_atom, tab_atom_count); return 0; exception: js_free_prop_enum(ctx, tab_atom, tab_atom_count); return -1; } /* only valid inside C functions */ static JSValueConst JS_GetActiveFunction(JSContext *ctx) { return ctx->rt->current_stack_frame->cur_func; } static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg) { JSVarRef *var_ref; struct list_head *el; list_for_each(el, &sf->var_ref_list) { var_ref = list_entry(el, JSVarRef, var_ref_link); if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) { var_ref->header.ref_count++; return var_ref; } } /* create a new one */ var_ref = js_malloc(ctx, sizeof(JSVarRef)); if (!var_ref) return NULL; var_ref->header.ref_count = 1; add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); var_ref->is_detached = FALSE; var_ref->is_arg = is_arg; var_ref->var_idx = var_idx; list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list); if (sf->js_mode & JS_MODE_ASYNC) { /* The stack frame is detached and may be destroyed at any time so its reference count must be increased. Calling close_var_refs() when destroying the stack frame is not possible because it would change the graph between the GC objects. Another solution could be to temporarily detach the JSVarRef of async functions during the GC. It would have the advantage of allowing the release of unused stack frames in a cycle. */ var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame); var_ref->async_func->header.ref_count++; } else { var_ref->async_func = NULL; } if (is_arg) var_ref->pvalue = &sf->arg_buf[var_idx]; else var_ref->pvalue = &sf->var_buf[var_idx]; return var_ref; } static JSValue js_closure2(JSContext *ctx, JSValue func_obj, JSFunctionBytecode *b, JSVarRef **cur_var_refs, JSStackFrame *sf) { JSObject *p; JSVarRef **var_refs; int i; p = JS_VALUE_GET_OBJ(func_obj); p->u.func.function_bytecode = b; p->u.func.home_object = NULL; p->u.func.var_refs = NULL; if (b->closure_var_count) { var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count); if (!var_refs) goto fail; p->u.func.var_refs = var_refs; for(i = 0; i < b->closure_var_count; i++) { JSClosureVar *cv = &b->closure_var[i]; JSVarRef *var_ref; if (cv->is_local) { /* reuse the existing variable reference if it already exists */ var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg); if (!var_ref) goto fail; } else { var_ref = cur_var_refs[cv->var_idx]; var_ref->header.ref_count++; } var_refs[i] = var_ref; } } return func_obj; fail: /* bfunc is freed when func_obj is freed */ JS_FreeValue(ctx, func_obj); return JS_EXCEPTION; } static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) { JSValue obj, this_val; int ret; this_val = JS_MKPTR(JS_TAG_OBJECT, p); obj = JS_NewObject(ctx); if (JS_IsException(obj)) return JS_EXCEPTION; set_cycle_flag(ctx, obj); set_cycle_flag(ctx, this_val); ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, JS_DupValue(ctx, this_val), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); if (ret < 0) { JS_FreeValue(ctx, obj); return JS_EXCEPTION; } return obj; } static const uint16_t func_kind_to_class_id[] = { [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION, [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION, [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION, [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION, }; static JSValue js_closure(JSContext *ctx, JSValue bfunc, JSVarRef **cur_var_refs, JSStackFrame *sf) { JSFunctionBytecode *b; JSValue func_obj; JSAtom name_atom; b = JS_VALUE_GET_PTR(bfunc); func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]); if (JS_IsException(func_obj)) { JS_FreeValue(ctx, bfunc); return JS_EXCEPTION; } func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf); if (JS_IsException(func_obj)) { /* bfunc has been freed */ goto fail; } name_atom = b->func_name; if (name_atom == JS_ATOM_NULL) name_atom = JS_ATOM_empty_string; js_function_set_properties(ctx, func_obj, name_atom, b->defined_arg_count); if (b->func_kind & JS_FUNC_GENERATOR) { JSValue proto; int proto_class_id; /* generators have a prototype field which is used as prototype for the generator object */ if (b->func_kind == JS_FUNC_ASYNC_GENERATOR) proto_class_id = JS_CLASS_ASYNC_GENERATOR; else proto_class_id = JS_CLASS_GENERATOR; proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]); if (JS_IsException(proto)) goto fail; JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto, JS_PROP_WRITABLE); } else if (b->has_prototype) { /* add the 'prototype' property: delay instantiation to avoid creating cycles for every javascript function. The prototype object is created on the fly when first accessed */ JS_SetConstructorBit(ctx, func_obj, TRUE); JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype, JS_AUTOINIT_ID_PROTOTYPE, NULL, JS_PROP_WRITABLE); } return func_obj; fail: /* bfunc is freed when func_obj is freed */ JS_FreeValue(ctx, func_obj); return JS_EXCEPTION; } #define JS_DEFINE_CLASS_HAS_HERITAGE (1 << 0) static int js_op_define_class(JSContext *ctx, JSValue *sp, JSAtom class_name, int class_flags, JSVarRef **cur_var_refs, JSStackFrame *sf, BOOL is_computed_name) { JSValue bfunc, parent_class, proto = JS_UNDEFINED; JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED; JSFunctionBytecode *b; parent_class = sp[-2]; bfunc = sp[-1]; if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) { if (JS_IsNull(parent_class)) { parent_proto = JS_NULL; parent_class = JS_DupValue(ctx, ctx->function_proto); } else { if (!JS_IsConstructor(ctx, parent_class)) { JS_ThrowTypeError(ctx, "parent class must be constructor"); goto fail; } parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype); if (JS_IsException(parent_proto)) goto fail; if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) { JS_ThrowTypeError(ctx, "parent prototype must be an object or null"); goto fail; } } } else { /* parent_class is JS_UNDEFINED in this case */ parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]); parent_class = JS_DupValue(ctx, ctx->function_proto); } proto = JS_NewObjectProto(ctx, parent_proto); if (JS_IsException(proto)) goto fail; b = JS_VALUE_GET_PTR(bfunc); assert(b->func_kind == JS_FUNC_NORMAL); ctor = JS_NewObjectProtoClass(ctx, parent_class, JS_CLASS_BYTECODE_FUNCTION); if (JS_IsException(ctor)) goto fail; ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf); bfunc = JS_UNDEFINED; if (JS_IsException(ctor)) goto fail; js_method_set_home_object(ctx, ctor, proto); JS_SetConstructorBit(ctx, ctor, TRUE); JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length, JS_NewInt32(ctx, b->defined_arg_count), JS_PROP_CONFIGURABLE); if (is_computed_name) { if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3], JS_PROP_CONFIGURABLE) < 0) goto fail; } else { if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0) goto fail; } /* the constructor property must be first. It can be overriden by computed property names */ if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, JS_DupValue(ctx, ctor), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_THROW) < 0) goto fail; /* set the prototype property */ if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype, JS_DupValue(ctx, proto), JS_PROP_THROW) < 0) goto fail; set_cycle_flag(ctx, ctor); set_cycle_flag(ctx, proto); JS_FreeValue(ctx, parent_proto); JS_FreeValue(ctx, parent_class); sp[-2] = ctor; sp[-1] = proto; return 0; fail: JS_FreeValue(ctx, parent_class); JS_FreeValue(ctx, parent_proto); JS_FreeValue(ctx, bfunc); JS_FreeValue(ctx, proto); JS_FreeValue(ctx, ctor); sp[-2] = JS_UNDEFINED; sp[-1] = JS_UNDEFINED; return -1; } static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) { struct list_head *el, *el1; JSVarRef *var_ref; int var_idx; list_for_each_safe(el, el1, &sf->var_ref_list) { var_ref = list_entry(el, JSVarRef, var_ref_link); /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */ if (var_ref->async_func) async_func_free(rt, var_ref->async_func); var_idx = var_ref->var_idx; if (var_ref->is_arg) var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]); else var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]); var_ref->pvalue = &var_ref->value; /* the reference is no longer to a local variable */ var_ref->is_detached = TRUE; } } static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg) { struct list_head *el, *el1; JSVarRef *var_ref; int var_idx = idx; list_for_each_safe(el, el1, &sf->var_ref_list) { var_ref = list_entry(el, JSVarRef, var_ref_link); if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) { list_del(&var_ref->var_ref_link); if (var_ref->async_func) async_func_free(ctx->rt, var_ref->async_func); var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]); var_ref->pvalue = &var_ref->value; /* the reference is no longer to a local variable */ var_ref->is_detached = TRUE; } } } #define JS_CALL_FLAG_COPY_ARGV (1 << 1) #define JS_CALL_FLAG_GENERATOR (1 << 2) static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags) { JSRuntime *rt = ctx->rt; JSCFunctionType func; JSObject *p; JSStackFrame sf_s, *sf = &sf_s, *prev_sf; JSValue ret_val; JSValueConst *arg_buf; int arg_count, i; JSCFunctionEnum cproto; p = JS_VALUE_GET_OBJ(func_obj); cproto = p->u.cfunc.cproto; arg_count = p->u.cfunc.length; /* better to always check stack overflow */ if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count)) return JS_ThrowStackOverflow(ctx); prev_sf = rt->current_stack_frame; sf->prev_frame = prev_sf; rt->current_stack_frame = sf; ctx = p->u.cfunc.realm; /* change the current realm */ #ifdef CONFIG_BIGNUM /* we only propagate the bignum mode as some runtime functions test it */ if (prev_sf) sf->js_mode = prev_sf->js_mode & JS_MODE_MATH; else sf->js_mode = 0; #else sf->js_mode = 0; #endif sf->cur_func = func_obj; sf->arg_count = argc; arg_buf = argv; if (unlikely(argc < arg_count)) { /* ensure that at least argc_count arguments are readable */ arg_buf = alloca(sizeof(arg_buf[0]) * arg_count); for(i = 0; i < argc; i++) arg_buf[i] = argv[i]; for(i = argc; i < arg_count; i++) arg_buf[i] = JS_UNDEFINED; sf->arg_count = arg_count; } sf->arg_buf = (JSValue*)arg_buf; func = p->u.cfunc.c_function; switch(cproto) { case JS_CFUNC_constructor: case JS_CFUNC_constructor_or_func: if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) { if (cproto == JS_CFUNC_constructor) { not_a_constructor: ret_val = JS_ThrowTypeError(ctx, "must be called with new"); break; } else { this_obj = JS_UNDEFINED; } } /* here this_obj is new_target */ /* fall thru */ case JS_CFUNC_generic: ret_val = func.generic(ctx, this_obj, argc, arg_buf); break; case JS_CFUNC_constructor_magic: case JS_CFUNC_constructor_or_func_magic: if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) { if (cproto == JS_CFUNC_constructor_magic) { goto not_a_constructor; } else { this_obj = JS_UNDEFINED; } } /* fall thru */ case JS_CFUNC_generic_magic: ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf, p->u.cfunc.magic); break; case JS_CFUNC_getter: ret_val = func.getter(ctx, this_obj); break; case JS_CFUNC_setter: ret_val = func.setter(ctx, this_obj, arg_buf[0]); break; case JS_CFUNC_getter_magic: ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic); break; case JS_CFUNC_setter_magic: ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic); break; case JS_CFUNC_f_f: { double d1; if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) { ret_val = JS_EXCEPTION; break; } ret_val = JS_NewFloat64(ctx, func.f_f(d1)); } break; case JS_CFUNC_f_f_f: { double d1, d2; if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) { ret_val = JS_EXCEPTION; break; } if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) { ret_val = JS_EXCEPTION; break; } ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2)); } break; case JS_CFUNC_iterator_next: { int done; ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf, &done, p->u.cfunc.magic); if (!JS_IsException(ret_val) && done != 2) { ret_val = js_create_iterator_result(ctx, ret_val, done); } } break; default: abort(); } rt->current_stack_frame = sf->prev_frame; return ret_val; } static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags) { JSObject *p; JSBoundFunction *bf; JSValueConst *arg_buf, new_target; int arg_count, i; p = JS_VALUE_GET_OBJ(func_obj); bf = p->u.bound_function; arg_count = bf->argc + argc; if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count)) return JS_ThrowStackOverflow(ctx); arg_buf = alloca(sizeof(JSValue) * arg_count); for(i = 0; i < bf->argc; i++) { arg_buf[i] = bf->argv[i]; } for(i = 0; i < argc; i++) { arg_buf[bf->argc + i] = argv[i]; } if (flags & JS_CALL_FLAG_CONSTRUCTOR) { new_target = this_obj; if (js_same_value(ctx, func_obj, new_target)) new_target = bf->func_obj; return JS_CallConstructor2(ctx, bf->func_obj, new_target, arg_count, arg_buf); } else { return JS_Call(ctx, bf->func_obj, bf->this_val, arg_count, arg_buf); } } /* argument of OP_special_object */ typedef enum { OP_SPECIAL_OBJECT_ARGUMENTS, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS, OP_SPECIAL_OBJECT_THIS_FUNC, OP_SPECIAL_OBJECT_NEW_TARGET, OP_SPECIAL_OBJECT_HOME_OBJECT, OP_SPECIAL_OBJECT_VAR_OBJECT, OP_SPECIAL_OBJECT_IMPORT_META, } OPSpecialObjectEnum; #define FUNC_RET_AWAIT 0 #define FUNC_RET_YIELD 1 #define FUNC_RET_YIELD_STAR 2 #define FUNC_RET_INITIAL_YIELD 3 /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSValueConst this_obj, JSValueConst new_target, int argc, JSValue *argv, int flags) { JSRuntime *rt = caller_ctx->rt; JSContext *ctx; JSObject *p; JSFunctionBytecode *b; JSStackFrame sf_s, *sf = &sf_s; const uint8_t *pc; int opcode, arg_allocated_size, i; JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval; JSVarRef **var_refs; size_t alloca_size; #if !DIRECT_DISPATCH #define SWITCH(pc) switch (opcode = *pc++) #define CASE(op) case op #define DEFAULT default #define BREAK break #else static const void * const dispatch_table[256] = { #define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id, #if SHORT_OPCODES #define def(id, size, n_pop, n_push, f) #else #define def(id, size, n_pop, n_push, f) && case_default, #endif #include "quickjs-opcode.h" [ OP_COUNT ... 255 ] = &&case_default }; #define SWITCH(pc) goto *dispatch_table[opcode = *pc++]; #define CASE(op) case_ ## op #define DEFAULT case_default #define BREAK SWITCH(pc) #endif if (js_poll_interrupts(caller_ctx)) return JS_EXCEPTION; if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) { if (flags & JS_CALL_FLAG_GENERATOR) { JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj); /* func_obj get contains a pointer to JSFuncAsyncState */ /* the stack frame is already allocated */ sf = &s->frame; p = JS_VALUE_GET_OBJ(sf->cur_func); b = p->u.func.function_bytecode; ctx = b->realm; var_refs = p->u.func.var_refs; local_buf = arg_buf = sf->arg_buf; var_buf = sf->var_buf; stack_buf = sf->var_buf + b->var_count; sp = sf->cur_sp; sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */ pc = sf->cur_pc; sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; if (s->throw_flag) goto exception; else goto restart; } else { goto not_a_function; } } p = JS_VALUE_GET_OBJ(func_obj); if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { JSClassCall *call_func; call_func = rt->class_array[p->class_id].call; if (!call_func) { not_a_function: return JS_ThrowTypeError(caller_ctx, "not a function"); } return call_func(caller_ctx, func_obj, this_obj, argc, (JSValueConst *)argv, flags); } b = p->u.func.function_bytecode; if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) { arg_allocated_size = b->arg_count; } else { arg_allocated_size = 0; } alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count + b->stack_size); if (js_check_stack_overflow(rt, alloca_size)) return JS_ThrowStackOverflow(caller_ctx); sf->js_mode = b->js_mode; arg_buf = argv; sf->arg_count = argc; sf->cur_func = func_obj; init_list_head(&sf->var_ref_list); var_refs = p->u.func.var_refs; local_buf = alloca(alloca_size); if (unlikely(arg_allocated_size)) { int n = min_int(argc, b->arg_count); arg_buf = local_buf; for(i = 0; i < n; i++) arg_buf[i] = JS_DupValue(caller_ctx, argv[i]); for(; i < b->arg_count; i++) arg_buf[i] = JS_UNDEFINED; sf->arg_count = b->arg_count; } var_buf = local_buf + arg_allocated_size; sf->var_buf = var_buf; sf->arg_buf = arg_buf; for(i = 0; i < b->var_count; i++) var_buf[i] = JS_UNDEFINED; stack_buf = var_buf + b->var_count; sp = stack_buf; pc = b->byte_code_buf; sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; ctx = b->realm; /* set the current realm */ if (ctx->handleFunctionEntered) ctx->handleFunctionEntered(ctx, this_obj); restart: for(;;) { int call_argc; JSValue *call_argv; SWITCH(pc) { CASE(OP_push_i32): *sp++ = JS_NewInt32(ctx, get_u32(pc)); pc += 4; BREAK; CASE(OP_push_const): *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]); pc += 4; BREAK; #if SHORT_OPCODES CASE(OP_push_minus1): CASE(OP_push_0): CASE(OP_push_1): CASE(OP_push_2): CASE(OP_push_3): CASE(OP_push_4): CASE(OP_push_5): CASE(OP_push_6): CASE(OP_push_7): *sp++ = JS_NewInt32(ctx, opcode - OP_push_0); BREAK; CASE(OP_push_i8): *sp++ = JS_NewInt32(ctx, get_i8(pc)); pc += 1; BREAK; CASE(OP_push_i16): *sp++ = JS_NewInt32(ctx, get_i16(pc)); pc += 2; BREAK; CASE(OP_push_const8): *sp++ = JS_DupValue(ctx, b->cpool[*pc++]); BREAK; CASE(OP_fclosure8): *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf); if (unlikely(JS_IsException(sp[-1]))) goto exception; BREAK; CASE(OP_push_empty_string): *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string); BREAK; CASE(OP_get_length): { JSValue val; val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length); if (unlikely(JS_IsException(val))) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = val; } BREAK; #endif CASE(OP_push_atom_value): *sp++ = JS_AtomToValue(ctx, get_u32(pc)); pc += 4; BREAK; CASE(OP_undefined): *sp++ = JS_UNDEFINED; BREAK; CASE(OP_null): *sp++ = JS_NULL; BREAK; CASE(OP_push_this): /* OP_push_this is only called at the start of a function */ { JSValue val; if (!(b->js_mode & JS_MODE_STRICT)) { uint32_t tag = JS_VALUE_GET_TAG(this_obj); if (likely(tag == JS_TAG_OBJECT)) goto normal_this; if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) { val = JS_DupValue(ctx, ctx->global_obj); } else { val = JS_ToObject(ctx, this_obj); if (JS_IsException(val)) goto exception; } } else { normal_this: val = JS_DupValue(ctx, this_obj); } *sp++ = val; } BREAK; CASE(OP_push_false): *sp++ = JS_FALSE; BREAK; CASE(OP_push_true): *sp++ = JS_TRUE; BREAK; CASE(OP_object): *sp++ = JS_NewObject(ctx); if (unlikely(JS_IsException(sp[-1]))) goto exception; BREAK; CASE(OP_special_object): { int arg = *pc++; switch(arg) { case OP_SPECIAL_OBJECT_ARGUMENTS: *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv); if (unlikely(JS_IsException(sp[-1]))) goto exception; break; case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS: *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv, sf, min_int(argc, b->arg_count)); if (unlikely(JS_IsException(sp[-1]))) goto exception; break; case OP_SPECIAL_OBJECT_THIS_FUNC: *sp++ = JS_DupValue(ctx, sf->cur_func); break; case OP_SPECIAL_OBJECT_NEW_TARGET: *sp++ = JS_DupValue(ctx, new_target); break; case OP_SPECIAL_OBJECT_HOME_OBJECT: { JSObject *p1; p1 = p->u.func.home_object; if (unlikely(!p1)) *sp++ = JS_UNDEFINED; else *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); } break; case OP_SPECIAL_OBJECT_VAR_OBJECT: *sp++ = JS_NewObjectProto(ctx, JS_NULL); if (unlikely(JS_IsException(sp[-1]))) goto exception; break; case OP_SPECIAL_OBJECT_IMPORT_META: *sp++ = js_import_meta(ctx); if (unlikely(JS_IsException(sp[-1]))) goto exception; break; default: abort(); } } BREAK; CASE(OP_rest): { int first = get_u16(pc); pc += 2; *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv); if (unlikely(JS_IsException(sp[-1]))) goto exception; } BREAK; CASE(OP_drop): JS_FreeValue(ctx, sp[-1]); sp--; BREAK; CASE(OP_nip): JS_FreeValue(ctx, sp[-2]); sp[-2] = sp[-1]; sp--; BREAK; CASE(OP_nip1): /* a b c -> b c */ JS_FreeValue(ctx, sp[-3]); sp[-3] = sp[-2]; sp[-2] = sp[-1]; sp--; BREAK; CASE(OP_dup): sp[0] = JS_DupValue(ctx, sp[-1]); sp++; BREAK; CASE(OP_dup2): /* a b -> a b a b */ sp[0] = JS_DupValue(ctx, sp[-2]); sp[1] = JS_DupValue(ctx, sp[-1]); sp += 2; BREAK; CASE(OP_dup3): /* a b c -> a b c a b c */ sp[0] = JS_DupValue(ctx, sp[-3]); sp[1] = JS_DupValue(ctx, sp[-2]); sp[2] = JS_DupValue(ctx, sp[-1]); sp += 3; BREAK; CASE(OP_dup1): /* a b -> a a b */ sp[0] = sp[-1]; sp[-1] = JS_DupValue(ctx, sp[-2]); sp++; BREAK; CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */ sp[0] = sp[-1]; sp[-1] = sp[-2]; sp[-2] = JS_DupValue(ctx, sp[0]); sp++; BREAK; CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */ sp[0] = sp[-1]; sp[-1] = sp[-2]; sp[-2] = sp[-3]; sp[-3] = JS_DupValue(ctx, sp[0]); sp++; BREAK; CASE(OP_insert4): /* this obj prop a -> a this obj prop a */ sp[0] = sp[-1]; sp[-1] = sp[-2]; sp[-2] = sp[-3]; sp[-3] = sp[-4]; sp[-4] = JS_DupValue(ctx, sp[0]); sp++; BREAK; CASE(OP_perm3): /* obj a b -> a obj b (213) */ { JSValue tmp; tmp = sp[-2]; sp[-2] = sp[-3]; sp[-3] = tmp; } BREAK; CASE(OP_rot3l): /* x a b -> a b x (231) */ { JSValue tmp; tmp = sp[-3]; sp[-3] = sp[-2]; sp[-2] = sp[-1]; sp[-1] = tmp; } BREAK; CASE(OP_rot4l): /* x a b c -> a b c x */ { JSValue tmp; tmp = sp[-4]; sp[-4] = sp[-3]; sp[-3] = sp[-2]; sp[-2] = sp[-1]; sp[-1] = tmp; } BREAK; CASE(OP_rot5l): /* x a b c d -> a b c d x */ { JSValue tmp; tmp = sp[-5]; sp[-5] = sp[-4]; sp[-4] = sp[-3]; sp[-3] = sp[-2]; sp[-2] = sp[-1]; sp[-1] = tmp; } BREAK; CASE(OP_rot3r): /* a b x -> x a b (312) */ { JSValue tmp; tmp = sp[-1]; sp[-1] = sp[-2]; sp[-2] = sp[-3]; sp[-3] = tmp; } BREAK; CASE(OP_perm4): /* obj prop a b -> a obj prop b */ { JSValue tmp; tmp = sp[-2]; sp[-2] = sp[-3]; sp[-3] = sp[-4]; sp[-4] = tmp; } BREAK; CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */ { JSValue tmp; tmp = sp[-2]; sp[-2] = sp[-3]; sp[-3] = sp[-4]; sp[-4] = sp[-5]; sp[-5] = tmp; } BREAK; CASE(OP_swap): /* a b -> b a */ { JSValue tmp; tmp = sp[-2]; sp[-2] = sp[-1]; sp[-1] = tmp; } BREAK; CASE(OP_swap2): /* a b c d -> c d a b */ { JSValue tmp1, tmp2; tmp1 = sp[-4]; tmp2 = sp[-3]; sp[-4] = sp[-2]; sp[-3] = sp[-1]; sp[-2] = tmp1; sp[-1] = tmp2; } BREAK; CASE(OP_fclosure): { JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]); pc += 4; *sp++ = js_closure(ctx, bfunc, var_refs, sf); if (unlikely(JS_IsException(sp[-1]))) goto exception; } BREAK; #if SHORT_OPCODES CASE(OP_call0): CASE(OP_call1): CASE(OP_call2): CASE(OP_call3): call_argc = opcode - OP_call0; goto has_call_argc; #endif CASE(OP_call): CASE(OP_tail_call): { call_argc = get_u16(pc); pc += 2; goto has_call_argc; has_call_argc: call_argv = sp - call_argc; sf->cur_pc = pc; ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, JS_UNDEFINED, call_argc, call_argv, 0); if (unlikely(JS_IsException(ret_val))) goto exception; if (opcode == OP_tail_call) goto done; for(i = -1; i < call_argc; i++) JS_FreeValue(ctx, call_argv[i]); sp -= call_argc + 1; *sp++ = ret_val; } BREAK; CASE(OP_call_constructor): { call_argc = get_u16(pc); pc += 2; call_argv = sp - call_argc; sf->cur_pc = pc; ret_val = JS_CallConstructorInternal(ctx, call_argv[-2], call_argv[-1], call_argc, call_argv, 0); if (unlikely(JS_IsException(ret_val))) goto exception; for(i = -2; i < call_argc; i++) JS_FreeValue(ctx, call_argv[i]); sp -= call_argc + 2; *sp++ = ret_val; } BREAK; CASE(OP_call_method): CASE(OP_tail_call_method): { call_argc = get_u16(pc); pc += 2; call_argv = sp - call_argc; sf->cur_pc = pc; ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2], JS_UNDEFINED, call_argc, call_argv, 0); if (unlikely(JS_IsException(ret_val))) goto exception; if (opcode == OP_tail_call_method) goto done; for(i = -2; i < call_argc; i++) JS_FreeValue(ctx, call_argv[i]); sp -= call_argc + 2; *sp++ = ret_val; } BREAK; CASE(OP_array_from): { int i, ret; call_argc = get_u16(pc); pc += 2; ret_val = JS_NewArray(ctx); if (unlikely(JS_IsException(ret_val))) goto exception; call_argv = sp - call_argc; for(i = 0; i < call_argc; i++) { ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i], JS_PROP_C_W_E | JS_PROP_THROW); call_argv[i] = JS_UNDEFINED; if (ret < 0) { JS_FreeValue(ctx, ret_val); goto exception; } } sp -= call_argc; *sp++ = ret_val; } BREAK; CASE(OP_apply): { int magic; magic = get_u16(pc); pc += 2; ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic); if (unlikely(JS_IsException(ret_val))) goto exception; JS_FreeValue(ctx, sp[-3]); JS_FreeValue(ctx, sp[-2]); JS_FreeValue(ctx, sp[-1]); sp -= 3; *sp++ = ret_val; } BREAK; CASE(OP_return): ret_val = *--sp; goto done; CASE(OP_return_undef): ret_val = JS_UNDEFINED; goto done; CASE(OP_check_ctor_return): /* return TRUE if 'this' should be returned */ if (!JS_IsObject(sp[-1])) { if (!JS_IsUndefined(sp[-1])) { JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined"); goto exception; } sp[0] = JS_TRUE; } else { sp[0] = JS_FALSE; } sp++; BREAK; CASE(OP_check_ctor): if (JS_IsUndefined(new_target)) { JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'"); goto exception; } BREAK; CASE(OP_check_brand): { int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]); if (ret < 0) goto exception; if (!ret) { JS_ThrowTypeError(ctx, "invalid brand on object"); goto exception; } } BREAK; CASE(OP_add_brand): if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0) goto exception; JS_FreeValue(ctx, sp[-2]); JS_FreeValue(ctx, sp[-1]); sp -= 2; BREAK; CASE(OP_throw): JS_Throw(ctx, *--sp); goto exception; CASE(OP_throw_error): #define JS_THROW_VAR_RO 0 #define JS_THROW_VAR_REDECL 1 #define JS_THROW_VAR_UNINITIALIZED 2 #define JS_THROW_ERROR_DELETE_SUPER 3 #define JS_THROW_ERROR_ITERATOR_THROW 4 { JSAtom atom; int type; atom = get_u32(pc); type = pc[4]; pc += 5; if (type == JS_THROW_VAR_RO) JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom); else if (type == JS_THROW_VAR_REDECL) JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom); else if (type == JS_THROW_VAR_UNINITIALIZED) JS_ThrowReferenceErrorUninitialized(ctx, atom); else if (type == JS_THROW_ERROR_DELETE_SUPER) JS_ThrowReferenceError(ctx, "unsupported reference to 'super'"); else if (type == JS_THROW_ERROR_ITERATOR_THROW) JS_ThrowTypeError(ctx, "iterator does not have a throw method"); else JS_ThrowInternalError(ctx, "invalid throw var type %d", type); } goto exception; CASE(OP_eval): { JSValueConst obj; int scope_idx; call_argc = get_u16(pc); scope_idx = get_u16(pc + 2) - 1; pc += 4; call_argv = sp - call_argc; sf->cur_pc = pc; if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) { if (call_argc >= 1) obj = call_argv[0]; else obj = JS_UNDEFINED; ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, JS_EVAL_TYPE_DIRECT, scope_idx); } else { ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, JS_UNDEFINED, call_argc, call_argv, 0); } if (unlikely(JS_IsException(ret_val))) goto exception; for(i = -1; i < call_argc; i++) JS_FreeValue(ctx, call_argv[i]); sp -= call_argc + 1; *sp++ = ret_val; } BREAK; /* could merge with OP_apply */ CASE(OP_apply_eval): { int scope_idx; uint32_t len; JSValue *tab; JSValueConst obj; scope_idx = get_u16(pc) - 1; pc += 2; tab = build_arg_list(ctx, &len, sp[-1]); if (!tab) goto exception; if (js_same_value(ctx, sp[-2], ctx->eval_obj)) { if (len >= 1) obj = tab[0]; else obj = JS_UNDEFINED; ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, JS_EVAL_TYPE_DIRECT, scope_idx); } else { ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len, (JSValueConst *)tab); } free_arg_list(ctx, tab, len); if (unlikely(JS_IsException(ret_val))) goto exception; JS_FreeValue(ctx, sp[-2]); JS_FreeValue(ctx, sp[-1]); sp -= 2; *sp++ = ret_val; } BREAK; CASE(OP_regexp): { sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED, sp[-2], sp[-1]); sp--; } BREAK; CASE(OP_get_super): { JSValue proto; proto = JS_GetPrototype(ctx, sp[-1]); if (JS_IsException(proto)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = proto; } BREAK; CASE(OP_import): { JSValue val; val = js_dynamic_import(ctx, sp[-1]); if (JS_IsException(val)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = val; } BREAK; CASE(OP_check_var): { int ret; JSAtom atom; atom = get_u32(pc); pc += 4; ret = JS_CheckGlobalVar(ctx, atom); if (ret < 0) goto exception; *sp++ = JS_NewBool(ctx, ret); } BREAK; CASE(OP_get_var_undef): CASE(OP_get_var): { JSValue val; JSAtom atom; atom = get_u32(pc); pc += 4; val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef); if (unlikely(JS_IsException(val))) goto exception; *sp++ = val; } BREAK; CASE(OP_put_var): CASE(OP_put_var_init): { int ret; JSAtom atom; atom = get_u32(pc); pc += 4; ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var); sp--; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_put_var_strict): { int ret; JSAtom atom; atom = get_u32(pc); pc += 4; /* sp[-2] is JS_TRUE or JS_FALSE */ if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) { JS_ThrowReferenceErrorNotDefined(ctx, atom); goto exception; } ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2); sp -= 2; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_check_define_var): { JSAtom atom; int flags; atom = get_u32(pc); flags = pc[4]; pc += 5; if (JS_CheckDefineGlobalVar(ctx, atom, flags)) goto exception; } BREAK; CASE(OP_define_var): { JSAtom atom; int flags; atom = get_u32(pc); flags = pc[4]; pc += 5; if (JS_DefineGlobalVar(ctx, atom, flags)) goto exception; } BREAK; CASE(OP_define_func): { JSAtom atom; int flags; atom = get_u32(pc); flags = pc[4]; pc += 5; if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags)) goto exception; JS_FreeValue(ctx, sp[-1]); sp--; } BREAK; CASE(OP_get_loc): { int idx; idx = get_u16(pc); pc += 2; sp[0] = JS_DupValue(ctx, var_buf[idx]); sp++; } BREAK; CASE(OP_put_loc): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, &var_buf[idx], sp[-1]); sp--; } BREAK; CASE(OP_set_loc): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1])); } BREAK; CASE(OP_get_arg): { int idx; idx = get_u16(pc); pc += 2; sp[0] = JS_DupValue(ctx, arg_buf[idx]); sp++; } BREAK; CASE(OP_put_arg): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, &arg_buf[idx], sp[-1]); sp--; } BREAK; CASE(OP_set_arg): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1])); } BREAK; #if SHORT_OPCODES CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK; CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK; CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK; CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK; CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK; CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK; CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK; CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK; CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK; CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK; CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK; CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK; CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK; CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK; CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK; CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK; CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK; CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK; CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK; CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK; CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK; CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK; CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK; CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK; CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK; CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK; CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; #endif CASE(OP_get_var_ref): { int idx; JSValue val; idx = get_u16(pc); pc += 2; val = *var_refs[idx]->pvalue; sp[0] = JS_DupValue(ctx, val); sp++; } BREAK; CASE(OP_put_var_ref): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, var_refs[idx]->pvalue, sp[-1]); sp--; } BREAK; CASE(OP_set_var_ref): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1])); } BREAK; CASE(OP_get_var_ref_check): { int idx; JSValue val; idx = get_u16(pc); pc += 2; val = *var_refs[idx]->pvalue; if (unlikely(JS_IsUninitialized(val))) { JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); goto exception; } sp[0] = JS_DupValue(ctx, val); sp++; } BREAK; CASE(OP_put_var_ref_check): { int idx; idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) { JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); goto exception; } set_value(ctx, var_refs[idx]->pvalue, sp[-1]); sp--; } BREAK; CASE(OP_put_var_ref_check_init): { int idx; idx = get_u16(pc); pc += 2; if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) { JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); goto exception; } set_value(ctx, var_refs[idx]->pvalue, sp[-1]); sp--; } BREAK; CASE(OP_set_loc_uninitialized): { int idx; idx = get_u16(pc); pc += 2; set_value(ctx, &var_buf[idx], JS_UNINITIALIZED); } BREAK; CASE(OP_get_loc_check): { int idx; idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); goto exception; } sp[0] = JS_DupValue(ctx, var_buf[idx]); sp++; } BREAK; CASE(OP_get_loc_checkthis): { int idx; idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE); goto exception; } sp[0] = JS_DupValue(ctx, var_buf[idx]); sp++; } BREAK; CASE(OP_put_loc_check): { int idx; idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); goto exception; } set_value(ctx, &var_buf[idx], sp[-1]); sp--; } BREAK; CASE(OP_put_loc_check_init): { int idx; idx = get_u16(pc); pc += 2; if (unlikely(!JS_IsUninitialized(var_buf[idx]))) { JS_ThrowReferenceError(ctx, "'this' can be initialized only once"); goto exception; } set_value(ctx, &var_buf[idx], sp[-1]); sp--; } BREAK; CASE(OP_close_loc): { int idx; idx = get_u16(pc); pc += 2; close_lexical_var(ctx, sf, idx, FALSE); } BREAK; CASE(OP_make_loc_ref): CASE(OP_make_arg_ref): CASE(OP_make_var_ref_ref): { JSVarRef *var_ref; JSProperty *pr; JSAtom atom; int idx; atom = get_u32(pc); idx = get_u16(pc + 4); pc += 6; *sp++ = JS_NewObjectProto(ctx, JS_NULL); if (unlikely(JS_IsException(sp[-1]))) goto exception; if (opcode == OP_make_var_ref_ref) { var_ref = var_refs[idx]; var_ref->header.ref_count++; } else { var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref); if (!var_ref) goto exception; } pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom, JS_PROP_WRITABLE | JS_PROP_VARREF); if (!pr) { free_var_ref(rt, var_ref); goto exception; } pr->u.var_ref = var_ref; *sp++ = JS_AtomToValue(ctx, atom); } BREAK; CASE(OP_make_var_ref): { JSAtom atom; atom = get_u32(pc); pc += 4; if (JS_GetGlobalVarRef(ctx, atom, sp)) goto exception; sp += 2; } BREAK; CASE(OP_goto): pc += (int32_t)get_u32(pc); if (unlikely(js_poll_interrupts(ctx))) goto exception; BREAK; #if SHORT_OPCODES CASE(OP_goto16): pc += (int16_t)get_u16(pc); if (unlikely(js_poll_interrupts(ctx))) goto exception; BREAK; CASE(OP_goto8): pc += (int8_t)pc[0]; if (unlikely(js_poll_interrupts(ctx))) goto exception; BREAK; #endif CASE(OP_if_true): { int res; JSValue op1; op1 = sp[-1]; pc += 4; if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { res = JS_VALUE_GET_INT(op1); } else { res = JS_ToBoolFree(ctx, op1); } sp--; if (res) { pc += (int32_t)get_u32(pc - 4) - 4; } if (unlikely(js_poll_interrupts(ctx))) goto exception; } BREAK; CASE(OP_if_false): { int res; JSValue op1; op1 = sp[-1]; pc += 4; /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */ if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { res = JS_VALUE_GET_INT(op1); } else { res = JS_ToBoolFree(ctx, op1); } sp--; if (!res) { pc += (int32_t)get_u32(pc - 4) - 4; } if (unlikely(js_poll_interrupts(ctx))) goto exception; } BREAK; #if SHORT_OPCODES CASE(OP_if_true8): { int res; JSValue op1; op1 = sp[-1]; pc += 1; if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { res = JS_VALUE_GET_INT(op1); } else { res = JS_ToBoolFree(ctx, op1); } sp--; if (res) { pc += (int8_t)pc[-1] - 1; } if (unlikely(js_poll_interrupts(ctx))) goto exception; } BREAK; CASE(OP_if_false8): { int res; JSValue op1; op1 = sp[-1]; pc += 1; if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { res = JS_VALUE_GET_INT(op1); } else { res = JS_ToBoolFree(ctx, op1); } sp--; if (!res) { pc += (int8_t)pc[-1] - 1; } if (unlikely(js_poll_interrupts(ctx))) goto exception; } BREAK; #endif CASE(OP_catch): { int32_t diff; diff = get_u32(pc); sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf); sp++; pc += 4; } BREAK; CASE(OP_gosub): { int32_t diff; diff = get_u32(pc); /* XXX: should have a different tag to avoid security flaw */ sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf); sp++; pc += diff; } BREAK; CASE(OP_ret): { JSValue op1; uint32_t pos; op1 = sp[-1]; if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT)) goto ret_fail; pos = JS_VALUE_GET_INT(op1); if (unlikely(pos >= b->byte_code_len)) { ret_fail: JS_ThrowInternalError(ctx, "invalid ret value"); goto exception; } sp--; pc = b->byte_code_buf + pos; } BREAK; CASE(OP_for_in_start): if (js_for_in_start(ctx, sp)) goto exception; BREAK; CASE(OP_for_in_next): if (js_for_in_next(ctx, sp)) goto exception; sp += 2; BREAK; CASE(OP_for_of_start): if (js_for_of_start(ctx, sp, FALSE)) goto exception; sp += 1; *sp++ = JS_NewCatchOffset(ctx, 0); BREAK; CASE(OP_for_of_next): { int offset = -3 - pc[0]; pc += 1; if (js_for_of_next(ctx, sp, offset)) goto exception; sp += 2; } BREAK; CASE(OP_for_await_of_start): if (js_for_of_start(ctx, sp, TRUE)) goto exception; sp += 1; *sp++ = JS_NewCatchOffset(ctx, 0); BREAK; CASE(OP_iterator_get_value_done): if (js_iterator_get_value_done(ctx, sp)) goto exception; sp += 1; BREAK; CASE(OP_iterator_check_object): if (unlikely(!JS_IsObject(sp[-1]))) { JS_ThrowTypeError(ctx, "iterator must return an object"); goto exception; } BREAK; CASE(OP_iterator_close): /* iter_obj next catch_offset -> */ sp--; /* drop the catch offset to avoid getting caught by exception */ JS_FreeValue(ctx, sp[-1]); /* drop the next method */ sp--; if (!JS_IsUndefined(sp[-1])) { if (JS_IteratorClose(ctx, sp[-1], FALSE)) goto exception; JS_FreeValue(ctx, sp[-1]); } sp--; BREAK; CASE(OP_nip_catch): { JSValue ret_val; /* catch_offset ... ret_val -> ret_eval */ ret_val = *--sp; while (sp > stack_buf && JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) { JS_FreeValue(ctx, *--sp); } if (unlikely(sp == stack_buf)) { JS_ThrowInternalError(ctx, "nip_catch"); JS_FreeValue(ctx, ret_val); goto exception; } sp[-1] = ret_val; } BREAK; CASE(OP_iterator_next): /* stack: iter_obj next catch_offset val */ { JSValue ret; ret = JS_Call(ctx, sp[-3], sp[-4], 1, (JSValueConst *)(sp - 1)); if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret; } BREAK; CASE(OP_iterator_call): /* stack: iter_obj next catch_offset val */ { JSValue method, ret; BOOL ret_flag; int flags; flags = *pc++; method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? JS_ATOM_throw : JS_ATOM_return); if (JS_IsException(method)) goto exception; if (JS_IsUndefined(method) || JS_IsNull(method)) { ret_flag = TRUE; } else { if (flags & 2) { /* no argument */ ret = JS_CallFree(ctx, method, sp[-4], 0, NULL); } else { ret = JS_CallFree(ctx, method, sp[-4], 1, (JSValueConst *)(sp - 1)); } if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret; ret_flag = FALSE; } sp[0] = JS_NewBool(ctx, ret_flag); sp += 1; } BREAK; CASE(OP_lnot): { int res; JSValue op1; op1 = sp[-1]; if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { res = JS_VALUE_GET_INT(op1) != 0; } else { res = JS_ToBoolFree(ctx, op1); } sp[-1] = JS_NewBool(ctx, !res); } BREAK; CASE(OP_get_field): { JSValue val; JSAtom atom; atom = get_u32(pc); pc += 4; val = JS_GetProperty(ctx, sp[-1], atom); if (unlikely(JS_IsException(val))) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = val; } BREAK; CASE(OP_get_field2): { JSValue val; JSAtom atom; atom = get_u32(pc); pc += 4; val = JS_GetProperty(ctx, sp[-1], atom); if (unlikely(JS_IsException(val))) goto exception; *sp++ = val; } BREAK; CASE(OP_put_field): { int ret; JSAtom atom; atom = get_u32(pc); pc += 4; ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-2]); sp -= 2; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_private_symbol): { JSAtom atom; JSValue val; atom = get_u32(pc); pc += 4; val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE); if (JS_IsException(val)) goto exception; *sp++ = val; } BREAK; CASE(OP_get_private_field): { JSValue val; val = JS_GetPrivateField(ctx, sp[-2], sp[-1]); JS_FreeValue(ctx, sp[-1]); JS_FreeValue(ctx, sp[-2]); sp[-2] = val; sp--; if (unlikely(JS_IsException(val))) goto exception; } BREAK; CASE(OP_put_private_field): { int ret; ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]); JS_FreeValue(ctx, sp[-3]); JS_FreeValue(ctx, sp[-1]); sp -= 3; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_define_private_field): { int ret; ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]); JS_FreeValue(ctx, sp[-2]); sp -= 2; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_define_field): { int ret; JSAtom atom; atom = get_u32(pc); pc += 4; ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1], JS_PROP_C_W_E | JS_PROP_THROW); sp--; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_set_name): { int ret; JSAtom atom; atom = get_u32(pc); pc += 4; ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE); if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_set_name_computed): { int ret; ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE); if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_set_proto): { JSValue proto; proto = sp[-1]; if (JS_IsObject(proto) || JS_IsNull(proto)) { if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0) goto exception; } JS_FreeValue(ctx, proto); sp--; } BREAK; CASE(OP_set_home_object): js_method_set_home_object(ctx, sp[-1], sp[-2]); BREAK; CASE(OP_define_method): CASE(OP_define_method_computed): { JSValue getter, setter, value; JSValueConst obj; JSAtom atom; int flags, ret, op_flags; BOOL is_computed; #define OP_DEFINE_METHOD_METHOD 0 #define OP_DEFINE_METHOD_GETTER 1 #define OP_DEFINE_METHOD_SETTER 2 #define OP_DEFINE_METHOD_ENUMERABLE 4 is_computed = (opcode == OP_define_method_computed); if (is_computed) { atom = JS_ValueToAtom(ctx, sp[-2]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; opcode += OP_define_method - OP_define_method_computed; } else { atom = get_u32(pc); pc += 4; } op_flags = *pc++; obj = sp[-2 - is_computed]; flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW; if (op_flags & OP_DEFINE_METHOD_ENUMERABLE) flags |= JS_PROP_ENUMERABLE; op_flags &= 3; value = JS_UNDEFINED; getter = JS_UNDEFINED; setter = JS_UNDEFINED; if (op_flags == OP_DEFINE_METHOD_METHOD) { value = sp[-1]; flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE; } else if (op_flags == OP_DEFINE_METHOD_GETTER) { getter = sp[-1]; flags |= JS_PROP_HAS_GET; } else { setter = sp[-1]; flags |= JS_PROP_HAS_SET; } ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj); if (ret >= 0) { ret = JS_DefineProperty(ctx, obj, atom, value, getter, setter, flags); } JS_FreeValue(ctx, sp[-1]); if (is_computed) { JS_FreeAtom(ctx, atom); JS_FreeValue(ctx, sp[-2]); } sp -= 1 + is_computed; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_define_class): CASE(OP_define_class_computed): { int class_flags; JSAtom atom; atom = get_u32(pc); class_flags = pc[4]; pc += 5; if (js_op_define_class(ctx, sp, atom, class_flags, var_refs, sf, (opcode == OP_define_class_computed)) < 0) goto exception; } BREAK; CASE(OP_get_array_el): { JSValue val; val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); JS_FreeValue(ctx, sp[-2]); sp[-2] = val; sp--; if (unlikely(JS_IsException(val))) goto exception; } BREAK; CASE(OP_get_array_el2): { JSValue val; val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); sp[-1] = val; if (unlikely(JS_IsException(val))) goto exception; } BREAK; CASE(OP_get_ref_value): { JSValue val; if (unlikely(JS_IsUndefined(sp[-2]))) { JSAtom atom = JS_ValueToAtom(ctx, sp[-1]); if (atom != JS_ATOM_NULL) { JS_ThrowReferenceErrorNotDefined(ctx, atom); JS_FreeAtom(ctx, atom); } goto exception; } val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1])); if (unlikely(JS_IsException(val))) goto exception; sp[0] = val; sp++; } BREAK; CASE(OP_get_super_value): { JSValue val; JSAtom atom; atom = JS_ValueToAtom(ctx, sp[-1]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE); JS_FreeAtom(ctx, atom); if (unlikely(JS_IsException(val))) goto exception; JS_FreeValue(ctx, sp[-1]); JS_FreeValue(ctx, sp[-2]); JS_FreeValue(ctx, sp[-3]); sp[-3] = val; sp -= 2; } BREAK; CASE(OP_put_array_el): { int ret; ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-3]); sp -= 3; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_put_ref_value): { int ret, flags; flags = JS_PROP_THROW_STRICT; if (unlikely(JS_IsUndefined(sp[-3]))) { if (is_strict_mode(ctx)) { JSAtom atom = JS_ValueToAtom(ctx, sp[-2]); if (atom != JS_ATOM_NULL) { JS_ThrowReferenceErrorNotDefined(ctx, atom); JS_FreeAtom(ctx, atom); } goto exception; } else { sp[-3] = JS_DupValue(ctx, ctx->global_obj); } } else { if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; } ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags); JS_FreeValue(ctx, sp[-3]); sp -= 3; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_put_super_value): { int ret; JSAtom atom; if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) { JS_ThrowTypeErrorNotAnObject(ctx); goto exception; } atom = JS_ValueToAtom(ctx, sp[-2]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4], JS_PROP_THROW_STRICT); JS_FreeAtom(ctx, atom); JS_FreeValue(ctx, sp[-4]); JS_FreeValue(ctx, sp[-3]); JS_FreeValue(ctx, sp[-2]); sp -= 4; if (ret < 0) goto exception; } BREAK; CASE(OP_define_array_el): { int ret; ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1], JS_PROP_C_W_E | JS_PROP_THROW); sp -= 1; if (unlikely(ret < 0)) goto exception; } BREAK; CASE(OP_append): /* array pos enumobj -- array pos */ { if (js_append_enumerate(ctx, sp)) goto exception; JS_FreeValue(ctx, *--sp); } BREAK; CASE(OP_copy_data_properties): /* target source excludeList */ { /* stack offsets (-1 based): 2 bits for target, 3 bits for source, 2 bits for exclusionList */ int mask; mask = *pc++; if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)], sp[-1 - ((mask >> 2) & 7)], sp[-1 - ((mask >> 5) & 7)], 0)) goto exception; } BREAK; CASE(OP_add): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { int64_t r; r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2); if (unlikely((int)r != r)) goto add_slow; sp[-2] = JS_NewInt32(ctx, r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) + JS_VALUE_GET_FLOAT64(op2)); sp--; } else if (JS_IsString(op1) && JS_IsString(op2)) { sp[-2] = JS_ConcatString(ctx, op1, op2); sp--; if (JS_IsException(sp[-1])) goto exception; } else { add_slow: if (js_add_slow(ctx, sp)) goto exception; sp--; } } BREAK; CASE(OP_add_loc): { JSValue op2; JSValue *pv; int idx; idx = *pc; pc += 1; op2 = sp[-1]; pv = &var_buf[idx]; if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) { int64_t r; r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2); if (unlikely((int)r != r)) goto add_loc_slow; *pv = JS_NewInt32(ctx, r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) { *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) + JS_VALUE_GET_FLOAT64(op2)); sp--; } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { sp--; op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); if (JS_IsException(op2)) goto exception; if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) { JS_FreeValue(ctx, op2); } else { op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2); if (JS_IsException(op2)) goto exception; set_value(ctx, pv, op2); } } else { JSValue ops[2]; add_loc_slow: /* In case of exception, js_add_slow frees ops[0] and ops[1], so we must duplicate *pv */ ops[0] = JS_DupValue(ctx, *pv); ops[1] = op2; sp--; if (js_add_slow(ctx, ops + 2)) goto exception; set_value(ctx, pv, ops[0]); } } BREAK; CASE(OP_sub): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { int64_t r; r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2); if (unlikely((int)r != r)) goto binary_arith_slow; sp[-2] = JS_NewInt32(ctx, r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) - JS_VALUE_GET_FLOAT64(op2)); sp--; } else { goto binary_arith_slow; } } BREAK; CASE(OP_mul): { JSValue op1, op2; double d; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { int32_t v1, v2; int64_t r; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); r = (int64_t)v1 * v2; if (unlikely((int)r != r)) { #ifdef CONFIG_BIGNUM if (unlikely(sf->js_mode & JS_MODE_MATH) && (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER)) goto binary_arith_slow; #endif d = (double)r; goto mul_fp_res; } /* need to test zero case for -0 result */ if (unlikely(r == 0 && (v1 | v2) < 0)) { d = -0.0; goto mul_fp_res; } sp[-2] = JS_NewInt32(ctx, r); sp--; } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { #ifdef CONFIG_BIGNUM if (unlikely(sf->js_mode & JS_MODE_MATH)) goto binary_arith_slow; #endif d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2); mul_fp_res: sp[-2] = __JS_NewFloat64(ctx, d); sp--; } else { goto binary_arith_slow; } } BREAK; CASE(OP_div): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { int v1, v2; if (unlikely(sf->js_mode & JS_MODE_MATH)) goto binary_arith_slow; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2); sp--; } else { goto binary_arith_slow; } } BREAK; CASE(OP_mod): #ifdef CONFIG_BIGNUM CASE(OP_math_mod): #endif { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { int v1, v2, r; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); /* We must avoid v2 = 0, v1 = INT32_MIN and v2 = -1 and the cases where the result is -0. */ if (unlikely(v1 < 0 || v2 <= 0)) goto binary_arith_slow; r = v1 % v2; sp[-2] = JS_NewInt32(ctx, r); sp--; } else { goto binary_arith_slow; } } BREAK; CASE(OP_pow): binary_arith_slow: if (js_binary_arith_slow(ctx, sp, opcode)) goto exception; sp--; BREAK; CASE(OP_plus): { JSValue op1; uint32_t tag; op1 = sp[-1]; tag = JS_VALUE_GET_TAG(op1); if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) { } else { if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } } BREAK; CASE(OP_neg): { JSValue op1; uint32_t tag; int val; double d; op1 = sp[-1]; tag = JS_VALUE_GET_TAG(op1); if (tag == JS_TAG_INT) { val = JS_VALUE_GET_INT(op1); /* Note: -0 cannot be expressed as integer */ if (unlikely(val == 0)) { d = -0.0; goto neg_fp_res; } if (unlikely(val == INT32_MIN)) { d = -(double)val; goto neg_fp_res; } sp[-1] = JS_NewInt32(ctx, -val); } else if (JS_TAG_IS_FLOAT64(tag)) { d = -JS_VALUE_GET_FLOAT64(op1); neg_fp_res: sp[-1] = __JS_NewFloat64(ctx, d); } else { if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } } BREAK; CASE(OP_inc): { JSValue op1; int val; op1 = sp[-1]; if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MAX)) goto inc_slow; sp[-1] = JS_NewInt32(ctx, val + 1); } else { inc_slow: if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } } BREAK; CASE(OP_dec): { JSValue op1; int val; op1 = sp[-1]; if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MIN)) goto dec_slow; sp[-1] = JS_NewInt32(ctx, val - 1); } else { dec_slow: if (js_unary_arith_slow(ctx, sp, opcode)) goto exception; } } BREAK; CASE(OP_post_inc): CASE(OP_post_dec): if (js_post_inc_slow(ctx, sp, opcode)) goto exception; sp++; BREAK; CASE(OP_inc_loc): { JSValue op1; int val; int idx; idx = *pc; pc += 1; op1 = var_buf[idx]; if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MAX)) goto inc_loc_slow; var_buf[idx] = JS_NewInt32(ctx, val + 1); } else { inc_loc_slow: /* must duplicate otherwise the variable value may be destroyed before JS code accesses it */ op1 = JS_DupValue(ctx, op1); if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc)) goto exception; set_value(ctx, &var_buf[idx], op1); } } BREAK; CASE(OP_dec_loc): { JSValue op1; int val; int idx; idx = *pc; pc += 1; op1 = var_buf[idx]; if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { val = JS_VALUE_GET_INT(op1); if (unlikely(val == INT32_MIN)) goto dec_loc_slow; var_buf[idx] = JS_NewInt32(ctx, val - 1); } else { dec_loc_slow: /* must duplicate otherwise the variable value may be destroyed before JS code accesses it */ op1 = JS_DupValue(ctx, op1); if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec)) goto exception; set_value(ctx, &var_buf[idx], op1); } } BREAK; CASE(OP_not): { JSValue op1; op1 = sp[-1]; if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1)); } else { if (js_not_slow(ctx, sp)) goto exception; } } BREAK; CASE(OP_shl): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { uint32_t v1, v2; v1 = JS_VALUE_GET_INT(op1); v2 = JS_VALUE_GET_INT(op2); #ifdef CONFIG_BIGNUM { int64_t r; if (unlikely(sf->js_mode & JS_MODE_MATH)) { if (v2 > 0x1f) goto shl_slow; r = (int64_t)v1 << v2; if ((int)r != r) goto shl_slow; } else { v2 &= 0x1f; } } #else v2 &= 0x1f; #endif sp[-2] = JS_NewInt32(ctx, v1 << v2); sp--; } else { #ifdef CONFIG_BIGNUM shl_slow: #endif if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; } } BREAK; CASE(OP_shr): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { uint32_t v2; v2 = JS_VALUE_GET_INT(op2); /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */ v2 &= 0x1f; sp[-2] = JS_NewUint32(ctx, (uint32_t)JS_VALUE_GET_INT(op1) >> v2); sp--; } else { if (js_shr_slow(ctx, sp)) goto exception; sp--; } } BREAK; CASE(OP_sar): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { uint32_t v2; v2 = JS_VALUE_GET_INT(op2); #ifdef CONFIG_BIGNUM if (unlikely(v2 > 0x1f)) { if (unlikely(sf->js_mode & JS_MODE_MATH)) goto sar_slow; else v2 &= 0x1f; } #else v2 &= 0x1f; #endif sp[-2] = JS_NewInt32(ctx, (int)JS_VALUE_GET_INT(op1) >> v2); sp--; } else { #ifdef CONFIG_BIGNUM sar_slow: #endif if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; } } BREAK; CASE(OP_and): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { sp[-2] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1) & JS_VALUE_GET_INT(op2)); sp--; } else { if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; } } BREAK; CASE(OP_or): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { sp[-2] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1) | JS_VALUE_GET_INT(op2)); sp--; } else { if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; } } BREAK; CASE(OP_xor): { JSValue op1, op2; op1 = sp[-2]; op2 = sp[-1]; if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { sp[-2] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1) ^ JS_VALUE_GET_INT(op2)); sp--; } else { if (js_binary_logic_slow(ctx, sp, opcode)) goto exception; sp--; } } BREAK; #define OP_CMP(opcode, binary_op, slow_call) \ CASE(opcode): \ { \ JSValue op1, op2; \ op1 = sp[-2]; \ op2 = sp[-1]; \ if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { \ sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \ sp--; \ } else { \ if (slow_call) \ goto exception; \ sp--; \ } \ } \ BREAK OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode)); OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode)); OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode)); OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode)); OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0)); OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1)); OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0)); OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1)); #ifdef CONFIG_BIGNUM CASE(OP_mul_pow10): if (rt->bigfloat_ops.mul_pow10(ctx, sp)) goto exception; sp--; BREAK; #endif CASE(OP_in): if (js_operator_in(ctx, sp)) goto exception; sp--; BREAK; CASE(OP_private_in): if (js_operator_private_in(ctx, sp)) goto exception; sp--; BREAK; CASE(OP_instanceof): if (js_operator_instanceof(ctx, sp)) goto exception; sp--; BREAK; CASE(OP_typeof): { JSValue op1; JSAtom atom; op1 = sp[-1]; atom = js_operator_typeof(ctx, op1); JS_FreeValue(ctx, op1); sp[-1] = JS_AtomToString(ctx, atom); } BREAK; CASE(OP_delete): if (js_operator_delete(ctx, sp)) goto exception; sp--; BREAK; CASE(OP_delete_var): { JSAtom atom; int ret; atom = get_u32(pc); pc += 4; ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0); if (unlikely(ret < 0)) goto exception; *sp++ = JS_NewBool(ctx, ret); } BREAK; CASE(OP_to_object): if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) { ret_val = JS_ToObject(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret_val; } BREAK; CASE(OP_to_propkey): switch (JS_VALUE_GET_TAG(sp[-1])) { case JS_TAG_INT: case JS_TAG_STRING: case JS_TAG_SYMBOL: break; default: ret_val = JS_ToPropertyKey(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret_val; break; } BREAK; CASE(OP_to_propkey2): /* must be tested first */ if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) { JS_ThrowTypeError(ctx, "value has no property"); goto exception; } switch (JS_VALUE_GET_TAG(sp[-1])) { case JS_TAG_INT: case JS_TAG_STRING: case JS_TAG_SYMBOL: break; default: ret_val = JS_ToPropertyKey(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret_val; break; } BREAK; #if 0 CASE(OP_to_string): if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) { ret_val = JS_ToString(ctx, sp[-1]); if (JS_IsException(ret_val)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = ret_val; } BREAK; #endif CASE(OP_with_get_var): CASE(OP_with_put_var): CASE(OP_with_delete_var): CASE(OP_with_make_ref): CASE(OP_with_get_ref): CASE(OP_with_get_ref_undef): { JSAtom atom; int32_t diff; JSValue obj, val; int ret, is_with; atom = get_u32(pc); diff = get_u32(pc + 4); is_with = pc[8]; pc += 9; obj = sp[-1]; ret = JS_HasProperty(ctx, obj, atom); if (unlikely(ret < 0)) goto exception; if (ret) { if (is_with) { ret = js_has_unscopable(ctx, obj, atom); if (unlikely(ret < 0)) goto exception; if (ret) goto no_with; } switch (opcode) { case OP_with_get_var: val = JS_GetProperty(ctx, obj, atom); if (unlikely(JS_IsException(val))) goto exception; set_value(ctx, &sp[-1], val); break; case OP_with_put_var: /* XXX: check if strict mode */ ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj, JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-1]); sp -= 2; if (unlikely(ret < 0)) goto exception; break; case OP_with_delete_var: ret = JS_DeleteProperty(ctx, obj, atom, 0); if (unlikely(ret < 0)) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = JS_NewBool(ctx, ret); break; case OP_with_make_ref: /* produce a pair object/propname on the stack */ *sp++ = JS_AtomToValue(ctx, atom); break; case OP_with_get_ref: /* produce a pair object/method on the stack */ val = JS_GetProperty(ctx, obj, atom); if (unlikely(JS_IsException(val))) goto exception; *sp++ = val; break; case OP_with_get_ref_undef: /* produce a pair undefined/function on the stack */ val = JS_GetProperty(ctx, obj, atom); if (unlikely(JS_IsException(val))) goto exception; JS_FreeValue(ctx, sp[-1]); sp[-1] = JS_UNDEFINED; *sp++ = val; break; } pc += diff - 5; } else { no_with: /* if not jumping, drop the object argument */ JS_FreeValue(ctx, sp[-1]); sp--; } } BREAK; CASE(OP_await): ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT); goto done_generator; CASE(OP_yield): ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD); goto done_generator; CASE(OP_yield_star): CASE(OP_async_yield_star): ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR); goto done_generator; CASE(OP_return_async): ret_val = JS_UNDEFINED; goto done_generator; CASE(OP_initial_yield): ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD); goto done_generator; CASE(OP_nop): BREAK; CASE(OP_is_undefined_or_null): if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED || JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { goto set_true; } else { goto free_and_set_false; } #if SHORT_OPCODES CASE(OP_is_undefined): if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) { goto set_true; } else { goto free_and_set_false; } CASE(OP_is_null): if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { goto set_true; } else { goto free_and_set_false; } /* XXX: could merge to a single opcode */ CASE(OP_typeof_is_undefined): /* different from OP_is_undefined because of isHTMLDDA */ if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) { goto free_and_set_true; } else { goto free_and_set_false; } CASE(OP_typeof_is_function): if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) { goto free_and_set_true; } else { goto free_and_set_false; } free_and_set_true: JS_FreeValue(ctx, sp[-1]); #endif set_true: sp[-1] = JS_TRUE; BREAK; free_and_set_false: JS_FreeValue(ctx, sp[-1]); sp[-1] = JS_FALSE; BREAK; CASE(OP_invalid): DEFAULT: JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x", (int)(pc - b->byte_code_buf - 1), opcode); goto exception; } } exception: if (JS_IsString(rt->current_exception)) { JSValue error_obj = JS_NewError(ctx); JSAtom msgProp = JS_NewAtom(ctx, "message"); JS_DefinePropertyValue(ctx, error_obj, msgProp, rt->current_exception, 0); rt->current_exception = error_obj; JS_FreeAtom(ctx, msgProp); } if (is_backtrace_needed(ctx, rt->current_exception)) { /* add the backtrace information now (it is not done before if the exception happens in a bytecode operation */ sf->cur_pc = pc; build_backtrace(ctx, rt->current_exception, NULL, 0, 0); } if (!JS_IsUncatchableError(ctx, rt->current_exception)) { while (sp > stack_buf) { JSValue val = *--sp; JS_FreeValue(ctx, val); if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) { int pos = JS_VALUE_GET_INT(val); if (pos == 0) { /* enumerator: close it with a throw */ JS_FreeValue(ctx, sp[-1]); /* drop the next method */ sp--; JS_IteratorClose(ctx, sp[-1], TRUE); } else { *sp++ = rt->current_exception; rt->current_exception = JS_NULL; pc = b->byte_code_buf + pos; goto restart; } } } } ret_val = JS_EXCEPTION; /* the local variables are freed by the caller in the generator case. Hence the label 'done' should never be reached in a generator function. */ if (b->func_kind != JS_FUNC_NORMAL) { done_generator: sf->cur_pc = pc; sf->cur_sp = sp; } else { done: if (unlikely(!list_empty(&sf->var_ref_list))) { /* variable references reference the stack: must close them */ close_var_refs(rt, sf); } /* free the local variables and stack */ for(pval = local_buf; pval < sp; pval++) { JS_FreeValue(ctx, *pval); } } rt->current_stack_frame = sf->prev_frame; if (ctx->handleFunctionExited) ctx->handleFunctionExited(ctx); return ret_val; } JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv) { return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); } static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, int argc, JSValueConst *argv) { JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); JS_FreeValue(ctx, func_obj); return res; } /* warning: the refcount of the context is not incremented. Return NULL in case of exception (case of revoked proxy only) */ static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) { JSObject *p; JSContext *realm; if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) return ctx; p = JS_VALUE_GET_OBJ(func_obj); switch(p->class_id) { case JS_CLASS_C_FUNCTION: realm = p->u.cfunc.realm; break; case JS_CLASS_BYTECODE_FUNCTION: case JS_CLASS_GENERATOR_FUNCTION: case JS_CLASS_ASYNC_FUNCTION: case JS_CLASS_ASYNC_GENERATOR_FUNCTION: { JSFunctionBytecode *b; b = p->u.func.function_bytecode; realm = b->realm; } break; case JS_CLASS_PROXY: { JSProxyData *s = p->u.opaque; if (!s) return ctx; if (s->is_revoked) { JS_ThrowTypeErrorRevokedProxy(ctx); return NULL; } else { realm = JS_GetFunctionRealm(ctx, s->target); } } break; case JS_CLASS_BOUND_FUNCTION: { JSBoundFunction *bf = p->u.bound_function; realm = JS_GetFunctionRealm(ctx, bf->func_obj); } break; default: realm = ctx; break; } return realm; } static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, int class_id) { JSValue proto, obj; JSContext *realm; if (JS_IsUndefined(ctor)) { proto = JS_DupValue(ctx, ctx->class_proto[class_id]); } else { proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); if (JS_IsException(proto)) return proto; if (!JS_IsObject(proto)) { JS_FreeValue(ctx, proto); realm = JS_GetFunctionRealm(ctx, ctor); if (!realm) return JS_EXCEPTION; proto = JS_DupValue(ctx, realm->class_proto[class_id]); } } obj = JS_NewObjectProtoClass(ctx, proto, class_id); JS_FreeValue(ctx, proto); return obj; } /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ static JSValue JS_CallConstructorInternal(JSContext *ctx, JSValueConst func_obj, JSValueConst new_target, int argc, JSValue *argv, int flags) { JSObject *p; JSFunctionBytecode *b; if (js_poll_interrupts(ctx)) return JS_EXCEPTION; flags |= JS_CALL_FLAG_CONSTRUCTOR; if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) goto not_a_function; p = JS_VALUE_GET_OBJ(func_obj); if (unlikely(!p->is_constructor)) return JS_ThrowTypeError(ctx, "not a constructor"); if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { JSClassCall *call_func; call_func = ctx->rt->class_array[p->class_id].call; if (!call_func) { not_a_function: return JS_ThrowTypeError(ctx, "not a function"); } return call_func(ctx, func_obj, new_target, argc, (JSValueConst *)argv, flags); } b = p->u.func.function_bytecode; if (b->is_derived_class_constructor) { return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags); } else { JSValue obj, ret; /* legacy constructor behavior */ obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT); if (JS_IsException(obj)) return JS_EXCEPTION; ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags); if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT || JS_IsException(ret)) { JS_FreeValue(ctx, obj); return ret; } else { JS_FreeValue(ctx, ret); return obj; } } } JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, JSValueConst new_target, int argc, JSValueConst *argv) { return JS_CallConstructorInternal(ctx, func_obj, new_target, argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); } JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, int argc, JSValueConst *argv) { return JS_CallConstructorInternal(ctx, func_obj, func_obj, argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); } JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, int argc, JSValueConst *argv) { JSValue func_obj; func_obj = JS_GetProperty(ctx, this_val, atom); if (JS_IsException(func_obj)) return func_obj; return JS_CallFree(ctx, func_obj, this_val, argc, argv); } static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, int argc, JSValueConst *argv) { JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv); JS_FreeValue(ctx, this_val); return res; } /* JSAsyncFunctionState (used by generator and async functions) */ static JSAsyncFunctionState *async_func_init(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv) { JSAsyncFunctionState *s; JSObject *p; JSFunctionBytecode *b; JSStackFrame *sf; int local_count, i, arg_buf_len, n; s = js_mallocz(ctx, sizeof(*s)); if (!s) return NULL; s->header.ref_count = 1; add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); sf = &s->frame; init_list_head(&sf->var_ref_list); p = JS_VALUE_GET_OBJ(func_obj); b = p->u.func.function_bytecode; sf->js_mode = b->js_mode | JS_MODE_ASYNC; sf->cur_pc = b->byte_code_buf; arg_buf_len = max_int(b->arg_count, argc); local_count = arg_buf_len + b->var_count + b->stack_size; sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1)); if (!sf->arg_buf) { js_free(ctx, s); return NULL; } sf->cur_func = JS_DupValue(ctx, func_obj); s->this_val = JS_DupValue(ctx, this_obj); s->argc = argc; sf->arg_count = arg_buf_len; sf->var_buf = sf->arg_buf + arg_buf_len; sf->cur_sp = sf->var_buf + b->var_count; for(i = 0; i < argc; i++) sf->arg_buf[i] = JS_DupValue(ctx, argv[i]); n = arg_buf_len + b->var_count; for(i = argc; i < n; i++) sf->arg_buf[i] = JS_UNDEFINED; s->resolving_funcs[0] = JS_UNDEFINED; s->resolving_funcs[1] = JS_UNDEFINED; s->is_completed = FALSE; return s; } static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) { JSStackFrame *sf = &s->frame; JSValue *sp; if (sf->arg_buf) { /* cannot free the function if it is running */ assert(sf->cur_sp != NULL); for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) { JS_FreeValueRT(rt, *sp); } js_free_rt(rt, sf->arg_buf); sf->arg_buf = NULL; } JS_FreeValueRT(rt, sf->cur_func); JS_FreeValueRT(rt, s->this_val); } static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) { JSRuntime *rt = ctx->rt; JSStackFrame *sf = &s->frame; JSValue func_obj, ret; assert(!s->is_completed); if (js_check_stack_overflow(ctx->rt, 0)) { ret = JS_ThrowStackOverflow(ctx); } else { /* the tag does not matter provided it is not an object */ func_obj = JS_MKPTR(JS_TAG_INT, s); ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR); } if (JS_IsException(ret) || JS_IsUndefined(ret)) { if (JS_IsUndefined(ret)) { ret = sf->cur_sp[-1]; sf->cur_sp[-1] = JS_UNDEFINED; } /* end of execution */ s->is_completed = TRUE; /* close the closure variables. */ close_var_refs(rt, sf); async_func_free_frame(rt, s); } return ret; } static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) { /* cannot close the closure variables here because it would potentially modify the object graph */ if (!s->is_completed) { async_func_free_frame(rt, s); } JS_FreeValueRT(rt, s->resolving_funcs[0]); JS_FreeValueRT(rt, s->resolving_funcs[1]); remove_gc_object(&s->header); if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) { list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list); } else { js_free_rt(rt, s); } } static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) { if (--s->header.ref_count == 0) { if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { list_del(&s->header.link); list_add(&s->header.link, &rt->gc_zero_ref_count_list); if (rt->gc_phase == JS_GC_PHASE_NONE) { free_zero_refcount(rt); } } } } /* Generators */ typedef enum JSGeneratorStateEnum { JS_GENERATOR_STATE_SUSPENDED_START, JS_GENERATOR_STATE_SUSPENDED_YIELD, JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR, JS_GENERATOR_STATE_EXECUTING, JS_GENERATOR_STATE_COMPLETED, } JSGeneratorStateEnum; typedef struct JSGeneratorData { JSGeneratorStateEnum state; JSAsyncFunctionState *func_state; } JSGeneratorData; static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s) { if (s->state == JS_GENERATOR_STATE_COMPLETED) return; if (s->func_state) { async_func_free(rt, s->func_state); s->func_state = NULL; } s->state = JS_GENERATOR_STATE_COMPLETED; } static void js_generator_finalizer(JSRuntime *rt, JSValue obj) { JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR); if (s) { free_generator_stack_rt(rt, s); js_free_rt(rt, s); } } static void free_generator_stack(JSContext *ctx, JSGeneratorData *s) { free_generator_stack_rt(ctx->rt, s); } static void js_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSGeneratorData *s = p->u.generator_data; if (!s || !s->func_state) return; mark_func(rt, &s->func_state->header); } /* XXX: use enum */ #define GEN_MAGIC_NEXT 0 #define GEN_MAGIC_RETURN 1 #define GEN_MAGIC_THROW 2 static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, BOOL *pdone, int magic) { JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR); JSStackFrame *sf; JSValue ret, func_ret; *pdone = TRUE; if (!s) return JS_ThrowTypeError(ctx, "not a generator"); switch(s->state) { default: case JS_GENERATOR_STATE_SUSPENDED_START: sf = &s->func_state->frame; if (magic == GEN_MAGIC_NEXT) { goto exec_no_arg; } else { free_generator_stack(ctx, s); goto done; } break; case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR: case JS_GENERATOR_STATE_SUSPENDED_YIELD: sf = &s->func_state->frame; /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */ ret = JS_DupValue(ctx, argv[0]); if (magic == GEN_MAGIC_THROW && s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, ret); s->func_state->throw_flag = TRUE; } else { sf->cur_sp[-1] = ret; sf->cur_sp[0] = JS_NewInt32(ctx, magic); sf->cur_sp++; exec_no_arg: s->func_state->throw_flag = FALSE; } s->state = JS_GENERATOR_STATE_EXECUTING; func_ret = async_func_resume(ctx, s->func_state); s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; if (s->func_state->is_completed) { /* finalize the execution in case of exception or normal return */ free_generator_stack(ctx, s); return func_ret; } else { assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); /* get the returned yield value at the top of the stack */ ret = sf->cur_sp[-1]; sf->cur_sp[-1] = JS_UNDEFINED; if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) { s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR; /* return (value, done) object */ *pdone = 2; } else { *pdone = FALSE; } } break; case JS_GENERATOR_STATE_COMPLETED: done: /* execution is finished */ switch(magic) { default: case GEN_MAGIC_NEXT: ret = JS_UNDEFINED; break; case GEN_MAGIC_RETURN: ret = JS_DupValue(ctx, argv[0]); break; case GEN_MAGIC_THROW: ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0])); break; } break; case JS_GENERATOR_STATE_EXECUTING: ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator"); break; } return ret; } static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags) { JSValue obj, func_ret; JSGeneratorData *s; s = js_mallocz(ctx, sizeof(*s)); if (!s) return JS_EXCEPTION; s->state = JS_GENERATOR_STATE_SUSPENDED_START; s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); if (!s->func_state) { s->state = JS_GENERATOR_STATE_COMPLETED; goto fail; } /* execute the function up to 'OP_initial_yield' */ func_ret = async_func_resume(ctx, s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR); if (JS_IsException(obj)) goto fail; JS_SetOpaque(obj, s); return obj; fail: free_generator_stack_rt(ctx->rt, s); js_free(ctx, s); return JS_EXCEPTION; } /* AsyncFunction */ static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSAsyncFunctionState *s = p->u.async_function_data; if (s) { async_func_free(rt, s); } } static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); JSAsyncFunctionState *s = p->u.async_function_data; if (s) { mark_func(rt, &s->header); } } static int js_async_function_resolve_create(JSContext *ctx, JSAsyncFunctionState *s, JSValue *resolving_funcs) { int i; JSObject *p; for(i = 0; i < 2; i++) { resolving_funcs[i] = JS_NewObjectProtoClass(ctx, ctx->function_proto, JS_CLASS_ASYNC_FUNCTION_RESOLVE + i); if (JS_IsException(resolving_funcs[i])) { if (i == 1) JS_FreeValue(ctx, resolving_funcs[0]); return -1; } p = JS_VALUE_GET_OBJ(resolving_funcs[i]); s->header.ref_count++; p->u.async_function_data = s; } return 0; } static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s) { JSValue func_ret, ret2; func_ret = async_func_resume(ctx, s); if (s->is_completed) { if (JS_IsException(func_ret)) { JSValue error; fail: error = JS_GetException(ctx); ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, 1, (JSValueConst *)&error); JS_FreeValue(ctx, error); JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ } else { /* normal return */ ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, 1, (JSValueConst *)&func_ret); JS_FreeValue(ctx, func_ret); JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ } } else { JSValue value, promise, resolving_funcs[2], resolving_funcs1[2]; int i, res; value = s->frame.cur_sp[-1]; s->frame.cur_sp[-1] = JS_UNDEFINED; /* await */ JS_FreeValue(ctx, func_ret); /* not used */ promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&value, 0); JS_FreeValue(ctx, value); if (JS_IsException(promise)) goto fail; if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { JS_FreeValue(ctx, promise); goto fail; } /* Note: no need to create 'thrownawayCapability' as in the spec */ for(i = 0; i < 2; i++) resolving_funcs1[i] = JS_UNDEFINED; res = perform_promise_then(ctx, promise, (JSValueConst *)resolving_funcs, (JSValueConst *)resolving_funcs1); JS_FreeValue(ctx, promise); for(i = 0; i < 2; i++) JS_FreeValue(ctx, resolving_funcs[i]); if (res) goto fail; } } static JSValue js_async_function_resolve_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags) { JSObject *p = JS_VALUE_GET_OBJ(func_obj); JSAsyncFunctionState *s = p->u.async_function_data; BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; JSValueConst arg; if (argc > 0) arg = argv[0]; else arg = JS_UNDEFINED; s->throw_flag = is_reject; if (is_reject) { JS_Throw(ctx, JS_DupValue(ctx, arg)); } else { /* return value of await */ s->frame.cur_sp[-1] = JS_DupValue(ctx, arg); } js_async_function_resume(ctx, s); return JS_UNDEFINED; } static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags) { JSValue promise; JSAsyncFunctionState *s; s = async_func_init(ctx, func_obj, this_obj, argc, argv); if (!s) return JS_EXCEPTION; promise = JS_NewPromiseCapability(ctx, s->resolving_funcs); if (JS_IsException(promise)) { async_func_free(ctx->rt, s); return JS_EXCEPTION; } js_async_function_resume(ctx, s); async_func_free(ctx->rt, s); return promise; } /* AsyncGenerator */ typedef enum JSAsyncGeneratorStateEnum { JS_ASYNC_GENERATOR_STATE_SUSPENDED_START, JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD, JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR, JS_ASYNC_GENERATOR_STATE_EXECUTING, JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN, JS_ASYNC_GENERATOR_STATE_COMPLETED, } JSAsyncGeneratorStateEnum; typedef struct JSAsyncGeneratorRequest { struct list_head link; /* completion */ int completion_type; /* GEN_MAGIC_x */ JSValue result; /* promise capability */ JSValue promise; JSValue resolving_funcs[2]; } JSAsyncGeneratorRequest; typedef struct JSAsyncGeneratorData { JSObject *generator; /* back pointer to the object (const) */ JSAsyncGeneratorStateEnum state; /* func_state is NULL is state AWAITING_RETURN and COMPLETED */ JSAsyncFunctionState *func_state; struct list_head queue; /* list of JSAsyncGeneratorRequest.link */ } JSAsyncGeneratorData; static void js_async_generator_free(JSRuntime *rt, JSAsyncGeneratorData *s) { struct list_head *el, *el1; JSAsyncGeneratorRequest *req; list_for_each_safe(el, el1, &s->queue) { req = list_entry(el, JSAsyncGeneratorRequest, link); JS_FreeValueRT(rt, req->result); JS_FreeValueRT(rt, req->promise); JS_FreeValueRT(rt, req->resolving_funcs[0]); JS_FreeValueRT(rt, req->resolving_funcs[1]); js_free_rt(rt, req); } if (s->func_state) async_func_free(rt, s->func_state); js_free_rt(rt, s); } static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj) { JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR); if (s) { js_async_generator_free(rt, s); } } static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR); struct list_head *el; JSAsyncGeneratorRequest *req; if (s) { list_for_each(el, &s->queue) { req = list_entry(el, JSAsyncGeneratorRequest, link); JS_MarkValue(rt, req->result, mark_func); JS_MarkValue(rt, req->promise, mark_func); JS_MarkValue(rt, req->resolving_funcs[0], mark_func); JS_MarkValue(rt, req->resolving_funcs[1], mark_func); } if (s->func_state) { mark_func(rt, &s->func_state->header); } } } static JSValue js_async_generator_resolve_function(JSContext *ctx, JSValueConst this_obj, int argc, JSValueConst *argv, int magic, JSValue *func_data); static int js_async_generator_resolve_function_create(JSContext *ctx, JSValueConst generator, JSValue *resolving_funcs, BOOL is_resume_next) { int i; JSValue func; for(i = 0; i < 2; i++) { func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1, i + is_resume_next * 2, 1, &generator); if (JS_IsException(func)) { if (i == 1) JS_FreeValue(ctx, resolving_funcs[0]); return -1; } resolving_funcs[i] = func; } return 0; } static int js_async_generator_await(JSContext *ctx, JSAsyncGeneratorData *s, JSValueConst value) { JSValue promise, resolving_funcs[2], resolving_funcs1[2]; int i, res; promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value, 0); if (JS_IsException(promise)) goto fail; if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), resolving_funcs, FALSE)) { JS_FreeValue(ctx, promise); goto fail; } /* Note: no need to create 'thrownawayCapability' as in the spec */ for(i = 0; i < 2; i++) resolving_funcs1[i] = JS_UNDEFINED; res = perform_promise_then(ctx, promise, (JSValueConst *)resolving_funcs, (JSValueConst *)resolving_funcs1); JS_FreeValue(ctx, promise); for(i = 0; i < 2; i++) JS_FreeValue(ctx, resolving_funcs[i]); if (res) goto fail; return 0; fail: return -1; } static void js_async_generator_resolve_or_reject(JSContext *ctx, JSAsyncGeneratorData *s, JSValueConst result, int is_reject) { JSAsyncGeneratorRequest *next; JSValue ret; next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link); list_del(&next->link); ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1, &result); JS_FreeValue(ctx, ret); JS_FreeValue(ctx, next->result); JS_FreeValue(ctx, next->promise); JS_FreeValue(ctx, next->resolving_funcs[0]); JS_FreeValue(ctx, next->resolving_funcs[1]); js_free(ctx, next); } static void js_async_generator_resolve(JSContext *ctx, JSAsyncGeneratorData *s, JSValueConst value, BOOL done) { JSValue result; result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done); /* XXX: better exception handling ? */ js_async_generator_resolve_or_reject(ctx, s, result, 0); JS_FreeValue(ctx, result); } static void js_async_generator_reject(JSContext *ctx, JSAsyncGeneratorData *s, JSValueConst exception) { js_async_generator_resolve_or_reject(ctx, s, exception, 1); } static void js_async_generator_complete(JSContext *ctx, JSAsyncGeneratorData *s) { if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) { s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; async_func_free(ctx->rt, s->func_state); s->func_state = NULL; } } static int js_async_generator_completed_return(JSContext *ctx, JSAsyncGeneratorData *s, JSValueConst value) { JSValue promise, resolving_funcs[2], resolving_funcs1[2]; int res; // Can fail looking up JS_ATOM_constructor when is_reject==0. promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value, /*is_reject*/0); // A poisoned .constructor property is observable and the resulting // exception should be delivered to the catch handler. if (JS_IsException(promise)) { JSValue err = JS_GetException(ctx); promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err, /*is_reject*/1); JS_FreeValue(ctx, err); if (JS_IsException(promise)) return -1; } if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), resolving_funcs1, TRUE)) { JS_FreeValue(ctx, promise); return -1; } resolving_funcs[0] = JS_UNDEFINED; resolving_funcs[1] = JS_UNDEFINED; res = perform_promise_then(ctx, promise, (JSValueConst *)resolving_funcs1, (JSValueConst *)resolving_funcs); JS_FreeValue(ctx, resolving_funcs1[0]); JS_FreeValue(ctx, resolving_funcs1[1]); JS_FreeValue(ctx, promise); return res; } static void js_async_generator_resume_next(JSContext *ctx, JSAsyncGeneratorData *s) { JSAsyncGeneratorRequest *next; JSValue func_ret, value; for(;;) { if (list_empty(&s->queue)) break; next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link); switch(s->state) { case JS_ASYNC_GENERATOR_STATE_EXECUTING: /* only happens when restarting execution after await() */ goto resume_exec; case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN: goto done; case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START: if (next->completion_type == GEN_MAGIC_NEXT) { goto exec_no_arg; } else { js_async_generator_complete(ctx, s); } break; case JS_ASYNC_GENERATOR_STATE_COMPLETED: if (next->completion_type == GEN_MAGIC_NEXT) { js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE); } else if (next->completion_type == GEN_MAGIC_RETURN) { s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN; js_async_generator_completed_return(ctx, s, next->result); } else { js_async_generator_reject(ctx, s, next->result); } goto done; case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD: case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR: value = JS_DupValue(ctx, next->result); if (next->completion_type == GEN_MAGIC_THROW && s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, value); s->func_state->throw_flag = TRUE; } else { /* 'yield' returns a value. 'yield *' also returns a value in case the 'throw' method is called */ s->func_state->frame.cur_sp[-1] = value; s->func_state->frame.cur_sp[0] = JS_NewInt32(ctx, next->completion_type); s->func_state->frame.cur_sp++; exec_no_arg: s->func_state->throw_flag = FALSE; } s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING; resume_exec: func_ret = async_func_resume(ctx, s->func_state); if (s->func_state->is_completed) { if (JS_IsException(func_ret)) { value = JS_GetException(ctx); js_async_generator_complete(ctx, s); js_async_generator_reject(ctx, s, value); JS_FreeValue(ctx, value); } else { /* end of function */ js_async_generator_complete(ctx, s); js_async_generator_resolve(ctx, s, func_ret, TRUE); JS_FreeValue(ctx, func_ret); } } else { int func_ret_code, ret; assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); func_ret_code = JS_VALUE_GET_INT(func_ret); value = s->func_state->frame.cur_sp[-1]; s->func_state->frame.cur_sp[-1] = JS_UNDEFINED; switch(func_ret_code) { case FUNC_RET_YIELD: case FUNC_RET_YIELD_STAR: if (func_ret_code == FUNC_RET_YIELD_STAR) s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR; else s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD; js_async_generator_resolve(ctx, s, value, FALSE); JS_FreeValue(ctx, value); break; case FUNC_RET_AWAIT: ret = js_async_generator_await(ctx, s, value); JS_FreeValue(ctx, value); if (ret < 0) { /* exception: throw it */ s->func_state->throw_flag = TRUE; goto resume_exec; } goto done; default: abort(); } } break; default: abort(); } } done: ; } static JSValue js_async_generator_resolve_function(JSContext *ctx, JSValueConst this_obj, int argc, JSValueConst *argv, int magic, JSValue *func_data) { BOOL is_reject = magic & 1; JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR); JSValueConst arg = argv[0]; /* XXX: what if s == NULL */ if (magic >= 2) { /* resume next case in AWAITING_RETURN state */ assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN || s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED); s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; if (is_reject) { js_async_generator_reject(ctx, s, arg); } else { js_async_generator_resolve(ctx, s, arg, TRUE); } } else { /* restart function execution after await() */ assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING); s->func_state->throw_flag = is_reject; if (is_reject) { JS_Throw(ctx, JS_DupValue(ctx, arg)); } else { /* return value of await */ s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg); } js_async_generator_resume_next(ctx, s); } return JS_UNDEFINED; } /* magic = GEN_MAGIC_x */ static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR); JSValue promise, resolving_funcs[2]; JSAsyncGeneratorRequest *req; promise = JS_NewPromiseCapability(ctx, resolving_funcs); if (JS_IsException(promise)) return JS_EXCEPTION; if (!s) { JSValue err, res2; JS_ThrowTypeError(ctx, "not an AsyncGenerator object"); err = JS_GetException(ctx); res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, (JSValueConst *)&err); JS_FreeValue(ctx, err); JS_FreeValue(ctx, res2); JS_FreeValue(ctx, resolving_funcs[0]); JS_FreeValue(ctx, resolving_funcs[1]); return promise; } req = js_mallocz(ctx, sizeof(*req)); if (!req) goto fail; req->completion_type = magic; req->result = JS_DupValue(ctx, argv[0]); req->promise = JS_DupValue(ctx, promise); req->resolving_funcs[0] = resolving_funcs[0]; req->resolving_funcs[1] = resolving_funcs[1]; list_add_tail(&req->link, &s->queue); if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) { js_async_generator_resume_next(ctx, s); } return promise; fail: JS_FreeValue(ctx, resolving_funcs[0]); JS_FreeValue(ctx, resolving_funcs[1]); JS_FreeValue(ctx, promise); return JS_EXCEPTION; } static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags) { JSValue obj, func_ret; JSAsyncGeneratorData *s; s = js_mallocz(ctx, sizeof(*s)); if (!s) return JS_EXCEPTION; s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START; init_list_head(&s->queue); s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); if (!s->func_state) goto fail; /* execute the function up to 'OP_initial_yield' (no yield nor await are possible) */ func_ret = async_func_resume(ctx, s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR); if (JS_IsException(obj)) goto fail; s->generator = JS_VALUE_GET_OBJ(obj); JS_SetOpaque(obj, s); return obj; fail: js_async_generator_free(ctx->rt, s); return JS_EXCEPTION; } /* JS parser */ enum { TOK_NUMBER = -128, TOK_STRING, TOK_TEMPLATE, TOK_IDENT, TOK_REGEXP, /* warning: order matters (see js_parse_assign_expr) */ TOK_MUL_ASSIGN, TOK_DIV_ASSIGN, TOK_MOD_ASSIGN, TOK_PLUS_ASSIGN, TOK_MINUS_ASSIGN, TOK_SHL_ASSIGN, TOK_SAR_ASSIGN, TOK_SHR_ASSIGN, TOK_AND_ASSIGN, TOK_XOR_ASSIGN, TOK_OR_ASSIGN, #ifdef CONFIG_BIGNUM TOK_MATH_POW_ASSIGN, #endif TOK_POW_ASSIGN, TOK_LAND_ASSIGN, TOK_LOR_ASSIGN, TOK_DOUBLE_QUESTION_MARK_ASSIGN, TOK_DEC, TOK_INC, TOK_SHL, TOK_SAR, TOK_SHR, TOK_LT, TOK_LTE, TOK_GT, TOK_GTE, TOK_EQ, TOK_STRICT_EQ, TOK_NEQ, TOK_STRICT_NEQ, TOK_LAND, TOK_LOR, #ifdef CONFIG_BIGNUM TOK_MATH_POW, #endif TOK_POW, TOK_ARROW, TOK_ELLIPSIS, TOK_DOUBLE_QUESTION_MARK, TOK_QUESTION_MARK_DOT, TOK_ERROR, TOK_PRIVATE_NAME, TOK_EOF, /* keywords: WARNING: same order as atoms */ TOK_NULL, /* must be first */ TOK_FALSE, TOK_TRUE, TOK_IF, TOK_ELSE, TOK_RETURN, TOK_VAR, TOK_THIS, TOK_DELETE, TOK_VOID, TOK_TYPEOF, TOK_NEW, TOK_IN, TOK_INSTANCEOF, TOK_DO, TOK_WHILE, TOK_FOR, TOK_BREAK, TOK_CONTINUE, TOK_SWITCH, TOK_CASE, TOK_DEFAULT, TOK_THROW, TOK_TRY, TOK_CATCH, TOK_FINALLY, TOK_FUNCTION, TOK_DEBUGGER, TOK_WITH, /* FutureReservedWord */ TOK_CLASS, TOK_CONST, TOK_ENUM, TOK_EXPORT, TOK_EXTENDS, TOK_IMPORT, TOK_SUPER, /* FutureReservedWords when parsing strict mode code */ TOK_IMPLEMENTS, TOK_INTERFACE, TOK_LET, TOK_PACKAGE, TOK_PRIVATE, TOK_PROTECTED, TOK_PUBLIC, TOK_STATIC, TOK_YIELD, TOK_AWAIT, /* must be last */ TOK_OF, /* only used for js_parse_skip_parens_token() */ }; #define TOK_FIRST_KEYWORD TOK_NULL #define TOK_LAST_KEYWORD TOK_AWAIT /* unicode code points */ #define CP_NBSP 0x00a0 #define CP_BOM 0xfeff #define CP_LS 0x2028 #define CP_PS 0x2029 typedef struct BlockEnv { struct BlockEnv *prev; JSAtom label_name; /* JS_ATOM_NULL if none */ int label_break; /* -1 if none */ int label_cont; /* -1 if none */ int drop_count; /* number of stack elements to drop */ int label_finally; /* -1 if none */ int scope_level; int has_iterator; } BlockEnv; typedef struct JSGlobalVar { int cpool_idx; /* if >= 0, index in the constant pool for hoisted function defintion*/ uint8_t force_init : 1; /* force initialization to undefined */ uint8_t is_lexical : 1; /* global let/const definition */ uint8_t is_const : 1; /* const definition */ int scope_level; /* scope of definition */ JSAtom var_name; /* variable name */ } JSGlobalVar; typedef struct RelocEntry { struct RelocEntry *next; uint32_t addr; /* address to patch */ int size; /* address size: 1, 2 or 4 bytes */ } RelocEntry; typedef struct JumpSlot { int op; int size; int pos; int label; } JumpSlot; typedef struct LabelSlot { int ref_count; int pos; /* phase 1 address, -1 means not resolved yet */ int pos2; /* phase 2 address, -1 means not resolved yet */ int addr; /* phase 3 address, -1 means not resolved yet */ RelocEntry *first_reloc; } LabelSlot; typedef struct LineNumberSlot { uint32_t pc; int line_num; } LineNumberSlot; typedef enum JSParseFunctionEnum { JS_PARSE_FUNC_STATEMENT, JS_PARSE_FUNC_VAR, JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW, JS_PARSE_FUNC_GETTER, JS_PARSE_FUNC_SETTER, JS_PARSE_FUNC_METHOD, JS_PARSE_FUNC_CLASS_STATIC_INIT, JS_PARSE_FUNC_CLASS_CONSTRUCTOR, JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR, } JSParseFunctionEnum; typedef enum JSParseExportEnum { JS_PARSE_EXPORT_NONE, JS_PARSE_EXPORT_NAMED, JS_PARSE_EXPORT_DEFAULT, } JSParseExportEnum; typedef struct JSFunctionDef { JSContext *ctx; struct JSFunctionDef *parent; int parent_cpool_idx; /* index in the constant pool of the parent or -1 if none */ int parent_scope_level; /* scope level in parent at point of definition */ struct list_head child_list; /* list of JSFunctionDef.link */ struct list_head link; BOOL is_eval; /* TRUE if eval code */ int eval_type; /* only valid if is_eval = TRUE */ BOOL is_global_var; /* TRUE if variables are not defined locally: eval global, eval module or non strict eval */ BOOL is_func_expr; /* TRUE if function expression */ BOOL has_home_object; /* TRUE if the home object is available */ BOOL has_prototype; /* true if a prototype field is necessary */ BOOL has_simple_parameter_list; BOOL has_parameter_expressions; /* if true, an argument scope is created */ BOOL has_use_strict; /* to reject directive in special cases */ BOOL has_eval_call; /* true if the function contains a call to eval() */ BOOL has_arguments_binding; /* true if the 'arguments' binding is available in the function */ BOOL has_this_binding; /* true if the 'this' and new.target binding are available in the function */ BOOL new_target_allowed; /* true if the 'new.target' does not throw a syntax error */ BOOL super_call_allowed; /* true if super() is allowed */ BOOL super_allowed; /* true if super. or super[] is allowed */ BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */ BOOL is_derived_class_constructor; BOOL in_function_body; BOOL backtrace_barrier; JSFunctionKindEnum func_kind : 8; JSParseFunctionEnum func_type : 8; uint8_t js_mode; /* bitmap of JS_MODE_x */ JSAtom func_name; /* JS_ATOM_NULL if no name */ JSVarDef *vars; int var_size; /* allocated size for vars[] */ int var_count; JSVarDef *args; int arg_size; /* allocated size for args[] */ int arg_count; /* number of arguments */ int defined_arg_count; int var_object_idx; /* -1 if none */ int arg_var_object_idx; /* -1 if none (var object for the argument scope) */ int arguments_var_idx; /* -1 if none */ int arguments_arg_idx; /* argument variable definition in argument scope, -1 if none */ int func_var_idx; /* variable containing the current function (-1 if none, only used if is_func_expr is true) */ int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */ int this_var_idx; /* variable containg the 'this' value, -1 if none */ int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */ int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ int home_object_var_idx; BOOL need_home_object; int scope_level; /* index into fd->scopes if the current lexical scope */ int scope_first; /* index into vd->vars of first lexically scoped variable */ int scope_size; /* allocated size of fd->scopes array */ int scope_count; /* number of entries used in the fd->scopes array */ JSVarScope *scopes; JSVarScope def_scope_array[4]; int body_scope; /* scope of the body of the function or eval */ int global_var_count; int global_var_size; JSGlobalVar *global_vars; DynBuf byte_code; int last_opcode_pos; /* -1 if no last opcode */ int last_opcode_line_num; BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */ LabelSlot *label_slots; int label_size; /* allocated size for label_slots[] */ int label_count; BlockEnv *top_break; /* break/continue label stack */ /* constant pool (strings, functions, numbers) */ JSValue *cpool; int cpool_count; int cpool_size; /* list of variables in the closure */ int closure_var_count; int closure_var_size; JSClosureVar *closure_var; JumpSlot *jump_slots; int jump_size; int jump_count; LineNumberSlot *line_number_slots; int line_number_size; int line_number_count; int line_number_last; int line_number_last_pc; /* pc2line table */ JSAtom filename; int line_num; DynBuf pc2line; char *source; /* raw source, utf-8 encoded */ int source_len; JSModuleDef *module; /* != NULL when parsing a module */ BOOL has_await; /* TRUE if await is used (used in module eval) */ } JSFunctionDef; typedef struct JSToken { int val; int line_num; /* line number of token start */ const uint8_t *ptr; union { struct { JSValue str; int sep; } str; struct { JSValue val; #ifdef CONFIG_BIGNUM slimb_t exponent; /* may be != 0 only if val is a float */ #endif } num; struct { JSAtom atom; BOOL has_escape; BOOL is_reserved; } ident; struct { JSValue body; JSValue flags; } regexp; } u; } JSToken; typedef struct JSParseState { JSContext *ctx; int last_line_num; /* line number of last token */ int line_num; /* line number of current offset */ const char *filename; JSToken token; BOOL got_lf; /* true if got line feed before the current token */ const uint8_t *last_ptr; const uint8_t *buf_ptr; const uint8_t *buf_end; /* current function code */ JSFunctionDef *cur_func; BOOL is_module; /* parsing a module */ BOOL allow_html_comments; BOOL ext_json; /* true if accepting JSON superset */ } JSParseState; typedef struct JSOpCode { #ifdef DUMP_BYTECODE const char *name; #endif uint8_t size; /* in bytes */ /* the opcodes remove n_pop items from the top of the stack, then pushes n_push items */ uint8_t n_pop; uint8_t n_push; uint8_t fmt; } JSOpCode; static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = { #define FMT(f) #ifdef DUMP_BYTECODE #define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f }, #else #define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f }, #endif #include "quickjs-opcode.h" #undef DEF #undef FMT }; #if SHORT_OPCODES /* After the final compilation pass, short opcodes are used. Their opcodes overlap with the temporary opcodes which cannot appear in the final bytecode. Their description is after the temporary opcodes in opcode_info[]. */ #define short_opcode_info(op) \ opcode_info[(op) >= OP_TEMP_START ? \ (op) + (OP_TEMP_END - OP_TEMP_START) : (op)] #else #define short_opcode_info(op) opcode_info[op] #endif static __exception int next_token(JSParseState *s); static void free_token(JSParseState *s, JSToken *token) { switch(token->val) { case TOK_NUMBER: JS_FreeValue(s->ctx, token->u.num.val); break; case TOK_STRING: case TOK_TEMPLATE: JS_FreeValue(s->ctx, token->u.str.str); break; case TOK_REGEXP: JS_FreeValue(s->ctx, token->u.regexp.body); JS_FreeValue(s->ctx, token->u.regexp.flags); break; case TOK_IDENT: case TOK_PRIVATE_NAME: JS_FreeAtom(s->ctx, token->u.ident.atom); break; default: if (token->val >= TOK_FIRST_KEYWORD && token->val <= TOK_LAST_KEYWORD) { JS_FreeAtom(s->ctx, token->u.ident.atom); } break; } } static void __maybe_unused dump_token(JSParseState *s, const JSToken *token) { switch(token->val) { case TOK_NUMBER: { double d; JS_ToFloat64(s->ctx, &d, token->u.num.val); /* no exception possible */ printf("number: %.14g\n", d); } break; case TOK_IDENT: dump_atom: { char buf[ATOM_GET_STR_BUF_SIZE]; printf("ident: '%s'\n", JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom)); } break; case TOK_STRING: { const char *str; /* XXX: quote the string */ str = JS_ToCString(s->ctx, token->u.str.str); printf("string: '%s'\n", str); JS_FreeCString(s->ctx, str); } break; case TOK_TEMPLATE: { const char *str; str = JS_ToCString(s->ctx, token->u.str.str); printf("template: `%s`\n", str); JS_FreeCString(s->ctx, str); } break; case TOK_REGEXP: { const char *str, *str2; str = JS_ToCString(s->ctx, token->u.regexp.body); str2 = JS_ToCString(s->ctx, token->u.regexp.flags); printf("regexp: '%s' '%s'\n", str, str2); JS_FreeCString(s->ctx, str); JS_FreeCString(s->ctx, str2); } break; case TOK_EOF: printf("eof\n"); break; default: if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) { goto dump_atom; } else if (s->token.val >= 256) { printf("token: %d\n", token->val); } else { printf("token: '%c'\n", token->val); } break; } } int FORMAT_ATTR(2, 3) js_parse_error(JSParseState *s, const char *fmt, ...) { JSContext *ctx = s->ctx; va_list ap; int backtrace_flags; va_start(ap, fmt); JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE); va_end(ap); backtrace_flags = 0; if (s->cur_func && s->cur_func->backtrace_barrier) backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL; build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num, backtrace_flags); return -1; } static int js_parse_expect(JSParseState *s, int tok) { if (s->token.val != tok) { /* XXX: dump token correctly in all cases */ return js_parse_error(s, "expecting '%c'", tok); } return next_token(s); } static int js_parse_expect_semi(JSParseState *s) { if (s->token.val != ';') { /* automatic insertion of ';' */ if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) { return 0; } return js_parse_error(s, "expecting '%c'", ';'); } return next_token(s); } static int js_parse_error_reserved_identifier(JSParseState *s) { char buf1[ATOM_GET_STR_BUF_SIZE]; return js_parse_error(s, "'%s' is a reserved identifier", JS_AtomGetStr(s->ctx, buf1, sizeof(buf1), s->token.u.ident.atom)); } static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p) { uint32_t c; StringBuffer b_s, *b = &b_s; /* p points to the first byte of the template part */ if (string_buffer_init(s->ctx, b, 32)) goto fail; for(;;) { if (p >= s->buf_end) goto unexpected_eof; c = *p++; if (c == '`') { /* template end part */ break; } if (c == '$' && *p == '{') { /* template start or middle part */ p++; break; } if (c == '\\') { if (string_buffer_putc8(b, c)) goto fail; if (p >= s->buf_end) goto unexpected_eof; c = *p++; } /* newline sequences are normalized as single '\n' bytes */ if (c == '\r') { if (*p == '\n') p++; c = '\n'; } if (c == '\n') { s->line_num++; } else if (c >= 0x80) { const uint8_t *p_next; c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { js_parse_error(s, "invalid UTF-8 sequence"); goto fail; } p = p_next; } if (string_buffer_putc(b, c)) goto fail; } s->token.val = TOK_TEMPLATE; s->token.u.str.sep = c; s->token.u.str.str = string_buffer_end(b); s->buf_ptr = p; return 0; unexpected_eof: js_parse_error(s, "unexpected end of string"); fail: string_buffer_free(b); return -1; } static __exception int js_parse_string(JSParseState *s, int sep, BOOL do_throw, const uint8_t *p, JSToken *token, const uint8_t **pp) { int ret; uint32_t c; StringBuffer b_s, *b = &b_s; /* string */ if (string_buffer_init(s->ctx, b, 32)) goto fail; for(;;) { if (p >= s->buf_end) goto invalid_char; c = *p; if (c < 0x20) { if (!s->cur_func) { if (do_throw) js_parse_error(s, "invalid character in a JSON string"); goto fail; } if (sep == '`') { if (c == '\r') { if (p[1] == '\n') p++; c = '\n'; } /* do not update s->line_num */ } else if (c == '\n' || c == '\r') goto invalid_char; } p++; if (c == sep) break; if (c == '$' && *p == '{' && sep == '`') { /* template start or middle part */ p++; break; } if (c == '\\') { c = *p; /* XXX: need a specific JSON case to avoid accepting invalid escapes */ switch(c) { case '\0': if (p >= s->buf_end) goto invalid_char; p++; break; case '\'': case '\"': case '\\': p++; break; case '\r': /* accept DOS and MAC newline sequences */ if (p[1] == '\n') { p++; } /* fall thru */ case '\n': /* ignore escaped newline sequence */ p++; if (sep != '`') s->line_num++; continue; default: if (c >= '0' && c <= '9') { if (!s->cur_func) goto invalid_escape; /* JSON case */ if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`') goto parse_escape; if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { p++; c = '\0'; } else { if (c >= '8' || sep == '`') { /* Note: according to ES2021, \8 and \9 are not accepted in strict mode or in templates. */ goto invalid_escape; } else { if (do_throw) js_parse_error(s, "octal escape sequences are not allowed in strict mode"); } goto fail; } } else if (c >= 0x80) { const uint8_t *p_next; c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { goto invalid_utf8; } p = p_next; /* LS or PS are skipped */ if (c == CP_LS || c == CP_PS) continue; } else { parse_escape: ret = lre_parse_escape(&p, TRUE); if (ret == -1) { invalid_escape: if (do_throw) js_parse_error(s, "malformed escape sequence in string literal"); goto fail; } else if (ret < 0) { /* ignore the '\' (could output a warning) */ p++; } else { c = ret; } } break; } } else if (c >= 0x80) { const uint8_t *p_next; c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) goto invalid_utf8; p = p_next; } if (string_buffer_putc(b, c)) goto fail; } token->val = TOK_STRING; token->u.str.sep = c; token->u.str.str = string_buffer_end(b); *pp = p; return 0; invalid_utf8: if (do_throw) js_parse_error(s, "invalid UTF-8 sequence"); goto fail; invalid_char: if (do_throw) js_parse_error(s, "unexpected end of string"); fail: string_buffer_free(b); return -1; } static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) { return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom && !s->token.u.ident.has_escape; } static __exception int js_parse_regexp(JSParseState *s) { const uint8_t *p; BOOL in_class; StringBuffer b_s, *b = &b_s; StringBuffer b2_s, *b2 = &b2_s; uint32_t c; p = s->buf_ptr; p++; in_class = FALSE; if (string_buffer_init(s->ctx, b, 32)) return -1; if (string_buffer_init(s->ctx, b2, 1)) goto fail; for(;;) { if (p >= s->buf_end) { eof_error: js_parse_error(s, "unexpected end of regexp"); goto fail; } c = *p++; if (c == '\n' || c == '\r') { goto eol_error; } else if (c == '/') { if (!in_class) break; } else if (c == '[') { in_class = TRUE; } else if (c == ']') { /* XXX: incorrect as the first character in a class */ in_class = FALSE; } else if (c == '\\') { if (string_buffer_putc8(b, c)) goto fail; c = *p++; if (c == '\n' || c == '\r') goto eol_error; else if (c == '\0' && p >= s->buf_end) goto eof_error; else if (c >= 0x80) { const uint8_t *p_next; c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { goto invalid_utf8; } p = p_next; if (c == CP_LS || c == CP_PS) goto eol_error; } } else if (c >= 0x80) { const uint8_t *p_next; c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { invalid_utf8: js_parse_error(s, "invalid UTF-8 sequence"); goto fail; } p = p_next; /* LS or PS are considered as line terminator */ if (c == CP_LS || c == CP_PS) { eol_error: js_parse_error(s, "unexpected line terminator in regexp"); goto fail; } } if (string_buffer_putc(b, c)) goto fail; } /* flags */ for(;;) { const uint8_t *p_next = p; c = *p_next++; if (c >= 0x80) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); if (c > 0x10FFFF) { goto invalid_utf8; } } if (!lre_js_is_ident_next(c)) break; if (string_buffer_putc(b2, c)) goto fail; p = p_next; } s->token.val = TOK_REGEXP; s->token.u.regexp.body = string_buffer_end(b); s->token.u.regexp.flags = string_buffer_end(b2); s->buf_ptr = p; return 0; fail: string_buffer_free(b); string_buffer_free(b2); return -1; } static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, const char *static_buf) { char *buf, *new_buf; size_t size, new_size; buf = *pbuf; size = *psize; if (size >= (SIZE_MAX / 3) * 2) new_size = SIZE_MAX; else new_size = size + (size >> 1); if (buf == static_buf) { new_buf = js_malloc(ctx, new_size); if (!new_buf) return -1; memcpy(new_buf, buf, size); } else { new_buf = js_realloc(ctx, buf, new_size); if (!new_buf) return -1; } *pbuf = new_buf; *psize = new_size; return 0; } /* convert a TOK_IDENT to a keyword when needed */ static void update_token_ident(JSParseState *s) { if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && (s->cur_func->js_mode & JS_MODE_STRICT)) || (s->token.u.ident.atom == JS_ATOM_yield && ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && !s->cur_func->in_function_body && s->cur_func->parent && (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || (s->token.u.ident.atom == JS_ATOM_await && (s->is_module || (s->cur_func->func_kind & JS_FUNC_ASYNC) || s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT || (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && !s->cur_func->in_function_body && s->cur_func->parent && ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) || s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) { if (s->token.u.ident.has_escape) { s->token.u.ident.is_reserved = TRUE; s->token.val = TOK_IDENT; } else { /* The keywords atoms are pre allocated */ s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; } } } /* if the current token is an identifier or keyword, reparse it according to the current function type */ static void reparse_ident_token(JSParseState *s) { if (s->token.val == TOK_IDENT || (s->token.val >= TOK_FIRST_KEYWORD && s->token.val <= TOK_LAST_KEYWORD)) { s->token.val = TOK_IDENT; s->token.u.ident.is_reserved = FALSE; update_token_ident(s); } } /* 'c' is the first character. Return JS_ATOM_NULL in case of error */ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, BOOL *pident_has_escape, int c, BOOL is_private) { const uint8_t *p, *p1; char ident_buf[128], *buf; size_t ident_size, ident_pos; JSAtom atom; p = *pp; buf = ident_buf; ident_size = sizeof(ident_buf); ident_pos = 0; if (is_private) buf[ident_pos++] = '#'; for(;;) { p1 = p; if (c < 128) { buf[ident_pos++] = c; } else { ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c); } c = *p1++; if (c == '\\' && *p1 == 'u') { c = lre_parse_escape(&p1, TRUE); *pident_has_escape = TRUE; } else if (c >= 128) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); } if (!lre_js_is_ident_next(c)) break; p = p1; if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) { atom = JS_ATOM_NULL; goto done; } } } atom = JS_NewAtomLen(s->ctx, buf, ident_pos); done: if (unlikely(buf != ident_buf)) js_free(s->ctx, buf); *pp = p; return atom; } static __exception int next_token(JSParseState *s) { const uint8_t *p; int c; BOOL ident_has_escape; JSAtom atom; if (js_check_stack_overflow(s->ctx->rt, 0)) { return js_parse_error(s, "stack overflow"); } free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; s->got_lf = FALSE; s->last_line_num = s->token.line_num; redo: s->token.line_num = s->line_num; s->token.ptr = p; c = *p; switch(c) { case 0: if (p >= s->buf_end) { s->token.val = TOK_EOF; } else { goto def_token; } break; case '`': if (js_parse_template_part(s, p + 1)) goto fail; p = s->buf_ptr; break; case '\'': case '\"': if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) goto fail; break; case '\r': /* accept DOS and MAC newline sequences */ if (p[1] == '\n') { p++; } /* fall thru */ case '\n': p++; line_terminator: s->got_lf = TRUE; s->line_num++; goto redo; case '\f': case '\v': case ' ': case '\t': p++; goto redo; case '/': if (p[1] == '*') { /* comment */ p += 2; for(;;) { if (*p == '\0' && p >= s->buf_end) { js_parse_error(s, "unexpected end of comment"); goto fail; } if (p[0] == '*' && p[1] == '/') { p += 2; break; } if (*p == '\n') { s->line_num++; s->got_lf = TRUE; /* considered as LF for ASI */ p++; } else if (*p == '\r') { s->got_lf = TRUE; /* considered as LF for ASI */ p++; } else if (*p >= 0x80) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); if (c == CP_LS || c == CP_PS) { s->got_lf = TRUE; /* considered as LF for ASI */ } else if (c == -1) { p++; /* skip invalid UTF-8 */ } } else { p++; } } goto redo; } else if (p[1] == '/') { /* line comment */ p += 2; skip_line_comment: for(;;) { if (*p == '\0' && p >= s->buf_end) break; if (*p == '\r' || *p == '\n') break; if (*p >= 0x80) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); /* LS or PS are considered as line terminator */ if (c == CP_LS || c == CP_PS) { break; } else if (c == -1) { p++; /* skip invalid UTF-8 */ } } else { p++; } } goto redo; } else if (p[1] == '=') { p += 2; s->token.val = TOK_DIV_ASSIGN; } else { p++; s->token.val = c; } break; case '\\': if (p[1] == 'u') { const uint8_t *p1 = p + 1; int c1 = lre_parse_escape(&p1, TRUE); if (c1 >= 0 && lre_js_is_ident_first(c1)) { c = c1; p = p1; ident_has_escape = TRUE; goto has_ident; } else { /* XXX: syntax error? */ } } goto def_token; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case '$': /* identifier */ p++; ident_has_escape = FALSE; has_ident: atom = parse_ident(s, &p, &ident_has_escape, c, FALSE); if (atom == JS_ATOM_NULL) goto fail; s->token.u.ident.atom = atom; s->token.u.ident.has_escape = ident_has_escape; s->token.u.ident.is_reserved = FALSE; s->token.val = TOK_IDENT; update_token_ident(s); break; case '#': /* private name */ { const uint8_t *p1; p++; p1 = p; c = *p1++; if (c == '\\' && *p1 == 'u') { c = lre_parse_escape(&p1, TRUE); } else if (c >= 128) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); } if (!lre_js_is_ident_first(c)) { js_parse_error(s, "invalid first character of private name"); goto fail; } p = p1; ident_has_escape = FALSE; /* not used */ atom = parse_ident(s, &p, &ident_has_escape, c, TRUE); if (atom == JS_ATOM_NULL) goto fail; s->token.u.ident.atom = atom; s->token.val = TOK_PRIVATE_NAME; } break; case '.': if (p[1] == '.' && p[2] == '.') { p += 3; s->token.val = TOK_ELLIPSIS; break; } if (p[1] >= '0' && p[1] <= '9') { goto parse_number; } else { goto def_token; } break; case '0': /* in strict mode, octal literals are not accepted */ if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) { js_parse_error(s, "octal literals are deprecated in strict mode"); goto fail; } goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* number */ parse_number: { JSValue ret; const uint8_t *p1; int flags, radix; flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | ATOD_ACCEPT_UNDERSCORES; flags |= ATOD_ACCEPT_SUFFIX; #ifdef CONFIG_BIGNUM if (s->cur_func->js_mode & JS_MODE_MATH) { flags |= ATOD_MODE_BIGINT; if (s->cur_func->js_mode & JS_MODE_MATH) flags |= ATOD_TYPE_BIG_FLOAT; } #endif radix = 0; #ifdef CONFIG_BIGNUM s->token.u.num.exponent = 0; ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix, flags, &s->token.u.num.exponent); #else ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, flags); #endif if (JS_IsException(ret)) goto fail; /* reject `10instanceof Number` */ if (JS_VALUE_IS_NAN(ret) || lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) { JS_FreeValue(s->ctx, ret); js_parse_error(s, "invalid number literal"); goto fail; } s->token.val = TOK_NUMBER; s->token.u.num.val = ret; } break; case '*': if (p[1] == '=') { p += 2; s->token.val = TOK_MUL_ASSIGN; } else if (p[1] == '*') { if (p[2] == '=') { p += 3; s->token.val = TOK_POW_ASSIGN; } else { p += 2; s->token.val = TOK_POW; } } else { goto def_token; } break; case '%': if (p[1] == '=') { p += 2; s->token.val = TOK_MOD_ASSIGN; } else { goto def_token; } break; case '+': if (p[1] == '=') { p += 2; s->token.val = TOK_PLUS_ASSIGN; } else if (p[1] == '+') { p += 2; s->token.val = TOK_INC; } else { goto def_token; } break; case '-': if (p[1] == '=') { p += 2; s->token.val = TOK_MINUS_ASSIGN; } else if (p[1] == '-') { if (s->allow_html_comments && p[2] == '>' && s->last_line_num != s->line_num) { /* Annex B: `-->` at beginning of line is an html comment end. It extends to the end of the line. */ goto skip_line_comment; } p += 2; s->token.val = TOK_DEC; } else { goto def_token; } break; case '<': if (p[1] == '=') { p += 2; s->token.val = TOK_LTE; } else if (p[1] == '<') { if (p[2] == '=') { p += 3; s->token.val = TOK_SHL_ASSIGN; } else { p += 2; s->token.val = TOK_SHL; } } else if (s->allow_html_comments && p[1] == '!' && p[2] == '-' && p[3] == '-') { /* Annex B: handle ` qbs Qbs Qt Project qbs Build tool that helps simplify the build process for developing projects across multiple platforms. Qbs is a tool that helps simplify the build process for developing projects across multiple platforms. https://wiki.qt.io/Qbs https://code.qt.io/cgit/qbs/qbs.git https://code.qt.io/cgit/qbs/qbs.git https://doc.qt.io/qbs/ http://lists.qt-project.org/mailman/listinfo/qbs https://bugreports.qt.io/browse/QBS qbs qt build © 2017 The Qt Company Ltd. http://doc.qt.io/qt-5/licensing.html false https://rawcdn.githack.com/qbs/qbs/v1.17.0/src/packages/chocolatey/icon.png qbs-src-2.6.1/src/packages/chocolatey/chocolatey.qbs0000644000175100001660000001160614776170045022014 0ustar runnerdockerimport qbs.Environment import qbs.File import qbs.FileInfo import qbs.Probes import qbs.TextFile import qbs.Utilities import qbs.Xml Product { Depends { name: "qbsversion" } Probes.BinaryProbe { id: choco condition: qbs.targetOS.contains("windows") names: ["choco"] platformSearchPaths: { var chocolateyInstall = Environment.getEnv("ChocolateyInstall"); if (chocolateyInstall) return [FileInfo.joinPaths(chocolateyInstall, "bin")]; else return [FileInfo.joinPaths(Environment.getEnv("PROGRAMDATA"), "chocolatey", "bin")]; } } condition: choco.found builtByDefault: false name: "qbs chocolatey" type: ["chocolatey.nupkg"] targetName: "qbs." + qbsversion.version destinationDirectory: project.buildDirectory property string chocoFilePath: choco.filePath Group { files: ["qbs.nuspec"] fileTags: ["chocolatey.nuspec"] } Group { files: ["chocolateyinstall.ps1"] fileTags: ["powershell.source"] } Group { files: ["../../../changelogs/*"] fileTags: ["changelog"] } Rule { inputs: ["chocolatey.nuspec", "powershell.source", "changelog"] multiplex: true Artifact { filePath: FileInfo.joinPaths(product.destinationDirectory, product.targetName + ".nupkg") fileTags: ["chocolatey.nupkg"] } prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.qbsVersion = product.qbsversion.version; cmd.powershellFilePath = inputs["powershell.source"][0].filePath; cmd.nuspecFileName = inputs["chocolatey.nuspec"][0].fileName; cmd.nuspecFilePath = inputs["chocolatey.nuspec"][0].filePath; cmd.chocoBuildDirectory = FileInfo.joinPaths(product.buildDirectory, "choco"); cmd.chocoOutDirectory = FileInfo.path(outputs["chocolatey.nupkg"][0].filePath); cmd.changelogs = (inputs["changelog"] || []).map(function (a) { return { filePath: a.filePath, version: a.fileName.replace(/^changes-([0-9](\.[0-9]+)*)(\.md)?$/, "$1") }; }).sort(function(a, b) { return Utilities.versionCompare(b.version, a.version); }); cmd.sourceCode = function () { File.makePath(chocoBuildDirectory); File.makePath(FileInfo.joinPaths(chocoBuildDirectory, "tools")); var tf = new TextFile(FileInfo.joinPaths( chocoBuildDirectory, "tools", "chocolateyinstall.ps1"), TextFile.WriteOnly); try { tf.writeLine("$qbsVersion = '" + qbsVersion + "'"); tf.writeLine(""); var tf2 = new TextFile(powershellFilePath, TextFile.ReadOnly); try { tf.write(tf2.readAll()); } finally { tf2.close(); } } finally { tf.close(); } var doc = new Xml.DomDocument(); doc.load(nuspecFilePath); var versionNode = doc.createElement("version"); versionNode.appendChild(doc.createTextNode(qbsVersion)); var releaseNotesNode = doc.createElement("releaseNotes"); var releaseNotesText = ""; changelogs.map(function (changelog) { releaseNotesText += "qbs " + changelog.version + "\n\n"; var tf = new TextFile(changelog.filePath, TextFile.ReadOnly); try { releaseNotesText += tf.readAll() + "\n"; } finally { tf.close(); } }); releaseNotesNode.appendChild(doc.createTextNode(releaseNotesText.trim())); var metadataNode = doc.documentElement().firstChild("metadata"); metadataNode.appendChild(versionNode); metadataNode.appendChild(releaseNotesNode); doc.save(FileInfo.joinPaths(chocoBuildDirectory, nuspecFileName)); }; var cmd2 = new Command(product.chocoFilePath, ["pack", FileInfo.joinPaths(cmd.chocoBuildDirectory, cmd.nuspecFileName), "--limitoutput", "--outputdirectory", cmd.chocoOutDirectory]); cmd2.description = "packing choco " + inputs["chocolatey.nuspec"][0].fileName; return [cmd, cmd2]; } } } qbs-src-2.6.1/src/libexec/0000755000175100001660000000000014776170045014652 5ustar runnerdockerqbs-src-2.6.1/src/libexec/qbs_processlauncher/0000755000175100001660000000000014776170045020717 5ustar runnerdockerqbs-src-2.6.1/src/libexec/qbs_processlauncher/qbs_processlauncher.qbs0000644000175100001660000000172514776170045025500 0ustar runnerdockerimport qbs.FileInfo QbsProduct { type: "application" name: "qbs_processlauncher" consoleApplication: true Depends { name: "Qt.network" } cpp.includePaths: base.concat(pathToProtocolSources) files: [ "launcherlogging.cpp", "launcherlogging.h", "launchersockethandler.cpp", "launchersockethandler.h", "processlauncher-main.cpp", ] property string pathToProtocolSources: sourceDirectory + "/../../lib/corelib/tools" Group { name: "protocol sources" prefix: pathToProtocolSources + '/' files: [ "launcherpackets.cpp", "launcherpackets.h", ] } Group { fileTagsFilter: product.type .concat(qbs.buildVariant === "debug" ? ["debuginfo_app"] : []) qbs.install: true qbs.installDir: targetInstallDir qbs.installSourceBase: buildDirectory } targetInstallDir: qbsbuildconfig.libexecInstallDir } qbs-src-2.6.1/src/libexec/qbs_processlauncher/launchersockethandler.h0000644000175100001660000000573214776170045025447 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LAUNCHERSOCKETHANDLER_H #define QBS_LAUNCHERSOCKETHANDLER_H #include #include #include #include QT_BEGIN_NAMESPACE class QLocalSocket; QT_END_NAMESPACE namespace qbs { namespace Internal { class Process; class LauncherSocketHandler : public QObject { Q_OBJECT public: explicit LauncherSocketHandler(QString socketPath, QObject *parent = nullptr); ~LauncherSocketHandler() override; void start(); private: void handleSocketData(); void handleSocketError(); void handleSocketClosed(); void handleProcessError(); void handleProcessFinished(); void handleStopFailure(); void handleStartPacket(); void handleStopPacket(); void handleShutdownPacket(); void sendPacket(const LauncherPacket &packet); Process *setupProcess(quintptr token); Process *senderProcess() const; const QString m_serverPath; QLocalSocket * const m_socket; PacketParser m_packetParser; QHash m_processes; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.6.1/src/libexec/qbs_processlauncher/launchersockethandler.cpp0000644000175100001660000002246214776170045026001 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "launchersockethandler.h" #include "launcherlogging.h" #include #include #include #include namespace qbs { namespace Internal { class Process : public QProcess { Q_OBJECT public: Process(quintptr token, QObject *parent = nullptr) : QProcess(parent), m_token(token), m_stopTimer(new QTimer(this)) { m_stopTimer->setSingleShot(true); connect(m_stopTimer, &QTimer::timeout, this, &Process::cancel); } void cancel() { switch (m_stopState) { case StopState::Inactive: m_stopState = StopState::Terminating; m_stopTimer->start(3000); terminate(); break; case StopState::Terminating: m_stopState = StopState::Killing; m_stopTimer->start(3000); kill(); break; case StopState::Killing: m_stopState = StopState::Inactive; emit failedToStop(); break; } } void stopStopProcedure() { m_stopState = StopState::Inactive; m_stopTimer->stop(); } quintptr token() const { return m_token; } signals: void failedToStop(); private: const quintptr m_token; QTimer * const m_stopTimer; enum class StopState { Inactive, Terminating, Killing } m_stopState = StopState::Inactive; }; LauncherSocketHandler::LauncherSocketHandler(QString serverPath, QObject *parent) : QObject(parent), m_serverPath(std::move(serverPath)), m_socket(new QLocalSocket(this)) { m_packetParser.setDevice(m_socket); } LauncherSocketHandler::~LauncherSocketHandler() { m_socket->disconnect(); if (m_socket->state() != QLocalSocket::UnconnectedState) { logWarn("socket handler destroyed while connection was active"); m_socket->close(); } for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) it.value()->disconnect(); } void LauncherSocketHandler::start() { connect(m_socket, &QLocalSocket::disconnected, this, &LauncherSocketHandler::handleSocketClosed); connect(m_socket, &QLocalSocket::readyRead, this, &LauncherSocketHandler::handleSocketData); connect(m_socket, &QLocalSocket::errorOccurred, this, &LauncherSocketHandler::handleSocketError); m_socket->connectToServer(m_serverPath); } void LauncherSocketHandler::handleSocketData() { try { if (!m_packetParser.parse()) return; } catch (const PacketParser::InvalidPacketSizeException &e) { logWarn(QStringLiteral("Internal protocol error: invalid packet size %1.") .arg(e.size)); return; } switch (m_packetParser.type()) { case LauncherPacketType::StartProcess: handleStartPacket(); break; case LauncherPacketType::StopProcess: handleStopPacket(); break; case LauncherPacketType::Shutdown: handleShutdownPacket(); return; default: logWarn(QStringLiteral("Internal protocol error: invalid packet type %1.") .arg(static_cast(m_packetParser.type()))); return; } handleSocketData(); } void LauncherSocketHandler::handleSocketError() { if (m_socket->error() != QLocalSocket::PeerClosedError) { logError(QStringLiteral("socket error: %1").arg(m_socket->errorString())); m_socket->disconnect(); qApp->quit(); } } void LauncherSocketHandler::handleSocketClosed() { for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) { if (it.value()->state() != QProcess::NotRunning) { logWarn("client closed connection while process still running"); break; } } m_socket->disconnect(); qApp->quit(); } void LauncherSocketHandler::handleProcessError() { Process * proc = senderProcess(); if (proc->error() != QProcess::FailedToStart) return; proc->stopStopProcedure(); ProcessErrorPacket packet(proc->token()); packet.error = proc->error(); packet.errorString = proc->errorString(); sendPacket(packet); } void LauncherSocketHandler::handleProcessFinished() { Process * proc = senderProcess(); proc->stopStopProcedure(); ProcessFinishedPacket packet(proc->token()); packet.error = proc->error(); packet.errorString = proc->errorString(); packet.exitCode = proc->exitCode(); packet.exitStatus = proc->exitStatus(); packet.stdErr = proc->readAllStandardError(); packet.stdOut = proc->readAllStandardOutput(); sendPacket(packet); } void LauncherSocketHandler::handleStopFailure() { // Process did not react to a kill signal. Rare, but not unheard of. // Forget about the associated Process object and report process exit to the client. Process * proc = senderProcess(); proc->disconnect(); m_processes.remove(proc->token()); ProcessFinishedPacket packet(proc->token()); packet.error = QProcess::Crashed; packet.exitCode = -1; packet.exitStatus = QProcess::CrashExit; packet.stdErr = proc->readAllStandardError(); packet.stdOut = proc->readAllStandardOutput(); sendPacket(packet); } void LauncherSocketHandler::handleStartPacket() { Process *& process = m_processes[m_packetParser.token()]; if (!process) process = setupProcess(m_packetParser.token()); if (process->state() != QProcess::NotRunning) { logWarn("got start request while process was running"); return; } const auto packet = LauncherPacket::extractPacket( m_packetParser.token(), m_packetParser.packetData()); process->setEnvironment(packet.env); process->setWorkingDirectory(packet.workingDir); process->start(packet.command, packet.arguments); } void LauncherSocketHandler::handleStopPacket() { Process * const process = m_processes.value(m_packetParser.token()); if (!process) { logWarn("got stop request for unknown process"); return; } if (process->state() == QProcess::NotRunning) { // This can happen if the process finishes on its own at about the same time the client // sends the request. logDebug("got stop request when process was not running"); return; } process->cancel(); } void LauncherSocketHandler::handleShutdownPacket() { logDebug("got shutdown request, closing down"); for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) { it.value()->disconnect(); if (it.value()->state() != QProcess::NotRunning) { logWarn("got shutdown request while process was running"); it.value()->terminate(); } } m_socket->disconnect(); qApp->quit(); } void LauncherSocketHandler::sendPacket(const LauncherPacket &packet) { m_socket->write(packet.serialize()); } Process *LauncherSocketHandler::setupProcess(quintptr token) { const auto p = new Process(token, this); connect(p, &QProcess::errorOccurred, this, &LauncherSocketHandler::handleProcessError); connect(p, static_cast(&QProcess::finished), this, &LauncherSocketHandler::handleProcessFinished); connect(p, &Process::failedToStop, this, &LauncherSocketHandler::handleStopFailure); return p; } Process *LauncherSocketHandler::senderProcess() const { return static_cast(sender()); } } // namespace Internal } // namespace qbs #include qbs-src-2.6.1/src/libexec/qbs_processlauncher/processlauncher-main.cpp0000644000175100001660000000520014776170045025542 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "launcherlogging.h" #include "launchersockethandler.h" #include #include #ifdef Q_OS_WIN #include BOOL WINAPI consoleCtrlHandler(DWORD) { // Ignore Ctrl-C / Ctrl-Break. Qbs will tell us to exit gracefully. return TRUE; } #endif int main(int argc, char *argv[]) { #ifdef Q_OS_WIN SetConsoleCtrlHandler(consoleCtrlHandler, TRUE); #endif QCoreApplication app(argc, argv); if (app.arguments().size() != 2) { qbs::Internal::logError("Need exactly one argument (path to socket)"); return 1; } qbs::Internal::LauncherSocketHandler launcher(app.arguments().constLast()); QTimer::singleShot(0, &launcher, &qbs::Internal::LauncherSocketHandler::start); return app.exec(); } qbs-src-2.6.1/src/libexec/qbs_processlauncher/launcherlogging.h0000644000175100001660000000450114776170045024240 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_LAUCHERLOGGING_H #define QBS_LAUCHERLOGGING_H #include #include namespace qbs { namespace Internal { Q_DECLARE_LOGGING_CATEGORY(launcherLog) template void logDebug(const T &msg) { qCDebug(launcherLog) << msg; } template void logWarn(const T &msg) { qCWarning(launcherLog) << msg; } template void logError(const T &msg) { qCCritical(launcherLog) << msg; } } } #endif // Include guard qbs-src-2.6.1/src/libexec/qbs_processlauncher/launcherlogging.cpp0000644000175100001660000000374614776170045024605 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "launcherlogging.h" namespace qbs { namespace Internal { Q_LOGGING_CATEGORY(launcherLog, "qbs.launcher", QtWarningMsg) } } qbs-src-2.6.1/src/libexec/qbs_processlauncher/CMakeLists.txt0000644000175100001660000000136314776170045023462 0ustar runnerdockerset(SOURCES launcherlogging.cpp launcherlogging.h launchersockethandler.cpp launchersockethandler.h processlauncher-main.cpp ) set(PATH_TO_PROTOCOL_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../../lib/corelib/tools") set(PROTOCOL_SOURCES launcherpackets.cpp launcherpackets.h ) list_transform_prepend(PROTOCOL_SOURCES ${PATH_TO_PROTOCOL_SOURCES}/) add_qbs_app(qbs_processlauncher DESTINATION ${QBS_LIBEXEC_INSTALL_DIR} DEPENDS Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network INCLUDES ${PATH_TO_PROTOCOL_SOURCES} SOURCES ${SOURCES} ${PROTOCOL_SOURCES} ) set_target_properties(qbs_processlauncher PROPERTIES BUILD_RPATH "${QBS_LIBEXEC_RPATH}" INSTALL_RPATH "${QBS_LIBEXEC_RPATH}" ) qbs-src-2.6.1/src/libexec/libexec.qbs0000644000175100001660000000013314776170045016771 0ustar runnerdockerProject { references: [ "qbs_processlauncher/qbs_processlauncher.qbs", ] } qbs-src-2.6.1/src/libexec/CMakeLists.txt0000644000175100001660000000004614776170045017412 0ustar runnerdockeradd_subdirectory(qbs_processlauncher) qbs-src-2.6.1/dist/0000755000175100001660000000000014776170045013413 5ustar runnerdockerqbs-src-2.6.1/dist/.gitignore0000644000175100001660000000000214776170045015373 0ustar runnerdocker* qbs-src-2.6.1/qbs.qbs0000644000175100001660000000212614776170045013745 0ustar runnerdockerProject { minimumQbsVersion: "1.6" qbsSearchPaths: ["qbs-resources"] property bool withCode: true property bool withDocumentation: true property bool withTests: withCode property stringList autotestArguments: [] property stringList autotestWrapper: [] references: [ "docker/docker.qbs", "examples/examples.qbs", "share/share.qbs", "scripts/scripts.qbs", "tutorial/tutorial.qbs", ] SubProject { filePath: "doc/doc.qbs" Properties { condition: parent.withDocumentation } } SubProject { filePath: "src/src.qbs" Properties { condition: parent.withCode } } SubProject { filePath: "tests/tests.qbs" Properties { condition: parent.withTests } } Product { name: "version" files: ["VERSION"] } Product { name: "continuous integration files" files: [ ".clang-tidy", "docker-compose.yml", ".github/**/*.yml", ] } } qbs-src-2.6.1/.mailmap0000644000175100001660000000266014776170045014075 0ustar runnerdocker qbs-src-2.6.1/.clang-format0000644000175100001660000000636114776170045015031 0ustar runnerdocker# .clang-format for Qbs # based on https://github.com/qt-creator/qt-creator/blob/v12.0.1/.clang-format # # This is for clang-format >= 5.0. # # Use ../../tests/clang-format-test/clang-format-test.cpp for documenting problems # or testing changes. # --- Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: AlwaysBreak AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: DontAlign AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: true AfterControlStatement: Never AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false AfterStruct: true AfterUnion: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: false SplitEmptyRecord: false SplitEmptyNamespace: false BreakBeforeBinaryOperators: All BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 100 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - forever # avoids { wrapped to next line - foreach - Q_FOREACH - BOOST_FOREACH IncludeCategories: - Regex: '^= 0 } Depends { name: "quickjs"; cpp.link: false } } qbs-src-2.6.1/qbs-resources/imports/QbsProduct.qbs0000644000175100001660000000247414776170045021546 0ustar runnerdockerProduct { Depends { name: "qbsbuildconfig" } Depends { name: "qbsversion" } Depends { name: "Qt.core"; versionAtLeast: minimumQtVersion } property string minimumQtVersion: "5.15.2" property bool install: true property bool hasCMakeFile: true property string targetInstallDir cpp.defines: { var res = [ "QT_NO_CAST_FROM_ASCII", "QT_NO_CAST_FROM_BYTEARRAY", "QT_NO_JAVA_STYLE_ITERATORS", "QT_NO_PROCESS_COMBINED_ARGUMENT_START", "QT_USE_QSTRINGBUILDER", "QT_DISABLE_DEPRECATED_BEFORE=0x050f00", "QT_DISABLE_DEPRECATED_UP_TO=0x050f00", "QT_WARN_DEPRECATED_BEFORE=0x060700", "QT_WARN_DEPRECATED_UP_TO=0x060700" ]; if (qbs.toolchain.contains("msvc")) res.push("_SCL_SECURE_NO_WARNINGS"); if (qbs.enableDebugCode) res.push("QT_STRICT_ITERATORS"); return res; } cpp.cxxLanguageVersion: "c++20" cpp.enableExceptions: true cpp.rpaths: qbsbuildconfig.libRPaths cpp.minimumMacosVersion: "11.0" Group { name: "CMake" condition: hasCMakeFile prefix: product.sourceDirectory + '/' files: "CMakeLists.txt" } } qbs-src-2.6.1/qbs-resources/imports/QbsLibrary.qbs0000644000175100001660000000556614776170045021537 0ustar runnerdockerimport qbs.FileInfo import qbs.Utilities QbsProduct { Depends { name: "cpp" } Depends { name: "Exporter.pkgconfig"; condition: generatePkgConfigFile } Depends { name: "Exporter.qbs"; condition: generateQbsModule } Depends { name: "span" } property string visibilityType: staticBuild ? "static" : "dynamic" property string headerInstallPrefix: "/include/qbs" property bool hasExporter: Utilities.versionCompare(qbs.version, "1.12") >= 0 property bool generatePkgConfigFile: qbsbuildconfig.generatePkgConfigFiles && hasExporter property bool generateQbsModule: install && qbsbuildconfig.generateQbsModules && hasExporter property bool staticBuild: Qt.core.staticBuild || qbsbuildconfig.staticBuild property stringList libType: [staticBuild ? "staticlibrary" : "dynamiclibrary"] version: qbsversion.version type: libType targetName: (qbs.enableDebugCode && qbs.targetOS.contains("windows")) ? (name + 'd') : name cpp.visibility: "minimal" cpp.defines: base.concat(visibilityType === "static" ? ["QBS_STATIC_LIB"] : ["QBS_LIBRARY"]) cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Properties { condition: qbs.toolchain.contains("gcc") cpp.soVersion: version.replace(/\.\d+$/, '') } Group { fileTagsFilter: libType.concat("dynamiclibrary_symlink") .concat(qbs.debugInformation ? ["debuginfo_dll"] : []) qbs.install: install qbs.installDir: targetInstallDir qbs.installSourceBase: buildDirectory } targetInstallDir: qbsbuildconfig.libInstallDir Group { fileTagsFilter: ["dynamiclibrary_import"] qbs.install: install qbs.installDir: qbsbuildconfig.importLibInstallDir } Group { fileTagsFilter: "Exporter.pkgconfig.pc" qbs.install: install qbs.installDir: qbsbuildconfig.pkgConfigInstallDir } Group { fileTagsFilter: "Exporter.qbs.module" qbs.install: install qbs.installDir: FileInfo.joinPaths(qbsbuildconfig.qbsModulesBaseDir, product.name) } Properties { condition: qbs.targetOS.contains("darwin") bundle.isBundle: false cpp.linkerFlags: ["-compatibility_version", cpp.soVersion] } Export { Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["core"] } Depends { name: "span" } Properties { condition: exportingProduct.hasExporter prefixMapping: [{ prefix: exportingProduct.sourceDirectory, replacement: FileInfo.joinPaths(exportingProduct.qbs.installPrefix, exportingProduct.headerInstallPrefix) }] } cpp.includePaths: [exportingProduct.sourceDirectory] cpp.defines: exportingProduct.visibilityType === "static" ? ["QBS_STATIC_LIB"] : [] } } qbs-src-2.6.1/qbs-resources/imports/QbsStaticLibrary.qbs0000644000175100001660000000031714776170045022674 0ustar runnerdockerQbsProduct { type: "staticlibrary" Export { Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["core"] } cpp.includePaths: [exportingProduct.sourceDirectory] } } qbs-src-2.6.1/qbs-resources/imports/QbsApp.qbs0000644000175100001660000000102714776170045020637 0ustar runnerdockerimport qbs.FileInfo QbsProduct { Depends { name: "qbscore" } Depends { name: "qbsversion" } Depends { name: "qbsconsolelogger" } type: ["application", "qbsapplication"] version: qbsversion.version consoleApplication: true Group { fileTagsFilter: product.type .concat(qbs.debugInformation ? ["debuginfo_app"] : []) qbs.install: true qbs.installDir: targetInstallDir qbs.installSourceBase: buildDirectory } targetInstallDir: qbsbuildconfig.appInstallDir } qbs-src-2.6.1/qbs-resources/imports/QbsAutotest.qbs0000644000175100001660000000145614776170045021735 0ustar runnerdockerimport qbs.FileInfo import qbs.Utilities QbsProduct { type: ["application", "autotest"] consoleApplication: true property string testName name: "tst_" + testName property string targetInstallDir: qbsbuildconfig.appInstallDir Depends { name: "Qt.testlib" } Depends { name: "qbscore" } Depends { name: "qbsbuildconfig" } cpp.defines: [ // deliberately override base defines "QBS_TEST_SUITE_NAME=" + Utilities.cStringQuote(testName.toUpperCase().replace("-", "_")) ] cpp.includePaths: [ "../../../src", ] qbs.commonRunEnvironment: ({ "QBS_INSTALL_DIR": FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix) }) Group { fileTagsFilter: product.type qbs.install: true qbs.installDir: targetInstallDir } } qbs-src-2.6.1/qbs-resources/modules/0000755000175100001660000000000014776170045016715 5ustar runnerdockerqbs-src-2.6.1/qbs-resources/modules/qbsbuildconfig/0000755000175100001660000000000014776170045021710 5ustar runnerdockerqbs-src-2.6.1/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs0000644000175100001660000001057314776170045025420 0ustar runnerdockerimport qbs.FileInfo import qbs.Utilities Module { Depends { condition: project.withCode name: "cpp" } property bool enableAddressSanitizer: false property bool enableUbSanitizer: false property bool enableThreadSanitizer: false property bool enableUnitTests: false property bool enableProjectFileUpdates: true property bool enableRPath: true property bool installApiHeaders: true property bool enableBundledQt: false property bool staticBuild: false property string libDirName: "lib" property string appInstallDir: "bin" property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName property string importLibInstallDir: libDirName property string libexecInstallDir: qbs.targetOS.contains("windows") ? appInstallDir : "libexec/qbs" property string systemSettingsDir property bool installManPage: qbs.targetOS.contains("unix") property bool installHtml: true property bool installQch: false property bool generatePkgConfigFiles: installApiHeaders && qbs.targetOS.contains("unix") && !qbs.targetOS.contains("darwin") property bool generateQbsModules: installApiHeaders property string docInstallDir: "share/doc/qbs/html" property string pkgConfigInstallDir: FileInfo.joinPaths(libDirName, "pkgconfig") property string qbsModulesBaseDir: FileInfo.joinPaths(libDirName, "qbs", "modules") property string relativeLibexecPath: "../" + libexecInstallDir property string relativePluginsPath: "../" + libDirName property string relativeSearchPath: ".." property stringList libRPaths: { if (enableRPath && project.withCode && cpp.rpathOrigin && product.targetInstallDir) { return [FileInfo.joinPaths(cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.targetInstallDir), FileInfo.joinPaths('/', libDirName)))]; } return []; } property string resourcesInstallDir: "" property string pluginsInstallDir: libDirName + "/qbs/plugins" property string qmlTypeDescriptionsInstallDir: FileInfo.joinPaths(resourcesInstallDir, "share/qbs/qml-type-descriptions") property bool dumpJsLeaks: qbs.buildVariant === "debug" Properties { condition: project.withCode && qbs.toolchain.contains("gcc") cpp.cxxFlags: { var flags = ["-Wno-missing-field-initializers"]; if (enableAddressSanitizer) flags.push("-fno-omit-frame-pointer"); function isClang() { return qbs.toolchain.contains("clang"); } function versionAtLeast(v) { return Utilities.versionCompare(cpp.compilerVersion, v) >= 0; }; if (isClang()) flags.push("-Wno-constant-logical-operand"); if ((!isClang() && versionAtLeast("9")) || (isClang() && !qbs.hostOS.contains("darwin") && versionAtLeast("10"))) { flags.push("-Wno-deprecated-copy"); } // workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105616 if (enableAddressSanitizer && !isClang() && versionAtLeast("13")) { flags.push("-Wno-maybe-uninitialized"); } return flags; } cpp.driverFlags: { var flags = []; if (enableAddressSanitizer) flags.push("-fsanitize=address"); if (enableUbSanitizer) { flags.push("-fsanitize=undefined"); flags.push("-fno-sanitize=vptr"); } if (enableThreadSanitizer) flags.push("-fsanitize=thread"); return flags; } } Properties { condition: project.withCode && qbs.toolchain.contains("msvc") && product.Qt && Utilities.versionCompare(product.Qt.core.version, "6.3") >= 0 && Utilities.versionCompare(cpp.compilerVersion, "19.10") >= 0 && Utilities.versionCompare(qbs.version, "1.23") < 0 cpp.cxxFlags: "/permissive-" } Properties { condition: project.withCode && qbs.toolchain.contains("msvc") cpp.defines: "_UCRT_NOISY_NAN" } } qbs-src-2.6.1/qbs-resources/modules/qbsversion/0000755000175100001660000000000014776170045021110 5ustar runnerdockerqbs-src-2.6.1/qbs-resources/modules/qbsversion/qbsversion.qbs0000644000175100001660000000115114776170045024010 0ustar runnerdockerimport qbs.File import qbs.FileInfo import qbs.TextFile Module { Probe { id: qbsVersionProbe property var lastModified: File.lastModified(versionFilePath) property string versionFilePath: FileInfo.joinPaths(path, "..", "..", "..", "VERSION") property string version configure: { var tf = new TextFile(versionFilePath, TextFile.ReadOnly); try { version = tf.readAll().trim(); found = !!version; } finally { tf.close(); } } } version: qbsVersionProbe.version } qbs-src-2.6.1/changelogs/0000755000175100001660000000000014776170045014562 5ustar runnerdockerqbs-src-2.6.1/changelogs/changes-1.16.0.md0000644000175100001660000001224114776170045017235 0ustar runnerdocker# General * A new freedesktop module helps UNIX application developers to follow the freedesktop.org guidelines. * The Android module now allows resourcesDir, sourcesDir and assetsDir to be specified as relative paths. * A new ConanfileProbe allows better and more flexible integration of Qbs and the Conan package manager. * A new hostArchitecture property has been added to the qbs module. # Language * List properties in modules are now merged according to inter-module dependencies. This is important when flags like cpp.staticLibraries are contributed by multiple modules with dependencies between each other. (QBS-1517). * Dependency matching of multiplexed products is now less strict and does not require all multiplex properties to match. For instance, if product A is multiplexed over qbs.architecture and qbs.buildVariant while product B is only multiplexed over one of these axes, then Qbs no longer fails (QBS-1515). # C/C++ Support * The Renesas RL78 architecture is now supported in GCC and IAR and the toolchains are auto-detected by qbs-setup-toolchains. * The Renesas RX as well as the RH850, V850, 78K are now supported in IAR and the toolchains are auto-detected by qbs-setup-toolchains. * The MPLAB X32 GCC-based toolchain is now auto-detected on Windows. * Multiple occurrences of static libraries on the linker command line are now pruned and the last instance always wins when using GCC or LLVM-based toolchains. This avoids problems with excessively long linker command lines (QBS-1273). * Clang-cl and MSVC toolchains use the compiler frontend instead of the linker when linking. The old behavior can be restored by setting cpp.linkerMode to "manual". This allows to use sanitizers with clang-cl by passing "-fsanitise=xxx" via cpp.driverFlags (QBS-1522). * The clang-cl toolchain now uses "link.exe" as the default linker. "lld-link.exe" can be explicitly selected by setting cpp.linkerVariant to "lld" (QBS-1522). * The MSVC, clang-cl and MinGW toolchains are now automatically detected if the profile does not set an explicit installation location, for instance because no profile was given. * Installation of separate debug information can now be enabled and configured by simply setting the installDebugInformation and debugInformationInstallDir properties in the Application and Library convenience items. This works for toolchains based upon GCC, MSVC or clang-cl. * Xcode version 11.4 is now supported on macOS. # Qt Support * Qbs now supports Qt 5.14 for Android which comes as a multi-architecture package. The qbs-setup-android tool has been updated accordingly (QBS-1497). * JSON metatype files generated by moc (Qt >= 5.15) are supported by setting Qt.core.generateMetaTypesFile and Qt.core.metaTypesInstallDir (QBS-1531). * Pure debug builds of Qt (>= 5.14) with MinGW are now properly supported. They don't have the 'd' suffix (QTBUG-80792). * The QML type declaration mechanism introduced in Qt 5.15 is now supported by the Qt.qml module (QBS-1531). * Generated qmltypes files are now named according to the product's targetName property (QTBUG-82710). # Documentation * The how-to chapter has been extended with sections about debugging Qbs files and about building separate debug information in C++ projects. * The item and module reference documentation has been improved for the cpp.libraryPaths, cpp.dynamicLibraries (QBS-1516), qbs.toolchainType and qbs.toolchain properties as well as the Export item and the Library convenience item. * Documentation for various path probes has been added (QBS-1187). * The README was extended and a CONTRIBUTING file has been added which provides useful information for potential contributors. This is important for people looking at our github mirror. # Infrastructure * The Debian Docker image has been removed. * We are now using ccache and clcache in our CI pipelines to shrink the build time. * Clang-tidy is now used to identify potential problems in the code base and a lot of action was taken upon a lot of findings. * A Docker image for testing Qbs with Android and Qt has been added. # Important Bug Fixes * Fix nullpointer access and heap-use-after-free error (QBS-1485). * Select the right instance when Depends.profiles is used on a dependency with an aggregator product (QBS-1513). * Fix crash when specifying a non-existing profile in Depends.profiles (QBS-1514). * Try harder to detect GCC toolchains in qbs-setup-toolchains (QBS-1524). * Code signing for Core Foundation Bundles on macOS has been fixed. * Automatic artifact scanning now prefers artifacts from product dependencies if multiple candidates are found. This improves dependency tracking in complex projects (QBS-1532). * The grpcIncludePath property in the probufcpp module has been fixed (QBS-1542). * Qbs does no longer crash when accessing a property of a non-existent module in "IDE mode". # Contributors * Alberto Mardegan * Björn Schäpers * BogDan Vatra * Christian Kandeler * Christian Stenger * Denis Shienkov * Ivan Komissarov * Jochen Ulrich * Joerg Bornemann * Leon Buckel * Marius Sincovici * Maximilian Goldstein * Mitch Curtis * Oliver Wolff * Orgad Shaneh * Raphaël Cotty * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.17.0.md0000644000175100001660000000651214776170045017242 0ustar runnerdocker# General * The lookup order in PathProbe changed to [environmentPaths, searchPaths, platformEnvironmentPaths, platformSearchPaths]. * The pathPrefix and platformPaths properties have been removed from the PathProbe item. They were deprecated since Qbs 1.13. * The protocBinary property in the protobuf module has been renamed to compilerPath. * A new module capnp for Cap'n Proto in C++ applications has been added. Cap'n Proto is a serialization protocol similar to protobuf. * The qbs-setup-android tool got a --system flag to install profiles system-wide similar to qbs-setup-qt and qbs-setup-toolchains. # Language * The product and project variables are now available on the right-hand-side of moduleProvider expressions and the default scope is product (QBS-1587). # C/C++ Support * Lots of improvements have been made on toolchain support for bare-metal devices in general. Bare-metal targets can be selected by setting qbs.targetPlatform to 'none'. * KEIL: The ARMCLANG, C166 and C251 toolchains are now supported. * IAR: National's CR16, Microchip's AVR32, NXP's M68K, Renesas' M8/16C/M32C/R32C/SuperH targets and RISC-V targets are now supported. * GCC: National's CR16, NXP M68K, Renesas M32C/M32R/SuperH/V850 as well as RISC-V and Xtensa targets are now supported. * MSVC: Module definition files can now be used to provide the linker with information about exports and attributes (QBS-571). * MSVC: "/external:I" is now used to set system include paths (QBS-1573). * MSVC: cpp.generateCompilerListingFiles is now supported to generate assembler listings. * Xcode: macOS framework paths on the command line are now automatically deduplicated (QBS-1552). * Xcode: Support for Xcode 12.0 has been added (QBS-1582). # Qt Support * The Qt for Android modules have been cleaned up. Support for ARMv5, MIPS and MIPS64 targets has been removed (QBS-1496). * Initial support for Qt6 has been added. # Android Support * A packageType property has been added to the Android.sdk module which allows to create Android App bundles (aab) instead of apk packages only. * A aaptName property has been added to the Android.sdk module which allows to use aapt2 (QBS-1562) since aapt has been deprecated. # Documentation * New bare-metal examples have been added and existing examples have been ported to more toolchains. * A new how-to about cpp.rPaths has been added (QBS-1204). * Various minor improvements have been made. # Important Bug Fixes * Building Qt for Android applications as static libraries has been fixed (QBS-1545). * Trailing slashes are no longer removed from Visual Studio environment variables (QBS-1551). * The MSVC cpp module did not use the cpp.distributionIncludePaths property (QBS-1572). * The visual studio generator has been fixed to work with Visual Studio 16.6 (QBS-1569). * Fixed extraction of build information from CONFIG and QT_CONFIG variables in Qt installations (QBS-1387). * The version number is no longer appended to .so files on Android (QBS-1578). * Compiler defines are now correctly passed to moc when processing header files (QBS-1592). # Contributors * Alberto Mardegan * Christian Gagneraud * Christian Kandeler * Christian Stenger * Denis Shienkov * Ivan Komissarov * Jake Petroules * Jochen Ulrich * Mitch Curtis * Oliver Wolff * Raphaël Cotty * Richard Weickelt * Sergey Zhuravlev qbs-src-2.6.1/changelogs/changes-1.23.2.md0000644000175100001660000000026614776170045017241 0ustar runnerdocker# Qt Support * Set _ENABLE_EXTENDED_ALIGNED_STORAGE for MSVC # Documentation * Fix installation with cmake # Contributors * Christian Kandeler * Ivan Komissarov * Marius Gripsgard qbs-src-2.6.1/changelogs/changes-1.23.0.md0000644000175100001660000000066214776170045017237 0ustar runnerdocker# C/C++ Support * Added new module Sanitizers.address for simple cross-platform ASan configuration. # Qt Support * Add the now-required /permissive- flag for MSVC automatically. # Android Support * Support use of cmdline-tools in addition to SDK tools. * Consider .jar files also in the product itself, not just in dependencies. # Contributors * Christian Kandeler * Dmitry Shachnev * Ivan Komissarov * Max Bespalov * Orgad Shaneh qbs-src-2.6.1/changelogs/changes-1.18.2.md0000644000175100001660000000171614776170045017246 0ustar runnerdocker# C/C++ Support * qbs-setup-toolchains is now able to detect clang-cl properly * The Library and Include probes take more paths into account on Linux to better support containerization systems such as Flatpak. * Xcode autodetection now uses xcode-select to find Xcode on the system. # Protocol Buffers Support (Protobuf Module) * A missing nanopb generator file extension on windows has been added. * The problem that property _libraryName was incorrect when protobuf was not found has been fixed. # Android Support * An assertion when building Android applications using additional java classes with native methods has been fixed (QBS-1628). # Qt Support * A problem related to handling Qt6EntryPoint in the Qt module provider has been fixed. # Infrastructure * A Qt4 docker image for basic testing has been added. # Contributors * Christian Kandeler * Eike Ziller * Ivan Komissarov * Jan Blackquill * Kai Dohmen * Raphaël Cotty * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.9.1.md0000644000175100001660000000037314776170045017163 0ustar runnerdocker# Important bugfixes * Lower the response file threshold on Windows to fix build failures with mingw (QBS-1201). * Fix explicitly specified build variant being ignored for Darwin targets (QBS-1202). * Fix building for the AVR architecture (QBS-1203). qbs-src-2.6.1/changelogs/changes-1.19.0.md0000644000175100001660000000471414776170045017246 0ustar runnerdocker# General * New codesign module was added to implement code signing for Apple, Android and Windows platforms (QBS-899, QBS-1546). * It is now possible to build Qbs with Qt 6. * Project files update API depending on the Qt.gui module was removed. This allows to enable project files update API unconditionally when building Qbs. * Convenience items such as Application, DynamicLibrary and StaticLibrary now properly install artifacts when multiplexing. # C/C++ Support * Qbs now supports multiple MSVC compiler versions installed in one Visual Studio installation (QBS-1498). Also, multiple compiler versions are properly detected by qbs setup-toolchains. * It is now possible to specify Windows SDK version for the MSVC and clang-cl toolchains via the new cpp.windowsSdkVersion property. * baremetal: Fix generation of compiler listing files with custom extension for the SDCC compiler. * baremetal: Fix generation of compiler listing files for the ARMCC compiler. * baremetal: Fix detection for Keil toolchains. * baremetal: Add support for HCS08 architectures to SDCC and IAR toolchains (QBS-1631, QBS-1629). * baremetal: Add support for HCS12 architectures to GCC and IAR toolchains (QBS-1630, QBS-1550). # Qt Support * Fix possible command line length issue with qmlimportscanner (QBS-1633). * Fix accessing binaries from libexec for Qt 6.1 and above (QBS-1636). # Android Support * Added a workaround for the Qt.Network module dependencies for 5.15.0 < Qt < 5.15.3 (QTBUG-87288) * Fix aapt command invocation on Windows. * Added support for ndk 22.1.7171670. # Documentation * Added How-To about codesigning on Apple platforms. * Cocoa Touch Application example is brought up-to date to use modern Apple practices. * Added example how to use the cpp.linkerVariant property. * Added missing documentation for the cpp.toolchainInstallPath property. * Added missing documentation for the supported 'bare-metal' architectures. # Important Bug Fixes * Added support for Xcode 12.5 (QBS-1644). * Fix support for Python 3.9 for building Apple DMG images (QBS-1642). # Infrastructure * Ubuntu Focal image was updated to use Qt 5.15.2 and Qbs 1.17.1. * Added automated tests for Qt 6 for macOS, Linux and Windows. * Added a self-hosted runner to run 'bare-metal' tests on Windows. # Contributors * Andrey Filipenkov * Denis Shienkov * Christian Kandeler * Jan Blackquill * Jake Petroules * Ivan Komissarov * Max Bespalov * Mitch Curtis * Orgad Shaneh * Raphaël Cotty * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.11.1.md0000644000175100001660000000050614776170045017232 0ustar runnerdocker# Important bugfixes * Speed up run environment setup (QTCREATORBUG-20175). * Fix qbs command line generated by the Visual Studio project generator (QBS-1303). * Install all required header files when building Qbs with qmake. * Fix undefined behavior in the qbscore library where a reference to a temporary object was stored. qbs-src-2.6.1/changelogs/changes-1.20.1.md0000644000175100001660000000055514776170045017236 0ustar runnerdocker# General * Fixed target linker flags on FreeBSD (QBS-1312). * Fixed file time precision on FreeBSD. * Added additional logging to the Qt module provider when no qmakes were found. * Some fixes to CMake build. * Fixed incorrect usage of the qmlcachegen binary (QBS-1676). # Android Support * Added stripping for release builds. * Fix generation of aab packages. qbs-src-2.6.1/changelogs/changes-2.5.1.md0000644000175100001660000000042714776170045017160 0ustar runnerdocker# General * Fixed use of wrong declaration when looking up properties via the parent item (QBS-1821). * Fixed crash when resolving Probes. # CI * Updated to Qt 6.7.3 for macOS (QBS-1799). * Switched macOS jobs to macOS 13. # Contributors * Christian Kandeler * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-1.10.0.md0000644000175100001660000000353714776170045017237 0ustar runnerdocker# General * Added the `vcs` module to provide VCS repository information. Git and Subversion are supported initially. * Added initial support for the Universal Windows Platform. * Improved a lot of error messages. # Language * Profiles can now be defined within a project using the `Profile` item. * Groups without a prefix now inherit the one of the parent group. * Both the `Module` and the `FileTagger` item now have a `priority` property, allowing them to override conflicting instances. * It is now possible to add file tags to generated artifacts by setting the new `fileTags` property in a group that has a `fileTagsFilter`. * Added new open mode `TextFile.Append`. * Added the `filePath` function to the `TextFile` class. * `Process` and `TextFile` objects in rules, commands and configure scripts are now closed automatically after script execution. # C/C++ Support * Added the `cpufeatures` module for abstracting compiler flags related to CPU features such as SSE. * Added property `cpp.discardUnusedData` abstracting linker options that strip unneeded symbols or sections. * Added property `cpp.variantSuffix` for making binary names unique when multiplexing products. * Added property `cpp.compilerDefinesByLanguage` providing the compiler's pre-defined macros. # Android * The deprecated `apkbuilder` tool is no longer used. # Qt * Added support for the Qt Quick compiler. * Added support for `qmlcachegen`. # Command-line interface * Removed some non-applicable options from a number of tools. * The `run` command can now deploy and run Android apps on devices, and deploy and run iOS and tvOS apps on the simulator. * Added new command `list-products`. # Documentation * Added porting guide for qmake projects. * Added in-depth descriptions of all command-line tools. * Added "How-to" for creating modules for third-party libraries. * Added a man page. qbs-src-2.6.1/changelogs/changes-2.0.1.md0000644000175100001660000000133214776170045017147 0ustar runnerdocker# General * Fixed crash when importing missing JavaScript file (QBS-1730). # C/C++ Support * Fixed building applications with mingw toolchain and Qt6 (QBS-1724). # Apple Support * Added support for Xcode 14.3. * Fixed codesigning on macOS (QBS-1722). * Fixed detecting Xcode via xcode-select tool. # Qt Support * Fixed support for Qt 6.3 on iOS. * Fixed install-qt.sh to properly support Qt for iOS. * Do not setup Qt in qbspkgconfig when cross compiling (QBS-1717). # Build System * Fixed qbsbuildconfig module. * Fixed build with Qt6.5. * Updated CI to test via Qt 6.5 on macOS and Windows. * Updated CI to test via Xcode 14.2 on macOS. # Contributors * Björn Schäpers * Christian Kandeler * Ivan Komissarov * Kai Dohmen qbs-src-2.6.1/changelogs/changes-1.22.0.md0000644000175100001660000000210714776170045017232 0ustar runnerdocker# General * A new Host service was introduced, providing information about the host system that used to be available from the qbs module, but did not really belong there. In addition, some more qbs module properties have moved to the FileInfo service. * The product variable in Export items now points to the importing product, rather than the exporting one. * Probes are now also available in ModuleProvider items. # C/C++ Support * Added support for the Open Watcom toolchain. * Reduced unneeded re-linking on Linux by ignoring changes to weak symbols in library dependencies by default. # Qt Support * Android multi-arch packages are supported again wth Qt >= 6.3. * We now use cpp.systemIncludePaths for Qt headers, so that building Qt applications no longer triggers warnings from Qt headers unrelated to the user code. # Infrastructure * Added coverage for Digital Mars compiler. * Added coverage for static Qt builds. # Contributors * Christian Kandeler * Denis Shienkov * Ivan Komissarov * Jan Blackquill * Leena Miettinen * Marius Gripsgard * Mitch Curtis * Raphael Cotty qbs-src-2.6.1/changelogs/changes-1.10.1.md0000644000175100001660000000123514776170045017231 0ustar runnerdocker# Important bugfixes * Fix assertion on project loading (QBS-1275). * Fix crash when the "original" value is misused (QBS-1255). * Fix qtquickcompiler support for qml files in subdirectories (QBS-1261). * Fix constant rebuilding after moving an external header file (QBS-1285). * Fix GCC support for "bare metal" systems (QBS-1263, QBS-1265). * Fix using ids in Depends items (QBS-1264). * Fix access to module instances in dependency parameters (QBS-1253). * Fix race condition when creating Inno Setup, NSIS, or WiX installers. * Fix release builds for Android with NDK r12 and above (QBS-1256). * Fix parametrized dependencies in Export and Module items (QBS-1287). qbs-src-2.6.1/changelogs/changes-1.13.0.md0000644000175100001660000000322614776170045017235 0ustar runnerdocker# General * Added a lot more documentation. * The `--show-progress` command line option is now supported on Windows. # Language * Introduced module providers. * The `Depends` item now falls back to `pkg-config` to locate dependencies whose names do not correspond to a qbs module. * Added the concept of job pools for limiting concurrent execution of commands by type. * Added support for rules without output artifacts. * Added `atEnd` function to the `Process` service. * Added `canonicalPath` function to the `FileInfo` service. * Removed the need to add "import qbs" at the head of project files. * The `Application`, `DynamicLibrary` and `StaticLibrary` items now have properties for more convenient installation of target binaries. # C/C++ Support * Added recursive dependency scanning of GNU ld linkerscripts. * Added new `cpp` property `linkerVariant` to force use of `gold`, `bfd` or `lld`. # Qt Support * It is no longer required to call `setup-qt` before building Qt projects. * Introduced the property `Qt.core.enableBigResources` for the creation of "big" Qt resources. * Static builds now pull in the default set of plugins as specified by Qt, and the user can specify the set of plugins by type. * Files can be explicitly tagged as mocable now. # Other modules * Added `protobuf` support for C++ and Objective-C. * Introduced the `texttemplate` module, a facility similar to qmake's `SUBSTITUTES` feature. # Android Support * The `AndroidApk` item was deprecated, a normal `Application` item can be used instead. * Building Qt apps is properly supported now, by making use of the `androiddeployqt` tool. # Autotest support * Introduced the `autotest` module. qbs-src-2.6.1/changelogs/changes-2.2.2.md0000644000175100001660000000100614776170045017150 0ustar runnerdocker# General * Fixed name collision check for multi-part modules (QBS-1772). * Fixed potential assertion when attaching properties on non-present modules (QBS-1776). # C/C++ * Fixed handling assember flags with MSVC (QBS-1774). # Qt * Fixed the qbspkgconfig Qt provider for the case when there is no Qt (QBS-1777). # Other * Make protobuf usable without qbspkgconfig again (QBS-1663). * Add support for the definePrefix option to qbspkgconfig. # Contributors * Björn Schäpers * Christian Kandeler * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-1.6.00000644000175100001660000000163114776170045016556 0ustar runnerdocker* Added lex_yacc module. * Introduced property cpp.systemRunPaths. * Introduced the ability to check a module's version in a Depends item. * Introduced cpp.driverFlags, which allows specifying flags to be passed to the compiler driver (in any mode), but never the system linker. * Introduced cpp.linkerMode property to allow selection of the correct linker (C driver, C++ driver, or system linker) based on the objects being linked. * Added automatic escaping of arguments passed to the cpp.linkerFlags and cpp.platformLinkerFlags properties using the -Wl or -Xlinker syntaxes. To revert to the old behavior, Project.minimumQbsVersion can be set to a version lower than 1.6. * Each build configuration now requires a unique name, which is specified on the command line in the same place that qbs.buildVariant used to be specified. This allows building for multiple configurations with the same variant. qbs-src-2.6.1/changelogs/changes-2.6.1.md0000644000175100001660000000027014776170045017155 0ustar runnerdocker# Language * Fixed behavior of SubProject.inheritProperties (QBS-1836). # Darwin support * Fixed generating iOS codesign entitlements (QBS-1826). # Contributors * Christian Kandeler qbs-src-2.6.1/changelogs/changes-1.8.00000644000175100001660000000317014776170045016560 0ustar runnerdockerFeatures: * General: * It is no longer strictly required to provide a profile. * Sub-second timestamp resolutions are now supported on Unix systems. * Added a convenient replacement for product.moduleProperty("module", "property"), namely product.module.property. * The loadFile and loadExtension functions are deprecated in favor of the new require function, which accepts arguments of either form accepted by the deprecated functions. * Added new tool qbs-create-project to set up a new qbs project from an existing source tree. * FileTagger items can now have conditions. * Probe items can now appear directly under a Project item. * Cpp module: * Added support for QNX and the QCC toolchain * Added the cpp.useRPathLink property to control whether to use the -rpath-link linker option. * Provided the means to easily combine source files for the C language family in order to support "amalgamation builds". * Introduced cpp.treatSystemHeadersAsDependencies. * Qt modules: * Introduced property Qt.core.combineMocOutput. * Introduced Qt.core.enableKeywords for simple disabling of the "signals", "slots" and "emit" symbols. Important bug fixes: * Improved scalability of parallel builds on Linux by starting Process commands via a dedicated launcher process. Behavior changes: * The base directory for source files changed from the product source directory to the parent directory of the file where the files are listed. qbs-src-2.6.1/changelogs/changes-1.8.10000644000175100001660000000077614776170045016572 0ustar runnerdockerImportant bug fixes: * Qbs-specific build errors are now correctly linked in Qt Creator's issues pane (QBS-1151). * Fixed automatic base profile assignment for MSVC Qt installations (QBS-1141) * Various QNX fixes (QBS-1136, QBS-1137, QBS-1138, QBS-1139, QBS-1143). Behavior changes: * Users now get early error messages if they forget the "modules", "products" or "projects" prefix in command line property overrides such as "modules.cpp.enableExceptions:false". qbs-src-2.6.1/changelogs/changes-1.24.0.md0000644000175100001660000000045314776170045017236 0ustar runnerdocker# General * Users can now control if and when warnings for deprecated properties are emitted. * Added FileInfo.executableSuffix(). # Qt Support * Minimum windows version is now 10.0, like for cmake and qmake. # Contributors * Christian Kandeler * Ivan Komissarov * Petr Mikhalicin * Raphael Cotty qbs-src-2.6.1/changelogs/changes-1.9.0.md0000644000175100001660000000531214776170045017160 0ustar runnerdocker# General * Setting module property values from the command line can now be done per product. * Introduced new properties `qbs.architectures` and `qbs.buildVariants` to allow product multiplexing by `qbs.architecture` and `qbs.buildVariant`, respectively. * When rebuilding a project, the environment, project file and property values are taken from the existing build graph. # Language * `Depends` items can now be parameterized to set special module parameters for one particular product dependency. The new item type `Parameter` is used to declare such parameters in a module. The new item type `Parameters` is used to allow products to set default values for such parameters in their `Export` item. * The functions `loadExtension` and `loadFile` have been deprecated and will be removed in a future version. Use the `require` function instead. # Custom Rules and Commands * Artifacts corresponding to the `explicitlyDependsOn` property are now available under this name in rules and commands. * A rule's `auxiliaryInputs` and `explicitlyDependsOn` tags are now also matched against rules of dependencies, if these rules are creating target artifacts. * Rules now have a property `requiresInputs`. If it is `false`, the rule will be run even if no artifacts are present that match its input tags. * Added a new property `relevantEnvironmentVariables` to the `Command` class. Use it if the command runs an external tool whose behavior can be influenced by special environment variables. # C/C++ Support * Added the `cpp.link` parameter to enable library dependencies to be excluded from linking. * When pulling in static library products, the new `Depends` parameter `cpp.linkWholeArchive` can now be specified to force all the library's objects into the target binary. * When pulling in library products, the new `Depends` parameter `cpp.symbolLinkMode` can now be specified to control how the library is linked into the target binary on Apple platforms: specifically, whether the library is linked as weak, lazy, reexported, and/or upward (see the `ld64` man page for more information). * The property `cpp.useCxxPrecompiledHeader`, as well as the variants for the other languages, now defaults to true. * The property `cpp.cxxLanguageVersion` now gets mapped to MSVC's `/std` option, if applicable. # Apple * Added support for building macOS disk images. # Android * Product multiplexing is no longer done via profiles, but via architecture, employing the new `qbs.architectures` property (see above). As a result, the `setup-android` command now sets up only one profile, rather than one for each architecture. * Added support for NDK Unified Headers. # Documentation * Added a "How-to" section. qbs-src-2.6.1/changelogs/changes-2.2.1.md0000644000175100001660000000040614776170045017152 0ustar runnerdocker# Language * Fixed JavaScript Date() constructor on Windows (QBS-1768). # C/C++ support * Worked around crash in cl.exe when retrieving built-in defines (QBS-1743). # CI * Fixed building release packages. # Contributors * Christian Kandeler * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-1.14.0.md0000644000175100001660000000167014776170045017237 0ustar runnerdocker# Language * The `PathProbe` item was extended to support looking for multiple files and filtering candidate files. # C/C++ Support * Added support for Visual Studio 2019. * Added support for clang-cl. * Various improvements for bare-metal toolchains, including new example projects and support for the SDCC toolchain. # Qt Support * Added the `Qt.android_support.extraLibs` property. # Other modules * The `pkgconfig` module now has a `sysroot` property. * Added gRPC support to the `protobuf.cpp` module. # Android Support * Removed support for NDK < r19. * Added new `Android.sdk` properties `versionCode` and `versionName`. # Infrastructure * Added configuration files for Travis CI. * Various fixes and improvements in the Debian Docker image; updated to to Qt 5.11.3. # Contributors * BogDan Vatra * Christian Kandeler * Christian Stenger * Davide Pesavento * Denis Shienkov * hjk * Ivan Komissarov * Joerg Bornemann * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.20.0.md0000644000175100001660000000410114776170045017224 0ustar runnerdocker# General * CMake and Qbs builds now fully support building with Qt6. * Qbs now prints the old properties set when refusing to build a project with changed properties. * Added convenience command to qbs-config to add a profile in one go instead of setting properties separately (QTCREATORBUG-25463). * Added profiling timer for module providers. # C/C++ Support * Added support for the COSMIC COLDFIRE (also known as M68K) compiler (QBS-1648). * Added support for the COSMIC HCS08 compiler (QBS-1641). * Added support for the COSMIC HCS12 compiler (QBS-1640). * Added support for the COSMIC STM8 compiler (QBS-1639). * Added support for the COSMIC STM32 compiler (QBS-1638). * Added support for the new Digital Mars toolchain (QBS-1636). * The new cpp.enableCxxLanguageMacro property was added for the MSVC toolchain that controls the /Zc:__cplusplus required for proper support of the new C++ standards (QBS-1655). * Added support for the "c++20" language version for the MSVC toolchain which results in adding the /std:c++latest flag (QBS-1656). # Qt Support * Consider "external" modules * Fix support for qml binaries that were moved to the libexec directory in Qt 6.2 (QBS-1636). # Android Support * Added option to use dex compiler d8 instead of dx. * Ministro support was removed. * Fix link with static stl on Android (QBS-1654) * The default Android Asset Packaging Tool was change from aapt to aapt2. # Apple Support * Qbs now uses embedded build specs from Xcode 12.4 when bundle.useXcodeBuildSpecs is true instead of older specs from Xcode 9.2. # Important Bug Fixes * Fix handling cpp.linkerWrapper with the MSVC toolchain (QBS-1653). # Infrastructure * Windows-only tests are moved to a separate tst_blackbox_windows binary. * Qbs was updated to 1.18.2 in Docker images as well as in GitHub actions jobs. * Added Qbs build and tests with the MinGW toolchain. * Added CMake build with Qt6 on Linux. # Contributors * Christian Kandeler * Denis Shienkov * Eike Ziller * Ivan Komissarov * Jan Blackquill * Mitch Curtis * Oswald Buddenhagen * Raphaël Cotty * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.12.1.md0000644000175100001660000000100514776170045017226 0ustar runnerdocker# Important bugfixes * Lifted the restriction that the -march option cannot appear in cpp.*Flags (QBS-1018). * All required header files get installed now (QBS-1370). * Fixed rpaths not ending up on the command line under certain circumstances (QBS-1372). * Fixed possible crash when scanning qrc files (QBS-1375). * Fixed spurious re-building of .pc and .qbs module files. * Fixed possible crash on storing a build graph after re-resolving. * Fixed possible assertion on input artifacts with alwaysUpdated == false. qbs-src-2.6.1/changelogs/changes-2.5.0.md0000644000175100001660000000302014776170045017147 0ustar runnerdocker# Language * `Product` items can now contain `Scanner` items. * `Group` items can now contain other items, namely `Depends`, `FileTagger`, `Rule`, and `Scanner`. * `Group` items can now act like `Properties` items. Top-level properties can be set via the `product` and `module` prefixes, respectively. * The conditions of `Properties` items can now overlap, allowing more than one such item to contribute to the value of list properties. * The "else case" semantics for `Properties` items is now deprecated. Instead, `Properties` items can be marked as containing fallback values by giving them a condition with the special value `undefined`. * The conditions of `Properties` items now default to `true`. * Introduced the special `module` variable for `Module` items, which acts like `product` in `Product` items. * Resolving values of path properties in `Export` items relative to the exporting product's location is now deprecated. # C/C++ Support * Added support for C++20 modules. # Android support * Added new properties `Android.sdk.d8Desugaring` and `Android.sdk.extraResourcePackages`. # Qt Support * Added new property `Qt.core.translationsPath`. * Adapted to changes in framework releases (QBS-1816). # Other * Added experimental WebAssembly support via emscripten. * The `freedesktop` module now supports localization and deployment of more than one icon. * The JSON API now supports renaming files. # Contributors * Aaron McCarthy * Christian Kandeler * Danya Patrushev * Ivan Komissarov * Leon Buckel * Roman Telezhynskyi qbs-src-2.6.1/changelogs/changes-2.4.0.md0000644000175100001660000000142714776170045017157 0ustar runnerdocker# General * Added a Conan module provider (QBS-1665). * Added a flatbuffers module (QBS-1666). * Rules trying to create artifacts outside the build directory is now a hard error (QBS-1268). * More details are now printed when a command times out (QBS-1750). * Updated the bundled quickjs library. # Language * The pkg-config based fallback provider was removed. * It is no longer allowed to attach a QML id to a module item. # Apple support * Fixed symlinks for multi-arch binaries on Apple platforms (QBS-1797). # C/C++ Support * Added new cpp.importPrivateLibraries property that controls whether to automatically import external libraries from dependencies. # Documentation * Added more tutorials. # Contributors * Christian Kandeler * Ivan Komissarov * Kai Dohmen * Raphael Cotty qbs-src-2.6.1/changelogs/changes-1.21.0.md0000644000175100001660000000412014776170045017226 0ustar runnerdocker# General * A new qbsModuleProviders property was added to Project and Product items which allows to specify which providers will be run (QBS-1604). * Added a new library for reading *.pc files which allows to avoid launching multiple pkg-config processes and also gives QBS more information about dependencies between *.pc files (QBS-1615). * A new qbspkgconfig provider was added which will replace the fallback provider (QBS-1614). This new provider uses the built-in library and is capable of setting Qt libraries as well. * capnproto and protobuf modules can now use runtime provided by the qbspkgconfig provider. * A new ConanfileProbe.verbose property was added which can be useful to debug problems with Conan. * Qbs no longer migrates the "profiles/" dir from earlier Qbs versions (QTCREATORBUG-26475). Old directories might be cleaned up manually. * FileInfo now always uses high-precision timer on all OSes. * Fixed a problem with overriding stringList properties in ModuleProviders from command-line. # C/C++ Support * Added support for c++23. * Add Elbrus E2K architecture for the GCC toolchain (QBS-1675). * COSMIC cpp module now avoids using relative file paths as much as possible. * Some refactoring was done in the cpp modules to share more code. # Android Support * Added Android.ndk.buildId property which allows to overwrite the default value (sha1) for the --build-id linker flag. * Fixed reading *.prl files with Qt >= 6.0. * Fixed rcc path with Qt >= 6.2. # Documentation * Added a new page with the list of ModuleProviders. * Qt provider now has its own page. * Clarified that application won't be runnable by default, unless env or rpaths are set correctly. # Infrastructure * Added standalone job for building documentation. * Xcode version was bumped to 12.5.1. * Added OpenSUSE Leap docker image. * Added Android tests with different NDK versions. * Fixed QMake build with Qt 6. # Contributors * Christian Kandeler * Christian Stenger * Davide Pesavento * Denis Shienkov * Ivan Komissarov * Kai Dohmen * Orgad Shaneh * Raphaël Cotty * Richard Weickelt * Thorbjørn Lindeijer qbs-src-2.6.1/changelogs/changes-2.4.1.md0000644000175100001660000000065414776170045017161 0ustar runnerdocker# General * Fix LibraryProbe to take into account libraries both with and without the "lib" prefix. This fixes the Conan provider for MinGW. * Conan module provider no longer sets platform to "none" for baremetal toolchains (QBS-1795). # CI * CI now covers Conan tests for all platforms. Conan is also included in Linux images now. * GDB is now included in Linux images. # Contributors * Christian Kandeler * Ivan Komissarovqbs-src-2.6.1/changelogs/changes-1.19.2.md0000644000175100001660000000033714776170045017245 0ustar runnerdocker# Important Bug Fixes * codesign: Fix checking if product is a framework (QBS-1649) * codesign: Add additional signing flags at end of command (QBS-1651) * codesign: Add new codesign.timestampAlgorithm property (QBS-1651) qbs-src-2.6.1/changelogs/changes-1.24.1.md0000644000175100001660000000023014776170045017230 0ustar runnerdocker# C/C++ Support Fix macros and include paths retrieval for IAR # Build System Add fix for cmake >= 3.18 # Contributors * Denis Shienkov * Eike Ziller qbs-src-2.6.1/changelogs/changes-2.2.0.md0000644000175100001660000000233114776170045017150 0ustar runnerdocker# General * Improved speed of project resolving by employing multiple CPU cores, if available. * Improved speed of probes execution on macOS. * Object and array (var and varList) properties are now immutable in Probe items. # Language * Modules can now contain `Parameters` items. * ModuleProviders can now contain `PropertyOptions` items. # C/C++ support * Allow `"mold"` as value for `cpp.linkerVariant`. * The systemIncludePaths property is now handled correctly for clang-cl. # Apple support * Updated dmgbuild tool. This fixes bug that additional licenses are not shown in the combobox in the resulting DMG image. # Qt support * Only create qbs modules for those Qt modules that products actually need. * Users can now opt out of using RPATH when linking on Linux. # Other * Protobuf module now requires pkg-config or built-in runtime. * Protobuf module now requires C++17 on all platforms. * Capnproto module: the outputDir property is now mutable. * Added support for Groups to the VisualStudio generator. * pkgconfig module provider: mergeDependencies property is deprecated. # Contributors * Christian Kandeler * Dmitrii Meshkov * Ivan Komissarov * Nick Karg * Serhii Olendarenko * Thiemo van Engelen * Thorbjørn Lindeijer qbs-src-2.6.1/changelogs/changes-1.14.1.md0000644000175100001660000000023414776170045017233 0ustar runnerdocker# Important bugfixes * Qt support: Fix static builds on Windows (QBS-1465). * Qt support: Fix static builds with Qt >= 5.13.1. * Darwin: Adapt to Xcode 11. qbs-src-2.6.1/changelogs/changes-1.19.1.md0000644000175100001660000000047014776170045017242 0ustar runnerdocker# C/C++ Support * Fix system include support with MSVC >= 19.29.30037 # Qt Support * Fix possible command line length issue with qmlimportscanner when cross-compiling (QBS-1633). # Apple platforms * Fix stripping debug symbols in multiplexed products when cpp.separateDebugInformation is false (QBS-1647) qbs-src-2.6.1/changelogs/changes-1.11.0.md0000644000175100001660000000606714776170045017241 0ustar runnerdocker# General * Added `qbs.targetPlatform` and `qbs.hostPlatform` properties which are scalar versions of `qbs.targetOS` and `qbs.hostOS`. `qbs.targetPlatform` is a "write-only" property that can be used to set the OS/platform that is being targeted, while `qbs.targetOS` and `qbs.hostOS` should continue to be used to *read* the OS/platform that is being targeted. `qbs.targetOS` is also now read-only. * The "run" functionality as used by the command-line command of the same name now considers an executable's library dependencies, that is, it adds the paths they are located in to the respective environment variable (e.g. PATH on Windows). # Language * Modules can now declare target artifacts using the new `filesAreTargets` property of the `Group` item. * The Module.setupRunEnvironment script now has a new parameter `config`. Users can set it via the `--setup-run-env-config` option of the `run` command. The only value currently supported is `ignore-lib-dependencies`, which turns off the abovementioned injection of library dependencies' paths into the run environment. * Module.setupBuildEnvironment and Module.setupRunEnvironment now have access to the `product` and `project` variables. With regards to accessing module properties, these script now behave like rules, rather than normal properties. * Added the `BinaryFile` service for reading and writing binary data files. * The `SubProject` item now has a condition property. # C/C++ Support * Added property `cpp.rpathOrigin` which evaluates to `@loader_path` on Darwin and `$ORIGIN` on other Unix-like platforms. * Added the `qbs.toolchainType` property, which is a scalar version of the `qbs.toolchain` property and is used to set the current toolchain. * Added `cpp.driverLinkerFlags` for flags to be passed to the compiler driver only when linking. * We now properly support `"c++17"` as a possible value of `cpp.cxxLanguageVersion`. * The auto-detection mechanism for GCC-like compilers now considers typical mingw prefixes. # Qt Support * Added the Qt.scxml.generateStateMethods property to back the --statemethods option. # Command-line interface * Configuration names are now passed as "config:". * Options do not have to precede property assignments anymore. * Referencing a non-existing product in a property override now results in an error. # Documentation * Major overhaul of the module and item reference for improved readability. * Added a how-to on the topic of pre-compiled headers. * Added documentation for the built-in XML support. * Added documentation for qbs.Utilities. * Added documentation on how to target specific platforms. # Important bug fixes * Fixed some inconsistencies related to item ids (QBS-1016, QBS-1262). * Fixed slow project resolving on macOS (QBS-1277). * Fixed problems with qtquickcompiler support in Qt 5.11 (QBS-1299). * Fixed race conditions in multi-configuration builds (QBS-1308). # Other * The `InnoSetup`, `nsis`, and `wix` modules' rules now have a dependency on installable artifacts of dependencies. * Introduced the `ico` module for creating .ico and .cur files. qbs-src-2.6.1/changelogs/changes-2.0.0.md0000644000175100001660000000111314776170045017143 0ustar runnerdocker# General * Switched JavaScript engine from QtScript to QuickJS * Removed the long-deprecated loadFile() and loadExtension() functions * Removed the qmake project files # Qt support * Adapt to androiddeployqt on Windows no longer accepting tool paths without suffix in 6.4 (QTBUG-111558) # BareMetal support * Added support for HPPA architectures # Other modules * Renamed "name" to "appName" in the freedesktop module to prevent clash with built-in property # Infrastructure * Added USBSAN CI job # Contributors * Christian Kandeler * Ivan Komissarov * Orgad Shaneh * Pino Toscano qbs-src-2.6.1/changelogs/changes-1.22.1.md0000644000175100001660000000054614776170045017240 0ustar runnerdocker# General * Adapted to changes in Xcode 13.3 (QBS-1693). * Re-added several bugfixes from 1.21.1 that got lost in 1.22.0. # Qt Support * Fixed building against static Qt 6 (QBS-1692). # Android Support * Fixed wrong include path being added to the command line (QBS-1691). # Documentation * Fixed outdated use of "product" in Export items (QBS-1694). qbs-src-2.6.1/changelogs/changes-1.7.20000644000175100001660000000045214776170045016561 0ustar runnerdockerImportant bug fixes: * macOS: Fixed App Extension builds on older versions of Xcode/macOS * Windows: Fixed handling of files on network shares * Fixed syntax error in Qt module that occurred with static Qt builds * Several fixes for the Visual Studio generator (QBS-1077, QBS-1100) qbs-src-2.6.1/changelogs/changes-1.7.10000644000175100001660000000037114776170045016560 0ustar runnerdockerImportant bug fixes: * Fixed race condition in qmake build (QBS-1091) * Qt Creator no longer leaves empty build directories behind after cancelled project loading (QTCREATORBUG-17543) * Fixed an exception crossing the API boundary qbs-src-2.6.1/changelogs/changes-2.1.2.md0000644000175100001660000000105214776170045017150 0ustar runnerdocker# General * Fixed handling JS floating-point values for x86. * Fixed scope pollution and potential crash when assigning to provider properties (QBS-1747). * Fixed potential access to freed JSValues (QBS-1751). # Qt * Fixed building against Qt with "profiling" build variant (QBS-1758). # Apple * Fixed bundle module with Xcode-less profiles. * Fixed ApplicationExtension with Xcode-less profiles. # Infrastructure * Added CI job to be able to test XCode-less profiles on macOS. # Contributors * Christian Kandeler * Dmitry Shachnev * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-2.3.1.md0000644000175100001660000000064714776170045017162 0ustar runnerdocker# Language * Fixed look-up of qbs properties in module providers via probes (QBS-1742). # Apple support * Fixed codesign module when multiplexing over build variants (QBS-1775). # Qt support * Fixed retrieving minimum macOS/iOS versions for Qt 6.7.1. # CI * Fixed release jobs. * Fixed macOS 14.2 job. * Updated GitHub actions to recent versions to avoid warnings. # Contributors * Christian Kandeler * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-2.4.2.md0000644000175100001660000000062514776170045017160 0ustar runnerdocker# General * Fixed possible crash when exiting Qbs Session (QBS-1803). * Fixed possible "undefined" value passed to the filterFunction in ProcessCommandExecutor. # JSON API * Undefined module properties are omitted now. # Docker * Linux images now contain GNU Debugger. # CI * CI now collects and prints coredumps on Mac and Linux on test failure. # Contributors * Christian Kandeler * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-1.12.2.md0000644000175100001660000000104114776170045017227 0ustar runnerdocker# Important bugfixes * The Visual Studio 2017 Build Tools are properly supported now. * Android NDK r18 is properly supported now. * Removed invalid assertion that prevented deriving from the Properties item. * Fixed build error on some BSD hosts (QBS-1395). * setup-qt fixes: * The QtWebkit module is now properly detected (QBS-1399). * The case of the qtmain library being called "qt5main" is properly handled now (QBS-767). * Building against a Qt that was built with sanitizing support works out of the box now (QBS-1387). qbs-src-2.6.1/changelogs/changes-1.18.0.md0000644000175100001660000000517114776170045017243 0ustar runnerdocker# General * capnp: The outputDir property is now public and read-only. * setup-toochains: Include the Xcode version into the profile name profile when auto-detection an Xcode installation. * innosetup module: Add support for InnoSetup v6 * JSON API: Use the full display name of multiplexed products in the dependencies array. This allows clients to for example to properly update the search path for multiplexed dynamic libraries. # Language * Deprecate the product variable inside Export items in favor of a new exportingProduct variable. It will be removed in Qbs 1.20 (QBS-1576). * Qbs now checks string and stringList values according to the allowedValues property in the PropertyOptions item. # Protocol Buffers Support (Protobuf Module) * The deprecated protocBinary property has been removed. Use compilerPath instead. * A nanopb submodule has been added. * The outputDir property is now public and read-only. # C/C++ Support * baremetal: cpp.generateCompilerListingFiles has been implemented for KEIL ARM Clang * baremetal: cpp.enableDefinesByLanguage does now work with SDCC as well. # Qt Support * Moc is now disabled when building aggregate products. # Android Support * Support for the new directory layout of Qt6 has been added (QBS-1609). * Input file generation for androiddeployqt has been improved (QBS-1613). * Debugging experience of multi-architecture Android projects with Qbs and Qt Creator has been improved. Binaries are now generated in a directory layout that Qt Creator expects and debug information is no longer stripped away. # Documentation * baremetal: A new WiFi access point example for the ESP8266 MCU using the GCC toolchain has been added. * baremetal: A new example for Nordic's pca10001 board has been added. It supports GCC, KEIL and IAR. * baremetal: The stm32f103 example supports IAR as well. * A howto has been added showing how to easily disable compiler warnings. * Instructions for building Qbs with CMake have been added (QBS-1618). # Important Bug Fixes * Qt modules could not be used in Export item when building for Android (QBS-1576). * Variable substitution in Info.plist files was broken for '@VAR@' syntax (QBS-1601). * CppApplication failed to build for Android when using Qt > 5.14.0 and multiplexing over multiple architectures (QBS-1608). * Moc output was broken when including Boost project header files (QBS-1621). # Contributors * Alberto Mardegan * André Pönitz * Christian Kandeler * Christian Stenger * Cristian Adam * Denis Shienkov * Eike Ziller * Ivan Komissarov * Jochen Ulrich * Kai Dohmen * Mitch Curtis * Orgad Shaneh * Raphaël Cotty * Richard Weickelt qbs-src-2.6.1/changelogs/changes-2.3.0.md0000644000175100001660000000254414776170045017157 0ustar runnerdocker# General * Added an LSP language server that provides support for following symbols and completion in IDEs (QBS-395). * Module properties are now directly available within groups in modules (QBS-1770). * Added possibility to export products to CMake via the new Exporter.cmake module. * Deprecated the pkgconfig-based fallback module provider. * If a project needs to be re-resolved, we now print the reason. * Added some tutorials. * Wildards handling was rewritten to track changes more accurate. * Module 'validate' scripts are no longer run for erroneous product in IDE mode. * Add example how to use Exporters. # C/C++ Support * Private dependencies of products are not traversed more than once anymore (QBS-1714). # Language * Module properties are now accessible for groups in modules (QBS-1770). * Fixed pathList properties in Probes (QBS-1785). * The qbspkgconfig.mergeDependencies property was removed. * ModuleProviders now support the 'allowedValues' property of the PropertyOptions item (QBS-1748). # Apple * Adapted darwin support to Xcode 15.3. # CI * Changed Linux Docker images from Focal to Jammy. * Updated compilers and linters to recent versions. * Added clang-format job to check code style. * The project.withExamples property was removed. # Contributors * Christian Kandeler * Dmitrii Meshkov * Ivan Komissarov * Raphael Cotty * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.7.00000644000175100001660000000204714776170045016561 0ustar runnerdockerFeatures: * Added a generator for Visual Studio projects. * The Group item is now nestable. * Stricter type checking for properties. * Added support for generating qrc files. * Added full support for the QtScxml module. * Introduced cpp.soVersion. * Added support for building Inno Setup packages. * Tentative support for Visual Studio 2017. * We now assume UTF-8 encoding for project files. * In Scanner items, input.fileName now contains a filename rather than the full path. * Warnings encountered during project resolving are now stored and re-displayed when the project is loaded. * Documentation was improved in several places, most notably for the Rule item. * Support for the deprecated Transformer item was removed. Important bug fixes: * Long paths on Windows are handled (QBS-1068). * Cyclic module dependencies are detected (QBS-1044). * The libqbscore soname now includes the minor version, so that it will not stay the same across ABI changes (QBS-1002). qbs-src-2.6.1/changelogs/changes-1.23.1.md0000644000175100001660000000115314776170045017234 0ustar runnerdocker# C/C++ Support * Added support for c17 and c2x values in cpp.cLanguageVersion. * Added support for cpp.cLanguageVersion for the MSVC toolchain. * Fix passing linker scripts to iar and keil toolchains (QBS-1704). # Qt Support * Adapted to new location of qscxmlc in Qt 6.3. * Adapted to new location of qhelpgenerator in Qt 6.3. * Fixed setting up Qt 6.3 with qbspkgconfig. * Added QtScript module to the source tarballs (QBS-1703). # Other modules * Fixed protobuf linking on macOS 11. * Fixed handling empty variables in qbspkgconfig (QBS-1702) # Contributors * Christian Kandeler * Ivan Komissarov * Orgad Shaneh qbs-src-2.6.1/changelogs/changes-1.12.0.md0000644000175100001660000000355714776170045017243 0ustar runnerdocker# General * Added new module `Exporter.qbs` for creating qbs modules from products. * Added new module `Exporter.pkgconfig` for creating pkg-config metadata files. * Introduced the concept of system-level qbs settings. * Added a Makefile generator. * All command descriptions now contain the product name. # Language * The `explicitlyDependsOn` property of the `Rule` item no longer considers target artifacts of product dependencies. The new property `explicitlyDependsOnFromDependencies` can be used for that purpose. * The `excludedAuxiliaryInputs` property of the `Rule` item has been renamed to `excludedInputs`. The old name is now deprecated. * Added a new property type `varList`. * Added `FileInfo.suffix` and `FileInfo.completeSuffix`. * The deprecated JS extensions `XmlDomDocument` and `XmlDomElement` have been removed. Use `Xml.DomDocument` and `Xml.DomDocument` instead. # C/C++ Support * For MSVC static libraries, compiler-generated PDB files are now tagged as `debuginfo_cl` to make them installable. * The `cxxLanguageVersion` property can now be set to different values in different modules, and the highest value will be chosen. # Qt Support * Amalgamation builds work properly now in the presence of "mocable" files. * Fixed some redundancy on the linker command line. # Other modules * Added support for `%option outfile` and `%output` to the `lex_yacc` module. * The `vcs` module now creates the header file even if no repository is present. # Autotest support * Added an `auxiliaryInputs` property to the `AutotestRunner` item for specifying run-time dependencies of test executables. * The `AutotestRunner` item now has a `workingDirectory` property. By default, the respective test executable's location is used. # Important bug fixes * Disabled products no longer cause their exported dependencies to get pulled into the importing product (QBS-1250). qbs-src-2.6.1/changelogs/changes-2.0.2.md0000644000175100001660000000054514776170045017155 0ustar runnerdocker# General * Fixed handling of non-string exceptions (QBS-1734). * Fixed Utilities.versionCompare() for four-segment versions numbers (QBS-1733). # Qt Support * Added special handling for unclean paths in prl files (QBS-1732). * Fixed support for static plugins and Qt >= 6.5 (QBS-1732). # Contributors * Christian Kandeler * Ivan Komissarov * Leon Buckel qbs-src-2.6.1/changelogs/changes-2.1.0.md0000644000175100001660000000156714776170045017161 0ustar runnerdocker# General * Improved speed and correctness of project resolving. * Fixed possible segmentation fault when quitting a session. * Fixed regression in BinaryFile (QBS-1740). * Added possibility to import and export Qbs settings in the JSON format (QBS-1685). # Modules * Dependencies are no longer merged by default in the qbspkgconfig module provider (QBS-1710). * Protobuf modules now export the desired c++ version (c++17 on macOS, c++14 otherwise). # Apple Support * Updated dmgbuild to the upstream. # Documentation * Added documentation for the path, filePath, product and project variables. * Added sample codesign settings to the Cocoa Touch Application example. # Build System * Updated Qt static Docker image to Qt 6.5.0 and Qbs 1.24. # Contributors * Andrey Filipenkov * Christian Kandeler * Denis Shienkov * Ivan Komissarov * Marc Mutz * Raphael Cotty * Thiemo van Engelen qbs-src-2.6.1/changelogs/changes-1.6.10000644000175100001660000000040714776170045016557 0ustar runnerdockerFeatures: * Added cpp.linkerWrapper property. Important bug fixes: * Fixed a number of bugs evaluating module properties (QBS-845, QBS-1005). * Fixed x86_64 > x86 cross compiling (QBS-1028). * Fixed dynamic rules with generated inputs (QBS-1029). qbs-src-2.6.1/changelogs/changes-1.17.1.md0000644000175100001660000000035714776170045017244 0ustar runnerdocker# Important bugfixes * Android: Fix support for Qt 5.15 (QBS-1580). * Android: Allow exporting of Qt modules in Export items (QBS-1576) * Darwin: Fix ios-simulator builds with XCode 12 # Contributors * Raphaël Cotty * Ivan Komissarov qbs-src-2.6.1/changelogs/changes-1.15.0.md0000644000175100001660000000327714776170045017245 0ustar runnerdocker# General * Added a session command which offers a JSON-based API for interaction with other tools via stdin/ stdout. This allows for proper Qbs support in IDEs that do not use Qt or even C++. # Language * Probes are now evaluated before Profile items and can be used to create profiles on project level. * AutotestRunner got a separate job pool. * Added a timeout property to Command, JavaScriptCommand and AutotestRunner. This allows to identify and kill stuck commands. # C/C++ Support * Ensure proper support of Xcode 11. * Linker map files can be generated with all toolchains. * Bare metal toolchains can now generate listing files. * Improve the command line output filtering of bare metal toolchains. * Added support for clang in mingw mode on Windows. * Added msp430 support to GCC and IAR. * Added STM8 support to IAR and SDCC. * Added IDE project generators for IAR Embedded Workbench for ARM, AVR, 8051, MSP430, and STM8 architectures. * Added IDE project generators for KEIL uVision v4 for ARM and 8051 architectures. * Added more bare metal project examples for various target platforms. * The IAR, KEIL and SDCC toolchains are now found automatically in various. locations by the setup-toolchains command and by probes if no installPath is set in the profile. # Infrastructure * Automated build and testing on Ubuntu, macOS and Windows. * Added Ubuntu bionic Docker image which replaces Debian stretch. * Updated Qt in the Ubuntu and Windows Docker images to 5.12. * When building Qbs, Qt libraries can now be bundled on Linux, macOS and Windows. # Contributors * Alberto Mardegan * Christian Kandeler * Denis Shienkov * Ivan Komissarov * Jochen Ulrich * Joerg Bornemann * Richard Weickelt qbs-src-2.6.1/changelogs/changes-1.13.1.md0000644000175100001660000000106114776170045017231 0ustar runnerdocker# Important bugfixes * Qt support: Plugins are no longer linked into static libraries when building against a static Qt (QBS-1441). * Qt support: Fixed excessively long linker command lines (QBS-1441). * Qt support: Host libraries are now looked up at the right location (QBS-1445). * Qt support: Fixed failure to find Qt modules in Qt Creator when re-parsing a project that hasn't been built yet. * macOS: Properties in bundle.infoPlist are no longer overridden (QBS-1447). * iOS: Fixed generation of default Info.plist (QBS-1447). qbs-src-2.6.1/changelogs/changes-2.6.0.md0000644000175100001660000000242114776170045017154 0ustar runnerdocker# General * Command descriptions are now printed with the product name as the prefix instead of the suffix. * When building only specific products via the `-p` option, dependent products are not necessarily built in their entirety anymore. Instead, only the artifacts required for the requested products are built. * ConanfileProbe now supports Conan 2 and QbsDeps generator. # Language * Added new `Rule` property `auxiliaryInputsFromDependencies`. * The `Rule` property `explicitlyDependsOnFromDependencies` now matches all artifacts from the dependencies, not just target artifacts. * The version requirement in a `Depends` item is now checked earlier, fixing the problem that a non-matching version of a library could break project resolving if it was found before the matching version. # API * Added a mode that loads a build graph followed by a forced re-resolve. * In IDE mode, messages of type "error" instead of "warning" are now emitted for errors that would stop the build in non-IDE mode (QBS-1818). # Darwin support * Added privacy manifest support for frameworks (QBS-1812). # Qt Support * Added `lupdate` support via the new `QtLupdateRunner` item (QBS-486). # Contributors * Christian Kandeler * Ivan Komissarov * Marcus Tillmanns * Orgad Shaneh * Turkaev Usman qbs-src-2.6.1/changelogs/changes-2.1.1.md0000644000175100001660000000032714776170045017153 0ustar runnerdocker# General * Fixed Probe lookup in multiplexed products. * Fixed excessively slow module merging in some circumstances. * Fixed building QuickJS on x86 systems. # Contributors * Christian Kandeler * Ivan Komissarov qbs-src-2.6.1/.gitignore0000644000175100001660000000075314776170045014445 0ustar runnerdocker.qmake.cache .qmake.stash .qbs .vscode* build *.dll *.dylib *.exe *.exp *.ilk *.manifest *.obj *.pdb *.pro.user* *.qbs.user* CMakeLists.txt.user* *.xcodeproj/ target_wrapper.sh *~ *.o *.lib *.so moc_*.cpp qrc_*.cpp *.moc *.qch *.a *.cpp.orig ui_*.h Makefile* debug/ release/ /tests/auto/blackbox/testWorkDir /tests/auto/blackbox/tst_blackbox /tests/auto/buildgraph/tst_buildgraph /tests/auto/language/tst_language /tests/auto/tools/tst_tools *.app/ *_resource.rc bin/* doc/qbs/html/* /lib qbs-src-2.6.1/LICENSE.GPL3-EXCEPT0000644000175100001660000010701314776170045015151 0ustar runnerdockerThis is the GNU General Public License version 3, annotated with The Qt Company GPL Exception 1.0: ------------------------------------------------------------------------- The Qt Company GPL Exception 1.0 Exception 1: As a special exception you may create a larger work which contains the output of this application and distribute that work under terms of your choice, so long as the work is not otherwise derived from or based on this application and so long as the work does not in itself generate output that contains the output from this application in its original or modified form. Exception 2: As a special exception, you have permission to combine this application with Plugins licensed under the terms of your choice, to produce an executable, and to copy and distribute the resulting executable under the terms of your choice. However, the executable must be accompanied by a prominent notice offering all users of the executable the entire source code to this application, excluding the source code of the independent modules, but including any changes you have made to this application, under the terms of this license. ------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qbs-src-2.6.1/scripts/0000755000175100001660000000000014776170045014137 5ustar runnerdockerqbs-src-2.6.1/scripts/build-qbs-doc.sh0000755000175100001660000000450114776170045017123 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com). ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -e if [ -z "${QBS_BUILD_PROFILE}" ]; then QBS_BUILD_PROFILE=$(qbs config defaultProfile | cut -d: -f2 | tr -d '[:space:]') fi if [ -z "${QBS_BUILD_PROFILE}" ]; then echo "Either QBS_BUILD_PROFILE or a defaultProfile must be set." exit 1 fi # # Additional build options # BUILD_OPTIONS="\ profile:${QBS_BUILD_PROFILE} \ ${BUILD_OPTIONS} \ config:documentation \ " qbs build -p "qbs documentation" ${BUILD_OPTIONS} qbs-src-2.6.1/scripts/test-qt-for-android.sh0000755000175100001660000000671114776170045020306 0ustar runnerdocker#!/usr/bin/env bash set -eu ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# export PATH="$1:$PATH" export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" # # These are set outside of this script, for instance in the Docker image # QT_INSTALL_DIR=/opt/Qt/${QT_VERSION} echo "Android SDK installed at ${ANDROID_SDK_ROOT}" echo "Android NDK installed at ${ANDROID_NDK_ROOT}" echo "Qt installed at ${QT_INSTALL_DIR}" # Cleaning profiles qbs config --unset profiles.qbs_autotests-android qbs config --unset profiles.qbs_autotests-android-qt # Setting auto test profiles qbs setup-android --ndk-dir ${ANDROID_NDK_ROOT} --sdk-dir ${ANDROID_SDK_ROOT} qbs_autotests-android qbs setup-android --ndk-dir ${ANDROID_NDK_ROOT} --sdk-dir ${ANDROID_SDK_ROOT} --qt-dir ${QT_INSTALL_DIR} qbs_autotests-android-qt export QBS_AUTOTEST_PROFILE=qbs_autotests-android export QBS_AUTOTEST_ALWAYS_LOG_STDERR=true export QTEST_FUNCTION_TIMEOUT=9000000 if [ ! "${QT_VERSION}" \< "5.14.0" ] && [ "${QT_VERSION}" \< "6.0.0" ]; then echo "Using multi-arch data sets for qml tests (only for qt version >= 5.14 and < 6.0.0) with all architectures" qbs config --list tst_blackbox-android fi; if [ ! "${QT_VERSION}" \< "6.3.0" ]; then echo "Using multi-arch data sets for qml tests (only for qt version >= 6.3.0) with all architectures" qbs config --list tst_blackbox-android fi; echo "Using single-arch (armv7a) data sets for qml tests" qbs config --unset profiles.qbs_autotests-android-qt.qbs.architectures qbs config profiles.qbs_autotests-android-qt.qbs.architecture armv7a qbs config --list tst_blackbox-android qbs-src-2.6.1/scripts/install-ow.sh0000755000175100001660000000753514776170045016601 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2022 Denis Shienkov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu set -o pipefail function show_help() { cat < Root directory where to install the components. Maps to c:/watcom on Windows, /opt/watcom on Linux by default. --version The desired toolchain version. Currently supported only 2.0 version. EOF } VERSION=2.0 INSTALL_DIR= BIN_DIR= if [[ "$OSTYPE" =~ "linux" ]]; then INSTALL_DIR="/opt/watcom" if [[ "$HOSTTYPE" == "x86_64" ]]; then BIN_DIR="binl64" elif [[ "$HOSTTYPE" == "x86" ]]; then BIN_DIR="binl" fi elif [[ "$OSTYPE" == "msys" ]]; then INSTALL_DIR="/c/watcom" if [[ "$HOSTTYPE" == "x86_64" ]]; then BIN_DIR="binnt64" elif [[ "$HOSTTYPE" == "x86" ]]; then BIN_DIR="binnt" fi fi while [ $# -gt 0 ]; do case "$1" in --directory|-d) INSTALL_DIR="$2" shift ;; --version) VERSION="$2" shift ;; --help|-h) show_help exit 0 ;; *) ;; esac shift done if [ -z "${INSTALL_DIR}" ]; then echo "No --directory specified or auto-detection failed." >&2 exit 1 fi if [ -z "${VERSION}" ]; then echo "No --version specified." >&2 exit 1 fi DOWNLOAD_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'ow-tmp'` VERSION_MAJOR=`echo $VERSION | cut -d. -f1` VERSION_MINOR=`echo $VERSION | cut -d. -f2` OW_URL="https://github.com/open-watcom/open-watcom-v${VERSION_MAJOR}/releases/download/Current-build/ow-snapshot.tar.xz" OW_TAR="${DOWNLOAD_DIR}/ow.tar.xz" echo "Downloading compiler from ${OW_URL}..." >&2 curl --progress-bar -L -o ${OW_TAR} ${OW_URL} >&2 echo "Unpacking compiler to ${INSTALL_DIR}..." >&2 7z x "${OW_TAR}" -so | 7z x -aoa -si -ttar -o"${INSTALL_DIR}" >/dev/null 2>&1 echo "${INSTALL_DIR}/${BIN_DIR}" rm -f ${OW_TAR} qbs-src-2.6.1/scripts/print-cores.sh0000755000175100001660000000040314776170045016740 0ustar runnerdocker#!/bin/bash for file in $(find /cores -maxdepth 1 -name 'core.*' -print); do echo "================================ $file ================================" gdb -ex 'thread apply all bt' -ex 'quit' ./release/install-root/usr/local/bin/qbs $file done; qbs-src-2.6.1/scripts/install-qt.sh0000755000175100001660000003641714776170045016601 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu function help() { cat < Root directory where to install the components. Maps to C:/Qt on Windows, /opt/Qt on Linux, /usr/local/Qt on Mac by default. -f, --force Force download and do not attempt to re-use an existing installation. --host The host operating system. Can be one of linux_x64, mac_x64, windows_x86. Auto-detected by default. --target The desired target platform. Can be one of desktop, android, ios. The default value is desktop. --toolchain The toolchain that has been used to build the binaries. Possible values depend on --host and --target, respectively: linux_x64 android any, android_armv7, android_arm64_v8a desktop gcc_64 (default) mac_x64 android any, android_armv7, android_arm64_v8a desktop clang_64 (default) ios ios windows_x86 android any, android_armv7, android_arm64_v8a desktop win64_mingw73, win64_msvc2017_64 (default) --version The desired Qt version. Currently supported are all versions above 5.9.0. EOF } TARGET_PLATFORM=desktop COMPONENTS= VERSION= FORCE_DOWNLOAD=false MD5_TOOL=md5sum case "$OSTYPE" in *linux*) HOST_OS=linux_x64 INSTALL_DIR=/opt/Qt TOOLCHAIN=gcc_64 ;; *darwin*) HOST_OS=mac_x64 INSTALL_DIR=/usr/local/Qt TOOLCHAIN=clang_64 MD5_TOOL="md5 -r" ;; msys) HOST_OS=windows_x86 INSTALL_DIR=/c/Qt TOOLCHAIN=win64_msvc2015_64 ;; *) HOST_OS= INSTALL_DIR= ;; esac while [ $# -gt 0 ]; do case "$1" in --directory|-d) INSTALL_DIR="$2" shift ;; --force|-f) FORCE_DOWNLOAD=true ;; --host) HOST_OS="$2" shift ;; --target) TARGET_PLATFORM="$2" shift ;; --toolchain) TOOLCHAIN=$(echo $2 | tr '[:upper:]' '[:lower:]') shift ;; --version) VERSION="$2" shift ;; --help|-h) help exit 0 ;; *) COMPONENTS="${COMPONENTS} $1" ;; esac shift done if [ -z "${HOST_OS}" ]; then echo "No --host specified or auto-detection failed." >&2 exit 1 fi if [ -z "${INSTALL_DIR}" ]; then echo "No --directory specified or auto-detection failed." >&2 exit 1 fi if [ -z "${VERSION}" ]; then echo "No --version specified." >&2 exit 1 fi if [ -z "${COMPONENTS}" ]; then echo "No components specified." >&2 exit 1 fi case "$TARGET_PLATFORM" in android) ;; ios) ;; desktop) ;; wasm) ;; *) echo "Error: TARGET_PLATFORM=${TARGET_PLATFORM} is not valid." >&2 exit 1 ;; esac HASH=$(echo "${OSTYPE} ${TARGET_PLATFORM} ${TOOLCHAIN} ${VERSION} ${INSTALL_DIR}" | ${MD5_TOOL} | head -c 16) HASH_FILEPATH="${INSTALL_DIR}/${HASH}.manifest" INSTALLATION_IS_VALID=false if ! ${FORCE_DOWNLOAD} && [ -f "${HASH_FILEPATH}" ]; then INSTALLATION_IS_VALID=true while read filepath; do if [ ! -e "${filepath}" ]; then INSTALLATION_IS_VALID=false break fi done <"${HASH_FILEPATH}" fi if ${INSTALLATION_IS_VALID}; then echo "Already installed. Skipping download." >&2 exit 0 fi MIRRORS="\ http://ftp.acc.umu.se/mirror/qt.io/qtproject \ http://ftp.fau.de/qtproject \ http://download.qt.io \ " for MIRROR in ${MIRRORS}; do if curl "${MIRROR}/online" -s -f -o /dev/null; then break; else echo "Server ${MIRROR} not availabe. Trying next alternative..." >&2 MIRROR="" fi done DOWNLOAD_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'install-qt'` # # The repository structure is a mess. Try different URL variants # function compute_url(){ local COMPONENT=$1 local CURL="curl -s -L" local BASE_URL="${MIRROR}/online/qtsdkrepository/${HOST_OS}/${TARGET_PLATFORM}" local ANDROID_ARCH=$(echo ${TOOLCHAIN##android_}) if [[ "${COMPONENT}" =~ "qtcreator" ]]; then if [[ "${HOST_OS}" == "windows_x86" ]]; then # newer QtC versions do not supported x86 version anymore HOST_OS="windows_x64" fi SHORT_VERSION=${VERSION%??} BASE_URL="${MIRROR}/official_releases/qtcreator" REMOTE_PATH="${SHORT_VERSION}/${VERSION}/installer_source/${HOST_OS}/qtcreator.7z" echo "${BASE_URL}/${REMOTE_PATH}" return 0 elif [[ "${COMPONENT}" =~ "mingw" ]]; then REMOTE_BASE="tools_mingw90/qt.tools.${TOOLCHAIN}${VERSION//./}" REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "[[:alnum:]_.\-]*7z" | grep -v "meta" | head -1)" if [ ! -z "${REMOTE_PATH}" ]; then echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}" return 0 fi else REMOTE_BASES=( # New repository format (>=6.0.0) "qt6_${VERSION//./}/qt.qt6.${VERSION//./}.${TOOLCHAIN}" "qt6_${VERSION//./}/qt.qt6.${VERSION//./}.${HOST_OS//_x64/}_${TOOLCHAIN}" "qt6_${VERSION//./}/qt.qt6.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}" "qt6_${VERSION//./}/qt.qt6.${VERSION//./}.${COMPONENT}.${HOST_OS//_x64/}_${TOOLCHAIN}" "qt6_${VERSION//./}_${ANDROID_ARCH}/qt.qt6.${VERSION//./}.${TOOLCHAIN}" "qt6_${VERSION//./}_${ANDROID_ARCH}/qt.qt6.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}" "qt${VERSION//./_}/qt6_${VERSION//./}_${TOOLCHAIN}/qt.qt6.${VERSION//./}.${TOOLCHAIN}" "qt${VERSION//./_}/qt6_${VERSION//./}_${TOOLCHAIN}/qt.qt6.${VERSION//./}.${COMPONENT}" "qt${VERSION//./_}/qt6_${VERSION//./}_${TOOLCHAIN}/qt.qt6.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}" # New repository format (>=5.9.6) "qt5_${VERSION//./}/qt.qt5.${VERSION//./}.${TOOLCHAIN}" "qt5_${VERSION//./}/qt.qt5.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}" # Multi-abi Android since 5.14 "qt5_${VERSION//./}/qt.qt5.${VERSION//./}.${TARGET_PLATFORM}" "qt5_${VERSION//./}/qt.qt5.${VERSION//./}.${COMPONENT}.${TARGET_PLATFORM}" # Older repository format (<5.9.0) "qt5_${VERSION//./}/qt.${VERSION//./}.${TOOLCHAIN}" "qt5_${VERSION//./}/qt.${VERSION//./}.${COMPONENT}.${TOOLCHAIN}" ) for REMOTE_BASE in ${REMOTE_BASES[*]}; do REMOTE_PATH="$(${CURL} ${BASE_URL}/${REMOTE_BASE}/ | grep -o -E "[[:alnum:]_.\-]*7z" | grep "${COMPONENT}" | tail -1)" if [ ! -z "${REMOTE_PATH}" ]; then echo "${BASE_URL}/${REMOTE_BASE}/${REMOTE_PATH}" return 0 fi done fi echo "Could not determine a remote URL for ${COMPONENT} with version ${VERSION}">&2 exit 1 } function version { echo "$@" | awk -F. '{ printf("%03d%03d%03d\n", $1,$2,$3); }'; } mkdir -p ${INSTALL_DIR} rm -f "${HASH_FILEPATH}" for COMPONENT in ${COMPONENTS}; do if [[ "${COMPONENT}" =~ "qtcreator" ]] && [[ "${HOST_OS}" != "mac_x64" ]]; then UNPACK_DIR="${INSTALL_DIR}/Tools/QtCreator" mkdir -p ${UNPACK_DIR} else UNPACK_DIR="${INSTALL_DIR}" fi if [ "$(version "${VERSION}")" -ge "$(version "6.0.0")" ]; then if [[ "${COMPONENT}" =~ "qtscript" ]] || [[ "${COMPONENT}" =~ "qtscxml" ]] || [[ "${COMPONENT}" =~ "qtx11extras" ]]; then echo "Component ${COMPONENT} was removed in Qt6, skipping" >&2 continue fi if [[ "${COMPONENT}" =~ "icu" ]] && [[ "${TARGET_PLATFORM}" =~ "wasm" ]]; then echo "Component ${COMPONENT} is not present in Qt6 (${TARGET_PLATFORM}), skipping" >&2 continue fi else if [[ "${COMPONENT}" =~ "qt5compat" ]]; then echo "Component ${COMPONENT} is not present in Qt ${VERSION}, skipping" >&2 continue fi fi URL="$(compute_url ${COMPONENT})" echo "Downloading ${COMPONENT} ${URL}..." >&2 curl --progress-bar -L -o ${DOWNLOAD_DIR}/package.7z ${URL} >&2 7z x -y -o${UNPACK_DIR} ${DOWNLOAD_DIR}/package.7z >/dev/null 2>&1 7z l -ba -slt -y ${DOWNLOAD_DIR}/package.7z | tr '\\' '/' | sed -n -e "s|^Path\ =\ |${UNPACK_DIR}/|p" >> "${HASH_FILEPATH}" 2>/dev/null rm -f ${DOWNLOAD_DIR}/package.7z # # conf file is needed for qmake # if [ "${COMPONENT}" == "qtbase" ]; then if [[ "${TOOLCHAIN}" =~ "win64_mingw" ]]; then SUBDIR="${TOOLCHAIN/win64_/}_64" elif [[ "${TOOLCHAIN}" =~ "win32_mingw" ]]; then SUBDIR="${TOOLCHAIN/win32_/}_32" elif [[ "${TOOLCHAIN}" =~ "win64_msvc" ]]; then SUBDIR="${TOOLCHAIN/win64_/}" elif [[ "${TOOLCHAIN}" =~ "win32_msvc" ]]; then SUBDIR="${TOOLCHAIN/win32_/}" elif [[ "${TOOLCHAIN}" =~ "any" ]] && [[ "${TARGET_PLATFORM}" == "android" ]]; then SUBDIR="android" elif [[ "${HOST_OS}" == "mac_x64" ]] && [[ ! "${VERSION}" < "6.1.2" ]] && [[ "${TARGET_PLATFORM}" == "desktop" ]]; then SUBDIR="macos" else SUBDIR="${TOOLCHAIN}" fi if [ "${TARGET_PLATFORM}" == "android" ] && [ ! "${VERSION}" \< "6.0.0" ]; then CONF_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/target_qt.conf" ANDROID_QMAKE_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/qmake" if [ "${TOOLCHAIN}" == "android_armv7" ] && [ ! "${VERSION}" \< "6.4.2" ]; then sed -i "s/\r//" "${CONF_FILE}" sed -i "s|HostLibraryExecutables=.\/bin|HostLibraryExecutables=.\/libexec|g" "${CONF_FILE}" chmod +x "${ANDROID_QMAKE_FILE}" sed -i "s|\\\|\/|g" "${ANDROID_QMAKE_FILE}" fi sed -i "s|target|../$TOOLCHAIN|g" "${CONF_FILE}" sed -i "/HostPrefix/ s|$|gcc_64|g" "${CONF_FILE}" QMAKE_FILE="${UNPACK_DIR}/${VERSION}/gcc_64/bin/qmake" sed -i "s|\/home\/qt\/work\/install\/bin\/qmake|$QMAKE_FILE|g" "${ANDROID_QMAKE_FILE}" sed -i "s|\/Users\/qt\/work\/install\/bin\/qmake|$QMAKE_FILE|g" "${ANDROID_QMAKE_FILE}" elif [ "${TARGET_PLATFORM}" == "ios" ] && [ ! "${VERSION}" \< "6.0.0" ]; then CONF_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/target_qt.conf" sed -i.bak "s|HostData=target|HostData=../$TOOLCHAIN|g" "${CONF_FILE}" sed -i.bak "s|HostPrefix=..\/..\/|HostPrefix=..\/..\/macos|g" "${CONF_FILE}" IOS_QMAKE_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/qmake" QMAKE_FILE="${UNPACK_DIR}/${VERSION}/macos/bin/qmake" sed -i.bak "s|\/Users\/qt\/work\/install\/bin\/qmake|${QMAKE_FILE}|g" "${IOS_QMAKE_FILE}" elif [ "${TARGET_PLATFORM}" == "wasm" ] && [ ! "${VERSION}" \< "6.0.0" ]; then CONF_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/target_qt.conf" sed -i.bak "s|HostData=target|HostData=../$TOOLCHAIN|g" "${CONF_FILE}" sed -i.bak "s|HostPrefix=..\/..\/|HostPrefix=..\/..\/gcc_64|g" "${CONF_FILE}" WASM_QMAKE_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/qmake" QMAKE_FILE="${UNPACK_DIR}/${VERSION}/gcc_64/bin/qmake" sed -i.bak "s|\/home\/qt\/work\/install\/bin\/qmake|${QMAKE_FILE}|g" "${WASM_QMAKE_FILE}" else CONF_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/bin/qt.conf" echo "[Paths]" > ${CONF_FILE} echo "Prefix = .." >> ${CONF_FILE} fi # Adjust the license to be able to run qmake # sed with -i requires intermediate file on Mac OS PRI_FILE="${UNPACK_DIR}/${VERSION}/${SUBDIR}/mkspecs/qconfig.pri" sed -i.bak 's/Enterprise/OpenSource/g' "${PRI_FILE}" sed -i.bak 's/licheck.*//g' "${PRI_FILE}" rm "${PRI_FILE}.bak" # Print the directory so that the caller can # adjust the PATH variable. echo $(dirname "${CONF_FILE}") elif [[ "${COMPONENT}" =~ "mingw" ]]; then VERSION_DIR="${VERSION//./}" if [[ "${TOOLCHAIN}" =~ "win64_mingw" ]]; then if [[ "${VERSION}" == "9.0.0" ]]; then VERSION_DIR="1120" fi echo "${UNPACK_DIR}/Tools/mingw${VERSION_DIR}_64/bin" elif [[ "${TOOLCHAIN}" =~ "win32_mingw" ]]; then echo "${UNPACK_DIR}/Tools/mingw${VERSION_DIR}_32/bin" fi elif [[ "${COMPONENT}" =~ "qtcreator" ]]; then if [ "${HOST_OS}" == "mac_x64" ]; then echo "${UNPACK_DIR}/Qt Creator.app/Contents/MacOS" else echo "${UNPACK_DIR}/bin" fi fi done qbs-src-2.6.1/scripts/address-sanitizer-suppressions.txt0000644000175100001660000000012414776170045023103 0ustar runnerdockerleak:QThread::QThread leak:QThreadPrivate::QThreadPrivate leak:QArrayData::allocate qbs-src-2.6.1/scripts/test-qbs.sh0000755000175100001660000000444614776170045016250 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2020 Ivan Komissarov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu -o pipefail # # Qbs is built with the address sanitizer enabled. # Suppress findings in some parts of Qbs / dependencies. # export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" export PATH="$1:$PATH" export QBS_AUTOTEST_PROFILE=${QBS_AUTOTEST_PROFILE:-qt} echo "Running Qbs tests." find $1 -name "tst*" | xargs -I{} -n1 bash -c "{}" qbs-src-2.6.1/scripts/update-dmgbuild.sh0000755000175100001660000000441714776170045017553 0ustar runnerdocker#!/bin/bash set -e ############################################################################# ## ## Copyright (C) 2016 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# python_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../src/3rdparty/python" repos=(biplist.git@v1.0.3 dmgbuild.git@v1.3.2 ds_store@v1.1.2 mac_alias.git@v2.0.7) for repo in "${repos[@]}" ; do pip install -U --isolated "--prefix=$python_dir" --no-binary :all: --no-compile --no-deps \ "git+git://github.com/qbs/$repo" done rm "$python_dir/lib/python2.7/site-packages/dmgbuild/resources/"*.tiff qbs-src-2.6.1/scripts/build-qbs-with-cmake.sh0000755000175100001660000000733314776170045020415 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com). ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu # # It might be desired to keep settings for Qbs testing # in a separate folder. # export QBS_AUTOTEST_SETTINGS_DIR="${QBS_AUTOTEST_SETTINGS_DIR:-/tmp/qbs-settings}" BUILD_OPTIONS="\ -DWITH_UNIT_TESTS=1 \ -DQBS_INSTALL_HTML_DOCS=1 \ -DQBS_INSTALL_QCH_DOCS=1 \ ${BUILD_OPTIONS:-} \ " EXE_SUFFIX="" if [[ "$OSTYPE" == "msys" ]]; then EXE_SUFFIX=".exe" else BUILD_OPTIONS="\ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ ${BUILD_OPTIONS} \ " fi QMAKE_PATH="${QMAKE_PATH:-$(which qmake)${EXE_SUFFIX}}" QT_DIR=$(dirname ${QMAKE_PATH})/../ # Use shadow build mkdir -p build pushd build # # Build all default products of Qbs # cmake -GNinja -DQt5_DIR=${QT_DIR}/lib/cmake/Qt5/ ${BUILD_OPTIONS} .. cmake --build . cmake --install . --prefix "install-root" WITH_TESTS=${WITH_TESTS:-1} if [ "$WITH_TESTS" -eq 0 ]; then exit 0 fi QBS_AUTOTEST_PROFILE="${QBS_AUTOTEST_PROFILE:-}" # # Set up profiles for the freshly built Qbs if not # explicitly specified otherwise # if [[ "${QBS_AUTOTEST_PROFILE}" == "" ]]; then export QBS_AUTOTEST_PROFILE=autotestprofile RUN_OPTIONS="\ --settings-dir ${QBS_AUTOTEST_SETTINGS_DIR} \ " ./bin/qbs setup-toolchains \ ${RUN_OPTIONS} \ --detect ./bin/qbs setup-qt \ ${RUN_OPTIONS} \ "${QMAKE_PATH}" ${QBS_AUTOTEST_PROFILE} ./bin/qbs config \ ${RUN_OPTIONS} \ ${QBS_AUTOTEST_PROFILE}.baseProfile gcc fi # # Run all autotests with QBS_AUTOTEST_PROFILE. Some test cases might run for # over 10 minutes. Output an empty line every 9:50 minutes to prevent a 10min # timeout on Travis CI. # (while true; do echo "" && sleep 590; done) & trap "kill $!; wait $! 2>/dev/null || true; killall sleep || true" EXIT ctest -j $(nproc --all) --output-on-failure qbs-src-2.6.1/scripts/install-dm.sh0000644000175100001660000001042314776170045016537 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2022 Denis Shienkov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu function show_help() { cat < Root directory where to install the components. Maps to c:/dm on Windows by default. --version The desired toolchain version. Currently supported only 8.57 version. EOF } VERSION="8.57" INSTALL_DIR="/c/dm" while [ $# -gt 0 ]; do case "$1" in --directory|-d) INSTALL_DIR="$2" shift ;; --version) VERSION="$2" shift ;; --help|-h) show_help exit 0 ;; *) ;; esac shift done if [ -z "${INSTALL_DIR}" ]; then echo "No --directory specified or auto-detection failed." >&2 exit 1 fi if [ -z "${VERSION}" ]; then echo "No --version specified." >&2 exit 1 fi DOWNLOAD_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'dm-tmp'` DM_URL="http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm${VERSION//./}c.zip" UTILS_URL="http://ftp.digitalmars.com/bup.zip" DOS_LIBS_URL="http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm850dos.zip" DOSX_LIBS_URL="http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm831x.zip" DM_ZIP="${DOWNLOAD_DIR}/dm.zip" UTILS_ZIP="${DOWNLOAD_DIR}/utils.zip" DOS_LIBS_ZIP="${DOWNLOAD_DIR}/doslibs.zip" DOSX_LIBS_ZIP="${DOWNLOAD_DIR}/dosxlibs.zip" echo "Downloading compiler from ${DM_URL}..." >&2 curl --progress-bar -L -o ${DM_ZIP} ${DM_URL} >&2 echo "Downloading utils from ${UTILS_URL}..." >&2 curl --progress-bar -L -o ${UTILS_ZIP} ${UTILS_URL} >&2 echo "Downloading DOS libs from ${DOS_LIBS_URL}..." >&2 curl --progress-bar -L -o ${DOS_LIBS_ZIP} ${DOS_LIBS_URL} >&2 echo "Downloading DOSX libs from ${DOSX_LIBS_URL}..." >&2 curl --progress-bar -L -o ${DOSX_LIBS_ZIP} ${DOSX_LIBS_URL} >&2 echo "Unpacking compiler to ${INSTALL_DIR}..." >&2 7z x -y -o${INSTALL_DIR} ${DM_ZIP} >/dev/null 2>&1 echo "Unpacking utils to ${INSTALL_DIR}..." >&2 7z x -y -o${INSTALL_DIR} ${UTILS_ZIP} >/dev/null 2>&1 echo "Unpacking DOS libs to ${INSTALL_DIR}..." >&2 7z x -y -o${INSTALL_DIR} ${DOS_LIBS_ZIP} >/dev/null 2>&1 echo "Unpacking DOSX libs to ${INSTALL_DIR}..." >&2 7z x -y -o${INSTALL_DIR} ${DOSX_LIBS_ZIP} >/dev/null 2>&1 echo "${INSTALL_DIR}/dm/bin" rm -f ${DM_ZIP} rm -f ${UTILS_ZIP} rm -f ${DOS_LIBS_ZIP} rm -f ${DOSX_LIBS_ZIP} qbs-src-2.6.1/scripts/git-clang-format0000755000175100001660000006137214776170045017231 0ustar runnerdocker#!/usr/bin/env python3 # #===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===# # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # #===------------------------------------------------------------------------===# r""" clang-format git integration ============================ This file provides a clang-format integration for git. Put it somewhere in your path and ensure that it is executable. Then, "git clang-format" will invoke clang-format on the changes in current files or a specific commit. For further details, run: git clang-format -h Requires Python 2.7 or Python 3 """ from __future__ import absolute_import, division, print_function import argparse import collections import contextlib import errno import os import re import subprocess import sys usage = ('git clang-format [OPTIONS] [] [|--staged] ' '[--] [...]') desc = ''' If zero or one commits are given, run clang-format on all lines that differ between the working directory and , which defaults to HEAD. Changes are only applied to the working directory, or in the stage/index. Examples: To format staged changes, i.e everything that's been `git add`ed: git clang-format To also format everything touched in the most recent commit: git clang-format HEAD~1 If you're on a branch off main, to format everything touched on your branch: git clang-format main If two commits are given (requires --diff), run clang-format on all lines in the second that differ from the first . The following git-config settings set the default of the corresponding option: clangFormat.binary clangFormat.commit clangFormat.extensions clangFormat.style ''' # Name of the temporary index file in which save the output of clang-format. # This file is created within the .git directory. temp_index_basename = 'clang-format-index' Range = collections.namedtuple('Range', 'start, count') def main(): config = load_git_config() # In order to keep '--' yet allow options after positionals, we need to # check for '--' ourselves. (Setting nargs='*' throws away the '--', while # nargs=argparse.REMAINDER disallows options after positionals.) argv = sys.argv[1:] try: idx = argv.index('--') except ValueError: dash_dash = [] else: dash_dash = argv[idx:] argv = argv[:idx] default_extensions = ','.join([ # From clang/lib/Frontend/FrontendOptions.cpp, all lower case 'c', 'h', # C 'm', # ObjC 'mm', # ObjC++ 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hh', 'hpp', 'hxx', 'inc', # C++ 'ccm', 'cppm', 'cxxm', 'c++m', # C++ Modules 'cu', 'cuh', # CUDA # Other languages that clang-format supports 'proto', 'protodevel', # Protocol Buffers 'java', # Java 'js', # JavaScript 'ts', # TypeScript 'cs', # C Sharp 'json', # Json 'sv', 'svh', 'v', 'vh', # Verilog ]) p = argparse.ArgumentParser( usage=usage, formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) p.add_argument('--binary', default=config.get('clangformat.binary', 'clang-format'), help='path to clang-format'), p.add_argument('--commit', default=config.get('clangformat.commit', 'HEAD'), help='default commit to use if none is specified'), p.add_argument('--diff', action='store_true', help='print a diff instead of applying the changes') p.add_argument('--diffstat', action='store_true', help='print a diffstat instead of applying the changes') p.add_argument('--extensions', default=config.get('clangformat.extensions', default_extensions), help=('comma-separated list of file extensions to format, ' 'excluding the period and case-insensitive')), p.add_argument('-f', '--force', action='store_true', help='allow changes to unstaged files') p.add_argument('-p', '--patch', action='store_true', help='select hunks interactively') p.add_argument('-q', '--quiet', action='count', default=0, help='print less information') p.add_argument('--staged', '--cached', action='store_true', help='format lines in the stage instead of the working dir') p.add_argument('--style', default=config.get('clangformat.style', None), help='passed to clang-format'), p.add_argument('-v', '--verbose', action='count', default=0, help='print extra information') p.add_argument('--diff_from_common_commit', action='store_true', help=('diff from the last common commit for commits in ' 'separate branches rather than the exact point of the ' 'commits')) # We gather all the remaining positional arguments into 'args' since we need # to use some heuristics to determine whether or not was present. # However, to print pretty messages, we make use of metavar and help. p.add_argument('args', nargs='*', metavar='', help='revision from which to compute the diff') p.add_argument('ignored', nargs='*', metavar='...', help='if specified, only consider differences in these files') opts = p.parse_args(argv) opts.verbose -= opts.quiet del opts.quiet commits, files = interpret_args(opts.args, dash_dash, opts.commit) if len(commits) > 2: die('at most two commits allowed; %d given' % len(commits)) if len(commits) == 2: if opts.staged: die('--staged is not allowed when two commits are given') if not opts.diff: die('--diff is required when two commits are given') elif opts.diff_from_common_commit: die('--diff_from_common_commit is only allowed when two commits are given') if os.path.dirname(opts.binary): opts.binary = os.path.abspath(opts.binary) changed_lines = compute_diff_and_extract_lines(commits, files, opts.staged, opts.diff_from_common_commit) if opts.verbose >= 1: ignored_files = set(changed_lines) filter_by_extension(changed_lines, opts.extensions.lower().split(',')) # The computed diff outputs absolute paths, so we must cd before accessing # those files. cd_to_toplevel() filter_symlinks(changed_lines) if opts.verbose >= 1: ignored_files.difference_update(changed_lines) if ignored_files: print( 'Ignoring changes in the following files (wrong extension or symlink):') for filename in ignored_files: print(' %s' % filename) if changed_lines: print('Running clang-format on the following files:') for filename in changed_lines: print(' %s' % filename) if not changed_lines: if opts.verbose >= 0: print('no modified files to format') return 0 if len(commits) > 1: old_tree = commits[1] revision = old_tree elif opts.staged: old_tree = create_tree_from_index(changed_lines) revision = '' else: old_tree = create_tree_from_workdir(changed_lines) revision = None new_tree = run_clang_format_and_save_to_tree(changed_lines, revision, binary=opts.binary, style=opts.style) if opts.verbose >= 1: print('old tree: %s' % old_tree) print('new tree: %s' % new_tree) if old_tree == new_tree: if opts.verbose >= 0: print('clang-format did not modify any files') return 0 if opts.diff: return print_diff(old_tree, new_tree) if opts.diffstat: return print_diffstat(old_tree, new_tree) changed_files = apply_changes(old_tree, new_tree, force=opts.force, patch_mode=opts.patch) if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1: print('changed files:') for filename in changed_files: print(' %s' % filename) return 1 def load_git_config(non_string_options=None): """Return the git configuration as a dictionary. All options are assumed to be strings unless in `non_string_options`, in which is a dictionary mapping option name (in lower case) to either "--bool" or "--int".""" if non_string_options is None: non_string_options = {} out = {} for entry in run('git', 'config', '--list', '--null').split('\0'): if entry: if '\n' in entry: name, value = entry.split('\n', 1) else: # A setting with no '=' ('\n' with --null) is implicitly 'true' name = entry value = 'true' if name in non_string_options: value = run('git', 'config', non_string_options[name], name) out[name] = value return out def interpret_args(args, dash_dash, default_commit): """Interpret `args` as "[commits] [--] [files]" and return (commits, files). It is assumed that "--" and everything that follows has been removed from args and placed in `dash_dash`. If "--" is present (i.e., `dash_dash` is non-empty), the arguments to its left (if present) are taken as commits. Otherwise, the arguments are checked from left to right if they are commits or files. If commits are not given, a list with `default_commit` is used.""" if dash_dash: if len(args) == 0: commits = [default_commit] else: commits = args for commit in commits: object_type = get_object_type(commit) if object_type not in ('commit', 'tag'): if object_type is None: die("'%s' is not a commit" % commit) else: die("'%s' is a %s, but a commit was expected" % (commit, object_type)) files = dash_dash[1:] elif args: commits = [] while args: if not disambiguate_revision(args[0]): break commits.append(args.pop(0)) if not commits: commits = [default_commit] files = args else: commits = [default_commit] files = [] return commits, files def disambiguate_revision(value): """Returns True if `value` is a revision, False if it is a file, or dies.""" # If `value` is ambiguous (neither a commit nor a file), the following # command will die with an appropriate error message. run('git', 'rev-parse', value, verbose=False) object_type = get_object_type(value) if object_type is None: return False if object_type in ('commit', 'tag'): return True die('`%s` is a %s, but a commit or filename was expected' % (value, object_type)) def get_object_type(value): """Returns a string description of an object's type, or None if it is not a valid git object.""" cmd = ['git', 'cat-file', '-t', value] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: return None return convert_string(stdout.strip()) def compute_diff_and_extract_lines(commits, files, staged, diff_common_commit): """Calls compute_diff() followed by extract_lines().""" diff_process = compute_diff(commits, files, staged, diff_common_commit) changed_lines = extract_lines(diff_process.stdout) diff_process.stdout.close() diff_process.wait() if diff_process.returncode != 0: # Assume error was already printed to stderr. sys.exit(2) return changed_lines def compute_diff(commits, files, staged, diff_common_commit): """Return a subprocess object producing the diff from `commits`. The return value's `stdin` file object will produce a patch with the differences between the working directory (or stage if --staged is used) and the first commit if a single one was specified, or the difference between both specified commits, filtered on `files` (if non-empty). Zero context lines are used in the patch.""" git_tool = 'diff-index' extra_args = [] if len(commits) == 2: git_tool = 'diff-tree' if diff_common_commit: commits = [f'{commits[0]}...{commits[1]}'] elif staged: extra_args += ['--cached'] cmd = ['git', git_tool, '-p', '-U0'] + extra_args + commits + ['--'] cmd.extend(files) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.stdin.close() return p def extract_lines(patch_file): """Extract the changed lines in `patch_file`. The return value is a dictionary mapping filename to a list of (start_line, line_count) pairs. The input must have been produced with ``-U0``, meaning unidiff format with zero lines of context. The return value is a dict mapping filename to a list of line `Range`s.""" matches = {} for line in patch_file: line = convert_string(line) match = re.search(r'^\+\+\+\ [^/]+/(.*)', line) if match: filename = match.group(1).rstrip('\r\n\t') match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line) if match: start_line = int(match.group(1)) line_count = 1 if match.group(3): line_count = int(match.group(3)) if line_count == 0: line_count = 1 if start_line == 0: continue matches.setdefault(filename, []).append(Range(start_line, line_count)) return matches def filter_by_extension(dictionary, allowed_extensions): """Delete every key in `dictionary` that doesn't have an allowed extension. `allowed_extensions` must be a collection of lowercase file extensions, excluding the period.""" allowed_extensions = frozenset(allowed_extensions) for filename in list(dictionary.keys()): base_ext = filename.rsplit('.', 1) if len(base_ext) == 1 and '' in allowed_extensions: continue if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions: del dictionary[filename] def filter_symlinks(dictionary): """Delete every key in `dictionary` that is a symlink.""" for filename in list(dictionary.keys()): if os.path.islink(filename): del dictionary[filename] def cd_to_toplevel(): """Change to the top level of the git repository.""" toplevel = run('git', 'rev-parse', '--show-toplevel') os.chdir(toplevel) def create_tree_from_workdir(filenames): """Create a new git tree with the given files from the working directory. Returns the object ID (SHA-1) of the created tree.""" return create_tree(filenames, '--stdin') def create_tree_from_index(filenames): # Copy the environment, because the files have to be read from the original # index. env = os.environ.copy() def index_contents_generator(): for filename in filenames: git_ls_files_cmd = ['git', 'ls-files', '--stage', '-z', '--', filename] git_ls_files = subprocess.Popen(git_ls_files_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout = git_ls_files.communicate()[0] yield convert_string(stdout.split(b'\0')[0]) return create_tree(index_contents_generator(), '--index-info') def run_clang_format_and_save_to_tree(changed_lines, revision=None, binary='clang-format', style=None): """Run clang-format on each file and save the result to a git tree. Returns the object ID (SHA-1) of the created tree.""" # Copy the environment when formatting the files in the index, because the # files have to be read from the original index. env = os.environ.copy() if revision == '' else None def iteritems(container): try: return container.iteritems() # Python 2 except AttributeError: return container.items() # Python 3 def index_info_generator(): for filename, line_ranges in iteritems(changed_lines): if revision is not None: if len(revision) > 0: git_metadata_cmd = ['git', 'ls-tree', '%s:%s' % (revision, os.path.dirname(filename)), os.path.basename(filename)] else: git_metadata_cmd = ['git', 'ls-files', '--stage', '--', filename] git_metadata = subprocess.Popen(git_metadata_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout = git_metadata.communicate()[0] mode = oct(int(stdout.split()[0], 8)) else: mode = oct(os.stat(filename).st_mode) # Adjust python3 octal format so that it matches what git expects if mode.startswith('0o'): mode = '0' + mode[2:] blob_id = clang_format_to_blob(filename, line_ranges, revision=revision, binary=binary, style=style, env=env) yield '%s %s\t%s' % (mode, blob_id, filename) return create_tree(index_info_generator(), '--index-info') def create_tree(input_lines, mode): """Create a tree object from the given input. If mode is '--stdin', it must be a list of filenames. If mode is '--index-info' is must be a list of values suitable for "git update-index --index-info", such as " ". Any other mode is invalid.""" assert mode in ('--stdin', '--index-info') cmd = ['git', 'update-index', '--add', '-z', mode] with temporary_index_file(): p = subprocess.Popen(cmd, stdin=subprocess.PIPE) for line in input_lines: p.stdin.write(to_bytes('%s\0' % line)) p.stdin.close() if p.wait() != 0: die('`%s` failed' % ' '.join(cmd)) tree_id = run('git', 'write-tree') return tree_id def clang_format_to_blob(filename, line_ranges, revision=None, binary='clang-format', style=None, env=None): """Run clang-format on the given file and save the result to a git blob. Runs on the file in `revision` if not None, or on the file in the working directory if `revision` is None. Revision can be set to an empty string to run clang-format on the file in the index. Returns the object ID (SHA-1) of the created blob.""" clang_format_cmd = [binary] if style: clang_format_cmd.extend(['-style='+style]) clang_format_cmd.extend([ '-lines=%s:%s' % (start_line, start_line+line_count-1) for start_line, line_count in line_ranges]) if revision is not None: clang_format_cmd.extend(['-assume-filename='+filename]) git_show_cmd = ['git', 'cat-file', 'blob', '%s:%s' % (revision, filename)] git_show = subprocess.Popen(git_show_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE) git_show.stdin.close() clang_format_stdin = git_show.stdout else: clang_format_cmd.extend([filename]) git_show = None clang_format_stdin = subprocess.PIPE try: clang_format = subprocess.Popen(clang_format_cmd, stdin=clang_format_stdin, stdout=subprocess.PIPE) if clang_format_stdin == subprocess.PIPE: clang_format_stdin = clang_format.stdin except OSError as e: if e.errno == errno.ENOENT: die('cannot find executable "%s"' % binary) else: raise clang_format_stdin.close() hash_object_cmd = ['git', 'hash-object', '-w', '--path='+filename, '--stdin'] hash_object = subprocess.Popen(hash_object_cmd, stdin=clang_format.stdout, stdout=subprocess.PIPE) clang_format.stdout.close() stdout = hash_object.communicate()[0] if hash_object.returncode != 0: die('`%s` failed' % ' '.join(hash_object_cmd)) if clang_format.wait() != 0: die('`%s` failed' % ' '.join(clang_format_cmd)) if git_show and git_show.wait() != 0: die('`%s` failed' % ' '.join(git_show_cmd)) return convert_string(stdout).rstrip('\r\n') @contextlib.contextmanager def temporary_index_file(tree=None): """Context manager for setting GIT_INDEX_FILE to a temporary file and deleting the file afterward.""" index_path = create_temporary_index(tree) old_index_path = os.environ.get('GIT_INDEX_FILE') os.environ['GIT_INDEX_FILE'] = index_path try: yield finally: if old_index_path is None: del os.environ['GIT_INDEX_FILE'] else: os.environ['GIT_INDEX_FILE'] = old_index_path os.remove(index_path) def create_temporary_index(tree=None): """Create a temporary index file and return the created file's path. If `tree` is not None, use that as the tree to read in. Otherwise, an empty index is created.""" gitdir = run('git', 'rev-parse', '--git-dir') path = os.path.join(gitdir, temp_index_basename) if tree is None: tree = '--empty' run('git', 'read-tree', '--index-output='+path, tree) return path def print_diff(old_tree, new_tree): """Print the diff between the two trees to stdout.""" # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output # is expected to be viewed by the user, and only the former does nice things # like color and pagination. # # We also only print modified files since `new_tree` only contains the files # that were modified, so unmodified files would show as deleted without the # filter. return subprocess.run(['git', 'diff', '--diff-filter=M', '--exit-code', old_tree, new_tree]).returncode def print_diffstat(old_tree, new_tree): """Print the diffstat between the two trees to stdout.""" # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output # is expected to be viewed by the user, and only the former does nice things # like color and pagination. # # We also only print modified files since `new_tree` only contains the files # that were modified, so unmodified files would show as deleted without the # filter. return subprocess.run(['git', 'diff', '--diff-filter=M', '--exit-code', '--stat', old_tree, new_tree]).returncode def apply_changes(old_tree, new_tree, force=False, patch_mode=False): """Apply the changes in `new_tree` to the working directory. Bails if there are local changes in those files and not `force`. If `patch_mode`, runs `git checkout --patch` to select hunks interactively.""" changed_files = run('git', 'diff-tree', '--diff-filter=M', '-r', '-z', '--name-only', old_tree, new_tree).rstrip('\0').split('\0') if not force: unstaged_files = run('git', 'diff-files', '--name-status', *changed_files) if unstaged_files: print('The following files would be modified but ' 'have unstaged changes:', file=sys.stderr) print(unstaged_files, file=sys.stderr) print('Please commit, stage, or stash them first.', file=sys.stderr) sys.exit(2) if patch_mode: # In patch mode, we could just as well create an index from the new tree # and checkout from that, but then the user will be presented with a # message saying "Discard ... from worktree". Instead, we use the old # tree as the index and checkout from new_tree, which gives the slightly # better message, "Apply ... to index and worktree". This is not quite # right, since it won't be applied to the user's index, but oh well. with temporary_index_file(old_tree): subprocess.run(['git', 'checkout', '--patch', new_tree], check=True) index_tree = old_tree else: with temporary_index_file(new_tree): run('git', 'checkout-index', '-f', '--', *changed_files) return changed_files def run(*args, **kwargs): stdin = kwargs.pop('stdin', '') verbose = kwargs.pop('verbose', True) strip = kwargs.pop('strip', True) for name in kwargs: raise TypeError("run() got an unexpected keyword argument '%s'" % name) p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate(input=stdin) stdout = convert_string(stdout) stderr = convert_string(stderr) if p.returncode == 0: if stderr: if verbose: print('`%s` printed to stderr:' % ' '.join(args), file=sys.stderr) print(stderr.rstrip(), file=sys.stderr) if strip: stdout = stdout.rstrip('\r\n') return stdout if verbose: print('`%s` returned %s' % (' '.join(args), p.returncode), file=sys.stderr) if stderr: print(stderr.rstrip(), file=sys.stderr) sys.exit(2) def die(message): print('error:', message, file=sys.stderr) sys.exit(2) def to_bytes(str_input): # Encode to UTF-8 to get binary data. if isinstance(str_input, bytes): return str_input return str_input.encode('utf-8') def to_string(bytes_input): if isinstance(bytes_input, str): return bytes_input return bytes_input.encode('utf-8') def convert_string(bytes_input): try: return to_string(bytes_input.decode('utf-8')) except AttributeError: # 'str' object has no attribute 'decode'. return str(bytes_input) except UnicodeError: return str(bytes_input) if __name__ == '__main__': sys.exit(main()) qbs-src-2.6.1/scripts/test-qt.sh0000755000175100001660000000433614776170045016105 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2021 Ivan Komissarov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu # # Qbs is built with the address sanitizer enabled. # Suppress findings in some parts of Qbs / dependencies. # export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" export PATH="$1:$PATH" export QBS_AUTOTEST_PROFILE=${QBS_AUTOTEST_PROFILE:-qt} tst_blackbox-qt qbs-src-2.6.1/scripts/build-qbs-with-qbs.sh0000755000175100001660000001177714776170045020131 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -e # # Qbs is built with the address sanitizer enabled. # Suppress findings in some parts of Qbs / dependencies. # export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" if [ -z "${QBS_BUILD_PROFILE}" ]; then QBS_BUILD_PROFILE=$(qbs config defaultProfile | cut -d: -f2 | tr -d '[:space:]') fi if [ -z "${QBS_BUILD_PROFILE}" ]; then echo "Either QBS_BUILD_PROFILE or a defaultProfile must be set." exit 1 fi # # Additional build options # BUILD_OPTIONS="\ profile:${QBS_BUILD_PROFILE} \ modules.qbsbuildconfig.enableUnitTests:true \ modules.cpp.treatWarningsAsErrors:true \ modules.cpp.separateDebugInformation:true \ ${BUILD_OPTIONS} \ config:release \ " # # Build all default products of Qbs # qbs resolve ${BUILD_OPTIONS} qbs build ${BUILD_OPTIONS} WITH_DOCS=${WITH_DOCS:-1} if [ "$WITH_DOCS" -ne 0 ]; then qbs build -p "qbs documentation" ${BUILD_OPTIONS} fi WITH_ARCHIVE=${WITH_ARCHIVE:-1} if [ "$WITH_ARCHIVE" -ne 0 ]; then qbs build -p "qbs_archive" ${BUILD_OPTIONS} fi WITH_TESTS=${WITH_TESTS:-1} if [ "$WITH_TESTS" -eq 0 ]; then exit 0 fi QMAKE_PATH=${QMAKE_PATH:-$(which qmake)} # # Set up profiles for the freshly built Qbs if not # explicitly specified otherwise # if [ -z "${QBS_AUTOTEST_PROFILE}" ]; then export QBS_AUTOTEST_PROFILE=autotestprofile export QBS_AUTOTEST_SETTINGS_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'qbs-settings'` QBS_AUTOTEST_QMAKE_PATH=${QBS_AUTOTEST_QMAKE_PATH:-${QMAKE_PATH}} RUN_OPTIONS="\ --settings-dir ${QBS_AUTOTEST_SETTINGS_DIR} \ " qbs run -p qbs_app ${BUILD_OPTIONS} -- setup-toolchains \ ${RUN_OPTIONS} \ --detect qbs run -p qbs_app ${BUILD_OPTIONS} -- setup-qt \ ${RUN_OPTIONS} \ "${QBS_AUTOTEST_QMAKE_PATH}" ${QBS_AUTOTEST_PROFILE} # Make sure that the Qt profile uses the same toolchain profile # that was used for building in case a custom QBS_BUILD_PROFILE # was set. Otherwise setup-qt automatically uses the default # toolchain profile. if [ -z "${QBS_AUTOTEST_BASE_PROFILE}" ]; then QBS_AUTOTEST_BASE_PROFILE=$(qbs config profiles.${QBS_BUILD_PROFILE}.baseProfile | cut -d: -f2) fi if [ ! -z "${QBS_AUTOTEST_BASE_PROFILE}" ]; then echo "Setting base profile for ${QBS_AUTOTEST_PROFILE} to ${QBS_AUTOTEST_BASE_PROFILE}" qbs run -p qbs_app ${BUILD_OPTIONS} -- config \ ${RUN_OPTIONS} \ profiles.${QBS_AUTOTEST_PROFILE}.baseProfile ${QBS_AUTOTEST_BASE_PROFILE} fi qbs run -p qbs_app ${BUILD_OPTIONS} -- config \ ${RUN_OPTIONS} \ --list # QBS_AUTOTEST_PROFILE has been added to the environment # which requires a resolve step qbs resolve ${BUILD_OPTIONS} fi # # Run all autotests with QBS_AUTOTEST_PROFILE. Some test cases might run for # over 10 minutes. Output an empty line every 9:50 minutes to prevent a 10min # timeout on Travis CI. # (while true; do echo "" && sleep 590; done) & trap "kill $!; wait $! 2>/dev/null || true; killall sleep || true" EXIT qbs build -p "autotest-runner" ${BUILD_OPTIONS} qbs-src-2.6.1/scripts/scripts.qbs0000644000175100001660000000013414776170045016333 0ustar runnerdockerProduct { name: "qbs dev scripts" files: [ "*.bat", "*.sh", ] } qbs-src-2.6.1/scripts/setup-conan-profiles.sh0000755000175100001660000000536214776170045020561 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu case "$OSTYPE" in *darwin*) HOST_OS=mac_x64 TOOLCHAIN=clang_64 ;; msys) HOST_OS=win_x64 TOOLCHAIN=msvc_64 ;; *) HOST_OS= ;; esac while [ $# -gt 0 ]; do case "$1" in --host) HOST_OS="$2" shift ;; --toolchain) TOOLCHAIN=$(echo $2 | tr '[A-Z]' '[a-z]') shift ;; esac shift done if [ -z "${HOST_OS}" ]; then echo "No --host specified or auto-detection failed." >&2 exit 1 fi if [ -z "${TOOLCHAIN}" ]; then echo "No --toolchain specified or auto-detection failed." >&2 exit 1 fi echo $HOST_OS echo $TOOLCHAIN mkdir -p "${HOME}/.conan2/profiles" SCRIPT_DIR=$( cd "$(dirname "$0")" ; pwd -P ) cp ${SCRIPT_DIR}/conan-profiles/${HOST_OS}/${TOOLCHAIN}/* "${HOME}/.conan2/profiles" qbs-src-2.6.1/scripts/test-for-android.sh0000755000175100001660000000507314776170045017664 0ustar runnerdocker#!/usr/bin/env bash set -eu ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# export PATH="$1:$PATH" export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" # # These are set outside of this script, for instance in the Docker image # echo "Android SDK installed at ${ANDROID_SDK_ROOT}" echo "Android NDK installed at ${ANDROID_NDK_ROOT}" # Cleaning profiles qbs config --unset profiles.qbs_autotests-android # Setting auto test profiles qbs setup-android --ndk-dir ${ANDROID_NDK_ROOT} --sdk-dir ${ANDROID_HOME} qbs_autotests-android export QBS_AUTOTEST_PROFILE=qbs_autotests-android export QBS_AUTOTEST_ALWAYS_LOG_STDERR=true export QTEST_FUNCTION_TIMEOUT=9000000 qbs config --list tst_blackbox-android qbs-src-2.6.1/scripts/make-release-archives.sh0000755000175100001660000000424014776170045020633 0ustar runnerdocker#!/bin/sh set -e ############################################################################# ## ## Copyright (C) 2016 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# test $# -eq 1 || { echo "Usage: $(basename "$0") " >&2; exit 1; } tag=${1} version=${tag#v} dir_name=qbs-src-${version} git archive --format=tar.gz "--prefix=${dir_name}/" -o "dist/${dir_name}.tar.gz" "${tag}" git archive --format=zip "--prefix=${dir_name}/" -o "dist/${dir_name}.zip" "${tag}" qbs-src-2.6.1/scripts/make-release-archives.bat0000644000175100001660000000670014776170045020767 0ustar runnerdocker@echo off REM Copyright (C) 2017 The Qt Company Ltd. REM Contact: https://www.qt.io/licensing/ REM REM This file is part of Qbs. REM REM $QT_BEGIN_LICENSE:LGPL$ REM Commercial License Usage REM Licensees holding valid commercial Qt licenses may use this file in REM accordance with the commercial license agreement provided with the REM Software or, alternatively, in accordance with the terms contained in REM a written agreement between you and The Qt Company. For licensing terms REM and conditions see https://www.qt.io/terms-conditions. For further REM information use the contact form at https://www.qt.io/contact-us. REM REM GNU Lesser General Public License Usage REM Alternatively, this file may be used under the terms of the GNU Lesser REM General Public License version 3 as published by the Free Software REM Foundation and appearing in the file LICENSE.LGPL3 included in the REM packaging of this file. Please review the following information to REM ensure the GNU Lesser General Public License version 3 requirements REM will be met: https://www.gnu.org/licenses/lgpl-3.0.html. REM REM GNU General Public License Usage REM Alternatively, this file may be used under the terms of the GNU REM General Public License version 2.0 or (at your option) the GNU General REM Public license version 3 or any later version approved by the KDE Free REM Qt Foundation. The licenses are as published by the Free Software REM Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 REM included in the packaging of this file. Please review the following REM information to ensure the GNU General Public License requirements will REM be met: https://www.gnu.org/licenses/gpl-2.0.html and REM https://www.gnu.org/licenses/gpl-3.0.html. REM REM $QT_END_LICENSE$ setlocal enabledelayedexpansion || exit /b if not exist VERSION ( echo This script must be run from the qbs source directory 1>&2 && exit /b 1 ) for /f %%j in (VERSION) do ( set "version=!version!%%j," ) set "version=%version:~0,-1%" set builddir=%TEMP%\qbs-release-%version% if exist "%builddir%" ( del /s /q "%builddir%" || exit /b ) qbs setup-toolchains --settings-dir "%builddir%\.settings" --detect || exit /b if exist "%QTDIR%" ( qbs setup-qt --settings-dir "%builddir%\.settings"^ "%QTDIR%\bin\qmake.exe" qt || exit /b ) else ( echo QTDIR environment variable not set or does not exist: %QTDIR% exit /b 1 ) if exist "%QTDIR64%" ( qbs setup-qt --settings-dir "%builddir%\.settings"^ "%QTDIR64%\bin\qmake.exe" qt64 || exit /b ) else ( echo QTDIR64 environment variable not set or does not exist: %QTDIR64% exit /b 1 ) REM Work around QBS-1142, where symlinks to UNC named paths aren't resolved REM properly, for example if this command is being run in a Docker container REM where the current directory is a symlink subst Q: "%CD%" && Q: qbs build --settings-dir "%builddir%\.settings"^ -f qbs.qbs -d "%builddir%\build"^ -p dist qbs.buildVariant:release project.withDocumentation:false products.qbs_archive.includeTopLevelDir:true^ modules.qbsbuildconfig.enableBundledQt:true^ config:release "qbs.installRoot:%builddir%\qbs-windows-x86-%version%" profile:qt^ config:release-64 "qbs.installRoot:%builddir%\qbs-windows-x86_64-%version%" profile:qt64 || exit /b copy /y "%builddir%\build\release\qbs.%version%.nupkg" dist || exit /b copy /y "%builddir%\build\release\qbs-windows-x86-%version%.zip" dist || exit /b copy /y "%builddir%\build\release-64\qbs-windows-x86_64-%version%.zip" dist || exit /b qbs-src-2.6.1/scripts/update-xcspecs.sh0000755000175100001660000000507314776170045017433 0ustar runnerdocker#!/bin/bash set -e ############################################################################# ## ## Copyright (C) 2016 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# # 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" specs_out_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../share/qbs/modules/bundle" 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")" > \ "$specs_out_dir/${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" qbs-src-2.6.1/scripts/cpu-count.sh0000755000175100001660000000414414776170045016416 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2020 Ivan Komissarov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# NPROC=`which nproc` SYSCTL=`which sysctl` CPU_COUNT=2 if [ ! -z "$NPROC" ]; then # Linux CPU_COUNT=`$NPROC --all` elif [ ! -z "$SYSCTL" ]; then # macOS CPU_COUNT=`$SYSCTL -n hw.physicalcpu_max` fi echo $CPU_COUNT qbs-src-2.6.1/scripts/test-qt4.sh0000755000175100001660000000454014776170045016166 0ustar runnerdocker#!/usr/bin/env bash set -eu ############################################################################# ## ## Copyright (C) 2020 Raphael Cotty. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# export PATH="$1:$PATH" export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" # Creating the qt4 profile qbs-setup-toolchains /usr/bin/g++ gcc qbs-setup-qt /usr/lib/x86_64-linux-gnu/qt4/bin/qmake qt4 # To avoid warnings due to qt4 include files qbs config profiles.gcc.cpp.cxxFlags "-Wno-deprecated-copy" qbs config profiles.qt4.baseProfile gcc qbs config --list export QBS_AUTOTEST_PROFILE=qt4 tst_blackbox-qt qbs-src-2.6.1/scripts/thread-sanitizer-suppressions.txt0000644000175100001660000000003314776170045022724 0ustar runnerdockercalled_from_lib:libtsan.so qbs-src-2.6.1/scripts/conan-profiles/0000755000175100001660000000000014776170045017056 5ustar runnerdockerqbs-src-2.6.1/scripts/conan-profiles/mac_x64/0000755000175100001660000000000014776170045020317 5ustar runnerdockerqbs-src-2.6.1/scripts/conan-profiles/mac_x64/clang_64/0000755000175100001660000000000014776170045021714 5ustar runnerdockerqbs-src-2.6.1/scripts/conan-profiles/mac_x64/clang_64/qbs-test0000644000175100001660000000020614776170045023377 0ustar runnerdocker[settings] arch=x86_64 build_type=Release compiler=apple-clang compiler.cppstd=17 compiler.libcxx=libc++ compiler.version=13 os=Macos qbs-src-2.6.1/scripts/conan-profiles/mac_x64/clang_64/qbs-test-libs0000644000175100001660000000020614776170045024326 0ustar runnerdocker[settings] arch=x86_64 build_type=Release compiler=apple-clang compiler.cppstd=17 compiler.libcxx=libc++ compiler.version=13 os=Macos qbs-src-2.6.1/scripts/conan-profiles/win_x64/0000755000175100001660000000000014776170045020354 5ustar runnerdockerqbs-src-2.6.1/scripts/conan-profiles/win_x64/mingw_64/0000755000175100001660000000000014776170045022006 5ustar runnerdockerqbs-src-2.6.1/scripts/conan-profiles/win_x64/mingw_64/qbs-test0000644000175100001660000000020714776170045023472 0ustar runnerdocker[settings] arch=x86_64 build_type=Release compiler=gcc compiler.cppstd=17 compiler.libcxx=libstdc++11 compiler.version=11.2 os=Windows qbs-src-2.6.1/scripts/conan-profiles/win_x64/msvc_64/0000755000175100001660000000000014776170045021635 5ustar runnerdockerqbs-src-2.6.1/scripts/conan-profiles/win_x64/msvc_64/qbs-test0000644000175100001660000000024214776170045023320 0ustar runnerdocker[settings] arch=x86_64 build_type=Release compiler=msvc compiler.cppstd=14 compiler.runtime=dynamic compiler.runtime_type=Release compiler.version=194 os=Windows qbs-src-2.6.1/scripts/conan-profiles/win_x64/msvc_64/qbs-test-libs0000644000175100001660000000024214776170045024247 0ustar runnerdocker[settings] arch=x86_64 build_type=Release compiler=msvc compiler.cppstd=14 compiler.runtime=dynamic compiler.runtime_type=Release compiler.version=193 os=Windows qbs-src-2.6.1/scripts/run-analyzer.sh0000755000175100001660000000766314776170045017141 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# LLVM_INSTALL_DIR=${LLVM_INSTALL_DIR:-""} # on Debian, it might be necessary to setup which version of clang-tidy and run-clang-tidy.py # is desired: # update-alternatives --install /usr/bin/run-clang-tidy.py run-clang-tidy.py /usr/bin/run-clang-tidy-4.0.py 1 CLANG_TIDY=`which clang-tidy` RUN_CLANG_TIDY=`which run-clang-tidy` if [ -z "$RUN_CLANG_TIDY" ] || [ -z "$CLANG_TIDY" ]; then if [ ! -z "$LLVM_INSTALL_DIR" ]; then CLANG_TIDY="$LLVM_INSTALL_DIR/bin/clang-tidy" RUN_CLANG_TIDY="$LLVM_INSTALL_DIR/bin/run-clang-tidy" else echo "Can't find clang-tidy and/or run-clang-tidy.py in PATH, try setting LLVM_INSTALL_DIR" exit 1 fi fi SCRIPT_DIR=$(dirname "$0") CPU_COUNT=$("${SCRIPT_DIR}/cpu-count.sh") BUILD_OPTIONS="\ ${QBS_BUILD_PROFILE:+profile:${QBS_BUILD_PROFILE}} \ modules.cpp.treatWarningsAsErrors:true \ modules.qbs.buildVariant:release \ project.withTests:false \ ${BUILD_OPTIONS} \ config:analyzer " QBS_SRC_DIR=${QBS_SRC_DIR:-`pwd`} if [ ! -f "$QBS_SRC_DIR/qbs.qbs" ]; then echo "Can't find qbs.qbs in $QBS_SRC_DIR, try setting QBS_SRC_DIR" exit 1 fi set -e set -o pipefail qbs resolve -f "$QBS_SRC_DIR/qbs.qbs" $BUILD_OPTIONS qbs build -f "$QBS_SRC_DIR/qbs.qbs" $BUILD_OPTIONS qbs generate -g clangdb -f "$QBS_SRC_DIR/qbs.qbs" $BUILD_OPTIONS SCRIPT=" import json import os import sys dbFile = sys.argv[1] blacklist = ['qmljsgrammar.cpp', 'qmljsparser.cpp'] seenFiles = set() patched_db = [] with open(dbFile, 'r') as f: db = json.load(f) for item in db: file = item['file'] if (os.path.basename(file) not in blacklist) and (file not in seenFiles): seenFiles.add(file) patched_db.append(item) with open(dbFile, 'w') as f: f.write(json.dumps(patched_db, indent=2)) " python3 -c "${SCRIPT}" analyzer/compile_commands.json RUN_CLANG_TIDY+=" -p analyzer -clang-tidy-binary ${CLANG_TIDY} -j ${CPU_COUNT} -header-filter=\".*qbs.*\.h$\" -quiet" ${RUN_CLANG_TIDY} 2>/dev/null | tee results.txt echo "$(grep -c 'warning:' results.txt) warnings in total" qbs-src-2.6.1/scripts/test-wasm.sh0000755000175100001660000000467014776170045016431 0ustar runnerdocker#!/usr/bin/env bash ############################################################################# ## ## Copyright (C) 2024 Ivan Komissarov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# set -eu -o pipefail export PATH="$1:$PATH" SCRIPT_DIR=$( cd "$(dirname "$0")" ; pwd -P ) qbs config --unset profiles.qbs_autotests_wasm qbs config --unset profiles.qbs_autotests_wasm_qt export QBS_AUTOTEST_PROFILE=qbs_autotests_wasm_qt EMCC_PATH=${EMCC_PATH:-$(which emcc)} QMAKE_PATH=${QMAKE_PATH:-$(which qmake)} qbs setup-toolchains --type emscripten ${EMCC_PATH} qbs_autotests_wasm qbs setup-qt ${QMAKE_PATH} qbs_autotests_wasm_qt qbs config profiles.qbs_autotests_wasm_qt.baseProfile qbs_autotests_wasm qbs config --list ${SCRIPT_DIR}/test-qbs.sh $1 qbs-src-2.6.1/scripts/test-baremetal.sh0000755000175100001660000000447514776170045017421 0ustar runnerdocker#!/usr/bin/env bash set -eu ############################################################################# ## ## Copyright (C) 2020 Denis Shienkov ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qbs. ## ## $QT_BEGIN_LICENSE:LGPL$ ## 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 https://www.qt.io/terms-conditions. For further ## information use the contact form at https://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 3 as published by the Free Software ## Foundation and appearing in the file LICENSE.LGPL3 included in the ## packaging of this file. Please review the following information to ## ensure the GNU Lesser General Public License version 3 requirements ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ## ## GNU General Public License Usage ## Alternatively, this file may be used under the terms of the GNU ## General Public License version 2.0 or (at your option) the GNU General ## Public license version 3 or any later version approved by the KDE Free ## Qt Foundation. The licenses are as published by the Free Software ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ## included in the packaging of this file. Please review the following ## information to ensure the GNU General Public License requirements will ## be met: https://www.gnu.org/licenses/gpl-2.0.html and ## https://www.gnu.org/licenses/gpl-3.0.html. ## ## $QT_END_LICENSE$ ## ############################################################################# export LSAN_OPTIONS="suppressions=$( cd "$(dirname "$0")" ; pwd -P )/address-sanitizer-suppressions.txt:print_suppressions=0" export PATH="$1:$PATH" export QBS_AUTOTEST_ALWAYS_LOG_STDERR=true echo "Auto-detecting the Qbs profiles." qbs-setup-toolchains --detect qbs-config --list profiles echo "Testing the Qbs toolchains." export QBS_AUTOTEST_PROFILE=${QBS_AUTOTEST_PROFILE:-arm-none-eabi-gcc-9_2} tst_blackbox-baremetal qbs-src-2.6.1/.github/0000755000175100001660000000000014776170045014010 5ustar runnerdockerqbs-src-2.6.1/.github/actions/0000755000175100001660000000000014776170045015450 5ustar runnerdockerqbs-src-2.6.1/.github/actions/download-ow/0000755000175100001660000000000014776170045017702 5ustar runnerdockerqbs-src-2.6.1/.github/actions/download-ow/action.yml0000644000175100001660000000065314776170045021706 0ustar runnerdockername: 'Download OpenWatcom' description: 'Downloads OpenWatcom' inputs: version: description: 'OpenWatcom version' required: false default: '2.0' runs: using: "composite" steps: - name: Install OpenWatcom run: | OW_DIR=$(./scripts/install-ow.sh -d $HOME/watcom --version ${{ inputs.version }}) (cygpath -w ${OW_DIR} 2>/dev/null || echo ${OW_DIR}) >> ${GITHUB_PATH} shell: bash qbs-src-2.6.1/.github/actions/download-mingw/0000755000175100001660000000000014776170045020376 5ustar runnerdockerqbs-src-2.6.1/.github/actions/download-mingw/action.yml0000644000175100001660000000104114776170045022372 0ustar runnerdockername: 'Download MinGW' description: 'Downloads MinGW' inputs: version: description: 'MinGW version' required: false default: '9.0.0' toolchain: description: 'Toolchain' required: false default: 'win64_mingw' runs: using: "composite" steps: - name: Install MinGW run: | MINGW_DIR=$(./scripts/install-qt.sh -d $HOME/Qt --version ${{ inputs.version }} --toolchain ${{ inputs.toolchain }} mingw) (cygpath -w ${MINGW_DIR} 2>/dev/null || echo ${MINGW_DIR}) >> ${GITHUB_PATH} shell: bash qbs-src-2.6.1/.github/actions/download-qtc/0000755000175100001660000000000014776170045020044 5ustar runnerdockerqbs-src-2.6.1/.github/actions/download-qtc/action.yml0000644000175100001660000000066714776170045022055 0ustar runnerdockername: 'Download Qt Creator' description: 'Downloads Qt Creator' inputs: version: description: 'Qt Creator version' required: false default: '11.0.3' runs: using: "composite" steps: - name: Install Qt Creator run: | QTC_DIR=$(./scripts/install-qt.sh -d $HOME/Qt --version ${{ inputs.version }} qtcreator) (cygpath -w ${QTC_DIR} 2>/dev/null || echo ${QTC_DIR}) >> ${GITHUB_PATH} shell: bash qbs-src-2.6.1/.github/actions/download-dm/0000755000175100001660000000000014776170045017655 5ustar runnerdockerqbs-src-2.6.1/.github/actions/download-dm/action.yml0000644000175100001660000000065414776170045021662 0ustar runnerdockername: 'Download DigitalMars' description: 'Downloads DigitalMars' inputs: version: description: 'DigitalMars version' required: false default: '8.57' runs: using: "composite" steps: - name: Install DigitalMars run: | DM_DIR=$(./scripts/install-dm.sh -d $HOME/dm --version ${{ inputs.version }}) (cygpath -w ${DM_DIR} 2>/dev/null || echo ${DM_DIR}) >> ${GITHUB_PATH} shell: bash qbs-src-2.6.1/.github/actions/download-qt/0000755000175100001660000000000014776170045017701 5ustar runnerdockerqbs-src-2.6.1/.github/actions/download-qt/action.yml0000644000175100001660000000124514776170045021703 0ustar runnerdockername: 'Download Qt' description: 'Downloads Qt' inputs: version: description: 'Qt version' required: false default: '6.6.3' target: description: 'Qt target (desktop, ios, android)' required: false default: 'desktop' toolchain: description: 'Qt toolchain' required: true runs: using: "composite" steps: - name: Install Qt run: | QT_DIR=$(./scripts/install-qt.sh -d $HOME/Qt --version ${{ inputs.version }} --target ${{ inputs.target }} --toolchain ${{ inputs.toolchain }} qtbase qtdeclarative qttools qtscxml qt5compat) (cygpath -w ${QTC_DIR} 2>/dev/null || echo ${QT_DIR}) >> ${GITHUB_PATH} shell: bash qbs-src-2.6.1/.github/workflows/0000755000175100001660000000000014776170045016045 5ustar runnerdockerqbs-src-2.6.1/.github/workflows/main.yml0000644000175100001660000007402714776170045017526 0ustar runnerdockername: Build and test Qbs on: push: paths-ignore: - 'changelogs/**' - 'doc/**' jobs: build-linux: name: ${{ matrix.config.name }} runs-on: ubuntu-latest timeout-minutes: 60 strategy: fail-fast: false matrix: config: - { name: 'Build on Linux (Noble, gcc)', image: 'noble-qt6', options: 'modules.cpp.compilerWrapper:ccache modules.qbs.debugInformation:true modules.qbsbuildconfig.enableBundledQt:true products.qbs_archive.targetName:qbs-linux-noble-${{ github.run_id }} products.qbs_archive.includeTests:true', script: './scripts/build-qbs-with-qbs.sh', cacheid: 'gcc-qt6-noble', suffix: 'linux-noble', } env: BUILD_OPTIONS: ${{ matrix.config.options }} WITH_TESTS: 0 steps: - uses: actions/checkout@v1 - name: Create .ccache dir run: mkdir -p ~/.ccache - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: ccache cache files uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache - name: Pull the Docker Image run: docker compose pull ${{ matrix.config.image }} - name: Print ccache stats run: docker compose run ${{ matrix.config.image }} ccache -s - name: Build Qbs run: docker compose run ${{ matrix.config.image }} ${{ matrix.config.script }} - name: Print ccache stats run: docker compose run ${{ matrix.config.image }} ccache -s - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.tar.gz path: release/qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.tar.gz build-linux-extra: name: ${{ matrix.config.name }} runs-on: ubuntu-latest timeout-minutes: 90 strategy: fail-fast: false matrix: config: - { name: 'Build on Linux (clang_tidy)', script: './scripts/run-analyzer.sh', image: 'noble-qt6', options: 'profile:qt-clang_64 modules.cpp.compilerWrapper:ccache', cacheid: 'clang', } - { name: 'Build on Linux (CMake)', script: './scripts/build-qbs-with-cmake.sh', image: 'noble-qt6', cacheid: 'cmake', } - { name: 'Build on Linux (gcc, ASAN)', image: 'noble-qt6', script: './scripts/build-qbs-with-qbs.sh', options: 'modules.cpp.compilerWrapper:ccache modules.qbsbuildconfig.enableAddressSanitizer:true modules.qbs.debugInformation:true modules.qbsbuildconfig.enableBundledQt:true', cacheid: 'gcc-asan', } - { name: 'Build on Linux (gcc, UBSAN)', image: 'noble-qt6', script: './scripts/build-qbs-with-qbs.sh', options: 'modules.cpp.compilerWrapper:ccache modules.qbsbuildconfig.enableUbSanitizer:true modules.qbs.debugInformation:true modules.qbsbuildconfig.enableBundledQt:true', cacheid: 'gcc-ubsan', } - { name: 'Build on Linux (gcc, Qt 5.15)', image: 'noble-qt5', script: './scripts/build-qbs-with-qbs.sh', options: 'modules.cpp.compilerWrapper:ccache modules.qbs.debugInformation:true modules.qbsbuildconfig.enableBundledQt:true', cacheid: 'gcc-qt5', } env: BUILD_OPTIONS: ${{ matrix.config.options }} QTEST_FUNCTION_TIMEOUT: 9000000 steps: - uses: actions/checkout@v1 - name: Create .ccache dir run: mkdir -p ~/.ccache - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: ccache cache files uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache - name: Pull the Docker Image run: docker compose pull ${{ matrix.config.image }} - name: Print ccache stats run: docker compose run ${{ matrix.config.image }} ccache -s - name: Build Qbs run: docker compose run ${{ matrix.config.image }} ${{ matrix.config.script }} - name: Print ccache stats run: docker compose run ${{ matrix.config.image }} ccache -s clang-format: name: Check Style runs-on: macos-13 timeout-minutes: 60 strategy: fail-fast: false steps: - uses: actions/checkout@v1 - name: Update PATH run: echo "$(brew --prefix llvm@15)/bin" >> ${GITHUB_PATH} - name: Run clang-format run: | git diff -U0 --no-color --relative HEAD^ | $(brew --prefix llvm@15)/share/clang/clang-format-diff.py -i -p1 -regex ".*\.(cxx|cpp|hpp|h)" -v - name: Check diff run: git diff --exit-code build-macos: name: ${{ matrix.config.name }} runs-on: macos-13 timeout-minutes: 60 strategy: fail-fast: false matrix: config: - { name: 'Build on macOS (Qbs)', script: './scripts/build-qbs-with-qbs.sh', options: 'modules.cpp.compilerWrapper:ccache modules.qbs.debugInformation:true modules.qbsbuildconfig.enableAddressSanitizer:false modules.qbsbuildconfig.enableBundledQt:true products.qbs_archive.targetName:qbs-macos-${{ github.run_id }} products.qbs_archive.includeTests:true', cacheid: 'clang', with_tests: 0, suffix: 'macos', } - { name: 'Build on macOS (CMake)', script: './scripts/build-qbs-with-cmake.sh', options: '', cacheid: 'clang-cmake', with_tests: 0, suffix: 'macos', } env: BUILD_OPTIONS: ${{ matrix.config.options }} WITH_TESTS: ${{ matrix.config.with_tests }} steps: - uses: actions/checkout@v1 - name: Create .ccache dir run: mkdir -p ~/.ccache - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: ccache cache files uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache - name: Install required packages run: | brew install ccache ninja p7zip python3 -m pip install --user beautifulsoup4 lxml - name: Install Qt uses: ./.github/actions/download-qt with: toolchain: clang_64 version: 6.7.3 - name: Install Qt Creator uses: ./.github/actions/download-qtc - name: Setup Qbs run: | qbs setup-toolchains --detect qbs setup-qt --detect qbs config profiles.qt.baseProfile xcode_14_2-macosx-x86_64 qbs config defaultProfile qt qbs config --list - name: Print ccache stats run: ccache -s - name: Build Qbs run: ${{ matrix.config.script }} - name: Print ccache stats run: ccache -s - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.tar.gz path: release/qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.tar.gz build-windows: name: ${{ matrix.config.name }} runs-on: windows-2022 timeout-minutes: 60 strategy: fail-fast: false matrix: config: - { name: 'Build on Windows (Qbs)', script: './scripts/build-qbs-with-qbs.sh', options: 'modules.cpp.compilerWrapper:clcache modules.qbs.debugInformation:true modules.qbsbuildconfig.enableAddressSanitizer:false modules.qbsbuildconfig.enableBundledQt:true products.qbs_archive.targetName:qbs-windows-${{ github.run_id }} products.qbs_archive.includeTests:true', cacheid: 'msvc', with_tests: 0, suffix: 'windows', } - { name: 'Build on Windows (CMake)', script: './scripts/build-qbs-with-cmake.sh', options: '', cacheid: 'msvc-cmake', with_tests: 0, suffix: 'windows-cmake', } env: BUILD_OPTIONS: ${{ matrix.config.options }} WITH_TESTS: ${{ matrix.config.with_tests }} QT_ASSUME_STDERR_HAS_CONSOLE: 1 steps: - uses: actions/checkout@v1 - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: clcache cache files uses: actions/cache@v4 with: path: ~/clcache key: ${{ runner.os }}-${{ matrix.config.cacheid }}-clcache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-msvc-clcache - name: Set up Python uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install required packages run: | python -m pip install --upgrade pip pip install beautifulsoup4 lxml pip install git+https://github.com/frerich/clcache.git@cae73d8255d78db8ba11e23c51fd2c9a89e7475b - name: Install Ninja run: choco install ninja shell: bash - name: Install Qt uses: ./.github/actions/download-qt with: toolchain: win64_msvc2019_64 - name: Install Qt Creator uses: ./.github/actions/download-qtc - name: Setup self-signed certificate run: | New-SelfSignedCertificate -DnsName qbs@community.test -Type CodeSigning -CertStoreLocation cert:\CurrentUser\My Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0] -FilePath qbs-code-signing.crt Import-Certificate -FilePath .\qbs-code-signing.crt -CertStoreLocation Cert:\CurrentUser\TrustedPublisher shell: powershell - uses: TheMrMilchmann/setup-msvc-dev@v3 with: arch: x64 - name: Setup Qbs run: | qbs setup-toolchains --detect qbs setup-qt $(which qmake).exe qt qbs config profiles.qt.baseProfile MSVC2022-1-x86_x64 qbs config defaultProfile qt qbs config --list shell: bash - name: Print clcache stats run: clcache -s - name: Build Qbs run: ${{ matrix.config.script }} shell: bash - name: Print clcache stats run: clcache -s - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.zip path: release/qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.zip build-windows-mingw: name: Build on Windows (MinGW) runs-on: windows-2022 timeout-minutes: 60 env: BUILD_OPTIONS: | modules.cpp.compilerWrapper:ccache modules.qbsbuildconfig.enableAddressSanitizer:false modules.qbsbuildconfig.enableBundledQt:true products.qbs_archive.targetName:qbs-windows-mingw-${{ github.run_id }} products.qbs_archive.includeTests:true, QT_ASSUME_STDERR_HAS_CONSOLE: 1 WITH_TESTS: 0 CCACHE_DIR: ${{ github.workspace }}\ccache steps: - uses: actions/checkout@v1 - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: ccache cache files uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-mingw-ccache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-mingw-ccache - name: Set up Python uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install required packages run: | choco install ccache python -m pip install --upgrade pip pip install beautifulsoup4 lxml - name: Install Qt uses: ./.github/actions/download-qt with: toolchain: win64_mingw - name: Install Qt Creator uses: ./.github/actions/download-qtc - name: Install MinGW uses: ./.github/actions/download-mingw - name: Setup Qbs run: | qbs setup-toolchains --type mingw $(which g++).exe mingw-qt qbs setup-qt $(which qmake).exe qt qbs config profiles.qt.baseProfile mingw-qt qbs config defaultProfile qt qbs config --list shell: bash - name: Print ccache stats run: ccache -s - name: Build Qbs run: scripts/build-qbs-with-qbs.sh shell: bash - name: Print ccache stats run: ccache -s - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-windows-mingw-${{ github.run_id }}.zip path: release/qbs-windows-mingw-${{ github.run_id }}.zip test-linux: name: ${{ matrix.config.name }} runs-on: ubuntu-latest timeout-minutes: 90 needs: build-linux strategy: fail-fast: false matrix: config: - { name: 'Run Linux tests (gcc, Qt 6)', image: 'noble-qt6', suffix: 'linux-noble', profile: 'qt-gcc_64', script: './scripts/test-qbs.sh', } - { name: 'Run Linux tests (clang, Qt 6)', image: 'noble-qt6', suffix: 'linux-noble', profile: 'qt-clang_64', script: './scripts/test-qbs.sh', } - { name: 'Run Linux tests (gcc, Qt 5)', image: 'noble-qt5', suffix: 'linux-noble', profile: 'qt-gcc_64', script: './scripts/test-qt.sh', } - { name: 'Run Android tests (Qt 6.5)', image: 'noble-android-65', suffix: 'linux-noble', profile: '', script: './scripts/test-qt-for-android.sh', } - { name: 'Run Android tests (Qt 5.15)', image: 'noble-android-515', suffix: 'linux-noble', profile: '', script: './scripts/test-qt-for-android.sh', } - { name: 'Run Android tests (ndk r25)', image: 'noble-android-ndk-r25', suffix: 'linux-noble', profile: '', script: './scripts/test-for-android.sh', } - { name: 'Run WebAssembly tests', image: 'noble-qt6-wasm', suffix: 'linux-noble', profile: '', script: './scripts/test-wasm.sh', } env: QBS_TEST_SOURCE_ROOT: 'tests' QBS_AUTOTEST_PROFILE: ${{ matrix.config.profile }} QTEST_FUNCTION_TIMEOUT: 9000000 steps: - uses: actions/checkout@v1 - name: Download artifact uses: actions/download-artifact@v4 with: name: qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.tar.gz path: ./ - name: Unpack artifact run: mkdir -p release/install-root/ && tar xzf qbs-${{ matrix.config.suffix }}-${{ github.run_id }}.tar.gz -C release/install-root/ - name: Setup Coredumps run: | sudo bash -c 'echo "/cores/core.%e.%t.%p" > /proc/sys/kernel/core_pattern' sudo mkdir /cores sudo chmod 777 /cores - name: Pull the Docker Image run: docker compose pull ${{ matrix.config.image }} - name: Run tests run: docker compose run ${{ matrix.config.image }} ${{ matrix.config.script }} release/install-root/usr/local/bin - name: Coredump on failure if: ${{ failure() }} run: docker compose run ${{ matrix.config.image }} ./scripts/print-cores.sh test-baremetal: name: Run Baremetal tests (Linux) runs-on: ubuntu-latest timeout-minutes: 60 needs: build-linux env: QBS_TEST_SOURCE_ROOT: 'tests' steps: - uses: actions/checkout@v1 - name: Download artifact uses: actions/download-artifact@v4 with: name: qbs-linux-noble-${{ github.run_id }}.tar.gz path: ./ - name: Unpack artifact run: mkdir -p release/install-root/ && tar xzf qbs-linux-noble-${{ github.run_id }}.tar.gz -C release/install-root/ - name: Pull the Docker Image run: docker compose pull noble-baremetal - name: arm-none-eabi-gcc-13_2 run: QBS_AUTOTEST_PROFILE=arm-none-eabi-gcc-13_2 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin - name: avr-gcc-7_3 run: QBS_AUTOTEST_PROFILE=avr-gcc-7_3 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin - name: riscv64-unknown-elf-gcc-13_2 run: QBS_AUTOTEST_PROFILE=riscv64-unknown-elf-gcc-13_2 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin - name: sdcc-4_0_0-hcs8 run: QBS_AUTOTEST_PROFILE=sdcc-4_2_0-hcs8 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin - name: sdcc-4_0_0-mcs51 run: QBS_AUTOTEST_PROFILE=sdcc-4_2_0-mcs51 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin - name: sdcc-4_0_0-stm8 run: QBS_AUTOTEST_PROFILE=sdcc-4_2_0-stm8 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin - name: xtensa-lx106-elf-gcc-13_2 run: QBS_AUTOTEST_PROFILE=xtensa-lx106-elf-gcc-13_2 docker compose run noble-baremetal scripts/test-baremetal.sh release/install-root/usr/local/bin test-macos: name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.runner }} timeout-minutes: 60 needs: build-macos env: QTEST_FUNCTION_TIMEOUT: 9000000 QBS_AUTOTEST_PROFILE: 'qt' QBS_TEST_SOURCE_ROOT: 'tests' QBS_EXTRA_GRPC_LIBS: 'absl_cord,absl_cordz_handle,absl_cordz_info,absl_synchronization,grpc,gpr' strategy: fail-fast: false matrix: config: - { name: 'Run macOS tests (Xcode 15.1)', runner: 'macos-13', target: 'desktop', toolchain: 'clang_64', xcodeVersion: '15.1', testProfile: 'xcode_15_1-macosx-x86_64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run macOS tests (Xcode 15.1, Qt 5.15)', runner: 'macos-13', target: 'desktop', toolchain: 'clang_64', xcodeVersion: '15.1', testProfile: 'xcode_15_1-macosx-x86_64', qtVersion: '5.15.2', script: './scripts/test-qt.sh', } - { name: 'Run iOS tests (Xcode 15.1)', runner: 'macos-13', target: 'ios', toolchain: 'ios', xcodeVersion: '15.1', testProfile: 'xcode_15_1-iphoneos-arm64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run iOS-sim tests (Xcode 15.1)', runner: 'macos-13', target: 'ios', toolchain: 'ios', xcodeVersion: '15.1', testProfile: 'xcode_15_1-iphonesimulator-x86_64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run macOS tests (Xcode 14.3.1)', runner: 'macos-13', target: 'desktop', toolchain: 'clang_64', xcodeVersion: '14.3.1', testProfile: 'xcode_14_3_1-macosx-x86_64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run macOS tests (Xcode 14.2)', runner: 'macos-13', target: 'desktop', toolchain: 'clang_64', xcodeVersion: '14.2', testProfile: 'xcode_14_2-macosx-x86_64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run macOS tests (Xcode-less)', runner: 'macos-13', target: 'desktop', toolchain: 'clang_64', xcodeVersion: '', testProfile: 'clang', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } steps: - uses: actions/checkout@v1 - name: Download artifact uses: actions/download-artifact@v4 with: name: qbs-macos-${{ github.run_id }}.tar.gz path: ./ - name: Unpack artifact run: mkdir -p release/install-root/ && tar xzf qbs-macos-${{ github.run_id }}.tar.gz -C release/install-root/ - name: Update PATH run: echo "./release/install-root/usr/local/bin" >> $GITHUB_PATH - name: Install required packages run: brew install capnp ccache grpc icoutils makensis protobuf p7zip - name: Set up Python uses: actions/setup-python@v5 if: matrix.config.toolchain == 'clang_64' with: python-version: 3.12 - name: Install Conan if: matrix.config.toolchain == 'clang_64' uses: turtlebrowser/get-conan@main - name: Setup Conan if: matrix.config.toolchain == 'clang_64' run: | brew install ninja ./scripts/setup-conan-profiles.sh - name: Install Host Qt if: matrix.config.toolchain == 'ios' uses: ./.github/actions/download-qt with: target: 'desktop' toolchain: 'clang_64' version: ${{ matrix.config.qtVersion }} - name: Install Qt uses: ./.github/actions/download-qt with: target: ${{ matrix.config.target }} toolchain: ${{ matrix.config.toolchain }} version: ${{ matrix.config.qtVersion }} - name: Select Xcode run: sudo xcode-select --switch /Applications/Xcode_${{ matrix.config.xcodeVersion }}.app if: matrix.config.xcodeVersion != '' - name: Setup Qbs run: | qbs setup-toolchains --detect qbs setup-qt $(which qmake) qt qbs config profiles.qt.baseProfile ${{ matrix.config.testProfile }} qbs config defaultProfile qt qbs config --list if: matrix.config.xcodeVersion != '' - name: Setup Qbs (Xcode-less) run: | qbs setup-toolchains /usr/bin/clang++ ${{ matrix.config.testProfile }} qbs setup-qt $(which qmake) qt qbs config profiles.qt.baseProfile ${{ matrix.config.testProfile }} qbs config defaultProfile qt qbs config --list if: matrix.config.xcodeVersion == '' - name: Run Tests run: | sudo chmod 777 /cores ulimit -c unlimited ${{ matrix.config.script }} ./release/install-root/usr/local/bin - name: Coredump on failure if: ${{ failure() }} run: | for f in $(find /cores -maxdepth 1 -name 'core.*' -print); do lldb --core $f --batch --one-line "bt all" done; test-windows: name: ${{ matrix.config.name }} runs-on: windows-2022 timeout-minutes: 60 needs: build-windows strategy: fail-fast: false matrix: config: - { name: 'Run Windows tests (MSVC 2022)', target: 'desktop', toolchain: 'win64_msvc2019_64', testProfile: 'MSVC2022-x64', conan_toolchain: 'msvc_64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run Windows tests (MSVC 2022, Qt 5.15)', target: 'desktop', toolchain: 'win64_msvc2019_64', testProfile: 'MSVC2022-x64', conan_toolchain: '', qtVersion: '5.15.2', script: './scripts/test-qt.sh', } - { name: 'Run Windows tests (clang-cl)', target: 'desktop', toolchain: 'win64_msvc2019_64', testProfile: 'clang-cl-x86_64', conan_toolchain: '', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } - { name: 'Run Windows tests (MinGW)', target: 'desktop', toolchain: 'win64_mingw', testProfile: 'mingw-qt', conan_toolchain: 'mingw_64', qtVersion: '6.5.0', script: './scripts/test-qbs.sh', } env: QTEST_FUNCTION_TIMEOUT: 9000000 QBS_AUTOTEST_PROFILE: 'qt' QBS_TEST_SOURCE_ROOT: 'tests' QT_ASSUME_STDERR_HAS_CONSOLE: 1 steps: - uses: actions/checkout@v1 - name: Download artifact uses: actions/download-artifact@v4 with: name: qbs-windows-${{ github.run_id }}.zip path: ./ - name: Unpack artifact run: | mkdir -p release/install-root cd release/install-root 7z x ../../qbs-windows-${{ github.run_id }}.zip shell: bash - name: Update PATH run: echo "./release/install-root/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Install required packages run: choco install -y pkgconfiglite --download-checksum=6004df17818f5a6dbf19cb335cc92702 continue-on-error: true # pkgconfiglite installation is flaky - name: Install Qt uses: ./.github/actions/download-qt with: toolchain: ${{ matrix.config.toolchain }} version: ${{ matrix.config.qtVersion }} - name: Install MinGW uses: ./.github/actions/download-mingw - name: Install Ninja if: matrix.config.conan_toolchain != '' run: | choco install ninja shell: bash - name: Install Conan if: matrix.config.conan_toolchain != '' uses: turtlebrowser/get-conan@main - name: Configure Conan if: matrix.config.conan_toolchain != '' run: | ./scripts/setup-conan-profiles.sh --toolchain ${{ matrix.config.conan_toolchain }} which ninja shell: bash - name: Setup Qbs run: | qbs setup-toolchains --detect qbs setup-toolchains --type mingw $(which g++).exe mingw-qt qbs setup-qt $(which qmake).exe qt qbs config profiles.qt.baseProfile ${{ matrix.config.testProfile }} qbs config defaultProfile qt qbs config --list shell: bash - name: Setup self-signed certificate run: | New-SelfSignedCertificate -DnsName qbs@community.test -Type CodeSigning -CertStoreLocation cert:\CurrentUser\My Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0] -FilePath qbs-code-signing.crt Import-Certificate -FilePath .\qbs-code-signing.crt -CertStoreLocation Cert:\CurrentUser\TrustedPublisher shell: powershell - name: Run Tests run: ${{ matrix.config.script }} ./release/install-root/bin shell: bash test-windows-extra: name: ${{ matrix.config.name }} runs-on: windows-latest timeout-minutes: 60 needs: build-windows strategy: fail-fast: false matrix: config: - { name: 'Run Windows tests (OpenWatcom DOS 32 bit)', testProfile: 'watcom-2_0_0-dos-x86', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (OpenWatcom DOS 16 bit)', testProfile: 'watcom-2_0_0-dos-x86_16', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (OpenWatcom OS/2 32 bit)', testProfile: 'watcom-2_0_0-os2-x86', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (OpenWatcom OS/2 16 bit)', testProfile: 'watcom-2_0_0-os2-x86_16', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (OpenWatcom Windows 32 bit)', testProfile: 'watcom-2_0_0-windows-x86', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (OpenWatcom Windows 16 bit)', testProfile: 'watcom-2_0_0-windows-x86_16', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (DigitalMars DOS 16 bit)', testProfile: 'dmc-8_57_0-dos-x86_16', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (DigitalMars Windows 32 bit)', testProfile: 'dmc-8_57_0-windows-x86', script: './scripts/test-baremetal.sh', } - { name: 'Run Windows tests (DigitalMars Windows 16 bit)', testProfile: 'dmc-8_57_0-windows-x86_16', script: './scripts/test-baremetal.sh', } env: QTEST_FUNCTION_TIMEOUT: 9000000 QBS_AUTOTEST_PROFILE: 'extra' QBS_TEST_SOURCE_ROOT: 'tests' QT_ASSUME_STDERR_HAS_CONSOLE: 1 steps: - uses: actions/checkout@v1 - name: Download artifact uses: actions/download-artifact@v4 with: name: qbs-windows-${{ github.run_id }}.zip path: ./ - name: Unpack artifact run: | mkdir -p release/install-root cd release/install-root 7z x ../../qbs-windows-${{ github.run_id }}.zip shell: bash - name: Update PATH run: echo "./release/install-root/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Install OpenWatcom uses: ./.github/actions/download-ow - name: Install DigitalMars uses: ./.github/actions/download-dm - name: Setup Qbs run: | qbs setup-toolchains --detect qbs config profiles.extra.baseProfile ${{ matrix.config.testProfile }} qbs config defaultProfile extra qbs config --list shell: bash - name: Run Tests run: ${{ matrix.config.script }} ./release/install-root/bin shell: bash qbs-src-2.6.1/.github/workflows/docs.yml0000644000175100001660000000163614776170045017526 0ustar runnerdockername: Build and Qbs docs on: push: paths: - 'doc/**' - 'examples/**' - 'scripts/build-qbs-doc.sh' - 'VERSION' jobs: build-docs: name: ${{ matrix.config.name }} runs-on: ubuntu-latest timeout-minutes: 60 strategy: fail-fast: false matrix: config: - { name: 'Build Qbs Docs', options: '', script: './scripts/build-qbs-doc.sh' } env: BUILD_OPTIONS: ${{ matrix.config.options }} WITH_TESTS: 0 steps: - uses: actions/checkout@v1 - name: Pull the Docker Image run: docker compose pull noble - name: Build Qbs Docs run: docker compose run noble ${{ matrix.config.script }} - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-docs-${{ github.run_id }} path: documentation/install-root/usr/local/share/doc/qbs/ qbs-src-2.6.1/.github/workflows/release.yml0000644000175100001660000002072114776170045020212 0ustar runnerdockername: Build release packages on: push: branches-ignore: - 'gerrit/*' tags: - 'v*' jobs: build-linux: name: ${{ matrix.config.name }} runs-on: ubuntu-latest timeout-minutes: 60 strategy: fail-fast: false matrix: config: - { name: 'Build on Linux (gcc)', options: 'qbs.installPrefix:"" modules.cpp.compilerWrapper:ccache modules.qbsbuildconfig.enableAddressSanitizer:false project.withTests:false modules.qbsbuildconfig.enableUnitTests:false modules.qbsbuildconfig.enableBundledQt:true products.qbs_archive.targetName:qbs-linux-${{ github.run_id }}', script: './scripts/build-qbs-with-qbs.sh', cacheid: 'gcc-release', } env: BUILD_OPTIONS: ${{ matrix.config.options }} WITH_TESTS: 0 steps: - uses: actions/checkout@v1 - name: Create .ccache dir run: mkdir -p ~/.ccache - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: ccache cache files uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-${{ matrix.config.cacheid }}-ccache - name: Pull the Docker Image run: docker compose pull noble-qt6 - name: Print ccache stats run: docker compose run noble-qt6 ccache -s - name: Build Qbs run: docker compose run noble-qt6 ${{ matrix.config.script }} - name: Print ccache stats run: docker compose run noble-qt6 ccache -s - name: Get archive name id: get-archive-name run: echo "archive-name=$(git describe)" >> $GITHUB_OUTPUT - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-linux-${{ github.run_id }}.tar.gz path: release/qbs-linux-${{ github.run_id }}.tar.gz build-macos: name: Build on macOS runs-on: macos-13 timeout-minutes: 60 env: BUILD_OPTIONS: | qbs.installPrefix:"" modules.cpp.compilerWrapper:ccache project.withTests:false modules.qbsbuildconfig.enableUnitTests:false modules.qbsbuildconfig.enableAddressSanitizer:false modules.qbsbuildconfig.enableBundledQt:true products.qbs_archive.targetName:qbs-macos-${{ github.run_id }} WITH_TESTS: 0 steps: - uses: actions/checkout@v1 - name: Create .ccache dir run: mkdir -p ~/.ccache - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: ccache cache files uses: actions/cache@v4 with: path: ~/.ccache key: ${{ runner.os }}-release-ccache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-release-ccache - name: Install required packages run: | brew install ccache p7zip python3 -m pip install --user beautifulsoup4 lxml - name: Install Qt uses: ./.github/actions/download-qt with: toolchain: clang_64 - name: Install Qt Creator uses: ./.github/actions/download-qtc - name: Setup Qbs run: | qbs setup-toolchains --detect qbs setup-qt --detect qbs config profiles.qt.baseProfile xcode_14_2-macosx-x86_64 qbs config defaultProfile qt qbs config --list - name: Print ccache stats run: ccache -s - name: Build Qbs run: scripts/build-qbs-with-qbs.sh - name: Print ccache stats run: ccache -s - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-macos-${{ github.run_id }}.tar.gz path: release/qbs-macos-${{ github.run_id }}.tar.gz build-windows-with-docker: name: Build on Windows (Docker) runs-on: windows-2019 timeout-minutes: 60 env: WITH_TESTS: 0 QT_ASSUME_STDERR_HAS_CONSOLE: 1 CLCACHE_DIR: C:\.ccache steps: - uses: actions/checkout@v1 - name: Create .ccache dir run: mkdir -p ~/.ccache shell: bash - name: prepare timestamp id: get-timestamp run: echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT shell: bash - name: clcache cache files uses: actions/cache@v4 with: path: ~/clcache key: ${{ runner.os }}-release-msvc-docker-clcache-${{ steps.get-timestamp.outputs.timestamp }} restore-keys: ${{ runner.os }}-release-msvc-docker-clcache - name: Pull the Windows Image run: docker compose pull windows - name: Print clcache stats run: docker compose run --rm windows clcache -s - name: Build Qbs run: > docker compose run --rm windows qbs build -p dist qbs.buildVariant:release modules.cpp.compilerWrapper:clcache project.withTests:false modules.qbsbuildconfig.enableBundledQt:true modules.qbsbuildconfig.enableUnitTests:false modules.cpp.treatWarningsAsErrors:true project.withDocumentation:true config:release profile:qt64 - name: Print clcache stats run: docker compose run --rm windows clcache -s - name: Get archive name id: get-archive-name run: echo "archive-name=$(git describe)" >> $GITHUB_OUTPUT - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-windows-${{ github.run_id }} path: | release/qbs.*.nupkg release/qbs-windows-*.zip create-archives: name: Create Archives runs-on: ubuntu-latest needs: [build-linux, build-windows-with-docker] steps: - uses: actions/checkout@v1 with: submodules: true - name: Get version name id: get-version-name run: echo "version-name=$(cat VERSION)" >> $GITHUB_OUTPUT - name: Create directories run: | mkdir release mkdir tmp - name: Copy sources run: rsync -av --exclude='.git/' --exclude='tmp/' . ./tmp/qbs-src-${{ steps.get-version-name.outputs.version-name }} - name: Zip Archive run: | cd tmp/ zip -r ../release/qbs-src-${{ steps.get-version-name.outputs.version-name }}.zip qbs-src-${{ steps.get-version-name.outputs.version-name }} - name: Tarball Archive run: | cd tmp/ tar czf ../release/qbs-src-${{ steps.get-version-name.outputs.version-name }}.tar.gz qbs-src-${{ steps.get-version-name.outputs.version-name }} - name: Download Linux artifacts uses: actions/download-artifact@v4 with: name: qbs-linux-${{ github.run_id }}.tar.gz path: ./tmp - name: Repack Linux artifact run: | mkdir -p tmp/qbs-linux-x86_64-${{ steps.get-version-name.outputs.version-name }} tar xzf ./tmp/qbs-linux-${{ github.run_id }}.tar.gz -C tmp/qbs-linux-x86_64-${{ steps.get-version-name.outputs.version-name }} cd tmp/ tar czf ../release/qbs-linux-x86_64-${{ steps.get-version-name.outputs.version-name }}.tar.gz qbs-linux-x86_64-${{ steps.get-version-name.outputs.version-name }} - name: Download Windows artifacts uses: actions/download-artifact@v4 with: name: qbs-windows-${{ github.run_id }} path: ./tmp/release - name: Copy Windows artifacts run: | cp ./tmp/release/qbs.*.nupkg ./release cp ./tmp/release/qbs-windows-x86_64-*.zip ./release - name: Copy changelog run: cp changelogs/changes-${{ steps.get-version-name.outputs.version-name }}.md release || echo "changelog not found" - name: Generate checksums run: | cd release/ find . -type f -printf '%f\n' | grep -v .txt | xargs md5sum > md5sums.txt find . -type f -printf '%f\n' | grep -v .txt | xargs sha256sum > sha256sums.txt - name: Get archive name id: get-archive-name run: echo "archive-name=$(git describe)" >> $GITHUB_OUTPUT - name: Upload artifacts uses: 'actions/upload-artifact@v4' with: name: qbs-release-${{ steps.get-archive-name.outputs.archive-name }} path: | release/qbs-src-*.zip release/qbs-src-*.tar.gz release/qbs-linux-*.tar.gz release/qbs.*.nupkg release/qbs-windows-x86_64-*.zip release/changes-*.md release/md5sums.txt release/sha256sums.txt qbs-src-2.6.1/CMakeLists.txt0000644000175100001660000000404114776170045015207 0ustar runnerdockercmake_minimum_required(VERSION 3.10) if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") cmake_policy(VERSION 3.15) endif() ## Add paths to check for cmake modules: list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(FeatureSummary) include(QbsBuildConfig) include(QbsDocumentation) file(STRINGS VERSION QBS_VERSION) project(Qbs VERSION ${QBS_VERSION}) # Force C++ standard, do not fall back, do not use compiler extensions set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Set up Qt stuff: set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) if(WITH_TESTS) enable_testing() set(QT_TEST_COMPONENT Test) set(IMPLICIT_DEPENDS Qt${QT_VERSION_MAJOR}::Test) endif() find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Concurrent Core Gui Network Widgets Xml ${QT_TEST_COMPONENT} REQUIRED ) find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS Script QUIET) if (Qt6_FOUND) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core5Compat REQUIRED) if(NOT TARGET Qt6Core5Compat) if(CMAKE_VERSION VERSION_LESS 3.18) set_property(TARGET Qt6::Core5Compat PROPERTY IMPORTED_GLOBAL TRUE) # hack for CMake < 3.18 endif() add_library(Qt6Core5Compat ALIAS Qt6::Core5Compat) endif() else() if(NOT TARGET Qt6Core5Compat) add_library(Qt6Core5Compat INTERFACE) endif() find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS DocTools) endif() if (QBS_INSTALL_HTML_DOCS OR QBS_INSTALL_QCH_DOCS) find_package(Python3 COMPONENTS Interpreter) if (Qt6_FOUND) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Tools REQUIRED) else() find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Help REQUIRED) endif() endif() add_definitions(-DQT_NO_QSNPRINTF -D_UCRT_NOISY_NAN) add_subdirectory(src) add_subdirectory(doc) add_subdirectory(share) if(WITH_TESTS) add_subdirectory(tests) endif() qbs-src-2.6.1/bin/0000755000175100001660000000000014776170045013220 5ustar runnerdockerqbs-src-2.6.1/bin/ibmsvc.xml0000644000175100001660000000112214776170045015221 0ustar runnerdocker qbs-src-2.6.1/bin/ibqbs.bat0000644000175100001660000000007514776170045015012 0ustar runnerdocker@xgConsole /profile=%~dp0\ibmsvc.xml /command="qbs -j 20 %*" qbs-src-2.6.1/.gitattributes0000644000175100001660000000014714776170045015345 0ustar runnerdocker/.gitignore export-ignore /.gitattributes export-ignore /scripts/make-release-archive.sh export-ignore qbs-src-2.6.1/cmake/0000755000175100001660000000000014776170045013530 5ustar runnerdockerqbs-src-2.6.1/cmake/QbsDocumentation.cmake0000644000175100001660000002634014776170045020016 0ustar runnerdocker# Options: option(QBS_INSTALL_HTML_DOCS "Whether to install Qbs HTML Documentation" OFF) option(QBS_INSTALL_QCH_DOCS "Whether to install Qbs QCH Documentation" OFF) option(QBS_INSTALL_MAN_PAGE "Whether to install Qbs man page" OFF) # Get information on directories from qmake # as this is not yet exported by cmake. # Used for QT_INSTALL_DOCS function(qt_query_qmake) if (NOT TARGET Qt${QT_VERSION_MAJOR}::qmake) message(FATAL_ERROR "Qmake was not found. Add find_package(Qt5 COMPONENTS Core) to CMake to enable.") endif() # dummy check for if we already queried qmake if (QT_INSTALL_BINS) return() endif() get_target_property(_qmake_binary Qt${QT_VERSION_MAJOR}::qmake IMPORTED_LOCATION) execute_process(COMMAND "${_qmake_binary}" "-query" TIMEOUT 10 RESULT_VARIABLE _qmake_result OUTPUT_VARIABLE _qmake_stdout OUTPUT_STRIP_TRAILING_WHITESPACE) if (NOT "${_qmake_result}" STREQUAL "0") message(FATAL_ERROR "Qmake did not execute successfully: ${_qmake_result}.") endif() # split into lines: string(REPLACE "\n" ";" _lines "${_qmake_stdout}") foreach(_line ${_lines}) # split line into key/value pairs string(REPLACE ":" ";" _parts "${_line}") list(GET _parts 0 _key) list(REMOVE_AT _parts 0) string(REPLACE ";" ":" _value "${_parts}") set("${_key}" "${_value}" CACHE PATH "qmake import of ${_key}" FORCE) endforeach() endfunction() function(_qbs_setup_doc_targets) # Set up important targets: if (NOT TARGET qbs_html_docs) add_custom_target(qbs_html_docs COMMENT "Build HTML documentation") endif() if (NOT TARGET qbs_qch_docs) add_custom_target(qbs_qch_docs COMMENT "Build QCH documentation") endif() if (NOT TARGET BuildQbsDocumentation) add_custom_target( BuildQbsDocumentation ALL COMMENT "Build Qbs documentation") add_dependencies(BuildQbsDocumentation qbs_html_docs qbs_qch_docs) endif() if (NOT TARGET qbs_docs) add_custom_target( qbs_docs ALL COMMENT "Build Qbs documentation") add_dependencies(qbs_docs BuildQbsDocumentation) endif() endfunction() function(_find_python_module module) string(TOUPPER ${module} module_upper) if (NOT PY_${module_upper}) if (ARGC GREATER 1 AND ARGV1 STREQUAL "REQUIRED") set(${module}_FIND_REQUIRED TRUE) endif() # A module's location is usually a directory, but for binary modules # it's a .so file. execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import re, ${module}; print(re.compile('/__init__.py.*').sub('',${module}.__file__))" RESULT_VARIABLE _${module}_status OUTPUT_VARIABLE _${module}_location ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (NOT _${module}_status) set(PY_${module_upper} ${_${module}_location} CACHE STRING "Location of Python module ${module}") endif() endif() find_package_handle_standard_args(PY_${module} DEFAULT_MSG PY_${module_upper}) endfunction() function(_qbs_setup_qdoc_targets _qdocconf_file _retval) cmake_parse_arguments(_arg "" "HTML_DIR;INSTALL_DIR;POSTFIX" "INDEXES;INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;ENVIRONMENT_EXPORTS;SOURCES" ${ARGN}) foreach(_index ${_arg_INDEXES}) list(APPEND _qdoc_index_args "-indexdir;${_index}") endforeach() set(_env "") foreach(_export ${_arg_ENVIRONMENT_EXPORTS}) if (NOT DEFINED "${_export}") message(FATAL_ERROR "${_export} is not known when trying to export it to qdoc.") endif() list(APPEND _env "${_export}=${${_export}}") endforeach() get_target_property(_qdoc Qt${QT_VERSION_MAJOR}::qdoc IMPORTED_LOCATION) set(_full_qdoc_command "${_qdoc}") if (_env) set(_full_qdoc_command "${CMAKE_COMMAND}" "-E" "env" ${_env} "${_qdoc}") endif() if (_arg_HTML_DIR STREQUAL "") set(_arg_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc") endif() get_filename_component(_target "${_qdocconf_file}" NAME_WE) set(_html_outputdir "${_arg_HTML_DIR}") file(MAKE_DIRECTORY "${_html_outputdir}") set(_qdoc_include_args "") if (_arg_INCLUDE_DIRECTORIES OR _arg_FRAMEWORK_PATHS) # pass include directories to qdoc via hidden @ option, since we need to generate a file # to be able to resolve the generators inside the include paths set(_qdoc_includes "${CMAKE_CURRENT_BINARY_DIR}/cmake/qdoc_${_target}.inc") set(_qdoc_include_args "@${_qdoc_includes}") set(_includes "") if (_arg_INCLUDE_DIRECTORIES) set(_includes "-I$\n") endif() set(_frameworks "") if (_arg_FRAMEWORK_PATHS) set(_frameworks "-F$\n") endif() file(GENERATE OUTPUT "${_qdoc_includes}" CONTENT "${_includes}${_frameworks}" ) endif() set(_html_artifact "${_html_outputdir}/index.html") add_custom_command( OUTPUT "${_html_artifact}" COMMAND cmake -E remove_directory "${_html_outputdir}" COMMAND ${_full_qdoc_command} -outputdir "${_html_outputdir}" "${_qdocconf_file}" ${_qdoc_index_args} ${_qdoc_include_args} DEPENDS "${_qdocconf_file}" ${_arg_SOURCES} COMMENT "Build HTML documentation from ${_qdocconf_file}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM ) if (NOT Python3_Interpreter_FOUND) message(WARNING "Cannot find python3 binary. Qbs documentation will not be built.") return() endif() _find_python_module(lxml) _find_python_module(bs4) if (NOT PY_LXML OR NOT PY_BS4) message(WARNING "Cannot import lxml and bs4 python modules. Qbs documentation will not be built.") return() endif() set(_fixed_html_artifact "${CMAKE_CURRENT_BINARY_DIR}/qbsdoc.dummy") set(_fix_qml_imports_script ${Qbs_SOURCE_DIR}/doc/fix-qmlimports.py) add_custom_command( OUTPUT "${_fixed_html_artifact}" COMMAND ${Python3_EXECUTABLE} "${_fix_qml_imports_script}" ${_html_outputdir} COMMAND cmake -E touch ${_fixed_html_artifact} DEPENDS "${_html_artifact}" "${_fix_qml_imports_script}" COMMENT "Fixing bogus QML import statements" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM ) set(_html_target "qbs_html_docs_${_target}") add_custom_target(${_html_target} DEPENDS "${_fixed_html_artifact}") add_dependencies(qbs_html_docs "${_html_target}") # artifacts might be required for QCH-only installation, so we build them # always, and skip HTML docs installation here if (QBS_INSTALL_HTML_DOCS) install(DIRECTORY "${_html_outputdir}" DESTINATION "${_arg_INSTALL_DIR}" COMPONENT qbs_docs) endif() set("${_retval}" "${_html_outputdir}" PARENT_SCOPE) endfunction() function(_qbs_setup_qhelpgenerator_targets _qdocconf_file _html_outputdir) cmake_parse_arguments(_arg "" "QCH_DIR;INSTALL_DIR" "" ${ARGN}) if (_arg_UNPARSED_ARGUMENTS) message(FATAL_ERROR "qdoc_build_qdocconf_file has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.") endif() if (NOT _arg_QCH_DIR) set(_arg_QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc") endif() if (NOT TARGET Qt${QT_VERSION_MAJOR}::qhelpgenerator) message(WARNING "qhelpgenerator missing: No QCH documentation targets were generated. Add find_package(Qt5 COMPONENTS Help) to CMake to enable.") return() endif() get_filename_component(_target "${_qdocconf_file}" NAME_WE) set(_html_target "qbs_html_docs_${_target}") if (NOT TARGET ${_html_target}) return() endif() set(_qch_outputdir "${_arg_QCH_DIR}") file(MAKE_DIRECTORY "${_qch_outputdir}") set(_fixed_html_artifact "${CMAKE_CURRENT_BINARY_DIR}/qbsdoc.dummy") set(_qhp_artifact "${_html_outputdir}/${_target}.qhp") set(_qch_artifact "${_qch_outputdir}/${_target}.qch") add_custom_command( OUTPUT "${_qch_artifact}" COMMAND Qt${QT_VERSION_MAJOR}::qhelpgenerator "${_qhp_artifact}" -o "${_qch_artifact}" DEPENDS "${_fixed_html_artifact}" COMMENT "Build QCH documentation from ${_qdocconf_file}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM ) set(_qch_target "qbs_qch_docs_${_target}") add_custom_target("${_qch_target}" DEPENDS "${_qch_artifact}") add_dependencies(qbs_qch_docs "${_qch_target}") install(FILES "${_qch_outputdir}/${_target}.qch" DESTINATION "${_arg_INSTALL_DIR}" COMPONENT qbs_docs) endfunction() # Helper functions: function(_qbs_qdoc_build_qdocconf_file _qdocconf_file) _qbs_setup_doc_targets() if (NOT TARGET Qt${QT_VERSION_MAJOR}::qdoc) message(WARNING "No qdoc binary found: No documentation targets were generated") return() endif() cmake_parse_arguments(_arg "QCH" "HTML_DIR;QCH_DIR;INSTALL_DIR;POSTFIX" "INDEXES;INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;ENVIRONMENT_EXPORTS;SOURCES" ${ARGN}) if (_arg_UNPARSED_ARGUMENTS) message(FATAL_ERROR "qdoc_build_qdocconf_file has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.") endif() if (NOT _arg_INSTALL_DIR) message(FATAL_ERROR "No INSTALL_DIR set when calling qdoc_build_qdocconf_file") endif() _qbs_setup_qdoc_targets("${_qdocconf_file}" _html_outputdir HTML_DIR "${_arg_HTML_DIR}" INSTALL_DIR "${_arg_INSTALL_DIR}" INDEXES ${_arg_INDEXES} ENVIRONMENT_EXPORTS ${_arg_ENVIRONMENT_EXPORTS} POSTFIX "${_arg_POSTFIX}" INCLUDE_DIRECTORIES ${_arg_INCLUDE_DIRECTORIES} FRAMEWORK_PATHS ${_arg_FRAMEWORK_PATHS} SOURCES ${_arg_SOURCES} ) if (_arg_QCH) _qbs_setup_qhelpgenerator_targets("${_qdocconf_file}" "${_html_outputdir}" QCH_DIR "${_arg_QCH_DIR}" INSTALL_DIR "${_arg_INSTALL_DIR}") endif() endfunction() function(add_qbs_documentation qdocconf_file) cmake_parse_arguments(_arg "" "" "INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;SOURCES" ${ARGN}) if (_arg_UNPARSED_ARGUMENTS) message(FATAL_ERROR "add_qbs_documentation has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.") endif() ### Skip docs setup if that is not needed! if (NOT QBS_INSTALL_HTML_DOCS AND NOT QBS_INSTALL_QCH_DOCS) return() endif() qt_query_qmake() set(SRCDIR "${Qbs_SOURCE_DIR}/doc") set(_qch_params) # if QBS_INSTALL_QCH_DOCS is No, qch generation will be skipped entirely if (QBS_INSTALL_QCH_DOCS) set(_qch_params QCH QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}") endif() set(_qdoc_params HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/${QBS_DOC_HTML_DIR_NAME}") list(APPEND _qdoc_params INSTALL_DIR "${QBS_DOC_INSTALL_DIR}") # Set up environment for qdoc: string(REPLACE "." "" QBS_VERSION_TAG "${QBS_VERSION}") list(APPEND _qdoc_params ENVIRONMENT_EXPORTS SRCDIR QBS_VERSION QBS_VERSION_TAG QT_INSTALL_DOCS ) _qbs_qdoc_build_qdocconf_file(${qdocconf_file} ${_qch_params} ${_qdoc_params} INCLUDE_DIRECTORIES ${_arg_INCLUDE_DIRECTORIES} FRAMEWORK_PATHS ${_arg_FRAMEWORK_PATHS} SOURCES ${_arg_SOURCES} ) endfunction() qbs-src-2.6.1/cmake/QbsBuildConfig.cmake0000644000175100001660000002506714776170045017377 0ustar runnerdockeroption(WITH_TESTS "Build Tests" ON) option(WITH_UNIT_TESTS "Build Unit Tests" OFF) option(INSTALL_PUBLIC_HEADERS "Whether to install public headers" ON) option(QBS_ENABLE_RPATH "Whether to enable RPATH" ON) include(CMakeDependentOption) cmake_dependent_option(QBS_QUICKJS_LEAK_CHECK "Whether to check for quickjs leaks at the end" ON "CMAKE_BUILD_TYPE STREQUAL Debug" OFF) set(QBS_APP_INSTALL_DIR "bin" CACHE STRING "Relative install location for Qbs binaries.") # default paths set(QBS_LIBDIR_NAME "lib") if(WIN32) set(_DEFAULT_LIB_INSTALL_DIR ${QBS_APP_INSTALL_DIR}) set(_DEFAULT_LIBEXEC_INSTALL_DIR ${QBS_APP_INSTALL_DIR}) else() set(_DEFAULT_LIB_INSTALL_DIR ${QBS_LIBDIR_NAME}) set(_DEFAULT_LIBEXEC_INSTALL_DIR "libexec/qbs") endif() # path options set(QBS_OUTPUT_PREFIX "" CACHE STRING "Qbs build output location relative to CMAKE_BINARY_DIR.") set(QBS_LIB_INSTALL_DIR "${_DEFAULT_LIB_INSTALL_DIR}" CACHE STRING "Relative install location for Qbs libraries.") set(QBS_DLL_INSTALL_DIR "${QBS_LIB_INSTALL_DIR}" CACHE STRING "Relative install location for Qbs DLLs.") set(QBS_LIBEXEC_INSTALL_DIR "${_DEFAULT_LIBEXEC_INSTALL_DIR}" CACHE STRING "Relative install location for Qbs libexec.") set(QBS_PLUGINS_INSTALL_BASE "${QBS_LIBDIR_NAME}" CACHE STRING "Relative install location for Qbs plugins.") set(QBS_RESOURCES_INSTALL_BASE "." CACHE STRING "Relative install location for Qbs resources.") set(QBS_HEADERS_INSTALL_DIR "include/qbs" CACHE STRING "Relative install location for Qbs headers.") set(QBS_DOC_INSTALL_DIR "${QBS_RESOURCES_INSTALL_BASE}/share/doc/qbs" CACHE STRING "Relative install location for Qbs documentation.") set(QBS_DOC_HTML_DIR_NAME "html" CACHE STRING "The name of the dir with HTML files, appended to QBS_DOC_INSTALL_DIR.") set(QBS_PLUGINS_INSTALL_DIR "${QBS_PLUGINS_INSTALL_BASE}/qbs/plugins") set(QBS_RESOURCES_INSTALL_DIR "${QBS_RESOURCES_INSTALL_BASE}/share") # rpaths file(RELATIVE_PATH QBS_RELATIVE_LIBEXEC_RPATH "/${QBS_LIBEXEC_INSTALL_DIR}" "/${QBS_LIB_INSTALL_DIR}") file(RELATIVE_PATH QBS_RELATIVE_APP_RPATH "/${QBS_APP_INSTALL_DIR}" "/${QBS_LIB_INSTALL_DIR}") file(RELATIVE_PATH QBS_RELATIVE_PLUGINS_RPATH "/${QBS_PLUGINS_INSTALL_DIR}" "/${QBS_LIB_INSTALL_DIR}") if(WIN32 OR NOT QBS_ENABLE_RPATH) set(QBS_MACOSX_RPATH OFF) set(QBS_LIB_RPATH "") set(QBS_LIBEXEC_RPATH "") set(QBS_APP_RPATH "") set(QBS_PLUGINS_RPATH "") elseif(APPLE) set(QBS_MACOSX_RPATH ON) set(QBS_LIB_RPATH "@loader_path") set(QBS_LIBEXEC_RPATH "@loader_path/${QBS_RELATIVE_LIBEXEC_RPATH}") set(QBS_APP_RPATH "@loader_path/${QBS_RELATIVE_APP_RPATH}") set(QBS_PLUGINS_RPATH "@loader_path/${QBS_RELATIVE_PLUGINS_RPATH}") else() set(QBS_MACOSX_RPATH OFF) set(QBS_LIB_RPATH "\$ORIGIN") set(QBS_LIBEXEC_RPATH "\$ORIGIN/${QBS_RELATIVE_LIBEXEC_RPATH}") set(QBS_APP_RPATH "\$ORIGIN/${QBS_RELATIVE_APP_RPATH}") set(QBS_PLUGINS_RPATH "\$ORIGIN/${QBS_RELATIVE_PLUGINS_RPATH}") endif() function(get_update_path_command var) if(WIN32) get_target_property(_QTCORE_LIBRARY Qt${QT_VERSION_MAJOR}::Core IMPORTED_LOCATION_RELEASE) if(NOT _QTCORE_LIBRARY) get_target_property(_QTCORE_LIBRARY Qt${QT_VERSION_MAJOR}::Core IMPORTED_LOCATION_DEBUG) endif() get_filename_component(_QT_LIBRARY_PATH "${_QTCORE_LIBRARY}" DIRECTORY) get_target_property(_QBS_LIBRARY_PATH qbscore LIBRARY_OUTPUT_DIRECTORY) file(TO_NATIVE_PATH "${_QT_LIBRARY_PATH}\;${_QBS_LIBRARY_PATH}\;$ENV{PATH}" _NEW_PATH) set(${var} "PATH=${_NEW_PATH}" PARENT_SCOPE) else() set(${var} "") endif() endfunction() if(WITH_UNIT_TESTS) set(QBS_UNIT_TESTS_DEFINES "QBS_ENABLE_UNIT_TESTS") else() set(QBS_UNIT_TESTS_DEFINES "") endif() file(RELATIVE_PATH QBS_RELATIVE_LIBEXEC_PATH "/${QBS_APP_INSTALL_DIR}" "/${QBS_LIBEXEC_INSTALL_DIR}") file(RELATIVE_PATH QBS_RELATIVE_SEARCH_PATH "/${QBS_APP_INSTALL_DIR}" "/${QBS_RESOURCES_INSTALL_BASE}") file(RELATIVE_PATH QBS_RELATIVE_PLUGINS_PATH "/${QBS_APP_INSTALL_DIR}" "/${QBS_PLUGINS_INSTALL_BASE}") set(DEFAULT_DEFINES QT_DISABLE_DEPRECATED_BEFORE=0x050f00 QT_DISABLE_DEPRECATED_UP_TO=0x050f00 QT_WARN_DEPRECATED_BEFORE=0x060700 QT_WARN_DEPRECATED_UP_TO=0x060700 QT_NO_JAVA_STYLE_ITERATORS QT_USE_QSTRINGBUILDER ) if(WIN32) list(APPEND DEFAULT_DEFINES UNICODE _UNICODE _SCL_SECURE_NO_WARNINGS) endif() if(WITH_TESTS) list(APPEND DEFAULT_DEFINES QBS_WITH_TESTS) endif() # CMake 3.10 doesn't have list(TRANSFORM) function(list_transform_prepend var prefix) set(temp "") foreach(f ${${var}}) list(APPEND temp "${prefix}${f}") endforeach() set(${var} "${temp}" PARENT_SCOPE) endfunction() function(add_qbs_app target_name) cmake_parse_arguments(_arg "" "DESTINATION" "DEFINES;PUBLIC_DEFINES;DEPENDS;PUBLIC_DEPENDS;INCLUDES;PUBLIC_INCLUDES;SOURCES;" ${ARGN} ) if (${_arg_UNPARSED_ARGUMENTS}) message(FATAL_ERROR "add_qbs_app had unparsed arguments") endif() set(_DESTINATION "${QBS_APP_INSTALL_DIR}") if(_arg_DESTINATION) set(_DESTINATION "${_arg_DESTINATION}") endif() add_executable(${target_name} ${_arg_SOURCES}) target_compile_definitions( ${target_name} PRIVATE ${_arg_DEFINES} ${DEFAULT_DEFINES} PUBLIC ${_arg_PUBLIC_DEFINES}) target_include_directories( ${target_name} PRIVATE ${_arg_INCLUDES} PUBLIC ${_arg_PUBLIC_INCLUDES}) target_link_libraries(${target_name} PRIVATE ${_arg_DEPENDS} PUBLIC ${_arg_PUBLIC_DEPENDS}) set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${_DESTINATION} BUILD_RPATH "${QBS_APP_RPATH}" INSTALL_RPATH "${QBS_APP_RPATH}" MACOSX_RPATH ${QBS_MACOSX_RPATH} ) install(TARGETS ${target_name} RUNTIME DESTINATION ${_DESTINATION}) endfunction() function(add_qbs_library target_name) cmake_parse_arguments(_arg "STATIC" "" "DEFINES;PUBLIC_DEFINES;DEPENDS;PUBLIC_DEPENDS;INCLUDES;PUBLIC_INCLUDES;SOURCES;" ${ARGN} ) if (${_arg_UNPARSED_ARGUMENTS}) message(FATAL_ERROR "add_qbs_library had unparsed arguments") endif() set(library_type SHARED) if (_arg_STATIC) set(library_type STATIC) endif() string(REGEX REPLACE "\\.[0-9]+$" "" _SOVERSION ${QBS_VERSION}) add_library(${target_name} ${library_type} ${_arg_SOURCES}) target_compile_definitions( ${target_name} PRIVATE ${_arg_DEFINES} ${DEFAULT_DEFINES} PUBLIC ${_arg_PUBLIC_DEFINES}) target_include_directories( ${target_name} PRIVATE ${_arg_INCLUDES} PUBLIC ${_arg_PUBLIC_INCLUDES} INTERFACE $) target_link_libraries(${target_name} PRIVATE ${_arg_DEPENDS} PUBLIC ${_arg_PUBLIC_DEPENDS}) set_target_properties(${target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_LIB_INSTALL_DIR} LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_LIB_INSTALL_DIR} RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_DLL_INSTALL_DIR} BUILD_RPATH "${QBS_LIB_RPATH}" INSTALL_RPATH "${QBS_LIB_RPATH}" MACOSX_RPATH ${QBS_MACOSX_RPATH} SOVERSION ${_SOVERSION} VERSION ${QBS_VERSION} ) if (NOT _arg_STATIC) install(TARGETS ${target_name} LIBRARY DESTINATION ${QBS_LIB_INSTALL_DIR} RUNTIME DESTINATION ${QBS_DLL_INSTALL_DIR} ) endif() if(MSVC) target_compile_options(${target_name} PUBLIC /EHsc) endif() endfunction() function(add_qbs_plugin target_name) cmake_parse_arguments(_arg "" "" "DEFINES;PUBLIC_DEFINES;DEPENDS;PUBLIC_DEPENDS;INCLUDES;PUBLIC_INCLUDES;SOURCES;" ${ARGN} ) if (${_arg_UNPARSED_ARGUMENTS}) message(FATAL_ERROR "add_qbs_plugin had unparsed arguments") endif() add_library(${target_name} MODULE ${_arg_SOURCES}) target_compile_definitions( ${target_name} PRIVATE ${_arg_DEFINES} ${DEFAULT_DEFINES} PUBLIC ${_arg_PUBLIC_DEFINES}) target_include_directories( ${target_name} PRIVATE ${_arg_INCLUDES} PUBLIC ${_arg_PUBLIC_INCLUDES}) target_link_libraries(${target_name} PRIVATE ${_arg_DEPENDS} PUBLIC ${_arg_PUBLIC_DEPENDS}) add_dependencies(qbs ${target_name}) set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_PLUGINS_INSTALL_DIR} RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_PLUGINS_INSTALL_DIR} BUILD_RPATH "${QBS_PLUGINS_RPATH}" INSTALL_RPATH "${QBS_PLUGINS_RPATH}" MACOSX_RPATH ${QBS_MACOSX_RPATH} ) install(TARGETS ${target_name} LIBRARY DESTINATION ${QBS_PLUGINS_INSTALL_DIR} RUNTIME DESTINATION ${QBS_PLUGINS_INSTALL_DIR} ) endfunction() function(add_qbs_test test_name) cmake_parse_arguments(_arg "" "" "DEFINES;PUBLIC_DEFINES;DEPENDS;PUBLIC_DEPENDS;INCLUDES;PUBLIC_INCLUDES;SOURCES;" ${ARGN} ) if (${_arg_UNPARSED_ARGUMENTS}) message(FATAL_ERROR "add_qbs_test had unparsed arguments") endif() set(target_name "tst_${test_name}") string(TOUPPER ${test_name} suite_name) # cmake is beatiful, here we have string(REPLACE - _ suite_name ${suite_name}) # and here we have add_executable(${target_name} ${_arg_SOURCES}) target_compile_definitions(${target_name} PRIVATE "QBS_TEST_SUITE_NAME=\"${suite_name}\"" "SRCDIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" ) set(TEST_DEFINES ${DEFAULT_DEFINES}) list(REMOVE_ITEM TEST_DEFINES QT_USE_QSTRINGBUILDER) target_compile_definitions( ${target_name} PRIVATE ${_arg_DEFINES} ${TEST_DEFINES} PUBLIC ${_arg_PUBLIC_DEFINES}) target_include_directories( ${target_name} PRIVATE ${_arg_INCLUDES} "${CMAKE_CURRENT_SOURCE_DIR}/../../../src" PUBLIC ${_arg_PUBLIC_INCLUDES} ) target_link_libraries( ${target_name} PRIVATE ${_arg_DEPENDS} qbscore qbsconsolelogger Qt${QT_VERSION_MAJOR}::Test PUBLIC ${_arg_PUBLIC_DEPENDS} ) set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${QBS_OUTPUT_PREFIX}${QBS_APP_INSTALL_DIR} BUILD_RPATH "${QBS_APP_RPATH}" INSTALL_RPATH "${QBS_APP_RPATH}" MACOSX_RPATH ${QBS_MACOSX_RPATH} ) install(TARGETS ${target_name} RUNTIME DESTINATION ${QBS_APP_INSTALL_DIR}) add_test(NAME ${target_name} COMMAND ${target_name}) endfunction() qbs-src-2.6.1/examples/0000755000175100001660000000000014776170045014266 5ustar runnerdockerqbs-src-2.6.1/examples/grpc/0000755000175100001660000000000014776170045015221 5ustar runnerdockerqbs-src-2.6.1/examples/grpc/server.cpp0000644000175100001660000000707414776170045017243 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif // __GNUC__ #include #include #include #include #include #include #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ #include #include #include class Service final : public PP::MyApi::Service { grpc::Status pingPong( grpc::ServerContext* context, const PP::Ping* request, PP::Pong* reply) override { (void)context; reply->set_count(request->count()); return grpc::Status::OK; } }; int main(int, char**) { std::string server_address("0.0.0.0:50051"); Service service; grpc::ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; server->Wait(); return 0; } qbs-src-2.6.1/examples/grpc/ping-pong-grpc.proto0000644000175100001660000000025214776170045021134 0ustar runnerdockersyntax = "proto3"; package PP; message Ping { int32 count = 1; } message Pong { int32 count = 1; } service MyApi { rpc pingPong(Ping) returns (Pong) {} } qbs-src-2.6.1/examples/grpc/grpc.qbs0000644000175100001660000000561614776170045016673 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ import qbs.Utilities Project { condition: Utilities.versionCompare(qbs.version, "1.14") >= 0 qbsModuleProviders: "qbspkgconfig" Application { Depends { name: "cpp" } Depends { name: "protobuf.cpp"; required: false } condition: protobuf.cpp.present && qbs.targetPlatform === qbs.hostPlatform protobuf.cpp.useGrpc: true consoleApplication: true cpp.cxxLanguageVersion: "c++17" cpp.minimumMacosVersion: "10.15" name: "client" files: "client.cpp" Properties { condition: qbs.toolchain.contains("gcc") cpp.cxxFlags: "-Wno-deprecated-declarations" } Group { files: "ping-pong-grpc.proto" fileTags: "protobuf.grpc" } } Application { Depends { name: "cpp" } Depends { name: "protobuf.cpp"; required: false } condition: protobuf.cpp.present && qbs.targetPlatform === qbs.hostPlatform protobuf.cpp.useGrpc: true consoleApplication: true cpp.cxxLanguageVersion: "c++17" cpp.minimumMacosVersion: "10.15" name: "server" files: "server.cpp" Properties { condition: qbs.toolchain.contains("gcc") cpp.cxxFlags: "-Wno-deprecated-declarations" } Group { files: "ping-pong-grpc.proto" fileTags: "protobuf.grpc" } } } qbs-src-2.6.1/examples/grpc/client.cpp0000644000175100001660000000764214776170045017214 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif // __GNUC__ #include #include #include #include #include #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ #include #include #include class Client { public: Client(const std::shared_ptr &channel) : m_stub(PP::MyApi::NewStub(channel)) {} int ping(int count) { PP::Ping request; request.set_count(count); PP::Pong reply; grpc::ClientContext context; const auto status = m_stub->pingPong(&context, request, &reply); if (status.ok()) { return reply.count(); } else { throw std::runtime_error("invalid status"); } } private: std::unique_ptr m_stub; }; int main(int, char**) { Client client( grpc::CreateCustomChannel( "localhost:50051", grpc::InsecureChannelCredentials(), grpc::ChannelArguments())); for (int i = 0; i < 1000; ++i) { std::cout << "Sending ping " << i << "... "; int result = client.ping(i); if (result != i) { std::cerr << "Invalid pong " << result << " for ping" << i << std::endl; continue; } std::cout << "got pong " << result << std::endl; } return 0; } qbs-src-2.6.1/examples/helloworld-qt/0000755000175100001660000000000014776170045017063 5ustar runnerdockerqbs-src-2.6.1/examples/helloworld-qt/main.cpp0000644000175100001660000000512114776170045020512 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include int main() { QTextStream ts(stdout); ts << QCoreApplication::translate("hello", "Hello, World!\n"); ts.flush(); } qbs-src-2.6.1/examples/helloworld-qt/helloworld-qt.qbs0000644000175100001660000000471614776170045022377 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ QtApplication { name: "HelloWorld-Qt" files: "main.cpp" } qbs-src-2.6.1/examples/app-and-lib/0000755000175100001660000000000014776170045016352 5ustar runnerdockerqbs-src-2.6.1/examples/app-and-lib/app-and-lib.qbs0000644000175100001660000000473614776170045021157 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { references: [ "app/app.qbs", "lib/lib.qbs" ] } qbs-src-2.6.1/examples/app-and-lib/app/0000755000175100001660000000000014776170045017132 5ustar runnerdockerqbs-src-2.6.1/examples/app-and-lib/app/app.qbs0000644000175100001660000000504114776170045020421 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Application { consoleApplication: true files : [ "main.cpp" ] Depends { name: "cpp" } Depends { name: "mylib" } install: true } qbs-src-2.6.1/examples/app-and-lib/app/main.cpp0000644000175100001660000000500614776170045020563 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main() { std::puts("Now calling a function from mylib:"); return bla(); } qbs-src-2.6.1/examples/app-and-lib/lib/0000755000175100001660000000000014776170045017120 5ustar runnerdockerqbs-src-2.6.1/examples/app-and-lib/lib/lib.h0000644000175100001660000000470514776170045020045 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LIB_H #define LIB_H int bla(); #endif // LIB_H qbs-src-2.6.1/examples/app-and-lib/lib/lib.qbs0000644000175100001660000000523114776170045020376 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ StaticLibrary { name: "mylib" files: [ "lib.cpp", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } } qbs-src-2.6.1/examples/app-and-lib/lib/lib.cpp0000644000175100001660000000503614776170045020376 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif int bla() { std::puts("Hello World!"); return 2; } qbs-src-2.6.1/examples/flatbuffers/0000755000175100001660000000000014776170045016571 5ustar runnerdockerqbs-src-2.6.1/examples/flatbuffers/monster-cpp/0000755000175100001660000000000014776170045021040 5ustar runnerdockerqbs-src-2.6.1/examples/flatbuffers/monster-cpp/conanfile.txt0000644000175100001660000000013014776170045023531 0ustar runnerdocker[requires] flatbuffers/24.3.25 [tool_requires] flatbuffers/24.3.25 [generators] QbsDeps qbs-src-2.6.1/examples/flatbuffers/monster-cpp/monster.cpp0000644000175100001660000000763214776170045023243 0ustar runnerdocker/* * Copyright 2015 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h". using namespace MyGame::Sample; // Example how to use FlatBuffers to create and read binary buffers. int main(int /*argc*/, const char * /*argv*/ []) { // Build up a serialized buffer algorithmically: flatbuffers::FlatBufferBuilder builder; // First, lets serialize some weapons for the Monster: A 'sword' and an 'axe'. auto weapon_one_name = builder.CreateString("Sword"); short weapon_one_damage = 3; auto weapon_two_name = builder.CreateString("Axe"); short weapon_two_damage = 5; // Use the `CreateWeapon` shortcut to create Weapons with all fields set. auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage); auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage); // Create a FlatBuffer's `vector` from the `std::vector`. std::vector> weapons_vector; weapons_vector.push_back(sword); weapons_vector.push_back(axe); auto weapons = builder.CreateVector(weapons_vector); // Second, serialize the rest of the objects needed by the Monster. auto position = Vec3(1.0f, 2.0f, 3.0f); auto name = builder.CreateString("MyMonster"); unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; auto inventory = builder.CreateVector(inv_data, 10); // Shortcut for creating monster with all fields set: auto orc = CreateMonster(builder, &position, 150, 80, name, inventory, Color_Red, weapons, Equipment_Weapon, axe.Union()); builder.Finish(orc); // Serialize the root of the object. // We now have a FlatBuffer we can store on disk or send over a network. // ** file/network code goes here :) ** // access builder.GetBufferPointer() for builder.GetSize() bytes // Instead, we're going to access it right away (as if we just received it). // Get access to the root: auto monster = GetMonster(builder.GetBufferPointer()); // Get and test some scalar types from the FlatBuffer. assert(monster->hp() == 80); assert(monster->mana() == 150); // default assert(monster->name()->str() == "MyMonster"); // Get and test a field of the FlatBuffer's `struct`. auto pos = monster->pos(); assert(pos); assert(pos->z() == 3.0f); (void)pos; // Get a test an element from the `inventory` FlatBuffer's `vector`. auto inv = monster->inventory(); assert(inv); assert(inv->Get(9) == 9); (void)inv; // Get and test the `weapons` FlatBuffers's `vector`. std::string expected_weapon_names[] = { "Sword", "Axe" }; short expected_weapon_damages[] = { 3, 5 }; auto weps = monster->weapons(); for (unsigned int i = 0; i < weps->size(); i++) { assert(weps->Get(i)->name()->str() == expected_weapon_names[i]); assert(weps->Get(i)->damage() == expected_weapon_damages[i]); } (void)expected_weapon_names; (void)expected_weapon_damages; // Get and test the `Equipment` union (`equipped` field). assert(monster->equipped_type() == Equipment_Weapon); auto equipped = static_cast(monster->equipped()); assert(equipped->name()->str() == "Axe"); assert(equipped->damage() == 5); (void)equipped; printf("The FlatBuffer was successfully created and verified!\n"); } qbs-src-2.6.1/examples/flatbuffers/monster-cpp/monster-cpp.qbs0000644000175100001660000000042714776170045024021 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.cpp"; required: false } name: "monster_cpp" consoleApplication: true condition: flatbuf.cpp.present && qbs.targetPlatform === qbs.hostPlatform files: [ "monster.cpp", "../shared/monster.fbs" ] } qbs-src-2.6.1/examples/flatbuffers/shared/0000755000175100001660000000000014776170045020037 5ustar runnerdockerqbs-src-2.6.1/examples/flatbuffers/shared/monster.fbs0000644000175100001660000000076714776170045022234 0ustar runnerdocker// Example IDL file for our monster's schema. namespace MyGame.Sample; enum Color:byte { Red = 0, Green, Blue = 2 } union Equipment { Weapon } // Optionally add more tables. struct Vec3 { x:float; y:float; z:float; } table Monster { pos:Vec3; mana:short = 150; hp:short = 100; name:string; friendly:bool = false (deprecated); inventory:[ubyte]; color:Color = Blue; weapons:[Weapon]; equipped:Equipment; } table Weapon { name:string; damage:short; } root_type Monster; qbs-src-2.6.1/examples/flatbuffers/monster-c/0000755000175100001660000000000014776170045020500 5ustar runnerdockerqbs-src-2.6.1/examples/flatbuffers/monster-c/conanfile.txt0000644000175100001660000000011214776170045023171 0ustar runnerdocker[requires] flatcc/0.6.1 [tool_requires] flatcc/0.6.1 [generators] QbsDeps qbs-src-2.6.1/examples/flatbuffers/monster-c/monster.c0000644000175100001660000003614414776170045022343 0ustar runnerdocker/* * Copyright 2019 dvidelabs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Example on how to build a Monster FlatBuffer. // Note: while some older C89 compilers are supported when // -DFLATCC_PORTABLE is defined, this particular sample is known not to // not work with MSVC 2010 (MSVC 2013 is OK) due to inline variable // declarations. These are easily move to the start of code blocks, but // since we follow the step-wise tutorial, it isn't really practical // in this case. The comment style is technically also in violation of C89. #include "monster_builder.h" // and already included. // Convenient namespace macro to manage long namespace prefix. // The ns macro makes it possible to write `ns(Monster_create(...))` // instead of `MyGame_Sample_Monster_create(...)` #undef ns #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. // A helper to simplify creating vectors from C-arrays. #define c_vec_len(V) (sizeof(V)/sizeof((V)[0])) // This allows us to verify result in optimized builds. #define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while (0) // Bottom-up approach where we create child objects and store these // in temporary references before a parent object is created with // these references. int create_monster_bottom_up(flatcc_builder_t *B, int flexible) { flatbuffers_string_ref_t weapon_one_name = flatbuffers_string_create_str(B, "Sword"); uint16_t weapon_one_damage = 3; flatbuffers_string_ref_t weapon_two_name = flatbuffers_string_create_str(B, "Axe"); uint16_t weapon_two_damage = 5; // Use the `MyGame_Sample_Weapon_create` shortcut to create Weapons // with all the fields set. // // In the C-API, verbs (here create) always follow the type name // (here Weapon), prefixed by the namespace (here MyGame_Sample_): // MyGame_Sample_Weapon_create(...), or ns(Weapone_create(...)). ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage)); ns(Weapon_ref_t) axe = ns(Weapon_create(B, weapon_two_name, weapon_two_damage)); // Serialize a name for our monster, called "Orc". // The _str suffix indicates the source is an ascii-z string. flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc"); // Create a `vector` representing the inventory of the Orc. Each number // could correspond to an item that can be claimed after he is slain. uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; flatbuffers_uint8_vec_ref_t inventory; // `c_vec_len` is the convenience macro we defined earlier. inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure)); // Here we use a top-down approach locally to build a Weapons vector // in-place instead of creating a temporary external vector to use // as argument like we did with the `inventory` earlier on, but the // overall approach is still bottom-up. ns(Weapon_vec_start(B)); ns(Weapon_vec_push(B, sword)); ns(Weapon_vec_push(B, axe)); ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B)); // Create a `Vec3`, representing the Orc's position in 3-D space. ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f }; // Set his hit points to 300 and his mana to 150. uint16_t hp = 300; // The default value is 150, so we will never store this field. uint16_t mana = 150; // Create the equipment union. In the C++ language API this is given // as two arguments to the create call, or as two separate add // operations for the type and the table reference. Here we create // a single union value that carries both the type and reference. ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); if (!flexible) { // Finally, create the monster using the `Monster_create` helper function // to set all fields. // // Note that the Equipment union only take up one argument in C, where // C++ takes a type and an object argument. ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red), weapons, equipped)); // Unlike C++ we do not use a Finish call. Instead we use the // `create_as_root` action which has better type safety and // simplicity. // // However, we can also express this as: // // ns(Monster_ref_t) orc = ns(Monster_create(B, ...)); // flatcc_builder_buffer_create(orc); // // In this approach the function should return the orc and // let a calling function handle the flatcc_buffer_create call // for a more composable setup that is also able to create child // monsters. In general, `flatcc_builder` calls are best isolated // in a containing driver function. } else { // A more flexible approach where we mix bottom-up and top-down // style. We still create child objects first, but then create // a top-down style monster object that we can manipulate in more // detail. // It is important to pair `start_as_root` with `end_as_root`. ns(Monster_start_as_root(B)); ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f)); // or alternatively //ns(Monster_pos_add(&pos); ns(Monster_hp_add(B, hp)); // Notice that `Monser_name_add` adds a string reference unlike the // add_str and add_strn variants. ns(Monster_name_add(B, name)); ns(Monster_inventory_add(B, inventory)); ns(Monster_color_add(B, ns(Color_Red))); ns(Monster_weapons_add(B, weapons)); ns(Monster_equipped_add(B, equipped)); // Complete the monster object and make it the buffer root object. ns(Monster_end_as_root(B)); // We could also drop the `as_root` suffix from Monster_start/end(B) // and add the table as buffer root later: // // ns(Monster_ref_t) orc = ns(Monster_start(B)); // ... // ns(Monster_ref_t) orc = ns(Monster_end(B)); // flatcc_builder_buffer_create(orc); // // It is best to keep the `flatcc_builder` calls in a containing // driver function for modularity. } return 0; } // Alternative top-down approach where parent objects are created before // their children. We only need to save one reference because the `axe` // object is used in two places effectively making the buffer object // graph a DAG. int create_monster_top_down(flatcc_builder_t *B) { uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; size_t treasure_count = c_vec_len(treasure); ns(Weapon_ref_t) axe; // NOTE: if we use end_as_root, we MUST also start as root. ns(Monster_start_as_root(B)); ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f)); ns(Monster_hp_add(B, 300)); //ns(Monster_mana_add(B, 150)); // We use create_str instead of add because we have no existing string reference. ns(Monster_name_create_str(B, "Orc")); // Again we use create because we no existing vector object, only a C-array. ns(Monster_inventory_create(B, treasure, treasure_count)); ns(Monster_color_add(B, ns(Color_Red))); if (1) { ns(Monster_weapons_start(B)); ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3)); // We reuse the axe object later. Note that we dereference a pointer // because push always returns a short-term pointer to the stored element. // We could also have created the axe object first and simply pushed it. axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5)); ns(Monster_weapons_end(B)); } else { // We can have more control with the table elements added to a vector: // ns(Monster_weapons_start(B)); ns(Monster_weapons_push_start(B)); ns(Weapon_name_create_str(B, "Sword")); ns(Weapon_damage_add(B, 3)); ns(Monster_weapons_push_end(B)); ns(Monster_weapons_push_start(B)); ns(Weapon_name_create_str(B, "Axe")); ns(Weapon_damage_add(B, 5)); axe = *ns(Monster_weapons_push_end(B)); ns(Monster_weapons_end(B)); } // Unions can get their type by using a type-specific add/create/start method. ns(Monster_equipped_Weapon_add(B, axe)); ns(Monster_end_as_root(B)); return 0; } // This isn't strictly needed because the builder already included the reader, // but we would need it if our reader were in a separate file. #include "monster_reader.h" #undef ns #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. int access_monster_buffer(const void *buffer) { // Note that we use the `table_t` suffix when reading a table object // as opposed to the `ref_t` suffix used during the construction of // the buffer. ns(Monster_table_t) monster = ns(Monster_as_root(buffer)); // Note: root object pointers are NOT the same as the `buffer` pointer. // Make sure the buffer is accessible. test_assert(monster != 0); uint16_t hp = ns(Monster_hp(monster)); uint16_t mana = ns(Monster_mana(monster)); // This is just a const char *, but it also supports a fast length operation. flatbuffers_string_t name = ns(Monster_name(monster)); size_t name_len = flatbuffers_string_len(name); test_assert(hp == 300); // Since 150 is the default, we are reading a value that wasn't stored. test_assert(mana == 150); test_assert(0 == strcmp(name, "Orc")); test_assert(name_len == strlen("Orc")); int hp_present = ns(Monster_hp_is_present(monster)); // 1 int mana_present = ns(Monster_mana_is_present(monster)); // 0 test_assert(hp_present); test_assert(!mana_present); ns(Vec3_struct_t) pos = ns(Monster_pos(monster)); // Make sure pos has been set. test_assert(pos != 0); float x = ns(Vec3_x(pos)); float y = ns(Vec3_y(pos)); float z = ns(Vec3_z(pos)); // The literal `f` suffix is important because double literals does // not always map cleanly to 32-bit represention even with only a few digits: // `1.0 == 1.0f`, but `3.2 != 3.2f`. test_assert(x == 1.0f); test_assert(y == 2.0f); test_assert(z == 3.0f); // We can also read the position into a C-struct. We have to copy // because we generally do not know if the native endian format // matches the one stored in the buffer (pe: protocol endian). ns(Vec3_t) pos_vec; // `pe` indicates endian conversion from protocol to native. ns(Vec3_copy_from_pe(&pos_vec, pos)); test_assert(pos_vec.x == 1.0f); test_assert(pos_vec.y == 2.0f); test_assert(pos_vec.z == 3.0f); // This is a const uint8_t *, but it shouldn't be accessed directly // to ensure proper endian conversion. However, uint8 (ubyte) are // not sensitive endianness, so we *could* have accessed it directly. // The compiler likely optimizes this so that it doesn't matter. flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster)); size_t inv_len = flatbuffers_uint8_vec_len(inv); // Make sure the inventory has been set. test_assert(inv != 0); // If `inv` were absent, the length would 0, so the above test is redundant. test_assert(inv_len == 10); // Index 0 is the first, index 2 is the third. // NOTE: C++ uses the `Get` terminology for vector elemetns, C use `at`. uint8_t third_item = flatbuffers_uint8_vec_at(inv, 2); test_assert(third_item == 2); ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); size_t weapons_len = ns(Weapon_vec_len(weapons)); test_assert(weapons_len == 2); // We can use `const char *` instead of `flatbuffers_string_t`. const char *second_weapon_name = ns(Weapon_name(ns(Weapon_vec_at(weapons, 1)))); uint16_t second_weapon_damage = ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1)))); test_assert(second_weapon_name != 0 && strcmp(second_weapon_name, "Axe") == 0); test_assert(second_weapon_damage == 5); // Access union type field. if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) { // Cast to appropriate type: // C does not require the cast to Weapon_table_t, but C++ does. ns(Weapon_table_t) weapon = (ns(Weapon_table_t)) ns(Monster_equipped(monster)); const char *weapon_name = ns(Weapon_name(weapon)); uint16_t weapon_damage = ns(Weapon_damage(weapon)); test_assert(0 == strcmp(weapon_name, "Axe")); test_assert(weapon_damage == 5); } return 0; } #include int main(int argc, char *argv[]) { // Create a `FlatBufferBuilder`, which will be used to create our // monsters' FlatBuffers. flatcc_builder_t builder; void *buf; size_t size; // Silence warnings. (void)argc; (void)argv; // Initialize the builder object. flatcc_builder_init(&builder); test_assert(0 == create_monster_bottom_up(&builder, 0)); // Allocate and extract a readable buffer from internal builder heap. // The returned buffer must be deallocated using `free`. // NOTE: Finalizing the buffer does NOT change the builder, it // just creates a snapshot of the builder content. // NOTE2: finalize_buffer uses malloc while finalize_aligned_buffer // uses a portable aligned allocation method. Often the malloc // version is sufficient, but won't work for all schema on all // systems. If the buffer is written to disk or network, but not // accessed in memory, `finalize_buffer` is also sufficient. buf = flatcc_builder_finalize_aligned_buffer(&builder, &size); //buf = flatcc_builder_finalize_buffer(&builder, &size); // We now have a FlatBuffer we can store on disk or send over a network. // ** file/network code goes here :) ** // Instead, we're going to access it right away (as if we just received it). //access_monster_buffer(buf); // prior to v0.5.0, use `aligned_free` flatcc_builder_aligned_free(buf); //free(buf); // // The builder object can optionally be reused after a reset which // is faster than creating a new builder. Subsequent use might // entirely avoid temporary allocations until finalizing the buffer. flatcc_builder_reset(&builder); test_assert(0 == create_monster_bottom_up(&builder, 1)); buf = flatcc_builder_finalize_aligned_buffer(&builder, &size); access_monster_buffer(buf); flatcc_builder_aligned_free(buf); flatcc_builder_reset(&builder); create_monster_top_down(&builder); buf = flatcc_builder_finalize_buffer(&builder, &size); test_assert(0 == access_monster_buffer(buf)); free(buf); // Eventually the builder must be cleaned up: flatcc_builder_clear(&builder); printf("The FlatBuffer was successfully created and accessed!\n"); return 0; } qbs-src-2.6.1/examples/flatbuffers/monster-c/monster-c.qbs0000644000175100001660000000041714776170045023120 0ustar runnerdockerCppApplication { Depends { name: "flatbuf.c"; required: false } name: "monster_c" consoleApplication: true condition: flatbuf.c.present && qbs.targetPlatform === qbs.hostPlatform files: [ "monster.c", "../shared/monster.fbs" ] } qbs-src-2.6.1/examples/flatbuffers/.clang-format0000644000175100001660000000005014776170045021137 0ustar runnerdockerDisableFormat: true SortIncludes: Never qbs-src-2.6.1/examples/examples.qbs0000644000175100001660000000465214776170045016622 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Product { files: "**/*" } qbs-src-2.6.1/examples/exporters/0000755000175100001660000000000014776170045016321 5ustar runnerdockerqbs-src-2.6.1/examples/exporters/lib_a/0000755000175100001660000000000014776170045017367 5ustar runnerdockerqbs-src-2.6.1/examples/exporters/lib_a/lib_a.cpp0000644000175100001660000000474214776170045021150 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib_a.h" const char *bla() { return "Hello World!"; } qbs-src-2.6.1/examples/exporters/lib_a/lib_a.qbs0000644000175100001660000000534514776170045021153 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MyLibrary { name: "lib_a" files: ["lib_a.cpp"] Group { name: "API headers" files: ["lib_a.h"] qbs.install: true qbs.installDir: headersInstallDir } Export { Depends { name: "cpp" } cpp.dynamicLibraries: "z" cpp.libraryPaths: "/opt/local/lib" } } qbs-src-2.6.1/examples/exporters/lib_a/lib_a.h0000644000175100001660000000474414776170045020617 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LIB_A_H #define LIB_A_H const char *bla(); #endif // LIB_A_H qbs-src-2.6.1/examples/exporters/qbs/0000755000175100001660000000000014776170045017106 5ustar runnerdockerqbs-src-2.6.1/examples/exporters/qbs/imports/0000755000175100001660000000000014776170045020603 5ustar runnerdockerqbs-src-2.6.1/examples/exporters/qbs/imports/MyLibrary.qbs0000644000175100001660000000717414776170045023235 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.FileInfo StaticLibrary { Depends { name: 'cpp' } property string headersInstallDir: "include" Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] prefixMapping: [{ prefix: exportingProduct.sourceDirectory, replacement: FileInfo.joinPaths(exportingProduct.qbs.installPrefix, exportingProduct.headersInstallDir) }] } install: true Depends { name: "Exporter.qbs" } Group { fileTagsFilter: "Exporter.qbs.module" qbs.install: install qbs.installDir: FileInfo.joinPaths(installDir, "qbs", "modules", product.name) } Depends { name: "Exporter.pkgconfig" } Exporter.pkgconfig.versionEntry: "1.0" Group { fileTagsFilter: ["Exporter.pkgconfig.pc"] qbs.install: install qbs.installDir: FileInfo.joinPaths(installDir, "pkgconfig") } Depends { name: "Exporter.cmake" } Group { fileTagsFilter: ["Exporter.cmake.package"] qbs.install: install qbs.installDir: FileInfo.joinPaths(installDir, "cmake", product.name) } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.6.1/examples/exporters/lib_b/0000755000175100001660000000000014776170045017370 5ustar runnerdockerqbs-src-2.6.1/examples/exporters/lib_b/lib_b.cpp0000644000175100001660000000501214776170045021141 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lib_b.h" #include #include int foo() { std::puts(bla()); return 2; } qbs-src-2.6.1/examples/exporters/lib_b/lib_b.h0000644000175100001660000000473414776170045020620 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef LIB_B_H #define LIB_B_H int foo(); #endif // LIB_B_H qbs-src-2.6.1/examples/exporters/lib_b/lib_b.qbs0000644000175100001660000000526614776170045021157 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MyLibrary { Depends { name: "lib_a" } name: "lib_b" files: ["lib_b.cpp"] Group { name: "API headers" files: ["lib_b.h"] qbs.install: true qbs.installDir: headersInstallDir } Export { Depends { name: 'lib_a' } } } qbs-src-2.6.1/examples/exporters/exporters.qbs0000644000175100001660000000502114776170045021061 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { references: [ "lib_a/lib_a.qbs", "lib_b/lib_b.qbs" ] qbsSearchPaths: "qbs" } qbs-src-2.6.1/examples/cocoa-touch-application/0000755000175100001660000000000014776170045020773 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-touch-application/cocoa-touch-application.qbs0000644000175100001660000001054114776170045026210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { Depends { name: "xcode"; required: false } Depends { condition: product.condition; name: "ib" } condition: qbs.hostOS.contains("macos") && xcode.present && qbs.targetPlatform.contains("ios") name: "Cocoa Touch Application" install: true bundle.identifierPrefix: "io.qbs" bundle.infoPlist: ({"UILaunchStoryboardName": "LaunchScreen"}) cpp.useObjcPrecompiledHeader: true cpp.minimumIosVersion: "9.0" cpp.automaticReferenceCounting: true cpp.frameworks: [ "UIKit", "Foundation", "CoreGraphics" ] // sample code signing settings: // codesign.enableCodeSigning: true // codesign.provisioningProfile: "my provisioning profile name" // codesign.signingIdentity: "Apple Development: My Team Name" Group { prefix: "CocoaTouchApplication/" files: [ "AppDelegate.h", "AppDelegate.m", "CocoaTouchApplication-Info.plist", "DetailViewController.h", "DetailViewController.m", "MasterViewController.h", "MasterViewController.m", "main.m" ] } Group { name: "Supporting Files" prefix: "CocoaTouchApplication/en.lproj/" files: [ "DetailViewController_iPad.xib", "DetailViewController_iPhone.xib", "MasterViewController_iPad.xib", "MasterViewController_iPhone.xib" ] } Group { id: bundle_resources files: [ "CocoaTouchApplication/LaunchScreen.storyboard", "CocoaTouchApplication/en.lproj/InfoPlist.strings" ] } bundle.resources: bundle_resources.files Group { name: "Xcode Project" files: [ "CocoaTouchApplication.xcodeproj/project.pbxproj" ] } Group { files: ["CocoaTouchApplication/CocoaTouchApplication-Prefix.pch"] fileTags: ["objc_pch_src"] } } qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/0000755000175100001660000000000014776170045025206 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/DetailViewController.m0000644000175100001660000000747414776170045031501 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import "DetailViewController.h" @interface DetailViewController () @property (nonatomic, retain) UIPopoverController *masterPopoverController; - (void)configureView; @end @implementation DetailViewController @synthesize detailItem = _detailItem; @synthesize detailDescriptionLabel = _detailDescriptionLabel; @synthesize masterPopoverController = _masterPopoverController; #pragma mark - Managing the detail item - (void)setDetailItem:(id)newDetailItem { if (_detailItem != newDetailItem) { _detailItem = newDetailItem; // Update the view. [self configureView]; } if (self.masterPopoverController != nil) { [self.masterPopoverController dismissPopoverAnimated:YES]; } } - (void)configureView { // Update the user interface for the detail item. if (self.detailItem) { self.detailDescriptionLabel.text = [self.detailItem description]; } } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self configureView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = NSLocalizedString(@"Detail", @"Detail"); } return self; } #pragma mark - Split view - (void)splitViewController:(UISplitViewController *) __unused splitController willHideViewController:(UIViewController *) __unused viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController { barButtonItem.title = NSLocalizedString(@"Master", @"Master"); [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES]; self.masterPopoverController = popoverController; } - (void)splitViewController:(UISplitViewController *) __unused splitController willShowViewController:(UIViewController *) __unused viewController invalidatingBarButtonItem:(UIBarButtonItem *) __unused barButtonItem { // Called when the view is shown again in the split view, invalidating the button and popover controller. [self.navigationItem setLeftBarButtonItem:nil animated:YES]; self.masterPopoverController = nil; } @end qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/LaunchScreen.storyboard0000644000175100001660000001072414776170045031676 0ustar runnerdocker qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/DetailViewController.h0000644000175100001660000000542314776170045031464 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import @interface DetailViewController : UIViewController { id _detailItem; UILabel *_detailDescriptionLabel; UIPopoverController *_masterPopoverController; } @property (nonatomic, retain) id detailItem; @property (nonatomic, retain) IBOutlet UILabel *detailDescriptionLabel; @end qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/AppDelegate.m0000644000175100001660000001212714776170045027542 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import "AppDelegate.h" #import "MasterViewController.h" #import "DetailViewController.h" @implementation AppDelegate @synthesize window = _window; @synthesize navigationController = _navigationController; @synthesize splitViewController = _splitViewController; - (BOOL)application:(UIApplication *) __unused application didFinishLaunchingWithOptions:(NSDictionary *) __unused launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:@"MasterViewController_iPhone" bundle:nil]; self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController]; self.window.rootViewController = self.navigationController; } else { MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:@"MasterViewController_iPad" bundle:nil]; UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController]; DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController_iPad" bundle:nil]; UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController]; masterViewController.detailViewController = detailViewController; self.splitViewController = [[UISplitViewController alloc] init]; self.splitViewController.delegate = detailViewController; self.splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavigationController, detailNavigationController, nil]; self.window.rootViewController = self.splitViewController; } [self.window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *) __unused application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *) __unused application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *) __unused application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *) __unused application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *) __unused application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/0000755000175100001660000000000014776170045026735 5ustar runnerdocker././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/MasterViewController_iPhone.xibqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/MasterViewController_i0000644000175100001660000002003514776170045033322 0ustar runnerdocker 1536 12A269 2835 1187 624.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 1919 IBProxyObject IBUITableView com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBCocoaTouchFramework IBFirstResponder IBCocoaTouchFramework 274 {{0, 20}, {320, 548}} 3 MQA YES IBUIScreenMetrics YES {320, 568} {568, 320} IBCocoaTouchFramework Retina 4 Full Screen 2 IBCocoaTouchFramework YES 1 0 YES 44 22 22 view 3 dataSource 4 delegate 5 0 -1 File's Owner -2 2 MasterViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 5 0 IBCocoaTouchFramework YES 3 YES 1919 qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/InfoPlist.strings0000644000175100001660000000005414776170045032256 0ustar runnerdocker/* Localized versions of Info.plist keys */ ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/DetailViewController_iPhone.xibqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/DetailViewController_i0000644000175100001660000003517014776170045033277 0ustar runnerdocker 1536 12A269 2835 1187 624.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 1919 IBNSLayoutConstraint IBProxyObject IBUILabel IBUIView com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBCocoaTouchFramework IBFirstResponder IBCocoaTouchFramework 274 298 {{20, 265}, {280, 18}} 3 MQA YES NO IBCocoaTouchFramework Detail view content goes here 1 MCAwIDAAA darkTextColor 1 10 1 1 4 Helvetica 14 16 {{0, 20}, {320, 548}} 3 MQA 2 IBUIScreenMetrics YES {320, 568} {568, 320} IBCocoaTouchFramework Retina 4 Full Screen 2 IBCocoaTouchFramework view 3 detailDescriptionLabel 6 0 1 10 0 10 1 0.0 1000 5 22 2 6 0 6 1 20 1000 8 29 3 5 0 5 1 20 1000 8 29 3 -1 File's Owner -2 4 7 9 11 DetailViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 0 IBCocoaTouchFramework YES 3 YES 1919 ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/DetailViewController_iPad.xibqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/DetailViewController_i0000644000175100001660000003170114776170045033273 0ustar runnerdocker 1536 12A206j 2519 1172.1 613.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 1856 IBNSLayoutConstraint IBProxyObject IBUILabel IBUIView com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 274 298 {{20, 495}, {728, 18}} 3 MQA YES NO IBIPadFramework 1 10 Detail view content goes here 1 MCAwIDAAA 1 1 4 Helvetica 14 16 {{0, 20}, {768, 1004}} NO 2 IBIPadFramework view 12 0 -1 File's Owner -2 8 10 0 10 1 0.0 1000 5 22 2 6 0 6 1 20 1000 8 29 3 5 0 5 1 20 1000 8 29 3 81 94 97 98 DetailViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 98 0 IBIPadFramework YES 3 YES 1856 ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/MasterViewController_iPad.xibqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/en.lproj/MasterViewController_i0000644000175100001660000002063414776170045033327 0ustar runnerdocker 1536 12A206j 2519 1172.1 613.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 1856 IBProxyObject IBUITableView com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 274 {{0, 20}, {320, 832}} 3 MQA YES 2 IBUISplitViewMasterSimulatedSizeMetrics YES {320, 852} {320, 768} IBIPadFramework Master IBUISplitViewController IBUISplitViewControllerContentSizeLocation IBUISplitViewControllerContentSizeLocationMaster IBIPadFramework YES 1 0 YES 44 22 22 view 3 dataSource 4 delegate 5 0 -1 File's Owner -2 2 MasterViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 5 0 IBIPadFramework YES 3 YES 1856 ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/CocoaTouchApplication-Info.plistqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/CocoaTouchApplication-Info.plis0000644000175100001660000000357414776170045033214 0ustar runnerdocker CFBundleDevelopmentRegion en CFBundleDisplayName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities armv7 UIStatusBarTintParameters UINavigationBar Style UIBarStyleDefault Translucent UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.m0000644000175100001660000001354014776170045031521 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import "MasterViewController.h" #import "DetailViewController.h" @implementation MasterViewController @synthesize detailViewController = _detailViewController; - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = NSLocalizedString(@"Master", @"Master"); if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { self.clearsSelectionOnViewWillAppear = NO; self.preferredContentSize = CGSizeMake(320.0, 600.0); } } return self; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.navigationItem.leftBarButtonItem = self.editButtonItem; UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; self.navigationItem.rightBarButtonItem = addButton; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)insertNewObject:(id) __unused sender { if (!_objects) { _objects = [[NSMutableArray alloc] init]; } [_objects insertObject:[NSDate date] atIndex:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } #pragma mark - Table View - (NSInteger)numberOfSectionsInTableView:(UITableView *) __unused tableView { return 1; } - (NSInteger)tableView:(UITableView *) __unused tableView numberOfRowsInSection:(NSInteger) __unused section { return _objects.count; } // Customize the appearance of table view cells. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } } NSDate *object = [_objects objectAtIndex:indexPath.row]; cell.textLabel.text = [object description]; return cell; } - (BOOL)tableView:(UITableView *) __unused tableView canEditRowAtIndexPath:(NSIndexPath *) __unused indexPath { // Return NO if you do not want the specified item to be editable. return YES; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [_objects removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. } } /* // Override to support rearranging the table view. - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { } */ /* // Override to support conditional rearranging of the table view. - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the item to be re-orderable. return YES; } */ - (void)tableView:(UITableView *) __unused tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSDate *object = [_objects objectAtIndex:indexPath.row]; if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { if (!self.detailViewController) { self.detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController_iPhone" bundle:nil]; } self.detailViewController.detailItem = object; [self.navigationController pushViewController:self.detailViewController animated:YES]; } else { self.detailViewController.detailItem = object; } } @end qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/main.m0000644000175100001660000000327614776170045026320 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import #import "AppDelegate.h" int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/CocoaTouchApplication-Prefix.pchqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/CocoaTouchApplication-Prefix.pc0000644000175100001660000000331314776170045033200 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import #ifndef __IPHONE_4_0 #warning "This project uses features only available in iOS SDK 4.0 and later." #endif #ifdef __OBJC__ #import #import #endif qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/AppDelegate.h0000644000175100001660000000553514776170045027542 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import @interface AppDelegate : UIResponder { UIWindow *_window; UINavigationController *_navigationController; UISplitViewController *_splitViewController; } @property (nonatomic, retain) UIWindow *window; @property (nonatomic, retain) UINavigationController *navigationController; @property (nonatomic, retain) UISplitViewController *splitViewController; @end qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.h0000644000175100001660000000531414776170045031514 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import @class DetailViewController; @interface MasterViewController : UITableViewController { NSMutableArray *_objects; DetailViewController *_detailViewController; } @property (nonatomic, retain) DetailViewController *detailViewController; @end qbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication.xcodeproj/0000755000175100001660000000000014776170045027202 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-touch-application/CocoaTouchApplication.xcodeproj/project.pbxproj0000644000175100001660000005101414776170045032257 0ustar runnerdocker// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 14E3FEAA175FB2E800C857C6 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E3FEA9175FB2E800C857C6 /* UIKit.framework */; }; 14E3FEAC175FB2E800C857C6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E3FEAB175FB2E800C857C6 /* Foundation.framework */; }; 14E3FEAE175FB2E800C857C6 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14E3FEAD175FB2E800C857C6 /* CoreGraphics.framework */; }; 14E3FEB4175FB2E800C857C6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 14E3FEB2175FB2E800C857C6 /* InfoPlist.strings */; }; 14E3FEB6175FB2E800C857C6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 14E3FEB5175FB2E800C857C6 /* main.m */; }; 14E3FEBA175FB2E800C857C6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14E3FEB9175FB2E800C857C6 /* AppDelegate.m */; }; 14E3FEC3175FB2E800C857C6 /* MasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14E3FEC2175FB2E800C857C6 /* MasterViewController.m */; }; 14E3FEC6175FB2E900C857C6 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14E3FEC5175FB2E900C857C6 /* DetailViewController.m */; }; 14E3FEC9175FB2E900C857C6 /* MasterViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14E3FEC7175FB2E900C857C6 /* MasterViewController_iPhone.xib */; }; 14E3FECC175FB2E900C857C6 /* MasterViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14E3FECA175FB2E900C857C6 /* MasterViewController_iPad.xib */; }; 14E3FECF175FB2E900C857C6 /* DetailViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14E3FECD175FB2E900C857C6 /* DetailViewController_iPhone.xib */; }; 14E3FED2175FB2E900C857C6 /* DetailViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14E3FED0175FB2E900C857C6 /* DetailViewController_iPad.xib */; }; AC83486F258674C900A9CBBB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AC83486E258674C900A9CBBB /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 14E3FEA6175FB2E800C857C6 /* Cocoa Touch Application.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Cocoa Touch Application.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 14E3FEA9175FB2E800C857C6 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 14E3FEAB175FB2E800C857C6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 14E3FEAD175FB2E800C857C6 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 14E3FEB1175FB2E800C857C6 /* CocoaTouchApplication-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CocoaTouchApplication-Info.plist"; sourceTree = ""; }; 14E3FEB3175FB2E800C857C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 14E3FEB5175FB2E800C857C6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 14E3FEB7175FB2E800C857C6 /* CocoaTouchApplication-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CocoaTouchApplication-Prefix.pch"; sourceTree = ""; }; 14E3FEB8175FB2E800C857C6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 14E3FEB9175FB2E800C857C6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 14E3FEC1175FB2E800C857C6 /* MasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MasterViewController.h; sourceTree = ""; }; 14E3FEC2175FB2E800C857C6 /* MasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MasterViewController.m; sourceTree = ""; }; 14E3FEC4175FB2E800C857C6 /* DetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; 14E3FEC5175FB2E900C857C6 /* DetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; 14E3FEC8175FB2E900C857C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MasterViewController_iPhone.xib; sourceTree = ""; }; 14E3FECB175FB2E900C857C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MasterViewController_iPad.xib; sourceTree = ""; }; 14E3FECE175FB2E900C857C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DetailViewController_iPhone.xib; sourceTree = ""; }; 14E3FED1175FB2E900C857C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DetailViewController_iPad.xib; sourceTree = ""; }; AC83486E258674C900A9CBBB /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 14E3FEA3175FB2E800C857C6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 14E3FEAA175FB2E800C857C6 /* UIKit.framework in Frameworks */, 14E3FEAC175FB2E800C857C6 /* Foundation.framework in Frameworks */, 14E3FEAE175FB2E800C857C6 /* CoreGraphics.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 14E3FE9D175FB2E800C857C6 = { isa = PBXGroup; children = ( 14E3FEAF175FB2E800C857C6 /* CocoaTouchApplication */, 14E3FEA8175FB2E800C857C6 /* Frameworks */, 14E3FEA7175FB2E800C857C6 /* Products */, ); sourceTree = ""; }; 14E3FEA7175FB2E800C857C6 /* Products */ = { isa = PBXGroup; children = ( 14E3FEA6175FB2E800C857C6 /* Cocoa Touch Application.app */, ); name = Products; sourceTree = ""; }; 14E3FEA8175FB2E800C857C6 /* Frameworks */ = { isa = PBXGroup; children = ( 14E3FEA9175FB2E800C857C6 /* UIKit.framework */, 14E3FEAB175FB2E800C857C6 /* Foundation.framework */, 14E3FEAD175FB2E800C857C6 /* CoreGraphics.framework */, ); name = Frameworks; sourceTree = ""; }; 14E3FEAF175FB2E800C857C6 /* CocoaTouchApplication */ = { isa = PBXGroup; children = ( 14E3FEB8175FB2E800C857C6 /* AppDelegate.h */, 14E3FEB9175FB2E800C857C6 /* AppDelegate.m */, 14E3FEC1175FB2E800C857C6 /* MasterViewController.h */, 14E3FEC2175FB2E800C857C6 /* MasterViewController.m */, 14E3FEC4175FB2E800C857C6 /* DetailViewController.h */, 14E3FEC5175FB2E900C857C6 /* DetailViewController.m */, 14E3FEC7175FB2E900C857C6 /* MasterViewController_iPhone.xib */, 14E3FECA175FB2E900C857C6 /* MasterViewController_iPad.xib */, 14E3FECD175FB2E900C857C6 /* DetailViewController_iPhone.xib */, 14E3FED0175FB2E900C857C6 /* DetailViewController_iPad.xib */, 14E3FEB0175FB2E800C857C6 /* Supporting Files */, AC83486E258674C900A9CBBB /* LaunchScreen.storyboard */, ); path = CocoaTouchApplication; sourceTree = ""; }; 14E3FEB0175FB2E800C857C6 /* Supporting Files */ = { isa = PBXGroup; children = ( 14E3FEB1175FB2E800C857C6 /* CocoaTouchApplication-Info.plist */, 14E3FEB2175FB2E800C857C6 /* InfoPlist.strings */, 14E3FEB5175FB2E800C857C6 /* main.m */, 14E3FEB7175FB2E800C857C6 /* CocoaTouchApplication-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 14E3FEA5175FB2E800C857C6 /* Cocoa Touch Application */ = { isa = PBXNativeTarget; buildConfigurationList = 14E3FED5175FB2E900C857C6 /* Build configuration list for PBXNativeTarget "Cocoa Touch Application" */; buildPhases = ( 14E3FEA2175FB2E800C857C6 /* Sources */, 14E3FEA3175FB2E800C857C6 /* Frameworks */, 14E3FEA4175FB2E800C857C6 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Cocoa Touch Application"; productName = CocoaTouchApplication; productReference = 14E3FEA6175FB2E800C857C6 /* Cocoa Touch Application.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 14E3FE9E175FB2E800C857C6 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1220; ORGANIZATIONNAME = io.qbs; }; buildConfigurationList = 14E3FEA1175FB2E800C857C6 /* Build configuration list for PBXProject "CocoaTouchApplication" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, en, ); mainGroup = 14E3FE9D175FB2E800C857C6; productRefGroup = 14E3FEA7175FB2E800C857C6 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 14E3FEA5175FB2E800C857C6 /* Cocoa Touch Application */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 14E3FEA4175FB2E800C857C6 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( AC83486F258674C900A9CBBB /* LaunchScreen.storyboard in Resources */, 14E3FEB4175FB2E800C857C6 /* InfoPlist.strings in Resources */, 14E3FEC9175FB2E900C857C6 /* MasterViewController_iPhone.xib in Resources */, 14E3FECC175FB2E900C857C6 /* MasterViewController_iPad.xib in Resources */, 14E3FECF175FB2E900C857C6 /* DetailViewController_iPhone.xib in Resources */, 14E3FED2175FB2E900C857C6 /* DetailViewController_iPad.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 14E3FEA2175FB2E800C857C6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 14E3FEB6175FB2E800C857C6 /* main.m in Sources */, 14E3FEBA175FB2E800C857C6 /* AppDelegate.m in Sources */, 14E3FEC3175FB2E800C857C6 /* MasterViewController.m in Sources */, 14E3FEC6175FB2E900C857C6 /* DetailViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 14E3FEB2175FB2E800C857C6 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 14E3FEB3175FB2E800C857C6 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; 14E3FEC7175FB2E900C857C6 /* MasterViewController_iPhone.xib */ = { isa = PBXVariantGroup; children = ( 14E3FEC8175FB2E900C857C6 /* en */, ); name = MasterViewController_iPhone.xib; sourceTree = ""; }; 14E3FECA175FB2E900C857C6 /* MasterViewController_iPad.xib */ = { isa = PBXVariantGroup; children = ( 14E3FECB175FB2E900C857C6 /* en */, ); name = MasterViewController_iPad.xib; sourceTree = ""; }; 14E3FECD175FB2E900C857C6 /* DetailViewController_iPhone.xib */ = { isa = PBXVariantGroup; children = ( 14E3FECE175FB2E900C857C6 /* en */, ); name = DetailViewController_iPhone.xib; sourceTree = ""; }; 14E3FED0175FB2E900C857C6 /* DetailViewController_iPad.xib */ = { isa = PBXVariantGroup; children = ( 14E3FED1175FB2E900C857C6 /* en */, ); name = DetailViewController_iPad.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 14E3FED3175FB2E900C857C6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 14E3FED4175FB2E900C857C6 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 14E3FED6175FB2E900C857C6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "CocoaTouchApplication/CocoaTouchApplication-Prefix.pch"; INFOPLIST_FILE = "CocoaTouchApplication/CocoaTouchApplication-Info.plist"; PRODUCT_BUNDLE_IDENTIFIER = "io.qbs.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Debug; }; 14E3FED7175FB2E900C857C6 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "CocoaTouchApplication/CocoaTouchApplication-Prefix.pch"; INFOPLIST_FILE = "CocoaTouchApplication/CocoaTouchApplication-Info.plist"; PRODUCT_BUNDLE_IDENTIFIER = "io.qbs.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 14E3FEA1175FB2E800C857C6 /* Build configuration list for PBXProject "CocoaTouchApplication" */ = { isa = XCConfigurationList; buildConfigurations = ( 14E3FED3175FB2E900C857C6 /* Debug */, 14E3FED4175FB2E900C857C6 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 14E3FED5175FB2E900C857C6 /* Build configuration list for PBXNativeTarget "Cocoa Touch Application" */ = { isa = XCConfigurationList; buildConfigurations = ( 14E3FED6175FB2E900C857C6 /* Debug */, 14E3FED7175FB2E900C857C6 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 14E3FE9E175FB2E800C857C6 /* Project object */; } qbs-src-2.6.1/examples/rpaths/0000755000175100001660000000000014776170045015567 5ustar runnerdockerqbs-src-2.6.1/examples/rpaths/rpaths.qbs0000644000175100001660000000311514776170045017577 0ustar runnerdockerimport qbs.FileInfo Project { condition: qbs.targetOS.contains("unix") //! [0] DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } name: "LibraryA" bundle.isBundle: false cpp.sonamePrefix: qbs.targetOS.contains("macos") ? "@rpath" : undefined cpp.rpaths: cpp.rpathOrigin cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.8" files: [ "objecta.cpp", "objecta.h", ] install: true installDir: "examples/lib" } //! [0] //! [1] DynamicLibrary { Depends { name: "cpp" } Depends { name: "bundle" } Depends { name: "LibraryA" } name: "LibraryB" bundle.isBundle: false cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.8" cpp.sonamePrefix: qbs.targetOS.contains("macos") ? "@rpath" : undefined cpp.rpaths: cpp.rpathOrigin files: [ "objectb.cpp", "objectb.h", ] install: true installDir: "examples/lib" } //! [1] //! [2] CppApplication { Depends { name: "bundle" } Depends { name: "LibraryA" } Depends { name: "LibraryB" } name: "rpaths-app" files: "main.cpp" consoleApplication: true bundle.isBundle: false cpp.rpaths: FileInfo.joinPaths(cpp.rpathOrigin, "..", "lib") cpp.cxxLanguageVersion: "c++11" cpp.minimumMacosVersion: "10.8" install: true installDir: "examples/bin" } //! [2] } qbs-src-2.6.1/examples/rpaths/objectb.cpp0000644000175100001660000000511314776170045017703 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "objectb.h" ObjectB::ObjectB() = default; std::string ObjectB::className() { return "ObjectB"; } const ObjectA &ObjectB::getA() const { return objectA; } qbs-src-2.6.1/examples/rpaths/objectb.h0000644000175100001660000000522414776170045017353 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECTB_H #define OBJECTB_H #include #include "objecta.h" class ObjectB { public: ObjectB(); static std::string className(); const ObjectA &getA() const; private: ObjectA objectA{"A"}; }; #endif // OBJECTB_H qbs-src-2.6.1/examples/rpaths/main.cpp0000644000175100001660000000533014776170045017220 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "objecta.h" #include "objectb.h" #include int main(int argc, char *argv[]) { (void)argc; (void)argv; std::cout << ObjectA::className() << std::endl; std::cout << ObjectB::className() << std::endl; ObjectB b; std::cout << b.getA().name() << std::endl; return 0; } qbs-src-2.6.1/examples/rpaths/objecta.h0000644000175100001660000000527514776170045017360 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef OBJECTA_H #define OBJECTA_H #include class ObjectA { public: explicit ObjectA(std::string name); static std::string className(); const std::string &name() const; void setName(std::string name); private: std::string m_name; }; #endif // OBJECTA_H qbs-src-2.6.1/examples/rpaths/objecta.cpp0000644000175100001660000000527714776170045017715 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "objecta.h" ObjectA::ObjectA(std::string name) : m_name(std::move(name)) { } std::string ObjectA::className() { return "ObjectA"; } const std::string &ObjectA::name() const { return m_name; } void ObjectA::setName(std::string name) { m_name = std::move(name); } qbs-src-2.6.1/examples/install-bundle/0000755000175100001660000000000014776170045017203 5ustar runnerdockerqbs-src-2.6.1/examples/install-bundle/coreutils.h0000644000175100001660000000470214776170045021370 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef _WIN32 __declspec(dllexport) #endif int foo(); qbs-src-2.6.1/examples/install-bundle/MainMenu.xib0000644000175100001660000014072114776170045021425 0ustar runnerdocker Default Left to Right Right to Left Default Left to Right Right to Left qbs-src-2.6.1/examples/install-bundle/white.iconset/0000755000175100001660000000000014776170045021766 5ustar runnerdockerqbs-src-2.6.1/examples/install-bundle/white.iconset/icon_16x16@2x.png0000644000175100001660000000123114776170045024640 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/examples/install-bundle/white.iconset/icon_16x16.png0000644000175100001660000000121114776170045024264 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/examples/install-bundle/assetcatalog1.xcassets/0000755000175100001660000000000014776170045023572 5ustar runnerdockerqbs-src-2.6.1/examples/install-bundle/assetcatalog1.xcassets/other.imageset/0000755000175100001660000000000014776170045026510 5ustar runnerdockerqbs-src-2.6.1/examples/install-bundle/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png0000644000175100001660000000123114776170045031362 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/examples/install-bundle/assetcatalog1.xcassets/other.imageset/Contents.json0000644000175100001660000000053314776170045031201 0ustar runnerdocker{ "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "icon_16x16.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "icon_16x16@2x.png" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } }qbs-src-2.6.1/examples/install-bundle/assetcatalog1.xcassets/other.imageset/icon_16x16.png0000644000175100001660000000121114776170045031006 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/examples/install-bundle/coreutils.cpp0000644000175100001660000000470114776170045021722 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "coreutils.h" int foo() { return 42; } qbs-src-2.6.1/examples/install-bundle/Storyboard.storyboard0000644000175100001660000000530414776170045023447 0ustar runnerdocker qbs-src-2.6.1/examples/install-bundle/assetcatalog2.xcassets/0000755000175100001660000000000014776170045023573 5ustar runnerdockerqbs-src-2.6.1/examples/install-bundle/assetcatalog2.xcassets/other.imageset/0000755000175100001660000000000014776170045026511 5ustar runnerdockerqbs-src-2.6.1/examples/install-bundle/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png0000644000175100001660000000123114776170045031363 0ustar runnerdockerPNG  IHDR szzsRGB pHYs%%IR$iTXtXML:com.adobe.xmp 4 4 1 #2IDATX A 1g ٻx\=/ @ 0M<^IENDB`qbs-src-2.6.1/examples/install-bundle/assetcatalog2.xcassets/other.imageset/Contents.json0000644000175100001660000000053314776170045031202 0ustar runnerdocker{ "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "icon_16x16.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "icon_16x16@2x.png" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } }qbs-src-2.6.1/examples/install-bundle/assetcatalog2.xcassets/other.imageset/icon_16x16.png0000644000175100001660000000121114776170045031007 0ustar runnerdockerPNG  IHDRasRGB pHYs  iTXtXML:com.adobe.xmp 4 4 1 #"IDAT8c & 􂵎0a k IENDB`qbs-src-2.6.1/examples/install-bundle/main.cpp0000644000175100001660000000507514776170045020642 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.show(); return app.exec(); } qbs-src-2.6.1/examples/install-bundle/install-bundle.qbs0000644000175100001660000000344114776170045022631 0ustar runnerdockerimport qbs.FileInfo Project { CppApplication { Depends { name: "bundle" } Depends { name: "windowutils" } Depends { name: "ib"; condition: qbs.targetOS.contains("darwin") } Depends { name: "Qt"; submodules: ["core", "gui", "widgets"] } condition: qbs.targetOS.contains("macos") || qbs.targetOS.contains("linux") || qbs.targetOS.contains("windows") name: "window" property bool isBundle: bundle.isBundle targetName: isBundle ? "Window" : "window" files: [ "main.cpp", "assetcatalog1.xcassets", "assetcatalog2.xcassets", "white.iconset", "MainMenu.xib", "Storyboard.storyboard" ] cpp.minimumMacosVersion: "10.10" Group { fileTagsFilter: qbs.targetOS.contains("darwin") && isBundle ? ["bundle.content"] : ["application"] qbs.install: true qbs.installDir: isBundle ? "Applications" : (qbs.targetOS.contains("windows") ? "" : "bin") qbs.installSourceBase: product.buildDirectory } } DynamicLibrary { Depends { name: "bundle" } Depends { name: "cpp" } name: "windowutils" property bool isBundle: qbs.targetOS.contains("darwin") && bundle.isBundle targetName: isBundle ? "WindowUtils" : "windowutils" files: ["coreutils.cpp", "coreutils.h"] Group { fileTagsFilter: isBundle ? ["bundle.content"] : ["dynamiclibrary", "dynamiclibrary_symlink", "dynamiclibrary_import"] qbs.install: true qbs.installDir: isBundle ? "Library/Frameworks" : (qbs.targetOS.contains("windows") ? "" : "lib") qbs.installSourceBase: product.buildDirectory } } } qbs-src-2.6.1/examples/code-generator/0000755000175100001660000000000014776170045017164 5ustar runnerdockerqbs-src-2.6.1/examples/code-generator/code-generator.qbs0000644000175100001660000000657514776170045022606 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { // A code generator that outputs a "Hello World" C++ program. CppApplication { name: "hwgen" consoleApplication: true files: ["hwgen.cpp"] Properties { condition: qbs.toolchain.contains("gcc") || qbs.toolchain.contains("clang-cl") cpp.cxxFlags: ["-Wno-deprecated-declarations"] } } // Generate and build a hello-world application. CppApplication { condition: qbs.targetPlatform === qbs.hostPlatform name: "hello-world" Depends { name: "hwgen" } Rule { inputsFromDependencies: ["application"] Artifact { filePath: "main.cpp" fileTags: ["cpp"] } prepare: { var hwgen = inputs["application"][0].filePath; var cmd = new Command(hwgen, [output.filePath]); cmd.description = "generating C++ source"; return cmd; } } } } qbs-src-2.6.1/examples/code-generator/hwgen.cpp0000644000175100001660000000537014776170045021005 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main(int argc, char **argv) { if (argc < 2) return 1; std::FILE *f = std::fopen(argv[1], "w"); if (!f) return 2; std::fprintf(f, "#include \n\n" "int main()\n" "{\n std::printf(\"Hello World!\\n\");\n return 0;\n}\n"); std::fclose(f); return 0; } qbs-src-2.6.1/examples/helloworld-minimal/0000755000175100001660000000000014776170045020065 5ustar runnerdockerqbs-src-2.6.1/examples/helloworld-minimal/main.cpp0000644000175100001660000000473714776170045021530 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include int main() { std::cout << "Hello, World!" << std::endl; } qbs-src-2.6.1/examples/helloworld-minimal/helloworld-minimal.qbs0000644000175100001660000000472414776170045024402 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { name: "HelloWorld-minimal" files: "main.cpp" } qbs-src-2.6.1/examples/protobuf/0000755000175100001660000000000014776170045016126 5ustar runnerdockerqbs-src-2.6.1/examples/protobuf/addressbook_cpp/0000755000175100001660000000000014776170045021270 5ustar runnerdockerqbs-src-2.6.1/examples/protobuf/addressbook_cpp/addressbook_cpp.qbs0000644000175100001660000000062314776170045025142 0ustar runnerdockerimport qbs.Host CppApplication { consoleApplication: true condition: protobuf.cpp.present && qbs.targetPlatform === Host.platform() Depends { name: "cpp" } cpp.minimumMacosVersion: "10.15" Depends { name: "protobuf.cpp"; required: false } files: [ "../shared/addressbook.proto", "main.cpp", "README.md", ] qbsModuleProviders: "qbspkgconfig" } qbs-src-2.6.1/examples/protobuf/addressbook_cpp/README.md0000644000175100001660000000127214776170045022551 0ustar runnerdocker### Addressbook c++ example This example shows how to build a cpp application that uses Google protobuf. In order to build this example, you'll need to have a protobuf headers and library installed in the system in locations where QBS can find them. On Linux, you can install a package to the system. On macOS, you can use brew or compile and install protobuf manually: - to /usr/local/ - to any folder, say /Users//protobuf. Then you'll need to set protobuf.libraryPath: "/Users//protobuf/lib" and protobuf.includePath: "/Users//protobuf/include" On Windows, you have to compile and install protobuf manually to any folder and use libraryPath and includePath as shown above qbs-src-2.6.1/examples/protobuf/addressbook_cpp/main.cpp0000644000175100001660000001442714776170045022730 0ustar runnerdocker// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include #include #ifdef __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-parameter" # include # pragma GCC diagnostic pop #else # include #endif // __GNUC__ #include "addressbook.pb.h" using google::protobuf::util::TimeUtil; int printUsage(char *argv0) { std::cerr << "Usage: " << argv0 << "add|list ADDRESS_BOOK_FILE" << std::endl; return -1; } std::string readString(const std::string &promt) { std::string result; std::cout << promt; std::getline(std::cin, result); return result; } // This function fills in a Person message based on user input. void promptForAddress(tutorial::Person* person) { std::cout << "Enter person ID number: "; int id; std::cin >> id; person->set_id(id); std::cin.ignore(256, '\n'); *person->mutable_name() = readString("Enter name: "); const auto email = readString("Enter email address (blank for none): "); if (!email.empty()) person->set_email(email); while (true) { const auto number = readString("Enter a phone number (or leave blank to finish): "); if (number.empty()) break; tutorial::Person::PhoneNumber *phone_number = person->add_phones(); phone_number->set_number(number); const auto type = readString("Is this a mobile, home, or work phone? "); if (type == "mobile") phone_number->set_type(tutorial::Person::MOBILE); else if (type == "home") phone_number->set_type(tutorial::Person::HOME); else if (type == "work") phone_number->set_type(tutorial::Person::WORK); else std::cout << "Unknown phone type. Using default." << std::endl; } *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL)); } // Iterates though all people in the AddressBook and prints info about them. void listPeople(const tutorial::AddressBook& address_book) { for (int i = 0; i < address_book.people_size(); i++) { const tutorial::Person& person = address_book.people(i); std::cout << "Person ID: " << person.id() << std::endl; std::cout << " Name: " << person.name() << std::endl; if (!person.email().empty()) { std::cout << " E-mail address: " << person.email() << std::endl; } for (int j = 0; j < person.phones_size(); j++) { const tutorial::Person::PhoneNumber& phone_number = person.phones(j); switch (phone_number.type()) { case tutorial::Person::MOBILE: std::cout << " Mobile phone #: "; break; case tutorial::Person::HOME: std::cout << " Home phone #: "; break; case tutorial::Person::WORK: std::cout << " Work phone #: "; break; default: std::cout << " Unknown phone #: "; break; } std::cout << phone_number.number() << std::endl; } if (person.has_last_updated()) { std::cout << " Updated: " << TimeUtil::ToString(person.last_updated()) << std::endl; } } } int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 3) return printUsage(argv[0]); tutorial::AddressBook address_book; // Read the existing address book. std::fstream input(argv[2], std::ios::in | std::ios::binary); if (!input) { std::cout << argv[2] << ": File not found." << std::endl; } else if (!address_book.ParseFromIstream(&input)) { std::cerr << "Failed to parse address book." << std::endl; return -1; } const std::string mode(argv[1]); if (mode == "add") { // Add an address. promptForAddress(address_book.add_people()); if (!input) std::cout << "Creating a new file." << std::endl; // Write the new address book back to disk. std::fstream output(argv[2], std::ios::out | std::ios::trunc | std::ios::binary); if (!address_book.SerializeToOstream(&output)) { std::cerr << "Failed to write address book." << std::endl; return -1; } } else if (mode == "list") { listPeople(address_book); } else { return printUsage(argv[0]); } // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; } qbs-src-2.6.1/examples/protobuf/shared/0000755000175100001660000000000014776170045017374 5ustar runnerdockerqbs-src-2.6.1/examples/protobuf/shared/addressbook.proto0000644000175100001660000000232214776170045022760 0ustar runnerdocker// See README.txt for information and build instructions. // // Note: START and END tags are used in comments to define sections used in // tutorials. They are not part of the syntax for Protocol Buffers. // // To get an in-depth walkthrough of this file and the related examples, see: // https://developers.google.com/protocol-buffers/docs/tutorials // [START declaration] syntax = "proto3"; package tutorial; import "google/protobuf/timestamp.proto"; // [END declaration] // [START java_declaration] option java_package = "com.example.tutorial"; option java_outer_classname = "AddressBookProtos"; // [END java_declaration] // [START csharp_declaration] option csharp_namespace = "Google.Protobuf.Examples.AddressBook"; // [END csharp_declaration] // [START messages] message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5; } // Our address book file is just one of these. message AddressBook { repeated Person people = 1; } // [END messages] qbs-src-2.6.1/examples/protobuf/addressbook_objc/0000755000175100001660000000000014776170045021423 5ustar runnerdockerqbs-src-2.6.1/examples/protobuf/addressbook_objc/README.md0000644000175100001660000000035114776170045022701 0ustar runnerdocker### Addressbook objc example This example shows how to build an objective-c application that uses Google protobuf. In order to build this example, you'll need to have a ProtocolBuffers library or framework installed in the system. qbs-src-2.6.1/examples/protobuf/addressbook_objc/addressbook_objc.qbs0000644000175100001660000000051414776170045025427 0ustar runnerdockerCppApplication { consoleApplication: true condition: protobuf.objc.present && qbs.targetOS.contains("macos") Depends { name: "cpp" } Depends { name: "protobuf.objc"; required: false } Group { cpp.automaticReferenceCounting: true files: "main.m" } files: "../shared/addressbook.proto" } qbs-src-2.6.1/examples/protobuf/addressbook_objc/main.m0000644000175100001660000001506514776170045022534 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import "Addressbook.pbobjc.h" #import int printUsage(char *argv0) { NSString *programName = [[NSString alloc] initWithUTF8String:argv0]; NSLog(@"Usage: %@ add|list ADDRESS_BOOK_FILE", programName); return -1; } NSString *readString(NSString *promt) { NSLog(@"%@", promt); NSFileHandle *inputFile = [NSFileHandle fileHandleWithStandardInput]; NSData *inputData = [inputFile availableData]; NSString *result = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding]; result = [result stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; return result; } // This function fills in a Person message based on user input. void promptForAddress(Person* person) { person.id_p = [readString(@"Enter person ID number:") intValue]; person.name = readString(@"Enter name:"); NSString *email = readString(@"Enter email address (blank for none):"); if ([email length] != 0) person.email = email; while (true) { NSString *number = readString(@"Enter a phone number (or leave blank to finish):"); if ([number length] == 0) break; Person_PhoneNumber* phoneNumber = [[Person_PhoneNumber alloc] init]; phoneNumber.number = number; NSString *type = readString(@"Is this a mobile, home, or work phone?:"); NSLog(@"\"%@\"", type); if ([type compare:@"mobile"] == NSOrderedSame) phoneNumber.type = Person_PhoneType_Mobile; else if ([type compare:@"home"] == NSOrderedSame) phoneNumber.type = Person_PhoneType_Home; else if ([type compare:@"work"] == NSOrderedSame) phoneNumber.type = Person_PhoneType_Work; else NSLog(@"Unknown phone type. Using default."); [person.phonesArray addObject:phoneNumber]; } } // Iterates though all people in the AddressBook and prints info about them. void listPeople(AddressBook *addressBook) { for (Person *person in addressBook.peopleArray) { NSLog(@"Person ID: %d", person.id_p); NSLog(@"Person name: %@", person.name); if ([person.email length] != 0) { NSLog(@"E-mail address: %@", person.email); } for (Person_PhoneNumber *phoneNumber in person.phonesArray) { NSString *phonePrefix; switch (phoneNumber.type) { case Person_PhoneType_Mobile: phonePrefix = @"Mobile phone"; break; case Person_PhoneType_Home: phonePrefix = @"Home phone"; break; case Person_PhoneType_Work: phonePrefix = @"Work phone"; break; default: phonePrefix = @"Unknown phone"; break; } NSLog(@" %@ #: %@", phonePrefix, phoneNumber.number); } printf("\n"); } } int main(int argc, char *argv[]) { if (argc != 3) return printUsage(argv[0]); @autoreleasepool { AddressBook *addressBook; NSString *filePath = [[NSString alloc] initWithUTF8String:argv[2]]; // Read the existing address book. NSData *data = [NSData dataWithContentsOfFile:filePath]; if (!data) { NSLog(@"%@ : File not found.", filePath); addressBook = [[AddressBook alloc] init]; } else { NSError *error; addressBook = [AddressBook parseFromData:data error:&error]; if (!addressBook) { NSLog(@"Failed to parse address book."); return -1; } } if (strcmp(argv[1], "add") == 0) { // Add an address. Person *person = [[Person alloc] init]; promptForAddress(person); [addressBook.peopleArray addObject:person]; if (!data) { NSLog(@"Creating a new file."); } [[addressBook data] writeToFile:filePath atomically:YES]; } else if (strcmp(argv[1], "list") == 0) { listPeople(addressBook); } else { return printUsage(argv[0]); } return 0; } } qbs-src-2.6.1/examples/protobuf/addressbook_conan/0000755000175100001660000000000014776170045021604 5ustar runnerdockerqbs-src-2.6.1/examples/protobuf/addressbook_conan/conanfile.txt0000644000175100001660000000012214776170045024276 0ustar runnerdocker[requires] protobuf/3.21.12 [tool_requires] protobuf/3.21.12 [generators] QbsDeps qbs-src-2.6.1/examples/protobuf/addressbook_conan/addressbook_conan.qbs0000644000175100001660000000060514776170045025772 0ustar runnerdocker//![0] import qbs.Host CppApplication { consoleApplication: true condition: protobuf.cpp.present && qbs.targetPlatform === Host.platform() Depends { name: "cpp" } cpp.minimumMacosVersion: "11.0" Depends { name: "protobuf.cpp"; required: false } files: [ "../shared/addressbook.proto", "main.cpp", ] qbsModuleProviders: "conan" } //![0] qbs-src-2.6.1/examples/protobuf/addressbook_conan/main.cpp0000644000175100001660000001441414776170045023240 0ustar runnerdocker// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include #include #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #include #pragma GCC diagnostic pop #else #include #endif // __GNUC__ #include "addressbook.pb.h" using google::protobuf::util::TimeUtil; int printUsage(char *argv0) { std::cerr << "Usage: " << argv0 << "add|list ADDRESS_BOOK_FILE" << std::endl; return -1; } std::string readString(const std::string &promt) { std::string result; std::cout << promt; std::getline(std::cin, result); return result; } // This function fills in a Person message based on user input. void promptForAddress(tutorial::Person *person) { std::cout << "Enter person ID number: "; int id; std::cin >> id; person->set_id(id); std::cin.ignore(256, '\n'); *person->mutable_name() = readString("Enter name: "); const auto email = readString("Enter email address (blank for none): "); if (!email.empty()) person->set_email(email); while (true) { const auto number = readString("Enter a phone number (or leave blank to finish): "); if (number.empty()) break; tutorial::Person::PhoneNumber *phone_number = person->add_phones(); phone_number->set_number(number); const auto type = readString("Is this a mobile, home, or work phone? "); if (type == "mobile") phone_number->set_type(tutorial::Person::MOBILE); else if (type == "home") phone_number->set_type(tutorial::Person::HOME); else if (type == "work") phone_number->set_type(tutorial::Person::WORK); else std::cout << "Unknown phone type. Using default." << std::endl; } *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL)); } // Iterates though all people in the AddressBook and prints info about them. void listPeople(const tutorial::AddressBook &address_book) { for (int i = 0; i < address_book.people_size(); i++) { const tutorial::Person &person = address_book.people(i); std::cout << "Person ID: " << person.id() << std::endl; std::cout << " Name: " << person.name() << std::endl; if (!person.email().empty()) { std::cout << " E-mail address: " << person.email() << std::endl; } for (int j = 0; j < person.phones_size(); j++) { const tutorial::Person::PhoneNumber &phone_number = person.phones(j); switch (phone_number.type()) { case tutorial::Person::MOBILE: std::cout << " Mobile phone #: "; break; case tutorial::Person::HOME: std::cout << " Home phone #: "; break; case tutorial::Person::WORK: std::cout << " Work phone #: "; break; default: std::cout << " Unknown phone #: "; break; } std::cout << phone_number.number() << std::endl; } if (person.has_last_updated()) { std::cout << " Updated: " << TimeUtil::ToString(person.last_updated()) << std::endl; } } } int main(int argc, char *argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 3) return printUsage(argv[0]); tutorial::AddressBook address_book; // Read the existing address book. std::fstream input(argv[2], std::ios::in | std::ios::binary); if (!input) { std::cout << argv[2] << ": File not found." << std::endl; } else if (!address_book.ParseFromIstream(&input)) { std::cerr << "Failed to parse address book." << std::endl; return -1; } const std::string mode(argv[1]); if (mode == "add") { // Add an address. promptForAddress(address_book.add_people()); if (!input) std::cout << "Creating a new file." << std::endl; // Write the new address book back to disk. std::fstream output(argv[2], std::ios::out | std::ios::trunc | std::ios::binary); if (!address_book.SerializeToOstream(&output)) { std::cerr << "Failed to write address book." << std::endl; return -1; } } else if (mode == "list") { listPeople(address_book); } else { return printUsage(argv[0]); } // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; } qbs-src-2.6.1/examples/compiled-qml/0000755000175100001660000000000014776170045016651 5ustar runnerdockerqbs-src-2.6.1/examples/compiled-qml/MainForm.ui.qml0000644000175100001660000000522114776170045021510 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.3 Rectangle { property alias mouseArea: mouseArea width: 360 height: 360 MouseArea { id: mouseArea anchors.fill: parent } Image { anchors.centerIn: parent source: "cheese.jpg" } } qbs-src-2.6.1/examples/compiled-qml/compiled-qml.qbs0000644000175100001660000000512614776170045021747 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { Depends { name: "Qt.quick" } files: [ "cheese.jpg", "main.cpp", "qml.qrc" ] Group { name: "QML Files" files: ["*.qml"] } } qbs-src-2.6.1/examples/compiled-qml/main.qml0000644000175100001660000000511114776170045020306 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.4 import QtQuick.Window 2.2 Window { visible: true MainForm { anchors.fill: parent mouseArea.onClicked: { Qt.quit(); } } } qbs-src-2.6.1/examples/compiled-qml/cheese.jpg0000644000175100001660000000572514776170045020620 0ustar runnerdockerJFIFHHAdobed@      ^^   s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?Ao<7k)nrM ȂAZF"7Pcv`Ht=F V1`kIQȑ„4ŎwɁlIb:N~e/'z?J Qy?=q-ҁj{d&apJJt"t0Uԇnی ;@ bJѨ| +|=ໞYbB!%O,̼ITk+[-:+ e)QN!|gN=NͶP7D'!#ai\ݽ;vJۘ#,G- J/9fqP!yEI9|HYh>R'KbIlQҞݜe>)Zr#1q_>y"L`Rv%SIEhۜRdaЩfA Z=5 1{|34jzNM<5 ZW5 k-9$.N}H%A]#JC)zzzt ԋK}N UfZ`~'<\'|+҆Z'`x(!ۓ56iBbR]"@jrO4*ܹ<@|rBe.e@?>:3s1 .ʵXlE!o& zU덡} 4ڸyrRO]OL<;գ8֣x]BG^׹*]ٶ5(VH_Dx6c6##͒T|@`\=B* TJT{cJwQl*kKxd$o`W=QxS/$q$liRnK}Qmb4r2$&1fh5;ɮ9 $2HҞ؀@t9=Թ'x4XTɵ*Ƈ4Rczn{L\&жqр"j)$PV%#y);P<*ޡPPīU(A^JSЂ(AanGaFgOߙ~.!$LTS#3$ً'jF4`5"ǻ0/8vB{\KQmj!jeEz岘csꖑCkk_101ʌz1Ro}[.i1!#lqJ]|J~'29-NxC0/2k^e- FQx{vP[թy죌˫?vx =t=A">$FAppU v׆Qr4 yku&l޵w*SrYQQZFₔڞ,2<7q'm\E|OCILɩҊⴂ7ğCoo7w=U9ӏMOy9/a>^ܐeL+$B|wGߕ~+;;H~‰G-}[{'P)d}麻Sʴ㙜%DF5o*w b I>id!eiqbs-src-2.6.1/examples/compiled-qml/qml.qrc0000644000175100001660000000023414776170045020150 0ustar runnerdocker main.qml MainForm.ui.qml cheese.jpg qbs-src-2.6.1/examples/compiled-qml/main.cpp0000644000175100001660000000520614776170045020304 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } qbs-src-2.6.1/examples/pkgconfig-provider/0000755000175100001660000000000014776170045020065 5ustar runnerdockerqbs-src-2.6.1/examples/pkgconfig-provider/pkgconfig-provider.qbs0000644000175100001660000000526114776170045024377 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ //! [0] CppApplication { consoleApplication: true Depends { name: "zlib"; required: false } condition: !qbs.toolchain.includes("emscripten") && zlib.present name: "PkgConfigProviderExample" files: "main.c" qbsModuleProviders: ["qbspkgconfig"] } //! [0] qbs-src-2.6.1/examples/pkgconfig-provider/main.c0000644000175100001660000000767514776170045021174 0ustar runnerdocker/**************************************************************************** ** ** MIT License ** Copyright (c) 2017 Aleksander Alekseev ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal ** in the Software without restriction, including without limitation the rights ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ** copies of the Software, and to permit persons to whom the Software is ** furnished to do so, subject to the following conditions: ** The above copyright notice and this permission notice shall be included in all ** copies or substantial portions of the Software. ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ** SOFTWARE. ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]) { int res; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } char* fname = argv[1]; struct stat file_stat; res = stat(fname, &file_stat); if (res == -1) { fprintf(stderr, "stat(...) failed, errno = %d\n", errno); return 1; } size_t temp_file_size = (size_t)file_stat.st_size; if (temp_file_size >= INT_MAX) { fprintf(stderr, "Error: filze_size >= INT_MAX (%d)\n", INT_MAX); return 1; } int file_size = (int)temp_file_size; int buff_size = file_size + 1; void* file_buff = malloc(buff_size); if (file_buff == NULL) { fprintf(stderr, "malloc(buff_size) failed, buff_size = %d\n", file_size); return 1; } int fid = open(fname, O_RDONLY); if (fid == -1) { fprintf(stderr, "open(...) failed, errno = %d\n", errno); free(file_buff); return 1; } if (read(fid, file_buff, file_size) != file_size) { fprintf(stderr, "read(...) failed, errno = %d\n", errno); free(file_buff); close(fid); return 1; } close(fid); uLongf compress_buff_size = compressBound(file_size); void* compress_buff = malloc(compress_buff_size); if (compress_buff == NULL) { fprintf(stderr, "malloc(compress_buff_size) failed, " "compress_buff_size = %lu\n", compress_buff_size); free(file_buff); return 1; } uLongf compressed_size = compress_buff_size; res = compress(compress_buff, &compressed_size, file_buff, file_size); if (res != Z_OK) { fprintf(stderr, "compress(...) failed, res = %d\n", res); free(compress_buff); free(file_buff); return 1; } memset(file_buff, 0, buff_size); uLongf decompressed_size = (uLongf)file_size; res = uncompress(file_buff, &decompressed_size, compress_buff, compressed_size); if (res != Z_OK) { fprintf(stderr, "uncompress(...) failed, res = %d\n", res); free(compress_buff); free(file_buff); return 1; } printf( "%s\n----------------\n" "File size: %d, compress_buff_size: %lu, compressed_size: %lu, " "decompressed_size: %lu\n", (char*)file_buff, file_size, compress_buff_size, compressed_size, decompressed_size); free(compress_buff); free(file_buff); } qbs-src-2.6.1/examples/rule/0000755000175100001660000000000014776170045015235 5ustar runnerdockerqbs-src-2.6.1/examples/rule/rule.qbs0000644000175100001660000000171314776170045016715 0ustar runnerdockerimport qbs.TextFile Product { type: "txt_output" Group { name: "lorem_ipsum" files: "lorem_ipsum.txt" fileTags: "txt_input" } //![1] Rule { multiplex: false inputs: ["txt_input"] Artifact { filePath: input.fileName + ".out" fileTags: ["txt_output"] } prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating" + output.fileName + " from " + input.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(input.filePath); var content = file.readAll(); file.close() content = content.toUpperCase(); file = new TextFile(output.filePath, TextFile.WriteOnly); file.write(content); file.close(); } return [cmd]; } } } qbs-src-2.6.1/examples/rule/lorem_ipsum.txt0000644000175100001660000000055214776170045020333 0ustar runnerdockerLorem ipsum dolor sit amet, consectetur adipiscing elit. Integer accumsan laoreet magna vitae elementum. Duis semper ex pellentesque nibh ullamcorper lacinia. Suspendisse sed diam magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In id maximus turpis, mattis commodo mauris. Sed bibendum accumsan leo. Nulla placerat. qbs-src-2.6.1/examples/capnproto/0000755000175100001660000000000014776170045016273 5ustar runnerdockerqbs-src-2.6.1/examples/capnproto/calculator_cpp/0000755000175100001660000000000014776170045021266 5ustar runnerdockerqbs-src-2.6.1/examples/capnproto/calculator_cpp/calculator.capnp0000644000175100001660000001105314776170045024442 0ustar runnerdocker# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors # Licensed under the MIT License: # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. @0x85150b117366d14b; interface Calculator { # A "simple" mathematical calculator, callable via RPC. # # But, to show off Cap'n Proto, we add some twists: # # - You can use the result from one call as the input to the next # without a network round trip. To accomplish this, evaluate() # returns a `Value` object wrapping the actual numeric value. # This object may be used in a subsequent expression. With # promise pipelining, the Value can actually be used before # the evaluate() call that creates it returns! # # - You can define new functions, and then call them. This again # shows off pipelining, but it also gives the client the # opportunity to define a function on the client side and have # the server call back to it. # # - The basic arithmetic operators are exposed as Functions, and # you have to call getOperator() to obtain them from the server. # This again demonstrates pipelining -- using getOperator() to # get each operator and then using them in evaluate() still # only takes one network round trip. evaluate @0 (expression :Expression) -> (value :Value); # Evaluate the given expression and return the result. The # result is returned wrapped in a Value interface so that you # may pass it back to the server in a pipelined request. To # actually get the numeric value, you must call read() on the # Value -- but again, this can be pipelined so that it incurs # no additional latency. struct Expression { # A numeric expression. union { literal @0 :Float64; # A literal numeric value. previousResult @1 :Value; # A value that was (or, will be) returned by a previous # evaluate(). parameter @2 :UInt32; # A parameter to the function (only valid in function bodies; # see defFunction). call :group { # Call a function on a list of parameters. function @3 :Function; params @4 :List(Expression); } } } interface Value { # Wraps a numeric value in an RPC object. This allows the value # to be used in subsequent evaluate() requests without the client # waiting for the evaluate() that returns the Value to finish. read @0 () -> (value :Float64); # Read back the raw numeric value. } defFunction @1 (paramCount :Int32, body :Expression) -> (func :Function); # Define a function that takes `paramCount` parameters and returns the # evaluation of `body` after substituting these parameters. interface Function { # An algebraic function. Can be called directly, or can be used inside # an Expression. # # A client can create a Function that runs on the server side using # `defFunction()` or `getOperator()`. Alternatively, a client can # implement a Function on the client side and the server will call back # to it. However, a function defined on the client side will require a # network round trip whenever the server needs to call it, whereas # functions defined on the server and then passed back to it are called # locally. call @0 (params :List(Float64)) -> (value :Float64); # Call the function on the given parameters. } getOperator @2 (op :Operator) -> (func :Function); # Get a Function representing an arithmetic operator, which can then be # used in Expressions. enum Operator { add @0; subtract @1; multiply @2; divide @3; } } qbs-src-2.6.1/examples/capnproto/calculator_cpp/calculator-client.cpp0000644000175100001660000003131014776170045025375 0ustar runnerdocker// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors // Licensed under the MIT License: // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "calculator.capnp.h" #include #include #include #include class PowerFunction final: public Calculator::Function::Server { // An implementation of the Function interface wrapping pow(). Note that // we're implementing this on the client side and will pass a reference to // the server. The server will then be able to make calls back to the client. public: kj::Promise call(CallContext context) { auto params = context.getParams().getParams(); KJ_REQUIRE(params.size() == 2, "Wrong number of parameters."); context.getResults().setValue(pow(params[0], params[1])); return kj::READY_NOW; } }; int main(int argc, const char* argv[]) { if (argc != 2) { std::cerr << "usage: " << argv[0] << " HOST:PORT\n" "Connects to the Calculator server at the given address and " "does some RPCs." << std::endl; return 1; } capnp::EzRpcClient client(argv[1]); Calculator::Client calculator = client.getMain(); // Keep an eye on `waitScope`. Whenever you see it used is a place where we // stop and wait for the server to respond. If a line of code does not use // `waitScope`, then it does not block! auto& waitScope = client.getWaitScope(); { // Make a request that just evaluates the literal value 123. // // What's interesting here is that evaluate() returns a "Value", which is // another interface and therefore points back to an object living on the // server. We then have to call read() on that object to read it. // However, even though we are making two RPC's, this block executes in // *one* network round trip because of promise pipelining: we do not wait // for the first call to complete before we send the second call to the // server. std::cout << "Evaluating a literal... "; std::cout.flush(); // Set up the request. auto request = calculator.evaluateRequest(); request.getExpression().setLiteral(123); // Send it, which returns a promise for the result (without blocking). auto evalPromise = request.send(); // Using the promise, create a pipelined request to call read() on the // returned object, and then send that. auto readPromise = evalPromise.getValue().readRequest().send(); // Now that we've sent all the requests, wait for the response. Until this // point, we haven't waited at all! auto response = readPromise.wait(waitScope); KJ_ASSERT(response.getValue() == 123); std::cout << "PASS" << std::endl; } { // Make a request to evaluate 123 + 45 - 67. // // The Calculator interface requires that we first call getOperator() to // get the addition and subtraction functions, then call evaluate() to use // them. But, once again, we can get both functions, call evaluate(), and // then read() the result -- four RPCs -- in the time of *one* network // round trip, because of promise pipelining. std::cout << "Using add and subtract... "; std::cout.flush(); Calculator::Function::Client add = nullptr; Calculator::Function::Client subtract = nullptr; { // Get the "add" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::ADD); add = request.send().getFunc(); } { // Get the "subtract" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::SUBTRACT); subtract = request.send().getFunc(); } // Build the request to evaluate 123 + 45 - 67. auto request = calculator.evaluateRequest(); auto subtractCall = request.getExpression().initCall(); subtractCall.setFunction(subtract); auto subtractParams = subtractCall.initParams(2); subtractParams[1].setLiteral(67); auto addCall = subtractParams[0].initCall(); addCall.setFunction(add); auto addParams = addCall.initParams(2); addParams[0].setLiteral(123); addParams[1].setLiteral(45); // Send the evaluate() request, read() the result, and wait for read() to // finish. auto evalPromise = request.send(); auto readPromise = evalPromise.getValue().readRequest().send(); auto response = readPromise.wait(waitScope); KJ_ASSERT(response.getValue() == 101); std::cout << "PASS" << std::endl; } { // Make a request to evaluate 4 * 6, then use the result in two more // requests that add 3 and 5. // // Since evaluate() returns its result wrapped in a `Value`, we can pass // that `Value` back to the server in subsequent requests before the first // `evaluate()` has actually returned. Thus, this example again does only // one network round trip. std::cout << "Pipelining eval() calls... "; std::cout.flush(); Calculator::Function::Client add = nullptr; Calculator::Function::Client multiply = nullptr; { // Get the "add" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::ADD); add = request.send().getFunc(); } { // Get the "multiply" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::MULTIPLY); multiply = request.send().getFunc(); } // Build the request to evaluate 4 * 6 auto request = calculator.evaluateRequest(); auto multiplyCall = request.getExpression().initCall(); multiplyCall.setFunction(multiply); auto multiplyParams = multiplyCall.initParams(2); multiplyParams[0].setLiteral(4); multiplyParams[1].setLiteral(6); auto multiplyResult = request.send().getValue(); // Use the result in two calls that add 3 and add 5. auto add3Request = calculator.evaluateRequest(); auto add3Call = add3Request.getExpression().initCall(); add3Call.setFunction(add); auto add3Params = add3Call.initParams(2); add3Params[0].setPreviousResult(multiplyResult); add3Params[1].setLiteral(3); auto add3Promise = add3Request.send().getValue().readRequest().send(); auto add5Request = calculator.evaluateRequest(); auto add5Call = add5Request.getExpression().initCall(); add5Call.setFunction(add); auto add5Params = add5Call.initParams(2); add5Params[0].setPreviousResult(multiplyResult); add5Params[1].setLiteral(5); auto add5Promise = add5Request.send().getValue().readRequest().send(); // Now wait for the results. KJ_ASSERT(add3Promise.wait(waitScope).getValue() == 27); KJ_ASSERT(add5Promise.wait(waitScope).getValue() == 29); std::cout << "PASS" << std::endl; } { // Our calculator interface supports defining functions. Here we use it // to define two functions and then make calls to them as follows: // // f(x, y) = x * 100 + y // g(x) = f(x, x + 1) * 2; // f(12, 34) // g(21) // // Once again, the whole thing takes only one network round trip. std::cout << "Defining functions... "; std::cout.flush(); Calculator::Function::Client add = nullptr; Calculator::Function::Client multiply = nullptr; Calculator::Function::Client f = nullptr; Calculator::Function::Client g = nullptr; { // Get the "add" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::ADD); add = request.send().getFunc(); } { // Get the "multiply" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::MULTIPLY); multiply = request.send().getFunc(); } { // Define f. auto request = calculator.defFunctionRequest(); request.setParamCount(2); { // Build the function body. auto addCall = request.getBody().initCall(); addCall.setFunction(add); auto addParams = addCall.initParams(2); addParams[1].setParameter(1); // y auto multiplyCall = addParams[0].initCall(); multiplyCall.setFunction(multiply); auto multiplyParams = multiplyCall.initParams(2); multiplyParams[0].setParameter(0); // x multiplyParams[1].setLiteral(100); } f = request.send().getFunc(); } { // Define g. auto request = calculator.defFunctionRequest(); request.setParamCount(1); { // Build the function body. auto multiplyCall = request.getBody().initCall(); multiplyCall.setFunction(multiply); auto multiplyParams = multiplyCall.initParams(2); multiplyParams[1].setLiteral(2); auto fCall = multiplyParams[0].initCall(); fCall.setFunction(f); auto fParams = fCall.initParams(2); fParams[0].setParameter(0); auto addCall = fParams[1].initCall(); addCall.setFunction(add); auto addParams = addCall.initParams(2); addParams[0].setParameter(0); addParams[1].setLiteral(1); } g = request.send().getFunc(); } // OK, we've defined all our functions. Now create our eval requests. // f(12, 34) auto fEvalRequest = calculator.evaluateRequest(); auto fCall = fEvalRequest.initExpression().initCall(); fCall.setFunction(f); auto fParams = fCall.initParams(2); fParams[0].setLiteral(12); fParams[1].setLiteral(34); auto fEvalPromise = fEvalRequest.send().getValue().readRequest().send(); // g(21) auto gEvalRequest = calculator.evaluateRequest(); auto gCall = gEvalRequest.initExpression().initCall(); gCall.setFunction(g); gCall.initParams(1)[0].setLiteral(21); auto gEvalPromise = gEvalRequest.send().getValue().readRequest().send(); // Wait for the results. KJ_ASSERT(fEvalPromise.wait(waitScope).getValue() == 1234); KJ_ASSERT(gEvalPromise.wait(waitScope).getValue() == 4244); std::cout << "PASS" << std::endl; } { // Make a request that will call back to a function defined locally. // // Specifically, we will compute 2^(4 + 5). However, exponent is not // defined by the Calculator server. So, we'll implement the Function // interface locally and pass it to the server for it to use when // evaluating the expression. // // This example requires two network round trips to complete, because the // server calls back to the client once before finishing. In this // particular case, this could potentially be optimized by using a tail // call on the server side -- see CallContext::tailCall(). However, to // keep the example simpler, we haven't implemented this optimization in // the sample server. std::cout << "Using a callback... "; std::cout.flush(); Calculator::Function::Client add = nullptr; { // Get the "add" function from the server. auto request = calculator.getOperatorRequest(); request.setOp(Calculator::Operator::ADD); add = request.send().getFunc(); } // Build the eval request for 2^(4+5). auto request = calculator.evaluateRequest(); auto powCall = request.getExpression().initCall(); powCall.setFunction(kj::heap()); auto powParams = powCall.initParams(2); powParams[0].setLiteral(2); auto addCall = powParams[1].initCall(); addCall.setFunction(add); auto addParams = addCall.initParams(2); addParams[0].setLiteral(4); addParams[1].setLiteral(5); // Send the request and wait. auto response = request.send().getValue().readRequest() .send().wait(waitScope); KJ_ASSERT(response.getValue() == 512); std::cout << "PASS" << std::endl; } return 0; } qbs-src-2.6.1/examples/capnproto/calculator_cpp/calculator_cpp.qbs0000644000175100001660000000134514776170045024773 0ustar runnerdockerimport qbs.Host Project { CppApplication { Depends { name: "capnproto.cpp"; required: false } name: "server" condition: capnproto.cpp.present && qbs.targetPlatform === Host.platform() consoleApplication: true capnproto.cpp.useRpc: true files: [ "calculator.capnp", "calculator-server.cpp" ] } CppApplication { Depends { name: "capnproto.cpp"; required: false } name: "client" condition: capnproto.cpp.present && qbs.targetPlatform === Host.platform() consoleApplication: true capnproto.cpp.useRpc: true files: [ "calculator.capnp", "calculator-client.cpp" ] } } qbs-src-2.6.1/examples/capnproto/calculator_cpp/calculator-server.cpp0000644000175100001660000001657114776170045025441 0ustar runnerdocker// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors // Licensed under the MIT License: // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "calculator.capnp.h" #include #include #include #include typedef unsigned int uint; kj::Promise readValue(Calculator::Value::Client value) { // Helper function to asynchronously call read() on a Calculator::Value and // return a promise for the result. (In the future, the generated code might // include something like this automatically.) return value.readRequest().send() .then([](capnp::Response result) { return result.getValue(); }); } kj::Promise evaluateImpl( Calculator::Expression::Reader expression, capnp::List::Reader params = capnp::List::Reader()) { // Implementation of CalculatorImpl::evaluate(), also shared by // FunctionImpl::call(). In the latter case, `params` are the parameter // values passed to the function; in the former case, `params` is just an // empty list. switch (expression.which()) { case Calculator::Expression::LITERAL: return expression.getLiteral(); case Calculator::Expression::PREVIOUS_RESULT: return readValue(expression.getPreviousResult()); case Calculator::Expression::PARAMETER: { KJ_REQUIRE(expression.getParameter() < params.size(), "Parameter index out-of-range."); return params[expression.getParameter()]; } case Calculator::Expression::CALL: { auto call = expression.getCall(); auto func = call.getFunction(); // Evaluate each parameter. kj::Array> paramPromises = KJ_MAP(param, call.getParams()) { return evaluateImpl(param, params); }; // Join the array of promises into a promise for an array. kj::Promise> joinedParams = kj::joinPromises(kj::mv(paramPromises)); // When the parameters are complete, call the function. return joinedParams.then([KJ_CPCAP(func)](kj::Array&& paramValues) mutable { auto request = func.callRequest(); request.setParams(paramValues); return request.send().then( [](capnp::Response&& result) { return result.getValue(); }); }); } default: // Throw an exception. KJ_FAIL_REQUIRE("Unknown expression type."); } } class ValueImpl final: public Calculator::Value::Server { // Simple implementation of the Calculator.Value Cap'n Proto interface. public: ValueImpl(double value): value(value) {} kj::Promise read(ReadContext context) { context.getResults().setValue(value); return kj::READY_NOW; } private: double value; }; class FunctionImpl final: public Calculator::Function::Server { // Implementation of the Calculator.Function Cap'n Proto interface, where the // function is defined by a Calculator.Expression. public: FunctionImpl(uint paramCount, Calculator::Expression::Reader body) : paramCount(paramCount) { this->body.setRoot(body); } kj::Promise call(CallContext context) { auto params = context.getParams().getParams(); KJ_REQUIRE(params.size() == paramCount, "Wrong number of parameters."); return evaluateImpl(body.getRoot(), params) .then([KJ_CPCAP(context)](double value) mutable { context.getResults().setValue(value); }); } private: uint paramCount; // The function's arity. capnp::MallocMessageBuilder body; // Stores a permanent copy of the function body. }; class OperatorImpl final: public Calculator::Function::Server { // Implementation of the Calculator.Function Cap'n Proto interface, wrapping // basic binary arithmetic operators. public: OperatorImpl(Calculator::Operator op): op(op) {} kj::Promise call(CallContext context) { auto params = context.getParams().getParams(); KJ_REQUIRE(params.size() == 2, "Wrong number of parameters."); double result; switch (op) { case Calculator::Operator::ADD: result = params[0] + params[1]; break; case Calculator::Operator::SUBTRACT:result = params[0] - params[1]; break; case Calculator::Operator::MULTIPLY:result = params[0] * params[1]; break; case Calculator::Operator::DIVIDE: result = params[0] / params[1]; break; default: KJ_FAIL_REQUIRE("Unknown operator."); } context.getResults().setValue(result); return kj::READY_NOW; } private: Calculator::Operator op; }; class CalculatorImpl final: public Calculator::Server { // Implementation of the Calculator Cap'n Proto interface. public: kj::Promise evaluate(EvaluateContext context) override { return evaluateImpl(context.getParams().getExpression()) .then([KJ_CPCAP(context)](double value) mutable { context.getResults().setValue(kj::heap(value)); }); } kj::Promise defFunction(DefFunctionContext context) override { auto params = context.getParams(); context.getResults().setFunc(kj::heap( params.getParamCount(), params.getBody())); return kj::READY_NOW; } kj::Promise getOperator(GetOperatorContext context) override { context.getResults().setFunc(kj::heap( context.getParams().getOp())); return kj::READY_NOW; } }; int main(int argc, const char* argv[]) { if (argc != 2) { std::cerr << "usage: " << argv[0] << " ADDRESS[:PORT]\n" "Runs the server bound to the given address/port.\n" "ADDRESS may be '*' to bind to all local addresses.\n" ":PORT may be omitted to choose a port automatically." << std::endl; return 1; } // Set up a server. capnp::EzRpcServer server(kj::heap(), argv[1]); // Write the port number to stdout, in case it was chosen automatically. auto& waitScope = server.getWaitScope(); uint port = server.getPort().wait(waitScope); if (port == 0) { // The address format "unix:/path/to/socket" opens a unix domain socket, // in which case the port will be zero. std::cout << "Listening on Unix socket..." << std::endl; } else { std::cout << "Listening on port " << port << "..." << std::endl; } // Run forever, accepting connections and handling requests. kj::NEVER_DONE.wait(waitScope); } qbs-src-2.6.1/examples/capnproto/addressbook_cpp/0000755000175100001660000000000014776170045021435 5ustar runnerdockerqbs-src-2.6.1/examples/capnproto/addressbook_cpp/addressbook_cpp.qbs0000644000175100001660000000044614776170045025312 0ustar runnerdockerCppApplication { Depends { name: "capnproto.cpp"; required: false } condition: capnproto.cpp.present && qbs.targetPlatform === qbs.hostPlatform consoleApplication: true cpp.minimumMacosVersion: "10.8" files: [ "addressbook.capnp", "addressbook.cpp" ] } qbs-src-2.6.1/examples/capnproto/addressbook_cpp/addressbook.capnp0000644000175100001660000000330014776170045024754 0ustar runnerdocker# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors # Licensed under the MIT License: # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. @0x9eb32e19f86ee174; using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("addressbook"); struct Person { id @0 :UInt32; name @1 :Text; email @2 :Text; phones @3 :List(PhoneNumber); struct PhoneNumber { number @0 :Text; type @1 :Type; enum Type { mobile @0; home @1; work @2; } } employment :union { unemployed @4 :Void; employer @5 :Text; school @6 :Text; selfEmployed @7 :Void; # We assume that a person is only one of these. } } struct AddressBook { people @0 :List(Person); } qbs-src-2.6.1/examples/capnproto/addressbook_cpp/addressbook.cpp0000644000175100001660000002271114776170045024444 0ustar runnerdocker// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors // Licensed under the MIT License: // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // This sample code appears in the documentation for the C++ implementation. // // If Cap'n Proto is installed, build the sample like: // capnp compile -oc++ addressbook.capnp // c++ -std=c++14 -Wall addressbook.c++ addressbook.capnp.c++ `pkg-config --cflags --libs capnp` -o addressbook // // If Cap'n Proto is not installed, but the source is located at $SRC and has been // compiled in $BUILD (often both are simply ".." from here), you can do: // $BUILD/capnp compile -I$SRC/src -o$BUILD/capnpc-c++ addressbook.capnp // c++ -std=c++14 -Wall addressbook.c++ addressbook.capnp.c++ -I$SRC/src -L$BUILD/.libs -lcapnp -lkj -o addressbook // // Run like: // ./addressbook write | ./addressbook read // Use "dwrite" and "dread" to use dynamic code instead. // TODO(test): Needs cleanup. #include "addressbook.capnp.h" #include #include #include using addressbook::Person; using addressbook::AddressBook; void writeAddressBook(int fd) { ::capnp::MallocMessageBuilder message; AddressBook::Builder addressBook = message.initRoot(); ::capnp::List::Builder people = addressBook.initPeople(2); Person::Builder alice = people[0]; alice.setId(123); alice.setName("Alice"); alice.setEmail("alice@example.com"); // Type shown for explanation purposes; normally you'd use auto. ::capnp::List::Builder alicePhones = alice.initPhones(1); alicePhones[0].setNumber("555-1212"); alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE); alice.getEmployment().setSchool("MIT"); Person::Builder bob = people[1]; bob.setId(456); bob.setName("Bob"); bob.setEmail("bob@example.com"); auto bobPhones = bob.initPhones(2); bobPhones[0].setNumber("555-4567"); bobPhones[0].setType(Person::PhoneNumber::Type::HOME); bobPhones[1].setNumber("555-7654"); bobPhones[1].setType(Person::PhoneNumber::Type::WORK); bob.getEmployment().setUnemployed(); writePackedMessageToFd(fd, message); } void printAddressBook(int fd) { ::capnp::PackedFdMessageReader message(fd); AddressBook::Reader addressBook = message.getRoot(); for (Person::Reader person : addressBook.getPeople()) { std::cout << person.getName().cStr() << ": " << person.getEmail().cStr() << std::endl; for (Person::PhoneNumber::Reader phone: person.getPhones()) { const char* typeName = "UNKNOWN"; switch (phone.getType()) { case Person::PhoneNumber::Type::MOBILE: typeName = "mobile"; break; case Person::PhoneNumber::Type::HOME: typeName = "home"; break; case Person::PhoneNumber::Type::WORK: typeName = "work"; break; } std::cout << " " << typeName << " phone: " << phone.getNumber().cStr() << std::endl; } Person::Employment::Reader employment = person.getEmployment(); switch (employment.which()) { case Person::Employment::UNEMPLOYED: std::cout << " unemployed" << std::endl; break; case Person::Employment::EMPLOYER: std::cout << " employer: " << employment.getEmployer().cStr() << std::endl; break; case Person::Employment::SCHOOL: std::cout << " student at: " << employment.getSchool().cStr() << std::endl; break; case Person::Employment::SELF_EMPLOYED: std::cout << " self-employed" << std::endl; break; } } } #if !CAPNP_LITE #include "addressbook.capnp.h" #include #include #include #include #include using ::capnp::DynamicValue; using ::capnp::DynamicStruct; using ::capnp::DynamicEnum; using ::capnp::DynamicList; using ::capnp::List; using ::capnp::Schema; using ::capnp::StructSchema; using ::capnp::EnumSchema; using ::capnp::Void; using ::capnp::Text; using ::capnp::MallocMessageBuilder; using ::capnp::PackedFdMessageReader; void dynamicWriteAddressBook(int fd, StructSchema schema) { // Write a message using the dynamic API to set each // field by text name. This isn't something you'd // normally want to do; it's just for illustration. MallocMessageBuilder message; // Types shown for explanation purposes; normally you'd // use auto. DynamicStruct::Builder addressBook = message.initRoot(schema); DynamicList::Builder people = addressBook.init("people", 2).as(); DynamicStruct::Builder alice = people[0].as(); alice.set("id", 123); alice.set("name", "Alice"); alice.set("email", "alice@example.com"); auto alicePhones = alice.init("phones", 1).as(); auto phone0 = alicePhones[0].as(); phone0.set("number", "555-1212"); phone0.set("type", "mobile"); alice.get("employment").as() .set("school", "MIT"); auto bob = people[1].as(); bob.set("id", 456); bob.set("name", "Bob"); bob.set("email", "bob@example.com"); // Some magic: We can convert a dynamic sub-value back to // the native type with as()! List::Builder bobPhones = bob.init("phones", 2).as>(); bobPhones[0].setNumber("555-4567"); bobPhones[0].setType(Person::PhoneNumber::Type::HOME); bobPhones[1].setNumber("555-7654"); bobPhones[1].setType(Person::PhoneNumber::Type::WORK); bob.get("employment").as() .set("unemployed", ::capnp::VOID); writePackedMessageToFd(fd, message); } void dynamicPrintValue(DynamicValue::Reader value) { // Print an arbitrary message via the dynamic API by // iterating over the schema. Look at the handling // of STRUCT in particular. switch (value.getType()) { case DynamicValue::VOID: std::cout << ""; break; case DynamicValue::BOOL: std::cout << (value.as() ? "true" : "false"); break; case DynamicValue::INT: std::cout << value.as(); break; case DynamicValue::UINT: std::cout << value.as(); break; case DynamicValue::FLOAT: std::cout << value.as(); break; case DynamicValue::TEXT: std::cout << '\"' << value.as().cStr() << '\"'; break; case DynamicValue::LIST: { std::cout << "["; bool first = true; for (auto element: value.as()) { if (first) { first = false; } else { std::cout << ", "; } dynamicPrintValue(element); } std::cout << "]"; break; } case DynamicValue::ENUM: { auto enumValue = value.as(); KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) { std::cout << enumerant->getProto().getName().cStr(); } else { // Unknown enum value; output raw number. std::cout << enumValue.getRaw(); } break; } case DynamicValue::STRUCT: { std::cout << "("; auto structValue = value.as(); bool first = true; for (auto field: structValue.getSchema().getFields()) { if (!structValue.has(field)) continue; if (first) { first = false; } else { std::cout << ", "; } std::cout << field.getProto().getName().cStr() << " = "; dynamicPrintValue(structValue.get(field)); } std::cout << ")"; break; } default: // There are other types, we aren't handling them. std::cout << "?"; break; } } void dynamicPrintMessage(int fd, StructSchema schema) { PackedFdMessageReader message(fd); dynamicPrintValue(message.getRoot(schema)); std::cout << std::endl; } #endif // !CAPNP_LITE int main(int argc, char* argv[]) { if (argc != 2) { std::cerr << "Missing arg." << std::endl; return 1; } else if (strcmp(argv[1], "write") == 0) { writeAddressBook(1); } else if (strcmp(argv[1], "read") == 0) { printAddressBook(0); #if !CAPNP_LITE } else if (strcmp(argv[1], "dwrite") == 0) { StructSchema schema = Schema::from(); dynamicWriteAddressBook(1, schema); } else if (strcmp(argv[1], "dread") == 0) { StructSchema schema = Schema::from(); dynamicPrintMessage(0, schema); #endif } else { std::cerr << "Invalid arg: " << argv[1] << std::endl; return 1; } return 0; } qbs-src-2.6.1/examples/collidingmice/0000755000175100001660000000000014776170045017070 5ustar runnerdockerqbs-src-2.6.1/examples/collidingmice/mice.qrc0000644000175100001660000000014114776170045020510 0ustar runnerdocker images/cheese.jpg qbs-src-2.6.1/examples/collidingmice/mouse.h0000644000175100001660000000571614776170045020402 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MOUSE_H #define MOUSE_H #include #include //! [0] class Mouse : public QGraphicsItem { public: Mouse(); QRectF boundingRect() const override; QPainterPath shape() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: void advance(int step) override; private: QRandomGenerator m_rand = QRandomGenerator::securelySeeded(); qreal angle; qreal speed; qreal mouseEyeDirection; QColor color; }; //! [0] #endif qbs-src-2.6.1/examples/collidingmice/collidingmice.qbs0000644000175100001660000000567314776170045022414 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { name : "CollidingMice" Depends { name: "Qt.widgets" } property bool isBundle: qbs.targetOS.contains("darwin") && bundle.isBundle files : [ "images/cheese.jpg", "main.cpp", "mouse.cpp", "mouse.h", "mice.qrc" ] Group { fileTagsFilter: isBundle ? ["bundle.content"] : ["application"] qbs.install: true qbs.installDir: isBundle ? "Applications" : (qbs.targetOS.contains("windows") ? "" : "bin") qbs.installSourceBase: product.buildDirectory } } qbs-src-2.6.1/examples/collidingmice/mouse.cpp0000644000175100001660000001524514776170045020733 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mouse.h" #include #include #include #include static const double Pi = 3.14159265358979323846264338327950288419717; static double TwoPi = 2.0 * Pi; static qreal normalizeAngle(qreal angle) { while (angle < 0) angle += TwoPi; while (angle > TwoPi) angle -= TwoPi; return angle; } //! [0] Mouse::Mouse() : angle(0), speed(0), mouseEyeDirection(0), color(m_rand.generate() % 256, m_rand.generate() % 256, m_rand.generate() % 256) { setRotation(m_rand.generate() % (360 * 16)); } //! [0] //! [1] QRectF Mouse::boundingRect() const { qreal adjust = 0.5; return {-18 - adjust, -22 - adjust, 36 + adjust, 60 + adjust}; } //! [1] //! [2] QPainterPath Mouse::shape() const { QPainterPath path; path.addRect(-10, -20, 20, 40); return path; } //! [2] //! [3] void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { // Body painter->setBrush(color); painter->drawEllipse(-10, -20, 20, 40); // Eyes painter->setBrush(Qt::white); painter->drawEllipse(-10, -17, 8, 8); painter->drawEllipse(2, -17, 8, 8); // Nose painter->setBrush(Qt::black); painter->drawEllipse(QRectF(-2, -22, 4, 4)); // Pupils painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4)); painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4)); // Ears painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red); painter->drawEllipse(-17, -12, 16, 16); painter->drawEllipse(1, -12, 16, 16); // Tail QPainterPath path(QPointF(0, 20)); path.cubicTo(-5, 22, -5, 22, 0, 25); path.cubicTo(5, 27, 5, 32, 0, 30); path.cubicTo(-5, 32, -5, 42, 0, 35); painter->setBrush(Qt::NoBrush); painter->drawPath(path); } //! [3] //! [4] void Mouse::advance(int step) { if (!step) return; //! [4] // Don't move too far away //! [5] QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0)); if (lineToCenter.length() > 150) { qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length()); if (lineToCenter.dy() < 0) angleToCenter = TwoPi - angleToCenter; angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2); if (angleToCenter < Pi && angleToCenter > Pi / 4) { // Rotate left angle += (angle < -Pi / 2) ? 0.25 : -0.25; } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) { // Rotate right angle += (angle < Pi / 2) ? 0.25 : -0.25; } } else if (::sin(angle) < 0) { angle += 0.25; } else if (::sin(angle) > 0) { angle -= 0.25; //! [5] //! [6] } //! [6] // Try not to crash with any other mice //! [7] const QList dangerMice = scene()->items(QPolygonF() << mapToScene(0, 0) << mapToScene(-30, -50) << mapToScene(30, -50)); for (QGraphicsItem *item : dangerMice) { if (item == this) continue; QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0)); qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length()); if (lineToMouse.dy() < 0) angleToMouse = TwoPi - angleToMouse; angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2); if (angleToMouse >= 0 && angleToMouse < Pi / 2) { // Rotate right angle += 0.5; } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) { // Rotate left angle -= 0.5; //! [7] //! [8] } //! [8] //! [9] } //! [9] // Add some random movement //! [10] if (dangerMice.size() > 1 && (m_rand.generate() % 10) == 0) { if (m_rand.generate() % 1) angle += (m_rand.generate() % 100) / 500.0; else angle -= (m_rand.generate() % 100) / 500.0; } //! [10] //! [11] speed += (-50 + m_rand.generate() % 100) / 100.0; qreal dx = ::sin(angle) * 10; mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5; setRotation(rotation() + dx); setPos(mapToParent(0, -(3 + sin(speed) * 3))); } //! [11] qbs-src-2.6.1/examples/collidingmice/images/0000755000175100001660000000000014776170045020335 5ustar runnerdockerqbs-src-2.6.1/examples/collidingmice/images/cheese.jpg0000644000175100001660000000572514776170045022304 0ustar runnerdockerJFIFHHAdobed@      ^^   s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?Ao<7k)nrM ȂAZF"7Pcv`Ht=F V1`kIQȑ„4ŎwɁlIb:N~e/'z?J Qy?=q-ҁj{d&apJJt"t0Uԇnی ;@ bJѨ| +|=ໞYbB!%O,̼ITk+[-:+ e)QN!|gN=NͶP7D'!#ai\ݽ;vJۘ#,G- J/9fqP!yEI9|HYh>R'KbIlQҞݜe>)Zr#1q_>y"L`Rv%SIEhۜRdaЩfA Z=5 1{|34jzNM<5 ZW5 k-9$.N}H%A]#JC)zzzt ԋK}N UfZ`~'<\'|+҆Z'`x(!ۓ56iBbR]"@jrO4*ܹ<@|rBe.e@?>:3s1 .ʵXlE!o& zU덡} 4ڸyrRO]OL<;գ8֣x]BG^׹*]ٶ5(VH_Dx6c6##͒T|@`\=B* TJT{cJwQl*kKxd$o`W=QxS/$q$liRnK}Qmb4r2$&1fh5;ɮ9 $2HҞ؀@t9=Թ'x4XTɵ*Ƈ4Rczn{L\&жqр"j)$PV%#y);P<*ޡPPīU(A^JSЂ(AanGaFgOߙ~.!$LTS#3$ً'jF4`5"ǻ0/8vB{\KQmj!jeEz岘csꖑCkk_101ʌz1Ro}[.i1!#lqJ]|J~'29-NxC0/2k^e- FQx{vP[թy죌˫?vx =t=A">$FAppU v׆Qr4 yku&l޵w*SrYQQZFₔڞ,2<7q'm\E|OCILɩҊⴂ7ğCoo7w=U9ӏMOy9/a>^ܐeL+$B|wGߕ~+;;H~‰G-}[{'P)d}麻Sʴ㙜%DF5o*w b I>id!eiqbs-src-2.6.1/examples/collidingmice/main.cpp0000644000175100001660000000727714776170045020535 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mouse.h" #include #include #include #include #include #include static const int MouseCount = 7; //! [0] int main(int argc, char **argv) { QApplication app(argc, argv); //! [0] //! [1] QGraphicsScene scene; scene.setSceneRect(-300, -300, 600, 600); //! [1] //! [2] scene.setItemIndexMethod(QGraphicsScene::NoIndex); //! [2] //! [3] for (int i = 0; i < MouseCount; ++i) { const auto mouse = new Mouse; mouse->setPos(::sin((i * 6.28) / MouseCount) * 200, ::cos((i * 6.28) / MouseCount) * 200); scene.addItem(mouse); } //! [3] //! [4] QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); view.setBackgroundBrush(QPixmap(":/images/cheese.jpg")); //! [4] //! [5] view.setCacheMode(QGraphicsView::CacheBackground); view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); view.setDragMode(QGraphicsView::ScrollHandDrag); //! [5] //! [6] view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice")); view.resize(400, 300); view.show(); QTimer timer; QObject::connect(&timer, &QTimer::timeout, &scene, &QGraphicsScene::advance); timer.start(1000 / 33); return app.exec(); } //! [6] qbs-src-2.6.1/examples/helloworld-complex/0000755000175100001660000000000014776170045020106 5ustar runnerdockerqbs-src-2.6.1/examples/helloworld-complex/helloworld-complex.qbs0000644000175100001660000000641414776170045024442 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { property bool hasSpecialFeature: true Application { name: 'HelloWorld-Complex' Depends { name: 'cpp' } cpp.defines: ['SOMETHING'] files: [ "src/foo.h", "src/foo.cpp" ] Group { condition: project.hasSpecialFeature prefix: "src/" files: ["specialfeature.cpp", "specialfeature.h"] } Group { cpp.defines: { var defines = outer.concat([ 'HAVE_MAIN_CPP', cpp.debugInformation ? 'HAS_DEBUG' : 'HAS_RELEASE' ]); if (project.hasSpecialFeature) defines.push("HAS_SPECIAL_FEATURE"); return defines; } prefix: "src/" files: [ 'main.cpp' ] } } } qbs-src-2.6.1/examples/helloworld-complex/src/0000755000175100001660000000000014776170045020675 5ustar runnerdockerqbs-src-2.6.1/examples/helloworld-complex/src/specialfeature.h0000644000175100001660000000476114776170045024052 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HELLO_SPECIAL_FEATURE #define HELLO_SPECIAL_FEATURE void bragAboutSpecialFeature(); #endif qbs-src-2.6.1/examples/helloworld-complex/src/foo.cpp0000644000175100001660000000476714776170045022202 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SOMETHING # error missing define SOMETHING #endif int someUsefulFunction() { return 156; } qbs-src-2.6.1/examples/helloworld-complex/src/main.cpp0000644000175100001660000000556614776170045022341 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "foo.h" #ifdef HAS_SPECIAL_FEATURE #include "specialfeature.h" #endif #include #ifndef HAVE_MAIN_CPP # error missing define HAVE_MAIN_CPP #endif #ifndef SOMETHING # error missing define SOMETHING #endif int main() { someUsefulFunction(); #if defined(HAS_DEBUG) std::puts("Hello World! (debug version)"); #elif defined(HAS_RELEASE) std::puts("Hello World! (release version)"); #endif #ifdef HAS_SPECIAL_FEATURE bragAboutSpecialFeature(); #endif } qbs-src-2.6.1/examples/helloworld-complex/src/specialfeature.cpp0000644000175100001660000000503414776170045024377 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "specialfeature.h" #include void bragAboutSpecialFeature() { std::cout << "I have a special feature!" << std::endl; } qbs-src-2.6.1/examples/helloworld-complex/src/foo.h0000644000175100001660000000471414776170045021637 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FOO_H #define FOO_H int someUsefulFunction(); #endif qbs-src-2.6.1/examples/cxx-modules/0000755000175100001660000000000014776170045016536 5ustar runnerdockerqbs-src-2.6.1/examples/cxx-modules/mod2/0000755000175100001660000000000014776170045017377 5ustar runnerdockerqbs-src-2.6.1/examples/cxx-modules/mod2/mod2.cppm0000644000175100001660000000210214776170045021114 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include #include export module Mod2; // module declaration import :Order; // import internal partition Order export class Customer { private: std::string name; std::vector orders; public: Customer(const std::string& n) : name{n} { } void buy(const std::string& ordername, double price) { orders.push_back(Order{1, ordername, price}); } void buy(int num, const std::string& ordername, double price) { orders.push_back(Order{num, ordername, price}); } double sumPrice() const; double averagePrice() const; void print() const; }; qbs-src-2.6.1/examples/cxx-modules/mod2/mod2order.cppm0000644000175100001660000000131214776170045022152 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include module Mod2:Order; // internal partition declaration struct Order { int count; std::string name; double price; Order(int c, std::string n, double p) : count{c}, name{n}, price{p} { } }; qbs-src-2.6.1/examples/cxx-modules/mod2/mod2price.cpp0000644000175100001660000000167214776170045021775 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; #include // gcc needs this module Mod2; // implementation unit of module Mod2 import :Order; // import internal partition Order double Customer::sumPrice() const { double sum = 0.0; for (const Order &od : orders) { // ERROR with VC++ //for (const auto& od : orders) { // OK sum += od.count * od.price; } return sum; } double Customer::averagePrice() const { if (orders.empty()) { return 0.0; } return sumPrice() / orders.size(); } qbs-src-2.6.1/examples/cxx-modules/mod2/testmod2.cpp0000644000175100001660000000116614776170045021650 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** #include import Mod2; int main() { Customer c1{"Kim"}; c1.buy("table", 59.90); c1.buy(4, "chair", 9.20); c1.print(); std::cout << " Average: " << c1.averagePrice() << '\n'; } qbs-src-2.6.1/examples/cxx-modules/mod2/mod2io.cpp0000644000175100001660000000176514776170045021305 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include #include #include module Mod2; // implementation unit of module Mod1 void Customer::print() const { // print name: std::cout << name << ":\n"; // print order entries: for (const auto &od : orders) { std::cout << std::format( "{:3} {:14} {:6.2f} {:6.2f}\n", od.count, od.name, od.price, od.count * od.price); } // print sum: std::cout << std::format("{:25} ------\n", ' '); std::cout << std::format("{:25} {:6.2f}\n", " Sum:", sumPrice()); } qbs-src-2.6.1/examples/cxx-modules/mod2/mod2.qbs0000644000175100001660000000133514776170045020751 0ustar runnerdockerCppApplication { condition: { if (qbs.toolchainType === "msvc" // see https://gcc.gnu.org/pipermail/gcc-bugs/2023-November/842674.html // || qbs.toolchainType === "gcc" // || qbs.toolchainType === "mingw" || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "mod2.cppm", "mod2io.cpp", "mod2order.cppm", "mod2price.cpp", "testmod2.cpp", ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/examples/cxx-modules/mod0/0000755000175100001660000000000014776170045017375 5ustar runnerdockerqbs-src-2.6.1/examples/cxx-modules/mod0/mod0main.cpp0000644000175100001660000000106714776170045021611 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** #include import Square; // import module ``Square'' int main() { Square x = toSquare(42); std::cout << x.getValue() << '\n'; } qbs-src-2.6.1/examples/cxx-modules/mod0/mod0.cppm0000644000175100001660000000137514776170045021123 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** export module Square; // declare module Square int square(int i); export class Square { private: int value; public: Square(int i) : value{square(i)} {} int getValue() const { return value; } }; export template Square toSquare(const T &x) { return Square{x}; } int square(int i) { return i * i; } qbs-src-2.6.1/examples/cxx-modules/mod0/mod0.qbs0000644000175100001660000000107214776170045020743 0ustar runnerdockerCppApplication { condition: { if (qbs.toolchainType === "msvc" || qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw" || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "mod0.cppm", "mod0main.cpp", ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/examples/cxx-modules/mod1/0000755000175100001660000000000014776170045017376 5ustar runnerdockerqbs-src-2.6.1/examples/cxx-modules/mod1/mod1.cppm0000644000175100001660000000233514776170045021122 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include #include export module Mod1; // module declaration struct Order { int count; std::string name; double price; Order(int c, const std::string &n, double p) : count{c} , name{n} , price{p} {} }; export class Customer { private: std::string name; std::vector orders; public: Customer(const std::string &n) : name{n} {} void buy(const std::string &ordername, double price) { orders.push_back(Order{1, ordername, price}); } void buy(int num, const std::string &ordername, double price) { orders.push_back(Order{num, ordername, price}); } double sumPrice() const; double averagePrice() const; void print() const; }; qbs-src-2.6.1/examples/cxx-modules/mod1/mod1.qbs0000644000175100001660000000130314776170045020742 0ustar runnerdockerCppApplication { condition: { if (qbs.toolchainType === "msvc" // see https://gcc.gnu.org/pipermail/gcc-bugs/2023-November/842674.html // || qbs.toolchainType === "gcc" // || qbs.toolchainType === "mingw" || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "mod1.cppm", "mod1io.cpp", "mod1price.cpp", "testmod1.cpp", ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/examples/cxx-modules/mod1/mod1io.cpp0000644000175100001660000000176514776170045021303 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include #include #include module Mod1; // implementation unit of module Mod1 void Customer::print() const { // print name: std::cout << name << ":\n"; // print order entries: for (const auto &od : orders) { std::cout << std::format( "{:3} {:14} {:6.2f} {:6.2f}\n", od.count, od.name, od.price, od.count * od.price); } // print sum: std::cout << std::format("{:25} ------\n", ' '); std::cout << std::format("{:25} {:6.2f}\n", " Sum:", sumPrice()); } qbs-src-2.6.1/examples/cxx-modules/mod1/testmod1.cpp0000644000175100001660000000116614776170045021646 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** #include import Mod1; int main() { Customer c1{"Kim"}; c1.buy("table", 59.90); c1.buy(4, "chair", 9.20); c1.print(); std::cout << " Average: " << c1.averagePrice() << '\n'; } qbs-src-2.6.1/examples/cxx-modules/mod1/mod1price.cpp0000644000175100001660000000150414776170045021765 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include module Mod1; // implementation unit of module Mod1 double Customer::sumPrice() const { double sum = 0.0; for (const auto &od : orders) { sum += od.count * od.price; } return sum; } double Customer::averagePrice() const { if (orders.empty()) { return 0.0; } return sumPrice() / orders.size(); } qbs-src-2.6.1/examples/cxx-modules/mod3/0000755000175100001660000000000014776170045017400 5ustar runnerdockerqbs-src-2.6.1/examples/cxx-modules/mod3/mod3price.cpp0000644000175100001660000000154014776170045021771 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; #include // gcc needs this module Mod3; // implementation unit of module Mod3 import :Order; // import internal partition to use Order double Customer::sumPrice() const { double sum = 0.0; for (const Order &od : orders) { sum += od.count * od.price; } return sum; } double Customer::averagePrice() const { if (orders.empty()) { return 0.0; } return sumPrice() / orders.size(); } qbs-src-2.6.1/examples/cxx-modules/mod3/mod3order.cppm0000644000175100001660000000133114776170045022155 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include module Mod3:Order; // internal partition declaration struct Order { int count; std::string name; double price; Order(int c, std::string n, double p) : count{c} , name{n} , price{p} {} }; qbs-src-2.6.1/examples/cxx-modules/mod3/mod3customer.cppm0000644000175100001660000000216214776170045022706 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include #include export module Mod3:Customer; // interface partition declaration import :Order; // import internal partition to use Order export class Customer { private: std::string name; std::vector orders; public: Customer(const std::string &n) : name{n} {} void buy(const std::string &ordername, double price) { orders.push_back(Order{1, ordername, price}); } void buy(int num, const std::string &ordername, double price) { orders.push_back(Order{num, ordername, price}); } double sumPrice() const; double averagePrice() const; void print() const; }; qbs-src-2.6.1/examples/cxx-modules/mod3/mod3.cppm0000644000175100001660000000114614776170045021125 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** export module Mod3; // module declaration export import :Customer; // import and export interface partition Customer //... // import and export other interface partitions qbs-src-2.6.1/examples/cxx-modules/mod3/testmod3.cpp0000644000175100001660000000116614776170045021652 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** #include import Mod3; int main() { Customer c1{"Kim"}; c1.buy("table", 59.90); c1.buy(4, "chair", 9.20); c1.print(); std::cout << " Average: " << c1.averagePrice() << '\n'; } qbs-src-2.6.1/examples/cxx-modules/mod3/mod3io.cpp0000644000175100001660000000206014776170045021274 0ustar runnerdocker//******************************************************** // The following code example is taken from the book // C++20 - The Complete Guide // by Nicolai M. Josuttis (www.josuttis.com) // http://www.cppstd20.com // // The code is licensed under a // Creative Commons Attribution 4.0 International License // http://creativecommons.org/licenses/by/4.0/ //******************************************************** module; // start module unit with global module fragment #include #include #include module Mod3; // implementation unit of module Mod3 import :Order; // import internal partition to use Order void Customer::print() const { // print name: std::cout << name << ":\n"; // print order entries: for (const Order &od : orders) { std::cout << std::format( "{:3} {:14} {:6.2f} {:6.2f}\n", od.count, od.name, od.price, od.count * od.price); } // print sum: std::cout << std::format("{:25} ------\n", ' '); std::cout << std::format("{:25} {:6.2f}\n", " Sum:", sumPrice()); } qbs-src-2.6.1/examples/cxx-modules/mod3/mod3.qbs0000644000175100001660000000137214776170045020754 0ustar runnerdockerCppApplication { condition: { if (qbs.toolchainType === "msvc" // see https://gcc.gnu.org/pipermail/gcc-bugs/2023-November/842674.html // || qbs.toolchainType === "gcc" // || qbs.toolchainType === "mingw" || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) return true; console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true files: [ "mod3.cppm", "mod3customer.cppm", "mod3io.cpp", "mod3order.cppm", "mod3price.cpp", "testmod3.cpp", ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true } qbs-src-2.6.1/examples/baremetal/0000755000175100001660000000000014776170045016222 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/baremetal.qbs0000644000175100001660000000554214776170045020673 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "BareMetal" references: [ "stm32f4discovery/stm32f4discovery.qbs", "at90can128olimex/at90can128olimex.qbs", "cc2540usbdongle/cc2540usbdongle.qbs", "stm8s103f3/stm8s103f3.qbs", "msp430f5529/msp430f5529.qbs", "cy7c68013a/cy7c68013a.qbs", "stm32f103/stm32f103.qbs", "pca10040/pca10040.qbs", "pca10001/pca10001.qbs", "esp8266/esp8266.qbs", ] } qbs-src-2.6.1/examples/baremetal/esp8266/0000755000175100001660000000000014776170045017337 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/esp8266/access-point/0000755000175100001660000000000014776170045021727 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/esp8266/access-point/user_main.c0000644000175100001660000001037014776170045024056 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "user_config.h" // From ESP8266 SDK. #include static const partition_item_t esp_partitions[] = { {SYSTEM_PARTITION_BOOTLOADER, ESP_PART_BL_ADDR, ESP_PART_BOOTLOADER_SIZE}, {SYSTEM_PARTITION_OTA_1, ESP_PART_APP1_ADDR, ESP_PART_APPLICATION_SIZE}, {SYSTEM_PARTITION_OTA_2, ESP_PART_APP2_ADDR, ESP_PART_APPLICATION_SIZE}, {SYSTEM_PARTITION_RF_CAL, ESP_PART_RF_CAL_ADDR, ESP_PART_RF_CAL_SIZE}, {SYSTEM_PARTITION_PHY_DATA, ESP_PART_PHY_DATA_ADDR, ESP_PART_PHY_DATA_SIZE}, {SYSTEM_PARTITION_SYSTEM_PARAMETER, ESP_PART_SYS_PARAM_ADDR, ESP_PART_SYS_PARAM_SIZE} }; enum { ESP_PART_COUNT = sizeof(esp_partitions) / sizeof(esp_partitions[0]) }; LOCAL void ICACHE_FLASH_ATTR user_init_done(void) { os_printf("esp: initialization completed\n"); } void ICACHE_FLASH_ATTR user_pre_init(void) { const bool ok = system_partition_table_regist(esp_partitions, ESP_PART_COUNT, SPI_FLASH_SIZE_MAP); if (!ok) { os_printf("esp: partitions registration failed\n"); while (true); } } void ICACHE_FLASH_ATTR user_init(void) { os_printf("esp: SDK version: %s\n", system_get_sdk_version()); os_printf("esp: reset reason: %u\n", system_get_rst_info()->reason); const bool ok = wifi_set_opmode(SOFTAP_MODE); if (!ok) { os_printf("esp: set softap mode failed\n"); } else { struct softap_config ap_cfg = {0}; ap_cfg.authmode = ESP_AUTO_MODE_CFG; ap_cfg.beacon_interval = ESP_BEACON_INTERVAL_MS_CFG; ap_cfg.channel = ESP_CHANNEL_NO_CFG; ap_cfg.max_connection = 0; ap_cfg.ssid_hidden = false; os_memcpy(&ap_cfg.ssid, ESP_SSID_CFG, sizeof(ESP_SSID_CFG)); const bool ok = wifi_softap_set_config(&ap_cfg); if (!ok) os_printf("esp: set softap configuration failed\n"); } system_init_done_cb(user_init_done); } qbs-src-2.6.1/examples/baremetal/esp8266/access-point/access-point.qbs0000644000175100001660000000106014776170045025023 0ustar runnerdockerCppApplication { condition: qbs.toolchain.contains("gcc") && qbs.architecture === "xtensa" Depends { name: "esp8266_sdk" } cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // This required because ESP8266 SDK includes this 'user_config.h' internally. cpp.includePaths: ["."] cpp.staticLibraries: [ "c", "crypto", "gcc", "lwip", "main", "net80211", "phy", "pp", "wpa" ] files: [ "user_config.h", "user_main.c" ] } qbs-src-2.6.1/examples/baremetal/esp8266/access-point/user_config.h0000644000175100001660000000535414776170045024412 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef ESP8266_USER_CONFIG_H #define ESP8266_USER_CONFIG_H // From ESP8266 SDK. #include #define ESP_SSID_CFG "HELLO FROM QBS\0" #define ESP_AUTO_MODE_CFG (AUTH_OPEN) #define ESP_BEACON_INTERVAL_MS_CFG (1000) #define ESP_CHANNEL_NO_CFG (3) #endif // ESP8266_USER_CONFIG_H qbs-src-2.6.1/examples/baremetal/esp8266/README.md0000644000175100001660000000206514776170045020621 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using GCC toolchain for Espressif ESP8266-WROOM02 MCU. An application is designed to be flashed on the external SPI FLASH with the following parameters: * SPI FLASH size: 16 MBit (2048 + 2048 KBytes) * SPI FLASH mode: DIO * SPI FLASH clock: 40 MHz * SPI FLASH map type: 5 An application is running as WiFi access point that discards all connection attempts, and has the following WiFi parameters: * SSID: "HELLO FROM QBS" * Authentication mode: "open" * Beacon interval: 1000 milliseconds * Channel number: 3 An application requires the ESP8266 NON-OS SDK: * https://github.com/espressif/ESP8266_NONOS_SDK the path to which should be set via the ESP8266_NON_OS_SDK_ROOT environment variable. To convert the ELF application to the final binary image (and also for re-program the ESP8266 MCU), you can use the open source 'esptool' utility (using the SPI FLASH parameters, provided above): * https://github.com/espressif/esptool The following toolchains are supported: * GNU ESP8266 Toolchain qbs-src-2.6.1/examples/baremetal/esp8266/qbs/0000755000175100001660000000000014776170045020124 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/esp8266/qbs/imports/0000755000175100001660000000000014776170045021621 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/esp8266/qbs/imports/Esp8266SdkProbe.qbs0000644000175100001660000000133414776170045025040 0ustar runnerdockerimport qbs.Environment import qbs.File import qbs.FileInfo import qbs.Probes Probes.PathProbe { // Inputs. environmentPaths: Environment.getEnv("ESP8266_NON_OS_SDK_ROOT") // Outputs. property string includesPath; property string libsPath; property string linkerScriptsPath; configure: { for (var i in environmentPaths) { var rootPath = environmentPaths[i]; if (!File.exists(rootPath)) continue; includesPath = FileInfo.joinPaths(rootPath, "include"); libsPath = FileInfo.joinPaths(rootPath, "lib"); linkerScriptsPath = FileInfo.joinPaths(rootPath, "ld"); found = true; return; } } } qbs-src-2.6.1/examples/baremetal/esp8266/qbs/modules/0000755000175100001660000000000014776170045021574 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/esp8266/qbs/modules/esp8266_sdk/0000755000175100001660000000000014776170045023552 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/esp8266/qbs/modules/esp8266_sdk/Esp8266SdkModule.qbs0000644000175100001660000000353714776170045027156 0ustar runnerdockerModule { Depends { name: "cpp" } Esp8266SdkProbe { id: esp_sdk_probe } validate: { if (!esp_sdk_probe.found) throw "ESP8266 NON OS SDK not found. Please set the ESP8266_NON_OS_SDK_ROOT env variable." } cpp.systemIncludePaths: [esp_sdk_probe.includesPath] cpp.libraryPaths: [esp_sdk_probe.libsPath] cpp.driverFlags: ["-nostdlib"] cpp.cFlags: [ "-Wpointer-arith", "-Wundef", "-fno-inline-functions", "-mlongcalls", "-mtext-section-literals", "-ffunction-sections", "-fdata-sections", "-fno-builtin-printf", "-fno-guess-branch-probability", "-freorder-blocks-and-partition", "-fno-cse-follow-jumps" ] cpp.linkerFlags: [ "--no-check-sections", "--gc-sections", "--start-group" ] cpp.defines: [ "ICACHE_FLASH", "USE_OPTIMIZE_PRINTF", // Target specific defines for the external 40MHz DIO // SPI 16 Mbit FLASH (2048 KByte + 2048 KByte) FOTA. "SPI_FLASH_SIZE_MAP=5", "ESP_PART_BL_ADDR=0x000000", "ESP_PART_APP1_ADDR=0x001000", "ESP_PART_APP2_ADDR=0x101000", "ESP_PART_RF_CAL_ADDR=0x1FB000", "ESP_PART_PHY_DATA_ADDR=0x1FC000", "ESP_PART_SYS_PARAM_ADDR=0x1FD000", "ESP_PART_BOOTLOADER_SIZE=0x001000", "ESP_PART_APPLICATION_SIZE=0x0E0000", "ESP_PART_RF_CAL_SIZE=0x001000", "ESP_PART_PHY_DATA_SIZE=0x001000", "ESP_PART_SYS_PARAM_SIZE=0x003000" ] property string _linker_scripts_path: esp_sdk_probe.linkerScriptsPath + "/" Group { name: "ESP8266 Linker Scripts" prefix: esp8266_sdk._linker_scripts_path + "/" fileTags: ["linkerscript"] files: [ "eagle.rom.addr.v6.ld", "eagle.app.v6.new.2048.ld" ] } } qbs-src-2.6.1/examples/baremetal/esp8266/esp8266.qbs0000644000175100001660000000507014776170045021165 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for esp8266-wroom-02 board" qbsSearchPaths: "qbs" references: [ "access-point/access-point.qbs" ] } qbs-src-2.6.1/examples/baremetal/pca10001/0000755000175100001660000000000014776170045017347 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10001/pca10001.qbs0000644000175100001660000000503414776170045021205 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for pca10001/pca10024 boards" references: [ "greenblink/greenblink.qbs" ] } qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/0000755000175100001660000000000014776170045021467 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10001/greenblink/README.md0000644000175100001660000000056514776170045022754 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different ARM toolchains. It is designed for the Nordic pca100001/pca100024 evaluation kit (based on nRF51822 MCU) and simply flashes the green LED on the board. The following toolchains are supported: * GNU Arm Embedded Toolchain * IAR Embedded Workbench * KEIL Microcontroller Development Kit qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/keil/0000755000175100001660000000000014776170045022413 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10001/greenblink/keil/flash.sct0000644000175100001660000000534514776170045024232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ ;; Load region size_region. LR_IROM1 0x00000000 0x00040000 { ;; Load address = execution address. ER_IROM1 0x00000000 0x00040000 { *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) .ANY (+XO) } ; RW data. RW_IRAM1 0x20000000 0x00004000 { .ANY (+RW +ZI) } } qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/keil/startup.s0000644000175100001660000001163014776170045024302 0ustar runnerdocker;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Copyright (C) 2020 Denis Shienkov ;; Contact: https://www.qt.io/licensing/ ;; ;; This file is part of the examples of Qbs. ;; ;; $QT_BEGIN_LICENSE:BSD$ ;; 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 https://www.qt.io/terms-conditions. For further ;; information use the contact form at https://www.qt.io/contact-us. ;; ;; BSD License Usage ;; Alternatively, you may use this file under the terms of the BSD license ;; as follows: ;; ;; "Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions are ;; met: ;; * Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; * Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in ;; the documentation and/or other materials provided with the ;; distribution. ;; * Neither the name of The Qt Company Ltd nor the names of its ;; contributors may be used to endorse or promote products derived ;; from this software without specific prior written permission. ;; ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ;; ;; $QT_END_LICENSE$ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _size_of_stack EQU 0x800 _size_of_heap EQU 0x800 ;; Stack configuration. AREA STACK, NOINIT, READWRITE, ALIGN=3 _start_of_stack SPACE _size_of_stack _end_of_stack ;; Heap configuration. AREA HEAP, NOINIT, READWRITE, ALIGN=3 _start_of_heap SPACE _size_of_heap _end_of_heap PRESERVE8 THUMB ;; Define the empty vectors table. AREA RESET, DATA, READONLY _vectors_table ;; Generic interrupts offset. DCD _end_of_stack ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Power clock. DCD 0 ; Radio. DCD 0 ; UART0. DCD 0 ; SPI0/TWI0 DCD 0 ; SPI1/TWI1 DCD 0 ; Reserved DCD 0 ; GPIOTE DCD 0 ; ADC DCD 0 ; TIMER0 DCD 0 ; TIMER1 DCD 0 ; TIMER2 DCD 0 ; RTC0 DCD 0 ; TEMP DCD 0 ; RNG DCD 0 ; ECB DCD 0 ; CCM/AAR DCD 0 ; WDT DCD 0 ; RTC1 DCD 0 ; QDEC DCD 0 ; LPCOMP DCD 0 ; SWI0 DCD 0 ; SWI1 DCD 0 ; SWI2 DCD 0 ; SWI3 DCD 0 ; SWI4 DCD 0 ; SWI5 DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved _end_of_vectors_table _size_of_vectors_table EQU _end_of_vectors_table - _vectors_table AREA |.text|, CODE, READONLY ;; Reset handler. reset_handler PROC EXPORT reset_handler [WEAK] IMPORT main LDR R0, =main BX R0 ENDP ALIGN END qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/iar/0000755000175100001660000000000014776170045022242 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10001/greenblink/iar/flash.icf0000644000175100001660000000644314776170045024031 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ define symbol _start_of_intvec_section = 0x00000000; define symbol _start_of_ram_section = 0x20000000; define symbol _end_of_ram_section = 0x20003FFF; define symbol _start_of_flash_section = 0x00000000; define symbol _end_of_flash_section = 0x0003FFFF; define symbol _min_stack_size = 0x800; define symbol _min_heap_size = 0x800; define memory mem with size = 4G; define region flash_section = mem:[from _start_of_flash_section to _end_of_flash_section]; define region ram_section = mem:[from _start_of_ram_section to _end_of_ram_section]; define block CSTACK with alignment = 8, size = _min_stack_size { }; define block HEAP with alignment = 8, size = _min_heap_size { }; initialize by copy { readwrite }; place at address mem:_start_of_intvec_section { readonly section .intvec }; place in flash_section { readonly }; place in ram_section { readwrite, block CSTACK, block HEAP }; qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/iar/startup.s0000644000175100001660000001116614776170045024135 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MODULE ?cstartup SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start PUBLIC _vectors_table DATA _vectors_table ;; Generic interrupts offset. DCD sfe(CSTACK) ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Power clock. DCD 0 ; Radio. DCD 0 ; UART0. DCD 0 ; SPI0/TWI0 DCD 0 ; SPI1/TWI1 DCD 0 ; Reserved DCD 0 ; GPIOTE DCD 0 ; ADC DCD 0 ; TIMER0 DCD 0 ; TIMER1 DCD 0 ; TIMER2 DCD 0 ; RTC0 DCD 0 ; TEMP DCD 0 ; RNG DCD 0 ; ECB DCD 0 ; CCM/AAR DCD 0 ; WDT DCD 0 ; RTC1 DCD 0 ; QDEC DCD 0 ; LPCOMP DCD 0 ; SWI0 DCD 0 ; SWI1 DCD 0 ; SWI2 DCD 0 ; SWI3 DCD 0 ; SWI4 DCD 0 ; SWI5 DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved ;; Reset handler. THUMB PUBWEAK reset_handler SECTION .text:CODE:REORDER:NOROOT(2) reset_handler BLX R0 LDR R0, =__iar_program_start BX R0 END qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/greenblink.qbs0000644000175100001660000001164214776170045024322 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.startsWith("arm")) return false; return (qbs.toolchain.contains("gcc") || qbs.toolchain.contains("iar") || qbs.toolchain.contains("keil")) && !qbs.toolchain.contains("xcode") } name: "pca10001-greenblink" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // GCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("gcc") cpp.assemblerFlags: [ "-mcpu=cortex-m0", ] cpp.driverFlags: [ "-mcpu=cortex-m0", "-specs=nosys.specs" ] } Group { condition: qbs.toolchain.contains("gcc") name: "GCC" prefix: "gcc/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.ld"] } } // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.assemblerFlags: [ "--cpu", "cortex-m0" ] cpp.driverFlags: [ "--cpu", "cortex-m0" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.icf"] } } // // KEIL-specific properties and sources. // Properties { condition: qbs.toolchain.contains("keil") cpp.assemblerFlags: [ "--cpu", "cortex-m0" ] cpp.driverFlags: [ "--cpu", "cortex-m0" ] } Group { condition: qbs.toolchain.contains("keil") name: "KEIL" prefix: "keil/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.sct"] } } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/gcc/0000755000175100001660000000000014776170045022223 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10001/greenblink/gcc/flash.ld0000644000175100001660000001153614776170045023647 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ ENTRY(reset_handler) MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x40000 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x4000 } SECTIONS { .text : { KEEP(*(.isr_vector)) *(.text*) KEEP(*(.init)) KEEP(*(.fini)) /* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors) /* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors) *(.rodata*) *(.eh_frame*) . = ALIGN(4); } > FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } > FLASH _start_of_exidx_section = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) . = ALIGN(4); } > FLASH _end_of_exidx_section = .; _end_of_code_section = .; .data : AT (_end_of_code_section) { _start_of_data_section = .; *(vtable) *(.data*) . = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN(__preinit_array_start = .); *(.preinit_array) PROVIDE_HIDDEN(__preinit_array_end = .); . = ALIGN(4); /* init data */ PROVIDE_HIDDEN(__init_array_start = .); *(SORT(.init_array.*)) *(.init_array) PROVIDE_HIDDEN(__init_array_end = .); . = ALIGN(4); /* finit data */ PROVIDE_HIDDEN(__fini_array_start = .); *(SORT(.fini_array.*)) *(.fini_array) PROVIDE_HIDDEN(__fini_array_end = .); *(.jcr) . = ALIGN(4); /* All data end */ _end_of_data_section = .; } > RAM .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; } > RAM .heap (COPY): { __end__ = .; end = __end__; *(.heap*) _heap_limit = .; } > RAM .stack_dummy (COPY): { *(.stack*) } > RAM /* Set stack top to end of RAM, and stack limit move down by size of stack_dummy section. */ _end_of_stack = ORIGIN(RAM) + LENGTH(RAM); _stack_limit = _end_of_stack - SIZEOF(.stack_dummy); PROVIDE(__stack = _end_of_stack); /* Check if data + heap + stack exceeds RAM limit */ ASSERT(_stack_limit >= _heap_limit, "region RAM overflowed with stack") } qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/gcc/startup.s0000644000175100001660000001362514776170045024120 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ .syntax unified .arch armv7e-m .thumb // Define the stack. .section .stack .align 3 .equ _size_of_stack, 2048 .globl _end_of_stack .globl _stack_limit _stack_limit: .space _size_of_stack .size _stack_limit, . - _stack_limit _end_of_stack: .size _end_of_stack, . - _end_of_stack // Define the heap. .section .heap .align 3 .equ _size_of_heap, 2048 .globl _end_of_heap .globl _heap_limit _end_of_heap: .space _size_of_heap .size _end_of_heap, . - _end_of_heap _heap_limit: .size _heap_limit, . - _heap_limit // Define the empty vectors table. .section .isr_vector, "ax" .align 2 .globl _vectors_table _vectors_table: // Generic interrupts offset. .word _end_of_stack // Initial stack pointer value. .word reset_handler // Reset. .word 0 // NMI. .word 0 // Hard fault. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // SVC. .word 0 // Reserved. .word 0 // Reserved. .word 0 // PendSV. .word 0 // SysTick. // External interrupts offset. .word 0 // POWER CLOCK. .word 0 // RADIO. .word 0 // UART0 .word 0 // SPI0/TWI0. .word 0 // SPI1/TWI1. .word 0 // Reserved. .word 0 // GPIOTE. .word 0 // ADC. .word 0 // TIMER0. .word 0 // TIMER1. .word 0 // TIMER2. .word 0 // RTC0. .word 0 // TEMP. .word 0 // RNG. .word 0 // ECB. .word 0 // CCM_AAR. .word 0 // WDT. .word 0 // RTC1. .word 0 // QDEC. .word 0 // LPCOMP. .word 0 // SWI0. .word 0 // SWI1. .word 0 // SWI2. .word 0 // SWI3. .word 0 // SWI4. .word 0 // SWI5. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .size _vectors_table, . - _vectors_table // Define the 'reset_handler' function, which is an entry point. .text .thumb .thumb_func .align 1 .globl reset_handler .type reset_handler, %function reset_handler: // Loop to copy data from read only memory to RAM. ldr r1, =_end_of_code_section ldr r2, =_start_of_data_section ldr r3, =__bss_start__ subs r3, r3, r2 ble _copy_data_init_done _copy_data_init: subs r3, r3, #4 ldr r0, [r1,r3] str r0, [r2,r3] bgt _copy_data_init _copy_data_init_done: // Zero fill the bss segment. ldr r1, =__bss_start__ ldr r2, =__bss_end__ movs r0, 0 subs r2, r2, r1 ble _loop_fill_zero_bss_done _loop_fill_zero_bss: subs r2, r2, #4 str r0, [r1, r2] bgt _loop_fill_zero_bss _loop_fill_zero_bss_done: // Call the application's entry point. bl main bx lr .size reset_handler, . - reset_handler qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/system.h0000644000175100001660000000575214776170045023175 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #include #ifdef __cplusplus extern "C" { #endif #define __IO volatile struct gpio_regs_map { uint32_t RESERVED0[321u]; __IO uint32_t OUT; __IO uint32_t OUTSET; __IO uint32_t OUTCLR; __IO uint32_t IN; __IO uint32_t DIR; __IO uint32_t DIRSET; __IO uint32_t DIRCLR; uint32_t RESERVED1[120u]; __IO uint32_t PIN_CNF[32u]; }; #define GPIO_REGS_ADDRESS (0x50000000u) #define GPIOD_REGS_MAP ((struct gpio_regs_map *)GPIO_REGS_ADDRESS) #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/gpio.h0000644000175100001660000000513214776170045022577 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_green_led(void); void gpio_toggle_green_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/main.c0000644000175100001660000000531014776170045022556 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include static void some_delay(uint32_t counts) { for (uint32_t index = 0u; index < counts; ++index) __asm("nop"); } int main(void) { gpio_init_green_led(); while (1) { gpio_toggle_green_led(); some_delay(1000000u); } } qbs-src-2.6.1/examples/baremetal/pca10001/greenblink/gpio.c0000644000175100001660000001063014776170045022571 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" #define GPIO_GREEN_LED_PIN_POS (18u) #define GPIO_GREEN_LED_PIN (1u << GPIO_GREEN_LED_PIN_POS) // Pin direction attributes. #define GPIO_PIN_CNF_DIR_POS (0u) // Position of DIR field. #define GPIO_PIN_CNF_DIR_OUT (1u) // Configure pin as an output pin. #define GPIO_PIN_CNF_DIR_MSK (GPIO_PIN_CNF_DIR_OUT << GPIO_PIN_CNF_DIR_POS) // Pin input buffer attributes. #define GPIO_PIN_CNF_INPUT_POS (1u) // Position of INPUT field. #define GPIO_PIN_CNF_INPUT_OFF (1u) // Disconnect input buffer. #define GPIO_PIN_CNF_INPUT_MSK (GPIO_PIN_CNF_INPUT_OFF << GPIO_PIN_CNF_INPUT_POS) // Pin pull attributes. #define GPIO_PIN_CNF_PULL_POS (2u) // Position of PULL field. #define GPIO_PIN_CNF_PULL_OFF (0u) // No pull. #define GPIO_PIN_CNF_PULL_MSK (GPIO_PIN_CNF_PULL_OFF << GPIO_PIN_CNF_PULL_POS) // Pin drive attributes. #define GPIO_PIN_CNF_DRIVE_POS (8u) // Position of DRIVE field. #define GPIO_PIN_CNF_DRIVE_S0S1 (0u) // Standard '0', standard '1'. #define GPIO_PIN_CNF_DRIVE_MSK (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_POS) // Pin sense attributes. #define GPIO_PIN_CNF_SENSE_POS (16u) // Position of SENSE field. #define GPIO_PIN_CNF_SENSE_OFF (0u) // Disabled. #define GPIO_PIN_CNF_SENSE_MSK (GPIO_PIN_CNF_SENSE_OFF << GPIO_PIN_CNF_SENSE_POS) void gpio_init_green_led(void) { GPIOD_REGS_MAP->PIN_CNF[GPIO_GREEN_LED_PIN_POS] = (GPIO_PIN_CNF_DIR_MSK | GPIO_PIN_CNF_INPUT_MSK | GPIO_PIN_CNF_PULL_MSK | GPIO_PIN_CNF_DRIVE_MSK | GPIO_PIN_CNF_SENSE_MSK); } void gpio_toggle_green_led(void) { const uint32_t gpio_state = GPIOD_REGS_MAP->OUT; GPIOD_REGS_MAP->OUTSET = (GPIO_GREEN_LED_PIN & ~gpio_state); GPIOD_REGS_MAP->OUTCLR = (GPIO_GREEN_LED_PIN & gpio_state); } qbs-src-2.6.1/examples/baremetal/cy7c68013a/0000755000175100001660000000000014776170045017632 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/cy7c68013a/cy7c68013a.qbs0000644000175100001660000000503014776170045021747 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for cy7c68013a board" references: [ "nes-gamepads/nes-gamepads.qbs" ] } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/0000755000175100001660000000000014776170045022176 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/irqs.h0000644000175100001660000000622714776170045023334 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_IRQS_H #define FX2_IRQS_H #ifdef __cplusplus extern "C" { #endif // Standard interrupt numbers. #define INT0_IRQ 0 // External interrupt 0. #define TMR0_IRQ 1 // Timer 0 interrupt. #define INT1_IRQ 2 // External interrupt 1. #define TMR1_IRQ 3 // Timer 1 interrupt. #define COM0_IRQ 4 // Serial port 0 transmit or receive interrupt. #define TMR2_IRQ 5 // Timer 2 interrupt. #define WKUP_IRQ 6 // Resume interrupt. #define COM1_IRQ 7 // Serial port 1 transmit or receive interrupt. #define USB_IRQ 8 // USB interrupt. #define I2C_IRQ 9 // I2C bus interrupt. #define INT4_IRQ 10 // External interrupt 4. #define INT5_IRQ 11 // External interrupt 5. #define INT6_IRQ 12 // External interrupt 6. #ifdef __cplusplus } #endif #endif // FX2_IRQS_H qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/nes-gamepads.qbs0000644000175100001660000001055214776170045025254 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.contains("mcs51")) return false; return qbs.toolchain.contains("iar") || qbs.toolchain.contains("keil") || qbs.toolchain.contains("sdcc") } name: "cy7c68013a-nes-gamepads" cpp.positionIndependentCode: false // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.commonCompilerFlags: ["-e"] cpp.staticLibraries: [ cpp.toolchainInstallPath + "/../lib/clib/cl-pli-nsid-1e16x01" ] cpp.driverLinkerFlags: [ "-D_IDATA_STACK_SIZE=0x40", "-D_PDATA_STACK_SIZE=0x80", "-D_XDATA_STACK_SIZE=0xEFF", "-D_XDATA_HEAP_SIZE=0xFF", "-D_EXTENDED_STACK_SIZE=0", "-D_EXTENDED_STACK_START=0" ] } Group { name: "IAR Linker Script" condition: qbs.toolchain.contains("iar") prefix: cpp.toolchainInstallPath + "/../config/devices/cypress/" fileTags: ["linkerscript"] files: ["lnk51ew_CY7C68013A.xcl"] } // // KEIL-specific properties and sources. // Properties { condition: qbs.toolchain.contains("keil") cpp.driverLinkerFlags: [ "RAMSIZE(256)", "CODE(0x80)", "XDATA(0x1000)" ] } // // SDCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("sdcc") cpp.driverLinkerFlags: [ "--code-loc", "0x80", "--xram-loc", "0x1000" ] } // // Common code. // files: [ "core.c", "core.h", "defs.h", "gpio.c", "gpio.h", "hid.c", "hid.h", "hiddesc.c", "hidep0.c", "hidep1.c", "irqs.h", "main.c", "regs.h", "usb.c", "usb.h", ] } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/README.md0000644000175100001660000000311014776170045023450 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different 8051 toolchains. It is designed for the target board based on Cypress FX2 cy7c68013a chip. It is possible to use the official development kit from the Cypress: * https://www.cypress.com/documentation/development-kitsboards/cy3684-ez-usb-fx2lp-development-kit but, a better solution is to buy the China's analogs or replacements, e.g. on Aliexpress. It implements a USB HID device that connects two 8-buttons NES (Dendy) gamepads to a PC. The gamepads are connected to the cy7c68013a chip as follows: 1. CLK - it is an output clock signal which generates by chip from the port A, pin 0 (PA0). This pin should be connected to the CLK inputs for both gamepads. 2. DATA1 - it is an input data signal which comes to chip on the the port A, pin 2 (PA2). This pin should be connected to the DATA output from the gamepad #1. 3. DATA2 - it is an input data signal which comes to chip on the the port A, pin 4 (PA4). This pin should be connected to the DATA output from the gamepad #2. 4. LATCH - it is an output clock signal which generates by chip from the port A, pin 6 (PA6). This pin should be connected to the LATCH inputs for both gamepads. Actual schematic and pinouts depends on an used gamepads (with 7, 9 or other pins connectors) and a development boards. Also, do not forget to connect the +3.3V and GND wires to the gamepads. Then it is possible to play 8-bit NES games using various PC simulators. The following toolchains are supported: * IAR Embedded Workbench * SDCC * KEIL C51 qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/hid.c0000644000175100001660000000625614776170045023117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hid.h" #include "core.h" #include "usb.h" void hid_init(void) { // Disable end point 1 output. EP1OUTCFG = bmEP_DISABLE; sync_delay(); // Enable end point 1 input in interrupt mode. EP1INCFG = bmEP_ENABLE | bmEP_INT; sync_delay(); // Disable end point 2. EP2CFG = bmEP_DISABLE; sync_delay(); // Disable end point 4. EP4CFG = bmEP_DISABLE; sync_delay(); // Disable end point 6. EP6CFG = bmEP_DISABLE; sync_delay(); // Disable end point 8. EP8CFG = bmEP_DISABLE; sync_delay(); // Reset all FIFOs. FIFORESET = bmNAKALL; // NAK all host transfers. sync_delay(); FIFORESET = 0x00; sync_delay(); // Enable dual autopointer(s). AUTOPTRSETUP |= bmAPTREN; sync_delay(); } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/hidep1.c0000644000175100001660000000625714776170045023526 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hid.h" struct hid_report { const BYTE id; BYTE buttons; BYTE ready; }; static struct hid_report g_reports[HID_REPORTS_COUNT] = { {HID_REPORT_ID_GAMEPAD1, 0, FALSE}, {HID_REPORT_ID_GAMEPAD2, 0, FALSE} }; static void ep1_report_send(BYTE index) { if (!g_reports[index].ready) return; if (EP1INCS & bmEPBUSY) return; EP1INBUF[0] = g_reports[index].id; EP1INBUF[1] = g_reports[index].buttons; EP1INBC = 2; g_reports[index].ready = FALSE; } void hid_ep1_task(void) { BYTE index = 0; for (index = 0; index < HID_REPORTS_COUNT; ++index) ep1_report_send(index); } void hid_ep1_report_update(BYTE index, BYTE buttons) { g_reports[index].buttons = buttons; g_reports[index].ready = TRUE; } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/defs.h0000644000175100001660000001135314776170045023273 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_DEFS_H #define FX2_DEFS_H #ifdef __cplusplus extern "C" { #endif enum bit_mask { bmBIT0 = 0x01, bmBIT1 = 0x02, bmBIT2 = 0x04, bmBIT3 = 0x08, bmBIT4 = 0x10, bmBIT5 = 0x20, bmBIT6 = 0x40, bmBIT7 = 0x80 }; enum boolean { FALSE = 0, TRUE }; typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef unsigned char BOOL; #ifndef NULL #define NULL (void *)0 #endif #if defined(__ICC8051__) #include # define NOP() __no_operation() # define XDATA __xdata # define CODE __code # define AT __at # define SFR __sfr # define SBIT __bit # define XDATA_REG(reg_name, reg_addr) \ XDATA __no_init volatile BYTE reg_name @ reg_addr; # define SPEC_FUN_REG(reg_name, reg_addr) \ SFR __no_init volatile BYTE reg_name @ reg_addr; # define SPEC_FUN_REG_BIT(bit_name, reg_addr, bit_num) \ SBIT __no_init volatile _Bool bit_name @ (reg_addr+bit_num); # define _PPTOSTR_(x) #x # define _PPARAM_(address) _PPTOSTR_(vector=address * 8 + 3) # define INTERRUPT(isr_name, vector) \ _Pragma(_PPARAM_(vector)) __interrupt void isr_name(void) #elif defined (__C51__) # include # define NOP() _nop_() # define XDATA xdata # define CODE code # define AT _at_ # define SFR sfr # define SBIT sbit # if defined(DEFINE_REGS) # define XDATA_REG(reg_name, reg_addr) \ XDATA volatile BYTE reg_name AT reg_addr; # else # define XDATA_REG(reg_name, reg_addr) \ extern XDATA volatile BYTE reg_name; # endif # define SPEC_FUN_REG(reg_name, reg_addr) \ SFR reg_name = reg_addr; # define SPEC_FUN_REG_BIT(bit_name, reg_addr, bit_num) \ sbit bit_name = reg_addr + bit_num; # define INTERRUPT(isr_name, num) \ void isr_name (void) interrupt num #elif defined (__SDCC_mcs51) # define NOP() __asm nop __endasm # define XDATA __xdata # define CODE __code # define AT __at # define SFR __sfr # define SBIT __sbit # define XDATA_REG(reg_name, reg_addr) \ XDATA AT reg_addr volatile BYTE reg_name; # define SPEC_FUN_REG(reg_name, reg_addr) \ SFR AT reg_addr reg_name; # define SPEC_FUN_REG_BIT(bit_name, reg_addr, bit_num) \ SBIT AT reg_addr + bit_num bit_name; # define INTERRUPT(isr_name, num) \ void isr_name (void) __interrupt num #else #error "Unsupported toolchain" #endif #ifdef __cplusplus } #endif #endif // FX2_DEFS_H qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/hid.h0000644000175100001660000000633214776170045023117 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_HID_H #define FX2_HID_H #include "usb.h" #ifdef __cplusplus extern "C" { #endif enum hid_constants { HID_CONFIG_NUMBER = 1, // Number of valid configuration. HID_IFACE_NUMBER = 0, // Number of valid interface. HID_ALT_IFACE_NUMBER = 0, // Number of valid alternate interface. HID_EP_IN = 0x81 // Active end point address. }; enum hid_gamepad_id { HID_REPORT_ID_GAMEPAD1 = 1, HID_REPORT_ID_GAMEPAD2 = 2 }; enum { HID_REPORTS_COUNT = 2, HID_REPORT_BITS_COUNT = 8 }; void hid_init(void); void hid_ep0_init(void); void hid_ep0_setup_task(void); const BYTE CODE *hid_ep0_std_desc_get(void); const BYTE CODE *hid_ep0_report_desc_get(WORD *length); void hid_ep1_task(void); void hid_ep1_report_update(BYTE index, BYTE buttons); #ifdef __cplusplus } #endif #endif // FX2_HID_H qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/regs.h0000644000175100001660000006331214776170045023314 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_REGS_H #define FX2_REGS_H #include "defs.h" #ifdef __cplusplus extern "C" { #endif // // XDATA registers. // XDATA_REG(GPIF_WAVE_DATA, 0xE400) // GPIF waveform descriptor. XDATA_REG(RES_WAVEDATA_END, 0xE480) // Reserved. // General configuration. XDATA_REG(CPUCS, 0xE600) // Control & status. XDATA_REG(IFCONFIG, 0xE601) // Interface configuration. XDATA_REG(PINFLAGSAB, 0xE602) // FIFO FLAGA and FLAGB assignments. XDATA_REG(PINFLAGSCD, 0xE603) // FIFO FLAGC and FLAGD assignments. XDATA_REG(FIFORESET, 0xE604) // Restore FIFOS to default state. XDATA_REG(BREAKPT, 0xE605) // Breakpoint. XDATA_REG(BPADDRH, 0xE606) // Breakpoint address H. XDATA_REG(BPADDRL, 0xE607) // Breakpoint address L. XDATA_REG(UART230, 0xE608) // 230 Kbaud clock for T0,T1,T2. XDATA_REG(FIFOPINPOLAR, 0xE609) // FIFO polarities. XDATA_REG(REVID, 0xE60A) // Chip revision. XDATA_REG(REVCTL, 0xE60B) // Chip revision control. // Endpoint configuration. XDATA_REG(EP1OUTCFG, 0xE610) // Endpoint 1-out configuration. XDATA_REG(EP1INCFG, 0xE611) // Endpoint 1-in configuration. XDATA_REG(EP2CFG, 0xE612) // Endpoint 2 configuration. XDATA_REG(EP4CFG, 0xE613) // Endpoint 4 configuration. XDATA_REG(EP6CFG, 0xE614) // Endpoint 6 configuration. XDATA_REG(EP8CFG, 0xE615) // Endpoint 8 configuration. XDATA_REG(EP2FIFOCFG, 0xE618) // Endpoint 2 FIFO configuration. XDATA_REG(EP4FIFOCFG, 0xE619) // Endpoint 4 FIFO configuration. XDATA_REG(EP6FIFOCFG, 0xE61A) // Endpoint 6 FIFO configuration. XDATA_REG(EP8FIFOCFG, 0xE61B) // Endpoint 8 FIFO configuration. XDATA_REG(EP2AUTOINLENH, 0xE620) // Endpoint 2 packet length H (in only). XDATA_REG(EP2AUTOINLENL, 0xE621) // Endpoint 2 packet length L (in only). XDATA_REG(EP4AUTOINLENH, 0xE622) // Endpoint 4 packet length H (in only). XDATA_REG(EP4AUTOINLENL, 0xE623) // Endpoint 4 packet length L (in only). XDATA_REG(EP6AUTOINLENH, 0xE624) // Endpoint 6 packet length H (in only). XDATA_REG(EP6AUTOINLENL, 0xE625) // Endpoint 6 packet length L (in only). XDATA_REG(EP8AUTOINLENH, 0xE626) // Endpoint 8 packet length H (in only). XDATA_REG(EP8AUTOINLENL, 0xE627) // Endpoint 8 packet length L (in only). XDATA_REG(EP2FIFOPFH, 0xE630) // EP2 programmable flag trigger H. XDATA_REG(EP2FIFOPFL, 0xE631) // EP2 programmable flag trigger L. XDATA_REG(EP4FIFOPFH, 0xE632) // EP4 programmable flag trigger H. XDATA_REG(EP4FIFOPFL, 0xE633) // EP4 programmable flag trigger L. XDATA_REG(EP6FIFOPFH, 0xE634) // EP6 programmable flag trigger H. XDATA_REG(EP6FIFOPFL, 0xE635) // EP6 programmable flag trigger L. XDATA_REG(EP8FIFOPFH, 0xE636) // EP8 programmable flag trigger H. XDATA_REG(EP8FIFOPFL, 0xE637) // EP8 programmable flag trigger L. XDATA_REG(EP2ISOINPKTS, 0xE640) // EP2 (if ISO) in packets per frame (1-3). XDATA_REG(EP4ISOINPKTS, 0xE641) // EP4 (if ISO) in packets per frame (1-3). XDATA_REG(EP6ISOINPKTS, 0xE642) // EP6 (if ISO) in packets per frame (1-3). XDATA_REG(EP8ISOINPKTS, 0xE643) // EP8 (if ISO) in packets per frame (1-3). XDATA_REG(INPKTEND, 0xE648) // Force in packet end. XDATA_REG(OUTPKTEND, 0xE649) // Force out packet end. // Interrupts. XDATA_REG(EP2FIFOIE, 0xE650) // Endpoint 2 flag interrupt enable. XDATA_REG(EP2FIFOIRQ, 0xE651) // Endpoint 2 flag interrupt request. XDATA_REG(EP4FIFOIE, 0xE652) // Endpoint 4 flag interrupt enable. XDATA_REG(EP4FIFOIRQ, 0xE653) // Endpoint 4 flag interrupt request. XDATA_REG(EP6FIFOIE, 0xE654) // Endpoint 6 flag interrupt enable. XDATA_REG(EP6FIFOIRQ, 0xE655) // Endpoint 6 flag interrupt request. XDATA_REG(EP8FIFOIE, 0xE656) // Endpoint 8 flag interrupt enable. XDATA_REG(EP8FIFOIRQ, 0xE657) // Endpoint 8 flag interrupt request. XDATA_REG(IBNIE, 0xE658) // IN-BULK-NAK interrupt enable. XDATA_REG(IBNIRQ, 0xE659) // IN-BULK-NAK interrupt request. XDATA_REG(NAKIE, 0xE65A) // Endpoint ping NAK interrupt enable. XDATA_REG(NAKIRQ, 0xE65B) // Endpoint ping NAK interrupt request. XDATA_REG(USBIE, 0xE65C) // USB Int enables. XDATA_REG(USBIRQ, 0xE65D) // USB interrupt requests. XDATA_REG(EPIE, 0xE65E) // Endpoint interrupt enables. XDATA_REG(EPIRQ, 0xE65F) // Endpoint interrupt requests. XDATA_REG(GPIFIE, 0xE660) // GPIF interrupt enable. XDATA_REG(GPIFIRQ, 0xE661) // GPIF interrupt request. XDATA_REG(USBERRIE, 0xE662) // USB error interrupt enables. XDATA_REG(USBERRIRQ, 0xE663) // USB error interrupt requests. XDATA_REG(ERRCNTLIM, 0xE664) // USB error counter and limit. XDATA_REG(CLRERRCNT, 0xE665) // Clear error counter EC[3..0]. XDATA_REG(INT2IVEC, 0xE666) // Interrupt 2 (USB) autovector. XDATA_REG(INT4IVEC, 0xE667) // Interrupt 4 (FIFOS & GPIF) autovector. XDATA_REG(INTSETUP, 0xE668) // interrupt 2 & 4 setup. // Input/Output. XDATA_REG(PORTACFG, 0xE670) // I/O PORTA alternate configuration. XDATA_REG(PORTCCFG, 0xE671) // I/O PORTC alternate configuration. XDATA_REG(PORTECFG, 0xE672) // I/O PORTE alternate configuration. XDATA_REG(I2CS, 0xE678) // Bus control & status. XDATA_REG(I2DAT, 0xE679) // Bus data. XDATA_REG(I2CTL, 0xE67A) // Bus control. XDATA_REG(XAUTODAT1, 0xE67B) // Autoptr1 movx access. XDATA_REG(XAUTODAT2, 0xE67C) // Autoptr2 movx access. // USB Control. XDATA_REG(USBCS, 0xE680) // USB control & status. XDATA_REG(SUSPEND, 0xE681) // Put chip into suspend. XDATA_REG(WAKEUPCS, 0xE682) // Wakeup source and polarity. XDATA_REG(TOGCTL, 0xE683) // Toggle control. XDATA_REG(USBFRAMEH, 0xE684) // USB frame count H. XDATA_REG(USBFRAMEL, 0xE685) // USB frame count L. XDATA_REG(MICROFRAME, 0xE686) // Microframe count, 0-7. XDATA_REG(FNADDR, 0xE687) // USB function address. // Endpoints. XDATA_REG(EP0BCH, 0xE68A) // Endpoint 0 byte count H. XDATA_REG(EP0BCL, 0xE68B) // Endpoint 0 byte count L. XDATA_REG(EP1OUTBC, 0xE68D) // Endpoint 1 out byte count. XDATA_REG(EP1INBC, 0xE68F) // Endpoint 1 in byte count. XDATA_REG(EP2BCH, 0xE690) // Endpoint 2 byte count H. XDATA_REG(EP2BCL, 0xE691) // Endpoint 2 byte count L. XDATA_REG(EP4BCH, 0xE694) // Endpoint 4 byte count H. XDATA_REG(EP4BCL, 0xE695) // Endpoint 4 byte count L. XDATA_REG(EP6BCH, 0xE698) // Endpoint 6 byte count H. XDATA_REG(EP6BCL, 0xE699) // Endpoint 6 byte count L. XDATA_REG(EP8BCH, 0xE69C) // Endpoint 8 byte count H. XDATA_REG(EP8BCL, 0xE69D) // Endpoint 8 byte count L. XDATA_REG(EP0CS, 0xE6A0) // Endpoint control and status. XDATA_REG(EP1OUTCS, 0xE6A1) // Endpoint 1 out control and status. XDATA_REG(EP1INCS, 0xE6A2) // Endpoint 1 in control and status. XDATA_REG(EP2CS, 0xE6A3) // Endpoint 2 control and status. XDATA_REG(EP4CS, 0xE6A4) // Endpoint 4 control and status. XDATA_REG(EP6CS, 0xE6A5) // Endpoint 6 control and status. XDATA_REG(EP8CS, 0xE6A6) // Endpoint 8 control and status. XDATA_REG(EP2FIFOFLGS, 0xE6A7) // Endpoint 2 flags. XDATA_REG(EP4FIFOFLGS, 0xE6A8) // Endpoint 4 flags. XDATA_REG(EP6FIFOFLGS, 0xE6A9) // Endpoint 6 flags. XDATA_REG(EP8FIFOFLGS, 0xE6AA) // Endpoint 8 flags. XDATA_REG(EP2FIFOBCH, 0xE6AB) // EP2 FIFO total byte count H. XDATA_REG(EP2FIFOBCL, 0xE6AC) // EP2 FIFO total byte count L. XDATA_REG(EP4FIFOBCH, 0xE6AD) // EP4 FIFO total byte count H. XDATA_REG(EP4FIFOBCL, 0xE6AE) // EP4 FIFO total byte count L. XDATA_REG(EP6FIFOBCH, 0xE6AF) // EP6 FIFO total byte count H. XDATA_REG(EP6FIFOBCL, 0xE6B0) // EP6 FIFO total byte count L. XDATA_REG(EP8FIFOBCH, 0xE6B1) // EP8 FIFO total byte count H. XDATA_REG(EP8FIFOBCL, 0xE6B2) // EP8 FIFO total byte count L. XDATA_REG(SUDPTRH, 0xE6B3) // Setup data pointer high address byte. XDATA_REG(SUDPTRL, 0xE6B4) // Setup data pointer low address byte. XDATA_REG(SUDPTRCTL, 0xE6B5) // Setup data pointer auto mode. XDATA_REG(SETUPDAT[8], 0xE6B8) // 8 bytes of setup data. // GPIF. XDATA_REG(GPIFWFSELECT, 0xE6C0) // Waveform selector. XDATA_REG(GPIFIDLECS, 0xE6C1) // GPIF done, GPIF idle drive mode. XDATA_REG(GPIFIDLECTL, 0xE6C2) // Inactive bus, ctl states. XDATA_REG(GPIFCTLCFG, 0xE6C3) // CTL out pin drive. XDATA_REG(GPIFADRH, 0xE6C4) // GPIF address H. XDATA_REG(GPIFADRL, 0xE6C5) // GPIF address L. XDATA_REG(GPIFTCB3, 0xE6CE) // GPIF transaction count byte 3. XDATA_REG(GPIFTCB2, 0xE6CF) // GPIF transaction count byte 2. XDATA_REG(GPIFTCB1, 0xE6D0) // GPIF transaction count byte 1. XDATA_REG(GPIFTCB0, 0xE6D1) // GPIF transaction count byte 0. XDATA_REG(EP2GPIFFLGSEL, 0xE6D2) // EP2 GPIF flag select. XDATA_REG(EP2GPIFPFSTOP, 0xE6D3) // Stop GPIF EP2 transaction on prog flag. XDATA_REG(EP2GPIFTRIG, 0xE6D4) // EP2 FIFO trigger. XDATA_REG(EP4GPIFFLGSEL, 0xE6DA) // EP4 GPIF flag select. XDATA_REG(EP4GPIFPFSTOP, 0xE6DB) // Stop GPIF EP4 transaction on prog flag. XDATA_REG(EP4GPIFTRIG, 0xE6DC) // EP4 FIFO trigger. XDATA_REG(EP6GPIFFLGSEL, 0xE6E2) // EP6 GPIF Flag select. XDATA_REG(EP6GPIFPFSTOP, 0xE6E3) // Stop GPIF EP6 transaction on prog flag. XDATA_REG(EP6GPIFTRIG, 0xE6E4) // EP6 FIFO trigger. XDATA_REG(EP8GPIFFLGSEL, 0xE6EA) // EP8 GPIF flag select. XDATA_REG(EP8GPIFPFSTOP, 0xE6EB) // Stop GPIF EP8 transaction on prog flag. XDATA_REG(EP8GPIFTRIG, 0xE6EC) // EP8 FIFO trigger. XDATA_REG(XGPIFSGLDATH, 0xE6F0) // GPIF data H (16-bit mode only). XDATA_REG(XGPIFSGLDATLX, 0xE6F1) // Read/write GPIF data L & trigger transac. XDATA_REG(XGPIFSGLDATLNOX, 0xE6F2) // Read GPIF data L, no transac trigger. XDATA_REG(GPIFREADYCFG, 0xE6F3) // Internal RDY,Sync/Async, RDY5CFG. XDATA_REG(GPIFREADYSTAT, 0xE6F4) // RDY pin states. XDATA_REG(GPIFABORT, 0xE6F5) // Abort GPIF cycles. // UDMA. XDATA_REG(FLOWSTATE, 0xE6C6) // Defines GPIF flow state. XDATA_REG(FLOWLOGIC, 0xE6C7) // Defines flow/hold decision criteria. XDATA_REG(FLOWEQ0CTL, 0xE6C8) // CTL states during active flow state. XDATA_REG(FLOWEQ1CTL, 0xE6C9) // CTL states during hold flow state. XDATA_REG(FLOWHOLDOFF, 0xE6CA) // Holdoff configuration. XDATA_REG(FLOWSTB, 0xE6CB) // CTL/RDY signal to use as master data strobe. XDATA_REG(FLOWSTBEDGE, 0xE6CC) // Defines active master strobe edge. XDATA_REG(FLOWSTBHPERIOD, 0xE6CD) // Half period of output master strobe. XDATA_REG(GPIFHOLDAMOUNT, 0xE60C) // Data delay shift. XDATA_REG(UDMACRCH, 0xE67D) // CRC upper byte. XDATA_REG(UDMACRCL, 0xE67E) // CRC lower byte. XDATA_REG(UDMACRCQUAL, 0xE67F) // UDMA in only, host terminated use only. // Endpoint buffers. #define MAX_EP0_SIZE 64 #define MAX_EP1_SIZE 64 #define MAX_EP2468_SIZE 1024 XDATA_REG(EP0BUF[MAX_EP0_SIZE], 0xE740) // EP0 buffer (in or out). XDATA_REG(EP1OUTBUF[MAX_EP1_SIZE], 0xE780) // EP1 buffer (out only). XDATA_REG(EP1INBUF[MAX_EP1_SIZE], 0xE7C0) // EP1 buffer (in only). XDATA_REG(EP2FIFOBUF[MAX_EP2468_SIZE], 0xF000) // 512/1024-byte EP2 buffer (in or out). XDATA_REG(EP4FIFOBUF[MAX_EP2468_SIZE], 0xF400) // 512 byte EP4 buffer (in or out). XDATA_REG(EP6FIFOBUF[MAX_EP2468_SIZE], 0xF800) // 512/1024-byte EP6 buffer (in or out). XDATA_REG(EP8FIFOBUF[MAX_EP2468_SIZE], 0xFC00) // 512 byte EP8 buffer (in or out). // Error correction code (ECC) registers (FX2LP/FX1 only). XDATA_REG(ECCCFG, 0xE628) // ECC configuration. XDATA_REG(ECCRESET, 0xE629) // ECC reset. XDATA_REG(ECC1B0, 0xE62A) // ECC1 byte 0. XDATA_REG(ECC1B1, 0xE62B) // ECC1 byte 1. XDATA_REG(ECC1B2, 0xE62C) // ECC1 byte 2. XDATA_REG(ECC2B0, 0xE62D) // ECC2 byte 0. XDATA_REG(ECC2B1, 0xE62E) // ECC2 byte 1. XDATA_REG(ECC2B2, 0xE62F) // ECC2 byte 2. // Feature registers(FX2LP/FX1 only). XDATA_REG(GPCR2, 0xE50D) // Chip features. // // SFR registers. // SPEC_FUN_REG(IOA, 0x80) // Port A. SPEC_FUN_REG_BIT(PA0, 0x80, 0) SPEC_FUN_REG_BIT(PA1, 0x80, 1) SPEC_FUN_REG_BIT(PA2, 0x80, 2) SPEC_FUN_REG_BIT(PA3, 0x80, 3) SPEC_FUN_REG_BIT(PA4, 0x80, 4) SPEC_FUN_REG_BIT(PA5, 0x80, 5) SPEC_FUN_REG_BIT(PA6, 0x80, 6) SPEC_FUN_REG_BIT(PA7, 0x80, 7) SPEC_FUN_REG(SP, 0x81) // Stack pointer. SPEC_FUN_REG(DPL, 0x82) // Data pointer 0 L. SPEC_FUN_REG(DPH, 0x83) // Data pointer 0 H. SPEC_FUN_REG(DPL1, 0x84) // Data pointer 1 L. SPEC_FUN_REG(DPH1, 0x85) // Data pointer 1 L. SPEC_FUN_REG(DPS, 0x86) // Data pointer 0/1 select. SPEC_FUN_REG(PCON, 0x87) // Power control. SPEC_FUN_REG(TCON, 0x88) // Timer/counter control. SPEC_FUN_REG_BIT(IT0, 0x88, 0) SPEC_FUN_REG_BIT(IE0, 0x88, 1) SPEC_FUN_REG_BIT(IT1, 0x88, 2) SPEC_FUN_REG_BIT(IE1, 0x88, 3) SPEC_FUN_REG_BIT(TR0, 0x88, 4) SPEC_FUN_REG_BIT(TF0, 0x88, 5) SPEC_FUN_REG_BIT(TR1, 0x88, 6) SPEC_FUN_REG_BIT(TF1, 0x88, 7) SPEC_FUN_REG(TMOD, 0x89) // Timer/counter mode control. SPEC_FUN_REG(TL0, 0x8A) // Timer 0 reload L. SPEC_FUN_REG(TL1, 0x8B) // Timer 1 reload L. SPEC_FUN_REG(TH0, 0x8C) // Timer 0 reload H. SPEC_FUN_REG(TH1, 0x8D) // Timer 1 reload H. SPEC_FUN_REG(CKCON, 0x8E) // Clock control. SPEC_FUN_REG(IOB, 0x90) // Port B. SPEC_FUN_REG_BIT(PB0, 0x90, 0) SPEC_FUN_REG_BIT(PB1, 0x90, 1) SPEC_FUN_REG_BIT(PB2, 0x90, 2) SPEC_FUN_REG_BIT(PB3, 0x90, 3) SPEC_FUN_REG_BIT(PB4, 0x90, 4) SPEC_FUN_REG_BIT(PB5, 0x90, 5) SPEC_FUN_REG_BIT(PB6, 0x90, 6) SPEC_FUN_REG_BIT(PB7, 0x90, 7) SPEC_FUN_REG(EXIF, 0x91) // External interrupt flag. SPEC_FUN_REG(MPAGE, 0x92) // Upper address page of movx. SPEC_FUN_REG(SCON0, 0x98) // Serial port 0 control. SPEC_FUN_REG_BIT(RI, 0x98, 0) SPEC_FUN_REG_BIT(TI, 0x98, 1) SPEC_FUN_REG_BIT(RB8, 0x98, 2) SPEC_FUN_REG_BIT(TB8, 0x98, 3) SPEC_FUN_REG_BIT(REN, 0x98, 4) SPEC_FUN_REG_BIT(SM2, 0x98, 5) SPEC_FUN_REG_BIT(SM1, 0x98, 6) SPEC_FUN_REG_BIT(SM0, 0x98, 7) SPEC_FUN_REG(SBUF0, 0x99) // Serial port 0 data buffer. SPEC_FUN_REG(AUTOPTRH1, 0x9A) // Auto-pointer 1 address H. SPEC_FUN_REG(AUTOPTRL1, 0x9B) // Auto-pointer 1 address L. SPEC_FUN_REG(AUTOPTRH2, 0x9D) // Auto-pointer 2 address H. SPEC_FUN_REG(AUTOPTRL2, 0x9E) // Auto-pointer 2 address L. SPEC_FUN_REG(IOC, 0xA0) // Port C. SPEC_FUN_REG_BIT(PC0, 0xA0, 0) SPEC_FUN_REG_BIT(PC1, 0xA0, 1) SPEC_FUN_REG_BIT(PC2, 0xA0, 2) SPEC_FUN_REG_BIT(PC3, 0xA0, 3) SPEC_FUN_REG_BIT(PC4, 0xA0, 4) SPEC_FUN_REG_BIT(PC5, 0xA0, 5) SPEC_FUN_REG_BIT(PC6, 0xA0, 6) SPEC_FUN_REG_BIT(PC7, 0xA0, 7) SPEC_FUN_REG(INT2CLR, 0xA1) // Interrupt 2 clear. SPEC_FUN_REG(INT4CLR, 0xA2) // Interrupt 4 clear. SPEC_FUN_REG(IE, 0xA8) // Interrupt enable. SPEC_FUN_REG_BIT(EX0, 0xA8, 0) SPEC_FUN_REG_BIT(ET0, 0xA8, 1) SPEC_FUN_REG_BIT(EX1, 0xA8, 2) SPEC_FUN_REG_BIT(ET1, 0xA8, 3) SPEC_FUN_REG_BIT(ES0, 0xA8, 4) SPEC_FUN_REG_BIT(ET2, 0xA8, 5) SPEC_FUN_REG_BIT(ES1, 0xA8, 6) SPEC_FUN_REG_BIT(EA, 0xA8, 7) SPEC_FUN_REG(EP2468STAT, 0xAA) // Endpoint 2,4,6,8 status flags. SPEC_FUN_REG(EP24FIFOFLGS, 0xAB) // Endpoint 2,4 slave FIFO status flags. SPEC_FUN_REG(EP68FIFOFLGS, 0xAC) // Endpoint 6,8 slave FIFO status flags. SPEC_FUN_REG(AUTOPTRSETUP, 0xAF) // Auto-pointer 1,2 setup. SPEC_FUN_REG(IOD, 0xB0) // Port D. SPEC_FUN_REG_BIT(PD0, 0xB0, 0) SPEC_FUN_REG_BIT(PD1, 0xB0, 1) SPEC_FUN_REG_BIT(PD2, 0xB0, 2) SPEC_FUN_REG_BIT(PD3, 0xB0, 3) SPEC_FUN_REG_BIT(PD4, 0xB0, 4) SPEC_FUN_REG_BIT(PD5, 0xB0, 5) SPEC_FUN_REG_BIT(PD6, 0xB0, 6) SPEC_FUN_REG_BIT(PD7, 0xB0, 7) SPEC_FUN_REG(IOE, 0xB1) // Port E. SPEC_FUN_REG(OEA, 0xB2) // Port A out enable. SPEC_FUN_REG(OEB, 0xB3) // Port B out enable. SPEC_FUN_REG(OEC, 0xB4) // Port C out enable. SPEC_FUN_REG(OED, 0xB5) // Port D out enable. SPEC_FUN_REG(OEE, 0xB6) // Port E out enable. SPEC_FUN_REG(IP, 0xB8) // Interrupt prority. SPEC_FUN_REG_BIT(PX0, 0xB8, 0) SPEC_FUN_REG_BIT(PT0, 0xB8, 1) SPEC_FUN_REG_BIT(PX1, 0xB8, 2) SPEC_FUN_REG_BIT(PT1, 0xB8, 3) SPEC_FUN_REG_BIT(PS0, 0xB8, 4) SPEC_FUN_REG_BIT(PT2, 0xB8, 5) SPEC_FUN_REG_BIT(PS1, 0xB8, 6) SPEC_FUN_REG(EP01STAT, 0xBA) // Endpoint 0,1 status. SPEC_FUN_REG(GPIFTRIG, 0xBB) // Endpoint 2,4,6,8 GPIF slave FIFO trigger. SPEC_FUN_REG(GPIFSGLDATH, 0xBD) // GPIF data H. SPEC_FUN_REG(GPIFSGLDATLX, 0xBE) // GPIF data L with trigger. SPEC_FUN_REG(GPIFSGLDATLNOX, 0xBF) // GPIF data L without trigger. SPEC_FUN_REG(SCON1, 0xC0) // Serial port 1 control. SPEC_FUN_REG_BIT(RI1, 0xC0, 0) SPEC_FUN_REG_BIT(TI1, 0xC0, 1) SPEC_FUN_REG_BIT(RB81, 0xC0, 2) SPEC_FUN_REG_BIT(TB81, 0xC0, 3) SPEC_FUN_REG_BIT(REN1, 0xC0, 4) SPEC_FUN_REG_BIT(SM21, 0xC0, 5) SPEC_FUN_REG_BIT(SM11, 0xC0, 6) SPEC_FUN_REG_BIT(SM01, 0xC0, 7) SPEC_FUN_REG(SBUF1, 0xC1) // Serial port 1 data buffer. SPEC_FUN_REG(T2CON, 0xC8) // Timer/counter 2 control. SPEC_FUN_REG_BIT(CP_RL2, 0xC8, 0) SPEC_FUN_REG_BIT(C_T2, 0xC8, 1) SPEC_FUN_REG_BIT(TR2, 0xC8, 2) SPEC_FUN_REG_BIT(EXEN2, 0xC8, 3) SPEC_FUN_REG_BIT(TCLK, 0xC8, 4) SPEC_FUN_REG_BIT(RCLK, 0xC8, 5) SPEC_FUN_REG_BIT(EXF2, 0xC8, 6) SPEC_FUN_REG_BIT(TF2, 0xC8, 7) SPEC_FUN_REG(RCAP2L, 0xCA) // Capture for timer 2 auto-reload up-counter L. SPEC_FUN_REG(RCAP2H, 0xCB) // Capture for timer 2 auto-reload up-counter H. SPEC_FUN_REG(TL2, 0xCC) // Timer 2 reload L. SPEC_FUN_REG(TH2, 0xCD) // Timer 2 reload H. SPEC_FUN_REG(PSW, 0xD0) // Program status word. SPEC_FUN_REG_BIT(P, 0xD0, 0) SPEC_FUN_REG_BIT(FL, 0xD0, 1) SPEC_FUN_REG_BIT(OV, 0xD0, 2) SPEC_FUN_REG_BIT(RS0, 0xD0, 3) SPEC_FUN_REG_BIT(RS1, 0xD0, 4) SPEC_FUN_REG_BIT(F0, 0xD0, 5) SPEC_FUN_REG_BIT(AC, 0xD0, 6) SPEC_FUN_REG_BIT(CY, 0xD0, 7) SPEC_FUN_REG(EICON, 0xD8) // External interrupt control. SPEC_FUN_REG_BIT(INT6, 0xD8, 3) SPEC_FUN_REG_BIT(RESI, 0xD8, 4) SPEC_FUN_REG_BIT(ERESI, 0xD8, 5) SPEC_FUN_REG_BIT(SMOD1, 0xD8, 7) SPEC_FUN_REG(ACC, 0xE0) // Accumulator. SPEC_FUN_REG(EIE, 0xE8) // External interrupt enable. SPEC_FUN_REG_BIT(EUSB, 0xE8, 0) SPEC_FUN_REG_BIT(EI2C, 0xE8, 1) SPEC_FUN_REG_BIT(EIEX4, 0xE8, 2) SPEC_FUN_REG_BIT(EIEX5, 0xE8, 3) SPEC_FUN_REG_BIT(EIEX6, 0xE8, 4) SPEC_FUN_REG(B, 0xF0) // B SPEC_FUN_REG(EIP, 0xF8) // External interrupt priority control. SPEC_FUN_REG_BIT(PUSB, 0xF8, 0) SPEC_FUN_REG_BIT(PI2C, 0xF8, 1) SPEC_FUN_REG_BIT(EIPX4, 0xF8, 2) SPEC_FUN_REG_BIT(EIPX5, 0xF8, 3) SPEC_FUN_REG_BIT(EIPX6, 0xF8, 4) // // Register bit masks. // // CPU control & status register (CPUCS). enum cpucs_bits { bmPRTCSTB = bmBIT5, bmCLKSPD = bmBIT4 | bmBIT3, bmCLKSPD1 = bmBIT4, bmCLKSPD0 = bmBIT3, bmCLKINV = bmBIT2, bmCLKOE = bmBIT1, bm8051RES = bmBIT0 }; // Port A (PORTACFG). enum portacfg_bits { bmFLAGD = bmBIT7, bmINT1 = bmBIT1, bmINT0 = bmBIT0 }; // Port C (PORTCCFG). enum portccfg_bits { bmGPIFA7 = bmBIT7, bmGPIFA6 = bmBIT6, bmGPIFA5 = bmBIT5, bmGPIFA4 = bmBIT4, bmGPIFA3 = bmBIT3, bmGPIFA2 = bmBIT2, bmGPIFA1 = bmBIT1, bmGPIFA0 = bmBIT0 }; // Port E (PORTECFG). enum portecfg_bits { bmGPIFA8 = bmBIT7, bmT2EX = bmBIT6, bmINT6 = bmBIT5, bmRXD1OUT = bmBIT4, bmRXD0OUT = bmBIT3, bmT2OUT = bmBIT2, bmT1OUT = bmBIT1, bmT0OUT = bmBIT0 }; // I2C control & status register (I2CS). enum i2cs_bits { bmSTART = bmBIT7, bmSTOP = bmBIT6, bmLASTRD = bmBIT5, bmID = bmBIT4 | bmBIT3, bmBERR = bmBIT2, bmACK = bmBIT1, bmDONE = bmBIT0 }; // I2C control register (I2CTL). enum i2ctl_bits { bmSTOPIE = bmBIT1, bm400KHZ = bmBIT0 }; // Interrupt 2 (USB) autovector register (INT2IVEC). enum int2ivec_bits { bmIV4 = bmBIT6, bmIV3 = bmBIT5, bmIV2 = bmBIT4, bmIV1 = bmBIT3, bmIV0 = bmBIT2 }; // USB interrupt request & enable registers (USBIE/USBIRQ). enum usbieirq_bits { bmEP0ACK = bmBIT6, bmHSGRANT = bmBIT5, bmURES = bmBIT4, bmSUSP = bmBIT3, bmSUTOK = bmBIT2, bmSOF = bmBIT1, bmSUDAV = bmBIT0 }; // End point interrupt request & enable registers (EPIE/EPIRQ). enum epieirq_bits { bmEP8 = bmBIT7, bmEP6 = bmBIT6, bmEP4 = bmBIT5, bmEP2 = bmBIT4, bmEP1OUT = bmBIT3, bmEP1IN = bmBIT2, bmEP0OUT = bmBIT1, bmEP0IN = bmBIT0 }; // Breakpoint register (BREAKPT). enum breakpt_bits { bmBREAK = bmBIT3, bmBPPULSE = bmBIT2, bmBPEN = bmBIT1 }; // Interrupt 2 & 4 setup (INTSETUP). enum intsetup_bits { bmAV2EN = bmBIT3, bmINT4SRC = bmBIT1, bmAV4EN = bmBIT0 }; // USB control & status register (USBCS). enum usbcs_bits { bmHSM = bmBIT7, bmDISCON = bmBIT3, bmNOSYNSOF = bmBIT2, bmRENUM = bmBIT1, bmSIGRESUME = bmBIT0 }; // Wakeup control and status register (WAKEUPCS). enum wakeupcs_bits { bmWU2 = bmBIT7, bmWU = bmBIT6, bmWU2POL = bmBIT5, bmWUPOL = bmBIT4, bmDPEN = bmBIT2, bmWU2EN = bmBIT1, bmWUEN = bmBIT0 }; // End point 0 control & status register (EP0CS). enum ep0cs_bits { bmHSNAK = bmBIT7 }; // End point 0-1 control & status registers // (EP0CS/EP1OUTCS/EP1INCS). enum ep01cs_bits { bmEPBUSY = bmBIT1, bmEPSTALL = bmBIT0 }; // End point 2-8 Control & status registers // (EP2CS/EP4CS/EP6CS/EP8CS). enum ep2468cs_bits { MSK_EP2468CS_NPAK = bmBIT6 | bmBIT5 | bmBIT4, MSK_EP2468CS_EPFULL = bmBIT3, MSK_EP2468CS_EPEMPTY = bmBIT2 }; // End point status SFR bits (EP2468STAT). enum ep2468stat_bits { bmEP8FULL = bmBIT7, bmEP8EMPTY = bmBIT6, bmEP6FULL = bmBIT5, bmEP6EMPTY = bmBIT4, bmEP4FULL = bmBIT3, bmEP4EMPTY = bmBIT2, bmEP2FULL = bmBIT1, bmEP2EMPTY = bmBIT0 }; // End point 0,1 status bits (EP01STAT). enum ep01stat_bits { bmEP1INBSY = bmBIT2, bmEP1OUTBSY = bmBIT1, bmEP0BSY = bmBIT0 }; // Setup data pointer auto mode (SUDPTRCTL). enum sudptrctl_bits { bmSDPAUTO = bmBIT0 }; // End point data toggle control (TOGCTL). enum togctl_bits { bmQUERYTOGGLE = bmBIT7, bmSETTOGGLE = bmBIT6, bmRESETTOGGLE = bmBIT5, bmTOGCTLEPMASK = bmBIT3 | bmBIT2 | bmBIT1 | bmBIT0 }; // In bulk NAK enable and request bits (IBNIE/IBNIRQ). enum ibnieirq_bits { bmEP8IBN = bmBIT5, bmEP6IBN = bmBIT4, bmEP4IBN = bmBIT3, bmEP2IBN = bmBIT2, bmEP1IBN = bmBIT1, bmEP0IBN = bmBIT0 }; // Ping NAK enable and request bits (NAKIE/NAKIRQ). enum nakieirq_bits { bmEP8PING = bmBIT7, bmEP6PING = bmBIT6, bmEP4PING = bmBIT5, bmEP2PING = bmBIT4, bmEP1PING = bmBIT3, bmEP0PING = bmBIT2, bmIBN = bmBIT0 }; // Interface configuration bits (IFCONFIG). enum ifconfig_bits { bmIFCLKSRC = bmBIT7, bm3048MHZ = bmBIT6, bmIFCLKOE = bmBIT5, bmIFCLKPOL = bmBIT4, bmASYNC = bmBIT3, bmGSTATE = bmBIT2, bmIFCFG = bmBIT0 | bmBIT1 }; // IFCFG field of IFCONFIG register. enum ifcfg_bits { bmIFPORTS = 0, bmIFRESERVED = bmBIT0, bmIFGPIF = bmBIT1, bmIFSLAVEFIFO = bmBIT0 | bmBIT1 }; // End point 2,4,6,8 FIFO configuration bits // (EP2FIFOCFG,EP4FIFOCFG,EP6FIFOCFG,EP8FIFOCFG). enum ep2468fifocfg_bits { bmINFM = bmBIT6, bmOEP = bmBIT5, bmAUTOOUT = bmBIT4, bmAUTOIN = bmBIT3, bmZEROLENIN = bmBIT2, bmWORDWIDE = bmBIT0 }; // Chip revision control bits (REVCTL). enum revctl_bits { bmNOAUTOARM = bmBIT1, bmSKIPCOMMIT = bmBIT0 }; // Fifo reset bits (FIFORESET). enum fiforeset_bits { bmNAKALL = bmBIT7, bmFREP3 = bmBIT3, bmFREP2 = bmBIT2, bmFREP1 = bmBIT1, bmFREP0 = bmBIT0 }; // Chip feature register (GPCR2). enum gpcr2_bits { bmFULLSPEEDONLY = bmBIT4 }; // Clock control register (CKCON). // Note: a RevE errata states that stretch must=0 // to set OUTxBC. enum ckcon_bits { bmT2M = bmBIT5, bmT1M = bmBIT4, bmT0M = bmBIT3, bmSTRETCH = bmBIT0 | bmBIT1 | bmBIT2 }; enum data_mem_stretch { bmFW_STRETCH1 = 0, // Movx: 2 cycles, R/W strobe: 2 cycles... bmFW_STRETCH2 = 1, // Movx: 3 cycles, R/W strobe: 4 cycles... bmFW_STRETCH3 = 2, // Movx: 4 cycles, R/W strobe: 8 cycles... bmFW_STRETCH4 = 3, // Movx: 5 cycles, R/W strobe: 12 cycles... bmFW_STRETCH5 = 4, // Movx: 6 cycles, R/W strobe: 16 cycles... bmFW_STRETCH6 = 5, // Movx: 7 cycles, R/W strobe: 20 cycles... bmFW_STRETCH7 = 6, // Movx: 8 cycles, R/W strobe: 24 cycles... bmFW_STRETCH8 = 7 // Movx: 9 cycles, R/W strobe: 28 cycles... }; // External interrupt flags (EXIF). enum exif_bits { bmIE5 = bmBIT7, bmIE4 = bmBIT6, bmI2CINT = bmBIT5, bmUSBNT = bmBIT4 }; // External interrupt control (EICON). enum eicon_bits { bmSMOD1 = bmBIT7, bmERESI = bmBIT5, bmRESI = bmBIT4, //bmINT6 = bmBIT3 }; // Power control (PCON). enum pcon_bits { bmSMOD0 = bmBIT7, bmIDLE = bmBIT0 }; // Autopointer 1 & 2 setup (AUTOPTRSETUP). enum autoptrsetup_bits { bmAPTR2INC = bmBIT2, bmAPTR1INC = bmBIT1, bmAPTREN = bmBIT0 }; #ifdef __cplusplus } #endif #endif // FX2_REGS_H qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/core.c0000644000175100001660000000622714776170045023301 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "core.h" #include "regs.h" enum cpu_freq_clk { CPU_CLK_12M = 0, CPU_CLK_24M, CPU_CLK_48M }; #define cpu_freq_clk_get() \ ((CPUCS & bmCLKSPD) >> 3) #define cpu_freq_clk_set(freq_clk) \ CPUCS = (CPUCS & ~bmCLKSPD) | (freq_clk << 3) void core_init(void) { // Set CPU clock to 48MHz. cpu_freq_clk_set(CPU_CLK_48M); sync_delay(); // Set stretch to 0. CKCON = ((CKCON & (~bmSTRETCH)) | bmFW_STRETCH1); sync_delay(); // Clear breakpoint register. BREAKPT = 0; sync_delay(); // Set all 8051 interrupts to low priority IP = 0; sync_delay(); // Clear interrupt enable bits. EIE = 0; sync_delay(); // Clear all external interrupt flags. EXIF = 0; sync_delay(); } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/usb.c0000644000175100001660000000751714776170045023145 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "core.h" #include "hid.h" #include "usb.h" void usb_init(void) { // Disable all USB interrupts. USBIE = 0; sync_delay(); // Disable all end point interrupts. EPIE = 0; sync_delay(); // Disable all end point ping-nak interrupts. NAKIE = 0; sync_delay(); // Disable all USB error interrupts. USBERRIE = 0; sync_delay(); // Disable USB && GPIF autovectoring. INTSETUP = 0; sync_delay(); // Clear USB interrupt requests. USBIRQ = bmSUDAV | bmSOF | bmSUTOK | bmSUSP | bmURES | bmHSGRANT | bmEP0ACK; sync_delay(); // Clear end point interrupt requests. EPIRQ = bmEP0IN | bmEP0OUT | bmEP1IN | bmEP1OUT | bmEP2 | bmEP4 | bmEP6 | bmEP8; sync_delay(); // Set USB interrupt to high priority. PUSB = 1; sync_delay(); // Enable USB interrupts. EUSB = 1; sync_delay(); // As we use SOFs to detect disconnect we have // to disable SOF synthesizing. USBCS |= bmNOSYNSOF; sync_delay(); hid_init(); // Disable FX2-internal enumeration support. USBCS |= bmRENUM; sync_delay(); } void usb_task(void) { if (USBIRQ & bmSUDAV) { USBIRQ = bmSUDAV; hid_ep0_setup_task(); } if (USBIRQ & bmEP0ACK) { USBIRQ = bmEP0ACK; } if (USBIRQ & bmURES) { USBIRQ = bmURES; } if (USBIRQ & bmSUSP) { USBIRQ = bmSUSP; } hid_ep1_task(); } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/gpio.h0000644000175100001660000000512014776170045023303 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_GPIO_H #define FX2_GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init(void); void gpio_task(void); #ifdef __cplusplus } #endif #endif // FX2_GPIO_H qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/main.c0000644000175100001660000000563114776170045023273 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // Allocate all registers once here (only for C51 compiler). #define DEFINE_REGS #include "regs.h" #include "core.h" #include "gpio.h" #include "usb.h" static void hw_init(void) { usb_disconnect(); code_all_irq_disable(); core_init(); gpio_init(); usb_init(); usb_connect(); code_all_irq_enable(); } static void hw_loop_exec(void) { while (TRUE) { gpio_task(); usb_task(); } } int main(void) { hw_init(); hw_loop_exec(); return 0; } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/usb.h0000644000175100001660000001567214776170045023153 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_USB_H #define FX2_USB_H #include "regs.h" #ifdef __cplusplus extern "C" { #endif enum usb_setup_bmreq_bits { bmSETUP_DIR = bmBIT7, bmSETUP_TYPE = bmBIT5 | bmBIT6, bmSETUP_RECIPIENT = bmBIT0 | bmBIT1 | bmBIT2 | bmBIT3 | bmBIT4 }; // Setup request direction. enum usb_setup_req_direction_bits { bmSETUP_TO_DEVICE = 0, // From host to sevice direction. bmSETUP_TO_HOST = bmBIT7 // From device to host direction. }; // Setup request type. enum usb_setup_req_type_bits { bmSETUP_STANDARD = 0, // Standard request. bmSETUP_CLASS = bmBIT5, // Class request. bmSETUP_VENDOR = bmBIT6, // Vendor request. }; // Setup request recipient. enum usb_setup_req_recipient_bits { bmSETUP_DEVICE = 0, // Device recipient. bmSETUP_IFACE = bmBIT0, // Interface recipient. bmSETUP_EP = bmBIT1, // End point recipient. bmSETUP_OTHER = bmBIT0 | bmBIT1 // Other recipient. }; // Setup request code. enum usb_setup_req_code { USB_SETUP_GET_STATUS = 0x00, // Get status code. USB_SETUP_CLEAR_FEATURE = 0x01, // Clear feature code. USB_SETUP_RESERVED1 = 0x02, // Reserved code. USB_SETUP_SET_FEATURE = 0x03, // Set feature code. USB_SETUP_RESERVED2 = 0x04, // Reserved code. USB_SETUP_SET_ADDRESS = 0x05, // Set address code. USB_SETUP_GET_DESCRIPTOR = 0x06, // Get descriptor code. USB_SETUP_SET_DESCRIPTOR = 0x07, // Set descriptor code. USB_SETUP_GET_CONFIGURATION = 0x08, // Get configuration code. USB_SETUP_SET_CONFIGURATION = 0x09, // Set configuration code. USB_SETUP_GET_INTERFACE = 0x0A, // Get interface code. USB_SETUP_SET_INTERFACE = 0x0B, // Set interface code. USB_SETUP_SYNC_FRAME = 0x0C, // Sync frame code. USB_SETUP_ANCHOR_LOAD = 0xA0 // Anchor load code. }; // Standard status responses. enum usb_setup_status_code { USB_STATUS_SELF_POWERED = 0x01, USB_STATUS_REMOTE_WAKEUP = 0x02 }; // Standard feature selectors. enum usb_setup_feature_selector { USB_FEATURE_STALL = 0x00, USB_FEATURE_REMOTE_WAKEUP = 0x01, USB_FEATRUE_TEST_MODE = 0x02 }; // Get descriptor codes. enum usb_setup_get_descriptor_code { USB_DESC_DEVICE = 0x01, // Device descriptor. USB_DESC_CONF = 0x02, // Configuration descriptor. USB_DESC_STRING = 0x03, // String descriptor. USB_DESC_INTERFACE = 0x04, // Interface descriptor. USB_DESC_ENDPOINT = 0x05, // End point descriptor. USB_DESC_DEVICE_QUAL = 0x06, // Device qualifier descriptor. USB_DESC_OTHER_SPEED_CONF = 0x07, // Other configuration descriptor. USB_DESC_INTERFACE_POWER = 0x08, // Interface power descriptor. USB_DESC_OTG = 0x09, // OTG descriptor. USB_DESC_DEBUG = 0x0A, // Debug descriptor. USB_DESC_INTERFACE_ASSOC = 0x0B, // Interface association descriptor. USB_DESC_HID = 0x21, // Get HID descriptor. USB_DESC_REPORT = 0x22 // Get report descriptor. }; // End point configuration (EP1INCFG/EP1OUTCFG/EP2/EP4/EP6/EP8). enum epcfg_bits { bmEP_VALID = bmBIT7, bmEP_DIR = bmBIT6, // Only for EP2-EP8! bmEP_TYPE = bmBIT5 | bmBIT4, bmEP_SIZE = bmBIT3, // Only for EP2-EP8! bmEP_BUF = bmBIT1 | bmBIT0 // Only for EP2-EP8! }; enum ep_valid_bits { bmEP_DISABLE = 0, bmEP_ENABLE = bmBIT7 }; // Only for EP2-EP8! enum ep_direction { bmEP_OUT = 0, bmEP_IN = bmBIT6 }; enum ep_type { bmEP_ISO = bmBIT4, // Only for EP2-EP8! bmEP_BULK = bmBIT5, // Default value. bmEP_INT = bmBIT4 | bmBIT5 }; // Only for EP2-EP8! enum ep_size { EP_512 = 0, EP_1024 = bmBIT3 // Except EP4/EP8. }; // Only for EP2-EP8! enum ep_buf { EP_QUAD = 0, EP_DOUBLE = bmBIT1, // Default value. EP_TRIPLE = bmBIT0 | bmBIT1 }; struct ep0_buf { BYTE *dat; WORD len; }; #define usb_disconnect() (USBCS |= bmDISCON) #define usb_connect() (USBCS &= ~bmDISCON) #define usb_is_high_speed() \ (USBCS & bmHSM) #define usp_ep_reset_toggle(ep) \ TOGCTL = (((ep & 0x80) >> 3) + (ep & 0x0F)); \ TOGCTL |= bmRESETTOGGLE #define usb_ep0_stall() \ EP0CS |= bmEPSTALL #define usb_ep0_hsnack() \ EP0CS |= bmHSNAK #define usb_word_msb_get(word) \ (BYTE)(((WORD)(word) >> 8) & 0xFF) #define usb_word_lsb_get(word) \ (BYTE)((WORD)(word) & 0xFF) #define usb_word_swap(x) \ ((((WORD)((x) & 0x00FF)) << 8) | \ (((WORD)((x) & 0xFF00)) >> 8)) #define usb_dword_swap(x) \ ((((DWORD)((x) & 0x000000FFul)) << 24) | \ (((DWORD)((x) & 0x0000FF00ul)) << 8) | \ (((DWORD)((x) & 0x00FF0000ul)) >> 8) | \ (((DWORD)((x) & 0xFF000000ul)) >> 24)) void usb_init(void); void usb_task(void); #ifdef __cplusplus } #endif #endif // FX2_USB_H qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/hidep0.c0000644000175100001660000002142514776170045023517 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hid.h" #include "core.h" #include "usb.h" static BOOL g_rwuen = FALSE; static BOOL g_selfpwr = FALSE; static void ep0_ep1in_reset(void) { EP1INCS &= ~bmEPBUSY; sync_delay(); usp_ep_reset_toggle(HID_EP_IN); sync_delay(); } // Get status handle. static BYTE *ep_address_get(BYTE ep) { const BYTE ep_num = ep & ~bmSETUP_DIR; switch (ep_num) { case 0: return (BYTE *)&EP0CS; case 1: return (ep & bmSETUP_DIR) ? (BYTE *)&EP1INCS : (BYTE *)&EP1OUTCS; default: break; } return NULL; } static BOOL ep0_dev_status_get(void) { BYTE status = 0; if (g_selfpwr) status |= USB_STATUS_SELF_POWERED; if (g_rwuen) status |= USB_STATUS_REMOTE_WAKEUP; EP0BUF[0] = status; EP0BUF[1] = 0; EP0BCH = 0; EP0BCL = 2; return TRUE; } static BOOL ep0_iface_status_get(void) { EP0BUF[0] = 0; EP0BUF[1] = 0; EP0BCH = 0; EP0BCL = 2; return TRUE; } static BOOL ep0_ep_status_get(void) { const volatile BYTE XDATA *pep = (BYTE XDATA *)ep_address_get(SETUPDAT[4]); if (pep) { EP0BUF[0] = *pep & bmEPSTALL ? 1 : 0; EP0BUF[1] = 0; EP0BCH = 0; EP0BCL = 2; return TRUE; } return FALSE; } static BOOL ep0_get_status_proc(void) { if ((SETUPDAT[0] & bmSETUP_TO_HOST) == 0) return FALSE; switch (SETUPDAT[0] & bmSETUP_RECIPIENT) { case bmSETUP_DEVICE: return ep0_dev_status_get(); case bmSETUP_IFACE: return ep0_iface_status_get(); case bmSETUP_EP: return ep0_ep_status_get(); default: break; } return FALSE; } // Clear feature handle. static BOOL ep0_dev_feature_clear(void) { if (SETUPDAT[2] == USB_FEATURE_REMOTE_WAKEUP) { g_rwuen = FALSE; return TRUE; } return FALSE; } static BOOL ep0_ep_feature_clear(void) { if (SETUPDAT[2] == USB_FEATURE_STALL) { volatile BYTE XDATA *pep = (BYTE XDATA *)ep_address_get(SETUPDAT[4]); if (!pep) return FALSE; *pep &= ~bmEPSTALL; return TRUE; } return FALSE; } static BOOL ep0_clear_feature_proc(void) { switch (SETUPDAT[0] & bmSETUP_RECIPIENT) { case bmSETUP_DEVICE: return ep0_dev_feature_clear(); case bmSETUP_EP: return ep0_ep_feature_clear(); default: break; } return FALSE; } // Set feature handle. static BOOL ep0_dev_feature_set(void) { switch (SETUPDAT[2]) { case USB_FEATURE_REMOTE_WAKEUP: g_rwuen = TRUE; return TRUE; case USB_FEATRUE_TEST_MODE: // This is "test mode", just return the handshake. return TRUE; default: break; } return FALSE; } static BOOL ep0_ep_feature_set(void) { if (SETUPDAT[2] == USB_FEATURE_STALL) { volatile BYTE XDATA *pep = (BYTE XDATA *)ep_address_get(SETUPDAT[4]); if (!pep) return FALSE; *pep |= bmEPSTALL; usp_ep_reset_toggle(SETUPDAT[4]); return TRUE; } return FALSE; } static BOOL ep0_set_feature_proc(void) { switch (SETUPDAT[0] & bmSETUP_RECIPIENT) { case bmSETUP_DEVICE: return ep0_dev_feature_set(); case bmSETUP_EP: return ep0_ep_feature_set(); default: break; } return FALSE; } // Get descriptor handle. static BOOL ep0_std_descriptor_proc(void) { const BYTE XDATA *pdesc = (BYTE XDATA *)hid_ep0_std_desc_get(); if (pdesc) { SUDPTRH = usb_word_msb_get(pdesc); SUDPTRL = usb_word_lsb_get(pdesc); return TRUE; } return FALSE; } static BOOL ep0_report_descriptor_proc(void) { WORD i = 0; WORD length = 0; const BYTE XDATA *pdesc = (BYTE XDATA *)hid_ep0_report_desc_get(&length); if (pdesc) { AUTOPTRH1 = usb_word_msb_get(pdesc); AUTOPTRL1 = usb_word_lsb_get(pdesc); for (i = 0; i < length; ++i) EP0BUF[i] = XAUTODAT1; EP0BCH = usb_word_msb_get(length); EP0BCL = usb_word_lsb_get(length); return TRUE; } return FALSE; } static BOOL ep0_get_descriptor_proc(void) { switch (SETUPDAT[3]) { case USB_DESC_DEVICE: case USB_DESC_CONF: case USB_DESC_STRING: case USB_DESC_DEVICE_QUAL: case USB_DESC_OTHER_SPEED_CONF: case USB_DESC_HID: return ep0_std_descriptor_proc(); case USB_DESC_REPORT: return ep0_report_descriptor_proc(); } return FALSE; } // Get configuration handle. static BOOL ep0_get_config_proc(void) { // We only support configuration 1. EP0BUF[0] = HID_CONFIG_NUMBER; EP0BCH = 0; EP0BCL = 1; return TRUE; } // Set configuration handle. static BOOL ep0_set_config_proc(void) { // We only support configuration 1. if (SETUPDAT[2] != HID_CONFIG_NUMBER) return FALSE; return TRUE; } // Get interface handle. static BOOL ep0_get_iface_proc(void) { if (SETUPDAT[4] != HID_IFACE_NUMBER) return FALSE; EP0BUF[0] = HID_ALT_IFACE_NUMBER; EP0BCH = 0; EP0BCL = 1; return TRUE; } // Set interface handle. static BOOL ep0_set_iface_proc(void) { if (SETUPDAT[4] != HID_IFACE_NUMBER) return FALSE; if (SETUPDAT[2] != HID_ALT_IFACE_NUMBER) return FALSE; ep0_ep1in_reset(); return TRUE; } static BOOL ep0_std_proc(void) { switch (SETUPDAT[1]) { case USB_SETUP_GET_STATUS: return ep0_get_status_proc(); case USB_SETUP_CLEAR_FEATURE: return ep0_clear_feature_proc(); case USB_SETUP_SET_FEATURE: return ep0_set_feature_proc(); case USB_SETUP_SET_ADDRESS: // Handles automatically by FX2. return TRUE; case USB_SETUP_GET_DESCRIPTOR: return ep0_get_descriptor_proc(); case USB_SETUP_GET_CONFIGURATION: return ep0_get_config_proc(); case USB_SETUP_SET_CONFIGURATION: return ep0_set_config_proc(); case USB_SETUP_GET_INTERFACE: return ep0_get_iface_proc(); case USB_SETUP_SET_INTERFACE: return ep0_set_iface_proc(); default: break; } return FALSE; } static BOOL ep0_setup(void) { switch (SETUPDAT[0] & bmSETUP_TYPE) { case bmSETUP_STANDARD: return ep0_std_proc(); default: break; } return FALSE; } void hid_ep0_setup_task(void) { if (!ep0_setup()) usb_ep0_stall(); usb_ep0_hsnack(); } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/gpio.c0000644000175100001660000001126714776170045023307 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "core.h" #include "gpio.h" #include "hid.h" #include "regs.h" static WORD g_counter = 0; // We use this empirical value to make a GPIO polling // every ~10 msec (rough). It is a simplest way, because // instead we need to use a timers with interrupts callbacks. enum { POLLING_COUNTER = 580 }; // Pins on the port A. enum gpio_pins { GPIO_CLK_PIN = bmBIT0, GPIO_DATA1_PIN = bmBIT2, GPIO_DATA2_PIN = bmBIT4, GPIO_LATCH_PIN = bmBIT6, }; static struct { const BYTE pin; BYTE buttons; } g_reports[HID_REPORTS_COUNT] = { {GPIO_DATA1_PIN, 0}, {GPIO_DATA2_PIN, 0} }; // Pulse width around ~1 usec. static void gpio_latch_pulse(void) { IOA |= GPIO_LATCH_PIN; sync_delay(); sync_delay(); sync_delay(); IOA &= ~GPIO_LATCH_PIN; sync_delay(); } // Pulse width around ~1 usec. static void gpio_clk_pulse(void) { IOA |= GPIO_CLK_PIN; sync_delay(); sync_delay(); sync_delay(); IOA &= ~GPIO_CLK_PIN; sync_delay(); } static void gpio_reports_clean(void) { BYTE index = 0; for (index = 0; index < HID_REPORTS_COUNT; ++index) g_reports[index].buttons = 0; } static void gpio_reports_send(void) { BYTE index = 0; for (index = 0; index < HID_REPORTS_COUNT; ++index) hid_ep1_report_update(index, g_reports[index].buttons); } static void gpio_poll(void) { BYTE pos = 0; // Cleanup reports. gpio_reports_clean(); // Send latch pulse. gpio_latch_pulse(); for (pos = 0; pos < HID_REPORT_BITS_COUNT; ++pos) { // TODO: Add some nops here? BYTE index = 0; for (index = 0; index < HID_REPORTS_COUNT; ++index) { // Low state means that a button is pressed. const BOOL v = (IOA & g_reports[index].pin) ? 0 : 1; g_reports[index].buttons |= (v << pos); } // Send clock pulse. gpio_clk_pulse(); } gpio_reports_send(); } void gpio_init(void) { // Set interface to ports. IFCONFIG = (IFCONFIG & (~bmIFCFG)) | bmIFPORTS; sync_delay(); // Initialize the CLK and LATCH pins as output. OEA = GPIO_CLK_PIN | GPIO_LATCH_PIN; sync_delay(); } void gpio_task(void) { if (g_counter < POLLING_COUNTER) { ++g_counter; } else { g_counter = 0; gpio_poll(); } } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/hiddesc.c0000644000175100001660000002756514776170045023764 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hid.h" enum usb_bcd_version { USB_SPEC_BCD_VERSION = 0x0200, USB_DEVICE_BCD_VERSION = 0x1234, USB_HID_BCD_VERSION = 0x0111 }; enum usb_ids { USB_DEVICE_VID = 0xFFFF, USB_DEVICE_PID = 0xFFFF }; enum usb_lang_id { USB_LANG_ID = 0x0409 }; enum usb_descriptor_string_index { USB_DESC_LANGID_STRING_INDEX = 0, USB_DESC_MFG_STRING_INDEX, USB_DESC_PRODUCT_STRING_INDEX, USB_DESC_SERIAL_STRING_INDEX }; enum usb_descr_length { // Standard length. USB_DESC_DEVICE_LEN = 18, USB_DESC_DEVICE_QUAL_LEN = 10, USB_DESC_CONF_LEN = 9, USB_DESC_OTHER_SPEED_CONF_LEN = 9, USB_DESC_INTERFACE_LEN = 9, USB_DESC_HID_LEN = 9, USB_DESCR_HID_REP_LEN = 56, USB_DESC_ENDPOINT_LEN = 7, // Total length. USB_DESC_DEVICE_TOTAL_LEN = USB_DESC_DEVICE_LEN, USB_DESC_DEVICE_QUAL_TOTAL_LEN = USB_DESC_DEVICE_QUAL_LEN, USB_DESC_CONF_TOTAL_LEN = USB_DESC_CONF_LEN + USB_DESC_INTERFACE_LEN + USB_DESC_HID_LEN + USB_DESC_ENDPOINT_LEN, USB_DESC_OTHER_SPEED_CONF_TOTAL_LEN = USB_DESC_OTHER_SPEED_CONF_LEN + USB_DESC_INTERFACE_LEN, }; enum usb_descr_attributes { // Attributes (b7 - buspwr, b6 - selfpwr, b5 - rwu). USB_DESC_ATTRIBUTES = 0xA0, // 100 mA (div 2). USB_DESC_POWER_CONSUMPTION = 50 }; enum usb_descr_numbers { USB_DESC_CONFIG_COUNT = 1 }; static const BYTE CODE g_hid_report_desc[USB_DESCR_HID_REP_LEN] = { // Pad #1 configuration. 0x05, 0x01, // Usage page (Generic Desktop). 0x09, 0x05, // Usage (Game Pad). 0xa1, 0x01, // Collection (Application). 0xa1, 0x00, // Collection (Physical). 0x85, HID_REPORT_ID_GAMEPAD1, // Report id (1). 0x05, 0x09, // Usage page (Button). 0x19, 0x01, // Usage minimum (Button 1). 0x29, 0x08, // Usage maximum (Button 8). 0x15, 0x00, // Logical minimum (0). 0x25, 0x01, // Logical maximum (1). 0x95, HID_REPORT_BITS_COUNT, // Report count (8). 0x75, 0x01, // Report size (1). 0x81, 0x02, // Input (Data,Var,Abs). 0xc0, // End collection. 0xc0, // End collection. // Pad #2 configuration. 0x05, 0x01, // Usage page (Generic Desktop). 0x09, 0x05, // Usage (Game Pad). 0xa1, 0x01, // Collection (Application). 0xa1, 0x00, // Collection (Physical). 0x85, HID_REPORT_ID_GAMEPAD2, // Report id (2). 0x05, 0x09, // Usage page (Button). 0x19, 0x01, // Usage minimum (Button 1). 0x29, 0x08, // Usage maximum (Button 8). 0x15, 0x00, // Logical minimum (0). 0x25, 0x01, // Logical maximum (1). 0x95, HID_REPORT_BITS_COUNT, // Report count (8). 0x75, 0x01, // Report size (1). 0x81, 0x02, // Input (Data,Var,Abs). 0xc0, // End collection 0xc0 // End collection. }; static const BYTE CODE g_device_desc[USB_DESC_DEVICE_TOTAL_LEN] = { USB_DESC_DEVICE_LEN, // Descriptor length. USB_DESC_DEVICE, // Descriptor type. usb_word_lsb_get(USB_SPEC_BCD_VERSION), // USB BCD version, lo. usb_word_msb_get(USB_SPEC_BCD_VERSION), // USB BCD version, hi. 0x00, // Device class. 0x00, // Device sub-class. 0x00, // Device protocol. MAX_EP0_SIZE, // Maximum packet size (ep0 size). usb_word_lsb_get(USB_DEVICE_VID), // Vendor ID, lo. usb_word_msb_get(USB_DEVICE_VID), // Vendor ID, hi. usb_word_lsb_get(USB_DEVICE_PID), // Product ID, lo. usb_word_msb_get(USB_DEVICE_PID), // Product ID, hi. usb_word_lsb_get(USB_DEVICE_BCD_VERSION), // Device BCD version, lo. usb_word_msb_get(USB_DEVICE_BCD_VERSION), // Device BCD version, hi. USB_DESC_MFG_STRING_INDEX, USB_DESC_PRODUCT_STRING_INDEX, USB_DESC_SERIAL_STRING_INDEX, USB_DESC_CONFIG_COUNT // Configurations count. }; static const BYTE CODE g_device_qual_desc[USB_DESC_DEVICE_QUAL_TOTAL_LEN] = { USB_DESC_DEVICE_QUAL_LEN, // Descriptor length. USB_DESC_DEVICE_QUAL, // Descriptor type. usb_word_lsb_get(USB_SPEC_BCD_VERSION), // USB BCD version, lo. usb_word_msb_get(USB_SPEC_BCD_VERSION), // USB BCD version, hi. 0x00, // Device class. 0x00, // Device sub-class. 0x00, // Device protocol. MAX_EP0_SIZE, // Maximum packet size (ep0 size). USB_DESC_CONFIG_COUNT, // Configurations count. 0x00 // Reserved. }; static const BYTE CODE g_config_desc[USB_DESC_CONF_TOTAL_LEN] = { USB_DESC_CONF_LEN, // Descriptor length. USB_DESC_CONF, // Descriptor type. usb_word_lsb_get(USB_DESC_CONF_TOTAL_LEN), // Total length, lo. usb_word_msb_get(USB_DESC_CONF_TOTAL_LEN), // Total length, hi. 0x01, // Interfaces count. HID_CONFIG_NUMBER, // Configuration number. 0x00, // Configuration string index. USB_DESC_ATTRIBUTES, // Attributes. USB_DESC_POWER_CONSUMPTION, // Power consumption. // Interface descriptor. USB_DESC_INTERFACE_LEN, // Descriptor length. USB_DESC_INTERFACE, // Descriptor type. HID_IFACE_NUMBER, // Zero-based index of this interfacce. HID_ALT_IFACE_NUMBER, // Alternate setting. 0x01, // End points count (ep1 in). 0x03, // Class code (HID). 0x00, // Subclass code (boot). 0x00, // Protocol code (none). 0x00, // Interface string descriptor index. // HID descriptor. USB_DESC_HID_LEN, // Descriptor length. USB_DESC_HID, // Descriptor type. usb_word_lsb_get(USB_HID_BCD_VERSION), // HID class BCD version, lo. usb_word_msb_get(USB_HID_BCD_VERSION), // HID class BCD version, hi. 0x00, // Country code (HW country code). 0x01, // Number of HID class descriptors to follow. USB_DESC_REPORT, // Repord descriptor type (HID). usb_word_lsb_get(USB_DESCR_HID_REP_LEN), // Report descriptor total length, lo. usb_word_msb_get(USB_DESCR_HID_REP_LEN), // Report descriptor total length, hi. // End point descriptor. USB_DESC_ENDPOINT_LEN, // Descriptor length. USB_DESC_ENDPOINT, // Descriptor type. HID_EP_IN, // End point address (ep1 in). 0x03, // End point type (interrupt). usb_word_lsb_get(MAX_EP1_SIZE), // Maximum packet size, lo (ep1 size). usb_word_msb_get(MAX_EP1_SIZE), // Maximum packet size, hi (ep1 size). 0x01 // Polling interval (1 ms). }; static const BYTE CODE g_other_config_desc[USB_DESC_OTHER_SPEED_CONF_TOTAL_LEN] = { USB_DESC_OTHER_SPEED_CONF_LEN, // Descriptor length. USB_DESC_OTHER_SPEED_CONF, // Descriptor type. usb_word_lsb_get(USB_DESC_OTHER_SPEED_CONF_TOTAL_LEN), // Total length, lo. usb_word_msb_get(USB_DESC_OTHER_SPEED_CONF_TOTAL_LEN), // Total length, hi. 0x01, // Interfaces number. 0x01, // Configuration number. 0x00, // Configuration string index. USB_DESC_ATTRIBUTES, // Attributes. USB_DESC_POWER_CONSUMPTION, // Power consumption. // Interface descriptor. USB_DESC_INTERFACE_LEN, // Descriptor length. USB_DESC_INTERFACE, // Descriptor type. 0x00, // Zero-based index of this interfacce. 0x00, // Alternate setting. 0x00, // End points number (only ep0). 0x00, // Class code. 0x00, // Subclass code.USB_DESC_OTHER_SPEED_CONFIGURATION 0x00, // Protocol code. 0x00 // Interface string descriptor index. }; static const BYTE CODE g_lang_id_desc[] = { 0x04, // Descriptor length. USB_DESC_STRING, // Descriptor type. usb_word_lsb_get(USB_LANG_ID), // Language id, lo. usb_word_msb_get(USB_LANG_ID) // Language id, hi. }; static const BYTE CODE g_manuf_str_desc[] = { 0x18, // Descriptor length. USB_DESC_STRING, // Descriptor type. // Unicode string: 'Q', 0, 'B', 0, 'S', 0, ' ', 0, 'e', 0, 'x', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0 }; static const BYTE CODE g_product_str_desc[] = { 0x1A, // Descriptor length. USB_DESC_STRING, // Descriptor type. // Unicode string: 'N', 0, 'E', 0, 'S', 0, ' ', 0, 'G', 0, 'a', 0, 'm', 0, 'e', 0, 'P', 0, 'a', 0, 'd', 0, 's', 0 }; static const BYTE CODE g_serialno_str_desc[] = { 0x1A, // Descriptor length. USB_DESC_STRING, // Descriptor type. // Unicode string: '0', 0 ,'1', 0, '0', 0, '2', 0, '0', 0, '3', 0, '0', 0, '4', 0, '0', 0, '5', 0, '0', 0, '6', 0 }; static const BYTE CODE *ep0_string_desc_get(void) { switch (SETUPDAT[2]) { case USB_DESC_LANGID_STRING_INDEX: return g_lang_id_desc; case USB_DESC_MFG_STRING_INDEX: return g_manuf_str_desc; case USB_DESC_PRODUCT_STRING_INDEX: return g_product_str_desc; case USB_DESC_SERIAL_STRING_INDEX: return g_serialno_str_desc; default: break; } return NULL; } static const BYTE CODE *ep0_config_desc_get(BOOL other) { if (!other) { if (SETUPDAT[2] == 0) { return usb_is_high_speed() ? g_config_desc : g_other_config_desc; } } else { return usb_is_high_speed() ? g_other_config_desc : g_config_desc; } return NULL; } const BYTE CODE *hid_ep0_std_desc_get(void) { switch (SETUPDAT[3]) { case USB_DESC_DEVICE: return g_device_desc; case USB_DESC_CONF: return ep0_config_desc_get(FALSE); case USB_DESC_STRING: return ep0_string_desc_get(); case USB_DESC_DEVICE_QUAL: return g_device_qual_desc; case USB_DESC_OTHER_SPEED_CONF: return ep0_config_desc_get(TRUE); case USB_DESC_HID: return &g_config_desc[USB_DESC_CONF_LEN + USB_DESC_INTERFACE_LEN]; default: break; } return NULL; } const BYTE CODE *hid_ep0_report_desc_get(WORD *length) { *length = sizeof(g_hid_report_desc); return g_hid_report_desc; } qbs-src-2.6.1/examples/baremetal/cy7c68013a/nes-gamepads/core.h0000644000175100001660000001373214776170045023305 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FX2_HW_H #define FX2_HW_H #include "defs.h" #ifdef __cplusplus extern "C" { #endif // Allowed range: 5000 - 48000. #ifndef CORE_IFREQ # define CORE_IFREQ 48000 // IFCLK frequency in kHz. #endif // Allowed values: 48000, 24000, or 12000. #ifndef CORE_CFREQ # define CORE_CFREQ 48000 // CLKOUT frequency in kHz. #endif #if (CORE_IFREQ < 5000) # error "CORE_IFREQ too small! Valid range: 5000 - 48000." #endif #if (CORE_IFREQ > 48000) # error "CORE_IFREQ too large! Valid range: 5000 - 48000." #endif #if (CORE_CFREQ != 48000) # if (CORE_CFREQ != 24000) # if (CORE_CFREQ != 12000) # error "CORE_CFREQ invalid! Valid values: 48000, 24000, 12000." # endif # endif #endif // Calculate synchronization delay. #define CORE_SCYCL (3 * (CORE_CFREQ) + 5 * (CORE_IFREQ) - 1) / (2 * (CORE_IFREQ)) #if (CORE_SCYCL == 1) # define sync_delay() {\ NOP(); } #endif #if (CORE_SCYCL == 2) # define sync_delay() {\ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 3) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 4) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 5) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 6) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 7) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 8) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 9) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 10) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 11) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 12) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 13) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 14) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 15) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #if (CORE_SCYCL == 16) # define sync_delay() {\ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); \ NOP(); } #endif #define code_all_irq_disable() (IE = 0) #define code_all_irq_enable() (IE = 1) void core_init(void); #ifdef __cplusplus } #endif #endif // FX2_HW_H qbs-src-2.6.1/examples/baremetal/msp430f5529/0000755000175100001660000000000014776170045017743 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/0000755000175100001660000000000014776170045022307 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/gamepads.ld0000644000175100001660000000526714776170045024423 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ g_setupdat = 0x2380; /* Setup packet block address. */ g_ep0 = 0x0920; /* Input ep0 configuration address. */ g_ep0_in_buf = 0x2378; /* Input ep0 buffer address. */ g_ep1_in = 0x23C8; /* Input ep1 configuration address. */ g_ep1_in_xbuf = 0x1C80; /* Ep1 X-buffer address. */ qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/pmm.c0000644000175100001660000002155314776170045023252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hwdefs.h" #include "pmm.h" #define PMMCTL0_H_ADDRESS (PMM_BASE + OFS_PMMCTL0_H) #define PMMCTL0_L_ADDRESS (PMM_BASE + OFS_PMMCTL0_L) #define PMMRIE_ADDRESS (PMM_BASE + OFS_PMMRIE) #define PMMIFG_ADDRESS (PMM_BASE + OFS_PMMIFG) #define SVSMHCTL_ADDRESS (PMM_BASE + OFS_SVSMHCTL) #define SVSMLCTL_ADDRESS (PMM_BASE + OFS_SVSMLCTL) #define PMM_OTHER_BITSL \ (SVSLRVL0 | SVSLRVL1 | SVSMLRRL0 | SVSMLRRL1 | SVSMLRRL2) #define PMM_OTHER_BITSH \ (SVSHRVL0 | SVSHRVL1 | SVSMHRRL0 | SVSMHRRL1 | SVSMHRRL2) #define PMM_CLEANUP_FLAGS \ (SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG) static void pmm_write_access_allow(bool allow) { HWREG8(PMMCTL0_H_ADDRESS) = allow ? PMMPW_H : 0; } static void pmm_interrupt_flags_clear(uint16_t flags) { HWREG16(PMMIFG_ADDRESS) &= ~flags; } static void pmm_interrupt_flags_wait(uint16_t flags) { while ((HWREG16(PMMIFG_ADDRESS) & flags) == 0) { ; } } static uint8_t pmm_level_mask(enum ppm_voltage voltage) { switch (voltage) { case PMM_VOLTAGE_1_35V: return PMMCOREV_0; case PMM_VOLTAGE_1_55V: return PMMCOREV_1; case PMM_VOLTAGE_1_75V: return PMMCOREV_2; case PMM_VOLTAGE_1_85V: return PMMCOREV_3; default: break; } return PMMCOREV_0; } static bool pmm_voltage_set_up(uint8_t level) { pmm_write_access_allow(true); // Disable interrupts and backup all registers. uint16_t pmmrie_backup = HWREG16(PMMRIE_ADDRESS); HWREG16(PMMRIE_ADDRESS) &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE | SVSLPE | SVMHVLRIE | SVMHIE | SVSMHDLYIE | SVMLVLRIE | SVMLIE | SVSMLDLYIE); uint16_t svsmhctl_backup = HWREG16(SVSMHCTL_ADDRESS); uint16_t svsmlctl_backup = HWREG16(SVSMLCTL_ADDRESS); // Clear all interrupt flags. pmm_interrupt_flags_clear(0xFFFF); // Set SVM high side to new level and check if voltage increase is possible. HWREG16(SVSMHCTL_ADDRESS) = SVMHE | SVSHE | (SVSMHRRL0 * level); pmm_interrupt_flags_wait(SVSMHDLYIFG); pmm_interrupt_flags_clear(SVSMHDLYIFG); // Check if a voltage increase is possible. if ((HWREG16(PMMIFG_ADDRESS) & SVMHIFG) == SVMHIFG) { // Vcc is too low for a voltage increase, recover the previous settings. HWREG16(PMMIFG_ADDRESS) &= ~SVSMHDLYIFG; HWREG16(SVSMHCTL_ADDRESS) = svsmhctl_backup; pmm_interrupt_flags_wait(SVSMHDLYIFG); pmm_interrupt_flags_clear(PMM_CLEANUP_FLAGS); // Restore interrupt enable register. HWREG16(PMMRIE_ADDRESS) = pmmrie_backup; pmm_write_access_allow(false); return false; } // Set SVS high side to new level. HWREG16(SVSMHCTL_ADDRESS) |= (SVSHRVL0 * level); pmm_interrupt_flags_wait(SVSMHDLYIFG); pmm_interrupt_flags_clear(SVSMHDLYIFG); // Set new voltage level. HWREG8(PMMCTL0_L_ADDRESS) = PMMCOREV0 * level; // Set SVM, SVS low side to new level. HWREG16(SVSMLCTL_ADDRESS) = SVMLE | (SVSMLRRL0 * level) | SVSLE | (SVSLRVL0 * level); pmm_interrupt_flags_wait(SVSMLDLYIFG); pmm_interrupt_flags_clear(SVSMLDLYIFG); // Restore low side settings and clear all other bits. HWREG16(SVSMLCTL_ADDRESS) &= PMM_OTHER_BITSL; // Clear low side level settings in backup register and keep all other bits. svsmlctl_backup &= ~PMM_OTHER_BITSL; // Restore low side SVS monitor settings. HWREG16(SVSMLCTL_ADDRESS) |= svsmlctl_backup; // Restore high side settings and clear all other bits. HWREG16(SVSMHCTL_ADDRESS) &= PMM_OTHER_BITSH; // Clear high side level settings in backup register and keep all other bits. svsmhctl_backup &= ~PMM_OTHER_BITSH; // Restore high side SVS monitor settings. HWREG16(SVSMHCTL_ADDRESS) |= svsmhctl_backup; pmm_interrupt_flags_wait(SVSMLDLYIFG | SVSMHDLYIFG); pmm_interrupt_flags_clear(PMM_CLEANUP_FLAGS); // Restore interrupt enable register. HWREG16(PMMRIE_ADDRESS) = pmmrie_backup; pmm_write_access_allow(false); return true; } static uint16_t pmm_voltage_set_down(uint8_t level) { pmm_write_access_allow(true); // Disable interrupts and backup all registers. uint16_t pmmrie_backup = HWREG16(PMMRIE_ADDRESS); HWREG16(PMMRIE_ADDRESS) &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE | SVSLPE | SVMHVLRIE | SVMHIE | SVSMHDLYIE | SVMLVLRIE | SVMLIE | SVSMLDLYIE ); uint16_t svsmhctl_backup = HWREG16(SVSMHCTL_ADDRESS); uint16_t svsmlctl_backup = HWREG16(SVSMLCTL_ADDRESS); pmm_interrupt_flags_clear(SVMHIFG | SVSMHDLYIFG | SVMLIFG | SVSMLDLYIFG); // Set SVM, SVS high & low side to new settings in normal mode. HWREG16(SVSMHCTL_ADDRESS) = SVMHE | (SVSMHRRL0 * level) | SVSHE | (SVSHRVL0 * level); HWREG16(SVSMLCTL_ADDRESS) = SVMLE | (SVSMLRRL0 * level) | SVSLE | (SVSLRVL0 * level); pmm_interrupt_flags_wait(SVSMHDLYIFG | SVSMLDLYIFG); pmm_interrupt_flags_clear(SVSMHDLYIFG | SVSMLDLYIFG); // Set new voltage level. HWREG8(PMMCTL0_L_ADDRESS) = PMMCOREV0 * level; // Restore low side settings and clear all other bits. HWREG16(SVSMLCTL_ADDRESS) &= PMM_OTHER_BITSL; // Clear low side level settings in backup register and keep all other bits. svsmlctl_backup &= ~PMM_OTHER_BITSL; //Restore low side SVS monitor settings. HWREG16(SVSMLCTL_ADDRESS) |= svsmlctl_backup; // Restore high side settings and clear all other bits. HWREG16(SVSMHCTL_ADDRESS) &= PMM_OTHER_BITSH; // Clear high side level settings in backup register and keep all other bits. svsmhctl_backup &= ~PMM_OTHER_BITSH; // Restore high side SVS monitor settings. HWREG16(SVSMHCTL_ADDRESS) |= svsmhctl_backup; pmm_interrupt_flags_wait(SVSMLDLYIFG | SVSMHDLYIFG); pmm_interrupt_flags_clear(PMM_CLEANUP_FLAGS); // Restore interrupt enable register. HWREG16(PMMRIE_ADDRESS) = pmmrie_backup; pmm_write_access_allow(false); return true; } bool pmm_voltage_init(enum ppm_voltage voltage) { const uint8_t exp_level = pmm_level_mask(voltage) & PMMCOREV_3; uint8_t act_level = (HWREG16(PMM_BASE + OFS_PMMCTL0) & PMMCOREV_3); bool result = true; while ((exp_level != act_level) && result) { if (exp_level > act_level) result = pmm_voltage_set_up(++act_level); else result = pmm_voltage_set_down(--act_level); } return result; } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/nes-gamepads.qbs0000644000175100001660000001162114776170045025363 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.contains("msp430")) return false; return qbs.toolchain.contains("iar") || qbs.toolchain.contains("gcc") } name: "msp430f5529-nes-gamepads" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") property path dlibIncludePath: cpp.toolchainInstallPath + "/../lib/dlib/dl430xssfn.h" property path dlibRuntimePath: cpp.toolchainInstallPath + "/../lib/dlib/dl430xssfn.r43" cpp.entryPoint: "__program_start" cpp.defines: ["__MSP430F5529__"] cpp.driverFlags: [ "-e", "--core=430X", "--data_model=small", "--code_model=small", "--dlib_config", dlibIncludePath ] cpp.driverLinkerFlags: [ "-D_STACK_SIZE=A0", "-D_DATA16_HEAP_SIZE=A0", "-D_DATA20_HEAP_SIZE=50" ] cpp.staticLibraries: [ // Explicitly link with the runtime dlib library (which contains // all required startup code and other stuff). dlibRuntimePath ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR Linker Script" prefix: cpp.toolchainInstallPath + "/../config/linker/" fileTags: ["linkerscript"] // Explicitly use the default linker scripts for current target. files: ["lnk430f5529.xcl"] } // // GCC-specific properties and soucres. // Properties { condition: qbs.toolchain.contains("gcc") property path supportFilesPath // A path to the MSP430 support files, which are // provided by the Texas Instruments separately: // e.g. 'c:/msp430-gcc-support-files/include/' cpp.includePaths: supportFilesPath cpp.libraryPaths: supportFilesPath cpp.driverFlags: ["-mmcu=msp430f5529"] } Group { condition: qbs.toolchain.contains("gcc") name: "GCC Linker Script" fileTags: ["linkerscript"] files: ["gamepads.ld"] } files: [ "gpio.c", "gpio.h", "hid.h", "hiddesc.c", "hidep0.c", "hidep1.c", "hwdefs.h", "main.c", "pmm.c", "pmm.h", "ucs.c", "ucs.h", "usb.c", "usb.h", "wdt_a.c", "wdt_a.h", ] } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/README.md0000644000175100001660000000256114776170045023572 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different MSP430 toolchains. It is designed for the MSP-EXP430F5529LP target board (based on msp430f5529 chip): * http://www.ti.com/tool/MSP-EXP430F5529LP It implements a USB HID device that connects two 8-buttons NES (Dendy) gamepads to a PC. The gamepads are connected to the msp430f5529 chip as follows: 1. CLK - it is an output clock signal which generates by chip from the port 6, pin 0 (P6.0). This pin should be connected to the CLK inputs for both gamepads. 2. DATA1 - it is an input data signal which comes to chip on the the port 6, pin 1 (P6.1). This pin should be connected to the DATA output from the gamepad #1. 3. DATA2 - it is an input data signal which comes to chip on the the port 6, pin 2 (P6.2). This pin should be connected to the DATA output from the gamepad #2. 4. LATCH - it is an output clock signal which generates by chip from the port 6, pin 3 (P6.3). This pin should be connected to the LATCH inputs for both gamepads. Actual schematic and pinouts depends on an used gamepads (with 7, 9 or other pins connectors) and a development boards. Also, do not forget to connect the +3.3V and GND wires to the gamepads. Then it is possible to play 8-bit NES games using various PC simulators. The following toolchains are supported: * IAR Embedded Workbench * GCC qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/hidep1.c0000644000175100001660000001500414776170045023625 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "hid.h" #include "hwdefs.h" #include "usb.h" // We use this empirical value to make a GPIO polling // every ~10 msec (rough). It is a simplest way, because // instead we need to use a timers with interrupts callbacks. enum { POLLING_COUNTER = 888 }; // Pins on the port 6. enum gpio_pins { GPIO_CLK_PIN = BIT0, GPIO_DATA1_PIN = BIT1, GPIO_DATA2_PIN = BIT2, GPIO_LATCH_PIN = BIT3, }; struct usb_ep { uint8_t EPCNF; // Endpoint configuration. uint8_t EPBBAX; // Endpoint X buffer base address. uint8_t EPBCTX; // Endpoint X Buffer byte count. uint8_t SPARE0; // No used. uint8_t SPARE1; // No used. uint8_t EPBBAY; // Endpoint Y buffer Base address. uint8_t EPBCTY; // Endpoint Y buffer byte count. uint8_t EPSIZXY; // Endpoint XY buffer size. }; #if defined(__ICC430__) #pragma location = 0x23C8 // Input ep1 configuration address. __no_init struct usb_ep __data16 g_ep1_in; #pragma location = 0x1C80 // Input ep1 X-buffer address. __no_init uint8_t __data16 g_ep1_in_xbuf[EP_MAX_PACKET_SIZE]; #elif defined(__GNUC__) extern struct usb_ep g_ep1_in; extern uint8_t g_ep1_in_xbuf[EP_MAX_PACKET_SIZE]; #endif static struct { const uint8_t data_pin; const uint8_t id; uint8_t buttons; bool ready; } g_reports[HID_REPORTS_COUNT] = { {GPIO_DATA1_PIN, HID_REPORT_ID_GAMEPAD1, 0, false}, {GPIO_DATA2_PIN, HID_REPORT_ID_GAMEPAD2, 0, false} }; static uint16_t g_poll_counter = 0; // Pulse width around ~10 usec. static void ep1_latch_pulse(void) { gpio_pins_set_high(GPIO_PORT_P6, GPIO_LATCH_PIN); gpio_pins_set_low(GPIO_PORT_P6, GPIO_LATCH_PIN); } // Pulse width around ~10 usec. static void ep1_clk_pulse(void) { gpio_pins_set_high(GPIO_PORT_P6, GPIO_CLK_PIN); gpio_pins_set_low(GPIO_PORT_P6, GPIO_CLK_PIN); } static void ep1_reports_clean(void) { for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) { g_reports[index].buttons = 0; g_reports[index].ready = false; } } static void ep1_reports_update(void) { for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) g_reports[index].ready = true; } static void ep1_gamepads_poll(void) { ep1_reports_clean(); ep1_latch_pulse(); for (uint8_t pos = 0; pos < HID_REPORT_BITS_COUNT; ++pos) { // TODO: Add some nops here? for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) { const uint8_t pin = g_reports[index].data_pin; const enum gpio_pin_status st = gpio_pin_get(GPIO_PORT_P6, pin); // Low state means that a button is pressed. const bool v = (st == GPIO_INPUT_PIN_LOW); g_reports[index].buttons |= (v << pos); } ep1_clk_pulse(); } ep1_reports_update(); } static void ep1_report_send(uint8_t report_index) { if (!g_reports[report_index].ready) return; if ((g_ep1_in.EPBCTX & NAK) == 0) return; g_ep1_in_xbuf[0] = g_reports[report_index].id; g_ep1_in_xbuf[1] = g_reports[report_index].buttons; g_ep1_in.EPBCTX = 2; g_reports[report_index].ready = false; } void hid_ep1_init(void) { enum { USBSTABUFF_ADDRESS = 0x1C00, // Start of buffer space address. USBIEPBBAX_1_ADDRESS = 0x1C80 // Input ep1 X-buffer address. }; g_ep1_in.EPCNF = UBME | USBIIE; g_ep1_in.EPBBAX = ((USBIEPBBAX_1_ADDRESS - USBSTABUFF_ADDRESS) >> 3) & 0x00FF; g_ep1_in.EPBCTX = NAK; g_ep1_in.EPSIZXY = EP_MAX_PACKET_SIZE; gpio_pins_set_as_out(GPIO_PORT_P6, GPIO_CLK_PIN | GPIO_LATCH_PIN); gpio_pins_set_as_in(GPIO_PORT_P6, GPIO_DATA1_PIN | GPIO_DATA2_PIN); } void hid_ep1_task(void) { if (!hid_ep0_is_enumerated()) return; for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) ep1_report_send(index); if (g_poll_counter <= POLLING_COUNTER) { ++g_poll_counter; } else { g_poll_counter = 0; ep1_gamepads_poll(); } } void hid_ep1_in_stall(void) { g_ep1_in.EPCNF |= STALL; } void hid_ep1_in_unstall(void) { g_ep1_in.EPCNF &= ~(STALL | TOGGLE); } bool hid_ep1_in_is_stalled(void) { return (g_ep1_in.EPCNF & STALL); } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.c0000644000175100001660000000522414776170045023554 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hwdefs.h" #include "wdt_a.h" #define WDT_CONTROL_ADDRESS (WDT_A_BASE + OFS_WDTCTL) void wdt_a_stop(void) { const uint8_t st = (HWREG16(WDT_CONTROL_ADDRESS) & 0x00FF) | WDTHOLD; HWREG16(WDT_CONTROL_ADDRESS) = WDTPW + st; } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/hid.h0000644000175100001660000000755014776170045023233 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_HID_H #define MSP430_HID_H #include #include #ifdef __cplusplus extern "C" { #endif enum hid_constants { HID_CONFIG_NUMBER = 1, // Number of valid configuration. HID_IFACE_NUMBER = 0, // Number of valid interface. HID_ALT_IFACE_NUMBER = 0, // Number of valid alternate interface. HID_EP_IN = 0x81 // Active end point address. }; enum hid_gamepad_id { HID_REPORT_ID_GAMEPAD1 = 1, HID_REPORT_ID_GAMEPAD2 = 2 }; enum { HID_REPORTS_COUNT = 2, HID_REPORT_BITS_COUNT = 8 }; void hid_ep0_init(void); // Called only in interrupt context. void hid_ep0_setup_handler(void); void hid_ep0_in_handler(void); void hid_ep0_in_nak(void); void hid_ep0_in_stall(void); void hid_ep0_in_clear(void); bool hid_ep0_in_is_stalled(void); void hid_ep0_out_nak(void); void hid_ep0_out_stall(void); void hid_ep0_out_clear(void); const uint8_t *hid_ep0_desc_get(uint8_t type, uint16_t *length); uint8_t hid_ep0_setup_bm_request_type_get(void); uint8_t hid_ep0_setup_request_get(void); uint8_t hid_ep0_setup_lvalue_get(void); uint8_t hid_ep0_setup_hvalue_get(void); uint8_t hid_ep0_setup_lindex_get(void); uint8_t hid_ep0_setup_hindex_get(void); void hid_ep0_enumerated_set(bool enumerated); bool hid_ep0_is_enumerated(void); void hid_ep1_init(void); void hid_ep1_task(void); void hid_ep1_in_stall(void); void hid_ep1_in_unstall(void); bool hid_ep1_in_is_stalled(void); #ifdef __cplusplus } #endif #endif // MSP430_HID_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/pmm.h0000644000175100001660000000534314776170045023256 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_PMM_H #define MSP430_PMM_H #include #ifdef __cplusplus extern "C" { #endif enum ppm_voltage { PMM_VOLTAGE_1_35V, PMM_VOLTAGE_1_55V, PMM_VOLTAGE_1_75V, PMM_VOLTAGE_1_85V }; bool pmm_voltage_init(enum ppm_voltage voltage); #ifdef __cplusplus } #endif #endif // MSP430_PMM_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/usb.c0000644000175100001660000002064414776170045023252 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "hid.h" #include "hwdefs.h" #include "ucs.h" #include "usb.h" static uint16_t usb_khz_freq_get(void) { uint16_t freq = 0; const uint8_t selm_curr = (UCSCTL4_L & SELM_7); if (selm_curr <= 4) { uint16_t fll_ref_freq = 33; // It is 32.768 kHz. if ((UCSCTL3_L & SELREF_7) >= 0x50) fll_ref_freq = (4.0) * 1000; uint16_t flln_curr = (UCSCTL2 & 0x03FF) + 1; if (selm_curr == SELM_3) { uint16_t flld_curr = (UCSCTL2 & FLLD_7); flld_curr >>= 12; flln_curr <<= flld_curr; } const uint8_t fll_ref_div = (UCSCTL3_L & FLLREFDIV_7); if (fll_ref_div == 0) freq = flln_curr * (fll_ref_freq / 1); else if (fll_ref_div == 1) freq = flln_curr * (fll_ref_freq / 2); else if (fll_ref_div == 2) freq = flln_curr * (fll_ref_freq / 4); else if (fll_ref_div == 3) freq = flln_curr * (fll_ref_freq / 8); else if (fll_ref_div == 4) freq = flln_curr * (fll_ref_freq / 12); else if (fll_ref_div == 5) freq = flln_curr * (fll_ref_freq / 16); } else { freq = (4.0) * 1000; } return freq >> (UCSCTL5_L & DIVM_7); } static uint16_t usb_delay_250us_get(void) { const uint16_t mclk_freq = usb_khz_freq_get(); const uint16_t delay_250us = ((mclk_freq >> 6) | (mclk_freq >> 7) | (mclk_freq >> 9)); return delay_250us; } static void usb_cfg_access_allow(bool allow) { enum { ALLOW_KEY = 0x9628, DENIED_KEY = 0x9600 }; USBKEYPID = allow ? ALLOW_KEY : DENIED_KEY; } static bool usb_pll_enable(void) { if (!(USBPWRCTL & USBBGVBV)) return false; if ((USBCNF & USB_EN) && (USBPLLCTL & UPLLEN)) return true; gpio_pins_set_as_pf_out(GPIO_PORT_P5, GPIO_PIN2); gpio_pins_set_as_pf_out(GPIO_PORT_P5, GPIO_PIN3); usb_cfg_access_allow(true); if (!ucs_xt2_blocking_turn_on(XT2DRIVE_0, 50000)) return false; USBPLLDIVB = USBPLL_SETCLK_4_0; USBPLLCTL = UPFDEN | UPLLEN; const uint16_t delay_250us = usb_delay_250us_get(); uint8_t j = 0; do { USBPLLIR = 0; for (uint8_t k = 0; k < 2; ++k) { for (uint16_t i = 0; i < delay_250us; ++i) { __no_operation(); } } if (j++ > 10) { usb_cfg_access_allow(false); return false; } } while (USBPLLIR != 0); USBCNF |= USB_EN; usb_cfg_access_allow(false); return true; } static void usb_reset(void) { usb_cfg_access_allow(true); hid_ep0_enumerated_set(false); USBCTL = 0; USBFUNADR = 0; USBOEPIE = 0; USBIEPIE = 0; hid_ep0_init(); hid_ep1_init(); USBCTL = FEN; USBIFG = 0; USBIE = SETUPIE | RSTRIE | SUSRIE; usb_cfg_access_allow(false); } static void usb_connect(void) { usb_cfg_access_allow(true); USBCNF |= PUR_EN; USBPWRCTL |= VBOFFIE; usb_cfg_access_allow(false); } static void usb_pwr_vbus_wait(void) { const uint16_t delay_250us = usb_delay_250us_get(); for (uint8_t j = 0; j < 4; ++j) { for (uint16_t i = 0; i < delay_250us; ++i) { __no_operation(); } } } static void usb_pwr_vbus_on_handler(void) { usb_pwr_vbus_wait(); if (USBPWRCTL & USBBGVBV) { usb_cfg_access_allow(true); USBPWRCTL |= VBOFFIE; USBPWRCTL &= ~ (VBONIFG + VBOFFIFG); usb_cfg_access_allow(false); } } static void usb_pwr_vbus_off_handler(void) { usb_pwr_vbus_wait(); if (!(USBPWRCTL & USBBGVBV)) { usb_cfg_access_allow(true); USBCNF = 0; USBPLLCTL &= ~UPLLEN; USBPWRCTL &= ~(VBOFFIE + VBOFFIFG + SLDOEN); usb_cfg_access_allow(false); } } void usb_suspend(void) { usb_cfg_access_allow(true); USBCTL |= FRSTE; USBIFG &= ~SUSRIFG; USBPLLCTL &= ~UPLLEN; ucs_xt2_turn_off(); USBIE = RESRIE; usb_cfg_access_allow(false); } void usb_resume(void) { usb_pll_enable(); USBIFG &= ~(RESRIFG | SUSRIFG); USBIE = SETUPIE | RSTRIE | SUSRIE; } void usb_init(void) { const uint16_t gie_backup = (__get_SR_register() & GIE); usb_cfg_access_allow(true); USBPHYCTL = PUSEL; USBPWRCTL = VUSBEN | SLDOAON; const uint16_t delay_250us = usb_delay_250us_get(); for (uint8_t j = 0; j < 20; ++j) { for (uint16_t i = 0; i < delay_250us; ++i) { __no_operation(); } } USBPWRCTL |= VBONIE; usb_cfg_access_allow(false); __bis_SR_register(gie_backup); if (USBPWRCTL & USBBGVBV) { if (usb_pll_enable()) { usb_reset(); usb_connect(); } } } void usb_task(void) { hid_ep1_task(); } INTERRUPT(usb_ubm_isr, USB_UBM_VECTOR) { bool wake_up = false; if (USBIFG & SETUPIFG) { hid_ep0_setup_handler(); USBIFG &= ~SETUPIFG; } switch (__even_in_range(USBVECINT & 0x3F, USBVECINT_OUTPUT_ENDPOINT7)) { case USBVECINT_PWR_DROP: __no_operation(); break; case USBVECINT_PLL_RANGE: wake_up = true; break; case USBVECINT_PWR_VBUSOn: usb_pwr_vbus_on_handler(); if (usb_pll_enable()) { usb_reset(); usb_connect(); } wake_up = true; break; case USBVECINT_PWR_VBUSOff: usb_pwr_vbus_off_handler(); ucs_xt2_turn_off(); wake_up = true; break; case USBVECINT_INPUT_ENDPOINT0: hid_ep0_in_handler(); break; case USBVECINT_RSTR: usb_reset(); wake_up = true; break; case USBVECINT_SUSR: usb_suspend(); wake_up = true; break; case USBVECINT_RESR: usb_resume(); wake_up = true; break; case USBVECINT_SETUP_PACKET_RECEIVED: hid_ep0_in_nak(); hid_ep0_out_nak(); hid_ep0_setup_handler(); break; default: break; } if (wake_up) { __bic_SR_register_on_exit(LPM3_bits); __no_operation(); } } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/gpio.h0000644000175100001660000000741514776170045023425 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_GPIO_H #define MSP430_GPIO_H #include #ifdef __cplusplus extern "C" { #endif enum gpio_port { GPIO_PORT_P1 = 1, GPIO_PORT_P2 = 2, GPIO_PORT_P3 = 3, GPIO_PORT_P4 = 4, GPIO_PORT_P5 = 5, GPIO_PORT_P6 = 6, GPIO_PORT_P7 = 7, GPIO_PORT_P8 = 8, GPIO_PORT_PJ = 13, }; enum gpio_pin { GPIO_PIN0 = 0x0001, GPIO_PIN1 = 0x0002, GPIO_PIN2 = 0x0004, GPIO_PIN3 = 0x0008, GPIO_PIN4 = 0x0010, GPIO_PIN5 = 0x0020, GPIO_PIN6 = 0x0040, GPIO_PIN7 = 0x0080, GPIO_PIN8 = 0x0100, GPIO_PIN9 = 0x0200, GPIO_PIN10 = 0x0400, GPIO_PIN11 = 0x0800, GPIO_PIN12 = 0x1000, GPIO_PIN13 = 0x2000, GPIO_PIN14 = 0x4000, GPIO_PIN15 = 0x8000, }; enum gpio_pin_status { GPIO_INPUT_PIN_HIGH = 0x01, GPIO_INPUT_PIN_LOW = 0x00 }; void gpio_pins_set_as_out(enum gpio_port port, uint16_t pins); void gpio_pins_set_as_in(enum gpio_port port, uint16_t pins); void gpio_pins_set_as_pf_out(enum gpio_port port, uint16_t pins); void gpio_pins_set_as_pf_in(enum gpio_port port, uint16_t pins); void gpio_pins_set_high(enum gpio_port port, uint16_t pins); void gpio_pins_set_low(enum gpio_port port, uint16_t pins); void gpio_pins_toggle(enum gpio_port port, uint16_t pins); enum gpio_pin_status gpio_pin_get(enum gpio_port port, uint16_t pins); #ifdef __cplusplus } #endif #endif // MSP430_GPIO_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/ucs.c0000644000175100001660000002105514776170045023250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hwdefs.h" #include "ucs.h" #if defined(__GNUC__) #define __delay_cycles(x) \ ({ \ for (uint16_t j = 0; j < x; j++) { \ __no_operation(); \ } \ }) #endif static uint16_t ucs_source_mask(enum ucs_source source) { switch (source) { case UCS_XT1CLK_SELECT: return SELM__XT1CLK; case UCS_VLOCLK_SELECT: return SELM__VLOCLK; case UCS_REFOCLK_SELECT: return SELM__REFOCLK; case UCS_DCOCLK_SELECT: return SELM__DCOCLK; case UCS_DCOCLKDIV_SELECT: return SELM__DCOCLKDIV; case UCS_XT2CLK_SELECT: return SELM__XT2CLK; default: break; } return SELM__XT1CLK; } static uint16_t ucs_divider_mask(enum ucs_divider divider) { switch (divider) { case UCS_CLOCK_DIVIDER_1: return DIVM__1; case UCS_CLOCK_DIVIDER_2: return DIVM__2; case UCS_CLOCK_DIVIDER_4: return DIVM__4; case UCS_CLOCK_DIVIDER_8: return DIVM__8; case UCS_CLOCK_DIVIDER_12: return DIVM__32; case UCS_CLOCK_DIVIDER_16: return DIVM__16; case UCS_CLOCK_DIVIDER_32: return DIVM__32; default: break; } return DIVM__1; } static void ucs_fll_init(uint16_t fsystem, uint16_t ratio) { const uint16_t sr_reg_backup = __get_SR_register() & SCG0; uint16_t mode = 0; uint16_t d = ratio; if (fsystem > 16000) { d >>= 1; mode = 1; } else { fsystem <<= 1; } uint16_t dco_div_bits = FLLD__2; while (d > 512) { dco_div_bits = dco_div_bits + FLLD0; d >>= 1; } // Disable FLL. __bis_SR_register(SCG0); // Set DCO to lowest tap. HWREG8(UCS_BASE + OFS_UCSCTL0_H) = 0; // Reset FN bits. HWREG16(UCS_BASE + OFS_UCSCTL2) &= ~(0x03FF); HWREG16(UCS_BASE + OFS_UCSCTL2) = dco_div_bits | (d - 1); if (fsystem <= 630) { // fsystem < 0.63MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_0; } else if (fsystem < 1250) { // 0.63MHz < fsystem < 1.25MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_1; } else if (fsystem < 2500) { // 1.25MHz < fsystem < 2.5MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_2; } else if (fsystem < 5000) { // 2.5MHz < fsystem < 5MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_3; } else if (fsystem < 10000) { // 5MHz < fsystem < 10MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_4; } else if (fsystem < 20000) { // 10MHz < fsystem < 20MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_5; } else if (fsystem < 40000) { // 20MHz < fsystem < 40MHz HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_6; } else { HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_7; } // Re-enable FLL. __bic_SR_register(SCG0); while (HWREG8(UCS_BASE + OFS_UCSCTL7_L) & DCOFFG) { // Clear OSC fault flags. HWREG8(UCS_BASE + OFS_UCSCTL7_L) &= ~(DCOFFG); // Clear OFIFG fault flag. HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; } // Restore previous SCG0. __bis_SR_register(sr_reg_backup); if (mode == 1) { // Select DCOCLK because fsystem > 16000. HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~(SELM_7 + SELS_7); HWREG16(UCS_BASE + OFS_UCSCTL4) |= SELM__DCOCLK + SELS__DCOCLK; } else { // Select DCODIVCLK. HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~(SELM_7 + SELS_7); HWREG16(UCS_BASE + OFS_UCSCTL4) |= SELM__DCOCLKDIV + SELS__DCOCLKDIV; } } void ucs_init(enum ucs_signal signal, enum ucs_source source, enum ucs_divider divider) { uint16_t source_msk = ucs_source_mask(source); uint16_t divider_msk = ucs_divider_mask(divider); switch (signal) { case UCS_ACLK: HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~SELA_7; source_msk |= source_msk << 8; HWREG16(UCS_BASE + OFS_UCSCTL4) |= source_msk; HWREG16(UCS_BASE + OFS_UCSCTL5) &= ~DIVA_7; divider_msk = divider_msk << 8; HWREG16(UCS_BASE + OFS_UCSCTL5) |= divider_msk; break; case UCS_SMCLK: HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~SELS_7; source_msk = source_msk << 4; HWREG16(UCS_BASE + OFS_UCSCTL4) |= source_msk; HWREG16(UCS_BASE + OFS_UCSCTL5) &= ~DIVS_7; divider_msk = divider_msk << 4; HWREG16(UCS_BASE + OFS_UCSCTL5) |= divider_msk; break; case UCS_MCLK: HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~SELM_7; HWREG16(UCS_BASE + OFS_UCSCTL4) |= source_msk; HWREG16(UCS_BASE + OFS_UCSCTL5) &= ~DIVM_7; HWREG16(UCS_BASE + OFS_UCSCTL5) |= divider_msk; break; case UCS_FLLREF: HWREG8(UCS_BASE + OFS_UCSCTL3) &= ~SELREF_7; source_msk = source_msk << 4; HWREG8(UCS_BASE + OFS_UCSCTL3) |= source_msk; HWREG8(UCS_BASE + OFS_UCSCTL3) &= ~FLLREFDIV_7; switch (divider) { case UCS_CLOCK_DIVIDER_12: HWREG8(UCS_BASE + OFS_UCSCTL3) |= FLLREFDIV__12; break; case UCS_CLOCK_DIVIDER_16: HWREG8(UCS_BASE + OFS_UCSCTL3) |= FLLREFDIV__16; break; default: HWREG8(UCS_BASE + OFS_UCSCTL3) |= divider_msk; break; } break; default: break; } } bool ucs_xt2_blocking_turn_on(uint16_t drive, uint16_t timeout) { // Check if drive value is expected one. if ((HWREG16(UCS_BASE + OFS_UCSCTL6) & XT2DRIVE_3) != drive) { // Clear XT2 drive field. HWREG16(UCS_BASE + OFS_UCSCTL6) &= ~XT2DRIVE_3; HWREG16(UCS_BASE + OFS_UCSCTL6) |= drive; } HWREG16(UCS_BASE + OFS_UCSCTL6) &= ~XT2BYPASS; // Switch on XT2 oscillator. HWREG16(UCS_BASE + OFS_UCSCTL6) &= ~XT2OFF; do { // Clear OSC fault Flags. HWREG8(UCS_BASE + OFS_UCSCTL7) &= ~XT2OFFG; // Clear OFIFG fault flag. HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; } while ((HWREG8(UCS_BASE + OFS_UCSCTL7) & XT2OFFG) && --timeout); return timeout > 0; } void ucs_xt2_turn_off(void) { HWREG16(UCS_BASE + OFS_UCSCTL6) |= XT2OFF; } void ucs_fll_settle_init(uint16_t fsystem, uint16_t ratio) { volatile uint16_t x = ratio * 32; ucs_fll_init(fsystem, ratio); while (x--) { __delay_cycles(30); } } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/main.c0000644000175100001660000000631714776170045023406 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hwdefs.h" #include "pmm.h" #include "ucs.h" #include "usb.h" #include "wdt_a.h" static void hw_clocks_init(uint32_t mclk_freq) { ucs_init(UCS_FLLREF, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); ucs_init(UCS_ACLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); ucs_fll_settle_init(mclk_freq / 1000, mclk_freq / 32768); // Use REFO for FLL and ACLK. UCSCTL3 = (UCSCTL3 & ~SELREF_7) | SELREF__REFOCLK; UCSCTL4 = (UCSCTL4 & ~SELA_7) | SELA__REFOCLK; } static void hw_init(void) { __disable_interrupt(); wdt_a_stop(); pmm_voltage_init(PMM_VOLTAGE_1_85V); hw_clocks_init(8000000); usb_init(); __enable_interrupt(); } static void hw_loop_exec(void) { for (;;) { usb_task(); } } int main(void) { hw_init(); hw_loop_exec(); return 0; } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/ucs.h0000644000175100001660000000661714776170045023264 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_UCS_H #define MSP430_UCS_H #ifdef __cplusplus extern "C" { #endif enum ucs_signal { UCS_ACLK = 0x01, UCS_MCLK = 0x02, UCS_SMCLK = 0x04, UCS_FLLREF = 0x08 }; enum ucs_source { UCS_XT1CLK_SELECT, UCS_VLOCLK_SELECT, UCS_REFOCLK_SELECT, UCS_DCOCLK_SELECT, UCS_DCOCLKDIV_SELECT, UCS_XT2CLK_SELECT }; enum ucs_divider { UCS_CLOCK_DIVIDER_1, UCS_CLOCK_DIVIDER_2, UCS_CLOCK_DIVIDER_4, UCS_CLOCK_DIVIDER_8, UCS_CLOCK_DIVIDER_12, UCS_CLOCK_DIVIDER_16, UCS_CLOCK_DIVIDER_32 }; enum ucs_fault_flag { UCS_XT2OFFG, UCS_XT1HFOFFG, UCS_XT1LFOFFG, UCS_DCOFFG }; void ucs_clocks_init(void); void ucs_init(enum ucs_signal signal, enum ucs_source source, enum ucs_divider divider); bool ucs_xt2_blocking_turn_on(uint16_t drive, uint16_t timeout); void ucs_xt2_turn_off(void); void ucs_fll_settle_init(uint16_t fsystem, uint16_t ratio); #ifdef __cplusplus } #endif #endif // MSP430_UCS_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/usb.h0000644000175100001660000001233514776170045023255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_USB_H #define MSP430_USB_H #ifdef __cplusplus extern "C" { #endif enum usb_setup_bmreq_bits { SETUP_DIR = 0x80, SETUP_TYPE = 0x60, SETUP_RECIPIENT = 0x1F }; // Setup request direction. enum usb_setup_req_direction_bits { SETUP_OUTPUT = 0, // From host to device direction. SETUP_INPUT = 0x80 // From device to host direction. }; // Setup request type. enum usb_setup_req_type_bits { SETUP_STANDARD = 0, // Standard request. SETUP_CLASS = 0x20, // Class request. SETUP_VENDOR = 0x40 // Vendor request. }; // Setup request recipient. enum usb_setup_req_recipient_bits { SETUP_DEVICE = 0, // Device recipient. SETUP_IFACE = 0x01, // Interface recipient. SETUP_EP = 0x02, // End point recipient. SETUP_OTHER = 0x03 // Other recipient. }; // Setup request code. enum usb_setup_req_code { SETUP_GET_STATUS = 0x00, // Get status code. SETUP_CLEAR_FEATURE = 0x01, // Clear feature code. SETUP_RESERVED1 = 0x02, // Reserved code. SETUP_SET_FEATURE = 0x03, // Set feature code. SETUP_RESERVED2 = 0x04, // Reserved code. SETUP_SET_ADDRESS = 0x05, // Set address code. SETUP_GET_DESCRIPTOR = 0x06, // Get descriptor code. SETUP_SET_DESCRIPTOR = 0x07, // Set descriptor code. SETUP_GET_CONFIGURATION = 0x08, // Get configuration code. SETUP_SET_CONFIGURATION = 0x09, // Set configuration code. SETUP_GET_INTERFACE = 0x0A, // Get interface code. SETUP_SET_INTERFACE = 0x0B, // Set interface code. SETUP_SYNC_FRAME = 0x0C, // Sync frame code. SETUP_ANCHOR_LOAD = 0xA0 // Anchor load code. }; // Standard status responses. enum usb_setup_status_code { STATUS_SELF_POWERED = 0x01, STATUS_REMOTE_WAKEUP = 0x02 }; // Standard feature selectors. enum usb_setup_feature_selector { FEATURE_STALL = 0x00, FEATURE_REMOTE_WAKEUP = 0x01, FEATURE_TEST_MODE = 0x02 }; // Get descriptor codes. enum usb_setup_get_descriptor_code { DESC_DEVICE = 0x01, // Device descriptor. DESC_CONF = 0x02, // Configuration descriptor. DESC_STRING = 0x03, // String descriptor. DESC_INTERFACE = 0x04, // Interface descriptor. DESC_ENDPOINT = 0x05, // End point descriptor. DESC_DEVICE_QUAL = 0x06, // Device qualifier descriptor. DESC_OTHER_SPEED_CONF = 0x07, // Other configuration descriptor. DESC_INTERFACE_POWER = 0x08, // Interface power descriptor. DESC_OTG = 0x09, // OTG descriptor. DESC_DEBUG = 0x0A, // Debug descriptor. DESC_INTERFACE_ASSOC = 0x0B, // Interface association descriptor. DESC_HID = 0x21, // Get HID descriptor. DESC_REPORT = 0x22 // Get report descriptor. }; enum usb_ep_size { EP0_MAX_PACKET_SIZE = 8, EP_MAX_PACKET_SIZE = 64, EP_MAX_FIFO_SIZE = 256, EP_NO_MORE_DATA = 0xFFFF }; void usb_init(void); void usb_task(void); #ifdef __cplusplus } #endif #endif // MSP430_USB_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.h0000644000175100001660000000510714776170045023561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_WDT_A_H #define MSP430_WDT_A_H #ifdef __cplusplus extern "C" { #endif void wdt_a_stop(void); #ifdef __cplusplus } #endif #endif // MSP430_WDT_A_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/hidep0.c0000644000175100001660000003464114776170045023634 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hid.h" #include "hwdefs.h" #include "usb.h" enum usb_ep0_action { STATUS_ACTION_NOTHING, STATUS_ACTION_DATA_IN }; struct usb_ep0 { uint8_t IEPCNFG; // Input ep0 configuration register. uint8_t IEPBCNT; // Input ep0 buffer byte count. uint8_t OEPCNFG; // Output ep0 configuration register. uint8_t OEPBCNT; // Output ep0 buffer byte count. }; struct usb_ep0_data { uint8_t data[EP_MAX_FIFO_SIZE]; uint16_t length; uint16_t offset; enum usb_ep0_action action; bool host_ask_more_data_than_available; }; #if defined(__ICC430__) #pragma location = 0x0920 // Input ep0 configuration address. __no_init struct usb_ep0 __data16 g_ep0; #pragma location = 0x2378 // Input ep0 buffer address. __no_init uint8_t __data16 g_ep0_in_buf[EP0_MAX_PACKET_SIZE]; #pragma location = 0x2380 // Setup packet block address. __no_init uint8_t __data16 g_setupdat[EP0_MAX_PACKET_SIZE]; #elif defined(__GNUC__) extern struct usb_ep0 g_ep0; extern uint8_t g_ep0_in_buf[EP0_MAX_PACKET_SIZE]; extern uint8_t g_setupdat[EP0_MAX_PACKET_SIZE]; #endif static volatile bool g_enumerated = false; static bool g_rwuen = false; static bool g_selfpwr = false; static struct usb_ep0_data g_ep0_response; static bool ep0_in_response_create(const uint8_t *data, uint16_t length) { if (sizeof(g_ep0_response.data) < length) return false; for (uint16_t i = 0; i < length; ++i) g_ep0_response.data[i] = data[i]; g_ep0_response.length = length; g_ep0_response.offset = 0; const uint16_t setup_length = (g_setupdat[7] << 8) | g_setupdat[6]; if (g_ep0_response.length >= setup_length) { g_ep0_response.length = setup_length; g_ep0_response.host_ask_more_data_than_available = false; } else { g_ep0_response.host_ask_more_data_than_available = true; } return true; } void ep0_in_frame_send(void) { uint8_t frame_size = 0; if (g_ep0_response.length != EP_NO_MORE_DATA) { if (g_ep0_response.length > EP0_MAX_PACKET_SIZE) { frame_size = EP0_MAX_PACKET_SIZE; g_ep0_response.length -= EP0_MAX_PACKET_SIZE; g_ep0_response.action = STATUS_ACTION_DATA_IN; } else if (g_ep0_response.length < EP0_MAX_PACKET_SIZE) { frame_size = g_ep0_response.length; g_ep0_response.length = EP_NO_MORE_DATA; g_ep0_response.action = STATUS_ACTION_NOTHING; } else { frame_size = EP0_MAX_PACKET_SIZE; if (g_ep0_response.host_ask_more_data_than_available) { g_ep0_response.length = 0; g_ep0_response.action = STATUS_ACTION_DATA_IN; } else { g_ep0_response.length = EP_NO_MORE_DATA; g_ep0_response.action = STATUS_ACTION_NOTHING; } } for (uint8_t i = 0; i < frame_size; ++i) { g_ep0_in_buf[i] = g_ep0_response.data[g_ep0_response.offset]; ++g_ep0_response.offset; } g_ep0.IEPBCNT = frame_size; } else { g_ep0_response.action = STATUS_ACTION_NOTHING; } } static bool ep0_dev_status_get(void) { uint16_t status = 0; if (g_selfpwr) status |= STATUS_SELF_POWERED; if (g_rwuen) status |= STATUS_REMOTE_WAKEUP; ep0_in_response_create((uint8_t *)&status, sizeof(status)); return true; } static bool ep0_iface_status_get(void) { uint16_t status = 0; ep0_in_response_create((uint8_t *)&status, sizeof(status)); return true; } static bool ep0_ep_status_get(void) { uint16_t status = 0; const uint8_t ep = hid_ep0_setup_lindex_get(); const uint8_t ep_num = ep & ~SETUP_DIR; if (ep_num == 0) { status = hid_ep0_in_is_stalled() ? 1 : 0; } else if ((ep_num == 1) && (ep & SETUP_DIR) == SETUP_INPUT) { // We support only one input ep1 in. status = hid_ep1_in_is_stalled() ? 1 : 0; } else { return false; } ep0_in_response_create((uint8_t *)&status, sizeof(status)); return true; } static bool ep0_get_status_proc(void) { const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); if ((bm_req_type & SETUP_DIR) != SETUP_INPUT) return false; const uint8_t recipient = bm_req_type & SETUP_RECIPIENT; switch (recipient) { case SETUP_DEVICE: return ep0_dev_status_get(); case SETUP_IFACE: return ep0_iface_status_get(); case SETUP_EP: return ep0_ep_status_get(); default: break; } return false; } static bool ep0_dev_feature_clear(void) { const uint8_t feature = hid_ep0_setup_lvalue_get(); if (feature != FEATURE_REMOTE_WAKEUP) return false; g_rwuen = false; return true; } static bool ep0_ep_feature_clear(void) { const uint8_t feature = hid_ep0_setup_lvalue_get(); if (feature != FEATURE_STALL) return false; const uint8_t ep = hid_ep0_setup_lindex_get(); const uint8_t ep_num = ep & ~SETUP_DIR; if (ep_num == 0) { // Do nothing. } else if ((ep_num == 1) && (ep & SETUP_DIR) == SETUP_INPUT) { // We support only one input ep1 in. hid_ep1_in_unstall(); } else { return false; } hid_ep0_in_clear(); return true; } static bool ep0_clear_feature_proc(void) { const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); if ((bm_req_type & SETUP_DIR) != SETUP_INPUT) return false; const uint8_t recipient = bm_req_type & SETUP_RECIPIENT; switch (recipient) { case SETUP_DEVICE: return ep0_dev_feature_clear(); case SETUP_EP: return ep0_ep_feature_clear(); default: break; } return false; } static bool ep0_dev_feature_set(void) { const uint8_t feature = hid_ep0_setup_lvalue_get(); switch (feature) { case FEATURE_REMOTE_WAKEUP: g_rwuen = true; return true; case FEATURE_TEST_MODE: // This is "test mode", just return the handshake. return true; default: break; } return false; } static bool ep0_ep_feature_set(void) { const uint8_t feature = hid_ep0_setup_lvalue_get(); if (feature != FEATURE_STALL) return false; const uint8_t ep = hid_ep0_setup_lindex_get(); const uint8_t ep_num = ep & ~SETUP_DIR; if (ep_num == 0) { // Do nothing. } else if ((ep_num == 1) && (ep & SETUP_DIR) == SETUP_INPUT) { // We support only one input ep1 in. hid_ep1_in_stall(); } else { return false; } hid_ep0_in_clear(); return true; } static bool ep0_set_feature_proc(void) { const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); switch (bm_req_type & SETUP_RECIPIENT) { case SETUP_DEVICE: return ep0_dev_feature_set(); case SETUP_EP: return ep0_ep_feature_set(); default: break; } return false; } static bool ep0_set_address_proc(void) { hid_ep0_out_stall(); const uint8_t address = hid_ep0_setup_lvalue_get(); if (address >= 128) return false; USBFUNADR = address; hid_ep0_in_clear(); return true; } static bool ep0_descriptor_proc(uint8_t type) { uint16_t length = 0; const uint8_t *pdesc = hid_ep0_desc_get(type, &length); if (!pdesc) return false; ep0_in_response_create(pdesc, length); return true; } static bool ep0_get_descriptor_proc(void) { const uint8_t descr_type = hid_ep0_setup_hvalue_get(); switch (descr_type) { case DESC_DEVICE: case DESC_CONF: case DESC_STRING: case DESC_DEVICE_QUAL: case DESC_OTHER_SPEED_CONF: case DESC_HID: case DESC_REPORT: return ep0_descriptor_proc(descr_type); } return false; } static bool ep0_get_config_proc(void) { // We only support configuration 1. const uint8_t cfg_num = HID_CONFIG_NUMBER; ep0_in_response_create(&cfg_num, sizeof(cfg_num)); return true; } static bool ep0_set_config_proc(void) { const uint8_t cfg_num = hid_ep0_setup_lvalue_get(); // We only support configuration 1. const bool is_valid = (cfg_num & HID_CONFIG_NUMBER); hid_ep0_enumerated_set(is_valid); return is_valid; } static bool ep0_get_iface_proc(void) { const uint8_t iface_num = hid_ep0_setup_lindex_get(); if (iface_num != HID_IFACE_NUMBER) return false; ep0_in_response_create(&iface_num, sizeof(iface_num)); return true; } static bool ep0_set_iface_proc(void) { const uint8_t iface_num = hid_ep0_setup_lindex_get(); if (iface_num != HID_IFACE_NUMBER) return false; const uint8_t alt_iface_num = hid_ep0_setup_lvalue_get(); if (alt_iface_num != HID_ALT_IFACE_NUMBER) return false; hid_ep0_out_stall(); hid_ep0_in_clear(); return true; } static bool ep0_std_proc(void) { const uint8_t request_code = hid_ep0_setup_request_get(); switch (request_code) { case SETUP_GET_STATUS: return ep0_get_status_proc(); case SETUP_CLEAR_FEATURE: return ep0_clear_feature_proc(); case SETUP_SET_FEATURE: return ep0_set_feature_proc(); case SETUP_SET_ADDRESS: return ep0_set_address_proc(); case SETUP_GET_DESCRIPTOR: return ep0_get_descriptor_proc(); case SETUP_GET_CONFIGURATION: return ep0_get_config_proc(); case SETUP_SET_CONFIGURATION: return ep0_set_config_proc(); case SETUP_GET_INTERFACE: return ep0_get_iface_proc(); case SETUP_SET_INTERFACE: return ep0_set_iface_proc(); default: break; } return false; } static bool ep0_setup(void) { const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); const uint8_t setup_type = bm_req_type & SETUP_TYPE; switch (setup_type) { case SETUP_STANDARD: return ep0_std_proc(); default: break; } return false; } static bool ep0_has_another_setup(void) { if ((USBIFG & STPOWIFG) != 0) { USBIFG &= ~(STPOWIFG | SETUPIFG); return true; } return false; } void hid_ep0_init(void) { hid_ep0_in_nak(); hid_ep0_out_nak(); g_ep0.IEPCNFG = UBME | STALL | USBIIE; g_ep0.OEPCNFG = UBME | STALL | USBIIE; // Enable only ep0in interrupts. USBIEPIE |= BIT0; } void hid_ep0_setup_handler(void) { USBCTL |= FRSTE; g_ep0_response.length = 0; g_ep0_response.offset = 0; g_ep0_response.action = STATUS_ACTION_NOTHING; g_ep0_response.host_ask_more_data_than_available = false; for (;;) { const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); if ((bm_req_type & SETUP_INPUT) == SETUP_INPUT) USBCTL |= DIR; else USBCTL &= ~DIR; const bool success = ep0_setup(); if (success) { hid_ep0_out_clear(); ep0_in_frame_send(); } else { hid_ep0_in_stall(); } if (!ep0_has_another_setup()) return; } } void hid_ep0_in_handler(void) { USBCTL |= FRSTE; hid_ep0_out_clear(); if (g_ep0_response.action == STATUS_ACTION_DATA_IN) ep0_in_frame_send(); else hid_ep0_in_stall(); } void hid_ep0_in_nak(void) { g_ep0.IEPBCNT = NAK; } void hid_ep0_in_stall(void) { g_ep0.IEPCNFG |= STALL; } void hid_ep0_in_clear(void) { g_ep0_response.length = EP_NO_MORE_DATA; g_ep0_response.action = STATUS_ACTION_NOTHING; g_ep0.IEPBCNT = 0; } bool hid_ep0_in_is_stalled(void) { return (g_ep0.IEPCNFG & STALL); } void hid_ep0_out_nak(void) { g_ep0.OEPBCNT = NAK; } void hid_ep0_out_stall(void) { g_ep0.OEPCNFG |= STALL; } void hid_ep0_out_clear(void) { g_ep0.OEPBCNT = 0; } uint8_t hid_ep0_setup_bm_request_type_get(void) { return g_setupdat[0]; } uint8_t hid_ep0_setup_request_get(void) { return g_setupdat[1]; } uint8_t hid_ep0_setup_lvalue_get(void) { return g_setupdat[2]; } uint8_t hid_ep0_setup_hvalue_get(void) { return g_setupdat[3]; } uint8_t hid_ep0_setup_lindex_get(void) { return g_setupdat[4]; } uint8_t hid_ep0_setup_hindex_get(void) { return g_setupdat[5]; } void hid_ep0_enumerated_set(bool enumerated) { g_enumerated = enumerated; } bool hid_ep0_is_enumerated(void) { return g_enumerated; } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/gpio.c0000644000175100001660000001327314776170045023417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hwdefs.h" #include "gpio.h" enum { INVALID_ADDRESS = 0xFFFF }; static uint16_t gpio_port_address_get(enum gpio_port port) { switch (port) { case GPIO_PORT_P1: return P1_BASE; case GPIO_PORT_P2: return P2_BASE; case GPIO_PORT_P3: return P3_BASE; case GPIO_PORT_P4: return P4_BASE; case GPIO_PORT_P5: return P5_BASE; case GPIO_PORT_P6: return P6_BASE; case GPIO_PORT_P7: return P7_BASE; case GPIO_PORT_P8: return P8_BASE; case GPIO_PORT_PJ: return PJ_BASE; default: break; } return INVALID_ADDRESS; } static uint16_t gpio_pins_adjust(enum gpio_port port, uint16_t pins) { if ((port & 1) ^ 1) pins <<= 8; return pins; } void gpio_pins_set_as_out(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PASEL) &= ~pins; HWREG16(base_address + OFS_PADIR) |= pins; } void gpio_pins_set_as_in(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PASEL) &= ~pins; HWREG16(base_address + OFS_PADIR) &= ~pins; HWREG16(base_address + OFS_PAREN) &= ~pins; } void gpio_pins_set_as_pf_out(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PADIR) |= pins; HWREG16(base_address + OFS_PASEL) |= pins; } void gpio_pins_set_as_pf_in(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PADIR) &= ~pins; HWREG16(base_address + OFS_PASEL) |= pins; } void gpio_pins_set_high(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PAOUT) |= pins; } void gpio_pins_set_low(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PAOUT) &= ~pins; } void gpio_pins_toggle(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return; pins = gpio_pins_adjust(port, pins); HWREG16(base_address + OFS_PAOUT) ^= pins; } enum gpio_pin_status gpio_pin_get(enum gpio_port port, uint16_t pins) { const uint16_t base_address = gpio_port_address_get(port); if (base_address == INVALID_ADDRESS) return GPIO_INPUT_PIN_LOW; pins = gpio_pins_adjust(port, pins); const uint16_t value = HWREG16(base_address + OFS_PAIN) & pins; return (value > 0) ? GPIO_INPUT_PIN_HIGH : GPIO_INPUT_PIN_LOW; } qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/hwdefs.h0000644000175100001660000000621214776170045023741 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MSP430_HW_DEFS_H #define MSP430_HW_DEFS_H #include #include #if defined(__ICC430__) # define _PPTOSTR_(x) #x # define _PPARAM_(address) _PPTOSTR_(vector=address) # define INTERRUPT(isr_name, vector) \ _Pragma(_PPARAM_(vector)) __interrupt void isr_name(void) #elif defined(__GNUC__) # define INTERRUPT(isr_name, vector) \ void __attribute__ ((interrupt(vector))) isr_name(void) #else # error "Unsupported toolchain" #endif #include #include #define HWREG8(x) \ (*((volatile uint8_t *)((uint16_t)x))) #define HWREG16(x) \ (*((volatile uint16_t *)((uint16_t)x))) #define HWREG32(x) \ (*((volatile uint32_t *)((uint16_t)x))) #endif // MSP430_HW_DEFS_H qbs-src-2.6.1/examples/baremetal/msp430f5529/nes-gamepads/hiddesc.c0000644000175100001660000002531714776170045024066 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "hid.h" #include "usb.h" #include #define usb_word_msb_get(word) \ (uint8_t)(((uint16_t)(word) >> 8) & 0xFF) #define usb_word_lsb_get(word) \ (uint8_t)((uint16_t)(word) & 0xFF) enum usb_bcd_version { SPEC_BCD_VERSION = 0x0200, DEVICE_BCD_VERSION = 0x1234, HID_BCD_VERSION = 0x0111 }; enum usb_ids { DEVICE_VID = 0xFFFF, DEVICE_PID = 0xFFFF }; enum usb_lang_id { LANG_ID = 0x0409 }; enum usb_descriptor_string_index { DESC_LANGID_STRING_INDEX = 0, DESC_MFG_STRING_INDEX, DESC_PRODUCT_STRING_INDEX, DESC_SERIAL_STRING_INDEX }; enum usb_descr_length { // Standard length. DESC_DEVICE_LEN = 18, DESC_DEVICE_QUAL_LEN = 10, DESC_CONF_LEN = 9, DESC_OTHER_SPEED_CONF_LEN = 9, DESC_INTERFACE_LEN = 9, DESC_HID_LEN = 9, DESCR_HID_REP_LEN = 56, DESC_ENDPOINT_LEN = 7, // Total length. DESC_DEVICE_TOTAL_LEN = DESC_DEVICE_LEN, DESC_DEVICE_QUAL_TOTAL_LEN = DESC_DEVICE_QUAL_LEN, DESC_CONF_TOTAL_LEN = DESC_CONF_LEN + DESC_INTERFACE_LEN + DESC_HID_LEN + DESC_ENDPOINT_LEN, DESC_OTHER_SPEED_CONF_TOTAL_LEN = DESC_OTHER_SPEED_CONF_LEN + DESC_INTERFACE_LEN, DESCR_HID_REP_TOTAL_LEN = DESCR_HID_REP_LEN }; enum usb_descr_attributes { // Attributes (b7 - buspwr, b6 - selfpwr, b5 - rwu). USB_DESC_ATTRIBUTES = 0xA0, // 100 mA (div 2). USB_DESC_POWER_CONSUMPTION = 50 }; enum usb_descr_numbers { USB_DESC_CONFIG_COUNT = 1 }; static const uint8_t g_hid_report_desc[DESCR_HID_REP_TOTAL_LEN] = { // Pad #1 configuration. 0x05, 0x01, // Usage page (Generic Desktop). 0x09, 0x05, // Usage (Game Pad). 0xa1, 0x01, // Collection (Application). 0xa1, 0x00, // Collection (Physical). 0x85, HID_REPORT_ID_GAMEPAD1, // Report id (1). 0x05, 0x09, // Usage page (Button). 0x19, 0x01, // Usage minimum (Button 1). 0x29, 0x08, // Usage maximum (Button 8). 0x15, 0x00, // Logical minimum (0). 0x25, 0x01, // Logical maximum (1). 0x95, HID_REPORT_BITS_COUNT, // Report count (8). 0x75, 0x01, // Report size (1). 0x81, 0x02, // Input (Data,Var,Abs). 0xc0, // End collection. 0xc0, // End collection. // Pad #2 configuration. 0x05, 0x01, // Usage page (Generic Desktop). 0x09, 0x05, // Usage (Game Pad). 0xa1, 0x01, // Collection (Application). 0xa1, 0x00, // Collection (Physical). 0x85, HID_REPORT_ID_GAMEPAD2, // Report id (2). 0x05, 0x09, // Usage page (Button). 0x19, 0x01, // Usage minimum (Button 1). 0x29, 0x08, // Usage maximum (Button 8). 0x15, 0x00, // Logical minimum (0). 0x25, 0x01, // Logical maximum (1). 0x95, HID_REPORT_BITS_COUNT, // Report count (8). 0x75, 0x01, // Report size (1). 0x81, 0x02, // Input (Data,Var,Abs). 0xc0, // End collection 0xc0 // End collection. }; static const uint8_t g_device_desc[DESC_DEVICE_TOTAL_LEN] = { DESC_DEVICE_LEN, // Descriptor length. DESC_DEVICE, // Descriptor type. usb_word_lsb_get(SPEC_BCD_VERSION), // USB BCD version, lo. usb_word_msb_get(SPEC_BCD_VERSION), // USB BCD version, hi. 0x00, // Device class. 0x00, // Device sub-class. 0x00, // Device protocol. EP0_MAX_PACKET_SIZE, // Maximum packet size (ep0 size). usb_word_lsb_get(DEVICE_VID), // Vendor ID, lo. usb_word_msb_get(DEVICE_VID), // Vendor ID, hi. usb_word_lsb_get(DEVICE_PID), // Product ID, lo. usb_word_msb_get(DEVICE_PID), // Product ID, hi. usb_word_lsb_get(DEVICE_BCD_VERSION), // Device BCD version, lo. usb_word_msb_get(DEVICE_BCD_VERSION), // Device BCD version, hi. DESC_MFG_STRING_INDEX, DESC_PRODUCT_STRING_INDEX, DESC_SERIAL_STRING_INDEX, USB_DESC_CONFIG_COUNT // Configurations count. }; static const uint8_t g_device_qual_desc[DESC_DEVICE_QUAL_TOTAL_LEN] = { DESC_DEVICE_QUAL_LEN, // Descriptor length. DESC_DEVICE_QUAL, // Descriptor type. usb_word_lsb_get(SPEC_BCD_VERSION), // USB BCD version, lo. usb_word_msb_get(SPEC_BCD_VERSION), // USB BCD version, hi. 0x00, // Device class. 0x00, // Device sub-class. 0x00, // Device protocol. EP0_MAX_PACKET_SIZE, // Maximum packet size (ep0 size). USB_DESC_CONFIG_COUNT, // Configurations count. 0x00 // Reserved. }; static const uint8_t g_config_desc[DESC_CONF_TOTAL_LEN] = { DESC_CONF_LEN, // Descriptor length. DESC_CONF, // Descriptor type. usb_word_lsb_get(DESC_CONF_TOTAL_LEN), // Total length, lo. usb_word_msb_get(DESC_CONF_TOTAL_LEN), // Total length, hi. 0x01, // Interfaces count. HID_CONFIG_NUMBER, // Configuration number. 0x00, // Configuration string index. USB_DESC_ATTRIBUTES, // Attributes. USB_DESC_POWER_CONSUMPTION, // Power consumption. // Interface descriptor. DESC_INTERFACE_LEN, // Descriptor length. DESC_INTERFACE, // Descriptor type. HID_IFACE_NUMBER, // Zero-based index of this interfacce. HID_ALT_IFACE_NUMBER, // Alternate setting. 0x01, // End points count (ep1 in). 0x03, // Class code (HID). 0x00, // Subclass code (boot). 0x00, // Protocol code (none). 0x00, // Interface string descriptor index. // HID descriptor. DESC_HID_LEN, // Descriptor length. DESC_HID, // Descriptor type. usb_word_lsb_get(HID_BCD_VERSION), // HID class BCD version, lo. usb_word_msb_get(HID_BCD_VERSION), // HID class BCD version, hi. 0x00, // Country code (HW country code). 0x01, // Number of HID class descriptors to follow. DESC_REPORT, // Repord descriptor type (HID). usb_word_lsb_get(DESCR_HID_REP_LEN), // Report descriptor total length, lo. usb_word_msb_get(DESCR_HID_REP_LEN), // Report descriptor total length, hi. // End point descriptor. DESC_ENDPOINT_LEN, // Descriptor length. DESC_ENDPOINT, // Descriptor type. HID_EP_IN, // End point address (ep1 in). 0x03, // End point type (interrupt). usb_word_lsb_get(EP_MAX_PACKET_SIZE), // Maximum packet size, lo (ep1 size). usb_word_msb_get(EP_MAX_PACKET_SIZE), // Maximum packet size, hi (ep1 size). 0x01 // Polling interval (1 ms). }; static const uint8_t g_lang_id_desc[] = { 0x04, // Descriptor length. DESC_STRING, // Descriptor type. usb_word_lsb_get(LANG_ID), // Language id, lo. usb_word_msb_get(LANG_ID) // Language id, hi. }; static const uint8_t g_manuf_str_desc[] = { 0x18, // Descriptor length. DESC_STRING, // Descriptor type. // Unicode string: 'Q', 0, 'B', 0, 'S', 0, ' ', 0, 'e', 0, 'x', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0 }; static const uint8_t g_product_str_desc[] = { 0x1A, // Descriptor length. DESC_STRING, // Descriptor type. // Unicode string: 'N', 0, 'E', 0, 'S', 0, ' ', 0, 'G', 0, 'a', 0, 'm', 0, 'e', 0, 'P', 0, 'a', 0, 'd', 0, 's', 0 }; static const uint8_t g_serialno_str_desc[] = { 0x1A, // Descriptor length. DESC_STRING, // Descriptor type. // Unicode string: '0', 0 ,'1', 0, '0', 0, '2', 0, '0', 0, '3', 0, '0', 0, '4', 0, '0', 0, '5', 0, '0', 0, '6', 0 }; static const uint8_t *ep0_string_desc_get(uint16_t *length) { const uint8_t index = hid_ep0_setup_lvalue_get(); switch (index) { case DESC_LANGID_STRING_INDEX: *length = sizeof(g_lang_id_desc); return g_lang_id_desc; case DESC_MFG_STRING_INDEX: *length = sizeof(g_manuf_str_desc); return g_manuf_str_desc; case DESC_PRODUCT_STRING_INDEX: *length = sizeof(g_product_str_desc); return g_product_str_desc; case DESC_SERIAL_STRING_INDEX: *length = sizeof(g_serialno_str_desc); return g_serialno_str_desc; default: break; } return 0; } const uint8_t *hid_ep0_desc_get(uint8_t type, uint16_t *length) { switch (type) { case DESC_DEVICE: *length = DESC_DEVICE_TOTAL_LEN; return g_device_desc; case DESC_CONF: *length = DESC_CONF_TOTAL_LEN; return g_config_desc; case DESC_STRING: return ep0_string_desc_get(length); case DESC_DEVICE_QUAL: *length = DESC_DEVICE_QUAL_TOTAL_LEN; return g_device_qual_desc; case DESC_HID: *length = DESC_HID_LEN; return &g_config_desc[DESC_CONF_LEN + DESC_INTERFACE_LEN]; case DESC_REPORT: *length = DESCR_HID_REP_TOTAL_LEN; return g_hid_report_desc; default: break; } return 0; } qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/0000755000175100001660000000000014776170045021535 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/README.md0000644000175100001660000000045714776170045023022 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different MSP430 toolchains. It is designed for the MSP-EXP430F5529LP target board (based on msp430f5529 chip) and simply flashes the red LED on the board. The following toolchains are supported: * IAR Embedded Workbench * GCC qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/system.h0000644000175100001660000000506614776170045023241 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #ifdef __cplusplus extern "C" { #endif void system_init(void); #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/redblink.qbs0000644000175100001660000001063414776170045024042 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.contains("msp430")) return false; return qbs.toolchain.contains("iar") || qbs.toolchain.contains("gcc") } name: "msp430f5529-redblink" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.driverFlags: ["--core=430X"] cpp.entryPoint: "__program_start" cpp.driverLinkerFlags: [ "-D_STACK_SIZE=A0", "-D_DATA16_HEAP_SIZE=A0", "-D_DATA20_HEAP_SIZE=50", ] cpp.staticLibraries: [ // Explicitly link with the runtime dlib library (which contains // all required startup code and other stuff). cpp.toolchainInstallPath + "/../lib/dlib/dl430xlsfn.r43" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Linker Script" prefix: cpp.toolchainInstallPath + "/../config/linker/" fileTags: ["linkerscript"] // Explicitly use the default linker scripts for current target. files: ["lnk430f5529.xcl", "multiplier32.xcl"] } } // // GCC-specific properties and soucres. // Properties { condition: qbs.toolchain.contains("gcc") property path supportFilesPath // A path to the MSP430 support files, which are // provided by the Texas Instruments separately: // e.g. 'c:/msp430-gcc-support-files/include/' cpp.includePaths: supportFilesPath cpp.libraryPaths: supportFilesPath cpp.driverFlags: ["-mmcu=msp430f5529"] } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.c", "system.h"] } files: [ "main.c", ] } qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/gpio.h0000644000175100001660000000512614776170045022650 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_red_led(void); void gpio_toggle_red_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/main.c0000644000175100001660000000535214776170045022632 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" #include static void some_delay(uint32_t counts) { for (uint32_t index = 0u; index < counts; ++index) __asm("nop"); } int main(void) { system_init(); gpio_init_red_led(); while (1) { gpio_toggle_red_led(); some_delay(10000u); } } qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/system.c0000644000175100001660000000523314776170045023230 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "system.h" #if defined(__ICC430__) #include #elif defined(__GNUC__) #include #else #error "Unsupported toolchain" #endif void system_init(void) { // Stop watchdog timer. WDTCTL = WDTPW + WDTHOLD; } qbs-src-2.6.1/examples/baremetal/msp430f5529/redblink/gpio.c0000644000175100001660000000566314776170045022651 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #if defined(__ICC430__) #include #elif defined(__GNUC__) #include #else #error "Unsupported toolchain" #endif // LED pin number. #define GPIO_RED_LED_PIN_POS (0u) // LED port direction. #define GPIO_RED_LED_PORT_DIR (P1DIR) // LED output port. #define GPIO_RED_LED_PORT_OUT (P1OUT) void gpio_init_red_led(void) { GPIO_RED_LED_PORT_DIR |= (1u << GPIO_RED_LED_PIN_POS); } void gpio_toggle_red_led(void) { GPIO_RED_LED_PORT_OUT ^= (1u << GPIO_RED_LED_PIN_POS); } qbs-src-2.6.1/examples/baremetal/msp430f5529/msp430f5529.qbs0000644000175100001660000000507214776170045022177 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for msp430f5529 board" references: [ "redblink/redblink.qbs", "nes-gamepads/nes-gamepads.qbs" ] } qbs-src-2.6.1/examples/baremetal/pca10040/0000755000175100001660000000000014776170045017352 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10040/pca10040.qbs0000644000175100001660000000502214776170045021210 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for pca10040 board" references: [ "greenblink/greenblink.qbs" ] } qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/0000755000175100001660000000000014776170045021472 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10040/greenblink/README.md0000644000175100001660000000055214776170045022753 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different ARM toolchains. It is designed for the Nordic pca10040 evaluation kit (based on nRF52832 MCU) and simply flashes the green LED on the board. The following toolchains are supported: * GNU Arm Embedded Toolchain * IAR Embedded Workbench * KEIL Microcontroller Development Kit qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/keil/0000755000175100001660000000000014776170045022416 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10040/greenblink/keil/flash.sct0000644000175100001660000000534514776170045024235 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ ;; Load region size_region. LR_IROM1 0x00000000 0x00080000 { ;; Load address = execution address. ER_IROM1 0x00000000 0x00080000 { *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) .ANY (+XO) } ; RW data. RW_IRAM1 0x20000000 0x00008000 { .ANY (+RW +ZI) } } qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/keil/startup.s0000644000175100001660000002021314776170045024302 0ustar runnerdocker;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Copyright (C) 2020 Denis Shienkov ;; Contact: https://www.qt.io/licensing/ ;; ;; This file is part of the examples of Qbs. ;; ;; $QT_BEGIN_LICENSE:BSD$ ;; 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 https://www.qt.io/terms-conditions. For further ;; information use the contact form at https://www.qt.io/contact-us. ;; ;; BSD License Usage ;; Alternatively, you may use this file under the terms of the BSD license ;; as follows: ;; ;; "Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions are ;; met: ;; * Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; * Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in ;; the documentation and/or other materials provided with the ;; distribution. ;; * Neither the name of The Qt Company Ltd nor the names of its ;; contributors may be used to endorse or promote products derived ;; from this software without specific prior written permission. ;; ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ;; ;; $QT_END_LICENSE$ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _size_of_stack EQU 0x2000 _size_of_heap EQU 0x2000 ;; Stack configuration. AREA STACK, NOINIT, READWRITE, ALIGN=3 _start_of_stack SPACE _size_of_stack _end_of_stack ;; Heap configuration. AREA HEAP, NOINIT, READWRITE, ALIGN=3 _start_of_heap SPACE _size_of_heap _end_of_heap PRESERVE8 THUMB ;; Define the empty vectors table. AREA RESET, DATA, READONLY _vectors_table ;; Generic interrupts offset. DCD _end_of_stack ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Memory management fault. DCD 0 ; Bus fault. DCD 0 ; Usage fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Debug monitor. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Power clock. DCD 0 ; Radio. DCD 0 ; UARTE0/UART0. DCD 0 ; SPIM0/SPIS0/TWIM0/TWIS0/SPI0/TWI0. DCD 0 ; SPIM1/SPIS1/TWIM1/TWIS1/SPI1/TWI1. DCD 0 ; NFCT. DCD 0 ; GPIOTE. DCD 0 ; SAADC. DCD 0 ; TIMER0. DCD 0 ; TIMER1. DCD 0 ; TIMER2. DCD 0 ; RTC0. DCD 0 ; TEMP. DCD 0 ; RNG. DCD 0 ; ECB. DCD 0 ; CCM/AAR. DCD 0 ; WDT. DCD 0 ; RTC1. DCD 0 ; QDEC. DCD 0 ; COMP/LPCOMP. DCD 0 ; SWI0/EGU0. DCD 0 ; SWI1/EGU1. DCD 0 ; SWI2/EGU2. DCD 0 ; SWI3/EGU3. DCD 0 ; SWI4/EGU4. DCD 0 ; SWI5/EGU5. DCD 0 ; TIMER3. DCD 0 ; TIMER4. DCD 0 ; PWM0. DCD 0 ; PDM. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; MWU. DCD 0 ; PWM1. DCD 0 ; PWM2. DCD 0 ; SPIM2/SPIS2/SPI2. DCD 0 ; RTC2. DCD 0 ; I2S. DCD 0 ; FPU. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. _end_of_vectors_table _size_of_vectors_table EQU _end_of_vectors_table - _vectors_table AREA |.text|, CODE, READONLY ;; Reset handler. reset_handler PROC EXPORT reset_handler [WEAK] IMPORT main LDR R0, =main BX R0 ENDP ALIGN END qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/iar/0000755000175100001660000000000014776170045022245 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10040/greenblink/iar/flash.icf0000644000175100001660000001174214776170045024032 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ define symbol _start_of_intvec_section = 0x00000000; define symbol _start_of_irom1_section = 0x00000000; define symbol _end_of_irom1_section = 0x0007FFFF; define symbol _start_of_irom2_section = 0x0; define symbol _end_of_irom2_section = 0x0; define symbol _start_of_erom1_section = 0x0; define symbol _end_of_erom1_section = 0x0; define symbol _start_of_erom2_section = 0x0; define symbol _end_of_erom2_section = 0x0; define symbol _start_of_erom3_section = 0x0; define symbol _end_of_erom3_section = 0x0; define symbol _start_of_iram1_section = 0x20000000; define symbol _end_of_iram1_section = 0x2000FFFF; define symbol _start_of_iram2_section = 0x0; define symbol _end_of_iram2_section = 0x0; define symbol _start_of_eram1_section = 0x0; define symbol _end_of_eram1_section = 0x0; define symbol _start_of_eram2_section = 0x0; define symbol _end_of_eram2_section = 0x0; define symbol _start_of_eram3_section = 0x0; define symbol _end_of_eram3_section = 0x0; define symbol _min_stack_size = 0x2000; define symbol _min_proc_stack_size = 0x0; define symbol _min_heap_size = 0x2000; define memory mem with size = 4G; define region irom_section = mem:[from _start_of_irom1_section to _end_of_irom1_section] | mem:[from _start_of_irom2_section to _end_of_irom2_section]; define region erom_section = mem:[from _start_of_erom1_section to _end_of_erom1_section] | mem:[from _start_of_erom2_section to _end_of_erom2_section] | mem:[from _start_of_erom3_section to _end_of_erom3_section]; define region iram_section = mem:[from _start_of_iram1_section to _end_of_iram1_section] | mem:[from _start_of_iram2_section to _end_of_iram2_section]; define region eram_section = mem:[from _start_of_eram1_section to _end_of_eram1_section] | mem:[from _start_of_eram2_section to _end_of_eram2_section] | mem:[from _start_of_eram3_section to _end_of_eram3_section]; define block CSTACK with alignment = 8, size = _min_stack_size { }; define block PROC_STACK with alignment = 8, size = _min_proc_stack_size { }; define block HEAP with alignment = 8, size = _min_heap_size { }; initialize by copy { readwrite }; place at address mem:_start_of_intvec_section { readonly section .intvec }; place in irom_section { readonly }; place in erom_section { readonly section application_specific_ro }; place in iram_section { readwrite, block CSTACK, block HEAP, block PROC_STACK }; place in eram_section { readwrite section application_specific_rw }; qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/iar/startup.s0000644000175100001660000001753314776170045024144 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MODULE ?cstartup SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start PUBLIC _vectors_table DATA _vectors_table ;; Generic interrupts offset. DCD sfe(CSTACK) ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Memory management fault. DCD 0 ; Bus fault. DCD 0 ; Usage fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; POWER CLOCK. DCD 0 ; RADIO. DCD 0 ; UARTE0/UART0 DCD 0 ; SPIM0/SPIS0/TWIM0/TWIS0/SPI0/TWI0. DCD 0 ; SPIM1/SPIS1/TWIM1/TWIS1/SPI1/TWI1. DCD 0 ; NFCT. DCD 0 ; GPIOTE. DCD 0 ; SAADC. DCD 0 ; TIMER0. DCD 0 ; TIMER1. DCD 0 ; TIMER2. DCD 0 ; RTC0. DCD 0 ; TEMP. DCD 0 ; RNG. DCD 0 ; ECB. DCD 0 ; CCM_AAR. DCD 0 ; WDT. DCD 0 ; RTC1. DCD 0 ; QDEC. DCD 0 ; COMP_LPCOMP. DCD 0 ; SWI0_EGU0. DCD 0 ; SWI1_EGU1. DCD 0 ; SWI2_EGU2. DCD 0 ; SWI3_EGU3. DCD 0 ; SWI4_EGU4. DCD 0 ; SWI5_EGU5. DCD 0 ; TIMER3. DCD 0 ; TIMER4. DCD 0 ; PWM0. DCD 0 ; PDM. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; MWU. DCD 0 ; PWM1. DCD 0 ; PWM2. DCD 0 ; SPIM2/SPIS2/SPI2. DCD 0 ; RTC2. DCD 0 ; I2S. DCD 0 ; FPU. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. ;; Reset handler. THUMB PUBWEAK reset_handler SECTION .text:CODE:REORDER:NOROOT(2) reset_handler BLX R0 LDR R0, =__iar_program_start BX R0 END qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/greenblink.qbs0000644000175100001660000001216214776170045024323 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.startsWith("arm")) return false; return (qbs.toolchain.contains("gcc") || qbs.toolchain.contains("iar") || qbs.toolchain.contains("keil")) && !qbs.toolchain.contains("xcode") } name: "pca10040-greenblink" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // GCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("gcc") cpp.assemblerFlags: [ "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", ] cpp.driverFlags: [ "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-specs=nosys.specs" ] } Group { condition: qbs.toolchain.contains("gcc") name: "GCC" prefix: "gcc/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.ld"] } } // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.assemblerFlags: [ "--cpu", "cortex-m4", "--fpu", "vfpv4_sp" ] cpp.driverFlags: [ "--cpu", "cortex-m4", "--fpu", "vfpv4_sp" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.icf"] } } // // KEIL-specific properties and sources. // Properties { condition: qbs.toolchain.contains("keil") cpp.assemblerFlags: [ "--cpu", "cortex-m4.fp.sp" ] cpp.driverFlags: [ "--cpu", "cortex-m4.fp.sp" ] } Group { condition: qbs.toolchain.contains("keil") name: "KEIL" prefix: "keil/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.sct"] } } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/gcc/0000755000175100001660000000000014776170045022226 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/pca10040/greenblink/gcc/flash.ld0000644000175100001660000001162614776170045023652 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ ENTRY(reset_handler) MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x80000 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 CODE_RAM (rwx) : ORIGIN = 0x800000, LENGTH = 0x10000 } SECTIONS { .text : { KEEP(*(.isr_vector)) *(.text*) KEEP(*(.init)) KEEP(*(.fini)) /* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors) /* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors) *(.rodata*) *(.eh_frame*) . = ALIGN(4); } > FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } > FLASH _start_of_exidx_section = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) . = ALIGN(4); } > FLASH _end_of_exidx_section = .; _end_of_code_section = .; .data : AT (_end_of_code_section) { _start_of_data_section = .; *(vtable) *(.data*) . = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN(__preinit_array_start = .); *(.preinit_array) PROVIDE_HIDDEN(__preinit_array_end = .); . = ALIGN(4); /* init data */ PROVIDE_HIDDEN(__init_array_start = .); *(SORT(.init_array.*)) *(.init_array) PROVIDE_HIDDEN(__init_array_end = .); . = ALIGN(4); /* finit data */ PROVIDE_HIDDEN(__fini_array_start = .); *(SORT(.fini_array.*)) *(.fini_array) PROVIDE_HIDDEN(__fini_array_end = .); *(.jcr) . = ALIGN(4); /* All data end */ _end_of_data_section = .; } > RAM .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; } > RAM .heap (COPY): { __end__ = .; end = __end__; *(.heap*) _heap_limit = .; } > RAM .stack_dummy (COPY): { *(.stack*) } > RAM /* Set stack top to end of RAM, and stack limit move down by size of stack_dummy section. */ _end_of_stack = ORIGIN(RAM) + LENGTH(RAM); _stack_limit = _end_of_stack - SIZEOF(.stack_dummy); PROVIDE(__stack = _end_of_stack); /* Check if data + heap + stack exceeds RAM limit */ ASSERT(_stack_limit >= _heap_limit, "region RAM overflowed with stack") } qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/gcc/startup.s0000644000175100001660000002226514776170045024123 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ .syntax unified .arch armv7e-m .thumb // Define the stack. .section .stack .align 3 .equ _size_of_stack, 8192 .globl _end_of_stack .globl _stack_limit _stack_limit: .space _size_of_stack .size _stack_limit, . - _stack_limit _end_of_stack: .size _end_of_stack, . - _end_of_stack // Define the heap. .section .heap .align 3 .equ _size_of_heap, 8192 .globl _end_of_heap .globl _heap_limit _end_of_heap: .space _size_of_heap .size _end_of_heap, . - _end_of_heap _heap_limit: .size _heap_limit, . - _heap_limit // Define the empty vectors table. .section .isr_vector, "ax" .align 2 .globl _vectors_table _vectors_table: // Generic interrupts offset. .word _end_of_stack // Initial stack pointer value. .word reset_handler // Reset. .word 0 // NMI. .word 0 // Hard fault. .word 0 // Memory management fault. .word 0 // Bus fault. .word 0 // Usage fault. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // SVC. .word 0 // Debug monitor. .word 0 // Reserved. .word 0 // PendSV. .word 0 // SysTick. // External interrupts offset. .word 0 // POWER CLOCK. .word 0 // RADIO. .word 0 // UARTE0/UART0 .word 0 // SPIM0/SPIS0/TWIM0/TWIS0/SPI0/TWI0. .word 0 // SPIM1/SPIS1/TWIM1/TWIS1/SPI1/TWI1. .word 0 // NFCT. .word 0 // GPIOTE. .word 0 // SAADC. .word 0 // TIMER0. .word 0 // TIMER1. .word 0 // TIMER2. .word 0 // RTC0. .word 0 // TEMP. .word 0 // RNG. .word 0 // ECB. .word 0 // CCM_AAR. .word 0 // WDT. .word 0 // RTC1. .word 0 // QDEC. .word 0 // COMP_LPCOMP. .word 0 // SWI0_EGU0. .word 0 // SWI1_EGU1. .word 0 // SWI2_EGU2. .word 0 // SWI3_EGU3. .word 0 // SWI4_EGU4. .word 0 // SWI5_EGU5. .word 0 // TIMER3. .word 0 // TIMER4. .word 0 // PWM0. .word 0 // PDM. .word 0 // Reserved. .word 0 // Reserved. .word 0 // MWU. .word 0 // PWM1. .word 0 // PWM2. .word 0 // SPIM2/SPIS2/SPI2. .word 0 // RTC2. .word 0 // I2S. .word 0 // FPU. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .size _vectors_table, . - _vectors_table // Define the 'reset_handler' function, which is an entry point. .text .thumb .thumb_func .align 1 .globl reset_handler .type reset_handler, %function reset_handler: // Loop to copy data from read only memory to RAM. ldr r1, =_end_of_code_section ldr r2, =_start_of_data_section ldr r3, =__bss_start__ subs r3, r3, r2 ble _copy_data_init_done _copy_data_init: subs r3, r3, #4 ldr r0, [r1,r3] str r0, [r2,r3] bgt _copy_data_init _copy_data_init_done: // Zero fill the bss segment. ldr r1, =__bss_start__ ldr r2, =__bss_end__ movs r0, 0 subs r2, r2, r1 ble _loop_fill_zero_bss_done _loop_fill_zero_bss: subs r2, r2, #4 str r0, [r1, r2] bgt _loop_fill_zero_bss _loop_fill_zero_bss_done: // Call the application's entry point. bl main bx lr .size reset_handler, . - reset_handler qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/system.h0000644000175100001660000000604114776170045023170 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #include #ifdef __cplusplus extern "C" { #endif #define __IO volatile struct gpio_regs_map { uint32_t RESERVED0[321u]; __IO uint32_t OUT; __IO uint32_t OUTSET; __IO uint32_t OUTCLR; __IO uint32_t IN; __IO uint32_t DIR; __IO uint32_t DIRSET; __IO uint32_t DIRCLR; __IO uint32_t LATCH; __IO uint32_t DETECTMODE; uint32_t RESERVED1[118u]; __IO uint32_t PIN_CNF[32u]; }; #define GPIO_REGS_ADDRESS (0x50000000u) #define GPIOD_REGS_MAP ((struct gpio_regs_map *)GPIO_REGS_ADDRESS) #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/gpio.h0000644000175100001660000000513214776170045022602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_green_led(void); void gpio_toggle_green_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/main.c0000644000175100001660000000531014776170045022561 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include static void some_delay(uint32_t counts) { for (uint32_t index = 0u; index < counts; ++index) __asm("nop"); } int main(void) { gpio_init_green_led(); while (1) { gpio_toggle_green_led(); some_delay(1000000u); } } qbs-src-2.6.1/examples/baremetal/pca10040/greenblink/gpio.c0000644000175100001660000001063014776170045022574 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" #define GPIO_GREEN_LED_PIN_POS (17u) #define GPIO_GREEN_LED_PIN (1u << GPIO_GREEN_LED_PIN_POS) // Pin direction attributes. #define GPIO_PIN_CNF_DIR_POS (0u) // Position of DIR field. #define GPIO_PIN_CNF_DIR_OUT (1u) // Configure pin as an output pin. #define GPIO_PIN_CNF_DIR_MSK (GPIO_PIN_CNF_DIR_OUT << GPIO_PIN_CNF_DIR_POS) // Pin input buffer attributes. #define GPIO_PIN_CNF_INPUT_POS (1u) // Position of INPUT field. #define GPIO_PIN_CNF_INPUT_OFF (1u) // Disconnect input buffer. #define GPIO_PIN_CNF_INPUT_MSK (GPIO_PIN_CNF_INPUT_OFF << GPIO_PIN_CNF_INPUT_POS) // Pin pull attributes. #define GPIO_PIN_CNF_PULL_POS (2u) // Position of PULL field. #define GPIO_PIN_CNF_PULL_OFF (0u) // No pull. #define GPIO_PIN_CNF_PULL_MSK (GPIO_PIN_CNF_PULL_OFF << GPIO_PIN_CNF_PULL_POS) // Pin drive attributes. #define GPIO_PIN_CNF_DRIVE_POS (8u) // Position of DRIVE field. #define GPIO_PIN_CNF_DRIVE_S0S1 (0u) // Standard '0', standard '1'. #define GPIO_PIN_CNF_DRIVE_MSK (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_POS) // Pin sense attributes. #define GPIO_PIN_CNF_SENSE_POS (16u) // Position of SENSE field. #define GPIO_PIN_CNF_SENSE_OFF (0u) // Disabled. #define GPIO_PIN_CNF_SENSE_MSK (GPIO_PIN_CNF_SENSE_OFF << GPIO_PIN_CNF_SENSE_POS) void gpio_init_green_led(void) { GPIOD_REGS_MAP->PIN_CNF[GPIO_GREEN_LED_PIN_POS] = (GPIO_PIN_CNF_DIR_MSK | GPIO_PIN_CNF_INPUT_MSK | GPIO_PIN_CNF_PULL_MSK | GPIO_PIN_CNF_DRIVE_MSK | GPIO_PIN_CNF_SENSE_MSK); } void gpio_toggle_green_led(void) { const uint32_t gpio_state = GPIOD_REGS_MAP->OUT; GPIOD_REGS_MAP->OUTSET = (GPIO_GREEN_LED_PIN & ~gpio_state); GPIOD_REGS_MAP->OUTCLR = (GPIO_GREEN_LED_PIN & gpio_state); } qbs-src-2.6.1/examples/baremetal/stm8s103f3/0000755000175100001660000000000014776170045017755 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm8s103f3/stm8s103f3.qbs0000644000175100001660000000502014776170045022214 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for stm8s103f3 board" references: [ "redblink/redblink.qbs" ] } qbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/0000755000175100001660000000000014776170045021547 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/README.md0000644000175100001660000000045114776170045023026 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different STM8 toolchains. It is designed for the STM8 target board (based on STMicroelectronics stm8s103f3 MCU) and simply flashes the red LED on the board. The following toolchains are supported: * IAR Embedded Workbench qbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/system.h0000644000175100001660000000651214776170045023250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #ifdef __cplusplus extern "C" { #endif // Define required registers of Port B (where the LED is connected): // * PB_ODR - Output Data Register. // * PB_DDR - Data Direction Register. // * PB_CR1 - Control Register #1. // * PB_CR2 - Control Register #2. #if defined(__ICCSTM8__) # define system_nop() __asm("nop") __near __no_init volatile unsigned char PB_ODR @ 0x5005; __near __no_init volatile unsigned char PB_DDR @ 0x5007; __near __no_init volatile unsigned char PB_CR1 @ 0x5008; __near __no_init volatile unsigned char PB_CR2 @ 0x5009; #elif defined (__SDCC_stm8) # define system_nop() __asm nop __endasm #define PB_ODR *(volatile unsigned char *)0x5005 #define PB_DDR *(volatile unsigned char *)0x5007 #define PB_CR1 *(volatile unsigned char *)0x5008 #define PB_CR2 *(volatile unsigned char *)0x5009 #else #error "Unsupported toolchain" #endif #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/redblink.qbs0000644000175100001660000000717314776170045024060 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.contains("stm8")) return false; return qbs.toolchain.contains("iar") || qbs.toolchain.contains("sdcc") } name: "stm8s103f3-redblink" cpp.positionIndependentCode: false // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.commonCompilerFlags: ["-e"] cpp.driverLinkerFlags: [ "--config_def", "_CSTACK_SIZE=0x100", "--config_def", "_HEAP_SIZE=0x100", ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Linker Script" prefix: cpp.toolchainInstallPath + "/../config/" fileTags: ["linkerscript"] files: ["lnkstm8s103f3.icf"] } } // // SDCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("sdcc") } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/gpio.h0000644000175100001660000000512614776170045022662 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_red_led(void); void gpio_toggle_red_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/main.c0000644000175100001660000000533214776170045022642 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" static void some_delay(unsigned long counts) { unsigned long index = 0u; for (index = 0u; index < counts; ++index) system_nop(); } int main(void) { gpio_init_red_led(); while (1) { gpio_toggle_red_led(); some_delay(20000u); } } qbs-src-2.6.1/examples/baremetal/stm8s103f3/redblink/gpio.c0000644000175100001660000000555114776170045022657 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" // A LED is connected to the pin #5 of Port B. #define GPIO_RED_LED_PIN_POS (0x20u) void gpio_init_red_led(void) { PB_ODR = 0x00; // Turn off all pins. PB_DDR = GPIO_RED_LED_PIN_POS; // Configure Pin as output. PB_CR1 = GPIO_RED_LED_PIN_POS; // Set Pin to Push-Pull. PB_CR2 = GPIO_RED_LED_PIN_POS; // Set Pin to Push-Pull. } void gpio_toggle_red_led(void) { PB_ODR ^= GPIO_RED_LED_PIN_POS; } qbs-src-2.6.1/examples/baremetal/stm32f103/0000755000175100001660000000000014776170045017564 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/0000755000175100001660000000000014776170045021704 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/README.md0000644000175100001660000000056314776170045023167 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different ARM toolchains. It is designed for the stm32f103 "Blue Pill" evaluation kit (based on stm32f103c8 MCU) and simply flashes the green LED on the board. The following toolchains are supported: * GNU Arm Embedded Toolchain * IAR Embedded Workbench * KEIL Microcontroller Development Kit qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/keil/0000755000175100001660000000000014776170045022630 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/keil/flash.sct0000644000175100001660000000534514776170045024447 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ ;; Load region size_region. LR_IROM1 0x08000000 0x00010000 { ;; Load address = execution address. ER_IROM1 0x08000000 0x00010000 { *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) .ANY (+XO) } ; RW data. RW_IRAM1 0x20000000 0x00005000 { .ANY (+RW +ZI) } } qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/keil/startup.s0000644000175100001660000001327514776170045024526 0ustar runnerdocker;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Copyright (C) 2020 Denis Shienkov ;; Contact: https://www.qt.io/licensing/ ;; ;; This file is part of the examples of Qbs. ;; ;; $QT_BEGIN_LICENSE:BSD$ ;; 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 https://www.qt.io/terms-conditions. For further ;; information use the contact form at https://www.qt.io/contact-us. ;; ;; BSD License Usage ;; Alternatively, you may use this file under the terms of the BSD license ;; as follows: ;; ;; "Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions are ;; met: ;; * Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; * Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in ;; the documentation and/or other materials provided with the ;; distribution. ;; * Neither the name of The Qt Company Ltd nor the names of its ;; contributors may be used to endorse or promote products derived ;; from this software without specific prior written permission. ;; ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ;; ;; $QT_END_LICENSE$ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _size_of_stack EQU 0x400 _size_of_heap EQU 0x200 ;; Stack configuration. AREA STACK, NOINIT, READWRITE, ALIGN=3 _start_of_stack SPACE _size_of_stack _end_of_stack ;; Heap configuration. AREA HEAP, NOINIT, READWRITE, ALIGN=3 _start_of_heap SPACE _size_of_heap _end_of_heap PRESERVE8 THUMB ;; Define the empty vectors table. AREA RESET, DATA, READONLY _vectors_table ;; Generic interrupts offset. DCD _end_of_stack ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Memory management fault. DCD 0 ; Bus fault. DCD 0 ; Usage fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Debug monitor. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Window watchdog. DCD 0 ; PVD through EXTI line detection. DCD 0 ; Tamper and TimeStamps through the EXTI line. DCD 0 ; RTC wakeup through the EXTI line. DCD 0 ; FLASH. DCD 0 ; RCC. DCD 0 ; EXTI line0. DCD 0 ; EXTI line1. DCD 0 ; EXTI line2. DCD 0 ; EXTI line3. DCD 0 ; EXTI line4. DCD 0 ; DMA1 channel 1. DCD 0 ; DMA1 channel 2. DCD 0 ; DMA1 channel 3. DCD 0 ; DMA1 channel 4. DCD 0 ; DMA1 channel 5. DCD 0 ; DMA1 channel 6. DCD 0 ; DMA1 channel 7. DCD 0 ; ADC1/2. DCD 0 ; USB high priority or CAN1 TX. DCD 0 ; USB low priority or CAN1 RX0. DCD 0 ; CAN1 RX1. DCD 0 ; CAN1 SCE. DCD 0 ; EXTI line 9..5. DCD 0 ; TIM1 break. DCD 0 ; TIM1 update. DCD 0 ; TIM1 trigger and commutation. DCD 0 ; IM1 capture compare. DCD 0 ; TIM2. DCD 0 ; TIM3. DCD 0 ; TIM4. DCD 0 ; I2C1 event. DCD 0 ; I2C1 error. DCD 0 ; I2C2 event. DCD 0 ; I2C2 error. DCD 0 ; SPI1. DCD 0 ; SPI2. DCD 0 ; USART1. DCD 0 ; USART2. DCD 0 ; USART3. DCD 0 ; EXTI line 15..10. DCD 0 ; RTC alarm through EXTI line. DCD 0 ; USB wakeup from suspend. _end_of_vectors_table _size_of_vectors_table EQU _end_of_vectors_table - _vectors_table AREA |.text|, CODE, READONLY ;; Reset handler. reset_handler PROC EXPORT reset_handler [WEAK] IMPORT main LDR R0, =main BX R0 ENDP ALIGN END qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/iar/0000755000175100001660000000000014776170045022457 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/iar/flash.icf0000644000175100001660000000650314776170045024243 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ define symbol _start_of_intvec_section = 0x08000000; define symbol _start_of_flash_section = 0x08000000; define symbol _end_of_flash_section = 0x0801FFFF; define symbol _start_of_ram_section = 0x20000000; define symbol _end_of_ram_section = 0x20004FFF; define symbol _min_stack_size = 0x400; define symbol _min_heap_size = 0x200; define memory mem with size = 4G; define region flash_section = mem:[from _start_of_flash_section to _end_of_flash_section]; define region ram_section = mem:[from _start_of_ram_section to _end_of_ram_section]; define block CSTACK with alignment = 8, size = _min_stack_size { }; define block HEAP with alignment = 8, size = _min_heap_size { }; initialize by copy { readwrite }; do not initialize { section .noinit }; place at address mem:_start_of_intvec_section { readonly section .intvec }; place in flash_section { readonly }; place in ram_section { readwrite, block CSTACK, block HEAP }; qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/iar/startup.s0000644000175100001660000001251414776170045024350 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MODULE ?cstartup SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start PUBLIC _vectors_table DATA _vectors_table ;; Generic interrupts offset. DCD sfe(CSTACK) ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; MPU fault. DCD 0 ; Bus fault. DCD 0 ; Usage fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Debug monitor. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Window watchdog. DCD 0 ; PVD through EXTI line detection. DCD 0 ; Tamper. DCD 0 ; RTC. DCD 0 ; Flash. DCD 0 ; RCC. DCD 0 ; EXTI line 0. DCD 0 ; EXTI line 1. DCD 0 ; EXTI line 2. DCD 0 ; EXTI line 3. DCD 0 ; EXTI line 4. DCD 0 ; DMA1 channel 1. DCD 0 ; DMA1 channel 2. DCD 0 ; DMA1 channel 3. DCD 0 ; DMA1 channel 4. DCD 0 ; DMA1 channel 5. DCD 0 ; DMA1 channel 6. DCD 0 ; DMA1 channel 7. DCD 0 ; ADC1/2. DCD 0 ; USB high priority or CAN1 TX. DCD 0 ; USB low priority or CAN1 RX0. DCD 0 ; CAN1 RX1. DCD 0 ; CAN1 SCE. DCD 0 ; EXTI line 9..5. DCD 0 ; TIM1 break. DCD 0 ; TIM1 update. DCD 0 ; TIM1 trigger and commutation. DCD 0 ; TIM1 capture compare. DCD 0 ; TIM2. DCD 0 ; TIM3. DCD 0 ; TIM4. DCD 0 ; I2C1 event. DCD 0 ; I2C1 error. DCD 0 ; I2C2 event. DCD 0 ; I2C2 error. DCD 0 ; SPI1. DCD 0 ; SPI2. DCD 0 ; USART1. DCD 0 ; USART2. DCD 0 ; USART3. DCD 0 ; EXTI line 15..10. DCD 0 ; RTC alarm through EXTI line. DCD 0 ; USB wakeup from suspend. ;; Reset handler. THUMB PUBWEAK reset_handler SECTION .text:CODE:REORDER:NOROOT(2) reset_handler BLX R0 LDR R0, =__iar_program_start BX R0 END qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/greenblink.qbs0000644000175100001660000001173414776170045024541 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.startsWith("arm")) return false; return (qbs.toolchain.contains("gcc") || qbs.toolchain.contains("iar") || qbs.toolchain.contains("keil")) && !qbs.toolchain.contains("xcode") } name: "stm32f103-greenblink" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // GCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("gcc") cpp.assemblerFlags: [ "-mcpu=cortex-m3" ] cpp.driverFlags: [ "-mcpu=cortex-m3", "-specs=nosys.specs" ] } Group { condition: qbs.toolchain.contains("gcc") name: "GCC" prefix: "gcc/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.ld"] } } // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.assemblerFlags: [ "--cpu", "cortex-m3", "--fpu", "none" ] cpp.driverFlags: [ "--cpu", "cortex-m3", "--fpu", "none" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.icf"] } } // // KEIL-specific properties and sources. // Properties { condition: qbs.toolchain.contains("keil") cpp.assemblerFlags: [ "--cpu", "cortex-m3" ] cpp.driverFlags: [ "--cpu", "cortex-m3" ] } Group { condition: qbs.toolchain.contains("keil") name: "KEIL" prefix: "keil/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.sct"] } } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/gcc/0000755000175100001660000000000014776170045022440 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/gcc/flash.ld0000644000175100001660000001325614776170045024065 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /* Entry point (defined in assembled file). */ ENTRY(reset_handler) /* End of RAM, it is the user mode stack pointer address. */ _end_of_stack = 0x20005000; /* Generate a link error if heap and stack don't fit into RAM. */ _size_of_heap = 0x200; /* Required amount of heap. */ _size_of_stack = 0x400; /* Required amount of stack. */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K } SECTIONS { /* The vectors table goes into FLASH. */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code. */ . = ALIGN(4); } > FLASH /* The program code and other data goes into FLASH. */ .text : { . = ALIGN(4); *(.text) *(.text*) *(.glue_7) /* Glue arm to thumb code. */ *(.glue_7t) /* Glue thumb to arm code. */ *(.eh_frame) KEEP(*(.init)) KEEP(*(.fini)) . = ALIGN(4); _end_of_text_section = .; /* Export global symbol at end of code. */ } > FLASH /* Constant data goes into FLASH. */ .rodata : { . = ALIGN(4); *(.rodata) *(.rodata*) . = ALIGN(4); } > FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } > FLASH .preinit_array : { PROVIDE_HIDDEN(__preinit_array_start = .); KEEP(*(.preinit_array*)) PROVIDE_HIDDEN(__preinit_array_end = .); } > FLASH .init_array : { PROVIDE_HIDDEN(__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array*)) PROVIDE_HIDDEN(__init_array_end = .); } > FLASH .fini_array : { PROVIDE_HIDDEN(__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array*)) PROVIDE_HIDDEN(__fini_array_end = .); } > FLASH _start_of_init_data_section = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code. */ .data : { . = ALIGN(4); _start_of_data_section = .; /* Export global symbol at data start. */ *(.data) *(.data*) . = ALIGN(4); _end_of_data_section = .; /* Export global symbol at data end. */ } > RAM AT > FLASH /* Uninitialized data section. */ . = ALIGN(4); .bss : { /* This is used by the startup in order to initialize the .bss secion. */ _start_of_bss_section = .; /* Export global symbol at bss start. */ __bss_start__ = _start_of_bss_section; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _end_of_bss_section = .; /* Export global symbol at bss end. */ __bss_end__ = _end_of_bss_section; } > RAM /* Used to check that there is enough RAM left. */ ._user_heap_stack : { . = ALIGN(4); PROVIDE(end = .); PROVIDE(_end = .); . = . + _size_of_heap; . = . + _size_of_stack; . = ALIGN(4); } > RAM /* Remove information from the standard libraries. */ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } .ARM.attributes 0 : { *(.ARM.attributes) } } qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/gcc/startup.s0000644000175100001660000001513514776170045024333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ .syntax unified .cpu cortex-m3 .fpu softvfp .thumb // These symbols are exported from the linker script. .word _start_of_init_data_section .word _start_of_data_section .word _end_of_data_section .word _start_of_bss_section .word _end_of_bss_section .equ _boot_ram, 0xF108F85F .section .text.reset_handler .weak reset_handler .type reset_handler, %function reset_handler: // Copy the data segment initializers from flash to SRAM. movs r1, #0 b _loop_copy_data_init _copy_data_init: ldr r3, =_start_of_init_data_section ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 _loop_copy_data_init: ldr r0, =_start_of_data_section ldr r3, =_end_of_data_section adds r2, r0, r1 cmp r2, r3 bcc _copy_data_init ldr r2, =_start_of_bss_section b _loop_fill_zero_bss // Zero fill the bss segment. _fill_zero_bss: movs r3, #0 str r3, [r2], #4 _loop_fill_zero_bss: ldr r3, = _end_of_bss_section cmp r2, r3 bcc _fill_zero_bss // Call the static constructors. bl __libc_init_array // Call the application entry point. bl main bx lr .size reset_handler, .-reset_handler // Define the empty vectors table. .section .isr_vector,"a",%progbits .type _vectors_table, %object .size _vectors_table, .-_vectors_table _vectors_table: // Generic interrupts offset. .word _end_of_stack // Initial stack pointer value. .word reset_handler // Reset. .word 0 // NMI. .word 0 // Hard fault. .word 0 // Memory management fault. .word 0 // Bus fault. .word 0 // Usage fault. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // SVC. .word 0 // Debug monitor. .word 0 // Reserved. .word 0 // PendSV. .word 0 // SysTick. // External interrupts offset. .word 0 // Window watchdog. .word 0 // PVD through EXTI Line detection. .word 0 // Tamper and timestamps through the EXTI line. .word 0 // RTC wakeup through the EXTI line. .word 0 // FLASH. .word 0 // RCC. .word 0 // EXTI line0. .word 0 // EXTI line1. .word 0 // EXTI line2. .word 0 // EXTI line3. .word 0 // EXTI line4. .word 0 // DMA1 stream 0. .word 0 // DMA1 stream 1. .word 0 // DMA1 stream 2. .word 0 // DMA1 stream 3. .word 0 // DMA1 stream 4. .word 0 // DMA1 stream 5. .word 0 // DMA1 stream 6. .word 0 // ADC1/2. .word 0 // USB HP/CAN1 TX. .word 0 // USB LP / CAN1 RX0. .word 0 // CAN1 RX1. .word 0 // CAN1 SCE. .word 0 // EXTI line [9:5]s. .word 0 // TIM1 break. .word 0 // TIM1 update. .word 0 // TIM1 trigger and communication. .word 0 // TIM1 capture compare. .word 0 // TIM2. .word 0 // TIM3. .word 0 // TIM4. .word 0 // I2C1 event. .word 0 // I2C1 error. .word 0 // I2C2 event. .word 0 // I2C2 error. .word 0 // SPI1. .word 0 // SPI2. .word 0 // USART1. .word 0 // USART2. .word 0 // USART3. .word 0 // EXTI line [15:10]s. .word 0 // RTC alarm. .word 0 // USB wakeup. .word 0 .word 0 .word 0 .word 0 .word 0 .word 0 .word 0 .word _boot_ram // Boot RAM mode for stm32f10x medium density devices. qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/system.h0000644000175100001660000000704714776170045023411 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #include #ifdef __cplusplus extern "C" { #endif #define __IO volatile // General purpose input/output registers map. struct gpio_regs_map { __IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; }; // Reset and clock control registers map. struct rcc_regs_map { __IO uint32_t CR; __IO uint32_t CFGR; __IO uint32_t CIR; __IO uint32_t APB2RSTR; __IO uint32_t APB1RSTR; __IO uint32_t AHBENR; __IO uint32_t APB2ENR; __IO uint32_t APB1ENR; __IO uint32_t BDCR; __IO uint32_t CSR; }; #define PERIPH_ADDRESS (0x40000000u) #define APB2PERIPH_ADDRESS (PERIPH_ADDRESS + 0x00010000u) #define AHBPERIPH_ADDRESS (PERIPH_ADDRESS + 0x00020000u) #define GPIOC_REGS_ADDRESS (APB2PERIPH_ADDRESS + 0x00001000u) #define RCC_REGS_ADDRESS (AHBPERIPH_ADDRESS + 0x00001000u) #define GPIOC_REGS_MAP ((struct gpio_regs_map *)GPIOC_REGS_ADDRESS) #define RCC_REGS_MAP ((struct rcc_regs_map *)RCC_REGS_ADDRESS) #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/gpio.h0000644000175100001660000000513214776170045023014 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_green_led(void); void gpio_toggle_green_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/main.c0000644000175100001660000000530714776170045023001 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include static void some_delay(uint32_t counts) { for (uint32_t index = 0u; index < counts; ++index) __asm("nop"); } int main(void) { gpio_init_green_led(); while (1) { gpio_toggle_green_led(); some_delay(100000u); } } qbs-src-2.6.1/examples/baremetal/stm32f103/greenblink/gpio.c0000644000175100001660000000727514776170045023021 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" #define GPIO_GREEN_LED_PIN_POS (13u) #define GPIO_GREEN_LED_PIN (1u << GPIO_GREEN_LED_PIN_POS) // Bit definition for RCC_APB2ENR register. #define RCC_APB2ENR_IOPCEN_POS (4u) #define RCC_APB2ENR_IOPCEN (0x1u << RCC_APB2ENR_IOPCEN_POS) // Bit definition for GPIO_CRL register. #define GPIO_CRL_MODE_POS (0u) // MODE field position. #define GPIO_CRL_MODE_MSK (0x3u << GPIO_CRL_MODE_POS) // MODE field mask. #define GPIO_CRL_MODE_OUT_FREQ_LOW (0x2u << GPIO_CRL_MODE_POS) // As output with low frequency. #define GPIO_CRL_CNF_POS (2u) // CNF field position. #define GPIO_CRL_CNF_MSK (0x3u << GPIO_CRL_CNF_POS) // CNF field mask. #define GPIO_CRL_CNF_OUTPUT_PP (0x00000000u) // General purpose output push-pull. void gpio_init_green_led(void) { // Enable RCC clock on GPIOC port. RCC_REGS_MAP->APB2ENR |= RCC_APB2ENR_IOPCEN; // Configure GPIOC pin #13. const uint32_t offset = ((GPIO_GREEN_LED_PIN_POS - 8u) << 2u); GPIOC_REGS_MAP->CRH &= ~((GPIO_CRL_MODE_MSK | GPIO_CRL_CNF_MSK) << offset); GPIOC_REGS_MAP->CRH |= ((GPIO_CRL_MODE_OUT_FREQ_LOW | GPIO_CRL_CNF_OUTPUT_PP) << offset); } void gpio_toggle_green_led(void) { GPIOC_REGS_MAP->ODR ^= GPIO_GREEN_LED_PIN; } qbs-src-2.6.1/examples/baremetal/stm32f103/stm32f103.qbs0000644000175100001660000000502314776170045021635 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2020 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for stm32f103 board" references: [ "greenblink/greenblink.qbs" ] } qbs-src-2.6.1/examples/baremetal/stm32f4discovery/0000755000175100001660000000000014776170045021354 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f4discovery/stm32f4discovery.qbs0000644000175100001660000000503014776170045025213 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for stm32f4discovery board" references: [ "blueblink/blueblink.qbs" ] } qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/0000755000175100001660000000000014776170045023323 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/README.md0000644000175100001660000000055514776170045024607 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different ARM toolchains. It is designed for the stm32f4discovery evaluation kit (based on stm32f407vg MCU) and simply flashes the blue LED on the board. The following toolchains are supported: * GNU Arm Embedded Toolchain * IAR Embedded Workbench * KEIL Microcontroller Development Kit qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/keil/0000755000175100001660000000000014776170045024247 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/keil/flash.sct0000644000175100001660000000532214776170045026061 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ ;; Load region size_region. LR_IROM1 0x08000000 0x00100000 { ;; Load address = execution address. ER_IROM1 0x08000000 0x00100000 { *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } ; RW data. RW_IRAM1 0x20000000 0x00020000 { .ANY (+RW +ZI) } } qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/keil/startup.s0000644000175100001660000001665614776170045026153 0ustar runnerdocker;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Copyright (C) 2019 Denis Shienkov ;; Contact: https://www.qt.io/licensing/ ;; ;; This file is part of the examples of Qbs. ;; ;; $QT_BEGIN_LICENSE:BSD$ ;; 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 https://www.qt.io/terms-conditions. For further ;; information use the contact form at https://www.qt.io/contact-us. ;; ;; BSD License Usage ;; Alternatively, you may use this file under the terms of the BSD license ;; as follows: ;; ;; "Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions are ;; met: ;; * Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; * Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in ;; the documentation and/or other materials provided with the ;; distribution. ;; * Neither the name of The Qt Company Ltd nor the names of its ;; contributors may be used to endorse or promote products derived ;; from this software without specific prior written permission. ;; ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ;; ;; $QT_END_LICENSE$ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _size_of_stack EQU 0x400 _size_of_heap EQU 0x200 ;; Stack configuration. AREA STACK, NOINIT, READWRITE, ALIGN=3 _start_of_stack SPACE _size_of_stack _end_of_stack ;; Heap configuration. AREA HEAP, NOINIT, READWRITE, ALIGN=3 _start_of_heap SPACE _size_of_heap _end_of_heap PRESERVE8 THUMB ;; Define the empty vectors table. AREA RESET, DATA, READONLY _vectors_table ;; Generic interrupts offset. DCD _end_of_stack ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Memory management fault. DCD 0 ; Bus fault. DCD 0 ; Usage fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Debug monitor. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Window WatchDog. DCD 0 ; PVD through EXTI Line detection. DCD 0 ; Tamper and TimeStamps through the EXTI line. DCD 0 ; RTC Wakeup through the EXTI line. DCD 0 ; FLASH. DCD 0 ; RCC. DCD 0 ; EXTI Line0. DCD 0 ; EXTI Line1. DCD 0 ; EXTI Line2. DCD 0 ; EXTI Line3. DCD 0 ; EXTI Line4. DCD 0 ; DMA1 Stream 0. DCD 0 ; DMA1 Stream 1. DCD 0 ; DMA1 Stream 2. DCD 0 ; DMA1 Stream 3. DCD 0 ; DMA1 Stream 4. DCD 0 ; DMA1 Stream 5. DCD 0 ; DMA1 Stream 6. DCD 0 ; ADC1, ADC2 and ADC3s. DCD 0 ; CAN1 TX. DCD 0 ; CAN1 RX0. DCD 0 ; CAN1 RX1. DCD 0 ; CAN1 SCE. DCD 0 ; External Line[9:5]s. DCD 0 ; TIM1 Break and TIM9. DCD 0 ; TIM1 Update and TIM10. DCD 0 ; TIM1 Trigger and Commutation and TIM11. DCD 0 ; TIM1 Capture Compare. DCD 0 ; TIM2. DCD 0 ; TIM3. DCD 0 ; TIM4. DCD 0 ; I2C1 Event. DCD 0 ; I2C1 Error. DCD 0 ; I2C2 Event. DCD 0 ; I2C2 Error. DCD 0 ; SPI1. DCD 0 ; SPI2. DCD 0 ; USART1. DCD 0 ; USART2. DCD 0 ; USART3. DCD 0 ; External Line[15:10]s. DCD 0 ; RTC Alarm (A and B) through EXTI Line. DCD 0 ; USB OTG FS Wakeup through EXTI line. DCD 0 ; TIM8 Break and TIM12. DCD 0 ; TIM8 Update and TIM13. DCD 0 ; TIM8 Trigger and Commutation and TIM14. DCD 0 ; TIM8 Capture Compare. DCD 0 ; DMA1 Stream7. DCD 0 ; FMC. DCD 0 ; SDIO. DCD 0 ; TIM5. DCD 0 ; SPI3. DCD 0 ; UART4. DCD 0 ; UART5. DCD 0 ; TIM6 and DAC1&2 underrun errors. DCD 0 ; TIM7. DCD 0 ; DMA2 Stream 0. DCD 0 ; DMA2 Stream 1. DCD 0 ; DMA2 Stream 2. DCD 0 ; DMA2 Stream 3. DCD 0 ; DMA2 Stream 4. DCD 0 ; Ethernet. DCD 0 ; Ethernet Wakeup through EXTI line. DCD 0 ; CAN2 TX. DCD 0 ; CAN2 RX0. DCD 0 ; CAN2 RX1. DCD 0 ; CAN2 SCE. DCD 0 ; USB OTG FS. DCD 0 ; DMA2 Stream 5. DCD 0 ; DMA2 Stream 6. DCD 0 ; DMA2 Stream 7. DCD 0 ; USART6. DCD 0 ; I2C3 event. DCD 0 ; I2C3 error. DCD 0 ; USB OTG HS End Point 1 Out. DCD 0 ; USB OTG HS End Point 1 In. DCD 0 ; USB OTG HS Wakeup through EXTI. DCD 0 ; USB OTG HS. DCD 0 ; DCMI. DCD 0 ; Reserved. DCD 0 ; Hash and Rng. DCD 0 ; FPU. _end_of_vectors_table _size_of_vectors_table EQU _end_of_vectors_table - _vectors_table AREA |.text|, CODE, READONLY ;; Reset handler. reset_handler PROC EXPORT reset_handler [WEAK] IMPORT main LDR R0, =main BX R0 ENDP ALIGN END qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/iar/0000755000175100001660000000000014776170045024076 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/iar/flash.icf0000644000175100001660000000702614776170045025663 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ define symbol _start_of_intvec_section = 0x08000000; define symbol _start_of_ram_section = 0x20000000; define symbol _end_of_ram_section = 0x2001FFFF; define symbol _start_of_ccmram_section = 0x10000000; define symbol _end_of_ccmram_section = 0x1000FFFF; define symbol _start_of_flash_section = 0x08000000; define symbol _end_of_flash_section = 0x080FFFFF; define symbol _min_stack_size = 0x400; define symbol _min_heap_size = 0x200; define memory mem with size = 4G; define region flash_section = mem:[from _start_of_flash_section to _end_of_flash_section]; define region ram_section = mem:[from _start_of_ram_section to _end_of_ram_section]; define region ccmram_section = mem:[from _start_of_ccmram_section to _end_of_ccmram_section]; define block CSTACK with alignment = 8, size = _min_stack_size { }; define block HEAP with alignment = 8, size = _min_heap_size { }; initialize by copy { readwrite }; do not initialize { section .noinit }; place at address mem:_start_of_intvec_section { readonly section .intvec }; place in flash_section { readonly }; place in ram_section { readwrite, block CSTACK, block HEAP }; qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/iar/startup.s0000644000175100001660000001621014776170045025764 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MODULE ?cstartup SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start PUBLIC _vectors_table DATA _vectors_table ;; Generic interrupts offset. DCD sfe(CSTACK) ; Initial stack pointer value. DCD reset_handler ; Reset. DCD 0 ; NMI. DCD 0 ; Hard fault. DCD 0 ; Memory management fault. DCD 0 ; Bus fault. DCD 0 ; Usage fault. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; Reserved. DCD 0 ; SVC. DCD 0 ; Debug monitor. DCD 0 ; Reserved. DCD 0 ; PendSV. DCD 0 ; SysTick. ;; External interrupts offset. DCD 0 ; Window WatchDog. DCD 0 ; PVD through EXTI Line detection. DCD 0 ; Tamper and TimeStamps through the EXTI line. DCD 0 ; RTC Wakeup through the EXTI line. DCD 0 ; FLASH. DCD 0 ; RCC. DCD 0 ; EXTI Line0. DCD 0 ; EXTI Line1. DCD 0 ; EXTI Line2. DCD 0 ; EXTI Line3. DCD 0 ; EXTI Line4. DCD 0 ; DMA1 Stream 0. DCD 0 ; DMA1 Stream 1. DCD 0 ; DMA1 Stream 2. DCD 0 ; DMA1 Stream 3. DCD 0 ; DMA1 Stream 4. DCD 0 ; DMA1 Stream 5. DCD 0 ; DMA1 Stream 6. DCD 0 ; ADC1, ADC2 and ADC3s. DCD 0 ; CAN1 TX. DCD 0 ; CAN1 RX0. DCD 0 ; CAN1 RX1. DCD 0 ; CAN1 SCE. DCD 0 ; External Line[9:5]s. DCD 0 ; TIM1 Break and TIM9. DCD 0 ; TIM1 Update and TIM10. DCD 0 ; TIM1 Trigger and Commutation and TIM11. DCD 0 ; TIM1 Capture Compare. DCD 0 ; TIM2. DCD 0 ; TIM3. DCD 0 ; TIM4. DCD 0 ; I2C1 Event. DCD 0 ; I2C1 Error. DCD 0 ; I2C2 Event. DCD 0 ; I2C2 Error. DCD 0 ; SPI1. DCD 0 ; SPI2. DCD 0 ; USART1. DCD 0 ; USART2. DCD 0 ; USART3. DCD 0 ; External Line[15:10]s. DCD 0 ; RTC Alarm (A and B) through EXTI Line. DCD 0 ; USB OTG FS Wakeup through EXTI line. DCD 0 ; TIM8 Break and TIM12. DCD 0 ; TIM8 Update and TIM13. DCD 0 ; TIM8 Trigger and Commutation and TIM14. DCD 0 ; TIM8 Capture Compare. DCD 0 ; DMA1 Stream7. DCD 0 ; FSMC. DCD 0 ; SDIO. DCD 0 ; TIM5. DCD 0 ; SPI3. DCD 0 ; UART4. DCD 0 ; UART5. DCD 0 ; TIM6 and DAC1&2 underrun errors. DCD 0 ; TIM7. DCD 0 ; DMA2 Stream 0. DCD 0 ; DMA2 Stream 1. DCD 0 ; DMA2 Stream 2. DCD 0 ; DMA2 Stream 3. DCD 0 ; DMA2 Stream 4. DCD 0 ; Ethernet. DCD 0 ; Ethernet Wakeup through EXTI line. DCD 0 ; CAN2 TX. DCD 0 ; CAN2 RX0. DCD 0 ; CAN2 RX1. DCD 0 ; CAN2 SCE. DCD 0 ; USB OTG FS. DCD 0 ; DMA2 Stream 5. DCD 0 ; DMA2 Stream 6. DCD 0 ; DMA2 Stream 7. DCD 0 ; USART6. DCD 0 ; I2C3 event. DCD 0 ; I2C3 error. DCD 0 ; USB OTG HS End Point 1 Out. DCD 0 ; USB OTG HS End Point 1 In. DCD 0 ; USB OTG HS Wakeup through EXTI. DCD 0 ; USB OTG HS. DCD 0 ; DCMI. DCD 0 ; CRYP crypto. DCD 0 ; Hash and RNG. DCD 0 ; FPU. ;; Reset handler. THUMB PUBWEAK reset_handler SECTION .text:CODE:REORDER:NOROOT(2) reset_handler BLX R0 LDR R0, =__iar_program_start BX R0 END qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/gcc/0000755000175100001660000000000014776170045024057 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/gcc/flash.ld0000644000175100001660000001412514776170045025500 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /* Entry point (defined in assembled file). */ ENTRY(reset_handler) /* End of RAM, it is the user mode stack pointer address. */ _end_of_stack = 0x20020000; /* Generate a link error if heap and stack don't fit into RAM. */ _size_of_heap = 0x200; /* Required amount of heap. */ _size_of_stack = 0x400; /* Required amount of stack. */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K } SECTIONS { /* The vectors table goes into FLASH. */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code. */ . = ALIGN(4); } > FLASH /* The program code and other data goes into FLASH. */ .text : { . = ALIGN(4); *(.text) *(.text*) *(.glue_7) /* Glue arm to thumb code. */ *(.glue_7t) /* Glue thumb to arm code. */ *(.eh_frame) KEEP(*(.init)) KEEP(*(.fini)) . = ALIGN(4); _end_of_text_section = .; /* Export global symbol at end of code. */ } > FLASH /* Constant data goes into FLASH. */ .rodata : { . = ALIGN(4); *(.rodata) *(.rodata*) . = ALIGN(4); } > FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } > FLASH .preinit_array : { PROVIDE_HIDDEN(__preinit_array_start = .); KEEP(*(.preinit_array*)) PROVIDE_HIDDEN(__preinit_array_end = .); } > FLASH .init_array : { PROVIDE_HIDDEN(__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array*)) PROVIDE_HIDDEN(__init_array_end = .); } > FLASH .fini_array : { PROVIDE_HIDDEN(__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array*)) PROVIDE_HIDDEN(__fini_array_end = .); } > FLASH _start_of_init_data_section = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code. */ .data : { . = ALIGN(4); _start_of_data_section = .; /* Export global symbol at data start. */ *(.data) *(.data*) . = ALIGN(4); _end_of_data_section = .; /* Export global symbol at data end. */ } > RAM AT > FLASH _start_of_iccm_ram_section = LOADADDR(.ccmram); /* CCM-RAM section. */ .ccmram : { . = ALIGN(4); _start_of_ccmram_section = .; /* Export global symbol at ccmram start. */ *(.ccmram) *(.ccmram*) . = ALIGN(4); _end_of_ccmram_section = .; /* Export global symbol at ccmram end. */ } > CCMRAM AT > FLASH /* Uninitialized data section. */ . = ALIGN(4); .bss : { /* This is used by the startup in order to initialize the .bss secion. */ _start_of_bss_section = .; /* Export global symbol at bss start. */ __bss_start__ = _start_of_bss_section; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _end_of_bss_section = .; /* Export global symbol at bss end. */ __bss_end__ = _end_of_bss_section; } > RAM /* Used to check that there is enough RAM left. */ ._user_heap_stack : { . = ALIGN(4); PROVIDE(end = .); PROVIDE(_end = .); . = . + _size_of_heap; . = . + _size_of_stack; . = ALIGN(4); } > RAM /* Remove information from the standard libraries. */ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } .ARM.attributes 0 : { *(.ARM.attributes) } } qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/gcc/startup.s0000644000175100001660000002056114776170045025751 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ .syntax unified .cpu cortex-m4 .fpu softvfp .thumb // These symbols are exported from the linker script. .word _start_of_init_data_section .word _start_of_data_section .word _end_of_data_section .word _start_of_bss_section .word _end_of_bss_section .word _end_of_stack // Define the 'reset_handler' function, which is an entry point. .section .text.reset_handler .weak reset_handler .type reset_handler, %function reset_handler: // Set the stack pointer. ldr sp, =_end_of_stack // Copy the data segment initializers from flash to SRAM. movs r1, #0 b _loop_copy_data_init _copy_data_init: ldr r3, =_start_of_init_data_section ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 _loop_copy_data_init: ldr r0, =_start_of_data_section ldr r3, =_end_of_data_section adds r2, r0, r1 cmp r2, r3 bcc _copy_data_init ldr r2, =_start_of_bss_section b _loop_fill_zero_bss // Zero fill the bss segment. _fill_zero_bss: movs r3, #0 str r3, [r2], #4 _loop_fill_zero_bss: ldr r3, = _end_of_bss_section cmp r2, r3 bcc _fill_zero_bss // Call the static constructors. bl __libc_init_array // Call the application's entry point. bl main bx lr .size reset_handler, .-reset_handler // Define the empty vectors table. .section .isr_vector,"a",%progbits .type _vectors_table, %object .size _vectors_table, .-_vectors_table _vectors_table: // Generic interrupts offset. .word _end_of_stack // Initial stack pointer value. .word reset_handler // Reset. .word 0 // NMI. .word 0 // Hard fault. .word 0 // Memory management fault. .word 0 // Bus fault. .word 0 // Usage fault. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // Reserved. .word 0 // SVC. .word 0 // Debug monitor. .word 0 // Reserved. .word 0 // PendSV. .word 0 // SysTick. // External interrupts offset. .word 0 // Window WatchDog. .word 0 // PVD through EXTI Line detection. .word 0 // Tamper and TimeStamps through the EXTI line. .word 0 // RTC Wakeup through the EXTI line. .word 0 // FLASH. .word 0 // RCC. .word 0 // EXTI Line0. .word 0 // EXTI Line1. .word 0 // EXTI Line2. .word 0 // EXTI Line3. .word 0 // EXTI Line4. .word 0 // DMA1 Stream 0. .word 0 // DMA1 Stream 1. .word 0 // DMA1 Stream 2. .word 0 // DMA1 Stream 3. .word 0 // DMA1 Stream 4. .word 0 // DMA1 Stream 5. .word 0 // DMA1 Stream 6. .word 0 // ADC1, ADC2 and ADC3s. .word 0 // CAN1 TX. .word 0 // CAN1 RX0. .word 0 // CAN1 RX1. .word 0 // CAN1 SCE. .word 0 // External Line[9:5]s. .word 0 // TIM1 Break and TIM9. .word 0 // TIM1 Update and TIM10. .word 0 // TIM1 Trigger and Commutation and TIM11. .word 0 // TIM1 Capture Compare. .word 0 // TIM2. .word 0 // TIM3. .word 0 // TIM4. .word 0 // I2C1 Event. .word 0 // I2C1 Error. .word 0 // I2C2 Event. .word 0 // I2C2 Error. .word 0 // SPI1. .word 0 // SPI2. .word 0 // USART1. .word 0 // USART2. .word 0 // USART3. .word 0 // External Line[15:10]s. .word 0 // RTC Alarm (A and B) through EXTI Line. .word 0 // USB OTG FS Wakeup through EXTI line. .word 0 // TIM8 Break and TIM12. .word 0 // TIM8 Update and TIM13. .word 0 // TIM8 Trigger and Commutation and TIM14. .word 0 // TIM8 Capture Compare. .word 0 // DMA1 Stream7. .word 0 // FSMC. .word 0 // SDIO. .word 0 // TIM5. .word 0 // SPI3. .word 0 // UART4. .word 0 // UART5. .word 0 // TIM6 and DAC1&2 underrun errors. .word 0 // TIM7. .word 0 // DMA2 Stream 0. .word 0 // DMA2 Stream 1. .word 0 // DMA2 Stream 2. .word 0 // DMA2 Stream 3. .word 0 // DMA2 Stream 4. .word 0 // Ethernet. .word 0 // Ethernet Wakeup through EXTI line. .word 0 // CAN2 TX. .word 0 // CAN2 RX0. .word 0 // CAN2 RX1. .word 0 // CAN2 SCE. .word 0 // USB OTG FS. .word 0 // DMA2 Stream 5. .word 0 // DMA2 Stream 6. .word 0 // DMA2 Stream 7. .word 0 // USART6. .word 0 // I2C3 event. .word 0 // I2C3 error. .word 0 // USB OTG HS End Point 1 Out. .word 0 // USB OTG HS End Point 1 In. .word 0 // USB OTG HS Wakeup through EXTI. .word 0 // USB OTG HS. .word 0 // DCMI. .word 0 // CRYP crypto. .word 0 // Hash and Rng. .word 0 // FPU. qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/system.h0000644000175100001660000001050714776170045025023 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #include #ifdef __cplusplus extern "C" { #endif #define __IO volatile // General purpose input/output registers map. struct gpio_regs_map { __IO uint32_t MODER; __IO uint32_t OTYPER; __IO uint32_t OSPEEDR; __IO uint32_t PUPDR; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t LCKR; __IO uint32_t AFR[2u]; }; // Reset and clock control registers map. struct rcc_regs_map { __IO uint32_t CR; __IO uint32_t PLLCFGR; __IO uint32_t CFGR; __IO uint32_t CIR; __IO uint32_t AHB1RSTR; __IO uint32_t AHB2RSTR; __IO uint32_t AHB3RSTR; uint32_t RESERVED0; __IO uint32_t APB1RSTR; __IO uint32_t APB2RSTR; uint32_t RESERVED1[2u]; __IO uint32_t AHB1ENR; __IO uint32_t AHB2ENR; __IO uint32_t AHB3ENR; uint32_t RESERVED2; __IO uint32_t APB1ENR; __IO uint32_t APB2ENR; uint32_t RESERVED3[2u]; __IO uint32_t AHB1LPENR; __IO uint32_t AHB2LPENR; __IO uint32_t AHB3LPENR; uint32_t RESERVED4; __IO uint32_t APB1LPENR; __IO uint32_t APB2LPENR; uint32_t RESERVED5[2u]; __IO uint32_t BDCR; __IO uint32_t CSR; uint32_t RESERVED6[2u]; __IO uint32_t SSCGR; __IO uint32_t PLLI2SCFGR; }; #define PERIPH_ADDRESS (0x40000000u) #define APB2PERIPH_ADDRESS (PERIPH_ADDRESS + 0x00010000u) #define AHB1PERIPH_ADDRESS (PERIPH_ADDRESS + 0x00020000u) // APB2 peripherals. #define SYSCFG_REGS_ADDRESS (APB2PERIPH_ADDRESS + 0x3800u) #define EXTI_REGS_ADDRESS (APB2PERIPH_ADDRESS + 0x3C00u) // AHB1 peripherals. #define GPIOD_REGS_ADDRESS (AHB1PERIPH_ADDRESS + 0x0C00u) #define RCC_REGS_ADDRESS (AHB1PERIPH_ADDRESS + 0x3800u) #define GPIOD_REGS_MAP ((struct gpio_regs_map *)GPIOD_REGS_ADDRESS) #define RCC_REGS_MAP ((struct rcc_regs_map *)RCC_REGS_ADDRESS) #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/gpio.h0000644000175100001660000000513014776170045024431 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_blue_led(void); void gpio_toggle_blue_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/main.c0000644000175100001660000000530514776170045024416 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include static void some_delay(uint32_t counts) { for (uint32_t index = 0u; index < counts; ++index) __asm("nop"); } int main(void) { gpio_init_blue_led(); while (1) { gpio_toggle_blue_led(); some_delay(100000u); } } qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs0000644000175100001660000001216314776170045026004 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.startsWith("arm")) return false; return (qbs.toolchain.contains("gcc") || qbs.toolchain.contains("iar") || qbs.toolchain.contains("keil")) && !qbs.toolchain.contains("xcode") } name: "stm32f4discovery-blueblink" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // GCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("gcc") cpp.assemblerFlags: [ "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", ] cpp.driverFlags: [ "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-specs=nosys.specs" ] } Group { condition: qbs.toolchain.contains("gcc") name: "GCC" prefix: "gcc/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.ld"] } } // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.assemblerFlags: [ "--cpu", "cortex-m4", "--fpu", "vfpv4_sp" ] cpp.driverFlags: [ "--cpu", "cortex-m4", "--fpu", "vfpv4_sp" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.icf"] } } // // KEIL-specific properties and sources. // Properties { condition: qbs.toolchain.contains("keil") cpp.assemblerFlags: [ "--cpu", "cortex-m4.fp" ] cpp.driverFlags: [ "--cpu", "cortex-m4.fp" ] } Group { condition: qbs.toolchain.contains("keil") name: "KEIL" prefix: "keil/" Group { name: "Startup" fileTags: ["asm"] files: ["startup.s"] } Group { name: "Linker Script" fileTags: ["linkerscript"] files: ["flash.sct"] } } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/stm32f4discovery/blueblink/gpio.c0000644000175100001660000000637314776170045024436 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" #define GPIO_BLUE_LED_PIN_POS (15u) #define GPIO_BLUE_LED_PIN (1u << GPIO_BLUE_LED_PIN_POS) // Output push pull mode. #define GPIO_MODE_OUTPUT_PP (0x00000001u) // Bit definition for RCC_AHB1ENR register. #define RCC_AHB1ENR_GPIODEN (0x00000008u) // Bits definition for GPIO_MODER register. #define GPIO_MODER_MODE0 (0x00000003u) void gpio_init_blue_led(void) { // Enable RCC clock on GPIOD port. RCC_REGS_MAP->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Configure GPIO pin #15 as an output. uint32_t value = GPIOD_REGS_MAP->MODER; value &= ~(GPIO_MODER_MODE0 << (GPIO_BLUE_LED_PIN_POS * 2u)); value |= (GPIO_MODE_OUTPUT_PP << (GPIO_BLUE_LED_PIN_POS * 2u)); GPIOD_REGS_MAP->MODER = value; } void gpio_toggle_blue_led(void) { GPIOD_REGS_MAP->ODR ^= GPIO_BLUE_LED_PIN; } qbs-src-2.6.1/examples/baremetal/at90can128olimex/0000755000175100001660000000000014776170045021132 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/at90can128olimex/redblink/0000755000175100001660000000000014776170045022724 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/at90can128olimex/redblink/README.md0000644000175100001660000000045014776170045024202 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different AVR toolchains. It is designed for the OLIMEX AVR-CAN target board (based on at90can128 chip) and simply flashes the red LED on the board. The following toolchains are supported: * GCC * IAR Embedded Workbench qbs-src-2.6.1/examples/baremetal/at90can128olimex/redblink/redblink.qbs0000644000175100001660000001126514776170045025232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.contains("avr")) return false; return qbs.toolchain.contains("gcc") || qbs.toolchain.contains("iar") } name: "at90can128olimex-redblink" cpp.cLanguageVersion: "c99" cpp.positionIndependentCode: false // // GCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("gcc") cpp.driverFlags: ["-mmcu=at90can128"] } // Note: We implicitly use the startup file and the linker script // which are already linked into the avr-gcc toolchain runtime. // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.driverFlags: ["--cpu=can128", "-ms"] cpp.entryPoint: "__program_start" cpp.driverLinkerFlags: [ "-D_..X_HEAP_SIZE=0", "-D_..X_NEAR_HEAP_SIZE=20", "-D_..X_CSTACK_SIZE=20", "-D_..X_RSTACK_SIZE=20", "-D_..X_FLASH_CODE_END=1FFFF", "-D_..X_FLASH_BASE=_..X_INTVEC_SIZE", "-D_..X_EXT_SRAM_BASE=_..X_SRAM_END", "-D_..X_EXT_ROM_BASE=_..X_SRAM_END", "-D_..X_EXT_NV_BASE=_..X_SRAM_END", "-D_..X_CSTACK_BASE=_..X_SRAM_BASE", "-D_..X_CSTACK_END=_..X_SRAM_END", "-D_..X_RSTACK_BASE=_..X_SRAM_BASE", "-D_..X_RSTACK_END=_..X_SRAM_END", "-h'1895'(CODE)0-(_..X_INTVEC_SIZE-1)", ] cpp.staticLibraries: [ // Explicitly link with the runtime dlib library (which contains // all required startup code and other stuff). cpp.toolchainInstallPath + "/../lib/dlib/dlAVR-3s-ec_mul-n.r90" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Linker Script" prefix: cpp.toolchainInstallPath + "/../src/template/" fileTags: ["linkerscript"] // Explicitly use the default linker scripts for current target. files: ["cfg3soim.xcl", "cfgcan128.xcl"] } } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/at90can128olimex/redblink/gpio.h0000644000175100001660000000512614776170045024037 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_red_led(void); void gpio_toggle_red_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/at90can128olimex/redblink/main.c0000644000175100001660000000530314776170045024015 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include static void some_delay(uint32_t counts) { for (uint32_t index = 0u; index < counts; ++index) __asm("nop"); } int main(void) { gpio_init_red_led(); while (1) { gpio_toggle_red_led(); some_delay(100000u); } } qbs-src-2.6.1/examples/baremetal/at90can128olimex/redblink/gpio.c0000644000175100001660000000561714776170045024037 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #if defined(__GNUC__) #include #elif defined (__ICCAVR__) #include #else #error "Unsupported toolchain" #endif // LED pin number. #define GPIO_RED_LED_PIN_POS (4u) // LED port direction. #define GPIO_RED_LED_PORT_DIR (DDRE) // LED output port. #define GPIO_RED_LED_PORT_OUT (PORTE) void gpio_init_red_led(void) { GPIO_RED_LED_PORT_DIR = 0xFF; } void gpio_toggle_red_led(void) { GPIO_RED_LED_PORT_OUT ^= (1u << GPIO_RED_LED_PIN_POS); } qbs-src-2.6.1/examples/baremetal/at90can128olimex/at90can128olimex.qbs0000644000175100001660000000502414776170045024552 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for Olimex AVR-CAN board" references: [ "redblink/redblink.qbs" ] } qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/0000755000175100001660000000000014776170045021025 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/0000755000175100001660000000000014776170045023145 5ustar runnerdockerqbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/README.md0000644000175100001660000000051714776170045024427 0ustar runnerdockerThis example demonstrates how to build a bare-metal application using different MCS-51 toolchains. It is designed for the CC2540 usb dongle target board (based on Texas Instruments CC2540 wireless MCU) and simply flashes the green LED on the board. The following toolchains are supported: * IAR Embedded Workbench * KEIL uVision qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/greenblink.qbs0000644000175100001660000001026114776170045025774 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ CppApplication { condition: { if (!qbs.architecture.contains("mcs51")) return false; return qbs.toolchain.contains("iar") || qbs.toolchain.contains("keil") || qbs.toolchain.contains("sdcc") } name: "cc2540usbdongle-greenblink" cpp.positionIndependentCode: false // // IAR-specific properties and sources. // Properties { condition: qbs.toolchain.contains("iar") cpp.commonCompilerFlags: ["-e"] cpp.driverLinkerFlags: [ "-D_IDATA_STACK_SIZE=0x40", "-D_PDATA_STACK_SIZE=0x00", "-D_XDATA_STACK_SIZE=0x00", "-D_XDATA_HEAP_SIZE=0x00", "-D_EXTENDED_STACK_SIZE=0", "-D_EXTENDED_STACK_START=0" ] cpp.staticLibraries: [ cpp.toolchainInstallPath + "/../lib/clib/cl-pli-nsid-1e16x01" ] } Group { condition: qbs.toolchain.contains("iar") name: "IAR" prefix: "iar/" Group { name: "Linker Script" prefix: cpp.toolchainInstallPath + "/../config/devices/_generic/" fileTags: ["linkerscript"] files: ["lnk51ew_8051.xcl"] } } // // KEIL-specific properties and sources. // Properties { condition: qbs.toolchain.contains("keil") cpp.driverLinkerFlags: [ "RAMSIZE(256)", "CODE(0x0000-0xFFFF)" ] } // // SDCC-specific properties and sources. // Properties { condition: qbs.toolchain.contains("sdcc") } // // Common code. // Group { name: "Gpio" files: ["gpio.c", "gpio.h"] } Group { name: "System" files: ["system.h"] } files: ["main.c"] } qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/system.h0000644000175100001660000000630314776170045024644 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H #ifdef __cplusplus extern "C" { #endif #if defined(__ICC8051__) #include # define system_nop() __no_operation() # define DEFINE_SFR(name,addr) __sfr __no_init volatile unsigned char name @ addr; #elif defined (__C51__) #include # define system_nop() _nop_() # define DEFINE_SFR(name, addr) sfr name = addr; #elif defined (__SDCC_mcs51) #include # define DEFINE_SFR(name, addr) __sfr __at(addr) name; # ifndef NOP # define NOP() __asm NOP __endasm # endif # define system_nop() NOP() #else #error "Unsupported toolchain" #endif DEFINE_SFR(P0 , 0x80u) // Port 0. DEFINE_SFR(P0SEL, 0xF3u) // Port 0 function select. DEFINE_SFR(P0DIR, 0xFDu) // Port 0 direction select. #ifdef __cplusplus } #endif #endif // SYSTEM_H qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/gpio.h0000644000175100001660000000513214776170045024255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GPIO_H #define GPIO_H #ifdef __cplusplus extern "C" { #endif void gpio_init_green_led(void); void gpio_toggle_green_led(void); #ifdef __cplusplus } #endif #endif // GPIO_H qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/main.c0000644000175100001660000000533614776170045024244 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" static void some_delay(unsigned long counts) { unsigned long index = 0u; for (index = 0u; index < counts; ++index) system_nop(); } int main(void) { gpio_init_green_led(); while (1) { gpio_toggle_green_led(); some_delay(20000u); } } qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/greenblink/gpio.c0000644000175100001660000000525414776170045024255 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "gpio.h" #include "system.h" #define GPIO_GREEN_LED_PIN_POS (1u) void gpio_init_green_led(void) { P0SEL = 0; // Choose the port. P0DIR = 0x01; // Set pin0 to output mode. } void gpio_toggle_green_led(void) { P0 ^= GPIO_GREEN_LED_PIN_POS; } qbs-src-2.6.1/examples/baremetal/cc2540usbdongle/cc2540usbdongle.qbs0000644000175100001660000000503114776170045024336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ Project { name: "Examples for cc2540usbdongle board" references: [ "greenblink/greenblink.qbs" ] } qbs-src-2.6.1/examples/cocoa-application/0000755000175100001660000000000014776170045017653 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-application/dmg.qbs0000644000175100001660000000655314776170045021142 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ AppleApplicationDiskImage { condition: qbs.targetOS.contains("macos") name: "Cocoa Application DMG" targetName: "cocoa-application-" + version version: "1.0" builtByDefault: false Depends { name: "Cocoa Application" } Depends { name: "ib" } files: [ "CocoaApplication/dmg.iconset", "CocoaApplication/en_US.lproj/LICENSE", ] // set to false to use a solid-color background (see dmg.backgroundColor below) property bool useImageBackground: true Group { condition: useImageBackground files: ["CocoaApplication/background*"] } dmg.backgroundColor: "#41cd52" dmg.badgeVolumeIcon: true dmg.iconPositions: [ {"x": 200, "y": 200, "path": "Cocoa Application.app"}, {"x": 400, "y": 200, "path": "Applications"} ] dmg.windowX: 420 dmg.windowY: 250 dmg.windowWidth: 600 dmg.windowHeight: 422 // this *includes* the macOS title bar height of 22 dmg.iconSize: 64 } qbs-src-2.6.1/examples/cocoa-application/app.qbs0000644000175100001660000000745214776170045021152 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.Utilities CppApplication { Depends { condition: product.condition; name: "ib" } condition: qbs.targetOS.contains("macos") name: "Cocoa Application" cpp.useObjcPrecompiledHeader: true cpp.minimumMacosVersion: "10.8" cpp.frameworks: ["Cocoa"] Group { prefix: "CocoaApplication/" files: [ "AppDelegate.h", "AppDelegate.m", "CocoaApplication-Info.plist", "CocoaApplication.xcassets", "main.m" ] } Group { name: "Supporting Files" prefix: "CocoaApplication/en.lproj/" files: [ "Credits.rtf", "InfoPlist.strings", "MainMenu.xib" ] } Group { name: "Xcode Project" files: [ "CocoaApplication.xcodeproj/project.pbxproj" ] } Group { files: ["CocoaApplication/CocoaApplication-Prefix.pch"] fileTags: ["objc_pch_src"] } Group { fileTagsFilter: ["bundle.content"] qbs.install: true qbs.installDir: "Applications" qbs.installSourceBase: product.destinationDirectory } ib.appIconName: "AppIcon" Properties { // codesign module only present starting from 1.19 condition: Utilities.versionCompare(qbs.version, "1.19") >= 0 codesign.enableCodeSigning: true codesign.signingType: "ad-hoc" } } qbs-src-2.6.1/examples/cocoa-application/CocoaApplication.xcodeproj/0000755000175100001660000000000014776170045025057 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-application/CocoaApplication.xcodeproj/project.pbxproj0000644000175100001660000003450714776170045030144 0ustar runnerdocker// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 14ABF7A71717761200140DA2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14ABF7A61717761200140DA2 /* Cocoa.framework */; }; 14ABF7B11717761200140DA2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 14ABF7AF1717761200140DA2 /* InfoPlist.strings */; }; 14ABF7B31717761200140DA2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 14ABF7B21717761200140DA2 /* main.m */; }; 14ABF7B71717761200140DA2 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 14ABF7B51717761200140DA2 /* Credits.rtf */; }; 14ABF7BA1717761200140DA2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14ABF7B91717761200140DA2 /* AppDelegate.m */; }; 14ABF7BD1717761300140DA2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14ABF7BB1717761300140DA2 /* MainMenu.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 14ABF7A31717761200140DA2 /* Cocoa Application.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Cocoa Application.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 14ABF7A61717761200140DA2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 14ABF7A91717761200140DA2 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 14ABF7AA1717761200140DA2 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 14ABF7AB1717761200140DA2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 14ABF7AE1717761200140DA2 /* CocoaApplication-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CocoaApplication-Info.plist"; sourceTree = ""; }; 14ABF7B01717761200140DA2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 14ABF7B21717761200140DA2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 14ABF7B41717761200140DA2 /* CocoaApplication-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CocoaApplication-Prefix.pch"; sourceTree = ""; }; 14ABF7B61717761200140DA2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 14ABF7B81717761200140DA2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 14ABF7B91717761200140DA2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 14ABF7BC1717761300140DA2 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 14ABF7A01717761200140DA2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 14ABF7A71717761200140DA2 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 14ABF79A1717761200140DA2 = { isa = PBXGroup; children = ( 14ABF7AC1717761200140DA2 /* CocoaApplication */, 14ABF7A51717761200140DA2 /* Frameworks */, 14ABF7A41717761200140DA2 /* Products */, ); sourceTree = ""; }; 14ABF7A41717761200140DA2 /* Products */ = { isa = PBXGroup; children = ( 14ABF7A31717761200140DA2 /* Cocoa Application.app */, ); name = Products; sourceTree = ""; }; 14ABF7A51717761200140DA2 /* Frameworks */ = { isa = PBXGroup; children = ( 14ABF7A61717761200140DA2 /* Cocoa.framework */, 14ABF7A81717761200140DA2 /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 14ABF7A81717761200140DA2 /* Other Frameworks */ = { isa = PBXGroup; children = ( 14ABF7A91717761200140DA2 /* AppKit.framework */, 14ABF7AA1717761200140DA2 /* CoreData.framework */, 14ABF7AB1717761200140DA2 /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 14ABF7AC1717761200140DA2 /* CocoaApplication */ = { isa = PBXGroup; children = ( 14ABF7B81717761200140DA2 /* AppDelegate.h */, 14ABF7B91717761200140DA2 /* AppDelegate.m */, 14ABF7BB1717761300140DA2 /* MainMenu.xib */, 14ABF7AD1717761200140DA2 /* Supporting Files */, ); path = CocoaApplication; sourceTree = ""; }; 14ABF7AD1717761200140DA2 /* Supporting Files */ = { isa = PBXGroup; children = ( 14ABF7AE1717761200140DA2 /* CocoaApplication-Info.plist */, 14ABF7AF1717761200140DA2 /* InfoPlist.strings */, 14ABF7B21717761200140DA2 /* main.m */, 14ABF7B41717761200140DA2 /* CocoaApplication-Prefix.pch */, 14ABF7B51717761200140DA2 /* Credits.rtf */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 14ABF7A21717761200140DA2 /* Cocoa Application */ = { isa = PBXNativeTarget; buildConfigurationList = 14ABF7C01717761300140DA2 /* Build configuration list for PBXNativeTarget "Cocoa Application" */; buildPhases = ( 14ABF79F1717761200140DA2 /* Sources */, 14ABF7A01717761200140DA2 /* Frameworks */, 14ABF7A11717761200140DA2 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Cocoa Application"; productName = CocoaApplication; productReference = 14ABF7A31717761200140DA2 /* Cocoa Application.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 14ABF79B1717761200140DA2 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0460; ORGANIZATIONNAME = "Petroules Corporation"; }; buildConfigurationList = 14ABF79E1717761200140DA2 /* Build configuration list for PBXProject "CocoaApplication" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 14ABF79A1717761200140DA2; productRefGroup = 14ABF7A41717761200140DA2 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 14ABF7A21717761200140DA2 /* Cocoa Application */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 14ABF7A11717761200140DA2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 14ABF7B11717761200140DA2 /* InfoPlist.strings in Resources */, 14ABF7B71717761200140DA2 /* Credits.rtf in Resources */, 14ABF7BD1717761300140DA2 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 14ABF79F1717761200140DA2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 14ABF7B31717761200140DA2 /* main.m in Sources */, 14ABF7BA1717761200140DA2 /* AppDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 14ABF7AF1717761200140DA2 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 14ABF7B01717761200140DA2 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; 14ABF7B51717761200140DA2 /* Credits.rtf */ = { isa = PBXVariantGroup; children = ( 14ABF7B61717761200140DA2 /* en */, ); name = Credits.rtf; sourceTree = ""; }; 14ABF7BB1717761300140DA2 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 14ABF7BC1717761300140DA2 /* en */, ); name = MainMenu.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 14ABF7BE1717761300140DA2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.8; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; 14ABF7BF1717761300140DA2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.8; SDKROOT = macosx; }; name = Release; }; 14ABF7C11717761300140DA2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "CocoaApplication/CocoaApplication-Prefix.pch"; INFOPLIST_FILE = "CocoaApplication/CocoaApplication-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Debug; }; 14ABF7C21717761300140DA2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "CocoaApplication/CocoaApplication-Prefix.pch"; INFOPLIST_FILE = "CocoaApplication/CocoaApplication-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 14ABF79E1717761200140DA2 /* Build configuration list for PBXProject "CocoaApplication" */ = { isa = XCConfigurationList; buildConfigurations = ( 14ABF7BE1717761300140DA2 /* Debug */, 14ABF7BF1717761300140DA2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 14ABF7C01717761300140DA2 /* Build configuration list for PBXNativeTarget "Cocoa Application" */ = { isa = XCConfigurationList; buildConfigurations = ( 14ABF7C11717761300140DA2 /* Debug */, 14ABF7C21717761300140DA2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 14ABF79B1717761200140DA2 /* Project object */; } qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/0000755000175100001660000000000014776170045023063 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/background@2x.png0000644000175100001660000065077414776170045026305 0ustar runnerdockerPNG  IHDR 3sRGB pHYs%%IR$@IDATxٲ9jfn9jUUЭEZIå.d ]eʁdfb;HtLU c#p8g^/>|??a/}YҚ_ŋW󡓇^[KS߿xMҿ?chyr-s0[=ks49ɔN _ׯ_?ڍ><|9>W|KN2+_ez^ h>|d=Sw߽K#+W?]w/~d۲Yk7[ofq !Ŭ iOo-@e,WsWH8\_)H"f(sS/ lM2oxkxG!z7:MRӴ?y|o<} ] ?` x:/W|he.mi+WL>oxU_nRSNPQx^*s>; h+tOהC~S{q??ှX֐%?lc#a]|wQt'kg?O蓄 Zb:i?[ Eܠ$.'->8:WZ>X~&ܔ޽{,e z.R<ǁie]Nݹ<wx{~_?Ʈ33qJZOO?فo)Yzpk7>Z_c';+ 0Q ( &rT7iHtY<{-{ԟr"[#'t^޹~@iC0 - .?N=48WodJO[]װN+4‡r~NOMᙺQy/~i Zy+y^CI%ӧ{y6U0~-Mk蟝)qcKWw<͑3.vGG[cw_vqa$?ƌcg*0tQ:m迵g t^1_|q/ؐM?;$6 (| <5G^ƍo62>o h5/k|WixZq$"7PKmʣMs<͎&|ѝ6&c8M)mI/>- }rp4:#筗 W2{;&=?X8ιt!m9G]|d >]k:_MN_???~tܫ{<ǤIeާggk)p!4 0'<-s7q1~l?zb=?[*FONP@Hb=X@M3`a~)AO9S~p9HOq])sNۧL'[uR7Ez5&;̻;r=\K^zb B)oUԆ{c<]+'06^WS\MN \nplW_o\'lˮȠ?#:6[mk czP^>^?nN|YoU`1 M2X%ƪYKۜ]|v5Ω;:ngMԬ33nwv2]AǬ:(YoVX?[>ƄbϿxQ(nB`.{Ate}@ n΁2u^>iW;cruC@ -#.A? &sy({xiCvlM C/H<u޴P^]=B\B]y|Hs7]Mܽg/أedGX_m@Ǡ]! 17&;b H sYbvlj=|0X+qޣc8$\ȥV(\z&:t7V?kʡ兤Lb2_m'Mk9ov2v2΀xc'k~K˄!sK7w?Ww?z"S"wEk ;tH>3>GBt/J[g5w:έ>'B'bOC`NٹV^^[LSw>.~7cʼn)s #ĮaZ/m{OZ/(*@)]|ͯ&d1:cidC|u/&W$k]zIwxoZb(%y{CvJ5f0}46s Vw72Vcw8pwIfVYC{v3F7[\],9rO20c4cs>)ч:'[gns( gൎspki -Z^kx4H w7+a> IM]M[嵍ke*ZN a9>ujԞ~2gH|4I̵Wk[dWZtw>~S1=?f,"% ||V4N0xzj5L =P3< i[tJbwtuY|џl[O@^l0}ɫs]]Ͻӛ>L>]G26DTuMG_:u1,w|Xo̅h\o_ڼXymt(vm;q2Jj*OQЋ0@)@'1wBWQ`()ߏ-ϳJ 8XjPC^O{b=OeW}͛7id"o&S)weN+ K.r}~7QL< nI[F^W;Ov]*vS7j7_/~ٌ_o`3/X&K>R 6gaE LZ_>Yhf,C^avI<֑QةY#<x<{xՇjWQ`k}l~ 9?v~ka~h}o:[vy0no0U*(:QNcʙeBe̴ X7/uY@FxwzJ[i{Rv9Z48_*Ts2WU>Wu0j[_nvC%Iߤ\_cZU9[62Fy{Wƈ>?:f[kv=??Xo]_K<0mmYb&h*K M'LKiH3Vx8P;Dk1!*dFk^^ %DPM=5@.UY# u⏆_Kj⼒Yʴ=Ӵ^[gTG鮄LL@#\]K;UEmYI~vk'-_=_o[_ǟ]~zfW)ӵ(ZP ^VQA/5ZNsWLCw0*e"fq0dlh{},?߮zG*[Uv3F[3 Ɩ%+r:SmChQQA~iI!joB4nڽSjgdvC#3_Gv/2zqY''uIa] G猸!:ytǽ_jg;x_3W[^~>21NFQ@ =Px`QE\K }\OGW=]0B!OCK s@ms~A~? 8W{~@Ϳ}H~<|p_S<M)~#>Jy^Ds]yT N%>Ii3gpu*m"Z\g 'pOfȬQbay:}Ng߾xܠ@ i PJb9D לB;&$n&k4sx.-_ӣ,պe[~ɯ|S}mRNP6 h[W_ O"}-eu;t} 4Cل8?Cs,ӧB‹ӂ|xJwȁٍ.mhqPgx\]m%[/v ac;Л?֘Ț:g_Ƃ_!4Q|\3H ėbj *Bsߕk>8{ by:EB?}_<ؚNl>p_M™dt6QD: w*D6kL/>]j=xd(1o^}4tLvf_H;ߪB:$G?w̃|qͥG:j:X:un2v}~~s@#MzۮkuL'kOOlst vkgH^Y{_[cF8i1\_4v j`Xp<# 4αdڡW(_]IMǕ_OCv+6xɫ4_O$n"ϣlSؠ)Yw?v_^]wy! c~7qrE`i]@=D2tж?qV_g(;PR|Q:?OC;w-,Ad\Kk/ZhČr*7Y8kҾ F)/@UZǘ9ϦЏT%T#azJKԓ54uK/6n~Q?~#ͮ]MS';t 5UM!X`K>Ȅ9:ǬwƊ7^S҄/@g%9o~>rS!s:Jpetd@g \] ڀ3WuOeh]ҳ]~be*4O^K׋xϲ{kV` ޼y J;.yy Bdh5,O r Szx=Ӧ9Y\kC&~~qh'?;g,g{~ϊۄ=r5c`&[oCWlosOM\P8߿'e@[(*M40]vTM ¹?@P!~89&yŮOZ?埕o7.>{]&_e9鹙Mog( uRWq |6myeppn* u/<- ϖaF>ӀV)3M ڡM&iYkq>+c_^#_yv -q4qٖ%G߬S>IuxD۩ ]~:qO uXgbi&;M CQO /MMy7w:p1^6$'5u4)ggCT>2^|oj ]NZMٙ1~dɀ:0䧧'v.Xi Shm{#;wHu]۞WHƌ(TG]wVG/i#"4_4(nN\x>eȲIN88\ׇ_GxtpuG>tmFn~zKX7Wf1AJ/v(9+mm=G߭ɼ<=^,f@^X.D\#Ɣ]Y):QdD/_~=Bj=ÿum2Io}aNզ]dDxMRsd|4Kٺ7IS'{gHv#;9"c?Į9?znXoؘј?36?yrи䞶_ZEA jxP}r 8fJR%M~[FQ<DN^ PX yI|\x3{|XT; ?z`WNi28Eh_]UrK;2?Czv+/ 'QwO˄ֶS9 v5_e:&cXno<9WYn:.隓s+Yv1.k˺+_֧twډ//<%_bvdpWAeS?(ԩȂ.\Fl;oS\z»NITY?sezN]w}͵_o%ZlV$Y?O-v||Su;vu 1$! ԸOy_ ~>tn҇ zɗw~ނy*Y.:UIzuۉ`]^zF^4y]hd2X?JOԩ vi>ߧrԯby}/v('FNu6>P{w/;p|Wn][o"v}l<W^|4(>mf:w*3{@[^PHLb {V7pOzyպ8 Rdz2N}=]^֧^EuP6&轜z?k|^Y~m,ˎ7mTPYۗI+oehߢ4[H;]5SU?_tM]]k7X[wkFe5۬X0=r7O5|hf 9L->:*tOGKu6t{%O(ñF S+j2<Jg'qOk!?ٕi)']Y:,r͘SwG Mʂבi^6{yt} w[Ѷ<^m ;kK׭)]/w?'m3k?_s~ݵe7?ӟe`aRؐ'0xzE)J/p ³FK ty{vG@ CCi>q.y,:HO}2isH:` Ku=|-'!ûI*_z*x]dwAoNO&n4vK|0 JRN=v1th~TIXxm0 vkw`:/i=o5͵n+u]~V;wӯE+ b̈_ky\o:bali=?O[` t|6;?ۗ {^!@ dLWBy){e\VM {=v|pI# N˦S>\'9ή/5LWv;=ۤէ:ʳ{ͮ5}'WւrtC T 2)M<kFߥs"c wkg\o?g$ xa7R xp x=}7p=`2|R`cCs8hЪ?L" =<H#2tliY%Ưؑ.<jp-A_'nԣܵP_~wP]WQĀkzHlxs:Ȩܣe?~ptõΛwk[Ʋ1>1~b x""Yu? ">t/G( ~u!1 ɿʓώ'H}XXuk?K-N<Wd >r6"w`soH~AK) TkSxJ:B)O~CthF|e?(k]w_oǗVlX37ǗO7uܯ_FοU\[~_| 1 RC&6`) cE_q0s=t"Vo;:M@5dyALfW9\o~v)3b8\5,~+{$=ʀJqS}?:OUKw5TfmodBwbuISn/{w_O'jKj7 -K 3.!(ᄉ:Fy?} v.=B_=T璩Ovu.# PFȠK{.џp'G'zL6m 6rv:h [\DIJu*K}y"pk^=*c_X=߱1pv~+_L kn_!dx2:5āuл+ ]v}E&v89y9/p4ˏ Sr^~e #ѫϯMFh oÜ\aW9"Gz^T!]L s5\ hde8W/V# =Yթ5|KkZGe'15sbyӫRv#9i]W{w֜ptĮ{߱[#Y#~& o< ( ӑwLSj^nOM,s}?RE&G˖@50*]r/vnvC}7׮i>l^1p̑$G=ظw?kX@g!5_Ñ;}~zkhQ`@ݼ8nK>{h7HHn49Bxol߽nd;S`h  x#fOBsNxpTHx$}ʡr~[^mz?|MvV^I#9Nݹ$g{*#sGꟽ;w_5kvqîkնb763tBmϵg.Y|7=YIo:y:;t,*œ6aRvDã1^^Y̤9- 4tJL݂rhfѤq*fARޫcԊoAER^퓯,u~mBx5P+ӻ:Or~L#X;[vڞ/('W *sv*fU7BL'?Wu3.=~XQ.Zصֵt_]o /Bp4 Iwxc: cYKc2D`.`Pöe?S>oE mi*Oǫ[Vh@/#_??iKfyom*_1O>\Z[9~]Q9>ׯN;}](Ldkh_Iv;h_ b5yxmdq; _+v_6^ȵg x ӸcOT%8?ӟaz\ۍFWz:iG 2P: hnK@5]~_DC!.7C #z&=ëuM$g&]J H\ "%0v8 gm:vG✦A hJ/v½ ~Cʃ\sA~i=K/Toqg:qv8?[/6fmq'ukw??_-WfNO< 2P+ac <$…7]&xpi@4s`c8iv?BIՃG߹Ž )/W#Ciߺǐ4mxO<\)wOs?':i?:`06v_:ƞa۰iZ"ktee}v?fgwpW +}>ΉGt>1s G$PWyce0Ko^4Xl1lPJ9C5!6kIe;Jwz5t `4i)7 #b'0|LneНS#ţ{QV-T&=.~}c]w_o?' kqy}ȷ,Ooui U3NL 8N)&& + xڢww!h0 @gvJ/S^[!h\"u:̢;h78Ź(K;>Wkۗ_~IyQn;G4Cx9G߲wwߠFu-|khAA_Ý;gY}g?6Sikߵ_?{9> v~1q7H$s=>|Gׁ`ti094DŽS3uYuP :8eC7GT~vQv "d1h:u_#_$9&v\ʡ>˷Cw?o5v7Vg=k@?;6ön[8AXfqPI🧟7tTO X `b\!pO~3o W^P<\4`ݷR^W9FիK搫GtvQi*TI"YWXenw_%LI|vkwH}G6|z]W\7usRisNPbrKVqKqht]?;3_? Y7kk B36=q wZå?")]g'-WAmH,@KhhJ/`JPnh[4ߘRV EʀLyZT~ L2xM+wPG$SNZlۙei=U~!We$o"J]/-6.V~3x~>4^AA0/b<| C/}߶Io;W{g7C;zss]w_oX7 [+I|˷bz??PG *UMsU9+v ,@aHSE]x1DU>xh8 t|̮-rH)&EEm8IlhH9ڀ_јx<g萝xޫN3V?w7',تk{Mɞ:7$O7bFxgw֌PO~TFZ--#/@ Pߏ:`@3[w82Hw@-þ+_~g~$07C p*(hxA_D t(1VħtHyiˈs]yU2+>/C77Fu(#}?s3GYGǬ_M֢9/v^-e3>菮'17kՇ[o՟e]g XPc@ D4G;UQ%O=~ )t]ObʑCW8x@[%-'B^ړ q^xߤ5ƇN6Wi s·[@{0&Qw^V<SiB<Z@6֖gl苽3ZvtNw,;J_4#c\[cb[Y/gz]C k#D7cL\€Ao"9$22DcnPqй*r͈Ru'x끾O_s>}K.9]ir9"zp^LL/~A&:Hr>t-]Yɟ{Yʵ^|U|ɅV}v}4S=u>>u.gIBh<&ƤlS;=Ť[VXRr1c.kO/Y;s˖֐fb:4cI~:VΨώʂsz);y@vP8nD@IDATC77皂!>n.~t9S+IzN>Gˁp/ov<MʥK&J;/3vRK;]Cv}?}pR 4v-ʷ~_69m>K{\KRȂN {݄{wgb^Yˬ%akWucKg l c8!֙<@-Mw|]foR/9wKXx (|d.>W|@չy؄z:~p'#o" QKkAY.hC!t);2#c(<+?(‘  !MKܥH(e0Z Nٱ3Q:+:'G Jg7L 'x\hGc9//M\oҤ+-]ΡJҴ)lbMZ&q\=9%u y,|qܗ~{(ssc[#w_xq__&xX< !@`EP4%y9&($߫qޯV %0L$}_csj]!k`T5?Ib)`ϯx IwWl qf\@~0k@;4 0)z&~XOshj$ ,@{ /:9$<;t2K kG'%FG9Ȏ6myiۜ'obxeaq"~@+?ZEqLaVxڥݯ 8~P(~GMohK￱t+|@_o,ɮaْ]H3>;i?s28#6IgL.Ga0\&R rvQWN]@igPv$+++p57q:'-S'z$mG 0$!n|+󚥺>}5QvIXIwܾUU)U7Y++ʕv2D= 0x4O vUnN{?&_Ykg]{;rc~|tb:t㧭?!'+9;-;bxfؘho_A aPҾ"OVZε>L-)u F#y&+ lɌb@qO= xk x=k\C|[t$ qKֹuMo19W:i{w#/)!_N vGl\s[Xka f }xg,4_/1P1H85ګyLL0d \?,Za(Zs[J38/ R91eC4;*Kh8C){N]U;uDe< <ʑѢ~0"ݮ/L?ͷ;,x Uf1Om& pMy2(??dq茝Wrk~\c`/7c?Owm@G_=cnc|Wa6$0eb_/b @~ʈS<:al1JyvR 27 -x3>9wch}Q\bZs#}?kʮn[ ) ~4g<|K?[LvJup=dߴ*H*Y-QCp |kh7@ \n$yK9q)[Peu/ZK(MŔ'q6\]<"B'Km-2Jfj V|i#. xkv~ ҄?jcaYlwAN%Ywf-8BXoI ыt<|wĴWo9yn NI 5+Qδ Jن0H9LHQEƋo#$+nHzxN=}@(uO=\_ d]sʟYG&֑ <5?r|Gj3`Ҩ׵vHl!/˘u~E{ں;0c._Y;fɬ ]s菵cDzCϳ_G/ տ T,  NH^@iDfb h21s rv3ޯ EO>7"w)$H{bM~񫯾 o~NȚBh? CvO OOQ]XBΧ o#{j|'GtP]tsit]l6Fk+kϿ'`wGo9M7!J`4 ݙ:] \te>:PΕ&AՖ8N7 C{^g+94oԏGLWJ\x?8b#oЪ4uEޏ[X7Ҧ+=w ܟQ~Ñhw3p?6bAÁg5!XWϵsfϮkuYr]_k`g\O? 5 RՄit4,>n7z@hwѩ8PV)ӥK^r+>ژER]Oѫd RxМr"LkG*LuӣLܥ/Љ,&O Cpw_~7͵_ZoF;Ğ=b,^5[ˮucl==u _^ uD2YȊk 2q9z^PVV{[6bq{ʩ2]\x Q~Xz9 |ƂŽ,M |IM3jOdwyEQ`MREwd!8+館ӣTZWVzC{'Ɗhxr?-d<_NXoٽAqY[l d7??>Ψp 50>_yC[D3@(XpfCXIy!w2b.pUO”W:s\uD`{`^3pJP݈Uu=Qøe'<}|~qo[^Qvxy߽Ϯu 2vx6&T8WLBc^95ΌA;%O!:;ZW*V6KCq;]G_5=[)9F&!h6qw0XDZ;pr PPw"bΧ.G}bz7`O?(?25r| ~ʴ"Pdב|EaN2.y $҄9eOH|>)?} ʯ/νѦQNQ=y\=9>]kx1ulԷrU@q}1:__SW_5u y8dBs2)u"5ˀ^8zςE<>; b_(M%WpF|3k_TP mk`vmʿt xX]#L{ɉCy:$׺/Zэ&ȏlUEiyu~t{'W[gݱVM5#wL]OkoLTG:Ϛ_|<6s[j0^?l>⮑.,\\2I/4Q:[ԁh6%vsы}JeFO=~7*s(frR4my'BSO^k[u&I:;ڤ=Ev eȂﴗI~[!?͉Vx@tuhVs|NVϘW?֔}'ǮgZkOGݰ&F `#q(䩪t]L7(\)Yo^-Cz/5dmWÏCP>k_ή,2`*!`*,E8`8N`YE2hcx9\̒<ť9y+_kKYi2BQF?3svG%D_o}y3kc/eil׾]8_>ӏ0Ic#9_8Pӟ7v0Q@ `1р9bG;٢r:_%B\[]:?u%~[V~&0e`q 4:W(zc<"A@gIreq2v_GڶݵK݅ж^|?/ȕH2y>x8VڟCW=~G?g@z3g>>vo] 6B_Dg؟lϵ?]b~|Cgw:V?/Υ|:f 1:@! qt >!vEHck}&~/삚B)gK|٩|>h.@U1)ʵ*@08: >+.gڍov<&nZ: vu\ \OQm˓ѯ#&,_^^{9T9uMyI=O/87νg!r/vg^'M9!W[{:W̛QV!1=k=k_;}_?cw@e.\Ns>0w+o4:LO~oͯks^9P1l'hԛ!N@;\&߿~ś/Nd=Rz^ORkG$}SW*Zi70WKKVuƀt di*  Z|s-uc;*Fm2;ώ̝Ug/=]Oǖ^ٗV79;>80Op?+tsNkR })GYFaͰ A@ї287N%ԃGە5ˆs|Ĕ.MǹC]h@#Bp}x=s~QZ7M &=\gM[2D@]7Y%0Y'j{ɝdоW)?Ҷ̏t{Qc?pa<;OG.O?_|K9KPzGTZc"/ߏFݡ^y˻Đ++aFYr&ksx?R y@H*O>3<?tG]9̀n7M|_ >;yBЧ;yvͮ/|azeڼ^g;]]+1 `~kGnXo?cak/}?O?_-c1c$~s 3o:==vH@;0:I-BG hAN޼'I+@gz&pdkuk_9Ӏ2Ȇ%>#:-md4O&ҡiq>#>I:sr7ߨ + MvG M'E' o2 U$̟:A;w_kMyлVfۯ_}VS !_!㷔.PC#PdSpqf@.M? >@ٙ$$C0ϻU{M |X JRnʗx*N]dl<뗯txj >ٝev{ FW(`w>/ xYyE3BZt? ŏ,{dt'%a7f[q>ec눵k]{qΌm ?L?{&]I<^}?#DPk+Pq)Lf&KC2KK+'rF>;`] #T6#LzSԿޏ _x`XOtUt6KzZp.;ԇ^_?V8\sc]; kӋ'YZ/QW0'O, Fg2Q:@*_>0(tMś6J +s鼂s^r\ '!x*Lŕa1ϒO>UɧNɷ4BC'9.i# Cnk5`_ꟴ;Rm~^Ob'JsK8yHB_Wz/v?b}l5;EeSEE Iѵ|)'>_4N~W ntġYu'XQ xwM;9@꫗Rky :y5 9| `ux< j msؤtJk*J_&O&Kk1?ڵ6m11MH<&fd#U{&w;_VkƮkk?urⳝ5sك'ϩƹ5|Wwnk'/3 H xPn6|]v K.f W:/@?AwWW;;w?]w??D`[+[ogξlyu特|e|(_#1_sjs])%SOz^wW_"?1PApY?/mz LS_FzX1DuJv S*CAF|k??㕲=!?^5cCkѫ,Xkn]5_GԮOA[{_ٝTCҠ΂0^t-*7PxsAeWĮ ?LG'h"߁G[f9ng SUbX&m2I=QY~d?M;EidlTN?c9wT~eا)+n]`\L49 !rA' +%ЬRvx7 nV%bC6i*a*`|T_Y,GgOɽ>+dӣ9xXϬ3&v_oOֱ'X7/q1GSG!Y/2S32f&r(Bٜm~g|fhѰ~Jc]s;l3 &N'RMh\CW#,u'0 8#+j|7޼~د_]bx*߹Ys0qït^STGP܇gYx7xkCDcgأICSgCEwl_acO?R *߼y` lO!*!:/L9pAs;,C;/r-:m! "]jwXo o嵅,^#.~5;0k往ca#a@#{@ɹ/3'WTW[׭a\vC?1s{~c6_E}뿘;gz1ͱeml_m~WD!]#JõrK7;(a]Bhb]g'Jz?0gwԻ+2ο#~bTkC@z GC|&LwCćoώӎOڐ6S=v|OcO.~ n;϶??)#-#P[xD9Bx%壈Th/9rRka4+[@/߼^>OXY4@S_Ηݥ5M&ώ-QxlˋR^9ukkw@ȹ4y/mV#>}E-}tʟgk(yOX,ܼ;> I߹rx;g=S ?c+Hj?5 GB|q_?EJ'6F6ӿӷc;>(\dS RŐK :N?zOiIcYؖn<(0/Zu YHs)p6k(|p__/&4iS'H=Y@<ˆFxW+mRK`ں(yHڤ|p~? L>KמdǠqG'雌 wS/ W߮3kHzi>F?hDo?xe@pw,펡T10G0]n΋Af; >e/qdgZA:P0MV搶r^Δr=ژMyd!8GкKw rcqxkUsnevm#YgN_vҮ\O‚hӕʡ.zoz'`w;P|I֎K֍]KA\@GX;joRz}":μ]C%/P_~e( 'mߤb4P-tr-;؄&}}%ax% :#OJFp<:vo(twW-W|NY/לqžO>ǿMB9_?O??z @TqhE:; (J'/@ sFz _:=eFyq1V*﭂Q;'5Av_Ǥju5^/o8e/yL"Gs)<ɗ h{2 ރuQڴnx.ߑ{Y-^{7_B\kc, 8k}~|z{;;1zd5N_j c[;??"kwJFX~%z:,80]\=7\[S,se-s#|W_}\Ыo*;| =;ECHC}[SG-e!y'9Dן^g/Gֽ5gh":}ՎG4Wd:p:EdלV*jj:я=Q_|Eio tXek|-rz`zz&^)ouw=];\c/>ijG>uW H:HZ6'wC:Ly=yɵux@ ~?` ^W&}2i<Ź+G6 ԛ '-t|㦰&QǗ^~=GWPic#n[i]V +rCe ).9q6đ-#}Fl& @7DGTWw?6NGG_;_<ӏX-@1P0@;5IYC7+|)(sP19S Qdݎ*~6BhwyԁfGT|%?7omvAI&28bym^&/F>>nw3T,@˵gmNjL|n,eۺQ=óKGjMֆŸ8>9P; Wng@IDAT;Є:瀣찲 ]O#caP@&A9Ą> ibQ.:OfIӯꖞ>7xHo'^W`JpOOBS94z{;g^{4@g8:+zeC?ɫ?? Tw_.w6oTIJnh[`「s2L\q^}H}W \PY@txy40`|m!'|G.[qMXqbW( \YAd/7*`chԭ<'ゑr_P CN`,uw}AqVZ#ogX*5k~ޓ?:1WڰkܨWr#腇~&㞾[_ӷntFBkC< /ţwv  Z0h#_b2:-gI]E1Dƥdδee4M{ɤ^9:WLu/Lf!tLl&(ȗw-F<έs}y.16٦}vcm{]LPvI+|B;Lƅv7?B]DTW[;]W?;QlP.[vGb1:OBvH6/k.H;@WyK]qSAG:Ÿ|sPn^qʣur姍εRWڄNe6}R,w;{1FX:mwT)';;чhr0Tf%>xEԕ}owWWw_aɆ\ƙH_| ?&6E_&Go;h&`D8$|xVT&eЉpHG `>A9G?xnK-Cp_\Z\?o^eK(2xFVk]^hߵcԗ?Moﱝi4+t=#On i:"=l?,@X׿)FjFZiA>Eu5h|s?<~2+T LDd|j^9`IxyB(A0S%S ?Bd(Z@vgå(ҶNNcvo<} ] *Wwzn+|'l\O͍|h %}>ϵX @r~ ne7xsszw?ֹ=D$y-/]SCjn:VIqѕ ^gOxX( b43i'4dOV2) A+M`})!E4N&/ dJ:o44@AP (+ Ҵ-$#+y Dfu#m{C911oX: DMzN06e4GFy\S_DG^ };gSAWwɓCqyˀ؜4@g 6}SP$?GBc_dʡLBہ%0t^to.{L/s&A}vN)&A.|ih}դ>ʥ+$^Z+=2Ϙ8/PFoιtQ_g8u^;j?w$WxYPu??28:=:u)Lu:43Z~ZY/,gG/ 4b7i/MdAu>dՕB+KFerD.un_ yʐ}ﻼG_GcB 묵լjŎ2O_>2w`10Il36Én1]O@)G0$UpB6%}>`ʉLɃF}^ΘrdqA/Wb!tXl^0oӇ.ƪ##O_9Oki3:>W;t?k VKq߶FCGtj?(;萮V[oӵ;v__|G!k?/~֠^q9GIqY7u.s̡,`xϹ5'0Q=ƚ|29wsrKs Q? "sᅇG({xiؚ!/F6qvuts.B1}&PLVyϤN ~wJ/־]hX;2=7j;z;O?q~O{|j֟g P/~:e1(uW,:?-дIg!k A& Yyn%x_!<##OGhU+rtr.}':d7@M~Qou(/l%Dͻmd3)u\p;vuy&`l?cy~#r$Ote/fLkP&5o]PߏIW-z y(+U?u/eA+f\+l%/.@ TʅO(YN:_M9G=G,4uDz'}P.;_y\'- dټaj;@>3vf~\[k]jv5!omֹvD_wvKs^ب3Ol虇o?ȍ'GYASߤ~Nf``\<Ub*[8'b4Ik#Ցsn~y 2<G;?{ni{$ BvOj+3xڱ%_^+;]V;|pϿH䒯rOy0eO? `_cʘ͟ 4G3.:/z/z-\X2Fc'5_?@X}::U`'?C/ZoEn{㌎ҟ;/EzBXqyPί°w, 0 ܒ⼼|r?& ~ǑcTv^:6ΧIO=M[%5@4/sishc Ի| {kz}\_nxs!o\> '琧N@ SBΡ JgǕrx!/o{b9ʮRׯ;LSN^Os2G4+-ޫμl9Co'aCiwM7E_uWzR׮j`S ux_>op,2#׳XҢ||ȓ'A0hQ8.)ׁ:vwԸǐJ6x9&tFL:MWWֵ2Bʊ;잦9^%]}-õ W4`Z g|wsALws]'tWf_ٗs]Lo8v"AbI=O 7u"d,<'-X |Fԝr9j'&ݵõc&^W]AXvPcVj[B/no0Q(UtKC)grYz|.c&&_<2;ڠHÐ{^Ѣ}D &w_yVt!R1,|?f7^~VI/1?} Ԋ62Fy׽ƕ1"AiGtWWwf]z쇟tfƉQ 2amX^Ndl^c' ԡo]soUEc&5(eI-1w_H2?-K?pNY((V$VϹԹs-GZ '&D̥њPeVyQ$zb]#_u(O.89D&#L쟦Z:S&"y9!?"N?"X~S~.\ƚ1sG~Uxwe_]kٽ]v}O˵86ykR ʸ?C#_RI{I+vuzOwg^? KEO7ΫunJ8O6u:>[+qd{J~3xCk;c km?ywq"0lE([s<LM`Ԭbhp-0q}=ҔM %xx [4$=4+ӴApm\EPFH^@ͿϽH~<|p_><4MWXGK(mhc#29׷EMv_u*yɖ?gG?R_o~"zt'u?p gfGuf͹Xa t:bn]?/z%1yJ"k zi1N1LILhUqBR6|OZRW꾗M]G%{L#ir b:uEt-OPneޯ=n.[ɗ&u(a*^韡 ?ˏ,ӧ.;w}ڑ+f7oCơ~P_OmVw 7DkGmjہ4F ~1k^Ƃ(dAf_ţu:.( ̡~WƮ S'  yI:Cwz`]sWjɋA D!;NLdrSk^cW])IAZ5d,λЦ4/@9? ]JFWw_9UXk#z ]o=M6_Xazx~֢P@B>l3;8\+I/M): H!v%R^_<eWOC㓐][lɻ0;|6IιΚXxtCczr rQf~?[)ME{ZwwWWw__a\?ys?^x|HC '+j0%ͯ z'$\`޷$c\Rnr#tyZ'yS=~X!4RVyF+<] f95mh1Ci_.D͛7 P HDViB\v1*uTm0SWp PzFiG)[_7_cGgGy]?]5AG:8 ǾG8Y+YWχ emPdkF_/ѫg\>5_%O?w`AG̉: z:j'\R8 Cʙaʠ }]e"4C,Kr[Lc`1bPT_Z J;.yyrѬ31r myZS(qr~ۣz\kCf'K?K⥝XgNB3fm9G#.ņ3Ojx]5QY/g_"9`Ȣi1||g&+~Nt5ccnM1 ݜ]~i|y -GüY iceysp3ϡM eawRRW)}R^_N{ނX(G>H~ h> hV^VoA;im$s6q C145;e2n\z[{g ;g_?u86;> ȌjQyM$8D)lOK~0/q_qXw@XpkTO4K(tE= "n2dctiԭ5G9;My5 .o/囲ZπSy<}qAu~do+J3 S鉝 c>_:}GShmHq@gDD'/i6ZUoB^??ZT?&tDt(_}P(st0ʜp~wNضݗ4[_ goMz9FD4( 49w彈#Gq> ?S9^,=B 5[KׯӼh},P6uW_}_|z|IR~Sі+o2wʟ:-6"<%״mk@.pnT)?qJ'-4掷k츚1@sD/a-G鎮]q3c_آt8VNkW%;,vqDqX?ɁL .>x^:eԹ ğ"+oUH P1yI|\xxvx&!/v('FNuo)0l~w/?:._zkEc;}lS?O~/_#&=+ P ${X&9\8_zyxAqɌF8=yQy 4]F 3[t lOGKu&d{$OñF: S+j2y2Z>>[8iOSɮLL9С97cNw߼[>ʥdpnFLvfˣ.nO$ MTW/ϴ s]Mg&N4fQPE~-ɋǥcE9'B:`tJq;"{F6`Sd{yv/(Ptr걋)&nkHUNdN\=\ q!]2y> Mmٷn+?u~Vo?JT/'t?EfD]cali=mO% =ߙG / {!@+E&Ve 0%P'_R)y5idXێOt.iIm_y|˓]_j4;vR?zMIO>V(5Q~BضPy(ȟA& xG^bm-?CdC];`F|8 wd ^؍ fN;ew:`iw=tM^oS'E+2I96"wҕz! bi{}9eji7yBO@'2]H<|͈LG啓ǃr KGj}|ٞlń`Ggn ǗOo:J_%c/e/tZ~]XA`D24#M<<>9Ѓ`iwhl#G[m#ف6ZeprN1shd!2L{^~d #ϏM๼ sr]E_XHxc!D4q%%_GzS;byg~Nʖ̉^i76ѥ|?9pT_ڴ;";WG?t,- !# ç9ȻX~Sr[pa'n747J?_.Parl4fQd{4///| nof7W_}a5}k,m•-,eШ[h! Rz1B!e$BiO|Dj#lۈI;i<<vwW?^Yx>jl5qQ_Y;Vy_ۏ y޿{?^|< l;"߀c1lm%GR8BxlB?͝(K3yYVKJ5v ?ya-9^ȟiܛ7 ʧxy<[EI+i8O_ z6fwMIIGV:[cvSְg_\{Gl8P? ;?[@LoQ>ǁ>,17?@!M;,R $]7A!nxo}3 0t4.x#͞x is8ǃ*Ex/\?ǦO9T1|+mS0oSUWw%aΧS^gs"#³KOkB℮b[j.۳%+ ?7X=IotK*١c0E漷 #Ꞿ><>LCRICP-(`MlD\{9 t`Z1X~xyG+ t_ڦB ȟӲm㯧*2\S&bnqڥ>K{N^P>gWS/^b7;;Go3tKtN?Wtyqbs_f{֨??E]kc7өZI!E8q Ivu s dq.}h[B ۔uxWІ&~"Oe2^W_~qOm9_yU@MwO~Nu^~ڣu`?`L~ٵZGw_a %R_t_?yY_{oסo~8/qwl 0_BwNl^3g03h8= Q+Yzh~:@3| -;byhFC=fm?lEε\Zb~1U MږzTG = [tgԈ{oG|p -IKnur/z3v]kcbA\Ap,oui]Pc냖G81y/8Л44kށ&߹ÀDM)+=Ox!LsDiZ#4gfyA)mLJsm/>@2<Țv 蝣O#r9r>eɻ:?An!zA]VkY;Yom5}eĆKZc[gߏcu( v~2/q7H$s=>|GY8@IDAT`ti094DŽS3u:Yu@y݂:8eҵoԩ:BxȧogKdd%2OL6fKy Z:GB$wrO/ӾM^翡P~DtC^@?ja[7j>[a BA-&~8ҹ:4 PR0U. a#ԯ?wL۱_+/(4`<>7rK+G|O?kv?[^tQnTw7',]k;[k;>,=)dn?oEDxyY֌P%3A[2SF)3@?》.4sS>e~#t:B2IS̏MCG >,M )Ƞ@v+ktNJJ:qA'/eDĨ*y7`cnz9{SȂP>x@ٽɟ  qx-IK,?mJ"-O?>i`L^ecB'o:͵ }?9W/DWwX0?;J_$#c\[_jGOuz1>׺5l߁umXp,1 L€Ao"9/^:WEqP*u/rϯ{>}K.9Yir9Vn<f21~}j4ԡ@kQkKޗ\aۋ/Ъn7l3߯^>/}C#oLii.{=g1?ƳbL9:;ITWXإcG._qk~lk o&C|ls6g\vi?vF#Q3we9]z);y@vPC*߽<tvrsxΙjXOs9ihB``}@4i_cMm;/s/F -mAv΋W|@/ѹy؄z:!j8h7ts QCkAYn C%N=蒇OSvd@G. =oکa r`Oz}y :];w&WS6olf|dldtwWWw'λ؃>;6jl`3O_=.O/ͨGSo}>}%l9w] ȸY|?}Ѝhf hܰ}r FxlA>I?v|v SrGPQR;䋡4K3|a'ӖUO J Sd*2 _ыԫ O 4bode&KzIPνYLd໼.ښvG&4Eny)1:JMX΁Evi۶M]n'i_ ?~H[1e¯]^u)By_EuļuF6F辙Wy@UW ƄyֆْYH3>_Vտ[@B1quF3&0ef]j1G0 |tvv $]2yQڽ~efIzĎz$'mGy1~wy:͛leٵ?p)>~ٻkzw A|ɭɰ/y}R4|}yh74GCKi푹bn*N{{cћ#a})߽_`Bi6'{BGܝg(/ׯ_]*#/֞OZ]f%MB9?Aʫ7KB᥯{/wO&P_ϮbkUj=q1rϯt]h_y2s_ݏZh,F_{0« K$ ^8yD/}'΂42SOI'Bk1PZdڶ CYOxͧ2<hw`׆t##w? (M#{snGٜQ'4SoڶlO{&3~g#KwwWW[w7jc+WϺP#:.b3?i,,03GhYPe,h#m!RM-;C ]Q@ x $DIm) ~v"G4+ OW2se@GGVg0i俷M}V3̖y_N'33:B9Wטx9🧟 @ȣg }_E/rl]0eb_/b @gA#LcvWʓ7;ȶ\`:?)#(@ـG{^9' k:dy--l'vԯڷisg,):||r~N#oa}ڏF]/P/ckOz?}8ߝQ|-'uS(Jg%u!\cd9L#RFX.۳@֫ 9HIdPVE>s~odv-^ShudoKH{|Ǐ_Wau|%Gj3`Ш׵vHl!o1A;ikܗ̘ ]鯵tw:}Wj_·G/~y70ˣct,b'FCMXH^@i,$ X% R} ?2>XCsd9'>+Iz&ή[͜f!/K¥Mۇ餑c2A ^udAyHgȉN o \?c*?(]#4zUjlm2_3Z=GvOOi]Kj7S5{Q?y~􋟿y9b]R^(Hyɞ6e\b1bp#׎#u\gah"z嗜7[|{IyKC'ɱٕ4kd,kOB2:p *u+O6{̀+nڰO}]͑y2Qm9OsU1⌇+;_:Ӊlj3 ׀_5>Vj?O?? d `%G#5vF84އoK/e <+sh(/u_e82n7{;Ձg#&<>rIx]ZOZ&_W9 8|ޅܶi /xpߗ-ܟR~Ñhw3pѓytPq^8g;'kv_/cw.k`O]>/wdQЀ(1PMOvIS.L^v 1wS/y&z <.J:ewʡ]mER]OѣdoHEs~Zod\;V?2 H_'}Iy4 t"pw_܁{xIOk o f=1Gͪ~_kiQ]k#hCtP?P6(z0`#eUA#:8.9Gcp\ b얲X=Ů_N.(R?NH}9|ƂŽ<,N |IM3[՞6Z~9Kգ4Kّ^H^ սN>=BE~!uo\#~od<97VE%ƓZx! j@ݛ;(?kWl d 3*8B Ͼ}Ҁ/SL G,8Gglyae\VܻrWy` >~/_/cN O\?"|#cd@O>yԟ0n١YCT>u?87-h(;u2+L,Mp-dK?mi8"ޭ$]΄-77sEJx|0}pEN>/=,Q$ |?Tgq3cc3sI8:?cwk]?*T6KC/q;]G_5=[)9F&!h6qw0XDZ;pr PP{|1Sbz7`O_k~TMs^?eZOw`(H>"0R'`L>Pso|z}{qo.WϥG{g&OWk_;^n\{Pܼc`f %oNyޚ:@؛IK~FN`[˷mMj mrL=y⪯m\x$}hm5|" ^W&yUnmzZ;'.Ze҇CQ~֡^Zi::nX?cn_XSMvjkUW?t?ӏߚ.,m#eࢠ_U=3b~IEu=Hq|7z2ġyR~HV}d08C<&"c;O /Rd>vcvnE/(,.@D˹@ʗ`|).x\\-]<^rJ*2`?*!:gˮk,Yw{q(Ksdg{eڵᘰ[~)TOϻb9O/~ޠyG.Ddҋ|RsnwgKԍtoUZ#ÔUP97T^Yr\;e 'c~ϳ j -uZ+fqU7uMU}Piiy9_LvQvҁF CiX5At_7ߜCsɎ{(ХOxN~׎,H$=^.Q80Op_+t<#S߁a@/Oqepn;ݝJvQd+kˆs|Ĕ.MǹC]h@#Bp}x=s(v-_2tIxo-dqmwGdaЌ [rtғ=CWNy2Oh߫CٔfiIGWƨ\8 ):Ęڳk3/k >zs-U~ӷ4Pcb)pix\Q9JCrLQ!H;4q:uyفx%@r%#+@dxlnOA2p^*A;h _ɇr畞G^~vd~=ۻN,} _wtOvп5ojeN+=3B]h ߾-~م6WAW@Hp 6e;kX ӷe,fOs p @Ggi(b_>@9 E~-]ɛG?ih\co:̵:ⱿW^i@fdÇ uL_C62M@Fy'kw4]VڑQ$9dlwTM&#|p&m̓ȢD7_*oO o;W&ZлVfۯ_}VS !?[J (2xV83 ʎ^@ L !XCق=y?bs`N%pc)7 <G.2r6W:<2^ <,G<"G홯vݯ^uG=2Nݓ_Yђ{3Ok8t uڵk={kŸ}v`g6]?r sbƄ[XuV}"S OI't,'ՀW͋Jˈgbx"([5(8ҔU&N\WVץ!GFإ/rF>;`^ #T6#LzSԿޗ _xxaX/i{7m;$4y \>v α5ɱ#_q`Ʈw@OB_7QW0c!>O, Fg2Q:@(_^0(t/MuU@K9tM9/OeKqϓpԐQ<&UJ°ҏg'rS{X \m4בI[~ Cnk5`_ꟴ;Rm~^Ob'JsK8\?;J_lk_;k㛭wvʦ1Iѵ|)'>_4N~ ntġYu'XQ xw|B 勗ϵ< :y9 9 `ux< j msؤtJk*J_<&M|b<mڴ4!WFH~&¢W7wGD?:~Y3?ow쯵_/vf&>>⺖_ ,?634f cd_+1C%(wyv]E$,/ӯu^J)<:H+y.#=c{w3PCW_=~5Fg29щ&]y^{1G5Y*d~~ȏ ԡinr7~8@ֻOfeK[^}!S,A^Vx t`CGF POϫ"xud;mȏWe 鏽;iP ctG[o1cצ^>Pua8돉ZiC]oNz2]e Oi!6wg\MoGu['vn~eNe獍g^7tz]3f kGbŮ'ݺyjh ]OGoÿ[-;Aa K[=ZU o皃&%,X#O9Љ]12/OѐE./r4,@9rMj=ZieX3Eef4҇-S9M_1WQ񨁆FQB_Yfp9$^M_o-][oĵ[K?8Amg?go\Ҝ X ;'♼ur{gB}Snh_auq1 vKy} :q%uT}8m@jxi?I#-ܮ/`YӧFec |zN.!i'Myus W.o =sf1$A& 0oyӺfLP:.\os[iN<?{KQ2 ~MDlO!*!:/.6)!F/#a\aN&y\eN})3$@֑aڪvxV^[ȢK:>Iw| @Ijv012/u3?} >Lq4H_٩׽J}i_ְ̉kmr.vC?][#tG6_611w.?vc$ɛ#eK/,>~m~[[<<!pT(t+ ˅nvg=nR_N{2y|0t}ou'Z }71q (M<ߝU͗\+6S=v|O#'?runigOHk(;޻;w+WZo}tv϶[md6gYOޠWEϛW:fc:z]:vomRش* )|bd7ӀEM+sz ]:_TX3E;ȒVPp%=ܴÎW@|_L))Wn{^C\?^'ZyqDڜO>i˻+y64 W7 Q/^f@1I^򯴤[|A]~pT2+]U]&XTIwޯ,*sʛ,}B_P뒻m{ #̩zOykajֺͭߚ'62?@ tXt]w_\ؕkj?b+ ᵗ"RY\K h\iW^^y>OXY4@S_Η?`RɳcK~)bwWNr.M^kqu'eghN,2}ߟu뀅0At+:7^v?;W9hig,7 5 GC}ǿ~W:1?O?Xey |1|z/U )+͠St4柅-ts-Ayz1$dA#!H+@ٴ ɿˣ}4n8/N{r} O*$W*ZK`J]Sy4;6)_9#Oҵ'ÓLr1hғMA;ڳ]}AW,:1Ag4̏F?hD୯zwq#XʎT10G0,C7  m2̗~@2VT1L[y9E˙R`GRNSyD/՞'_kӧK|O>Us.]RyW sBIKU6F]赟L]lE%@IDATrs?_cҩt֍V/k tcM_zLNXyg^kKu="tvMG:/q7`b̂OSF"&-ۅg9Oq&hr)0ǘkiʨ.7X!yGnx7(Kp?z)sLh~渠 ġ a%62bZm_~Zv]R?@C-K.ʓMUyFyeXHI O|r￝~;w_V]ϣƻ_lŵA=b_4cӬ7 牟i~$K2:* ǀD̨R:63 ŎѽydmZ.u]W!dfQ9o; ݻy/m*dsk28W_=e( 'oҀ[sk# T` ݽv +m6iߥ$ ~Qgi]"Zv^]ceV}]Rk?)_OY/k8aO So{՟ 8 "~uuݝPe%W ńч#j׹N(/.?FB*h?)kgu}/Islk<0_|~^D`Ryf\1/1ܵ)nx{z=,Z=o?6Z߫{w[3w vFqVk\?_ocWZ7_ yWoD2Kā (H(? Irmqo u?)G/B_\Ыo*SumޝHu}mվ3Q@KmvmwE{s]ןS+}rdͭ?çmDS)/bW;"i֫ׯȽ{w]GA'RW"5g+yuu[أ?W_qQ?~*;>_{ yR< sM/G YL5|I li]QZ3)Qws뤗o5|GmLIlQQP^]SfAAJ#×ԁN^( q&*_#ԫc*xt߱%cstz` "x9҃)㰎: y14P 4iu㛎'Lpǣ/_9G\+Knhgu?h>T8 rpqo'w%6^GcҡI& {w^OtCugGG[1ӟ;+[b`B1Kw5IYC7U]9w@ b(v?iTHTY&)Q٦\Zmvh wN(avtMK^0J/~f[aZ O2Y?Źk6yTt߹Kg>AYk;Ϝ U'X◺Q=s{w_c[ozl[o?Z{ps( INhsQwXDʤh~u, $(G_@L黠ȋLrԩ|iہ */"F+9{Q+(#狍FN3RWe&ewfj(w|9P4 S_жn헽gdcG} ?C|ۙ#3Vxl]fk@釵|_ 0a#րb%0'0ί{^ѿGkwO'_1\win$u0v,B ^8\\SVPJOE5,P߾QrWPh@ <1=;`=>Tvй^ }G4 ٽn<4ns}tq=q^qx|{[cw3v3 * 3^?oo ZSWg;v?kѓk=|!<nH5Z'vZA*Nҝ2 pŮ|Qp@32^yPڇZMSţv9t +T)vbdJLBmTp%]~'IޜOH#6+W_wɷ skcR}7FO_NLgb@e?Iw{1y)v?Ceg8_o?OX?c`_S"Dg N߄1wf Go :}ι2?|[?~_h/D<S{z8|h#Р? so? r2}!zΪrҥyϏw?t㜭6w?O?2Բnh[`뀌s2yn87/DeR_u+ 0 /L/\rWYH_NhÏ5!ĮQWǹ:W_%*`14~qwqH9 ϡK;:6(C&V/^ҥ_~b#!u}?L%xci5ף/(ֈ[3FIq5ttc#kG7a_QtdC{nO?m"7݁Ѽ";鬲Yh `wx!A=Dyf!tLl&(w-F<9@_^^?mK.3< @rxXi .iveOhyiGBv7?Y[v?c{f3lg~\ߍxƀKtڄ T[F?0O2ч(J^BLw*{vɃyuo?Glj>\aɆk3ÑZou=dLx!Y_o-pcD睄ϪʴX:(skv3XRO=½~e+s"~T'SʤK(2xVVk]^h ߵcԗ?Moﱝm4+t=#Oe7ՆCKG6?aN16VVklL)E{0OޚX&ce@*Τ MNƗ%t rGzNmJ!PƵ׹v^'RmIls{{v'it1Q>.`; 闫\>8C#](-sijx6nϝ:Xg Ev]ݳ釵M۪~1)=1r7j?zG{Os?tz!;/Vy 9Jii*|y['yzNS sD~;wdo??8 Wod5cWHzN_uWڝӁ;8Y?]͇ձ][|ĈͶ]c_ew$Zocك? z5C-hBG637tj)pk)]ߛwAE_;"",ydnO/pH#UIxi|i*CQ Zk 9J:b pG#y~IuF_۽%F7>>dվBe+2=*:W_2d}Q#s a]g[ڹa[oa8p>Oށn&WPx'λ(R>3`HwlJqG_1oQw;<78)Gkmp%Jdy/`ϿO]U1GFrx߆8o:reW>tD# ][{ݾGs j}Mim·ncҨ4vnQ?ѵ;etȮV[oӵk;2N[; ]sw1 sԘM9P"1Wլ??zwpgoqaSRwp(͢3C^$8& YyqxaP|d']r ~4ʪ9 :9N9=E)/⍗兤L^COUV`LxOw.M6?ݽy3`&?KtG/fLk߳Mj8;k_۟!q#YB ^>(z^$eE۠*=gQRXnP9//x|*Ё<TʕO(_Ytxǣ"vO@9JבX>'+HvC+_}wOoZm1Ȓaսg|g|c-3vfd~CT׮_od5v:u;vȋ:λ]?ة/gt|wv̥9_ب3Omꙇo?ȍ'G\}YߤK?UGzOap2 ob7 ΉEe†8Iw0pB:z-/Zuh~wޅFG¼`!t`wp j*=c[嵍ke*sO' @.+׽ YkL1t?Oy@zwֹь Ϋޫ\Om^X:Fv?u֢3ѩ>Y9EX8Ho+!ςe, cihY>W勗O0Ms+GTn^^:6ΧIo=M[%5@4/smshc >ٽr-폻O ;8C\skn?3-&J@\%e9@G^~L9L񹌙W6My['dwE!5iER AL~iWw /A|?Nb&w#Tj}t@Ӷ4ʻ߸2F1(m1;WZu~ҙgk* S_Y.4Cy@vG=8d2kql澇l+1?KNS^Rr /'|7^Gʶ}ӯ{ww^G? KUO7W?dqpͫ;tn9xC,Wb{jg臵_ZG,D `IE( 9S51] ->GW=5!OCK s@msMA~7@8W{?@Ϳ{kyi+><4MWXGK(6a41וI[*Kӎ N%>Ii3?(m"zt'YvƉp 'i3d[st틉[ݱ K_??{k$&#OIp͙A/Ɖ4`0ɷɹM\,'˪e(n婯u{%~_+cԭ|l  U9ӵA,OP'HK'[-wY)ɫA D!;NLU_Ef2x9VUWwrdV4t_ؙ| m@.'{|ߜ? ]JVSk=k-uTO??[O/_Xa^ߺ0vy_[nA . BgwqV^'&_9Ru!v%ZO/3pd.ʙaʠ =2E!5_?齹:<+=&wEqL56ׯ?Di%:V,MGЭ‹v*|) ߧQ}ڣz\kC&~~qh'{wNg{~ϊkhΣKŮw~:^l8ı?^5g{"9`i1||o&+~Nt5cc\RepB7]G>61ZS{2>8/ r] Ȍ[E̍הO2㱮DLcw? "}7%]kA  w\J?κ,k=pViZn*;Ё{е9?5G9;My5 ݷ~_|-(|#&W3 O67u6a*H?OOO\|rN7Fv7;Mig}Sdn2t'q]J?ŢQ@<(pJ:Eh^z5^lɗvd~=S3/8VW^Lk5DG]mږ: aý{*;w w]A7I7VDl'Fa|Kjsd(l{u 蚵.O_ȘX/` Yk$v`Y0@v,a 4["UƮ PK4{BD)s9F;#\+:.cug&Ewv&MwԃN#_ xBK6ӋفfvdyqGAeS?|7<LR5 NӖ20VS7y).=]$q(g\=^?rq׾Zo?k_|G}9AlU1b__zx߀;}8o򫪝I|;S HczycpRjǧu5=׈~msE C91:u;|?<ϿG[Yv_/lܗf?}Ky勗@B͌vpS^UZyq(xK=y @,Az^yv^!hS3sOףi/m/n z/ޯ/%-s|yo7|~- mmTPYۗI+oehߢ4[H;]5SU?_tN]]k7X[w]kݷYo?kg}[[`$z?n?^jO^T^cÌV0iѽӭJdqp;oPgCG1kt 2.&3̓?TXO|oxGk>x=}LQ>'23+ B97cNw߾ N2V7q+ ^Gypڀ^;; yOyK> mˣEv2֖[]S^l:Nzfl[Fko?z088'L!OxaM)JC_j g*# @, ԅ4߁PeB}\z hYq `':JePo'tZ^z*?[O*Cw6U~\v!<y.9I?IҜ %OϤXzյ戹]lΟ]߱-\>LJ]oϦb >ps#{'))14*kI_<.x8H%ҁ+u 4w!ڂ-|^ʮ(Ptr걋&C5Gk*N27FOcyſ7H\pkT/'|>Hyi=}v^GW=e[{O+ӫ']3#[q/a^Cw?O?[`Az7;?=}^UAU&TYC+ a TK=2kN&` o;^/WւrtC T 2)M<kFߥs"c wkg\o?#?zLv#nנW۷Ix+C&'694w@誏#$Ã4+Cw{ΖK>`U‹o|4u@PkrO:q#U׋|&RoCv{_G#kw tp r|~;wIz];ObmXǧ[o+xE(\sdֱ# pR $N6?k# ^Q:Bb|e'OK.^̱>eS,O%ڗZNx O_Lyڈu+u! b\_rNYZM4S:ЉLd/Oy;C3+QFy^륽Wk>lOb`Ga,8;"( >~Mԏu_5ʦ/tXA`D24#M>nА]/z2xg׏kQ`Kx'с-m& %gjyx5v>ya2/6iJ59ȩ\CQBS'Y)PTNqߵkE#c26@.}>z$3>a7s@rI{$FgPuo@s-9 yihPR!k[(v]c]m!~зBx!N|Zmro x6l+ߺHZ.鋋>M+i8*Tk@IDATO_ ?m8?s6;'%?tѭl56n>5PYsv_oy֏kǑ;}~5 4X(v| Ne7Х`@ ]=4BNwX$]7A!nxo}; 0t4rs'B!m 9's<8Y sz<>P9?-M=ߦN;zKœOE\{3\K;Wߚ5냸aj[]:3BsT^Q^o_DOVGқg+#x~ b:_Sa{0^);/ ,fj: %nA9h8d RcԊoAER퓯,u~mBx5P+ӻ:O_O*F.-svhR{=y'_PNP@v?TjQȫ{ǝ;Go3tKuNZ֯g\X{Ǎ}Zv?]߱k͡k ]Ե~/#h9/$ݍf/c1h(\c!Ztȷ;-:y+jhKSyZ?^Bz/>C@𓶔/i?m ѦA|ť5ʑh~8v 0}&Sڽ~E6Iǯ~5;F.{ bjw%\_vOؐ1;apxE\_m :n$4+I;'HT)o@ vXL>/T<.$—P}tAz_'\։6m:tuS(. 3rà ,,4u!s)2)-_(${S iCzѓ^:iW~ܲ56kXo؟#ؘ矬wݽ?{[ % .yv5 eRW~/.(ApxH moHM7xpi@4s`e8iv?BIՃG߹Ž )//5/GҢǿuI!;ivy:V]5=S ^~Nu^~ڣu{1alpV\n{mæ1>jk~ffwpW >/tj:S~9ӣLuﱲE7/F,df(윋q]C_;frikqL T0zTG = [tgԈ{(oG|p IKnuz__1v_][f#kww~^oȷ,'oui Q3NL 8N)&& + xڢww!h0 @gvJ/S^[!h\"u:̢;/h78Ź(K;>GkI{:+k6wiO#r=reɻ:ÿA[y7А\{7;wWeskV\FLmwS_gߏXyGt(o,y _C=fk&hkU]s͋ҥ| NSNdyߟXu@BA(`λzqkS=uF)OOgKde%'&pvXA3שG V6 W)\yۗ{翡 #icS>l{kma8yա] -,ր)rW#~_|pX/s+= }ͷ>UQ| qr.*m?X]׀>}#/Mm_uU1Z~xQG8`vdçE!n{ŕy[9+6ԟ )/@d7Oy߽+N1uC8Xqplu鰶 Ώ=1cCCg0\ø(Pu>>}?y{`ԆdxΪ68h冶uH)e~ѽw|>S޵ (WW1I OOIơOy.jhdICb;9H&E睏z76mGjƘchQ;WWovt4^k>V}f}!q}+}?r6/f 3n9ĝBPE47YZ>b'OHQw߾ /:'q|.oٵES1D3(-@')C y>|w)XB{4&?^G_/OZ:7xTnymGS*i?NBZPsS -i8Pg؝>|O?a{q?:dު] kw^?>LJeS'΍9o|X[?-Gb8S( Z J1>A'/eDԨ*y7`ku=)GYoʗp;" ynxhO/yy~X~8M_^'DZϵ ~n} #4F6y[ˊGgL iIc"\[[/h9KW߱`~(}`qqlmѓ:gw9nt Yw;1xG902q /Y_4&;^G"׌8(պZw⋇kGp@"'<+M.7\V?40si닟~P \{:]KfgV.ux_r퇴_m_rUjo^I3߯^>/}>SZZ#hFmrcҦLEhTޣ-hN}ѠgM1\|-vԩ|su> `k?},|hW ~NۇO{:?3gk7;01cW2kɮF?6k.jXҙk?Xo"o6wu&?^ K_|S;.u'~[bx윻ίKXx (|d.>W|@/ѹy؄z:j8h7ts(ϵ,]|4ơ@GFr[woKy^I3aS칎 ")˚3LD`nsk݋|^mʲM2]?D"ӔБK~O2g{;m;!^6.Ft'{h}h8_EڹC8>5\^osTnڄfGFW?GO ]Gc߱Qk 6klOKcߌI>+!sz3#&>{yЍhv hܰ{gxo_c= 3˧in' ͼL< S^N9Jc@UIeCiI==B3|a'SʪހRCʇv#u8^e|bmfp | &yz/A9& 7.vW&4Un<Ϩ<G^?v?;VQW4nzLlʮ).ctcG英_Ď[~_#^_6znBx ge`geA8!9$ @t) ,ޜFkA [;;v;Wk_wqCBiz^>C7 _):%妟}~ʜ1]m%^o`&nrac3?O? X%@PcҁB= sK o%x]eM@3In(J\]ǃpEch'FQ9JoAd/SC^(ye*4<+Q-}Ζ)q? U>Ugۢzf]Pޫz;[{*3;0w?(:;WWv;k'''ؘrG🧟՟~MS1@t4&*D^*bO#zI2+/LR}xOܣ<4Ina &[jP-LˇиV89^'exC?D9'c7/* PzwSF{&\ʖN'b?{T'P$4ZX)K`H <kւPs&Q#??Z @*"A̸6qX-`=׀Z ~w 04Θ\”aF! M,^C.8A.ήHR%GWVjKotNZ;N?A O$ ^bv> O^}I*l#./{mP!/=𒧻G Ջ LGW q&v74G_Jslscb{Fq2_xo,w㑯|l }?otIΣx/ p$>x(@8ϿQc^ ui1MkND(XA47~.\k2d衏@իWKed}sȀ2#/?7 u+/o^*oO&P{;v_+bkU[hlYbeίtњӱ@̍_yDiD3 16wRM.x@#u1yZu{N?T2@re1w>O9eԛ<hw`Wsj:~d~푻Izu)> UKG tH;M~c*/3Wftʨ/e=8ztO=.>o/MRVHB}v=:񑏗xWȩmh^ ;Hf?]w_=Vnydsc_>?~]FhӁXrW)U\]L |xO:,*D 9ޝG9etm!Eϻ h =&On[=|qT&JN7ˊt 0]U<]ur>\i'#@WK?$`;AiWƻdN_I:}hw:vukik#7wO'C;~B{BПO_)c(`&OY{@??Lz4:,RJڻC)JkԹvc5P')u_%nG51`"=be_6-x3CH:r;^Z ;^zGe"/H۽՗KH++hkP|&H::R[x˞`w`5;g[:`_By}zȀDA©1^cgb! 1geъ CyofגRy U0o_,#]PFOVX@9O6wZ?~zީ *׀ʣ-sj#; Ӽ _eA[x Ь2IW}o4g_輇k/N3Nf;Y(Ϯkp{y_$>z`s݀-+"~lI7` c^'xu€1b:N AQ?4ew([gŕy>pC+G{POZ?_/is]g,-:||r~N#/0>G#Nl9r{x֔]wgݬRXi[x~]LvJup9d*H*Y-QCp} kh7@ \n$yK9q)[Peu /ZK(MŔ'q6\]<"BKn-2Jfj V|i#. xcv~ ҄?jcaYlwAN%Ywf-x?}z }!7?I ыt<|wĴלs7G"5}{^J.0 )S0˃Hg-˘ :95'S׀HPd-}^FkۧFN<i0BQL?}^ڑ5~*tT(Du5|~Q]XBΧ w#{j|'GtP]tsit],lc[W_SaOZow釿לSϦQ0D wG.`Qt2|Ib/RwG(Ozo ]hKϡ=3 axQ#(@vR8W&|[6ꟴ;Ms@q +\4|Wo߽}\n3q_ʏ~8N{?;gtf\?:hq`ٽlMqs휮#k}'vX]_k`g\Oߛ 5 RՄit4,>l7z@h}3{WXxpy(V)ӥK^r+>ژER]Oѣd Rxyќr"LkG(LuӣLܥ /Љ,&O Cpw_~7͵_ZoF;Ğ=b,5[ˮucl==u _ uD2YȊk 2q9zPVVͯ`mȃSGe~5;\;H$;"9r( Y}lOY@PgS՞pip-VʋouQ֥B/4/Cpz5WWIQ߇G/52O{/O΍cx|ZxX]3{3@d\7?߿^Ψp 50>y_yC[D3@(XpfCXIy!w2b.p]kx1ulԷrQ@q}1:__C'_6u y8dBs2)u"5ˀ8zςE<^; b_(M% 8#wޙ5TP mk`vmʿt xX]#L{ɉCy:$׺/Zэ&ȏlUEayu~t{'W[gݱVM5ǏG0q_w?~^c:yY^[ۚP[̅Ҹ6wXtHe ILzi9p(')ؔD,n/^Pb(+==59(ﳚk W_}r;bo&'/M#9m-߶7}}.1quXwrM#\iQV,N{_Wai#/hI>G DWH[Vzi9g;Ha }cM7}b|]U]t _X?O??}mb` 9 J~Uδ `y'QX: 3kK  w[T{/+X<=J 03Km S?عEyH vv /+_Yїb_9's}s˷tm>z=+WF<{f/?ճxfmŵ,͑ڗkc[oP=ilğ_?6j@PʒR`L'Y$(S,?I =Nz:X[;uġm\;]hO?mŧ^\\$!wi9$|wdx}Vow| vu\ \OQm{ˉ˓ѯ#&,_^{9T9uMyI=O/87νg!r/vg^'M9=+M(tG琘m?\0 J;|bIVނ!htX_g}_~k?[zg_ZY䬛Zx?z(G4e ɋ'7=}E_w;RK '/mW.0Η Z()#]s; рFcM{"|QZ/z!@Ҥ'ki Y\]=h&$4斜>+_r:SP6Y6u1j|=D/NdžekJFv81f ǂ\bK?Fót5# شX4\Z,*38bTвyyx,6 0;u{]uv p@&,^/\ #4 3}9=`ǓE1JZGWy򡯜y_罴5C;^ K4%Ӿ*ox }[|ZJ쌐g·/G_vg/hg.йw<pk3_?$u#yӜ3H1y9C D؁W_iNh:_@ zwQ=!OZ<%/ۯ,sxWtP&Dgcd!SWE7УL&Q]:4M?Շvd'IcN/Y?UqE: I#uQMFx״ʛC'w;?kWi?lB+j`(1z`Lz*sA. a6P2;dy74P`Oiu/+OG \_MrOѩ'>qy+ڂrxvg^B ]tKF#yW]kWC:e#K]ɯhI{G5G`?:X:bb\ƾd;3c}9?cBO:pb)Q'`Ϥ:RroE~eĈ31<-e rgi*Y +Ґ#y x D y9#Jx0yґy*J[}h&tK~}_eKՅ/` \_UɧNɻ4BC'9.i# uM'j`?iw-L+u5\O#斶q# }v\]땾̋kv֤/7[^9.Mc%7jR'}Fm_~8Yw_k0: XF d `2ם`Ey|;@3Mw;r H}Uɋ]T{婽ePh,8mk&ue/ϦSZSQ'qH4nbk֦-& 2B~ϵ5Ռldp￱?$nѱ_Wa`cN7X|fw6{598׵7|Эm`u1i#Z*-G&ϻ<."!` }~T LA*~^s\vq=ۻ O?/1: N4{o$z7ݣ)?=R_'+gG㚲TOu/&GQ҇Q칞| &1VxmXo;ם':Y|2gl̩1+'w[Xg1?ͣ~)vyߒG(%p:c F&gfށԙs @apiw xL?ycK@&wddVu72O~y`I) 6tdTOQ*W^HۆxUF2vOWtAmcO!}xѢk?OsN~hha5,/mF l ,=N%;wt֒]zmN\-t滯6c?O?ş`rjgKs.0bmDgAB [ѫWNC~[}ꞲŔ+@ț)W|P/" Z۶gr&ɫ<5N#TQ99'y|'Yh=m1T5B_{9|]WpG?sıcYgLحcOo'_b't׍C_GeNMgd LϳQ̳9?}/~:@ (Тa}וƺN)vV# fL"fAOи&W#,u'0 8%5qcV^zL/.1|*߹Ys0qïtSTGPܻgYx7xkCDcgأICSgCE̛As޴?, 1}߱[\?>o|_acOO_S *?䓀- {;CTC(u^\,L9mR8C^FàLWRfH# ´UY+My᭼E?St|r;< iv&H0 5u=ace^@g|*hu 4Sկ{ҾՍ?W[׭a\~ٻw͍12G̕ml.cb\~ MH7GʬnI_Y|Bx ?ׄxx$BPyW xt  b]'I%s|{9ݤCW]zte #a<N(F6Tch=Q#42!x #=;/O; >Wymd{ܟxGN.~ n;ҟQw~=Ƿq,1w{w_OW? fM麱켵mk_}m^ggW' ;Aꋎ7tDL?5tLteFG0 ic5iU24Sxnn9W6BPgwglLYu Z|gw K/%JziaP~ik~1{:lh&_7Һ7bxrTzb{h~1mRchs>1'J9/擯4{?a:f }|x®}Y;cY(ӗom[:'G_7?OO^F< 8PtSM*M88o$\(G^|" 4 O%8e /old2YY慠6i5 J~eQyG{Pdcb̀ZmchaNի~ ] Sπ~hn M߹rse3 ]ӏK)]c_ Y1k_p4Gwgqycy_ b2T.^rSVA_)-i? [Z*8cHȂFCVHهig^G+z1=>h0Lq^&O#d#A:^UHT!L?ʵ՗ (yhw|?mRr8d)F&@ʥkO'E=??c8̱'雎 wVgX|kubƃ` Yzi>~|~7;_k_(>GޱC3c`` Yn΋Af;>e/8e3 bl+dsH3z.?C[ 2>^ =Ot /OS}F]dv,3zA愫hד#']m8{k?شge9$kS]?vH_3k㛬zqA3 CJmdŴp+MY;ڼ*ʑ ȣ>>tyAo:n +0y:xW/_r9.ƂG"i]V rDKP0<ʅ%ǽzߕ4fxMy:Gh1J&m4z'6 jx,νX^何ɫOKu __:yL\y\/:>Ruݷ{x[/|cSG ܃CaWH:pBS>( R&E]O#caP@&A9bJE^dmNL',`Py}g1Zۭ-Z@߾;_l<=?7w*|4-OH"|'͗eI#ZKh\<5ZmF~IƉ1f|4 ;34 W92i]f?k~XokW[oO, ܸ(!>uq~=_{ 8)ˆN+v#y g ^=x<'Wz=/2a7r@+ F١6ѧڐӇνJ;iL5tSQWuKo~:J{7@KavxNp9zőyjˆ|ˉɃ6LHL@7=in\1fw7/V>5eծg7~H kgX kg E1%bKt^P$MO_0⬌"twƫCh,"9*C 2K!&uN$F32ZN~zÛ dדvU. @)y#Z֫+ܡoKoUp}DP,D 7̋IwPnu*(҆Keԍ|[Wp;GQ?;ds1m f̵uGlpsOG68m˧'GN,, Qh+xQz(;Q@h Лyq /MΕ 5u_|dkL 펪L= s{EQ\};`#F.F:yBSoz ӗ+HWgLY#0%s)6r {wϼ0v G/G)=/] \(Ώ]K;kg;5*J-ȸ1/wyNC`#=lb*]F sRF'_,XR?K&l["㤉C7 IvWٍsuG?(rvr/xW{; ah;" gkc][oI? ߲qK;فED 'oQ;:i~agWyUK]u[A#LO9r(Wh嫜smsm"G+<6 ;&\`|2 . hi3RnxUվ8'ds}g%2k5 GjZ2!cφg} y/5pcD睄ϪʴX:=r7}Q'(hf*lz{Vw-Dkq}OzI]Qe מﻼik/ ֩ߴc;6iWob zGn m:*=lYmaw[bl??[HSW\`?O6L*ʀ4UI/^K8, J?D1 O1`' CkO^yDKQm'Y#ٝ 9Fy@@T/n+|'_~sCftէ+WdR~@d 租~p۸C{+o;+YhPNyL0͵B  jӴw܀)FߠQ2J_:ꐗ':J_{cg}/v^Ǟk+6'_w5Ǝ [`tZ?](PH~A敖ǘdʡLBہ%0t^taxKw^M L^A4sx$cXk'mm8S]S9LX`dw713ͳ1bul9oZG?(7mWw<͑]z#zckkw쏵}z3׳C;Wxgo֜[ pvJ\H+{ j>h%"[$\i=ǛQKo&>3?A]5)k@R+T wr$'Ǵ;mRom'  hOj~ w9huF*Ap nI;=}2k;#$^Z+21q_xUAtΥ댎w?6Y.ww~k*$Y8qnB_=N!.SL<ާ_ 0E^unNμ * !Y/,g#s×xB|CMKKS2(𸎇\^[[Qz). Lo`k>xKs4-1Q!땯,-[9Qԙ!{֏K9ǽ;3GgL;W.:kmjεekÁc䀏w,Fv3 mƣ8u-F42uC[ /dSbg'#<-'| %^IgL98 \k+P:u${{ }:}j92b޽ƣ6ġĮ< W|aC7qA4 ҵȓ9M K]ici3;uz]lkk^_GCms=V_ۏ_|芨!G?kF|]L`5tG<'xƶ, ן6xkIeg={,p%]ѿZpsLbk˽ak i2s?vL7/w o\'_ZW2(ϮǞ~X?67?XXsxƹ:7N{d^ F;q\Yq>͉8\|)i&2x:/^D*$?7#B(kTwg'Hovo s*ku»e;|E:p/(/<>: ٱ5+==zC^eltu9crH{>+y(d&zZ rﯞfY $c#??}} 2x+Cl4%,Dxő4?4U`ȢuS.M U|ߏ拏$4uDGWJ)?qO^A{_W~ʕӚo@ g?;?kI3'vv?v#c]kg8ձkC^lֹv޵Dz9@N}9cck'd.F1~jV<|En%_ya5˞~})c>ɛ?h\:ww>qAy{Փ«kVȮG>SZƁ}::U`'k?_/vgt u`=Y0L_aw, 0 꼼@o?CӅ?9=< i[tFqy(~I %Kmz*Ze4πavoe+'OݧU'>zNo^ܯ0Z^zQi-4?L;R=x5Wςue.cc??̅`Xt/{@Niw9ڻ=˹>zvC5ROc9)c֝_h94zBC?ʷR.1]<*sy*k^:HC$Sy[7z݃\Os2#su剕Cߴ/GA297pCiwo?]g} vS3j7[?~3/Yy!_c}>=? Vw<}J6$k>b]ROudwԸǐJ6 x9&tFL:Ҧ+MYWֵ2Bˊ;잦9^ %]!^Bo_Kw{el Pa_{wg]ι ;]:a[yĝSx f l|;9<.T+4hk߾9r]7Y,NF払w@4>5hJ䓵r <zMkkԳ#L}qځF[i7_\/_DFf|+whnML04ʶb ?ڦ:{gxOƨ]Ǿ[/k?jf;c)`WEC?OO_Ը(ުW3094h f݅r=:J)`A+A r:J7ν@ihKW>;s>~eԀFv.7C({6mia7"> V Sn 7\ sͭԤz NK%*tN1;*߇u&_\m#~n(8{Py|kCo_*gOF&(zǠG_kmծ~Kgqb|5b~wة~vc Z:ܛq΢1R該jLLkQ)c3КasB9D" <[gZGZ '&DhPVe"(~VɦmʪlepWʓ?:NNy$<ô^[g@$6=d] q|GMH{;֌82VUMivey"?;;W^oO\_6{Zŵɛ#߮{?}g?y y'kh3MNCɱwAƙ \\TxLPVcny{7E?EwR&M@ mO!]Y6|j=wU5#4s=KO]2#ǡSO mfx/I_pJ[xo>Ӹi:&Vu~:zdQ^zqY'n^F֟ޡsYg3'wOo7Uw?G?kw@); F1@'aiC/($<LM`t1xBi_`¦s< M/Md6=5YeQ _f5Eïekջ \d7A_a#{.Cz&?ۄh\W&ezo,IO;/`^:<$e{x?gt3 ѵd 'G56͐Yo?6kb_Yk/&^o?v7.}~?ym$&#OIp͙A/Ɖ4`0ɷɹM\,'˪e(n婯u{%~_+cԭ|l  U9ӵA,OP'HK'[-wY)ɫA D!;NLU_Ef2x9VUWwrdV4t_ؙ| m@.'{|ߜ? ]JVSk=k-uTO??[O/_Xa^ߺ0vy_knA . BgwqV^'&_9Ru!v%ZO/3>'rR~9ՁY @'4ǣy?Sۯ#CgsG.[-\y>폴;u?lД],{dWk8\7y?a[3O`W`K_z'$\`߷$c\RnrS89y uS`dk](?lF+< 3`zz4: "OP+HDViB s`Y̮lh-uxükԓ54l;mҧD/0u)_7ƎΘ1$nGOPtD]~ǻ>PXؗkN`w?+χ %6(_E&_7_W|kT.O?w`AG̉: WbD_ !Av袜)K . ҳ]*SYObA^Kޛ{\ó2yc}WQcC< Pz=+@v\ hr|t !hG[}^%N.ѧ=ǵ6o?io}^Za^vb由!wW7^Y6YH~4gh]/o[m 71MtΦ0tKW#)s1sn?cи8"QYh)vcMƇakrIFq<֕3{Aw޼=cvà0]4NkTYw%s /MMy7w:p1^6 '5u(gg T>/2o>·eZπS}<}1rvfy}#F:|22L鉝 1/wCZ#CiQRXp5mUoJSݾ~XXWGTk/[Sst0ʜp~w]n?mWiRfOO^&r~%i 4Uhs{1F@+|4 ?S9^,=B*5ԵGWaӼh}(FFB諯O?5^(i =0um&3 S%)ڴli[kq  K_*:'n]f37W3Fv{sD/WZ"菞#gkul3%3u֚[֒A, ]A.šgVyg=9 3s'%M~[FYx&YyrhLc<I|\xxvx&H>@GВ _dvdyqGAeS};<LR5 NӖ20VS7y).=]$q(g\=^?rq׾Zo?k_|G}9AlU1bWG_zx߀;߾;o򫪝I|;S HczycpRjǧu5=׈~msE C91:u;|?<ϿG[Yv_/lܗfx=}LQ>'23+ B97cN7߼ N2V7q+ ^Gypڀ^;; yOyK> mˣEv2֖[]S^l:Nzfl[Fko?x088'L!OxnꓜS2w .#.@-UFX89ک i1 ǹi* CN.KW*Aik%6B[Leݽ]Q ,cSMLkHUNdn\o^i};g=\kчk'16, _ӭ?ecS?فcz<"D|E9v8)hD}t/G( ~u!1 ɿʓώ'H}XXuk?K-N<@&}L$?yw'o9AQ> _G3vN͋y/ ®o>747HE&G˖@ow@Mw[yiGlv;};kWT4j~/`X8w2h `4yP^q bF~iIAZ3ܡէ{0puϻV?]v?\oWks?k=񩌋[]+<7{nv}g(G8} |1x+o Qz+GhtvKY ? =P4w?5@!/ J9dmՎk^~B-9A?oɃOMφt[y<<UE6}qч~%9W_3MII;>]t(ۣoyu ֜][o~d^?qaWߘ,trP};w>RxƄO~M;,R ^[s<[oc~zzDswhg6yŜ9U,҅ƹp=IrCWۦa߀oSUWw%aΧSw.Ir=ރHѥgWoMAܰck.Ps!l9K?(`oqFOVGқg+#x~ b:_Sa{0^);/ ,fj: %nA9h8d RދcԊoAER퓯,u~mBx5P+ӻ:O_O*F.-svhR{=y'_PNP@v?TjQȫ{ǝ;Go3tKuNZ֯g\X{Ǎ}Zv?]߱k͡k ]Ե~'#h9/$ݍf/c1h(\c!Ztȷ;-:y+jhKSyZ?^Bz/>y}@𓶔/i?m ѦA|ť5ʑh~8v 0}&Sڽ~E6Iǯ~5;F.{ bjw%\_vOؐ1;apxE\M :n$4+I;'HT)o@ vXL>/T<.$—P}tAz_'\։6m:tuS(. 3rà ,,4u!s)2)-_(${S iCzѓ^:iW~ܲ56kXo؟#ؘ矬wݽxS % .yv5 eRW~/.(ApxH moHMxpi@4s`e8iv?BIՃG߹Ž )//5/FҢǿuI!;ivy:V]5=S _~Nu^~ڣu{1alpV\n{mæ1>jk~f fGwpW >/tj:S~9ӣLuﱲE7/F,df(윋q]C_;frikqL T0zTG = [tgԈ{(oG|p IKnuz__1v_][f#kww~^oȷ, goti Q3NL 8N)&& + xڢww!hx? @gvJ/S^[!h\"u:̢;/h78Ź(K;ޟGkg}I{:+k6wiO#r=reɻ:ÿA[y7А\{7;wWeskV\FLmwS_gߏXyGt(o,y _C=fk&`kU]s͋ҥ| NSNdyߟXu@BA(`wozqkS=uF)OOgKde%'&pvXA3שG V6 W)\yۗ{翡߫ #icS>l{kma8? yѼK.@nKQtkLV+P?8Sv,}9 ʕ̾\Ps*Ǩzr8hzpKg6Ϯk@aڦ/-Sw?(aO}}XCB?C"ߜJNsτp{^]ڼCcsWz:!_o88GL]˺itX[[XjǞ!!at3.a\ N:S>mĽ jCx`ZB@[gUzt4@UrC:yǔ;Pz)cnR +$uLr$'xyr5xM@2夡vYPO6?SrUF.Uz1Bm;me;|CDJM "G=m}ƋqcM1訝7;W:G[g>uG|_3[7ڜ ^NP l,}'X`i CZU(Z^o߆@Tgvi8@7`"Gt驘b"_}_ Ȇ<;sin zxz=Zã/'-As<*ѣ)}ttʴ'!ms-ӹҩC H4(o3NMǃԇ8o{itucv;[uccwò)ٓBƜ7>F_HO?/q1N`(Yg7Auhҁ2( 4s[e~#t:J2 i嗩qG: p:B4x"bkGFN($>w@Ng/#ui䥾>TV4F/Wp__هnxF~Xɷ,i`L^e#3{y҄x1Pmխ-{{g wX0?v?vh0GƸ8kŶZx^_Z7/;1xG902q /Y_4&;^G"׌8(պZw⋇kGp@"'<+M.7\V?40si닟~P \{:]KfgV.ux_r퇴_m_rUj_N3߯^:/}>SZZc [ xS|J;Xx7f/ggZ%W=t%bigdAτn½;3WwG1PactVe֒]l]Zպ3RDl]L~@-Mw|]fORy/9w_ W2L+ Q2Dɜ],}<"GcQvʃqdOGE@;?ׂt] C%n=蚇Ȁ\)=o۩u90§ 8C{@GC/*N©?5jVr&76;>:6:v_>zR:|{GյZlg@__`{]O/fHѬO_ 韜sA7#n _G@ߓ?HA_>Mˍt>YheQ0rUhPJ*pmJOC;RV?U>k=*k3Xo1ɳ̄sxW> ʹ7M5uֶ2rw'FU!8ٱ:vqEcb[W7WvMvvf b&k5ܲh(pʴ| kSnpR'9Cs2V^zeϿJ'}7e'm"%lt-C)1JN+{\E2 yMC鉶|鏤?૱`lO__A;kg-X|M>j?B?Go$-$ΌkO&ߓ{ 衵wǓ>y&eRuIwN~v[dhuW:_t.ש,ڂP J]A=; dȶK>sT/.0 Wn_)t~hШSWo<)ͱ=:W̍|_㽱ћGC|)o޽}`Bi6'9⽀:wgY <>W^E. pgMk Ӻ"ˌdOh 3ԭz[Nt ^a{,>!@i8ѯt]-[VYoڣeї9bGkN'37[8OXh,F_{0 KD/QoXY_ Sϩ,FwG*'?p`#y|o*s4;umrϦLo54h~ʽNtFo[qg]X_Fbu b3 o ,@# 4T $"6z)5_K\Q@݁it]>RXD"Ih"+O۝Wy2sSF})őգ{ u!&G~i> O@D::>։|ēV@NhG, Xj-A:4}4syluWtkk,ݿ8%㰘?7?ٛ'5G =(@H(bX{t<`QhL ɹ}4QvI_V;`WILn*骛,}suEJ;Z~'N M*7M'vJi{wGw_Ѭsfw_N[p??[}:1[ZXHC13yl|7?Hz4:,RJڻC)JkԹvc5P')u_%nG51`"=be_6-x3CH:r{^Z ;^zGe"˯L۽՗KH++hkP|&H::R[x˞`w`5;g[:`_Byo|zȀDA©1^cgb! 1geъ CyogגRy U0o_,#]PFOVX@9O6wZ?~zީ *׀ʣ-sj#; Ӽ _eA[x Ь2IW}o4g_輇k/N3Nf;Y(Ϯkp{7H}[WE^ꫯtgO@#Lct+۝dK=؃Σ~/0hʫ4PQ#`Ћ+g}dMW,n!ص~Sj_YZu> .ߝF^a}ڏF>Frsj={Ͻ)ϺYo?679Ӭ@?-O/˻siU T`87(-Z;fzy7o(HlMWr1SN_xQv)#N%CEt9g EO>qkc;_͌zvIy8b 1X^>'96e\b1bp#׎#u04 KW~5_:^R/#cbi19"]Is#kda>1ZCM˨NUuȁyW h]qӆ> @ۣ#dQʷ*Hc+;3_v_?k3 c@k|_Snz#r'BG!(&~䋎_|EˀN/ȚBh?CvO O(.,!S}{ϻȌa5>y:D΋.C_:jǮ?l6Fk+kϿ'`w?7SϦQ0D wG.`Qt2_NE\Ym mt9q_! ϡ~=pdn7T꽀~9$<^V~ˆVpwz7waߔKw -Ts&KG@i{gی;G???)|Vw}5;5v_cd.kK|t-1_ `UwFU@Qj0 6\G:F1w[/y&z >.J:ewwKnЧ}WHI02zT쿾$@ //S;Pd־Ip~eѾnzi}4y:E䩿ah B׏vC+-h󟾠GףfwuٵҢw_oG[xXn:Xoa٠‚H&YQA#:8.=Gcp\ j얲Xyrꨌbׯf'^kvd'V_:G>%`#)K_Ry?m#w^y㭮X=@ӺTYbNJ:)(վF){ɹb,/=7O W뿵C[oBvofP\_?,GKN'/B4#oh(S` ,tQ~+)6n\FaޕSI*[gy.>y7y5^<_cN o\?*|Vq1' =7O|#3Vv_Чw/f7^_V= (n1]3C?<7"P=vl\h]@&ND`&tpcwGYqwA4 E_ |qg; Wr ,Ӯ-QNsUϼvDi/9pw8o[ZX6\ >ۀ#$V"޼ӲH>.`Xto;֪ȵ]?k?[]ZۏkoLTG:Ϛ_|<6s[j0^?h^⮑.,\\2I/4Q:[ԁh6%vsыJeF9}Vsm?0UaVQ%id#'6Obυ69<q׶N.<>uvI{6> i/+<*6LCr=-~2á(?y iJ/4?PI71A)YO]+[\?a oLL6GpQPɯәv1B?濫p:K8wfzy~ms$n>2~j!||eve˝G Sf`)M1u;"pAN|Ҏ\ sKW0K>V Kϲ j -uZ+/gqU7uMU}Piiy9_Lv]qWeyB!ST9^rbizȩ h*G2UN]S#sd> IyyhN::dkOy5j#9$gwgykutwp9avޭC谾0?o5F9/xcQ4͐V'JSFP O^z}q&;@:<] :}_; 铘 xGJ QN\ꖧ^3O@O$KUGoAhkW ߹=7r؍m)vd?r?}>k?[zg_ZY䬛Zx?z(G4e ɋ'7}E_w;RK '/mW.0Η Z()#]s; рFcM{"|QZ/ z!@Ҥ'ki Y\]=h&$4斜>+_r:SP6Y6u1j|=D/NdžekJFv81f ǂ\bK?FótĿD釿GihXU@9 E~-]ɛG?ih\co:̵:Ɀ/_i@fdÇ uL_C62M@Fy'kw4]VڑQ$9dlwTM&#|p&m̓ȢD7_*oO o;W&ZлVfۯ_}VS !?J (2xV83 ʎ^@ L !XCق=y?bs`N%pc)7 <G.2r6/txj >ٝev{ FW(`w>/ xYyD3_!t_ ŏ,{dt'%a7f[q>ec눵k]{qΌm ?‰E@F=.O$KYN#DPk+Pq)Lf&KC2KK+_/@|Bw(ZHG(mGPo"../EW5|s}v;_c GX?:s͍]w_4kO/dkXohϯX`ǞC}X,dt(v?Q`Pt);^6J +sy49<.=OPCFTTe+ bJ?ޟ%| ^OY"wc+h>Nsr]\G& o// 零OՀ|C[KWk 9z=G(-mxGr츺+}k=쳵gcI_W?oٽ/r\>(",*KjR'}Fm_~8Y_?7`Hw#u; &d;) (vf`M]hǛ7+w/>}\󫠓RûVS{ˠ99АY0q6M^MO?J@IDAThxw-vM[LLe'ɟkk",xzcyIcG?ÚZob\o4}'_}Wct&S<hҕXH~GS~z\2/NVSOb5e*89P|uR_L%:t+s=tweM| +ch&ۂ]k?#ve˳;O̕u(XGu2eؘSc1VN#>6oo@;CcKG'R%PJ~3t|LGy3#73X:L)%?ǖ/" :4 Mz;ɬ ~iЫo=dj72ȿ !SlȨU 2\)yU$,}g ?52 d_O`k?xk꣮?l"x[Q#'y1q`HNT LU)Q:ۥ g}@I@Iʒv_x܅X8s?m7 Mu !/YE C3ǮNkjC^l){Yy2;y Vڐdכ@^ b}WBSkZ C{WdaGV_S'oyccp4>cCkѫ,Xk IZ/#jӧ =~uN!iPgAVanwq<栉2G S#tbob }#s4d#-dˋM3 EN瀩*c6zVvZs$~QY~d?M;EidlTN?c9wT~ 2S0.\Gޜ?̐L / +%ЬRvx| *D޶]>}h~710M^!p&M 9K;Bi\Џz6ZN#/rM;={w#͌wZI?y4n?/sj:e?#lY`"w"d͹V7zn`F 뻮4ֵwJ9Q0`ɿ4 z/Մ59ľhǗa8iY!/ ߯GPzcb|yvU1M+~:r=b޿;ƋX}';O҇>:e%.繾B]Y.|]ל OGig}Z4kƮp?}2O̕9vgg=L6YS[??0x~)!@)/l?g1f zz6`2x#4e@;./[ G oV n/|!qt|J~,{vSEۀj vGZϹ]_,Oʪb  \Bʵ0NĻzg ]ߜ<{{cHMWad um]wgt\铵-ty㳭Ӝx/d@Pq- {7CTC(u^\,L9mR8C^FàLWRfH# ´UY+My᭼E?St|r;< iv&H0 5u=ace^@g|*hu 4Sկ{ҾՍ?W[׭a\~ٻw͍12G̕ml.cb\~ MH7GʬnI_Y|Bx ?7xx$BPyW xt  b]'I%s|{9ݤCW]zte #a<N(F6Tobh=Q#42!x #;;/O; >Wymd{ܟxGN.~ n;ҟQw~=Ƿq,1w{w_OW? fM麱켵mk_}m^ggW' ;Aꋎ7tDL?5tLteFo0 ic5iU24Sxnn9W6BPgwglLYu Z|gw K/%JziaP,] 5=ZSHS64iA1Z~ p*I=}NKs?6u[)19}x_%ӜwW{xƊ?>LD='9.h4q@c 9n)kGW졽]WO9Pw˒KAr{UxQ^&Rf?~_oWrcG[qcPϟm.=iX4=?yg3>> 1 s;3uLCcuto@Yz1K]U2Afj;Bv{漊 ir>eey Wm <ȉ&44\ZHBw/Jz*Mhw+ ëi_YyZW}?h?iWWf/n>U߮k8~!w֋3NSB#>z(cG oH*_]]w'EYI7H1a38gun#~);e4ʋˏyr GyfO~5Av_Ec\e~5:}O//?g%IDv.':mo{.];FgGLܳoݳo&[ sm(Xzݱ@\5sA`7gT'mu3.w;vuc_x%zVq\'h`@GA"GA)W`O&k{p^`L=W=ҿB_XЫo*SumޝHu}mվ3Q@KmvmwE{s]ןS+}bdͭ?çmDS)/bW;"iW/Ƚ{w]GA'RW"5g+yuu[أ?W_qQ?~*;>_{ y7R< sM/G YL5|I li]QZ3)^sիo5|GmLJlQQP^]SfAAJ#ԁN^( q&*_#ԫc*xt߱%cstz` "x9҃)㰎: y14P 4iu㛎'Lpǣ/^W9G\+Knhgu?h>T8 rpqo'w%6^GcҡI& {w^OtCugGG[5OX-@1P0@;? _*; tt(v?iTHTY&)Q٦\Zmvh wN(avtMK^0JW_?l+l@I&28bymN&V>>.;7|}1#( rmsA[ SKYRu>gx?qWotkMbCMJnma b(DӌUk%l%5 -4_N'|h/)sh}e&'Ƙp3v0FG$8_?vL3viPak_m?8& `prBL=r+z|)S #Ɩwo;ۍ17X(x #r \iȼ%۷>V $G=gSGGjCN:+晴3!M}G_-}o.N'+>]xqkL^.qƎq&A%a5vG?xWV_kCtǮ?zrc_oZ?dV?7Ov}7"i &F$ʼn44j&t C\k)_ЌL}owLLd 2#[cMPowTey-( T ȄO!4r1/d|ӣ7PD\GڭT?/oe"B)==m UN>Nysh~慹9z =BgUOyRӼGw~]q_?voTqPjYM|7-u@ƍ9T|y7S"΋c:tAG r9l,h?/'4|oqbW(+\YAdꫯ|Ruk;`wzХ}ad\\/FV՗_e4oHo(!S 'X| s:5VkxGv{2]+MlصA/<å7^2)X7p;0Xd U6  .@=$#\(`ЀG?{Y2:-gQ]E5T_2IWg'Miox L굻n?'O~~/rvr/xW{; ah;" gkc][oI? ߲qK7فED 'oQ;:i~aWyUK]u[A#LO9r(Wh嫜smsm"G+<6տWe6}R,w;9OpI@#?N*wF^&^i>^)vCer.y[ 8'{w;W;;,ِ_|qf8Rn> 6?닾MOw<L4ZqI Lˊ+ #w w|r֝?xnK_ׯleq~B!:xWu)[p9 MA _}l@ >GiM=SmFx.zvcƽgV?׿)#]w_o_iA>q5h}?ˤ{ HcPܙ4弄s>qxB(A\-@v/pP8ʸоz* 4 $\m;zny$m@_9f6^xxWv[;!rk<ҧ7|h }>X"Z  9?쳀[ƍ7^^y{YVW[Aظ]r{;_Ϻ`[[/&ű'FWUm_}G뤙IL&Vh:ځ>Zʴ,4w>>84hb_;L^<:tH44@AP (+ Ҵ-_$#+yTfum{C9117 1'WOZ)sƦ }F(/kC^+]\~?>gz{J?kǯHZywo0v\x޲$6' 2B'E z4<ƌ$SOf,cΎ8 #<_JoZ t`" IC=Wƣ' JJ~{5OAfSK4 > ͼԭF޼|=ԩݹvUXxG{pw?2Of+$=g:+t`p|ÌXѮkw>bfۮD=?5UCI>2 sc$`BQ'FUo? 4Ƈ#p{q~!goF4i]@Mzyzڄ100[>\|5%-,rֻ RQ*_;д,>imGh#Ǒ%u͵<闶ug#[Iل?qk͘cy?gEɸn[Al~GG[cw_oc?k՛yTŻ;g愌BlG(UGx\cPWiF;(&J92^R&f}ͷ<|/_| E:ƯI4XXhF#1>9ݹ~nzh;Q}e`G_|ZV{KG#߮3V$ [@w[M铩\'YW]镹}sz{Ϩ2w7s.]gt_9rq|XoW'[x¹p?p??28:=Mv q e >:\)84sswtJg]PQ7r~a9}. ҈|o0^_ʐAuY?E0Gwڣ+*Vp :V0f~,40bɤМ<>b=3dI3=_#O*;e+ћu+?r/\LI攟tmC*2rMf ~6v&qgk߮;2k{Vowkg?q~쭵O+yj֟@=;8ӏ7Ǹ0)AB8f!/@SBW ACS^,Z<~}0^W(hH2.9Q?e_KD'TdxeKPBR&'*?Pg|[&u\p;vuy`lje<0pv~%pr3&kUX&5ok{{[/ O?}? ]Ar=/Xk"mP()_PRZ7sZye ( X^^<>L @ _ n*ʧe͏S:WSQQ'\胀NSA|H_L,$ ;_y\7 dI033@>ӱ;3x2`w?[n[kW72vƁ]f_X;fk]KĮ_dԗ3v:>;}BҜwlԎ㧶j÷]ƓףDG{|ЬoҥG?u2 ob7 ΉEe†8Iw0pB:z-/Zu}: #o߾ tyCI vU65zO;k}egTi生N=\W1{Pgaט2&c~\?zswtWW=-fu<խEkgѧS6 }sh⋮}o?ϽqFG hPVC#ʔ!Y@y-}ˋO_ .84]x#=Syzs0;&Hg7Y쎒nYҼ۶ͭrZ]6HSo fVz}\_nys奧XVB#{o-Ճw],(YWv?XZo?6#\X G7~'?{i@vwZ;0hJjX\j0dQ(H?FXC2v8nVCO#,9| =ώ+x!=իo4t@2@uy˩=;'ӎ<9WWXna<M{:q q; w}4@LQ-㛷o ZHL9۟v>: z?Z:{O;ƨƝǾ[/k?jb;c)`WEC?O?Ը()oU4Bs  MfJQiyM{7m8+Oٟh|5Ug-^/)9g|޺4_7"6 V o27\ sBg8(Lyshٔ0|GAs3/o>|+&L v8[Niz#tCjiFK% tMgX2yHK^/|?j(q"7"W3-m Ԫ-?uH#}+}?:f;k;v>O_:scߜ7/4Ȅؠt^N$${ƠgC۬wW?ɛL3)E*K/ĻVH<:?Vx,@@_+RQs-ez C89rNbh (2o~mdyn6:U@)h%[Y\hUd⏎%z5q^,oy*Oe8-y G4WBy}&ƹ@#&$>}k̽+4}{uHÎw?[ח{M_o~g?{u{h3 CɱwAƙ \TxLWkn ߙd0t=7^Fm=#t҅}]︎o\ɚᮛWusYhȌɝvڪ;Σ[;}sыӏf,D `II( 9S51 ->GW95!CKk@nsOA~7@8W}?@ͿH~54|z_KLC&+vd#q}H٤g0$Ol%&SȣMw}yO_o|{?3H0]I氝w~?\}CIt:jYXC rkŜ[ݱ K_ `@OcpPϑ$jx̠WDDЙ[Zp&|Zeռ xzE7ҔײZ=or~_˟cҔ-_l  U9ӽ4A:9%nKC|A2Mû34Ua'2m*(póU{GW?DntynCC?:ctÎ3lÍ-#m?Sglc̩ۮ|/ b'ottGjp|)iv(0^]w0Ѝ'OK (I;9֜,sWjdNh'p@!ZE&Uv*"3j+rWym*;8PdW8t_X| UeIP}Kw$mdVkI'pme~bCG OPW%8T~g|Z?&[F~/>='|عw֜Y@'4&ǫ묌 ۟ȩWš19#O'[M@.< >϶GꝲN6hJrD}iimwgϛ[tw^OX_+<>$aii i~=W WC0Val%&5WTr(w??OYVM"ldW<1)ghK㺯{m&"F ET U2\ X&*Z@ ~/5*0SWpP{FGMSV\5>hAr?{_Ow?z#2he>Bac_G8ݹW? .|ؠ|暜[Rz]wu1 0&\z*iR8tCLY_J}eUrW"Nyp5]?}:<+&ؽ8&@YիWXl@+D&Ϥc E;>c(qr>W9աm{7ii-9s~wLŽg{~ϫW7o&\G5w_șupƉcu^?jb|4- 1:i  2|0 \]iI4|#~6AC;}.O :|ub( H\Lo&i~y|}p8 c5_| 往ynLg0J@#xq@+ZPzsմV5 =Ҹ>weL\YO/;w V?P4"-q4;I7#W[os06S>(Ǽ2ͶF~"6O.O?Mx?fgt@u'ir*tNSbAPYi)`? R.C;M8Yh, O>m^F3T_1O_w h5eY6 ?eDHO:ܔ@) =-=gBxנȐǿ~@gTT,]6y7n_??ZMYs#[Fؗ k?s˿}a|߹t0p~w_n?mWv$/~g?{c5"1&?WY9o#cŁV|t)h"q@IDAT, z98O'2s`4|.I}(3Ϝ?EVZ'( iCZx8oTWGlʣ)D:7|rVU ؒ. z )g68VWZLk=DjG]mꖁ: a&óz*>};w w]A77VDl'Fa|Kjsl{u 蚵3/O{8>_ҙI~2a:~}R12%YЅ"jT B̓/Hk$J1BN^qC-˒O<3/2iʼ@(+_t)X΀'d1}:8+^ϊ,{5PT6wc$a@fwƌ8t6ƹn=KOx7J?o;;3Vv_׮\~[ϤvQ_ufp^6ߪD1Y'obg&Z$H+4:G`(R?>FzVYѹUH8R. p>]"EJ?Qϲu}+@ȋ&  ^ M `mq},Wj|O,͵)Si? e~W|>t^Wg߬o߆_l*k2qW| m[4e ǵ}ʙ*>UrOY9vu@[oڨlݵ7}3wַubDgMk_xF5L>V1lsژ:Z^>]:*tOGKe6{%O(ñF S˲*j<J-O~M֧)Çdm&xySrfs&oƜ|~mz[Y:2+S|ϏN(&>]-]OD\> Cx^<lSE mƹwTٍr t^˗o?J?:Z[TO7s/v_ψXo!_qAyln޼vGlBy5VA0_aK |OKƏoRɖ^sp X5gb'?K 4o?#ϕ?zi]/^ߛRYyeshLZyWU^+fUkڨ\ zX }<%P[7Ȥ8OHY4.ښ}O}hwcwX>q__?1^XH3'C:܃>^oNVLf'6&94w@*#DÃ4+CW{ϒK>`U§aqS9L AuFޫeS,O%RNx &O[Lu*}+}!tb호_rN^ZMx.4]w=Dfė#AzJ;W}|ٞlņ^?cC_pw|)D|Q|P.:kM[^[X:NРD2 8gF|}ݠ!8;:Z_Ϊ8G/.}7.@?vlq1P5X캠PR&ݯfW9o~V3Mq'9kh9}+{$Y=ʀJqݩ|_X*%Ci ;e *:h72hw!;geo/w_O'jKj? 3\CQn."=oޚh^~ќ`3(ϊ_u0~Pyd KKʢ.+Ӄ`="fpVY(~&2O|PSX/zHG_>uݣ?Fհlgܳk ~`Ww'b[omJWڼ7_!dx2:5āuл* ]v ٟiVuIG+N)&|a L#?\gStK &;Ae0zw<Û0׀+xXUD/"_X/xk!I<*M~Y N;+T{.AމlMiU1+>};xkL~uT{8V_tb߱[#Y>L$y7l( #B;m_żpa7j8HE}&G@oW@MW[ٴܫyݼ Nj:Z0ߋ>X5:adk9 1M=Dj;Wn!4^ZF.dķ@:>BL%&*O(i<<>}> \grg6Am>kWjmgw?>~߹sE񟧟 ݷfЧ|6z%3}0u}Yp9[yM[(8{%Fg Puo@s- \s ihP![(6Uc]uQ!~з Bx!N|Zer_x6l߲H/i>+i8T!|˫uSo)ʪ>+b;y)蔝[vO}&Ϡ2<|4;:gw~pnV챵ffN%k- @ѓՑ&* _BXgT%{@o"=>LCRCPĔ-ȇ`VMl&D\J{1 x`R5 ?/>9"^C׺ɄP7,uʹ_iBq R]L'?Wu/=㞵}1v?]߱kk Ե~/+h9/$]fk4g dq-}hB MN<TW^Vh@/a?KI3nt:3O6.-t_WFé څ*DLqsM V'l*t܎3F/W슝Ͷ߱;rg;|Y=cC^4a*y7V8,@k芯@' ^PJ'-X` 2ghgP _r(CVHeC[j}0r)gs=Z&jLrn╉NTʻ$+U2(R\ kpV)op$ejhʠ|y+Oexb4 {>};wGO^zzĭ_q̭gcb`cw?d3/G)yehV4HNh/H\U e!&.} lB)BܯV%Kq&"usP~@' %U v=PH~~q~12=-K| ىS{#հr~W>s=Iy6Gui}B?dѝw0 ۆMYo#/5/C&寂N+}6tvS5)ӳk G$PVyaߴOhXb›s, zH'~lZɥ.{ 1^+Pho PGb0| nyНS#ţ{W-TF=.y>mϿ}Gw_o?',8|D쳔HGPߛWYY[kS~L9끗kͫ+& y4B[nydo!U{}owV?c?s7-ؽp[اϾQi___(]'_Cfk&`i];kFap>hk )g} ,:  0wi!:-S9YuFOOf9J!2ϙlYa5ܧKi+^:GC$5[^>'sv(_׭_:ގ#O?b'Џ짵Mk_|?kY`7釳ՠ -Lր)3Z F8B?Z/_]`U)m}0'QN!!lt{[_-\BNsτt/@dunz>W]g;Jnjia`=b_MsܺP;? _O?;ow?E3&UP+s : ؠږ!S:{o@#|&{H2,@&<-c ?eK"<ɦ k啧 u' ۝̂z _ў"O2v;/:L{i+s W)5m:L|3w>街жoķm}_}nC;zcc;kc1oro'Q.|6oM *UU9+v,@a믊EKoË F8I_KgVm#FL1/ E6"y(! Z{Vr?<~}mh+&%(cmG:z5{PG'Oq"R72];(2qyNÁ>Ѥ{=Hyx O?!;VWFg7VoLlw_o?U?6q;>,=)tlE|㟮m4mfw ֌:POzTF\-#-@tPGy0oC;e;YETzn_@M/ 3>gd?,Mp85Ƞ ]+D5r&GA%9)s;4qV^2ܗFZʻCe/OJ }gn5t+3 6Yrs͇.y?>glwh?k8\4GE$_f_{[o:G7kL ~,h(5T`TQUҔko,%0M~"ҽǩ+2//g< yފ|'䵺>@WM\; UZuBZ=m'/ >޽?cԫ㝗Uxy<,Tϟx>㺷EFZLnq܏3k$"4?\}R_)ǎ~Ť[VO_Tr1c.kO/;s˖fBuhs٥1;?`^!^;4RVU@A8non=Bmn(+sVn'~8͗-@_ 8W~IDsoOIKz^g/F K=wA+Ͼ6c [ x)S|J=W~Xx7f/geZ휺%W=t%}RȂN Մwgb´^%;akWycKg l }s|Ct3@_r47u?Igw_ᙫs>.eb)rWhd9X\iE>}1{# UIF+\,VF/ ~y麤0 (42˹k^#:rII|6+,(!h>蝓>}m{<46|QewN)ivOW[:Ѿ;ѓBQ;ڃ6⨮wl`k=ڂͼۓ}z7Ff|JH\_ H>m?BPu4ۑ4X6.>W_ Ӹ<f6)dS|WPURmӝ4xRN rXɔʸ)7؟VN|d]w)W :388 | &yZ/A>& I7,zW&4UnסL_N _l=Ps?&[& Nq\zx=Iy皌Y٨4@IMIsɯ[:lt yR+S@LGZjae{?_h,a#/;wWW~k ;@5_Ϲ{(F?%I`ęqo[{R=&xR9<' $OʙxdQgIFA}Ǝ}3 O';憵gKvn#NXڧ?zR(g'~`h1/pBJ*I#UDq&]>e]9UCYK& / 霸r8FLG<$6m釿ٛw߾ 0bdi4E\G^@HZ|LP>w?[Gc/s}Ok9kdXo1ј8.@ & V`HMD/ؼvJk; yo@ hҚ H_P9=\W66|(7y-,)t&##wJ9m0y7VD 5 xBnyf'[ e&~ie}ac+?c H̎Al~ M 4eOCW3V;Mlc)Xo)pR#}iG,x9{qn*pkʯ@d\#x7Ua 4dt߄c_'d5֭O8Y* WūTye LvmL=\+(WI4UӴC6 7tNnUn/(gq'r ~˴[݄]W8ڹuogrt}OGT'T_RjWCvc?olgp!'"~Ɨ H$żvL0d :\7}n(YdsKJ9/ |c W4+|n%H!pw.@*W|ʝ2 <~ <Ѥ~0"ު/L;^Xjo9_*3xq}'g>,Bgi7 ϞbL֯w3QΟ[o[oG 5e O t3[l<_i `ӕM8S+8Vx1< h)@t0`Lx%?yRl){yMA~ewOy = slti -svԮꗸDi>>wc}Q6_9r}x攝wgݬRXi[O^LVJs=d{Z$X,uJWGԬ"\wwFyD|Ffis3y 4NـҴZL^qB/Z.ש%2eIKL&"$o|*;/{kQ:;-TcO#M}xu]_+K'D)Wd={CY;W;cW7dޙpð7غ'=3G/=i˧pRckWt*i a#s 捑"R{#$+jHzxN9m\^ 򪔲ȧt˯rM:;?5JLMy -#xk:~H{]ICi΀A,K\!~`+]9i)_yi>y.^w?g\&36t~s?[_?>'g_XϫY^#@ 5!"J $,Xdch) >t Δz_D oyxyY9|gkħ9wUEC3ư!\64N'M@Y.Fʂ<׭#.t@2i: >}k;ϪG?5s\V]V;gckvk=͏k 23]={ݳφ`go8/!vX%eCqEGbֱ̻l>6y댜b1mp=׊#e04 KWKҚ._qj8t39"UIs#kda>gQ1?<4)T%'M+y4̪C }ݠy*X~fs5/;WNtgw_o1_5>Vjy|0k6@8F(jڃQpi ߝMɥ/%yA2y f`yL:0C6|BA'&>$s Wk~MkD'{;#F:_|/2K+&ڏCS; KA >>8~?OyEWy1VOCDzƈYo?6ye7}~stB4 3X:`ܝYY>^F9H}<]k&AՖ8N7 C{^guS(Ñ P⪻P)v\+϶GLy}c 'Nӯ+n>{aKw ly>sxk# g }pzOmŎVV`^q;?霝ƚ?;>bk%>:/ `QPh@L৫`Nwz0d@wމGܻ»K@Nǝ.][>ULʺx^$oEIFs~72 Qϫ<=֍Ҟ}ZoFŞݎ=/^5[ucl==u ^ uD2XȊsd-kuq# ƛ_oj)ˈ#ޓOYɅ޵E YՍSW3LVd=y=%5\>:Y+/rM 4-K]^hZnjR_hYm[kd_ڟ\+k;;:a#df:g[oȔ߂ĝQj`}_iC[D3@(XpfCXI~!O2b.p .ߕOW:sɻ`^3pJP~݈Uu=Q~øe*'W?w]?>c?i;Ӈ蘮h]kLਬ7o5g?:by L 1D08gi&hs wVq0+} *t/"z}_l@Ӎ}͏#Swxft9"-#evICW''׹BpI&姍!T<u*_eӛ|#>}Wv_Чwn{йi>wMJ.1::@:ytkepV:]Х]M|W=hg"|Xhί㟎`Xto;9w{;_?L{O{__t9wxcm&so]%M0TRDYe"_ZqU+tʷ+6 lKpCw?rƞ _`,+ʭ؇IKzFN`[nMjurL9y*ukO.<?e{6> ߩ/+4*:LEr?5~eωVx䟴@tuhŗVk|NVOW?}&gZkOGݰ S`ĸl\T4ULϞT.ZG)fϬW/ϯ-Cz @2{[T/*X3rvG%D_o~y3sc/eil׾]8_>ӏ0I}#ۜ/V/Go8 (xX 4`lRt_!B܄K:>e%|J+e}dmJ~$<O?󟿱r߫ G@(+r4 :P=C$#޵FO8`~b)s`|-/֤^ޯ>,&SYR'/rV*-y P~SdK^? z WCdZ3Þ]!O@97͙^<r*o"ǑLSӔwH<#/u{&"bG?84n:ח^G_oX1n:Gm;:ٝw_f^okg]ooP AiO6F.-Fu?o~5Fѹ.xcQ4W'JG _ׯ^CsɊ{(Х O'xNr#@IDAT|׊,HD=6*Zq70WKҔKVeƀx di h Z|\s/}ҕ'Hw-EVύVcy}w;ϫܫj_zr;Oǖ^ٗ0W79;>80Np_+4\< #Jdc9߁a@/Ow(+R&K  'kˆs/.NǵCYIh@#BpxXS9_Atv/_ is{웩 Y[]>h(&(4摜6+_:ʐ7Y6e/>=D/NisJFVN?g: ǂ\bK?Fót_ #TX4ܚ,*^9bTмi?yL6 0Ǟ:{^׽/:;8 C/\ #4 3 TZM$HFVi|+gx^8y'sh'իݾ={bi|wZ O{;_V+;#Y6h*y2tp>};w :w;Wc0.Xoݰ^~g?{SΌ4 @ g^tt?=v@+0:E-BG hA^Nڼ'+@geU^{eA|Nd J4||:d4̆*Qfe ^%N2-ؓ=.`ɘ́9y5%/ WϞxʎNYdy?hM_T|ó+ˬzP*|ē_0LI$gB^tzɋY>eOzeEK?=ҷ1z:ˎ)s;l2%ہt˵3._`YL?{&^y/y91/n6+-#9sAHP&j@)q'}W/v|ǎty;i[^<> mgG[_ Ώ=`Q0@FXW8Rvl6J +sy49<.{S`b*D ?K:V'"4BC'5Z/q#Y nڦsVk`?qu-%O+e=O#~# }V\]kV֤-7[^9.Mc&% 5?ykO}/h\?/~ jvAxġq0J "?XSV͹oK!Q_|"幗WA/"VS}ʠ99АY0pZ7Mʸ^O=hݜX6u10 H<&}fd#U}&w;_Vs;kk?yrⳝ9s؃'ϩss݋k|_,>5#kd^_+1]%*ۤ {"\W:/@vd?+in#>k{W0PC}W_=~5Fg09с&^~^{1G=Y*$|D`[+[ogξlyuljl2>yY]WY/CG}$=c`>OOtPѿ5f9yxR * -yR N+`dp6=kz hO鹡-zv\vwJ/>~ȏ ԡiPor7v8@ַßC)Y.~#{"%+)Xڡ #>ҞWAJIvVېw_(@Ǝw_. cM|>&+95>~_s.?L< })*9Jg4ς( H4WX. v\O+ =Mv{KVk$"cC?\cՁoV'ͽ=ZG:|,[^roen` Nv"nry7$Y*lBSk\ C=}WdaGVډ]_S'my}cƍp2>cCkѫ,Xk IZ/#jӧ =FȬN!SgBRaouu<9e&W12-/ѐE7*/r4,@9]IJY&m䵏VVZs$~QQ~d?M=EqdlTN?b5wT~eاܲ|his!@2C2*804@fJ_R6Py[wgZޜi*}00il*߁/vZNkv ճqWr}yvՕ{2g8v7V3s[#u3>_~$K܌琬~S(g1l!lO??}fhQu)ʪ6DLA$~LITp@+K|wI~E';cS[Ԟ[ov&{̩IsG?Jm~7AǷ+ʂg5Q V@ /+>|%\["kt(rLV@AO%$_`3ɯL{wvv- 綛g  `|_ =z}C?Asݸέ?, gdc ?ݹ|l4&~˟(Tܿ~:` 6 | ,w.61!F/#a\0x'e|hUEr B|Ȅ0uW=a)/Wh{y@ncg.œ~=+xMY'}Nzy:<_7iFrʺu\w?c1g9욛\ ;Џ9{1Vƈ{>͑?_Ev?/Y:.y$is$i\'ԎOB98ī]i/t 3<Bc%TźOB>sdzIy:AFy8ԕPju(ڭs (MߝUMK+:Sv|nO#?ruŬngiϏk(;^&i>};w+W\o~3tv϶[md6gߙOi֠WEϋWgcڧz_:ڲvośVLEZYF{l\L:dj/Y4`QM&h꬀-C!kA,;EۑWPp%>ÊW@^_LR ͜W~Ӵ.{ݷbx rerL<㴉:uY)13ps]M'_i+ŽtV`2g5:3w]2Q/6ܯyMOԗߎ<~0@ 4I'^ lPiyW݆&:B+xŧ/2@C~$-W\͏GVFVz8*WUdW!V>hU]+;F&K_'wF uݺX=Rʧlp^6xĵCsk9NWp?:u;GOwʵNJ[oxD}&壈T&hkxq}-н4˫ׯ§,`2XhҬؒ^EGnN6)[ݣBIky|8ҷxmVP&S?b0i5Hw|kZ>}ˎg@x;w>͗S n> Y1k_p4Gq^c?bc:'o*.`\׾T5&8NϿSZ&ͽf*8)cHȂFCWHއie^~Gw+ژ4j8/L}r} M=c*$W*ZZ~K`JYy5_OY ЧpI&{(\9v$}~Aw#3c_o2OL!kߙ/c/6.Bf?x!8cqdAssH4ts^t2ж|tӕQh@ݴyX!C\伜);s=5 Cq ?кSw9}ʘt^s0 P5"۵+叜g8m2'\@+^h^?\?haBdbS}wʍch|I֊KW7:?[[O_#ko2y$:ayC%.8x6qab̄c'@#UzA\M݃t̋8Ashr)0טji(.Z!yFnx7K?ؔ} &zOz?s\ HhЅ0xr}1Jy׊6W졽]WO9PvKA|gUx_,$&dJ;W?3UǎZ/kǠ?/\{ܱizl4 ?Gg8w^H1M2* ǀD̨R63 '-S5_ʺL@I 4s3,t+ٷiB?@V퇕(#s %믾zPAN49nM8P-t|-ķw M.m%bx52+OjGpUQ𓞼VFMPW4W_ϲNӆ_~'1(ʥ$_CܣMd_bESVh ߑ{Y-\g7o?:;ýW>>O#ѷ;Vw7g9솵ㄱ;?EǮ4o?olca%=q`F: < O'{6ܛ[,:s s#//o^ySXwO,DC(Hw YZCh'9iwMOً5f Me@'ŮzDS^+?.N"VI$sfҳyu[kэ~\T\?:_{OHt2=et\wt^Er=dybP2 8K\`KU1^y>#ə:?J^oua b)(DSU%lY%5] -W EN/'G>cxjkږ>t}LhD;wk##"\};cd;ʹ a(_X0a q9!QC|ڼ=҇_{ 8)ˆݷgO+V#y g ^pdpsў˓O^A^kXP|#o J=@ykzV>fd}:$k^ ݣJz̄^C7NvUCs=݇}okܥ#NϜSz;~_ל?ݱv_\ol[Y̕7|ծ{#!`btjMT؉Chs¤ڗph+V-勂Q>W Ž%0U:Yj'C^Αyj{n\z yl"7%"EJ=F]_ccx}Mv|9U:Ir!H 1dfzÛ dדvU. @)y#Z֫+ܡwoKoUp}DP,D ꫷͋IwPnu*(҆Keԍ|[Wp;GQ?;ds1m f̵uGlpsOG68m˧7 #y'ruƆ(4 t|hx(@ 4nEyba/`BK~SsehMd"k)oz.ShmF<x`WE&|ᤑNx!Bx70%:8Rn|x+yFL i\rtʣCn3/̽4@g8:zeKן?? cҵsٴy/AwC[dܘCŗɻow3Źx!(8o\PY@txy4`|-FʂF#rB~< 1'vҾ>ΕA:1W ,Q FyWx]ڡy@FpM6zrd._F sW{; ah;" gkc][oI? ߲qKsفED 'oQ;:i~aWyUK]u[A#LO9r(Wh嫜smsm"G+<6(;&\`|2 . hi~0RnxUվ8'ds}g%2k5 GjZ2!cφg} y74 0"Vw> hNb;G޳;IЗsٽtW/_=VNH\O9B?miO{-VȤV@>,Vq㍇<׭W;wxֹ=?k 6.w\잵N?腵n:VIqѕ}U|ן< ʣtṳL&+4dOV2- A+M`}ϩ!"N'φNj257R& PFT=ʸ4mxFwƣxv+YhPNyL0͵B  jӴw܀)FߠQ2J_>ꐗ':J_{cg}/v^Ǟk+6'_ Ǝ [`tZ?](PH~A敖ǘdʡLBہ%0t^taxKw^M L^A4sx$cXk'mm8S]S9LX`dw}013ͳ1bul9oZG?(7mWw<͑]z#zckkw쏵}z3׳C;Wxgo֜; pvN\H+{ j>h%"[$\i=ǛQK.>/2?A]5)k@R+T wr$'Ǵ;mRom'  hOj~ w9huF*Ap nI;=}2k;#$^Z+21q_xUAtΥ댎w?6Y.ww~k*$Y8qn !ïd'ЩqXPӯ"C:7wGtvi`~pË,瑹Kh<!W& x\CFe./h-(st?Q&HG75Gt<%9}mMx(WWb E\L_ yʐ=]G_G3&WOtl5kkՎ2O_o1rG?y #_6Ci?:zJ:؂!ݭ)1k} LɃF}\s/ 3Yd X(: 潀=>>t5V1~y^~~jMxp+S0 YupՁ%ɴ￱]:a= \6x / 6x'kg_{tETEA _|Fd_=5XM&0; K a|RY>( \I}ެ;_s|b2H2k22!m24{4";9-\@\0fWGy{6܃{Z9rorM}7,Y [[Gh]zY{x lBw]ǘX~mWobׂY\t>X>m3:D:55=|ܧ9{Ix?CGutDעG֗![o1zL&W8YoH3tu~W?cPǀd\QcR\#4qSB<\(_=.{M589!w0?랋@5]|nR<*X',΅{BPؚ҆!V6qCݜP9}xL<k2Up=i7a?;ceXv)l9_سzccG^?$6plco^WWw@ > P EgMI: ^qd/MMyhn%x_<#OGhU+rtr.=LszR Pu_/A IʟL'&Cmq1\}]m{1+gLIi]]>H_̘!VagԼqw_o,?CF+NwFW}P`I ʊ6AUzϢ|AK hk-0s^^byy0U6y&41 n+Q6?N:_M9GEF힀Asգ:MsR#}1<|OW잇2W|啟rߴb,%yx{OZgɀnn]kkvul}auw-^S_X? Ks߱Q;fڪ3~vO^AI~nfe00Aފ*oz1-D?1G kqatu[>h?_^/5{1 #o߾ tyCI vU65zO;k}egTk生N\W1{Pgaט2&c~\?zswtWW=-fu<խEkgѧS6 }sh⋮}?ϽqFG hPVC#ʔ!?Y@y-}/za.<WȩXt9mOz3˛,vGIKj,i^rmS9j.7| {+[a=?y>e/Tiʑ_ҵ~+t5R?H\%.W/_QIi25 bC|;Wv_o_o_ K9e.`;^q\1Ԥq@\'OyDbWv2x5OC*x?G VB'u\8Xk];\K/0aӋ:Dӎ6;Y^=SWd2ahmAN1~Mu2naw??Q}_Vɵ_?~$w5?8S8~˟ qPSUf`rh̺ {t$R+Vz<F+Gu6Oo{zЖ|,>v|~eԀFv.7C({6miq7"> V Sn k aclڜk;\?Hȵs??>7\ sͭԤz NK%*tN1;*u&_\m#~n(8{Py|kCo_*gOF&(zǠG_kmծ~Kgqb|5b~wة~vc Z:ܛq۟ɢ1R該jLLkQ)c3КasB9D" <[gZGZ '&Dh͋ (2oymdyn^?tdSO жK~eU''_KhoWp.GW̩:'k⭧kg,0Fzo]xsk3ͭ_:w^xX_/<>$a ~=W WG*-a& ;NN{hC{(>uX!4ZW<[6 k_h #?>->f(oB(>T U:\ X*Z@ ~/5*0"4+d :ێG) L]iJ {3f|ɱn{ux@++;|؝k}?; k!0g WlI͗3E.?/ӗ;91@vAQAz]e*4C,kr{suxV&1zL1jl(gׯ_bҎKtY.8?[#7ThS@Ʌ7G?\ֆM'ݴK?kN26 ƫW7o&ќG9]w_șupc ^?jbzErEb LW4鄁k MʘnNyĮ$_>C~?/AVB;}NO :|mb( iHI\N oiye|}p88 c7_| 庀ynLg0J@#xq@Цz۴I@lz+q C4=2w?ֽ3/(Eu8b]?vd|֑+k?9k?)wdc]n[o?8~ Do~K?<|[VQ 8GLZMfg:"l'nl T~عr=5;2>Ooo) w\FQ54GxjuDu(aGy7/̏;1o@ G|Iv&e['Io"׈WƘ@J_e\??箼c(˧[Ap3ʢqy(ҋ]k8@]xd~&/ES&@ԭ62G|'}Y:FyH_Y?Ch˕7a /Nզ]dDxMR\cM~x]\T)?qj'4{o׸ɸ1;W#}A?36[c(!4.֬w`Y v1/5<2Γ?ɁL)M <)/i{23ǿ C4|/e鐗/N~ֿNjEã6yQzv!u~wzjvU ؒ/ zg^pZ#Cvz~Ǐ29-uNL9{kXCU{wnNo_m].7AO@عQ,kl5kg]1_YI~`:~}R12%YЅ"ilE]A]Wfɗh+#2RrwFV&u\PLL:/ W|G:2l ~Iّ M:|d0I9׀8#L[Ȍ.\XѓNw4mwrƽ?sexǝ_j,ki%ZlV$Ym񟧟}v|ɯv& (N% AeM#I0BHqcD#@U!}. zɗw~rp>]"EJ?Iϲy;uӺ+@ȋ& Lv_):U8.-|'X\#],Ϲ7ԩ e< 63 FM;{Wi= -/ ${X&=\8_zyպ8 Rdz2N}=]^֧^EuP6&轜zO>k|^Y~m, QBem_&J}n!vոN=SWeKn;wW9;%wv `m[6*[wwfm_l{?c{o>zQy 4]F 3[vGO+]RA  pѹ.Ժ슚3ORc=ٿ @I1Eiʴϔ,p ??J",ތ9~6|k;Zĭ,xizG'( =]-]O$~bBJ !s.UdA6x(CI $C@[h=^"xn> NTW/sgE~䩻$$mKs.Ld>I?`mU3?7{w#wϲ9v_/Ƕsv?I~'T=yЎVOpв,ȯ%}tqD|"] $> HTץ,ҼJmh "λ{)$BYʩ.>Uͯ:= =\ q!ҮyRlSE vTٍzt^˗o?J?:Z_TOr/v_όXo#_yA yټ/ y 1>/yz M2_aK -G_R)^s p X51kx1%\8-Os^t+:0iv^~nV>q_8~͘d/F @0 ANWLO l,rhUGMZGIiWr-| ;aiS=L AuFޫ>J=];٧y/z*kuX?>?X1ƯC,BOX#kQ!q@'_AWhr9\+(v_][/e{?;z cMGiAk~Q6}yo7??2H D 鐦 i1?thu~;~\w|~nv]r?li0P5Y&v^P(9W+ƃc~x?Ԕ|ISzeANZrz_Ȟ:ɢlvO2t_w*>ViZeprN1s^hd!܏~脗_,vH`w<Û0+xUD/"_XH/xc!I<&M~Y NCOVujG=/AIl͜XGHNE{5'v??:?/m?~E^_k_G? w@C{GOrבLSrnOM,s}?RE&G˖@ow@Mw[yiGlv;}7kWT4j~/`X8w2h `4yP^q bF~iIAZ3ܡէ{0puϻV?]v?\oWks?k=񩌋[]+<7{nvy#پ SwEǘc7(Kr#4:,ph؄;o/.p9P HC3}Y"%Gyׅ<jv}v:mφt[y<<UE6}qч~%9a篍{wg&q礤G?uѷgYúw?kήk7?2Q[c8Ұpz(ӏ@NQ>ǁTv] Ԙ/C#ttE*@uK~vgw#y_πCO@Shn-7<7{,&8Ϡs8ǃ*E8#Ss|j8lm괳J$Tt%IN={PU{??T] ]>v_{l٥j{?#->Gu[| \Edu$ y <(١c0U漷 #Ꞟb&͡lPbC 0+&SI6 _.K:0F\^/>9"]G׶)P7,m_ίiB2=kv.9_w d7c@%}ή^Ōx=CTWg._ƅzXׯYk5j?EkZٺ5N]?` oRιXG?DYO(yQsm&;XǤ{L@UIKW(@i 1AwvOqGY PٚV{ow؟l`6X|Bw{7}DgOBK 5cff2:_u97ؼ(]:L`-1?L]Dف_d }6NGyQ:Ճ]GhQ?yZDVVyb g4s/y䑯ku  mo;.zP[_|񻟷}Ix;w Ϗg=k@?;6ön[8AXfqPI🧟;tTিhAgLAh+BO>3o~㯼\yi(o<>7rK搫GtvQi*TI}mj 2uû&$>;;$>#>=ԍ.rq+\Λ:9^9L(O1^x%yڥ{gX84v:wŮw]c{Nuv~_8;Ow?Eꔮ3Kܫ۠6$%4 uVAAT%(7CwL)=V EʀLyZT~ L2xMW+wPG$SNZ/lۙei=U~!We$o"J]/-6{/V3g<84AA0/b<| C/}߶Io;W{g7C;zss]w_oX7 [+I|˷x1s_ppG%ڀ*ʦҪ;yv0WEmx1DU>xh8 t|̮-rH)&EEm8IlhH9ڀ_ǯڣ1 5<xy1rk=wPIGLq6ׂ:;(:iOÁ?{,=)tnI|㟮o4}/%:&% !3A[:[F^qf}˷,qd@gQZ}4W25HB8:`anZTPH"__D t(1VħtHyieĹ.w݇*]J# k9vgnZ}n\ܛ 8u]4H@E}>qֱ1Wp0kh]}k~IL9kísӗgo=B{XF!Qj$">|-#FwTS\4IL9rȂPx@ٽOcuC{r}8i*:!zPsVyƤ1Kj]V}K.9Yir9"zp^LL\M uh`}Z4;?uk?j ViYޫEx׽/r>4gJKKz \' ?ƳbL9v+&ݲBY}p][oz8yk_ĵ7 ա9[4~Nre\Ogy tF}vP(Kq3T8Q<twrsxΙjXOs94_}!0xsd_G'u|͵wڨW.uL^4Qyɿh-{-^/3߮:opΧmQwmjvi)_rsOZ^'zFtL&?su?Fw_oZf-ǦXoڥ_k_:sX`[+Mѵ+=/te$B Ϝspu) O@%Oʓ(<:7PC'TW '|r=n.%4뒏f8t(H.qA<~4eGtLm 4|N}WvM,!>]?Z/|QuvN)y=wMW[6￱ѱѓBQ؃>⨮wl`k=ͼۓ}z7Ff|JH윻^ ȸ>}!tc(:7,/Y.>XOG iZnuB3/)SrGPURmPxRO rɔ7x?E4|];G/W Xhw}Ie&KziPν &o2 ݕ 4tOs=3(ƑϿώ}Թ(.lJQ#bcᗍ+CìCYY4@@h1v h]$.EB(7ZpΎ9ҙX899gdW<_La7ʅv:=Ƒst՟&M$/'MҮKζ+ۤZhO<]\PPaʸ}Iiߡ2g77v_5rj[[8XIǿ\EXlXӟWRC,ʀQw(1@!%҅7&$z7Wztp8Ϣ14h(zӜsB L)t/?@tm2G@}VШ\gKՔAfmQ~(oiyUi=?OgGW;yr鎝?;wVk ˵ϓ֊k{}l_M9+W߼}6K X)YJ:DH"@ hʎ@YMЕ Qx)W^>'PQs`ˤ by0Ww5\ ECSdh\WrC2<ɡ"՛({UB=)=iq. \eKmN=Q}u_(ikz_-l %0L$}_csj]B_?kk9_P`(RßQ H{83M\ Vw?qz p~O5ւOGI={A_'9Y4m5rQN=_HFW~ם_:?襅~εXdG6鼴mΓ71Z0NO8@+?~hɋ20kvz= WA]ʣPW}/GMohK￱t+|@_o,ɮaْ]H3>;i?}_ŗoT Q3&0eQHC@)Pc9yu(N+.4k(;TtDi8R8zĎpid=d|6£@ӹן~"Ȯ-K_ԃC`Kn}Ol;3HQBgџ Q:uîۣsXo؞Q?? xg07By/z#@N\t9yչ;P^3J=yuLKs~.>ip 3򕿘+Ȃ|&%kMQ =>(~:"lZ{n@]f%{G&ߠnr KeM| J~#WoZl k-k\ӟ??Zs:_}4QvI_V;`WILn*骛,}suEJ;Z~'N M*7M'vJi{wGw_Ѭsfw_N[p??[}:1[ZXHC13yl|G?Jz4:,RJڻC)JkԹvc5P')u_%nG51`"=be_6-x3CH:r^Z ;^zGe"W_*}oV_.#s|Ru@][FLN z;KJmkȮ-{ۃ-2융36?nDXo?DYB_$^ #g_e<1B#a0 @{9),ĀKE+6 彝]K^pnKi%T<~~TptA~?/[b -<H?ei ꕞz>_*rd(&}GxH,<&]x_I#mҞa~7 {;8!l\?:cg?kkLe g t3[l<_y믿`ӝM8S&f+"p 䧌?0'ow -\`:?)#(@قG폀=C/S5^a>܃bO}I:Kdi3|wy9i?Gqe%Α?~?ǫ?fؐkO?xcpyR\}; u ,@E#pyG"\B< WIRN0fiY{o:Jn1ev dhh __{C_k͏k}`#k?}8ߝy1m_|Ƹ["ePLľ61F9@f7F.J5^! ]Dg],vKW@3sȠF|A*! 460ZS(:275\?'g#uVW'_x6,z]k4VzR QW{L3_kiv:=ɻXo?v,;TXwÿw`=fytl!vb40Ԅ86@H(% 4`M@?K@(')?2>9rgs@"ҡ.Rc_Azx_mJF_exe@Y)Fʂ#呖gʉN o \kgWVŚ5bNW?MˮVϱqgӵYK_oY.Ǟǽ[gC3ӗ+10;Bq@b;7`}Nrmʸ69h5bFG6 gah*zO_+/~YMKC'JY#o BhZF]ppӔ\G<7${Rf@슛6iH'3ͮP}WA#xX]Duv[yomj_l񟧟W3`1 Xɏ3;h݈G{y)$/HL,~ fH߆/cB(<֤dN]"A ymr;w|=G1&_t/B_*+;ڏC吮S;J KAߠ.2cdqXx󢋮1Cc.Zelpko=2?]?_ΩgM("͂baAswfΣo0g(ki:]O?4#seI.x% pО|0Z-ZOZÝ_W9 8|ޅS.m+w=@.rP/[?Yv=W{3z:o3.v8^8]ZvNt~\/ѵ|Yo03.PKMUDj4~Hr ez=gCm |xt+,|<_+NqR%/C]m"'QIZ t)hN@YF&#JwyQPGQSE\DA{M/?w^?^қځc@bn1V_eZK1c]oa`gϮG V|L:",cdEN\D sqs]\(+H{[6bq{ʩ2]\x Q~X}z9|ƂŽ>,N |IM3jOdwyER`MREwd!8+館TZWVzC{'Ɗhxr?-d<_NXoٽAqY[l d[\/qgTp8@}Ҁ/SL G,8Ggېq1cU{W*L'al\qD`{|y08%rxnĪZG :|aܲCsC׾Tu?87-h(;woeW{X^H;<K *{K&1Zsq?cgNǠg~~qt'oW~T\o 橦_l>^~wk{=Sr2L&=C,9$m`*cw!WYR@ @IDAT`"bΧ.Gņv(?25r ~ʴ"Pdב|EaN2.y $҄9eOHм>)?} hS('b<]K{XMC[v\{}:6[(y>wJ/1oLDt{<52\LJi.pM2&;ó`>Xhۀ#$V"޼ӲH>.`Xto;֪ȵ]?k?[]ZۏkoLTG:Ϛ_|<6s[j0^?d^⮑.,\\2I/4Q:[ԁh6%vsыJeF9}Vsmo>0UaVQ%id#'6Obυ69<q׶N.<>uvI{6> i/+<*6LCr=-~2á(?y iJ/4?PI71A)YO]+[\?a goLL6GpQPɯәv1B?濫p:K8wf~u~ms$n>2~j!||Uve˝G Sf`)M1u;"pAN|Ҏ\ sKW0K>V KJz$<K+O!y+#ʿ{ JA3sh};sl]y/3[oOϯ.1??gcCs߫ GY@(;rt :P5C"#ݹFO8`~]@R)Z_o}õ_'}YvAMN>YK_pT[>Y4n\*Ñ1)ʵ*@08: >+.gڍwv<&nZ:gc t@='# >@{Y+ȥny%:cOD_qx}->ѹﺱ| s#X6AogG(ۗ\9klﱥ%Mκ_};79\ekc69'@Ƶ㈆򔣬#ywfXoS\uw]Tbqw\+%1eKqPף|r$`:s;\~iO䜯 ] xW z!@Ҥ'ki Y\]=h&$4斜>+_r:SP6Y6u1j|=D/NdžekJFv81f ǂ\bK?Fót_~jlZ,.-@1*PihY?J<iw:{Y.:;8 CC}wdșT^M"HFK%h#-@LiGvFȳ mv}ӣ/3՗?{43 flc_?z`t _{y/zSbH4 @ gt}Nz"v`|7tZЂ޵yTOHVn<#\,{gF6|(Yq?iM gIO\x9/}S[Q,K5?@N~i2}$#xО kmzU,~dI#=- {1cغ,;wGPW[G]߳_ؗlvflӵ/_ϼ0'[gL UgN,22 tyB@'^rb^ xhܯq&'\,^R,MYe4+0ueu]r$o]Z\r|: gC 8պ@:2OEi#>z ͤw8uɯO})닇ۉ≮7}zCrI^/Y c {_˸;g\=֙knYoz$k[+]E[o~8?o`tf\ D〢KIן`ࡴ h 2/#xx1,wɵ y?2¤*]\IS,SNX|z ]A#?t򝓫:2I`xo^yax_Mߴ}b KVz_ʴR\MI=Bini{;w??Зgյ^]wϼXa?{kgMba|u}A9fQ_&uҧlt-v ?xC@0>ށe0qh@&sIi@VǷ4kj,>@;-_y#@}es-ϯN^HEX^d.O.@Cfi\6.{y6Қ?8Cɯw%ߵص6m11MH<&=fd#U{&w;_VkƮkk?urⳝ5sك'ϩƹ5|Wwnk'(3 H xPn<6|]v K.f wĀRa ϟRlKrDH5L T|g|׏_љLuNptIWc}#auLqMj88YOe^kPUps>֥KuDIFVz'ʚJz'WZ=Lb?~F˖g_w+kPg5?3eʜ1cG}nlb?dŗo@;CcKG'R%PJ~3t|LGy3#73X:L)%?ǖ/" :4 Mz;ɬ ~iЫo=dj72ȿ !SlȨU 2\)yU$,}g ?52 d_O`k?xk꣮?l"x[Q#'y1q񟧟78Rxh5irBw9'ʏG 44066LA'};o:lkɮgkG'_ o?u-🧟o\Ҝ X ;'♼ur{gB}Snh_auq1 K/F~tcmh1h {?ihJlQX( ]weIou^s.8?q맽;w+W1kѬa<1Wkk3kgM]o,8PjKӯ?RBR^~&VQc$leF(Źi4 w85]_臓" \tt_biC-1B4%vǕQY" e'BsYdMNU (9k `6Չw%\A n9x6`ΙǐE#W76ü4Mښ3B'k[pεg[o69[Q@_~Qyy>cwsb΋ )ǶM g~4x2>s*W٢S_ 9 !udA*a)/{}꒎@nc]!-.Dif'u qLxuxSe .Fvus_{w?s1g5Z Џ5{1V戹{>ݑ?_E}_̝Ot]IH-9Ooa;>/D!]#JõrON@a;^kd"d~0q<`誫SLd$ ߛGC Ũֆj޽kGyhȤ~1DH|j<(Z^yՆuqSsU9ï/g'pK1'J9/擯4{?a:f }|x®}OY;cY(ӗom[:'G_?O?/F< 8PtSM*M88$\(G^xILr'yɿҒn}2vU6QȬwUEvmbP%y#=ld(o er 1Sf@K140U?EmlgJZ ?4~kXȰtB' cѩw?zrcW?>V|#?^|%:^Zo@+t-zN S4/E85|)͛7٥5M@gǖ*R< d )5; \6+wO .}ہGO,h_}~kgY e2O??>  7`\|;Wuow_sz)X? v_XXo$k?fk(?3.?tbc?O/Xey |1|z/U )+͠St4柅-ts-Ayz1$dA#!H+@ٴ ɿˣ}4n8/N{r} O*$W*ZK`J]Sy4;6)_9#Oҵ'ÓLr1hғMA;ڳ]}AW,:1Ag4̏F?hDzwq#XʎT10G0,C7  m2̗~@2VT1L[y9E˙R`GROSyD/՞'_kӧK|O>Us.]RyW sBIKU6F]赟L]lڳrs?_cҩt֍V/k tcM_zLNXyg^kKu="tvMG?01@f'@#U~A\3M݃ ̋8A4vcLٵ4eԉϗX!yGnx7(Kp?y)sLh~渠 ġ a%62bZm_~Zv]R?@C-K.ʓMUyFyeXHI O|r￝~;w_V]ϣƻ_lŵA=b_4cӬ7 牟i~$K2:* ǀD̨R:63 ŎѽydmZ.u]W!dfQ9o; y/m*dsk28~ܖhҾIKnE4P-tr-;؄}0Euޏ#Vh8vyueҎ閽 ;w?k[]wKk|>g9=%O>׿mB9_<~ /@TqhE; (J'@ 9G䕯sTK)#Q^\~s^U83~SΨ *r_*xzaW7_9e/yL"Gs< h{3 ރuQڔa7ZE[)%,/uT9;D?W~GPЯp%(u/?JǷ}ɫʗ|ly*:j&^)?ݳwl\c/>iktǧ^?1~`k 8_~>/qG10$( a26+/ykZyo/v}7"i &F$ʼn44j&t C\k)_Ќxt%qxTd:r]k#8x XC>Y>~8쬒f'G\I_9 my7S& Hʕ=jCܚT޽K0'}rb<( yOퟂ7"mҝ{(Eu-֕QG'?놸ώ8~L[o?:;s\?ӑ Nw'[Ƅ: cCxqy:>}a^ypH'Oh}?M@!tsej~S ^<# yq.T9:FΡA}eB3U=KOVVt9[[lY_~wzˠRj⻡m2n̡7ϻ\q^}H}(, :<X0EpՖs| d#_eA#9{K?ׄDi_A ~@7_,:F/c|;.)^9tiv_F{h57#ˑU4re4oHo(!S 'X| s:5VkxGv{2]+MlصA/<å7^/˿[ o(Fw`4ȎA:lZ]x,{HPGQпM2:-gY]E5T_2IWg'Miox L굻n///~ENu/LBv_c&6Bqqpږ#mg//6%fXC T9nj4'ʴǣq!?a]D_opk?;=d[3?wZ_~:;("}1jTyXSg6 5L3@WyUK]u[A#LO9r(Wh嫜smsm"G+<6/";&\`|2 . hi7RnxUվ8'ds}g%2k5 GjZ2!cφg} yo1fFЊNBgM@eZV,XI typ 9Zwv5 ,'[^Ź] Z\?o^eRץto<++õ./4CZ~}K}u7NöM[둧jCۡ~#q~@X]VϏ@w_?6Rl|=?}ӏoM,Jp2 Apg&b'WK:ϣlQ `r=%S Be(Z@׹v^'RmIls{{v'it1Q>.`; 闫\>8C#](-sijx͛[ƍ7^^y{YVW[Aظ]r{;_Ϻ`[[/&ű'FWUm_WG뤙IL&Vh:ځ/teZRVySCyE4N&/ dj:ڏoL  zqis/GxΑ}_W*Ѷ=ꡜo`kK?@䫧icSA|eޗϿz}5!/Ot..@{R___}]=[Wm$O?_<[ ,80IP(I9@+-1#?ɔCK`ؽ4l?N.'t{\#ݽ̓ƻ` ICqJ:p#'_0:bkٶk'Q~OMկ5?tubqҤρ&a;'Ṍ5y3rX7 P Q՛O:()y\g_`zZ+t^޹6?u ̖O_ͪcz˯2K.+Tz}ǰN+4?O:qqdI]s?**O'r-h>dc6!y{Og\g3fcĸr޴;~Q2nVx#:GQE֘][kO7{fg=Ewޯ/<emnY߬9!c; pvN\H+{ j>h%"[$\i=ǛQKo}cno~6~f…hуkR> (6"/N@T)E$^0rȷ댼U(ICVvzd*vFI78oUWzen)cܿC3;KWl\:_;[UI7=p?\:"O+ {t`r8׏{wgΘv_?]uںլkW;<____X/f~? Gp[i(e3c t >]ȦN! Gx5[N3&yK#|sͽ,ΘrdqA/WbtH6/tXsd+{GmC]g7yAL Їnhdkkב'sU&gwwd1&Xs]3;6/̏ڤz_"#;~Q_C?8+3O~˷: j2 4'`y|OmY?mLgu?zIYJxfʏ0 F9']и.ϔі iI2}ۣ<+ >{1vӡveܽa2n2^&߸OX?kѵdP̟]=kl[o 㯯 vcBsu>x,ȼ@vda|hs p©RMTeu_TI~@oGp^77QdOͿoLM?SW#p< }돱Mc6~ctGk_}Gkwo֠ɸƤFhمyQ^{]X5^kqrCՓ`'~s=+j4GuyTNY >(/<>: ٱ5+==zC^eltu9crH>+y(d&zZ rﯞfY $c#~wz{ 2+Cl4%,Dxő4?4U`ȢuS.M U|ߏ拏$4uDGWJ)?qO^A{_W~ʕӚo@ g?;?kI3'vv?v#c]kg8ձkC^lֹv޵Dz9@N}9cck'd.F1~jV<|En4=^'5`PU[<ؒ/m|].Sy|S~ >w8OrW^9}X@Ͳ{`_cʘycsݝf\=t^^j{ǚ1Ѯ T6q DN,Ρ/_m{㌎ҟ"< F)#B0,򎥡f[8\/^!84]x#=Syzs0;&Hg7Y쎒nYҼ۶ͭrZ]6HSo fVz}\_nys奧XVB#{-Ճw],(YWv?XZo?6#\X G7?<iʑ_ҵ(t5R?H\%.W/_QIi25 bC|;Wv_o_o_K9e.`Ʒ;^q\1Ԥq@\'OyDbWv2x5OC*x?G VB'u\8Xk];\K/0aӋ:Dӎo޽N.@֫W/#he#}3Tƕ;4?'menvSmS{3[]cTc߭Ur_m3|0+"g?O?_ qPSUf`rh̺ {t$R+Vz<F+Gu6Oo{zЖ|,>v|~eԀFv.7C({6miy7"> V Sn k aclڜk;\?Hȵs??>7\ sͭ!̋g[8(LyJ4r0r&GAs3-l>|+N 8[Oiz# tCjy=G':'}X:yHKY/|?g7^~MG<>5ơZm#iwqecPcv_뿵jc?t3w_81>yBL zKO苻eTLFz]1?k?Ofk͸Zooh̤;z,)~* S_Y.4Cy@vG=8d2kql澇l+1?KNS^Rr /'|7^Gʶ}ӯ{ww^G? KUO7W?dqpͫ;tn9xC,Wb{jg臵_Z ,D `IE( 9S51] ->GW=5!CK s@msMA~;@8W{?@Ϳ{kyi+><4MWXGK$6a41וI[*Kӎ N%>Ii3?(m"zt'YvƉp 'i3d[st틉[ݱ K\o Ĥs)9380 &v39\ 3|D'o Gjp$Gt\Q C/]; S'  }I:C`k;=.K\U8>yu2:x(d@{)t՝>kL/>JU[jNN2 79;/wmhd?:KsjcI6xi =[W2\?O?O֢[P@B>$odvkɗ&pme~bC֓G OPw%I uŖ金VNZ;Bޝ5: 褗bx2:;'rjdq yVuyW.Ozoq1F ]Q F e,@O@QqɃc6x"Eg1tk my 9xu8F臫оI}yiy_ډSƆ_xfd=9Gk9- 庀ynLg0J@#xy@Цz۴I@lz+q C4?2w?ֽ3/?ȺEKM;m2> Ȍ[E̍הO2㱮DLcw? "}7ӏ%]kA  w\J?κ,k=pViZn*;Ё{е9?5G9;My5 7|ś |[VQ 8GLZMfg:"l'nl T~عr=5;2>Ooo) w\FQ54GxjuDu(aGy7/̏;1o@ G|Iv&e[Io"׈WƘ@J_e\??箼c(˧[Ap3ʢqy(ҋ]k8@]xd~&/ES&@ԭ62G_o޼5^(i =0um&3 S%)ڴli[kq  K_*:'n]f37W3Fv{sD/WZ"菞#gkul3%3u֚[֒?A, ]A.šgVyg=9 3s'%M~[FYx&YyrhLc<I|\xxvx& 1080 11D50 2457 1138.32 568.00 com.apple.InterfaceBuilder.CocoaPlugin 2457 NSWindowTemplate NSView NSMenu NSMenuItem NSCustomObject com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion NSApplication FirstResponder NSApplication AMainMenu CocoaApplication 1048576 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: CocoaApplication About CocoaApplication 2147483647 YES YES 1048576 2147483647 Preferences… , 1048576 2147483647 YES YES 1048576 2147483647 Services 1048576 2147483647 submenuAction: Services _NSServicesMenu YES YES 1048576 2147483647 Hide CocoaApplication h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 1048576 2147483647 YES YES 1048576 2147483647 Quit CocoaApplication q 1048576 2147483647 _NSAppleMenu File 1048576 2147483647 submenuAction: File New n 1048576 2147483647 Open… o 1048576 2147483647 Open Recent 1048576 2147483647 submenuAction: Open Recent Clear Menu 1048576 2147483647 _NSRecentDocumentsMenu YES YES 1048576 2147483647 Close w 1048576 2147483647 Save… s 1048576 2147483647 Revert to Saved 2147483647 YES YES 1048576 2147483647 Page Setup... P 1179648 2147483647 Print… p 1048576 2147483647 Edit 1048576 2147483647 submenuAction: Edit Undo z 1048576 2147483647 Redo Z 1179648 2147483647 YES YES 1048576 2147483647 Cut x 1048576 2147483647 Copy c 1048576 2147483647 Paste v 1048576 2147483647 Paste and Match Style V 1572864 2147483647 Delete 1048576 2147483647 Select All a 1048576 2147483647 YES YES 1048576 2147483647 Find 1048576 2147483647 submenuAction: Find Find… f 1048576 2147483647 1 Find and Replace… f 1572864 2147483647 12 Find Next g 1048576 2147483647 2 Find Previous G 1179648 2147483647 3 Use Selection for Find e 1048576 2147483647 7 Jump to Selection j 1048576 2147483647 Spelling and Grammar 1048576 2147483647 submenuAction: Spelling and Grammar Show Spelling and Grammar : 1048576 2147483647 Check Document Now ; 1048576 2147483647 YES YES 2147483647 Check Spelling While Typing 1048576 2147483647 Check Grammar With Spelling 1048576 2147483647 Correct Spelling Automatically 2147483647 Substitutions 1048576 2147483647 submenuAction: Substitutions Show Substitutions 2147483647 YES YES 2147483647 Smart Copy/Paste f 1048576 2147483647 1 Smart Quotes g 1048576 2147483647 2 Smart Dashes 2147483647 Smart Links G 1179648 2147483647 3 Text Replacement 2147483647 Transformations 2147483647 submenuAction: Transformations Make Upper Case 2147483647 Make Lower Case 2147483647 Capitalize 2147483647 Speech 1048576 2147483647 submenuAction: Speech Start Speaking 1048576 2147483647 Stop Speaking 1048576 2147483647 Format 2147483647 submenuAction: Format Font 2147483647 submenuAction: Font Show Fonts t 1048576 2147483647 Bold b 1048576 2147483647 2 Italic i 1048576 2147483647 1 Underline u 1048576 2147483647 YES YES 2147483647 Bigger + 1048576 2147483647 3 Smaller - 1048576 2147483647 4 YES YES 2147483647 Kern 2147483647 submenuAction: Kern Use Default 2147483647 Use None 2147483647 Tighten 2147483647 Loosen 2147483647 Ligatures 2147483647 submenuAction: Ligatures Use Default 2147483647 Use None 2147483647 Use All 2147483647 Baseline 2147483647 submenuAction: Baseline Use Default 2147483647 Superscript 2147483647 Subscript 2147483647 Raise 2147483647 Lower 2147483647 YES YES 2147483647 Show Colors C 1048576 2147483647 YES YES 2147483647 Copy Style c 1572864 2147483647 Paste Style v 1572864 2147483647 _NSFontMenu Text 2147483647 submenuAction: Text Align Left { 1048576 2147483647 Center | 1048576 2147483647 Justify 2147483647 Align Right } 1048576 2147483647 YES YES 2147483647 Writing Direction 2147483647 submenuAction: Writing Direction YES Paragraph 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 YES Selection 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 Show Ruler 2147483647 Copy Ruler c 1310720 2147483647 Paste Ruler v 1310720 2147483647 View 1048576 2147483647 submenuAction: View Show Toolbar t 1572864 2147483647 Customize Toolbar… 1048576 2147483647 Window 1048576 2147483647 submenuAction: Window Minimize m 1048576 2147483647 Zoom 1048576 2147483647 YES YES 1048576 2147483647 Bring All to Front 1048576 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help CocoaApplication Help ? 1048576 2147483647 _NSHelpMenu _NSMainMenu 15 2 {{335, 390}, {480, 360}} 1954021376 CocoaApplication NSWindow 256 {480, 360} {{0, 0}, {2560, 1418}} {10000000000000, 10000000000000} YES AppDelegate NSFontManager terminate: 449 orderFrontStandardAboutPanel: 142 delegate 495 performMiniaturize: 37 arrangeInFront: 39 print: 86 runPageLayout: 87 clearRecentDocuments: 127 performClose: 193 toggleContinuousSpellChecking: 222 undo: 223 copy: 224 checkSpelling: 225 paste: 226 stopSpeaking: 227 cut: 228 showGuessPanel: 230 redo: 231 selectAll: 232 startSpeaking: 233 delete: 235 performZoom: 240 performFindPanelAction: 241 centerSelectionInVisibleArea: 245 toggleGrammarChecking: 347 toggleSmartInsertDelete: 355 toggleAutomaticQuoteSubstitution: 356 toggleAutomaticLinkDetection: 357 saveDocument: 362 revertDocumentToSaved: 364 runToolbarCustomizationPalette: 365 toggleToolbarShown: 366 hide: 367 hideOtherApplications: 368 unhideAllApplications: 370 newDocument: 373 openDocument: 374 raiseBaseline: 426 lowerBaseline: 427 copyFont: 428 subscript: 429 superscript: 430 tightenKerning: 431 underline: 432 orderFrontColorPanel: 433 useAllLigatures: 434 loosenKerning: 435 pasteFont: 436 unscript: 437 useStandardKerning: 438 useStandardLigatures: 439 turnOffLigatures: 440 turnOffKerning: 441 toggleAutomaticSpellingCorrection: 456 orderFrontSubstitutionsPanel: 458 toggleAutomaticDashSubstitution: 461 toggleAutomaticTextReplacement: 463 uppercaseWord: 464 capitalizeWord: 467 lowercaseWord: 468 pasteAsPlainText: 486 performFindPanelAction: 487 performFindPanelAction: 488 performFindPanelAction: 489 showHelp: 493 alignCenter: 518 pasteRuler: 519 toggleRuler: 520 alignRight: 521 copyRuler: 522 alignJustified: 523 alignLeft: 524 makeBaseWritingDirectionNatural: 525 makeBaseWritingDirectionLeftToRight: 526 makeBaseWritingDirectionRightToLeft: 527 makeTextWritingDirectionNatural: 528 makeTextWritingDirectionLeftToRight: 529 makeTextWritingDirectionRightToLeft: 530 performFindPanelAction: 535 addFontTrait: 421 addFontTrait: 422 modifyFont: 423 orderFrontFontPanel: 424 modifyFont: 425 window 532 0 -2 File's Owner -1 First Responder -3 Application 29 19 56 217 83 81 75 78 72 82 124 77 73 79 112 74 125 126 205 202 198 207 214 199 203 197 206 215 218 216 200 219 201 204 220 213 210 221 208 209 57 58 134 150 136 144 129 143 236 131 149 145 130 24 92 5 239 23 295 296 297 298 211 212 195 196 346 348 349 350 351 354 371 372 375 376 377 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 450 451 452 453 454 457 459 460 462 465 466 485 490 491 492 494 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 534 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{380, 496}, {480, 360}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin 535 ABCardController NSObject id id id id id id id addCardViewField: id copy: id cut: id doDelete: id find: id paste: id saveChanges: id ABCardView NSButton NSManagedObjectContext NSSearchField NSTextField NSWindow mCardView ABCardView mEditButton NSButton mManagedObjectContext NSManagedObjectContext mSearchField NSSearchField mStatusTextField NSTextField mWindow NSWindow IBProjectSource ./Classes/ABCardController.h ABCardView NSView id id commitAndSave: id statusImageClicked: id NSObjectController NSImageView NSView ABNameFrameView NSView NSImage ABImageView mBindingsController NSObjectController mBuddyStatusImage NSImageView mHeaderView NSView mNameView ABNameFrameView mNextKeyView NSView mUserImage NSImage mUserImageView ABImageView IBProjectSource ./Classes/ABCardView.h ABImageView NSImageView id id id id copy: id cut: id delete: id paste: id IBProjectSource ./Classes/ABImageView.h DVTBorderedView DVTLayoutView_ML contentView NSView contentView contentView NSView IBProjectSource ./Classes/DVTBorderedView.h DVTDelayedMenuButton NSButton IBProjectSource ./Classes/DVTDelayedMenuButton.h DVTGradientImageButton NSButton IBProjectSource ./Classes/DVTGradientImageButton.h DVTImageAndTextCell NSTextFieldCell IBProjectSource ./Classes/DVTImageAndTextCell.h DVTImageAndTextColumn NSTableColumn IBProjectSource ./Classes/DVTImageAndTextColumn.h DVTLayoutView_ML NSView IBProjectSource ./Classes/DVTLayoutView_ML.h DVTOutlineView NSOutlineView IBProjectSource ./Classes/DVTOutlineView.h DVTSplitView NSSplitView IBProjectSource ./Classes/DVTSplitView.h DVTStackView_ML DVTLayoutView_ML IBProjectSource ./Classes/DVTStackView_ML.h DVTTableView NSTableView IBProjectSource ./Classes/DVTTableView.h DVTViewController NSViewController IBProjectSource ./Classes/DVTViewController.h HFController NSObject selectAll: id selectAll: selectAll: id IBProjectSource ./Classes/HFController.h HFRepresenterTextView NSView selectAll: id selectAll: selectAll: id IBProjectSource ./Classes/HFRepresenterTextView.h IBEditor NSObject id id id id id changeFont: id performCopy: id performCut: id selectAll: id sizeSelectionToFit: id IBProjectSource ./Classes/IBEditor.h IDECapsuleListView DVTStackView_ML dataSource id dataSource dataSource id IBProjectSource ./Classes/IDECapsuleListView.h IDEDMArrayController NSArrayController IBProjectSource ./Classes/IDEDMArrayController.h IDEDMEditor IDEEditor DVTBorderedView NSView IDEDMEditorSourceListController DVTSplitView bottomToolbarBorderView DVTBorderedView sourceListSplitViewPane NSView sourceListViewController IDEDMEditorSourceListController splitView DVTSplitView IBProjectSource ./Classes/IDEDMEditor.h IDEDMEditorController IDEViewController IBProjectSource ./Classes/IDEDMEditorController.h IDEDMEditorSourceListController IDEDMEditorController DVTBorderedView IDEDMEditor DVTImageAndTextColumn DVTOutlineView NSTreeController borderedView DVTBorderedView parentEditor IDEDMEditor primaryColumn DVTImageAndTextColumn sourceListOutlineView DVTOutlineView sourceListTreeController NSTreeController IBProjectSource ./Classes/IDEDMEditorSourceListController.h IDEDMHighlightImageAndTextCell DVTImageAndTextCell IBProjectSource ./Classes/IDEDMHighlightImageAndTextCell.h IDEDataModelBrowserEditor IDEDMEditorController IDEDataModelPropertiesTableController IDECapsuleListView NSArrayController IDEDataModelPropertiesTableController IDEDataModelEntityContentsEditor IDEDataModelPropertiesTableController attributesTableViewController IDEDataModelPropertiesTableController capsuleView IDECapsuleListView entityArrayController NSArrayController fetchedPropertiesTableViewController IDEDataModelPropertiesTableController parentEditor IDEDataModelEntityContentsEditor relationshipsTableViewController IDEDataModelPropertiesTableController IBProjectSource ./Classes/IDEDataModelBrowserEditor.h IDEDataModelConfigurationEditor IDEDMEditorController IDECapsuleListView IDEDataModelEditor IDEDataModelConfigurationTableController capsuleListView IDECapsuleListView parentEditor IDEDataModelEditor tableController IDEDataModelConfigurationTableController IBProjectSource ./Classes/IDEDataModelConfigurationEditor.h IDEDataModelConfigurationTableController IDEDMEditorController NSArrayController NSArrayController IDEDataModelConfigurationEditor XDTableView configurationsArrayController NSArrayController entitiesArrayController NSArrayController parentEditor IDEDataModelConfigurationEditor tableView XDTableView IBProjectSource ./Classes/IDEDataModelConfigurationTableController.h IDEDataModelDiagramEditor IDEDMEditorController XDDiagramView IDEDataModelEntityContentsEditor diagramView XDDiagramView parentEditor IDEDataModelEntityContentsEditor IBProjectSource ./Classes/IDEDataModelDiagramEditor.h IDEDataModelEditor IDEDMEditor DVTDelayedMenuButton DVTDelayedMenuButton NSSegmentedControl IDEDataModelConfigurationEditor IDEDataModelEntityContentsEditor IDEDataModelFetchRequestEditor NSSegmentedControl NSTabView addEntityButton DVTDelayedMenuButton addPropertyButton DVTDelayedMenuButton browserDiagramSegmentControl NSSegmentedControl configurationViewController IDEDataModelConfigurationEditor entityContentsViewController IDEDataModelEntityContentsEditor fetchRequestViewController IDEDataModelFetchRequestEditor hierarchySegmentControl NSSegmentedControl tabView NSTabView IBProjectSource ./Classes/IDEDataModelEditor.h IDEDataModelEntityContentsEditor IDEDMEditorController IDEDataModelBrowserEditor IDEDataModelDiagramEditor IDEDataModelEditor NSTabView browserViewController IDEDataModelBrowserEditor diagramViewController IDEDataModelDiagramEditor parentEditor IDEDataModelEditor tabView NSTabView IBProjectSource ./Classes/IDEDataModelEntityContentsEditor.h IDEDataModelFetchRequestEditor IDEDMEditorController NSArrayController IDEDataModelEditor IDECapsuleListView entityController NSArrayController parentEditor IDEDataModelEditor tableView IDECapsuleListView IBProjectSource ./Classes/IDEDataModelFetchRequestEditor.h IDEDataModelPropertiesTableController IDEDMEditorController IDEDMArrayController NSTableColumn NSArrayController IDEDataModelBrowserEditor IDEDMHighlightImageAndTextCell XDTableView arrayController IDEDMArrayController entitiesColumn NSTableColumn entityArrayController NSArrayController parentEditor IDEDataModelBrowserEditor propertyNameAndImageCell IDEDMHighlightImageAndTextCell tableView XDTableView IBProjectSource ./Classes/IDEDataModelPropertiesTableController.h IDEDocDownloadsTableViewController NSObject NSButtonCell DVTTableView IDEDocViewingPrefPaneController _downloadButtonCell NSButtonCell _tableView DVTTableView prefPaneController IDEDocViewingPrefPaneController IBProjectSource ./Classes/IDEDocDownloadsTableViewController.h IDEDocSetOutlineView NSOutlineView IBProjectSource ./Classes/IDEDocSetOutlineView.h IDEDocSetOutlineViewController NSObject id id id id id getDocSetAction: id showProblemInfoForUpdate: id subscribeToPublisherAction: id unsubscribeFromPublisher: id updateDocSetAction: id docSetOutlineView IDEDocSetOutlineView docSetOutlineView docSetOutlineView IDEDocSetOutlineView IBProjectSource ./Classes/IDEDocSetOutlineViewController.h IDEDocViewingPrefPaneController IDEViewController id id id id id id id id id id id addSubscription: id checkForAndInstallUpdatesNow: id deleteDocSet: id downloadAction: id minimumFontSizeComboBoxAction: id minimumFontSizeEnabledAction: id showHelp: id showSubscriptionSheet: id subscriptionCancelAction: id toggleAutoCheckForAndInstallUpdates: id toggleDocSetInfo: id DVTGradientImageButton DVTGradientImageButton DVTGradientImageButton NSSplitView NSView NSView DVTBorderedView DVTBorderedView NSButton NSTextView IDEDocSetOutlineViewController IDEDocDownloadsTableViewController NSComboBox NSTextField NSButton NSTextField NSWindow NSButton _addButton DVTGradientImageButton _deleteButton DVTGradientImageButton _showInfoAreaButton DVTGradientImageButton _splitView NSSplitView _splitViewDocSetInfoSubview NSView _splitViewDocSetsListSubview NSView borderedViewAroundSplitView DVTBorderedView borderedViewBelowTable DVTBorderedView checkAndInstallNowButton NSButton docSetInfoTextView NSTextView docSetOutlineViewController IDEDocSetOutlineViewController downloadsTableViewController IDEDocDownloadsTableViewController minimumFontSizeControl NSComboBox noUpdatesAvailableMessage NSTextField showInfoButton NSButton subscriptionTextField NSTextField subscriptionWindow NSWindow validateAddSubscriptionButton NSButton IBProjectSource ./Classes/IDEDocViewingPrefPaneController.h IDEEditor IDEViewController IBProjectSource ./Classes/IDEEditor.h IDEViewController DVTViewController IBProjectSource ./Classes/IDEViewController.h IKImageView id id id id copy: id crop: id cut: id paste: id IBProjectSource ./Classes/IKImageView.h NSDocument id id id id id id printDocument: id revertDocumentToSaved: id runPageLayout: id saveDocument: id saveDocumentAs: id saveDocumentTo: id IBProjectSource ./Classes/NSDocument.h NSResponder _insertFindPattern: id _insertFindPattern: _insertFindPattern: id IBProjectSource ./Classes/NSResponder.h QLPreviewBubble NSObject id id hide: id show: id parentWindow NSWindow parentWindow parentWindow NSWindow IBProjectSource ./Classes/QLPreviewBubble.h QTMovieView id id id id id showAll: id showCustomButton: id toggleLoops: id zoomIn: id zoomOut: id IBProjectSource ./Classes/QTMovieView.h WebView id id id id reloadFromOrigin: id resetPageZoom: id zoomPageIn: id zoomPageOut: id IBProjectSource ./Classes/WebView.h XDDiagramView NSView id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id _graphLayouterMenuItemAction: id _zoomPopUpButtonAction: id alignBottomEdges: id alignCentersHorizontallyInContainer: id alignCentersVerticallyInContainer: id alignHorizontalCenters: id alignLeftEdges: id alignRightEdges: id alignTopEdges: id alignVerticalCenters: id bringToFront: id collapseAllCompartments: id copy: id cut: id delete: id deleteBackward: id deleteForward: id deselectAll: id diagramZoomIn: id diagramZoomOut: id expandAllCompartments: id flipHorizontally: id flipVertically: id layoutGraphicsConcentrically: id layoutGraphicsHierarchically: id lock: id makeSameHeight: id makeSameWidth: id moveDown: id moveDownAndModifySelection: id moveLeft: id moveLeftAndModifySelection: id moveRight: id moveRightAndModifySelection: id moveUp: id moveUpAndModifySelection: id paste: id rollDownAllCompartments: id rollUpAllCompartments: id selectAll: id sendToBack: id sizeToFit: id toggleGridShown: id toggleHiddenGraphicsShown: id togglePageBreaksShown: id toggleRuler: id toggleSnapsToGrid: id unlock: id _diagramController IDEDataModelDiagramEditor _diagramController _diagramController IDEDataModelDiagramEditor IBProjectSource ./Classes/XDDiagramView.h XDTableView NSTableView showAllTableColumns: id showAllTableColumns: showAllTableColumns: id IBProjectSource ./Classes/XDTableView.h AppDelegate NSObject id id applicationShouldTerminate: id applicationWillFinishLaunching: id IBProjectSource ./Classes/AppDelegate.h 0 IBCocoaFramework YES 3 {11, 11} {10, 3} YES qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication-Info.plist0000644000175100001660000000225214776170045030242 0ustar runnerdocker CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier org.example.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright Copyright © 2014 Petroules Corporation. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/main.m0000644000175100001660000000314314776170045024166 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #import int main(int argc, char *argv[]) { return NSApplicationMain(argc, (const char **)argv); } qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/0000755000175100001660000000000014776170045030127 5ustar runnerdocker././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000755000175100001660000000000014776170045033214 5ustar runnerdocker././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16@2x.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000000253614776170045033224 0ustar runnerdockerPNG  IHDR DPLTE7E6C6C6D NNNzzz ...OOOUUU"""ppp 888bbbfffjjj]]]///ARFWHX}݉n{谢aoK[HYBŞ[jCT˥ݺO_mzTdUcÜɀތ䢏ގFVhsŪٓhuTchvK[Žbp_lWfKZÿx׽ӼιǺľftRNS )2 4 $ .372?(au#!?-X5q:>QVWZfw&(/F9L,Y%L+MkL#6"(wIDATMKqon(nP!ֱS"BK/ ЩSk.K 몳\>Cz XrN6 "[:{8+&4`I4ͿxXhuAV`1M3VHc@#bRLOAZ1, ϲ/*RG%d|5j5r^%;cxrp0\pY{ˮpB0<0Uˮ.%#y5)r̕5[5Ǿ>GSs7JF5 Ƙ48 `( dߣ0 6-{K7rc$:$=o:-Xh..Cp>zTH}jbIYJg㭾Rx4g)R☜eV٩My HٖհDUA#sAN'mDO014K}g)>^ZIENDB`././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000000253614776170045033224 0ustar runnerdockerPNG  IHDR DPLTE7E6C6C6D NNNzzz ...OOOUUU"""ppp 888bbbfffjjj]]]///ARFWHX}݉n{谢aoK[HYBŞ[jCT˥ݺO_mzTdUcÜɀތ䢏ގFVhsŪٓhuTchvK[Žbp_lWfKZÿx׽ӼιǺľftRNS )2 4 $ .372?(au#!?-X5q:>QVWZfw&(/F9L,Y%L+MkL#6"(wIDATMKqon(nP!ֱS"BK/ ЩSk.K 몳\>Cz XrN6 "[:{8+&4`I4ͿxXhuAV`1M3VHc@#bRLOAZ1, ϲ/*RG%d|5j5r^%;cxrp0\pY{ˮpB0<0Uˮ.%#y5)r̕5[5Ǿ>GSs7JF5 Ƙ48 `( dߣ0 6-{K7rc$:$=o:-Xh..Cp>zTH}jbIYJg㭾Rx4g)R☜eV٩My HٖհDUA#sAN'mDO014K}g)>^ZIENDB`././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000001221014776170045033212 0ustar runnerdockerPNG  IHDR>aOIDATx] |WڿD"R ڎFbf|7Ӗ)ih1ZeQ6XcOX$ds}7yysk)RH"E)RH"E)RH"E)RH"E)RH"E)RH"E)R ;ϯ9sIĥ;bނh>}BKp~s/p%;Ř9siW>Zp߿{#}YB/@M+Y _r~𫿽L%44>c,%072PS/U &/@ hDA)?]h++(+(+(+x#@?RU@e/gǾfߥNgC7i,vMv5:Kw%>v_f 2VoN`-[(8|z"s=Ϣg=`#G7{YE{Ű]~3zP?  <5köD2Ok@i*@4ye/$~x%M8h: (@46< x/5ooƵ-`icOQ$~ŝ{C0 yR_qB{?.D'G)CتXAA|;wysYM3w @VD@m`&J=3VF0c%p$pre!4K^pl$ "wN..=$oiIzRG>34xncOѼen Hg#(É;w%qv=bo8Z`ijN͖ܺ>!d4Z`[svN4ת8j'H iÉ

`5Y'(R}dlh~v[a`Ýک0_[ZU 5LU. ;69N s B4F+vVNɌ?:(13wR-&ku xF|ڪPzIv;N @ǣ==tV&B@.>+'myc'p ?h^tҾ0שWAm 'B^2V= dbIˆL*B|J+6j޼sӧOç~?G40F7ePQ@1;Ć=zz-;w~oCLG½t%@8ʠAگ]6k07}._˜M3GNfd&8r5M6uÆ | :3pb}Zɓ'*bj+x6{$W{GȚр tϦmf#vcK#?!۷Çk޼=^VZxON>a jٲ߸aVhOǽm֡Ntb_m [q=**J[]vMc#_h̻/9s$QUly* alyOh9{Bxx0.\Єo .b|y2<СCqJ9IJo[{&_ͣP{av!T-Q =uyGW!,/߫Yf{0gm_<~ZxVx0HBX2 [2 @hx5=@ /"  Zqcbb̙3llUk.M5kG*"yٚ(z+_ r0aYdP@<ohbeGVDw_fz+_ r5k53.' B|[`ul{ŒEC [gA\xb-̃x2 xٳg')yBķ!*|4]"އS Aٳ:&ǔ6^U Rѧ#86Liɹ-O9w$awi!4 ! 8 Ƀ '󏑴yӾFZpؘvKሿ4-87n& YcuQΚ#1evI"{=E3G z~(N)TT苘h粐\qѺ4u> Q@y _Oo ]P*#(AJ*\~#Neh;r50,P 1oTV-,ou+>A -1,\'hݪU0L4M2` uQԁDBXfgQskͫ'~GO*A\RZj{ &d8 z HfA3@CiN{y2 @o\&;ёe;pD@+]0u xW(Q1]d Pgȑ0d\2n yإ#X@PqǎétC8=z1Mb{ˀ {$x!82߼yÇ_˟tI PO)`xZjdvۻSN]WLie&QF-c^C1> T |TD[m *=r @H>CfWǿt:u|A!߫(/J=z ׇdy8{0  ϗu_~O`D@G}Af#0\/>Od4hР'zߤl_E{u?Rde@@؎ !`A+}aN<8]V.A%! Pk׮0P  g aÆ ۄS(l?S^k-Z[־Ch`$}B`,#Bt|k:P~V ͗=~8M2<*Th̛<}u} BeΞ㯨]31 y^,,T @baiI!\0~q|RtbCIGі>z R&/M@5v,sM֭,!ؖWC|z|vIuHVZ}9^zxu89ƌ~m8s'8'w>dȐM}Yضm۱qtA?嵛GѯI5tK܃H,UIENDB`././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128@2x.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000002605014776170045033221 0ustar runnerdockerPNG  IHDR\rf+IDATx] M2Fez'Piy"T4hE@ty"O 3 xE2 @H~_\b1mߏ^V QX [q;>k>+˰Vvk+}A  "╕zW.u{)C / BɸV{|klHH,+Xx?Z76>!mh%Z۳sc,wL<@Hy ܿ&e,>ux{ҟ @>ޗVkm DclD;tZڎ@HBeGςׂ!)Ab ?x^}C@/7˚ty@WcǏ&z}ע=0"9w`0+ a<.͗Pq^o?>p 66pNx>.{Wy%d&KDf[yOpDK8AٵLB1  jq sx?8k0>ߑʳ(zrx?ɓ K)>{~3 Y? ώƮaǏPya-^ t92?`DU_R<V)^0LAP2J;arz1o){?WavxZ bTȔV \aV} ]ԣG^؏/yiӦȟHYt5oMAktoF$(W{챻da÷سg]!yv %,@(6Y_Ͼ+JoDX[㕅@G^T2e*u3;f#F8RN竪9 A0 o/y_V?L"(*m񖑾~Kv3|;w%ŒjP rŻanÔg2 -L0(!0ڳnk1 )+W[r. S5"*T^+|u$yz|.\T{>eJuY|~$vq|U$!EEOQ @(2nqc=vx}fؿu~}ǩI8f-P[ζqET?v_.] UT?sɼwd.{6ozhrsvRIr6lX?cƌbUX򽮔0ꟋQ5`b6 Hʸ0#b.Nuq΢7Z #K+Đv_xH7-Z mg!7I;ug F|̙#f̘r.JXj ? Rv[XdsbFƒHE5eϛ7OlٲEL>}ӦM;i'0pߋ-zG,2DBż@M!p}3xw' 6@(߾}ضm2e@KΝ+-[vkڵkS Ti# qJ|ѢE \f}W^bرbժUC׷m۶bO+CV][dg]T8 Pw6Sq M8Q,]T>믿 9O~1a~zA0` Gf? X>icl៑yM ۑgKS:Acw}'~7k׮ _ѧOߺu_ƏD?S%!V\ HmG~גJf9v9ӞO4dիO0z?R~ Ow.\c;R~`Z X_p߇z&EP+oL~W =-ADGyVnO?t{wСw\(~а`r} ÔD߱!W{/H-G1A 3h?? # ` 6}kmV3//~DD{׮\A9~~^3BcADw%~"gzJw9~Jq 5(9芌If+es;=m{m%KXo^;qҤI})mw9}giif6U^k񢇬t=7jAT=b=EQ(`zO1F?hf/gΜ)~m!yɓ'[ ~a҆nq`%mmZ~CNM0wzkwo>#jbۻEڿBNAhWT^iCW9TfX(Fd<?x*gh5bp}[|H類_ڃY~7o>!'gMSG ,?MV[i0~ zNqᐵ1|,ϾCC_hkW͞=G ElQ؃_[;pos'HZ1db/SuNA;c܏#0ɝ7cE/m:駌՟`>8vXLJ<>Wīzla۴Mbuy#&C z駟TOʛYq_J9 I~kو#Wi .M"l1 nN 0@k-~h>?(I&Jb?ps,z7D1߄ڣƁ]|LF"zן ߦ-n"5h }o5FM!,FMFٯ/~(>]Xs,$$ޖc;>V{`@\ǐ!C` E*foƍ_R/GD`8::4ғ\W|lua6MqMYcUƪ_y-^hdj__6P|7NGrhH$|Kݮ'+ǡHthh>sXnݺs~)>#NՁyuP&p&rj@{VM^9 =herŢKEɹ8%G:oIq#uؒ;au8]WA{^|>>_ O1IJ C.8N GM~=H)ʁ!ZjLI>IƏp&rsዣC;4ŤWAuVWKPym$``'-{F58vwJjѐzӇy`V5 @*GziZ_vB)w rNYq9.n"l1n聻&RшA4cw7(Rq^Ec fOG+i` ?jx.cL 2R7~9Pd{ZH_ &(e4c, 7HF0"]tG6< _%i.BʿA{c%U$Td {ɔ>I|XM&>@k؝}hd Ez7 jh(Uw0 s+KP[6J[ʊ 7HF0|=뫯Ѽd\$}jժ;ȯgX2FL k՗*U?#lG]F b[9-4PP/UI%!ڡAnӾos2T`z&"ҏ:!>3'\|kU꯻z6b8K5?dJXNj\R䨯5TD&F࿈~ڰ{bIbPb4d]ojwDӕWyJ䳔jCEڕՖyEznXv܂>R{(E]?j`2`xS…P.ntG*yW۞BJ b!25,xIK*'Oڲv~2$&9rGI0|7&SPxdIiѢś*}*;3qt!ȫn3 S TpzH/GT5fvɪ 7xCJGbJ )G뿯O>dʮ\urگ &dj׈زe'i(^/EYe0~9B {)}Ї=K.yHeUd<'W7 d hPIjlq 5\UӏmN* @̭۶m{;#S!dj7-1m1$&bEuL =r_*PT]2*vO`'-ĺ`KemY&"a V}0 )HM'!H }ֿjժw E?D@A%خV% DD IC}D7߉E[[T1UEWw`Wl"Et*Wh` pkVFwW1 ͂3++*UGa򑱁?"XPHmU^!ަD"a8+?F?nbLAϛC>dzr[ҥՊ}[S+W Y_orѿ}(A==)Ѝ_ [_Gm/P[⏁?·`gN$k](q %^0(ˇ9(={_d nf?3iE'+K*u5h ?mf D?=<4MnCOyn I#˖-{s$ GoM‰Adde"EܕC]è?h E+!`Ķ>.&S) e9+>(W7fT!g֟wPzD~>}eNL 'Ak&\wu8+ߏ)JN?n@ @~]d5C@]ʸHjCcZ/xg M R!xlf͚uRA?+;"2GG+`GY/ QAM 8?">h:0F .~?D %K~L W*kG?31qĿ ߉ Yw2vVVUA?3OXA@Ypnv)p4EǎC9oOab_xᅁY9gYVq'Or5|5\.(A+?}ptX!D"x|Ge圓qյ]àx0r) wy`$G_""e5G/F{r3G^쓜]ytc@N<0~0,"fmm e+T_00)OH m9,.{`GƏ^~nB*A:hiݺuO?)pR3}n0('Ge1K#h aL X2haÆrfTtҠGcMG[}taZ/҅;ѫ h@(Ӕd 4!C}}+"ܗy|١#pLZ5 ,ի?8wh8$ 9)4~"v[-0nݺYH{0-Vs066Kն>;HvM0H{ m2rtCVӁˁׯ [0jGǿ0jjUOdd,bfGZs hDne͋/W_|zlҤɇ=P϶mfwa0Ce>_Vu=7nܹN:P-{6Q@Rp R"i>~)OP 7PڃQk(1F 2[[k}J ]@{}%*iVu5cF}૩H3sj hm *s3|?n ,r(㪨Zm+CBU@k)cpש݃SVz\>W ޟ6bj/@OPX@>ZQ+hIe\PVN +) eU*]]e^[EE+ϲWsԵћ}^'( Fu2ʧ>Sٚ0UZNU2`7VP?{z]9^{)OW;SJo}>D-n 2؊tC1WYRߕHBaFgj^RWqgh^0x}{ojO'Bp-Rš2֢J(lp3E #/{~VziAri[<`-4EgkFO{+n4zH2MSty iD1'Ͱ "/AAAAs$t3IENDB`././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/Contents.jsonqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000000242414776170045033220 0ustar runnerdocker{ "images" : [ { "size" : "16x16", "idiom" : "mac", "filename" : "icon_16x16.png", "scale" : "1x" }, { "size" : "16x16", "idiom" : "mac", "filename" : "icon_16x16@2x.png", "scale" : "2x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "icon_32x32.png", "scale" : "1x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "icon_32x32@2x.png", "scale" : "2x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "icon_128x128.png", "scale" : "1x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "icon_128x128@2x.png", "scale" : "2x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "icon_256x256.png", "scale" : "1x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "icon_256x256@2x.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "icon_512x512.png", "scale" : "1x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "icon_512x512@2x.png", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } }././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000006455014776170045033230 0ustar runnerdockerPNG  IHDRxi/IDATxx\ϨYղe[܍ ^B dIv&dHd!MoPj:ۀPm46Kz^ڣS{dI;=;|"B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!%B8/[B!yo (}BC3@ȟ!ׄ<E!~w !?z#@-BH>׆P)M!X?O&BU$ So$qF &7"ۼ0WE=Gӌ_# FN#~Xl񏘼/VG:% BH{E[A ('oG>V+'?}*.$Cwac`"Io04P+'>JI! K.YO+ əG,ĿYg_YZ_}^NB@}4fb0$_p<ʲѕrB-ҷF*fuS_g]QPE' @ [!'_`'BS{D|VxXD x_d 'YX?!'e"aU_g|gcI!)gtOm@M @p_7"BLr9şB$}X$RBHf3V7 XQP`q?BH ;95P !$3f& WQ !$jm& şBz~{; aO!WW/B'k?u4B @(#|?!{4B!yP !gh(xi(B?!^N@(BhşB şO!O'B@BS !P !?!B@'Bh(B şBB!4B!O!P !?!O!O'B@BS !P)BhB @+(Bh!@KzgB!46QWR !;7şB @x*?!b?!|(ѿg(GGU2xTKyAe$)>vD[wbmhz]JcOn=MԳBE7X(j)1e2AJGʨ~2()(9tźeSҹM*;6˪}{K"d8`&E!\ RQUSeZTT>^fr زڑHOSEy2|v|yǐ%xoG/B"1(U _@cFPF.?Ѧj ݷ@^󺼿c!?1Pė@07Lx;eSQ<٬ b~nj%,&Q)篯Fu)/?=O4/Y;{?G!HS#!WN8ȱUGjreaR^BHD73PN4/0F7MV4xǦ鲮cc^^|g,8/>B?}#3 @|}7-{AFÎU}=[v5d y&q\i?%y1R_Su 8^^g. dt#b7xrK_o5IKʍ'6gd'@34nZ?ɬ@!0|z͵j/}([ W39{7F L?Q_&_# uBh(_c 9'ɟ'^%CbdZ$p2Zh$BhlZir rO<ۉ5!ǪBKLB̀ 9쁧4\r Z,0 lx !4~Cѧ!'U+?CoT @&4Ax̤1C?2d/F7.@dn}w4Fk,#(o% FCȑ숿"  !|_~c:\9^f @^fHR1I.U^sY2n%A)j+. ]KU-U)p _E  '?Z9i_/wUyCc9}.[gȩ*"ɩX/<%ս/f  `T}{Ŀ Uں_v\}\S4 0@h9?נ<$*fQm3We-9}._[( DGز9}K[W_.KZW:j_+,_q*Rp kK !圞O>kB_Z[$˃ ʽ !E?2g=|~)$pպ[r:CΑ  ĄH1W7mn3l?Krr~ 1L|fh sglNν{\ꏁ*K%i?k./En-d_]]33пKՎ-VBOY~}YAXhBRQQP~`nԮT\#ULƖ?`F]ya >ȤyAA( \ iqRA yyQz0A{u ąqbcO91#ʾfYںsY9 ϙP>FX9/ M*ϋ8?7} ВR]ԟ>1˽5;6&l[Pq,9 4{qw#o<|,/| k ro\زކ-==߄1OA0+VM`!c==ߞ&Nsuj@g+-gz["xm·,v)Fm==ߘ:^9xJm^ZYV2=B@<(R(zz xc`/za  "޽lݲNԹ2[B@b;1qFO7LޏB@#M·(k>oBR<6;i\& 0֣<-CuIWsUub8廹kDg=f?_mq6ǢBhHZxk'/Kvx\49< WEWx%U! e+ !4$`s 4u{k*y  aA@^mZzZy]qf{#6[BhH*FZvXfY14p OBhHȩ.2-Q3g<ѷy^^2mHB m"X;/zC+ J34_Oןuu`+ @oO0#B@BJI$" (mE B/.cv40oo*5kQ̋N +^Gyx=k'^;B@BL 0K0g 03B@Biޘ&P !4$ @= ׎mEȵ d03KۗK|ï  EOEUR(`f kH۵ފr))(w !H߄8&|u0@_?bq@,}?B@\k7 XIcO/:!ވ[=z_|6q];== M@H~EXK->7~~_a qɎ]oX^t -ËN|m/uuu.]+۷o$ķd/KhE'$'(ޭ( q:0u;ӄΐ}x/"GN?{נo۷n 2fNg҂~ʳ&GL>^wun#FHkRiKKK'= ޼v$$sHjv`j$^t&5R6$E3දI~T7`i?3^/K0 ?yQ;㏿%{뭷> ,L3$uVhT{v3jN۟O&^ As?3at'5 U/SLib?4%D}|C2XoeZ}g眨݌W+:ȤsZh @MAāezſK.93MyyyF :::tMܩI-_9^^>ȷף%E߬]IQ[k:'MTwo-[zſOto HF @my_|$T&@@]UuW_}ډ#E(znVcKfHFT&{QZ 6@wϋOi8Ha?ЅTzh{ӟ7o~g֬YK`߿a ɀU^kzb/Ұĥ#z~޿kؽtɊu᯺ a駟~_YY٤l?Y57?4$#( ο~=o! :{=z=*E7 '7 {4?S|ߜSSSs77nܹsNvmؔUpU' Uu\VqN*۳/iUZ_v͛A0?/6O3vX~=zEj_OTG}19tM@K$+Y=/8"?|n@x @,gOx&0jUZYUT)֢JbСƎ{i*IEEEOtݺuzF%I՜ )/DU)ES:͋eϋu991ra7W#eY9Gea T&Ɣ @=jx5몭9sUT„ ҿimMmR{T.7z'?'ҤRį5fT//PZ'wmy#?28S}t@]3,ErYͲVkو]McJe R\P,RVX*%@ST}?_BxҼmH~c.jo ᯫ˥1U}-օv}'I&yj_sftyWrպUm@^G!$xd>U;>@];*x=2iGI_7f P@/%ŗ^zi'tҷU>%GԨQ2dꒅ k@Ѩ56?Ik d?iY"*yL(wt#*z}|S(G^zsmy(jQCjC 2mvxRG1⋏?3[YY9.]CVC^QÂ*ihhEٛO?}?kb(gd>!&L@ -_tVUj8_<{?T=~j*Ň24@1N>䯩51~k.Ybwl٫E*(UH>בֿCߏ??*U'd!j^$KZWԊIx>K4q}eE.c/۠9sg圁UQ'<=A.g(o U>}\׫?]lٲE֬Y~SS⏚܎*T*KunѷiHָg#rÄ9Al/U /ZмP6tltSQc5Fv/'>h,jYuPNJr\RU-yZaD|}>Q_zlݺU{۶mZ @AA7N3 vgw;`_eo  ٍ0<3NF:f:^XܲL.,jAז IUxD_sfj.E @ Cwbertar:JRjg?-⇨߽{߾}9RԾ1yd PgN=+-[ҥKӍ3@9a@QeTNXfvmm;K7@Tڹpo*9к%5?H rh?_AKuߑf Zd9}S[0`}<-YDZZZ?|=JKKE WZS ~[s Y-xl)pcFkG>1{ZGyݜfp PP[Y")2NWKJ?~K,D:+T j9a[p3@C۞SMI#Ckp~'w̑/ <-%4LųS˱mSeSkX^gU^:;;?#Fh4hL8Oq`َNfdU}ͺ[Wl=s~Zng~OTZC` @MO9\6IJcCkkk5~5Q০Iss]V[k>28`e*^Qsc$}eO@|pMe5gʕZ?LT#1i$Sd7Oe;6iܼٜN܁v?vn4]:BF4G\h5?!{@j"xaPݏaf[3A0==,9x _rɄ 9ro?+:V(7MRiA=i*MVY+mmmL?1FX3'vo^? [~E / #flZ} ~j< B3"8lP?AEGMQ]Ӫۀ@#҇Ef?Z~T &8ZB@޽{c=7-㙈iHNhn\5]w`ݛG.\V?CQ dJxm>IAӛ.Hc}}'J}Uz?#1) -{[-iH[6ޭwYj~?^ 󺚉݆ۥ5Ƌ_i5'#)/jnn;)}#fd;! GI{z?Æ i޶2={r߳w&KZVKU]$^ sm~Azgڜ9WkU ӲR-'KT^q/3[^#/4"-Zc⏷n*G ^Z!g$? :\0BOea/Т:sdz2ks2Mm!|| e:6iִW6׫Fm 5R @xT@~…ZTTTh8J#PHhU>!2iXZTuoz#/ec^ (RS+&qɱUG!vs2[:6k^OW &v6z*"o>F*v`2"Àq8JC^KJaPy%Id%ߟA .ޣ0)N8`%}ïmϿ`j~iObK0pm12dE0F{;Ⱦ -ٵ[4%%[;whYݍ(QȞaA𱾟h??5΋SOF- 5 .v#*Tj_a2M^,/KUa@htǻ]Y!*;pVX7Q'h}!a&,_t_ Zo~2.uf @"3 rGK$,lY*?,/>ClmjĆ?*$BW[,7^fe/>"o'[fT/YD d?< ] ob='kk0htڀ̚jD xQlEqBCJc^m}cOb D߾PG?ǿJ}#;Te nP(yځ 8QN9OeMnu%/Sc;QħƍgHChRmSF@,XY B?Sv3J[ﺾYwp <{|Q;P=rvpRxO*mR}DMƣ y՛WQBCGğ*~' Տb?c Ņ|t+@KFM{/FFѽ!#sc@QZƗ7AUpr];e `ǡ۟%OKCHU';FhCzDi}>gjB_:_mvoܸqZ?Qxinj9 0p8jO@B ,DjԲAm05L[Svj*Ԋ SvT{Ϸ%XR|Ïc]FYܺ\X\=d yMM!vǪ~E؀t.RJ1io GLn>s=&DFS҉iq$Ƒl AK+MTj^]RXvD|?>~"---b]+ƒIz? 2&M:$[ILk׮}S7Yb?7cf?o[#l/Rl  T|T?*kE{J>"՟{m Pyk3Q:?L o̓f-?+? !9s_ozG>7䜜|I^R/}ڶ P/RQ~6}oL(fo%"d # x~K[m6Ex!húȑ# Jr#hKɨ"ď^{UbYd cnx8:'[b"fNJ+/SS >Ga*]-,ܵ!2,(T>@wxfG:#Z> p sj?~hàd<|QnO& f`*KMPP-e= !`Η쁧˔99?n__FP(;c&bU}z>y/h|&X_G駟իo嫿Me*W;ϑC['َi!hMZ<j.]q\hD$Гb1On¯[BQow-z,j"d6n8_&,om|uȹ99aK z9o} 9m4|HgWԾEZ)5kp`pݼH=j׿{cֿĩ7rז0?\FTER|rmF_Рҿ6kqH0o$wl^;krU#yMC4s:'&H~GQOe'L&WoUM? !>Ex7oK:)9We?Xw(:9e b_6k?_iq`#??Qτ!??jG9M1yPwl'w̑TZa[ Dg[a]>hCюL)*sb/RaoODcxF(Ҭ*}71🬚Bv <^24' HLZ?Ub>>|SQt>GO?h=ӆ;a?#TKͲjՎS өF޾iz_)_}4`R} /ϧLASl|m"x/1_k?ذa=FY;pSy\c͢ѭ8Oe3#خݽ crrd|y|ڶת(^rdJUH=#G1J7[עkS}O}} :TG_&L?] (N4bڵoi8/d]i t]u{vh:>Kt7aLNʨH]̇33;0hD?RȰ$Vlꩧwci 8[:ɣJk{Nyf̮5wJcǩ}\=B߭脭8/~*ZquLz& &Uy歖|9ȶrFgtDV en⚌Um}g;UF O>s>@Q!EEb?-^m|vMݻ5ч#.P"2rȔ~6/ g鏚cШ&}y: $n=)-Ǐiu_w*3v<#;vFYjm3}67h [N?| *!uuuZ z *1؈ UG_ڿo2fxV۰g\Y'O|Af|N{Z6UN{Ÿ3h"j^~XcCLz6 U2_{?FO2*ƻ妉7ҷkf6M0`5~DN+̙O87qDm{p_. ͢bG[U,ڧ $,jYm}Zis{ ֛[&aYv@6?c&ODc}Rgj̢}bO>>*fßM $ܱy\}lV>;lXQa.]ԾW q!gڸ\,`f+ Ąq PS ??>fw 섟BHji&uX_'<Ȍ|zQ{aPJݦsmG 5(w3P"&]C;ځH*~nHTCa K-L׆kfѿjo\5s̅ҷ?*K@ ~r^;dž2Lga#鋴?"f#Go6?[ Fo[n7&>C@7VӤQg,Tm~hDXE,WۧOn f!:Mt~֜ş?7GԏA?hO0ADɕTgQci!sOi>Pm+VЊ0c~f?XGل T%{瞗DGjh!@;k[+g>|pFY>F>z2.ѾX~Iw+~1~c*l_D4rB2g KQi>㯅 b/vMZ:.Xg8eбv)19i!ZNl>kpS7M|ܬ͛J>za Ⱥ J(ccY ˪qkB|ϙj؏]_MM3x_oǰޏ6?Ҝ {6 Վ>`|9+jet˯)1pW[jGE/!@wPfoK.*2u4ܡn7v"~S=r*PhX鏙n x≧- ů? !$L'C 3"~DXG3G?sq0=Uw俵l]]熬l}g3ECaw?}]L.gg-3&7Ȁh˯I@s%9O|H?_oCʿ2=C0|/CZ8 !$9ϣSgGDiT lT[D' pO !sP?ۺh[ o ܬE?:mŭ00Xo*gY;ci!֩GH<7#Տ7b }?r~38<]V̙3qٿ寛M}K@g&$TE+sq3w="c`yEˠ=Uf ѿ~_G4 !m͆A|sևJ2(>wRC:d=xfDGT+ xwx/s?m a?ּ?υ`vٳg/3~O=02kV~?1O|xƍZ?ި*D6H~f_ jKz͖Xc ) xq)EL;G A J\E~2!feϚ5+97k ?fĝx3|aၴt:#7!*oݺuZԫWc#%?̀u [ߞ@͎(o˄xzgc=nLZ_׷ڿ٫sڌ4TA-$]u{10A\?7!vK)cǎ~/uA6jǿGе@nO,~,;v)-z{\„ $b`8"BH~1x?mI*+oFVa?/Z2r1@u; vG ^鏷*HǺ}?1+E- "o}[p81 ?cѷ~Mg9^ |Y#Tυ?Tt?Р ?*f> Bwf lAy U?sV&n5/LYehH>Gf⏿?~7u[-PmP7n8-/**: a-3{ձK,ya @Ea3fK< 74aPL:}7EQk8|fb?~X>A*"kC`۟2mwyL1/o0'f tcJ~O n~B#@hAOLGWqz?pB?QM#k ?2(;x_&" h[3OO(}E_?fHO;]|s0z25552f-AFgcv|ODVF#C`$_ kvExoQ>X[69SO=?X Y3D/01'%Fzv Dt?Xr__DX_ ?0ѿ%Zc1Юm_K?Vp'3C1(fX,Yc|ݟ0[חW7}cL>}?Ac?챘̕+Wn}yM42OzkD'"f3ShߘfԬ?hllԊc}JDV`."P߬戻?1 юA$&O@ 1/T3Ma];L|LE2%n&DF./S*#ZbX|2FP}f >ώRV 9䇍k0~0H3g0Jv=j9e3>¿YeB1q|3#4iioTi0XG{P%wC$:qQ&*]F`g̾6 |~#P`Gn%b Qm/*!b `2"?}>|0cy\xf1N;]q^@`g>O@hɡ6*=;Y1@6?}+!O 2&0PVYu5`?R)ww`f$Iܓ72%!Ÿ7igDtMGG?`_J[eEFvvvjVlJ~z*w3c7/ 03b<#n`_ot3Ԗ ˇ95ao胔?@b?RzL>aտ̟?wygXEyrC8љED 1DUScyfM0~c?R0FVRz=%C)$.Sfw9裇ʡ3\T t?JIto>G;U F0B#@'XԚQچL>k[b/Wښ^ר vZ-6IGO,X$`e$C}?kcϖ-[!?f?M rGD^Ei HMD\D;@V?#F`S$ ?gC$̔j#Mt_h sS@H80NgnZ2{lsУW;i~~Y'-@U?6o޼?o%Qa !즪(kQjE^>h{LCkW]{^4Q.G hiTCb?W'V#7*xt*aYwsN,m27p>G/K?o h!<"G@b?zǢ"}ٳo[|9*,Ͷ52yYG@IUEw(5k3[;0y  8d+m8MMMZYߏ>?(Q_+"u뮻e0i=4 /TGZK~4)>XGx|/3hO<ĭ .(Ί3~vBHe|L¡ ]c4&/++E(ӧCA?0vQ3Ж?3#?/BHf y@Du&"}O니=XOEvc?CwDUNcO@q"L<k~}/k?@n?<0+T7'MS@4dTd}O)+VhU-|!Y9DȮX2m7|u*@'Y?i!Y3P鯷sf)!ɕF?!*31c-Vn%ߣBH AD d18[@?~W7U\9zQu !$(L} }}DGbE֯_d^^k?3g2O@VF Kيu (K&>⏴Y" Ǣ%۱uEW^y6?h?o !$%7B7}ʕ+TcommV臹\Oqp"jy`1OJYH!BlrDVFh=ĦI;ӧD*Tk \XCO叩BHP=6!k{`-b 4GAY}Џ]?n?1N͢74tDsn%]wk P~3/̆+30wrh86g&IͫAv-ccY;V~b R{SWΜ9Yf-fd#`' }޷BM\t36#5S^~aÆI]]ۉ  G1W?oJv ~Rq? !۷/#L#+=1sG*(ྠ׉S~Wc~Cvsj̢}BHPvݙ00(CĿ|r>bocc#g_uU3Fz U? sb;ŋv{7?$ =i!^Ts wͱ.|Hc?fCJ G~x0YNK|Wܣ5K@'\nHuSB:֏5AsU}j|SM.??% !#pb tK ۷oׄ*Tר;H0KENXl<ߩ"G E4dZbmN*i~lǮ~.~X7|Cq,\5>ٿ8*wDŽE4%vQd@j9l#͝:ĉb?L8ϟ? J?YYG@5*=bgO%O{# ~hF3m Rf!窯)Ԑn\QϢ?BA @&: JQ鏝( 5#J|384>]yrpȏN6a !Koޛ[LC"1B;tZ^!"(t= /,CBhp4eǁ ,]ݎ!8w슛n zo\d 6Zgm~FTSi!9bVLe ǎ~cb~`kj_ք$7Iq" x,U~O& zP:?qx!a+ Ԩ Cki9X#ƳI_uF $ xvENg@Æ RSSC#ׅϣv&q_\"Sķf? dY#&7]vkv}!~q@_ TbV^=_߽sF1NGm"~#ON? !$@LnqS C 1u)LCI/!Ǡ~_s̹{S5;G HͲFo1 Q p+`&h* Ґɩ? !gq))[-SV':4D = ⏏A9R \7fJ?RuV ~|ս%{FvBÒWo1U~ A?KVV?~s#S#TYf=>{i~fsD'ASi!4 7g&790j@?Rfo'AZwXG袏I&DV˝jYW3wbG PD?Mw,._[C+j^ z]S7Ckު&pwa>f[ZBBboQլDrqZ&B?U~;|]ݡmkoSi!n>zϷ, @0BЯ%_c4'h"yc{SlѼy^1c; ?X rd;_? !ħi:|2\,Àn ׆@d[يP˗^]`faO, Si!4@⡉*ۄIh DdqO| ~T֭[z*<'fۉUDjG(4e {TSNZ}!^K/~g̙oXb:/Y [ (4DNfqgy&h~Oj†O?c-)n;(B7~%c'N/!I: ޣ((=TE>34}TWE-[/[^xaUȡ"~'~? !$ m L:*9O?KXP+NXN6 ڕko.8N|*oV#v|}*}ߨ*oRk=6y&6}7ѿ]V n* X/$~ۂ$`$N10 f_LČ>q}z[ifѿYzޭ ;cb烝S} B`40Y$"IG7q_[}|}$~,f9'Swc쾇%BH~~#j"1/02K3 6cRv 0.8z ? ! 'Ѕm$ d8 1F-{SBB0,&os`AקopbMoUW"NBH|>87|n?5Uw e7n|F4 m@=f"qwtVt2.S !$mC\Fَsi3ۉ=?p!$U+}QW~1"| ? !Dl h?մTSpc>(43;Sz6ZX s<K &|ֿlفtDOh!gc{~>Uw[`%4<Brj2!Nis's"6B@!!nM$4F?݌@:Q{}<şBHZTm4h?S&~) #4Bwŧg0QΤS !7J4sLWL98EBqod^ҍ3YG'4@g"Yٸųq !~ V|,!BBy=-E !%A'C#߯(P{ŝB!B!B!B!xXIENDB`././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32@2x.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000000456714776170045033232 0ustar runnerdockerPNG  IHDR@@iq >IDATx[ PTic Ē4N&1mC8ڦbudb@ BVѶ1h:iLkJ@ 5K~ sν3;,{}u`3 f0`ތT & sg10?c] MdX43 ?Et)>79t߫Yol gV?6B "‡@os^bxA0g+1zKaj23벷޲hIi8G'G՟Kz!~yh;:HYp$ D>(;Hϫ8Xtl{.ٟG69,G..N6(&%t'[B(fذb E^˶,}Z篘prO:muosnQ=ndl.=ˬrd۾ 9E!c6LP5pfb),#1(p"` 5I]K.{) 拊 cܷ)/W1R)tc>ZkkkȸѫW8ti<5t#m;?rG1馡 k"߆/tyL{1{R5ocvd]ě!2ݍ& F^QQPvv6ZXXlo3Zam2gW2f6;t&]~***3']* hTFF`tvpmP'"cTɫ^b)33(::Z`ϼQ}# OK KX t⁖7n&{x_<[]]M===q󝝝MtዌO@ ZK/)))Ig{{{H01/_n8=Otz$-け:A>syϋ@׮],V)AP b*}.C^ESyFRqZc^ƅ۷J릦&jnn5A/CX)29ık׺2>K \l,jw'4KG1Aq%r1bB-ːusg%X555(i"""b lٲAct/>J2ޢ*..J)!(i B,x܇ W;ޗ4Q ?JNNB BoĘi,kѓx~:%c-m 3 >>>ŹRՆ %< Dh#MJKKM\ԩSY}NH<9L ?111.Z^QӍ70BèVwN750/f3ūWe5Qxr QAAtwAtȑ~b>$LXvDea “" ^xx8eddR$//OB~~ hLMMs3)'-wڵ^QbǶRNo4:@NN$\ڿj*7xܷAvܹ ر+9B1` KM6yN^`bB&<u떄ܼyB ;;;b^As[[['Q 1o]7o>Z"E.YU1h!^b9d!?gee+_YTB^<~c,GpCT`r{xx|lٲ_g=W]'B ne={{㮮8𹝝ݱ5kIRme~Ͱ>ͫ<} {M#/;\/P^nɉ':pbݜ./ʈ5Bsb~U\'hAIENDB`././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000000074714776170045033226 0ustar runnerdockerPNG  IHDR(-SPLTEDUcnŹARARt~ARBSL\N]O_P_P`\j]lcocqdrkx{܇|܈Ƒʩ̮ɿ\tRNS,׆P)M!X?O&BU$ So$qF &7"ۼ0WE=Gӌ_# FN#~Xl񏘼/VG:% BH{E[A ('oG>V+'?}*.$Cwac`"Io04P+'>JI! K.YO+ əG,ĿYg_YZ_}^NB@}4fb0$_p<ʲѕrB-ҷF*fuS_g]QPE' @ [!'_`'BS{D|VxXD x_d 'YX?!'e"aU_g|gcI!)gtOm@M @p_7"BLr9şB$}X$RBHf3V7 XQP`q?BH ;95P !$3f& WQ !$jm& şBz~{; aO!WW/B'k?u4B @(#|?!{4B!yP !gh(xi(B?!^N@(BhşB şO!O'B@BS !P !?!B@'Bh(B şBB!4B!O!P !?!O!O'B@BS !P)BhB @+(Bh!@KzgB!46QWR !;7şB @x*?!b?!|(ѿg(GGU2xTKyAe$)>vD[wbmhz]JcOn=MԳBE7X(j)1e2AJGʨ~2()(9tźeSҹM*;6˪}{K"d8`&E!\ RQUSeZTT>^fr زڑHOSEy2|v|yǐ%xoG/B"1(U _@cFPF.?Ѧj ݷ@^󺼿c!?1Pė@07Lx;eSQ<٬ b~nj%,&Q)篯Fu)/?=O4/Y;{?G!HS#!WN8ȱUGjreaR^BHD73PN4/0F7MV4xǦ鲮cc^^|g,8/>B?}#3 @|}7-{AFÎU}=[v5d y&q\i?%y1R_Su 8^^g. dt#b7xrK_o5IKʍ'6gd'@34nZ?ɬ@!0|z͵j/}([ W39{7F L?Q_&_# uBh(_c 9'ɟ'^%CbdZ$p2Zh$BhlZir rO<ۉ5!ǪBKLB̀ 9쁧4\r Z,0 lx !4~Cѧ!'U+?CoT @&4Ax̤1C?2d/F7.@dn}w4Fk,#(o% FCȑ숿"  !|_~c:\9^f @^fHR1I.U^sY2n%A)j+. ]KU-U)p _E  '?Z9i_/wUyCc9}.[gȩ*"ɩX/<%ս/f  `T}{Ŀ Uں_v\}\S4 0@h9?נ<$*fQm3We-9}._[( DGز9}K[W_.KZW:j_+,_q*Rp kK !圞O>kB_Z[$˃ ʽ !E?2g=|~)$pպ[r:CΑ  ĄH1W7mn3l?Krr~ 1L|fh sglNν{\ꏁ*K%i?k./En-d_]]33пKՎ-VBOY~}YAXhBRQQP~`nԮT\#ULƖ?`F]ya >ȤyAA( \ iqRA yyQz0A{u ąqbcO91#ʾfYںsY9 ϙP>FX9/ M*ϋ8?7} ВR]ԟ>1˽5;6&l[Pq,9 4{qw#o<|,/| k ro\زކ-==߄1OA0+VM`!c==ߞ&Nsuj@g+-gz["xm·,v)Fm==ߘ:^9xJm^ZYV2=B@<(R(zz xc`/za  "޽lݲNԹ2[B@b;1qFO7LޏB@#M·(k>oBR<6;i\& 0֣<-CuIWsUub8廹kDg=f?_mq6ǢBhHZxk'/Kvx\49< WEWx%U! e+ !4$`s 4u{k*y  aA@^mZzZy]qf{#6[BhH*FZvXfY14p OBhHȩ.2-Q3g<ѷy^^2mHB m"X;/zC+ J34_Oןuu`+ @oO0#B@BJI$" (mE B/.cv40oo*5kQ̋N +^Gyx=k'^;B@BL 0K0g 03B@Biޘ&P !4$ @= ׎mEȵ d03KۗK|ï  EOEUR(`f kH۵ފr))(w !H߄8&|u0@_?bq@,}?B@\k7 XIcO/:!ވ[=z_|6q];== M@H~EXK->7~~_a qɎ]oX^t -ËN|m/uuu.]+۷o$ķd/KhE'$'(ޭ( q:0u;ӄΐ}x/"GN?{נo۷n 2fNg҂~ʳ&GL>^wun#FHkRiKKK'= ޼v$$sHjv`j$^t&5R6$E3දI~T7`i?3^/K0 ?yQ;㏿%{뭷> ,L3$uVhT{v3jN۟O&^ As?3at'5 U/SLib?4%D}|C2XoeZ}g眨݌W+:ȤsZh @MAāezſK.93MyyyF :::tMܩI-_9^^>ȷף%E߬]IQ[k:'MTwo-[zſOto HF @my_|$T&@@]UuW_}ډ#E(znVcKfHFT&{QZ 6@wϋOi8Ha?ЅTzh{ӟ7o~g֬YK`߿a ɀU^kzb/Ұĥ#z~޿kؽtɊu᯺ a駟~_YY٤l?Y57?4$#( ο~=o! :{=z=*E7 '7 {4?S|ߜSSSs77nܹsNvmؔUpU' Uu\VqN*۳/iUZ_v͛A0?/6O3vX~=zEj_OTG}19tM@K$+Y=/8"?|n@x @,gOx&0jUZYUT)֢JbСƎ{i*IEEEOtݺuzF%I՜ )/DU)ES:͋eϋu991ra7W#eY9Gea T&Ɣ @=jx5몭9sUT„ ҿimMmR{T.7z'?'ҤRį5fT//PZ'wmy#?28S}t@]3,ErYͲVkو]McJe R\P,RVX*%@ST}?_BxҼmH~c.jo ᯫ˥1U}-օv}'I&yj_sftyWrպUm@^G!$xd>U;>@];*x=2iGI_7f P@/%ŗ^zi'tҷU>%GԨQ2dꒅ k@Ѩ56?Ik d?iY"*yL(wt#*z}|S(G^zsmy(jQCjC 2mvxRG1⋏?3[YY9.]CVC^QÂ*ihhEٛO?}?kb(gd>!&L@ -_tVUj8_<{?T=~j*Ň24@1N>䯩51~k.Ybwl٫E*(UH>בֿCߏ??*U'd!j^$KZWԊIx>K4q}eE.c/۠9sg圁UQ'<=A.g(o U>}\׫?]lٲE֬Y~SS⏚܎*T*KunѷiHָg#rÄ9Al/U /ZмP6tltSQc5Fv/'>h,jYuPNJr\RU-yZaD|}>Q_zlݺU{۶mZ @AA7N3 vgw;`_eo  ٍ0<3NF:f:^XܲL.,jAז IUxD_sfj.E @ Cwbertar:JRjg?-⇨߽{߾}9RԾ1yd PgN=+-[ҥKӍ3@9a@QeTNXfvmm;K7@Tڹpo*9к%5?H rh?_AKuߑf Zd9}S[0`}<-YDZZZ?|=JKKE WZS ~[s Y-xl)pcFkG>1{ZGyݜfp PP[Y")2NWKJ?~K,D:+T j9a[p3@C۞SMI#Ckp~'w̑/ <-%4LųS˱mSeSkX^gU^:;;?#Fh4hL8Oq`َNfdU}ͺ[Wl=s~Zng~OTZC` @MO9\6IJcCkkk5~5Q০Iss]V[k>28`e*^Qsc$}eO@|pMe5gʕZ?LT#1i$Sd7Oe;6iܼٜN܁v?vn4]:BF4G\h5?!{@j"xaPݏaf[3A0==,9x _rɄ 9ro?+:V(7MRiA=i*MVY+mmmL?1FX3'vo^? [~E / #flZ} ~j< B3"8lP?AEGMQ]Ӫۀ@#҇Ef?Z~T &8ZB@޽{c=7-㙈iHNhn\5]w`ݛG.\V?CQ dJxm>IAӛ.Hc}}'J}Uz?#1) -{[-iH[6ޭwYj~?^ 󺚉݆ۥ5Ƌ_i5'#)/jnn;)}#fd;! GI{z?Æ i޶2={r߳w&KZVKU]$^ sm~Azgڜ9WkU ӲR-'KT^q/3[^#/4"-Zc⏷n*G ^Z!g$? :\0BOea/Т:sdz2ks2Mm!|| e:6iִW6׫Fm 5R @xT@~…ZTTTh8J#PHhU>!2iXZTuoz#/ec^ (RS+&qɱUG!vs2[:6k^OW &v6z*"o>F*v`2"Àq8JC^KJaPy%Id%ߟA .ޣ0)N8`%}ïmϿ`j~iObK0pm12dE0F{;Ⱦ -ٵ[4%%[;whYݍ(QȞaA𱾟h??5΋SOF- 5 .v#*Tj_a2M^,/KUa@htǻ]Y!*;pVX7Q'h}!a&,_t_ Zo~2.uf @"3 rGK$,lY*?,/>ClmjĆ?*$BW[,7^fe/>"o'[fT/YD d?< ] ob='kk0htڀ̚jD xQlEqBCJc^m}cOb D߾PG?ǿJ}#;Te nP(yځ 8QN9OeMnu%/Sc;QħƍgHChRmSF@,XY B?Sv3J[ﺾYwp <{|Q;P=rvpRxO*mR}DMƣ y՛WQBCGğ*~' Տb?c Ņ|t+@KFM{/FFѽ!#sc@QZƗ7AUpr];e `ǡ۟%OKCHU';FhCzDi}>gjB_:_mvoܸqZ?Qxinj9 0p8jO@B ,DjԲAm05L[Svj*Ԋ SvT{Ϸ%XR|Ïc]FYܺ\X\=d yMM!vǪ~E؀t.RJ1io GLn>s=&DFS҉iq$Ƒl AK+MTj^]RXvD|?>~"---b]+ƒIz? 2&M:$[ILk׮}S7Yb?7cf?o[#l/Rl  T|T?*kE{J>"՟{m Pyk3Q:?L o̓f-?+? !9s_ozG>7䜜|I^R/}ڶ P/RQ~6}oL(fo%"d # x~K[m6Ex!húȑ# Jr#hKɨ"ď^{UbYd cnx8:'[b"fNJ+/SS >Ga*]-,ܵ!2,(T>@wxfG:#Z> p sj?~hàd<|QnO& f`*KMPP-e= !`Η쁧˔99?n__FP(;c&bU}z>y/h|&X_G駟իo嫿Me*W;ϑC['َi!hMZ<j.]q\hD$Гb1On¯[BQow-z,j"d6n8_&,om|uȹ99aK z9o} 9m4|HgWԾEZ)5kp`pݼH=j׿{cֿĩ7rז0?\FTER|rmF_Рҿ6kqH0o$wl^;krU#yMC4s:'&H~GQOe'L&WoUM? !>Ex7oK:)9We?Xw(:9e b_6k?_iq`#??Qτ!??jG9M1yPwl'w̑TZa[ Dg[a]>hCюL)*sb/RaoODcxF(Ҭ*}71🬚Bv <^24' HLZ?Ub>>|SQt>GO?h=ӆ;a?#TKͲjՎS өF޾iz_)_}4`R} /ϧLASl|m"x/1_k?ذa=FY;pSy\c͢ѭ8Oe3#خݽ crrd|y|ڶת(^rdJUH=#G1J7[עkS}O}} :TG_&L?] (N4bڵoi8/d]i t]u{vh:>Kt7aLNʨH]̇33;0hD?RȰ$Vlꩧwci 8[:ɣJk{Nyf̮5wJcǩ}\=B߭脭8/~*ZquLz& &Uy歖|9ȶrFgtDV en⚌Um}g;UF O>s>@Q!EEb?-^m|vMݻ5ч#.P"2rȔ~6/ g鏚cШ&}y: $n=)-Ǐiu_w*3v<#;vFYjm3}67h [N?| *!uuuZ z *1؈ UG_ڿo2fxV۰g\Y'O|Af|N{Z6UN{Ÿ3h"j^~XcCLz6 U2_{?FO2*ƻ妉7ҷkf6M0`5~DN+̙O87qDm{p_. ͢bG[U,ڧ $,jYm}Zis{ ֛[&aYv@6?c&ODc}Rgj̢}bO>>*fßM $ܱy\}lV>;lXQa.]ԾW q!gڸ\,`f+ Ąq PS ??>fw 섟BHji&uX_'<Ȍ|zQ{aPJݦsmG 5(w3P"&]C;ځH*~nHTCa K-L׆kfѿjo\5s̅ҷ?*K@ ~r^;dž2Lga#鋴?"f#Go6?[ Fo[n7&>C@7VӤQg,Tm~hDXE,WۧOn f!:Mt~֜ş?7GԏA?hO0ADɕTgQci!sOi>Pm+VЊ0c~f?XGل T%{瞗DGjh!@;k[+g>|pFY>F>z2.ѾX~Iw+~1~c*l_D4rB2g KQi>㯅 b/vMZ:.Xg8eбv)19i!ZNl>kpS7M|ܬ͛J>za Ⱥ J(ccY ˪qkB|ϙj؏]_MM3x_oǰޏ6?Ҝ {6 Վ>`|9+jet˯)1pW[jGE/!@wPfoK.*2u4ܡn7v"~S=r*PhX鏙n x≧- ů? !$L'C 3"~DXG3G?sq0=Uw俵l]]熬l}g3ECaw?}]L.gg-3&7Ȁh˯I@s%9O|H?_oCʿ2=C0|/CZ8 !$9ϣSgGDiT lT[D' pO !sP?ۺh[ o ܬE?:mŭ00Xo*gY;ci!֩GH<7#Տ7b }?r~38<]V̙3qٿ寛M}K@g&$TE+sq3w="c`yEˠ=Uf ѿ~_G4 !m͆A|sևJ2(>wRC:d=xfDGT+ xwx/s?m a?ּ?υ`vٳg/3~O=02kV~?1O|xƍZ?ި*D6H~f_ jKz͖Xc ) xq)EL;G A J\E~2!feϚ5+97k ?fĝx3|aၴt:#7!*oݺuZԫWc#%?̀u [ߞ@͎(o˄xzgc=nLZ_׷ڿ٫sڌ4TA-$]u{10A\?7!vK)cǎ~/uA6jǿGе@nO,~,;v)-z{\„ $b`8"BH~1x?mI*+oFVa?/Z2r1@u; vG ^鏷*HǺ}?1+E- "o}[p81 ?cѷ~Mg9^ |Y#Tυ?Tt?Р ?*f> Bwf lAy U?sV&n5/LYehH>Gf⏿?~7u[-PmP7n8-/**: a-3{ձK,ya @Ea3fK< 74aPL:}7EQk8|fb?~X>A*"kC`۟2mwyL1/o0'f tcJ~O n~B#@hAOLGWqz?pB?QM#k ?2(;x_&" h[3OO(}E_?fHO;]|s0z25552f-AFgcv|ODVF#C`$_ kvExoQ>X[69SO=?X Y3D/01'%Fzv Dt?Xr__DX_ ?0ѿ%Zc1Юm_K?Vp'3C1(fX,Yc|ݟ0[חW7}cL>}?Ac?챘̕+Wn}yM42OzkD'"f3ShߘfԬ?hllԊc}JDV`."P߬戻?1 юA$&O@ 1/T3Ma];L|LE2%n&DF./S*#ZbX|2FP}f >ώRV 9䇍k0~0H3g0Jv=j9e3>¿YeB1q|3#4iioTi0XG{P%wC$:qQ&*]F`g̾6 |~#P`Gn%b Qm/*!b `2"?}>|0cy\xf1N;]q^@`g>O@hɡ6*=;Y1@6?}+!O 2&0PVYu5`?R)ww`f$Iܓ72%!Ÿ7igDtMGG?`_J[eEFvvvjVlJ~z*w3c7/ 03b<#n`_ot3Ԗ ˇ95ao胔?@b?RzL>aտ̟?wygXEyrC8љED 1DUScyfM0~c?R0FVRz=%C)$.Sfw9裇ʡ3\T t?JIto>G;U F0B#@'XԚQچL>k[b/Wښ^ר vZ-6IGO,X$`e$C}?kcϖ-[!?f?M rGD^Ei HMD\D;@V?#F`S$ ?gC$̔j#Mt_h sS@H80NgnZ2{lsУW;i~~Y'-@U?6o޼?o%Qa !즪(kQjE^>h{LCkW]{^4Q.G hiTCb?W'V#7*xt*aYwsN,m27p>G/K?o h!<"G@b?zǢ"}ٳo[|9*,Ͷ52yYG@IUEw(5k3[;0y  8d+m8MMMZYߏ>?(Q_+"u뮻e0i=4 /TGZK~4)>XGx|/3hO<ĭ .(Ί3~vBHe|L¡ ]c4&/++E(ӧCA?0vQ3Ж?3#?/BHf y@Du&"}O니=XOEvc?CwDUNcO@q"L<k~}/k?@n?<0+T7'MS@4dTd}O)+VhU-|!Y9DȮX2m7|u*@'Y?i!Y3P鯷sf)!ɕF?!*31c-Vn%ߣBH AD d18[@?~W7U\9zQu !$(L} }}DGbE֯_d^^k?3g2O@VF Kيu (K&>⏴Y" Ǣ%۱uEW^y6?h?o !$%7B7}ʕ+TcommV臹\Oqp"jy`1OJYH!BlrDVFh=ĦI;ӧD*Tk \XCO叩BHP=6!k{`-b 4GAY}Џ]?n?1N͢74tDsn%]wk P~3/̆+30wrh86g&IͫAv-ccY;V~b R{SWΜ9Yf-fd#`' }޷BM\t36#5S^~aÆI]]ۉ  G1W?oJv ~Rq? !۷/#L#+=1sG*(ྠ׉S~Wc~Cvsj̢}BHPvݙ00(CĿ|r>bocc#g_uU3Fz U? sb;ŋv{7?$ =i!^Ts wͱ.|Hc?fCJ G~x0YNK|Wܣ5K@'\nHuSB:֏5AsU}j|SM.??% !#pb tK ۷oׄ*Tר;H0KENXl<ߩ"G E4dZbmN*i~lǮ~.~X7|Cq,\5>ٿ8*wDŽE4%vQd@j9l#͝:ĉb?L8ϟ? J?YYG@5*=bgO%O{# ~hF3m Rf!窯)Ԑn\QϢ?BA @&: JQ鏝( 5#J|384>]yrpȏN6a !Koޛ[LC"1B;tZ^!"(t= /,CBhp4eǁ ,]ݎ!8w슛n zo\d 6Zgm~FTSi!9bVLe ǎ~cb~`kj_ք$7Iq" x,U~O& zP:?qx!a+ Ԩ Cki9X#ƳI_uF $ xvENg@Æ RSSC#ׅϣv&q_\"Sķf? dY#&7]vkv}!~q@_ TbV^=_߽sF1NGm"~#ON? !$@LnqS C 1u)LCI/!Ǡ~_s̹{S5;G HͲFo1 Q p+`&h* Ґɩ? !gq))[-SV':4D = ⏏A9R \7fJ?RuV ~|ս%{FvBÒWo1U~ A?KVV?~s#S#TYf=>{i~fsD'ASi!4 7g&790j@?Rfo'AZwXG袏I&DV˝jYW3wbG PD?Mw,._[C+j^ z]S7Ckު&pwa>f[ZBBboQլDrqZ&B?U~;|]ݡmkoSi!n>zϷ, @0BЯ%_c4'h"yc{SlѼy^1c; ?X rd;_? !ħi:|2\,Àn ׆@d[يP˗^]`faO, Si!4@⡉*ۄIh DdqO| ~T֭[z*<'fۉUDjG(4e {TSNZ}!^K/~g̙oXb:/Y [ (4DNfqgy&h~Oj†O?c-)n;(B7~%c'N/!I: ޣ((=TE>34}TWE-[/[^xaUȡ"~'~? !$ m L:*9O?KXP+NXN6 ڕko.8N|*oV#v|}*}ߨ*oRk=6y&6}7ѿ]V n* X/$~ۂ$`$N10 f_LČ>q}z[ifѿYzޭ ;cb烝S} B`40Y$"IG7q_[}|}$~,f9'Swc쾇%BH~~#j"1/02K3 6cRv 0.8z ? ! 'Ѕm$ d8 1F-{SBB0,&os`AקopbMoUW"NBH|>87|n?5Uw e7n|F4 m@=f"qwtVt2.S !$mC\Fَsi3ۉ=?p!$U+}QW~1"| ? !Dl h?մTSpc>(43;Sz6ZX s<K &|ֿlفtDOh!gc{~>Uw[`%4<Brj2!Nis's"6B@!!nM$4F?݌@:Q{}<şBHZTm4h?S&~) #4Bwŧg0QΤS !7J4sLWL98EBqod^ҍ3YG'4@g"Yٸųq !~ V|,!BBy=-E !%A'C#߯(P{ŝB!B!B!B!xXIENDB`././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512@2x.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000017413014776170045033224 0ustar runnerdockerPNG  IHDR+IDATxxdW}73w{ƍpGsBB  ZlbBLy )`=b{YlߕV];kiF̣͜hսsC*gF.@g`" : ( ($S2F6a"{@pAhס9@ Msן2 X  @rM{(Λ(D:r^̲ /j^Uʯ\lS#8@^[~On^'澘*wUZC5Tk^ jBx-ըUgy/h}FA@^C(s\_*g@Ti_p@*=G ~>@3-gy5~G5CTzf0U@|͔{Bځ@-_S{tEy+Z*@j[KL_+&(<Ɋl!oMno-o. +Ivm L"jrβ -s{mɭ/]ZPѽ =h"fe>T#POXC;߶Yusa@PFQc? LW h⿒! ׁ=DT9(5쿜(d?:/k?5 &t%!@ _W_⿜q qo:45 !Tg h!{?UPoK(dWs*AQ3WߨZB)!fQ@}?OԬ<!L=%5 @++ Wh"((L7(O~s&PQ)$o!?3kp; ]([{9 @8 G[p>s%@S.W=r&N.'(LwlxtD?K?l$iυ*.d?T@'*g?}j P+T?e~d!t4}@_^R^j /-LӷvIZ4Xy!L?` 3+{Lõ+h y9{>jS>Fԉ(rSC>q5?ML̤.@SS˽R&rBɞ@#+sy {N%!@nh݇)hT_wy*@u˟O%å!^$p&xse#?4P*-P@\( Sn?Ф!LϤ0.Wk }( (޹2& =Uq_:*^P+Fp @s3sq]/?4a_|&W@(Y] (``}\vſx2ޗGP#@_ oG @_ @#?WP+(?ſ@?ſ@_ @WWP+((WP+((@W P+({"(s W P+d/= "/se0Fߢd/؟@@3] TZBesͩ.h>C,g}Whp 7sf2?P⿜K{Z*_h~h?̠^5 0QWKgw֝}^M$\k{tth+=؎G紐 slgǝl LFTR{??dJ>Z%mⶅai%ɭ7zZ.ss{$KÖѭaydk8%:m@@3St??d_޾4n_Vu캥: ߱:Zbz[{.,xdxcX?pxphm{OF ;(M;EYûw>8uPXپ<>HÂ=AG}|8ppε~ܔPϢܯM7+ڿpc:Á:Vo,<ө{€v~wsqF rӄn-h>{GwNB8YtڞNGK |ǯon mqZ@,$S/q[^[GK{89)OR8d 9nh}ՎOoq/à+D{M>lMn#mlm| |&Se ]]1gQ&g UxN% X`tW0 ZzsY 0@D Zr-a0fG(QOd  u`x(ӆzm u+U}$3xBwrtA,gs@<~œ8OG_/O?oa0jДZrI```V)5AK?ܹ+/N.xR|ºv Miw +X@[.9QW(i8Gt>z(vhӭ?MXغ Wlgа:ZßpB1ѕh"]0'}=‚\p?!\{UƓ>zÑ݇4IH@ sr%>zJH/CTdyG\[|At@uA)LUOu_䓕_ ~β4_8>,nuCP/UOrW7v~IDG$^yau{! )4]9zYr;=t`G蜳Ig2eAwsP/Pû8oªvQ:z1~yXҶΠ:2VW{sSܟ5~'hjG&P򰷇Ύ:KF#,P"]P`?T@s|=d|WXվΠA: +K 쿡{ =Н3ȔIwGӔSc Oym.]-v}Y2mw@uAԊyd^z]wngi4wfAs11@rsLI?{ϡo =yv$H׆|.og0G3 r/ћO/o_jg^Nr̎`: @&Z;athg$+/#S=!z?ɽ0~a8s0[S)gg0\8 @@~ J:Uk^jG@z=Uq ԥP2;.;u.:j" j^_\mg \Y ϰ#CT@hw9eg+^`Lru^-3*-s~V{^iGPn E}-ߥ )ޘbig@pᒧ}"\3A$ᄞcWӰ}A:!s~-'[_[ceՆ70\./c|#3OWpqwmgPN. z`|UL Ic0=6o F67 mְc/o;HE?;ˇdړZeYemKgۊeQ{{|c m@U U%ĞcY7>ܾp}ᇊgka0n/]R`&uP8КTןí? c; aU(si_*Iw{mM;8x_=XGK{8p̼#± 'S\ўYU7\vUb*@^ⶅv,lnm7k-/dúg.xbr;%pqf뛾Π*LPvnMd؜+mM*ܞlczԃZ\?EO->;u wΠ*\@P?_drFސNŎl{$Y-]3d /yie:eᬅ'`r9So]@LN_prlz̗ؔ1w 1\ .^j;f(* \x^xJ _Y x#ܪK-3 uM):Ў(!]_b†(+THg)'KּıVM%f) fMxpa؀R%B_IOÛB:BǼpCGK$'JvBF& {߳#slgkknkg~;FxÝS,n[v3 ̅ɥVw#vmׇn3u /G~jg ]-v3$L|JA2ܘ] [_~!;o}C #3+:3/(Q;kiKe];2|OJCJ/ Fg~\bHw^7gg~|g «npL4{̠`/;"}ppɭo,OcypnK9 Vs"gӳ˯G *;~wsfAe=cPS{l_^x[4LJ›zwSuG]3 >^s[Md@xع6۟uۗ:*.XLn--#[Mo? adS:pg,y  q3CokO;^zAФQⴀyƒslFvenW_i6͒t )'8(*,XN=&s _@$G~f2 a 'S<<>u 2#pګ2ն5|gkЈ\İmQ|*=pƏԽµ?mpS5r_pl!];hxd a]-df{ p#q+L])~G3u]OZxjhi%[gon _ OL" Þ3}cFϘL P&5NP#@6S矔=ydkqGVT07Z`ЖkĶn㑯i=\Л~[||r=GKFwOt2%;׺Z:i<;ohɵy-SJiOu$ϭwW@dSm =vrxɪD;Vú(iO.޲jn-5pOۙhEcF kBoNS\ xLȒt݇D~I}sgfd(5)'W\0oG581~c46LlmfJyGv { [o}db7fmpt` @dĒEaM3 gvX6aO` "+G-?^{@f cڰnhƦ,컩xňY3f 6|p"m<*Ȃ%m2ܨ 8f9ZCC 2 89ܙLJ,Ha$m<0 UG;3{#a MmG,354> #~lg%v yÏ#[`@ey[0+ 9Ql(`nF<7~GWb=6ٙF a0)'30>FK\ot7Ao4Y;~ަdI:ڤ-[n @&}y P5u#LͥE҆Mn_A!@6lX7Xj7id 6-i[Zr# Ҷq#D<$' @4Em 7jd6-j]@4Й.ʬ@ḏ5#@4wwa M}æ+GjdfS@4oy~kFСoԂlD@#_ @4q>52u> VTӶ9@S@ݏxz=Qo6#TMO~д@kv40wG}}c;52u^ V-5 gXF@{xGkdh>_W3+$M"{h Ύ|r&/ b՟/khj`Бo}ܹ @bw/R  fp|H#S"h4]-q@]gKF|vTY#[42%(cՑ3@uc0f^zrx|83@3vsF@-< C "}&/泰4/!#hF 91!:Mh#pU_.fثL>C "}c@m=k*ѱg @4Ko-1_"}b '#otH| " EqբCK"kN?Y@)u2WEr5x&} *c :0x5@GPFbu2WǞ5@Ƈ.,Ȝ3@=0^ 7F40f3T;h lb?ҩmhmP Gt42s;I#6^|@#/hivbz8اwI2@#m "@ xۗn>LЄ ɿGاIž|F:#52fBFPg"cO#hFO 1q4Z3@zz=N}chZ"λuF{#~ءZ6mQoߢZod?%W @g1WI_@l-@ce&E<ƓCok O>`&xrn(a@}E PnMeC]ȧ@ąC 'sz ‚V>bq(@*$G~VoQB M]6WM-Qo6##)jYi} 8YQU" ?7wJ ~ym{jW3-Ia`MXNewO|~ni+j G ӱq?)sux~zk[bż겮O콟$jlz-'h9آPWgsU/zыM'%ge˖\c? ۖidȅM2\;_Ww~;v|鵯}~Gh_m C[MQ?x{c9暖Ba?LJcgs6D%ų]#&G4 P|rG>ߛîaÆ knO.I jb0RvZuT@XȋR+In- |3$[ccc}`rwxb_j[V3G&C-`lZcmK޾="-Ň=Ͼpw?i9+oPSoz@GľVQi \Y{ w^|_X // s@Mz8[ٱ\#Sq_i_ϙϕܽgZЇ>ʓO>ijP7pe?5pccCClF`.j|,LRuQ 򖷼oѢE77lٲ_";Z@=5425}E۶hn߳|??8G!'LKog?!LX@um Cw+0l? ]ײggZ.{Z2d9֭׾~!اlPfidduJ>/݉+Usu]W\qî'\W+]k`|0"h3@!u+g[Z̯'?GuY?}xTo|ڵ;cssSF5#".VT]Rk0l +Tߓ}xk^s9mmmO }K/ƄS:wi1tzs_WR϶/u9]*/:#ޙ. #wߝ?n@Uzu{P8sM `nj~쾵}ы7{ſ[nܸ_>vP PHZ\KXӱ:;F44B Jj{Lk񎗿_xW';_<ߎ뮻؄}7Sڻg5bm0+CGK{g@3?¿rz{c9---=w?|~p 5wຨ-)Vhh꠮Sc)S;#^{=>Xi?44to|"_S*P{GwQkT|m W`"Pf{&g*/}K袋!{馛vݺuᱳ{i?ŽO8LuG Qq ??cn{C]>_im_ I~B"PE> C42Uup䡒5(plll :+SU'xI>]w/7{zPEt' "0Go9kWO J6 J.îMܿ{ @Gh_V\ ]fЮB>vƇ#5tY1;h~"Zvړ=yK;7rlTrٿv]0E}P`ÍʱҠ99!DH/=?~矿K^+,XjlX'/ }O 89+TX{Ji-C%*)KZ_N;mmm]ZpUW}4>&_r{殝k޾#TX;X+ȼ QUOT_߳_Uc'=IV[?xwl _o@bf#}pݾc\[8++WCO#"xf42(ds%g;^x^?sۓ]v]3{v@ݱoiⰲ}yxh͌5=w 5Z-AyK"0)k?%w|ᇿa M? [Tq=G6 Gklݦ1^1$o.u>>/|z{{Ooٲ?8:?Q}Y?p=y }/Kz= zfZ϶n!]_~?5Wc_?]o6;;wN=6( ,zFG_f/K䵷kdV?gT/Uqig߼|o]wݵ5?O@ Y Ovyܫ:V@:0`,@ ƣ޾yn qe /gw>zc``}ׇDo~O=ACS13?cFPI4Dbק+gzK"Y5^{ɜk]~ӟ^m۶Rr~pƂS—7Ʀl'6޶N -@ܡBa_*0{mO?/?}\qJTi_$J#eڢS]a؀gZ]|zh2D@/{BdVuz+/7%s7oCaM/\h֎H9*ml˵S{O 48:mQb5{x8/?O#C\AW,WZ!K[[[y6l7]sgjksۢ߉xC+ECW`X_7G#Cs|=WϞjo)y^Yg>8㌫>>}#9+~st\krsTSRk.NOF7k E,n[!AAaB^(3Pp0IY/y{[¿!.nݺWzWxlA9g |^G 9񫾛\sh'⚮?ntRqc%f%g5ZW>)*?:_< 3nlllĵa߹*LS>0'vW?fޑQoK"`J.:;ms`m5O@# RwJݟ)w~wq!,z_k֬yI.kv~p%g &%̍}O \}hO^xzi.z^ P0  LuFMiQp}K $q`mЇ5_~a |E9~ӫs>ֈꦛnnڵ[cg+Y80M_j5uKK]^=}S7|]8->'mLjJGVuМEaUr S'~?c^4|+Bx\>(4A/0+.xf2L>fGvwxΣ/ vLJ4xb @1h_1_ig:e/{.wtww;omҔJӍ(`Neeh.fYВ϶Rc@WHX RC'>6K O #6l{֒37f5^ #Vw T)Yѿr~r=׿.O|S{{{Ӥ??>::/cNu Fs*nh}ٚˇ.dzu=oy݈7ު.&d~W_ B ڿǙf^sۜ ΖE8^] V^ @K[;[rϹ>,XwϻvфxMIo?3@9o5Jd-߉=K?ecp =C!  bޛwO x5\sΝw޹nʕ?MJJ*ӵv_6{ Ŀ9asPB˶8֔d\'۔^(i8m;djzzX\s %r| *c'uyw<|px7"=h D,lͱ~"YHLϗ}6tf~!9a SOZ!  ,ߎFGYFIII_W_DQQD霺cTByxeM.oU6؇?FAX.~!:nc1*7bg߈ Ֆc_6,^;8477?iӦf9^+KoOw*!`rzRf% 'f-,6tcm83sNMHn{ Rꪫ޽f͚gqYONeU{￯콯*  =[luU^5-NjBVa2 ݛ#*H|~؄#M_*z뭿G?6++k^{̓g-o6/!4lxU9^;Zo8.ߨTUx%GƏq5!ǹ(\XPK]ӗ,YR?o}[O-\Iȍ7޸Vfz"<hxǜ BR9?ۻV\Z*߮7~Wxk?0rtmS#R !QFz>ƽ߽_{/˧kkkvzXU!{ `}2@1O?÷h Tl}~94vyQR8!x?>D}]w؉'"+/ 7ܰN|g w#ST+-c+E_"%O뿧ۉ' =Ih=lLX WW\Vk 7saw9ܐ^oE}78|0|e io+~Bػvnj/Y -7٪(%) mu0{aXmUl D_xG?3̩wq _|,xߟ2?o__@{5l:B ?4s&v?25i;m};lӯMR HHTӜ/҆oW_~$''KfffLT耣^˿s׼K!Uzu-[{vRfˊ̥<⌴TYٶ㾎yD*Lx$ '$6_Ę_˔wKJJaUUU/Q_Ա?񏏊(_(A!Ĕ|¶Ǟ)^#95Dqg8_!bVǛtZ~)E<\w5C?ro~]wuo~_]]-vD9۷H_OڇG!/KDm!s^ ab&Ks+kDp=qO^)Ow?'O<+{IlNV-] .HQ])zv~65퐭}yb3qNh¬o_lٗɗ5riٽ{(iW'es730!Ĕ8pSreglúoɚdѿZ&?$v 2Ha 'G^mǔ[C{dp4Hd$,ydm_钢g4u,纐V2 0@LX ܄׿\Kexj&%&&jY;wh^WFN /?gbZ(W}JeȧK>&rݡ(O Kk_z̝i;9Rm0vkGġ2qa~D{FbOծǒ̄t~Aw៨ 2}褓N:]vdF QfzC1 x xbBSWnK ηZw.1Fߨ\M[yRD"k(66SqYjIIܼg#UP'<&)???_O9+b%/++70+AWW455\;=KOOk-[Qa\<; ??P CiJ\'r귾-E Ɠ}ߤ0mlD7f"`\(*P@NJh^{;ӯTT;vL80+uNk"A2*"޳FV'hH`{J \ i 2-7+orQ@^R\Y@g@D =Q͡CEBXx 8 ]k0-- V/o>ikk<Tdddx|ͥKj?knn{ݼy3Ag wiWj jZ\qd/ek87QPb0  )3<󙙙xSk+p39YYY~"˗/u\ڈ@`A[n 'O@BH|[S9?qOUގA;boF ܼw?-Ui\7ڭHTP@M $ 7dOk.z׻X p1noUb]rrra{ߛ6mBD @ <1q BT\S%UK呮 F A{|RVMbZ$lU a@H,:&_y窌'p._h&>nppPss?n=zT  Y(/}mNzUAm< ;^e.bx '?]'lUUOq|AT6cPr.yNaoBĀ^dĊdw2{rϏ{Pb}2:poll3yz L_1iBH\qgB YƑjw5{Ɗ%ᢋ Ԩt..Dxcp0{3$Q?r29mI=;1~eKJJ #_WW7r@w/-[Ԁq)T?f `7VUY`jl5u5WUe6mǝ]r*?/RZʓ$Њ=˅qvޙ\8$ZNe˪r2IN{Ѕ?DRW~immsW__?y*,YD6@@eת =~pgBH܁?Ug*vƔ>2Z+>AVhfgA$ͣe]c\j,H`DyJY6Q~sJ}hhH z=\=dnT Ae =FA G۴`=ʬaERMD$?cň1wh< i\8&-$BTLC'Jxe̒%/\аrUp)((e˖iYc۸qxIÒg`YghYm/ *#^T>Aǐ+Xm`T_lJRʢ2N[$K_ i 3v>ߐ؃`d4d%ƫ]+@k%ī(kcA5e``@sΞHA-);oPXke:###Z?G;;h*T 6?!q=.D!<e) M kۘ*SF;A)U>>:53 EUoS^_Q,e˱)@纃|#yg ȡ' !̐U Id1j/'''hkk}ðСC~~`?w-+j;)!$n r1L2 yRŰk7vq!L<$W#Na "M~gee:(Go}ޮ^ڏ)p7Zm.󿧞zj"Eg {1g FvF /{G5\XFl'$qA"#. Fh~g $G=J=٣eu&''j~~8"h}KOO޻eqD3/?w-7'H^R.0&Ko< V?L'ʑZTV2(pٟ?8d@w`01gy>u1.sGk_T B>ǀߡ $LrX>sswrAYzdx!ߑ#FNFk&ӿ>⯥E^CF=@9!! =˦ޭ̄xLy =$;^S;Vq1 wV=Q.',c51 !îgܾ]v: Y*{Qwd}o޼ydu7X(fKrr N $v 7 GBw'/R$bؘ gV;r)--y8qwΟ$  Nn]k?0\'89BH`t5]ME9/=\x w7# J(_paYv#>|X駃p0{Tge~ K3R! u?q^? `9 #K_Zߏs?RH ?!}`sPDA(رc `@LgbY:&?D_Neno a!^xC|B>\8 IeƫrS'ChCXߗnjj7#G}hНP=~ OM(_A,gbi0#?L~ǒ!~V~r‚mZӊ%\ XN%iI2z,NC+1D}wA܏h 'ZB^{TE$03@< 'ա?iz`V@]'I9\&~KjxOGd;u޷oLLLhϏq~ NK.ÉkA0(8OId݃H!FAY/Q_7K()-`K~'@( Jj%f ~@ww{8"n^pD?N_ӓĿ BlwsIw՗4.4ijؓ_5R~\ 4f+pG=F-EwnwP]z#2w(*!Ė2\C4"e9#EKK~Z=)N)ₘ& XR8eW, >)++62X~Ж= `ؽ{ʿ }ܟ BlK~wyIiJ1XQ}rM#M`@A/z9A\ӽ,MǬT"el+JW+ѿT5ʴ9'_;wjWG2 rwA?Ͻd?3@!.<ۻMT-ₐr{Z?!vȺd[\Tp2$-HdN((S1Y"KFkdX23g +11Q둇Ge(h=0$)iӿ'\A4eʀDBqcAʞoeĖbjP}W:>`A'SBHdW:tK!==]JKK4n8vGW =x>}СK-2M[.!x`9xMCrJ1#?p6ލpqhX|}ᢋ%;1 A2TE0' ~l9S=/!alaaaCYtP~ {Upw70& o['{"O" x}mrruڗafĈ<HD86ަAQ Gtu=Piv`41lId,Q*w~咚?^BȤCCC+8&l`ZC,@>|-[4qpyf0@!addjT~s\Hob.?[~VU ImL++g)U\Ύ;'8LH*ehM-fj WN9=^mw`z ߈؏zʿ4Qaݯ/p%x%zĆؼ ^gbDet˿]6Lbz2bQڢޛwJNZn)192֪{d~dOERѶ)g x@C#yq!M  v_I $,H.rn.([Blp_ 'g +3ɒz)Hγ̱NNOvi;J[6u~ݽxm\xF__ڵKn>7P]]cGeÆ  Y`&x1k2EoY@H/_AbF}y47B@QrϨڦ*SU Ai+T~dtLti}3BoT߾$bD+7{+}{~~޽ڥ+5QWW`P>W\qwe&A쿧3Bqd\G2k|cwqQHT/Hko6B.8. Կ)RR$E $7)Wmj.n*^G& 9zs[OȐ<$esXLFy;ޑ;5N# scP6oެgĘ_0ߓpYB ;_H@ /'7q1)Ap vlHMHe%fjU v̄t;453lLC8}1bF3Mji$a:~Z222,7XE755isOfh^yf;^̿/8@*C 0@!a@]^r;4$Q+_ʙ gm1ňrYR?^zkQ"T;C#n5&''~g'afXQQ1GLw@x饗V fb|S$!Dvk[Yj|b`EZi+!$GN š?p1!b*)2y\?eddDvܩe?otUUq04Ӻbo,K?'죒gB"Hr]r۱{Y,\…!dCfym-.!$/pQҮgu|Q{nmLp⾾~^o=p8z믿z(ǚT1 ~p߻vڠ?83@!19 7t9/ !󙒏˳=[,V.!'iTPeڨ g|# ?٣J.W(w^-S*ǎlm04W& /?a?bvl6mè+T`i*$ D&%!YWic!ĕܩlWY:_9Q:ߎ7NrdQZ aF">h?\cc#ߥaB17e)r sZ&ىY\$bSOƞ-\ Bl?\UY:>55uVCڙ1G;0=s| ``zݺuaJc+ !NtCOhh3kKu".5 ;^~6JUY_%Δ>du3?ͥ>`qw?1X3W^ܶmA:P~O!$j 6zErR *P'5RQ rF4A R3HjV>Y&~8]]]Ԥ=Ki̟ٝ=8FFFz?jW T!$޿LȦޭڦS/u32I^l5BŁуrV<O~VV'!"y:I*˴ "ɞʌcRb⟢>0CGG?==W#fwD.o@;gb?@g  =٫m(AhaJuYTRIʶı:roٯm;(''_-fh7{W=Asd'z]#c~7>Ą606nwd Hf |iP:&uy{T)HӪB\i.7&j9.S#225*#R!;'}Ske1}MzolY *OTi I*_?%X"˯ UCߛe`WQCC'%%͹oٲezW6AM@h_,V #`q!+ %+1S 'i ;_%aN˵)`sC>a%1!{ϖ~ܖ>DbnV~58hJOOvw8288 {L^^q}K. )A=WjqgBH M k[<*oV]%S$%+&J40^-9S#~뢟Y}@#K{1x\n ;nf"MD3|!AÄN\}[9yy^@HqWW/#3?0z(se``@G;MkUSS#eeeq{7;v<PZg:ϟp7mB!ckm|Jye͸ $ArB ~_3V!yS996W~Н@Ͽ{?>:Xw8o {lqW9^O==^Ĥ!ؒ?ܬ&,i ;v;~rm !EcQ?e:&Ξ$4 ?& s|{+;oΝO*cDD$|"3@!Ė`]/[yy5ē0pDde Fr(~LMMݻ5CIggx` ]G WjF9rD {;Z` "Gttt?w/b[ B!$|B.-@g^y6:x2[Ȓ -_;HN/Ho{BϞ=-]]]ۿFt.]TV@2͛]{ pJ  /dNˮ!`qJ\Q)<yVӇ̰w5GYVg~|yL~8m;Wh@x_<<>ꢞB!$@Gc]E?^ayy;̓X$W~UįJ2-P!gqi;dw#kN~'^p8~ގ;cCB3 d"/K B"MΔ{Dj=SFy2&C׌-%c5RJx\!Gx7K}vLiCCÜ,?\u*I }7t&w0@!àcHn:z|[ҌUq<OwNekcZµ޺ǖdim@{jAzPdž`RGz@ٹsSjr°7 /#_)!~V.)<_N:j'{x2S8>FQ3r&ҝ{<8>oB|;o/B B!s߷.$-Hg$fȿ.B~|=Ob:`Y9^诒=%P jmcF_e O}UUUZ<KWl%TB3OP<&v~ob[ . B!h=F>.(-Wy2SbU_#Kezz7K@ݻ5qsTZGcz/>n`B3@!mgIQr-$qOSѿL8zYYYZX1:g?.1- Bh@y )8rȎ[ b@3@!xadjTr6Axw\ Ye㿼2yy94v',ȾTgJJ>~ݭ?B,ķՃ_Iss7QEcӲf'?&#Jwwu픹F"L3@!-7Od{҂$jf4sDB…bud׳FVdp"6;:PB^km۶!1 T0!⇣mc|<* xM<HHdOej9atO{{!gܺA dGl?8 fg0Ժvvm/-?BֶN.?GRKlyZq9x2p*3Z++tb/@et~à0p&1"A{r78>Q)HW_}10*Fo% . B!ZnoNʒ*>/6O|G,?g*>! uo4,=??۷o1eees(#ON~ݻVSP~-i"J  B #7i9'IzB^u|i׵29=ɓ|N*-_5^%h,g0kllp?jkk0k<<~Lf~xSz!1%w/_.-QjS?hk@MD8DsOv$zL?D?]8p@LNffJ8τ΀_WYܹ3i/A1(g B!fG䒂:m-se.-cx2،$I%#򮑕pYXݵF ZWC:=z {18 )a&q}z?*'}~xxG:Iu֟B!$HK'Edʫ[{Myl_*' /TSWY~W?o-uϞ=ӣEssv1o<<Mƍ`ļ@%F1@![C噞}O>A.,8[[bUUyX]\{m'ΠE #?<< X1pG?zAGcx͛7?B; D|/U4B!$rvywiiO LGɣ%a^'4+%%%'_;c̟z|CIG?P`K]wu_ >n B!A;'[#_-??9O\<,@TZ'O!D?2zAp_WW?MMMZb}HQQQTy4P744m}Gńڦ$<ĿxŲ B!!PrjXؖᢋeCfy{'CR4/(F$ALQo'nu̶nN# W1W鿡ay<`(*ҷzg?^M":!ʗ!w-7ɟ–8k2G G`C'Jx]dX!~f%q!G?\ľn;2 l1 5USj`XRt-6J>^a}=O+C'Kd2cC65X5o-y,D>۸T [!0`UfAM^۟@+ďW`?BHX}orNޙk-/HDO zyЩH?1q}WP:n0ӿޣ!81x:T%!"C`BՀGƖǟ*ߨ|ox2L׎-NxOJt l7,ķvQnղp9EEd-X@xKׯDfb[U!0Trirr <3rVɹy-}/d0r໤d7:AH=}wFfmV+c:p Dc]1 u &Z^ݼyAOqg B!euٯ%iA-kW+oOs?d}#Ӭ*8-74 0s}cXx @;3 N-Oݟ_\!&G˃'?b/LΗ/].w}SxDڨeIdX2V+G2aFy6 jrrR #:durm0F;GK3' "m_8@oޟ`Bk; ΑxFeS☞!R}Q{GiunƏc P ]8 ?b >FP]z23/1FĿ'mb \J!˒ѿkI~di$DbBP>{;r"dPgy溅-0oyVȢs-~CC9?A5b7|љ ODWx #!Bne\FK;w= o7tb^glf\7霫Us<p+]t?Yx>q!Tիv'-gB27]ޓ{d%fޭ?4vNGʜKKĶẅ߳gϜqs"bųctH5  {!T&U'/!b?BH[#_2fa9&Ot=DL5ދtra,gYYdggSp ?NZzzz<}F[VUUE7ເ6 7f͚G?#)33@!Āj%ɲQo}? :ADbh匌>imFupGza744?T`Xg?_sA<W_}0e Bb_!^' "/Z':䁎GQ5oNX||IPjj6,Xwoẙp-ojjuG9n:c7@B@sxb,h @?@% B!1qd<|҈cAyF(rd\$Hd=#P@?㽡Q~uuu;3 `eY>GD_<h!rN޻%/)7Q~;x{蔈>4O͠E]o߾9#p/++K/b٪ <3A_O>P!ƣwT5/r[:5ō?LYFELOm.uX|dfzǘ?~ X$AGc,o!8z$x_+ g B!OuoV)'|ǴCۦ cG&[N^GE$zLv-ó\y!~*++WU/?;l߿q>f B]2qI&q#Sd&YtMp!" Gv3V% ZDr ]w7L?azalFP~v۳bcĀ@q B!?ZKc򩒏}l_{J{F=FMpLكED0=dJQ W!L\q"\b:*dd~?Բ.3@!mo͹hl"i'ʄ9t1tR_β2KNoQqxuJ!1.)Σ`{U0t ]{ 0!b> ]5;0&Yd zuCImu?>Ju1744̎ChT0 p?ǘ1_nH_?B2n͔#\ S3^| Y V ZXo ݝ1OeCNz???_ЏgUʶm"" `B!mCm\Sȓ] ~H8S|3huCGG>|xp#gQ ?Vb.d3}쿫D R[60!BHd:{.TgJ^Qpg-y`"8鿵U;6qZ?eOnߔ7L @X ~ڎ# B1*ԧz/JIOOd^KzLj8,#OiOc0֭[쿑FDWbgK B1Eⰽ"))ͺnp?rmTݻwNY9^ b'*4Azt|H{-}?B!Y1Z/' / !2gwOiapcGy!]?_C^{Q5qL_*EsB!SWw]Vؿ@gB!7 Կϒ锰Ό9IpZ+~ss4({_itA;:t_|EfaD*ڧ% BsR_JNN3Kn.uqw-ǘ?x_x%*`{ytitf~A9w./~ B!Leɹ v˵'E$w>އ1cǘ?EEEZL UolذaW')`?@!BJSZ=u6:v]7DW1h@KNNNkA/}e  D7 B_6nd1@O!BghԌW51M,9-ko߾9BӘBG*N wGG0{_WW' #_<?1@!b%?̰J1";׭Fo~~'8C-g8slٲN]5Jٿ'/#?Ϫ!Br*ɚu !+ Nu/4Q9{1Xd~A'%%VGc_FFFڷj9v뭷({'D~ ž!BS4/kj\~(Hԙ\E#aFˋ7;x#Xؿ92f `${/bϗ B!3dHCnH?W?66݇ɒ%&P:!ԹгzgFV3CK!B iЍPɾo[]( Ёŋgo@4Pz_}GT xGj@0!B0 +x$38wwwռ<-Z(U/,/ǃzj曟cDg | ~!Bs2w:@m%}G8WVVjshП}s>!~y1 dz{\}n?c)]2B!<$g)U]TTDɠEܭC>dwu~W;xtuui2~-<*?B!:B2!D9'=釒pápnF>0_@w(5b:_$4U0rcB!*NC':}ʢd"“?1:(ǘ?8#/vLj쿫c (_5k<"3) )ƳnxoBH:AҦSCz d@}Sp2hau7wdG1ӿf8FΠ_Ol{a)l5. {f < !ϠȊ_Pho-̼nӿk&-sQ___M@"N D7з|?.1{b9"3@!',4ghdEh+ NoJ]GᲵU;6q0֎-oeqnŀ71ZZZ^ڼy1?ϥ Q30!Bgi+C~}\X89yr_YYژ?*έP=:9뿻0g#\B!du3i_FFQ|3hau~3{?888Gdhm-Ɩ(7o瀀ُƎ}}}Aѣ>SMy_Y!U0a@B ӆOx[7u'_Gk ]Gcf?Fx?>{x(f"ƫ0!BjIdaHh No3~cc_xY=x}LЫ&v]<E_F"ƲZ( B g :c*"u]> :4G,fffŋIx(G4>]=aÆ +aB exiH .9̿NG@w8r@GGG~~GGǮk׾!30o"Ƴ˱B\N^E=??Ӧ; "U{s/))Y h?Ljׄ(}b\gCq! FӋH"B,Et, 5G4E$[7OB?TUUi#,ZuS@ ^\EGk֬yM]uN O+/ 0 `!B迤xS|S|a0MMMsD D~}} ?:F!S[+{I{ 0!BH44D5Bm :C꠼fm(KbOx@?_! > _'B)i쿙D$Z7O#=|CU(K+O;#>'Gf]M3@/ @!Ķ<,c,4o-FϿ霽e*WPUk hLj@ڭz_Pc x/'^B!3(Bz K8Z75M92+.!8 }}}spBUw7€@#0/|IoDgD5hB,ϒZIs|LFdϡCxfb9?({mmm!Xu"c 0E{؟k!؄ǖ|1AX `7888{'V=FdGFFBڷWgbHF BmrfȢʥ1'ʂ_,na>oxRBa`A@JAÇ:Du=>1Koڴiwq?_PG3`F\.1!+d4<X ~8%xLKK˼nNK}٧TVTUWuya'N7Bsl_|蒪Eᗣpy^@x^_O>ĘI]C-|-t oPIj xZ&M??Uj'&iӦuPǴhv ?lciѤKh_CӅO^zUz?QKi'(s // W_ C-p1v*107i… oЇO<^Qm7iQd6NB$ҥKn7|jժ=J26.?a?o?YD>@G"O[ 9G0|~ 3L&@׵ߴ:GoLeێ;6[ /_/^HoXf)ڹs}QS71/2[ -#JWkkC=tݣP@ˈze߈ѶDMu[oIJKkeʂ]M[<_*D^z,O#:9.\FF&w}?U9HRKQOARa$"eP  <_74t\,:EYH 8zɓ>s By٦?wsFU7T1@%H%uc;U1 O'JЎbއ;=I˾} _X2cƌ/,\Z7Jҿm NPDK<ւ 2Whw!0|Nh=ܳU]OYW?m?_er./bEZRnyjߨ??듗jG|wi!kguv0vH0ɒ%FIUT٦|nNMKʮ_w4PDc `OkLu8O3vޒvkv2@CMp__oԢi˓%3U~9K9rdP'2/zݦ~HPӢMeϏO(@16l0?{`ɿ簙qm'?yL]oQn("10=gg u9o:rVXQ]|9 e$0t輊竛oRq\EfO:Ux[{}^ګҫFRT1Ϫg}qjF@V?) CCIдIzӓ;u7-R0Mk $O<9h_h!Lމ' _~衇~Oʇ0# PE?"*bT`ĿIкB?yGU˿\M./JB5s݊Bw9M?|pкk֬  \pc4C"ΫS/8tm^ۿRT1@br@t(h-vW5εv2dG@+ y*}~dݺuj֬Yy &7KR^:ac}^Q[mLg:= }Bm<% AWe?6Tuب??E',?k'*yw޷+W?Jߞ={&Tm_ ?c:RtMm)\٦IH>ShSJ>IpI@K4&* ߶z#~L~oBjk~듯z]MD~tH?<O"KMb! x 3<^ h9`'mHu"?&/(mz5}f =A͙3'/ŋԩSK73ώpAQ _)PH̛\gPO{x./^@k.eǫ P3ի\IBGSǎ ǑI"_Ŀfۓ/Yo@(Ejf Dn{yEGoѱ.w$io&UIfR .Fu'J0/H %7Jb$;ٳGQ׫y~Ti?dn?H/_-e[I&RW1ZYO:wX?ESLjPoo/-\Th%OrD ܿ I200X./f.*yg"%ŋ /ަO%L10DV(GyGyKVmBlc@ $gG8h_SGܿJoʕ+ ooL8R?x?sLxR?iҤ*F|%Ec)W~GIY/g:@J0LGLF򌅤㺃>FI@ZLV_=C^θm8ZB ƒ#GLT%?/PZ߾^Z{⦅e$+<*@,D}MMKڎQк@7"-P6JJ͞=ika@Ur  @.#˖-K/&@# ؞MxI~?'/_?9& tai7 t(Hy__x3J jWժU3u'{] uLۆR^K=j(&K$KW +e֭?+HJPdUc@D X 5/y-)ޤp$2N韮UcvmkZHҿ˰IUVyA3P?TP*I"ϱ#]GKIA-7-^d2CMþETr߷3gΌ-'}GYtip0&wp(||'c+lٿyߦ PPUkN(_eo c _ѷ2\TN@jf "UTb%_B guQ?ql(S H3LMۊQlcoLۊȗy-RqI̞=9C"fࠗuj3߃OyfP)5 TŋWa Ǵ6Yի6;=:v:LR[n,_3f@cڦTeu {챷UrMIRٕc@KFuɎhw]A./@Dy#ʲ~"$y}c#QdY+W%FDbk_Ygu#k?-o$1@ZPF@6B?*&[O8:ݥ紝};ZIOOOp^DYbE& urίcz~ ,IR׫6U3YT1b&@mbT#OgO ٴ&I:igr.uM \ '&@Yvm0/HS;Cmӧ<YyӦM࿰ocٿPa@;}>T7&wZNL%zLJ<֌ v55$`` 8/]|IIs ۔Ǔ;`$\{P[HW&@q^ (qy=e}ik^Tpٸ|iw3ljY90_nqD_~l DR$c`đ/zy.oƖ;v,UgUOwُg<5/^ Z k5')A֭[,hܿ쿯?La1j;Ρ(D|2[-~]! Ė'\KڵkܹsKKdCc !`>[u?+?hF"F@Cow1j Ůynm08d:L@.]4vK.UK, z&#\y)T__,N[zD +3F5޶(./&Ra ey?Y/n-eՁvhuC<!sO=:R-??fd {Yj|3sS)ߵwM I2g-#q'U!/!ktAzzy'F ]P)0reu}hzGx{a{#GqI:2/7bC n,ObV.gc``@6;rY`Q9 w is%쯿$ݺucO+mT};.~߿pUe/*we.e5{0.{}R-KIɼGp;i_jXҿMVL\)Z1#̀fl[Vh.nZ9:p1&k`U'KR?C6e``ojtɿ!s_0{>c\wNzwZЗ@ǀBgʔ)A3$wp(t*>П͛7ߣG $BZ -a4<@i45Po{.'jrZaIY/osoƖm۶TݵC O03 i, 8~6 *$Kߍ7z;'NTAB:S\8t;wqǶ+%7m c!6_3+N$ۥc@BBAo߾`:2bӧO!!`K>te׿IyпjMH`d70 ~yIu%jM 9}@KȟI_k֬3̤  4dL%ɠrA^7m]="k[s&U}~_aT@/͛7uC3*mZH_ZE?>Xohhh/^/_>v^fNuG7wbR>}sx饗}?۪D=@&@Ҩtxj+v!%_Zի ΋13{ I$\fİt=FT~Iۿm?P4A+_K8ijRtPP P?5kyӤ  |ۈ~q_}@+V#iI%L(dl" ! 0Y@I؟TEH\LIڵkt@b4k{b\IdU@]E57#o*ih!6wi79VD,'~i?zI߆  71$!ЬU΋OTqAwj^rP%'TFFY՟ʈJrWZ? ?~xPENL~Y/  HP^K6mt9].bA0?5,PΏ:)YKs/B_J_{G }}}O'j4XW19-iL_x z{{@%?tRdɒǑ ;lۓAoGy7']Ľm?g h!KTn&&3"߾}A [j7oe3g F^67>)WR~W3 MG'$h4 .llYۓԞ~<ӗ#ߤZQI)| B3RׇЪYIZϟ?ݺuj֬YcIR?CۓϬXq7oML& ̗}YP.Pޫj`FDm]Z'NCM$K؟TC= q޾\/3>~Rf6KV}-G?`@eBZ? D1̜9S_>d_$7KRo(e?YOZH߆ ƽI@+@)e* tIw ?ڟgąs0 hКaN_PT\:u*h)a%$o͚5A i>D⼜mv*bf5zG/}ف#*?M#`gp@H_ZeY4N|I03E/_>2p]q޸mv*ci/c_رcdz_7Ŀk?/f_)?E_`@/g E'I"u[sp:DWVs'n ^ bdIKY-2^yǾJEYsiy?O#*#k=T@TŘo߾qQK?j&#\1M1_L2Џ;_xU}'Ue'/0 h0mZ`TIwqLEKA4!mʪe z,-[yꩧg/;<џoRFBP7H_'N:O n6ŒtHտ8w _C4eֿ!ZO̫YcYBeFYJb"'Ar("}mSNTjw~<^qE+rm*_r1RF0aҿ֯E9sfy{6mC *|+&-kt?wJ *a:l쬞]D4"ǃl_en:Dׯ_GEfe+@YJ>e->w׾ބ\3ߵr$`"XF S9i1v=noY]vЗӲ_HC7fV>r(YprӦM{W>QʼE-Bt跹oy1 2_IdXQ7EPzU k'O . R_n# '¿\ ^cϭt4ap?m os@P9N K._F<O8p`Lȗo8/goԜ||]vUK tWVe h{3dy`膥 ¤A:c'IҿTyئN߈9p۷ov?3 __EoZNԛ\nt;vi#ȑ#c'1C ? aOu+CCP]*B_x-w+jbП/?oɿӈlc4ZH/* L 4R۷/0"#7}ty H/6\ zTg]w;s@⿎ ;?lD'2$e%iUڻw' +mgTVC[m]xW{^TWcVT?0x ƀbH).gbH_=VC`rq,\/n \1|oSo===;?spy$} hpeyg.YГ!ojH+m') .wp?  WȒp f{-=ЯU 2P`r޽E7nMi_n5kָH*$ĈSYmї y睛uf-0D-KgHG`@ κE7$"LuѦ[neB{ 21 U>\xwu^Ws@n?`[r#1& ,Ѥv+ojxyǎ/?~]/_dE3G^B`@ mGtR2,'e˖MN߉C >C4Gy>?sEV˱̿B`?n3orzΎu$;/~닑?͛ E%w!IG(E臢]^ww\.->^d8$zz[oգ[u$//J:iT(/_[]v8/iV[G{__4? 6yeE @+j~]+k]B{2~K}X~lڴiޅ%@u pU~]9}v1yBmxRv?4PZ9HdNKJ9n90Z5uo~N:k=ywd_%/g3` R9gϞ=p†mg*)(Y'd#ǎ;\7$4҄hO3 :,~)߹Ǐoe˖*#BL6U,?ҫ6I q`;ߴ 7C ,(1E{Q1}/Ƿ\;wO{jmE1j/: &mT9;# ~nʔ)MζM3.糄xuI?:o~?ݡ_Vy6U!m+ (Q0}E< ͞=3IMh 3tяwر'|[g^S-#*M޶GkK?(]/ 7׍;y]v[ܿ|IRvK𹜟kQ߼?0J6L2v:tUڵky9s̑?[V1Rw(ߵ-` ̀Ds}_xGЫ\Օ~]߿_[oI"6Eh75PP؛t9!oo}*xʕ+:Cm~+Yx_¿]7`@e-$ {9pօ ~~ƌKS@ٷo~T*4?-_)3.+؈}[ {y?spO%OG] aR)0]Ѣ_Vuş5k2sU)NW_}k"Trr.s Q/M?<+i?: 0aJxqyu͚5-ZnΜ9LrN,?kA~' |>ۈ"RЂ 7@`L4iɟНW\^ KЗOO &;wdooݻwoڱcTGk#Er7l SG?@W)t I&ӧz뭋n喕S`͒%KVkS`>RgsҥzǎiD>5MEQ#`ڥ~ W< #.7=LJ0&-[l)\uʹs.S8W^~n_z|ZoZOfV}W3#0 p1: L:?`mݶpÆ KAhuni5JkcZ>{|Q'VV+C+Un_^˿G?฿55 09d $SB.Iz`g?مԧks`y7|oqNV#0Ҿ9'NKE|GtU/"B\]MFU syiž?e_&@-2j]kv0Esu<=N0_3OwΙ9s\}lV'C s:O"ԙ3gNY:N?JL26?2ۖ2 23 Jُ6,ڔq>}nS`ڵkg9{fmM0[4mڴaFx܎oz}/^x… ]gu~ɓ'tɁK1AkܞM96e!}/"Є+Y]6¿` }oAt-_|ŋgp™z` m(za(>arg}<]?uԠ@lUz^r%9?44tE_?, Z_ЇKZ_ЇBA A}Nۿiů&"-DL mT0|,M_# sf~*e6e@>7a&؊<'] oo+}.}**[ȺXъ&.u@Y&f@^e@zS^/p_oz~6F@]J/M Ϫ? ]vk"k$"¿+fܧJPx7yk <]Q-bFvS`0y]yK{n*}|d D F72ԯf &Oo"}^f*] `r-$MDZ@ ~}I!`"mDU^%6@Q#/bV 0QC O i&DowI/+ pVr("}[Y9EM"߷3f>iąO>2b ~>l5=o+}?:0Y*C۴gb@?Fo p>ME46I:VF@T/eo,_e""(oq#%m<ZH p1_S3 Oך(jT(+oTQ-ndi@S5/*5P,Zy Pe}\>Om(@R7@]f } ς/#Q5\̀׹}?@P-%L*ys&ݵnVo(3ѫ Mľue ?@ @4Pii0_D(5K-)]Ct@$qߤror} <|8'}UZk\2lh"9]W2??M7\ż\E~wտȾxW(4pݶPID|̇/((_+>M_"5cؚbU~UĿO1DQ/K#0Ty͚/kV0|zJka>^L_b ~+~?@L"݇/KCſ,#`naCV&/SXV\Yf@3/sEF {ߢր=E8aU~*ke޶ m%}[qݬ} ~?`F@ u]Y"vmUeV! ]׈}5k_^%^_z&д}Zůy2kte fZ_o aY/ަׂBL-6ll!__eYxJžB'e FZVݾLq `?{b[Յj#xJ Zߏv3M|~~KMS;RoA@_j-\[ysM `_`"F`MiS70tQ9~} 7Ob`_ }~D>?N 7Dx'OoIENDB`././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256.pngqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appicons0000644000175100001660000002605014776170045033221 0ustar runnerdockerPNG  IHDR\rf+IDATx] M2Fez'Piy"T4hE@ty"O 3 xE2 @H~_\b1mߏ^V QX [q;>k>+˰Vvk+}A  "╕zW.u{)C / BɸV{|klHH,+Xx?Z76>!mh%Z۳sc,wL<@Hy ܿ&e,>ux{ҟ @>ޗVkm DclD;tZڎ@HBeGςׂ!)Ab ?x^}C@/7˚ty@WcǏ&z}ע=0"9w`0+ a<.͗Pq^o?>p 66pNx>.{Wy%d&KDf[yOpDK8AٵLB1  jq sx?8k0>ߑʳ(zrx?ɓ K)>{~3 Y? ώƮaǏPya-^ t92?`DU_R<V)^0LAP2J;arz1o){?WavxZ bTȔV \aV} ]ԣG^؏/yiӦȟHYt5oMAktoF$(W{챻da÷سg]!yv %,@(6Y_Ͼ+JoDX[㕅@G^T2e*u3;f#F8RN竪9 A0 o/y_V?L"(*m񖑾~Kv3|;w%ŒjP rŻanÔg2 -L0(!0ڳnk1 )+W[r. S5"*T^+|u$yz|.\T{>eJuY|~$vq|U$!EEOQ @(2nqc=vx}fؿu~}ǩI8f-P[ζqET?v_.] UT?sɼwd.{6ozhrsvRIr6lX?cƌbUX򽮔0ꟋQ5`b6 Hʸ0#b.Nuq΢7Z #K+Đv_xH7-Z mg!7I;ug F|̙#f̘r.JXj ? Rv[XdsbFƒHE5eϛ7OlٲEL>}ӦM;i'0pߋ-zG,2DBż@M!p}3xw' 6@(߾}ضm2e@KΝ+-[vkڵkS Ti# qJ|ѢE \f}W^bرbժUC׷m۶bO+CV][dg]T8 Pw6Sq M8Q,]T>믿 9O~1a~zA0` Gf? X>icl៑yM ۑgKS:Acw}'~7k׮ _ѧOߺu_ƏD?S%!V\ HmG~גJf9v9ӞO4dիO0z?R~ Ow.\c;R~`Z X_p߇z&EP+oL~W =-ADGyVnO?t{wСw\(~а`r} ÔD߱!W{/H-G1A 3h?? # ` 6}kmV3//~DD{׮\A9~~^3BcADw%~"gzJw9~Jq 5(9芌If+es;=m{m%KXo^;qҤI})mw9}giif6U^k񢇬t=7jAT=b=EQ(`zO1F?hf/gΜ)~m!yɓ'[ ~a҆nq`%mmZ~CNM0wzkwo>#jbۻEڿBNAhWT^iCW9TfX(Fd<?x*gh5bp}[|H類_ڃY~7o>!'gMSG ,?MV[i0~ zNqᐵ1|,ϾCC_hkW͞=G ElQ؃_[;pos'HZ1db/SuNA;c܏#0ɝ7cE/m:駌՟`>8vXLJ<>Wīzla۴Mbuy#&C z駟TOʛYq_J9 I~kو#Wi .M"l1 nN 0@k-~h>?(I&Jb?ps,z7D1߄ڣƁ]|LF"zן ߦ-n"5h }o5FM!,FMFٯ/~(>]Xs,$$ޖc;>V{`@\ǐ!C` E*foƍ_R/GD`8::4ғ\W|lua6MqMYcUƪ_y-^hdj__6P|7NGrhH$|Kݮ'+ǡHthh>sXnݺs~)>#NՁyuP&p&rj@{VM^9 =herŢKEɹ8%G:oIq#uؒ;au8]WA{^|>>_ O1IJ C.8N GM~=H)ʁ!ZjLI>IƏp&rsዣC;4ŤWAuVWKPym$``'-{F58vwJjѐzӇy`V5 @*GziZ_vB)w rNYq9.n"l1n聻&RшA4cw7(Rq^Ec fOG+i` ?jx.cL 2R7~9Pd{ZH_ &(e4c, 7HF0"]tG6< _%i.BʿA{c%U$Td {ɔ>I|XM&>@k؝}hd Ez7 jh(Uw0 s+KP[6J[ʊ 7HF0|=뫯Ѽd\$}jժ;ȯgX2FL k՗*U?#lG]F b[9-4PP/UI%!ڡAnӾos2T`z&"ҏ:!>3'\|kU꯻z6b8K5?dJXNj\R䨯5TD&F࿈~ڰ{bIbPb4d]ojwDӕWyJ䳔jCEڕՖyEznXv܂>R{(E]?j`2`xS…P.ntG*yW۞BJ b!25,xIK*'Oڲv~2$&9rGI0|7&SPxdIiѢś*}*;3qt!ȫn3 S TpzH/GT5fvɪ 7xCJGbJ )G뿯O>dʮ\urگ &dj׈زe'i(^/EYe0~9B {)}Ї=K.yHeUd<'W7 d hPIjlq 5\UӏmN* @̭۶m{;#S!dj7-1m1$&bEuL =r_*PT]2*vO`'-ĺ`KemY&"a V}0 )HM'!H }ֿjժw E?D@A%خV% DD IC}D7߉E[[T1UEWw`Wl"Et*Wh` pkVFwW1 ͂3++*UGa򑱁?"XPHmU^!ަD"a8+?F?nbLAϛC>dzr[ҥՊ}[S+W Y_orѿ}(A==)Ѝ_ [_Gm/P[⏁?·`gN$k](q %^0(ˇ9(={_d nf?3iE'+K*u5h ?mf D?=<4MnCOyn I#˖-{s$ GoM‰Adde"EܕC]è?h E+!`Ķ>.&S) e9+>(W7fT!g֟wPzD~>}eNL 'Ak&\wu8+ߏ)JN?n@ @~]d5C@]ʸHjCcZ/xg M R!xlf͚uRA?+;"2GG+`GY/ QAM 8?">h:0F .~?D %K~L W*kG?31qĿ ߉ Yw2vVVUA?3OXA@Ypnv)p4EǎC9oOab_xᅁY9gYVq'Or5|5\.(A+?}ptX!D"x|Ge圓qյ]àx0r) wy`$G_""e5G/F{r3G^쓜]ytc@N<0~0,"fmm e+T_00)OH m9,.{`GƏ^~nB*A:hiݺuO?)pR3}n0('Ge1K#h aL X2haÆrfTtҠGcMG[}taZ/҅;ѫ h@(Ӕd 4!C}}+"ܗy|١#pLZ5 ,ի?8wh8$ 9)4~"v[-0nݺYH{0-Vs066Kն>;HvM0H{ m2rtCVӁˁׯ [0jGǿ0jjUOdd,bfGZs hDne͋/W_|zlҤɇ=P϶mfwa0Ce>_Vu=7nܹN:P-{6Q@Rp R"i>~)OP 7PڃQk(1F 2[[k}J ]@{}%*iVu5cF}૩H3sj hm *s3|?n ,r(㪨Zm+CBU@k)cpש݃SVz\>W ޟ6bj/@OPX@>ZQ+hIe\PVN +) eU*]]e^[EE+ϲWsԵћ}^'( Fu2ʧ>Sٚ0UZNU2`7VP?{z]9^{)OW;SJo}>D-n 2؊tC1WYRߕHBaFgj^RWqgh^0x}{ojO'Bp-Rš2֢J(lp3E #/{~VziAri[<`-4EgkFO{+n4zH2MSty iD1'Ͱ "/AAAAs$t3IENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/CocoaApplication-Prefix.pch0000644000175100001660000000303714776170045030225 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qbs. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms and ** conditions see http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifdef __OBJC__ #import #endif qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/en_US.lproj/0000755000175100001660000000000014776170045025221 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/en_US.lproj/LICENSE0000644000175100001660000000275314776170045026235 0ustar runnerdockerCopyright (C) 2017 The Qt Company Ltd. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of The Qt Company Ltd and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/en_US.lproj/Credits.rtf0000644000175100001660000000070314776170045027333 0ustar runnerdocker{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} {\colortbl;\red255\green255\blue255;} \paperw9840\paperh8400 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \f0\b\fs24 \cf0 Engineering: \b0 \ Some people\ \ \b Human Interface Design: \b0 \ Some other people\ \ \b Testing: \b0 \ Hopefully not nobody\ \ \b Documentation: \b0 \ Whoever\ \ \b With special thanks to: \b0 \ Mom\ } qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/en_US.lproj/InfoPlist.strings0000644000175100001660000000005414776170045030542 0ustar runnerdocker/* Localized versions of Info.plist keys */ qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/en_US.lproj/MainMenu.xib0000644000175100001660000113401714776170045027445 0ustar runnerdocker 1080 11D50 2457 1138.32 568.00 com.apple.InterfaceBuilder.CocoaPlugin 2457 NSWindowTemplate NSView NSMenu NSMenuItem NSCustomObject com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion NSApplication FirstResponder NSApplication AMainMenu CocoaApplication 1048576 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: CocoaApplication About CocoaApplication 2147483647 YES YES 1048576 2147483647 Preferences… , 1048576 2147483647 YES YES 1048576 2147483647 Services 1048576 2147483647 submenuAction: Services _NSServicesMenu YES YES 1048576 2147483647 Hide CocoaApplication h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 1048576 2147483647 YES YES 1048576 2147483647 Quit CocoaApplication q 1048576 2147483647 _NSAppleMenu File 1048576 2147483647 submenuAction: File New n 1048576 2147483647 Open… o 1048576 2147483647 Open Recent 1048576 2147483647 submenuAction: Open Recent Clear Menu 1048576 2147483647 _NSRecentDocumentsMenu YES YES 1048576 2147483647 Close w 1048576 2147483647 Save… s 1048576 2147483647 Revert to Saved 2147483647 YES YES 1048576 2147483647 Page Setup... P 1179648 2147483647 Print… p 1048576 2147483647 Edit 1048576 2147483647 submenuAction: Edit Undo z 1048576 2147483647 Redo Z 1179648 2147483647 YES YES 1048576 2147483647 Cut x 1048576 2147483647 Copy c 1048576 2147483647 Paste v 1048576 2147483647 Paste and Match Style V 1572864 2147483647 Delete 1048576 2147483647 Select All a 1048576 2147483647 YES YES 1048576 2147483647 Find 1048576 2147483647 submenuAction: Find Find… f 1048576 2147483647 1 Find and Replace… f 1572864 2147483647 12 Find Next g 1048576 2147483647 2 Find Previous G 1179648 2147483647 3 Use Selection for Find e 1048576 2147483647 7 Jump to Selection j 1048576 2147483647 Spelling and Grammar 1048576 2147483647 submenuAction: Spelling and Grammar Show Spelling and Grammar : 1048576 2147483647 Check Document Now ; 1048576 2147483647 YES YES 2147483647 Check Spelling While Typing 1048576 2147483647 Check Grammar With Spelling 1048576 2147483647 Correct Spelling Automatically 2147483647 Substitutions 1048576 2147483647 submenuAction: Substitutions Show Substitutions 2147483647 YES YES 2147483647 Smart Copy/Paste f 1048576 2147483647 1 Smart Quotes g 1048576 2147483647 2 Smart Dashes 2147483647 Smart Links G 1179648 2147483647 3 Text Replacement 2147483647 Transformations 2147483647 submenuAction: Transformations Make Upper Case 2147483647 Make Lower Case 2147483647 Capitalize 2147483647 Speech 1048576 2147483647 submenuAction: Speech Start Speaking 1048576 2147483647 Stop Speaking 1048576 2147483647 Format 2147483647 submenuAction: Format Font 2147483647 submenuAction: Font Show Fonts t 1048576 2147483647 Bold b 1048576 2147483647 2 Italic i 1048576 2147483647 1 Underline u 1048576 2147483647 YES YES 2147483647 Bigger + 1048576 2147483647 3 Smaller - 1048576 2147483647 4 YES YES 2147483647 Kern 2147483647 submenuAction: Kern Use Default 2147483647 Use None 2147483647 Tighten 2147483647 Loosen 2147483647 Ligatures 2147483647 submenuAction: Ligatures Use Default 2147483647 Use None 2147483647 Use All 2147483647 Baseline 2147483647 submenuAction: Baseline Use Default 2147483647 Superscript 2147483647 Subscript 2147483647 Raise 2147483647 Lower 2147483647 YES YES 2147483647 Show Colors C 1048576 2147483647 YES YES 2147483647 Copy Style c 1572864 2147483647 Paste Style v 1572864 2147483647 _NSFontMenu Text 2147483647 submenuAction: Text Align Left { 1048576 2147483647 Center | 1048576 2147483647 Justify 2147483647 Align Right } 1048576 2147483647 YES YES 2147483647 Writing Direction 2147483647 submenuAction: Writing Direction YES Paragraph 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 YES Selection 2147483647 CURlZmF1bHQ 2147483647 CUxlZnQgdG8gUmlnaHQ 2147483647 CVJpZ2h0IHRvIExlZnQ 2147483647 YES YES 2147483647 Show Ruler 2147483647 Copy Ruler c 1310720 2147483647 Paste Ruler v 1310720 2147483647 View 1048576 2147483647 submenuAction: View Show Toolbar t 1572864 2147483647 Customize Toolbar… 1048576 2147483647 Window 1048576 2147483647 submenuAction: Window Minimize m 1048576 2147483647 Zoom 1048576 2147483647 YES YES 1048576 2147483647 Bring All to Front 1048576 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help CocoaApplication Help ? 1048576 2147483647 _NSHelpMenu _NSMainMenu 15 2 {{335, 390}, {480, 360}} 1954021376 CocoaApplication NSWindow 256 {480, 360} {{0, 0}, {2560, 1418}} {10000000000000, 10000000000000} YES AppDelegate NSFontManager terminate: 449 orderFrontStandardAboutPanel: 142 delegate 495 performMiniaturize: 37 arrangeInFront: 39 print: 86 runPageLayout: 87 clearRecentDocuments: 127 performClose: 193 toggleContinuousSpellChecking: 222 undo: 223 copy: 224 checkSpelling: 225 paste: 226 stopSpeaking: 227 cut: 228 showGuessPanel: 230 redo: 231 selectAll: 232 startSpeaking: 233 delete: 235 performZoom: 240 performFindPanelAction: 241 centerSelectionInVisibleArea: 245 toggleGrammarChecking: 347 toggleSmartInsertDelete: 355 toggleAutomaticQuoteSubstitution: 356 toggleAutomaticLinkDetection: 357 saveDocument: 362 revertDocumentToSaved: 364 runToolbarCustomizationPalette: 365 toggleToolbarShown: 366 hide: 367 hideOtherApplications: 368 unhideAllApplications: 370 newDocument: 373 openDocument: 374 raiseBaseline: 426 lowerBaseline: 427 copyFont: 428 subscript: 429 superscript: 430 tightenKerning: 431 underline: 432 orderFrontColorPanel: 433 useAllLigatures: 434 loosenKerning: 435 pasteFont: 436 unscript: 437 useStandardKerning: 438 useStandardLigatures: 439 turnOffLigatures: 440 turnOffKerning: 441 toggleAutomaticSpellingCorrection: 456 orderFrontSubstitutionsPanel: 458 toggleAutomaticDashSubstitution: 461 toggleAutomaticTextReplacement: 463 uppercaseWord: 464 capitalizeWord: 467 lowercaseWord: 468 pasteAsPlainText: 486 performFindPanelAction: 487 performFindPanelAction: 488 performFindPanelAction: 489 showHelp: 493 alignCenter: 518 pasteRuler: 519 toggleRuler: 520 alignRight: 521 copyRuler: 522 alignJustified: 523 alignLeft: 524 makeBaseWritingDirectionNatural: 525 makeBaseWritingDirectionLeftToRight: 526 makeBaseWritingDirectionRightToLeft: 527 makeTextWritingDirectionNatural: 528 makeTextWritingDirectionLeftToRight: 529 makeTextWritingDirectionRightToLeft: 530 performFindPanelAction: 535 addFontTrait: 421 addFontTrait: 422 modifyFont: 423 orderFrontFontPanel: 424 modifyFont: 425 window 532 0 -2 File's Owner -1 First Responder -3 Application 29 19 56 217 83 81 75 78 72 82 124 77 73 79 112 74 125 126 205 202 198 207 214 199 203 197 206 215 218 216 200 219 201 204 220 213 210 221 208 209 57 58 134 150 136 144 129 143 236 131 149 145 130 24 92 5 239 23 295 296 297 298 211 212 195 196 346 348 349 350 351 354 371 372 375 376 377 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 450 451 452 453 454 457 459 460 462 465 466 485 490 491 492 494 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 534 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{380, 496}, {480, 360}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin 535 ABCardController NSObject id id id id id id id addCardViewField: id copy: id cut: id doDelete: id find: id paste: id saveChanges: id ABCardView NSButton NSManagedObjectContext NSSearchField NSTextField NSWindow mCardView ABCardView mEditButton NSButton mManagedObjectContext NSManagedObjectContext mSearchField NSSearchField mStatusTextField NSTextField mWindow NSWindow IBProjectSource ./Classes/ABCardController.h ABCardView NSView id id commitAndSave: id statusImageClicked: id NSObjectController NSImageView NSView ABNameFrameView NSView NSImage ABImageView mBindingsController NSObjectController mBuddyStatusImage NSImageView mHeaderView NSView mNameView ABNameFrameView mNextKeyView NSView mUserImage NSImage mUserImageView ABImageView IBProjectSource ./Classes/ABCardView.h ABImageView NSImageView id id id id copy: id cut: id delete: id paste: id IBProjectSource ./Classes/ABImageView.h DVTBorderedView DVTLayoutView_ML contentView NSView contentView contentView NSView IBProjectSource ./Classes/DVTBorderedView.h DVTDelayedMenuButton NSButton IBProjectSource ./Classes/DVTDelayedMenuButton.h DVTGradientImageButton NSButton IBProjectSource ./Classes/DVTGradientImageButton.h DVTImageAndTextCell NSTextFieldCell IBProjectSource ./Classes/DVTImageAndTextCell.h DVTImageAndTextColumn NSTableColumn IBProjectSource ./Classes/DVTImageAndTextColumn.h DVTLayoutView_ML NSView IBProjectSource ./Classes/DVTLayoutView_ML.h DVTOutlineView NSOutlineView IBProjectSource ./Classes/DVTOutlineView.h DVTSplitView NSSplitView IBProjectSource ./Classes/DVTSplitView.h DVTStackView_ML DVTLayoutView_ML IBProjectSource ./Classes/DVTStackView_ML.h DVTTableView NSTableView IBProjectSource ./Classes/DVTTableView.h DVTViewController NSViewController IBProjectSource ./Classes/DVTViewController.h HFController NSObject selectAll: id selectAll: selectAll: id IBProjectSource ./Classes/HFController.h HFRepresenterTextView NSView selectAll: id selectAll: selectAll: id IBProjectSource ./Classes/HFRepresenterTextView.h IBEditor NSObject id id id id id changeFont: id performCopy: id performCut: id selectAll: id sizeSelectionToFit: id IBProjectSource ./Classes/IBEditor.h IDECapsuleListView DVTStackView_ML dataSource id dataSource dataSource id IBProjectSource ./Classes/IDECapsuleListView.h IDEDMArrayController NSArrayController IBProjectSource ./Classes/IDEDMArrayController.h IDEDMEditor IDEEditor DVTBorderedView NSView IDEDMEditorSourceListController DVTSplitView bottomToolbarBorderView DVTBorderedView sourceListSplitViewPane NSView sourceListViewController IDEDMEditorSourceListController splitView DVTSplitView IBProjectSource ./Classes/IDEDMEditor.h IDEDMEditorController IDEViewController IBProjectSource ./Classes/IDEDMEditorController.h IDEDMEditorSourceListController IDEDMEditorController DVTBorderedView IDEDMEditor DVTImageAndTextColumn DVTOutlineView NSTreeController borderedView DVTBorderedView parentEditor IDEDMEditor primaryColumn DVTImageAndTextColumn sourceListOutlineView DVTOutlineView sourceListTreeController NSTreeController IBProjectSource ./Classes/IDEDMEditorSourceListController.h IDEDMHighlightImageAndTextCell DVTImageAndTextCell IBProjectSource ./Classes/IDEDMHighlightImageAndTextCell.h IDEDataModelBrowserEditor IDEDMEditorController IDEDataModelPropertiesTableController IDECapsuleListView NSArrayController IDEDataModelPropertiesTableController IDEDataModelEntityContentsEditor IDEDataModelPropertiesTableController attributesTableViewController IDEDataModelPropertiesTableController capsuleView IDECapsuleListView entityArrayController NSArrayController fetchedPropertiesTableViewController IDEDataModelPropertiesTableController parentEditor IDEDataModelEntityContentsEditor relationshipsTableViewController IDEDataModelPropertiesTableController IBProjectSource ./Classes/IDEDataModelBrowserEditor.h IDEDataModelConfigurationEditor IDEDMEditorController IDECapsuleListView IDEDataModelEditor IDEDataModelConfigurationTableController capsuleListView IDECapsuleListView parentEditor IDEDataModelEditor tableController IDEDataModelConfigurationTableController IBProjectSource ./Classes/IDEDataModelConfigurationEditor.h IDEDataModelConfigurationTableController IDEDMEditorController NSArrayController NSArrayController IDEDataModelConfigurationEditor XDTableView configurationsArrayController NSArrayController entitiesArrayController NSArrayController parentEditor IDEDataModelConfigurationEditor tableView XDTableView IBProjectSource ./Classes/IDEDataModelConfigurationTableController.h IDEDataModelDiagramEditor IDEDMEditorController XDDiagramView IDEDataModelEntityContentsEditor diagramView XDDiagramView parentEditor IDEDataModelEntityContentsEditor IBProjectSource ./Classes/IDEDataModelDiagramEditor.h IDEDataModelEditor IDEDMEditor DVTDelayedMenuButton DVTDelayedMenuButton NSSegmentedControl IDEDataModelConfigurationEditor IDEDataModelEntityContentsEditor IDEDataModelFetchRequestEditor NSSegmentedControl NSTabView addEntityButton DVTDelayedMenuButton addPropertyButton DVTDelayedMenuButton browserDiagramSegmentControl NSSegmentedControl configurationViewController IDEDataModelConfigurationEditor entityContentsViewController IDEDataModelEntityContentsEditor fetchRequestViewController IDEDataModelFetchRequestEditor hierarchySegmentControl NSSegmentedControl tabView NSTabView IBProjectSource ./Classes/IDEDataModelEditor.h IDEDataModelEntityContentsEditor IDEDMEditorController IDEDataModelBrowserEditor IDEDataModelDiagramEditor IDEDataModelEditor NSTabView browserViewController IDEDataModelBrowserEditor diagramViewController IDEDataModelDiagramEditor parentEditor IDEDataModelEditor tabView NSTabView IBProjectSource ./Classes/IDEDataModelEntityContentsEditor.h IDEDataModelFetchRequestEditor IDEDMEditorController NSArrayController IDEDataModelEditor IDECapsuleListView entityController NSArrayController parentEditor IDEDataModelEditor tableView IDECapsuleListView IBProjectSource ./Classes/IDEDataModelFetchRequestEditor.h IDEDataModelPropertiesTableController IDEDMEditorController IDEDMArrayController NSTableColumn NSArrayController IDEDataModelBrowserEditor IDEDMHighlightImageAndTextCell XDTableView arrayController IDEDMArrayController entitiesColumn NSTableColumn entityArrayController NSArrayController parentEditor IDEDataModelBrowserEditor propertyNameAndImageCell IDEDMHighlightImageAndTextCell tableView XDTableView IBProjectSource ./Classes/IDEDataModelPropertiesTableController.h IDEDocDownloadsTableViewController NSObject NSButtonCell DVTTableView IDEDocViewingPrefPaneController _downloadButtonCell NSButtonCell _tableView DVTTableView prefPaneController IDEDocViewingPrefPaneController IBProjectSource ./Classes/IDEDocDownloadsTableViewController.h IDEDocSetOutlineView NSOutlineView IBProjectSource ./Classes/IDEDocSetOutlineView.h IDEDocSetOutlineViewController NSObject id id id id id getDocSetAction: id showProblemInfoForUpdate: id subscribeToPublisherAction: id unsubscribeFromPublisher: id updateDocSetAction: id docSetOutlineView IDEDocSetOutlineView docSetOutlineView docSetOutlineView IDEDocSetOutlineView IBProjectSource ./Classes/IDEDocSetOutlineViewController.h IDEDocViewingPrefPaneController IDEViewController id id id id id id id id id id id addSubscription: id checkForAndInstallUpdatesNow: id deleteDocSet: id downloadAction: id minimumFontSizeComboBoxAction: id minimumFontSizeEnabledAction: id showHelp: id showSubscriptionSheet: id subscriptionCancelAction: id toggleAutoCheckForAndInstallUpdates: id toggleDocSetInfo: id DVTGradientImageButton DVTGradientImageButton DVTGradientImageButton NSSplitView NSView NSView DVTBorderedView DVTBorderedView NSButton NSTextView IDEDocSetOutlineViewController IDEDocDownloadsTableViewController NSComboBox NSTextField NSButton NSTextField NSWindow NSButton _addButton DVTGradientImageButton _deleteButton DVTGradientImageButton _showInfoAreaButton DVTGradientImageButton _splitView NSSplitView _splitViewDocSetInfoSubview NSView _splitViewDocSetsListSubview NSView borderedViewAroundSplitView DVTBorderedView borderedViewBelowTable DVTBorderedView checkAndInstallNowButton NSButton docSetInfoTextView NSTextView docSetOutlineViewController IDEDocSetOutlineViewController downloadsTableViewController IDEDocDownloadsTableViewController minimumFontSizeControl NSComboBox noUpdatesAvailableMessage NSTextField showInfoButton NSButton subscriptionTextField NSTextField subscriptionWindow NSWindow validateAddSubscriptionButton NSButton IBProjectSource ./Classes/IDEDocViewingPrefPaneController.h IDEEditor IDEViewController IBProjectSource ./Classes/IDEEditor.h IDEViewController DVTViewController IBProjectSource ./Classes/IDEViewController.h IKImageView id id id id copy: id crop: id cut: id paste: id IBProjectSource ./Classes/IKImageView.h NSDocument id id id id id id printDocument: id revertDocumentToSaved: id runPageLayout: id saveDocument: id saveDocumentAs: id saveDocumentTo: id IBProjectSource ./Classes/NSDocument.h NSResponder _insertFindPattern: id _insertFindPattern: _insertFindPattern: id IBProjectSource ./Classes/NSResponder.h QLPreviewBubble NSObject id id hide: id show: id parentWindow NSWindow parentWindow parentWindow NSWindow IBProjectSource ./Classes/QLPreviewBubble.h QTMovieView id id id id id showAll: id showCustomButton: id toggleLoops: id zoomIn: id zoomOut: id IBProjectSource ./Classes/QTMovieView.h WebView id id id id reloadFromOrigin: id resetPageZoom: id zoomPageIn: id zoomPageOut: id IBProjectSource ./Classes/WebView.h XDDiagramView NSView id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id _graphLayouterMenuItemAction: id _zoomPopUpButtonAction: id alignBottomEdges: id alignCentersHorizontallyInContainer: id alignCentersVerticallyInContainer: id alignHorizontalCenters: id alignLeftEdges: id alignRightEdges: id alignTopEdges: id alignVerticalCenters: id bringToFront: id collapseAllCompartments: id copy: id cut: id delete: id deleteBackward: id deleteForward: id deselectAll: id diagramZoomIn: id diagramZoomOut: id expandAllCompartments: id flipHorizontally: id flipVertically: id layoutGraphicsConcentrically: id layoutGraphicsHierarchically: id lock: id makeSameHeight: id makeSameWidth: id moveDown: id moveDownAndModifySelection: id moveLeft: id moveLeftAndModifySelection: id moveRight: id moveRightAndModifySelection: id moveUp: id moveUpAndModifySelection: id paste: id rollDownAllCompartments: id rollUpAllCompartments: id selectAll: id sendToBack: id sizeToFit: id toggleGridShown: id toggleHiddenGraphicsShown: id togglePageBreaksShown: id toggleRuler: id toggleSnapsToGrid: id unlock: id _diagramController IDEDataModelDiagramEditor _diagramController _diagramController IDEDataModelDiagramEditor IBProjectSource ./Classes/XDDiagramView.h XDTableView NSTableView showAllTableColumns: id showAllTableColumns: showAllTableColumns: id IBProjectSource ./Classes/XDTableView.h AppDelegate NSObject id id applicationShouldTerminate: id applicationWillFinishLaunching: id IBProjectSource ./Classes/AppDelegate.h 0 IBCocoaFramework YES 3 {11, 11} {10, 3} YES qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/background.png0000644000175100001660000025114314776170045025716 0ustar runnerdockerPNG  IHDRXr5sRGB pHYs  @IDATxٲeq:YUA#kQ~6I$E } .2c@2kjX>+$/Hub{?==}w}Tͷ~'}}7'|;>G?NZ?>>zCυN奩{7~իݷ}ʵl+nSzH׎oi0ɔNr}:mˏ^|h7/߆j zIf^N߾y3"VC'#)M?}6^<گ럮X_5r/ߍE7t18 %~3 F'xb'~O]}<ʈsh_}*qa#=ն4-OC^y [\69~wxW#rz$?yh}>6WN>:L>ŧifZ u]χW}ؐؒl'X72nj02-0撞2򫔛WZ@0п}6_\e|rM VvKG1hN,}?s~:Z>7O_zzgV**V4ҪHV}.FCG8ԟ'&wȃn;TH gˣ~)AS' ɔ]1)|TiuN?G5qQ9UyҾWN<®bd;ZW%oǿݑ79bun 7vym58wΎ̫61ASUͳS`4>7|Wo1s!;*213yWo-#s\<@Xt<^\qw XņNa⯧J~r|}e>|d!cw#oXoAC Sr|wy1 zINC~~ËGۨ0ێ{]KhcݎJ`JnI0L``v~с@F1BOա7%v&!/@LoSnY8O\ 8򣭱$O&ҩC]qx|JAƇã߆8^ S^2^yhcٹƩ 럂Xٹ6;fhO?Np5Rڡ fk{6pհ'S0g|0MqeՑ.ʾG7 sO/ϔіqi?qeMi{:9儕 @_?K^znv,;[dA>Mz/B̟iMǪ-Gcvqi]#SM.׿yGT%, 2l$4=u.p$__NU6z,wVrj:׎>Vgzi}MC TNǿi;ж}#đO۵&Ʈ]&³>W7WBn&̓TJ0Ȍm5lŠK.]ƛ0׆c00o;s=*0)] ̟ ~]@#_i@Emr(mgTMJdkڄ\w,@+>.CG =}k>?Ow ]u{OfsmΓ̉KOU_)ZGm.viz)_=;(]@cg! ;庘(g6z'_$[)ir; .yF#y4zwG|:S>y{|ce0yN=<Ӧ;r!u)Ӽ,M2A2>:9m'wJ㟞8ӹR?kb"}(y\`?W;ll_hY{ 2QC/-gʙႠҿ_:xQo X˛'>XIqJ)RpA|0?aejQi5_cx_ct(;gOv}pu?wlVTmt'gƁ<ںw0P]C^zP (n,;ތOݺ5a!+*sY}!hf m %=j89=t@z'3e[7>r5$0&GʑsiUg]L0&LOudwi( W^@*Shӕ%S ײ|N!ǧ̤kCx'0Pʩ˃gS1hxq凾}-k/?3#Uʩc]֜}_]'O4pv t*_d/0Bǯ)\Ԕ: &#+:-ç z_䓵r bG^@٤{ĥiR|+O;ШIvZ/_~:>#SWd@Lw04ʶ| '?ڦL/v_ٸݛćXy#]z(1L?U]W_DL4|1&,"ZZ.-%WokZ\M(i=6ԃӴF@ O~wׁW?ԫ\xǗ4Nb&]ݭ.msm߾7o2G9(m1ި^~<u7O~9roKX?Hct jH'.oh䡗o!q?H*[_z"U^@\R4M3B3i ßSCoe.T ȼ"^z>>y<=v>\>z3`L!O.iMGUVɟ mK現=OeGǣ /-CVnߜ?`tlc߷-B%FV`pON L`O-t> MLzQ1jܹ́sA.ȣ+y<dRZ=:ugu.kR 7WCvECʉ6}sUYϭG[6e'>rCKC׺7M4yNƎzW,򓹃eB0&#nmXn 8 E!.pA_y)znpTG;`&w"2{(ۂ$(e:`|~|kVp7_%N=xG8eՅW0O&'%/tv$9C&/[~*0O|:DߣǧqKS?7Ix3}6yhȩ/"ȓrÇz_!VM'nG_O20{ߜo5Y^X|5bǐeƻ vtP ;# ر)KCQǡNq<2S_x~*{ 4y=֣2dƫ C,w"|飫KCѧ&~m=@ԺZOiGZ&>}tbg pu׋Hmh%]tҮt!~?;͟fcktcyN^Ł ЮWYMyT3` *@;ZO28T^)WI+'-凝0qhSzizteܑSۧ.<-hO.< g#ힲSi4MUȲ>';]GӥGVc:@5"(<NZ |LqX!pe[ƨ?<`KGOԛO\Z]dh+_8*W#Jj^JnJ{Q v.!#:-(ƣ}uhՑ$p>WO8ᤫyu;ߔ|Y?3gdΘMw?tG171+|&Y'gQCc4_*?ć<0*bUeҎ -SYȥ>29yW\q>2sH`,!e.%A\dh&ݤ^my e8 hFϥѫqmh$K~~h!k~ōmb&VB uʔax)p'@3>'@tޡPp 8 @/ 3GhSĴom 84Vjvhpġ 8FW<;e2.~;zuz!zhAi?2Xѵ+\ |HjX05WCL5sdLv|t+d=i/jƲ~6;Z1ʦ\  sd8֧N}PG 5B*+,4Mv5,SnԸ~5@veS ·}" j]M/h#VԩJߖ^ώȵK5n'O_3֎\eZqJ, >P)joyg_iH#]K?){5r"Lw{ 6]^֧^h //H\͗ޖ, fPU{ehߦ{K;ϺT}yq̋]Ǿuoux]>sc#1\AtKc˗f`hPzOzJu֕#7`G'^Ժ*8xcNߧ8qR>'23+ MZGI"WeY^+v&b:fTT@NL As` Ԏ"ggrWQu>Rv oFQآ rH?T9?kL9^31:;J { uҔ`|[]ySD{qt,||9e0&</eGx1;9ϮQ,Oq?KN<ΪL&`I\\yŽyOȐ)9e[zi)("r\)O~!:4#2r7/v_?[bGjt)Tڮ4>+M㡛bc5횈4Y}$4xzv_?WWGL&ai$gD^7Q_G|L>+2qS֣\vۄIeHq;|}ӆ9*d(<.|NN^]enM3'8sMy]Wk~׿x3&R((|՛X(\`)y?g}21Cs Z9;^_ ,=,1 ,@ 32(b9ҞKz#%Gx'A=ڦMyY)F<NJ#+&~̓Q`xowv6zTk]Ʈy}8^a` -ۉ˜րtW]#6.fQ̦(kH3XxO0@)0?{L^4}Ij2'#ox_çryoH" .u̩B9UD&E>i~JQ0Θ~_;e'15s|yӫRv#9i]W]Å5hXxV_t:bQ;j?or4<%)t0A-Oh/wy|/ ߟTz_:@`‚l ηCS8-ăK]W?k[_F~;79sGޑ @>@3ۭͬ^p$I)w@͹أ`=Ё;o3U QX݃Ҷ;|}1pvW[s탖㓿m'>ӑg 6ҕo]riÛ"h<׫,M^wv-RJrɢ7cjFˏMPoNg$0 _  &xL -g~u=6u.O(yQt y8H'">(yшQeնm8:Lu m O%RdTFrKώ]Wgjkuw 2; 2< pktOWT/C#ϣlc,usʡ QzdSy,_ ?ort'_9Y7m UvL0U62\[avh7Rڞ)đ 0 K^yС @l>qu,yRd Orhor&N#}4}ΩgDŽ\+'s19c*;wwP`1&}aH NmFz*]6di`4 7?uL]m9~$`oS:)^\׾yZzsQ`6ٸN}#Oqus˷C>ump:5 w!#3V_,Ʒy";@1w#W_<.gʋ;*S2,|F#::IơSC=/5& N9ih]hr1:Ӧԟ*O2F,r':myico8̎v{O(->xr7_:/͏miv_6'F.&wί!op{&TYnJZwey gg|R7`dv'N0gx|s)h y'ڠć/ ~zT8u3~6:r(x(CDYy(:'8igG}xrq;g_t]`XGwDGXl7V!>\ra1cQu1(4d/p[eSǑA]gdDG(V<ƨM](5r;@%ƕWy!1|Ë˱ٔ'_.ooozwѴ~7KzچlO͹& ;/=}wYI~cwo)~3Cڲ憾ٲs.L_n@W6sl?r;Xb4J p3MOvNv3|OU8p GݝJxd`p\=Sqc=h.<^/1q"c04E4;[ɿ}-w,gVǔ~G>ؽ/Zy{y"} 'a,;?vg臙OwWϚ5.X5t'PyeX)Q;4N:bgHAs@$Ơ_k≣w =eǸ_ai|V z F`Łe2??isCq_4.Z =.m)>};}Xq&[הK=NXOs k?6yu"ڼbӯ_r3xR;kl*?;VC#ub1 G'XauXrN z,+q@ 7U?w j랯>y^Ĺ` XD x##]n.Gr+#ʯL-op4|N}WvV}ǀx4FdWÝZO\'Î71?sNxszIQbiLJ2DрX7e˧iYXnX)|/^ /ZmFmw;ip;AVз ww3v_Уtd_5$ؕ-7Ֆ@Q$Ԩ?<M󂆁fO7_#Nss^/}s]W_O:"jTBOuɷ=jr'H>h$ h>fgcԁwңf(Tn XciWwS^AIiS]q¥<*4<ҲSw_/rg"젍Kx8i|2֝Skq]G֞~__ٵ/^-?.@KӅ)Jq>I49I2R\(RPuD 6đ =1×㓭B.c-&!^~iDŽz," ghC0+/_+sGzwSFZDK~Hd@pKՙ](Koaef^!̑Q_&}ͮV_6,r:6kO?Oad\[l| V]8\u£yR&ߣnGo!ݪtUw#Bp6G~eGyםIOm'G. 0:3=Wyۗ -^'i&w#[_)6M]J?KymW޷}юV۷?s9|@{tY?7?yPIx:kHyI 7P<0;nXj.`!8y݅ Mr y*;:*dr(^H?:c B\mǽ.;~Oaimtd}G2k[ߓA0G G۽+]YeϮfG(J7؞7YGdx:IĈǸOx2tYC]y\@L)zO>ys "$,ШO9x>ԭﴍ#tG@@U&= Og#E}-l H Ǯ.-?cȿ.3/m߼4㲩gmnkʸ4ƞ I+^nPܹ[N8:шTOJU1ٹI[GΧr{)<590J[#wiCZWs9p[Uْ7{ʳ`RɘU#S%^I'~]9bj\fhcp 9'[ Qawoٕ1bM1૿q-7A}3#Uv=Eɏnjv,Q\GTN7  !NzG~yGg%JxL: l ˀ't]ic\/mզ>S].Yz|hLM;+T~32M-||dk;WkW r(?_*#L6au*?tYgϷw_v4v/?dރ2 eP1{ H0'51S~2ceG!{𞰸 G%jL O iO \G{)[p1LW99}$ΑG=Q54 _~I RXYN9w2|W:i]tDuB%F!wW ݉a&o/_cNb0a=zZUaE&佝]ۋ}25ʽ~rGS rk%#@y*NZU/ziIWh_M_wۮa=34Gx꿷o72IIS_n&m퉑dhhӆKu֠eKL!"ls]򝗻=dNUYUvkqp٣])Cn<W;sA?_`@IDATf?:khY3Ο_h 3pXiƟ.@0tA ;2>,F.` =\ 39Hw@ \]S:d\~vFfd)m)rdok?'C4/uN_u@H6Xk4QNz5#mL} yXp,\To~CǷç% aOC!3>J?1"=@ ϡ备GU`-HuT)ʂ>Ps_|:΋.lC_:jtȇdk3wƚtlhxrKl~9?oONټ|8m_*:ϻ]ŕZ]e4}]ghTjL Yp12 k aA%nwFDYNZ'O?wg1?=Qf' /N\؎O p"{9z!`Cױd3U&tL8u\ m$G~[y.ULYm䚗^MJ:){)9׾2O;;K瓰b/ O»wBuɝ¤9a1\. 3`OJHN(蔿@YtxBwU?lJ?Lj+v8NU\7aN9||*FmeU#!nN{G@__[!zm\8j'G/1~CG<*Y?Gӝoy?zZ?_rZlqnjx=U#|)'̨Hxr=ƛqVV9=5P|2(%xY~}o*LQ^Mpxe)z14@<]dCN2> W F?iz.<'/d\*Gƻ/`sQ=y\ K;;׼wtlc^v=X5|5J 3@A+Ƅbˣû B~Md#wl'b@Qm80]!U;wцvwOM/'|k܈:}tŷ2tMbʌlWXz*O"y:J?럎M *P@ZHC+a1I/4aQr-£<) ّ*?zI|@Lz8M@}ͼ_Pc˃g% `6O*'8zry׶u'rx' ϸVի,YtW&y0 IVsrU&}8tx'/<].mZ饕&ώ ;D׈]:1G̏Gꏇ[Ga~7ڠְ2&*o10a ܉hЄnW|@>sgW)3D{[#3 "Msd&𚴗Ӄ|>h@} M]S,e6|eЮOPIo@v [;Sy+H;GV.'"Qtk>ovu5b~WZmRpZ'a.@#P;S`Upc+yuM+/ lGYݩO˼yPA;a2(vQ<HGtiK9 ߅,'OQm\ ?yzkJK4:kʩkENX$fHqn)_47/iuuhMMW]ﺬ:j*K^^,Z?owA6vHrq|&<#kPkPP_m뾝w^5}+4dM:P#i%vx>N~tҎ'ЇgD^׎5?cGBi oyꭑt`Iگx'x}療/g?}a>3~vwEI_wg+R>5D&;85̏|x$\,( ):lʳy!:ež.w@9$t9[|q,~z.@gO>{3m!ݹN"@]7Y%&wF,K'=3a}2 N'8͟()Ü5:LHռ1Gpwы`_߹Utn1!\cx] 8XXlֵ,(/8`}Ͻp],P^'< Fh3F`F])ΎFF {Q\AQ#^C.I KLj@ UI~mn]] ś]3|{q-~ś#ԗ?;;g]WӋlc/kKigushJS)YOLjq!>@XUVCSP!.9RUp<թ9>ʱwG,^rN#>Q/Ph?h#Ӥqd'-}2vMЎɕt<&\i#@#&'|!t6F=:idF~?R¯uT$̟:Nk&EgRFWAhOX*Wv?F~vvg-M:-n ^*Gܔ/ LL QEf}ˏ|>\S[ڇxvg.@GZN#Xʧ Gw&(z'$Rܥ e+*+ASɳ?=Bw£'W mV) NFgER^ॡ>Y|yxp H+; yej.ML\<*Ґ#7Mz fҸAQskDeԋm$ xקEIauMoYvO 褿^ix幨._7HZA,yS>y?ώ]t8z-z{t í_yΌX0kVVMetB:{ԣ\s1,pgΩ+0 {<.Oe-gqp?D?&U$aX䓯j|ʺo@&eIW &W%Mmu@-MVz3e_kh4>OÕkǎ]Wk&~*Af*,ƙ1G 40 J0 :'rť5ʖ?CO_>qWHw ;紷 1|9`mG r˳g?/_ǝh~K~n;ᒟ;;E]FƫŎL1kY_3V7lbuxN&^8Avɽ!q0\ }BV=)< &9Ov%9؅/>ϛI{މ6~r+wel){Yy 7<7]=2J XQ;%Nt~Lաߎo>y럎ґVKf[~N>y?,c?'d;;gw%uyV  f-2\.ޱN<'.y@|G30$7C MJ ԵP?cd*a5w7>'}B~F vqf oՍNY̵H~ U1Ik+;}r/~xvת?N.w؛ѣ~Ϝx_uQ kpZ) N0p+(*RvD 89ym|͎ZzRaPb^mk<8W[ޥ|y >>B 0p9 RnӏS]x _ӝ<}Z]ȩbφ_l|"NLՒv+^w#nrgkφ?ׯQhr]1½S1_X Q{ixQ z`S~*Y[G}/}(r+bWNN>i)?af:Ȧzm`0^iox-COGy'?2wQܮթ -Žӏ`U/`ӉS<~H{ -? ܌ +`&292}0CW.6S_ 9CQ*:Xe*ࢼV^[ȢK:>yAwZ>.xkiaS?-}\>\b.+;hd˩]?{u6M@@!:K.K3Abp͎NA Sh:'<{[-޻S8 h\'?H\)kG*|B?`ex8l[Cw̨>o `nq=1}6m:)ם(?s.w'+}:HMOxa*ם,2?ɿNM;;wN_lC^4Zp3 ՘3 Pt4?aǯ[ Qr*$/SQK?sika >X?owvǸ2,ccXfAH1vBɳQ]^.*F2j&G_ >>OW%]\TWV w"M;b*h2PMZy+mӶ;wOcV9mܤW87M3ֺ֦^2ϼ1 süO_oD7O7ƕ{5>`1ҁƗc9q. 8͏>O/,boMN䝣#Hu p!rxi64yi6eq(}ہGO`+wĮhNs>2O~D&:]Vu/?_9^rtNO?zJѤ;G ܥⷢ)+M |18p]Y@(P4\ɻˣ̷ '\XFP%vu䤾)kGВ=ױj˧Qw˒ Ar&+Bp)3ʄwgΦv3fԮs+ǐaO6)e?4K v8uVzfC˵D?N̴c?ݲ`c۪oWCOpFS#΀*nr`j:"^h#(y+̀^N#U)Y1){&nLGR9J<]R8;?I?u<ތ'{XD]6ewFgu\|#@`՛[SG߫]1z$vt]B?_;:s a:/͌M1=?.,YXod C<$ rAZa/I uXU`\H^Ie?r?[7SV;Hh=\A ^ItwmVR좩Kywy]Nwxrx槀LMe@<ҹ#y/_ϼ2W]?3bEt }r!se IeMo2]}U#gI0Hj4|+[dp?R߬.6wlKsɽȌ)(9B (!V01#=`C|LX9!S/h<=it|ɧqoy֫rV<,Rm,: 4u+k,\e@47v_ލm#Ÿfh17,Bc{&GlCxS2]4$)GN/>wh?nm)Q%S$whCd|dvF6yh@P#4OT~׫5Z.^>ێK;&Qw_3wԸW GÇh,74pr-F8D'1yu͎e | ~Gj_=w{c,@38 \sE\5lDB'vEom:}呗SX܁2L^>Ն>o-48 SwkKNI.mߜ0W,s^&u+5?P_̷z7VY0%;ihνse1鸸k7ՔH0v}%9^q /Y"ǓsF̣2J;|~ (J2;Fh˓ );RkrkyDž_ ܚ'm"W_+nF/mN ~xG'ڶET&F<??uB'kg5 uek`htAl9~hcހ(() XPS0s:06!3Q) M]]'~hiW 'od:#+_z4Gy#m, _=~e!թ<@{mm/E]GWvl&w;#ttCQ£S/ ;Y@ `I|~q!v\&LВ|Coz#u#aYS}E&|rD8rr!Oh#裯HƩG_VƓv<⭌/#|39<94vww_?:uLHjc&p&ULb'.X_~@P0D_|q Cww8(o廩 چ|[2SG'ymCsVKx neF P93ff/ړoFN'mvoBMm:.9&׿[Ĵzamcww;\W #Pcx)XN<p5h u4CΩ @)#̧ A3x"_ MJt8?GTSS5K^6aI׾{h;Sl2_P͐e^q-ǵp,y*cD|m(vO5Ad` XV[{Ő=jl"~a` Xٻe˒<(̪ik@Fb? R{A@~Ac@Ue]2Kꁈ\'n7G^[ <~*Lƃ? 6Q.e/kW9am6 OuM~5 UkGJ>Gir#kF{ErUr˥L쒧;]9yu}Q>o_>Lc :^ 1/\#00wめ4^3C` ~ijc2iv |=/@OP(EI%^eR䵞 d`+7z]E/> >Ao]2erH#rxkٶҏӾZ^o?vww"]7χD֦k&EǯtE ;6"܀Iu'a~1aC}#~q-|xؕ*оeUI -?M ?m6 SĹQ>y阱u_~C/#}z3~C(shK\}x7WВ.?jRt 63ƍ^y;;ww?zqQ~tǗϺ\?vOq[$鐇!ϥjY Ng =fyم߷N.25:q;GL1߼ :[~ /d36y}wFY<>7-& #'M\n`Y#`l..,4ҺVxƛB+=?YL4 ,t^މ*A <:ao狫*F]*)>12*4駶#?eRsʓMr:Py&3~\SvGsz6y+ܴm>#2~ %{T9^{(*V4@/vsw07K|c}4ߎK];NADhуbGEq cC4hFCq4^giC;Hݺf4*kw N|u]f/2T\e]z,9wvV~}ъ?KP#]F)KoAϝlA˵]w9\%? w3}xUvu'O_6Hk8SǿkvmG>#wq޳k9L~Np?u )v{oT- 3j~t +J >$4 [n/f\ LJ2uNSF+x*h%cDi;sjJҔJdkAKf@W,@+>.~'W;)G[yiyA$~Wz,&?˼2g.:7;vɜT9bCC%Owqt!Hi@tɊy 5(Τ9 |u[b7@\<3(eшF/+͠N(O<7Ǘo=V ˧)\Hdl'x46,q2zzt;ٌӎ]oz#}2 n*?Įy1al͘te΢jKOx 2=E^ \T^/uқW~:w~^۹p"_xͥ:_ڮNy~36=LO'{O, si]|jN??ǼhߌxPNXKw^ǭ?)ͫ:yW Ba^$3eTȋΛ!ͮȯW};ZlJv$^(84 m:&Hʛ,e5@ ]'O_6ʁVkHzD3`-olc%)eK[o1lDky>*KWnÎkrvn?pTd׿ݝ˫Wqm'{> iU` Bc (n;ޔO!Rn~Cj p~v4_3cFѕWӞkx5ϏD: N{9>.2^a.]]rS\ͥWStG2yש'royṡ̹]Ůtw?K1%CZC*6ir@;mY~W17d\MZph p.pa5^'PnrWS?{\0oZa|ʂFz@츽? HrZ\Pc׮uW\%]*~xsEΉ?.d=dO/<;gC}ka.a>ƄeTXK˥5qwAC|s?;W8uǿH6ȈӴiE MC O~w^:GD^zF#<%ߟIW_Ĥ>G2{|ZZW#i .3vw?ެ葉sh[ҟHƐ}=[ ݝau#zh䡗o!q?H1/=^*/߷v .ghFЌ}Z۽t WK?|<_~OF;C7^2|ydÓK|szo=CR.CX9Qvxt&uSG6w_ȏJg{j3{?}2w9r F3n0&"c\A:=T!.pA_y)z:t pTG*wDi'V6qppk;r CGzٍ'sQ_w|'g_ʶ~40GzY'юWq0 *KhҎ^j]"U^wrb@IDAT>MɛGؑ6 J?Q<|;lqrQ27ihRϡMR.NMbAr2oWȁ&4/;nNM?e`V9j_]?|5bǐeƻ vtP ;# ر)KCQǡNq<2S_x~*{ 4y=֣2dƫ C,w"|飫KCѧ&~m=@Y%ZO{ʟOħaB'\"Ri[8u ?o??]|_NGWa+@80WaGUxSu Σ֓Ń 92||'|ʕ金_O/&_9i)?9 SG@%KP׭/rGNmO!ϓ>y Ry mw_(3|:폴;u:x)=Yvd?]w?֘LO |<ԓ54v?ڤKnV?i툽Y?޶72 7PT-OCc4_!>&?a $xc=2Le!5_?G5\#6:G.siG\7^`oǿkv?__cqckأ GUGp))DqscOΟtޡzf'GxL]MW:MF{(}To<͎gpw_ka?ѭANx=m2o',8<{l%̡m}Nɳ',W^M3AJCE8Kvy21u%d'\g}>ў|/pkoʭx[ߑs0y@yoא)?Oə8U_վ!4uͼ9fk[qk(q5JUh)gpҍq{h/>w-#4ԁu&`p>`G^~h ̈½xG 9Ҕz(ʹe v@ן^|x#QƯmO=o ]ŬLvq\ {mޚ}!V.uؾ~Zʯ2J\D"\1 _:s$6G̓0o̥꜔1ώ΢ÞutԵ?r}d_Ă +o@[8vU8V]$2MB]V &eE^@R䚸2chHL$VEԣ|OvS'G#dp&Ї>lS sd8(>u:e; MC4MzRװOIS}?skɜg_|v< SN@Mt%m < }|)O| V4wpvq<~/1qs7a"EL~ep~uMy0?{_ȧlT8\O\ACW-w#:]CI@+gvww_}NIW:n7O~vu .CLъT&`QaJ9tW~7xK=3aqJ tFz^IY8>aҸS3Q>uoGۇ>@nhϽ~>i>=\nǷe1;ڨ~.C6-\1uoꙺ*.wW} ve37F:{"tKc3L }.}x,NIYκv,P Z] p)^`=Ogwdpv14|OvegIWxBMC>L6xE(vA\$,xxMm@y8e{yKc<ږG٫ ;Z]W__ӿO^1 cʍ9? h/?ϫ FKWpx0"@t657aGH@| f iPYR|PҶI ?a#?\=G!6U x]d/N^ L?cKB;m:n PյMgtQM2iտr\<̛4WyXm@1GW./:1! xu?Aυ򃔔LJI;S6;g8<#qhퟰ=3?v3E)j7'a 8bLzMƒN^>wN 4wrGC2@ \w@P,#K>`W,\nj ԩWzC!(?q.^Lq]d,Unqu##NİP(M:0qȷѕ'<JG'^ǗS6cɿʓώ|Rfx3'/Ӿxē;:[d FUxϕ/1iSDs}mS:PD&SCthF|eз-|9^7?==o^bGjt)Tڮ4>+M㡛bc5횈4Y}$4x ,FM@-.hIщoPWze vLDaLk@ A lfSvcC\Wz , ÔIK㌽p&t$5Α7XSu7$:T!vy*"Wdgj~I4pC?N(ugLkٚ9U)I+š|4?O*/ S0aA{ZBxrݡ)]DwmO9{L/nv^nl&]iW6adk=]!`4f ^Ch/- ?-PƇKi$eWh?vwosxS vė(/9l{HEw  bfH/8$O”;`r?0͝t* ~h(mAi[>ˋly-9A߶ ʷsx?iQ_\MniPa4U&n;t){dϛ1kgW& yjxsTv^vSr/ o}{`t&lK K~Ƴuu=6u.O(yQt y8H'">(yшQeնm8:Lu m O%RdTFrKώ]Wgjkuw 2; 2< pktOWT/C#ϣlc,usʡ QzdSy ,_ ?ort'_9Y7m UvL0U62\[avh7Rڞ)đ 0 K^h/_1yvMhid'O=E5ߚ x^B7{{\59}J~.nTh"H'}|xL&>?;}?wWG_s *EGZ t! ]1#tGV\ υ@_rW'S.Oι7'}|PSF1m4q)@N껀;rI ʽ.,!:;H}yС @l>qu,yRd Orhor&N{#}4}ΩgDŽ\+'s19c*;ww{`{Ӱc$'Fg6\qwGS. y4u0w:Ѷw?}[A7 )yp.kP9/p2+7IwK}AiFy N>P5iihs~_D~@1 Z7:a Q|>!pK/Ey}->? {sEb؁ՏlGm7_]^CZ>ݓdޙ ( 7qƽu2 ODx⎱ + ȃc!dqԁgPϋk@M SNZv\Nx$/䪌dj\:㉎h[^Z,Ni+/Ǔs4J)s˪\ww͗Kks[Z1]W͉okfɝ!kț,'(Uۄ]} Ԅ óJ\Z>)@A02^ɓn'KŌ@v3{_l`C^9<ޓHSw}mPWȀxi?|}cM:rk9t<93vy:p~0ޣ;FgǐZ1Eb`b cpXT]L6ʥ*MAEKo(:oY qdAg ih|E#V|:+'{AEqU Q|QУ v6ΕoM4 [2-K_HЗᙾVo'.<3;;ugm92L3sm\H>TNY/O^ݍlxBDGI5jħo0,(ݑ3۟%FqG\<=Ҹ*;D9;_oxq96KWMZ}M fIBB0Ե[4I>/:wܤxG.k?io,.?eFr[[v;3[vtNҥ f5]:7nsRFi@C<`N .| *.胾S , _'"x ;Nt,G~%&N6B_Dq tS fg+W\6ţ}y٪OW|EC+/|t6O_o?$L\]e1ǎ0iYa \d;v[%6$yd$k^H.`eĖ_)՗o۩<|ЪOu>4f߈l {SISk^dv;F;gbN?_"z<7?WW5 CI^Ft1pw#|xl4- k BÓC?ԫJSPQ0󡈼`A E;A@z8g‘.S2@(_ //_ܥ"#ʈ[E赵bG# ]nG9_4jѮ]z쫆WsE.)cgjԟLytLڦyA@3§ᯑnڹѹ 9j|z)['?5Htr+CpI?.ۃ$x8r/÷F\vT yG~ϟGx<~(]WV9:@؂u|^dw_O?oL5*@Pw:g 5$44 ƿeC31@I@Aщ3 *q ؄,|۱޴U).8UtGGOi٩x/}U93avF~rrԋ|<4z=֝Skq]G֞~__ٵ'ׯQ@cRA HIgBF\^%D8[$ݜM).Qx)Wwct }hIᅞ]!P1GٖW/?cx=3!N^9ãX=)#-m"%?pltw 8%.uL %i}밲}5Ȩ/?fىW?95׿~R@0.`-6>tAN.lp c|p"d!Lw껱QvJ?{VٿQ=Ju3}[2IY$bcǧd<\SH.JA<.m& =`L'g?^{ZPVbhԧf7l[6]ORt.o^}hC<}QwƑCQ om OxʧBkѢ6 $yՄcWr1_Ǘo^?P[qPֳ6iO~J2:g9#wJ۱`9:wfr|gVGN4|3SoRi!$upL Dvni@)\rʨ7wuͥx0]ZоC,\&VUM,oxy2f~TE1!>xɅ?_lw_}cR m .s<Ἕc}r5vwz],6JÌ % (`_|0;d9:Iηk@KGgCXy L lq's?njWZV߱dVr o}d2<|6&=vo~ʮָh8m^N2*o w肵Ox('p~q0>`c@ IaP0q>dܠ+-^wz̽4Vre7V`oY~qZS0ߌ@|r FΕڕB\i'# W.}8Mi-;;yfFY]W fO{Xf[ J2qvAi%आ;{OfL(dy$1_DsId >?㩡<𕓟vO[9e .&3r*:9g8*?_~/T9v8S_ +i8V[J'ޱ럎N:dN9;=lc~_+s,I x:̢a\'Q/^\*h/fe{rħ\&eu(-4Eb.<@;i/rՋ7ynZGFWӯYmׁ0_vn~#<|72IIS_n[ZNc{Hx ]7[Sw0Z١Ozh ]]r[?O#Oix*`PGeA'mÕ(F`u@؎ڮ]W~'?+,*ry|#NcɅk`maF ؠ (('r5bu@x*z==S^ꩡpߌR=HǯLp@K~0ihZF]ɟ);+u] JS?,78mȿIKWSrdHx(//mvWNs<;;w=?hE ;]0 ^Y.€Bo<ځ/~]8ul< KF6 &0Ȝ+k9Z)g'{?4-=jO|#;Ne@ۮrHN`#[32vȎ@?̓}]:/}=4!?+3wƚtlhxrKp~9?oONټ|8m_*:ϻ]ŕZ]e4}]ghTjL Yp12 k aA%nwFDYNZ'O?wg1?=Q/g' /N\؎O p"{9z!`Cױd3U&tL8u\ m$G~[y.ULYm䚗^MJ:){)9׾2O;;K瓰b/ O»wBuɝ¤9a1\. 3`OJHN(蔿@YtxBwU?lJ?Lj+v8NU\7aN9||*FmeU#!nN{G@__[!zm\8j'G/1~CG<*Y?Gӝoy?zZ?_rZlqnjx=U#|)'̨Hxr=ƛqVV9=5P|2(%xY~}o*LQ^Mpxe)z14@<]dCN2> W F?iz.<'/d\*Gƻ/`sQ=y\ K;;׼wtlc^v=X5|5J 3@A+Ƅbˣû B~Md#wl':ze.q`O^C4w` .=m+^O׶//tFo]e˕ٮUEvyu~{??zaM *P@ZHC+a1I/4aQr-£<) ّ*?zI|@Lz8M@}l/u(xK~Ȇ0my'A hvM=9k[uVNӓgEU,N:+:|<.Jg߇sktݮgBϘ#`íO?ǿzePkXJaƷ[ Є~DY4hB7 +\ 빳˔Q= ܭ`E긇/O<w D S?$}v /a0폂-˓_Z> +_k3ƬƠv?*#:gmO~"SƝ-l  'h5WC{\1Qdp2tU? ~U2C+uE<2:X!^Gm 9Q&iꟶqLʁǣO:Tiݪ|qhۆ/2m4 3ǡm?_^؃].}G+3Oww[+WuPv9+;?5jdcǸ2vnt" K+?kܝ*XJ7`A5[_WO?G}])r䓵^bvzO 2o{C<~SKـ)_+ m=:wۯ];wC$`ĥRƀIHڿ۾];gMuƮ3jVg?ExC։vX P2ΠX_@J^~S0$aʋorpeVw2Gy.0m;(P@Q P BORUħ6o.o55h(^(u;/w]z2&ߴ;3~vwEI_wg+R>5D&;85̏|x$\,( ):lʳy!:ež.7@9$t9[|q,~z.@gO>{=m!ݹN"@]7Y%&wF,K'=3a}2 N'8͟()Ü5:LHռ1Gpwы`_߹Utn)l~i1rJt.w,X,|Z}C@ >^V v(y@ Fr#Cw#0|#gH##~ֽ(AwO%d|9p^*\uu|wϤ?w6zۮ.rg|Fͮ͑c m˟3MtE6g س:{4 %ԩDi 5hhz)Nq*8^XWG,^rN#>Q/RW'FI(OZd|.q+xLG2GpMvOC6m{tȌ~:_먼I?);t<eM|/_1#'ўtᱺT \ 5fC >>9[\u([0ݘ TAdU 9I)_@09 n}"s)~Omiٝ[]h;t`)&Y܍d0Fj;;S&Ϯ]ݵ>\[^7l?X5N(*8 :J|(Kzd+#$[y 4e;0apJC b^7y)`' HHÃEϽiy#ƖQ/>(_&5 ?1v{ 確|idހ"iNq<;;w9%|;3c8l5rXY55= FQr{Űå;"`b' 0hL<9~I3TTe뒄aAߒO#q)A']9.'._\m4nם+C?Oj4OZy| ̔i$&>iW[;;w_b?Pnwg ĠO-(3+(Lză+[ ]޺>>x5[v@PGf>V+m8z`H_M?)xu܉&w|?/J~V_.I?ɟXldXd3v:c`an@IDAT`es#-S5vJ6Q H ۅb/f  )Hc86)yUG (ɱ. 64}QNS則Gz%t@exy3;ch'Ke|1Vq`8K}խK}1Kt%(ZJz?[x:4X^?\q5:lZt(X] voqSd s@08|&O.)'"@Λ'/;Kx=zk@[\~iЫ}JK[^c]L=S 2G9ҟ WN~;Ua>H?`onQ|7:a 4 vujb&q>i0Swx 8!/YN 3rf|o'#x&~M{'Vɭܕ%gV1dw#tpG+mHk(cE88U6~~2Vփ;fxծ:nKGNZt/ݚu_na5:5s|b^o`b0#Q21 ъ@|sTX0!O9Gd| <84n*힏hhr6dKxMx;[9\v,m#{\٩璇tH  ߋD( k?xL뎛0T~< H%VY;r*U,iē>ObOֱ!9 4[d;,] cC! ()74xOAi]) ?f`Hn@:k~R?Us jzCo|`O^@4Bk.ݫk=mtcӧWv^.|Uӣv]_7GW-912޵R@ܝ&a=W@8QUD:qrڄ1o,|y8p3/K||"`6+~s W_ݻ/;ySy|Sn_C لD6U%W<& OGitck W(C 4Ю)P/,\(P=MC4{|=[)y?uї{`mrLF{r9ae펕+ zo{W'@_^vD]3OtdSV=6i\\ 7<T'\Y#}ؼ^W(knmaGvjL@b:1b|<t|WA?p%,D&G&|XC*&tK!p(J[GԡvC\k Yý>uILJ#0HBǿEOcM?m@6u1lx㧥RL%~EFvw\ÇNnY]g.$̭  YvI,,FX#$,/kvt Zz/Dcб8. +uzmޝx=.@ B>YDy@eJY;R+à a۪ZcFuaO_}ScwC社iL!D)s6#8Yӡ@o~ SdIտ'?wZm>X|ubfyhò/PVcθj>`d7h@I< DnYCp4DʡzKl"NY7v?D=/ÏƇLS㚺 M})K_~qaAZv1_~-ҌG)G| nMx|=!_wO3vVݰfq=X ?ƕ`2 D]aS$?gHe4uVy5Q799U>h/͸-aldͷ梺T+ٵmsTAIm[n]ݹCʜ+i H&MGvĹm~h6ayeNgze a|af\ (-8i|i:`=)ʢ(0 >NKwL9j; }8T72+kK6Pm]iҷxrG[?ǟ#K:mR`y5aZˮמӏ%~J>WS*g&p,9j.5OYi*VNt9t@r 4'Fه2aJ]je8/º6rh*ݠ,.4|䩳>p(Cۡ\o[}SXPꚢ-=Ms.5K?I&g!׎yg tyAwH{V۳y\1?̚w?o|{%a̢p<sYje9C"TFv YBe5mO6y-v'?"F&F^C#]Ncp9o.]gd+htivҖ:er[6k?8ڳwW?[Qtf>e&-ǁ1Fݣ݉{ L8F1)p1Ev}.@4uχs7G^@|S,9ߖ1PUl@8eBX/ZACK^Ǫ-BG-K&tʓMJ<2^ ̤+9\yrSQѦWC=ڤؖ.31>\̟HjRC~L>E;B7soh >;UߕV)GF)>ڢAN4/ĤU{ \Io[wE6}ңëq/\i ~iǎe|dǶU߮_OpFS#΀*nr`j:"^h#(y+̀^N#U)Y1){&nLGRWs竕xPO7%qv~ʓ|uxO;mڍJ-7f;;wcH~X?vtu^?b 6{?W.,YXod C<$ rAZa/I uXU`\H^Ieo?r?[7SV;Hh=\A ^ItwmVR좩Kywy]Nwxrx槀LMe@<ҹ#y/^ϼ2W]?3bEt }r!senm:ze5*E]ʷ7ZNx”'^uU}T?GK{;40m_N[ZG @<4i%]Q$gz9X?kbo2 ʕQshp@@og PY}eg_1~#_*aE]w0! l1u+8mKz}tPs.OYt/ȕz&ż_$YJ? `G.37Du܁XAִy8,Wފ~m #mI`ۢϓ>47v_ލm#bh16,Bc{&GlCxS2]4$)GN/>whnm)Q%S$whCd|dvF6yh@P#4OT~׫5Z.^>ێK;&Qw_3wԸW Gûh,74pr-F8D'1yu͎e | ~Gj_~qT)Xhfp+@璋,hk\ʅN8힋v8t.}+ G^N~R8`Qsʄ2yeDTvP;RҴ'O}ۣIӯꖮ-i;q'vcf *s\̝z4,]]yC[WB}ֻ9:Ȃx(ICs c/IM^þ @Qo(=)xi,=CW'0dQ{D? HNGaVҕ1B[MxHّZ+];.oM?i>|^p3zi0UOw =Z>yж-@21 _Giyޮ:X6W~4ͫ׀W2\'&>rPP S@Ab `(p#;uamCfS%N5Ү:N>t>8FxWiX9auG~X#@z:&ʥL_C01҅ߪSy*K ^Lu;;w[?JqCwMv68Gn1 P8 =ͣG^4fy/2KtUEG'l׿0͏=3 {+0psLp0bJ1+ic8g8ugd{N_pܕQ#!KSʤk=-@rJVnv84)/_UY}A}ߴ߻dlFx6ٶҏӾZ^>vww"]7χD֦k&E'uE ;6"܀Iu'a~1aC}#~q-|xؕ*оUUI -?M ?m6 SĹQ>yevt:/W>?yh}>+hIP5e)Ar|u^h[];unu=(?:Kg]_V?V@-tÀva,'33Œounu5dj:Z)h=٣I#M-_GmvS҅ݝ&GgD"㢐Ɨ䫧i!BCo(_"y\jϱ딫(Ot/ {sgg.`_'rX_r̸͝@&o^i-?|oR|mY;,x⏏yқf&}IH:= e+qp #@Sǥv2Mi\zo7CpO_ۉVvK[*"{ ݎtk]Z?Jc?:zM>7OvD0}UIi]HMD7u>oǥ|' `"AѢ8ɱh4O){ѝs#@}9;MJ Oj>ؼ v[44n]/wd+vFI ^`vŤW2;g:3]̓KיV9⽷c_v.hy tAtc?qixKoie7ay~`aqϹLy8hA (u sU IZ+4hk'щ3F4 NYxG>zat;=}_?anήz]29( - Ep. #-1jUC9nJdMB._@e.&[^1''^T~|k,Cf\ԡ. g8<C|}%!wZ.8LWr'eq|8@|wwwV_vn agNof[0mHi00:|&Gz5I00&̷ >h:RCw9 sO/ϔіqi?qeMi\`O儕 @_?K^zn>Yh]٥˝_?ӚUZSX 7+F:̛̗#n?>JgYO/k 2l$4=u.p$@M?թW[+>}}|}%FXG!\wt c;;#yu=Jg^oD?Xx]>}ŗ1^xZҕou9ar r%ݷNU6ڮ.;Tәľv*: xГih5 թei;ж}#đOص&Y?'n⺆v_|^]Tbq5 ? pSpܕWh@\JF-3qxGX&KSu:@)#e}1S5%swi% Y5%3WKr^r qMn?pݣܭӂ =^Oe^3]owWdN\zjs!Lgpjh8Xw@4{ vPd<BokgRwmN:]g-vC uGWhD#ӗfP|wʧ\+cІA ̓pڔzW]._2cM\ bCL|Ș0fLx:m2gQ5a'wLyih<Sw➢XBI/.*K:+?T_;?`|\D/R~em/@xmWhKټB? yKz's} }\Azoh4.>5c^}oF<ssz̥]WGV}u/?e`l0I2`}ENMfWg嫾-`RL;{/a G_9"'?Etx6LzmM2֮Oh[O@yV$=}7[O|V㔲SޥX-w{zaݵ_V\+"?Zg[>r2vO?=>owgleKǞ*=@BZj;!:Xd½87Ӄ2v[wvzH<\e_!k:/׌ctUg^ p##Sdl^N˴aKAW\#osiUg]Lp4|btmȷ/^7+ | MC+̕O^YpH~X Z_ jڵ.+{3||߶\zqN99q<٥ַgW}vw_79"1 1ǘ0ki0Η.h=>ϵr7g*.>w5FyV?ТiBa;X@爈KY`>#z';qs7kwHsRCo_{d""e؎]ÛP=2qXc͑}]Ziұ]t 3 `9_O<-$NGI=\5+\v"a% MӈOKX}2~cPSz7ϗSyfKQ5/ uxrIobN=Ogh;\%<(K2=G7^[܎9٤Ǧk[K8>'91ș:[ }@9OrQ1jܹ́sA.ȣ+y<d66>s[ܕEjh3uɻϥhtmfJ.ÅnIo!SG+M4mSWCT_3g̡͑:oGפnjQ1sx]_5?qW_f~A,EC0ь&Xp7nN$1xK\>W#m(6Ha<ՑJ54i M,2\ڎ\p_^ve.p&_YW龲 >G:{ >ǀhc)l8 c>I;g?}}{ӟ/2KD_?M66S}y;%{`%lf04:Cۂ$(Ϋ'n|kVp_%N=xO8eՅW0O&'%/tv$9C&/[~*\t̋ => ;_ݝ9IEI,CCN}YF> 9ЄeS7'v[ kV3oCr?xwa1Žag;6?x{(8t<}tv2phl];[^D*m@.Gv Vk??5[#=0x4vP8yh\&<3v]|oʶΣҟSPyzx?@~wOݝO70 I+'-凝0qhSziueYȩWۣ3y#OZ*N#yeOdzvSg4GW9"ˎYv_~b@Sgl'-F_g1ͿgC B?NYGq`:cRU,.ld#)/̡ PY8-p}>/ %7XBႴFZPHUeCk Ho$~ćzF;ێGt56u?Sѷ;Y]G?_7kǻ&Y>Bfjq1cc&~ ;ć<B} 27G,R:+'⨆}d缉ݑ?`I' )g+%A\dh&O7a!hG[BWȅ7z~. ^kC& ^_wMܮY_,nom{4j`?``Q2e|?[x:e(ع"xn)3;JYW0(!J,e~Vᯞy7\x]I֙gS%-oYw$2pS2j ]mz8`N[ \ci5g|]W;EnfϮtѮ&Ƅf%g_~w07`? Wn:a:ZOĪJ1Us隫!\&Ž5`@z˩>4Y%<O>·M %˯/~|cQ7|л;[N섹K){J_GiOz;rN&("=2 |4#9K׺7dN4;;W3Gv_op?`Qy%F7V <-1U1Ηqλe`:՝ΑV .L\OmYWV?!G[L9HC7yW//^pd~6 D . do-[o4ʥ7oh~\U@Hd+t]ߢWgDwy2歹T2YtسΝVg]NWo`1؞2XP@rvh Ǯ gתdVFI(_Ĥ̵ЫH\W&u MIwѝ\[zINt(>`l߇Τhv9bM9|Qa z֧N}PLw?Ix_Io;\)7ij?;;gt-w~]}Yl~cώs|*ɷ#ӝ Hrٻi.dMs/>o0c_`..G#:&B~&\d耉Oҳ.`4/޴q P3ϗ>v M*g 4ޕu5 hJX]~Sk( ~[xy`֎])Iu_ޭfӏ^3֎\e)Zq, >P)joyg&,#_iH#]K?){5r"8Lw{ 6]^֧^h O?'|>m٧ޖ, fPU{ehߦ;K;M=SWee?b/zcow[^A׮l?{(TGr\n1viLqZVѠŸO\z2)YWގܸxAP벫4!+| n>x==ɮLL9OwigsɦoN2 赳 ^ly#oR~xLƒG({aCWkk3׌1˜rcΏ@4?ѫc*U ]M 25McR@P#,yTE7wOXxeyuWttQeŤMyu8msW.}2O҄Ўd"{ۨTu_kA;?/w_TuLZlo7&7&`}bl xVx6Dj̑29UKN{L` h]OPs %%PNvz(FD)N2Gı`]Yv127 Nt7ܾk+_y[~@U3?vwwu׷iV_cl5d's7R.Q'G@ɫ\5H( qv( \ſ?~[S, AH #|9o*po/)@,pG/O0ʫWe&ԕ^8ȩL]Q.;imBGr$}Re8ܿY>x>Vi^2VS''2[7uǙ&ͼŮӉOfUOVY RX>H,t.?弟꣏>J9XE?`~kE}d K+Ĺm{ =1# ЂG  @=8~ɃGp_b$IPiS^VJ-ϱpvʷh"Ey۝^>g:v׿y@7Dg^W?;X&Cv05 AW∍مqT6)1!R+L=S a}{ˤϥq^~e@8W:M_ID\}޺ es;<NIh35@QOyRv3_5WVIl_GHNE{paM>6]X~FgԎ(ϛ wG w\7~Ph :N8ϔJ?_LXО-}6\whJW ]ǓuS ݢ7kW)n5oCZO'}c+/ +i?Wo&,4K BiO| Rg1IէxpԂ?Eeh `/7Ƹ>y.jv}r|u:2wF?O|Z.m}x[Zd9 TzCێvw_]J^:YtfLmh sv^^,ă  ›awd  ߺloxxfπM] bct_CGq<,$,ҹ? 9x^4~T+~ymlN;S+BC'aSC#9Yw;\Rkل~?̎;81 H8(U( 3([$| w.@IDATKݜrhZ;öV٤w(pDaF[ziٹr@ .̀8Ǹsw@xzA4Rą?/ݧW0 UP!&oЮ!-Y=}#, ش'[sϫ\&^uooе&>OOWمݍ \ ?܄w'g|8g{A(Hk8an7D:@ "=cĕhZЊ+2a>p9 %zu0-o{c~Ƿ 0a$/ӆ[IS)䤾 Hٹ#t2hۯx27=6HU\hJ7 OUFݧ.06R|5 ut[Y'f̝ÓLY}yq``g%]– {jš`_0{gYױho)-.p?S7PPqU}Ǖ]d$<RFۍG_X)VZx.lvwN8\Ky׾˽O&xewk&jz`9an ؊ˎ?V>q:0s`40_y|k%\Qo]OM9Fܙ=xU"':C:H':<%O }!]U퍜]@I`xov9uᘐkys66&y 7=\e5}@][ j?y 2vJfwǷ {a3ހz`+FNՀFR K˚ډ#^PUkscBN;S6?> @tuȓi:ӻ`HY=1`J^(k x-r|+G'ӷ;w_ylwovfthj܅!oCA3xNS8ږ'~p+H6fa?e"eq훧u?;fSC>mċl@ÿ㓍;:Jݗ$aG{ 0(W o'S t3/^΅A(U'`>rË tosU>6OIL~I Nu#ҮK Rg;ww?W$VX[QvvwK5:S(=I)/}g[ھ, D<? )/@OʀA<<BO&Nxv Ԕo8夡uog'O NRȊE9┶2;=r<9Gr8ɕ|4?:uٜ麨fV̛8i}b<~ h;ZNĩc+ёc@IC򠟄 ʋGԡ?9}I8 _ ?|?ÓÏ?`3w=#:jtg s]$&?Eń]\:hTráo2NGtvaJ Аʗ_$:b%'lri|(^dH^e(G=+)li\fK#Ju+S<߲})io9v3aQw.s43Ƶ]C~?W[Oz>߸?뻑 UX(I&C4F%e3;R`ZyT>4uQУR! PGW^a;xg+ /.fS|_ C I/DӶ,]Hh&s&?iÇW>4ReM'M忾߅,HVukˎbfˮ]Ή^t3}]V?lKϱ5`Qq(b'=~79< :;B؅ϔc=WE#Ń}ww*%!]rs_Oalj"VVCۏ?xX(Nu$l%3k?&xO3:/[Si`Hxh兏m'+?f>_=k>?0VϺ`[`Н}=XaDx08 M\~u'o&HR~~]wZ)0N< BnɠO`&*RaoxLbғѰh(jx/`řl_S/:au>1v-ʷL^IhzO^|~ϘK㮱яg֮dֆgXl3ئ{H։r\,`5a51:1WyZ&ܙ*O{QziG3`4!t˻+2ؾrm;!^]S?ڂZu?⩮և?_awj=irkX ;wh91W]K$]F0y(Q.F.nc?Oܔ-eaM]`!@hx2C|zb}Ai * fA|>L=p{M7M[ JJ.]AWyq)җxQ<Nfm''XJI(<* nY8UΙ];ud'Ϯ՟];k~Oo4v9(ĀtZ.dHQBQOIڔBrxu;?&j@Ї!^l}r U }m0 qSN;&c9C"Xy_3<Փ2&\GʖN'{<]2BM^D^2 |޷+W `2;;nvxaӱY -  # ,b 6bJwt;FS2g8v;rx Vd䤓;/BFC <+;3L}LhC?a(8ri]Չ陽۾lh*n?I35+? 2iۅnq􃺔v}ѷh};9_]]WW/ tGuM?kLjYDKerSF*Ps A0D.LiSP VQ%#Fi @)P@;TF0'j\_ՇPė 8 w8Q}7>] w|*v7;GTY|n֜}[}Y&7ZDx'k Iב5E)H O>@"Jrj>@ CMzWvFKiY ฿Û My?NN8rHw4 T TmiCOA~V}-=2ZW2$pJ32>vw]WgjKc;.Zz&ӏ^P]16gwdN^^u;,GPՌP 0p qՉFpwR~-P*- D>M Mh啋SNqxPڂKK׺>%܄ުʖIWS/Olܯ(2@07O:KSsye'v O@@fN߲+=9c;A xW CSSy (N|K Ѽ ľtt64@ @:8g2G㦬v :KmKn+縏@GF>ߚ*cW+Q9mZnЃ]fGz{hƋ6촑;X 2;;摹׫W.XTN7  !NzG~yGg%JxL: l ˀ't]ic\/mզ>S].Yz|s' vHWfde[,Ȕ6w׮J;Q~NGr%TFlx7OTnyM;33|wo_hlg_0eʠ$ckv{^ Njcd$B=aq)@B>K3m_9iSb2#-:rsH#;^z&2kh姿LLnn;։sl5et8]KJޡCV?? M\߬?'?v?:pa,:=zZUaE&}1>/dk{3 >2i/㏮nGipX/.sK GځLU~^3D/vӒ82*~}n9Jkfw xsu}xL:Ozz<:wiWPA܎9y2S\tƮמ'pw0|7 Ͽy0~)v9~|/ĕſpA. S<tZ1GFOZC=9̺ :/܈{ߧr6O5+GS/6_/ib&K˴G•ghyǤ-hv^g:'۫tb~E()NUAB?6,*G\4;LBެ>¹5aFѪnBDHل*;/w{(M=׾kGRPّx뱡3<"{w~><tPЮӫW-۳?f?O?fDҌ?# (=]$1pz S10V@&<0r5t#2(KpuO=˯rQ~r=<ȑ u$ D㧾U8}Ew"q b2#G9K2E9"4V|wϱ]Jv>KC7yu?'?tz{W_?(` oI& GԀd&11 ^ubepCS]<|򿃗,?0~SdG+ƈ)<ZFyڦyJ;W SR<* ?ym=G1t7vw;v_kLm~?{E@E.oĉ{2p 5-̈>06ڂ]BظhOB>輧gʋ7_=5.qQ8g) Y8|O& M˨+^0qp @vYo[>؝8w%ӟGiod~;I (6v}Uک>ldk>v4X\S}ݎ?yҹ/?UE]6⡯ZZ??:}O?xMy7.TX3QnQݕ|m]Qqi2!]4 )7Og' 9ҷsh{ĐAg7 `au?( xI]󮩖k^y|iH%bu xz1 Ld0T}־#o'{Vx#\m5ov/?wlI\uv:kXW=璻29\ QT) ̤Y-WWYz?Io BG"҉W^rӾL]OQzJ )w]܃W1@SO*M+ߋsxr2W$3񸫾UKz?GO"?GڷC){||6WaIxZ|X}O?.S"'9Eqav\ W8I)[^/H`9O53VGq#4^sxm~]_>Gϧnơ k_F\u?洗{ vEY?Fq2p[oi7z2qs4X[]%=̶mFױ]51—q.pyŒz (cxpages.]Sw?!.R'zzݷȤ]\2GCDصO?$`{`$ơsJr$oh6o_\>q_uǿհȱ[}K׬_&?6e7kOރUʗXc)034Yh8`L(Y9J̓v<: Daosf;u+vsxo)= \<s mhhwwn[~·̍xG7Z|*C@$_v7,w˫;;] W?orgPBzZ ILzi 3̎oTLY`Ȏ W9`O'binJSM.g~;@?/(^F6 H@kqU_:םu4<.ZmT\dw_䩧rk4$q[˝Vy@tuhV0>;>4]#Ʈv?z1?V?n?kZPr|u 4*l] &s'ʢAYH\_ϝW/_vanU$,P=<ǀ/_YK5i/god}!/*877uM ؘA<^@٣s' +npgL= Hvl_?skw[Ha=k8``Eŏ(C :zOUA 7J&&1o,Wfu>?-f AٶE:z H^A.,e9i\eO|j3r|~fɓoԣ_Vr^r,,XsTN],w'1c@{/pNi`~ODCkrMm`}eQU]ڇg2Vo?;H j'C3YZcO>$o[88>'vIL]&i]?:--FJ|axSoT̤OO~UhvwРG8FN|? vӮ;gG{Yѝt|v8.SIdxSHǎ@.Pæ<Sƣ؅R@@gȥv<W> fpj#y @ DX!~xKB=sѡt&=7۝$)y uURmrgRtғ?<'Ny23.;IϜ>YsɄ4_sT].w8 lPuJƟo25ZNׅ`0Ŗo]ˢ0(]6g 7^ޕ%hC8bdց9co<ܕidU|=544۾Ĕ̡WPNtGQ!UϱP`54ɛc9.OZSѫk2quQy^Ωsad ſ=TZO>4iIKݥCt#>#wr% uP z&0y`NߏT'#k7 'egokUcd1ړ.ǀpKe Fs*Q!6:)7&3S<@=uY$#߭O?|1_Ԗ!ݙ upSH`‘ݨs[މ5:w4HY e2v|ʊ}|Cc&)9eO]g>%{vc#Uc Y@W!xiO9@_1@@eǰKS*4 p|Y4;OIU.Id-+0'ItҕvIo-yݹ2=D}|6q @SLW88a0 z0ywqp@@  2ï<+L¤N<\qiM/%Ň~Or&݅?29Gl _XiClO˯N4A%yxQSpOL"`d#Uxb&K\ט]g}Wkm?,Xi9ASbɧeEroH. c~1C_od@OG Iy?'=`@I>va&;pҞ*O<<#m.*˛OC;ď8Y*d (:ЈQ^ꓯn]_C(IF>NVW \nيc?E0ӡƺ9'j{ p `3Т @BLx{О:'H':3~vL?}Gvvȯ>yYs[ZOK[^}LS_Jz/]d'e) PQ=iLZiC]C+jq|O:<7v3vq]:rt{֬r ӯѩ'oe~Ǟcz-qfp)V ‚ y9"\qWi|DCV#](k) 8d2cQmyN>'rpgw*ݎsr=gl̉O^ɰ4  2"//eH$Љ&̷쨥'5]~f%۶,xu]˗  Tݭ Ǎ_+c/08%ޥ|ѐ/<ɛۅ-vJle&̗. į]-m5aNx:O;w+WX{l__fDjɅvNBĤ'~` Fi;DM3قM) {dmM#ncB4ړ +ow_Y{ۻ:9 S?p'|l|ҧ#aUNORnx9E?G ]GGYsWW/̶_l ;"^3:_2<;fTy70v8ʘ>6N9h;> $L0Nܟ_[yRs&]W'Vg6X 8i5;0Fv4OnE=GCz|oGF.2I @ipcGCϏ?8m|4;=K';Rk~&]i(ߋ:/xrdڄG/~>?sika >X?oރp;c\11,L$f;EzaY_( ./ISZnW#5xA \ Ќ+֮F|[n.+LAR]ۦ1W{A H4Tx(&i՝;ٱBziDnԫ~}dN&PIk]jkk/vgޘW愹axvWV7Ƨnmƕ{5>`1ҁƗc9q. 8͏>O/,bo_^v]`'eQiY9]\EXqj2H8u';bW_G9D?]}@irc|ϻ +:ww͗]Xv_~d/9S:'_R9c4`Q+?wyJSr¥+-xL&Ρ2\DW+P,hy8i0> ;W(W-5ֵC<Tyeq O ߅>G#Ouff|EZꛜR%_>lQmR@-w\&O29cVvw3h,Betowߝ%\(^n1dHbW=_}+ Ah{nHiU>4픹:y k&|q"۵{Ov{FO''jZ.m| ϑ*S*eC?zo =;;w1zwӏ/_3 ըKg_?lr0c=ݝ'pȄcԯSdDSG|4?wC|4̧:eɢ@_]/%9|[D3])40Er]9ot*}1du+4}ݲdBQ`M]x]齿7z7?"z֔ñvN9w]O6 C:y$O9W cbFQ̼.O.=d_ϖg>͈g~'Y<sbX,,tthcX RyGA ]/&wQ GI^ڣ -Q?iy LՅ?e?9* _7#L^)M&ʗ|l!^oe7v#V_?_꛵掍}ix.c1B]şc5GhYa<;f~ß l9 +G6 D}''-r]/V>nm:zU5*E]ʷ7ZNz”'^uU}T?GK{;40m_N[ZG @<4i%]Q$gz9X?kbo2 ʕQshp@@og PY}eg_1~#_*aE]w0! l1u+8mKz}|Ps.OYt/ȕz&弙7_$YJ? `G.37Du܁XAִy8,Wފ~m #mI`ۢϓ>47v_ލm#fh15,Bc{&GlCxS2]4$)GN/>wh'nm)Q%S$whCd|dvF6yh@P#4OT~׫5Z.^>ێK;&Qw_3wԸW Gh,74pr-F8D'1yu͎e | ~Gj_~qT)Xhfp+@璋,hk\ʅN8힋v8t.}+ G^N~R8`Qsʄ2yeDTvP;RҴ'O}ۣIӯꖮ-i;q'vcf *s\̝z4,]]yC[Bpֻ9:Ȃx(ICs c/IM^þ @Qo(=)xi,=CW'0dQ{D? HNGaVҕ1B[MxHّZ+];.oM?i>|^p3zi0UOwê4 IDAT =Z>yж-@21 _Giyޮ:X6W~4׀W2\'&>rPP S@Ab `(p#;uamCfS%N5Ү:N>t>8FxWiX9auG~X#@z:&ʥL_C01҅ߩSy*K ^Lu;;w[?JqCMv68Gn1 P8 =G^9.p Pߎ˯.km=Lx䙶 gϡFXQ.1tL6r@Iv p(|42jO9=OrrվqW 6htÛJP1WAqs>6A8/g;L إ,cYڈsm *L?lh˥^޴W=y>mO~,>IFJ%]ڑ':Wr#k'uʽEU3Kٕ;]ʁҶTvw[/c:^*/_'15g8Mi< >d}vLg794 퓻2!dO$]XAw,^cơQ]IM³POzHAP&*G=Z˿41gh嫇NUfm}{3EsKo1H@iʵS\;uHf +#ǡ/w3Y* )=1:N꯻u~6NښArUyҿ)W^Nc 3yٶWR_uD;fכc5G̻_?g'o{QI0ԞK}ZÊF0Ѓ3W!ncί||7 LPb`v3 dP}4?4/'ԽtO#@@3M>zO/$ؼ rvm@굟}p҂|%̮|e81Ye.o\[gv_sŻ_v.ќ(3;+s_`q 쨠@, :pe~7ye%/ LWK;myD (mʃ%#}Mա/#?Dt-F4Ax'%lpȬKyij}˃<ˣ ?y?sgk_ώ_G<`t 8@ʂ9' `uBqйLA Q qmyh٢r9>Zc+KǷΒL;g^vwYC7?_ ٦k6ukŜ_ރң_/@^cK8 «8*ʼo#~?BWz/UrK Svqy(X2} z΄ ]eZ~=pC5$l<}MC|ԦO~m#zRe c>/ZNf?㬟6]מok>յ'pZI_2;PˡC܀CJFI!- yH~LyWe2@wmLN}vw`a hۑgŻ~h RtS9y{Rce#aPyC=;xv748}JëWƶ41:- |-ˤ\➌Bn?8]a7I۔XoNPC/9֌)3O|L}IѸLu]b  @AP?o/_j'c>x;=Q 9_Yۆ xW˴hKݼc|"Sykʧ?hZy{GݎyKG;fě-0:w:/ͮ \*[=l Wu^ `I25^b|GyS1Ll1vԩrAbR>Cy#r2[Kô1/h+o(s?X9w(Vm6LBW?R:*A*zy)sKKIϮñSɮ;coǞ)=G Ԧ` ܟ =zL&3OGqfxP ﶝ.OzH\27-/ A3ca8]e?` C8iH!C'nYOôaC󉮮\#3EW>rɅr6mė̹]Ůl $n>4IENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/AppDelegate.h0000644000175100001660000000511414776170045025410 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #import @interface AppDelegate : NSObject @property (nonatomic, assign) IBOutlet NSWindow *window; @end qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/0000755000175100001660000000000014776170045025275 5ustar runnerdockerqbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16@2x.png0000644000175100001660000000253614776170045030160 0ustar runnerdockerPNG  IHDR DPLTE7E6C6C6D NNNzzz ...OOOUUU"""ppp 888bbbfffjjj]]]///ARFWHX}݉n{谢aoK[HYBŞ[jCT˥ݺO_mzTdUcÜɀތ䢏ގFVhsŪٓhuTchvK[Žbp_lWfKZÿx׽ӼιǺľftRNS )2 4 $ .372?(au#!?-X5q:>QVWZfw&(/F9L,Y%L+MkL#6"(wIDATMKqon(nP!ֱS"BK/ ЩSk.K 몳\>Cz XrN6 "[:{8+&4`I4ͿxXhuAV`1M3VHc@#bRLOAZ1, ϲ/*RG%d|5j5r^%;cxrp0\pY{ˮpB0<0Uˮ.%#y5)r̕5[5Ǿ>GSs7JF5 Ƙ48 `( dߣ0 6-{K7rc$:$=o:-Xh..Cp>zTH}jbIYJg㭾Rx4g)R☜eV٩My HٖհDUA#sAN'mDO014K}g)>^ZIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32.png0000644000175100001660000000253614776170045027602 0ustar runnerdockerPNG  IHDR DPLTE7E6C6C6D NNNzzz ...OOOUUU"""ppp 888bbbfffjjj]]]///ARFWHX}݉n{谢aoK[HYBŞ[jCT˥ݺO_mzTdUcÜɀތ䢏ގFVhsŪٓhuTchvK[Žbp_lWfKZÿx׽ӼιǺľftRNS )2 4 $ .372?(au#!?-X5q:>QVWZfw&(/F9L,Y%L+MkL#6"(wIDATMKqon(nP!ֱS"BK/ ЩSk.K 몳\>Cz XrN6 "[:{8+&4`I4ͿxXhuAV`1M3VHc@#bRLOAZ1, ϲ/*RG%d|5j5r^%;cxrp0\pY{ˮpB0<0Uˮ.%#y5)r̕5[5Ǿ>GSs7JF5 Ƙ48 `( dߣ0 6-{K7rc$:$=o:-Xh..Cp>zTH}jbIYJg㭾Rx4g)R☜eV٩My HٖհDUA#sAN'mDO014K}g)>^ZIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128.png0000644000175100001660000001221014776170045027744 0ustar runnerdockerPNG  IHDR>aOIDATx] |WڿD"R ڎFbf|7Ӗ)ih1ZeQ6XcOX$ds}7yysk)RH"E)RH"E)RH"E)RH"E)RH"E)RH"E)R ;ϯ9sIĥ;bނh>}BKp~s/p%;Ř9siW>Zp߿{#}YB/@M+Y _r~𫿽L%44>c,%072PS/U &/@ hDA)?]h++(+(+(+x#@?RU@e/gǾfߥNgC7i,vMv5:Kw%>v_f 2VoN`-[(8|z"s=Ϣg=`#G7{YE{Ű]~3zP?  <5köD2Ok@i*@4ye/$~x%M8h: (@46< x/5ooƵ-`icOQ$~ŝ{C0 yR_qB{?.D'G)CتXAA|;wysYM3w @VD@m`&J=3VF0c%p$pre!4K^pl$ "wN..=$oiIzRG>34xncOѼen Hg#(É;w%qv=bo8Z`ijN͖ܺ>!d4Z`[svN4ת8j'H iÉ

`5Y'(R}dlh~v[a`Ýک0_[ZU 5LU. ;69N s B4F+vVNɌ?:(13wR-&ku xF|ڪPzIv;N @ǣ==tV&B@.>+'myc'p ?h^tҾ0שWAm 'B^2V= dbIˆL*B|J+6j޼sӧOç~?G40F7ePQ@1;Ć=zz-;w~oCLG½t%@8ʠAگ]6k07}._˜M3GNfd&8r5M6uÆ | :3pb}Zɓ'*bj+x6{$W{GȚр tϦmf#vcK#?!۷Çk޼=^VZxON>a jٲ߸aVhOǽm֡Ntb_m [q=**J[]vMc#_h̻/9s$QUly* alyOh9{Bxx0.\Єo .b|y2<СCqJ9IJo[{&_ͣP{av!T-Q =uyGW!,/߫Yf{0gm_<~ZxVx0HBX2 [2 @hx5=@ /"  Zqcbb̙3llUk.M5kG*"yٚ(z+_ r0aYdP@<ohbeGVDw_fz+_ r5k53.' B|[`ul{ŒEC [gA\xb-̃x2 xٳg')yBķ!*|4]"އS Aٳ:&ǔ6^U Rѧ#86Liɹ-O9w$awi!4 ! 8 Ƀ '󏑴yӾFZpؘvKሿ4-87n& YcuQΚ#1evI"{=E3G z~(N)TT苘h粐\qѺ4u> Q@y _Oo ]P*#(AJ*\~#Neh;r50,P 1oTV-,ou+>A -1,\'hݪU0L4M2` uQԁDBXfgQskͫ'~GO*A\RZj{ &d8 z HfA3@CiN{y2 @o\&;ёe;pD@+]0u xW(Q1]d Pgȑ0d\2n yإ#X@PqǎétC8=z1Mb{ˀ {$x!82߼yÇ_˟tI PO)`xZjdvۻSN]WLie&QF-c^C1> T |TD[m *=r @H>CfWǿt:u|A!߫(/J=z ׇdy8{0  ϗu_~O`D@G}Af#0\/>Od4hР'zߤl_E{u?Rde@@؎ !`A+}aN<8]V.A%! Pk׮0P  g aÆ ۄS(l?S^k-Z[־Ch`$}B`,#Bt|k:P~V ͗=~8M2<*Th̛<}u} BeΞ㯨]31 y^,,T @baiI!\0~q|RtbCIGі>z R&/M@5v,sM֭,!ؖWC|z|vIuHVZ}9^zxu89ƌ~m8s'8'w>dȐM}Yضm۱qtA?嵛GѯI5tK܃H,UIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128@2x.png0000644000175100001660000002605014776170045030325 0ustar runnerdockerPNG  IHDR\rf+IDATx] M2Fez'Piy"T4hE@ty"O 3 xE2 @H~_\b1mߏ^V QX [q;>k>+˰Vvk+}A  "╕zW.u{)C / BɸV{|klHH,+Xx?Z76>!mh%Z۳sc,wL<@Hy ܿ&e,>ux{ҟ @>ޗVkm DclD;tZڎ@HBeGςׂ!)Ab ?x^}C@/7˚ty@WcǏ&z}ע=0"9w`0+ a<.͗Pq^o?>p 66pNx>.{Wy%d&KDf[yOpDK8AٵLB1  jq sx?8k0>ߑʳ(zrx?ɓ K)>{~3 Y? ώƮaǏPya-^ t92?`DU_R<V)^0LAP2J;arz1o){?WavxZ bTȔV \aV} ]ԣG^؏/yiӦȟHYt5oMAktoF$(W{챻da÷سg]!yv %,@(6Y_Ͼ+JoDX[㕅@G^T2e*u3;f#F8RN竪9 A0 o/y_V?L"(*m񖑾~Kv3|;w%ŒjP rŻanÔg2 -L0(!0ڳnk1 )+W[r. S5"*T^+|u$yz|.\T{>eJuY|~$vq|U$!EEOQ @(2nqc=vx}fؿu~}ǩI8f-P[ζqET?v_.] UT?sɼwd.{6ozhrsvRIr6lX?cƌbUX򽮔0ꟋQ5`b6 Hʸ0#b.Nuq΢7Z #K+Đv_xH7-Z mg!7I;ug F|̙#f̘r.JXj ? Rv[XdsbFƒHE5eϛ7OlٲEL>}ӦM;i'0pߋ-zG,2DBż@M!p}3xw' 6@(߾}ضm2e@KΝ+-[vkڵkS Ti# qJ|ѢE \f}W^bرbժUC׷m۶bO+CV][dg]T8 Pw6Sq M8Q,]T>믿 9O~1a~zA0` Gf? X>icl៑yM ۑgKS:Acw}'~7k׮ _ѧOߺu_ƏD?S%!V\ HmG~גJf9v9ӞO4dիO0z?R~ Ow.\c;R~`Z X_p߇z&EP+oL~W =-ADGyVnO?t{wСw\(~а`r} ÔD߱!W{/H-G1A 3h?? # ` 6}kmV3//~DD{׮\A9~~^3BcADw%~"gzJw9~Jq 5(9芌If+es;=m{m%KXo^;qҤI})mw9}giif6U^k񢇬t=7jAT=b=EQ(`zO1F?hf/gΜ)~m!yɓ'[ ~a҆nq`%mmZ~CNM0wzkwo>#jbۻEڿBNAhWT^iCW9TfX(Fd<?x*gh5bp}[|H類_ڃY~7o>!'gMSG ,?MV[i0~ zNqᐵ1|,ϾCC_hkW͞=G ElQ؃_[;pos'HZ1db/SuNA;c܏#0ɝ7cE/m:駌՟`>8vXLJ<>Wīzla۴Mbuy#&C z駟TOʛYq_J9 I~kو#Wi .M"l1 nN 0@k-~h>?(I&Jb?ps,z7D1߄ڣƁ]|LF"zן ߦ-n"5h }o5FM!,FMFٯ/~(>]Xs,$$ޖc;>V{`@\ǐ!C` E*foƍ_R/GD`8::4ғ\W|lua6MqMYcUƪ_y-^hdj__6P|7NGrhH$|Kݮ'+ǡHthh>sXnݺs~)>#NՁyuP&p&rj@{VM^9 =herŢKEɹ8%G:oIq#uؒ;au8]WA{^|>>_ O1IJ C.8N GM~=H)ʁ!ZjLI>IƏp&rsዣC;4ŤWAuVWKPym$``'-{F58vwJjѐzӇy`V5 @*GziZ_vB)w rNYq9.n"l1n聻&RшA4cw7(Rq^Ec fOG+i` ?jx.cL 2R7~9Pd{ZH_ &(e4c, 7HF0"]tG6< _%i.BʿA{c%U$Td {ɔ>I|XM&>@k؝}hd Ez7 jh(Uw0 s+KP[6J[ʊ 7HF0|=뫯Ѽd\$}jժ;ȯgX2FL k՗*U?#lG]F b[9-4PP/UI%!ڡAnӾos2T`z&"ҏ:!>3'\|kU꯻z6b8K5?dJXNj\R䨯5TD&F࿈~ڰ{bIbPb4d]ojwDӕWyJ䳔jCEڕՖyEznXv܂>R{(E]?j`2`xS…P.ntG*yW۞BJ b!25,xIK*'Oڲv~2$&9rGI0|7&SPxdIiѢś*}*;3qt!ȫn3 S TpzH/GT5fvɪ 7xCJGbJ )G뿯O>dʮ\urگ &dj׈زe'i(^/EYe0~9B {)}Ї=K.yHeUd<'W7 d hPIjlq 5\UӏmN* @̭۶m{;#S!dj7-1m1$&bEuL =r_*PT]2*vO`'-ĺ`KemY&"a V}0 )HM'!H }ֿjժw E?D@A%خV% DD IC}D7߉E[[T1UEWw`Wl"Et*Wh` pkVFwW1 ͂3++*UGa򑱁?"XPHmU^!ަD"a8+?F?nbLAϛC>dzr[ҥՊ}[S+W Y_orѿ}(A==)Ѝ_ [_Gm/P[⏁?·`gN$k](q %^0(ˇ9(={_d nf?3iE'+K*u5h ?mf D?=<4MnCOyn I#˖-{s$ GoM‰Adde"EܕC]è?h E+!`Ķ>.&S) e9+>(W7fT!g֟wPzD~>}eNL 'Ak&\wu8+ߏ)JN?n@ @~]d5C@]ʸHjCcZ/xg M R!xlf͚uRA?+;"2GG+`GY/ QAM 8?">h:0F .~?D %K~L W*kG?31qĿ ߉ Yw2vVVUA?3OXA@Ypnv)p4EǎC9oOab_xᅁY9gYVq'Or5|5\.(A+?}ptX!D"x|Ge圓qյ]àx0r) wy`$G_""e5G/F{r3G^쓜]ytc@N<0~0,"fmm e+T_00)OH m9,.{`GƏ^~nB*A:hiݺuO?)pR3}n0('Ge1K#h aL X2haÆrfTtҠGcMG[}taZ/҅;ѫ h@(Ӕd 4!C}}+"ܗy|١#pLZ5 ,ի?8wh8$ 9)4~"v[-0nݺYH{0-Vs066Kն>;HvM0H{ m2rtCVӁˁׯ [0jGǿ0jjUOdd,bfGZs hDne͋/W_|zlҤɇ=P϶mfwa0Ce>_Vu=7nܹN:P-{6Q@Rp R"i>~)OP 7PڃQk(1F 2[[k}J ]@{}%*iVu5cF}૩H3sj hm *s3|?n ,r(㪨Zm+CBU@k)cpש݃SVz\>W ޟ6bj/@OPX@>ZQ+hIe\PVN +) eU*]]e^[EE+ϲWsԵћ}^'( Fu2ʧ>Sٚ0UZNU2`7VP?{z]9^{)OW;SJo}>D-n 2؊tC1WYRߕHBaFgj^RWqgh^0x}{ojO'Bp-Rš2֢J(lp3E #/{~VziAri[<`-4EgkFO{+n4zH2MSty iD1'Ͱ "/AAAAs$t3IENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512.png0000644000175100001660000006455014776170045027754 0ustar runnerdockerPNG  IHDRxi/IDATxx\ϨYղe[܍ ^B dIv&dHd!MoPj:ۀPm46Kz^ڣS{dI;=;|"B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!%B8/[B!yo (}BC3@ȟ!ׄ<E!~w !?z#@-BH>׆P)M!X?O&BU$ So$qF &7"ۼ0WE=Gӌ_# FN#~Xl񏘼/VG:% BH{E[A ('oG>V+'?}*.$Cwac`"Io04P+'>JI! K.YO+ əG,ĿYg_YZ_}^NB@}4fb0$_p<ʲѕrB-ҷF*fuS_g]QPE' @ [!'_`'BS{D|VxXD x_d 'YX?!'e"aU_g|gcI!)gtOm@M @p_7"BLr9şB$}X$RBHf3V7 XQP`q?BH ;95P !$3f& WQ !$jm& şBz~{; aO!WW/B'k?u4B @(#|?!{4B!yP !gh(xi(B?!^N@(BhşB şO!O'B@BS !P !?!B@'Bh(B şBB!4B!O!P !?!O!O'B@BS !P)BhB @+(Bh!@KzgB!46QWR !;7şB @x*?!b?!|(ѿg(GGU2xTKyAe$)>vD[wbmhz]JcOn=MԳBE7X(j)1e2AJGʨ~2()(9tźeSҹM*;6˪}{K"d8`&E!\ RQUSeZTT>^fr زڑHOSEy2|v|yǐ%xoG/B"1(U _@cFPF.?Ѧj ݷ@^󺼿c!?1Pė@07Lx;eSQ<٬ b~nj%,&Q)篯Fu)/?=O4/Y;{?G!HS#!WN8ȱUGjreaR^BHD73PN4/0F7MV4xǦ鲮cc^^|g,8/>B?}#3 @|}7-{AFÎU}=[v5d y&q\i?%y1R_Su 8^^g. dt#b7xrK_o5IKʍ'6gd'@34nZ?ɬ@!0|z͵j/}([ W39{7F L?Q_&_# uBh(_c 9'ɟ'^%CbdZ$p2Zh$BhlZir rO<ۉ5!ǪBKLB̀ 9쁧4\r Z,0 lx !4~Cѧ!'U+?CoT @&4Ax̤1C?2d/F7.@dn}w4Fk,#(o% FCȑ숿"  !|_~c:\9^f @^fHR1I.U^sY2n%A)j+. ]KU-U)p _E  '?Z9i_/wUyCc9}.[gȩ*"ɩX/<%ս/f  `T}{Ŀ Uں_v\}\S4 0@h9?נ<$*fQm3We-9}._[( DGز9}K[W_.KZW:j_+,_q*Rp kK !圞O>kB_Z[$˃ ʽ !E?2g=|~)$pպ[r:CΑ  ĄH1W7mn3l?Krr~ 1L|fh sglNν{\ꏁ*K%i?k./En-d_]]33пKՎ-VBOY~}YAXhBRQQP~`nԮT\#ULƖ?`F]ya >ȤyAA( \ iqRA yyQz0A{u ąqbcO91#ʾfYںsY9 ϙP>FX9/ M*ϋ8?7} ВR]ԟ>1˽5;6&l[Pq,9 4{qw#o<|,/| k ro\زކ-==߄1OA0+VM`!c==ߞ&Nsuj@g+-gz["xm·,v)Fm==ߘ:^9xJm^ZYV2=B@<(R(zz xc`/za  "޽lݲNԹ2[B@b;1qFO7LޏB@#M·(k>oBR<6;i\& 0֣<-CuIWsUub8廹kDg=f?_mq6ǢBhHZxk'/Kvx\49< WEWx%U! e+ !4$`s 4u{k*y  aA@^mZzZy]qf{#6[BhH*FZvXfY14p OBhHȩ.2-Q3g<ѷy^^2mHB m"X;/zC+ J34_Oןuu`+ @oO0#B@BJI$" (mE B/.cv40oo*5kQ̋N +^Gyx=k'^;B@BL 0K0g 03B@Biޘ&P !4$ @= ׎mEȵ d03KۗK|ï  EOEUR(`f kH۵ފr))(w !H߄8&|u0@_?bq@,}?B@\k7 XIcO/:!ވ[=z_|6q];== M@H~EXK->7~~_a qɎ]oX^t -ËN|m/uuu.]+۷o$ķd/KhE'$'(ޭ( q:0u;ӄΐ}x/"GN?{נo۷n 2fNg҂~ʳ&GL>^wun#FHkRiKKK'= ޼v$$sHjv`j$^t&5R6$E3දI~T7`i?3^/K0 ?yQ;㏿%{뭷> ,L3$uVhT{v3jN۟O&^ As?3at'5 U/SLib?4%D}|C2XoeZ}g眨݌W+:ȤsZh @MAāezſK.93MyyyF :::tMܩI-_9^^>ȷף%E߬]IQ[k:'MTwo-[zſOto HF @my_|$T&@@]UuW_}ډ#E(znVcKfHFT&{QZ 6@wϋOi8Ha?ЅTzh{ӟ7o~g֬YK`߿a ɀU^kzb/Ұĥ#z~޿kؽtɊu᯺ a駟~_YY٤l?Y57?4$#( ο~=o! :{=z=*E7 '7 {4?S|ߜSSSs77nܹsNvmؔUpU' Uu\VqN*۳/iUZ_v͛A0?/6O3vX~=zEj_OTG}19tM@K$+Y=/8"?|n@x @,gOx&0jUZYUT)֢JbСƎ{i*IEEEOtݺuzF%I՜ )/DU)ES:͋eϋu991ra7W#eY9Gea T&Ɣ @=jx5몭9sUT„ ҿimMmR{T.7z'?'ҤRį5fT//PZ'wmy#?28S}t@]3,ErYͲVkو]McJe R\P,RVX*%@ST}?_BxҼmH~c.jo ᯫ˥1U}-օv}'I&yj_sftyWrպUm@^G!$xd>U;>@];*x=2iGI_7f P@/%ŗ^zi'tҷU>%GԨQ2dꒅ k@Ѩ56?Ik d?iY"*yL(wt#*z}|S(G^zsmy(jQCjC 2mvxRG1⋏?3[YY9.]CVC^QÂ*ihhEٛO?}?kb(gd>!&L@ -_tVUj8_<{?T=~j*Ň24@1N>䯩51~k.Ybwl٫E*(UH>בֿCߏ??*U'd!j^$KZWԊIx>K4q}eE.c/۠9sg圁UQ'<=A.g(o U>}\׫?]lٲE֬Y~SS⏚܎*T*KunѷiHָg#rÄ9Al/U /ZмP6tltSQc5Fv/'>h,jYuPNJr\RU-yZaD|}>Q_zlݺU{۶mZ @AA7N3 vgw;`_eo  ٍ0<3NF:f:^XܲL.,jAז IUxD_sfj.E @ Cwbertar:JRjg?-⇨߽{߾}9RԾ1yd PgN=+-[ҥKӍ3@9a@QeTNXfvmm;K7@Tڹpo*9к%5?H rh?_AKuߑf Zd9}S[0`}<-YDZZZ?|=JKKE WZS ~[s Y-xl)pcFkG>1{ZGyݜfp PP[Y")2NWKJ?~K,D:+T j9a[p3@C۞SMI#Ckp~'w̑/ <-%4LųS˱mSeSkX^gU^:;;?#Fh4hL8Oq`َNfdU}ͺ[Wl=s~Zng~OTZC` @MO9\6IJcCkkk5~5Q০Iss]V[k>28`e*^Qsc$}eO@|pMe5gʕZ?LT#1i$Sd7Oe;6iܼٜN܁v?vn4]:BF4G\h5?!{@j"xaPݏaf[3A0==,9x _rɄ 9ro?+:V(7MRiA=i*MVY+mmmL?1FX3'vo^? [~E / #flZ} ~j< B3"8lP?AEGMQ]Ӫۀ@#҇Ef?Z~T &8ZB@޽{c=7-㙈iHNhn\5]w`ݛG.\V?CQ dJxm>IAӛ.Hc}}'J}Uz?#1) -{[-iH[6ޭwYj~?^ 󺚉݆ۥ5Ƌ_i5'#)/jnn;)}#fd;! GI{z?Æ i޶2={r߳w&KZVKU]$^ sm~Azgڜ9WkU ӲR-'KT^q/3[^#/4"-Zc⏷n*G ^Z!g$? :\0BOea/Т:sdz2ks2Mm!|| e:6iִW6׫Fm 5R @xT@~…ZTTTh8J#PHhU>!2iXZTuoz#/ec^ (RS+&qɱUG!vs2[:6k^OW &v6z*"o>F*v`2"Àq8JC^KJaPy%Id%ߟA .ޣ0)N8`%}ïmϿ`j~iObK0pm12dE0F{;Ⱦ -ٵ[4%%[;whYݍ(QȞaA𱾟h??5΋SOF- 5 .v#*Tj_a2M^,/KUa@htǻ]Y!*;pVX7Q'h}!a&,_t_ Zo~2.uf @"3 rGK$,lY*?,/>ClmjĆ?*$BW[,7^fe/>"o'[fT/YD d?< ] ob='kk0htڀ̚jD xQlEqBCJc^m}cOb D߾PG?ǿJ}#;Te nP(yځ 8QN9OeMnu%/Sc;QħƍgHChRmSF@,XY B?Sv3J[ﺾYwp <{|Q;P=rvpRxO*mR}DMƣ y՛WQBCGğ*~' Տb?c Ņ|t+@KFM{/FFѽ!#sc@QZƗ7AUpr];e `ǡ۟%OKCHU';FhCzDi}>gjB_:_mvoܸqZ?Qxinj9 0p8jO@B ,DjԲAm05L[Svj*Ԋ SvT{Ϸ%XR|Ïc]FYܺ\X\=d yMM!vǪ~E؀t.RJ1io GLn>s=&DFS҉iq$Ƒl AK+MTj^]RXvD|?>~"---b]+ƒIz? 2&M:$[ILk׮}S7Yb?7cf?o[#l/Rl  T|T?*kE{J>"՟{m Pyk3Q:?L o̓f-?+? !9s_ozG>7䜜|I^R/}ڶ P/RQ~6}oL(fo%"d # x~K[m6Ex!húȑ# Jr#hKɨ"ď^{UbYd cnx8:'[b"fNJ+/SS >Ga*]-,ܵ!2,(T>@wxfG:#Z> p sj?~hàd<|QnO& f`*KMPP-e= !`Η쁧˔99?n__FP(;c&bU}z>y/h|&X_G駟իo嫿Me*W;ϑC['َi!hMZ<j.]q\hD$Гb1On¯[BQow-z,j"d6n8_&,om|uȹ99aK z9o} 9m4|HgWԾEZ)5kp`pݼH=j׿{cֿĩ7rז0?\FTER|rmF_Рҿ6kqH0o$wl^;krU#yMC4s:'&H~GQOe'L&WoUM? !>Ex7oK:)9We?Xw(:9e b_6k?_iq`#??Qτ!??jG9M1yPwl'w̑TZa[ Dg[a]>hCюL)*sb/RaoODcxF(Ҭ*}71🬚Bv <^24' HLZ?Ub>>|SQt>GO?h=ӆ;a?#TKͲjՎS өF޾iz_)_}4`R} /ϧLASl|m"x/1_k?ذa=FY;pSy\c͢ѭ8Oe3#خݽ crrd|y|ڶת(^rdJUH=#G1J7[עkS}O}} :TG_&L?] (N4bڵoi8/d]i t]u{vh:>Kt7aLNʨH]̇33;0hD?RȰ$Vlꩧwci 8[:ɣJk{Nyf̮5wJcǩ}\=B߭脭8/~*ZquLz& &Uy歖|9ȶrFgtDV en⚌Um}g;UF O>s>@Q!EEb?-^m|vMݻ5ч#.P"2rȔ~6/ g鏚cШ&}y: $n=)-Ǐiu_w*3v<#;vFYjm3}67h [N?| *!uuuZ z *1؈ UG_ڿo2fxV۰g\Y'O|Af|N{Z6UN{Ÿ3h"j^~XcCLz6 U2_{?FO2*ƻ妉7ҷkf6M0`5~DN+̙O87qDm{p_. ͢bG[U,ڧ $,jYm}Zis{ ֛[&aYv@6?c&ODc}Rgj̢}bO>>*fßM $ܱy\}lV>;lXQa.]ԾW q!gڸ\,`f+ Ąq PS ??>fw 섟BHji&uX_'<Ȍ|zQ{aPJݦsmG 5(w3P"&]C;ځH*~nHTCa K-L׆kfѿjo\5s̅ҷ?*K@ ~r^;dž2Lga#鋴?"f#Go6?[ Fo[n7&>C@7VӤQg,Tm~hDXE,WۧOn f!:Mt~֜ş?7GԏA?hO0ADɕTgQci!sOi>Pm+VЊ0c~f?XGل T%{瞗DGjh!@;k[+g>|pFY>F>z2.ѾX~Iw+~1~c*l_D4rB2g KQi>㯅 b/vMZ:.Xg8eбv)19i!ZNl>kpS7M|ܬ͛J>za Ⱥ J(ccY ˪qkB|ϙj؏]_MM3x_oǰޏ6?Ҝ {6 Վ>`|9+jet˯)1pW[jGE/!@wPfoK.*2u4ܡn7v"~S=r*PhX鏙n x≧- ů? !$L'C 3"~DXG3G?sq0=Uw俵l]]熬l}g3ECaw?}]L.gg-3&7Ȁh˯I@s%9O|H?_oCʿ2=C0|/CZ8 !$9ϣSgGDiT lT[D' pO !sP?ۺh[ o ܬE?:mŭ00Xo*gY;ci!֩GH<7#Տ7b }?r~38<]V̙3qٿ寛M}K@g&$TE+sq3w="c`yEˠ=Uf ѿ~_G4 !m͆A|sևJ2(>wRC:d=xfDGT+ xwx/s?m a?ּ?υ`vٳg/3~O=02kV~?1O|xƍZ?ި*D6H~f_ jKz͖Xc ) xq)EL;G A J\E~2!feϚ5+97k ?fĝx3|aၴt:#7!*oݺuZԫWc#%?̀u [ߞ@͎(o˄xzgc=nLZ_׷ڿ٫sڌ4TA-$]u{10A\?7!vK)cǎ~/uA6jǿGе@nO,~,;v)-z{\„ $b`8"BH~1x?mI*+oFVa?/Z2r1@u; vG ^鏷*HǺ}?1+E- "o}[p81 ?cѷ~Mg9^ |Y#Tυ?Tt?Р ?*f> Bwf lAy U?sV&n5/LYehH>Gf⏿?~7u[-PmP7n8-/**: a-3{ձK,ya @Ea3fK< 74aPL:}7EQk8|fb?~X>A*"kC`۟2mwyL1/o0'f tcJ~O n~B#@hAOLGWqz?pB?QM#k ?2(;x_&" h[3OO(}E_?fHO;]|s0z25552f-AFgcv|ODVF#C`$_ kvExoQ>X[69SO=?X Y3D/01'%Fzv Dt?Xr__DX_ ?0ѿ%Zc1Юm_K?Vp'3C1(fX,Yc|ݟ0[חW7}cL>}?Ac?챘̕+Wn}yM42OzkD'"f3ShߘfԬ?hllԊc}JDV`."P߬戻?1 юA$&O@ 1/T3Ma];L|LE2%n&DF./S*#ZbX|2FP}f >ώRV 9䇍k0~0H3g0Jv=j9e3>¿YeB1q|3#4iioTi0XG{P%wC$:qQ&*]F`g̾6 |~#P`Gn%b Qm/*!b `2"?}>|0cy\xf1N;]q^@`g>O@hɡ6*=;Y1@6?}+!O 2&0PVYu5`?R)ww`f$Iܓ72%!Ÿ7igDtMGG?`_J[eEFvvvjVlJ~z*w3c7/ 03b<#n`_ot3Ԗ ˇ95ao胔?@b?RzL>aտ̟?wygXEyrC8љED 1DUScyfM0~c?R0FVRz=%C)$.Sfw9裇ʡ3\T t?JIto>G;U F0B#@'XԚQچL>k[b/Wښ^ר vZ-6IGO,X$`e$C}?kcϖ-[!?f?M rGD^Ei HMD\D;@V?#F`S$ ?gC$̔j#Mt_h sS@H80NgnZ2{lsУW;i~~Y'-@U?6o޼?o%Qa !즪(kQjE^>h{LCkW]{^4Q.G hiTCb?W'V#7*xt*aYwsN,m27p>G/K?o h!<"G@b?zǢ"}ٳo[|9*,Ͷ52yYG@IUEw(5k3[;0y  8d+m8MMMZYߏ>?(Q_+"u뮻e0i=4 /TGZK~4)>XGx|/3hO<ĭ .(Ί3~vBHe|L¡ ]c4&/++E(ӧCA?0vQ3Ж?3#?/BHf y@Du&"}O니=XOEvc?CwDUNcO@q"L<k~}/k?@n?<0+T7'MS@4dTd}O)+VhU-|!Y9DȮX2m7|u*@'Y?i!Y3P鯷sf)!ɕF?!*31c-Vn%ߣBH AD d18[@?~W7U\9zQu !$(L} }}DGbE֯_d^^k?3g2O@VF Kيu (K&>⏴Y" Ǣ%۱uEW^y6?h?o !$%7B7}ʕ+TcommV臹\Oqp"jy`1OJYH!BlrDVFh=ĦI;ӧD*Tk \XCO叩BHP=6!k{`-b 4GAY}Џ]?n?1N͢74tDsn%]wk P~3/̆+30wrh86g&IͫAv-ccY;V~b R{SWΜ9Yf-fd#`' }޷BM\t36#5S^~aÆI]]ۉ  G1W?oJv ~Rq? !۷/#L#+=1sG*(ྠ׉S~Wc~Cvsj̢}BHPvݙ00(CĿ|r>bocc#g_uU3Fz U? sb;ŋv{7?$ =i!^Ts wͱ.|Hc?fCJ G~x0YNK|Wܣ5K@'\nHuSB:֏5AsU}j|SM.??% !#pb tK ۷oׄ*Tר;H0KENXl<ߩ"G E4dZbmN*i~lǮ~.~X7|Cq,\5>ٿ8*wDŽE4%vQd@j9l#͝:ĉb?L8ϟ? J?YYG@5*=bgO%O{# ~hF3m Rf!窯)Ԑn\QϢ?BA @&: JQ鏝( 5#J|384>]yrpȏN6a !Koޛ[LC"1B;tZ^!"(t= /,CBhp4eǁ ,]ݎ!8w슛n zo\d 6Zgm~FTSi!9bVLe ǎ~cb~`kj_ք$7Iq" x,U~O& zP:?qx!a+ Ԩ Cki9X#ƳI_uF $ xvENg@Æ RSSC#ׅϣv&q_\"Sķf? dY#&7]vkv}!~q@_ TbV^=_߽sF1NGm"~#ON? !$@LnqS C 1u)LCI/!Ǡ~_s̹{S5;G HͲFo1 Q p+`&h* Ґɩ? !gq))[-SV':4D = ⏏A9R \7fJ?RuV ~|ս%{FvBÒWo1U~ A?KVV?~s#S#TYf=>{i~fsD'ASi!4 7g&790j@?Rfo'AZwXG袏I&DV˝jYW3wbG PD?Mw,._[C+j^ z]S7Ckު&pwa>f[ZBBboQլDrqZ&B?U~;|]ݡmkoSi!n>zϷ, @0BЯ%_c4'h"yc{SlѼy^1c; ?X rd;_? !ħi:|2\,Àn ׆@d[يP˗^]`faO, Si!4@⡉*ۄIh DdqO| ~T֭[z*<'fۉUDjG(4e {TSNZ}!^K/~g̙oXb:/Y [ (4DNfqgy&h~Oj†O?c-)n;(B7~%c'N/!I: ޣ((=TE>34}TWE-[/[^xaUȡ"~'~? !$ m L:*9O?KXP+NXN6 ڕko.8N|*oV#v|}*}ߨ*oRk=6y&6}7ѿ]V n* X/$~ۂ$`$N10 f_LČ>q}z[ifѿYzޭ ;cb烝S} B`40Y$"IG7q_[}|}$~,f9'Swc쾇%BH~~#j"1/02K3 6cRv 0.8z ? ! 'Ѕm$ d8 1F-{SBB0,&os`AקopbMoUW"NBH|>87|n?5Uw e7n|F4 m@=f"qwtVt2.S !$mC\Fَsi3ۉ=?p!$U+}QW~1"| ? !Dl h?մTSpc>(43;Sz6ZX s<K &|ֿlفtDOh!gc{~>Uw[`%4<Brj2!Nis's"6B@!!nM$4F?݌@:Q{}<şBHZTm4h?S&~) #4Bwŧg0QΤS !7J4sLWL98EBqod^ҍ3YG'4@g"Yٸųq !~ V|,!BBy=-E !%A'C#߯(P{ŝB!B!B!B!xXIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32@2x.png0000644000175100001660000000456714776170045030162 0ustar runnerdockerPNG  IHDR@@iq >IDATx[ PTic Ē4N&1mC8ڦbudb@ BVѶ1h:iLkJ@ 5K~ sν3;,{}u`3 f0`ތT & sg10?c] MdX43 ?Et)>79t߫Yol gV?6B "‡@os^bxA0g+1zKaj23벷޲hIi8G'G՟Kz!~yh;:HYp$ D>(;Hϫ8Xtl{.ٟG69,G..N6(&%t'[B(fذb E^˶,}Z篘prO:muosnQ=ndl.=ˬrd۾ 9E!c6LP5pfb),#1(p"` 5I]K.{) 拊 cܷ)/W1R)tc>ZkkkȸѫW8ti<5t#m;?rG1馡 k"߆/tyL{1{R5ocvd]ě!2ݍ& F^QQPvv6ZXXlo3Zam2gW2f6;t&]~***3']* hTFF`tvpmP'"cTɫ^b)33(::Z`ϼQ}# OK KX t⁖7n&{x_<[]]M===q󝝝MtዌO@ ZK/)))Ig{{{H01/_n8=Otz$-け:A>syϋ@׮],V)AP b*}.C^ESyFRqZc^ƅ۷J릦&jnn5A/CX)29ık׺2>K \l,jw'4KG1Aq%r1bB-ːusg%X555(i"""b lٲAct/>J2ޢ*..J)!(i B,x܇ W;ޗ4Q ?JNNB BoĘi,kѓx~:%c-m 3 >>>ŹRՆ %< Dh#MJKKM\ԩSY}NH<9L ?111.Z^QӍ70BèVwN750/f3ūWe5Qxr QAAtwAtȑ~b>$LXvDea “" ^xx8eddR$//OB~~ hLMMs3)'-wڵ^QbǶRNo4:@NN$\ڿj*7xܷAvܹ ر+9B1` KM6yN^`bB&<u떄ܼyB ;;;b^As[[['Q 1o]7o>Z"E.YU1h!^b9d!?gee+_YTB^<~c,GpCT`r{xx|lٲ_g=W]'B ne={{㮮8𹝝ݱ5kIRme~Ͱ>ͫ<} {M#/;\/P^nɉ':pbݜ./ʈ5Bsb~U\'hAIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16.png0000644000175100001660000000074714776170045027610 0ustar runnerdockerPNG  IHDR(-SPLTEDUcnŹARARt~ARBSL\N]O_P_P`\j]lcocqdrkx{܇|܈Ƒʩ̮ɿ\tRNS,׆P)M!X?O&BU$ So$qF &7"ۼ0WE=Gӌ_# FN#~Xl񏘼/VG:% BH{E[A ('oG>V+'?}*.$Cwac`"Io04P+'>JI! K.YO+ əG,ĿYg_YZ_}^NB@}4fb0$_p<ʲѕrB-ҷF*fuS_g]QPE' @ [!'_`'BS{D|VxXD x_d 'YX?!'e"aU_g|gcI!)gtOm@M @p_7"BLr9şB$}X$RBHf3V7 XQP`q?BH ;95P !$3f& WQ !$jm& şBz~{; aO!WW/B'k?u4B @(#|?!{4B!yP !gh(xi(B?!^N@(BhşB şO!O'B@BS !P !?!B@'Bh(B şBB!4B!O!P !?!O!O'B@BS !P)BhB @+(Bh!@KzgB!46QWR !;7şB @x*?!b?!|(ѿg(GGU2xTKyAe$)>vD[wbmhz]JcOn=MԳBE7X(j)1e2AJGʨ~2()(9tźeSҹM*;6˪}{K"d8`&E!\ RQUSeZTT>^fr زڑHOSEy2|v|yǐ%xoG/B"1(U _@cFPF.?Ѧj ݷ@^󺼿c!?1Pė@07Lx;eSQ<٬ b~nj%,&Q)篯Fu)/?=O4/Y;{?G!HS#!WN8ȱUGjreaR^BHD73PN4/0F7MV4xǦ鲮cc^^|g,8/>B?}#3 @|}7-{AFÎU}=[v5d y&q\i?%y1R_Su 8^^g. dt#b7xrK_o5IKʍ'6gd'@34nZ?ɬ@!0|z͵j/}([ W39{7F L?Q_&_# uBh(_c 9'ɟ'^%CbdZ$p2Zh$BhlZir rO<ۉ5!ǪBKLB̀ 9쁧4\r Z,0 lx !4~Cѧ!'U+?CoT @&4Ax̤1C?2d/F7.@dn}w4Fk,#(o% FCȑ숿"  !|_~c:\9^f @^fHR1I.U^sY2n%A)j+. ]KU-U)p _E  '?Z9i_/wUyCc9}.[gȩ*"ɩX/<%ս/f  `T}{Ŀ Uں_v\}\S4 0@h9?נ<$*fQm3We-9}._[( DGز9}K[W_.KZW:j_+,_q*Rp kK !圞O>kB_Z[$˃ ʽ !E?2g=|~)$pպ[r:CΑ  ĄH1W7mn3l?Krr~ 1L|fh sglNν{\ꏁ*K%i?k./En-d_]]33пKՎ-VBOY~}YAXhBRQQP~`nԮT\#ULƖ?`F]ya >ȤyAA( \ iqRA yyQz0A{u ąqbcO91#ʾfYںsY9 ϙP>FX9/ M*ϋ8?7} ВR]ԟ>1˽5;6&l[Pq,9 4{qw#o<|,/| k ro\زކ-==߄1OA0+VM`!c==ߞ&Nsuj@g+-gz["xm·,v)Fm==ߘ:^9xJm^ZYV2=B@<(R(zz xc`/za  "޽lݲNԹ2[B@b;1qFO7LޏB@#M·(k>oBR<6;i\& 0֣<-CuIWsUub8廹kDg=f?_mq6ǢBhHZxk'/Kvx\49< WEWx%U! e+ !4$`s 4u{k*y  aA@^mZzZy]qf{#6[BhH*FZvXfY14p OBhHȩ.2-Q3g<ѷy^^2mHB m"X;/zC+ J34_Oןuu`+ @oO0#B@BJI$" (mE B/.cv40oo*5kQ̋N +^Gyx=k'^;B@BL 0K0g 03B@Biޘ&P !4$ @= ׎mEȵ d03KۗK|ï  EOEUR(`f kH۵ފr))(w !H߄8&|u0@_?bq@,}?B@\k7 XIcO/:!ވ[=z_|6q];== M@H~EXK->7~~_a qɎ]oX^t -ËN|m/uuu.]+۷o$ķd/KhE'$'(ޭ( q:0u;ӄΐ}x/"GN?{נo۷n 2fNg҂~ʳ&GL>^wun#FHkRiKKK'= ޼v$$sHjv`j$^t&5R6$E3දI~T7`i?3^/K0 ?yQ;㏿%{뭷> ,L3$uVhT{v3jN۟O&^ As?3at'5 U/SLib?4%D}|C2XoeZ}g眨݌W+:ȤsZh @MAāezſK.93MyyyF :::tMܩI-_9^^>ȷף%E߬]IQ[k:'MTwo-[zſOto HF @my_|$T&@@]UuW_}ډ#E(znVcKfHFT&{QZ 6@wϋOi8Ha?ЅTzh{ӟ7o~g֬YK`߿a ɀU^kzb/Ұĥ#z~޿kؽtɊu᯺ a駟~_YY٤l?Y57?4$#( ο~=o! :{=z=*E7 '7 {4?S|ߜSSSs77nܹsNvmؔUpU' Uu\VqN*۳/iUZ_v͛A0?/6O3vX~=zEj_OTG}19tM@K$+Y=/8"?|n@x @,gOx&0jUZYUT)֢JbСƎ{i*IEEEOtݺuzF%I՜ )/DU)ES:͋eϋu991ra7W#eY9Gea T&Ɣ @=jx5몭9sUT„ ҿimMmR{T.7z'?'ҤRį5fT//PZ'wmy#?28S}t@]3,ErYͲVkو]McJe R\P,RVX*%@ST}?_BxҼmH~c.jo ᯫ˥1U}-օv}'I&yj_sftyWrպUm@^G!$xd>U;>@];*x=2iGI_7f P@/%ŗ^zi'tҷU>%GԨQ2dꒅ k@Ѩ56?Ik d?iY"*yL(wt#*z}|S(G^zsmy(jQCjC 2mvxRG1⋏?3[YY9.]CVC^QÂ*ihhEٛO?}?kb(gd>!&L@ -_tVUj8_<{?T=~j*Ň24@1N>䯩51~k.Ybwl٫E*(UH>בֿCߏ??*U'd!j^$KZWԊIx>K4q}eE.c/۠9sg圁UQ'<=A.g(o U>}\׫?]lٲE֬Y~SS⏚܎*T*KunѷiHָg#rÄ9Al/U /ZмP6tltSQc5Fv/'>h,jYuPNJr\RU-yZaD|}>Q_zlݺU{۶mZ @AA7N3 vgw;`_eo  ٍ0<3NF:f:^XܲL.,jAז IUxD_sfj.E @ Cwbertar:JRjg?-⇨߽{߾}9RԾ1yd PgN=+-[ҥKӍ3@9a@QeTNXfvmm;K7@Tڹpo*9к%5?H rh?_AKuߑf Zd9}S[0`}<-YDZZZ?|=JKKE WZS ~[s Y-xl)pcFkG>1{ZGyݜfp PP[Y")2NWKJ?~K,D:+T j9a[p3@C۞SMI#Ckp~'w̑/ <-%4LųS˱mSeSkX^gU^:;;?#Fh4hL8Oq`َNfdU}ͺ[Wl=s~Zng~OTZC` @MO9\6IJcCkkk5~5Q০Iss]V[k>28`e*^Qsc$}eO@|pMe5gʕZ?LT#1i$Sd7Oe;6iܼٜN܁v?vn4]:BF4G\h5?!{@j"xaPݏaf[3A0==,9x _rɄ 9ro?+:V(7MRiA=i*MVY+mmmL?1FX3'vo^? [~E / #flZ} ~j< B3"8lP?AEGMQ]Ӫۀ@#҇Ef?Z~T &8ZB@޽{c=7-㙈iHNhn\5]w`ݛG.\V?CQ dJxm>IAӛ.Hc}}'J}Uz?#1) -{[-iH[6ޭwYj~?^ 󺚉݆ۥ5Ƌ_i5'#)/jnn;)}#fd;! GI{z?Æ i޶2={r߳w&KZVKU]$^ sm~Azgڜ9WkU ӲR-'KT^q/3[^#/4"-Zc⏷n*G ^Z!g$? :\0BOea/Т:sdz2ks2Mm!|| e:6iִW6׫Fm 5R @xT@~…ZTTTh8J#PHhU>!2iXZTuoz#/ec^ (RS+&qɱUG!vs2[:6k^OW &v6z*"o>F*v`2"Àq8JC^KJaPy%Id%ߟA .ޣ0)N8`%}ïmϿ`j~iObK0pm12dE0F{;Ⱦ -ٵ[4%%[;whYݍ(QȞaA𱾟h??5΋SOF- 5 .v#*Tj_a2M^,/KUa@htǻ]Y!*;pVX7Q'h}!a&,_t_ Zo~2.uf @"3 rGK$,lY*?,/>ClmjĆ?*$BW[,7^fe/>"o'[fT/YD d?< ] ob='kk0htڀ̚jD xQlEqBCJc^m}cOb D߾PG?ǿJ}#;Te nP(yځ 8QN9OeMnu%/Sc;QħƍgHChRmSF@,XY B?Sv3J[ﺾYwp <{|Q;P=rvpRxO*mR}DMƣ y՛WQBCGğ*~' Տb?c Ņ|t+@KFM{/FFѽ!#sc@QZƗ7AUpr];e `ǡ۟%OKCHU';FhCzDi}>gjB_:_mvoܸqZ?Qxinj9 0p8jO@B ,DjԲAm05L[Svj*Ԋ SvT{Ϸ%XR|Ïc]FYܺ\X\=d yMM!vǪ~E؀t.RJ1io GLn>s=&DFS҉iq$Ƒl AK+MTj^]RXvD|?>~"---b]+ƒIz? 2&M:$[ILk׮}S7Yb?7cf?o[#l/Rl  T|T?*kE{J>"՟{m Pyk3Q:?L o̓f-?+? !9s_ozG>7䜜|I^R/}ڶ P/RQ~6}oL(fo%"d # x~K[m6Ex!húȑ# Jr#hKɨ"ď^{UbYd cnx8:'[b"fNJ+/SS >Ga*]-,ܵ!2,(T>@wxfG:#Z> p sj?~hàd<|QnO& f`*KMPP-e= !`Η쁧˔99?n__FP(;c&bU}z>y/h|&X_G駟իo嫿Me*W;ϑC['َi!hMZ<j.]q\hD$Гb1On¯[BQow-z,j"d6n8_&,om|uȹ99aK z9o} 9m4|HgWԾEZ)5kp`pݼH=j׿{cֿĩ7rז0?\FTER|rmF_Рҿ6kqH0o$wl^;krU#yMC4s:'&H~GQOe'L&WoUM? !>Ex7oK:)9We?Xw(:9e b_6k?_iq`#??Qτ!??jG9M1yPwl'w̑TZa[ Dg[a]>hCюL)*sb/RaoODcxF(Ҭ*}71🬚Bv <^24' HLZ?Ub>>|SQt>GO?h=ӆ;a?#TKͲjՎS өF޾iz_)_}4`R} /ϧLASl|m"x/1_k?ذa=FY;pSy\c͢ѭ8Oe3#خݽ crrd|y|ڶת(^rdJUH=#G1J7[עkS}O}} :TG_&L?] (N4bڵoi8/d]i t]u{vh:>Kt7aLNʨH]̇33;0hD?RȰ$Vlꩧwci 8[:ɣJk{Nyf̮5wJcǩ}\=B߭脭8/~*ZquLz& &Uy歖|9ȶrFgtDV en⚌Um}g;UF O>s>@Q!EEb?-^m|vMݻ5ч#.P"2rȔ~6/ g鏚cШ&}y: $n=)-Ǐiu_w*3v<#;vFYjm3}67h [N?| *!uuuZ z *1؈ UG_ڿo2fxV۰g\Y'O|Af|N{Z6UN{Ÿ3h"j^~XcCLz6 U2_{?FO2*ƻ妉7ҷkf6M0`5~DN+̙O87qDm{p_. ͢bG[U,ڧ $,jYm}Zis{ ֛[&aYv@6?c&ODc}Rgj̢}bO>>*fßM $ܱy\}lV>;lXQa.]ԾW q!gڸ\,`f+ Ąq PS ??>fw 섟BHji&uX_'<Ȍ|zQ{aPJݦsmG 5(w3P"&]C;ځH*~nHTCa K-L׆kfѿjo\5s̅ҷ?*K@ ~r^;dž2Lga#鋴?"f#Go6?[ Fo[n7&>C@7VӤQg,Tm~hDXE,WۧOn f!:Mt~֜ş?7GԏA?hO0ADɕTgQci!sOi>Pm+VЊ0c~f?XGل T%{瞗DGjh!@;k[+g>|pFY>F>z2.ѾX~Iw+~1~c*l_D4rB2g KQi>㯅 b/vMZ:.Xg8eбv)19i!ZNl>kpS7M|ܬ͛J>za Ⱥ J(ccY ˪qkB|ϙj؏]_MM3x_oǰޏ6?Ҝ {6 Վ>`|9+jet˯)1pW[jGE/!@wPfoK.*2u4ܡn7v"~S=r*PhX鏙n x≧- ů? !$L'C 3"~DXG3G?sq0=Uw俵l]]熬l}g3ECaw?}]L.gg-3&7Ȁh˯I@s%9O|H?_oCʿ2=C0|/CZ8 !$9ϣSgGDiT lT[D' pO !sP?ۺh[ o ܬE?:mŭ00Xo*gY;ci!֩GH<7#Տ7b }?r~38<]V̙3qٿ寛M}K@g&$TE+sq3w="c`yEˠ=Uf ѿ~_G4 !m͆A|sևJ2(>wRC:d=xfDGT+ xwx/s?m a?ּ?υ`vٳg/3~O=02kV~?1O|xƍZ?ި*D6H~f_ jKz͖Xc ) xq)EL;G A J\E~2!feϚ5+97k ?fĝx3|aၴt:#7!*oݺuZԫWc#%?̀u [ߞ@͎(o˄xzgc=nLZ_׷ڿ٫sڌ4TA-$]u{10A\?7!vK)cǎ~/uA6jǿGе@nO,~,;v)-z{\„ $b`8"BH~1x?mI*+oFVa?/Z2r1@u; vG ^鏷*HǺ}?1+E- "o}[p81 ?cѷ~Mg9^ |Y#Tυ?Tt?Р ?*f> Bwf lAy U?sV&n5/LYehH>Gf⏿?~7u[-PmP7n8-/**: a-3{ձK,ya @Ea3fK< 74aPL:}7EQk8|fb?~X>A*"kC`۟2mwyL1/o0'f tcJ~O n~B#@hAOLGWqz?pB?QM#k ?2(;x_&" h[3OO(}E_?fHO;]|s0z25552f-AFgcv|ODVF#C`$_ kvExoQ>X[69SO=?X Y3D/01'%Fzv Dt?Xr__DX_ ?0ѿ%Zc1Юm_K?Vp'3C1(fX,Yc|ݟ0[חW7}cL>}?Ac?챘̕+Wn}yM42OzkD'"f3ShߘfԬ?hllԊc}JDV`."P߬戻?1 юA$&O@ 1/T3Ma];L|LE2%n&DF./S*#ZbX|2FP}f >ώRV 9䇍k0~0H3g0Jv=j9e3>¿YeB1q|3#4iioTi0XG{P%wC$:qQ&*]F`g̾6 |~#P`Gn%b Qm/*!b `2"?}>|0cy\xf1N;]q^@`g>O@hɡ6*=;Y1@6?}+!O 2&0PVYu5`?R)ww`f$Iܓ72%!Ÿ7igDtMGG?`_J[eEFvvvjVlJ~z*w3c7/ 03b<#n`_ot3Ԗ ˇ95ao胔?@b?RzL>aտ̟?wygXEyrC8љED 1DUScyfM0~c?R0FVRz=%C)$.Sfw9裇ʡ3\T t?JIto>G;U F0B#@'XԚQچL>k[b/Wښ^ר vZ-6IGO,X$`e$C}?kcϖ-[!?f?M rGD^Ei HMD\D;@V?#F`S$ ?gC$̔j#Mt_h sS@H80NgnZ2{lsУW;i~~Y'-@U?6o޼?o%Qa !즪(kQjE^>h{LCkW]{^4Q.G hiTCb?W'V#7*xt*aYwsN,m27p>G/K?o h!<"G@b?zǢ"}ٳo[|9*,Ͷ52yYG@IUEw(5k3[;0y  8d+m8MMMZYߏ>?(Q_+"u뮻e0i=4 /TGZK~4)>XGx|/3hO<ĭ .(Ί3~vBHe|L¡ ]c4&/++E(ӧCA?0vQ3Ж?3#?/BHf y@Du&"}O니=XOEvc?CwDUNcO@q"L<k~}/k?@n?<0+T7'MS@4dTd}O)+VhU-|!Y9DȮX2m7|u*@'Y?i!Y3P鯷sf)!ɕF?!*31c-Vn%ߣBH AD d18[@?~W7U\9zQu !$(L} }}DGbE֯_d^^k?3g2O@VF Kيu (K&>⏴Y" Ǣ%۱uEW^y6?h?o !$%7B7}ʕ+TcommV臹\Oqp"jy`1OJYH!BlrDVFh=ĦI;ӧD*Tk \XCO叩BHP=6!k{`-b 4GAY}Џ]?n?1N͢74tDsn%]wk P~3/̆+30wrh86g&IͫAv-ccY;V~b R{SWΜ9Yf-fd#`' }޷BM\t36#5S^~aÆI]]ۉ  G1W?oJv ~Rq? !۷/#L#+=1sG*(ྠ׉S~Wc~Cvsj̢}BHPvݙ00(CĿ|r>bocc#g_uU3Fz U? sb;ŋv{7?$ =i!^Ts wͱ.|Hc?fCJ G~x0YNK|Wܣ5K@'\nHuSB:֏5AsU}j|SM.??% !#pb tK ۷oׄ*Tר;H0KENXl<ߩ"G E4dZbmN*i~lǮ~.~X7|Cq,\5>ٿ8*wDŽE4%vQd@j9l#͝:ĉb?L8ϟ? J?YYG@5*=bgO%O{# ~hF3m Rf!窯)Ԑn\QϢ?BA @&: JQ鏝( 5#J|384>]yrpȏN6a !Koޛ[LC"1B;tZ^!"(t= /,CBhp4eǁ ,]ݎ!8w슛n zo\d 6Zgm~FTSi!9bVLe ǎ~cb~`kj_ք$7Iq" x,U~O& zP:?qx!a+ Ԩ Cki9X#ƳI_uF $ xvENg@Æ RSSC#ׅϣv&q_\"Sķf? dY#&7]vkv}!~q@_ TbV^=_߽sF1NGm"~#ON? !$@LnqS C 1u)LCI/!Ǡ~_s̹{S5;G HͲFo1 Q p+`&h* Ґɩ? !gq))[-SV':4D = ⏏A9R \7fJ?RuV ~|ս%{FvBÒWo1U~ A?KVV?~s#S#TYf=>{i~fsD'ASi!4 7g&790j@?Rfo'AZwXG袏I&DV˝jYW3wbG PD?Mw,._[C+j^ z]S7Ckު&pwa>f[ZBBboQլDrqZ&B?U~;|]ݡmkoSi!n>zϷ, @0BЯ%_c4'h"yc{SlѼy^1c; ?X rd;_? !ħi:|2\,Àn ׆@d[يP˗^]`faO, Si!4@⡉*ۄIh DdqO| ~T֭[z*<'fۉUDjG(4e {TSNZ}!^K/~g̙oXb:/Y [ (4DNfqgy&h~Oj†O?c-)n;(B7~%c'N/!I: ޣ((=TE>34}TWE-[/[^xaUȡ"~'~? !$ m L:*9O?KXP+NXN6 ڕko.8N|*oV#v|}*}ߨ*oRk=6y&6}7ѿ]V n* X/$~ۂ$`$N10 f_LČ>q}z[ifѿYzޭ ;cb烝S} B`40Y$"IG7q_[}|}$~,f9'Swc쾇%BH~~#j"1/02K3 6cRv 0.8z ? ! 'Ѕm$ d8 1F-{SBB0,&os`AקopbMoUW"NBH|>87|n?5Uw e7n|F4 m@=f"qwtVt2.S !$mC\Fَsi3ۉ=?p!$U+}QW~1"| ? !Dl h?մTSpc>(43;Sz6ZX s<K &|ֿlفtDOh!gc{~>Uw[`%4<Brj2!Nis's"6B@!!nM$4F?݌@:Q{}<şBHZTm4h?S&~) #4Bwŧg0QΤS !7J4sLWL98EBqod^ҍ3YG'4@g"Yٸųq !~ V|,!BBy=-E !%A'C#߯(P{ŝB!B!B!B!xXIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512@2x.png0000644000175100001660000017413014776170045030322 0ustar runnerdockerPNG  IHDR+IDATxxdW}73w{ƍpGsBB  ZlbBLy )`=b{YlߕV];kiF̣͜hսsC*gF.@g`" : ( ($S2F6a"{@pAhס9@ Msן2 X  @rM{(Λ(D:r^̲ /j^Uʯ\lS#8@^[~On^'澘*wUZC5Tk^ jBx-ըUgy/h}FA@^C(s\_*g@Ti_p@*=G ~>@3-gy5~G5CTzf0U@|͔{Bځ@-_S{tEy+Z*@j[KL_+&(<Ɋl!oMno-o. +Ivm L"jrβ -s{mɭ/]ZPѽ =h"fe>T#POXC;߶Yusa@PFQc? LW h⿒! ׁ=DT9(5쿜(d?:/k?5 &t%!@ _W_⿜q qo:45 !Tg h!{?UPoK(dWs*AQ3WߨZB)!fQ@}?OԬ<!L=%5 @++ Wh"((L7(O~s&PQ)$o!?3kp; ]([{9 @8 G[p>s%@S.W=r&N.'(LwlxtD?K?l$iυ*.d?T@'*g?}j P+T?e~d!t4}@_^R^j /-LӷvIZ4Xy!L?` 3+{Lõ+h y9{>jS>Fԉ(rSC>q5?ML̤.@SS˽R&rBɞ@#+sy {N%!@nh݇)hT_wy*@u˟O%å!^$p&xse#?4P*-P@\( Sn?Ф!LϤ0.Wk }( (޹2& =Uq_:*^P+Fp @s3sq]/?4a_|&W@(Y] (``}\vſx2ޗGP#@_ oG @_ @#?WP+(?ſ@?ſ@_ @WWP+((WP+((@W P+({"(s W P+d/= "/se0Fߢd/؟@@3] TZBesͩ.h>C,g}Whp 7sf2?P⿜K{Z*_h~h?̠^5 0QWKgw֝}^M$\k{tth+=؎G紐 slgǝl LFTR{??dJ>Z%mⶅai%ɭ7zZ.ss{$KÖѭaydk8%:m@@3St??d_޾4n_Vu캥: ߱:Zbz[{.,xdxcX?pxphm{OF ;(M;EYûw>8uPXپ<>HÂ=AG}|8ppε~ܔPϢܯM7+ڿpc:Á:Vo,<ө{€v~wsqF rӄn-h>{GwNB8YtڞNGK |ǯon mqZ@,$S/q[^[GK{89)OR8d 9nh}ՎOoq/à+D{M>lMn#mlm| |&Se ]]1gQ&g UxN% X`tW0 ZzsY 0@D Zr-a0fG(QOd  u`x(ӆzm u+U}$3xBwrtA,gs@<~œ8OG_/O?oa0jДZrI```V)5AK?ܹ+/N.xR|ºv Miw +X@[.9QW(i8Gt>z(vhӭ?MXغ Wlgа:ZßpB1ѕh"]0'}=‚\p?!\{UƓ>zÑ݇4IH@ sr%>zJH/CTdyG\[|At@uA)LUOu_䓕_ ~β4_8>,nuCP/UOrW7v~IDG$^yau{! )4]9zYr;=t`G蜳Ig2eAwsP/Pû8oªvQ:z1~yXҶΠ:2VW{sSܟ5~'hjG&P򰷇Ύ:KF#,P"]P`?T@s|=d|WXվΠA: +K 쿡{ =Н3ȔIwGӔSc Oym.]-v}Y2mw@uAԊyd^z]wngi4wfAs11@rsLI?{ϡo =yv$H׆|.og0G3 r/ћO/o_jg^Nr̎`: @&Z;athg$+/#S=!z?ɽ0~a8s0[S)gg0\8 @@~ J:Uk^jG@z=Uq ԥP2;.;u.:j" j^_\mg \Y ϰ#CT@hw9eg+^`Lru^-3*-s~V{^iGPn E}-ߥ )ޘbig@pᒧ}"\3A$ᄞcWӰ}A:!s~-'[_[ceՆ70\./c|#3OWpqwmgPN. z`|UL Ic0=6o F67 mְc/o;HE?;ˇdړZeYemKgۊeQ{{|c m@U U%ĞcY7>ܾp}ᇊgka0n/]R`&uP8КTןí? c; aU(si_*Iw{mM;8x_=XGK{8p̼#± 'S\ўYU7\vUb*@^ⶅv,lnm7k-/dúg.xbr;%pqf뛾Π*LPvnMd؜+mM*ܞlczԃZ\?EO->;u wΠ*\@P?_drFސNŎl{$Y-]3d /yie:eᬅ'`r9So]@LN_prlz̗ؔ1w 1\ .^j;f(* \x^xJ _Y x#ܪK-3 uM):Ў(!]_b†(+THg)'KּıVM%f) fMxpa؀R%B_IOÛB:BǼpCGK$'JvBF& {߳#slgkknkg~;FxÝS,n[v3 ̅ɥVw#vmׇn3u /G~jg ]-v3$L|JA2ܘ] [_~!;o}C #3+:3/(Q;kiKe];2|OJCJ/ Fg~\bHw^7gg~|g «npL4{̠`/;"}ppɭo,OcypnK9 Vs"gӳ˯G *;~wsfAe=cPS{l_^x[4LJ›zwSuG]3 >^s[Md@xع6۟uۗ:*.XLn--#[Mo? adS:pg,y  q3CokO;^zAФQⴀyƒslFvenW_i6͒t )'8(*,XN=&s _@$G~f2 a 'S<<>u 2#pګ2ն5|gkЈ\İmQ|*=pƏԽµ?mpS5r_pl!];hxd a]-df{ p#q+L])~G3u]OZxjhi%[gon _ OL" Þ3}cFϘL P&5NP#@6S矔=ydkqGVT07Z`ЖkĶn㑯i=\Л~[||r=GKFwOt2%;׺Z:i<;ohɵy-SJiOu$ϭwW@dSm =vrxɪD;Vú(iO.޲jn-5pOۙhEcF kBoNS\ xLȒt݇D~I}sgfd(5)'W\0oG581~c46LlmfJyGv { [o}db7fmpt` @dĒEaM3 gvX6aO` "+G-?^{@f cڰnhƦ,컩xňY3f 6|p"m<*Ȃ%m2ܨ 8f9ZCC 2 89ܙLJ,Ha$m<0 UG;3{#a MmG,354> #~lg%v yÏ#[`@ey[0+ 9Ql(`nF<7~GWb=6ٙF a0)'30>FK\ot7Ao4Y;~ަdI:ڤ-[n @&}y P5u#LͥE҆Mn_A!@6lX7Xj7id 6-i[Zr# Ҷq#D<$' @4Em 7jd6-j]@4Й.ʬ@ḏ5#@4wwa M}æ+GjdfS@4oy~kFСoԂlD@#_ @4q>52u> VTӶ9@S@ݏxz=Qo6#TMO~д@kv40wG}}c;52u^ V-5 gXF@{xGkdh>_W3+$M"{h Ύ|r&/ b՟/khj`Бo}ܹ @bw/R  fp|H#S"h4]-q@]gKF|vTY#[42%(cՑ3@uc0f^zrx|83@3vsF@-< C "}&/泰4/!#hF 91!:Mh#pU_.fثL>C "}c@m=k*ѱg @4Ko-1_"}b '#otH| " EqբCK"kN?Y@)u2WEr5x&} *c :0x5@GPFbu2WǞ5@Ƈ.,Ȝ3@=0^ 7F40f3T;h lb?ҩmhmP Gt42s;I#6^|@#/hivbz8اwI2@#m "@ xۗn>LЄ ɿGاIž|F:#52fBFPg"cO#hFO 1q4Z3@zz=N}chZ"λuF{#~ءZ6mQoߢZod?%W @g1WI_@l-@ce&E<ƓCok O>`&xrn(a@}E PnMeC]ȧ@ąC 'sz ‚V>bq(@*$G~VoQB M]6WM-Qo6##)jYi} 8YQU" ?7wJ ~ym{jW3-Ia`MXNewO|~ni+j G ӱq?)sux~zk[bż겮O콟$jlz-'h9آPWgsU/zыM'%ge˖\c? ۖidȅM2\;_Ww~;v|鵯}~Gh_m C[MQ?x{c9暖Ba?LJcgs6D%ų]#&G4 P|rG>ߛîaÆ knO.I jb0RvZuT@XȋR+In- |3$[ccc}`rwxb_j[V3G&C-`lZcmK޾="-Ň=Ͼpw?i9+oPSoz@GľVQi \Y{ w^|_X // s@Mz8[ٱ\#Sq_i_ϙϕܽgZЇ>ʓO>ijP7pe?5pccCClF`.j|,LRuQ 򖷼oѢE77lٲ_";Z@=5425}E۶hn߳|??8G!'LKog?!LX@um Cw+0l? ]ײggZ.{Z2d9֭׾~!اlPfidduJ>/݉+Usu]W\qî'\W+]k`|0"h3@!u+g[Z̯'?GuY?}xTo|ڵ;cssSF5#".VT]Rk0l +Tߓ}xk^s9mmmO }K/ƄS:wi1tzs_WR϶/u9]*/:#ޙ. #wߝ?n@Uzu{P8sM `nj~쾵}ы7{ſ[nܸ_>vP PHZ\KXӱ:;F44B Jj{Lk񎗿_xW';_<ߎ뮻؄}7Sڻg5bm0+CGK{g@3?¿rz{c9---=w?|~p 5wຨ-)Vhh꠮Sc)S;#^{=>Xi?44to|"_S*P{GwQkT|m W`"Pf{&g*/}K袋!{馛vݺuᱳ{i?ŽO8LuG Qq ??cn{C]>_im_ I~B"PE> C42Uup䡒5(plll :+SU'xI>]w/7{zPEt' "0Go9kWO J6 J.îMܿ{ @Gh_V\ ]fЮB>vƇ#5tY1;h~"Zvړ=yK;7rlTrٿv]0E}P`ÍʱҠ99!DH/=?~矿K^+,XjlX'/ }O 89+TX{Ji-C%*)KZ_N;mmm]ZpUW}4>&_r{殝k޾#TX;X+ȼ QUOT_߳_Uc'=IV[?xwl _o@bf#}pݾc\[8++WCO#"xf42(ds%g;^x^?sۓ]v]3{v@ݱoiⰲ}yxh͌5=w 5Z-AyK"0)k?%w|ᇿa M? [Tq=G6 Gklݦ1^1$o.u>>/|z{{Ooٲ?8:?Q}Y?p=y }/Kz= zfZ϶n!]_~?5Wc_?]o6;;wN=6( ,zFG_f/K䵷kdV?gT/Uqig߼|o]wݵ5?O@ Y Ovyܫ:V@:0`,@ ƣ޾yn qe /gw>zc``}ׇDo~O=ACS13?cFPI4Dbק+gzK"Y5^{ɜk]~ӟ^m۶Rr~pƂS—7Ʀl'6޶N -@ܡBa_*0{mO?/?}\qJTi_$J#eڢS]a؀gZ]|zh2D@/{BdVuz+/7%s7oCaM/\h֎H9*ml˵S{O 48:mQb5{x8/?O#C\AW,WZ!K[[[y6l7]sgjksۢ߉xC+ECW`X_7G#Cs|=WϞjo)y^Yg>8㌫>>}#9+~st\krsTSRk.NOF7k E,n[!AAaB^(3Pp0IY/y{[¿!.nݺWzWxlA9g |^G 9񫾛\sh'⚮?ntRqc%f%g5ZW>)*?:_< 3nlllĵa߹*LS>0'vW?fޑQoK"`J.:;ms`m5O@# RwJݟ)w~wq!,z_k֬yI.kv~p%g &%̍}O \}hO^xzi.z^ P0  LuFMiQp}K $q`mЇ5_~a |E9~ӫs>ֈꦛnnڵ[cg+Y80M_j5uKK]^=}S7|]8->'mLjJGVuМEaUr S'~?c^4|+Bx\>(4A/0+.xf2L>fGvwxΣ/ vLJ4xb @1h_1_ig:e/{.wtww;omҔJӍ(`Neeh.fYВ϶Rc@WHX RC'>6K O #6l{֒37f5^ #Vw T)Yѿr~r=׿.O|S{{{Ӥ??>::/cNu Fs*nh}ٚˇ.dzu=oy݈7ު.&d~W_ B ڿǙf^sۜ ΖE8^] V^ @K[;[rϹ>,XwϻvфxMIo?3@9o5Jd-߉=K?ecp =C!  bޛwO x5\sΝw޹nʕ?MJJ*ӵv_6{ Ŀ9asPB˶8֔d\'۔^(i8m;djzzX\s %r| *c'uyw<|px7"=h D,lͱ~"YHLϗ}6tf~!9a SOZ!  ,ߎFGYFIII_W_DQQD霺cTByxeM.oU6؇?FAX.~!:nc1*7bg߈ Ֆc_6,^;8477?iӦf9^+KoOw*!`rzRf% 'f-,6tcm83sNMHn{ Rꪫ޽f͚gqYONeU{￯콯*  =[luU^5-NjBVa2 ݛ#*H|~؄#M_*z뭿G?6++k^{̓g-o6/!4lxU9^;Zo8.ߨTUx%GƏq5!ǹ(\XPK]ӗ,YR?o}[O-\Iȍ7޸Vfz"<hxǜ BR9?ۻV\Z*߮7~Wxk?0rtmS#R !QFz>ƽ߽_{/˧kkkvzXU!{ `}2@1O?÷h Tl}~94vyQR8!x?>D}]w؉'"+/ 7ܰN|g w#ST+-c+E_"%O뿧ۉ' =Ih=lLX WW\Vk 7saw9ܐ^oE}78|0|e io+~Bػvnj/Y -7٪(%) mu0{aXmUl D_xG?3̩wq _|,xߟ2?o__@{5l:B ?4s&v?25i;m};lӯMR HHTӜ/҆oW_~$''KfffLT耣^˿s׼K!Uzu-[{vRfˊ̥<⌴TYٶ㾎yD*Lx$ '$6_Ę_˔wKJJaUUU/Q_Ա?񏏊(_(A!Ĕ|¶Ǟ)^#95Dqg8_!bVǛtZ~)E<\w5C?ro~]wuo~_]]-vD9۷H_OڇG!/KDm!s^ ab&Ks+kDp=qO^)Ow?'O<+{IlNV-] .HQ])zv~65퐭}yb3qNh¬o_lٗɗ5riٽ{(iW'es730!Ĕ8pSreglúoɚdѿZ&?$v 2Ha 'G^mǔ[C{dp4Hd$,ydm_钢g4u,纐V2 0@LX ܄׿\Kexj&%&&jY;wh^WFN /?gbZ(W}JeȧK>&rݡ(O Kk_z̝i;9Rm0vkGġ2qa~D{FbOծǒ̄t~Aw៨ 2}褓N:]vdF QfzC1 x xbBSWnK ηZw.1Fߨ\M[yRD"k(66SqYjIIܼg#UP'<&)???_O9+b%/++70+AWW455\;=KOOk-[Qa\<; ??P CiJ\'r귾-E Ɠ}ߤ0mlD7f"`\(*P@NJh^{;ӯTT;vL80+uNk"A2*"޳FV'hH`{J \ i 2-7+orQ@^R\Y@g@D =Q͡CEBXx 8 ]k0-- V/o>ikk<Tdddx|ͥKj?knn{ݼy3Ag wiWj jZ\qd/ek87QPb0  )3<󙙙xSk+p39YYY~"˗/u\ڈ@`A[n 'O@BH|[S9?qOUގA;boF ܼw?-Ui\7ڭHTP@M $ 7dOk.z׻X p1noUb]rrra{ߛ6mBD @ <1q BT\S%UK呮 F A{|RVMbZ$lU a@H,:&_y窌'p._h&>nppPss?n=zT  Y(/}mNzUAm< ;^e.bx '?]'lUUOq|AT6cPr.yNaoBĀ^dĊdw2{rϏ{Pb}2:poll3yz L_1iBH\qgB YƑjw5{Ɗ%ᢋ Ԩt..Dxcp0{3$Q?r29mI=;1~eKJJ #_WW7r@w/-[Ԁq)T?f `7VUY`jl5u5WUe6mǝ]r*?/RZʓ$Њ=˅qvޙ\8$ZNe˪r2IN{Ѕ?DRW~immsW__?y*,YD6@@eת =~pgBH܁?Ug*vƔ>2Z+>AVhfgA$ͣe]c\j,H`DyJY6Q~sJ}hhH z=\=dnT Ae =FA G۴`=ʬaERMD$?cň1wh< i\8&-$BTLC'Jxe̒%/\аrUp)((e˖iYc۸qxIÒg`YghYm/ *#^T>Aǐ+Xm`T_lJRʢ2N[$K_ i 3v>ߐ؃`d4d%ƫ]+@k%ī(kcA5e``@sΞHA-);oPXke:###Z?G;;h*T 6?!q=.D!<e) M kۘ*SF;A)U>>:53 EUoS^_Q,e˱)@纃|#yg ȡ' !̐U Id1j/'''hkk}ðСC~~`?w-+j;)!$n r1L2 yRŰk7vq!L<$W#Na "M~gee:(Go}ޮ^ڏ)p7Zm.󿧞zj"Eg {1g FvF /{G5\XFl'$qA"#. Fh~g $G=J=٣eu&''j~~8"h}KOO޻eqD3/?w-7'H^R.0&Ko< V?L'ʑZTV2(pٟ?8d@w`01gy>u1.sGk_T B>ǀߡ $LrX>sswrAYzdx!ߑ#FNFk&ӿ>⯥E^CF=@9!! =˦ޭ̄xLy =$;^S;Vq1 wV=Q.',c51 !îgܾ]v: Y*{Qwd}o޼ydu7X(fKrr N $v 7 GBw'/R$bؘ gV;r)--y8qwΟ$  Nn]k?0\'89BH`t5]ME9/=\x w7# J(_paYv#>|X駃p0{Tge~ K3R! u?q^? `9 #K_Zߏs?RH ?!}`sPDA(رc `@LgbY:&?D_Neno a!^xC|B>\8 IeƫrS'ChCXߗnjj7#G}hНP=~ OM(_A,gbi0#?L~ǒ!~V~r‚mZӊ%\ XN%iI2z,NC+1D}wA܏h 'ZB^{TE$03@< 'ա?iz`V@]'I9\&~KjxOGd;u޷oLLLhϏq~ NK.ÉkA0(8OId݃H!FAY/Q_7K()-`K~'@( Jj%f ~@ww{8"n^pD?N_ӓĿ BlwsIw՗4.4ijؓ_5R~\ 4f+pG=F-EwnwP]z#2w(*!Ė2\C4"e9#EKK~Z=)N)ₘ& XR8eW, >)++62X~Ж= `ؽ{ʿ }ܟ BlK~wyIiJ1XQ}rM#M`@A/z9A\ӽ,MǬT"el+JW+ѿT5ʴ9'_;wjWG2 rwA?Ͻd?3@!.<ۻMT-ₐr{Z?!vȺd[\Tp2$-HdN((S1Y"KFkdX23g +11Q둇Ge(h=0$)iӿ'\A4eʀDBqcAʞoeĖbjP}W:>`A'SBHdW:tK!==]JKK4n8vGW =x>}СK-2M[.!x`9xMCrJ1#?p6ލpqhX|}ᢋ%;1 A2TE0' ~l9S=/!alaaaCYtP~ {Upw70& o['{"O" x}mrruڗafĈ<HD86ަAQ Gtu=Piv`41lId,Q*w~咚?^BȤCCC+8&l`ZC,@>|-[4qpyf0@!addjT~s\Hob.?[~VU ImL++g)U\Ύ;'8LH*ehM-fj WN9=^mw`z ߈؏zʿ4Qaݯ/p%x%zĆؼ ^gbDet˿]6Lbz2bQڢޛwJNZn)192֪{d~dOERѶ)g x@C#yq!M  v_I $,H.rn.([Blp_ 'g +3ɒz)Hγ̱NNOvi;J[6u~ݽxm\xF__ڵKn>7P]]cGeÆ  Y`&x1k2EoY@H/_AbF}y47B@QrϨڦ*SU Ai+T~dtLti}3BoT߾$bD+7{+}{~~޽ڥ+5QWW`P>W\qwe&A쿧3Bqd\G2k|cwqQHT/Hko6B.8. Կ)RR$E $7)Wmj.n*^G& 9zs[OȐ<$esXLFy;ޑ;5N# scP6oެgĘ_0ߓpYB ;_H@ /'7q1)Ap vlHMHe%fjU v̄t;453lLC8}1bF3Mji$a:~Z222,7XE755isOfh^yf;^̿/8@*C 0@!a@]^r;4$Q+_ʙ gm1ňrYR?^zkQ"T;C#n5&''~g'afXQQ1GLw@x饗V fb|S$!Dvk[Yj|b`EZi+!$GN š?p1!b*)2y\?eddDvܩe?otUUq04Ӻbo,K?'죒gB"Hr]r۱{Y,\…!dCfym-.!$/pQҮgu|Q{nmLp⾾~^o=p8z믿z(ǚT1 ~p߻vڠ?83@!19 7t9/ !󙒏˳=[,V.!'iTPeڨ g|# ?٣J.W(w^-S*ǎlm04W& /?a?bvl6mè+T`i*$ D&%!YWic!ĕܩlWY:_9Q:ߎ7NrdQZ aF">h?\cc#ߥaB17e)r sZ&ىY\$bSOƞ-\ Bl?\UY:>55uVCڙ1G;0=s| ``zݺuaJc+ !NtCOhh3kKu".5 ;^~6JUY_%Δ>du3?ͥ>`qw?1X3W^ܶmA:P~O!$j 6zErR *P'5RQ rF4A R3HjV>Y&~8]]]Ԥ=Ki̟ٝ=8FFFz?jW T!$޿LȦޭڦS/u32I^l5BŁуrV<O~VV'!"y:I*˴ "ɞʌcRb⟢>0CGG?==W#fwD.o@;gb?@g  =٫m(AhaJuYTRIʶı:roٯm;(''_-fh7{W=Asd'z]#c~7>Ą606nwd Hf |iP:&uy{T)HӪB\i.7&j9.S#225*#R!;'}Ske1}MzolY *OTi I*_?%X"˯ UCߛe`WQCC'%%͹oٲezW6AM@h_,V #`q!+ %+1S 'i ;_%aN˵)`sC>a%1!{ϖ~ܖ>DbnV~58hJOOvw8288 {L^^q}K. )A=WjqgBH M k[<*oV]%S$%+&J40^-9S#~뢟Y}@#K{1x\n ;nf"MD3|!AÄN\}[9yy^@HqWW/#3?0z(se``@G;MkUSS#eeeq{7;v<PZg:ϟp7mB!ckm|Jye͸ $ArB ~_3V!yS996W~Н@Ͽ{?>:Xw8o {lqW9^O==^Ĥ!ؒ?ܬ&,i ;v;~rm !EcQ?e:&Ξ$4 ?& s|{+;oΝO*cDD$|"3@!Ė`]/[yy5ē0pDde Fr(~LMMݻ5CIggx` ]G WjF9rD {;Z` "Gttt?w/b[ B!$|B.-@g^y6:x2[Ȓ -_;HN/Ho{BϞ=-]]]ۿFt.]TV@2͛]{ pJ  /dNˮ!`qJ\Q)<yVӇ̰w5GYVg~|yL~8m;Wh@x_<<>ꢞB!$@Gc]E?^ayy;̓X$W~UįJ2-P!gqi;dw#kN~'^p8~ގ;cCB3 d"/K B"MΔ{Dj=SFy2&C׌-%c5RJx\!Gx7K}vLiCCÜ,?\u*I }7t&w0@!àcHn:z|[ҌUq<OwNekcZµ޺ǖdim@{jAzPdž`RGz@ٹsSjr°7 /#_)!~V.)<_N:j'{x2S8>FQ3r&ҝ{<8>oB|;o/B B!s߷.$-Hg$fȿ.B~|=Ob:`Y9^诒=%P jmcF_e O}UUUZ<KWl%TB3OP<&v~ob[ . B!h=F>.(-Wy2SbU_#Kezz7K@ݻ5qsTZGcz/>n`B3@!mgIQr-$qOSѿL8zYYYZX1:g?.1- Bh@y )8rȎ[ b@3@!xadjTr6Axw\ Ye㿼2yy94v',ȾTgJJ>~ݭ?B,ķՃ_Iss7QEcӲf'?&#Jwwu픹F"L3@!-7Od{҂$jf4sDB…bud׳FVdp"6;:PB^km۶!1 T0!⇣mc|<* xM<HHdOej9atO{{!gܺA dGl?8 fg0Ժvvm/-?BֶN.?GRKlyZq9x2p*3Z++tb/@et~à0p&1"A{r78>Q)HW_}10*Fo% . B!ZnoNʒ*>/6O|G,?g*>! uo4,=??۷o1eees(#ON~ݻVSP~-i"J  B #7i9'IzB^u|i׵29=ɓ|N*-_5^%h,g0kllp?jkk0k<<~Lf~xSz!1%w/_.-QjS?hk@MD8DsOv$zL?D?]8p@LNffJ8τ΀_WYܹ3i/A1(g B!fG䒂:m-se.-cx2،$I%#򮑕pYXݵF ZWC:=z {18 )a&q}z?*'}~xxG:Iu֟B!$HK'Edʫ[{Myl_*' /TSWY~W?o-uϞ=ӣEssv1o<<Mƍ`ļ@%F1@![C噞}O>A.,8[[bUUyX]\{m'ΠE #?<< X1pG?zAGcx͛7?B; D|/U4B!$rvywiiO LGɣ%a^'4+%%%'_;c̟z|CIG?P`K]wu_ >n B!A;'[#_-??9O\<,@TZ'O!D?2zAp_WW?MMMZb}HQQQTy4P744m}Gńڦ$<ĿxŲ B!!PrjXؖᢋeCfy{'CR4/(F$ALQo'nu̶nN# W1W鿡ay<`(*ҷzg?^M":!ʗ!w-7ɟ–8k2G G`C'Jx]dX!~f%q!G?\ľn;2 l1 5USj`XRt-6J>^a}=O+C'Kd2cC65X5o-y,D>۸T [!0`UfAM^۟@+ďW`?BHX}orNޙk-/HDO zyЩH?1q}WP:n0ӿޣ!81x:T%!"C`BՀGƖǟ*ߨ|ox2L׎-NxOJt l7,ķvQnղp9EEd-X@xKׯDfb[U!0Trirr <3rVɹy-}/d0r໤d7:AH=}wFfmV+c:p Dc]1 u &Z^ݼyAOqg B!euٯ%iA-kW+oOs?d}#Ӭ*8-74 0s}cXx @;3 N-Oݟ_\!&G˃'?b/LΗ/].w}SxDڨeIdX2V+G2aFy6 jrrR #:durm0F;GK3' "m_8@oޟ`Bk; ΑxFeS☞!R}Q{GiunƏc P ]8 ?b >FP]z23/1FĿ'mb \J!˒ѿkI~di$DbBP>{;r"dPgy溅-0oyVȢs-~CC9?A5b7|љ ODWx #!Bne\FK;w= o7tb^glf\7霫Us<p+]t?Yx>q!Tիv'-gB27]ޓ{d%fޭ?4vNGʜKKĶẅ߳gϜqs"bųctH5  {!T&U'/!b?BH[#_2fa9&Ot=DL5ދtra,gYYdggSp ?NZzzz<}F[VUUE7ເ6 7f͚G?#)33@!Āj%ɲQo}? :ADbh匌>imFupGza744?T`Xg?_sA<W_}0e Bb_!^' "/Z':䁎GQ5oNX||IPjj6,Xwoẙp-ojjuG9n:c7@B@sxb,h @?@% B!1qd<|҈cAyF(rd\$Hd=#P@?㽡Q~uuu;3 `eY>GD_<h!rN޻%/)7Q~;x{蔈>4O͠E]o߾9#p/++K/b٪ <3A_O>P!ƣwT5/r[:5ō?LYFELOm.uX|dfzǘ?~ X$AGc,o!8z$x_+ g B!OuoV)'|ǴCۦ cG&[N^GE$zLv-ó\y!~*++WU/?;l߿q>f B]2qI&q#Sd&YtMp!" Gv3V% ZDr ]w7L?azalFP~v۳bcĀ@q B!?ZKc򩒏}l_{J{F=FMpLكED0=dJQ W!L\q"\b:*dd~?Բ.3@!mo͹hl"i'ʄ9t1tR_β2KNoQqxuJ!1.)Σ`{U0t ]{ 0!b> ]5;0&Yd zuCImu?>Ju1744̎ChT0 p?ǘ1_nH_?B2n͔#\ S3^| Y V ZXo ݝ1OeCNz???_ЏgUʶm"" `B!mCm\Sȓ] ~H8S|3huCGG>|xp#gQ ?Vb.d3}쿫D R[60!BHd:{.TgJ^Qpg-y`"8鿵U;6qZ?eOnߔ7L @X ~ڎ# B1*ԧz/JIOOd^KzLj8,#OiOc0֭[쿑FDWbgK B1Eⰽ"))ͺnp?rmTݻwNY9^ b'*4Azt|H{-}?B!Y1Z/' / !2gwOiapcGy!]?_C^{Q5qL_*EsB!SWw]Vؿ@gB!7 Կϒ锰Ό9IpZ+~ss4({_itA;:t_|EfaD*ڧ% BsR_JNN3Kn.uqw-ǘ?x_x%*`{ytitf~A9w./~ B!Leɹ v˵'E$w>އ1cǘ?EEEZL UolذaW')`?@!BJSZ=u6:v]7DW1h@KNNNkA/}e  D7 B_6nd1@O!BghԌW51M,9-ko߾9BӘBG*N wGG0{_WW' #_<?1@!b%?̰J1";׭Fo~~'8C-g8slٲN]5Jٿ'/#?Ϫ!Br*ɚu !+ Nu/4Q9{1Xd~A'%%VGc_FFFڷj9v뭷({'D~ ž!BS4/kj\~(Hԙ\E#aFˋ7;x#Xؿ92f `${/bϗ B!3dHCnH?W?66݇ɒ%&P:!ԹгzgFV3CK!B iЍPɾo[]( Ёŋgo@4Pz_}GT xGj@0!B0 +x$38wwwռ<-Z(U/,/ǃzj曟cDg | ~!Bs2w:@m%}G8WVVjshП}s>!~y1 dz{\}n?c)]2B!<$g)U]TTDɠEܭC>dwu~W;xtuui2~-<*?B!:B2!D9'=釒pápnF>0_@w(5b:_$4U0rcB!*NC':}ʢd"“?1:(ǘ?8#/vLj쿫c (_5k<"3) )ƳnxoBH:AҦSCz d@}Sp2hau7wdG1ӿf8FΠ_Ol{a)l5. {f < !ϠȊ_Pho-̼nӿk&-sQ___M@"N D7з|?.1{b9"3@!',4ghdEh+ NoJ]GᲵU;6q0֎-oeqnŀ71ZZZ^ڼy1?ϥ Q30!Bgi+C~}\X89yr_YYژ?*έP=:9뿻0g#\B!du3i_FFQ|3hau~3{?888Gdhm-Ɩ(7o瀀ُƎ}}}Aѣ>SMy_Y!U0a@B ӆOx[7u'_Gk ]Gcf?Fx?>{x(f"ƫ0!BjIdaHh No3~cc_xY=x}LЫ&v]<E_F"ƲZ( B g :c*"u]> :4G,fffŋIx(G4>]=aÆ +aB exiH .9̿NG@w8r@GGG~~GGǮk׾!30o"Ƴ˱B\N^E=??Ӧ; "U{s/))Y h?Ljׄ(}b\gCq! FӋH"B,Et, 5G4E$[7OB?TUUi#,ZuS@ ^\EGk֬yM]uN O+/ 0 `!B迤xS|S|a0MMMsD D~}} ?:F!S[+{I{ 0!BH44D5Bm :C꠼fm(KbOx@?_! > _'B)i쿙D$Z7O#=|CU(K+O;#>'Gf]M3@/ @!Ķ<,c,4o-FϿ霽e*WPUk hLj@ڭz_Pc x/'^B!3(Bz K8Z75M92+.!8 }}}spBUw7€@#0/|IoDgD5hB,ϒZIs|LFdϡCxfb9?({mmm!Xu"c 0E{؟k!؄ǖ|1AX `7888{'V=FdGFFBڷWgbHF BmrfȢʥ1'ʂ_,na>oxRBa`A@JAÇ:Du=>1Koڴiwq?_PG3`F\.1!+d4<X ~8%xLKK˼nNK}٧TVTUWuya'N7Bsl_|蒪Eᗣpy^@x^_O>ĘI]C-|-t oPIj xZ&M??Uj'&iӦuPǴhv ?lciѤKh_CӅO^zUz?QKi'(s // W_ C-p1v*107i… oЇO<^Qm7iQd6NB$ҥKn7|jժ=J26.?a?o?YD>@G"O[ 9G0|~ 3L&@׵ߴ:GoLeێ;6[ /_/^HoXf)ڹs}QS71/2[ -#JWkkC=tݣP@ˈze߈ѶDMu[oIJKkeʂ]M[<_*D^z,O#:9.\FF&w}?U9HRKQOARa$"eP  <_74t\,:EYH 8zɓ>s By٦?wsFU7T1@%H%uc;U1 O'JЎbއ;=I˾} _X2cƌ/,\Z7Jҿm NPDK<ւ 2Whw!0|Nh=ܳU]OYW?m?_er./bEZRnyjߨ??듗jG|wi!kguv0vH0ɒ%FIUT٦|nNMKʮ_w4PDc `OkLu8O3vޒvkv2@CMp__oԢi˓%3U~9K9rdP'2/zݦ~HPӢMeϏO(@16l0?{`ɿ簙qm'?yL]oQn("10=gg u9o:rVXQ]|9 e$0t輊竛oRq\EfO:Ux[{}^ګҫFRT1Ϫg}qjF@V?) CCIдIzӓ;u7-R0Mk $O<9h_h!Lމ' _~衇~Oʇ0# PE?"*bT`ĿIкB?yGU˿\M./JB5s݊Bw9M?|pкk֬  \pc4C"ΫS/8tm^ۿRT1@br@t(h-vW5εv2dG@+ y*}~dݺuj֬Yy &7KR^:ac}^Q[mLg:= }Bm<% AWe?6Tuب??E',?k'*yw޷+W?Jߞ={&Tm_ ?c:RtMm)\٦IH>ShSJ>IpI@K4&* ߶z#~L~oBjk~듯z]MD~tH?<O"KMb! x 3<^ h9`'mHu"?&/(mz5}f =A͙3'/ŋԩSK73ώpAQ _)PH̛\gPO{x./^@k.eǫ P3ի\IBGSǎ ǑI"_Ŀfۓ/Yo@(Ejf Dn{yEGoѱ.w$io&UIfR .Fu'J0/H %7Jb$;ٳGQ׫y~Ti?dn?H/_-e[I&RW1ZYO:wX?ESLjPoo/-\Th%OrD ܿ I200X./f.*yg"%ŋ /ަO%L10DV(GyGyKVmBlc@ $gG8h_SGܿJoʕ+ ooL8R?x?sLxR?iҤ*F|%Ec)W~GIY/g:@J0LGLF򌅤㺃>FI@ZLV_=C^θm8ZB ƒ#GLT%?/PZ߾^Z{⦅e$+<*@,D}MMKڎQк@7"-P6JJ͞=ika@Ur  @.#˖-K/&@# ؞MxI~?'/_?9& tai7 t(Hy__x3J jWժU3u'{] uLۆR^K=j(&K$KW +e֭?+HJPdUc@D X 5/y-)ޤp$2N韮UcvmkZHҿ˰IUVyA3P?TP*I"ϱ#]GKIA-7-^d2CMþETr߷3gΌ-'}GYtip0&wp(||'c+lٿyߦ PPUkN(_eo c _ѷ2\TN@jf "UTb%_B guQ?ql(S H3LMۊQlcoLۊȗy-RqI̞=9C"fࠗuj3߃OyfP)5 TŋWa Ǵ6Yի6;=:v:LR[n,_3f@cڦTeu {챷UrMIRٕc@KFuɎhw]A./@Dy#ʲ~"$y}c#QdY+W%FDbk_Ygu#k?-o$1@ZPF@6B?*&[O8:ݥ紝};ZIOOOp^DYbE& urίcz~ ,IR׫6U3YT1b&@mbT#OgO ٴ&I:igr.uM \ '&@Yvm0/HS;Cmӧ<YyӦM࿰ocٿPa@;}>T7&wZNL%zLJ<֌ v55$`` 8/]|IIs ۔Ǔ;`$\{P[HW&@q^ (qy=e}ik^Tpٸ|iw3ljY90_nqD_~l DR$c`đ/zy.oƖ;v,UgUOwُg<5/^ Z k5')A֭[,hܿ쿯?La1j;Ρ(D|2[-~]! Ė'\KڵkܹsKKdCc !`>[u?+?hF"F@Cow1j Ůynm08d:L@.]4vK.UK, z&#\y)T__,N[zD +3F5޶(./&Ra ey?Y/n-eՁvhuC<!sO=:R-??fd {Yj|3sS)ߵwM I2g-#q'U!/!ktAzzy'F ]P)0reu}hzGx{a{#GqI:2/7bC n,ObV.gc``@6;rY`Q9 w is%쯿$ݺucO+mT};.~߿pUe/*we.e5{0.{}R-KIɼGp;i_jXҿMVL\)Z1#̀fl[Vh.nZ9:p1&k`U'KR?C6e``ojtɿ!s_0{>c\wNzwZЗ@ǀBgʔ)A3$wp(t*>П͛7ߣG $BZ -a4<@i45Po{.'jrZaIY/osoƖm۶TݵC O03 i, 8~6 *$Kߍ7z;'NTAB:S\8t;wqǶ+%7m c!6_3+N$ۥc@BBAo߾`:2bӧO!!`K>te׿IyпjMH`d70 ~yIu%jM 9}@KȟI_k֬3̤  4dL%ɠrA^7m]="k[s&U}~_aT@/͛7uC3*mZH_ZE?>Xohhh/^/_>v^fNuG7wbR>}sx饗}?۪D=@&@Ҩtxj+v!%_Zի ΋13{ I$\fİt=FT~Iۿm?P4A+_K8ijRtPP P?5kyӤ  |ۈ~q_}@+V#iI%L(dl" ! 0Y@I؟TEH\LIڵkt@b4k{b\IdU@]E57#o*ih!6wi79VD,'~i?zI߆  71$!ЬU΋OTqAwj^rP%'TFFY՟ʈJrWZ? ?~xPENL~Y/  HP^K6mt9].bA0?5,PΏ:)YKs/B_J_{G }}}O'j4XW19-iL_x z{{@%?tRdɒǑ ;lۓAoGy7']Ľm?g h!KTn&&3"߾}A [j7oe3g F^67>)WR~W3 MG'$h4 .llYۓԞ~<ӗ#ߤZQI)| B3RׇЪYIZϟ?ݺuj֬YcIR?CۓϬXq7oML& ̗}YP.Pޫj`FDm]Z'NCM$K؟TC= q޾\/3>~Rf6KV}-G?`@eBZ? D1̜9S_>d_$7KRo(e?YOZH߆ ƽI@+@)e* tIw ?ڟgąs0 hКaN_PT\:u*h)a%$o͚5A i>D⼜mv*bf5zG/}ف#*?M#`gp@H_ZeY4N|I03E/_>2p]q޸mv*ci/c_رcdz_7Ŀk?/f_)?E_`@/g E'I"u[sp:DWVs'n ^ bdIKY-2^yǾJEYsiy?O#*#k=T@TŘo߾qQK?j&#\1M1_L2Џ;_xU}'Ue'/0 h0mZ`TIwqLEKA4!mʪe z,-[yꩧg/;<џoRFBP7H_'N:O n6ŒtHտ8w _C4eֿ!ZO̫YcYBeFYJb"'Ar("}mSNTjw~<^qE+rm*_r1RF0aҿ֯E9sfy{6mC *|+&-kt?wJ *a:l쬞]D4"ǃl_en:Dׯ_GEfe+@YJ>e->w׾ބ\3ߵr$`"XF S9i1v=noY]vЗӲ_HC7fV>r(YprӦM{W>QʼE-Bt跹oy1 2_IdXQ7EPzU k'O . R_n# '¿\ ^cϭt4ap?m os@P9N K._F<O8p`Lȗo8/goԜ||]vUK tWVe h{3dy`膥 ¤A:c'IҿTyئN߈9p۷ov?3 __EoZNԛ\nt;vi#ȑ#c'1C ? aOu+CCP]*B_x-w+jbП/?oɿӈlc4ZH/* L 4R۷/0"#7}ty H/6\ zTg]w;s@⿎ ;?lD'2$e%iUڻw' +mgTVC[m]xW{^TWcVT?0x ƀbH).gbH_=VC`rq,\/n \1|oSo===;?spy$} hpeyg.YГ!ojH+m') .wp?  WȒp f{-=ЯU 2P`r޽E7nMi_n5kָH*$ĈSYmї y睛uf-0D-KgHG`@ κE7$"LuѦ[neB{ 21 U>\xwu^Ws@n?`[r#1& ,Ѥv+ojxyǎ/?~]/_dE3G^B`@ mGtR2,'e˖MN߉C >C4Gy>?sEV˱̿B`?n3orzΎu$;/~닑?͛ E%w!IG(E臢]^ww\.->^d8$zz[oգ[u$//J:iT(/_[]v8/iV[G{__4? 6yeE @+j~]+k]B{2~K}X~lڴiޅ%@u pU~]9}v1yBmxRv?4PZ9HdNKJ9n90Z5uo~N:k=ywd_%/g3` R9gϞ=p†mg*)(Y'd#ǎ;\7$4҄hO3 :,~)߹Ǐoe˖*#BL6U,?ҫ6I q`;ߴ 7C ,(1E{Q1}/Ƿ\;wO{jmE1j/: &mT9;# ~nʔ)MζM3.糄xuI?:o~?ݡ_Vy6U!m+ (Q0}E< ͞=3IMh 3tяwر'|[g^S-#*M޶GkK?(]/ 7׍;y]v[ܿ|IRvK𹜟kQ߼?0J6L2v:tUڵky9s̑?[V1Rw(ߵ-` ̀Ds}_xGЫ\Օ~]߿_[oI"6Eh75PP؛t9!oo}*xʕ+:Cm~+Yx_¿]7`@e-$ {9pօ ~~ƌKS@ٷo~T*4?-_)3.+؈}[ {y?spO%OG] aR)0]Ѣ_Vuş5k2sU)NW_}k"Trr.s Q/M?<+i?: 0aJxqyu͚5-ZnΜ9LrN,?kA~' |>ۈ"RЂ 7@`L4iɟНW\^ KЗOO &;wdooݻwoڱcTGk#Er7l SG?@W)t I&ӧz뭋n喕S`͒%KVkS`>RgsҥzǎiD>5MEQ#`ڥ~ W< #.7=LJ0&-[l)\uʹs.S8W^~n_z|ZoZOfV}W3#0 p1: L:?`mݶpÆ KAhuni5JkcZ>{|Q'VV+C+Un_^˿G?฿55 09d $SB.Iz`g?مԧks`y7|oqNV#0Ҿ9'NKE|GtU/"B\]MFU syiž?e_&@-2j]kv0Esu<=N0_3OwΙ9s\}lV'C s:O"ԙ3gNY:N?JL26?2ۖ2 23 Jُ6,ڔq>}nS`ڵkg9{fmM0[4mڴaFx܎oz}/^x… ]gu~ɓ'tɁK1AkܞM96e!}/"Є+Y]6¿` }oAt-_|ŋgp™z` m(za(>arg}<]?uԠ@lUz^r%9?44tE_?, Z_ЇKZ_ЇBA A}Nۿiů&"-DL mT0|,M_# sf~*e6e@>7a&؊<'] oo+}.}**[ȺXъ&.u@Y&f@^e@zS^/p_oz~6F@]J/M Ϫ? ]vk"k$"¿+fܧJPx7yk <]Q-bFvS`0y]yK{n*}|d D F72ԯf &Oo"}^f*] `r-$MDZ@ ~}I!`"mDU^%6@Q#/bV 0QC O i&DowI/+ pVr("}[Y9EM"߷3f>iąO>2b ~>l5=o+}?:0Y*C۴gb@?Fo p>ME46I:VF@T/eo,_e""(oq#%m<ZH p1_S3 Oך(jT(+oTQ-ndi@S5/*5P,Zy Pe}\>Om(@R7@]f } ς/#Q5\̀׹}?@P-%L*ys&ݵnVo(3ѫ Mľue ?@ @4Pii0_D(5K-)]Ct@$qߤror} <|8'}UZk\2lh"9]W2??M7\ż\E~wտȾxW(4pݶPID|̇/((_+>M_"5cؚbU~UĿO1DQ/K#0Ty͚/kV0|zJka>^L_b ~+~?@L"݇/KCſ,#`naCV&/SXV\Yf@3/sEF {ߢր=E8aU~*ke޶ m%}[qݬ} ~?`F@ u]Y"vmUeV! ]׈}5k_^%^_z&д}Zůy2kte fZ_o aY/ަׂBL-6ll!__eYxJžB'e FZVݾLq `?{b[Յj#xJ Zߏv3M|~~KMS;RoA@_j-\[ysM `_`"F`MiS70tQ9~} 7Ob`_ }~D>?N 7Dx'OoIENDB`qbs-src-2.6.1/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256.png0000644000175100001660000002605014776170045027757 0ustar runnerdockerPNG  IHDR\rf+IDATx] M2Fez'Piy"T4hE@ty"O 3 xE2 @H~_\b1mߏ^V QX [q;>k>+˰Vvk+}A  "╕zW.u{)C / BɸV{|klHH,+Xx?Z76>!mh%Z۳sc,wL<@Hy ܿ&e,>ux{ҟ @>ޗVkm DclD;tZڎ@HBeGςׂ!)Ab ?x^}C@/7˚ty@WcǏ&z}ע=0"9w`0+ a<.͗Pq^o?>p 66pNx>.{Wy%d&KDf[yOpDK8AٵLB1  jq sx?8k0>ߑʳ(zrx?ɓ K)>{~3 Y? ώƮaǏPya-^ t92?`DU_R<V)^0LAP2J;arz1o){?WavxZ bTȔV \aV} ]ԣG^؏/yiӦȟHYt5oMAktoF$(W{챻da÷سg]!yv %,@(6Y_Ͼ+JoDX[㕅@G^T2e*u3;f#F8RN竪9 A0 o/y_V?L"(*m񖑾~Kv3|;w%ŒjP rŻanÔg2 -L0(!0ڳnk1 )+W[r. S5"*T^+|u$yz|.\T{>eJuY|~$vq|U$!EEOQ @(2nqc=vx}fؿu~}ǩI8f-P[ζqET?v_.] UT?sɼwd.{6ozhrsvRIr6lX?cƌbUX򽮔0ꟋQ5`b6 Hʸ0#b.Nuq΢7Z #K+Đv_xH7-Z mg!7I;ug F|̙#f̘r.JXj ? Rv[XdsbFƒHE5eϛ7OlٲEL>}ӦM;i'0pߋ-zG,2DBż@M!p}3xw' 6@(߾}ضm2e@KΝ+-[vkڵkS Ti# qJ|ѢE \f}W^bرbժUC׷m۶bO+CV][dg]T8 Pw6Sq M8Q,]T>믿 9O~1a~zA0` Gf? X>icl៑yM ۑgKS:Acw}'~7k׮ _ѧOߺu_ƏD?S%!V\ HmG~גJf9v9ӞO4dիO0z?R~ Ow.\c;R~`Z X_p߇z&EP+oL~W =-ADGyVnO?t{wСw\(~а`r} ÔD߱!W{/H-G1A 3h?? # ` 6}kmV3//~DD{׮\A9~~^3BcADw%~"gzJw9~Jq 5(9芌If+es;=m{m%KXo^;qҤI})mw9}giif6U^k񢇬t=7jAT=b=EQ(`zO1F?hf/gΜ)~m!yɓ'[ ~a҆nq`%mmZ~CNM0wzkwo>#jbۻEڿBNAhWT^iCW9TfX(Fd<?x*gh5bp}[|H類_ڃY~7o>!'gMSG ,?MV[i0~ zNqᐵ1|,ϾCC_hkW͞=G ElQ؃_[;pos'HZ1db/SuNA;c܏#0ɝ7cE/m:駌՟`>8vXLJ<>Wīzla۴Mbuy#&C z駟TOʛYq_J9 I~kو#Wi .M"l1 nN 0@k-~h>?(I&Jb?ps,z7D1߄ڣƁ]|LF"zן ߦ-n"5h }o5FM!,FMFٯ/~(>]Xs,$$ޖc;>V{`@\ǐ!C` E*foƍ_R/GD`8::4ғ\W|lua6MqMYcUƪ_y-^hdj__6P|7NGrhH$|Kݮ'+ǡHthh>sXnݺs~)>#NՁyuP&p&rj@{VM^9 =herŢKEɹ8%G:oIq#uؒ;au8]WA{^|>>_ O1IJ C.8N GM~=H)ʁ!ZjLI>IƏp&rsዣC;4ŤWAuVWKPym$``'-{F58vwJjѐzӇy`V5 @*GziZ_vB)w rNYq9.n"l1n聻&RшA4cw7(Rq^Ec fOG+i` ?jx.cL 2R7~9Pd{ZH_ &(e4c, 7HF0"]tG6< _%i.BʿA{c%U$Td {ɔ>I|XM&>@k؝}hd Ez7 jh(Uw0 s+KP[6J[ʊ 7HF0|=뫯Ѽd\$}jժ;ȯgX2FL k՗*U?#lG]F b[9-4PP/UI%!ڡAnӾos2T`z&"ҏ:!>3'\|kU꯻z6b8K5?dJXNj\R䨯5TD&F࿈~ڰ{bIbPb4d]ojwDӕWyJ䳔jCEڕՖyEznXv܂>R{(E]?j`2`xS…P.ntG*yW۞BJ b!25,xIK*'Oڲv~2$&9rGI0|7&SPxdIiѢś*}*;3qt!ȫn3 S TpzH/GT5fvɪ 7xCJGbJ )G뿯O>dʮ\urگ &dj׈زe'i(^/EYe0~9B {)}Ї=K.yHeUd<'W7 d hPIjlq 5\UӏmN* @̭۶m{;#S!dj7-1m1$&bEuL =r_*PT]2*vO`'-ĺ`KemY&"a V}0 )HM'!H }ֿjժw E?D@A%خV% DD IC}D7߉E[[T1UEWw`Wl"Et*Wh` pkVFwW1 ͂3++*UGa򑱁?"XPHmU^!ަD"a8+?F?nbLAϛC>dzr[ҥՊ}[S+W Y_orѿ}(A==)Ѝ_ [_Gm/P[⏁?·`gN$k](q %^0(ˇ9(={_d nf?3iE'+K*u5h ?mf D?=<4MnCOyn I#˖-{s$ GoM‰Adde"EܕC]è?h E+!`Ķ>.&S) e9+>(W7fT!g֟wPzD~>}eNL 'Ak&\wu8+ߏ)JN?n@ @~]d5C@]ʸHjCcZ/xg M R!xlf͚uRA?+;"2GG+`GY/ QAM 8?">h:0F .~?D %K~L W*kG?31qĿ ߉ Yw2vVVUA?3OXA@Ypnv)p4EǎC9oOab_xᅁY9gYVq'Or5|5\.(A+?}ptX!D"x|Ge圓qյ]àx0r) wy`$G_""e5G/F{r3G^쓜]ytc@N<0~0,"fmm e+T_00)OH m9,.{`GƏ^~nB*A:hiݺuO?)pR3}n0('Ge1K#h aL X2haÆrfTtҠGcMG[}taZ/҅;ѫ h@(Ӕd 4!C}}+"ܗy|١#pLZ5 ,ի?8wh8$ 9)4~"v[-0nݺYH{0-Vs066Kն>;HvM0H{ m2rtCVӁˁׯ [0jGǿ0jjUOdd,bfGZs hDne͋/W_|zlҤɇ=P϶mfwa0Ce>_Vu=7nܹN:P-{6Q@Rp R"i>~)OP 7PڃQk(1F 2[[k}J ]@{}%*iVu5cF}૩H3sj hm *s3|?n ,r(㪨Zm+CBU@k)cpש݃SVz\>W ޟ6bj/@OPX@>ZQ+hIe\PVN +) eU*]]e^[EE+ϲWsԵћ}^'( Fu2ʧ>Sٚ0UZNU2`7VP?{z]9^{)OW;SJo}>D-n 2؊tC1WYRߕHBaFgj^RWqgh^0x}{ojO'Bp-Rš2֢J(lp3E #/{~VziAri[<`-4EgkFO{+n4zH2MSty iD1'Ͱ "/AAAAs$t3IENDB`qbs-src-2.6.1/examples/cocoa-application/cocoa-application.qbs0000644000175100001660000000524114776170045023751 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2015 Petroules Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import qbs.Utilities Project { references: [ "app.qbs" ] SubProject { filePath: "dmg.qbs" Properties { condition: Utilities.versionCompare(qbs.version, "1.9") >= 0 } } }